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

Python梯度下降算法异常:过最低点后回升,梯度函数有误

梯度下降算法偏导数计算错误修复

问题重现

实现简单梯度下降算法并在热力图可视化时,出现异常行为:算法经过最低点后回升并停在随机位置,而非在最低点附近波动。通过测试用例验证梯度计算错误:

print(grad(lambda x, y : x**2 - y**2)(1., 1.))

返回结果为[2., 2.],但正确的梯度应为[2., -2.]。进一步排查发现,当x=y时,ddx和ddy返回的偏导数结果相同,导致梯度向量计算错误。

用户原始实现代码:

from math import cos, sin, exp
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative

def f(x, y):
    return 4 * exp(-((x**2)/2 + (y**2)/2)) * sin(x*(y-1/2)) * cos(x/2 + y)

precision = 10e-5

# Derivee par rapport a x
def ddx(f):
    return lambda x, y: derivative(f, x, dx=precision, n=1, args=(y,))

# Derivee par rapport a y
def ddy(f):
    return lambda x, y: derivative(f, y, dx=precision, n=1, args=(x,))

# grad(f) retourne la fonction vectorielle de deux variables réelles : (x, y) -> ∇(x, y)
def grad(f):
    return lambda x, y: np.array([ddx(f)(x, y), ddy(f)(x, y)])

def display_heatmap_with_gradient_descent(f, a, b, c, d, n, x0, y0, iterations, h):
    x = np.arange(a,b,n)
    y = np.arange(c,d,n)
    X, Y = np.meshgrid(x, y) # préparation du maillage
    f_vect = np.vectorize(f) # transformation de f en une fonction vectorielle
    Z = f_vect(X,Y) # calcul des images

    # Trace la carte de couleur
    fig, ax = plt.subplots()
    colormap = ax.pcolormesh(X, Y, Z, cmap='YlGnBu')
    fig.colorbar(colormap)

    # Fonction gradient pour f
    gradient = grad(f)

    # Ajoute la descente de gradient
    x = x0
    y = y0
    for i in range(iterations):
        vecteur = -gradient(x, y)
        new_x = x + h * vecteur[0]
        new_y = y + h * vecteur[1]
        print("Itération " + str(i) + " : (" + str(x) + ", " + str(y) + ") -> (" + str(new_x) + ", " + str(new_y) + ")")
        print("	Vecteur : " + str(vecteur))
        ax.plot([x, new_x], [y, new_y], color='black')
        x = new_x
        y = new_y

    # Affiche le point d'arrêt
    ax.plot([x], [y], marker='o', markersize=3, color="red")
        
    plt.show()

display_heatmap_with_gradient_descent(f, -5, 5, -5, 5, 0.05, -0.36, -0.39, 100, 0.1)

错误原因

问题出在ddx和ddy的实现上:scipy.misc.derivative默认对函数的第一个参数求导,而原始代码中直接传递原函数f并指定args的方式,混淆了参数顺序:

  • ddy(f)中调用derivative(f, y, args=(x,)),实际计算的是f(t, x)对t的导数(t取y的值),而非f(x, y)对y的导数。
  • 当x=y时,这种参数混淆会导致ddx和ddy计算的是同一个导数,从而得到错误的梯度向量。

修复方案

重新实现ddx和ddy,通过lambda函数固定非求导参数,明确指定对目标变量求导:

# 对x求偏导:固定y,仅对x变量求导
def ddx(f):
    return lambda x, y: derivative(lambda t: f(t, y), x, dx=precision, n=1)

# 对y求偏导:固定x,仅对y变量求导
def ddy(f):
    return lambda x, y: derivative(lambda t: f(x, t), y, dx=precision, n=1)

修复后重新运行测试用例:

print(grad(lambda x, y : x**2 - y**2)(1., 1.))

将返回正确结果[2., -2.],梯度下降算法也会正常在最低点附近波动,不再出现异常回升的情况。


内容的提问来源于stack exchange,提问作者Mattéo Menager

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:25:15