当求解器可能成功求解时
终点等于初始点
初始点可能是一个局部最小值或解,因为一阶最优性测度接近于 0。您可能对此结果不满意,因为求解器并未改进您的初始点。
如果您不确定初始点是否确实为局部最小值,请尝试:
从不同点开始 - 请参阅更改初始点。
检查您的目标和约束是否正确定义(例如,它们在某些点处是否返回了正确的值?)- 请参阅检查您的目标函数和约束函数。检查以确保不可行点不会导致函数中出现错误;请参阅迭代可能违反约束。
更改容差,例如
OptimalityTolerance、ConstraintTolerance和StepTolerance- 请参阅使用适当的容差。缩放您的问题,使每个坐标具有大致相同的影响 - 请参阅重新缩放问题。
提供梯度和黑塞矩阵信息 - 请参阅提供解析梯度或雅可比矩阵和提供黑塞矩阵。
可能是局部最小值
求解器可能已达到局部最小值,但无法确定,因为一阶最优性测度不小于 OptimalityTolerance 容差。(要了解有关一阶最优性测度的更多信息,请参阅一阶最优性测度。)要查看报告的解是否可靠,请考虑以下建议。
| 1.非平滑函数 |
| 2.以终点作为起点重新执行优化 |
| 3.尝试不同算法 |
| 4.更改容差 |
| 5.重新缩放问题 |
| 6.检查附近的点 |
| 7.更改有限差分选项 |
| 8.提供解析梯度或雅可比矩阵 |
| 9.提供黑塞矩阵 |
1.非平滑函数
如果您尝试最小化非平滑函数,或具有非平滑约束,“可能是局部最小值”也许是最好的退出消息。这是因为,一阶最优性条件不适用于非平滑点。
为了让自己确信该解是充分的,请尝试检查附近的点。
2.以终点作为起点重新执行优化
如果在终点处重新开始优化,则可以生成具有更好的一阶最优性测度的解。更好(较低)的一阶最优性测度让您更有理由相信解是可靠的。
例如,假设有以下最小化问题,摘自示例使用符号数学和 Optimization Toolbox 求解器:
options = optimoptions('fminunc','Algorithm','quasi-newton');
funh = @(x)log(1 + (x(1) - 4/3)^2 + 3*(x(2) - (x(1)^3 - x(1)))^2);
[xfinal fval exitflag] = fminunc(funh,[-1;2],options)
Local minimum possible.
fminunc stopped because it cannot decrease the
objective function along the current search direction.
xfinal =
1.3333
1.0370
fval =
8.5265e-014
exitflag =
5退出标志值 5 表示一阶最优性测度大于函数容差。从 xfinal 开始再次运行最小化:
[xfinal2 fval2 exitflag2] = fminunc(funh,xfinal,options)
Local minimum found.
Optimization completed because the size of the gradient is
less than the default value of the function tolerance.
xfinal2 =
1.3333
1.0370
fval2 =
6.5281e-014
exitflag2 =
1局部最小值是“找到”,而不是“可能”,exitflag 为 1 而不是 5。这两个解实际上相同。然而,第二次运行有更令人满意的退出消息,因为一阶最优性测度相当低,是 7.5996e-007,而不是 3.9674e-006。
3.尝试不同算法
许多求解器都允许您选择算法。不同的算法可能会导致使用不同的停止条件。
例如,以终点作为起点重新执行优化会返回第一次运行时的 exitflag 5。这次运行使用 quasi-newton 算法。
信赖域算法需要用户提供的梯度。betopt.m 包含目标函数和梯度的计算:
function [f gradf] = betopt(x) g = 1 + (x(1)-4/3)^2 + 3*(x(2) - (x(1)^3-x(1)))^2; f = log(g); gradf(1) = 2*(x(1)-4/3) + 6*(x(2) - (x(1)^3-x(1)))*(1-3*x(1)^2); gradf(1) = gradf(1)/g; gradf(2) = 6*(x(2) - (x(1)^3 -x(1)))/g;
使用 trust-region 算法运行优化会生成不同的 exitflag:
options = optimoptions('fminunc','Algorithm','trust-region','SpecifyObjectiveGradient',true);
[xfinal3 fval3 exitflag3] = fminunc(@betopt,[-1;2],options)
Local minimum possible.
fminunc stopped because the final change in function value
relative to its initial value is less than the default value
of the function tolerance.
xfinal3 =
1.3333
1.0370
fval3 =
7.6659e-012
exitflag3 =
3退出条件优于 quasi-newton 条件,尽管前者仍不是最佳条件。从终点重新运行该算法会产生更好的点,其一阶最优性测度极小:
[xfinal4 fval4 eflag4 output4] = fminunc(@betopt,xfinal3,options)
Local minimum found.
Optimization completed because the size of the gradient is
less than the default value of the function tolerance.
xfinal4 =
1.3333
1.0370
fval4 =
0
eflag4 =
1
output4 =
iterations: 1
funcCount: 2
cgiterations: 1
firstorderopt: 7.5497e-11
algorithm: 'trust-region'
message: 'Local minimum found.
Optimization completed because the size o...'
constrviolation: []4.更改容差
有时,收紧或放松容差会产生更令人满意的结果。例如,在尝试不同算法部分中选择较小的 OptimalityTolerance 值:
options = optimoptions('fminunc','Algorithm','trust-region',...
'OptimalityTolerance',1e-8,'SpecifyObjectiveGradient',true); % default=1e-6
[xfinal3 fval3 eflag3 output3] = fminunc(@betopt,[-1;2],options)
Local minimum found.
Optimization completed because the size of the gradient is
less than the selected value of the function tolerance.
xfinal3 =
1.3333
1.0370
fval3 =
0
eflag3 =
1
output3 =
iterations: 15
funcCount: 16
cgiterations: 12
firstorderopt: 7.5497e-11
algorithm: 'trust-region'
message: 'Local minimum found.
Optimization completed because the size...'
constrviolation: []fminunc 比以前多进行了一次迭代,但得到的解更好。
5.重新缩放问题
尝试通过缩放和中心化,让每个坐标对目标函数和约束函数的影响大致相同。有关示例,请参阅中心化和缩放问题。
6.检查附近的点
在接近终点的点处计算您的目标函数和约束(如果它们存在)。如果终点是局部最小值,附近的可行点具有较大的目标函数值。有关示例,请参阅检查附近的点。
如果您有 Global Optimization Toolbox 许可证,请尝试从终点运行 patternsearch (Global Optimization Toolbox) 求解器。patternsearch 会检查附近的点,并接受所有类型的约束。
7.更改有限差分选项
中心有限差分计算起来更费时,但更精确。当您的问题可能有高曲率时,请使用中心差分。
要在命令行中选择中心差分,请使用 optimoptions 将 'FiniteDifferenceType' 设置为 'central',而不是默认值 'forward'。
8.提供解析梯度或雅可比矩阵
如果不提供梯度或雅可比矩阵,求解器会通过有限差分来估计梯度和雅可比矩阵。因此,提供这些导数可以节省计算时间,并可以提高准确度。基于问题的方法可以自动提供梯度;请参阅 Optimization Toolbox 中的自动微分。
对于约束问题,提供梯度还有另一个优势。求解器可以到达点 x,这说明 x 是可行点,但 x 附近的有限差分总是导致不可行点。在这种情况下,求解器可能会失败或过早停止。提供梯度可允许求解器继续。
在文件中为目标函数和非线性约束函数提供梯度或雅可比矩阵。有关语法的详细信息,请参阅编写标量目标函数、编写向量和矩阵目标函数和非线性约束。
要检查梯度或雅可比函数是否正确,请使用 checkGradients 函数,如检查梯度或雅可比矩阵的有效性中所述。
如果您有 Symbolic Math Toolbox™ 许可证,您可以通过编程方式计算梯度和黑塞矩阵。有关示例,请参阅使用 Symbolic Math Toolbox 计算梯度和 Hessian。
有关使用梯度和雅可比矩阵的示例,请参阅使用梯度和黑塞矩阵的最小化、带梯度的非线性约束、使用 Symbolic Math Toolbox 计算梯度和 Hessian、求解不含和含雅可比矩阵的非线性系统 和具有雅可比矩阵的大型稀疏非线性方程组。对于基于问题的方法中的自动微分,请参阅自动微分在基于问题的优化中的作用。
9.提供黑塞矩阵
当您提供黑塞矩阵时,求解器的运行通常更可靠,迭代次数也更少。
以下求解器和算法接受黑塞矩阵:
fminconinterior-point.将黑塞矩阵编写为一个单独的函数。有关示例,请参阅使用解析黑塞函数的 fmincon 内点算法。fmincontrust-region-reflective.通过目标函数的第三个输出给出黑塞矩阵。有关示例,请参阅使用密集结构 Hessian 和线性等式进行最小化。fminunctrust-region.通过目标函数的第三个输出给出黑塞矩阵。有关示例,请参阅使用梯度和黑塞矩阵的最小化。
如果您有 Symbolic Math Toolbox 许可证,您可以通过编程方式计算梯度和黑塞矩阵。有关示例,请参阅使用 Symbolic Math Toolbox 计算梯度和 Hessian。要在基于问题的方法中提供黑塞矩阵,请参阅基于问题的工作流中的供应衍生品。
使用 Symbolic Math Toolbox 计算梯度和 Hessian中的示例说明 fmincon 在没有黑塞矩阵的情况下进行 77 次迭代,但在有黑塞矩阵的情况下只进行 19 次迭代。
奇异矩阵警告
优化过程可能会发出以下一个或多个警告:
警告:矩阵在工作精度方面具有独特性。
警告:矩阵是奇异、接近奇异或缩放不当的。结果可能不准确。RCOND = <条件数>。
警告:矩阵接近奇异或缩放不当。结果可能不准确。RCOND = <条件数>。
这些警告通常在求解器尝试求解步方程(参阅 直接步)时遇到数值困难时出现。
为了解决这个问题,请尝试以下步骤。
检查结果
求解器遇到困难并不意味着它无法充分求解最小化问题。通常情况下,结果本身并没有问题。检查退出标志,并执行相应的步骤以确保返回的答案可靠。这些步骤在本页面以及主题 当求解器失败时 和 求解成功后 中有详细说明。如果您发现结果可靠,则无需采取进一步行动。
更改子问题算法
有时,更改子问题算法可能会导致求解器采取不同的解路径,从而避免奇异点。此选项仅适用于使用默认算法
"interior-point"的fmincon求解器。options = optimoptions("fmincon",SubproblemAlgorithm="cg")
中心化并缩放
有时,通过将问题数据居中和缩放,可以解决数值问题。尝试将输入数据(例如 bounds
lb和ub)设置为大致为 1 的数量级,然后让软件在内部执行必要的缩放操作。例如,如果您的设备可在 1e-6 m 至 2e-5 m 范围内运行,则指定下界为 1(即 1e-6 m),上界为 20(即 2e-5 m),而不是下界为 1e-6,上界为 2e-5。同样,如果您的设备在 1e6+1 到 1e6+4 的距离范围内工作,则指定下界为 1,上界为 4,并在内部将 1e6 添加到变量中。
扰动数据
当对数据进行扰动时,奇异矩阵通常会变得不那么奇异。您可以扰动的数据包括起点
x0、边界lb和ub、任何其他约束以及目标函数定义。不要进行任何可能实质性改变问题的更改。为了扰动数据,添加一个小的随机量。例如,如果
x是数据,请尝试使用x + 1e-6*randn(size(x))代替。请选择以下显示的一个或多个扰动。% Perturb x0. x0 = x0 + 1e-6*randn(size(x0)); % Perturb bounds. lb = lb + 1e-6*randn(size(lb)); ub = ub + 1e-6*randn(size(ub)); % Perturb linear inequality constraints A*x <= b. b = b + 1e-6*randn(size(b)); % Perturb objective function myfun(x) by changing the evaluation point. z = 1e-6*randn(size(x0)); % Choose one perturbation. fun = @(x)myfun(x + z) % Repeated evaluations of fun are not random.