带种子的TensorFlow层权重初始化在不同层及实例中生成相同值
问题描述
我定义了一个包含两个不同形状权重的自定义层:
import tensorflow as tf class SimpleDense(tf.keras.layers.Layer): def __init__(self): super(SimpleDense, self).__init__() def build(self): self.w1 = self.add_weight(shape=(5, 5), initializer=tf.keras.initializers.truncated_normal(seed=1234), trainable=True) self.w2 = self.add_weight(shape=(5,6), initializer=tf.keras.initializers.truncated_normal(seed=1234), trainable=True) def call(self, inputs): pass
权重w1和w2的前25个浮点值完全相同,同一组浮点向量被复用。此外,该层的不同实例也拥有完全相同的权重:
sd1 = SimpleDense() sd1.build() sd2 = SimpleDense() sd2.build() sd1.w1 # 输出: <tf.Variable 'Variable:0' shape=(5, 5) dtype=float32, numpy= array([[-0.00682165, 0.03804878, -0.08698365, 0.02000416, -0.0379169 ], [-0.04041002, 0.00349349, -0.04125977, -0.04460358, 0.06052992], [ 0.09549459, 0.06161878, -0.02399441, 0.07976086, 0.05028958], [-0.00204308, -0.09973445, -0.07213714, 0.0325163 , -0.09121864], [-0.07422495, -0.04935479, -0.03293147, 0.01593254, 0.03643443]], dtype=float32)> sd1.w2 # 输出: <tf.Variable 'Variable:0' shape=(5, 6) dtype=float32, numpy= array([[-0.00682165, 0.03804878, -0.08698365, 0.02000416, -0.0379169 , -0.04041002], [ 0.00349349, -0.04125977, -0.04460358, 0.06052992, 0.09549459, 0.06161878], [-0.02399441, 0.07976086, 0.05028958, -0.00204308, -0.09973445, -0.07213714], [ 0.0325163 , -0.09121864, -0.07422495, -0.04935479, -0.03293147, 0.01593254], [ 0.03643443, 0.04764059, 0.00034371, -0.0784961 , -0.01348116, -0.05637978]], dtype=float32)> sd2.w2 # 输出: <tf.Variable 'Variable:0' shape=(5, 6) dtype=float32, numpy= array([[-0.00682165, 0.03804878, -0.08698365, 0.02000416, -0.0379169 , -0.04041002], [ 0.00349349, -0.04125977, -0.04460358, 0.06052992, 0.09549459, 0.06161878], [-0.02399441, 0.07976086, 0.05028958, -0.00204308, -0.09973445, -0.07213714], [ 0.0325163 , -0.09121864, -0.07422495, -0.04935479, -0.03293147, 0.01593254], [ 0.03643443, 0.04764059, 0.00034371, -0.0784961 , -0.01348116, -0.05637978]], dtype=float32)>
原本预期不同层及不同实例的权重值应该不同,请问这是什么原因?
原因分析与解决方案
原因
你给两个权重的初始化器都设置了相同的固定seed值1234。TensorFlow的截断正态初始化器在使用相同seed时,会生成完全一致的随机数序列:
- 初始化
w1时,用该seed生成了25个随机数;初始化w2时,会接着这个序列继续生成后续数值,因此w2的前25个值和w1完全重合。 - 不同层实例的初始化器也用了相同的固定seed,所以每个实例初始化权重时都会生成一模一样的随机数序列,导致所有实例的权重完全相同。
解决方案
方案1:不设置固定seed(推荐)
让TensorFlow自动使用随机seed,这样每次初始化都会生成不同的随机数:
import tensorflow as tf class SimpleDense(tf.keras.layers.Layer): def __init__(self): super(SimpleDense, self).__init__() def build(self): self.w1 = self.add_weight(shape=(5, 5), initializer=tf.keras.initializers.truncated_normal(), trainable=True) self.w2 = self.add_weight(shape=(5,6), initializer=tf.keras.initializers.truncated_normal(), trainable=True) def call(self, inputs): pass
方案2:给不同权重/实例分配不同seed
如果需要可复现的初始化,但又要不同权重、不同实例的数值不同,可以在层初始化时分配不同的seed:
import tensorflow as tf class SimpleDense(tf.keras.layers.Layer): def __init__(self, base_seed=None): super(SimpleDense, self).__init__() # 自动生成随机base_seed,或使用传入的seed self.base_seed = base_seed if base_seed is not None else tf.random.uniform(shape=(), maxval=10000, dtype=tf.int32).numpy() def build(self): # 给w1和w2设置不同的seed偏移量 self.w1 = self.add_weight(shape=(5, 5), initializer=tf.keras.initializers.truncated_normal(seed=self.base_seed), trainable=True) self.w2 = self.add_weight(shape=(5,6), initializer=tf.keras.initializers.truncated_normal(seed=self.base_seed + 1), trainable=True) def call(self, inputs): pass
这样每个实例可以传入不同的base_seed,或者自动生成随机seed,同时w1和w2用不同的seed保证数值不重复。
内容的提问来源于stack exchange,提问作者Ergun Bicici
相关产品推荐
相关产品推荐

