Ceres學習-3.Solver


使用Ceres求解非線性優化問題,一共分為三個部分:

  1. 第一部分:構建cost fuction,即代價函數,也就是尋優的目標式。參見《Ceres學習-1.CostFunction》https://www.cnblogs.com/vivian187/p/15393995.html
  2. 第二部分:通過代價函數構建待求解的優化問題。參見《Ceres學習-2.Problem》https://www.cnblogs.com/vivian187/p/15394000.html
  3. 第三部分:配置求解器參數並求解問題,這個步驟就是設置方程怎么求解、求解過程是否輸出等,然后調用一下Solve方法。

這節就講述第三個部分:

一個簡單的應用例子

// 來自於ceres-solver-1.14.0/examples/helloworld.cc

// 第三部分: 配置並運行求解器

// Run the solver!
Solver::Options options;
options.minimizer_progress_to_stdout = true;
options.linear_solver_type = ceres::DENSE_QR;
Solver::Summary summary; // 優化信息
Solve(options, &problem, &summary);// 求解!!!

std::cout << summary.BriefReport() << "\n"; // 輸出優化的簡要信息

求解最小二乘問題

ceres::Solve函數是Ceres求解最小二乘問題的核心函數,函數原型如下:

// 來自於ceres-solver-1.14.0/include/ceres/solver.h

void Solve(const Solver::Options& options, Problem* problem, Solver::Summary* summary);

參數:

Solver::Options 求解選項。是Ceres求解的核心,包括消元順序、分解方法、收斂精度等在內的求解器所有行為均由Solver::Options控制。
Problem         求解問題。參考《Ceres學習-2.Problem》
Solver::Summary 求解報告。用於存儲求解過程中的相關信息,並不影響求解器性能

參數詳解

Solver::Options

Solver::Options含有的參數種類繁多,API文檔中對於每個參數的作用和意義都給出了詳細的說明。由於在大多數情況下,絕大多數參數我們都會使用Ceres的默認設置。列舉了一些可能會改變的參數:

  • linear_solver_type:信賴域方法中求解線性方程組所使用的求解器類型,默認為DENSE_QR,其他可選項如下:
    DENSE_QR:QR分解,用於小規模最小二乘問題求解;
    DENSE_NORMAL_CHOLESKY&SPARSE_NORMAL_CHOLESKY:Cholesky分解,用於具有稀疏性的大規模非線性最小二乘問題求解;
    CGNR:使用共軛梯度法求解稀疏方程;
    DENSE_SCHUR&SPARSE_SCHUR:SCHUR分解,用於BA問題求解;
    ITERATIVE_SCHUR:使用共軛梯度SCHUR求解BA問題;
  • min_linear_solver_iteration/max_linear_solver_iteration:線性求解器的最小/最大迭代次數,默認為0/500,一般不需要更改;

  • max_num_iterations:求解器的最大迭代次數;

  • num_threads:Ceres求解時使用的線程數

  • linear_solver_ordering:線性方程求解器的消元順序,默認為NULL,即由Ceres自行決定消元順序;在以BA為典型代表的,對消元順序有特殊要求的應用中,可以通過成員函數reset設定消元順序,稍后將詳細說明;

linear_solver_ordering

Ceres消元順序的設置由linear_solver_ordering的reset函數完成,該函數接受參數為ParameterBlockOrdering對象。該對象將所有待優化參數存儲為帶標記(ID)的組(Group),
ID小的Group在求解線性方程的過程中會被首先消去。因此,我們需要做的第一個工作是調用其成員函數AddElementToGroup將參數添加到對應ID的Group中,函數原型為:

bool ParameterBlockOrdering::AddElementToGroup(const double *element, const int group)

接收的元素為變量數組的指針;組ID為非負整數,最小為0,如果該Id對應的Group不存在,則Ceres會自動創建。下面我們來看一個BA中的例子:

ceres::ParameterBlockOrdering* ordering = new ceres::ParameterBlockOrdering();

    // set all points in ordering to 0
    for(int i = 0; i < num_points; i++){
        ordering->AddElementToGroup(points + i * point_block_size, 0);
    }
    // set all cameras in ordering to 1
    for(int i = 0; i < num_cameras; i++){
        ordering->AddElementToGroup(cameras + i * camera_block_size, 1);
    }

該例子中,所有路標點被分到了ID = 0組,而所有相機位姿被分到了ID = 1組,因此在線性方程組的求解中,所有路標點會變首先SCHUR消元。

接下來,我們就可以使用reset函數制定線性求解器的消元順序了:

// set ordering in options
options->linear_solver_ordering.reset(ordering);

在實際應用中,對最終求解性能最大的就是線性方程求解器類型linear_solver_type和線程數,如果發現最后的求解精度或求解效率不能滿足要求,應首先嘗試更換這兩個參數。

Solver::Summary

Solver::Summary包含了求解器本身和求解中各變量的信息,許多成員函數與Solver::Options一致,詳細列表同樣請參閱API文檔,這里只給出另外兩個常用的成員函數:

  • BriefReport():輸出單行的簡單總結;
  • FullReport():輸出多行的完整總結。

實例Bundle Adjustment,參照下面兩個網站

https://blog.csdn.net/weixin_43991178/article/details/100568128?utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link 《最小二乘問題構建與求解》

https://www.cnblogs.com/vivian187/p/15331483.html 《5.Ceres官方教程-非線性最小二乘~Bundle Adjustment》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM