Ceres solver

Ceres可以解决鲁棒约束的非线性最小二乘问题,具有一下形式:

minx12iρi(fi(xi1,,xik)2)s.t.ljxjuj

表达式 ρi(fi(xi1,...,xik)2) Residual Block
fi() CostFunction
[xi1,...,xik] parameter blocks
lj uj parameter block xj 的取值范围。
ρi LossFunction,可以降低由于outliers带来的影响。

ρi(x)=x lj= 并且 uj= ,即为一个最小二乘问题。

示例1:求极值

首先我们以Ceres库官网中的Hello World例子来进行说明。这里例子的目的是为了计算方程 f(x)=12(10x)2 取得最小值时x的值。从这个方程很容易看出来当 x=10 时, f(x) 取得最小值0。这个方程虽然没有什么实际意义,但是为了演示Ceres库还是很不错的例子。

1、编写一个 f(x)=10x 的残差方程。代码如下:

struct CostFunctor{
   template <typename T>
   bool operator()(const T* const x, T* residual) const {
     residual[0] = T(10.0) - x[0];
     return true;
   }
};

这里值得注意的是,必须要编写一个重载()运算,而且必须使用模板类型,所有的输入参数和输出参数都要使用T类型。

2、当我们写完了上面的计算残差的方程,接下来就可以使用Ceres库来构造一个求解非线性最小二乘法的Problem来进行求解未知数了。代码如下:

int main(int argc, char** argv)
{
  google::InitGoogleLogging(argv[0]);

  // 指定求解的未知数的初值,这里设置为5.0
  double initial_x = 5.0;
  double x = initial_x;

  // 建立Problem
  Problem problem;

   // 建立CostFunction(残差方程)
   CostFunction* cost_function =
       new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
   problem.AddResidualBlock(cost_function, NULL, &x);

   // 求解方程!
   Solver::Options options;
   options.linear_solver_type = ceres::DENSE_QR;
   options.minimizer_progress_to_stdout = true;
   Solver::Summary summary;
   Solve(options, &problem, &summary);

   std::cout << summary.BriefReport() << "\n";
   std::cout << "x : " << initial_x
             << " -> " << x << "\n";
   return 0;
}

AutoDiffCostFunction需要CostFunctor作为输入。上面的例子编译执行后,会输出下面的信息:

       0: f: 1.250000e+01 d: 0.00e+00 g: 5.00e+00h: 0.00e+00 rho: 0.00e+00 mu: 1.00e+04 li: 0 it: 6.91e-06 tt: 1.91e-03  
       1: f: 1.249750e-07 d: 1.25e+01 g: 5.00e-04h: 5.00e+00 rho: 1.00e+00 mu: 3.00e+04 li: 1 it: 2.81e-05 tt: 1.99e-03  
       2: f: 1.388518e-16 d: 1.25e-07 g: 1.67e-08h: 5.00e-04 rho: 1.00e+00 mu: 9.00e+04 li: 1 it: 1.00e-05 tt: 2.01e-03  
    CeresSolver Report: Iterations: 2, Initial cost: 1.250000e+01, Final cost:1.388518e-16, Termination: PARAMETER_TOLERANCE.  
    x : 5-> 10  

3、从上面的输出信息中可以看出,经过三次迭代计算,求得的x值为10时可以取得最小值。接下来我们分析下main函数中的代码。

第2行代码为Google的log库,详细内容请参考Google log库的相关说明。
第5、6行为定义了求解未知数的初值,初值设置为5。
第9行,声明一个Problem对象,用于求解。
第12行,声明一个残差方程,CostFunction通过模板类AutoDiffCostFunction来进行构造,第一个模板参数为残差对象,也就是最开始写的那个那个带有重载()运算符的结构体,第二个模板参数为残差个数,第三个模板参数为未知数个数,最后参数是结构体对象。
第14行,将观测值和残差方程加入Problem对象中,如果有多个观测值,都需要加进去,这点可以看后面的示例。
第16~19行,定义一个求解选项,里面主要包括对方程线性化的方式,迭代次数等,具体参考官网帮助文档。
第20行,定义一个求解结果报告。
第21行,调用Solve函数进行求解,第一个参数就是求解选项,第二个参数为Problem指针,第三个参数为求解报告指针。
第23行,输出求解报告信息。
第24行,输出求解前的初值和求解后的值。

Ref:
Non-linear Least Squares

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值