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

LCa*_*sta 6 python tensorflow

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

任何评论/建议欢迎.

谢谢,

洛朗

Pet*_*dan 6

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

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

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

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

在我们的例子中,种子设置在图形级别,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获得的四个警告与此无关,这些仅是可以优化(加速)某些计算的编译选项.

另一件事是这不应该影响代码的训练行为,这个问题只会改变随机种子.因此,必须存在一些其他差异,导致您观察到的学习速度变慢.