目录

一 、简介

二、安装

三、介绍

四、Hello Word!

五、导数

1 数值导数

2解析求导

六、实践

Powell函数


一 、简介

笔者已经半年没有更新新的内容了,最近学习视觉SLAM的过程中发现自己之前学习的库基础不够扎实。Ceres作为一个优化库在视觉SLAM中使用非常广泛,笔者会跟随着Ceres Solver的官方教程一直学习下来,并且会在专栏中持续更新,如需转载请声明出处

二、安装

虽然说是从零开始教学Cere Solver的使用,但是基本linux和git指令还是需要一定基础。具体的安装步骤如下,需要不同的安装版本可以去GitHub上找到。

1、依赖项

Ceres Solver 2.2 需要完全符合 C++17 的编译器。

Cmake需要3.10版本以上和Eigen3.3以上

注意官方维护的ubuntu版本必须在18.04以上。老版本的ubuntu可能安装使用会出现不兼容。

# CMake
sudo apt-get install cmake
# google-glog + gflags
sudo apt-get install libgoogle-glog-dev libgflags-dev
# Use ATLAS for BLAS & LAPACK
sudo apt-get install libatlas-base-dev
# Eigen3
sudo apt-get install libeigen3-dev
# SuiteSparse (optional)
sudo apt-get install libsuitesparse-dev

2、安装

Ceres是使用Cmake进行安装的,具体的步骤如下:

tar zxf ceres-solver-2.1.0.tar.gz
mkdir ceres-bin
cd ceres-bin
cmake ../ceres-solver-2.1.0
make -j3
make test
# Optionally install Ceres, it can also be exported using CMake which
# allows Ceres to be used without requiring installation, see the documentation
# for the EXPORT_BUILD_DIR option for more information.
make install

安装完成之后可以测试自己是否安装成功,可以使用Ceres自带的华盛顿大学的 BAL 数据集进行测试运行看是否安装成功。

bin/simple_bundle_adjuster ../ceres-solver-2.1.0/data/problem-16-22106-pre.txt

这将使用 DENSE_SCHUR 线性求解器运行 Ceres 最多 10 次迭代。Ceres还可以这Window、Mac、ios和Android安装。具体的安装请参看官方文档。本专栏只针对运行在linux上。

三、介绍

Ceres可以解决以下边界约束鲁棒化的非线性最小二乘问题:

这种形式的问题在工程领域运用的非常多比如拟合统计曲线到计算机视觉的图片构建等。

接下来笔者将带大家一起学习Ceres Solver求解, ρi(‖fi(xi1,...,xik)‖2) 被称为ResidualBlock为残差块, fi(⋅) 为损失函数。 [xi1,...,xik]就是我们需要优化的变量,我们将它定位ParameterBlock。接下来为了理解,举一个例子。在视觉SLAM中,平移有3个分量,旋转使用四元数有4个分量,比如我们最小化重投影误差中需要优化的就是位置和位姿。lj和 uj是参数块的界限xj,当然,lj和 uj都可以取负无穷和正无穷,并且优化的参数也可以是一个,这样可以得到一个我们熟知的非线性最小化问题:

四、Hello Word!

学习的开始,我们将和编程一样从一个最简单的Hello Word开始!

首先,我们先考虑以下函数的最小值:

从式子可以看出最小值计算x=10的时候,用这样一个简单的例子来讲解Ceres。

1、首先我们定义一个仿函数来评估函数f(x)=10−x。

这里我先简单介绍一下什么是仿函数,这里需要一定的C++的基础。仿函数就是在类中对()运算符号进行重载。为什么要使用仿函数主要是为了方便维护类的成员函数和运行效率更高。笔者接触这个也很少,在ORB-SLAM中也同样遇到过仿函数,有空对仿函数专门进行更新。

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

这里解释一下输入的const T* const x, const T*x表示 *x指向的对象不可修改,T* const x表示指针不能修改,const T* const x就是两者的结合指向的对象和指针都不能进行修改。这里我们使用了模板函数,这也是C++的基本知识在这里就不详细介绍了。这里的x变量就是我们需要输入数据,x可以是n维向量。residual则是我们误差(或者残差)也就是损失函数。接下来看主函数:

int main(int, char**) {// 设置初始值double ininal_num=5.0;double x=ininal_num;// 构建问题Problem有两个重要的成员函数:// Problem::AddResidalBlock() and Problem::AddParameterBlock()ceres::Problem problem;//设置损失函数,这里使用自动求导计算雅克比矩阵以我们自己定义的CostFunctor为类型在进行初始化ceres::CostFunction* cost_functor=new ceres::AutoDiffCostFunction<CostFunctor,1,1>(new CostFunctor);// 添加残差problem.AddResidualBlock(cost_functor,nullptr,&x);// 配置求解器ceres::Solver::Options options;// options.max_num_iterations=20; //可以设置最大迭代次数options.linear_solver_type=ceres::DENSE_QR;options.minimizer_progress_to_stdout=true;ceres::Solver::Summary summary;//开始求解ceres::Solve(options,&problem,&summary);std::cout<<summary.BriefReport()<<"\n";std::cout<<"x:"<<ininal_num<<"->"<<x<<"\n";return 0;}

五、导数

和大多数的优化库一样,Ceres能够在任意参数值下估计目标函数中每个项的值和导数。上面我们就使用到了自动求导。现在我们讨论两种解析导数和数值导数。

1 数值导数

在某些情况下,是不能写出模板损失函数,比如损失函数使用了其他库中的函数,这样就不能使用自动求导AutoDiffCostFunction。在这种情况下我们可以使用数值导数。数值导数也和自动求导类似,首先定义一个仿函数,之后在传递给NumericDiffCostFunctor。例如:

struct NumericDiffCostFunctor {bool operator()(const double* const x, double* residual) const {residual[0] = 10.0 - x[0];return true;}
};
//添加到problem中CostFunction* cost_function =new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(new NumericDiffCostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);

基本的构造和AutoDiffCostFunction相同,就是多了一个参数的输入。这个多出来参数用于计算数值导数的有限差分种类,这个之后讲解。在刚开始学习的过程官方也推荐我们最好使用自动求导

2解析求导

解析求导就是在以封闭式计算导数则不能使用自动求导,这是官方所说的有点难懂。简单来说就是你定义了一个抽象函数或者说这个函数中包含了更多函数时,Ceres就不能帮你自动求导了。这种情况就是自己提供残差和雅克比计算了。我们以10-x函数为例子(只是为了方便理解,这个函数可以使用自动求导解决):

class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {public:virtual ~QuadraticCostFunction() {}virtual bool Evaluate(double const* const* parameters,double* residuals,double** jacobians) const {const double x = parameters[0][0];residuals[0] = 10 - x;//计算雅克比矩阵if (jacobians != nullptr && jacobians[0] != nullptr) {jacobians[0][0] = -1;}return true;}
};

我们重构虚函数Evaluate,第一个输入为参数数组,第二个为残差,第三个为雅克比矩阵。Evaluate检查雅克比矩阵是否为空,如果是则用残差函数的导数填充。本例子中因为是线性函数,所以是数值。

官方推荐我们如果我们有能力管理自己的雅克比计算,就使解析导数。否则还是优先自动求导和数值求导。

Ceres提供了更多的导数计算,还有更加高级的计算DynamicAutoDiffCostFunction和CostFunctionToFunctor在之后我会进一步补充。

六、实践

可能你现在还一头雾水,不太理解上面代码的详细功能。接下来我将带大家完成几个例子加深对代码的理解。

Powell函数

现在我们来考虑一个复一定的问题。powell函数x=[x1,x2,x3,x4]是F(x)中的四个参数有以下等式:

可以看出我们有四个残差,我们希望1/2‖F(x)‖2是最小的。

首先我们从f4这个式子开始:

首先还是一样需要定义目标函数中的项进行评估:

struct F1 {template <typename T>bool operator()(const T* const x1, const T* const x2, T* residual) const {// f1 = x1 + 10 * x2;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 {// f2 = sqrt(5) (x3 - x4)residual[0] = sqrt(5.0) * (x3[0] - x4[0]);return true;}
};
struct F3 {template <typename T>bool operator()(const T* const x2, const T* const x3, T* residual) const {// f3 = (x2 - 2 x3)^2residual[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 {// f4 = sqrt(10) (x1 - x4)^2residual[0] = sqrt(10.0) * (x1[0] - x4[0]) * (x1[0] - x4[0]);return true;}
};

之后的我们开始构造问题:

 double x1 = 3.0;double x2 = -1.0;double x3 = 0.0;double x4 = 1.0;Problem problem;//添加残差并且使用自动求导problem.AddResidualBlock(new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), nullptr, &x1, &x2);problem.AddResidualBlock(new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), nullptr, &x3, &x4);problem.AddResidualBlock(new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), nullptr, &x2, &x3);problem.AddResidualBlock(new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), nullptr, &x1, &x4);

之后的优化和之前一样配置就可以了:

Solver::Options options;
options.max_num_iterations = 100;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.FullReport() << "\n";

从我们自身进行观察我们就可以看出最优解是x1=x2=x3=x4=0 ,可以看出最终的优化结果也是是否接近。

Ceres Solver从零开始手把手教学使用相关推荐

  1. Ceres Solver Document学习笔记

    Ceres Solver Document学习笔记 Ceres Solver Document学习笔记 1. 基本概念 2. 基本方法 2.1 CostFunction 2.2 AutoDiffCos ...

  2. Ceres Solver 非线性优化库

    Ceres Solver 非线性优化库 1. Ceres Solver 2. 下载安装 3. 简易例程 4. 环境运行 5. 非线性拟合 1. Ceres Solver Ceres solver 是谷 ...

  3. Ceres Solver安装

    先是ceres solver的依赖安装 # CMake sudo apt-get install cmake # google-glog + gflags sudo apt-get install l ...

  4. Ceres Solver: 高效的非线性优化库(二)实战篇

    Ceres Solver: 高效的非线性优化库(二)实战篇 接上篇: Ceres Solver: 高效的非线性优化库(一) 如何求导 Ceres Solver提供了一种自动求导的方案,上一篇我们已经看 ...

  5. 【环境配置】ceres solver安装

    1. 安装 github地址 # CMake sudo apt-get install cmake # google-glog + gflags sudo apt-get install libgoo ...

  6. Ceres Solver安装及bug解决

    Ceres Solver安装与入门使用 安装教程:http://www.ceres-solver.org/installation.html 点击下载最新的稳定版 解压.编译 .测试.安装 1.Lin ...

  7. Ceres Solver:Terminating: Residual and Jacobian evaluation failed

    文章目录 前言 一.Ceres-Solver 二.解决方法 总结 前言 使用ceres-solver库求解非线性优化问题时,打印summary.message时出现报错: [trust_region_ ...

  8. Ceres Solver 官方教程学习笔记(十二)——非线性最小二乘法建模Modeling Non-linear Least Squares (下)

    这一部分主要是最后的Problem比较重要. 带条件的代价函数ConditionedCostFunction 这个类使用户可以在使用封装好的代价函数的同时,对残差值加入一定的条件限制.举个例子,现在已 ...

  9. Ceres solver安装与测试

    官方安装教程 点击下载最新的稳定版 解压.编译 .测试.安装 tar zxf ceres-solver-2.1.0.tar.gz mkdir ceres-bin cd ceres-bin cmake ...

最新文章

  1. 参会邀请 | “新时代与新范式:新兴交叉学科的研究议程与发展路径”——第三届全国计算社会科学高端论坛...
  2. 五月记事 2005-05-03
  3. SaltStack:Salt SSH
  4. 一友人昨夜接到电话,发生何事
  5. 启动elasticsearch命令_快速安装ElasticSearch
  6. [ubuntu] chromium不断自己刷新问题
  7. click事件在什么时候出发_剖析setTimeout和click点击事件的触发顺序
  8. linux bcc_使用bcc / BPF在Linux中分析性能的7种工具
  9. mysql怎么设置密码都不正确的一个解决方法
  10. [USACO14JAN]Recording the Moolympics
  11. python的sdk是什么意思_python sdk
  12. McAfee Agent漏洞可导致黑客以Windows 系统权限运行代码
  13. linux 权限加号是,请教:drwxrwxr-x   什么权限后面有个加号,代表什么意思
  14. 画家唐小唐:中国水墨画的传承者与创新者
  15. 服务器机柜型号大全,标准机柜尺寸表
  16. Wincc经典版下载
  17. 关于Pillow与PIL
  18. 经济学方面的电子书挺多
  19. Java中2.5D游戏(斜45度角)的设计与实现(1)
  20. unity 项目实践经验 和 架构体系

热门文章

  1. python 根据身份证号计算年龄和性别_excel如何根据身份证号计算男女出生日期、性别和年龄?分享了!...
  2. Mysql经典面试题(建议收藏)
  3. error: Unable to load contents of file list: '/Users/.../Products/Debug-appletvos/myapp.app/Info....
  4. Python机器学习基础教程(1)Irises(鸢尾花)分类之新手上路
  5. 网站怎么被搜索引擎快速收录?
  6. MongoDB单机集群搭建
  7. 入行程序员培训还是不培训
  8. [work] 如果看了此文你还不懂傅里叶变换,那就过来掐死我吧【完整版】
  9. Altium中PCB板上开窗
  10. 三节点大数据环境安装教程1