Kornia 角度转换精度修复解析:rad2deg/deg2rad 的整数输入与 float64 精度保障
2026/9/23 10:24:41 网站建设 项目流程

Kornia 角度转换精度修复解析:rad2deg/deg2rad 的整数输入与 float64 精度保障

【免费下载链接】kornia🐍 Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/gh_mirrors/ko/kornia

导读

本篇文章围绕 Kornia 仓库变更记录changelog.d/+migration-034.fixed.md(对应上游 issue #4358)中的一项核心修复展开:rad2degdeg2rad两个角度单位转换函数此前在整数张量输入下会静默产生错误结果,且在 float64 双精度下丢失精度;而angle_to_rotation_matrix由于内部直接调用deg2rad受同样问题影响。读者在阅读本文后将理解这三个函数的确切行为、精度问题的根因、仓库中的回归测试与修复实现,并掌握在实际几何计算中正确使用这些函数的方法。

修复背景:一个容易被忽视的精度陷阱

角度单位转换是计算机视觉中最基础、最频繁的操作之一。Kornia 中大量下游功能——特征点方向估计、姿态评估、图像仿射变换、坐标变换——都在内部依赖角度转换。该修复变更记录指出:

rad2deganddeg2radnow handle integer tensor inputs correctly and preserve float64 precision.angle_to_rotation_matrixinherits the corrected conversion, while the implementation preserves ONNX export compatibility. (#4358)

也就是说,本次修复涵盖三个层面:

  1. 整数张量输入:此前对整数类型(如torch.int64torch.int32)张量调用rad2deg/deg2rad会得到错误甚至不可预期的结果;
  2. float64 精度保留:此前双精度输入在转换过程中精度受损(与 issue #3937 相关);
  3. 下游函数继承angle_to_rotation_matrix通过deg2rad继承了修正后的行为,同时保持 ONNX 导出兼容性。

修复后的实现:三个函数的源码全貌

rad2deg:弧度转角度

修复后的实现位于 kornia/geometry/conversions.py:

def rad2deg(tensor: torch.Tensor) -> torch.Tensor: r"""Convert angles from radians to degrees. Convention: - the input is in **radians** and the output in **degrees**; the conversion is elementwise and preserves shape, device and float dtype ... """ if not isinstance(tensor, torch.Tensor): raise TypeError(f"Input type is not a torch.Tensor. Got {type(tensor)}") return tensor * (180.0 / math.pi)

关键实现要点:

  • 类型守卫:非torch.Tensor输入直接抛出TypeError,避免静默错误;
  • 标量乘法实现tensor * (180.0 / math.pi)中,Python 浮点标量与张量相乘会触发 PyTorch 的类型提升(type promotion),整数张量被自动提升为浮点类型(默认torch.float32),从而避免整数截断问题;同时 float64 输入因乘数本身就是 float64 精度的标量(180.0 / math.pi),精度得以完整保留;
  • 逐元素且保形:输出 shape、device 与输入一致,浮点 dtype 不变。

deg2rad:角度转弧度

同样位于 kornia/geometry/conversions.py:

def deg2rad(tensor: torch.Tensor) -> torch.Tensor: r"""Convert angles from degrees to radians. Convention: - the input is in **degrees** and the output in **radians**; it performs the opposite conversion to :func:`~kornia.geometry.conversions.rad2deg` ... """ if not isinstance(tensor, torch.Tensor): raise TypeError(f"Input type is not a torch.Tensor. Got {type(tensor)}") return tensor * (math.pi / 180.0)

rad2deg对称,乘数math.pi / 180.0为 float64 标量,同样通过类型提升处理整数输入并保留双精度。

angle_to_rotation_matrix:角度的旋转矩阵化

修复的核心价值在于下游函数angle_to_rotation_matrix,见 kornia/geometry/conversions.py:

def angle_to_rotation_matrix(angle: torch.Tensor) -> torch.Tensor: r"""Create a rotation matrix out of angles in degrees. Convention: - ``angle`` is in **degrees**, shape :math:`(*)` in and :math:`(*, 2, 2)` out - the matrix is ``[[cos, sin], [-sin, cos]]`` with ``det = +1``; for ``angle = 30`` it is ``[[0.8660, 0.5000], [-0.5000, 0.8660]]`` ... """ ang_rad = deg2rad(angle) cos_a: torch.Tensor = torch.cos(ang_rad) sin_a: torch.Tensor = torch.sin(ang_rad) return torch.stack([cos_a, sin_a, -sin_a, cos_a], dim=-1).view(*angle.shape, 2, 2)

三个值得注意的实现细节:

  1. 角度单位约定是「度」而非弧度:该函数接收degrees输入,内部第一行就调用deg2rad(angle)完成单位转换——这正是它“继承”修复行为的途径。测试 tests/geometry/test_conversions.py 中专门固定了这一约定(convention pin):输入30.0得到[[0.8660254, 0.5], [-0.5, 0.8660254]];如果某实现错误地按弧度读取,则pi/2会被当作 1.5708 度,退化为近单位矩阵,测试中的对比值可清晰暴露此类错误;
  2. 输出方向约定:矩阵为[[cos, sin], [-sin, cos]],即教科书数学坐标系中逆时针矩阵的转置,适配 Kornia 图像坐标 y 轴朝下的约定,左乘列向量(x, y)时在图像上呈现逆时针旋转;
  3. 纯张量算子组合:整个实现仅由deg2radtorch.costorch.sintorch.stackview构成,全部是标准 ONNX 可导出算子,这正是变更记录中“preserves ONNX export compatibility”的源码依据。测试文件 tests/augmentation/test_onnx_export.py 的注释也印证:仿射/shear 的compute_transformation路径依赖deg2rad的内联(inlining)来保证 eager 与 ONNX 数值等价。

回归测试:修复如何被验证

仓库在 tests/geometry/test_conversions.py 中通过TestRadDegConversions测试类系统性地固定了修复行为,与变更记录形成一一对应:

float64 精度回归(对应 issue #3937)

@pytest.mark.parametrize( ("op_name", "arg", "expected"), [ ("rad2deg", torch.pi, 180.0), ("deg2rad", 180.0, torch.pi), ("angle_to_rotation_matrix", 90.0, [[0.0, 1.0], [-1.0, 0.0]]), ], ) def test_convention_float64_results_are_exact_3937(self, device, op_name, arg, expected): # Regression for #3937: rad2deg and deg2rad must preserve float64 precision. # angle_to_rotation_matrix inherits the corrected conversion through deg2rad, # so a 90-degree input should produce the expected quarter-turn matrix without # the previous float32 pi bias. # float64 is hardcoded because this regression specifically checks double precision. ... out = op(torch.tensor(arg, device=device, dtype=torch.float64)) self.assert_close(out, torch.tensor(expected, device=device, dtype=torch.float64), atol=1e-12, rtol=1e-12)

这段测试(tests/geometry/test_conversions.py)揭示了修复前的典型缺陷:float32 的 π 偏差(float32 pi bias)。此前如果转换路径中先将 π 截断为 float32,90°转出的旋转矩阵就不会是精确的[[0, 1], [-1, 0]]四分之一转;修复后三个函数在 float64 下均以atol=rtol=1e-12的严格容差通过。测试还注明了 MPS 设备因不支持 float64 而跳过。

整数输入提升回归

@pytest.mark.parametrize( ("op_name", "arg", "expected"), [ ("rad2deg", [1, 2, 3], [57.29577951308232, 114.59155902616465, 171.88733853924697]), ("deg2rad", [180, 90], [3.141592653589793, 1.5707963267948966]), ("angle_to_rotation_matrix", [90], [[[0.0, 1.0], [-1.0, 0.0]]]), ], ) def test_integer_input_promotes_to_float_3937(self, device, op_name, arg, expected): op = getattr(kornia.geometry.conversions, op_name) out = op(torch.tensor(arg, device=device)) assert out.dtype == torch.float32 ...

该测试(tests/geometry/test_conversions.py)验证整数张量输入被自动提升为torch.float32(默认浮点 dtype),且数值结果与期望完全一致——例如deg2rad([180, 90])得到[π, π/2]的完整双精度数值。

往返一致性测试

此外,test_rad2degtest_deg2rad(tests/geometry/test_conversions.py)对多种 batch shape((2, 3)(1, 2, 3)(2, 3, 3)(5, 5, 3))执行了“转过去再转回来”的往返闭合验证,并用gradcheck确认梯度可微性,保证修复没有破坏自动微分链路。

上游与下游的实际影响

下游调用链

从源码搜索可见,本次修复波及的不仅仅是三个孤立函数:

  • kornia/feature/orientation.py 在特征方向估计(orientation estimation)中调用rad2deg(angles_radians)输出角度;
  • kornia/feature/laf.py 与 kornia/feature/sift/pyramid.py、kornia/feature/sift/scale_space.py 在 SIFT 金字塔与尺度空间构建中通过torch.rad2deg处理旋转角度;
  • kornia/metrics/pose.py 在姿态评估指标中用torch.rad2deg(cos_theta.acos())计算角度误差;
  • kornia/geometry/transform/imgwarp.py 在图像仿射变换中执行torch.deg2rad(angles)

其中angle_to_rotation_matrix还被 tests/feature/test_laf.py 直接用于 LAF 旋转矩阵的构造与torch.jit.script脚本化验证,说明其行为正确性直接影响特征模块的输出。

对 ONNX 导出的意义

变更记录特别强调修复“preserves ONNX export compatibility”,结合 tests/augmentation/test_onnx_export.py 的注释可以确认:在 Kornia 中,随机仿射等增强模块的compute_transformation路径会将deg2rad内联进导出的计算图。因此,修复必须以“不引入不可导出的新算子”为前提——当前实现完全由乘法与三角函数等标准算子构成,天然满足该约束。这也提醒使用者:若自行改写实现(例如引入torch.deg2rad之外的自定义分支),需额外验证 ONNX 导出路径的数值等价性(参见 tests/augmentation/test_onnx_export.py 中的 eager 与 ONNX Runtime 数值对比机制)。

实际使用建议

结合本次修复,在实际项目中调用这三个 API 时值得注意以下几点:

  1. 角度单位务必分清rad2deg/deg2rad的输入输出单位在 docstring 中已有明确约定(kornia/geometry/conversions.py),而angle_to_rotation_matrix接收的是degrees,不要混用;
  2. 整数输入现在是安全的:修复后可以直接传入torch.tensor([90, 180], dtype=torch.int64)这类整数张量,类型提升机制会将其转为 float32 并给出正确结果;但若追求更高数值精度,建议显式构造dtype=torch.float64输入;
  3. 高精度场景显式使用 float64:涉及相机标定、姿态评估、SLAM 等对角度误差敏感的场景,建议显式指定dtype=torch.float64,以利用修复后保留的双精度;注意 MPS 设备不支持 float64(测试中已跳过);
  4. 依赖 gradcheck 验证可微性:两个转换函数均通过gradcheck测试(tests/geometry/test_conversions.py),可直接用于可微渲染、姿态优化等梯度场景。

结语

+migration-034.fixed.md所记录的这次修复虽然改动量小(本质上是乘法标量选择与类型提升的配合),却消除了几何计算链路中一个隐蔽的精度隐患:整数输入的错误结果与 float64 精度丢失。通过 kornia/geometry/conversions.py 的源码与 tests/geometry/test_conversions.py 中针对性回归测试,我们完整还原了问题根因、修复方案与验证手段。对于所有在特征匹配、姿态估计、图像变换中依赖角度运算的 Kornia 使用者而言,这一修复意味着更可靠、更精确的角度数值基础。

【免费下载链接】kornia🐍 Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/gh_mirrors/ko/kornia

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询