深度学习(2):梯度下降
文章目录
- 梯度下降
- 梯度是什么
- 常见梯度下降算法
- 代码实现
- 批量梯度下降
梯度下降
梯度是什么
类似y = ax + b这种单变量的函数来说,导数就是它的斜率,这种情况下可以说梯度就是导数。
但在多变量函数中,梯度是一个向量,其分量是各个单一变量的偏导数。这个向量指向函数增长最快的方向,其向量的模(大小)表示在那个方向上的最大变化率。
所以我们沿着梯度的反方向走,这就是下降最快的方向,这样就能够使得损失函数最快的下降了
常见梯度下降算法
-
批量梯度下降(Batch Gradient Descent)
- 原理:在每次迭代中,使用整个训练集计算损失函数的梯度,然后更新参数。
- 优点:
- 全局最优:每次更新都基于全数据,方向稳定。
- 收敛稳定:梯度的方向一致,易于收敛。
- 缺点:
- 计算开销大:对于大型数据集,计算梯度耗时长。
- 缺乏在线学习能力:无法实时更新模型。
-
随机梯度下降(Stochastic Gradient Descent, SGD)
- 原理:在每次迭代中,只使用一个样本计算梯度并更新参数。
- 优点:
- 计算效率高:每次更新只需计算一个样本的梯度。
- 在线学习:适合流式数据处理。
- 缺点:
- 收敛不稳定:梯度受单个样本影响,可能产生较大波动。
- 可能陷入局部最优:由于更新方向不稳定。
-
小批量梯度下降(Mini-batch Gradient Descent)
- 原理:在每次迭代中,使用一小批样本(如32、64、128个)计算梯度并更新参数。
- 优点:
- 权衡计算效率和稳定性:比批量方法快,比随机方法稳。
- 利用矩阵运算:可充分利用GPU等硬件加速。
- 缺点:
- 需要选择合适的批量大小:批量过小或过大会影响性能。
-
动量法(Momentum)
- 原理:在参数更新中引入动量项,累计之前梯度的指数加权平均,公式为:
- 优势:
- 加速收敛:在一致的梯度方向上加速移动。
- 减少振荡:在梯度变化方向上抑制波动。
-
Nesterov加速梯度(Nesterov Accelerated Gradient, NAG)
-
原理:在动量法的基础上,先对参数进行一步预估,然后计算预估位置的梯度,公式为:
-
优势:
- 提前感知:对未来位置的梯度进行评估,提高了更新的准确性。
- 更快收敛:比标准动量法具有更好的收敛速度。
-
-
AdaGrad(Adaptive Gradient)
- 原理:为每个参数适应性地调整学习率,累积梯度的平方和,公式为:
-
优势:
- 自适应学习率:对频繁更新的参数降低学习率,稀疏参数仍保持较大学习率。
- 适合稀疏数据:在自然语言处理等领域表现良好。
-
缺点:
- 学习率单调递减:可能导致后期学习过慢或停止。
-
RMSProp
- 原理:对AdaGrad进行改进,采用梯度平方的指数加权移动平均,公式为:
- 优势:
- 防止学习率过快下降:保持学习率在较为稳定的范围内。
- 适合非平稳目标:在处理递归神经网络等问题时表现良好。
-
Adam(Adaptive Moment Estimation)
- 原理:结合Momentum和RMSProp,同时计算梯度的一阶和二阶矩的估计,公式为:
- 优势:
- 自适应学习率:对每个参数进行动态调整。
- 快速收敛:在实践中表现出优秀的性能和稳定性。
- 广泛适用:已成为深度学习中最常用的优化算法之一。
代码实现
批量梯度下降
import matplotlib.pyplot as plt
# 准备数据集,线性关系
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# 随机的初始化权重
w = 1.0
# 找线性模型
def forward(x):
return x * w
# 损失函数MSE
def loss(xs, ys):
cost = 0 # 储存loss ^ 2的和
for x, y in zip(xs, ys):
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs) # MSE
# 批量梯度下降:选取所有的样本做梯度下降
# 获取当前的梯度是多少
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
epoch_list = []
loss_list = []
print('predict (before training)', 4, forward(4))
for epoch in range(100):
cost_val = loss(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val # 0.01 学习率
print('epoch:', epoch, 'w=', w, 'loss=', cost_val)
epoch_list.append(epoch)
loss_list.append(cost_val)
print('predict (after training)', 4, forward(4))
plt.plot(epoch_list, loss_list)
plt.ylabel('cost')
plt.xlabel('epoch')
plt.show()