优化具有多个数据集的数值模型(scipy.minimize / scipy.optimise,pymoo 或 ??)

Optimisation of a numerical model with several data sets (scipy.minimize / scipy.optimise, pymoo or ??)

所以我有一个问题,此时我有点迷茫。所以任何意见都将不胜感激,因为我现在真的很挣扎!

我有一个模型,我想 check/optimise 使用我得到的一些实验数据。

一般来说,我的模型有两个输入(我们称之为:时间和温度)并且有 8 个变量 (x0-x7)。该模型生成两个输出(out1 和 out2)。

我的每组实验数据都为我提供了 4 组可用于优化的信息:2 个输入(时间和温度)和 2 个实验结果(result1 和 result2)。

最终我想最小化 result1 & out1 和 result2 & out2 之间的差异。所以基本上用几组数据最小化两个残差,这些数据受 8 个参数的影响,它们都有共同点 (x0-x7)。

我对参数 x0-x7 有一些限制,这可以提供帮助,但除此之外没有真正的限制。

到目前为止,我已经尝试使用 scipy.minimize 对我的实验结果数据集进行迭代,如下所示(非常示意性):

import numpy as np
from scipy.optimize import minimize
    
Experiment=[['Set 1','Set 2',
             'Set 3','Set 4'],
                   [Out 1-1,Out 1-2,
                    Out 1-3,Out 1-4],
                   [Out 2-1,Out 2-2,
                    Out 2-3,Out 2-4],
            ]
global curr_case
curr_case=0 #just for debugging in the first place
    
def objective_fcn(x):
        
    SetFitParameters(x) #x0-x7
        
    #---------probably totally dumb: iteration-----------
    global curr_case    #number of experimental set
        curr_case=curr_case+1
    if curr_case==len(Experiment):
        curr_case=0
    #----------------------------------------------------
        
    getTemp(curr_case) # function that gets time and temperature from experimental data as two arrays - time and temperature
        
    RefVariables(x) #sets some global variabales needed for ModelCal using x0-x7
        
    ModelCal(time,Temperature)  #gives Out1 and Out2
        
    f1 = abs(Out1[Upper_index-1]-Experiment[1][curr_case]) #compares Out1 with result1 (from experimental data)
    f2 = abs(Out2[Upper_index-1]-Experiment[2][curr_case]) #compares Out2 with result2 (from experimental data)
        
    # some weighting factors for the future - maybe?
    A=1
    B=1
       
    return A*f1+B*f2
       
bounds_x1=(1450,1700) #upper and lower bonds of x0
bounds_x2=(0.1,1)
bounds_x3=(1450,1700)
bounds_x4=(0.1,7)
bounds_x5=(1450,1700)
bounds_x6=(0.1,7)
bounds_x7=(1450,1700)
bounds_x8=(0.1,7)
    
bounds=[bounds_x1,bounds_x2,bounds_x3,bounds_x4,bounds_x5,bounds_x6,bounds_x7,bounds_x8]
    
x0=[1663,0.156,1523,6.37,1663,4.38,1523,2.2] #some initial guesses
    
result=minimize(objective_fcn, x0,bounds=bounds)

这显然行不通,因为我只是遍历了不同的案例。在 Whosebug 上搜索已经产生了一些结果,但是,它们似乎都优化了一个给定的函数,而我没有!

第一个问题是:您会推荐哪种优化?这甚至接近有用的东西吗?

第二个问题:如何在优化时考虑多个实验数据集?我获取输入的方法似乎相当粗糙。我还尝试用已经实现为数组元素的数据创建两个列表,但也无济于事。

最后:任何对优化有一点了解的人都可以看出,我在这个领域还很新手 - 所以我提前道歉,但如果有人能指出我正确的方向或可以提供帮助 - 将不胜感激!

我已经找到的来源: -Fitting multiple data sets using scipy.optimize with the same parameters -

共享对象函数的基本思想很好。我并没有真正详细介绍 OP 尝试,因为这可能会产生误导。该过程将定义可用于最小二乘拟合的适当残差函数。在 Python 中有几种可能性可以做到这一点。我将展示 scipy.optimize.leastsq 和密切相关的 scipy.optimize.least_squares.

import numpy as np
from scipy.optimize import least_squares ## allows bounds and has given loss functions but provides only Jacobian
from scipy.optimize import leastsq ## provides scaled covariance matrix


"""
some arbitrary test function taking two inputs and providing
two correlated outputs with shared parameters - only three for testing.
"""
def test_function( time, temp, x0, x1, x2 ):
    s = np.sqrt( time/x0 ) * np.log( ( temp - x1 ) / x2 )
    t = np.exp( - time/x0 ) * np.sqrt( (time/x0)**2 + ( ( temp - x1 ) / x2 )**2 )
    return s, t

### make some data with noise
indata = list()
for _ in range( 60 ):
    a = 50 * np.random.random()
    b = 10 + 25 * np.random.random()
    indata.append( [a,b] )

outdata = list()
for a,b in indata:
    s,t = test_function( a, b, 3.78, 5.33, 12.88 )
    noise1 = np.random.normal( scale=0.01 )
    noise2 = np.random.normal( scale=0.01 )
    outdata.append( [s + noise1, t + noise2 ] )

indata = np.array( indata)
outdata = np.array( outdata)

#########################################################################
### define the residuals function for fitting This is the important part!
#########################################################################

def residuals( params, xdata, ydata, weightA=1, weightB=1 ):
    x0, x1, x2 = params
    diff = list()
    for ab, st in zip( indata, outdata ):
        a, b = ab
        s, t = st
        sf, tf = test_function( a, b, x0,x1, x2 )
        diff.append( weightA * ( s - sf ) )
        diff.append( weightB * ( t - tf ) )
    return diff

### Fit
solx, cov, info, msg, ier = leastsq( 
    residuals, [ 3.8, 5.0, 12.5],
    args=( indata, outdata ), full_output=True
)
print solx
print cov
sol = least_squares( residuals, [ 3.8, 5.0, 12.5 ], args=( indata, outdata ))
print sol.x

根据 OP 的需要修改它应该很容易。