在前面我们讲解了动量法(Momentum),也就是动量随机梯度下降法。它使用了一阶动量。然而,我们同时也提到了二阶动量。使用二阶动量的梯度下降算法的改进版就是本节要讲的AdaGrad算法。二阶动量的出现,才意味着真正的自适应学习率优化算法时代的到来。
AdaGrad算法的基本思想
我们先回顾一下传统的随机梯度下降法(SGD)及其各种变种。它们都是以同样的学习率来更新每一个参数的。但深度神经网络往往包含大量参数,这些参数并不总是均匀更新的。有些参数更新得频繁,有些则很少更新。对于经常更新的参数,我们已经积累了大量关于它的知识,希望它不被新的单个样本影响太大,也就是说希望对这些参数的学习率小一些。对于偶尔更新的参数,我们了解的信息较少,希望从每一个样本中多学一些,即学习率大一些。
要动态度量历史更新的频率,我们引入二阶动量。二阶动量通过将每一位各自的历史梯度的平方叠加起来来计算。具体公式如下:
\[ v_t = v_{t-1} + g_t^2 \]
其中,\( g_t \) 是当前的梯度。
算法流程
1. **计算当前梯度 \( g_t \)**:
\[ g_t = \nabla f(\theta_t) \]
2. **更新一阶动量 \( m_t \) 和二阶动量 \( v_t \)**:
\[ m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t \]
\[ v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 \]
3. **计算当前时刻的下降梯度**:
\[ \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{v_t} + \epsilon} g_t \]
其中,\( \alpha \) 是学习率,\( \epsilon \) 是一个小的平滑项,防止分母为0。
稀疏特征处理
AdaGrad算法主要针对稀疏特征进行了优化。稀疏特征在很多样本中只出现少数几次,在训练模型时,这些稀疏特征的更新很少,但每次更新可能带来较大影响。AdaGrad通过调整每个特征的学习率,针对这种情况进行了优化。
优缺点
优点:
1. 有效处理稀疏特征:自动调整每个参数的学习率,使得稀疏特征的更新更少。
2. 加速收敛:在自动调整学习率的同时,使得模型在训练过程中更快收敛。
缺点:
1. 学习率逐渐减小:每次迭代中学习率都会减小,导致训练后期学习率变得非常小,从而使收敛速度变慢。
2. 固定调整方式:对于不同参数,学习率调整方式是固定的,无法根据不同任务自动调整。
代码实现
下面是一个简单的PyTorch实现AdaGrad算法的示例:
python
import torch
import matplotlib.pyplot as plt# 定义超参数
learning_rate = 0.01
epochs = 100# 随机生成一些数据
x = torch.randn(100, 1)
y = 2 * x + 3 + torch.randn(100, 1) * 0.5# 初始化参数
w = torch.randn(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)# 定义AdaGrad优化器
optimizer = torch.optim.Adagrad([w, b], lr=learning_rate)# 记录损失
losses = []for epoch in range(epochs):# 预测y_pred = x * w + b# 计算损失loss = torch.mean((y_pred - y) ** 2)losses.append(loss.item())# 清空梯度optimizer.zero_grad()# 反向传播loss.backward()# 更新参数optimizer.step()# 可视化训练过程
plt.plot(range(epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
总结
本节我们介绍了一种新的梯度下降算法变体——AdaGrad。与动量法相比,它最大的改进在于使用二阶动量来动态调整学习率,能够记住历史上的梯度信息,以动态调整学习率。其主要优点是能够处理稀疏特征问题,但也有学习率逐渐减小和调整方式固定的缺点。
到目前为止,我们一共讲了五种梯度下降算法。AdaGrad是2011年提出的,而动量法在1993年提出,SGD在1951年提出。通过时间轴的对比,我们可以看出人们在不断研究和改进梯度下降算法,从最早的梯度下降法到SGD,再到动量法、小批量梯度下降,最后到2011年的AdaGrad。