本文主要是介绍[基础知识点]PCG算法以及代码解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 基本介绍
- 共轭梯度法是介于梯度下降法与牛顿法之间的一个方法,是一个一阶方法,它克服了梯度下降法收敛慢的缺点,又避免了存储和计算牛顿法所需要的二阶导数信息。
- 共轭梯度法的思想是,选择一个优化方向后,本次选择的步长能够将这个方向的误差更新完,在以后的优化更新过程中不再需要朝这个方向更新了。由于每次将一个方向优化到了极小,后面的优化过程将不再影响之前优化方向上的极小值,所以理论上对N维问题求极小只用对N个方向都求出极小就行了。为了不影响之前优化方向上的更新量,需要每次优化方向共轭正交。在 n 维的优化问题中,共轭梯度法最多 n 次迭代就能找到最优解(是找到,不是接近)。
- 虽然 CG 方法可以减小求解时间和内存占用,但是缺点是矩阵 A 的条件数会很大程度上影响收敛速度。为了减小条件数,需要对 A 进行预处理,即得到预处理共轭梯度法 PCG。
2. 算法流程
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;
}
这篇关于[基础知识点]PCG算法以及代码解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!