Ceres优化库学习01----HelloWorld 构建一个极简线性优化问题(使用自动求导的方式)

本文展示了如何使用Ceres优化库构建一个简单的最小二乘问题,通过定义CostFunctor并利用自动求导实现非线性问题求解。从初始值5.0出发,经过两次迭代,解得x=10。代码示例包括CPP和CMakeLists.txt配置。
摘要由CSDN通过智能技术生成

在这里插入图片描述

  本文介绍如何使用ceres优化库搭建一个最小二乘问题,要提前安装好ceres库。

一、问题定义

  首先,考虑寻找函数最小值的问题:
1 2 ( 10 − x ) 2 . \frac{1}{2}(10 -x)^2. 21(10x)2.
  这是一个很简单的问题,其最小值位于 x = 10 x = 10 x=10,但这是一个很好的说明用Ceres解决问题的函数。第一步是编写一个代价函数CostFunctor,这个代价函数CostFunctor可以用来衡量 1 2 ( 10 − x ) 2 \frac{1}{2}(10 -x)^2 21(10x)2的大小,我们选用原函数的导数形式 f ( x ) = 10 − x f(x) = 10 - x f(x)=10x作为代价函数,该代价函数的为0时对应原函数的最小值。

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

  这里需要注意的重要一点是,operator()是一种模板化方法,它假设其所有输入和输出都是某种类型的T。这里使用模板化允许Ceres调用CostFunctor::operator<T>(),当只需要残差值时使用T=double,当需要雅可比时使用特殊类型T=Jet

  一旦我们有了计算残差函数的方法,现在是时候用它来构造一个非线性最小二乘问题,并让Ceres解决它了。本文使用自动求导的方式进行求解,关于自动求导的介绍以及其余求导方式的介绍,见博主的其他博客。(链接待补充…)

int main(int argc, char** argv) {
  
  // 定义要优化求解的变量,并赋予初值
  double initial_x = 5.0;
  double x = initial_x;

  // 构建problem
  ceres::Problem problem;

  // Set up the only cost function (also known as residual). This uses
  // auto-differentiation to obtain the derivative (jacobian).
  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);

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

AutoDiffCostFunction将一个CostFunctor作为输入,自动对其进行微分,并为其提供一个CostFunction接口。

iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
   0  1.250000e+01    0.00e+00    5.00e+00   0.00e+00   0.00e+00  1.00e+04        0    1.69e-05    3.70e-05
   1  1.249750e-07    1.25e+01    5.00e-04   5.00e+00   1.00e+00  3.00e+04        1    2.79e-05    1.12e-04
   2  1.388518e-16    1.25e-07    1.67e-08   5.00e-04   1.00e+00  9.00e+04        1    5.01e-06    1.27e-04
Ceres Solver Report: Iterations: 3, Initial cost: 1.250000e+01, Final cost: 1.388518e-16, Termination: CONVERGENCE
x : 5 -> 10

  从x=5开始,求解器在两次迭代中变为10。细心的读者会注意到这是一个线性问题,一个线性解应该足以获得最佳值。求解器的默认配置是针对非线性问题的,为了简单起见,在本例中我们没有更改它。确实可以使用Ceres在一次迭代中获得该问题的解决方案。还要注意,在第一次迭代中,解算器确实非常接近最优函数值0。在讨论Ceres的收敛性和参数设置时,我们将更详细地讨论这些问题。

二、完整代码

1.CPP代码

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

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

int main(int argc, char** argv) {
  
  // 定义要优化求解的变量,并赋予初值
  double initial_x = 5.0;
  double x = initial_x;

  // 构建problem
  ceres::Problem problem;

  // Set up the only cost function (also known as residual). This uses
  // auto-differentiation to obtain the derivative (jacobian).
  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);

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

2.CMakeLists.txt配置文件

cmake_minimum_required(VERSION 2.8)

project(ceres_test)
set(CMAKE_CXX_STANDARD 14)

find_package(Ceres REQUIRED )

include_directories( ${CERES_INCLUDE_DIRS})
# include_directories("/usr/include/eigen3")

add_executable(HelloWorld HelloWorld.cpp)
target_link_libraries(HelloWorld ${CERES_LIBRARIES})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值