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

时间:2017-04-24 10:15:55

标签: python-3.x lambda tensorflow initialization initializer

为什么使用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不应该返回一个新的匿名函数,例如tf.random_normal提供的mean=0.0stddev=0.01,就像lambda语句一样吗?

1 个答案:

答案 0 :(得分:2)

错误表示函数tf.random_normaltf.contrib.layers.xavier_initializer没有名称为partition_info的参数,事实确实如此。没有此类参数(请参阅herehere)。

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

另外,请确保不要与返回初始化值的函数(如tf.random_normal)和相应的初始值设定项(如tf.random_normal_initializer)混淆。第一个返回浮点数,后者创建一个可调用的,需要shapedtypepartition_info。调用时,此callable返回正态分布值。

你的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):
    # ...

您可以使用partial,就好像它是这样定义的:

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

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

要自定义mean和stddev之类的内容,您不需要创建自定义初始值设定项。例如,这会创建一个初始值设定项,返回平均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