本文讨论了经典梯度下降法之外的常用优化器,它们都是基于梯度下降法进行了改进的方法,它们往往会比经典梯度下降法取得更好的优化速度和精度。掌握这些优化器的用法,并取得初步实践经验是提高深度学习应用能力的重要内容。读者在学习了基本知识后,要求AI大模型来辅助设置参数,提高效率。本文最后还简要说明了梯度消散和梯度爆炸问题。
本专栏之四讨论了梯度下降法,它是优化机器学习模型参数的基本方法。以它为基础,人们又发展出了许多改进方法,它们有不同的特点和适用场景。了解并实践这些内容,有助于选择合适的优化器及其参数以加快优化速度和精度。本文数学公式较多,读者也可以先跳过理论推导,通过示例掌握应用方法。
以梯度下降法为基础的改进方法,主要是从增加动量和调整步长两方面着手。
1.动量优化算法
在经典力学中,动量(Momentum)表示为物体的质量和速度的乘积,体现为物体运动的惯性。在梯度下降法(见本专栏之四)中,如果使梯度下降的过程具有一定的“动量”,保持原方向运动的一定的 “惯性”,则有可能在下降的过程中“冲过”小的“洼地”,避免陷入极小值点,如图11-1所示。其中,在第3个点处,其梯度负方向为蓝色虚线实箭头所示,而在动量的影响下,仍然保持向左的惯性,从而“冲出”了局部极小点。
图11-1 加入动量的梯度下降过程示意
加入动量优化,梯度下降法还可以克服前进路线振荡的问题,从而加快收敛速度。
梯度下降的迭代关系式(本专栏之四中的式4-1)为:
xi+1=xi+α⋅(−df(x)dx)x=xi=xi−α⋅df(x)dx∣x=xi x_{i+1} = x_i + \alpha \cdot \left( -\frac{df(x)}{dx} \right)_{x=x_i} = x_i - \alpha \cdot \frac{df(x)}{dx} \bigg|_{x=x_i}xi+1=xi+α⋅(−dxdf(x))x=xi=xi−α⋅dxdf(x)x=xi
对照上式,加入动量的梯度下降法迭代关系式为:
θi+1=βθi−α⋅df(x)dx∣x=xixi+1=xi+θi+1(式11-1) \theta_{i+1} = \beta \theta_i - \alpha \cdot \left. \dfrac{df(x)}{dx} \right|_{x=x_i} \\[10pt] x_{i+1} = x_i + \theta_{i+1} \tag{式11-1}θi+1=βθi−α⋅dxdf(x)x=xixi+1=xi+θi+1(式11-1)
可见,加入动量之后的前进量θi+1\theta_{i+1}θi+1是由上一步的前进量θi\theta_iθi和新梯度值df(x)dx∣x=xi\frac{df(x)}{dx}\big|_{x=x_i}dxdf(x)x=xi的加权和,其中β\betaβ决定了保留上一步前进量的大小,称为动量系数。初始θ0=0\theta_0 = 0θ0=0。
加入动量的梯度下降的迭代关系式还有一种改进方法,称为 NAG(Nesterov accelerated gradient):
θi+1=βθi−α⋅(df(x)dx)x=xi+βθixi+1=xi+θi+1(式11-2) \theta_{i+1} = \beta\theta_i - \alpha \cdot \left( \frac{df(x)}{dx} \right)_{x=x_i+\beta\theta_i}\\[10pt] x_{i+1} = x_i + \theta_{i+1}\tag{式11-2}θi+1=βθi−α⋅(dxdf(x))x=xi+βθixi+1=xi+θi+1(式11-2)
该方法计算梯度的点发生了变化,即在xi+βθix_i + \beta\theta_ixi+βθi处计算梯度,而不是原xix_ixi点处。它可以理解为先按“惯性”前进一小步βθi\beta\theta_iβθi,再计算梯度。这种方法在每一步都往前多走了一小步,有时可以加快收敛速度。
在 PyTorch 中,动量优化和 NAG 方法主要通过设置torch.optim.SGD的momentum(动量系数)和nesterov两个参数的来实现。
代码11-1.1示例了它们的用法。
代码11-1.1 动量优化算法应用示例
### 1.导入和设置环境importtorchimporttorch.nnasnnimporttorch.optimasoptimfromtorch.utils.dataimportDataLoader,TensorDatasetimportdatetimefromtorchvisionimportdatasets,transforms# 设置随机种子torch.manual_seed(0)### 2.训练样本和验证样本数据预处理# 数据预处理方式transform=transforms.Compose([transforms.ToTensor(),# 转换为 torch.Tensor])# 加载MNIST数据集train_dataset=datasets.MNIST('./data',train=True,download=True,transform=transform)val_dataset=datasets.MNIST('./data',train=False,transform=transform)# 样本拉平、归一化后X_train=train_dataset.data.float().view(-1,784)/255.0y_train=train_dataset.targets X_val=val_dataset.data.float().view(-1,784)/255.0y_val=val_dataset.targets# 转换为独热编码y_train=torch.nn.functional.one_hot(y_train,num_classes=10).float()y_val=torch.nn.functional.one_hot(y_val,num_classes=10).float()# 创建数据加载器batch_size=200train_loader=DataLoader(TensorDataset(X_train,y_train),batch_size=batch_size,shuffle=True)val_loader=DataLoader(TensorDataset(X_val,y_val),batch_size=batch_size)### 3.定义神经网络模型# relu-relu-softmaxclassMNISTModel(nn.Module):def__init__(self):super(MNISTModel,self).__init__()self.fc1=nn.Linear(784,784)self.fc2=nn.Linear(784,784)self.fc3=nn.Linear(784,10)self.relu=nn.ReLU()self.softmax=nn.Softmax()defforward(self,x):x=self.relu(self.fc1(x))x=self.relu(self.fc2(x))x=self.softmax(self.fc3(x))returnx### 4.采用不同的优化器进行对比试验deftrain_process():# 训练模型,开始计时start_time=datetime.datetime.now()epochs=10forepochinrange(epochs):# 每轮中的训练model.train()train_loss=0.0forbatch_X,batch_yintrain_loader:optimizer.zero_grad()outputs=model(batch_X)loss=criterion(outputs,batch_y)loss.backward()optimizer.step()train_loss+=loss.item()# 看一下该轮训练后的效果model.eval()correct=0total=0withtorch.no_grad():forbatch_X,batch_yintrain_loader:outputs=model(batch_X)_,predicted=torch.max(outputs.data,1)# 模型预测值的独热编码_,labels=torch.max(batch_y.data,1)# 真实标签值的独热编码total+=labels.size(0)correct+=(predicted==labels).sum().item()# 准确率print(f'Epoch{epoch+1}/{epochs}, 对训练样本进行预测的准确率(Train Acc):{100*correct/total:.2f}%')# 训练结束,终止计时end_time=datetime.datetime.now()print(f"训练用时:{end_time-start_time}")criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.SGD(model.parameters(),lr=0.15)# 基本梯度下降法优化器train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 46.40%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 42.39%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 51.85%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 58.24%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 74.46%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 82.62%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 85.90%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 87.47%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 88.53%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 89.14%
训练用时: 0:01:19.254175criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.SGD(model.parameters(),lr=0.15,momentum=0.9)# 启用动量优化的梯度下降法优化器train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 88.11%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 91.55%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 92.71%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 93.86%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 94.56%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 95.15%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 95.60%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 95.87%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 96.29%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 96.86%
训练用时: 0:01:25.797210criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.SGD(model.parameters(),lr=0.15,momentum=0.9,nesterov=True)# 启用NAG的梯度下降法优化器train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 87.90%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 91.56%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 92.46%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 93.72%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 94.41%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 95.05%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 95.57%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 96.07%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 96.58%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 96.87%
训练用时: 0:01:24.306429
2.步长优化算法
在讨论梯度下降法时,简要说明了步长对梯度下降的影响。针对步长,人们研究了不少的优化算法。
2.1 Adagrad算法
Adagrad(Adaptive Gradient)算法的梯度迭代关系式为:
ri=ri−1+(df(x)dx∣x=xi)2xi=xi−1−lrri+ϵ⋅df(x)dx∣x=xi(式11-3) r_i = r_{i-1} + \left(\frac{df(\boldsymbol{x})}{d\boldsymbol{x}}\bigg|_{\boldsymbol{x}=\boldsymbol{x}_i}\right)^2 \\ x_i = x_{i-1} - \frac{lr}{\sqrt{r_i + \epsilon}} \cdot \frac{df(x)}{dx}\bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \tag{式11-3}ri=ri−1+(dxdf(x)x=xi)2xi=xi−1−ri+ϵlr⋅dxdf(x)x=xi(式11-3)
其中,rir_iri称为累积平方梯度,它是到当前为止所有梯度的平方和,初值为000。这里的(df(x)dx∣x=xi)x=xi2\left( \frac{df(x)}{dx}\bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)_{x=x_i}^2(dxdf(x)x=xi)x=xi2表示向量元素的平方向量:df(x)dx∣x=xi⨀df(x)dx∣x=xi\frac{df(x)}{dx} \bigg|_{x=x_i} \bigodot \frac{df(x)}{dx} \bigg|_{x=x_i}dxdf(x)x=xi⨀dxdf(x)x=xi,下同。超参数lrlrlr为事先设置的步长,ϵ\epsilonϵ为很小的常数。初始r0=0r_0 = 0r0=0。
可见,随着迭代次数的增加,rir_iri越来越大,实际步长lrri+1+ϵ\frac{lr}{\sqrt{r_{i+1}}+\epsilon}ri+1+ϵlr越来越小,可以防止在极小值附近来回振荡。
PyTorch中实现该算法的是torch.optim.Adagrad(),它的lr、eps和initial_accumulator_value三个参数分别设置lrlrlr、ϵ\epsilonϵ和r0r_0r0,另外还设置了步长衰减参数lr_decay和L2正则化参数weight_decay。
该算法的应用示例如代码11-1.2所示。
代码11-1.2 Adagrad优化器应用示例
criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.Adagrad(model.parameters(),lr=0.01)# Adagrad优化器train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 96.76%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 98.04%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 98.64%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 98.97%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 99.20%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 99.36%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 99.51%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 99.58%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 99.64%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 99.70%
训练用时: 0:01:19.308178
2.2 RMSProp算法
RMSProp(Root Mean Square Prop)算法的原始形式对Adagrad算法进行了简单改进,增加了一个系数rhorhorho来控制历史信息与当前梯度的比例:
ri=rho⋅ri−1+(1−rho)(df(x)dx∣x=xi)2xi=xi−1−lrri+ϵ⋅df(x)dx∣x=xi(式11-4) r_i = rho \cdot r_{i-1} + (1 - rho) \left( \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)^2 \\ \boldsymbol{x}_i = \boldsymbol{x}_{i-1} - \frac{lr}{\sqrt{r_i + \epsilon}} \cdot \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \tag{式11-4}ri=rho⋅ri−1+(1−rho)(dxdf(x)x=xi)2xi=xi−1−ri+ϵlr⋅dxdf(x)x=xi(式11-4)
对RMSProp的原始形式增加动量因子如下:
ri=rho⋅ri−1+(1−rho)(df(x)dx∣x=xi)2θi=βθi−1+lrri+ϵ⋅df(x)dx∣x=xixi=xi−1−θi(式11-5) r_i = rho \cdot r_{i-1} + (1 - rho) \left( \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)^2 \\ \boldsymbol{\theta}_i = \beta \boldsymbol{\theta}_{i-1} + \frac{lr}{\sqrt{r_i + \epsilon}} \cdot \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \\ \boldsymbol{x}_i = \boldsymbol{x}_{i-1} - \boldsymbol{\theta}_i \tag{式11-5}ri=rho⋅ri−1+(1−rho)(dxdf(x)x=xi)2θi=βθi−1+ri+ϵlr⋅dxdf(x)x=xixi=xi−1−θi(式11-5)
其中,β\betaβ为动量系数。
下式为 RMSProp 的中心化版本:
si=rho⋅si−1+(1−rho)df(x)dx∣x=xiri=rho⋅ri−1+(1−rho)(df(x)dx∣x=xi)2θi=βθi−1+lrri−si2+ϵ⋅df(x)dx∣x=xixi=xi−1−θi(式11-6) \boldsymbol{s}_i = rho \cdot \boldsymbol{s}_{i-1} + (1 - rho) \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \\ r_i = rho \cdot r_{i-1} + (1 - rho) \left( \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)^2\\ \boldsymbol{\theta}_i = \beta \boldsymbol{\theta}_{i-1} + \frac{lr}{\sqrt{r_i - \boldsymbol{s}_i^2 + \epsilon}} \cdot \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i}\\ \boldsymbol{x}_i = \boldsymbol{x}_{i-1} - \boldsymbol{\theta}_i\tag{式11-6}si=rho⋅si−1+(1−rho)dxdf(x)x=xiri=rho⋅ri−1+(1−rho)(dxdf(x)x=xi)2θi=βθi−1+ri−si2+ϵlr⋅dxdf(x)x=xixi=xi−1−θi(式11-6)
它增加了一个累积梯度si\boldsymbol{s}_isi,在求动量因子θi\boldsymbol{\theta}_iθi时,通过si\boldsymbol{s}_isi对rir_iri进行了一个中心化过程:ri−si2初始s0=0,r0=0r_i - \boldsymbol{s}_i^2 \quad 初始 \boldsymbol{s}_0 = \boldsymbol{0}, r_0 = 0ri−si2初始s0=0,r0=0。
RMSProp 在实践中效果较好,得到了较多的应用,在 PyTorch中也提供了实现类,可以通过设置相关参数来实现以上三个版本的 RMSProp 算法。
该算法的应用示例如代码11-1.3所示。
代码11-1.3 RMSProp 优化器应用示例
criterion=nn.MSELoss()model=MNISTModel()optimizer=torch.optim.RMSprop(model.parameters(),lr=0.001,momentum=0,centered=False)# RMSprop优化器原始版本train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 95.33%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 98.02%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 98.21%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 98.82%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 98.91%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 99.33%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 99.35%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 99.36%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 99.36%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 99.54%
训练用时: 0:02:55.587366criterion=nn.MSELoss()model=MNISTModel()optimizer=torch.optim.RMSprop(model.parameters(),lr=0.001,alpha=0.9,# 梯度平滑系数momentum=0.8,# 添加动量加速收敛weight_decay=1e-5,# L2正则化centered=False)train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 93.75%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 96.19%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 95.52%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 97.39%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 97.03%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 97.13%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 97.80%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 97.58%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 97.05%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 97.30%
训练用时: 0:07:34.488462criterion=nn.MSELoss()model=MNISTModel()optimizer=torch.optim.RMSprop(model.parameters(),lr=0.001,alpha=0.9,# 梯度平滑系数momentum=0.8,# 添加动量加速收敛weight_decay=1e-5,# L2正则化centered=True# 中心化)train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 91.83%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 95.06%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 96.34%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 95.43%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 96.05%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 97.22%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 97.39%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 97.39%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 97.46%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 96.95%
训练用时: 0:06:58.417171
3.结合动量和步长优化的算法
Adam(Adaptive moment estimation)算法结合了AdaGrad算法和RMSProp算法的优势,它的迭代关系式为:
si=β1⋅si−1+(1−β1)df(x)dx∣x=xiri=β2⋅ri−1+(1−β2)(df(x)dx∣x=xi)2s^i=si1−β1ir^i=ri1−β2ixi=xi−1−lr⋅s^ir^i+ϵ(式11-7) \boldsymbol{s}_i = \beta_1 \cdot \boldsymbol{s}_{i-1} + (1 - \beta_1) \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i}\\ r_i = \beta_2 \cdot r_{i-1} + (1 - \beta_2) \left( \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)^2\\ \hat{\boldsymbol{s}}_i = \frac{\boldsymbol{s}_i}{1 - \beta_1^i}\\ \hat{r}_i = \frac{r_i}{1 - \beta_2^i}\\ \boldsymbol{x}_i = \boldsymbol{x}_{i-1} - \frac{lr \cdot \hat{\boldsymbol{s}}_i}{\sqrt{\hat{r}_i} + \epsilon}\tag{式11-7}si=β1⋅si−1+(1−β1)dxdf(x)x=xiri=β2⋅ri−1+(1−β2)(dxdf(x)x=xi)2s^i=1−β1isir^i=1−β2irixi=xi−1−r^i+ϵlr⋅s^i(式11-7)
式中,β1,β2∈[0,1]\beta_1, \beta_2 \in [0, 1]β1,β2∈[0,1]分别为累积梯度的动量系数和累积平方梯度的动量系数。初始s0=0,r0=0\boldsymbol{s}_0 = \boldsymbol{0}, r_0 = 0s0=0,r0=0。
对比式11-7和式11-6,可知Adam算法是RMSProp中心化版本的进一步改进。
对累积平方梯度rir_iri可以取历史最大值用来更新,称为 AMSGrad,此时 Adam 算法为:
si=β1⋅si−1+(1−β1)df(x)dx∣x=xiri=β2⋅ri−1+(1−β2)(df(x)dx∣x=xi)2ri′=max(ri−1′,ri)s^i=si1−β1ir^i=ri′1−β2ixi=xi−1−lr⋅s^ir^i+ϵ(式11-8) \boldsymbol{s}_i = \beta_1 \cdot \boldsymbol{s}_{i-1} + (1 - \beta_1) \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i}\\ r_i = \beta_2 \cdot r_{i-1} + (1 - \beta_2) \left( \frac{df(\boldsymbol{x})}{d\boldsymbol{x}} \bigg|_{\boldsymbol{x}=\boldsymbol{x}_i} \right)^2\\ r_i' = \max(r_{i-1}', r_i)\\ \hat{\boldsymbol{s}}_i = \frac{\boldsymbol{s}_i}{1 - \beta_1^i}\\ \hat{r}_i = \frac{r_i'}{1 - \beta_2^i}\\ \boldsymbol{x}_i = \boldsymbol{x}_{i-1} - \frac{lr \cdot \hat{\boldsymbol{s}}_i}{\sqrt{\hat{r}_i} + \epsilon}\tag{式11-8}si=β1⋅si−1+(1−β1)dxdf(x)x=xiri=β2⋅ri−1+(1−β2)(dxdf(x)x=xi)2ri′=max(ri−1′,ri)s^i=1−β1isir^i=1−β2iri′xi=xi−1−r^i+ϵlr⋅s^i(式11-8)
初始r0′=0r_0' = 0r0′=0。
Adam 算法综合效果较好,在PyTorch 中有相应的实现类,通过设置参数可以实现上述两个算法。
该算法的应用示例如代码11-1.4所示。
代码11-1.4 Adam 优化器应用示例
criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.Adam(model.parameters(),lr=0.001)# Adam优化器train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 95.18%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 97.85%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 98.42%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 98.30%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 99.01%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 99.27%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 99.30%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 98.91%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 99.43%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 99.30%
训练用时: 0:01:35.730784criterion=nn.MSELoss()model=MNISTModel()optimizer=optim.Adam(model.parameters(),lr=0.001,amsgrad=True)# Adam优化器AMSGrad版本train_process()输出:
Epoch 1/10, 对训练样本进行预测的准确率(Train Acc): 96.44%
Epoch 2/10, 对训练样本进行预测的准确率(Train Acc): 97.58%
Epoch 3/10, 对训练样本进行预测的准确率(Train Acc): 98.43%
Epoch 4/10, 对训练样本进行预测的准确率(Train Acc): 98.59%
Epoch 5/10, 对训练样本进行预测的准确率(Train Acc): 98.85%
Epoch 6/10, 对训练样本进行预测的准确率(Train Acc): 99.06%
Epoch 7/10, 对训练样本进行预测的准确率(Train Acc): 99.37%
Epoch 8/10, 对训练样本进行预测的准确率(Train Acc): 99.42%
Epoch 9/10, 对训练样本进行预测的准确率(Train Acc): 99.42%
Epoch 10/10, 对训练样本进行预测的准确率(Train Acc): 99.56%
训练用时: 0:01:41.566383
不同的优化算法有不同的特点,读者可通过更多的练习来摸索它们的应用方法和特点。
4.梯度消散与梯度爆炸问题
本专栏中,本文之前的几篇文章讨论了多层神经网络的激活函数、损失函数和优化器等问题。这里简要说明一下与这几个问题都有关的在多层神经网络训练中非常重要的梯度消散和梯度爆炸问题。
在校对误差反向传播的过程中,如果偏导数较小,在多次连乘之后,校对误差会趋近于0,导致梯度也趋近于0,前面层的参数无法得到有效更新,称之为梯度消散。梯度消散会使得增加再多的层也无法提高效果,甚至反而会降低。
相反,如果偏导数较大,则会在反向传播的过程中呈指数级增长,导致溢出,无法计算,网络不稳定,称之为梯度爆炸。
梯度消散和梯度爆炸只在层次较多的网络中出现,常用的解决方法包括尽量使用合适的激活函数(如Relu函数,它在正数部分导数为1)和损失函数;适当的优化器;预训练;合适的网络模型(有些网络模型具有防消散和爆炸能力,将在后文讨论);梯度截断等等。