梯度下降法是最基础的一阶优化算法,其核心思想是通过迭代方式沿着目标函数梯度的反方向更新参数,逐步逼近函数的极小值点。对于目标函数f(x),其更新公式为:
x_{k+1} = x_k - η∇f(x_k)
其中η为学习率(learning rate),控制每次更新的步长。在本次示例中,我们使用的目标函数是三次多项式:
f(x) = 2x³ + 6x² + 7
这个函数在实数域上有两个驻点:
关键提示:选择学习率时需要特别注意,过大的学习率会导致震荡甚至发散,过小则收敛缓慢。对于本例函数,经过测试发现η=0.01能保证稳定收敛。
代码实现可分为五个核心部分:
python复制def f(x):
return 2 * x**3 + 6 * x**2 + 7
def grad_f(x):
return 6 * x**2 + 12 * x
这里明确定义了目标函数及其梯度函数,采用解析法计算导数而非数值近似,保证了计算精度。
python复制x = 1.0 # 初始点
lr = 0.01 # 学习率
max_iter = 15 # 迭代轮次
history = np.zeros((max_iter + 1, 2)) # 迭代历史记录
初始点选择x=1位于极大值点右侧,理论上应该向极大值点x=0收敛。
python复制for iter in range(1, max_iter + 1):
dx = grad_f(x) # 计算当前梯度
x = x - lr * dx # 参数更新
history[iter] = [x, f(x)]
每次迭代都计算当前点的梯度,并沿负梯度方向更新参数。
python复制print(f"x = {x:.4f}, f(x) = {f(x):.4f}")
格式化输出最终结果,保留4位小数保证精度。
python复制plt.plot(x_range, y_range, 'b-', linewidth=1.5, label='函数曲线')
plt.plot(history[:,0], history[:,1], 'r-o', linewidth=1.2, markersize=6, label='迭代路径')
使用matplotlib绘制函数曲线和迭代路径,直观展示优化过程。
从输出结果可以看到,经过15次迭代后:
这与理论分析一致,算法确实在向极大值点x=0靠近。但需要注意:
Adam(Adaptive Moment Estimation)是结合了动量法和RMSProp的自适应学习率算法。对于双变量函数g(x1,x2)=2x1³+6x2²,其优化过程需要分别计算两个维度的梯度:
∂g/∂x1 = 6x1²
∂g/∂x2 = 12x2
Adam的核心在于为每个参数维护两个矩估计:
一阶矩(动量):
m_t = β₁m_{t-1} + (1-β₁)g_t
二阶矩(梯度平方的指数移动平均):
v_t = β₂v_{t-1} + (1-β₂)g_t²
经过偏差修正后:
m̂_t = m_t/(1-β₁^t)
v̂_t = v_t/(1-β₂^t)
最终参数更新公式:
x_t = x_{t-1} - ηm̂_t/(√v̂_t + ε)
代码实现中的几个关键部分:
python复制dx1 = 6 * x1 ** 2
dx2 = 12 * x2
分别计算两个变量的偏导数,这是Adam算法的基础。
python复制m1 = beta1 * m1 + (1 - beta1) * dx1
v1 = beta2 * v1 + (1 - beta2) * dx1 ** 2
对每个参数独立维护一阶和二阶矩估计。
python复制m1_hat = m1 / (1 - beta1 ** t)
v1_hat = v1 / (1 - beta2 ** t)
消除初始零值偏差,特别在迭代初期很重要。
python复制x1 = x1 - lr * m1_hat / (np.sqrt(v1_hat) + epsilon)
应用自适应学习率进行参数更新,ε=1e-8防止除零。
从实验结果可以看出:
可视化结果显示:
| 算法 | 动量项 | 自适应学习率 | 超参数数量 | 内存占用 | 适用场景 |
|---|---|---|---|---|---|
| SGD | 无 | 无 | 1(lr) | 低 | 大规模数据 |
| AdaGrad | 无 | 有(累积) | 1(lr) | 中 | 稀疏数据 |
| RMSProp | 无 | 有(EMA) | 2(lr,γ) | 中 | 非平稳目标 |
| Adadelta | 无 | 有(自适应) | 2(γ,ε) | 中 | 无需调lr |
| Adam | 有 | 有(EMA) | 4(lr,β1,β2,ε) | 高 | 通用场景 |
SGD
AdaGrad
RMSProp
Adadelta
Adam
根据实际问题特点选择优化器:
工程经验:在实际项目中,建议先用Adam快速验证想法,再根据需要尝试其他优化器。对于超大规模数据,可考虑SGD的变种如带动量的SGD。
在具体实现时,可以借助现代深度学习框架提供的优化工具。例如PyTorch中的优化器实现:
python复制import torch.optim as optim
# 创建模型和优化器
model = MyModel()
optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
# 训练循环
for epoch in range(epochs):
for data, target in dataloader:
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
这种封装好的优化器实现既方便使用,又能保证计算效率。理解底层原理有助于在出现问题时能够有效调试。