前言 
之前看的A-LOAM代码把优化交给了ceres,而最初自己看论文时也只明白要优化变量和原理,并没有自己推导细节。后来在总结LOAM代码时,突然发现自己完全不知道这部分应该怎么手写,因此有必要自己来一遍数学推导。
非标量求导 
上学期上课时我就对包含向量/矩阵的求导一头雾水,搞不清楚怎么求,每次都是上网找别人写的往上套。最近看 numerical optimization 回炉 SLAM用到的非线性优化,各种求导又让我无语了。上网研究了一下,算是找到一些不错的资料。
首先要明白,矩阵求导是有不同的使用习惯的,主要有两种:分子布局和分母布局,后者也称混合布局。
对于分子布局,向量y 对标量x求导,得到的是列向量,标量y对向量x 求导,得到的是行向量;
对于分母布局,向量y 对标量x求导,得到的是行向量,标量y对向量x 求导,得到的是列向量;
其他详细内容需要参考 wiki  。
根据矩阵求导术(下) - 知乎  中所说,机器学习/优化中的梯度矩阵常用分母布局,而控制论等领域中的Jacobian矩阵采用分子布局,后者的例子有 numerical optimization 的最小二乘部分(其他没看)以及LOAM的代码。实际上,还有两种规定混用的,似乎Matrix Cookbook就是这样。另外,SLAM十四讲也比较奇怪,它在附录中规定了分子布局,但它前面用的雅可比J J J 
如果仅仅是首次看矩阵求导,我觉得下面的文章思想十分不错,它是按分母布局来的:
为了能形成一种长期快速使用的方法,则 Matrix_Derivatives 下面的PDF手册很好,可配合 Matrix Cookbook食用。注意,关于行列这些,这个手册有自己的规范。
最后,矩阵求导其实本没有所谓链式法则,但在一些情况下也可以根据相应布局来使用,这部分还没有深入研究,可以参考wiki和这里 。对于分子布局的向量对向量 求导,可以沿用以前的链式顺序。
高斯牛顿法 
最小二乘问题 
min  x F ( x ) = 1 2 ∥ f ( x ) ∥ 2 2 \min _{\boldsymbol{x}} F(\boldsymbol{x})=\frac{1}{2}\|f(\boldsymbol{x})\|_{2}^{2}
 x min  F ( x ) = 2 1  ∥ f ( x ) ∥ 2 2  
r j ( x ) = ϵ j = ϕ ( x ; t j ) − y j r_{j}(x)=\epsilon_{j}=\phi\left(x ; t_{j}\right)-y_{j}
 r j  ( x ) = ϵ j  = ϕ ( x ; t j  ) − y j  
比如让 $$f(x)=r(x)$$
则将error以最小平方来优化,原理是假设观测数据与预测数据之差符合正态分布,找最好的模型参数应该能让观测数据与产生的预测数据之差在其正态分布中的可能性最大,即寻找一组参数使之最可能产生现在的已有数据,这就是一个最大似然估计问题。假设各残差项相互独立,则有:
p ( y ; x , σ ) = ∏ j = 1 m g σ ( ϵ j ) = ∏ j = 1 m g σ ( ϕ ( x ; t j ) − y j ) p(y ; x, \sigma)=\prod_{j=1}^{m} g_{\sigma}\left(\epsilon_{j}\right)=\prod_{j=1}^{m} g_{\sigma}\left(\phi\left(x ; t_{j}\right)-y_{j}\right)
 p ( y ; x , σ ) = j = 1 ∏ m  g σ  ( ϵ j  ) = j = 1 ∏ m  g σ  ( ϕ ( x ; t j  ) − y j  ) 
由于假设正态分布,有:
g σ ( ϵ ) = 1 2 π σ 2 exp  ( − ϵ 2 2 σ 2 ) g_{\sigma}(\epsilon)=\frac{1}{\sqrt{2 \pi \sigma^{2}}} \exp \left(-\frac{\epsilon^{2}}{2 \sigma^{2}}\right)
 g σ  ( ϵ ) = 2 π σ 2  1  exp ( − 2 σ 2 ϵ 2  ) 
得出问题实质就是给定正态分布和一组数据,就是估计参数使下面p p p 
p ( y ; x , σ ) = ( 2 π σ 2 ) − m / 2 exp  ( − 1 2 σ 2 ∑ j = 1 m [ ϕ ( x ; t j ) − y j ] 2 ) p(y ; x, \sigma)=\left(2 \pi \sigma^{2}\right)^{-m / 2} \exp \left(-\frac{1}{2 \sigma^{2}} \sum_{j=1}^{m}\left[\phi\left(x ; t_{j}\right)-y_{j}\right]^{2}\right)
 p ( y ; x , σ ) = ( 2 π σ 2 ) − m /2 exp ( − 2 σ 2 1  j = 1 ∑ m  [ ϕ ( x ; t j  ) − y j  ] 2 ) 
这就要将括号里的平方项最小化,这就是前面最小平方差的来源。
非线性最小二乘 
如果上面的f ( x ) f(x) f ( x ) 
求解这个方程需要我们知道关于目标函数的全局性质,而通常这是不大可能的。对于不方便直接求解的最小二乘问题,我们可以用迭代的方式,从一个初始值出发,不断地更新当前的优化变量,使目标函数下降。
 
这让求解导函数为零的问题变成了一个不断寻找下降增量Δk的冋题,我们将看到,由于可以对f进行线性化,增量的计算将简单很多。当函数下降直到增量非常小的时候,就认为算收敛,目标函数达到了一个极小值。在这个过程中,问题在于如何找到每次迭代点的增量,而这是一个局部的问题,我们只需要关心f在迭代值处的局部性质而非全局性质。这类方法在最优化、机器学习等领域应用非常广泛。
 
首先是要进行局部线性化,如果直接将min  x F ( x ) = 1 2 ∥ f ( x ) ∥ 2 2 \min _{\boldsymbol{x}} F(\boldsymbol{x})=\frac{1}{2}\|f(\boldsymbol{x})\|_{2}^{2} min x  F ( x ) = 2 1  ∥ f ( x ) ∥ 2 2  F ( x ) F(x) F ( x ) 
对于后者,有:
Δ x ∗ = arg  min  ( F ( x ) + J ( x ) T Δ x + 1 2 Δ x T H Δ x ) \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)
 Δ x ∗ = arg  min ( F ( x ) + J ( x ) T Δ x + 2 1  Δ x T H Δ x ) 
J + H Δ x = 0 ⇒ H Δ x = − J \boldsymbol{J}+\boldsymbol{H} \Delta \boldsymbol{x}=\mathbf{0} \Rightarrow \boldsymbol{H} \Delta \boldsymbol{x}=-\boldsymbol{J}
 J + H Δ x = 0 ⇒ H Δ x = − J 
不过,这两种方法也存在它们自身的问题。最速下降法过于贪心容易走出锯齿路线,反而增加了迭代次数。而牛顿法则需要计算目标数的H矩阵,这在问题规模较大时非常困难,我们通常倾向于避免H的计算。对于一般的问题,一些拟牛顿法可以得到较好的结果,而对于最小二乘问题,还有几类更实用的方法:高斯牛顿法和列文伯格一马夸尔特方法。
 
高斯牛顿法 
同样使用一阶泰勒展开,但是不再对F ( x ) F(x) F ( x ) f ( x ) f(x) f ( x ) 
f ( x + Δ x ) ≈ f ( x ) + J ( x ) Δ x f(\boldsymbol{x}+\Delta \boldsymbol{x}) \approx f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}
 f ( x + Δ x ) ≈ f ( x ) + J ( x ) Δ x 
1 2 ∥ f ( x ) + J ( x ) Δ x ∥ 2 = 1 2 ( f ( x ) + J ( x ) Δ x ) ( f ( x ) + J ( x ) Δ x ) = 1 2 ( ∥ f ( x ) ∥ 2 2 + 2 f ( x ) J ( x ) Δ x + Δ x T J ( x ) T J ( x ) Δ x ) \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)\left(f(\boldsymbol{x})+\boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\right) \\ &=\frac{1}{2}\left(\|f(\boldsymbol{x})\|_{2}^{2}+2 f(\boldsymbol{x}) \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}+\Delta \boldsymbol{x}^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}\right) \end{aligned}
 2 1  ∥ f ( x ) + J ( x ) Δ x ∥ 2  = 2 1  ( f ( x ) + J ( x ) Δ x ) ( f ( x ) + J ( x ) Δ x ) = 2 1  ( ∥ f ( x ) ∥ 2 2  + 2 f ( x ) J ( x ) Δ x + Δ x T J ( x ) T J ( x ) Δ x )  
J ( x ) T J ⏟ H ( x ) ( x ) Δ x = − J ( x ) T f ( x ) ⏟ g ( x ) \underbrace{\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}}_{\boldsymbol{H}(\boldsymbol{x})}(\boldsymbol{x}) \Delta \boldsymbol{x}=\underbrace{-\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} f(\boldsymbol{x})}_{\boldsymbol{g}(\boldsymbol{x})}
 H ( x ) J ( x ) T J   ( x ) Δ x = g ( x ) − J ( x ) T f ( x )   
H Δ x = g H \Delta x=g
 H Δ x = g 
这个方程就是正规方程,左侧虽然记成H但并不是二阶Hessian矩阵 ,只是对它一种近似。
高斯牛顿法优点是相比牛顿法简化计算,收敛快;
缺点是:
需要H可逆,但是J J T JJ^T J J T  
有可能解出的 Δ x \Delta x Δ x  
 
// TODO LM与dog-leg法整理
LOAM优化部分推导 
构造最小二乘 
J ( x ) T J ( x ) Δ x = − J ( x ) T f ( x ) \boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{J}(\boldsymbol{x}) \Delta \boldsymbol{x}=-\boldsymbol{J}(\boldsymbol{x})^{\mathrm{T}} \boldsymbol{f}(\boldsymbol{x})
 J ( x ) T J ( x ) Δ x = − J ( x ) T f ( x ) 
J ( x ) J(x) J ( x ) n*6的矩阵,这个6即tx,ty,tz,rx,ry,rz
Δ x \Delta x Δ x f ( x ) f(x) f ( x ) 
迭代方法 :
使用本轮给出的tranform初值计算距离残差f ( x ) f(x) f ( x )  
计算J ( x ) J(x) J ( x ) Δ x \Delta x Δ x Δ x \Delta x Δ x  
如果Δ x \Delta x Δ x f ( x ) f(x) f ( x )  
 
雅可比推导 
退化情况处理 
LOAM代码里,优化会根据首先判断出是否退化,如果退化优化更新会另做处理。这源于作者的另一论文 On Degeneracy of Optimization-based State Estimation Problems。
作者指出,在使用视觉传感器时缺少纹理特征、使用激光传感器缺少几何结构信息等情况时,优化问题会退化,这样就算求解出全局最优解,也基本不靠近真实的解,极影响优化方法的可靠性。而观察发现,即便数据局部退化,仍可以尝试用部分约束在问题子空间中求解。由此,作者首先提出了退化因子的概念,配合一个阈值用于检测退化;然后提出了Solution Remapping 的方法,用于加入到优化过程中,从良好方向出分离出去退化方向,优化迭代中只在良好方向上更新(非线性问题的情况),避免得出错误解。
假设A满秩,我们考虑解决如下已经线性化的最小二乘问题:
arg  min  x ∥ A x − b ∥ 2 \arg \min _{\boldsymbol{x}}\|\mathbf{A} \boldsymbol{x}-\boldsymbol{b}\|^{2}
 arg  x min  ∥ A x − b ∥ 2 
退化因子的定义 
对于下图中已有黑色约束,添加一法线为c \bold{c} c 
c T ( x − x 0 ) = 0 , ∥ c ∥ = 1 \boldsymbol{c}^{T}\left(\boldsymbol{x}-\boldsymbol{x}_{0}\right)=0,\|\boldsymbol{c}\|=1
 c T ( x − x 0  ) = 0 , ∥ c ∥ = 1 
因其通过原解 x 0 x0 x 0 
接着将新约束沿法线方向移动一个确定距离δ d \delta d δ d 沿c的方向 变化 δ x c \delta x_c δ x c  c \bold{c} c δ x c ∗ \delta x_c^* δ x c ∗  
D = δ d / δ x c ∗ \mathcal{D}=\delta d / \delta x_{c}^{*}
 D = δ d / δ x c ∗  
数学证明 
结论1:对于上面研究的线性系统问题,退化因子只与决定方向的A有关,与初始位置b无关,这和Fig.1.中表现一致。 
证明 :
分别列出干扰前后带新约束的方程:
[ A c T ] x = [ b c T x 0 ] \left[\begin{array}{c}\mathbf{A} \\ \boldsymbol{c}^{T}\end{array}\right] \boldsymbol{x}=\left[\begin{array}{c}\boldsymbol{b} \\ \boldsymbol{c}^{T} \boldsymbol{x}_{0}\end{array}\right]
 [ A c T  ] x = [ b c T x 0   ] 
[ A c T ] x = [ b c T x 0 + δ d ] \left[\begin{array}{c}\mathbf{A} \\ \boldsymbol{c}^{T}\end{array}\right] \boldsymbol{x}=\left[\begin{array}{c}\boldsymbol{b} \\ \boldsymbol{c}^{T} \boldsymbol{x}_{0}+\delta d\end{array}\right]
 [ A c T  ] x = [ b c T x 0  + δ d  ] 
下减上得,利用伪逆求得:
δ x = ( A T A + c c T ) − 1 c δ d \delta \boldsymbol{x}=\left(\mathbf{A}^{T} \mathbf{A}+\boldsymbol{c} \boldsymbol{c}^{T}\right)^{-1} \boldsymbol{c} \delta d
 δ x = ( A T A + c c T ) − 1 c δ d 
因为定义了 ∥ c ∥ = 1 \|\boldsymbol{c}\|=1 ∥ c ∥ = 1 δ x \delta \boldsymbol{x} δ x c \boldsymbol{c} c 
δ x c = c T δ x = c T ( A T A + c c T ) − 1 c δ d \delta x_{c}=\boldsymbol{c}^{T} \delta \boldsymbol{x}=\boldsymbol{c}^{T}\left(\mathbf{A}^{T} \mathbf{A}+\boldsymbol{c} \boldsymbol{c}^{T}\right)^{-1} \boldsymbol{c} \delta d
 δ x c  = c T δ x = c T ( A T A + c c T ) − 1 c δ d 
可以看出只与 c \boldsymbol{c} c δ d \delta d δ d A \mathbf{A} A 
 
结论2:D = λ min  + 1 \mathcal{D}=\lambda_{\min }+1 D = λ m i n  + 1 λ min  是 A T A 最小的特征值 \lambda_{\min } \text {是} \mathbf{A}^{T} \mathbf{A} \text{最小的特征值} λ m i n  是 A T A 最小的特征值  
证明 :
因为定义了 ∥ c ∥ = 1 \|\boldsymbol{c}\|=1 ∥ c ∥ = 1 c \boldsymbol{c} c c l e f t − 1 = ( c T c ) − 1 c T = c T  and  c r i g h t − T = c ( c T c ) − 1 = c \boldsymbol{c}_{\mathrm{left}}^{-1}=\left(\boldsymbol{c}^{T} \boldsymbol{c}\right)^{-1} \boldsymbol{c}^{T}=\boldsymbol{c}^{T} \text { and } \boldsymbol{c}_{\mathrm{right}}^{-T}=\boldsymbol{c}\left(\boldsymbol{c}^{T} \boldsymbol{c}\right)^{-1}=\boldsymbol{c} c left − 1  = ( c T c ) − 1 c T = c T  and  c right − T  = c ( c T c ) − 1 = c 
δ x c = c l e f t − 1 ( A T A + c c T ) − 1 c r i g h t − T δ d = ( c T ( A T A + c c T ) c ) − 1 δ d = ( c T A T A c + 1 ) − 1 δ d \begin{aligned} \delta x_{c} &=\boldsymbol{c}_{\mathrm{left}}^{-1}\left(\mathbf{A}^{T} \mathbf{A}+\boldsymbol{c} \boldsymbol{c}^{T}\right)^{-1} \boldsymbol{c}_{\mathrm{right}}^{-T} \delta d \\ &=\left(\boldsymbol{c}^{T}\left(\mathbf{A}^{T} \mathbf{A}+\boldsymbol{c} \boldsymbol{c}^{T}\right) \boldsymbol{c}\right)^{-1} \delta d \\ &=\left(\boldsymbol{c}^{T} \mathbf{A}^{T} \mathbf{A} \boldsymbol{c}+1\right)^{-1} \delta d \end{aligned}
 δ x c   = c left − 1  ( A T A + c c T ) − 1 c right − T  δ d = ( c T ( A T A + c c T ) c ) − 1 δ d = ( c T A T A c + 1 ) − 1 δ d  
要得到退化因子,就要让δ x c \delta x_c δ x c  
c ∗ = arg  min  c T A T A c ,  s.t.  ∥ c ∥ = 1 \boldsymbol{c}^{*}=\arg \min \boldsymbol{c}^{T} \mathbf{A}^{T} \mathbf{A} \boldsymbol{c}, \text { s.t. }\|\boldsymbol{c}\|=1
 c ∗ = arg  min c T A T A c ,  s.t.  ∥ c ∥ = 1 
等价于:
c ∗ = arg  min  c c T A T A c c T c \boldsymbol{c}^{*}=\arg \min _{\boldsymbol{c}} \frac{\boldsymbol{c}^{T} \mathbf{A}^{T} \mathbf{A} \boldsymbol{c}}{\boldsymbol{c}^{T} \boldsymbol{c}}
 c ∗ = arg  c min  c T c c T A T A c  
根据Rayleigh quotient , 由于A T A \mathbf{A}^{T} \mathbf{A} A T A A T A \mathbf{A}^{T} \mathbf{A} A T A 
δ x c ∗ = δ d λ min  + 1 \delta x_{c}^{*}=\frac{\delta d}{\lambda_{\min }+1}
 δ x c ∗  = λ m i n  + 1 δ d  
D = δ d / δ x c ∗ = λ min  + 1 \mathcal{D}=\delta d / \delta x_{c}^{*}=\lambda_{\min }+1
 D = δ d / δ x c ∗  = λ m i n  + 1 
最小特征值对应特征向量的方向是第一大的可能退化方向,由于实对称矩阵A T A \mathbf{A}^{T} \mathbf{A} A T A Rayleigh quotient ,得出每个特征向量的方向的退化因子就是相应的特征值 +1 ,它们就是第i i i 
 
Solution Remapping 
算法 
设A T A \mathbf{A}^{T} \mathbf{A} A T A m , 0 ≤ m ≤ n m, 0 \leq m \leq n m , 0 ≤ m ≤ n m = 0 m=0 m = 0 m = n m=n m = n 
构造如下矩阵用于分离方向:
V p = [ v 1 , … , v m , 0 , … , 0 ] T V u = [ 0 , … , 0 , v m + 1 , … , v n ] T V f = [ v 1 , … , v m , v m + 1 , … , v n ] T \begin{aligned} \mathbf{V}_{p} &=\left[\boldsymbol{v}_{1}, \ldots, \boldsymbol{v}_{m}, 0, \ldots, 0\right]^{T} \\ \mathbf{V}_{u} &=\left[0, \ldots, 0, \boldsymbol{v}_{m+1}, \ldots, \boldsymbol{v}_{n}\right]^{T} \\ \mathbf{V}_{f} &=\left[\boldsymbol{v}_{1}, \ldots, \boldsymbol{v}_{m}, \boldsymbol{v}_{m+1}, \ldots, \boldsymbol{v}_{n}\right]^{T} \end{aligned}
 V p  V u  V f   = [ v 1  , … , v m  , 0 , … , 0 ] T = [ 0 , … , 0 , v m + 1  , … , v n  ] T = [ v 1  , … , v m  , v m + 1  , … , v n  ] T  
x p x_p x p  x u x_u x u  x f x_f x f  
我们让预测值投影到退化方向,更新值投影到未退化方向,综合两部分得到最终的解,如上图所示。
x p ′ = V f − 1 V p x p  and  x u ′ = V f − 1 V u x u \boldsymbol{x}_{p}^{\prime}=\mathbf{V}_{f}^{-1} \mathbf{V}_{p} \boldsymbol{x}_{p} \text { and } \boldsymbol{x}_{u}^{\prime}=\mathbf{V}_{f}^{-1} \mathbf{V}_{u} \boldsymbol{x}_{u}
 x p ′  = V f − 1  V p  x p   and  x u ′  = V f − 1  V u  x u  
(原来就是把右侧逆拿到左边,可以从投影/变换的角度理解。)
最后合成两部分:
x f = x p ′ + x u ′ \boldsymbol{x}_{f}=\boldsymbol{x}_{p}^{\prime}+\boldsymbol{x}_{u}^{\prime}
 x f  = x p ′  + x u ′  
对于实际非线性问题,算法如下:
其他: 
文章中采集了退化与非退化场景的最小特征值,取边界中值作为阈值。
论文中说,根据经验只需要在迭代开始确定退化方向,没必要每轮都更新。除此之外,只在非退化方向上更新,舍弃了退化方向的更新。
LOAM代码中退化处理 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 if  (iterCount == 0 ) {         cv::Mat matE (1 , 6 , CV_32F, cv::Scalar::all(0 ))  ;          cv::Mat matV (6 , 6 , CV_32F, cv::Scalar::all(0 ))  ;     cv::Mat matV2 (6 , 6 , CV_32F, cv::Scalar::all(0 ))  ;          cv::eigen (matAtA, matE, matV);     matV.copyTo (matV2);     isDegenerate = false ;          float  eignThre[6 ] = {10 , 10 , 10 , 10 , 10 , 10 };     for  (int  i = 5 ; i >= 0 ; i--) {         if  (matE.at<float >(0 , i) < eignThre[i]) {             for  (int  j = 0 ; j < 6 ; j++) {                 matV2.at<float >(i, j) = 0 ;             }             isDegenerate = true ;         } else  {             break ;         }     }          matP = matV.inv () * matV2; } if  (isDegenerate) {    cv::Mat matX2 (6 , 1 , CV_32F, cv::Scalar::all(0 ))  ;     matX.copyTo (matX2);     matX = matP * matX2; } 
第一轮迭代时判断是否退化,如果退化,每次用V f − 1 V u Δ x u \mathbf{V}_{f}^{-1} \mathbf{V}_{u} \Delta \boldsymbol{x}_{u} V f − 1  V u  Δ x u  
结语 
至此,LOAM终于学习完了,接下来可能看看Lego LOAM,LIO等。
参考 
[1] J. Zhang和S. Singh, 《LOAM: Lidar Odometry and Mapping in Real-time》, 发表于 Robotics: Science and Systems 2014, 7月 2014. doi: 10.15607/RSS.2014.X.007 .
[2] J. Zhang, M. Kaess和S. Singh, 《On degeneracy of optimization-based state estimation problems》, 收入 2016 IEEE International Conference on Robotics and Automation (ICRA) , Stockholm, Sweden, 5月 2016, 页 809–816. doi: 10.1109/ICRA.2016.7487211 .
[3] 基于 LOAM 的方法中平面点和边缘线的残差构建以及雅可比推导 
[4] 矩阵求导总结(二) | Dwzb’s Blog 
[5] LOAM后端优化算法分析 - 知乎 
[6] https://github.com/soloice/Matrix_Derivatives 
[7] 矩阵求导术(上) - 知乎 
[8 矩阵求导术(下) - 知乎 
[9] Matrix calculus - Wikipedia 
[10] Rayleigh quotient