首页 > 解决方案 > scipy.optimize.minimize 如何对损失函数求导?

问题描述

我试图弄清楚 scipy.optimize.minimize 在机器学习中是如何工作的。到目前为止,我知道您向它传递了一个损失函数,以便它可以找到给您带来最低损失的参数值。但据我了解,它首先必须找到损失函数的梯度/Hessian,然后才能找到最小值。它是如何做到的?它是如何知道如何获取包含其他函数调用和算法的python函数的导数?它如何将其推导出为一个数学函数,它可以对其进行导数?在我的例子中,我传递给最小化的损失函数执行以下操作:首先它解决了一个流行病学模型 (SEIRD),该模型旨在预测 COVID-19 的确诊病例和死亡人数。然后它将模型结果与实际数据进行比较,并找到它返回的 MSLE。

def model_decay(params, data, population, return_solution=False, full_validation=True, forecast_days=0):
R_0, theta, k, L, R_t, D_rec, D_inc = params # R_0, fatality rate, k form, L shape, R end
N = population # Population of each country

n_infected = data['ConfirmedCases'].iloc[0] 
n_dead = data['Fatalities'].iloc[0]
max_days = len(data) + forecast_days 
rho = 1.0 / D_rec
alpha = 1.0 / D_inc    
beta = R_0 * rho  

y0 = N - n_infected, 0, n_infected, 0 ,0  

def beta(t):
    return ((R_0-R_t) / (1 + (t/L)**k)+R_t) * rho

t= np.arange(max_days)

# Solve the SEIR differential equation.
sol = solve_ivp(seir_d, [0, max_days],y0,  args=(N, beta, rho, alpha, theta),t_eval=t)
sus, exp, inf, rec, dead = sol.y    

#model_decay.counter +=1
#print(model_decay.counter)

# Predict confirmedcases
y_pred_cases = np.clip((inf + rec+dead),0,np.inf) 
y_true_cases = data['ConfirmedCases'].values

# Predict fatalities
y_pred_dead = np.clip((dead),0,np.inf) 
y_true_dead = data['Fatalities'].values    

#Thanks to anjum-48 for the following lines of code in this function.

optim_days = min(20, len(data))  # Days to optimise for finds the lowest num. 

weights = 1 / np.arange(1, optim_days+1)[::-1]  # Recent data is more heavily weighted
# using mean squre log error to evaluate
msle_conf = mean_squared_log_error(y_true_cases[-optim_days:], y_pred_cases[-optim_days:],weights)
msle_dead = mean_squared_log_error(y_true_dead[-optim_days:], y_pred_dead[-optim_days:],weights)
if full_validation == True :
    msle = np.mean([msle_conf,msle_dead])
else : 
    msle = msle_conf

if return_solution:
    return msle, sol
else:
    return msle

最小化调用如下所示:

model_decay_res = minimize(model_decay, [1.8, 0.04, 2, 20, 1 ,15, 4.9], 
                bounds=((0, 6.49), (0.01, 0.15), (0, 5), (0, 200),(0,6.49),(3.48,18),(4.9,5.9)),
                args=(train_data, population, False,full_validation),
                method='L-BFGS-B')

它最终给了我一个非常低的 MSLE,所以它工作得很好,我只是不明白到底是怎么回事。

标签: machine-learningoptimizationscipyloss-functionscipy-optimize-minimize

解决方案


但据我了解,它首先必须找到损失函数的梯度/Hessian,然后才能找到最小值。它是如何做到的?

这取决于您为参数提供的内容以及您在 python 环境中拥有的 SciPy 版本。最后我检查了一些支持渐变的方法。此处 1.4.1 版本的文档: https ://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html

节目

jac{callable, ‘2-point’, ‘3-point’, ‘cs’, bool}, optional

并描述了哪些最小化器支持哪些。您可以使用有限差分方案“2 点”,这是许多人的默认设置。

Acallable表示您提供了一个已__call__实现属性的函数或对象(独立函数默认具有此属性,对象没有)。如果你知道你已经分析计算并在 python 中实现的雅可比或梯度 b/c(或通过低级可调用的 C/C++:https ://docs.scipy.org/doc/scipy-),通常会使用它1.4.0/reference/generated/scipy.LowLevelCallable.html?highlight=lowlevelcallable#scipy.LowLevelCallable )

这个cs选项非常酷,我在第一次开始使用 SciPy 时就知道了这个选项。基本上,您在目标函数中的所有操作都传递了具有非常小的复杂值(例如 0.0001)的复杂参数,然后取结果的复杂部分可以很好地估计梯度(优于有限差分)。

布尔值更多的是关于是否表示为稀疏或密集,并且并非在所有优化程序例程中都使用。

我应该澄清的一件事是minimize例程只是转发到实际处理优化的相关优化器方法(例如'trust-constr'、'slsqp'等)。尤其是黑森州。

希望这可以帮助您了解minimize例行程序的“幕后”发生了什么。

它是如何知道如何获取包含其他函数调用和算法的python函数的导数?

在您提供的情况下,我认为它只是调用该函数并没有什么特别之处。

此外,作为旁注(不是您的两个问题中的任何一个),如果您想跟踪优化器的进度,您可以通过disp=True,或者disp=1随着优化器的进展,它应该向您显示一些高级跟踪输出。


推荐阅读