主要内容

本页采用了机器翻译。点击此处可查看英文原文。

优化代码生成基础知识

fmincon 生成代码

此示例说明如何为 fmincon 优化求解器生成代码。代码生成需要 MATLAB® Coder™ 许可证。有关代码生成要求的详细信息,请参阅fmincon 背景中的代码生成

该示例使用以下简单的目标函数。要在您自己的测试中使用此目标函数,请将代码复制到名为 rosenbrockwithgrad.m 的文件中。将此文件保存到您的 MATLAB 路径中。

function [f,g] = rosenbrockwithgrad(x)
% Calculate objective f
f = 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2;

if nargout > 1 % gradient required
    g = [-400*(x(2) - x(1)^2)*x(1) - 2*(1 - x(1));
        200*(x(2) - x(1)^2)];
end
end

要使用 rosenbrockwithgrad 目标函数生成代码,请创建一个名为 test_rosen.m 的文件,其中包含调用 rosenbrockwithgrad 的代码。您必须设置选项才能使用 "sqp" 算法。若要使用目标函数的预设梯度,请将 SpecifyObjectiveGradient 选项设置为 true。若要使用与生成代码相同的代码来验证 MATLAB 中的结果,请将 UseCodegenSolver 选项设置为 true

function [x,fval,exitflag,output] = test_rosen(x0,lb,ub)
opts = optimoptions("fmincon",...
    Algorithm="sqp",SpecifyObjectiveGradient=true,...
    UseCodegenSolver=true);
[x,fval,exitflag,output] = fmincon(@rosenbrockwithgrad,...
    x0,[],[],[],[],lb,ub,[],opts);
end

在 MATLAB 中测试这段代码。

x0 = [-1 1];
lb = [-3 -3];
ub = [3 3];
[x,fval,exitflag,output] = test_rosen(x0,lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.


x =

    1.0000    1.0000


fval =

   5.6989e-20


exitflag =

     1


output = 

  struct with fields:

         iterations: 13
          funcCount: 49
          algorithm: 'sqp'
    constrviolation: 0
           stepsize: 2.1608e-06
       lssteplength: 1
      firstorderopt: 8.9962e-09
            message: 'Local minimum found that satisfies the constraints.↵↵Optimization completed because the objective function is non-decreasing in ↵feasible directions, to within the value of the optimality tolerance,↵and constraints are satisfied to within the value of the constraint tolerance.'

test_rosen 文件生成代码。

codegen -config:mex test_rosen -args {x0,lb,ub}

一段时间后,codegen 会创建一个名为 test_rosen_mex.mexw64 的 MEX 文件(文件扩展名因系统而异)。您可以通过输入以下内容来运行生成的 C 代码:

[x,fval] = test_rosen_mex(x0,lb,ub)

结果如下或与以下内容类似:

x =

    1.0000    1.0000


fval =

   5.6977e-20

使用代码生成得到的结果与在 MATLAB 中运行代码的结果几乎相同。

修改示例以提高效率

按照实时应用的优化代码生成中的一些建议,设置生成代码的配置,以减少检查并使用静态内存分配。

cfg = coder.config("mex");
cfg.IntegrityChecks = false;
cfg.SaturateOnIntegerOverflow = false;
cfg.EnableDynamicMemoryAllocation = false;

首先,使用默认的 mex 代码生成选项,检查使用生成代码运行该问题的平均耗时。

N = 10000; % Run 10,000 trials
pp = zeros(N,1);
for i=1:N
    tic
    [x,fval,exitflag,output] = test_rosen_mex(x0,lb,ub);
    pp(i) = toc;
end
m = mean(pp)
m =

   8.9106e-05

使用 cfg 配置生成代码。

codegen -config cfg test_rosen -args {x0,lb,ub}

检查使用 cfg 配置生成代码运行该问题的平均耗时。

N = 10000; % Run 10,000 trials
pp = zeros(N,1);
for i=1:N
    tic
    [x,fval,exitflag,output] = test_rosen_mex(x0,lb,ub);
    pp(i) = toc;
end
m = mean(pp)
m =

   6.0810e-05

运行生成代码所需的平均时间约为之前所需时间的 2/3。

试着将允许的迭代次数限制为 20 次,这大约是第一次计算中迭代次数的一半。

function [x,fval,exitflag,output] = test_rosen3(x0,lb,ub)
options = optimoptions("fmincon",...
    Algorithm="sqp",SpecifyObjectiveGradient=true,...
    UseCodegenSolver=true,MaxIterations=20);
[x,fval,exitflag,output] = fmincon(@rosenbrockwithgrad,...
    x0,[],[],[],[],lb,ub,[],options);
end

在 MATLAB 中运行 test_rosen3

[x,fval,exitflag,output] = test_rosen3(x0,lb2,ub2)
x =

    0.2852    0.0716


fval =

    0.5204


exitflag =

     0


output = 

  struct with fields:

         iterations: 20
          funcCount: 70
          algorithm: 'sqp'
    constrviolation: 0
           stepsize: 0.0225
       lssteplength: 1
      firstorderopt: 1.9507
            message: 'Solver stopped prematurely.↵↵fmincon stopped because it exceeded the iteration limit,↵options.MaxIterations = 2.000000e+01.'

在这种严格的迭代限制下,fmincon 不能得到良好解。准确性和速度之间的权衡难以把握。

生成单精度计算的代码

要生成针对单精度数据的代码,您只需将所有数据作为单精度数据传递即可。

x0 = single([-1 1]);
lb = single([-3 -3]);
ub = single([3 3]);
[x,fval] = test_rosen(x0,lb,ub)
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.


x =

  1×2 single row vector

    1.0000    1.0001


fval =

  single

  9.6799e-10

所得的 fval 量级为 1e-10,而非量级为 1e-20 的双精度结果,但除此之外,该过程完全相同。

生成代码,然后再次尝试单精度计算。

codegen -config:mex test_rosen -args {x0,lb,ub}

将单精度值传递给生成的函数。

[x,fval] = test_rosen_mex(x0,lb,ub)
x =

  1×2 single row vector

    0.9999    0.9998


fval =

  single

  1.1349e-08

生成代码得出的结果与 MATLAB 的结果非常接近。

另请参阅

| (MATLAB Coder) |

主题