Kornia 本地特征提取优化基准:基于 Oxford graf 数据集的 GPU/CPU/MPS 端到端加速与质量验证
2026/9/24 16:53:45 网站建设 项目流程
  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

本文基于 benchmarks/feature/graf_benchmark.md 记录的一次正式 A/B 基准评测,系统讲解 Kornia(0.9.0rc1)三条本地特征提取管线——SIFT、SIFT–AffNet–HardNet、KeyNet–HardNet——在优化提交(e8e4ec0f等)相对基线提交(601b5a4a等)下的端到端性能差异:包括 RTX 4090 / Intel i7-14700K / Apple M1 三种硬件的速度与质量数据、torch.compile 选择性编译的收益边界,以及方向直方图累积(scatter_add_)、亚像素精化批处理、channels-last 激活等优化的源码级实现。读完本文,你将掌握如何解读这类"加速但保质量"的基准报告、如何用仓库内的基准脚本在 CPU/CUDA/MPS 上复现,以及哪些优化路径在哪种硬件上真正生效。

基准概览:工作量、被比较提交与评测口径

该基准使用Oxford graf序列(6 张 640×800 原始分辨率图像及其 5 个H1toKp单应矩阵真值),输入为灰度 float32、batch 1、请求4096个特征。第一、二小节(GPU/CPU)采用 eager 模式,不开启 autocast 也不做 torch.compile;两版实现的金字塔层数、尺度、迭代预算、描述子、权重、匹配阈值与 RANSAC 设置完全一致,因此速度差异只来自实现层面而非配置漂移。

小节基线提交优化提交
GPU / CPU eager601b5a4ae8e4ec0f
选择性编译(CUDA)601b5a4afb66de1d(同一优化库实现 + 编译模式)
MPS1eea5835f61ea9e4

计时口径由基准脚本 benchmarks/feature/local_features.py 定义:包含两张图像的特征提取与 SNN 匹配,排除图像 I/O 与 RANSAC;每格取五对图像(1–2 … 1–6)各自 median 的均值,原始中位数与 IQR 保留在 JSON 中。质量指标为平均 L1 角点重投影误差(像素),即用 RANSAC 估计的单应与真值单应分别把图像四个角点投影后的平均距离,实现见 benchmarks/feature/scale_space_detector.py。

GPU 端到端速度与质量(RTX 4090)

环境:RTX 4090、PyTorch 2.14.0+cu130、Python 3.11.14、Kornia 0.9.0rc1、WSL2 Linux。单位 ms/pair:

管线基线 ms/pair优化 ms/pair加速比平均角点误差 基线 → 优化
SIFT215.9114.51.89×223.640 → 223.640
SIFT–AffNet–HardNet269.4174.11.55×2.183 → 2.183
KeyNet–HardNet131.5126.91.04×5.638 → 5.638

几个需要谨慎解读的结论:

  • KeyNet–HardNet 的约 4% 提升小于观测到的计时波动,不足以构成端到端 GPU 加速的证据;SIFT 与 SIFT–AffNet–HardNet 的提升则远大于波动。
  • 两版 GPU 运行在每一对图像、每一条管线上的匹配数、RANSAC 内点数与角点误差完全相同——加速没有以牺牲匹配质量为代价。

逐对 GPU 角点误差(px):

图像对SIFT 误差SIFT–AffNet–HardNet 误差KeyNet–HardNet 误差
1–21.3811.3252.029
1–31.5061.2161.428
1–42.7770.8602.531
1–5507.1322.6243.700
1–6605.4054.89118.500

表中揭示一个重要事实:纯 SIFT 在两个最大视角变化(1–5、1–6)上本已严重失败(数百像素误差),优化前后失败模式完全一致——大均值误差不是"只平均成功对"造成的假象,优化也没有掩盖失败。

GPU 峰值额外显存(MiB,指一次提取+匹配调用中,超出已驻留图像/模型/输出的最大新增张量分配,不含 RANSAC 与分配器预留):

管线基线峰值额外 CUDA MiB优化峰值额外 CUDA MiB
SIFT576.0665.8
SIFT–AffNet–HardNet1058.31058.6
KeyNet–HardNet1057.71057.7

SIFT 的提速大约以90 MiB 额外峰值显存为代价,换来更少的精化(refinement)启动次数。

从源码看计时实现:脚本在 benchmarks/feature/local_features.py 中对 CUDA 使用torch.cuda.reset_peak_memory_stats记录峰值分配,并通过 benchmarks/common.py 的time_us(内部封装torch.utils.benchmark.Timer.blocked_autorange)得到带预热、多次重复的 median/IQR 墙钟时间。

CPU 速度与质量(Intel Core i7-14700K)

环境为单 CPU 线程。代表性 1–2 对被反复计时,其余四对仍全部评估质量(JSON 中这些对的 timing 字段为null,表示有意不计时)。每格为 median ± IQR,单位为秒/pair:

管线基线 s/pair优化 s/pair加速比
SIFT3.861 ± 0.0222.856 ± 0.0511.35×
SIFT–AffNet–HardNet16.343 ± 0.14512.714 ± 0.0801.29×
KeyNet–HardNet16.368 ± 0.03112.887 ± 0.1131.27×

CPU 上的匹配数、内点数与重投影误差同样在每对图像上完全一致。注意CPU 与 GPU 的结果不可直接互比:两者的自适应精化后端与数值内核不同,正确的做法是各自与同设备的基线对比。

逐对 CPU 角点误差(px):

图像对SIFT 误差SIFT–AffNet–HardNet 误差KeyNet–HardNet 误差
1–21.2471.3431.263
1–31.4351.2271.679
1–42.6111.5481.833
1–5507.0371.7923.658
1–6605.42711.6588.828

Apple Silicon(MPS)速度与质量

环境:Apple M1(8 GB)、macOS 26.5.1、PyTorch 2.14.0、Python 3.11.14、Kornia 0.9.0rc1,与 CPU/CUDA 运行使用相同输入(input_sha256一致)。每对图像都计时,每格同样为五对 median 的均值:

管线基线 ms/pair优化 ms/pair加速比平均角点误差 基线 → 优化
SIFT1787.81068.81.67×223.546 → 223.546
SIFT–AffNet–HardNet3066.72342.21.31×3.741 → 3.741
KeyNet–HardNet2109.52118.61.00×3.452 → 3.452

MPS 评测有两个关键工程细节(见 benchmarks/feature/local_features.py):harness 在计时区域内显式调用torch.mps.synchronize;而 RANSAC 由于其批量化 SVD 在 MPS 上会使进程崩溃(issue #4201/#4204),被放到 CPU 上评估,且 RANSAC 位于计时区域之外,因此计时不受影响。MPS 上peak_extra_cuda_bytesnull

逐对 MPS 计时(median ± IQR,ms):

图像对SIFT ms 基线 → 优化SIFT–AffNet–HardNet ms 基线 → 优化KeyNet–HardNet ms 基线 → 优化
1–21770 ± 23 → 1059 ± 103115 ± 43 → 2353 ± 312118 ± 33 → 2120 ± 17
1–31789 ± 10 → 1062 ± 183069 ± 20 → 2344 ± 232107 ± 6 → 2122 ± 24
1–41778 ± 6 → 1068 ± 63067 ± 4 → 2338 ± 42107 ± 6 → 2121 ± 10
1–51791 ± 12 → 1078 ± 23046 ± 4 → 2343 ± 22107 ± 17 → 2110 ± 9
1–61812 ± 48 → 1076 ± 103037 ± 16 → 2334 ± 102108 ± 18 → 2120 ± 9

逐对 MPS 角点误差(px):

图像对SIFT 误差SIFT–AffNet–HardNet 误差KeyNet–HardNet 误差
1–21.2471.9271.263
1–31.4351.3651.679
1–42.5861.9611.833
1–5507.0371.7923.657
1–6605.42711.6588.828

MPS 上所有对的匹配数、内点数与角点误差在两次运行间也完全一致。KeyNet–HardNet 在 MPS 上完全不变(噪声范围内):因为 channels-last 转换只在 CPU/CUDA 生效,且 KeyNet 使用 OriNet 而非梯度直方图定向,MPS 上这条管线没有走到任何优化路径——这正是源码里 kornia/feature/keynet.py 的x.device.type in ("cpu", "cuda")条件门控的直接结果。

选择性编译(CUDA):torch.compile 只编译关键热区

第三组实验对比基线601b5a4afb66de1d(同一优化库实现 + 编译基准模式)。注意:这不是全管线编译——现有工厂只编译尺度空间金字塔、响应与亚像素模块(或 KeyNet 的响应/NMS),使用dynamic=True与默认 Inductor 设置;描述子、定向、仿射适应、匹配与 RANSAC 保持 eager。

管线基线编译 ms/pair优化编译 ms/pair加速比平均角点误差 基线 → 优化
SIFT94.6471.231.33×223.654 → 223.654
SIFT–AffNet–HardNet158.27132.871.19×2.381 → 2.381
KeyNet–HardNet106.01105.081.01×5.638 → 5.638

解读要点:

  • KeyNet 的差异仍是计时噪声;两个编译版本间所有对的匹配数、内点数、特征数与角点误差完全一致。
  • 编译本身会改变部分尺度空间结果,因此 eager 与编译的质量必须分开比较,例如 SIFT–AffNet–HardNet 编译后均值误差 2.381 px,eager 为 2.183 px。
  • 每个版本在独立进程中用全新的TORCHINDUCTOR_CACHE_DIR启动;首次调用被排除在预热与稳态计时之外,但记录在 JSON 中:SIFT 首次提取+匹配调用基线 43.42 s / 优化 43.38 s;KeyNet 15.25 s / 16.84 s。SIFT–AffNet–HardNet 在 SIFT 之后运行,复用了已编译的检测器图(0.233/0.209 s),因此其首次调用不是独立的冷编译测量;首次延迟包含实际执行与初始化,不只是编译时间。
  • 编译模式峰值额外 CUDA 分配:SIFT 566.9 → 690.1 MiB;SIFT–AffNet–HardNet 1058.6 → 1058.6 MiB;KeyNet–HardNet 1057.7 → 1057.7 MiB。五对各自的 median/IQR 与首次调用延迟全部保留在原始 JSON 中。

编译模式命令(源码见 benchmarks/feature/local_features.py 的--compile参数):

.venv/bin/python -m benchmarks.feature.local_features --seq /data/graf --device cuda --compile --json graf-compiled.json

从 benchmarks/feature/scale_space_detector.py 可以看到编译范围:scalespace 方法通过compile_modules=["subpix", "resp", "scale_pyr"]编译三个模块;KeyNet 方法则在 KeyNetExtractor 中执行det.model = torch.compile(det.model, dynamic=True)det.nms = torch.compile(det.nms, dynamic=True)——注释说明 model 与 nms 在 6 种不同图像尺寸上运行,dynamic=True可避免重复编译;而 aff/ori/descriptor 不编译,因为extract_patches_from_pyramid若被追踪,每个 (特征数, patch 尺寸) 组合都会特化出新图,导致预热尖峰。

本次未运行编译模式的 CPU 对比。更早的 SIFT 运行时图表(benchmarks/feature/sift_runtime.md)覆盖公开尺度空间 SIFT 预设在 batch 1 的 CPU eager/编译,以及 CUDA batch 1/4/8 的运行时,与本次 graf 配对基准是不同的工作量(单图提取 vs 双图提取+匹配),不要互比绝对数值:

优化实现细节(源码级佐证)

原文档"Implementation"一节列出了四项核心优化,均可直接对应到当前仓库源码:

1. 用scatter_add_累积方向直方图。每个梯度像素只向相邻的两个方向 bin 投票,替代原来对整块 patch 的 36 次完整扫描。实现在 kornia/feature/orientation.py 的PatchDominantGradientOrientation.forward:先计算 36-bin 角度与加权幅度,然后两次ang_bins.scatter_add_分别累加左右两个 bin,半精度输入提升到 float32 累积后再除回 patch 面积。文档注释同时提醒:CUDA 上scatter_add_使用原子操作,两次相同输入可能产生 ulp 级差异,极端接近的 bin 可能返回相邻峰,torch.use_deterministic_algorithms(True)可恢复确定性。

2. 内建亚像素模块的正/负响应精化批处理。正负响应精化合并为批量调用,减少 kernel 启动次数(这也是 GPU 显存表中"以约 90 MiB 换更少精化启动"的由来);NMS 邻域保持分离,自定义模块与精化器保留独立调用并带候选数上限,且精化迭代次数不变。

3. 合并前只 gather 被选中的坐标。在合并正/负结果前先按选中坐标 gather,避免在整个 octave 上做密集的三坐标合并。

4. KeyNet / HardNet 的 channels-last float32 激活。KeyNet 窄卷积块在 CPU/CUDA 上于块边界转换一次 channels-last(kornia/feature/keynet.py),HardNet 在 CPU 上同样处理(kornia/feature/hardnet.py)。参数布局与 checkpoint 键保持不变,因此预训练权重契约不受影响——这也是 MPS 上 KeyNet 管线完全看不到收益的原因。

复现指南

数据准备。使用 Oxford affine graf 数据集(Oxford affine 评测数据集中的 graf 序列),归档 SHA-256 为999871b945ee968a00a0d5f9af957d1382fb9dae1511cdee9553366817b53b5b;每张输入图像与单应矩阵的哈希同样记录在 JSON 元数据的input_sha256字段中(见 benchmarks/feature/graf_results/optimized-cuda.json),可逐字节校验输入一致性。原版 Oxford PPM 优先,仅当 PPM 不存在时才用 PNG(转换副本可能解码出不同像素)。

运行命令(在仓库根目录、使用.venv解释器):

# CUDA:五对全部计时 .venv/bin/python -m benchmarks.feature.local_features --seq /data/graf --device cuda --json graf-cuda.json # CPU:--timing-pairs 2 只计时代表性 1–2 对,但仍评估全部五对质量 .venv/bin/python -m benchmarks.feature.local_features --seq /data/graf --device cpu --timing-pairs 2 --json graf-cpu.json # MPS:五对全部计时,RANSAC 自动落到 CPU .venv/bin/python -m benchmarks.feature.local_features --seq /data/graf --device mps --json graf-mps.json

基线对比。在基线 worktree 根目录用主检出(primary checkout)的显式解释器通过runpy.run_path运行同一 harness,并确认打印的kornia.__file__指向基线 worktree 而非 editable 主检出。最终基准进程顺序执行、无并发测试干扰。

管线配置(与文档一致,全部在 benchmarks/feature/scale_space_detector.py 中可查):

  • 尺度空间管线:ScalePyramid(3, 1.6, 32, double_image=True)(3 层 + 3 个额外层)、DoG 极小/极大值、AdaptiveQuadInterp3d默认参数、32 像素梯度方向 patch。
  • SIFT 使用SIFTDescriptor(32, rootsift=True)(RootSIFT);SIFT–AffNet–HardNet 在定向前加预训练 AffNet、定向后加预训练 HardNet;KeyNet–HardNet 使用公开预设与预训练 OriNet。
  • SNN 匹配 ratio 0.85;单应 RANSAC 参数:threshold 2.0、max_iter 10、batch_size 8196、confidence 0.9999、seed 3407(见 benchmarks/feature/local_features.py);模型构建使用 PyTorch seed 0。

方法论约束(详见 benchmarks/common.py 与 benchmarks/README.md 的 methodology contract):计时预算至少扩展到 5 次预热调用时长,避免慢 CPU 调用退化为单一样本;CPU 线程数为 1,与共享 Timer 一致;matmul TF32 被禁用,cuDNN 保持默认 TF32 并记录在元数据中;结果 JSON 为严格合法 JSON(NaN 转为 null),形状为{"metadata": ..., "results": [...]}

原始结果文件

以下 JSON 保留每对的 median/IQR、首次调用延迟、特征数、匹配数、内点数、峰值显存与完整元数据(benchmarks/feature/graf_results/):

  • 基线 CUDA
  • 优化 CUDA
  • 基线 CPU
  • 优化 CPU
  • 基线选择性编译 CUDA
  • 优化选择性编译 CUDA
  • 基线 MPS
  • 优化 MPS

需要强调的是:这些是本地基准结果而非发布级的性能承诺。它们是 benchmarks/README.md 意义上的对比工件(comparison artefacts),由benchmarks/results_schema.pyresults_schema.validate_artefact在 CI 中校验;测量发生在 harness 记录聚合load快照之前,且各次运行顺序执行、无并发负载。引用任何数字时,请同时引用 Kornia 版本与git_commit,因为一个<kornia-version>目录可能横跨多个提交。

  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

相关推荐

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

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

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

立即咨询