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

Jupyter与Python脚本中optimize.minimize拟合结果差异问题求助

解决Scipy Optimize.minimize在Jupyter与脚本中的拟合结果差异问题

看起来你遇到的核心问题是Scipy版本差异导致TNC优化器的行为变化——毕竟你用的Jupyter环境是Scipy 0.19.1,而脚本环境是0.18.0,这两个版本之间scipy.optimize.minimize的TNC实现有不少细节更新,很可能是拟合结果不一致的根源。结合你的代码和现象,我整理了几个针对性的解决方案:

1. 优先升级Scipy版本到0.19.1或更高

这是最直接的解决办法。Scipy 0.18到0.19的更新中,TNC优化器修复了边界约束处理、收敛准则判断的一些bug,同时优化了数值梯度的计算精度。把脚本环境的Scipy升级到和Jupyter一致的版本后,拟合逻辑对齐,结果应该就能匹配了。

2. 提供解析梯度替代数值梯度

TNC默认会用数值梯度来计算参数的变化方向,但不同版本的数值梯度计算步长、精度控制可能有差异,这会直接影响优化路径。手动计算似然函数的解析梯度,传给minimize的jac参数,能让优化过程更稳定,避免版本间的数值计算差异。

比如针对你的ds_lnlike函数,写出对应的梯度函数:

import numpy as np

def ds_jac(par, logm, d, d_err):
    logms, ds1, ds2, a1, a2 = par
    delta_logm = logm - logms
    log10 = np.log(10)
    
    # 计算模型的中间变量
    term1 = 10 ** ((a1 + 1) * delta_logm)
    term2 = 10 ** ((a2 + 1) * delta_logm)
    exp_term = np.exp(10 ** delta_logm)
    model = log10 * (ds1 * term1 + ds2 * term2) / exp_term
    
    # 计算每个参数的偏导数
    d_logms = log10 * (
        (ds1*(a1+1)*term1*log10 + ds2*(a2+1)*term2*log10)/exp_term
        + (ds1*term1 + ds2*term2)/exp_term * 10**delta_logm * log10
    )
    d_ds1 = log10 * term1 / exp_term
    d_ds2 = log10 * term2 / exp_term
    d_a1 = log10 * ds1 * term1 * delta_logm * log10 / exp_term
    d_a2 = log10 * ds2 * term2 * delta_logm * log10 / exp_term
    
    # 转换为负对数似然的梯度(因为nll是-lnlike)
    residual = (d - model) / d_err**2
    grad = -0.5 * np.sum(2 * residual * (-np.array([d_logms, d_ds1, d_ds2, d_a1, d_a2])), axis=1)
    return grad

然后修改minimize的调用,指定jac参数:

nll = lambda *args: -model.ds_lnlike(*args)
# 注意jac要对应负对数似然的梯度,所以取负的ds_jac
result = op.minimize(nll, 
                     [logms[j], ds1[j], ds2[j], a1[j], a2[j]], 
                     args=(x, y, dy), 
                     method='TNC', 
                     bounds=((7,13),(0, 0.1),(0, 0.1), (-2, 4), (-2, -1)), 
                     tol=1.0e-4,
                     jac=lambda par, *args: -model.ds_jac(par, *args))

3. 验证初始值的绝对一致性

虽然你说初始值是固定的,但还是建议在脚本和Jupyter中分别打印初始参数数组,确认[logms[j], ds1[j], ds2[j], a1[j], a2[j]]的数值完全一致——比如脚本中是否因为索引j的取值、变量提前赋值等问题,导致初始值和Jupyter有细微差别(比如浮点数精度的微小差异),这也可能让优化器走向不同的极值点。

4. 调整TNC的优化参数

如果暂时无法升级Scipy,可以尝试调整TNC的额外选项,强制让优化器更彻底地搜索最优解:

result = op.minimize(nll, 
                     [logms[j], ds1[j], ds2[j], a1[j], a2[j]], 
                     args=(x, y, dy), 
                     method='TNC', 
                     bounds=((7,13),(0, 0.1),(0, 0.1), (-2, 4), (-2, -1)), 
                     tol=1.0e-4,
                     options={'maxiter': 1000,  # 增加最大迭代次数
                              'epsilon': 1e-8}) # 缩小数值梯度的步长,提升精度

5. 尝试替代优化方法

可以试试用L-BFGS-B方法替代TNC,看看在两个版本中结果是否一致。如果L-BFGS-B在两个环境中拟合结果相同,那基本可以确定是TNC的版本差异问题,升级Scipy就可以解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:05:51