最適化のためのコード生成の基本
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
とより良く (小さく) なっています。
参考
fmincon
| codegen
(MATLAB Coder) | optimoptions