ceres学习笔记(二)

文章介绍了鲍威尔函数及Ceres库在无约束优化中的应用。通过定义四个残差方程,构建寻优问题并配置求解器,最终找到使四个函数残差平方和最小的x值。两种不同的代码实现方式得到相似的结果,证明了求解的正确性。
摘要由CSDN通过智能技术生成

继续关于ceres官方doc里教程的学习,对于powell's function的学习。

一、powell's function

鲍威尔法,严格来说是鲍威尔共轭方向法,是迈克尔J.D.鲍威尔提出的一种求解函数局部最小值的算法。该函数不能是可微分的,并且不会导出衍生函数。

该函数必须是固定数量的实值输入的实值函数。通过传入一组初始搜索向量,通常会传入N个搜索向量(譬如{s1,,,,,sn})这是与每个轴对齐的法线。

鲍威尔法是在无约束优化共扼方向,从某个初始点出发,求目标函数在这些方向上的极小值点,然后以该点为新的出发点,取复这一过程直到获得满意解,其优点是不必计算目标函数的 梯度就可以在有限步内找到极值点。

以上内容引用自百科,直接看官方的例子:

 它的意思是说, F(x)是上面四个残差值的方程,现在要寻找合适的x使\frac{1}{2}*||F(X)||^2最小。

下面使用ceres进行求解。

二、定义残差方程

按照前面学习的步骤,进行定义:

struct f1{
    template<typename T>
    bool operator()(const T* const x1, const T* const x2, T* residual) const {
        residual[0] = x1[0] + 10.0 * x2[0];
        return true;
    }
};

struct f2{
    template<typename T>
    bool operator()(const T* const x3, const T* const x4, T* residual) const {
        residual[0] = sqrt(5) * (x3[0] - x4[0]);
        return true;
    }
};

struct f3{
    template<typename T>
    bool operator()(const T* const x2, const T* const x3, T* residual) const {
        residual[0] = (x2[0] - 2.0 * x3[0]) * (x2[0] - 2.0 * x3[0]);
        return true;
    }
};

struct f4{
    template<typename T>
    bool operator()(const T* const x1, const T* const x4, T* residual) const {
        residual[0] = sqrt(10) * (x1[0] -   x4[0]) * (x1[0] -   x4[0]) ;
        return true;
    }
};

这里我调试的时候,犯了几个错误,记录一下:

1. 关于x1的设置,要写成x1[0]的形式。

2. 所有的数要写成double的形式。10 要写成 10.0。

三、构建寻优问题

    Problem problem;
    problem.AddResidualBlock(new AutoDiffCostFunction<f1, 1, 1, 1>(new f1), NULL, &x1, &x2);
    problem.AddResidualBlock(new AutoDiffCostFunction<f2, 1, 1, 1>(new f2), NULL, &x3, &x4);
    problem.AddResidualBlock(new AutoDiffCostFunction<f3, 1, 1, 1>(new f3), NULL, &x2, &x3);
    problem.AddResidualBlock(new AutoDiffCostFunction<f4, 1, 1, 1>(new f4), NULL, &x1, &x4);

也是按照之前的格式来写的,没什么问题。

四、配置并运行求解器

    Solver::Options options;
    options.linear_solver_type = ceres::DENSE_QR;
    options.minimizer_progress_to_stdout = true;
    Solver::Summary summary;
    Solve(options, &problem, &summary);

五、输出结果

    cout << summary.BriefReport() << "\n";

    cout << "x1 : " << x1 << "\n";
    cout << "x2 : " << x2 << "\n";
    cout << "x3 : " << x3 << "\n";
    cout << "x4 : " << x4 << "\n";

最后算出来到结果是:

 基本上和0,差不多。符合官网的参考答案。

六、换成其它的格式

#include <ceres/ceres.h>
#include <iostream>

using namespace std;
using namespace ceres;

struct f{
    template<typename T>
    bool operator()(const T* const x, T* residual) const {
        residual[0] = x[0] + 10.0 * x[1];
        residual[1] = sqrt(5) * (x[2] - x[3]);
        residual[2] = (x[1] - 2.0 * x[2]) * (x[1] - 2.0 * x[2]);
        residual[3] = sqrt(10) * (x[0] -   x[3]) * (x[0] -   x[3]) ;
        return true;
    }
};

int main(int argc, char** argv)
{
    double x[4] = {1,2,3,4};


    Problem problem;
    problem.AddResidualBlock(new AutoDiffCostFunction<f, 4, 4>(new f), 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);

    cout << summary.BriefReport() << "\n";

    cout << "x1 : " << x[0] << "\n";
    cout << "x2 : " << x[1] << "\n";
    cout << "x3 : " << x[2] << "\n";
    cout << "x4 : " << x[3] << "\n";

    return 0;
}

按造自己的想法,优化了下。主要是使用了x数组代替了4个单独的变量,并重新设置residual的纬度。需要注意的是,problem.AddResidualBlock()函数中最后一个参数,原来是单个数就需要取地址符号,设置成数组就直接写数组名就好了。

最后算出结果:

 两次结果基本一致。

准备把官方doc里面的example部分全部刷一遍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值