非线性优化

  • 6.1 状态估计问题
    • 6.1.1 批量状态估计与最大后验估计
    • 6.1.2 最小二乘的引出
    • 6.1.3 最小二乘问题解析解
  • 6.2 非线性最小二乘
    • 6.2.1 一阶和二阶梯度法
      • (1)最速下降法
      • (2)牛顿法
      • (3)小结 1
      • (4)**补充:矩阵求导公式**
    • 6.2.2 高斯牛顿法
      • **高斯牛顿法的缺陷**
    • 6.2.3 列文伯格——马夸尔特方法
      • 列文伯格-马夸尔特算法伪代码
    • 6.2.4 Dogleg最小化法(占坑)
  • 6.3 实践:曲线拟合问题
    • 6.3.2 手写高斯牛顿法
    • 6.3.1 手写列文伯格-马夸尔特方法
    • 6.3.3 使用Ceres进行曲线拟合(占坑)
    • 6.3.4 使用g2o进行曲线拟合(占坑)
    • 6.3.5 使用GTSAM进行曲线拟合(占坑)

6.1 状态估计问题

6.1.1 批量状态估计与最大后验估计

考虑从111到NNN的所有时刻,并假设有MMM个路标点。定义所有时刻的机器人位姿和路标点坐标为
x={x1,…,xN},y={y1,…,yM}\boldsymbol{x}=\left\{\boldsymbol{x}_{1}, \ldots, \boldsymbol{x}_{N}\right\}, \quad \boldsymbol{y}=\left\{\boldsymbol{y}_{1}, \ldots, \boldsymbol{y}_{M}\right\} x={x1​,…,xN​},y={y1​,…,yM​}
同样地, 用不带下标的 u\boldsymbol{u}u 表示所有时刻的输人, z\boldsymbol{z}z 表示所有时刻的观测数据。 对机 器人状态的估计, 就是已知输人数据 u\boldsymbol{u}u 和观测数据 z\boldsymbol{z}z 的条件下, 求状态 x,y\boldsymbol{x}, \boldsymbol{y}x,y 的条件概率分布:
P(x,y∣z,u)(6.4)P(\boldsymbol{x}, \boldsymbol{y} \mid \boldsymbol{z}, \boldsymbol{u})\tag{6.4} P(x,y∣z,u)(6.4)
特别地, 当我们不知道控制输人, 只有一张张的图像时, 即只考虑观测方程带来的数据时, 相当于估计 P(x,y∣z)P(\boldsymbol{x}, \boldsymbol{y} \mid \boldsymbol{z})P(x,y∣z) 的条件概率分布, 此问题也称为 SfM\mathrm{SfM}SfM , 即如何从许多图像中重建三维空间结构。为了估计状态变量的条件分布, 利用贝叶斯法则, 有
P(x,y∣z,u)=P(z,u∣x,y)P(x,y)P(z,u)∝P(z,u∣x,y)⏟似然 P(x,y)⏟先验 .(6.5)P(\boldsymbol{x}, \boldsymbol{y} \mid \boldsymbol{z}, \boldsymbol{u})=\frac{P(\boldsymbol{z}, \boldsymbol{u} \mid \boldsymbol{x}, \boldsymbol{y}) P(\boldsymbol{x}, \boldsymbol{y})}{P(\boldsymbol{z}, \boldsymbol{u})} \propto \underbrace{P(\boldsymbol{z}, \boldsymbol{u} \mid \boldsymbol{x}, \boldsymbol{y})}_{\text {似然 }} \underbrace{P(\boldsymbol{x}, \boldsymbol{y})}_{\text {先验 }} .\tag{6.5} P(x,y∣z,u)=P(z,u)P(z,u∣x,y)P(x,y)​∝似然 P(z,u∣x,y)​​先验 P(x,y)​​.(6.5)
贝叶斯法则左侧称为后验概率,右侧的P(z∣x)P(\boldsymbol{z} \mid \boldsymbol{x})P(z∣x)称为似然 (Likehood),另一部分P(x)P(\boldsymbol{x})P(x)称为先验 (Prior)

注:式(6.5)的一个重要意义是,当先验概率确定时,后验概率与似然成正比。

直接求后验分布是困难的,但是求一个状态最有估计,使得在该状态下后验概率最大化,则是可行的:
(x,y)MAP ∗=arg⁡max⁡P(x,y∣z,u)=arg⁡max⁡P(z,u∣x,y)P(x,y)(6.6)(\boldsymbol{x}, \boldsymbol{y})_{\text {MAP }}^{*}=\arg \max P(\boldsymbol{x}, \boldsymbol{y} \mid \boldsymbol{z}, \boldsymbol{u})=\arg \max P(\boldsymbol{z}, \boldsymbol{u} \mid \boldsymbol{x}, \boldsymbol{y}) P(\boldsymbol{x}, \boldsymbol{y}) \tag{6.6} (x,y)MAP ∗​=argmaxP(x,y∣z,u)=argmaxP(z,u∣x,y)P(x,y)(6.6)
贝叶斯法则的分母部分与待估计的状态x,y\boldsymbol{x}, \boldsymbol{y}x,y无关,因而可以忽略。贝叶斯法则告诉我们,求解最大后验概率等价于最大化似然与先验的乘积。如果我们不知道机器人位姿或路标大概在在什么地方(预测),此时就没有了先验。那么,可以求解最大似然估计:
(x,y)MLE∗=arg⁡max⁡P(z,u∣x,y)(6.7)(\boldsymbol{x}, \boldsymbol{y})_{\mathrm{MLE}}^{*}=\arg \max P(\boldsymbol{z}, \boldsymbol{u} \mid \boldsymbol{x}, \boldsymbol{y}) \tag{6.7} (x,y)MLE∗​=argmaxP(z,u∣x,y)(6.7)
通过贝叶斯法则,我们的求解目标由“基于现在观测到的数据,机器人最可能处于什么样的状态”转换成“在什么样的状态下,最可能产生现在观测到的数据”。

6.1.2 最小二乘的引出

SLAM的观测模型:
zk,j=h(yj,xk)+vk,j\boldsymbol{z}_{k, j}=h\left(\boldsymbol{y}_{j}, \boldsymbol{x}_{k}\right)+\boldsymbol{v}_{k, j} zk,j​=h(yj​,xk​)+vk,j​
由于我们假设了噪声项 vk∼N(0,Qk,j)\boldsymbol{v}_{k} \sim \mathcal{N}\left(0, \boldsymbol{Q}_{k, j}\right)vk​∼N(0,Qk,j​) , 所以观测数据的条件概率为
P(zj,k∣xk,yj)=N(h(yj,xk),Qk,j)P\left(\boldsymbol{z}_{j, k} \mid \boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right)=N\left(h\left(\boldsymbol{y}_{j}, \boldsymbol{x}_{k}\right), \boldsymbol{Q}_{k, j}\right) P(zj,k​∣xk​,yj​)=N(h(yj​,xk​),Qk,j​)
它依然是一个高斯分布。考虑单次观测的最大似然估计, 可以使用最小化负对数来求一个高斯分布的最大似然。

我们知道高斯分布在负对数下有较好的数学形式。考虑任意高维高斯分布 x∼N(μ,Σ)x \sim \mathcal{N}(\mu, \Sigma)x∼N(μ,Σ) , 它 的概率密度函数展开形式为
P(x)=1(2π)Ndet⁡(Σ)exp⁡(−12(x−μ)TΣ−1(x−μ))(6.8)P(\boldsymbol{x})=\frac{1}{\sqrt{(2 \pi)^{N} \operatorname{det}(\boldsymbol{\Sigma})}} \exp \left(-\frac{1}{2}(\boldsymbol{x}-\boldsymbol{\mu})^{\mathrm{T}} \boldsymbol{\Sigma}^{-1}(\boldsymbol{x}-\boldsymbol{\mu})\right)\tag{6.8} P(x)=(2π)Ndet(Σ)​1​exp(−21​(x−μ)TΣ−1(x−μ))(6.8)
对其取负对数, 则变为
−ln⁡(P(x))=12ln⁡((2π)Ndet⁡(Σ))+12(x−μ)TΣ−1(x−μ)(6.9)-\ln (P(\boldsymbol{x}))=\frac{1}{2} \ln \left((2 \pi)^{N} \operatorname{det}(\boldsymbol{\Sigma})\right)+\frac{1}{2}(\boldsymbol{x}-\boldsymbol{\mu})^{\mathrm{T}} \boldsymbol{\Sigma}^{-1}(\boldsymbol{x}-\boldsymbol{\mu})\tag{6.9} −ln(P(x))=21​ln((2π)Ndet(Σ))+21​(x−μ)TΣ−1(x−μ)(6.9)
因为对数函数时单调递增的,所有对原函数求最大化相当于对负对数求最小化。在最小化上式的x\boldsymbol{x}x时,第一项与x\boldsymbol{x}x无关,可以略去。于是,只要最小化右侧的二次型项,就得到了对状态的最大似然估计。代入SLAM的观测模型,相当于在求:
(xk,yj)∗=arg⁡max⁡N(h(yj,xk),Qk,j)=arg⁡min⁡((zk,j−h(xk,yj))TQk,j−1(zk,j−h(xk,yj)))(6.10)\begin{aligned} \left(\boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right)^{*} &=\arg \max \mathcal{N}\left(h\left(\boldsymbol{y}_{j}, \boldsymbol{x}_{k}\right), \boldsymbol{Q}_{k, j}\right) \\ &=\arg \min \left(\left(\boldsymbol{z}_{k, j}-h\left(\boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right)\right)^{\mathrm{T}} \boldsymbol{Q}_{k, j}^{-1}\left(\boldsymbol{z}_{k, j}-h\left(\boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right)\right)\right) \end{aligned}\tag{6.10} (xk​,yj​)∗​=argmaxN(h(yj​,xk​),Qk,j​)=argmin((zk,j​−h(xk​,yj​))TQk,j−1​(zk,j​−h(xk​,yj​)))​(6.10)
该式等价于最小化噪声项(即误差)的马氏距离

现在我们考虑批量时刻的数据。通常假设各个时刻的输入和观测是相互独立的,这意味着各个输入之间的独立的,各个观测之间是独立的,并且输入和观测也是独立的。于是我们可以对联合分布进行因式分解:
P(z,u∣x,y)=∏kP(uk∣xk−1,xk)∏k,jP(zk,j∣xk,yj)(6.11)P(\boldsymbol{z}, \boldsymbol{u} \mid \boldsymbol{x}, \boldsymbol{y})=\prod_{k} P\left(\boldsymbol{u}_{k} \mid \boldsymbol{x}_{k-1}, \boldsymbol{x}_{k}\right) \prod_{k, j} P\left(\boldsymbol{z}_{k, j} \mid \boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right)\tag{6.11} P(z,u∣x,y)=k∏​P(uk​∣xk−1​,xk​)k,j∏​P(zk,j​∣xk​,yj​)(6.11)
这说明我们可以独立地处理各时刻的运动和观测。定义各次输人和观测数据与模型之间的误差:
eu,k=xk−f(xk−1,uk)ez,j,k=zk,j−h(xk,yj)(6.12)\begin{aligned} e_{\boldsymbol{u}, k} &=\boldsymbol{x}_{k}-f\left(\boldsymbol{x}_{k-1}, \boldsymbol{u}_{k}\right) \\ e_{\boldsymbol{z}, j, k} &=\boldsymbol{z}_{k, j}-h\left(\boldsymbol{x}_{k}, \boldsymbol{y}_{j}\right) \end{aligned}\tag{6.12} eu,k​ez,j,k​​=xk​−f(xk−1​,uk​)=zk,j​−h(xk​,yj​)​(6.12)
那么, 最小化所有时刻估计值与真实读数之间的马氏距离, 等价于求最大似然估计。负对数允许我们把乘积变成求和:
min⁡J(x,y)=∑keu,kTRk−1eu,k+∑k∑jez,k,jTQk,j−1ez,k,j(6.13)\min J(\boldsymbol{x}, \boldsymbol{y})=\sum_{k} e_{\boldsymbol{u}, k}^{\mathrm{T}} \boldsymbol{R}_{k}^{-1} \boldsymbol{e}_{\boldsymbol{u}, k}+\sum_{k} \sum_{j} e_{\boldsymbol{z}, k, j}^{\mathrm{T}} \boldsymbol{Q}_{k, j}^{-1} e_{\boldsymbol{z}, k, j}\tag{6.13} minJ(x,y)=k∑​eu,kT​Rk−1​eu,k​+k∑​j∑​ez,k,jT​Qk,j−1​ez,k,j​(6.13)
这样就得到了一个最小二乘问题,它的解等价于状态的最大似然估计。

6.1.3 最小二乘问题解析解

最小二乘的目标函数为
min⁡∑k=13eu,kTQk−1eu,k+∑k=13ez,kTRk−1ez,k\min \sum_{k=1}^{3} e_{\boldsymbol{u}, k}^{\mathrm{T}} \boldsymbol{Q}_{k}^{-1} e_{\boldsymbol{u}, k}+\sum_{k=1}^{3} e_{\boldsymbol{z}, k}^{\mathrm{T}} \boldsymbol{R}_{k}^{-1} \boldsymbol{e}_{z, k} mink=1∑3​eu,kT​Qk−1​eu,k​+k=1∑3​ez,kT​Rk−1​ez,k​
如果系统是线性系统,那么我们可以很容易地将它写成向量形式,定义向量y=[u,z]T\mathrm{y}=[\mathrm{u},\mathrm{z}]^Ty=[u,z]T,那么可以写出矩阵H\mathrm{H}H,使得
y−Hx=e∼N(0,Σ)y-H x=e \sim \mathcal{N}(0, \Sigma) y−Hx=e∼N(0,Σ)
那么:
H=[1−10001−10001−1010000100001]\boldsymbol{H}=\left[\begin{array}{cccc} 1 & -1 & 0 & 0 \\ 0 & 1 & -1 & 0 \\ 0 & 0 & 1 & -1 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right] H=⎣⎢⎢⎢⎢⎢⎢⎡​100000​−110100​0−11010​00−1001​⎦⎥⎥⎥⎥⎥⎥⎤​
且 Σ=diag⁡(Q1,Q2,Q3,R1,R2,R3)\boldsymbol{\Sigma}=\operatorname{diag}\left(\boldsymbol{Q}_{1}, \boldsymbol{Q}_{2}, \boldsymbol{Q}_{3}, \boldsymbol{R}_{1}, \boldsymbol{R}_{2}, \boldsymbol{R}_{3}\right)Σ=diag(Q1​,Q2​,Q3​,R1​,R2​,R3​) 。整个问题可以写成
xmap∗=arg⁡min⁡eTΣ−1ex_{\mathrm{map}}^{*}=\arg \min e^{\mathrm{T}} \Sigma^{-1} e xmap∗​=argmineTΣ−1e
之后我们将看到, 这个问题有唯一的解:
xmap∗=(HTΣ−1H)−1HTΣ−1y\boldsymbol{x}_{\mathrm{map}}^{*}=\left(\boldsymbol{H}^{\mathrm{T}} \boldsymbol{\Sigma}^{-1} \boldsymbol{H}\right)^{-1} \boldsymbol{H}^{\mathrm{T}} \boldsymbol{\Sigma}^{-1} \boldsymbol{y} xmap∗​=(HTΣ−1H)−1HTΣ−1y

6.2 非线性最小二乘

最小二乘问题的基本形式:
min⁡xF(x)=12∥f(x)∥22(6.24)\min _{\boldsymbol{x}} F(\boldsymbol{x})=\frac{1}{2}\|f(\boldsymbol{x})\|_{2}^{2} \tag{6.24} xmin​F(x)=21​∥f(x)∥22​(6.24)
迭代求解过程:

  1. 给定某个初始值x0x_0x0​
  2. 给定第kkk次迭代,寻找一个增量Δxk\Delta x_kΔxk​,使得∣∣f(xk+Δxk)∣∣22||f(x_k+\Delta x_k)||^2_2∣∣f(xk​+Δxk​)∣∣22​达到极小值
  3. 若Δxk\Delta x_kΔxk​足够小,则停止
  4. 否则,令xk+1=xk+Δxkx_{k+1}=x_k+\Delta x_kxk+1​=xk​+Δxk​,返回第2步

6.2.1 一阶和二阶梯度法

将目标方程在xkx_kxk​附近进行泰勒展开:
F(xk+Δxk)≈F(xk)+J(xk)TΔxk+12ΔxkTH(xk)Δxk(6.26)F\left(\boldsymbol{x}_{k}+\Delta \boldsymbol{x}_{k}\right) \approx F\left(\boldsymbol{x}_{k}\right)+\boldsymbol{J}\left(\boldsymbol{x}_{k}\right)^{\mathrm{T}} \Delta \boldsymbol{x}_{k}+\frac{1}{2} \Delta \boldsymbol{x}_{k}^{\mathrm{T}} \boldsymbol{H}\left(\boldsymbol{x}_{k}\right) \Delta \boldsymbol{x}_{k}\tag{6.26} F(xk​+Δxk​)≈F(xk​)+J(xk​)TΔxk​+21​ΔxkT​H(xk​)Δxk​(6.26)
其中 J(xk)\boldsymbol{J}\left(\boldsymbol{x}_{k}\right)J(xk​) 是 F(x)F(\boldsymbol{x})F(x) 关于 x\boldsymbol{x}x 的一阶导数 [也叫梯度、雅可比 ( Jacobian ) 矩阵],H\boldsymbol{H}H 则是二阶 导数 [海塞 (Hessian ) 矩阵],它们都在 xkx_{k}xk​ 处取值。

(1)最速下降法

如果保留一阶梯度,那么取增量为反向的梯度,即可保证函数下降:
Δx∗=−J(xk)(6.27)\Delta x^{*}=-J\left(x_{k}\right)\tag{6.27} Δx∗=−J(xk​)(6.27)
当然这只是个方向,通常我们还要再指定一个步长λ\lambdaλ。

(2)牛顿法

我们可以对式(6.26)保留二阶梯度信息,此时增量方程味:
Δx∗=arg⁡min⁡(F(x)+J(x)TΔx+12ΔxTHΔx)(6.28)\Delta \boldsymbol{x}^{*}=\arg \min \left(F(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \Delta \boldsymbol{x}+\frac{1}{2} \Delta \boldsymbol{x}^{\mathrm{T}} \boldsymbol{H} \Delta \boldsymbol{x}\right)\tag{6.28} Δx∗=argmin(F(x)+J(x)TΔx+21​ΔxTHΔx)(6.28)
右侧只含 Δx\Delta xΔx 的零次、一次和二次项。求右侧等式关于 Δx\Delta xΔx 的导数并令它为零,得到
J+HΔx=0⇒HΔx=−J(6.29)J+H \Delta x=0 \Rightarrow H \Delta x=-J\tag{6.29} J+HΔx=0⇒HΔx=−J(6.29)
求解这个Δx=−H−1J\Delta x=-H^{-1}JΔx=−H−1J即可得到增量。

(3)小结 1

  1. 最速下降法过于贪心,容易走出锯齿路线,反而增加了迭代次数。
  2. 牛顿法需要计算目标函数的HHH矩阵,这在问题规模较大时非常困难,我们通常倾向于避免HHH的计算。

(4)补充:矩阵求导公式

若 f(X)和g(X)f(\mathbf{X}) 和 g(\mathbf{X})f(X)和g(X) 分别是矩阵 X\mathbf{X}X 的实值函数, c1,c2c_{1}, c_{2}c1​,c2​ 为实常数, 则

  • 线性法则 :
    ∂[c1f(X)+c2g(X)]∂X=c1∂f∂X+c2∂g∂X\frac{\partial\left[c_{1} f(\mathbf{X})+c_{2} g(\mathbf{X})\right]}{\partial \mathbf{X}}=c_{1} \frac{\partial f}{\partial \mathbf{X}}+c_{2} \frac{\partial g}{\partial \mathbf{X}}∂X∂[c1​f(X)+c2​g(X)]​=c1​∂X∂f​+c2​∂X∂g​ .
  • 乘积法则: ∂[f(X)g(X)]∂X=g(X)∂f∂X+f(X)∂g∂X\frac{\partial[f(\mathbf{X}) g(\mathbf{X})]}{\partial \mathbf{X}}=g(\mathbf{X}) \frac{\partial f}{\partial \mathbf{X}}+f(\mathbf{X}) \frac{\partial g}{\partial \mathbf{X}}∂X∂[f(X)g(X)]​=g(X)∂X∂f​+f(X)∂X∂g​ .
  • 商法则 : ∂[f(X)/g(X)]∂X=1g2(X)[g(X)∂f∂X−f(X)∂g∂X]\frac{\partial[f(\mathbf{X}) / g(\mathbf{X})]}{\partial \mathbf{X}}=\frac{1}{g^{2}(\mathbf{X})}\left[g(\mathbf{X}) \frac{\partial f}{\partial \mathbf{X}}-f(\mathbf{X}) \frac{\partial g}{\partial \mathbf{X}}\right]∂X∂[f(X)/g(X)]​=g2(X)1​[g(X)∂X∂f​−f(X)∂X∂g​].
  • 链式法则: 若 y=f(X),g(y)y=f(\mathbf{X}), g(y)y=f(X),g(y) 分别为矩阵 X\mathbf{X}X 和标量 yyy 的实值函数, 则
    ∂g(f(X))∂X=dg(y)dy∂f(X)∂X\frac{\partial g(f(\mathbf{X}))}{\partial \mathbf{X}}=\frac{\mathrm{d} g(y)}{\mathrm{d} y} \frac{\partial f(\mathbf{X})}{\partial \mathbf{X}} ∂X∂g(f(X))​=dydg(y)​∂X∂f(X)​

以下设 a、A\mathbf{a} 、 \mathbf{A}a、A 为与变量 x\mathbf{x}x 无关的向量或者矩阵。则
∂a⊤x∂x=∂x⊤a∂x=a\frac{\partial \mathbf{a}^{\top} \mathbf{x}}{\partial \mathbf{x}}=\frac{\partial \mathbf{x}^{\top} \mathbf{a}}{\partial \mathbf{x}}=\mathbf{a} ∂x∂a⊤x​=∂x∂x⊤a​=a
∂x⊤Ay∂x=Ay,∂y⊤Ax∂x=A⊤y\frac{\partial \mathbf{x}^{\top} \mathbf{A} \mathbf{y}}{\partial \mathbf{x}}=\mathbf{A} \mathbf{y}, \quad \frac{\partial \mathbf{y}^{\top} \mathbf{A x}}{\partial \mathbf{x}}=\mathbf{A}^{\top} \mathbf{y} ∂x∂x⊤Ay​=Ay,∂x∂y⊤Ax​=A⊤y
∂x⊤A∂x=A,∂x⊤Ax∂x=(A+A⊤)x\frac{\partial \mathbf{x}^{\top} \mathbf{A}}{\partial \mathbf{x}}=\mathbf{A}, \quad \frac{\partial \mathbf{x}^{\top} \mathbf{A} \mathbf{x}}{\partial \mathbf{x}}=\left(\mathbf{A}+\mathbf{A}^{\top}\right) \mathbf{x} ∂x∂x⊤A​=A,∂x∂x⊤Ax​=(A+A⊤)x
设 f=12x⊤Qxf=\frac{1}{2} \mathbf{x}^{\top} \mathbf{Q} \mathbf{x}f=21​x⊤Qx, 其中 Q\mathbf{Q}Q 为对称矩阵。则 ∇f=Qx,∇2f=Q\nabla f=\mathbf{Q} \mathbf{x}, \nabla^{2} f=\mathbf{Q} ∇f=Qx,∇2f=Q


6.2.2 高斯牛顿法

它的思想是将f(x)f(x)f(x)进行一阶的泰勒展开。注意这里不是目标函数F(x)F(x)F(x),而是f(x)f(x)f(x),否则就变成牛顿法了。
f(x+Δx)≈f(x)+J(x)Δx(6.30)f(\boldsymbol{x}+\Delta \boldsymbol{x}) \approx f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\tag{6.30} f(x+Δx)≈f(x)+J(x)Δx(6.30)
这里 J(x)T\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}}J(x)T 为 f(x)f(\boldsymbol{x})f(x) 关于 x\boldsymbol{x}x 的导数, 为 n×1n \times 1n×1 的列向量。根据前面的框架, 当前的目标是寻找增 量 Δx\Delta xΔx , 使得 ∥f(x+Δx)∥2\|f(x+\Delta x)\|^{2}∥f(x+Δx)∥2 达到最小。为了求 Δx\Delta xΔx , 我们需要解一个线性的最小二乘问题:
Δx∗=arg⁡min⁡Δx12∥f(x)+J(x)Δx∥2(6.31)\Delta x^{*}=\arg \min _{\Delta x} \frac{1}{2}\left\|f(x)+J(x) \Delta x\right\|^{2}\tag{6.31} Δx∗=argΔxmin​21​∥f(x)+J(x)Δx∥2(6.31)
注:必须说明的是,《视觉SLAM十四讲》里的式(6.30)泰勒展开有误,展开后的雅克比矩阵是不需要转置的
12∥f(x)+J(x)Δx∥2=12(f(x)+J(x)Δx)T(f(x)+J(x)Δx)=12(f(x)T+ΔxTJ(x)T)(f(x)+J(x)Δx)=12(f(x)Tf(x)+f(x)TJ(x)Δx+ΔxTJ(x)Tf(x)+ΔxTJ(x)TJ(x)Δx)(6.32)\begin{aligned} \frac{1}{2}\left\|f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x})\Delta \boldsymbol{x}\right\|^{2} &=\frac{1}{2}\left(f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\right)^{\mathrm{T}}\left(f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x})\Delta \boldsymbol{x}\right) \\ &= \frac{1}{2}\left(f(\boldsymbol{x})^{\mathrm{T}}+\Delta \boldsymbol{x}^{\mathrm{T}}\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \right) \left(f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\right)\\ &= \frac{1}{2}\left(f(\boldsymbol{x})^{\mathrm{T}} f(\boldsymbol{x})+ f(\boldsymbol{x})^\mathrm{T} \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x} + \Delta \boldsymbol{x}^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}}f(\boldsymbol{x})+\Delta \boldsymbol{x}^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\right)\\ \end{aligned}\tag{6.32} 21​∥f(x)+J(x)Δx∥2​=21​(f(x)+J(x)Δx)T(f(x)+J(x)Δx)=21​(f(x)T+ΔxTJ(x)T)(f(x)+J(x)Δx)=21​(f(x)Tf(x)+f(x)TJ(x)Δx+ΔxTJ(x)Tf(x)+ΔxTJ(x)TJ(x)Δx)​(6.32)
求上式关于 Δx\Delta xΔx 的导数, 并令其为零:
J(x)Tf(x)+J(x)TJ(x)Δx=0(6.33)\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}=\mathbf{0}\tag{6.33} J(x)Tf(x)+J(x)TJ(x)Δx=0(6.33)
可以得到如下方程组:
JT(x)J⏟H(x)(x)Δx=−JT(x)f(x)⏟g(x).(6.34)\underbrace{\boldsymbol{J}^{\mathrm{T}}(\boldsymbol{x}) \boldsymbol{J}}_{\boldsymbol{H}(\boldsymbol{x})}(\boldsymbol{x}) \Delta \boldsymbol{x}=\underbrace{-\boldsymbol{J}^{\mathrm{T}}(\boldsymbol{x}) f(\boldsymbol{x})}_{\boldsymbol{g}(\boldsymbol{x})} .\tag{6.34} H(x)JT(x)J​​(x)Δx=g(x)−JT(x)f(x)​​.(6.34)
这个方程是关于变量 Δx\Delta xΔx 的线性方程组, 我们称它为增量方程, 也可以称为高斯牛顿方程 ( Gauss-Newton equation) 或者正规方程 (Normal equation )。我们把左边的系数定义为 H\boldsymbol{H}H , 右边 定义为 ggg , 那么上式变为
HΔx=g(6.35)\boldsymbol{H} \Delta \boldsymbol{x}=\boldsymbol{g}\tag{6.35} HΔx=g(6.35)

这里把左侧记作H\boldsymbol{H}H是有意义的。对比牛顿法可见,高斯牛顿法用J(x)JT\boldsymbol{J}(\boldsymbol{x}) \boldsymbol{J}^{\mathrm{T}}J(x)JT作为牛顿法中二阶海森矩阵的近似,从而省略了计算H\boldsymbol{H}H的过程。

高斯牛顿法的缺陷

为了求解增量方程,我们需要求解H−1\boldsymbol{H}^{-1}H−1,但实际数据中计算得到的J(x)JT\boldsymbol{J}(\boldsymbol{x}) \boldsymbol{J}^{\mathrm{T}}J(x)JT只有半正定性。也就是说,求H−1\boldsymbol{H}^{-1}H−1时可能无解,导致算法不收敛。直观地说,原函数在这个点的局部近似不像一个二次函数。因此,每次求逆都需要判断判断是否求逆成功。

6.2.3 列文伯格——马夸尔特方法

高斯牛顿法中采用的近似二阶泰勒展开只能在展开点附近有较好的近似效果,所以我们应该给Δx\Delta \boldsymbol{x}Δx添加一个范围,称为信赖区域。这个范围定义了在什么情况下二阶近似是有效的。

那么,如何确定这个信赖区域的范围呢?一个比较好的方法是根据我们的近似模型跟实际函数之间的差异来确定:如果差异小,说明近似效果好,我们扩大近似的范围;反之,如果差异搭,就缩小近似的范围。我们定义一个指标ρ\rhoρ来刻画近似的好坏程度:
ρ=f(x+Δx)−f(x)J(x)TΔx(6.34)\rho=\frac{f(\boldsymbol{x}+\Delta \boldsymbol{x})-f(\boldsymbol{x})}{\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \Delta \boldsymbol{x}}\tag{6.34} ρ=J(x)TΔxf(x+Δx)−f(x)​(6.34)
ρ\rhoρ的分子式实际函数下降的值,分母式近似模型下降的值。

  1. 如果ρ\rhoρ接近于1,则近似是好的。
  2. 如果ρ\rhoρ太小,说明实际减小的值远少于近似减小的值,则认为近似比较差。需要缩小近似范围。
  3. 如果ρ\rhoρ比较大,则说明实际下降的比预计的更大,我们可以放大近似范围。

算法流程:

  1. 给定初始值x0\boldsymbol{x}_0x0​,以及初始优化半径μ\muμ。
  2. 对于第kkk次迭代,在高斯牛顿法的基础上加上信赖区域,求解:
    min⁡Δxk12∥f(xk)+J(xk)TΔxk∥2,s.t. ∥DΔxk∥2⩽μ(6.35)\min _{\Delta \boldsymbol{x}_{k}} \frac{1}{2}\left\|f\left(\boldsymbol{x}_{k}\right)+\boldsymbol{J}\left(\boldsymbol{x}_{k}\right)^{\mathrm{T}} \Delta \boldsymbol{x}_{k}\right\|^{2}, \quad \text { s.t. } \quad\left\|\boldsymbol{D} \Delta \boldsymbol{x}_{k}\right\|^{2} \leqslant \mu\tag{6.35} Δxk​min​21​∥∥∥​f(xk​)+J(xk​)TΔxk​∥∥∥​2, s.t. ∥DΔxk​∥2⩽μ(6.35)
    其中,μ\muμ是信赖区域的半径,D\boldsymbol{D}D为系数矩阵
  3. 按照式(6.34)计算ρ\rhoρ。
  4. 若ρ>34\rho > \frac{3}{4}ρ>43​,则设置μ=2μ\mu=2\muμ=2μ
  5. 若ρ<14\rho < \frac{1}{4}ρ<41​,则设置μ=0.5μ\mu=0.5\muμ=0.5μ
  6. 如果ρ\rhoρ大于某阈值,则认为近似可行。令xk+1=xk+Δxk\boldsymbol{x}_{k+1}=\boldsymbol{x}_k+\Delta\boldsymbol{x}_kxk+1​=xk​+Δxk​
  7. 判断算法是否收敛。如不收敛则返回第2步,否则结束。

这里近似范围扩大的倍数和阈值都是经验值,可以替换成别的数值。在式(6.35)中,我们把增量限定于一个半径为μ\muμ的球中,认为只在这个球内才是有效的。带上D\boldsymbol{D}D之后,这个球可以看成一个椭球。在列文伯格提出的优化方法中,把D\boldsymbol{D}D取成单位阵I\boldsymbol{I}I,相当于直接把Δxk\Delta \boldsymbol{x}_kΔxk​约束在一个球中。随后,马夸尔特提出将D\boldsymbol{D}D取成非负数对角阵——实际中通常用JTJ\boldsymbol{J}^\boldsymbol{T}\boldsymbol{J}JTJ的对角元素平方根,使得在梯度小的维度上的维度上约束范围更大一些。

这个子问题是带不等式约束的优化问题,我们用拉格朗日乘子把约束项放到目标函数中,构成拉格朗日函数:
L(Δxk,λ)=12∥f(xk)+J(xk)TΔxk∥2+λ2(∥DΔxk∥2−μ)(6.36)\mathcal{L}\left(\Delta \boldsymbol{x}_{k}, \lambda\right)=\frac{1}{2}\left\|f\left(\boldsymbol{x}_{k}\right)+\boldsymbol{J}\left(\boldsymbol{x}_{k}\right)^{\mathrm{T}} \Delta \boldsymbol{x}_{k}\right\|^{2}+\frac{\lambda}{2}\left(\left\|\boldsymbol{D} \Delta \boldsymbol{x}_{k}\right\|^{2}-\mu\right)\tag{6.36} L(Δxk​,λ)=21​∥∥∥​f(xk​)+J(xk​)TΔxk​∥∥∥​2+2λ​(∥DΔxk​∥2−μ)(6.36)
这里 λ\lambdaλ 为拉格朗日乘子。类似于高斯牛顿法中的做法, 令该拉格朗日函数关于 Δx\Delta xΔx 的导数为零, 它的核心仍是计算增量的线性方程:
(H+λDTD)Δxk=g(6.37)\left(\boldsymbol{H}+\lambda \boldsymbol{D}^{\mathrm{T}} \boldsymbol{D}\right) \Delta \boldsymbol{x}_{k}=\boldsymbol{g}\tag{6.37} (H+λDTD)Δxk​=g(6.37)
可以看到, 相比于高斯牛顿法, 增量方程多了一项 λDTD\lambda \boldsymbol{D}^{T} \boldsymbol{D}λDTD 。如果考虑它的简化形式(列文伯格提出), 即 D=I\boldsymbol{D}=\boldsymbol{I}D=I , 那么相当于求解 :
(H+λI)Δxk=g(6.37-1)(\boldsymbol{H}+\lambda \boldsymbol{I}) \Delta \boldsymbol{x}_{k}=\boldsymbol{g}\tag{6.37-1} (H+λI)Δxk​=g(6.37-1)

  • 当参数λ\lambdaλ比较小时,H\boldsymbol{H}H占主要地位,这说明二次近似模型在该范围内是比较好的,列文伯格-马夸尔特方法更接近于高斯牛顿法
  • 当参数λ\lambdaλ比较大时,λI\lambda \boldsymbol{I}λI占据主要地位,列文伯格-马夸尔特方法更接近于最速下降法,这说明附近的二次近似不够好。

进一步地,马夸尔特提出了通过对角线元素增加比例系数来提供更快的收敛速度:
(J(x)TJ(x)+λdiag(J(x)J(x)T))Δxk=−J(x)f(x)(6.37-2)\left(\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x}) + \lambda \text{diag}\left(\boldsymbol{J}(\boldsymbol{x})\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \right)\right)\Delta \boldsymbol{x}_{k}=-\boldsymbol{J}(\boldsymbol{x}) f(\boldsymbol{x})\tag{6.37-2} (J(x)TJ(x)+λdiag(J(x)J(x)T))Δxk​=−J(x)f(x)(6.37-2)

  • 如果梯度值很小(目标函数几乎是平面的区域),对角线元素的倒数将会变得很大,那么这个修改就会导致在梯度方向上产生较大的步长。
  • 反之,在目标函数的梯度方向上,算法将变得更加保守,并采取更小的步长。

式(6.37-1)和式(6.37-2)对正规方程HΔx=g\boldsymbol{H} \Delta \boldsymbol{x}=\boldsymbol{g}HΔx=g的修改都可以从贝叶斯的角度理解为给系统增加了一个零均值的先验信息。

列文伯格-马夸尔特算法伪代码


高斯牛顿法和列文伯格-马夸尔特算法之间最关键的区别在于,后者会拒绝可能导致更大的残差平方和的更新,而前者不会。一个更新被拒绝,说明非线性函数在局部附近表现不好,所以需要更小的更新步长。缩小更新步长可以通过启发式地增大λ\lambdaλ的值来实现,例如,可以将现有的λ\lambdaλ值乘以因子10,并且求解修改后的正规方程。另一方面,如果一个步长导致了残差平方和的减小,这个步长就会被接受,并且状态估计值也会相应地被更新。在这种情况下,减小λ\lambdaλ(通过将λ\lambdaλ除以10),算法在一个新的线性化点处继续迭代,直到收敛为止。

6.2.4 Dogleg最小化法(占坑)

待续。。。

6.3 实践:曲线拟合问题

考虑一条满足以下方程的曲线:
y=exp⁡(ax2+bx+c)+w,y=\exp \left(a x^{2}+b x+c\right)+w, y=exp(ax2+bx+c)+w,
其中, a,b,ca, b, ca,b,c 为曲线的参数, www 为高斯噪声, 满足 w∼(0,σ2)w \sim\left(0, \sigma^{2}\right)w∼(0,σ2) 。现在, 假设我们有 NNN 个关于 x,yx, yx,y 的观测数据点, 想根据这些数据点求出曲线的参数。那么, 可以求解下面的最小二乘问题以估计曲线参数:
min⁡a,b,c12∑i=1N∥yi−exp⁡(axi2+bxi+c)∥2\min _{a, b, c} \frac{1}{2} \sum_{i=1}^{N}\left\|y_{i}-\exp \left(a x_{i}^{2}+b x_{i}+c\right)\right\|^{2} a,b,cmin​21​i=1∑N​∥∥​yi​−exp(axi2​+bxi​+c)∥∥​2
请注意, 在这个问题中, 待估计的变量是 a,b,ca, b, ca,b,c , 而不是 xxx 。我们的程序里先根据模型生成 x,yx, yx,y 的真值, 然后在真值中添加高斯分布的噪声。随后, 使用高斯牛顿法从带噪声的数据拟合参数模型。定义误差为
ei=yi−exp⁡(axi2+bxi+c),e_{i}=y_{i}-\exp \left(a x_{i}^{2}+b x_{i}+c\right), ei​=yi​−exp(axi2​+bxi​+c),
那么, 可以求出每个误差项对于状态变量的导数:
∂ei∂a=−xi2exp⁡(axi2+bxi+c)∂ei∂b=−xiexp⁡(axi2+bxi+c)∂ei∂c=−exp⁡(axi2+bxi+c)\begin{array}{l} \frac{\partial e_{i}}{\partial a}=-x_{i}^{2} \exp \left(a x_{i}^{2}+b x_{i}+c\right) \\ \frac{\partial e_{i}}{\partial b}=-x_{i} \exp \left(a x_{i}^{2}+b x_{i}+c\right) \\ \frac{\partial e_{i}}{\partial c}=-\exp \left(a x_{i}^{2}+b x_{i}+c\right) \end{array} ∂a∂ei​​=−xi2​exp(axi2​+bxi​+c)∂b∂ei​​=−xi​exp(axi2​+bxi​+c)∂c∂ei​​=−exp(axi2​+bxi​+c)​
于是 Ji=[∂ei∂a,∂ei∂b,∂ei∂c]T\boldsymbol{J}_{i}=\left[\frac{\partial e_{i}}{\partial a}, \frac{\partial e_{i}}{\partial b}, \frac{\partial e_{i}}{\partial c}\right]^{\mathrm{T}}Ji​=[∂a∂ei​​,∂b∂ei​​,∂c∂ei​​]T , 高斯牛顿法的增量方程为
(∑i=1100Ji(σ2)−1Ji⊤)Δxk=∑i=1100−Ji(σ2)−1ei,\left(\sum_{i=1}^{100} J_{i}\left(\sigma^{2}\right)^{-1} J_{i}{ }^{\top}\right) \Delta x_{k}=\sum_{i=1}^{100}-J_{i}\left(\sigma^{2}\right)^{-1} e_{i,} (i=1∑100​Ji​(σ2)−1Ji​⊤)Δxk​=i=1∑100​−Ji​(σ2)−1ei,​
为了让求解过程更加清晰,我们选择把所有的Ji\boldsymbol{J}_{i}Ji​排成一列,将这个方程写成矩阵形式。不过这样会消耗较多的内存。

6.3.2 手写高斯牛顿法

#include <iostream>
#include <chrono>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>using namespace Eigen;int main(int argc, char** argv) {// 配置真实值double ar = 1.0, br = 2.0, cr = 1.0;// 配置噪声值double w_sigma = 1.0;double inv_w_sigma = 1.0/w_sigma;// 生成数据点int N = 100;// OpenCV随机数生成器cv::RNG rng; // 雅克比矩阵Eigen::Matrix<double, 100, 3> J;J.setZero();// 正规矩阵H = J^T*JEigen::Matrix<double, 3, 3> H;H.setZero();// J_nEigen::Matrix<double, 1, 3> Jn;Jn.setZero();// f(x)Eigen::Matrix<double, 100, 1> f;f.setZero();// g(x)Eigen::Matrix<double, 3, 1> g;g.setZero();// /Delta xEigen::Matrix<double, 3, 1> Delta_x;Delta_x.setZero();std::vector<double> x_data, y_data;for(size_t i=0; i<N; i++){double x = i/100.0;x_data.push_back(x);y_data.push_back(std::exp(ar*x*x+br*x+cr)+rng.gaussian(w_sigma*w_sigma));}// 设置初始值double ae = 2.0, be = -1.0, ce = 5.0;// 开始最速下降法迭代// 设置迭代次数// 设置结束条件size_t numIter = 100;double cost = 0.0;double last_cost = 0.0;size_t count = 0;std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();for(size_t i=0; i<numIter; i++){for(size_t j=0; j<N; j++){Jn(0, 0) = x_data[j]*x_data[j]*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);Jn(0, 1) = x_data[j]*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);Jn(0, 2) = 1*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);J.block(j, 0, 1, 3) = inv_w_sigma*Jn; // 记得配置上噪声权值f(j, 0) = inv_w_sigma*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce) - y_data[j]; // 记得配置上噪声权值}cost = f.norm();H = J.transpose()*J;g = -J.transpose()*f;// 直接求逆// Delta_x = H.inverse()*g;// 使用cholesky分解来解方程// Delta_x = H.ldlt().solve(g);// 使用QR分解来解方程,速度比较快Delta_x = H.colPivHouseholderQr().solve(g);if(isnan(Delta_x[0])){std::cout<<"result is nan!"<<std::endl;break;}if(cost>=last_cost && i>0){std::cout<<"cost: "<<cost<<" >= last cost: "<<last_cost<<", break."<<std::endl;break;}last_cost = cost;ae = ae + Delta_x(0, 0);be = be + Delta_x(1, 0);ce = ce + Delta_x(2, 0);count = i;}std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();std::chrono::duration<double> time_used = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);std::cout << "solve time cost = " << time_used.count() << " seconds. " << std::endl;std::cout<<"estimated abc = "<<ae<<", "<<be<<", "<<ce<<std::endl;std::cout<<"number of iterations = "<<count<<std::endl;return 0;}

6.3.1 手写列文伯格-马夸尔特方法

#include <iostream>
#include <chrono>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>using namespace Eigen;int main(int argc, char** argv) {// 配置真实值double ar = 1.0, br = 2.0, cr = 1.0;// 配置噪声值double w_sigma = 1.0;double inv_w_sigma = 1.0/w_sigma;// 生成数据点int N = 100;// OpenCV随机数生成器cv::RNG rng; double lambda = 1e-4;// 雅克比矩阵Eigen::Matrix<double, 100, 3> J;J.setZero();// 正规矩阵H = J^T*JEigen::Matrix<double, 3, 3> H;H.setZero();// J_nEigen::Matrix<double, 1, 3> Jn;Jn.setZero();// f(x)Eigen::Matrix<double, 100, 1> f;f.setZero();// g(x)Eigen::Matrix<double, 3, 1> g;g.setZero();// /Delta xEigen::Matrix<double, 3, 1> Delta_x;Delta_x.setZero();Eigen::Matrix3d DeltaMatrix;DeltaMatrix.setZero();std::vector<double> x_data, y_data;for(size_t i=0; i<N; i++){double x = i/100.0;x_data.push_back(x);y_data.push_back(std::exp(ar*x*x+br*x+cr)+rng.gaussian(w_sigma*w_sigma));}// 设置初始值double ae = 2.0, be = -1.0, ce = 5.0;// 开始最速下降法迭代// 设置迭代次数// 设置结束条件size_t numIter = 100;double cost = 0.0;double last_cost = 0.0;size_t count = 0;std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();for(size_t i=0; i<numIter; i++){for(size_t j=0; j<N; j++){Jn(0, 0) = x_data[j]*x_data[j]*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);Jn(0, 1) = x_data[j]*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);Jn(0, 2) = 1*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce);J.block(j, 0, 1, 3) = inv_w_sigma*Jn; // 记得配置上噪声权值f(j, 0) = inv_w_sigma*std::exp(ae*x_data[j]*x_data[j]+be*x_data[j]+ce) - y_data[j]; // 记得配置上噪声权值}cost = f.norm();H = J.transpose()*J;Eigen::Matrix3d diagMatrix = Eigen::Matrix3d(H.diagonal().asDiagonal());DeltaMatrix = H + lambda*diagMatrix;g = -J.transpose()*f;// 直接求逆// Delta_x = DeltaMatrix.inverse()*g;// 使用cholesky分解来解方程// Delta_x = DeltaMatrix.ldlt().solve(g);// 使用QR分解来解方程,速度比较快Delta_x = DeltaMatrix.colPivHouseholderQr().solve(g);if(isnan(Delta_x[0])){std::cout<<"result is nan!"<<std::endl;break;}if(Delta_x.norm()<0.001){std::cout<<"result is converge!"<<std::endl;break;}// 接受更新if((cost<last_cost && i>0) || i==0){ae = ae + Delta_x(0, 0);be = be + Delta_x(1, 0);ce = ce + Delta_x(2, 0);if(i>0) lambda*=0.1;}// 发散了,拒绝更新else{lambda*=10.0;}last_cost = cost;count = i;}std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();std::chrono::duration<double> time_used = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);std::cout << "solve time cost = " << time_used.count() << " seconds. " << std::endl;std::cout<<"estimated abc = "<<ae<<", "<<be<<", "<<ce<<std::endl;std::cout<<"number of iterations = "<<count<<std::endl;return 0;}

6.3.3 使用Ceres进行曲线拟合(占坑)

学习Ceres-solver最全的文档:Ceres Solver

代码以后再补…

6.3.4 使用g2o进行曲线拟合(占坑)

在图优化库里,g2o和GTSAM的功能类似,而我自己更喜欢用GTSAM,因为它集成了ISAM2。因此这里暂时搁置g2o。

6.3.5 使用GTSAM进行曲线拟合(占坑)

学习GTSAM最全的文档:GTSAM

代码以后再补…

《视觉SLAM十四讲》读书笔记(四)相关推荐

  1. 《淘宝技术这十年》读书笔记 (四). 分布式时代和中间件

    前面两篇文章介绍了淘宝的发展历程.Java时代的变迁和淘宝开始创新技术:              <淘宝技术这十年>读书笔记 (一).淘宝网技术简介及来源              &l ...

  2. 视觉SLAM十四讲读书笔记(5)P40-P52

    目录 Q:什么是eigen Q:正交矩阵的定义和性质 Q:什么是特殊正交群 Q:什么叫齐次坐标 Q:什么是特殊欧氏群 Q:什么是运算符重载 Q:什么是g2o Q:什么是sophus Q:什么是eige ...

  3. 视觉SLAM十四讲读书笔记(2)P10-P27

    目录​​​​​​​ Q:一个视觉SLAM框架由哪几个模块组成,各模块的任务又是什么 Q:什么是机器人的自主运动能力 Q:什么是机器人的感知 Q:什么是激光雷达 Q:什么是增强现实 Q:什么是IMU单元 ...

  4. 视觉SLAM十四讲读书笔记(3)P27-P31

    目录 Q:介绍一些常见的Linux系统 Q:Kinect是什么 Q:什么是编译器 Q:GNU是什么 Q:GNUME桌面环境是什么 Q:gedit是什么 Q:unix和Linux有什么关系和不同 Q:什 ...

  5. 【读书笔记】《视觉SLAM十四讲(高翔著)》 第13讲

    文章目录 工程文件一:dense_monocular(单目稠密地图) 工程文件二:dense_RGBD(点云地图 & 八叉树地图) 本博客的内容是本章程序编译运行方法,记录调通本章程序的过程. ...

  6. 《视觉SLAM十四讲 第二版》笔记及课后习题(第七讲)

    读书笔记:视觉里程计1 之前的内容,介绍了运动方程和观测方程的具体形式,并讲解了以非线性优化为主的求解方法.从本讲开始,我们结束了基础知识的铺垫,开始步入正题:按照第二讲的内容,分别介绍视觉里程计.优 ...

  7. 视觉SLAM总结——视觉SLAM十四讲笔记整理

    视觉SLAM总结--视觉SLAM十四讲笔记整理 说明 基础知识点 1. 特征提取.特征匹配 (1)Harris (2)SIFT (3)SUFT (4)ORB (5)特征匹配 2. 2D-2D:对极约束 ...

  8. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-三角测量和实践

     专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第 ...

  9. 视觉SLAM十四讲学习笔记-第七讲-视觉里程计-对极几何和对极约束、本质矩阵、基础矩阵

    专栏系列文章如下:  专栏汇总 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第二讲-初识SLAM_goldqiu的博客-CSDN博客 视觉SLA ...

  10. 视觉SLAM十四讲学习笔记-第六讲学习笔记总结(1)---非线性优化原理

    第六讲学习笔记如下: 视觉SLAM十四讲学习笔记-第六讲-非线性优化的状态估计问题_goldqiu的博客-CSDN博客 ​​​​​​视觉SLAM十四讲学习笔记-第六讲-非线性优化的非线性最小二乘问题_ ...

最新文章

  1. python ffmpeg模块,python执行ffmpeg
  2. ZooKeeper的一致性算法赏析
  3. linux 不接显示器不启动_不知道这十项Linux常识,就别说自己玩过Linux
  4. 2013 Multi-University Training Contest 9 1011 Arc of Dream
  5. LeetCode每日一题 844. 比较含退格的字符串
  6. Node.js笔记-使用socket.io构建websocket聊天室
  7. Android Theme 主题总结
  8. iptables表与链的相关性图
  9. 《大型数据库技术》MySQL数据库的开发基础
  10. 对于react-redux的理解
  11. webstorm下载微信小程序插件_微信电脑版可以打开小程序喽 前提你得下载测试版...
  12. web安全day35:Linux防火墙进阶
  13. 生物信息学资料1,常用软件,酶切位点分析
  14. ps-通道+高低频磨皮去斑
  15. android 软解8k视频,Android Q+5G现场播放8K视频:画面流畅
  16. 一定要收藏的面试思维导图
  17. 关于小程序 scroll
  18. Altium Designer PCB电路板设计总结
  19. CSDN自动回复灌水乐园帖子-httpClient篇
  20. Autofill Framework(自动填写)用法详解

热门文章

  1. dp在约会上是什么意思_第一次约会,女生让你碰这三个部位,十有八九就是对你有意思...
  2. 网站服务器无法打开ie,internet explorer无法打开站点怎么办
  3. python实现whois查询_Python 工具whois查询
  4. cf446 div2
  5. 网站HTML SEO优化
  6. 沙盘游戏模型的基本象征
  7. 计算机无线网卡连接网络,台式机怎么连接无线网络?台式电脑不用网卡怎么连接网络?...
  8. 解决gitlab内置node_exporter提供外部prometheus使用
  9. 搜狐股票接口获取数据方法
  10. AC的集中和本地转发