如何用Numpy复现TensorFlow v1.15中tf.get_variable的默认行为?
如何用NumPy复现TensorFlow的Glorot/Xavier初始化分布
首先你已经正确计算了Glorot均匀分布的范围:
fan_in = 2 fan_out = 3 glorot_scale = 1. / max(1., (fan_in + fan_out) / 2.) glorot_limit = np.sqrt(3.0 * glorot_scale) # 计算结果约为1.0954
你的各个模式输出不一致,核心原因在于随机数生成器实现差异、种子作用范围不同以及初始化器调用逻辑差异,下面逐个解析:
各模式输出差异的原因
mode0 vs mode1/mode2
- mode0使用
tf.get_variable默认初始化,依赖全局种子tf.set_random_seed(0) - mode1/mode2显式指定
glorot_uniform_initializer(seed=0),这里的seed是局部种子,优先级高于全局种子,会生成独立于全局种子的随机序列,因此输出和mode0不同。 - 若要让mode0和mode1输出一致,去掉mode1中initializer的
seed参数即可,让它也依赖全局种子:variable = tf.compat.v1.get_variable(name='variable', shape=[fan_in, fan_out], initializer=tf.glorot_uniform_initializer())
- mode0使用
mode3 vs 其他TF模式
- mode3使用
tf.random.stateless_uniform,这是TensorFlow的无状态随机数生成器,算法和glorot_uniform_initializer底层的tf.random_uniform不同(前者是无状态Philox实现,后者是带状态Philox),即使种子相同,生成的序列也不匹配,因此输出无法一致。
- mode3使用
mode4/mode5 vs TF模式
- NumPy的
np.random.uniform使用Mersenne Twister随机数算法,而TensorFlow默认用Philox算法,两者是完全独立的实现,无法通过设置相同种子生成一致的随机序列,这就是mode4/5输出和所有TF模式都不同的原因。
- NumPy的
用NumPy复现TF Glorot初始化的可行方案
如果需要让NumPy生成和TensorFlow完全一致的初始化值,有两种可行方式:
方案1:从TensorFlow导出随机数到NumPy
最简单的方式是先用TensorFlow生成符合要求的初始化张量,再转换为NumPy数组使用:
import tensorflow as tf import numpy as np fan_in = 2 fan_out = 3 # 用TF生成Glorot初始化张量 tf.set_random_seed(0) init = tf.glorot_uniform_initializer() tf_tensor = init(shape=[fan_in, fan_out], dtype=tf.float32) # 转换为NumPy数组 with tf.compat.v1.Session() as sess: np_array = sess.run(tf_tensor) print(np_array) # 输出与mode0一致: # [[-0.39295787 0.4208691 0.53050697] # [ 0.8091326 1.007618 0.95607924]]
方案2:在NumPy中复现TensorFlow的随机数生成逻辑
如果必须完全用NumPy实现,需要手动复现TensorFlow的Philox随机数生成算法,再将原始随机数映射到Glorot分布范围。以下是适配你的场景的简化实现:
import numpy as np def philox_4x32_10(counter, key): # 简化的Philox 4x32-10算法实现,适配TF核心逻辑 PHILOX_MULTIPLITER = 0xD2511F53 PHILOX_INCREMENT = 0x9E3779B9 for _ in range(10): counter[0] = (counter[0] * PHILOX_MULTIPLITER) & 0xFFFFFFFF key[0] = (key[0] + PHILOX_INCREMENT) & 0xFFFFFFFF key[1] = (key[1] + PHILOX_INCREMENT + 1) & 0xFFFFFFFF # 置换操作 t = counter[1] ^ key[0] counter[1] = counter[2] ^ key[1] counter[2] = t return counter def tf_random_uniform(shape, seed, minval, maxval): # 复现TF1.x tf.random_uniform的逻辑 counter = [seed, seed, 0, 0] key = [0, 0] flat_size = np.prod(shape) num_blocks = (flat_size + 3) // 4 random_bits = [] for i in range(num_blocks): counter[2] = i block = philox_4x32_10(counter.copy(), key.copy()) random_bits.extend(block) # 转换为[0,1)浮点数并映射到目标范围 float_vals = np.array(random_bits[:flat_size], dtype=np.uint32) / (2**32) float_vals = float_vals * (maxval - minval) + minval return float_vals.reshape(shape) # 生成Glorot初始化数组 fan_in = 2 fan_out = 3 glorot_scale = 1. / max(1., (fan_in + fan_out) / 2.) glorot_limit = np.sqrt(3.0 * glorot_scale) np_array = tf_random_uniform(shape=[fan_in, fan_out], seed=0, minval=-glorot_limit, maxval=glorot_limit) print(np_array) # 输出与mode0一致
内容的提问来源于stack exchange,提问作者AKG
相关产品推荐
相关产品推荐

