在训练神经网络的时候,我们经常会碰到梯度消失和梯度爆炸的问题,而将梯度下降控制在一定范围内有助于解决梯度消失/爆炸问题,本文我们介绍如何手动计算梯度下降方向,并且进行人为控制。
在神经网络模型中通常我们通过下面的代码来进行优化参数,首先定义一个优化器,然后指定最小化的损失,最后在session中进行运行。
optimizer = tf.train.GradientDescentOptimizer(learning_rate = 1.0)
self.train_op = optimizer.minimize(self.cost)
sess.run([train_op], feed_dict={x:data, y:labels})
在这个过程中,调用minimize方法的时候,底层进行的工作包括:
- 计算trainable_variables 集合中所有参数的梯度,这个在Tensorflow学习笔记(2): 变量及共享变量 37中进行了介绍
- 然后将梯度应用到变量上进行梯度下降
- 然后我们在调用sess.run(train_op)的时候,会对variables进行更新
如果我们希望对梯度进行截断,那么就要自己计算出梯度,然后进行clip,最后应用到变量上,代码如下所示,接下来我们一一介绍其中的主要步骤
#return a list of trainable variable in you model
params = tf.trainable_variables()
#create an optimizer
opt = tf.train.GradientDescentOptimizer(self.learning_rate)
#compute gradients for params
gradients = tf.gradients(loss, params)
#process gradients
clipped_gradients, norm = tf.clip_by_global_norm(gradients,max_gradient_norm)
train_op = opt.apply_gradients(zip(clipped_gradients, params)))
1. tf.gradients
用来进行梯度求解,代码如下所示
import tensorflow as tf
w1 = tf.Variable([[1,2]])
w2 = tf.Variable([[3]])
res1 = tf.matmul(w1, [[1],[1]]) + w2
grads = tf.gradients([res1],[w1,w2])
with tf.Session() as sess:
tf.global_variables_initializer().run()
re = sess.run(grads)
print(type(re))
print re
************************************输出**************************************
<type 'list'>
[array([[1, 1]], dtype=int32), array([[1]], dtype=int32)]
tf.gradients(ys, xs),其中ys表示xs里的变量的计算之后的结果,表示计算 [图片上传失败...(image-3523b-1591777862757)]
,结果为list,每个list元素表示每个xs里的x的导数。在上面的例子中,我们查看res1和w1的关系
res1 = 1 * x + 1 * y
因此得到的结果是[array([[1,1]], dtype=int32)
2. tf.clip_by_global_norm
tf.clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None)
其中
- t_list 表示梯度张量
- clip_norm是截取的比率
在应用这个函数之后,t_list[i]的更新公示变为:
global_norm = sqrt(sum(l2norm(t)**2 for t in t_list))
t_list[i] = t_list[i] * clip_norm / max(global_norm, clip_norm)
也就是分为两步:
- 计算所有梯度的平方和global_norm
- 如果梯度平方和 global_norm 超过我们指定的clip_norm,那么就对梯度进行缩放;否则就按照原本的计算结果,这个应该很好理解。
3. gradient clipping实例
在基于循环神经网络的语言模型的介绍与TensorFlow实现(4):TensorFlow实现RNN-based语言模型 16中我们的神经网络语言模型的训练部分代码如下所示:
trainable_variables = tf.trainable_variables() # 获取到模型中所有需要训练的变量
grads, _ = tf.clip_by_global_norm(tf.gradients(self.cost, trainable_variables), MAX_GRAD_NORM) # 求导,并且进行截断
optimizer = tf.train.GradientDescentOptimizer(learning_rate = 1.0)
self.train_op = optimizer.apply_gradients(
zip(grads, trainable_variables)
)
如果我们采用没有加入gradient clipping的方法来替换,如下所示
optimizer = tf.train.GradientDescentOptimizer(learning_rate = 1.0)
self.train_op = optimizer.minimize(self.cost)
那么运行结果如下所示,可以看到由于梯度下降的原因,复杂度已经到达正无穷,大家可以自行验证,完整代码请见TensorFlowExamples/Chapter9/language_model.ipynb 18。
In iteration: 1
After 0 steps, perplexity is 10010.877
/Users/apple/Library/Python/2.7/lib/python/site-packages/ipykernel_launcher.py:30: RuntimeWarning: overflow encountered in exp
After 100 steps, perplexity is inf
After 200 steps, perplexity is inf
After 300 steps, perplexity is inf
After 400 steps, perplexity is inf
网友评论