中间层使 tensorflow 优化器停止工作

Posted

技术标签:

【中文标题】中间层使 tensorflow 优化器停止工作【英文标题】:Intermediate layer makes tensorflow optimizer to stop working 【发布时间】:2018-07-26 18:41:00 【问题描述】:

该图训练了一个简单的信号标识编码器,实际上表明优化器正在进化权重:

import tensorflow as tf
import numpy as np
initia = tf.random_normal_initializer(0, 1e-3)

DEPTH_1 = 16
OUT_DEPTH = 1
I = tf.placeholder(tf.float32, shape=[None,1], name='I') # input
W = tf.get_variable('W', shape=[1,DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # weights
b = tf.get_variable('b', shape=[DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # biases
O = tf.nn.relu(tf.matmul(I, W) + b, name='O') # activation / output

#W1 = tf.get_variable('W1', shape=[DEPTH_1,DEPTH_1], initializer=initia, dtype=tf.float32) # weights
#b1 = tf.get_variable('b1', shape=[DEPTH_1], initializer=initia, dtype=tf.float32) # biases
#O1 = tf.nn.relu(tf.matmul(O, W1) + b1, name='O1')

W2 = tf.get_variable('W2', shape=[DEPTH_1,OUT_DEPTH], initializer=initia, dtype=tf.float32) # weights
b2 = tf.get_variable('b2', shape=[OUT_DEPTH], initializer=initia, dtype=tf.float32) # biases
O2 = tf.matmul(O, W2) + b2

O2_0 = tf.gather_nd(O2, [[0,0]])

estimate0 = 2.0*O2_0

eval_inp = tf.gather_nd(I,[[0,0]])
k = 1e-5
L = 5.0
distance = tf.reduce_sum( tf.square( eval_inp - estimate0 ) )

opt = tf.train.GradientDescentOptimizer(1e-3)
grads_and_vars = opt.compute_gradients(distance, [W, b, #W1, b1,
  W2, b2])
clipped_grads_and_vars = [(tf.clip_by_value(g, -4.5, 4.5), v) for g, v in grads_and_vars]

train_op = opt.apply_gradients(clipped_grads_and_vars)

saver = tf.train.Saver()
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
  sess.run(init_op)
  for i in range(10000):
    print sess.run([train_op, I, W, distance], feed_dict= I: 2.0*np.random.rand(1,1) - 1.0)
  for i in range(10):
    print sess.run([eval_inp, W, estimate0], feed_dict= I: 2.0*np.random.rand(1,1) - 1.0)

但是,当我取消对中间隐藏层的注释并训练生成的网络时,我发现权重不再变化:

import tensorflow as tf
import numpy as np
initia = tf.random_normal_initializer(0, 1e-3)

DEPTH_1 = 16
OUT_DEPTH = 1
I = tf.placeholder(tf.float32, shape=[None,1], name='I') # input
W = tf.get_variable('W', shape=[1,DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # weights
b = tf.get_variable('b', shape=[DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # biases
O = tf.nn.relu(tf.matmul(I, W) + b, name='O') # activation / output

W1 = tf.get_variable('W1', shape=[DEPTH_1,DEPTH_1], initializer=initia, dtype=tf.float32) # weights
b1 = tf.get_variable('b1', shape=[DEPTH_1], initializer=initia, dtype=tf.float32) # biases
O1 = tf.nn.relu(tf.matmul(O, W1) + b1, name='O1')

W2 = tf.get_variable('W2', shape=[DEPTH_1,OUT_DEPTH], initializer=initia, dtype=tf.float32) # weights
b2 = tf.get_variable('b2', shape=[OUT_DEPTH], initializer=initia, dtype=tf.float32) # biases
O2 = tf.matmul(O1, W2) + b2

O2_0 = tf.gather_nd(O2, [[0,0]])

estimate0 = 2.0*O2_0

eval_inp = tf.gather_nd(I,[[0,0]])

distance = tf.reduce_sum( tf.square( eval_inp - estimate0 ) )

opt = tf.train.GradientDescentOptimizer(1e-3)
grads_and_vars = opt.compute_gradients(distance, [W, b, W1, b1,
  W2, b2])
clipped_grads_and_vars = [(tf.clip_by_value(g, -4.5, 4.5), v) for g, v in grads_and_vars]

train_op = opt.apply_gradients(clipped_grads_and_vars)

saver = tf.train.Saver()
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
  sess.run(init_op)
  for i in range(10000):
    print sess.run([train_op, I, W, distance], feed_dict= I: 2.0*np.random.rand(1,1) - 1.0)
  for i in range(10):
    print sess.run([eval_inp, W, estimate0], feed_dict= I: 2.0*np.random.rand(1,1) - 1.0)

estimate0 的评估迅速收敛到某个固定值,该值变得独立于输入信号。我不知道为什么会这样

问题:

知道第二个例子有什么问题吗?

【问题讨论】:

您如何验证权重是否“不断变化”? @EvanWeissburg 在第二个示例中 W 的值几乎没有变化,distance 不会变小,并且在推理循环中 estimate0 几乎不会随着不同的输入而改变值。在第一个示例中,W 变化,distance 在一百步内变为 1e-5 的数量级,estimate0 密切跟踪输入值 下面的答案很好。另一个提示:尝试使用其他优化器,例如 Adam,而不是普通的 Gradient Descent。你甚至可以尝试其他激活函数,例如leaky relu。 【参考方案1】:

TL;DR:神经网络越深,你越应该关注梯度流(参见“梯度消失”的this discussion)。一种特殊情况是变量初始化


问题分析

我已将变量和渐变的 tensorboard 摘要添加到您的两个脚本中,并得到以下结果:

2层网络

三层网络

图表显示了W:0 变量(第一层)的分布以及它们如何从 0 epoch 更改为 1000(可点击)。事实上,我们可以看到,2 层网络的变化率要高得多。但我想注意梯度分布,它在 3 层网络中更接近于 0(第一个方差约为 0.005,第二个方差约为 0.000002,即小 1000 倍)。这就是梯度消失问题

如果您有兴趣,这里是帮助代码:

for g, v in grads_and_vars:
  tf.summary.histogram(v.name, v)
  tf.summary.histogram(v.name + '_grad', g)

merged = tf.summary.merge_all()
writer = tf.summary.FileWriter('train_log_layer2', tf.get_default_graph())

...

_, summary = sess.run([train_op, merged], feed_dict=I: 2*np.random.rand(1, 1)-1)
if i % 10 == 0:
  writer.add_summary(summary, global_step=i)

解决方案

所有深度网络都在一定程度上受此影响,并且 没有通用的解决方案可以自动修复任何网络。但是有一些技术可以将其推向正确的方向。初始化就是其中之一。

我将您的正常初始化替换为:

W_init = tf.contrib.layers.xavier_initializer()
b_init = tf.constant_initializer(0.1)

Xavier init 有很多教程,你可以看看this one,例如。 请注意,我将偏差 init 设置为略微正,以确保 ReLu 输出对于大多数神经元都是正的,至少在开始时是这样。

这立即改变了画面:

权重仍然没有像以前那样快速移动,但它们正在移动(注意W:0 值的比例),梯度分布在 0 处的峰值变得更少,因此更好。

当然,这还没有结束。为了进一步改进它,您应该实现完整的自动编码器,因为目前损失受[0,0] 元素重建的影响,所以大多数输出​​没有用于优化。您还可以使用不同的优化器(我会选择 Adam)和学习率。

【讨论】:

这就是为什么我直接使用 keras 而不是 tensorflow - 明智的默认设置 感谢您的回复,它让我走上了正轨 @denfromufa 是什么意思。张量流中的合理默认值是什么?你总是必须自己设置初始化器和类似的东西,然后选择正确的优化器。 @Maxim 我无法真正看到 xavier 初始化之后和之前的结果之间的区别。权重似乎相同,而梯度变化很小。但最大的区别在哪里? @thigi 注意 grad 分布的方差。它从~0.000002 跳到~0.1。这足以让 NN 学习【参考方案2】:

这看起来很令人兴奋。这段代码到底属于哪里?我最近才发现 TensorBoard

这是在回调中以某种方式:

  for g, v in grads_and_vars:
  tf.summary.histogram(v.name, v)
  tf.summary.histogram(v.name + '_grad', g)

merged = tf.summary.merge_all()
writer = tf.summary.FileWriter('train_log_layer2', tf.get_default_graph())

拟合后是这样的吗:

_, summary = sess.run([train_op, merged], feed_dict=I: 2*np.random.rand(1, 1)-1)
if i % 10 == 0:
  writer.add_summary(summary, global_step=i)

【讨论】:

以上是关于中间层使 tensorflow 优化器停止工作的主要内容,如果未能解决你的问题,请参考以下文章

SQL UPDATE, WHERE 条件限制(索引停止工作)

OpenCv-C++ - 在视频中间停止工作

基于 AUC 的提前停止

电脑总是弹出WINDOWS资源管理器已停止工作怎么办?

我的WINDOWS7出现资源管理器停止工作 代码是BEX 求大神

拟合模型时,内核在一段时间后停止工作