Ceres詳解(三)最小二乘問題構建與求解

2021-09-26 21:52:27 字數 4741 閱讀 2219

solver::summary

在前兩講中,我們研究了ceres中代表最小二乘問題的problem類以及代表誤差函式的類costfunction,本講我們以bundle adjustment為例,研究如何利用這兩個類構建最小二乘問題,並使用ceres::solve()函式求解。

例子中使用的資料集為bundle adjustment in the large

資料集,完整的示例**參見github。

首先我們需要構建乙個balproblem物件用於資料集的讀取和儲存,該類的源**位於bal_problem.hbal_problem.cpp中,本例中我們需要用到的成員函式說明如下:

這裡需要說明下,bal資料集中的1次觀測定義為乙個相機位姿+乙個空間點3d座標+空間點2d畫素座標

balproblem bal_problem;

// 建立balproblem物件

// 由命令列給定的路徑讀取資料集檔案if(

!bal_problem.

loadfile

(ar**[1]

))// 獲取資料集的觀測量資訊,在ba問題中為二維畫素座標[u, v]

const

double

* observations = bal_problem.

observations()

;

隨後我們構建乙個ceres::problem物件,並利用addresidualblock向其中新增殘差模組。這裡由於資料集本身使用的位姿表示即旋轉向量,不需要使用localparameterization進行區域性引數重構,因此並沒有使用addparameterblock()顯式傳遞引數。

在後續vins-mono的**分析中我們將看到,由於使用的優化引數為四元數,需要使用localparameterization將四元數重構為三維旋轉向量進行優化和更新,就必須使用addparameterblock()顯式傳遞引數。

// 構建ba問題

ceres::problem problem;

for(

int i =

0; i < bal_problem.

num_observations()

; i++

)

至此,乙個最小二乘ba問題邊構建完成了,接下來我們使用ceres::solve函式求解該問題。

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

void

solve

(const solver::options& options, problem* problem, solver::summary* summary)

函式接受的三個引數分別為求解選項solver::options、求解問題problem以及求解報告solver::summary。其中problem類我們已經在第一講詳細介紹過;solver::summary只用於儲存求解過程中的相關資訊,並不影響求解器效能;solver::options則是ceres求解的核心,包括消元順序、分解方法、收斂精度等在內的求解器所有行為均由solver::options控制。

solver::options含有的引數種類繁多,api文件中對於每個引數的作用和意義都給出了詳細的說明。由於在大多數情況下,絕大多數引數我們都會使用ceres的預設設定,這裡只列出一些常用或較為重要的引數。

linear_solver_ordering:線性方程求解器的消元順序,預設為null,即由ceres自行決定消元順序;在以ba為典型代表的,對消元順序有特殊要求的應用中,可以通過成員函式reset設定消元順序,稍後將詳細說明;

min_linear_solver_iteration/max_linear_solver_iteration:線性求解器的最小/最大迭代次數,預設為0/500,一般不需要更改;

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

max_solver_time_in_seconds:求解器的最大執行秒數;

num_threads:ceres求解時使用的執行緒數,在老版本的ceres中還有乙個針對線性求解器的執行緒設定選項num_linear_solver_threads,最新版本的ceres中該選項已被取消;雖然為了保證程式的相容性,使用者依舊可以設定該引數,但ceres會自動忽略該引數,並沒有實際意義;

minimizer_progress_to_stdout:是否向終端輸出優化過程資訊,具體內容稍後詳細說明;

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

ceres消元順序的設定由linear_solver_orderingreset函式完成,該函式接受引數為parameterblockordering物件。該物件將所有待優化引數儲存為帶標記(id)的組(group),id小的group在求解線性方程的過程中會被首先消去。因此,我們需要做的第乙個工作是呼叫其成員函式addelementtogroup將引數新增到對應idgroup中,函式原型為:

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++

)// set all cameras in ordering to 1

for(

int i =

0; i < num_cameras; i++

)

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

// set ordering in options

options-

>linear_solver_ordering.

reset

(ordering)

;

該選型預設為false,即根據vlog設定等級的不同,只會在向stderr中輸出錯誤資訊;若設定為true則會向程式的執行終端輸出優化過程的所有資訊,根據所設定優化方法的不同,輸出的引數亦不同。

線性搜尋方法

現在我們來看本例中的求解器設定,

ceres::solver::options options;

options.linear_solver_type = ceres::dense_schur;

//使用dense_schur分解

options.minimizer_progress_to_stdout =

true

;// 輸出優化過程資訊

solver::summary包含了求解器本身和求解中各變數的資訊,許多成員函式與solver::options一致,詳細列表同樣請參閱api文件,這裡只給出另外兩個常用的成員函式:

現在我們來看本例中的solver::summary的使用:

ceres::solver::summary summary;

ceres::

solve

(options,

&problem,

&summary)

;std::cout << summary.

fullreport()

<<

"\n"

;// 輸出完整的報告

最小二乘擬合 6 7 最小二乘擬合問題

資料擬合問題的一般形式 任給一組離散資料 注 這裡的擬合函式不一定為多項式函式 記殘量的平方和為 求使得殘量平方和最小得一組係數就是線性最小二乘問題,為最小二乘問題得基函式,求得的擬合函式為資料的最小二乘擬合。求解 利用偏導數為零得到極值點的原理可以得到最小二乘問題滿足的方程組,求解方程組中未知係數...

最小二乘擬合詳解

最小二乘法多項式曲線擬合,根據給定的m個點,並不要求這條曲線精確地經過這些點,而是曲線y f x 的近似曲線y x 原理部分由個人根據網際網路上的資料進行總結,希望對大家能有用 給定資料點pi xi,yi 其中i 1,2,m。求近似曲線y x 並且使得近似曲線與y f x 的偏差最小。近似曲線在點p...

最小二乘 加權最小二乘 matlab實現

最小二乘 最小二乘法 又稱最小平方法 是一種數學優化技術。它通過最小化誤差的平方和尋找資料的最佳函式匹配。利用最小二乘法可以簡便地求得未知的資料,並使得這些求得的資料與實際資料之間誤差的平方和為最小 最小二乘法還可用於曲線擬合,其他一些優化問題也可通過最小化能量或最大化熵用最小二乘法來表達。加權最小...