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

如何在等高线图中得到正确的随机梯度下降(SGD)结果?

随机梯度下降(SGD)代码错误排查

问题描述

我实现随机梯度下降(Stochastic Gradient Descent, SGD)并尝试绘制参数更新的等高线图,但代码运行结果不符合预期。

我的代码

import numpy as np
from matplotlib import pyplot as plt
xk = np.linspace(-1,1,100)
yk= 2 * xk + 3 + np.random.rand(len(xk))
x1,x2 = np.meshgrid(xk,yk)

F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2
fig=plt.figure()
surf = fig.add_subplot(1,1,1, projection='3d')
surf.plot_surface(x1,x2,F)
surf.contour(x1,x2,F)

fig, surf=plt.subplots()
plt.contour(x1, x2, F, 20)

m = 0
c = 0
learning_rate=0.01

我认为问题出在以下这段代码中,但找不到具体错误:

for k in range(10):  
    shuffel_index=np.random.permutation(len(xk))
    xk = xk[shuffel_index]
    yk = yk[shuffel_index]
    for i in range(len(xk)):
       grad_m = - 2 * xk[i] * (yk[i] - (np.dot(m,xk[i]) + c))
       grad_c = - 2 * (yk[i] - (np.dot(m,xk[i])+c))
       m = m - learning_rate * grad_m
       c = c - learning_rate * grad_c
       surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
       if (k != 10 or i != len(xk)):
         surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
    plt.show()

当前结果

当前运行结果

期望效果

期望得到类似梯度下降的参数路径图,示例如下:
期望效果示例

请问我的代码中存在哪些错误?


错误分析与修正方案

1. 损失函数与参数空间不匹配

你定义的F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2是针对样本特征x1,x2的函数,和线性模型的参数m,c完全无关。而我们需要的是参数空间(m,c)上的损失等高线,即基于线性回归的残差平方和损失:
$$L(m,c) = \sum_{i=1}^n (y_i - (m x_i + c))^2$$
需要生成以m为x轴、c为y轴的网格,再计算每个(m,c)对应的损失值。

2. 绘图逻辑完全错误

循环中你绘制的是样本点的前两个值xk[0],yk[0]和xk[1],yk[1]的连线,这和参数(m,c)的更新路径毫无关系。正确做法是每次更新m,c后,在参数空间(m为横坐标,c为纵坐标)上绘制当前参数点,并连接路径。

3. 循环与绘图时机错误

  • plt.show()放在外层循环内,会在每轮迭代后弹出新窗口,应该放在所有循环结束后一次性显示。
  • 条件判断if (k != 10 or i != len(xk))逻辑错误,且重复绘制无效点,完全没必要保留。
  • 变量名拼写错误:shuffel_index应为shuffle_index,属于不规范写法。

4. 梯度计算冗余

np.dot(m,xk[i])中m是标量,直接用m * xk[i]即可,无需使用np.dot。


修正后的完整代码

import numpy as np
from matplotlib import pyplot as plt

# 生成样本数据
xk = np.linspace(-1, 1, 100)
yk = 2 * xk + 3 + np.random.rand(len(xk))  # 真实参数m=2, c=3,添加噪声

# 1. 生成参数空间(m,c)的损失等高线
# 定义参数范围,覆盖真实值附近
m_grid = np.linspace(0, 4, 100)
c_grid = np.linspace(1, 5, 100)
M, C = np.meshgrid(m_grid, c_grid)

# 计算每个(m,c)对应的残差平方和损失
loss = np.zeros_like(M)
for i in range(len(xk)):
    loss += (yk[i] - (M * xk[i] + C)) ** 2

# 绘制等高线图
fig, ax = plt.subplots()
contour = ax.contour(M, C, loss, 20)
ax.clabel(contour, inline=True, fontsize=8)
ax.set_xlabel('m (斜率)')
ax.set_ylabel('c (截距)')
ax.set_title('SGD参数更新路径')

# 2. 执行随机梯度下降并记录参数路径
m = 0
c = 0
learning_rate = 0.01
epochs = 10
path_m = [m]
path_c = [c]

for k in range(epochs):
    shuffle_index = np.random.permutation(len(xk))
    x_shuffled = xk[shuffle_index]
    y_shuffled = yk[shuffle_index]
    for i in range(len(x_shuffled)):
        y_pred = m * x_shuffled[i] + c
        # 计算梯度
        grad_m = -2 * x_shuffled[i] * (y_shuffled[i] - y_pred)
        grad_c = -2 * (y_shuffled[i] - y_pred)
        # 更新参数
        m -= learning_rate * grad_m
        c -= learning_rate * grad_c
        # 记录参数用于绘制路径
        path_m.append(m)
        path_c.append(c)

# 绘制参数更新路径和真实参数点
ax.plot(path_m, path_c, 'ko-', markersize=3, linewidth=1, label='SGD路径')
ax.plot(2, 3, 'r*', markersize=10, label='真实参数')
ax.legend()
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:15:34