状态:草稿 (2026-10-13),部分为实际测量值。 论文中的数值已通过打开原文并结合条件进行确认(AdaSpot 的会议信息已通过官方仓库标记确认)。亲自尝试的内容是笔记本 CPU 上的 numpy 示例(
code/10_map_delta.py)。TT Score 的事件实测值记录在《TT Score 模型剖析》第 5 篇以及 2026-10-13 研究日志的「采用」栏中(进行中的研究,仓库之外)。本篇中的 PES 模型从未在乒乓球视频上运行过(未实测)。 2026-10-15 补充: 我们在 8GB 级 GPU 上重新测试了 AdaSpot(网球 small)和 E2E-Spot(网球,RegNet-Y 200MF)的公开权重速度,并将其附在第 6 节。乒乓球准确率需要重新训练才有意义,因此仍然属于未实测状态。 系列《阅读视觉模型 2》第 10 篇。前一篇: 小而快的球追踪。关于视频模型的基础知识,请参见 第 6 篇。
目录
1. 直觉:「什么时候」而非「是什么」
第 6 篇中的视频模型为整个片段附加了一个标签:「这 2 秒是在打乒乓球」。然而,若要进行评分,则需要一个不同的问题: 球击中接收方球台的瞬间准确地是第几个帧?
寻找这种「瞬间发生事件的准确帧」的工作被称为 精确事件定位(Precise Event Spotting, PES) 。与足球中的「进球」或「角球」这类允许 1–5 秒误差的行为检测(action spotting)不同,PES 要求精度在 1–2 帧 以内。网球的弹跳与击球、花样滑冰的跳跃着地、跳水的入水都是典型的任务。
这里有两个难点:
- 极端的类别不平衡。 事件帧占整体比例甚至不到 3%(E2E-Spot 论文)。这相当于在时间维度上重新遇到了第 9 篇中的球像素问题。
- 相邻帧几乎完全相同。 弹跳帧与其前后的帧画面几乎一模一样。若要挑出「正是这一帧」,就必须观察极其微小的差异。
2. 如何进行训练
E2E-Spot (ECCV 2022):对每个帧进行到底的分类
E2E-Spot 的结构在设计上非常简单。
- 在一个轻量级 2D 图像网络(RegNet-Y 200MF,由 ImageNet 初始化)中插入第 6 篇的 时间移位模块(GSM) ,在逐帧提取特征的同时混合相邻帧的信息。
- 在其之上叠加一层 双向 GRU 来观察整个片段的上下文。
- 对每个帧进行 (K+1) 类分类。K 是事件的种类(例如:近端弹跳、远端击球……),+1 表示「无事发生」。损失函数为 softmax 交叉熵。
训练方式的核心正如其名,即 端到端(end-to-end) 。它不是在预先提取的固定特征上仅训练头部,而是将 100 帧的片段(224×224)整体输入,连同图像网络一起训练。数据不平衡问题通过给事件类别的损失赋予 5 倍权重来解决。使用了裁剪、色彩抖动和 mixup 增强,在测试时将片段重叠一半并取平均值(引自论文)。
相比于仅在固定特征上训练头部的传统方法,它在 δ=1 时 mAP 领先了 4–11(引自论文)。这可以理解为预训练特征更侧重于「是什么」,无法捕捉到单个帧的微小差异。
T-DEED (CVPRW 2024):单独预测「相距多少帧」
如果只对每一帧进行分类,事件紧邻的帧也会看起来「像事件」,导致概率发生扩散。T-DEED 采用了双分支结构:
- 分类分支:像 E2E-Spot 一样进行逐帧的 (C+1) 类分类(带正样本权重的交叉熵)。
- 位移分支:在事件周围半径内的每一帧中,回归「距离真正的事件还有多少帧」(均方误差)。
在测试时,利用分类来找到大致的位置,并通过位移来修正准确的帧。据论文报告,这种位移分支优于单纯将事件周边帧扩大为「正样本」的标签扩展(label dilation)方法(引自论文)。网络采用编码器-解码器结构,在缩减和放大时间分辨率的同时混合了多种时间尺度的上下文。
AdaSpot (CVPR 2026):将分辨率用在刀刃上
在网球和乒乓球中,事件的主角是一个小球。在缩减至 224px 的画面中,球几乎完全消失了。然而,如果以高分辨率观察所有帧,代价又过于高昂。AdaSpot 设置了两个分支:
- 低分辨率分支:以低分辨率观察整个画面。
- 挑选感兴趣区域(ROI):通过低分辨率特征的通道平均值制作「显眼区域」地图,在时空上进行平滑处理后,挑选出能够充分包含重要度的最小矩形,并从原图中裁剪出 112×112 的大小。 这个挑选过程不参与训练。 不需要单独的感兴趣区域标签。
- 高分辨率分支:仅以原始分辨率观察裁剪后的小区域。
损失函数为加权交叉熵(事件权重为 5),并且在两个分支各自挂载了辅助的 GRU 头部以增加损失(各占 ⅓)。论文指出,如果没有这些辅助损失,训练将会变得不稳定(引自论文)。
3. 评估:mAP@δ
PES 的评分机制如下:
- 将预测结果(帧、种类、置信度)按置信度从高到低排列。
- 如果与同种类正确答案的帧之差 小于等于 δ,则判定为正确。一个正确答案只能与一个预测结果配对。
- 精确率-召回率曲线下的面积为 AP,各类别的平均值为 mAP。
δ=1 意味着「正确帧或其相邻帧」。在 60fps 下为 ±17ms,在 25fps 下为 ±40ms,因此 即使 δ 相同,根据帧率的不同,实际允许的时间误差也各不相同。
我们在
code/10_map_delta.py 动手实践code/10_map_delta.out.txt中实现了这种评分,并针对 400 个事件(遗漏 5%,错误地点的虚假预测 5%)制作了三个具有不同时间误差的「模型」进行了评分( )。由于每一行都是随机抽取遗漏和虚假预测的,请 在同一行内
| 进行比较。 | 时间误差(标准差) | δ=0 | δ=1 | δ=2 |
|---|---|---|---|---|
| δ=4 | 0.759 | 0.914 | 0.914 | 0.914 |
| 0.3 帧 | 0.317 | 0.905 | 0.944 | 0.948 |
| 0.7 帧 | 0.039 | 0.339 | 0.667 | 0.928 |
2.0 帧 同一个模型(2.0 帧)根据 δ 的不同,得分会从 0.04 到 0.93 不等。 离开 δ 谈 mAP 数值是没有意义的。
并且,当 δ=0(精确到那一帧)时,即使时间误差只有 0.7 帧,分数也会暴跌至 0.3 左右。这就是论文开始单独报告 δ=0 的原因(见下方的 AdaSpot 表格)。
중복 그대로 δ=0: 0.294 δ=1: 0.654 δ=2: 0.739
NMS(±2) 뒤 δ=0: 0.208 δ=1: 0.690 δ=2: 0.875
我们还对重复预测进行了实验。在每个事件的 ±1–2 帧内,额外生成了 2 个置信度较低的预测。
重复预测会被当作「没有正确答案的预测」来计算,从而拉低精确率。通过使用 NMS 消除 ±2 帧内的重复项,δ=2 的分数从 0.739 恢复到了 0.875。相反,δ=0 的分数反而下降了。这是因为 NMS 留下的「最具置信度」的预测有时并不精确对应那一帧。后处理的好坏也因 δ 而异。
| 4. 论文数值 | 模型 | 数据 | δ=0 | δ=1 | δ=2 |
|---|---|---|---|---|---|
| 条件(论文) | E2E-Spot | — | 96.1 | 97.7 | 网球 |
| 200MF。网球 3,345 个片段·33,791 个事件,6 种(近端/远端 × 发球·击球·弹跳) | E2E-Spot | — | 81.0 · 68.4 · 47.9 | 93.5 · 85.3 · 65.2 | 花样滑冰 (FS-Comp) · 跳水 · 体操 |
| 同一模型 | T-DEED | — | 85.15 · 71.48 | 91.70 · 87.62 | 花样滑冰 (FS-Comp) · 跳水 |
| 200MF。800MF 跳水 73.23 · 88.88 | AdaSpot | 74.02 | 97.36 | 97.79 | 网球 |
| RegNetY-400MF, 1,063 万参数, 56.78 GFLOPs, 3 个随机种子平均值 | AdaSpot | 55.38 | 69.37 | 69.94 | F3Set(网球精细事件) |
| 同上 | E2E-Spot + MFS | 36.43 | 69.50 | 78.12 | 乒乓球 (TTA) |
手机拍摄 39 场比赛,30fps 720p,4,878 个事件 8 种
- 这里有几点需要注意。
- AdaSpot 论文中的对比表格是其他方法也使用相同后处理(SNMS)重新运行后的数值,因此 E2E-Spot 网球 δ=1 为 97.01,与原论文(96.1)不同。在混合表格时必须对齐出处。 网球的 δ=1 已经在 97% 附近饱和。
- 差距体现在 δ=0 上(AdaSpot 为 74.02)。 乒乓球要困难得多。
在手机拍摄的乒乓球(TTA)中,δ=1 为 69.50,比同系列模型在网球上的数值低了 25 分以上。球很小,事件密集(每 100 帧 7.73 个),且相机在晃动。F3Set 的乒乓球部分只有 42 个回合,因此训练数据也很少(引自论文)。
- 5. 局限性 片段级别 = 延迟。
- 双向 GRU 与重叠片段平均值需要观察未来的帧。若要实时使用,必须等待片段结束,因此会产生 1–2 秒的延迟(推测)。它更适合在回合结束后进行重新确认。 物种(项目)之间的鸿沟。
- 公开权重多用于网球、花样滑冰等,没有乒乓球权重。必须使用乒乓球重新训练,而公开的乒乓球数据大多具有非商业限制条件。 无法用视频大语言模型替代。
F3Set 论文指出,虽然 GPT-4V 能够识别项目和记分牌,但由于无法捕捉击球方向与帧之间的时间关系,因此被排除在对比之外(第 12 篇)。
- 6. 与我们项目的联系 我们的引擎观察的是轨迹,而非像素。 TT Score 是通过球检测(第 9 篇)获取的轨迹,并基于规则产生弹跳(《TT Score 模型剖析》第 5 篇)。剩余错误中的很大一部分并非漏掉的弹跳,而是虚假弹跳
- (例如将击球误读为弹跳等)。可学习的边界判定器正是本文内容的微缩版。 轨迹特征 9个过去的16帧的1D卷积(约1.8万个参数),逐帧输出弹跳、击球和球网概率。训练直接沿用这一思路。平滑标签(弹跳帧为1,紧邻帧为0.5),仅在标记区间内计算的加权BCE,以及混合了30fps副本的训练。当把使用该模型的规则弹跳过滤版投入实际部署的流式传输链路时,在OpenTTGames测试的7场清晰视频中,弹跳F1(±2帧)从0.801提升至0.830,在11种劣化条件下的627个回合中,回合胜者准确率提升了+4.9%p(95%区间+2.9…+7.2)。该版本已被采纳,自2026-10-14起对实时和录像处理人员全部启用(基于研究日志,进行中的研究——日志尚在代码库之外)。
- 前瞻为 0 的陷阱。 在早期实验中,我们曾让前瞻为 0 的模型直接挑选弹跳峰值,结果失败了。要挑选峰值,需要下一帧的概率,而无法前瞻的模型的概率会扩散到弹跳前后的 1–2 帧中。 前因此,训练出的模型仅用作对规则检测出的弹跳进行过滤(veto)的角色。这与上面 mAP 实验中的“δ=0 对视觉误差极其敏感”是同一个道理。
- 录像教师候选。 AdaSpot 的代码和网球权重已遵循 MIT 协议开源,如果用乒乓球重新训练,它将成为 4 篇“录像教师”候选之一。速度测于 2026-10-15(8GB 级 GPU,随机输入,预热后取中位数)。网球 small 版(RegNet-Y 200MF 双分支,推理使用 758 万参数)处理 100 帧剪辑(高分辨率分支 448×796)耗时 85.9ms(使用 bf16), 每帧 0.86ms ,GPU 内存占用最高 1.4GB。在同款显卡上,E2E-Spot(RegNet-Y 200MF + GRU,445 万参数,224×224)耗时 29.2ms(使用 fp16),每帧 0.29ms。用作回看录像的教师模型,两者都足够快。用乒乓球重新训练后的准确率尚未实测(需先使用乒乓球真值数据进行训练)。
Titi 一言。 当听到“找弹跳准确率 97 分!”时,请先问一句:“δ 是多少?”同一个模型在 δ=0 时可能得 4 分,在 δ=4 时可能得 93 分。我亲自打分验证过。
参考文献
- Hong et al., Spotting Temporally Precise, Fine-Grained Events in Video(E2E-Spot), ECCV 2022. https://arxiv.org/abs/2207.10213
- Xarles et al., T-DEED: Temporal-Discriminability Enhancer Encoder-Decoder for Precise Event Spotting in Sports Videos, CVPR 2024 Workshops. https://arxiv.org/abs/2404.05392
- Xarles et al., AdaSpot: Spend Resolution Where It Matters for Precise Event Spotting, CVPR 2026(仓库标记). https://arxiv.org/abs/2602.22073
- Xu et al., Multi-Focus Temporal Shifting for Precise Event Spotting in Sports Videos(TTA 乒乓球数据), arXiv 2025. https://arxiv.org/abs/2507.07381
- Liu et al., F³Set: Towards Analyzing Fast, Frequent, and Fine-grained Events from Videos, ICLR 2025. https://arxiv.org/abs/2504.08222
- Sudhakaran et al., Gate-Shift Networks for Video Action Recognition, CVPR 2020. https://arxiv.org/abs/1912.00381
- 我们的测量:2026-10-13 研究日志的采纳记录(进行中的研究,仓库外)。示例代码与输出:
code/10_map_delta.py,code/10_map_delta.out.txt