我最近在线课程使用TensorFlow完成了CNN实现,我不想提及,以避免违反平台规则.我遇到了令人惊讶的结果,我的本地实现与平台服务器上的实现差异很大.经过进一步调查后,我将问题确定tf.contrib.layers.fully_connected()
为TensorFlow版本1.3和1.4之间的行为变化.
我准备了一小部分源代码来重现问题:
import numpy as np
import tensorflow as tf
np.random.seed(1)
def create_placeholders(n_H0, n_W0, n_C0, n_y):
X = tf.placeholder(tf.float32, [None, n_H0, n_W0, n_C0])
Y = tf.placeholder(tf.float32, [None, n_y])
return X, Y
def initialize_parameters():
tf.set_random_seed(1)
W1 = tf.get_variable("W1", [4, 4, 3, 8], initializer=tf.contrib.layers.xavier_initializer(seed=0))
W2 = tf.get_variable("W2", [2, 2, 8, 16], initializer=tf.contrib.layers.xavier_initializer(seed=0))
parameters = {"W1": W1, "W2": W2}
return parameters
def forward_propagation(X, parameters):
W1 = parameters['W1']
W2 = parameters['W2']
Z1 = tf.nn.conv2d(X, W1, strides=[1, 1, 1, 1], padding='SAME')
A1 = tf.nn.relu(Z1)
P1 = tf.nn.max_pool(A1, ksize=[1, 8, 8, 1], strides=[1, 8, 8, 1], padding='SAME')
Z2 = tf.nn.conv2d(P1, W2, strides=[1, 1, 1, 1], padding='SAME')
A2 = tf.nn.relu(Z2)
P2 = tf.nn.max_pool(A2, ksize=[1, 4, 4, 1], strides=[1, 4, 4, 1], padding='SAME')
F2 = tf.contrib.layers.flatten(P2)
Z3 = tf.contrib.layers.fully_connected(F2, 6, activation_fn=None)
return Z3
tf.reset_default_graph()
with tf.Session() as sess:
np.random.seed(1)
X, Y = create_placeholders(64, 64, 3, 6)
parameters = initialize_parameters()
Z3 = forward_propagation(X, parameters)
init = tf.global_variables_initializer()
sess.run(init)
a = sess.run(Z3, {X: np.random.randn(2,64,64,3), Y: np.random.randn(2,6)})
print("Z3 = " + str(a))
Run Code Online (Sandbox Code Playgroud)
运行tensorflow 1.3-(测试1.2.1)时,Z3的输出为:
Z3 = [[-0.44670227 -1.57208765 -1.53049231 -2.31013036 -1.29104376 0.46852064]
[-0.17601591 -1.57972014 -1.4737016 -2.61672091 -1.00810647 0.5747785 ]]
Run Code Online (Sandbox Code Playgroud)
当运行tensorflow 1.4+(测试高达1.7)时,Z3的输出为:
Z3 = [[ 1.44169843 -0.24909666 5.45049906 -0.26189619 -0.20669907 1.36546707]
[ 1.40708458 -0.02573211 5.08928013 -0.48669922 -0.40940708 1.26248586]]
Run Code Online (Sandbox Code Playgroud)
所有在张量的详细审查forward_propagation()
(即Wx, Ax, Px, etc.
)点tf.contrib.layers.fully_connected()
,因为Z3
是唯一的发散张量.
功能签名没有改变所以我不知道幕后发生了什么.
我得到1.3的警告,之前1.4及以后消失:
2018-04-09 23:13:39.954455: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
2018-04-09 23:13:39.954495: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
2018-04-09 23:13:39.954508: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations.
2018-04-09 23:13:39.954521: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.
Run Code Online (Sandbox Code Playgroud)
我想知道参数的默认初始化是否可能发生了某些变化?无论如何,这就是我现在所处的位置.我可以继续学习这门课程,但是我觉得有点沮丧,因为我无法在这个问题上得到最后的决定.我想知道这是一个已知的行为还是某个地方引入了一个bug.
此外,在完成分配时,期望最终模型0.78
在100个时期之后提供图像识别任务的测试精度.这正是0.58
1.3- 所发生的情况,但准确度下降到1.4+,其他条件相同.这是一个巨大的差异.我想更长时间的训练可能会消除差异,但仍然不是轻微的,所以值得一提.
任何评论/建议欢迎.
谢谢,
洛朗
所以这是故障.这个问题有点令人惊讶,是 tf.contrib.layers.flatten()
因为它在不同的版本中以不同的方式改变随机种子.有两种方法可以在Tensorflow中对随机数生成器进行种子处理,或者使用它为整个图表播种,tf.set_random_seed()
或者可以指定seed
有意义的参数.根据文档tf.set_random_seed()
,请注意第2点:
依赖随机种子的操作实际上是从两个种子派生出来的:图级和操作级种子.这将设置图级别种子.
它与操作级别种子的交互如下:
- 如果既未设置图级别也未设置操作种子:随机种子用于此操作.
- 如果设置了图级别种子,但操作种子不是:系统确定性地选择与图级别种子一起的操作种子,以便它获得唯一的随机序列.
- 如果未设置图级种子,但设置了操作种子:默认图级种子和指定的操作种子用于确定随机序列.
- 如果设置了图级别和操作种子:两个种子一起用于确定随机序列.
在我们的例子中,种子设置在图形级别,Tensorflow进行一些确定性计算以计算在操作中使用的实际种子.此计算显然也取决于操作的数量.
此外,tf.contrib.layers.flatten()
版本1.3和1.4之间的实现已经完全改变.您可以在存储库中查找它,但基本上代码已经简化并从中tensorflow/contrib/layers/python/layers/layers.py
移入tensorflow/tensorflow/python/layers/core.py
,但对我们来说重要的是它改变了执行的操作数,从而更改了在完全连接的Xavier初始化程序中应用的随机种子层.
一种可能的解决方法是分别为每个权重张量指定种子,但这需要手动生成完全连接的层或触摸Tensorflow代码.如果您只是想知道这些信息以确保您的代码没有问题,那么请放心.
重现行为的最小示例,请注意以Xf开头的注释掉的行:
import numpy as np
import tensorflow as tf
tf.reset_default_graph()
tf.set_random_seed(1)
with tf.Session() as sess:
X = tf.constant( [ [ 1, 2, 3, 4, 5, 6 ] ], tf.float32 )
#Xf = tf.contrib.layers.flatten( X )
R = tf.random_uniform( shape = () )
R_V = sess.run( R )
print( R_V )
Run Code Online (Sandbox Code Playgroud)
如果您运行上面的代码,您将获得以下打印输出:
0.38538742
对于这两个版本.如果你取消注释Xf线,你会得到
0.013653636
和
0.6033112
对于版本1.3和1.4.有趣的是,Xf永远不会被执行,只需创建它就足以引起问题.
最后两个注意事项:您使用1.3获得的四个警告与此无关,这些仅是可以优化(加速)某些计算的编译选项.
另一件事是这不应该影响代码的训练行为,这个问题只会改变随机种子.因此,必须存在一些其他差异,导致您观察到的学习速度变慢.
归档时间: |
|
查看次数: |
821 次 |
最近记录: |