线性/非线性最小二乘 与 牛顿/高斯牛顿/LM 原理及算法

最小二乘分为线性最小二乘非线性最小二乘

最小二乘目标函数都是min ||f(x)||2

  • 若f(x) = ax + b,就是线性最小二乘;
  • 若f(x) = ax2 + b / ax2 + bx 之类的,就是非线性最小二乘;

1. 求解线性最小二乘

【参考】

2. 求解非线性最小二乘

需要用到牛顿法,高斯牛顿法,或者LM法
目标函数都是min F(x) = min ||f(x)||2
求解的时候需要求解的是f(x)的最小值,其实求解的就是f(x)'=0的地方

(1) 牛顿法/高斯梯度下降

牛顿法是将f(x)进行二阶泰勒展开: f(x)=f(xk)+f’(xk)(x-xk)+1/2 f’‘(xk)(x-xk)2
因为求解的其实是上式的最小值,也就是求解上式导数为0的值
核心迭代等式:xk+1 = xk - f’(xk)/f’'(xk)
其中,一阶导f’(xk)可以看成雅可比矩阵J,二阶导f’'(xk)可以看成海森矩阵H

算法

  1. 给定初值x0
  2. 对于第k次迭代,求出一阶导f’(xk)和二阶导f’'(xk)
  3. 如果f’(xk)足够小则停止;否则xk+1=xk - f’(xk)/f’'(xk),返回2

(2) 高斯牛顿法

这里的f(x)代表的是目标函数F(x)
是将f(x)进行一阶泰勒展开:f(x+dx) = f(x) + J*dx
取得最小值的条件也就是 f(x) + J * dx这个式子对dx的导数为0,
可以求解得到: JTJ * dx = - J * f(x) ,可以简化为 H dx = g
刚好利用JTJ代替H,减少H计算量

算法

求解等式为 JTJ * dx = - J * f(x),即增量方程,这里的dx也就是每次需要寻找的变化量

  1. 给定初值x0
  2. 对于第k次迭代,求出雅可比J(xk) 和f(xk)
  3. 将以上两值代入,利用方程H dx = g,求解dx
  4. 如果dx足够小则停止,否则xk+1=xk+dx,返回2

(3) LM法

高斯牛顿本质求解的是xk+1 = xk - H-1 * J(xk) * f(xk) 但是H如果非正定,那 H-1不存在,因此将其加上单位矩阵结局正定问题 :(H + kI)dx = g

计算信赖区间 ρ请添加图片描述
算法

求解等式为 (JTJ+ μI) dx = -J f(x),其中J = J(xk),f(x) = f(xk)

  1. 给定初值x0
  2. 对于第k次迭代,求出雅可比J(xk) 和f(xk)
  3. 计算ρ,若 ρ > 3/4,则 μ = 2μ;
        若 ρ < 1/4,则 μ = 0.5μ;
  4. 将J(xk) ,f(xk)和 μ代入,利用方程 (H + μI) dx = g,求解dx
  5. 如果dx足够小则停止,否则xk+1=xk+dx,返回2

参考
https://zhuanlan.zhihu.com/p/556170185?utm_id=0
https://blog.csdn.net/weixin_43763292/article/details/128060801
https://blog.csdn.net/weixin_41869763/article/details/103603089

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ceres是一款开源的C++库,用于实现非线性最小二乘问题的求解。它支持许多常见的最优化算法,包括牛顿法、高斯牛顿法和阻尼最小二乘法牛顿法是一种迭代法,用于寻找非线性函数的最小值。它使用函数的一阶和二阶导数来逼近函数,并使用这些信息来更新当前解的位置。Ceres实现了一种变形的牛顿法,称为LM(Levenberg-Marquardt)算法,它使用一个参数来平衡牛顿法和梯度下降法之间的权衡。 高斯牛顿法是一种迭代法,用于寻找非线性函数的最小值。它使用函数的一阶导数和雅克比矩阵来逼近函数,并使用这些信息来更新当前解的位置。Ceres实现了一种变形的高斯牛顿法,称为Schur-Jacobi算法,它使用一个参数来平衡高斯牛顿法和梯度下降法之间的权衡。 阻尼最小二乘法是一种迭代法,用于寻找非线性函数的最小值。它使用函数的一阶导数和雅克比矩阵来逼近函数,并使用这些信息来更新当前解的位置。不同于牛顿法和高斯牛顿法,阻尼最小二乘法在更新步长时引入了一个阻尼因子,以避免步长过大,从而导致求解过程不稳定。 下面是一个使用Ceres实现最小二乘问题的示例代码: ```c++ #include <iostream> #include "ceres/ceres.h" using namespace std; // 定义残差函数 struct CostFunctor { template <typename T> bool operator()(const T* const x, T* residual) const { residual[0] = T(10.0) - x[0]; return true; } }; int main(int argc, char** argv) { // 初始化问题 ceres::Problem problem; // 添加变量 double x = 0.5; problem.AddParameterBlock(&x, 1); // 添加残差项 ceres::CostFunction* cost_function = new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor); problem.AddResidualBlock(cost_function, nullptr, &x); // 设置求解选项 ceres::Solver::Options options; options.linear_solver_type = ceres::DENSE_QR; options.minimizer_progress_to_stdout = true; // 求解问题 ceres::Solver::Summary summary; ceres::Solve(options, &problem, &summary); // 输出结果 cout << summary.BriefReport() << endl; cout << "x = " << x << endl; return 0; } ``` 在这个例子中,我们定义了一个简单的残差函数,它的目标是让变量x的值接近10。然后,我们使用Ceres来求解这个最小二乘问题。我们首先将变量x添加到问题中,并添加一个残差项。然后,我们设置求解选项并调用ceres::Solve函数来求解问题。最后,我们输出求解结果。 这只是一个简单的例子,Ceres还支持更复杂的问题和算法。如果你想深入了解Ceres的使用,请参考官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值