
本文详解如何修复梯度下降算法中因梯度计算错误和参数更新逻辑混乱导致的θ值发散或不收敛问题,重点展示如何推导并实现成本函数的精确解析梯度,替代错误的数值/符号梯度,并采用单步向量化更新确保稳定收敛。
本文详解如何修复梯度下降算法中因梯度计算错误和参数更新逻辑混乱导致的θ值发散或不收敛问题,重点展示如何推导并实现成本函数的精确解析梯度,替代错误的数值/符号梯度,并采用单步向量化更新确保稳定收敛。
在实现梯度下降时,参数更新的准确性完全依赖于梯度的正确性。原代码中存在两个根本性缺陷:一是 gradient() 函数未真正反映成本函数 erreurJ 对参数 θ = [w, b] 的偏导关系(它错误地引入了输入 X、预测输出 Y 等中间变量,却未链式求导至 θ),二是内层 for i in range(len(theta)) 循环导致权重 w 和偏置 b 在同一迭代中被非同步更新——即先用旧 b 更新 w,再用新 w 更新 b,破坏了梯度下降的数学一致性。
正确的做法是:直接对 erreurJ(θ) 求解析梯度 ∇J(θ)。根据题设成本函数
$$
J(\theta) = \frac{1}{4}\left[\sigma(b)^2 + \sigma(w+b)^2\right], \quad \text{其中 } \sigma(z) = z^2 - 1,
$$
通过链式法则可严格推导出:
- $\frac{\partial J}{\partial w} = 2b^3 + 3b^2 w + 3b w^2 - 2b + w^3 - w$
- $\frac{\partial J}{\partial b} = b^3 + 3b^2 w + 3b w^2 - b + w^3 - w$
该解析梯度已封装在 grad(theta) 函数中,完全脱离输入数据流干扰,仅依赖当前 θ,保证数学严谨性。
此外,更新逻辑必须是原子化、向量化的:
theta = np.array(theta, dtype=np.float64)
while np.linalg.norm(grad(theta)) > epsilon:
theta = theta - eta * grad(theta) # ✅ 一次性同步更新 w 和 b而非原代码中逐分量更新(易引发数值不稳定)或在循环内重复调用 calculh/calculY(引入冗余计算与状态污染)。
其他关键改进包括:
-
学习率调优:
eta = 0.01(原0.1过大,易跳过极小点); -
发散防护:使用
np.any(np.abs(theta) > 100)统一检测整体参数爆炸; -
类型安全:显式转为
np.float64避免整数溢出或精度丢失; -
职责解耦:
pasfixe()不再接收X,Y,Ysol等无关参数,聚焦纯优化逻辑。
最终,5000 个随机初值 (w₀, b₀) ∈ [-3, 3]² 将稳定收敛至四个理论极小点:(-2,1), (2,-1), (0,-1), (0,1),对应不同 basin of attraction——这正是目标收敛图(如 Stack Exchange 所示)的数学基础。若仍出现红点(发散),应进一步降低 eta 或增加 epsilon 容差;若聚类模糊,可对 listetheta 添加 np.clip(theta, -5, 5) 增强可视化对比度。
总结:梯度下降不是“写个循环减梯度”即可,而是需确保 ——
✅ 梯度来源与成本函数严格匹配(解析推导优先);
✅ 参数更新为同步向量操作;
✅ 学习率、容差、数值类型经实证调优;
✅ 可视化前对结果做合理截断与归约。

















