别再死记硬背公式了!用Python从零实现共轭梯度法(CG),手把手带你理解每一步
2026/5/16 23:24:59 网站建设 项目流程

用Python从零实现共轭梯度法:代码拆解与可视化实战

在机器学习与科学计算的领域中,线性方程组求解是一个基础但至关重要的问题。当面对大规模稀疏矩阵时,传统直接解法往往效率低下,而迭代法中的共轭梯度法(Conjugate Gradient, CG)因其优异性能成为工程师的首选工具。本文将以Python为实践工具,从零开始构建CG算法,通过可视化手段揭示其内在数学之美。

1. 环境准备与问题建模

共轭梯度法要求系数矩阵A对称正定。我们首先生成一个满足条件的测试矩阵:

import numpy as np from scipy.sparse import diags # 生成对称正定矩阵 def generate_spd_matrix(n, kappa=10): """生成n×n对称正定矩阵,条件数为kappa""" A = diags([1, -0.25, -0.25], [0, 1, -1], shape=(n, n)).toarray() A = (A + A.T)/2 # 确保对称 # 调整条件数 eigvals = np.linspace(1, kappa, n) Q, _ = np.linalg.qr(np.random.randn(n,n)) return Q @ np.diag(eigvals) @ Q.T n = 50 A = generate_spd_matrix(n) b = np.random.randn(n)

关键参数说明:

  • n: 矩阵维度
  • kappa: 条件数控制
  • A: 对称正定矩阵
  • b: 随机生成的右侧向量

2. 算法核心实现

CG算法的精妙之处在于其共轭方向的构造方式。下面我们分步骤实现算法主体:

def conjugate_gradient(A, b, x0=None, max_iter=1000, tol=1e-6): if x0 is None: x0 = np.zeros_like(b) x = x0.copy() r = b - A @ x p = r.copy() rs_old = r.dot(r) residuals = [] solutions = [x.copy()] for i in range(max_iter): Ap = A @ p alpha = rs_old / p.dot(Ap) x += alpha * p r -= alpha * Ap rs_new = r.dot(r) residuals.append(np.sqrt(rs_new)) solutions.append(x.copy()) if np.sqrt(rs_new) < tol: break beta = rs_new / rs_old p = r + beta * p rs_old = rs_new return x, residuals, solutions

算法关键变量说明:

变量名数学含义作用
x解向量当前迭代解
r残差向量b - Ax
p共轭方向搜索方向
alpha步长沿p方向的最优步长
beta组合系数新共轭方向权重

3. 收敛分析与可视化

理解CG的收敛行为对于实际应用至关重要。我们通过可视化手段展示其特性:

import matplotlib.pyplot as plt # 运行CG算法 x_cg, residuals, solutions = conjugate_gradient(A, b) # 绘制残差下降曲线 plt.figure(figsize=(10,6)) plt.semilogy(residuals, 'o-', label='CG Residual') plt.xlabel('Iteration') plt.ylabel('Residual Norm') plt.title('Convergence History') plt.grid(True) # 添加理论收敛边界 kappa = np.linalg.cond(A) theoretical_bound = [2*( (np.sqrt(kappa)-1)/(np.sqrt(kappa)+1) )**k for k in range(len(residuals))] plt.semilogy(theoretical_bound, '--', label='Theoretical Bound') plt.legend()

典型输出结果分析:

  1. 实际收敛曲线通常位于理论边界下方
  2. 前几次迭代往往能大幅降低残差
  3. 条件数越大,收敛速度越慢

注意:实际应用中,残差可能不会严格单调下降,这与浮点运算精度有关

4. 性能对比与工程实践

我们将自实现的CG与标准库函数进行对比:

from scipy.sparse.linalg import cg as scipy_cg # 使用相同初始值比较 x0 = np.random.randn(n) x_sp, info = scipy_cg(A, b, x0=x0, tol=1e-6) x_our, _, _ = conjugate_gradient(A, b, x0=x0, tol=1e-6) # 验证解的正确性 exact_solution = np.linalg.solve(A, b) print(f"Scipy CG error: {np.linalg.norm(x_sp - exact_solution):.2e}") print(f"Our CG error: {np.linalg.norm(x_our - exact_solution):.2e}")

工程实践建议:

  1. 预处理技术能显著改善条件数
  2. 对于非对称系统,考虑使用GMRES等算法
  3. 实际应用中应监控残差而非依赖固定迭代次数

5. 算法变体与扩展应用

CG算法有多种变体适用于不同场景:

变体名称适用场景特点
PCG病态系统使用预处理矩阵加速收敛
Nonlinear CG非线性优化处理一般函数极小化
BiCGSTAB非对称系统扩展CG到非对称矩阵

以非线性CG为例,其Python实现核心差异在于:

def nonlinear_conjugate_gradient(f, grad_f, x0, max_iter=100): x = x0.copy() grad = grad_f(x) p = -grad for _ in range(max_iter): # 使用线搜索确定步长 alpha = line_search(f, grad_f, x, p) x_new = x + alpha * p grad_new = grad_f(x_new) # PR+方法计算beta beta = max( (grad_new.dot(grad_new - grad)) / grad.dot(grad), 0 ) p = -grad_new + beta * p x, grad = x_new, grad_new return x

在机器学习中的应用场景:

  • 逻辑回归参数优化
  • 神经网络权重训练
  • 支持向量机求解

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询