为什么使用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.0
和stddev=0.01
,就像lambda语句一样吗?
答案 0 :(得分:2)
错误表示函数tf.random_normal
和tf.contrib.layers.xavier_initializer
没有名称为partition_info
的参数,事实确实如此。没有此类参数(请参阅here和here)。
你的lambda有效,因为它没有将partition_info
传递给tf.random_normal
,这是正确的。
另外,请确保不要与返回初始化值的函数(如tf.random_normal
)和相应的初始值设定项(如tf.random_normal_initializer
)混淆。第一个返回浮点数,后者创建一个可调用的,需要shape
,dtype
和partition_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