稠密匹配 · 实测解读
UniFlowMatch vs RoMa v2 · RTX 5060 Ti · FP32 · 2026.07
「给一张照片和另一张不同角度拍的照片,让算法告诉我——每一个像素跑到哪去了。」
这个听起来有点哲学的问题,是计算机视觉里经典到发霉的 dense correspondence(稠密对应)任务。过去十年的主流玩法都是「先抽特征、再匹配」——SIFT、SuperPoint、SuperGlue、LoFTR 一路走来,方法越来越花,但稀疏关键点这个底层范式没变过。
2025 年 NeurIPS 上 Carnegie Mellon 的 Castacks Lab 丢了一篇论文 UFM (UniFlowMatch),直接把这件事换成「一张图直接回归像素位移」的端到端范式:
输入两张图 → DINOv2 视觉骨干 → 双视图 Global Attention Transformer → 一次前向同时吐出 稠密光流 (flow) 和 共视性掩码 (covisibility)。
6 月他们又放出了一个用 DINOv2-Giant 初始化的变体 UFM-Base-DINOv2G-init(社区叫它 UFM-G),说精度和鲁棒性都上了一个台阶。我就直接拿 6 对真实场景图,在 RTX 5060 Ti 上跑了一遍,看看到底差多少。

UFM 把这件事做对的关键不是「模型大」,而是 用 DINOv2 的全局语义特征替代了传统局部描述子。语义特征天然对视角变化、尺度变化、轻微遮挡都更鲁棒,再加一个双视图 Joint Attention,就能同时输出 flow 和 covisibility——不再需要先抽 SIFT 再 RANSAC 那套老古董。
实测下来,UFM-Base 的核心卖点是「快且省」——185 ms / 3 GB,跑在 RTX 5060 Ti 上是消费级 GPU 能轻松扛的水平。代价是 covisibility 在高分辨率大场景下不如 RoMa v2 抓得稳(toronto 30.9% vs 54.3%)。UFM-G 在 6 对图上跟 Base 打平,更多显存和时间没换到明显收益。
先把它的工作流说清楚(看图就行):

图 1 · UFM 端到端稠密匹配流程:从两张图直接回归出像素级位移 + 共视性掩码
几个关键设计


图 2 · 传统两阶段范式 vs UFM 端到端。左边 SIFT/SuperGlue/LoFTR 那套,右边是 UFM 一次前向搞定一切
左边那套「检测关键点 → 提描述子 → 最近邻匹配 → RANSAC 清洗」的范式已经统治了 15+ 年。它的根本问题是——关键点检测器本身就在低纹理、重复纹理场景下失效。白墙、天空、阴影、皮肤、单一色块……这些地方压根没有「独特角点」可检测。
UFM 的解法是 跳过关键点这一步,用 DINOv2 训练好的视觉语义特征当底层表示,再加一层双视图 attention 让两张图的 token 互相看——最后用 DPT 头把 token 级信息解回像素级的 (dx, dy) 偏移和可见性 mask。这条路线下,纹理不是必须,语义相似度才是关键。

图 3 · UFM-Base vs UFM-G 架构对比。注意 backbone、attention 深度、mlp 类型都变了
UFM-G 不是简单把 Backbone 换大就完事——整个 Info Sharing Transformer 也跟着深了:
维度 | UFM-Base | UFM-G |
|---|---|---|
Backbone | DINOv2-ViT-L/14 | DINOv2-ViT-G/14 (reg4) |
Backbone 参数 | 304 M | 1.10 B |
Info Sharing 层数 | 12 | 16 |
hidden dim | 1024 | 1536 |
MLP 类型 | Mlp (GELU) | SwiGLU (DINOv2 风格) |
总参数 | 0.43 B | 1.18 B |
权重文件大小 | 1.6 GB | 4.4 GB |
实测里 G 并不比 Base 慢太多。6 对图均值上,Base 是 178 ms,G 是 255 ms,只多了 ~40%。G 的 Info Sharing 用了 SwiGLU 加 16 层,1080p 这个尺寸下算子融合和显存访问模式综合下来,反倒没吃亏太多。
每对图都跑 Base 和 G 两个模型,记录推理耗时、显存峰值、covisibility 覆盖率。

图 4 · 6 对真实图 × Base vs UFM-G 实战对比。左列 Base warped、中列 G warped、右列 G covisibility 热图
逐对点评

原始数据
pair | 分辨率 | Base ms | Base GB | Base cov | G ms | G GB | G cov |
|---|---|---|---|---|---|---|---|
bike | 1080×1080 | 415 | 3.05 | 53.9% | 258 | 7.62 | 52.7% |
building | 810×1080 | 122 | 3.05 | 78.6% | 254 | 7.62 | 69.5% |
cook | 607×1080 | 140 | 3.05 | 15.8% | 254 | 7.62 | 15.4% |
fire_academy | 580×1080 | 133 | 3.04 | 76.6% | 253 | 7.61 | 76.0% |
scene | 810×1080 | 124 | 3.05 | 25.0% | 253 | 7.62 | 21.6% |
toronto | 1530×2040 | 126 | 3.12 | 30.9% | 257 | 7.68 | 35.8% |
均值 | — | 178 | 3.06 | 46.8% | 255 | 7.63 | 45.2% |
表 1 · 6 对真实图实测数据(RTX 5060 Ti · FP32 · batch=1)
既然要横评,绕不开 RoMa v2。同样 6 对图,用 setting="precise"(LR 800 + HR 1280 + 双向推断)也跑一遍,三引擎同台对比:

图 5 · RoMa v2 precise vs UFM-Base vs UFM-G — 6 对真实图 × 3 引擎 (列向看同一对图的不同引擎输出)
三引擎均值对比
引擎 | 参数量 | 输出分辨率 | 推理 (ms) | 显存 (GB) | cov>0.5 均值 |
|---|---|---|---|---|---|
RoMa v2 precise | 0.43B | 1280×1280 (HR) | 1374 | 10.57 | 45.7% |
UFM-Base | 0.43B | 原始分辨率 | 185 | 3.06 | 46.8% |
UFM-G | 1.18B | 原始分辨率 | 255 | 7.63 | 45.2% |
表 2 · 三引擎均值(6 对图平均 · RTX 5060 Ti · FP32 · batch=1)
均值 covisibility 三家几乎打平 (45.7% / 46.8% / 45.2%),单看覆盖率没人有绝对优势。但速度 / 显存差距是数量级的:UFM-Base 比 RoMa v2 precise 快 ~7.4×,省 ~3.5× 显存。UFM-G 比 RoMa v2 快 ~5.4×,省 ~1.4× 显存。
数据里有一处反直觉:bike (1080×1080) 推理耗时 415 ms,toronto (2040×1530) 只要 126 ms。原因在 UFM 内部会把输入先 pad 到固定 internal resolution 再切块,toronto 的实际 padding 后尺寸比 1080×1080 还要"对齐"一些。Base 在小图上反而吃亏。
挑 fire_academy 这对图细看,因为它场景最具代表性(室外 + 建筑 + 车辆 + 天空),且 Base 和 G 的覆盖率几乎相同 (76.6% / 76.0%),可以直接对比「质量 vs 数量」。

图 6a · UFM-Base 在 fire_academy 上。covisibility 给大块模糊区域,flow color 估计正确

图 6b · UFM-G 在 fire_academy 上。同样的覆盖率,但 covisibility 把屋顶边、车辆轮廓、楼梯线全部画清
覆盖率几乎一样,但 G 输出的 covisibility 热图(右下)能看出 屋顶、车辆、楼梯线、建筑立面 的清晰边界;Base 的同样位置是大片均匀的"亮黄",没有结构信息。
这就是 DINOv2-G 的「语义优势」——它知道「这块像素和那块像素是不是同一个 object part」,而 DINOv2-L 只能告诉你「这两块像素的特征向量是不是接近」。前者对应着 covisibility 的细粒度判断,后者只够给一个粗略的 yes/no。
坑 1 · SSL_CERT_FILE 环境变量指向不存在的路径
UniFlowMatchConfidence.from_pretrained(...) 第一次会从 HuggingFace 下载权重。如果你的环境里 SSL_CERT_FILE 指向旧文件,会直接 FileNotFoundError 挂掉。修法:
export SSL_CERT_FILE="$(python -c 'import certifi; print(certifi.where())')"
坑 2 · pip 默认装的是 CPU-only PyTorch
第一次 pip install -e UFM/UniCeption 时,pip 会从默认 PyPI 拉 torch==2.13.0+cpu(约 200MB)。这玩意儿在 RTX 5060 Ti 上能用,但所有 autocast 都会被禁掉,推理慢 10×。修法:装完先 force-reinstall 一次带 CUDA 的 wheel:
pip install --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cu130 torch torchvision torchaudio
注意:cu130 是 sm_120(RTX 50 系)唯一支持的索引;cu126/cu129 编译时没带 sm_120 内核,会报 CUDA capability sm_120 is not compatible。
坑 3 · UFM-G 加载报 TypeError: 'str' object is not callable
UFM-G 的 config.json 里 mlp_layer: "SwiGLU"(字符串),而 UniCeption v0.6 的 MultiViewGlobalAttentionTransformer 默认是直接把类对象传下去。修法是给构造函数加一个字符串→类的解析器,把 "SwiGLU" 解析为 v0.6 里的 SwiGLUFFN(注意 DINOv2 风格的 SwiGLU 用的是 hidden = dim * mlp_ratio * 2/3,不是 v0.6 默认的 dim * mlp_ratio,需要新建一个子类)。
三引擎跑下来,我的实际建议是——UFM 不是「比 RoMa v2 更好」,而是「跟 RoMa v2 各擅胜场」。把这场实测里真正能下的结论列出来:
选 UFM-Base 需要实时 (≥5 fps)、显存紧张 (< 8 GB)、想上 batch、场景在 1080p 以下。性价比最优,185 ms / 3 GB 跑 6 对图均值。
选 UFM-G 需要 语义级 covisibility(3DGS / NeRF / 视觉定位下游),对边缘敏感。255 ms / 7.6 GB 换精细 mask。
选 RoMa v2 precise 做研究 / 离线重建,对 高分辨率大场景 的 covisibility 质量有硬要求(toronto 上 RoMa v2 54.3% vs UFM-G 35.8%);能扛 10.6 GB 显存和 1.4 s 的耗时。
UFM-Base 的真正卖点不是精度,是「在 RTX 5060 Ti 这种消费级显卡上,几百毫秒就能拿到稠密对应」。RoMa v2 precise 输出 1280×1280 是真稠密,但需要 1.4 s + 10.6 GB;UFM-Base 输出 580×1080 但只花 185 ms + 3 GB——速度差 7.4×,显存差 3.5×。这两个量级决定了 UFM 能塞进实时 pipeline,RoMa v2 一般只能离线。
RoMa v2 的真正卖点是「HR refinement + 双向推断 + DPT 重建头」这堆工程细节在高分辨率场景下确实多捞出来一些召回(toronto 多 18.5 个百分点)。如果你要做的是 SfM / 3DGS 重建这种「错了就崩」的任务,covisibility 召回率比推理时间更重要。
UFM-G 的尴尬是它在 6 对图上的 covisibility 表现基本跟 Base 打平,反而花了 2.5× 的显存和 1.4× 的时间。G 的真正价值可能在它 没被覆盖到的场景(强遮挡、跨季节、跨模态),而不是 6 对图这种「两个相近视角」的设定。
· UniFlowMatch 官方仓库:github.com/UniFlowMatch/UFM
· 权重:huggingface.co/UniFlowMatch
本文全部 6 对真实图测试由作者在 RTX 5060 Ti + Windows 11 上完成。注意 UFM 预训练权重继承 CC BY-NC-SA 4.0(训练数据限制,不可商用)。
— END —
觉得有用,欢迎转发给需要的朋友。