函数返回标量仍触发ValueError:目标函数需返回标量问题排查
问题排查:scipy.optimize.minimize(BFGS)触发ValueError:目标函数需返回标量
使用scipy.optimize.minimize的BFGS方法优化时,持续触发如下错误:
ValueError: The user-provided objective function must return a scalar value
但确认自定义目标函数my_func_v每次返回的都是标量或SymPy常量,附上代码寻求原因排查:
from sympy import Symbol from sympy.stats import Normal, density, sample_iter from scipy.optimize import minimize from sympy import Sum, binomial, exp, simplify def my_func_v(args): print(args) N = Normal("N", args[0], args[1]) y = Symbol("y", real = True) samples = list(sample_iter(N, numsamples=200)) sampleSum = sum(samples) print("Gotten samples") func = simplify((Sum(sum([simplify(binomial(20,y)*(1/(1+exp(-sample)))**y*(exp(-sample)/(1+exp(-sample)))**(20-y)*density(N)(sample))/sampleSum for sample in samples]), (y, 0, 10)).doit() - 0.8)**2) print(f"Done with func with end value: {func}") return func print("Now optimizing") results = minimize(my_func_v, [1,1], method='BFGS', options={"disp": True, "return_all": True})
错误原因
- 目标函数返回的是SymPy符号表达式对象,而非scipy优化器要求的Python原生数值标量(如
float类型)。即使SymPy常量看起来是数值,它本质是符号对象,scipy无法将其识别为可用于优化的数值标量。 - 代码中
func经过simplify处理后仍是SymPy的符号类型(比如Float),不符合scipy对目标函数返回值的类型要求。
解决方法
转换返回值类型:在返回结果前,将SymPy对象转换为Python原生数值,修改目标函数的return语句:
return float(func)或者用
func.evalf()先求值再转float,效果一致。额外优化建议:
- 当前代码用SymPy做采样+符号求和,计算效率极低,且BFGS算法依赖目标函数的梯度(当前实现无法提供有效解析梯度,自动差分也会因为符号运算变得异常缓慢)。
- 建议改用纯数值计算替代SymPy符号运算,或者切换到不需要梯度的优化方法(如
Nelder-Mead);如果坚持用BFGS,需要手动实现目标函数的梯度计算。
内容的提问来源于stack exchange,提问作者Striking eagle
相关产品推荐
相关产品推荐

