大家好,
我嘗試使用 JSL 中的最小化函數來獲取兩個(或更多)變數的值,以最小化大型模型的誤差均方。 即使我知道它應該收斂到哪個值(透過反覆試驗),我也無法讓它收斂。
我使用的基本語法是:
minfun = Minimize( min_test, {kD( 0.4, 0.8 ), wshc( 0.1, 1.5 )}, <<DETAILS></DETAILS>我嘗試過不同的訊息,但它們沒有改變任何東西。
這裡的目標是找到 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 秒的計算,其結果會重新引入 JSL 中以計算 MSE。
這個過程本身似乎工作正常,因為它在每一步都正確讀取目標函數值,並且似乎將參數值正確傳遞給表達式。 問題在於,該演算法相對於我給定的初始值,對 kD 和 wshc 參數的「移動」幅度非常小(僅小數點後第五位),以至於無法收斂。 例如,如果我分別從 0.8 和 0.5 的初始值開始,我通常會得到類似的結果
0.8
0.49999945654133
在下一次迭代中,因此不會顯著影響生成的 MSE。 根據我在最小化函數中給出的參數界限,參數有足夠的移動空間。 我知道我的情況與典型的簡單可微函數相差甚遠。 然而,透過「手動」運行具有不同參數值的程序,我知道目標函數相對於參數來說非常凸,因此認為最小化函數可以正常工作,特別是使用 <
在這種情況下有什麼建議可以幫助解決問題嗎?
預先非常感謝,伊夫
這確實不是我的領域,但看起來應該可行。 這是我的測試 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 44.86266 210.178 0.080004 128 12 1 0 0.799999 0.50001
和第三個
/*: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,比上面的結果好得多。 我唯一能想到的是,初始值存在一個非常局部的最小值,但這似乎不太可能,因為無論我的初始值是多少,我都會得到相同的結果...
如果無法自行運行該範例,則很難確切地說出發生了什麼,但是您可以嘗試另外兩種方法。第一個是使用約束最小化函數沒有任何線性約束。它使用與以下方法不同的方法最小化功能,所以它可能會有所幫助。 因此,根據 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} );
或者您可以嘗試的另一種方法是建立一個小型資料表並使用分析器進行最佳化。我不太確定這與你的公式的配合效果如何,但我附上了一個例子,說明它如何與克雷格的例子配合使用。 以下是在分析器中優化函數時獲得的解決方案的圖片:

如果您執行附加到資料表的第一個腳本,您將在最佳化之前啟動分析器。第二個腳本啟動具有最佳解決方案的探查器。 分析器使用多個隨機啟動,因此對於尋找全域最優解更加穩健。