Ceres Solver: 高效的非線性優化庫(一)

Ceres Solver: 高效的非線性優化庫(一)html

注:本文基於Ceres官方文檔,大部分由英文翻譯而來。可做爲非官方參考文檔。linux


簡介

Ceres,原意是穀神星,是發現不久的一顆軌道在木星和火星之間「矮行星」(冥王星降級以後,同爲矮行星)。Google開源了Ceres Solver庫,是一個解不少非線性最優化問題的高效、方便的工具。git


安裝

引用地址:http://ceres-solver.org/installation.htmlgithub

目前開源方未提供可安裝文件。須要源碼下載編譯。
下載方式,首先安裝Git。Git,主流版本管理工具,使用方法見官方文檔。
git clone https://ceres-solver.googlesource.com/ceres-solver
依賴項:函數

  • Eigen,好用的數學庫,無源碼,所有是頭文件。
  • CMake,工程生產工具,跨平臺。
  • Glog,log庫,選裝。TBB,選裝。
  • Gflags,SuiteSparse, CXSparse,BLAS,LAPACK主要是用來解大型稀疏矩陣的,必需要裝。

Linux系統下能夠很方便的用命令行安裝各類庫。
sudo apt-get install cmake libatalas-base-dev libeigen3-dev libsuitesparse-dev
安裝Ceres-Solver,根據CMake的方式,進入Ceres目錄,工具

mkdir build & cmake ..
make -j4
sudo make install

能夠愉快的使用Ceres啦!先看Example,有示例嘛,學起來更快!
直接運行一下以下結果,
bin/simple_bundle_adjuster ../ceres-solver-1.14.0/data/problem-16-22106-pre.txt
彷佛成功了?輸出不少內容,好像看不懂。不要緊,能運行成功,說明Ceres安裝成功,能夠愉快的使用。
注:這裏解釋的是更多在linux下面安裝。Widows下基本大同小異,須要花點時間的是SuiteSparse幾個三方庫的安裝和配置,不過也並不複雜。優化


實戰

找到並使用Ceres-Solver

推薦使用CMake工具找到並使用Ceres,相似OpenCV。網站

什麼是非線性最小二乘問題

Ceres-Solver可解形以下列公式的問題
\[ \begin{split}\min_{\mathbf{x}} &\quad \frac{1}{2}\sum_{i} \rho_i\left(\left\|f_i\left(x_{i_1}, ... ,x_{i_k}\right)\right\|^2\right) \\ \text{s.t.} &\quad l_j \le x_j \le u_j\end{split} \]
有點複雜,具體什麼含義呢?
好比,平面(空間)不少帶噪聲的點,咱們要擬合一條直線(平面)或曲線。好比,三維視覺的全局最優問題。
曲線擬合問題
注意:直線擬合通常也可用線性迴歸解決。
公式中的目標函數集合稱之爲殘差項,目標是是這個值最小;\(f_i\)函數被稱爲代價函數,由參數\(x_i\)組成。\(l_i, u_j\)則是函數的取值範圍。
下面用了一個具體的示例說明。
求以下目標函數的最小值。
\[ \frac{1}{2}(10 -x)^2. \]
經過求二階導數咱們很容易知道x=10時,最小值取0.但這裏咱們嘗試用Ceres來解決。ui

  • 第一步,代價函數\(f(x) = 10 - x\).
struct CostFunctor {
   template <typename T>
   bool operator()(const T* const x, T* residual) const {
     residual[0] = T(10.0) - x[0];
     return true;
   }};

代碼中符號()是一個模板方法,輸入是同一類型。google

  • 第二步,構建非線性最小二乘問題。
int main(int argc, char** argv)
 {
  // The variable to solve for with its initial value.
  double initial_x = 5.0;
  double x = initial_x;

  // Build the problem.
  Problem problem;

  // Set up the only cost function (also known as residual). This uses
  // auto-differentiation to obtain the derivative (jacobian).
  CostFunction* cost_function =
      new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
  problem.AddResidualBlock(cost_function, NULL, &x);

  // Run the solver!
  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;
}

AutoDiffCostFunctionCostFunctor做爲輸入,並提供了一個自動求微分的接口。
計算example/helloworld.cc會獲得相應輸出結果。

iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
   0  4.512500e+01    0.00e+00    9.50e+00   0.00e+00   0.00e+00  1.00e+04       0    5.33e-04    3.46e-03
   1  4.511598e-07    4.51e+01    9.50e-04   9.50e+00   1.00e+00  3.00e+04       1    5.00e-04    4.05e-03
   2  5.012552e-16    4.51e-07    3.17e-08   9.50e-04   1.00e+00  9.00e+04       1    1.60e-05    4.09e-03
Ceres Solver Report: Iterations: 2, Initial cost: 4.512500e+01, Final cost: 5.012552e-16, Termination: CONVERGENCE
x : 0.5 -> 10

實際上此示例是個線性問題,卻能很好的解釋非線性優化的思想。 接下來的文章會處理一些更加複雜的問題,敬請期待。

相關文章
相關標籤/搜索