使用scipy.optimize.minimize在每次迭代时对Nelder-Mead单纯形进行优化

xzabzqsa  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(136)

一些背景:
我正在使用scipy.optimize.minimize中的Nelder-Mead单纯形优化算法对深度学习模型进行一些超参数优化。对于输入x和函数fminimize试图通过改变x来优化函数值f(x)。在我的例子中,x是模型f的超参数,它对一组恒定的训练样本进行预测。
由于f非常大,并且有许多训练示例,当对所有训练示例进行预测的并行问题分布在20个rtx-2080 GPU中时,每次调用f(x)大约需要10分钟。每一步都很昂贵。
由于某种原因(崩溃,GPU上的时间耗尽),脚本将在优化过程中停止。因此,我希望保存优化的状态,这样我就可以从它停止的地方继续它。我能够在每个NM期间保存超参数值
x
。一步,但这只是到此为止。即使你已经恢复了x(让我们称恢复的版本为x '),Nelder-Mead单纯形也会丢失。如果在x '处重新开始优化fminimize必须通过计算f(x' + p)*N次来重建单纯形,其中p是对x的一个维度的扰动,N是dim(x)或dim(x)+ 1。在我的例子中,x是高维的(>20),所以仅仅恢复单纯形就需要大约3个小时。
问:
我需要一种方法来访问单工在每一步的情况下崩溃。其他人建议使用回调来解决在使用scipy.optimize.minimize(不一定是Nelder-Mead)优化期间恢复参数和函数值的问题。然而,在minimize的文档中,它指出唯一可以通过回调返回当前参数值(x)* 和 * OptimizeResult对象(在N.M.情况下可以包含单纯形的对象)的minimize版本是“trust_constr”方法。换句话说,我很确定在“nelder_mead”版本中使用回调只能让你访问x
我们提出的最佳解决方案是在minimize源代码中编辑_minimize_neldermead函数,以便在每一步之后保存单纯形值。有没有更优雅的方式来实现这一点?难道minimize已经有这个能力了,只是我们找不到它?

dpiehjr4

dpiehjr41#

我也遇到了同样的问题。对我来说有效的解决方案是以正常的方式定义函数f(x),这样minimize()就可以用输入数组x调用它。但是你也可以提供额外的参数,比如一个列表或数组,你可以用它来存储你的单纯形,它们的值,以及你的函数在此过程中可能计算的任何其他沿着的东西。所以你的函数看起来像这样:

def f(x, simplex_list):
    # do math here to calculate your value. I'll use sum().
    my_val = np.sum(x)

    # Here's the magic bit. Add whatever else you want into the dict
    my_simplex = {'x': x, 'f_x': my_val}
    simplex_list.append(my_simplex)

    return my_val

当你调用scipy.opt.minimize时,你的调用现在看起来像这样:

# initialize your simplex record stash 
simplex_list = []

# do whatever steps to figure out your first guess x0, bounds
opt_result = opt.minimize(f, x0=b, bounds=bounds, args=(simplex_list),
                          method='Nelder-Mead', 
                          options={'xatol': 1, 'fatol': 2, 'maxiter': 40}
                          )

# Now dump out the contents of simplex_list.

应该根据您的问题适当地设置各种选项值。通过使用args参数,minimize知道传入额外的参数simplex_list,并且您将其用作记录保存机制。
请注意,如果您稍后向f()添加其他参数,例如要写入调试信息的目录路径或f()可能需要计算的其他变量,则还必须以正确的顺序将它们添加到args参数中。如果你不这样做,minimize()将悄悄地对你失败。我对自己做过很多次...:)

相关问题