这两天实现了一维搜索算法,以及BFGS方法。
在Nocedal 的 Numerical Optimization一书中,一维搜索的大概方法是逐步增大步长,发现步长太大时(例如,函数开始上升、wolfe充分下降条件不再满足),或者找到满足wolfe充分下降和曲率条件的步长时,停止增大步长,转为尝试用一个函数去插值这些数据点,再找这个函数在给定区间的极小值点。函数可以选二次或三次函数。顺便说一声,书中57页(3.43)给出了已知两点导数和函数值拟合三次函数的公式,我经过实验后发现这个公式是不对的(算出来的不是极小值点),后来自己推导了一个公式。
在一维搜索的过程中,需要多次求函数值或导数值,在我的有限元模拟程序中,这两项都有一定开销,尤其是导数值。因为函数值对应能量,导数值对应力,能量需要把每个四面体代入本构模型计算,而力的计算类似,但是每个四面体的计算量较大。因此,需要尽量减少这些求值的次数。在我的实现中,发现采用准确的Hessian的情况下,初始步长1.0能够满足wolfe条件,但在到达最小值点附近是,估计是由于数值误差,一维搜索一般会失败(计算出的步长为0)。
之后尝试了BFGS方法,发现效果不如想象的好。在我的程序中,Hessian矩阵可以分成四块,其中一块计算量较大(需要计算雅可比矩阵对自变量的导数,详细见Rig Space Physics这篇论文),因此希望用BFGS方法进行近似。我的方法是按照BFGS更新Hessian(注意不是Hessian^-1)的公式,把这一块用上一次的Hessian各块、自变量增量、梯度增量更新,而其他各块仍然用准确的计算方法。但是发现这样算出来的函数值一开始(也就是第二次迭代,第一次迭代我用准确的Hessian)不降反升,有时候会突然变大再变小,而且收敛速度明显放慢。
下一步检查 BFGS 方法的计算是否存在问题。
现在参数只控制平移旋转缩放,因此下下一步是实现一个复杂一些的变形器(具体形式暂时没想好……),以此检验牛顿法的稳定程度。
再下一步考虑直接与Maya通信,利用其节点求值机制,这样就不用自己写变形器了。这一步可考虑用Python编程,这样同时就掌握到了Python了。
最后发模拟一个圆环弹跳的结果……