4 梯度、反向传播与优化算法
4.1 简介
求导是几乎所有深度学习优化算法的关键步骤。
虽然求导的计算很简单,只需要一些基本的微积分。但对于复杂的模型,手工进行更新是一件很痛苦的事情(而且经常容易出错)。 深度学习框架通过自动计算导数,即自动微分(automatic differentiation)来加快求导。
实际情况下,根据设计好的模型,系统会构建一个计算图(computational graph),来跟踪计算是哪些数据通过哪些操作组合起来产生输出。自动微分使系统能够随后反向传播梯度。这里,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数。
4.2 梯度下降与反向传播
4.2.1 梯度
什么是梯度:
- 向量
- 导数+变化最快的方向(参数更新的方向)
模型评估:
- 收集数据
,构建机器学习模型 ,得到 - 回归任务:均方误差(MSE)
- 分类任务:交叉熵
4.2.2 梯度下降
- 计算梯度
- 更新参数
提示
:学习率,控制参数更新的步长 < 0,w将增大 > 0,w将减小
4.2.3 反向传播
反向传播从后往前,计算每一层的梯度。即跟踪整个计算图,填充关于每个参数的偏导数。
- 示例
在计算 y 关于 x 的梯度之前,需要一个地方来存储梯度。重要的是,我们不会在每次对一个参数求导时都分配新的内存。因为我们经常会成千上万次地更新相同的参数,每次都分配新的内存可能很快就会将内存耗尽。
相关信息
一个标量函数关于向量x的梯度是向量,并且与x具有相同的形状。
import torch
# 初始化
x = torch.arange(4)
# 存储梯度
x.requires_grad_(True)
# 等价于
x = torch.arange(4, requires_grad=True)
x.grad # 默认值是None
# 计算
y = 2 * torch.dot(x, x)
# 调用反向传播函数来自动计算y关于x每个分量的梯度
y.backward()
x.grad
x.grad == 4 * x提示
当设置 requires_grad=True 后,之后的每次计算都会修改其 grad_fn 属性,用来记录历史操作。
现在,计算x的另一个函数:
# 默认情况下,pytorch会累积梯度,因此需要清除之前的梯度
x.grad.zero_()
y = x.sum()
y.backward()
x.grad提示
调用 backward 函数后,会计算 y 关于 x 的梯度,并将结果存储在 x.grad 中。
虽然这些更奇特的对象确实出现在高级机器学习中(包括深度学习中),但当调用向量的反向计算时, 我们通常会试图计算一批训练样本中每个组成部分的损失函数的导数。这里,我们的目的不是计算微分矩阵, 而是单独计算批量中每个样本的偏导数之和。
# 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。
# 本例只想求偏导数的和,所以传递一个1的梯度是合适的
x.grad.zero_()
y = x * x
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
x.grad4.3 梯度下降及其优化算法
4.3.1 梯度下降
挑选初始值:
重复迭代参数:
沿梯度方向将增加损失函数
学习率
:步长的超参数,太小收敛慢,太大易抖动
4.3.2 小批量随机梯度下降
在整个数据集上算梯度开销大
随机采样b个样本来近似损失:
- 批量大小
:另一重要超参数,太小不适合并行,太大开销大
重要
- 梯度下降通过不断沿着反梯度方向更新参数
- 小批量随机梯度下降是深度学习默认的求解算法
- 两个重要的超参数:批量大小和学习率
4.3.3 梯度消失与梯度爆炸
- 梯度消失
在深层神经网络中,由于每个层的输出都是上一层输出的非线性函数,所以如果每个层的输出都在0到1之间,那么无论神经网络有多少层,输出的梯度都将非常小。当神经网络输出初始权重过小或使用过饱和神经元(sigmoid在0和1处的导数接近0,无法更新参数)时,梯度在神经网络反向传播时呈指数缩小,产生消失现象。
- 梯度爆炸
在深层神经网络中,由于每个层的输出都是上一层输出的非线性函数,所以如果每个层的输出都在一个较大的范围内,那么无论神经网络有多少层,输出的梯度都将非常大。当神经网络输出初始权重过大时,梯度在神经网络反向传播时呈指数放大,产生爆炸现象。
- 场景及其原因
梯度消失与梯度爆炸其实是一种,以下情况梯度消失和梯度爆炸经常出现:
在深层神经网络中
采用了不合适的损失函数,比如 sigmoid。梯度爆炸一般出现在深层网络和权值初始化值太大的情况下
对激活函数进行求导,如果此部分大于 1,那么层数增多的时候,最终的求出的梯度更新将以指数形式增加,即发生梯度爆炸,如果此部分小于1,那么随着层数增多,求出的梯度更新信息将会以指数形式衰减,即发生了梯度消失.
- 解决方法
替换激活函数:
sigmoid->LeakyReLU,tanh->ReLU,可以缓解梯度消失改进梯度优化算法:使用
Adam等算法使用
batch.normalization使用残差结构
4.3.4 优化算法
梯度下降法(batch gradient descent, BGD):全局模式。
随机梯度下降法(stochastic gradient descent, SGD):随机从样本抽出一个子样本进行梯度更新。
小批量梯度下降法(mini-batch gradient descent, MBGD):找一批次数据计算梯度,使用均值更新参数。
动量法(Momentum):MBGD需要一个合适的学习率,太小则网络收敛太慢,太大则容易跳过最优点。动量法基于梯度的移动指数加权平均,对网络参数进行平滑处理,让梯度摆动幅度变小。
- AdaGrad:将每一个参数的每一次迭代的梯度取平方累加后开方,用全局学习率除以它,作为新的学习率,从而到达自适应学习率的效果。
- RMSProp:对参数梯度使用平方加权平均,进一步加快收敛。对梯度平滑处理。
- Adam (Adaptive Moment Estimation):将 Momentum 和 RMSProp 结合。自适应学习率,梯度摆幅小。
- 初始化梯度的累积量和平方累积量
- 第
t轮训练,计算参数更新
- 更新参数
注
SGD的api为torch.optim.SGD()Adam的api为torch.optim.Adam()