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

使用scipy.optimize.fmin_bfgs最小化多元函数不收敛报错如何解决

问题背景

尝试最小化如下多元函数:
函数公式
其中α_i为可正可负的常数,n为5~10之间的随机整数,要求使用scipy.optimize.fmin_bfgs实现,满足以下约束:

  • 随机起点所有值均保留4位小数,格式为m.dddd
  • 迭代至连续迭代值的L∞范数绝对差小于2%时停止
  • 系数α_i保留4位小数,至少40%为负、至少25%为正

错误根因

  1. 目标函数无下界,不存在极小值:你定义的目标函数为sum(α_i * x_i²),由于存在负的α_i,对应维度的x_i绝对值越大,函数值越小,会趋向负无穷,无约束的BFGS算法不可能找到收敛点,这是精度损失报错的核心原因。
  2. 停止条件逻辑错误:要求的停止条件是连续两次迭代值的L∞范数差小于2%,但你现有回调仅判断函数值是否小于0.02,既没有保存上一轮迭代值,也没有计算范数差,完全不符合要求。
  3. 维度不匹配:生成的初始值x0是(n,1)的二维数组,fmin_bfgs要求输入一维数组,会导致迭代计算异常。
  4. α生成规则不满足硬要求:现有加权采样逻辑无法100%保证生成的α序列满足至少40%负、25%正的要求,存在概率性不符合规则的情况。
  5. 返回值解包错误:fmin_bfgs共返回7个值,你仅用3个变量接收会触发解包报错。

修正代码

要实现收敛需要先给x增加取值范围约束,这里我们补充x_i∈[-10,10]的约束,改用支持约束的L-BFGS-B算法实现,同时修正所有逻辑问题:

import numpy as np
from scipy.optimize import fmin_l_bfgs_b

# 1. 随机生成n:5~10之间的整数
n = np.random.randint(5, 11)

# 2. 生成满足要求的α:至少40%负,至少25%正,保留4位小数
neg_cnt = int(np.ceil(n * 0.4))  # 负α最少数量
pos_cnt = int(np.ceil(n * 0.25))  # 正α最少数量
remain_cnt = n - neg_cnt - pos_cnt  # 剩余随机符号的α数量

alpha = []
# 先加负α
alpha.extend(np.round(np.random.uniform(-1, -0.01, size=neg_cnt), 4).tolist())
# 再加正α
alpha.extend(np.round(np.random.uniform(0.01, 1, size=pos_cnt), 4).tolist())
# 剩余的随机正负
if remain_cnt > 0:
    remain_alpha = np.round(np.random.uniform(-1, 1, size=remain_cnt), 4)
    # 避免生成0
    remain_alpha[remain_alpha == 0] = np.random.choice([-0.01, 0.01])
    alpha.extend(remain_alpha.tolist())
# 打乱顺序
np.random.shuffle(alpha)
alpha = np.array(alpha)
print("n值:", n)
print("α序列:", alpha)

# 3. 生成初始点:保留4位小数,一维数组
x0 = np.round(np.random.uniform(-5, 5, size=n), 4)
print("初始点x0:", x0)

# 4. 定义目标函数
def func(x):
    return np.sum(alpha * (x ** 2))

# 5. 定义满足要求的回调函数:判断连续迭代的L∞范数差小于2%停止
class StopCallback:
    def __init__(self, thresh=0.02):
        self.prev_x = None
        self.thresh = thresh
        self.opt_x = None
    
    def __call__(self, xk):
        if self.prev_x is not None:
            l_inf_diff = np.max(np.abs(xk - self.prev_x))
            if l_inf_diff < self.thresh:
                self.opt_x = xk
                # 抛出异常停止迭代
                raise StopIteration
        self.prev_x = xk.copy()

cb = StopCallback(thresh=0.02)

# 6. 带约束优化:x的范围限制在[-10,10]
bounds = [(-10, 10) for _ in range(n)]
try:
    x_opt, f_opt, info = fmin_l_bfgs_b(func, x0, bounds=bounds, callback=cb)
except StopIteration:
    x_opt = cb.opt_x
    f_opt = func(x_opt)

print("最优解x:", np.round(x_opt, 4))
print("最优函数值:", f_opt)

补充说明

如果你必须使用无约束的fmin_bfgs,需要确认目标函数是否书写错误,比如是否应为sum(α_i² * x_i²)、sum(|α_i| * x_i²)这类所有系数为正的形式,只有当目标函数为凸函数且存在下界时,无约束BFGS才能正常收敛。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 05:06:00