线性回归调优问题:学习率与方程精度异常(Python)
线性回归梯度下降不收敛问题排查与修复
我尝试用0.01的学习率调优线性回归模型,但拟合直线无法正常收敛,参数更新路径不符合预期,反而出现随机偏移。确认问题不在学习率,而是模型参数更新方程有误。
原实现代码
from sklearn.datasets import make_regression, make_classification, make_blobs import matplotlib.pyplot as plt import numpy as np import random as rd # 生成回归数据集 x, y = make_regression( n_samples=100, n_features=1, noise=30 ) # 划分训练集和测试集 train_x = x[:-20] test_x = x[-20:] train_y = y[:-20] test_y = y[-20:] # 绘图函数 def graph_linear_regression(): # 绘制数据点 plt.scatter(train_x, train_y, color='blue', label='Data') # 绘制回归直线(原错误:直接画y=x) plt.plot(train_x, train_x, color='red', label='Linear Regression') # 添加标签和标题 plt.xlabel('x') plt.ylabel('y') plt.title('Linear Regression') # 显示图例和图像 plt.legend() plt.show() # 参数更新函数(原错误核心) def calculate_update_error(): global m global b learning_rate = 0.01 # 原注释的公式也有误 M = 1 / n * np.sum(f(train_x) - train_y) B = 1 / n * np.sum(np.sum(f(train_x) - train_y) * train_x) m = m - learning_rate * M b = b - learning_rate * B # 初始化参数 m = rd.randint(1, 100) b = rd.randint(1, 100) n = len(train_x) learning_rate = 0.01 print(f"n: {n}") print(f"m: {m}") print(f"b: {b}") print(f"learning_rate: {learning_rate}") # 线性回归预测函数 def f(x): return m * x + b # 迭代更新参数(原错误:迭代次数不足) for i in range(n): calculate_update_error() print() graph_linear_regression()
当前问题表现
拟合直线与数据点严重偏离,无收敛趋势,参数更新出现随机偏移。
期望达到:最小二乘法的拟合效果(直线贴合数据点的整体分布趋势)
错误分析与修复方案
1. 梯度计算公式错误(核心问题)
线性回归用MSE作为损失函数,对参数m(斜率)和b(截距)的梯度推导如下:
- 损失函数:$L = \frac{1}{2n}\sum_{i=1}^n (f(x_i)-y_i)^2$,其中$f(x_i)=m x_i + b$
- 对m求导:$\frac{\partial L}{\partial m} = \frac{1}{n}\sum_{i=1}^n (f(x_i)-y_i) \cdot x_i$
- 对b求导:$\frac{\partial L}{\partial b} = \frac{1}{n}\sum_{i=1}^n (f(x_i)-y_i)$
原代码的错误:
- m的梯度少乘了x,导致更新方向错误
- b的梯度多了一层sum且错误乘以x,导致梯度被错误放大
2. 绘图函数错误
原代码中plt.plot(train_x, train_x, ...)直接绘制了y=x的直线,完全没有使用训练得到的m和b,无法展示模型的拟合效果,应改为绘制f(train_x)。
3. 迭代次数不足
梯度下降需要足够多的迭代轮次才能让参数收敛,原代码只迭代了80次(训练集样本数),通常需要几百到几千次迭代。
修正后的完整代码
from sklearn.datasets import make_regression import matplotlib.pyplot as plt import numpy as np import random as rd # 生成回归数据集 x, y = make_regression( n_samples=100, n_features=1, noise=30, random_state=42 # 加随机种子保证可复现 ) # 划分训练集和测试集 train_x = x[:-20] train_y = y[:-20] # 绘图函数修复 def graph_linear_regression(): plt.scatter(train_x, train_y, color='blue', label='Data') # 使用模型预测值绘制回归直线 plt.plot(train_x, f(train_x), color='red', label='Linear Regression') plt.xlabel('x') plt.ylabel('y') plt.title('Linear Regression') plt.legend() plt.show() # 参数更新函数修复 def calculate_update_error(): global m global b learning_rate = 0.01 # 计算预测值与真实值的误差 error = f(train_x) - train_y # 正确计算梯度 m_gradient = (1 / n) * np.sum(error * train_x) b_gradient = (1 / n) * np.sum(error) # 更新参数 m -= learning_rate * m_gradient b -= learning_rate * b_gradient # 初始化参数 m = rd.randint(1, 100) b = rd.randint(1, 100) n = len(train_x) learning_rate = 0.01 print(f"初始参数 - n: {n}, m: {m}, b: {b}, learning_rate: {learning_rate}") # 线性回归预测函数 def f(x): return m * x + b # 增加迭代次数,比如1000轮 for i in range(1000): calculate_update_error() # 每100轮打印一次参数变化 if i % 100 == 0: print(f"迭代第{i}轮 - m: {round(m,2)}, b: {round(b,2)}") graph_linear_regression()
修复效果
修正后模型会逐步收敛,最终拟合直线会贴合数据点的整体趋势,达到接近最小二乘法的效果。
内容的提问来源于stack exchange,提问作者Tincho
相关产品推荐
相关产品推荐

