带回溯线搜索的梯度下降实现故障排查:f(x0)更新后数值无变化,疑与lambda表达式相关
解决回溯线搜索梯度下降中f(x0)不更新的问题
嘿,你的lambda表达式完全没问题!问题出在回溯线搜索函数的逻辑实现上,咱们一步步梳理清楚:
核心错误点
- 循环条件逻辑混乱:你把
count < 50和Armijo条件用or连在一起,这会导致循环在计数没到50时一直跑,完全违背了回溯线搜索“找到满足Armijo条件的步长就停止”的初衷。 - 提前更新x0:回溯线搜索的目的是先找到合适的步长
t,而不是在试步长的过程中就修改x0——你应该先拿候选点测试t,找到合格的t后再更新参数。 - 全局变量干扰:你在函数外定义了
d和grad,在函数内直接修改全局变量,这很容易导致逻辑混乱,应该在每次回溯时基于当前点重新计算梯度和搜索方向。 - Armijo条件写反:原代码里用了
>来判断,正确的Armijo条件是“候选点的函数值不超过预期的下降下界”,应该用<=来触发终止。
修复后的完整代码
import numpy as np import math alpha = 0.1 beta = 0.6 # 目标函数 f = lambda x: math.exp(x[0] + 3*x[1] - 0.1) + math.exp(x[0] - 3*x[1] -0.1) + math.exp(-x[0] - 0.1) # 偏导数 dfx1 = lambda x: math.exp(x[0] + 3*x[1] - 0.1) + math.exp(x[0] - 3*x[1] -0.1) - math.exp(-x[0] - 0.1) dfx2 = lambda x: 3*math.exp(x[0] + 3*x[1] - 0.1) - 3*math.exp(x[0] - 3*x[1] -0.1) def backtrack(x0, f, dfx1, dfx2, t_initial, alpha, beta, max_iter=50): # 先计算当前点的梯度和搜索方向(回溯过程中固定这个梯度,只找合适的t) grad = np.array([dfx1(x0), dfx2(x0)]) d = -grad t = t_initial count = 0 # 正确的循环逻辑:Armijo条件不满足,且没到最大迭代次数时继续缩小步长 while count < max_iter: x_candidate = x0 + t * d # 检查Armijo条件:候选点函数值 <= 当前点函数值 + alpha*t*(搜索方向·梯度) if f(x_candidate) <= f(x0) + alpha * t * np.dot(d, grad): break # 不满足就缩小步长 t *= beta count += 1 # 找到合适的t后,再更新x0 x_new = x0 + t * d return t, x_new # 初始化参数 x0 = np.array([1.0, 1.0]) t_initial = 1.0 # 执行回溯线搜索 final_t, x_final = backtrack(x0, f, dfx1, dfx2, t_initial, alpha, beta) print("最终步长:", final_t) print("最终x值:", x_final) print("初始f(x0):", f(x0)) print("最终f(x_final):", f(x_final))
关键修复说明
- 修正循环条件:现在只有当Armijo条件不满足,且迭代次数没到上限时,才会继续缩小步长,确保找到符合要求的
t。 - 分离步长测试与参数更新:用
x_candidate测试不同的t,找到合格的步长后再更新x0,避免提前修改参数导致的逻辑混乱。 - 函数内计算梯度:每次回溯时基于当前传入的
x0重新计算梯度和搜索方向,彻底避免全局变量的干扰。 - 修正Armijo条件判断:把原有的
>改成<=,符合回溯线搜索的终止逻辑。
现在运行这段代码,你会看到f(x)的数值明显下降,说明梯度下降和回溯线搜索已经正常工作了!
内容的提问来源于stack exchange,提问作者DockingBlade
相关产品推荐
相关产品推荐

