CAUVIS / CODE TRACE
Executable truth · official implementation

从像素到检测框
逐算子追踪

这张图把官方代码的实际执行路径放在主层,把论文中存在但代码未执行的机制作为红色审计层。所有“因果”“解耦”等词只代表论文命名,不把它们当成代码已经证明的性质。

青色=张量/标准路径琥珀=Cauvis 可训练路径红色=论文↔代码差异
24×同一份 Cauvis 在 24 个 ViT block 后重复调用
4.9M日志记录的可训练 backbone 参数,约 1.6%
0代码中的 SVD / top-k / 奇异值软阈值操作
1600配置中的 prompt token 数;论文建议约 100
01 / End-to-end path

真实执行总流程

从一张道路图像开始,逐步跟踪它怎样变成候选框。每一步都列出输入、计算、输出和作用;先理解主干流程,再到下一节放大 Cauvis 内部。

Bbatch size,一次送入网络的图像数量
C / channel每个位置保存多少维特征,可理解为描述信息的长度
token把图像小块转换成的向量;模型处理向量序列而非直接处理像素
feature map保留空间排布的特征张量,形状通常写作 B×C×H×W
01
Dataset pipeline

读取图像与标注

数据集给出一张道路图像,以及训练时使用的类别和真实框。测试时没有真实框参与预测。

输入磁盘图像 + GT 类别/边界框
处理直接缩放到 640×640;训练时以 0.5 概率水平翻转,框同步变换
为什么需要固定输入尺寸后,后续 token 数量恒定,batch 内也能组成规则张量。
代码位置configs/cauvis/...sdgod.py:15–21
02
Data preprocessor

通道转换与归一化

把像素调整到预训练 DINOv2 熟悉的数值分布,生成真正送入 backbone 的张量。

输入B×3×640×640,读取器产生的 BGR 像素
计算BGR→RGB,再逐通道执行 (pixel−mean)/std
输出B×3×640×640 浮点张量
为什么需要输入统计分布需与 ImageNet/DINOv2 预训练阶段保持一致。
代码位置configs/_base_/models/dinov2_dinohead.py:13–18
03
Patch embedding

把图像切成 1600 个 token

ViT 不逐像素计算,而把每个 16×16 图像块编码为一条 1024 维向量。

空间切分640÷16=40,因此得到 40×40=1600 个 patch
向量化每个 patch → 1024 维 token,并加入位置编码
额外 token序列前加入 1 个 CLS,最终长度 1601
为什么需要位置编码告诉模型每块来自图像哪里;CLS 用于汇总全局信息。
形状变化B×3×640×640 → B×1601×1024
04
Frozen DINOv2 backbone + trainable Cauvis

重复 24 次:Block → Cauvis

这是方法真正改动 backbone 的位置。DINOv2 block 提取上下文特征,随后共享的 Cauvis 对 patch tokens 做一次小幅修正。

单层执行顺序
当前 tokens冻结 ViT block共享 Cauvis下一层
DINOv2 block自注意力让 1601 个 token 交换信息,FFN 再变换每个 token;参数冻结。
Cauvis暂存 CLS,仅修改 1600 个 patch token;同一份 prompt/分支参数调用 24 次。
形状输入与输出均为 B×1601×1024,不改变序列长度和通道数。
为什么这样插入让少量可训练参数在不同语义深度反复影响特征,同时保留预训练 backbone。
代码位置cauvis_backbone.py:35–42 · cauvis.py:123–134
05
Feature collection

从第 7 / 11 / 15 / 23 层取特征

检测器需要不同尺度的信息,所以在四个深度截取 token,并重新排成二维特征图。

去掉 CLSB×1601×1024 → B×1600×1024
恢复空间1600=40×40,重排为 B×1024×40×40
四个深度层 7、11、15、23 分别提供由浅到深的语义表示
注意四个输出来自不同网络深度;刚取出时空间尺寸其实都相同。
代码位置cauvis_backbone.py:43–50
06
Artificial feature pyramid

把四张 40×40 特征图变成多尺度

DINOv2 原生只有单一 patch 尺度,代码用插值构造检测器需要的四级金字塔。

层 7B×1024×160×160 · stride 4
层 11B×1024×80×80 · stride 8
层 15B×1024×40×40 · stride 16
层 23B×1024×20×20 · stride 32
为什么需要高分辨率层更适合定位小目标,低分辨率层拥有更大感受野,适合大目标与整体语义。
代码位置dino_v2.py:358–386
07
Neck / ChannelMapper

统一为 256 个通道

Transformer 检测器使用 256 维特征,因此 neck 把 backbone 的 1024 通道压缩到 256。

计算每个尺度分别经过 1×1 convolution + GroupNorm(32)
空间尺寸160²、80²、40²、20² 都保持不变
输出四张 B×256×H×W 特征图
为什么需要降低计算量,并让四个尺度与后续 encoder/decoder 的 256 维接口一致。
代码位置dinov2_dinohead.py:39–46
08
DINO encoder + query initialization

编码四尺度特征并选出 900 个候选

6 层 deformable encoder 跨尺度聚合信息;two-stage 机制再从 encoder 输出中选择高分候选,初始化 decoder queries。

Encoder6 层、256 维,在四个特征层级的少量采样点间聚合信息
位置加入二维正弦位置编码,使展平后的特征仍知道原空间坐标
Two-stageencoder 候选按分数取 top 900,形成初始 reference boxes/queries
为什么用 query每个 query 可理解为一个“负责寻找某个目标”的检测槽位。
代码位置dinov2_dinohead.py:8–12, 47–53, 64–69
09
DINO decoder

900 个 query 反复查询图像特征

6 层 decoder 让 queries 彼此交互,并从四尺度 encoder memory 中寻找与各自目标相关的信息。

Self-attentionqueries 之间交流,减少多个 query 重复描述同一目标
Cross-attentionquery 在四尺度图像特征中采样,补充目标外观和位置证据
逐层精修每层根据当前 reference box 继续修正框;6 层中间结果都用于训练监督
这里的 attention属于标准 DINO 检测器,与前面 Cauvis 的 prompt cross-attention 是两套不同机制。
代码位置dinov2_dinohead.py:54–63
10
DINOHead / output

每个 query 输出类别与边界框

检测头把 decoder 特征翻译为 7 类得分和归一化框坐标。训练与推理在这里采取不同的收尾方式。

每个 query 的输出7 个 sigmoid 分类得分 + 4 个框参数;最多有 900 个候选 query
训练 / 推理分叉
TRAINHungarian matching 将 queries 与 GT 一对一匹配;计算 Focal + L1 + GIoU。另有标准 DINO denoising queries,仅训练使用。
INFERENCE展平 sigmoid 分数后直接 top-k,最多输出 300 个类别—框组合,再映射回原图尺寸;没有 NMS。
最终得到每个检测结果包含类别、置信度和图像坐标中的边界框。
代码位置dinov2_dinohead.py:70–89 · detr_head.py:605–620
阅读提示:Cauvis 只替换了第 04 步中的 backbone 行为;第 07–10 步是标准 DINO 检测器。官方推理不是“阈值 + NMS”,而是对 sigmoid 分类分数直接取 top-k(max_per_img=300)。
02 / Module microscope

Cauvis 到底算了什么

下面只按 cauvis.py 的算子画图。变量名 main / causal / auxiliary 沿用代码与论文,但这些名称本身不能证明特征具有因果含义。

INPUT / AFTER EACH VIT BLOCK

分离 CLS 与 patch tokens

X : B × 1600 × 1024

CLS token 不参加 Cauvis 内部计算,结束后再拼回。空间 H、W 参数传入模块,但当前前向没有用它们做二维频域变换。

cls = x[:, :1]
feats = x[:, 1:]
SHARED TRAINABLE MODULE / CALLED 24 TIMES

零初始化 Prompt → 直接点积注意力

P : 1600 × 1024   (initially zeros)
A = softmax((X · Pᵀ) / √1024)
V = Linear(P)
R = Linear(A · V)
MAIN / “CAUSAL”

m = SiLU(Linear(R))
output = α · m

AUX / FOURIER

u = SiLU(MLP(R))
f = FourierBranch(u) + u
output = β · f

X′ = δ · X + α · main(R) + β · aux(R)
return concat(cls, X′)
论文缺失实现:这里没有 Wq/Wk,也没有对 A 做 SVD、top-k 截断或软阈值。论文 §4.1 的“最大奇异值因果子空间”没有进入这条可执行路径。
LEARNABLE SCALES

三标量融合

α=0.001 · β=0.001 · δ=1.0

三者都是 nn.Parameter,因此融合比例可学习。它们控制分支强度,但不是按样本动态生成的门控权重。

表述边界:论文“dynamically adjust”可宽泛理解为训练中可学习;若理解为输入相关的动态门控,则代码不支持。

Fourier 分支:1D token FFT 的真实掩码

1600 → zero pad 2048 → FFT(dim=1) → mask → iFFT → crop
index 0 · DCindex 1024 · Nyquist / |f|最高index 2047 · 接近 DC 的负频

掩码保留索引 820…1227,即围绕 Nyquist 的最高约 20% 双边频带;它不是最低 20% 低频。由于 FFT 沿 token 序列做,所谓“高频”取决于 token 排列顺序,并非直接的二维图像空间频率。

论文内部矛盾:正文 §4.2 说 high-pass;Appendix D 又描述 low-pass / amplitude threshold 以衰减高频噪声。代码采用接近正文的“保留高频”,但实现为 1D token FFT,而非 Appendix D 的 C×H×W 特征 2D DFT。
00
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23

每个圆形 C 都是对同一个 self.cauvis 的调用;青色底线表示送到 neck 的层 7 / 11 / 15 / 23。不是 24 份独立 prompt。

03 / Detector behavior

训练与推理

Cauvis 没有独立损失函数,也没有推理时开关。它通过标准检测损失的梯度学习;训练专用的 denoising queries 属于标准 DINO,而不是 Cauvis 的训练/推理不对称。

冻结范围

backbone 内名称包含 cauvis 的参数可训练,其余 DINOv2 backbone 参数冻结。detector 的 neck/head 在 backbone 外,照常训练。

分类损失

Focal Loss,sigmoid,γ=2,α=0.25。论文中笼统写“cross-entropy”并不精确。

框损失

L1 Loss(权重 5)+ GIoU Loss(权重 2),没有额外蒸馏、解耦、频谱或对抗损失。

推理路径

Cauvis 仍在 24 层后执行。分类结果做 sigmoid + top-k,最多 300 个框;代码路径没有 NMS。

04 / Paper ↔ code audit

差异地图

红色是会改变方法定义或理论支撑的结构差异;琥珀色是实现选择、配置或表述边界。严重度按对论文核心机制可复验性的影响排序。

CRITICAL

SVD 因果子空间完全缺席

论文把 top-k 大奇异值方向、对小奇异值软阈值作为后门调整解释核心;cross_attention 只有点积、缩放、softmax、加权求和与线性层。

CRITICAL

Fourier 输入与维度都改变

论文 Appendix D:backbone 中间特征 Z∈RC×H×W 做 2D DFT;代码:对 cross-attention 输出 R 沿 token 维做 1D FFT。

HIGH

论文的 Q/K 投影不存在

论文 Q=XWq、K=PWk、V=PWv;代码 Q/K 直接使用 X/P,只对 prompt 值做 mlp_prompt 投影。

HIGH

Eq.9 sigmoid 变为 SiLU

论文要求 y=σ(MLP(p̃)) 且输出位于 [0,1];代码是 Linear + SiLU,输出无 [0,1] 约束。

HIGH

频率叙述相互冲突

正文 high-pass,附录 low-pass/幅度阈值;代码使用固定索引窗,保留 Nyquist 周围约 20% 的最高频带。

HIGH

Prompt 长度建议与运行配置分离

论文消融称约 100 近最优并建议默认 100;官方配置是 token_length=1600。这不能解释 SVD 缺失,因为代码无论长度多少都没有 SVD 分支。

MEDIUM

Fourier 分支多一个内部残差

AuxiliaryBranch 返回 out + x,论文 Eq.10–11 的文字/公式没有清楚呈现这一实现残差。

MEDIUM

“只用交叉熵”与配置不符

实际检测头使用 Focal + L1 + GIoU。这仍是标准检测损失,但不是只有交叉熵。

MEDIUM

“约 1%”实际日志约 1.6%

冻结逻辑方向正确;日志记录 backbone 可训练 4,919,363 / 304,255,082 参数,约 1.6%。且 neck/head 仍需训练。

MEDIUM

命名不能建立因果对应

代码没有监督 prompt 对应 confounder 状态,也没有显式独立性/干预约束。“causal branch”是模块名,不是可执行保证。

LOW

部分配置参数不控制前向

link_token_to_query=False 被传入并保存,但在 Cauvis 前向中未读取;use_softmax 也未决定是否 softmax,代码始终执行 softmax。

LOW

零初始化带来早期对称性

所有 prompt token 初始完全相同。初始注意力对 1600 prompts 均匀;训练能否快速打破对称取决于梯度路径,这是数学风险,不是仅凭源码能判定的性能结论。

05 / Evidence ledger

证据索引

行号针对工作区当前文件。表中把“论文声称什么”和“代码真正执行什么”并列,便于回到原文复核。

判定规则:只有实际参与当前配置前向或损失计算的代码才算“实现”。注释、未读取的构造参数、模块命名与理论解释不能替代算子。论文内部互相冲突时单独标记,不替作者选择其中一版。
核对项论文证据代码证据判定
SVD / 软阈值全文文本 268–313、402–406、1186–1205:SVD、top-k causal subspace、抑制小奇异值。cauvis.py:108–116:einsum → scale → softmax → value aggregation → to_out;无 SVD/截断/阈值。不一致
Fourier 输入Appendix D,1053:输入为 backbone 中间特征 Z=f(x)。cauvis.py:129–131aux_branch(res_prompt),输入来自 cross-attention。不一致
DFT 维度Appendix D,1053:C×H×W 特征的 2D DFT。cauvis.py:38torch.fft.fft(..., dim=1),沿 token 维做 1D FFT。不一致
频段正文 510:high-pass;Appendix D 1073:low-pass / amplitude threshold 抑制高频。cauvis.py:40–46:中心 index 1024 开窗;未 shift 的 FFT 中该处是 Nyquist。论文自相矛盾;代码高通
激活Eq.9,434:σ 为 sigmoid,y∈[0,1]dcauvis.py:56–66:Linear + SiLU。不一致
Q / K / VAppendix E,1156–1161:Q=XWq、K=PWk、V=PWv。cauvis.py:112–115:X 与 P 直接点积;V=mlp_prompt(P)部分实现
Prompt 初始化§3.2,237:prompts initialized to zero;同句“random perturbations”描述其作用语境,不等于随机参数初始化。cauvis.py:97nn.Parameter(torch.zeros(...))一致
Prompt 长度605–610:约 100 near-optimal,并推荐 100 为默认。...sdgod.py:35token_length=1600不一致
逐层插入/共享论文图示与实现描述:模块集成进 backbone 层。cauvis_backbone.py:24,35–42:单一 self.cauvis 在每个 block 后调用。逐层一致;参数共享
融合比例245:learnable parameters dynamically adjust fusion ratio。cauvis.py:101–103,132:α、β、δ 为可学习标量。基本一致;非样本自适应
冻结891:all backbone parameters remain frozen;正文称通常约 1%。cauvis_backbone.py:56–57:只解冻名称含 cauvis 的 backbone 模块。策略一致
损失1102:classifier and cross-entropy,学习信号来自标准检测目标。dinov2_dinohead.py:73–76:Focal、L1、GIoU;未发现 Cauvis 额外 loss。“无额外 loss”一致;具体损失不精确
训练/推理方法未声明推理时移除 Cauvis。cauvis_backbone.py:35–42:前向无 train/test 条件分支。一致