ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kornia 的 `ellipse_to_laf` 性能重写:用闭式 2×2 矩阵逆替代 `torch.inverse`

Kornia 的 `ellipse_to_laf` 性能重写:用闭式 2×2 矩阵逆替代 `torch.inverse` 计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载本文解读 KorniaGeometric Computer Vision Library for Spatial AI中kornia.feature.ellipse_to_laf的一次底层重写将批量torch.inverse替换为 2×2 下三角矩阵的闭式求逆。该变更记录于 changelog.d/migration-113.fixed.md在保持数值结果一致的前提下显著提升了 CPU、CUDA 与 MPS 三种后端的吞吐并解锁了torch.compile(fullgraphTrue)与 CPU 低精度 dtype 支持。读完本文你将理解椭圆到 LAF 的数学转换、闭式逆的数值稳定性设计以及如何在本地复现其基准结论。背景ellipse_to_laf在局部特征流程中的角色在 Kornia 的局部特征模块中检测器输出的特征区域通常以LAFLocal Affine Frames局部仿射框架格式表示一个形状为(B, N, 2, 3)的张量前两列构成仿射线性变换第三列是中心坐标x, y。ellipse_to_laf负责把Oxford 格式的椭圆参数(B, N, 5) [x, y, a, b, c]转换为 LAF。其中(x, y)是椭圆中心a, b, c是描述椭圆形状的二次型系数。从 kornia/feature/laf.py 的文档字符串可以确认其数学语义Ellipse (a, b, c) and upright covariance matrix [a11 a12; 0 a22] are connected by inverse matrix square root:A invsqrt([a b; b c]).也就是说椭圆形状由协方差矩阵M [[a, b], [b, c]]描述而 LAF 的线性部分正是该矩阵的逆矩阵平方根。这一转换是 SIFT、Hessian-Affine 等检测器输出与 Kornia 匹配、可视化管线之间的标准接口在特征描述与匹配见 kornia/feature/matching.py中高频调用因此它的单次延迟会直接放大到整个批处理管线。该函数在 kornia/feature/init.py 中以kornia.feature.ellipse_to_laf公开导出并在 docs/source/feature.laf.rst 中通过autofunction自动生成 API 文档。变更动机旧实现的四个短板旧实现的核心是调用torch.matrix_power(torch.cholesky(ell_shape, False), -1)代码中被注释掉的旧逻辑见 kornia/feature/laf.py即先做 Cholesky 分解再求逆最终经由批量torch.inverse完成。这个方案在四个维度上存在明确缺陷片段逐一记录性能差批量torch.inverse走通用linalg求解路径对(B, N, 2, 2)这样的小矩阵属于杀鸡用牛刀开销远高于解析求逆。低精度不支持在 CPU 上原始的.inverse()对float16/bfloat16会直接报错。虽然_torch_inverse_cast理论上可以解除 dtype 限制但那是为兼容而非为速度设计的。MPS 后端病态在 Apple Silicon 的 MPS 后端上批量求逆会命中一条性能病态的linalg路径每次调用都发出deprecated-resize的UserWarning并且无法被torch.compile捕获graph break。无法图编译旧实现导致torch.compile在图编译时断图无法享受编译后的融合与调度优化。片段还记录了一次 MPS 上的临时测量在 N20000 时旧实现慢了约1500 倍并注明该数字为 ad hoc 测量需要重新运行基准才能作为可引用数据。闭式解的数学原理2×2 矩阵平方根与下三角逆新实现不再走通用数值线性代数路径而是利用 2×2 矩阵的特殊结构直接解析求解。推导基于两个经典公式2×2 矩阵平方根三角化特例对形如M (A 0; C D)的矩阵其平方根为R (sqrt(A) 0; C / (sqrt(A)sqrt(D)) sqrt(D))参见源码注释引用的 Square root of a 2 by 2 matrix。由于输入[a, b, c]构成对称矩阵[[a, b], [b, c]]其平方根经过整理后恰好是一个下三角矩阵a11 sqrt(|a|) a22 sqrt(|c|) a21 b / (a11 a22)下三角矩阵的闭式逆矩阵[[a11, 0], [a21, a22]]的逆可以手写为[[1/a11, 0], [-a21/(a11*a22), 1/a22]]这正是新实现的核心对应 kornia/feature/laf.py 中的inv11、inv22、inv21三个量。整个计算只涉及逐元素的sqrt、加减与除法全部为逐元素算子不触发任何批处理求解器因而天然可以被torch.compile静态编译。新实现源码级分析以下是 kornia/feature/laf.py 中重写后的核心逻辑节选a11 ells[..., 2:3].abs().sqrt() a22 ells[..., 4:5].abs().sqrt() a21 ells[..., 3:4] / (a11 a22) # 下三角矩阵 [[a11, 0], [a21, a22]] 的闭式逆 inv11 1.0 / a11 inv22 1.0 / a22 # 关键除以根的乘积而不是乘以各自的倒数 inv21 -a21 / (a11 * a22) A torch.stack([inv11, torch.zeros_like(inv11), inv21, inv22], dim-1).view(B, N, 2, 2) return torch.cat([A, ells[..., :2].view(B, N, 2, 1)], dim3)几个值得注意的实现细节输入校验函数入口通过KORNIA_CHECK_SHAPE(ells, [B, N, 5])校验形状kornia/feature/laf.py。对a、c取绝对值再开方ells[..., 2:3].abs().sqrt()保证了即使出现符号噪声也不会产生nan。中心直接透传ells[..., :2]即x, y原样拼接进 LAF 的第三列形状从(B, N, 5)规整为(B, N, 2, 3)。非对角元素的分母是a11 a22而非sqrt(a) sqrt(c)的变体这是 2×2 平方根公式的标准形式且该分母在正定椭圆上恒为正避免了符号歧义。数值稳定性设计为什么除以根的乘积而不是乘以倒数这是本次重写中最微妙也最关键的设计决策值得单独展开。非对角逆元素理论上可以写成-a21 * inv11 * inv22先乘两个倒数但新实现刻意写成-a21 / (a11 * a22)除以根的乘积。片段与源码注释给出了理由乘积a11 * a22 sqrt(a) * sqrt(c)既不会溢出也不会舍入为零而先乘倒数的每种排列顺序在足够倾斜lopsided或次正规subnormal的对角线上都会让某个中间结果溢出为inf或把可表示的值冲刷为0。具体来说存在两类失败模式测试套件 tests/feature/test_laf.py 中的三个回归测试逐一覆盖test_no_overflow_asymmetric_diag当a取 dtype 的最小正规数、c取与之配合的极大值时固定顺序-a21 * (1/a11) * (1/a22)的中间量会溢出为inf而真实结果本身完全在可表示范围内。乘以倒数会得到inf除以乘积则得到正确值。test_no_overflow_subnormal_diag镜像场景。次正规但非简并的对角线使1 / (a11 * a22)溢出若先形成该乘积数学上为零的非对角元素会变成0 * inf nan。除以乘积则不会测试对后端冲刷次正规的情形做了pytest.skip保护因为那已使对角线简并化。test_no_underflow_asymmetric_diag针对另一种排列顺序先乘较小的倒数历史提交f7b573a3曾采用的回归测试——那种顺序能通过前两个测试却会把一个可表示的非对角元素静默冲刷为假的0。而除以根的乘积这条路径的精度行为可以精确刻画只要乘积a11 * a22是正规数除法结果就是正确舍入correctly rounded非精确但误差有界当乘积为次正规数时除法会损失精度但绝不会把可表示的结果破坏成0、inf或nan——这正是该设计希望保证的不变式。简并椭圆的行为不抛异常但产生非有限值重写带来的一个行为变化值得使用者注意旧的批量torch.inverse遇到奇异矩阵会抛出linalg.LinAlgError而闭式求逆不会抛异常而是返回非有限的 LAF。相关语义在 kornia/feature/laf.py 的Note中明确记录简并椭圆a或c按ells.dtype舍入后为0描述的是无界带状区域其协方差矩阵奇异其 LAF 一定非有限inf总是出现在对角线上而nan只出现在b恰好为0的子情形0 * inf因此筛选结果应使用 laf_is_valid检查有限性 行列式非零不要用isnan测试——它会漏掉纯inf的情形舍入本身是条件的一部分在float16中a低于约3e-8半个最小次正规数即舍入为0若后端把次正规冲刷为零该截止值会抬升到最小正规数约6e-5。对应测试test_degenerate_ellipse_is_non_finitetests/feature/test_laf.py验证了简并输入返回非有限 LAF 且中心列不受影响。正确性与旧实现的一致性验证片段记录的重写验收标准是数值一致性Results agree with the previous implementation to ~1.6e-7 relative infloat32(machine epsilon infloat64).即在float32下相对误差约1.6e-7量级接近float32的机器精度在float64下则达到机器精度水平。这意味着新实现不是近似——它在该精度下与旧实现一致同时拥有可证明更好的边界行为。测试套件 tests/feature/test_laf.py 的TestELL2LAF提供了多维验证test_shape(5,3,5)→(5,3,2,3)、test_conversion手工构造的解析期望值、test_gradcheck保证反向传播可导、test_small_root_sum_is_not_clamped根之和有限非零时不得被钳制否则会把合法逆改变数量级、test_jitTorchScript 兼容。性能收益片段记录的实测加速片段给出了可复现的基准数字对应 benchmarks/feature/ellipse_to_laf.pyfloat32N1e3..1e5torch 2.9.1Linux/WSL2基线 commit2009933e后端eager 加速torch.compile加速CPUi7-14700K~2.4–5.3×~3–6.5×CUDARTX 4090~1.4–1.7×~4.2–5.5×MPSApple Silicon旧实现病态修复后可正常编译修复前 ad hoc 测得 ~1500× 差距需重跑以获得可引用数字编译列使用torch.compile(fullgraphTrue)预热失败会以NOTE形式报告而不会静默跳过benchmarks/feature/ellipse_to_laf.py。注意benchmarks/feature/ellipse_to_laf.py是 Kornia 唯一的此转换基准仓库注明没有其他库暴露此转换因此没有跨库对比列基线是同一脚本在其他 Kornia 修订版上的运行结果见 benchmarks/feature/ellipse_to_laf.py。本地复现基准在仓库根目录工作树运行基准脚本需要显式设置PYTHONPATH$PWD以确保导入的是工作树中的 Kornia 而非可编辑安装版本脚本头部注释说明了原因见 benchmarks/feature/ellipse_to_laf.py# 默认CPU、float32、N 1000 / 20000 / 100000 PYTHONPATH$PWD python benchmarks/feature/ellipse_to_laf.py --device cpu # CUDA torch.compile 输出 JSON 结果 PYTHONPATH$PWD python benchmarks/feature/ellipse_to_laf.py --device cuda --compile --json ellipse_cuda.json # Apple Silicon MPS 编译 float32 PYTHONPATH$PWD python benchmarks/feature/ellipse_to_laf.py --device mps --compile --dtype float32脚本支持的命令行参数benchmarks/feature/ellipse_to_laf.py--device默认cpu、--dtypefloat16/bfloat16/float32/float64默认float32、--sizes逗号分隔的 N默认1000,20000,100000、--compile追加一个torch.compile(fullgraphTrue)列、--json输出严格 JSON 结果文件。输入为固定种子的、良态的 Oxford 格式椭圆(1, N, 5)保证正定benchmarks/feature/ellipse_to_laf.py吞吐单位是每秒处理的椭圆数MPS 通过torch.mps.synchronize同步CUDA 由blocked_autorange自行同步。编译能力与低精度 dtype重写的隐藏收益除了吞吐重写还解锁了两项此前缺失的能力torch.compile(fullgraphTrue)全图编译旧实现因torch.inverse断图而无法编译新实现全部由逐元素算子构成在 CPU、CUDA、MPS 三个后端上均可fullgraphTrue编译。测试 test_dynamo_fullgraph 显式断言编译结果与 eager 结果一致其注释写明被替换的批量torch.inverse会 graph-break闭式必须保持可捕获。CPU 上的float16/bfloat16支持原始的.inverse()调用对低精度 dtype 会报错_torch_inverse_cast本可以解除该限制但闭式是为速度而生的。新实现天然接受低精度输入配合逐元素算子在 CPU 上即可完成float16/bfloat16的椭圆到 LAF 转换。配套的test_dynamo与test_jittests/feature/test_laf.py进一步保证torch.compile、TorchScript 与 eager 三路结果一致。附该变更的 changelog 载体该变更记录于 changelog.d/migration-113.fixed.md。Kornia 采用 Towncrier 的 changelog 片段机制见 changelog.d/README.md每个 PR 在changelog.d/下新增PR.type.md文件added/fixed/breaking三种类型发布时由 Towncrier 合并进 CHANGELOG.md。migration-*文件是引入该工作流时对既有 Unreleased 条目的一次性遗留例外使用 Towncrier 的孤儿前缀以避免生成重复的 PR 链接并在下次发布时被消费。本地可通过pixi run changelog-preview预览待发布条目。小结ellipse_to_laf的这次重写是一个小而深的经典优化案例用 2×2 矩阵的解析结构替代通用数值线性代数在保持~1.6e-7float32精度一致的前提下同时解决了性能、MPS 病态路径、CPU 低精度 dtype 与torch.compile图编译四个问题而除以根的乘积而非乘以倒数的数值设计配合三个定向回归测试把极端输入下的溢出/下溢/冲刷风险收敛到了可证明的边界内。对于在 Kornia 中高频使用局部特征的开发者这一改动意味着 CPU 推理提速约 2.4–5.3 倍eager、编译路径最高约 6.5 倍且首次可以在 MPS 上获得可编译、无告警的转换实现。赞分享计算机视觉人工智能深度学习图像处理【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址https://gitcode.com/gh_mirrors/ko/kornia点击查看免费下载相关推荐Kornia 椭圆到 LAF 转换的闭式逆数值优化ellipse_to_laf 如何摆脱批量 torch.inverseKornia 椭圆到 LAF 转换的闭式逆数值优化 ellipse_to_laf 如何摆脱批量 torch.inverse 本篇技术指南围绕 Kornia 变计算机视觉深度学习人工智能图像处理raylib C语言游戏开发从 clone 到亮屏只要 3 分钟raylib C语言游戏开发从 clone 到亮屏只要 3 分钟 脑子里冒出一个小游戏点子时最快的验证方式不是开编辑器而是把主循环写出来让画面先动起来。游戏开发图形学3D渲染矩阵求逆与伪逆latexify_py中线性代数函数转换方案矩阵求逆与伪逆latexify_py中线性代数函数转换方案 在科学计算和工程应用中矩阵求逆Matrix Inversion和伪逆Pseudoinver代码生成开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表