You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现随机梯度下降(SGD)时权重更新异常问题排查

嘿,你猜得太对了!问题核心就是权重更新的方式完全错了——你现在是把整个损失值直接统一加到所有权重上,这根本不是随机梯度下降(SGD)的正确逻辑。SGD要求我们针对每个权重单独计算它的梯度,再逐个更新。咱们一步步把代码改对:

修正后的SGD多项式回归实现

先看完整的修正代码,后面我会拆解关键修改点:

from matplotlib import pyplot as plt
import math
import numpy as np

def epsilon():
    '''Adds noise to the data points'''
    return np.random.normal(0, 0.3, 100)

def yFunction(x):
    '''Function to predict'''
    return np.sin(2 * math.pi * x) + epsilon()

def predict(x, thetas):
    '''Predict value of x with the given thetas'''
    # 用矩阵运算替代循环,更高效且易读
    x_powers = np.array([x**i for i in range(thetas.size)])
    return np.dot(x_powers, thetas)

# 学习率(可根据收敛情况调整)
alpha = 0.1
# 多项式阶数:这里是2阶,对应3个权重(x^0, x^1, x^2)
poly_degree = 2

# 生成随机数据点
X = np.random.random_sample(100)
y = yFunction(X)

# 初始化权重:对应各次项的系数
thetas = np.random.normal(0, 0.5, poly_degree + 1)

# 记录损失变化
lossHistory = []

for epoch in range(1000):
    # 取当前样本(用epoch%100实现循环遍历,SGD也可以随机选样本)
    idx = epoch % 100
    x_sample = X[idx]
    y_true = y[idx]
    
    # 计算预测值
    y_pred = predict(x_sample, thetas)
    
    # 计算单样本误差
    error = y_pred - y_true
    
    # 记录单样本损失
    loss = error ** 2
    lossHistory.append(loss)
    
    # 核心:逐个更新每个权重
    for i in range(thetas.size):
        # 每个权重对应x的i次幂特征
        feature = x_sample ** i
        # 梯度下降更新:沿着负梯度方向调整权重
        thetas[i] -= alpha * error * feature

# 用排序后的X绘图,避免折线混乱
X_sorted = np.sort(X)
Y_pred = predict(X_sorted, thetas)

# 绘制原始数据与拟合曲线
fig = plt.figure()
plt.scatter(X, y, label='Actual Data')
plt.plot(X_sorted, Y_pred, "r-", label='Prediction')
plt.legend()
plt.suptitle("Prediction Line Over Actual Values")

# 绘制损失曲线
fig = plt.figure()
plt.plot(np.arange(0, len(lossHistory)), lossHistory)
plt.suptitle("Training Loss")
plt.show()
关键修改点说明
  1. 权重更新逻辑(最核心的错误)
    原代码里的thetas += alpha * loss/thetas -= alpha * loss完全不符合梯度下降的原理。正确的单样本SGD更新规则是:
    对于每个权重theta_i,它的梯度是误差 × 对应特征值(来自损失函数对theta_i的偏导数),所以更新公式为:

    thetas[i] -= alpha * error * (x_sample ** i)
    

    每个权重都要单独计算、单独更新,不能所有权重用同一个值调整。

  2. 绘图优化
    原代码用随机无序的X值绘图,导致拟合线是混乱的折线。改成排序后的X_sorted绘图,能清晰展示拟合曲线的趋势。

  3. 代码可读性优化
    把predict函数里的循环改成矩阵点积运算,既高效又更符合Python/NumPy的写法习惯。

额外优化建议
  • 调整学习率:如果损失曲线波动太大,可以尝试减小学习率(比如alpha=0.01),或者添加学习率衰减(比如每100轮把学习率乘以0.9)。
  • Mini-batch SGD:单样本SGD收敛波动较大,可以改成每次用5-10个样本计算平均梯度,收敛会更稳定。
  • 特征归一化:多项式特征中,x^2的取值范围可能远大于x,归一化特征能让权重更新更均衡,加快收敛速度。

内容的提问来源于stack exchange,提问作者hildebro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:57:12