我最近在线课程使用TensorFlow完成了CNN实现,我不想提及它以避免违反平台规则。我遇到了令人惊讶的结果,我的本地实现与平台服务器上的实现差异很大。
经过进一步调查后,我将问题解决为TensorFlow版本1.3和1.4之间tf.contrib.layers.fully_connected()
行为的变化。
我准备了一小部分源代码来重现这个问题:
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))
当运行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 ]]
当运行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]]
对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.
我想知道参数的默认初始化是否可能发生了某些变化? 无论如何,这就是我现在所处的位置。我可以继续学习这门课程,但是我觉得有点沮丧,我无法在这个问题上得到最后的电话。我想知道这是一个已知行为还是某个地方引入了一个错误。
此外,在完成作业时,最终模型预计在100个时期之后对图像识别任务提供0.78
的测试精度。这正是1.3-所发生的情况,但准确度下降到0.58
1.4+,其他条件相同。
这是一个巨大的差异。我想更长时间的训练可能会消除差异,但仍然不是轻微的,所以值得一提。
任何评论/建议欢迎。
谢谢,
劳伦
答案 0 :(得分:6)
所以这是故障。有些令人惊讶的是,问题是由tf.contrib.layers.flatten()
引起的,因为它在不同版本中以不同方式更改随机种子。有两种方法可以在Tensorflow中对随机数生成器进行播种,或者使用tf.set_random_seed()
为整个图表播种,或者可以在有意义的情况下指定seed
参数。根据{{3}}上的文档,请注意第2点:
依赖随机种子的操作实际上是从两个种子派生出来的:图级和操作级种子。这将设置图级别种子。
它与操作级别种子的交互如下:
- 如果既未设置图表级别也未设置操作种子:此操作使用随机种子。
- 如果设置了图级别种子,但操作种子不是:系统确定性地选择一个操作种子与图级种子一起使用,以便它获得一个唯一的随机序列。
- 如果未设置图级种子,但设置了操作种子:使用默认的图级种子和指定的操作种子来确定随机序列。
- 如果同时设置了图级和操作种子:两个种子一起用于确定随机序列。
醇>
在我们的例子中,种子设置在图形级别,Tensorflow进行一些确定性计算以计算在操作中使用的实际种子。此计算显然还取决于操作次数。
此外,tf.set_random_seed()
的实施在版本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 )
如果您按上述方式运行此代码,则会获得以下打印输出:
0.38538742
两个版本。如果你取消注释Xf线,你得到
0.013653636
和
0.6033112
分别用于版本1.3和1.4。有趣的是,Xf永远不会被执行,只需创建它就足以引起问题。
最后两个注意事项:您使用1.3获得的四个警告与此无关,这些仅是可以优化(加速)某些计算的编译选项。
另一个原因是这不应该影响代码的训练行为,这个问题只会改变随机种子。因此,必须存在一些其他差异,导致您观察到的学习速度变慢。
答案 1 :(得分:0)
我想我和您在上有关CNN的课程。在线python笔记本中的训练和测试准确性分别为94%和78%,而在本地运行时,我的准确性约为50%。
您已经注意到,在更高的python版本中,初始化是不同的。彼得的答案已经很好地描述了,为什么呢。但是,正如评论中所提到的,这不应该是准确性较低的原因。这只是在更高版本的python版本中如何不同地使用随机种子的问题。
我使用一系列不同的学习率来运行代码,实际上我发现了另一个学习率,我得到了84%和77%的训练和测试准确性。 因此,可能必须进行一些更改,例如对AdamOptimizer进行更改,以防止针对较旧的tf版本优化的学习率也无法在较新的版本中达到最佳。