tf.contrib.layers.fully_connected()行为是否会在tensorflow 1.3和1.4之间发生变化?

时间:2018-04-09 21:36:59

标签: python tensorflow

我最近在线课程使用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+,其他条件相同。 这是一个巨大的差异。我想更长时间的训练可能会消除差异,但仍然不是轻微的,所以值得一提。

任何评论/建议欢迎。

谢谢,

劳伦

2 个答案:

答案 0 :(得分:6)

所以这是故障。有些令人惊讶的是,问题是由tf.contrib.layers.flatten()引起的,因为它在不同版本中以不同方式更改随机种子。有两种方法可以在Tensorflow中对随机数生成器进行播种,或者使用tf.set_random_seed()为整个图表播种,或者可以在有意义的情况下指定seed参数。根据{{​​3}}上的文档,请注意第2点:

  

依赖随机种子的操作实际上是从两个种子派生出来的:图级和操作级种子。这将设置图级别种子。

     

它与操作级别种子的交互如下:

     
      
  1. 如果既未设置图表级别也未设置操作种子:此操作使用随机种子。
  2.   
  3. 如果设置了图级别种子,但操作种子不是:系统确定性地选择一个操作种子与图级种子一起使用,以便它获得一个唯一的随机序列。
  4.   
  5. 如果未设置图级种子,但设置了操作种子:使用默认的图级种子和指定的操作种子来确定随机序列。
  6.   
  7. 如果同时设置了图级和操作种子:两个种子一起用于确定随机序列。
  8.   

在我们的例子中,种子设置在图形级别,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版本优化的学习率也无法在较新的版本中达到最佳。