1.自动微分(AD)
开源里面比较干净的Forward Mode实现应该是ceres-solver里的的Jet[1]了。文件注释里解释得很详细。Reverse Mode比较成熟的实现是Stan[3]的。Adept[2]的实现思路有点意思,速度上跟Stan差不多(Stan在对节点函数上做了更多优化的工作),但是似乎缺乏实际产品的检验,稳定性可能不如Stan。Adept 2.0 版本自己实现了Array,原因大抵是作者想写出自己的风格…向不成熟的方向又迈进了一步。
AD在优化问题里面是一个非常方便的工具。但是不要忘了最简单的 df = (f(x+h) - f(x-h)) / 2h 这样简单而高效的形式,结合两者在某些优化问题里会有更好的效果。
Ceres中提供了三种求导方式:
- 解析法求导
- 数值法求导
- 自动微分法(AD)求导
[1]: ceres-solver/jet.h at master · kashif/ceres-solver · GitHub[2]: Adept: Fast Automatic Differentiation using Expression Templates
[3]: GitHub - stan-dev/math: Stan Math Library
[4]: https://en.wikipedia.org/wiki/Automatic_differentiation
[5]: http://www.ceres-solver.org/tutorial.html
2.数值微分:
https://en.wikipedia.org/wiki/Numerical_differentiation
求解非线性最小二乘法 Eigen http://blog.sina.com.cn/s/blog_a29eae2b0102whjp.html
Eigen中Levenberg-Marquardt算法的应用https://stackoverflow.com/questions/18509228/how-to-use-the-eigen-unsupported-levenberg-marquardt-implementation
https://scicomp.stackexchange.com/questions/16237/eigen-unsupported-levenberg-marquardt-algorithm
Eigen3中的数值微分法:
在Eigen3中,数值微分法也是继承自自定义的Functor数据结构的,写法大概是如下这样。
这样自定义的my_functor中就只定义了 operator() 函数,虽然没有定义 df() 函数,但是NumericalDiff数据结构是定义了 df() 函数的。
my_functor functor;
Eigen::NumericalDiff<my_functor> numDiff(functor);
Eigen::LevenbergMarquardt<Eigen::NumericalDiff<my_functor>, double> lm(numDiff);
当然可以完全自己定义一个结构体,自己实现df函数求偏导,和operator()函数求函数值。