[基础知识点]PCG算法以及代码解析

1. 基本介绍

  1. 共轭梯度法是介于梯度下降法与牛顿法之间的一个方法,是一个一阶方法,它克服了梯度下降法收敛慢的缺点,又避免了存储和计算牛顿法所需要的二阶导数信息。
  2. 共轭梯度法的思想是,选择一个优化方向后,本次选择的步长能够将这个方向的误差更新完,在以后的优化更新过程中不再需要朝这个方向更新了。由于每次将一个方向优化到了极小,后面的优化过程将不再影响之前优化方向上的极小值,所以理论上对N维问题求极小只用对N个方向都求出极小就行了。为了不影响之前优化方向上的更新量,需要每次优化方向共轭正交。在 n 维的优化问题中,共轭梯度法最多 n 次迭代就能找到最优解(是找到,不是接近)。
  3. 虽然 CG 方法可以减小求解时间和内存占用,但是缺点是矩阵 A 的条件数会很大程度上影响收敛速度。为了减小条件数,需要对 A 进行预处理,即得到预处理共轭梯度法 PCG。

2. 算法流程

[基础知识点]PCG算法以及代码解析_第1张图片

3. 相关代码

节选自BA代码,求解 A δ x p = b A\delta x_p = b Aδxp=b中使用PCG代码进行求解。

VecX Problem::PCGSolver(const MatXX &A, const VecX &b, int maxIter = -1) {    
    assert(A.rows() == A.cols() && "PCG solver ERROR: A is not a square matrix");    
    int rows = b.rows();    
    int n = maxIter < 0 ? rows : maxIter;    
    VecX x(VecX::Zero(rows));    
    MatXX M_inv = A.diagonal().asDiagonal().inverse();    
    VecX r0(b);  // initial r = b - A*0 = b    
    VecX z0 = M_inv * r0;    
    VecX p(z0);    
    VecX w = A * p;    
    double r0z0 = r0.dot(z0);    
    double alpha = r0z0 / p.dot(w);    
    VecX r1 = r0 - alpha * w;    
    int i = 0;    
    double threshold = 1e-6 * r0.norm();    
    while (r1.norm() > threshold && i < n) {        
         i++;        
         VecX z1 = M_inv * r1;        
         double r1z1 = r1.dot(z1);        
         double belta = r1z1 / r0z0;        
         z0 = z1;        
         r0z0 = r1z1;        
         r0 = r1;        
         p = belta * p + z1;        
         w = A * p;        
         alpha = r1z1 / p.dot(w);        
         x += alpha * p;        
         r1 -= alpha * w;    
     }    
     return x;
}

你可能感兴趣的:(从零手写VIO,论文知识点补充)