使用伪逆求解DX=G得异常结果,移除逆运算却正常?
伪逆求解DX=G时的结果异常问题分析
问题回顾
需要求解非方阵线性方程$DX=G$,正确的最小二乘伪逆解法应为$X=(DTD){-1}D^TG$,对应的代码是:
X = np.matmul(np.linalg.inv(np.matmul(np.transpose(D), D)), np.matmul(np.transpose(D), G))
但该代码输出结果带有随机噪声;而错误地去掉逆运算,使用公式$X=(DTD)DTG$(对应代码如下)时,却得到了视觉上平滑的结果:
X = np.matmul(np.matmul(np.transpose(D), D), np.matmul(np.transpose(D), G))
原因分析
第二个公式完全不符合数学逻辑
$X=(DTD)DTG$不是求解$DX=G$的任何合法解法,它只是对$DTG$做了一次$(DTD)$的矩阵乘法操作。如果$D$是和图像平滑相关的算子(比如梯度算子),那么$DTD$通常是类似拉普拉斯的平滑矩阵,这个操作相当于对$DTG$做了平滑,所以视觉上看起来“理想”,但该结果完全不满足原方程$DX=G$,是错误的计算结果。第一个公式的数值稳定性问题
直接计算$(DTD){-1}$的前提是$DTD$是可逆矩阵,但如果$D$的列存在线性相关或近似线性相关的情况,$DTD$会是奇异或接近奇异的矩阵,直接用np.linalg.inv求逆会引入极大的数值误差,最终表现为输出结果中的随机噪声。
注意事项
- 优先使用内置伪逆函数:永远不要手动计算$(DTD){-1}D^T$,numpy提供了数值稳定性更好的
np.linalg.pinv(D),它通过SVD分解计算伪逆,能有效处理奇异或接近奇异的矩阵,正确代码应为:X = np.matmul(np.linalg.pinv(D), G) - 处理病态问题:如果$D$是欠定或病态矩阵(秩不足),需要加入正则化项来获得稳定且平滑的解,比如岭回归的形式:
正则化项$\lambda I$会让$D^TD+\lambda I$变得可逆,同时能抑制解的噪声,得到更平滑的结果。lambda_reg = 1e-5 # 正则化参数,根据实际情况调整 X = np.matmul(np.linalg.inv(np.matmul(D.T, D) + lambda_reg * np.eye(D.shape[1])), np.matmul(D.T, G)) - 验证结果正确性:不要只依赖视觉效果,要计算残差$||DX - G||_2$,正确解法的残差应该远小于错误解法的残差,确保结果满足原方程的最小二乘要求。
- 理解需求本质:如果需要平滑的解,应该在损失函数中加入平滑正则项(比如$||X||_2$或总变分正则),而不是修改伪逆公式,避免得到数学上无效的结果。
内容的提问来源于stack exchange,提问作者Deepak Raj
相关产品推荐
相关产品推荐

