共计 1972 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要随机梯度下降
在机器学习中,梯度下降是最常用的优化算法之一。传统的批量梯度下降 (BGD) 每次迭代都要计算整个数据集的梯度,当数据集很大时(比如百万级样本),这会带来巨大的计算开销。

想象一下,每次更新参数都要遍历全部数据,就像每次调整方向都要问遍所有路人,效率实在太低了。这就是我们需要随机梯度下降 (SGD) 的原因 – 它每次只随机选取一个样本计算梯度,大大提高了迭代速度。
数学原理
SGD 的参数更新规则很简单:
$$\theta_{t+1} = \theta_t – \eta \cdot \nabla_\theta J(\theta_t; x^{(i)}, y^{(i)})$$
其中:
– $\theta$ 是模型参数
– $\eta$ 是学习率
– $(x^{(i)}, y^{(i)})$ 是随机选取的一个训练样本
与 BGD 相比,SGD 有两大优势:
1. 计算量小,每次迭代只需处理一个样本
2. 随机性可以帮助跳出局部最优解
Python 实现
下面我们用一个简单的线性回归任务来演示 SGD 的实现。我们将:
1. 生成二维线性数据
2. 实现 SGD 优化
3. 可视化优化过程
import numpy as np
import matplotlib.pyplot as plt
# 1. 生成数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1) # 100 个 0 - 2 之间的随机数
y = 4 + 3 * X + np.random.randn(100, 1) # 添加噪声
# 2. SGD 实现
def sgd(X, y, n_epochs=50, eta0=0.1):
m = len(X)
theta = np.random.randn(2, 1) # 随机初始化参数
# 记录损失和参数变化
losses = []
thetas = [theta.copy()]
for epoch in range(n_epochs):
# 学习率衰减
eta = eta0 / (epoch + 1)
for i in range(m):
random_index = np.random.randint(m)
xi = np.c_[1, X[random_index]] # 添加偏置项
yi = y[random_index]
# 计算梯度
gradients = 2 * xi.T.dot(xi.dot(theta) - yi)
# 更新参数
theta = theta - eta * gradients
thetas.append(theta.copy())
# 计算当前 epoch 的损失
y_pred = np.c_[np.ones((m,1)), X].dot(theta)
loss = np.mean((y_pred - y)**2)
losses.append(loss)
return theta, losses, thetas
# 运行 SGD
theta_sgd, losses_sgd, thetas_sgd = sgd(X, y)
对比实验
我们可以将 SGD 与 BGD 的收敛过程进行对比:
# BGD 实现
def bgd(X, y, n_epochs=50, eta=0.1):
m = len(X)
theta = np.random.randn(2, 1)
losses = []
for epoch in range(n_epochs):
# 计算整个数据集的梯度
gradients = 2/m * np.c_[np.ones((m,1)), X].T.dot(np.c_[np.ones((m,1)), X].dot(theta) - y)
# 更新参数
theta = theta - eta * gradients
# 计算损失
y_pred = np.c_[np.ones((m,1)), X].dot(theta)
loss = np.mean((y_pred - y)**2)
losses.append(loss)
return theta, losses
# 运行 BGD
theta_bgd, losses_bgd = bgd(X, y)
# 绘制收敛曲线
plt.plot(losses_bgd, 'b-', label='BGD')
plt.plot(losses_sgd, 'r-', label='SGD')
plt.legend()
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('BGD vs SGD Convergence')
plt.show()
避坑指南
在实践 SGD 时,新手常会遇到以下问题:
- 学习率设置不当:
- 学习率太大会导致震荡不收敛
- 学习率太小收敛速度太慢
-
建议使用学习率衰减策略
-
特征未归一化:
- 不同特征尺度差异大会导致收敛困难
-
务必对特征进行标准化处理
-
随机性的收敛判断:
- SGD 的损失曲线会有较大波动
- 建议观察移动平均损失而非单个 epoch
延伸思考
掌握了 SGD 的基本原理后,你可以尝试:
- 用 SGD 实现逻辑回归
- 在神经网络中应用 SGD
- 实现更高级的优化器如 Momentum 或 Adam
SGD 虽然简单,但它是深度学习优化的基础。理解它的工作原理对后续学习更复杂的优化算法很有帮助。
正文完
发表至: 未分类
近一天内
