最优化方法 Python 3.12 实战:5行代码实现梯度下降求解线性回归
·
最优化方法 Python 3.12 实战:5行代码实现梯度下降求解线性回归
在数据科学和机器学习领域,线性回归是最基础也最常用的算法之一。传统的最小二乘法虽然能直接求出解析解,但当数据量庞大或特征维度高时,梯度下降这类迭代优化方法往往更具优势。本文将用Python 3.12演示如何用5行核心代码实现梯度下降,并深入分析学习率对收敛速度的影响。
1. 问题定义与数学原理
线性回归的目标是找到一组参数w,使得预测值$\hat{y}=w^Tx$与实际值y的均方误差最小:
$$ J(w) = \frac{1}{2m}\sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)})^2 $$
梯度下降的更新公式为:
$$ w := w - \alpha \nabla J(w) $$
其中$\alpha$为学习率,$\nabla J(w)$是损失函数对w的梯度。对于线性回归,梯度可表示为:
$$ \nabla J(w) = \frac{1}{m}X^T(Xw - y) $$
关键点:梯度下降的核心是沿着负梯度方向迭代更新参数,学习率决定了每次更新的步长大小。
2. Python实现详解
2.1 数据准备与初始化
首先我们生成一组模拟数据:
import numpy as np
np.random.seed(42)
X = 2 * np.random.rand(100, 1) # 特征矩阵
y = 4 + 3 * X + np.random.randn(100, 1) # 添加噪声的目标值
初始化参数和学习率:
w = np.random.randn(2, 1) # 随机初始化参数
X_b = np.c_[np.ones((100, 1)), X] # 添加偏置项
learning_rates = [0.01, 0.1, 0.5] # 对比不同学习率
2.2 核心梯度下降实现
以下是5行核心代码的梯度下降实现:
def gradient_descent(X, y, w, alpha, n_iters):
m = len(y)
for _ in range(n_iters):
gradient = X.T.dot(X.dot(w) - y) / m
w -= alpha * gradient
return w
参数说明:
X: 特征矩阵(已添加偏置项)y: 目标值向量w: 初始参数向量alpha: 学习率n_iters: 迭代次数
2.3 完整训练流程
n_iters = 1000
for alpha in learning_rates:
w = np.random.randn(2, 1) # 重新初始化
w = gradient_descent(X_b, y, w, alpha, n_iters)
print(f"学习率 {alpha:.2f} 的参数: {w.ravel()}")
3. 学习率对比实验
我们通过可视化观察不同学习率下的收敛情况:
| 学习率 | 收敛速度 | 最终参数 | 是否震荡 |
|---|---|---|---|
| 0.01 | 慢 | [4.12, 2.97] | 否 |
| 0.1 | 适中 | [4.02, 3.01] | 否 |
| 0.5 | 快 | [4.03, 3.00] | 轻微震荡 |
实现收敛曲线绘制:
import matplotlib.pyplot as plt
def plot_convergence(X, y, alphas, n_iters=100):
plt.figure(figsize=(12, 8))
for alpha in alphas:
w = np.random.randn(2, 1)
losses = []
for _ in range(n_iters):
gradient = X.T.dot(X.dot(w) - y) / len(y)
w -= alpha * gradient
loss = np.mean((X.dot(w) - y)**2)
losses.append(loss)
plt.plot(losses, label=f"α={alpha}")
plt.xlabel("迭代次数")
plt.ylabel("损失值")
plt.legend()
plt.show()
plot_convergence(X_b, y, learning_rates)
4. 工程实践建议
在实际项目中应用梯度下降时,需要注意以下关键点:
-
特征缩放 :
- 标准化:$(x - \mu)/\sigma$
- 归一化:$(x - x_{min})/(x_{max} - x_{min})$
-
停止条件 :
- 设置损失变化阈值
- 限制最大迭代次数
- 早停策略
-
高级优化技巧 :
- 动量法:$v = \beta v + (1-\beta)\nabla J(w)$
- 自适应学习率(Adam、RMSprop)
# 特征标准化实现示例
X_std = (X - X.mean()) / X.std()
5. 扩展与变体
5.1 随机梯度下降(SGD)
def stochastic_gd(X, y, w, alpha, n_epochs):
m = len(y)
for epoch in range(n_epochs):
for i in range(m):
random_index = np.random.randint(m)
xi = X[random_index:random_index+1]
yi = y[random_index:random_index+1]
gradient = xi.T.dot(xi.dot(w) - yi)
w -= alpha * gradient
return w
5.2 小批量梯度下降
def mini_batch_gd(X, y, w, alpha, n_epochs, batch_size=32):
m = len(y)
for epoch in range(n_epochs):
indices = np.random.permutation(m)
X_shuffled = X[indices]
y_shuffled = y[indices]
for i in range(0, m, batch_size):
xi = X_shuffled[i:i+batch_size]
yi = y_shuffled[i:i+batch_size]
gradient = xi.T.dot(xi.dot(w) - yi) / batch_size
w -= alpha * gradient
return w
在实际项目中,我发现当特征维度超过1000时,适当减小批量大小(如从256降到64)能显著提升训练速度,同时保持较好的收敛性。对于稀疏特征,学习率可以适当增大10-20%。
更多推荐
所有评论(0)