中间层导致TensorFlow优化器停止工作

这个图表训练了一个简单的信号身份编码器,实际上显示了优化器正在演化权重:

import tensorflow as tfimport numpy as npinitia = tf.random_normal_initializer(0, 1e-3)DEPTH_1 = 16OUT_DEPTH = 1I = tf.placeholder(tf.float32, shape=[None,1], name='I') # inputW = tf.get_variable('W', shape=[1,DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # weightsb = tf.get_variable('b', shape=[DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # biasesO = 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) # weightsb2 = tf.get_variable('b2', shape=[OUT_DEPTH], initializer=initia, dtype=tf.float32) # biasesO2 = tf.matmul(O, W2) + b2O2_0 = tf.gather_nd(O2, [[0,0]])estimate0 = 2.0*O2_0eval_inp = tf.gather_nd(I,[[0,0]])k = 1e-5L = 5.0distance = 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 tfimport numpy as npinitia = tf.random_normal_initializer(0, 1e-3)DEPTH_1 = 16OUT_DEPTH = 1I = tf.placeholder(tf.float32, shape=[None,1], name='I') # inputW = tf.get_variable('W', shape=[1,DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # weightsb = tf.get_variable('b', shape=[DEPTH_1], initializer=initia, dtype=tf.float32, trainable=True) # biasesO = tf.nn.relu(tf.matmul(I, W) + b, name='O') # activation / outputW1 = tf.get_variable('W1', shape=[DEPTH_1,DEPTH_1], initializer=initia, dtype=tf.float32) # weightsb1 = tf.get_variable('b1', shape=[DEPTH_1], initializer=initia, dtype=tf.float32) # biasesO1 = 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) # weightsb2 = tf.get_variable('b2', shape=[OUT_DEPTH], initializer=initia, dtype=tf.float32) # biasesO2 = tf.matmul(O1, W2) + b2O2_0 = tf.gather_nd(O2, [[0,0]])estimate0 = 2.0*O2_0eval_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的评估迅速收敛到某个与输入信号无关的固定值。我不知道为什么会发生这种情况

问题:

对第二个例子可能有什么问题有任何想法吗?


回答:

TL;DR: 神经网络越深,你就越应该关注梯度流(参见关于“梯度消失”的讨论)。一个特别的情况是变量初始化


问题分析

我在你的两个脚本中添加了变量和梯度的TensorBoard摘要,得到了以下结果:

2层网络

2-layer

3层网络

3-layer network

图表显示了W:0变量(第一层)的分布,以及它们从0个epoch到1000个epoch的变化情况(可点击)。确实,我们可以看到,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初始化的教程有很多,你可以看看这个。请注意,我将偏置初始化设置为稍微正值,以确保ReLu输出的神经元在开始时至少大部分是正值。

这立即改变了图景:

3-layer-improved

权重仍然没有像以前那样快速移动,但它们确实是在移动(注意W:0值的规模),并且梯度分布不再那么集中在0点,因此有了很大的改善。

当然,这还不是结束。为了进一步改进,你应该实现完整的自编码器,因为目前损失仅受[0,0]元素重建的影响,因此大多数输出在优化中未被使用。你还可以尝试不同的优化器(我会选择Adam)和学习率。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注