ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Kornia 深度平面方程 `depth_from_plane_equation` 掠射光线数值稳定性修复解析

Kornia 深度平面方程 `depth_from_plane_equation` 掠射光线数值稳定性修复解析 计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载depth_from_plane_equation是 Kornia 几何模块中通过平面方程Hessian 形式n · X d逐像素计算相机坐标系深度z的核心函数。本篇文章围绕该函数的一处关键缺陷修复展开当光线与平面精确平行掠射grazing ray时旧的近奇点保护逻辑会因torch.sign(0) 0而失效导致深度返回inf。读完本文你将理解该 Bug 的数学成因、比较形式comparison form修复的取舍、为何不能改用torch.copysign、半精度float16下的eps约束以及该修复如何在 ONNX 导出覆盖测试中被固定下来。一、问题背景掠射光线是真实场景而非边缘输入在基于平面假设的深度估计、地面平面深度推理与自动驾驶感知中经常需要把某个平面例如地面的方程与相机光心发出的光线求交从而为每个像素解出深度。depth_from_plane_equation做的正是这件事其核心公式为denom ray · n depth d / denom当denom趋于零即光线与平面趋于平行时深度会趋于无穷大。在地面平面场景中地平线上的每一个像素都对应一条与地面近似平行、甚至严格平行的光线——这是非常普遍的输入而不是数值测试才会构造的极端用例。原 changelog 条目changelog.d/migration-045.fixed.md明确指出depth_from_plane_equationreturns a finite depth for a ray exactly parallel to the plane.修复前near-singular 保护逻辑为eps * torch.sign(denom)。问题在于torch.sign在输入恰好为零时返回 0因此在精确奇点处epsilon 被乘法抵消eps * 0 0分母仍然以零参与除法最终返回inf。二、修复前的缺陷根因sign 在零处的空洞从源码实现可以复现这条缺陷路径。函数位于 kornia/geometry/depth.py旧版保护逻辑大致是# 修复前的形式有缺陷 denom torch.sum(rays * plane_normals_exp, dim-1) zero_mask torch.abs(denom) eps denom torch.where(zero_mask, eps * torch.sign(denom), denom) depth plane_offsets / denom关键缺陷链条如下torch.sign(denom)在denom 0时返回0这是torch.sign的语义——零的符号是零因此在掩码命中denom 0时保护值变成eps * 0 0等于没有保护除法plane_offsets / 0直接返回inf破坏了对精确平行光线返回有限深度的契约。这正是 issue #4280 报告并最终由 PR #4348 修复的问题见测试中的回归标注tests/geometry/test_depth.py。三、修复方案用比较取符号堵住零点的空洞修复后的逻辑改用比较来为 epsilon 选择符号kornia/geometry/depth.pydenom torch.sum(rays * plane_normals_exp, dim-1) # (B, N) denom_abs torch.abs(denom) zero_mask denom_abs eps # 用比较选择符号denom 0 取 -eps否则取 eps signed_eps torch.where(denom 0, torch.full_like(denom, -eps), torch.full_like(denom, eps)) denom torch.where(zero_mask, signed_eps, denom) depth plane_offsets / denom # (B, N)该方案有两个关键性质在零处无空洞denom 0是布尔比较对denom 0的结果是False因此精确为零的奇点会被替换为正的eps。测试明确断言了这一点对(0, ±1, 0)两种符号的法向量返回的都是2 / 1e-8 2e8——零处没有符号可保留因此固定为正号tests/geometry/test_depth.py。保持已有小非零分母的符号对于绝对值小于eps但非零的denom比较形式保留了denom原有的符号denom 0取负、否则取正与旧逻辑中eps * sign(denom)对非零输入的行为一致。测试test_small_denominators_keep_their_sign用±eps/4构造一对符号相反的小分母断言两个深度幅值相等、符号相反tests/geometry/test_depth.py。此外掩码分支保证了掩码之外的元素完全不受影响Nothing outside the mask is touched因此正视平面fronto-paralleln (0, 0, 1), d 2上每个像素深度精确等于 2 的约定不受扰动convention 测试以atol0.0, rtol0.0严格验证tests/geometry/test_depth.py。四、为何不用torch.copysignONNX 导出约束决定了实现形式从工程实现上看torch.copysign(eps, denom)也能读出同样的语义甚至代码更简洁。但函数注释kornia/geometry/depth.py与 ONNX 导出测试tests/onnx/test_export_coverage.py共同给出了明确的否决理由legacy ONNX exporter没有aten::copysign算子dynamo ONNX exporter在把torch.copysign分解为prims.signbit后同样缺少对应的 ONNX 函数。也就是说torch.copysign在两条导出路径上都不可导出。而depth_from_plane_equation是 Kornia文档化的 ONNX 导出面的一部分它出现在 docs/source/geometry.depth.rst 的autofunction列表中它被收录在导出支持探测用例集 docs/export_support/cases_geomB.py 中tests/onnx/test_export_coverage.py中专门构造了与平面精确平行的光线作为输入plane_normals [[0, 1, 0]]主点光线(0, 0, 1)与之点积精确为零确保被导出的正是掠射分支本身并用onnx.checker ONNX Runtime 推理与 eager 模式逐位比对_assert_samertol/atol 均为 1e-4。因此比较形式torch.where(denom 0, -eps, eps)被固定下来成为该函数的正式实现——它既是数值上正确的也是导出友好的。五、半精度陷阱默认eps1e-8低于 float16 分辨率changelog 条目末尾还强调了一个 dtype 层面的边界The finite-depth promise is bounded by the dtype: the defaulteps1e-8is below float16 resolution, so half-precision callers must pass a representableeps.原因可以从两处测试的注释中得到印证默认eps1e-8在 float16 下会舍入为零导致denom_abs eps永远不成立掩码形同虚设即使掩码生效2 / 1e-8 2e8也超出 float16 的有限表示范围float16 最大约 65504结果依然是inf。因此测试中统一采用eps max(1e-8, float(torch.finfo(dtype).eps))来为 float16 提供可表示的 epsilontests/geometry/test_depth.py并在若干 convention 测试中对 float16 显式pytest.skip例如正常分量2.38e-9在 float16 下下溢为零输入不再是小但非零的分母见 tests/geometry/test_depth.py。实践建议当调用方使用 float16/bfloat16 张量时应显式传入eps例如eps1e-3或float(torch.finfo(dtype).eps)并注意被钳制后的深度量级d / eps是否落在该 dtype 的有限范围内。float32/float64 下默认值1e-8可直接使用。六、函数完整契约与使用方式结合源码 docstringkornia/geometry/depth.py与测试类TestDepthFromPlaneEquationtests/geometry/test_depth.py该函数的使用契约如下6.1 参数与形状参数形状说明plane_normals(B, 3)相机坐标系下的平面法向量Hessian 形式n · X dplane_offsets(B, 1)平面偏移量dpoints_uv(B, N, 2)整数像素中心的像素坐标函数内部用camera_matrix自行归一化输入的是像素而非归一化坐标camera_matrix(B, 3, 3)相机内参矩阵epsfloat 1e-8数值稳定性 epsilon返回(B, N)的深度张量——每个像素一个深度值是深度列表而非深度图。6.2 约定Convention平面以 Hessian 形式给出n (0, 0, 1)且d 2表示平面z 2其上每个像素深度均为 2结果是被测像素的相机坐标系z值射线-平面点积在(-eps, eps)内被掩码钳制到±eps保留分母符号精确为零的分母替换为正eps掩码之外的值完全不动。6.3 使用示例import torch import kornia B, N 1, 4 plane_normals torch.tensor([[0.0, 0.0, 1.0]]) # (B, 3)正视平面 z 2 plane_offsets torch.tensor([[2.0]]) # (B, 1) points_uv torch.tensor([[[0., 0.], [1., 0.], [0., 1.], [1., 1.]]]) # (B, N, 2) camera_matrix torch.eye(3).unsqueeze(0) # (B, 3, 3) depth kornia.geometry.depth.depth_from_plane_equation( plane_normals, plane_offsets, points_uv, camera_matrix ) # depth [[2., 2., 2., 2.]]与 test_simple 的期望一致float16 场景请显式传入可表示的epseps max(1e-8, float(torch.finfo(torch.float16).eps)) depth kornia.geometry.depth.depth_from_plane_equation( plane_normals.half(), plane_offsets.half(), points_uv.half(), camera_matrix.half(), epseps )6.4 测试覆盖总览TestDepthFromPlaneEquationtests/geometry/test_depth.py从多个维度锁定行为test_smoke/test_shapes/test_shapes_broadcast形状与广播(B, N)输出、(1, 3)法向量与(B, N, 2)像素的广播test_simple正视平面逐像素深度精确为 2test_grazing_ray_is_finite精确平行光线返回有限深度test_small_denominators_keep_their_sign小非零分母保留符号test_gradcheckfloat64 下对法向量、偏移、像素坐标与内参矩阵求梯度验证可微性test_convention_*Hessian 约定、钳制行为与奇点回归#4280。七、小结depth_from_plane_equation的这次修复#4280 / #4348是一个典型的数值奇点 导出兼容性双重约束下的工程决策根因eps * torch.sign(denom)在denom 0时被 sign 的零值抵消保护失效返回inf修复改用torch.where(denom 0, -eps, eps)比较形式堵住零点空洞并保留非零分母的符号约束因torch.copysign在 legacy 与 dynamo 两条 ONNX 导出路径上均不可用比较形式被写入文档化导出面并固定在 tests/onnx/test_export_coverage.py 中边界默认eps1e-8低于 float16 分辨率半精度调用方必须传入可表示的eps并注意钳制深度d/eps的量级是否超出该 dtype 的有限范围。对于在地面平面感知、深度补全或平面拟合类任务中使用kornia.geometry.depth.depth_from_plane_equation的开发者理解这条修复路径既能帮助你规避半精度下的inf陷阱也能解释为何该函数在导出为 ONNX 后依然保持相同的数值行为。赞分享计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载相关推荐Kornia 修复 depth_from_plane_equation 掠射射线数值稳定性从 inf 到有限深度Kornia 修复 depth_from_plane_equation 掠射射线数值稳定性从 inf 到有限深度 本文聚焦 Kornia 中 kornia.g计算机视觉深度学习人工智能图像处理Kornia 相机去畸变数值稳定性修复解析undistort_points_kannala_brandt 的 float16 精度与梯度修复Kornia 相机去畸变数值稳定性修复解析 undistort_points_kannala_brandt 的 float16 精度与梯度修复 本篇技术指南围计算机视觉人工智能深度学习图像处理Kornia 修复 distance_transform 全零输入下 NaN 梯度级联卷积距离变换的数值稳定性解析Kornia 修复 distance_transform 全零输入下 NaN 梯度级联卷积距离变换的数值稳定性解析 kornia.contrib.distan计算机视觉深度学习人工智能图像处理上一篇突破性能瓶颈egui与WebGPU集成的高性能渲染方案下一篇在 Android 应用中集成 Lightweight Charts™Android Wrapper 安装、配置与数据填充实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表