TensorFlow 层:使用自定义(化)初始化函数?

TensorFlow layers: using custom(ized) initialization function?

为什么使用 partial 获取新的初始化函数会报错,而 lambda 不会?

所有这些功能:

f_init = partial(tf.random_normal, mean=0.0, stddev=0.01, partition_info=None)
f_init = partial(tf.contrib.layers.xavier_initializer, partition_info=None)
f_init = partial(tf.random_normal, mean=0.0, stddev=0.01)
f_init = tf.contrib.layers.xavier_initializer

抛出以下异常:

TypeError: ... got an unexpected keyword argument 'partition_info'

(而 ... 代表 xavier_initializer 和其他功能,当然)

应用于简单的 conv2d 图层时:

conv1 = tf.layers.conv2d(x, 32, [5, 5],
                         strides=[1, 1],
                         padding="same",
                         activation=tf.nn.relu,
                         kernel_initializer=f_init,
                         name="conv1")

但是,如果我使用 lambda 来获取自定义初始化函数:

f_init = lambda shape, dtype, partition_info=None:\
         tf.random_normal(shape, mean=0.0, stddev=0.01, dtype=dtype)

...它没有任何问题。

不应该 partial 也 return 一个新的匿名函数,例如 tf.random_normalmean=0.0stddev=0.01 一起提供,就像 lambda 语句那样?

错误说函数 tf.random_normaltf.contrib.layers.xavier_initializer 没有名称为 partition_info 的参数,事实确实如此。没有这样的参数(参见here and here)。

你的 lambda 有效,因为它没有将 partition_info 传递给 tf.random_normal,这是正确的。

还要确保不要与返回初始化值的函数(如 tf.random_normal)和相应的初始化程序(如 tf.random_normal_initializer)混淆。第一个 returns 浮动,后者创建一个可调用对象,需要 shapedtypepartition_info。调用时,此可调用 returns 正态分布值。

您的 lambda 确实符合此签名,因此可以正常工作。但是,当使用 partial 时,生成的可调用对象的签名只是尚未被调用 partial:

冻结的参数列表
f_init = partial(tf.random_normal, mean=0.0, stddev=0.01)

因为tf.random_normal有签名:

def random_normal(shape, mean=0.0, stddev=1.0, dtype=dtypes.float32,
        seed=None, name=None):
    # ...

您可以像这样定义部分一样使用它:

def f_init(shape, dtype=dtypes.float32, seed=None, name=None):
    # ...

请注意,没有名为 partition_info 的参数,但 TensorFlow 会在调用 f_init 时尝试传递它,导致出现错误。

要自定义 mean 和 stddev 之类的东西,您不需要创建自定义初始化程序。例如,这会创建一个初始值设定项,即 returns 均值 0.0 和标准差 0.01:

的正态分布值
f_init = tf.random_normal_initializer(mean=0.0, stddev=0.01)

但是如果你需要一个自定义的初始化器,例如要实现自定义初始化逻辑,您可以遵循以下模式(参见 here):

class RandomNormal(Initializer):
    def __init__(self, mean=0.0, stddev=1.0, seed=None, dtype=dtypes.float32):
        self.mean = mean
        self.stddev = stddev
        self.seed = seed
        self.dtype = _assert_float_dtype(dtypes.as_dtype(dtype))

    def __call__(self, shape, dtype=None, partition_info=None):
        if dtype is None:
        dtype = self.dtype
        normal = random_ops.random_normal(shape, self.mean, self.stddev,
            dtype, seed=self.seed)
        # do what you want with normal here
        return normal

    def get_config(self):
        return {"mean": self.mean,
            "stddev": self.stddev,
            "seed": self.seed,
            "dtype": self.dtype.name}

# Alias to lower_case, 'function-style' name
random_normal = RandomNormal