梯度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}")
你可以把自己的代码和这段对比,重点查:
- 梯度计算是否正确,尤其是
2*f1*∇f1 + 2*f2*∇f2这部分 - Armijo条件的不等式方向和公式是否正确
- 每轮迭代是否重置了步长
t=1 - x的更新是否是
x = x + t*(-grad)(负梯度方向)
内容的提问来源于stack exchange,提问作者Chen
相关产品推荐
相关产品推荐

