Main Content

最適化のためのコード生成の基本

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

目的関数 rosenbrockwithgrad を使用してコードを生成する場合は、このコードを含む test_rosen.m という名前のファイルを作成します。

function [x,fval] = test_rosen
opts = optimoptions('fmincon','Algorithm','sqp');
[x fval] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],[-3,-3],[3,3],[],opts)

test_rosen ファイルのコードを生成します。

codegen -config:mex test_rosen

しばらくすると、codegen によって test_rosen_mex.mexw64 という名前の MEX ファイルが生成されます (ファイル拡張子はシステムによって異なります)。test_rosen_mex と入力すると、得られた C コードを実行できます。以下のとおりの結果または似た結果になります。

x =

    1.0000    1.0000


fval =

   1.3346e-11


ans =

    1.0000    1.0000

効率を高める変更例

リアルタイム アプリケーションの最適化コード生成のいくつかのヒントに従って、行われるチェックを減らし、静的なメモリ割り当てを使用するよう、生成コードの構成を設定します。

cfg = coder.config('mex');
cfg.IntegrityChecks = false;
cfg.SaturateOnIntegerOverflow = false;
cfg.DynamicMemoryAllocation = 'Off';

問題の範囲を [-3,3] から [-2,2] に狭めます。また、最適性の許容誤差を既定の 1e-6 よりも緩くします。

function [x,fval] = test_rosen2
opts = optimoptions('fmincon','Algorithm','sqp',...
    'OptimalityTolerance',1e-5);
[x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],...
    [-2,-2],[2,2],[],opts)

test_rosen2 ファイルのコードを生成します。

codegen -config cfg test_rosen2

得られたコードを実行します。

test_rosen2_mex
x =

    1.0000    1.0000


fval =

   2.0057e-11


eflag =

     2


output = 

  struct with fields:

         iterations: 40
          funcCount: 155
          algorithm: 'sqp'
    constrviolation: 0
           stepsize: 5.9344e-08
       lssteplength: 1


ans =

    1.0000    1.0000

この解は先ほどの解と同程度の精度であり、fval の出力が先ほどは 1e-11 だったのに対し、約 2e-11 になっています。

許容反復回数を先ほどの計算の半分に制限してみましょう。

function [x,fval] = test_rosen3
options = optimoptions('fmincon','Algorithm','sqp',...
    'MaxIterations',20);
[x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],...
    [-2,-2],[2,2],[],options)

MATLAB で test_rosen3 を実行します。

test_rosen3
x =

    0.2852    0.0716


fval =

    0.5204


eflag =

     0


output = 

  struct with fields:

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


ans =

    0.2852    0.0716

このように反復回数を大幅に制限したことで、fmincon は適切な解が得られていません。精度と速度のトレードオフは扱いが難しい場合があります。

関数評価の回数を抑えて精度の向上を図るには、この例の組み込み導関数を、SpecifyObjectiveGradient オプションを true に設定して使用します。

function [x,fval] = test_rosen4
options = optimoptions('fmincon','Algorithm','sqp',...
    'SpecifyObjectiveGradient',true);
[x fval eflag output] = fmincon(@rosenbrockwithgrad,[-1,1],[],[],[],[],...
    [-2,-2],[2,2],[],options)

test_rosen2 と同じ構成を使用して、test_rosen4 のコードを生成します。

codegen -config cfg test_rosen4

得られたコードを実行します。

test_rosen4_mex
x =

    1.0000    1.0000


fval =

   3.3610e-20


eflag =

     2


output = 

  struct with fields:

         iterations: 40
          funcCount: 113
          algorithm: 'sqp'
    constrviolation: 0
           stepsize: 9.6356e-08
       lssteplength: 1


ans =

    1.0000    1.0000

test_rosen2 と比べると、反復回数は同じく 40 ですが、関数評価回数は 155 から 113 に減っています。結果として、目的関数の値が 2e-11 から 3e-20 とより良く (小さく) なっています。

参考

| (MATLAB Coder) |

関連するトピック