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

单特征梯度下降线性回归发散问题:代码未收敛原因排查

梯度下降实现单特征线性回归模型发散排查

我参考教程实现了基于梯度下降的单特征线性回归,代码逻辑是按梯度更新权重,但运行后模型明显发散,Cost值持续大幅增长,参数m、c严重偏离预期的0.4和3。以下是我的代码、运行输出及数据集散点图,求帮忙排查问题:

我的代码

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (12.0, 9.0)


x = np.linspace(0, 100, 100) # 100个0到100之间的数值
y = 0.4*x + 3


# 预处理输入数据
plt.scatter(x, y)
plt.show()
# 构建模型
m = 0
c = 0

L = 0.001  # 学习率
epochs = 10  # 梯度下降迭代次数


n = float(len(x)) # X的样本数量

# 执行梯度下降 
for i in range(epochs): 
    y_pred = m*x + c  # 当前Y的预测值
    cost=np.sum(np.square(y - y_pred))
    D_m = (-2/n) * sum(x * (y - y_pred))  # 对m的导数
    D_c = (-2/n) * sum(y - y_pred)  # 对c的导数
    m = m - L * D_m  # 更新m
    c = c - L * D_c  # 更新c
    print("Cost: {}, m: {}, c: {}".format(cost, m, c))

    
print (m, c)

运行输出

Cost: 66502.69360269362, m: 2.980134680134681, c: 0.04600000000000002

Cost: 2154894.319611961, m: -14.012236408983222, c: -0.20610546801346816

Cost: 70050303.28853585, m: 82.87521068285723, c: 1.241530383820881

Cost: 2277388248.5411315, m: -469.56062336187455, c: -7.002473745232483

Cost: 74039836741.10417, m: 2680.334036437331, c: 40.01359353844544

Cost: 2407098544049.198, m: -15279.827701739041, c: -228.05383729236456

Cost: 78256836757675.23, m: 87125.94814145382, c: 1300.4310405561246

Cost: 2544196836061482.0, m: -496774.302711737, c: -7414.71863567037

Cost: 8.271401974355902e+16, m: 2832525.2415301367, c: 42277.587072774666

Cost: 2.6891036751423396e+18, m: -16150572.367496913, c: -241059.4462543846

-16150572.367496913 -241059.4462543846

数据集散点图

数据集散点图


问题排查与修复方案

核心问题

  1. 学习率过大:L=0.001对于取值范围0-100的x来说步长太大,参数更新时直接跳过最优值,甚至在最小值附近来回震荡、发散。
  2. 数据未做归一化:x的数值范围是0-100,较大的数值导致梯度计算结果也很大,结合大学习率进一步加剧了参数发散。

修复后的代码

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (12.0, 9.0)

x = np.linspace(0, 100, 100)
y = 0.4*x + 3

# 数据归一化:将x缩放到0-1区间
x_normalized = (x - np.min(x)) / (np.max(x) - np.min(x))

plt.scatter(x, y)
plt.show()

m = 0
c = 0

L = 0.1  # 归一化后可适当增大学习率,保证收敛速度
epochs = 1000  # 增加迭代次数,确保参数收敛到最优值

n = float(len(x_normalized))

for i in range(epochs): 
    y_pred = m*x_normalized + c
    cost = np.sum(np.square(y - y_pred))
    D_m = (-2/n) * sum(x_normalized * (y - y_pred))
    D_c = (-2/n) * sum(y - y_pred)
    m = m - L * D_m
    c = c - L * D_c
    # 每100轮打印一次状态,方便观察收敛情况
    if i % 100 == 0:
        print(f"第{i}轮 - Cost: {cost:.2f}, m: {m:.2f}, c: {c:.2f}")

# 将归一化后的m转换回原始x尺度的参数
m_original = m / (np.max(x) - np.min(x))
c_original = c - m_original * np.min(x)
print(f"\n原始尺度下的最优参数:m={m_original:.2f}, c={c_original:.2f}")

关键调整说明

  • 数据归一化:把x缩放到0-1区间,消除数值范围差异带来的梯度爆炸问题,让梯度下降更稳定。
  • 调整学习率:归一化后可以使用更大的学习率(如0.1),既保证收敛速度,又不会出现发散。
  • 增加迭代次数:归一化后收敛过程更平稳,需要足够的迭代次数让参数逼近真实值0.4和3。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:05:22