我使用optimize.fmin_l_bfgs_b来优化用Fortran编写的函数。代码类似于:
def f(m, *args):
# Optmization values
Opt1 = m[0]
Opt2 = m[1]
# Rest of arguments:
Var1 = args[0]
Var2 = args[1]
# Fortran Function
r1, r2 = FortranFunction(Opt1, Opt2)
# Evaluation of the result
evaluation = sqrt((r1-Var1)**2 + (r2-Var2)**2)
return evaluation
initial_values = numpy.array([1.09, 0.0025])
mybounds = [(1, 1.2), (0, 0.1)]
m = optimize.fmin_l_bfgs_b(f, x0 = initial_values, args=(x, file_vars), approx_grad = True, bounds = mybounds)
fortran函数返回2个值,用于使用两个所需结果(Var1和Var2)评估函数。我遇到的问题是算法没有优化第一个变量。如果我在每次迭代中打印它,这就是我获得的:
1.09
1.09
1.09000001
1.09
1.09
1.09
1.09000001
1.09
1.09
1.09
1.09000001
1.09
1.09
1.09
1.09000001
...
似乎只是通过1.09和1.09000001之间的差异来评估函数,这个值太小而无法在Fortran函数中获得不同的值(这可能是它未被优化的原因)。第二个变量不会出现这个问题。这是正常行为吗?有没有选项让算法使用更高的步骤?
答案 0 :(得分:1)
有很多可能的修复方法,具体取决于Fortran功能的确切功能。我从你的电话签名中看到你正在使用最小化器以数字方式估计梯度。你能直接计算的渐变吗?如果是这样,请尝试编写执行此操作的函数,将其作为fprime
传递,并将approx_grad
设置为False
。适当的梯度函数很有可能提供更好的结果。
另一种可能性是尝试epsilon
的不同值,它控制数值梯度近似的步长。但我认为fmin_l_bfgs_b
只接受epsilon
的单个浮点值,这意味着您不能为不同的维度采用不同的步长。这可能不是问题;如果较大的epsilon为第一维提供了更好的梯度估计,并且没有抛弃第二维的估计值,那么您的问题可能会得到修复。您也可以尝试传递一个数组,每个维度都有一个epsilon值 - 可能可以工作。最后,您可以做一些有点笨重的事情,比如优化一个维度,然后调整epsilon,然后优化其他维度。如果我有时间,我会稍后做一些实验。
最后一种方法可能是使用不同的最小化函数。你试过fmin_cg
吗?我发现它处理了我投入的大部分问题。但我以前从未使用它而没有硬编码的渐变功能。您也可以尝试this list上的其他功能 - 尤其是Powell
和Anneal
之类的功能,这些功能可以在不使用任何渐变信息的情况下工作。
这些方法中的哪些方法(如果有的话)将在很大程度上取决于您尝试最小化的函数的特定性质。你可能需要做一些实验!