使用 optimize.fmin_l_bfgs_b 的错误收敛
Wrong convergence using optimize.fmin_l_bfgs_b
我正在使用 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 函数 returns 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函数中得到不同的值(这可能是它没有优化的原因)。第二个变量不存在这个问题。这是正常行为吗?是否有任何选项可以使算法使用更高的步骤?
根据 Fortran 函数的具体作用,有多种可能的修复方法。我从您的呼叫签名中看到您正在让最小化器以数字方式估计梯度。可以直接计算梯度吗?如果是这样,请尝试编写一个执行此操作的函数,将其作为 fprime
传递,并将 approx_grad
设置为 False
。适当的梯度函数很有可能会产生更好的结果。
另一种可能性是尝试 epsilon
的不同值,它控制数值梯度近似的步长。但在我看来 fmin_l_bfgs_b
只接受 epsilon
的单个浮点值,这意味着你不能对不同的维度采用不同的步长。那可能不是问题;如果较大的 epsilon 可以为第一维提供更好的梯度估计,并且不会影响第二维的估计,那么您的问题可能会得到解决。您也可以尝试传递一个数组,每个维度都有一个 epsilon 值——它 可能 有效。最后,您可能可以做一些有点笨拙的事情,比如优化一个维度,然后调整 epsilon,然后优化另一个维度。如果我有时间,我稍后会做一些实验。
最后一种方法可能是使用不同的最小化函数。例如,您是否尝试过 fmin_cg
?我发现它可以很好地处理我提出的大部分问题。但我以前从未在没有硬编码渐变函数的情况下使用过它。您也可以在 this list 上尝试其他函数——尤其是像 Powell
和 Anneal
这样的函数,它们被设计为在不使用任何梯度信息的情况下工作。
这些方法中哪一种有效(如果有的话)在很大程度上取决于您要最小化的函数的具体性质。您可能需要做一些实验!
我正在使用 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 函数 returns 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函数中得到不同的值(这可能是它没有优化的原因)。第二个变量不存在这个问题。这是正常行为吗?是否有任何选项可以使算法使用更高的步骤?
根据 Fortran 函数的具体作用,有多种可能的修复方法。我从您的呼叫签名中看到您正在让最小化器以数字方式估计梯度。可以直接计算梯度吗?如果是这样,请尝试编写一个执行此操作的函数,将其作为 fprime
传递,并将 approx_grad
设置为 False
。适当的梯度函数很有可能会产生更好的结果。
另一种可能性是尝试 epsilon
的不同值,它控制数值梯度近似的步长。但在我看来 fmin_l_bfgs_b
只接受 epsilon
的单个浮点值,这意味着你不能对不同的维度采用不同的步长。那可能不是问题;如果较大的 epsilon 可以为第一维提供更好的梯度估计,并且不会影响第二维的估计,那么您的问题可能会得到解决。您也可以尝试传递一个数组,每个维度都有一个 epsilon 值——它 可能 有效。最后,您可能可以做一些有点笨拙的事情,比如优化一个维度,然后调整 epsilon,然后优化另一个维度。如果我有时间,我稍后会做一些实验。
最后一种方法可能是使用不同的最小化函数。例如,您是否尝试过 fmin_cg
?我发现它可以很好地处理我提出的大部分问题。但我以前从未在没有硬编码渐变函数的情况下使用过它。您也可以在 this list 上尝试其他函数——尤其是像 Powell
和 Anneal
这样的函数,它们被设计为在不使用任何梯度信息的情况下工作。
这些方法中哪一种有效(如果有的话)在很大程度上取决于您要最小化的函数的具体性质。您可能需要做一些实验!