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

梯度Armijo法求解Freudenstein-Roth测试函数的代码问题求助

排查Armijo回溯梯度法求解Freudenstein and Roth函数的问题

先给你梳理几个最可能导致“无论初始点结果都不变”的核心问题,再附一段可运行的参考代码:

常见错误点

  • 梯度计算完全错误:目标函数是f1² + f2²,梯度得用链式法则算:∇f = 2*f1*∇f1 + 2*f2*∇f2。很多人会直接算∇f1 + ∇f2,或者漏掉2*f1/2*f2的系数,导致搜索方向完全不对,迭代根本不收敛。
  • Armijo条件写反/逻辑错误:Armijo的核心是f(x_new) ≤ f(x) + α*t*(∇f(x)·d),其中d是负梯度方向(d = -∇f(x))。如果把不等式方向搞反,或者忘了α是乘在t*(梯度点乘方向)上,会导致回溯直接跳过所有步长更新,始终用初始步长甚至直接不更新x。
  • 迭代时没重置初始步长:每轮迭代开始前要把t重置为1,如果一直用上次回溯后的小步长,可能导致步长太小,x几乎不动。
  • 终止条件设置离谱:比如把梯度范数阈值设成1e-1这么大,或者迭代次数设为0,直接返回初始点。

参考可运行代码

import numpy as np

# 定义Freudenstein and Roth测试函数
def freudenstein_roth(x):
    x1, x2 = x
    f1 = -13 + x1 + ((5 - x2)*x2 - 2)*x2
    f2 = -29 + x1 + ((x2 + 1)*x2 - 14)*x2
    return f1**2 + f2**2

# 计算梯度
def gradient(x):
    x1, x2 = x
    f1 = -13 + x1 + ((5 - x2)*x2 - 2)*x2
    f2 = -29 + x1 + ((x2 + 1)*x2 - 14)*x2
    # 计算f1和f2的偏导
    df1_dx1 = 1
    df1_dx2 = (5 - 2*x2)*x2 + ((5 - x2)*x2 - 2)
    df2_dx1 = 1
    df2_dx2 = (2*x2 +1)*x2 + ((x2 +1)*x2 -14)
    # 目标函数的梯度
    grad_x1 = 2*f1*df1_dx1 + 2*f2*df2_dx1
    grad_x2 = 2*f1*df1_dx2 + 2*f2*df2_dx2
    return np.array([grad_x1, grad_x2])

# Armijo回溯线搜索
def armijo_backtracking(x, grad, alpha=0.5, beta=0.5, t_init=1):
    t = t_init
    f_x = freudenstein_roth(x)
    # 搜索方向是负梯度
    d = -grad
    # Armijo条件:f(x + t*d) ≤ f(x) + alpha * t * (grad · d)
    while freudenstein_roth(x + t*d) > f_x + alpha * t * np.dot(grad, d):
        t *= beta
    return t

# 梯度法主循环
def gradient_descent(x0, max_iter=1000, tol=1e-6):
    x = np.array(x0, dtype=np.float64)
    for i in range(max_iter):
        grad = gradient(x)
        # 梯度范数小于阈值则终止
        if np.linalg.norm(grad) < tol:
            print(f"迭代{i+1}次收敛")
            return x
        # Armijo找步长
        t = armijo_backtracking(x, grad)
        # 更新x
        x = x + t*(-grad)
    print("达到最大迭代次数未收敛")
    return x

# 测试不同初始点
if __name__ == "__main__":
    # 接近驻点的初始点(已知驻点大概是(4,2))
    x0_1 = [3.9, 1.9]
    res1 = gradient_descent(x0_1)
    print(f"初始点{x0_1}的结果:{res1},函数值:{freudenstein_roth(res1):.6f}")
    
    # 随机初始点
    x0_2 = [0, 0]
    res2 = gradient_descent(x0_2)
    print(f"初始点{x0_2}的结果:{res2},函数值:{freudenstein_roth(res2):.6f}")

你可以把自己的代码和这段对比,重点查:

  1. 梯度计算是否正确,尤其是2*f1*∇f1 + 2*f2*∇f2这部分
  2. Armijo条件的不等式方向和公式是否正确
  3. 每轮迭代是否重置了步长t=1
  4. x的更新是否是x = x + t*(-grad)(负梯度方向)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 10:50:18