- 计算机视觉
- 深度学习
- 图像处理
【免费下载链接】kornia
🐍 Geometric Computer Vision Library for Spatial AI
本文基于 changelog.d/+migration-091.fixed.md 的变更记录,深入剖析 Kornia 几何模块中symmetric_transfer_error在遇到奇异(不可逆)单应矩阵时返回NaN的根因、修复方案与行为契约变化。读者将理解"在可微逆矩阵之前屏蔽输入而非屏蔽输出"这一关键技巧,掌握该函数在 DLT/IRWLS 求解流程中的应用场景,以及如何通过现有测试用例验证梯度有限性。
背景:对称传递误差是什么
在双视图几何中,单应矩阵(Homography)描述同一平面场景在两幅图像间的投影映射。给定一对对应点与一个单应矩阵,Kornia 提供了两类误差度量:
- oneway_transfer_error:单向传递误差,计算把第一幅图像的点通过
H投影到第二幅图像后与观测点的平方欧氏距离; - symmetric_transfer_error:对称传递误差,同时计算正向投影
d(x', Hx)与反向投影d(x, H⁻¹x')两个方向,再求和。
按 Hartley & Zisserman《Multiple View Geometry》第 4.7 节的公式,对称传递误差为:
dist = Σ ( d(x, H⁻¹x')² + d(x', Hx)² )该函数在 find_homography_dlt_iterated(迭代加权最小二乘 IRWLS)中被反复调用:每一轮迭代都用上一次估计的H计算对称传递误差,再以torch.exp(-errors / (2.0 * (soft_inl_th**2)))生成新的权重,直至收敛。因此,误差数值一旦出现NaN,会直接污染后续所有迭代的权重与最终求解结果。
问题现象:奇异单应矩阵导致 NaN
find_homography_dlt在四对共线点、零权重对应点等退化场景下可能产出奇异(行列式为零、不可逆)的单应矩阵。当这样的H传入symmetric_transfer_error时,旧实现会返回NaN,而非文档所承诺的惩罚值max_num(torch.finfo(pts1.dtype).max)。
根因分析:屏蔽时机错误导致梯度被污染
旧实现的处理流程大致是:先对H求逆,得到包含非有限值(inf/nan)的未屏蔽逆矩阵H_inv,用safe_inverse_with_mask拿到有效掩码后,再通过算术掩码
(there + back) * mask + max_num * (~mask)把奇异行的误差替换为max_num。
问题在于屏蔽发生在求逆之后、误差计算之后。代码注释明确指出:inv_ex的反向传播公式为-H_inv^T @ grad @ H_inv^T,它依赖保存下来的H_inv。当H_inv满是inf/nan时,即使最终输出被掩码遮盖,反向传播中依然会产生0 * nan = nan,从而污染:
pts1/pts2对应点的梯度;- 单应矩阵
H自身的梯度(H.grad出现nan)。
一旦梯度被污染,整个可微几何求解管线(如端到端训练中通过H反传损失)都会失效。
修复方案:先屏蔽输入,再用 torch.where 赋惩罚值
修复后的实现(kornia/geometry/homography.py#L123-L143)将防护前移到求逆的输入侧,核心是三条原则:
- 在可微求逆之前把奇异行替换为单位矩阵。先用
safe_inverse_with_mask(H.detach())在一个脱离计算图(detached)的副本上计算有效掩码good_H(这样掩码本身不携带梯度),再通过torch.where(good_H.view(-1, 1, 1), H, eye)将奇异行替换为 3×3 单位矩阵eye。可微求逆从此只面对合法的输入矩阵。 - 对替换后的
H_safe求逆:H_inv_safe, _ = safe_inverse_with_mask(H_safe)。由于输入已合法,逆矩阵及其反向传播都是有限的——奇异行上的梯度恒为零,其余行保持不变。 - 用
torch.where干净地赋予惩罚值:torch.where(good_H_reshape, out, max_tensor),不再使用会产生0 * nan的算术掩码。
正向与反向误差仍由oneway_transfer_error计算(内部对w_den加上eps保证除零安全,见 kornia/geometry/homography.py#L87-L94),可逆单应矩阵的数值结果与修复前完全一致。
行为契约变化:squared=False 下的取值修正
变更记录同时修正了squared=False分支的取值语义:
- 修复前:奇异行得分为
(max_num + eps).sqrt()——这是先把平方误差的惩罚值开平方,数值略大于max_num的平方根; - 修复后:奇异行直接得分为
max_num,与文档契约("Rows whose homography is not invertible scoremax_num")一致,见函数 docstring(kornia/geometry/homography.py#L111-L114)。
这意味着无论squared=True还是squared=False,奇异行都返回同一惩罚值max_num,语义统一且可预测。
底层支撑:safe_inverse_with_mask 的实现
整个修复依赖 safe_inverse_with_mask。该函数对输入矩阵执行torch.linalg.inv_ex,并通过info == 0生成"是否可逆"的布尔掩码;在 ONNX 导出或 tracing 场景下,会退化为基于伴随矩阵与行列式的闭式求逆(_adjugate_closed_form),以det != 0作为掩码。它保证奇异输入不会引发运行时崩溃,只返回掩码标记。
修复中用到的关键点在于:safe_inverse_with_mask(H.detach())返回的掩码不参与计算图,因此可以安全地用于torch.where选择;而随后对已屏蔽的H_safe求逆时,掩码结果虽被丢弃,但求逆本身及其梯度路径都是有限的。
测试验证:数值与梯度的双重保障
tests/geometry/test_homography.py 中的TestSymmetricTransferError为该修复提供了系统性的回归测试:
- test_singular:构造批大小为 2 的输入,其中第二个单应矩阵为奇异(全零矩阵仅保留
H[1, 0, 0] = 1)。分别验证squared取True/False时输出无NaN、可逆行有限、奇异行恰好等于max_num;并检查pts1.grad无NaN、可逆行梯度有限、奇异行梯度为零。 - test_singular_gradient_wrt_homography:验证
H.grad整体有限,奇异行梯度为零。 - test_singular_gradient_through_estimated_homography:模拟
find_homography_dlt_iterated通过估计出的H反传误差的场景,确保奇异中间结果不会污染产生它的对应点梯度。
此外,test_gradcheck 继续对常规(可逆)输入做梯度检查,保证修复不破坏原有微分正确性。
实际影响与适用场景
此次修复直接受益的调用链包括:
find_homography_dlt_iterated的 IRWLS 迭代重加权流程(奇异中间估计不再中断收敛);- RANSAC 验证阶段对候选单应矩阵的误差打分(
NaN误差会静默地使验证失效); - 端到端可微几何训练管线(梯度保持有限,奇异行贡献零梯度而非
NaN)。
从使用角度,调用方无需任何改动:symmetric_transfer_error(pts1, pts2, H, squared=True, eps=1e-8)的签名与形状契约(B, N)保持不变,唯一需要留意的是squared=False下奇异行的取值从(max_num + eps).sqrt()变为max_num,若下游代码依赖旧数值需相应更新。
小结
+migration-091.fixed.md记录了一次典型的"数值安全修复":表面问题是输出NaN,根因却是屏蔽时机与可微求逆反向传播的相互作用。修复通过在求逆之前将奇异行替换为单位矩阵、在求逆之后用torch.where干净地赋予max_num,同时保证了数值有限性与梯度有限性;对于可逆单应矩阵,行为完全不变。这一模式对任何涉及"掩码 + 可微矩阵求逆"的实现都有直接借鉴价值。
- 计算机视觉
- 深度学习
- 图像处理
【免费下载链接】kornia
🐍 Geometric Computer Vision Library for Spatial AI
相关推荐
Kornia 修复 symmetric_transfer_error 对奇异单应矩阵返回 NaN:遮蔽输入而非输出,保住可微梯度
Kornia 修复 symmetric_transfer_error 对奇异单应矩阵返回 NaN:遮蔽输入而非输出,保住可微梯度 本篇技术文章围绕 Kornia
人工智能计算机视觉深度学习图像处理kornia 视频框修复:`VideoBoxes.get_boxes_shape()` 与 `to_mask()` 的 `as_padded_sequence` 传递问题解析
kornia 视频框修复: VideoBoxes.get_boxes_shape 与 to_mask 的 as_padded_sequence 传递问题解析 导
计算机视觉深度学习图像处理Kornia 修复旋转奇异点梯度 NaN:`quaternion_exp_to_log` 与 `euler_from_quaternion` 的边界防护实现解析
Kornia 修复旋转奇异点梯度 NaN: quaternion_exp_to_log 与 euler_from_quaternion 的边界防护实现解析 本篇
人工智能计算机视觉深度学习图像处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考