やあみんな、
JSL の minimum 関数を使用して、大規模なモデルの誤差平均二乗を最小化する 2 つ (またはそれ以上) の変数の値を取得しようとしています。 どの値に収束すべきかはわかっているのに、収束させることができません(試行錯誤)。
私が使用した基本的な構文は次のとおりです。
minfun = Minimize( min_test, {kD( 0.4, 0.8 ), wshc( 0.1, 1.5 )}, <<DETAILS></DETAILS>さまざまなメッセージを試しましたが、何も変わりません。
ここでの目標は、式 min_test を最小化する kD と wshc の値を見つけることです。式 min_test は、次のように評価された式のシーケンスです。
min_test = Expr(
Eval( light );
Eval( parafile );
Eval( runprg );
Eval( reshandling2 );
Eval( SSE2 );
);
変更された kD 値と wshc 値は、「light」式と「parafile」式を変更します。これにより、(runprg 式内で) プログラム実行可能ファイルが実行され、その結果が操作され、そこから平均二乗誤差 (MSE) が最終的に計算されます。 SSE2 式で評価されます。 コンテキストとして、「runprg」式は、湖の熱進化をシミュレートするスタンドアロンの実行可能ファイルに作成された複数のファイルを送信します。 「runprg」式の各パスには約 10 ~ 20 秒の計算が必要で、その結果は MSE を計算するために JSL に再取り込まれます。
プロセス自体は、各ステップで目的関数の値を正しく読み取り、パラメーターの値を式に正しく渡すため、正しく動作しているようです。 問題は、アルゴリズムが kD パラメーターと wshc パラメーターを、与えた初期値に対してわずかに (小数点第 5 位のみ) 移動させるため、収束しないことです。 たとえば、それぞれ 0.8 と 0.5 の初期値から始めると、通常は次のような結果が得られます。
0.8
0.49999945654133
次の反復で実行されるため、結果として生じる MSE には大きな影響はありません。 minimum 関数でパラメータの範囲を指定すると、パラメータを移動するための十分なスペースが確保されます。 私の場合は、典型的な単純な微分可能関数とはかなりかけ離れていることを理解しています。 ただし、異なるパラメーター値を使用してプログラムを「手動で」実行すると、目的関数がパラメーターに関してかなり凸であることがわかり、特に <
この状況で役立つ可能性のある回避策の提案はありますか?
よろしくお願いします、イヴ
これは実際には私の分野ではありませんが、うまくいくようです。 これが私のテストJSLです。
aa = expr(
Show( "evaluating", Char( a, 19, 16 ), Char( b, 19, 16 ) ); // peek inside
(a - 10) ^ 2 + (b - 11) ^ 2 // the function, roots at 10 and 11
);
min_test = Expr( Eval( aa ) );
a = 33; // initial guesses
b = -55; // (not very good)
minfun = Minimize(
min_test,
{a( -100, 100 ), b( -100, 100 )},
<<DETAILS></DETAILS>
これがログです。 最初の *本当の * 推測ではほぼ完璧な答えが得られるように見えるにもかかわらず、まったく同じ最初の間違った推測で多数の呼び出しが行われるのは奇妙に思えます。
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000005066394806";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "32.9999994933605194";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-54.999999165534973";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000000834465027";
"evaluating";
Char(a, 19, 16) = "33.0002058854513791";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "32.9997941145486209";
Char(b, 19, 16) = "-55.000000000000000";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-54.999660894550665";
"evaluating";
Char(a, 19, 16) = "33.0000000000000000";
Char(b, 19, 16) = "-55.000339105449335";
"evaluating";
Char(a, 19, 16) = "33.0003391054493349";
Char(b, 19, 16) = "-54.999660894550665";
"evaluating";
Char(a, 19, 16) = "32.9996608945506651";
Char(b, 19, 16) = "-54.999660894550665";
"evaluating";
Char(a, 19, 16) = "33.0003391054493349";
Char(b, 19, 16) = "-55.000339105449335";
"evaluating";
Char(a, 19, 16) = "32.9996608945506651";
Char(b, 19, 16) = "-55.000339105449335";
nParm=2 SR1 ******************************************************
Iter nFree Objective RelGrad NormGrad2 Ridge nObj nGrad nHess Parm0 Parm1
0 2 4885 9770 9770 0 1 1 1 33 -55
"evaluating";
Char(a, 19, 16) = "9.9999350076876112";
Char(b, 19, 16) = "11.0000734771922168";
"evaluating";
Char(a, 19, 16) = "9.9999351715994163";
Char(b, 19, 16) = "11.0000734771922168";
"evaluating";
Char(a, 19, 16) = "9.9999348437758062";
Char(b, 19, 16) = "11.0000734771922168";
"evaluating";
Char(a, 19, 16) = "9.9999350076876112";
Char(b, 19, 16) = "11.0000736560072454";
"evaluating";
Char(a, 19, 16) = "9.9999350076876112";
Char(b, 19, 16) = "11.0000732983771883";
1 2 9.623e-9 0.006344 1.925e-8 0 1 1 0 9.999935 11.00007
"evaluating";
Char(a, 19, 16) = "9.9999999999733351";
Char(b, 19, 16) = "10.9999999999907079";
"evaluating";
Char(a, 19, 16) = "10.0000001638861082";
Char(b, 19, 16) = "10.9999999999907079";
"evaluating";
Char(a, 19, 16) = "9.9999998360605620";
Char(b, 19, 16) = "10.9999999999907079";
"evaluating";
Char(a, 19, 16) = "9.9999999999733351";
Char(b, 19, 16) = "11.0000001788046422";
"evaluating";
Char(a, 19, 16) = "9.9999999999733351";
Char(b, 19, 16) = "10.9999998211767736";
2 2 7.97e-22 2.42e-15 1.59e-21 0 1 1 0 10 11
Convergence SUCCESS: Gradient
Time: 0
"evaluating";
Char(a, 19, 16) = "9.9999999999733351";
Char(b, 19, 16) = "10.9999999999907079";
minfun = 7.97360035815878e-22;
a = 9.99999999997334;
b = 10.9999999999907;
10 ~ 20 秒の関数に対して 27 回の呼び出しが予想されるようです。
あなたのアルゴリズムは同じ入力に対して同じ答えを生成しますか? それともランダムな要素が含まれていますか? それが違いを生むかもしれない。
とても興味深いクレイジです。 私はあなたのアプローチに従い、実行中の値をピークにしました。 この例では、初期値はそれぞれ 0.8 と 0.5 です。
minfun = Minimize( min_test, {kD( 0.4, 0.8 ), wshc( 0.1, 1.5 )}, <<DETAILS></DETAILS>2 回目の反復ではこれが得られます
/*:2 2 44.86266 210.178 0.080004 128 12 1 0 0.799999 0.50001
そして3番目
/*:3 2 45.33956 0 0.080004 4096 16 0 0 0.799999 0.50001
反復 2 よりも優れた結果は得られないため、そこで終了します。 ここで、最適な目的関数の値は 44.86 です。
ただし、アルゴリズムに (それぞれ) 0.52 と 1.13 のパラメーター値を「手動で」与えると、目的関数 (MSE) は約 6.8 となり、上記の結果よりもはるかに優れています。 私が考えることができる唯一のことは、初期値に非常に局所的な最小値があるということですが、初期値が何であっても同じ種類の結果が得られるため、その可能性は低いと思われます...
自分でサンプルを実行できない限り、何が起こっているのかを正確に言うのは困難ですが、試してみることができるアプローチが他に 2 つ思いつきます。1 つ目は、制約された最小化線形制約なしで機能します。とは異なる方法を使用します。最小化する機能があるので、役立つかもしれません。 したがって、Craige の例から、次のようなことができます。
aa = expr(
Show( "evaluating", Char( a, 19, 16 ), Char( b, 19, 16 ) ); // peek inside
(a - 10) ^ 2 + (b - 11) ^ 2 // the function, roots at 10 and 11
);
min_test = Expr( Eval( aa ) );
minFun =
Constrained Minimize(
min_test,
{a( -100, 100 ), b( -100, 100 )},
<<StartingValues( [0, 0] ), <<show details(true)
);
Eval List( {a, b, minFun} );
または、小さなデータ テーブルを作成し、プロファイラーを使用して最適化を実行することもできます。それがあなたの式でどの程度うまく機能するかはよくわかりませんが、クレイジの例でそれがどのように機能するかという例を添付します。 プロファイラーで関数を最適化した場合に得られるソリューションの図を次に示します。

データテーブルに添付された最初のスクリプトを実行すると、最適化の前にプロファイラーが起動します。2 番目のスクリプトは、最適なソリューションを使用してプロファイラーを起動します。 プロファイラーは複数のランダムな開始を使用するため、全体的な最適なソリューションを見つけることがより堅牢になります。