IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 从0开始学习Ceres NO.2 -> 正文阅读

[C++知识库]从0开始学习Ceres NO.2

上一篇文章从0开始学习Ceres NO.1中学了用ceres自动求解一个简单的最小化问题。对于同样的问题,这篇文章介绍两个事情:

如果不用模板呢?

在某些情况下我们可能无法定义残差的模板,那么我们不得不确定地给出残差的形式。(具体什么情况我现在也不知道,碰到了再回来补充吧)
那么我们定义残差的结构体就从模板变成了:

struct  NumericDiffCostFunctor{
    bool operator()(const double* const x, double* residual) const{
        residual[0] = 10.0 -x[0];
        return true;
    }
};

主函数与原来基本相同,只是CostFunction类的定义变成了,这里我们将求导的方式从自动求导转变成了数值微分求导:

ceres::CostFunction* cost_function =
        new ceres::NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(new NumericDiffCostFunctor);

ceres::NumericDiffCostFunction
用来表示接受非模板结构体使用数值微分求导的Cost函数类,跟AutoDiffCostFunction一样都是SizedCostFunction的子类。模板参数列表为

// 对应main函数中的<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>
template <typename CostFunctor,											// 自己定义的CostFunctor结构体
          NumericDiffMethodType method = CENTRAL,			// 用于计算的微分方法
          																										// CENTRAL表示中心有限差分f'(x) ~ (f(x+h) - f(x-h)) / 2h.
          																										// FORWARD表示前向有限差分 f'(x) ~ (f(x+h) - f(x)) / h.
          																										// RIDDERS表示自适应微分
          int kNumResiduals = 0,														// 输入参数块的维度
          int... Ns>																					// 参数块每个成员的维度

主函数为

int main(){
    double initial_x=5.0;
    double x = initial_x;
    
    ceres::Problem problem;
    ceres::CostFunction* cost_function =
        new ceres::NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(new 	NumericDiffCostFunctor);

    problem.AddResidualBlock(cost_function, nullptr, &x);

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

    cout << summary.BriefReport() << endl;
    cout << "x: " << initial_x << "-> " << x << endl;

    return 0;
}

如果自己定义求导呢?

在某些情况下使用自动求导是不现实的(具体什么情况下以后再补充),那么我们可以直接继承SizedCostFunction自己编写CostFunction类,如下

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;
    }
};

在这种简单问题下,我们对CostFunction的定义只有一个任务,即重写Evaluate函数。
Evaluate
CostFunction类中计算残差和雅克比矩阵的函数,输入为:parameters参与计算的参数、residuals返回的残差容器、jacobians返回的雅克比容器。当jacobians是nullptr时不用计算残差,否则需要给出雅克比计算的定义,jacobians每一块是residuals.size()*parameters[i].size()(即残差块对第i个参数块的求导),表示每个参数对残差的求导。当jacobians[i]是nullptr时不用计算该行雅克比,在第i个参数被固定不优化时会出现这种情况。
雅克比计算如下:
j a c o b i a n s [ i ] [ r ? p a r a m e t e r s [ i ] . s i z e ( ) + c ] = δ r e s i d u a l [ r ] δ p a r a m e t e r s [ i ] [ c ] jacobians[i][r*parameters[i].size()+c]=\frac{\delta residual[r]}{\delta parameters[i][c]} jacobians[i][r?parameters[i].size()+c]=δparameters[i][c]δresidual[r]?
主函数为

int main(){
    double initial_x=5.0;
    double x = initial_x;
    
    ceres::Problem problem;

    ceres::CostFunction* cost_function = new QuadraticCostFunction;

    problem.AddResidualBlock(cost_function, nullptr, &x);

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

    cout << summary.BriefReport() << endl;
    cout << "x: " << initial_x << "-> " << x << endl;

    return 0;
}

总结

本文介绍了如何不使用模板来构造微分求导以及如何自己定义求导构造CostFunction

ceres建议使用自动求导(automatic differentiation) 而不是 数值微分求导(numeric differentiation),因为使用模板类的自动求导效率更高,且数值微分求导容易出现数值误差,导致收敛速度慢
ceres还建议除非你必须使用自定义求导,否则还是使用上面两种方式吧

文章的源程序可以去我的github下,CeresLearning中tag名字为Ceres_Turotial_02的文件
请添加图片描述

文章列表

Ceres安装和卸载 ubuntu18.04
从0开始学习Ceres NO.1
?从0开始学习Ceres NO.2
从0开始学习Ceres NO.3

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 11:50:13  更:2022-04-04 11:55:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:16:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码