大家好,
我试图使用 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} );
或者您可以尝试的另一种方法是创建一个小型数据表并使用分析器进行优化。我不太确定这与你的公式的配合效果如何,但我附上了一个例子,说明它如何与克雷格的例子配合使用。 下面是在分析器中优化函数时获得的解决方案的图片:

如果您运行附加到数据表的第一个脚本,您将在优化之前启动分析器。第二个脚本启动具有最佳解决方案的探查器。 分析器使用多个随机启动,因此对于寻找全局最优解更加稳健。