与 yolo11n-pose 拓扑完全相同、每层通道翻倍。网球的姿态打分头 tennis_pose_score_v0(3072 维特征)架在 s 上,
但同一条 tennis-latest v2.3 管线里的击球头 hitting_head_v0/coco 和持拍检测 racketeer_v3.0 都是 n,所以这条管线现在同时跑 n 和 s 两种骨干。这一页拆 s 的结构,逐项量出它和 n 在
量化上会有哪些不同,再把量化方案和对比实验列清楚。
24 层,同样三段:backbone(0–10) → neck(11–22) → Pose 头(23)。 和 n 相比,差别只在宽度:层数、连线、C3k 开关、输出形状都一样。
ultralytics 用同一份 yolo11-pose.yaml 缩放出 n/s/m/l/x。n→s 只改了 width 这一个旋钮。
| 项 | n | s | 影响 |
|---|---|---|---|
| depth / width / max_channels | 0.50 / 0.25 / 1024 | 0.50 / 0.50 / 1024 | 只有宽度翻倍,深度(Bottleneck 重复数)不变 |
| 各层通道 | 16 → 256 | 32 → 512 | 处处 ×2,卷积参数和 FLOPs 约 ×4 |
| C2PSA 注意力头数 | 2 | 4 | head_dim 64、key_dim 32、scale 0.1768 不变,头数随通道翻倍 |
| Pose 头 cv2(框 DFL)中间宽度 | 64 | 64 | max(16, ch/4, 64) 被 16×4 的下限钉住,不随宽度变 |
| Pose 头 cv3(类别)中间宽度 | 64 | 128 | max(ch[0], nc),跟着 P3 通道翻倍 |
| Pose 头 cv4(关键点)中间宽度 | 51 | 51 | max(ch/4, 51),被 17×3 的下限钉住 |
| 输出 | (1,56,8400) | (1,56,8400) | 完全相同:anchor 数、通道布局、DFL 16 bin 都一样 |
| 我们的抽头特征(层 4/6/8/10 avg+max) | 1536 | 3072 | 现有板球打分/门控头不能直接用,要在 s 特征上重训 |
与 n 同构。虚线是跨层连接(6→12、4→15、13→18、10→21);上方虚线是打分/门控用的抽头。
| 段 | 结构 | 产出(s) | 参数 s | vs n |
|---|
每个模块内部怎么工作(C3k2 的 CSP 劈分、SPPF 串联池化、C2PSA、DFL)与 n 完全一样, 这里不重复,见 /v/y11pose/ 特殊层与特殊算子。下面只列 s 上数值变了的部分。
注意力在 20×20=400 个 token 上做,QKT 是 4 个 400×400 的矩阵。 头多了一倍,但每个头的缩放不变,所以单个 logit 的量级主要由特征本身决定。
1×1 卷积 512→256,三次串联 5×5 maxpool,四路 concat(1024 通道),再 1×1 回到 512。 maxpool 不产生新值,四路 concat 的幅度天然一致(实测比 1.01×)。
仍是 16 bin、权重 0…15 的 1×1 卷积。它的输出是像素坐标,与模型大小无关 —— 这决定了 s 的全模型臂和 n 一样必须 a16(见量化视角)。
n 的 FLOPs 有 37.7% 在 Pose 头;s 的头只长了 1.8×,比例掉到约 21%,backbone 升到过半。 所以 s 从「只切 backbone」拿到的加速比 n 小。
| 模型 | 段 | 参数 | 占比 | GFLOPs | 占比 |
|---|
蓝色高亮行是抽头层。最后一列是这一层 s/n 的 FLOPs 倍数:卷积层都是 4×, Pose 头只有 1.7×,Upsample/Concat 是纯访存(2×)。
| # | 模块 | from | 输出(s) | 参数 s | GFLOPs s | GFLOPs n | s/n |
|---|
A100 fp32,三个切点都带 8 路抽头。bs=1 下 n 和 s 几乎一样快,因为 GPU 此时受 kernel launch 限制,不受算力限制; bs=32 按每张摊下来,s 是 n 的约 1.9 倍。两种口径都不能直接换算到 HTP,端侧必须实测。
「每档」= 跨度 ÷ 档位数(per-tensor),也就是这个张量在该位宽下能分辨多细。
这是 s 在量化上最大的结构性差别。avg 块在 s 上更小(avg4 0.72),max 块更大(max6 19.5): 通道多了,全局 max 更容易撞到极值,全局 avg 反而被稀释。
output_0…7,映射同样要按位置验证。逐个拦截了前向里的 torch.cat,按各输入的跨度算幅度比(最大/最小)。判据沿用 n 上得出的「> 约 3× 要查编码」。
输入张量都是 1×3×640×640,完全一样。输出这边:A 臂抽头翻倍但只有 6 KB; B 臂特征图翻倍到 2.87 MB;C 臂 (1,56,8400) 与 n 完全相同,因为 Pose 头把空间压成了固定的 anchor 预测。
n 在 S23 上有实测(W8A16、fp32 I/O)。s 的数据还没有,下表按两种倍数给估计区间: 下沿用 GPU bs=32 的每张倍数(算力吃满时的实际倍数),上沿用 FLOPs 倍数(纯算力外推)。 n 的 GPU 相对代价曾经对端侧外推失败(加 neck GPU 上 +67%,端侧只 +26%),所以这张表只用来排优先级。
backbone 段实测 Δ_irr:a16 −0.0032(过线),a8 −0.0164(建议线 −0.005 的三倍多)→ W8A16 必需。 全模型臂另有 DFL 3 px 的硬理由。
但这个 a8 结论是打分头的 Spearman 口径,对检测输出和 s 都没验证过(QUANTIZATION.md §4 已列为待办)。
「要不要上 s」不是一个量化问题。混在一起比,会把 s 在 FP32 下的精度收益和量化损失搅成一个数,哪个都读不出来。
纯模型选择问题,与量化无关。板球现有的两个头是在 n 的 1536 维上训的,要在 s 的 3072 维上重训(同一份数据、5 seed)才能比。 网球反过来:已有 s 的头,要比就得补一个 n 的头。
不做 Q1,量化实验就算全部过线,也回答不了「s 值不值」。
与 n 已有交付逐项对齐的量化实验:同一校准集、同一位宽、同一编译、同一设备, 报量化损失(相对各自 FP32)和端侧代价(延迟、内存、落位)。
决策式:s 的 Q1 收益 > s 相对 n 多出的 Q2 损失,且端侧代价在预算内。
四个维度全排列是 2×3×3×2 = 36 个臂,其中大部分用 n 的结论或本页测到的数就能先剪掉。
| 维度 | 取值 | 剪枝 | 保留 |
|---|---|---|---|
| 模型 | n / s | n 各臂已有实测,直接复用作对照 | s(新跑),n(复用) |
| 切点 | A backbone+8 路 · B +neck+抽头 · C +Pose 头+抽头 | B 只服务 RoIAlign 头,下游没定之前不跑 | A、C;B 待定 |
| 位宽 | W8A16 · W8A8 · 混合 | C 臂 a8 已被 DFL 3 px 否掉(与模型无关);混合精度只在 a8 超线时再做 | W8A16 全部;A 臂加 W8A8;混合按需 |
| 输出形态 | 8 路 · 图内 concat+逐通道缩放 | 27× 幅度差,未缩放 concat 直接排除;缩放版要重推系数,且 v3 已经回到 8 路 | 8 路 |
S0 回答 Q1,S1–S3 是 Q2 的核心,S4–S6 看前面的结果再决定做不做。n 列是已有实测,直接作对照。
| ID | 配置 | 回答什么 | 主要指标 | n 对照(已有) | 优先级 |
|---|---|---|---|---|---|
| S0 | FP32 · s vs n | Q1 s 的特征和关键点是不是更好 | 板球打分/门控头在 s 特征上重训(5 seed 均值);网球补 n 头;两者 COCO-17 关键点在我们测试集上的质量 | 板球出厂头 5-seed 均值 0.8015 | P0 |
| S1 | s · A · W8A16 · 8 路 | 与交付 v3 一一对应 | 抽头特征相对 L2;冻结 FP32 头下的 Δ;S23 延迟/落位/内存;8 路编码与 output_i 映射 |
相对 L2 0.027;3.505 ms;NPU 177/CPU 0 | P0 |
| S2 | s · C+抽头 · W8A16 | 与交付 quant_full 一一对应 | 按 IoU 配对的框/关键点误差(px)、配对率;抽头 vs S1 一致性;17 个 concat 编码;延迟 | 配对 97.1%,框 1.77 px,关键点 1.56 px;抽头 vs A 0.00112;5.900 ms | P0 |
| S3 | s · A · W8A8 · 8 路 | s 的 a8 是否比 n 更能扛;能省多少毫秒 | Δ_irr(同口径)、冻结头 Δ、延迟 | a8 Δ_irr −0.0164(超线) | P1 |
| S4 | s · A/C · 混合精度 | a8 超线时能不能只保几个张量 | 同 S3;逐张量敏感度排序 | 无(n 也没试过) | P2 |
| S5 | s · B+抽头 · W8A16 · qio | RoIAlign 头的特征图代价 | P3/P4/P5 相对 L2;2.87 MB 输出下 qio 收益 | 4.120 ms;P3/P4/P5 0.060/0.088/0.107 | P2 |
| S6 | S1 换网球校准集 | 校准域对 s 的影响(网球是 s 的实际部署域) | 网球头在两种校准下的 Δ | — | P1 |
| 层级 | 指标 | 为什么用它 |
|---|---|---|
| 特征 | 抽头相对 L2、逐块误差 | 最底层,定位哪一块坏了 |
| 任务(主指标) | 冻结 FP32 头下的 Δ(Spearman / raw |Δ| / gate 翻转数) | 头固定、没有 seed 噪声,只量特征本身 |
| 任务(交付) | 在量化特征上重训的头,5-seed 均值 | seed 方差 0.005–0.015,和量化效应同一量级;单 seed 不可比 |
| 检测 | 按 IoU 配对的框/关键点 px、配对率 | top-1 会被「两人置信度接近」的翻转污染 |
| 端侧 | 最小/中位延迟、NPU/CPU 落位、峰值内存、context bin 大小 | CPU 回退是静默变慢,每次都要看 |
| 跨模型 | 各自相对自己的 FP32报量化损失,再与 Q1 的 FP32 差并列 | n 和 s 的特征空间不同,直接比两个量化模型的特征没有意义 |
quant_calib_v1、--n-calib 128(S6 除外)cricket_quant_testsets_v1,头训练的数据与 splitmetrics.json 实为 3072,接网球头时以后者为准先写下来,跑完再对。哪一条错了,都说明本页的 FP32 范围分析漏了什么。
| # | 预测 | 依据 | 证伪条件 |
|---|---|---|---|
| 1 | S1/S2 全部算子落 NPU | 拓扑与 n 相同,n 三个臂零回退 | profile 里出现 CPU 算子 |
| 2 | 17 个 concat 无截断 | 幅度比 ≤ 2.34× | 任一 concat 的输出编码不覆盖输入并集 |
| 3 | S1 抽头相对 L2 与 n(0.027)同量级 | s 的层级跨度只大 1–1.7×,a16 下每档仍远小于信号 | > 0.05 |
| 4 | S2 框误差与 n(1.77 px)接近 | 框张量跨度 692 与 n 相同 | 明显大于 2.5 px |
| 5 | S1 延迟落在估计区间偏下沿 | 输入搬运等固定开销被摊薄 | 超过上沿 |
| 6 | S3 a8 仍然超线 | 抽头 max 块跨度更大 | Δ_irr 在 −0.005 以内(这会是好消息) |
量化流水线整体可复用,但有 12 个 scripts/quant_*.py 写死了 n 的权重路径(encoder_path())或 1536 维。
| 改动 | 涉及 |
|---|---|
加 --weights / --scale 参数,取代 encoder_path() | quant_export_onnx · quant_export_full_onnx · quant_eval_baseline |
特征维度从模型探测(block_layout() 已有),去掉 1536 字面量 | quant_build_delivery_heads · quant_package_handoff · quant_export_heads_onnx · quant_ondevice_check 等 |
| AI Hub 提交/profile 的 variant 名带上 scale,避免覆盖 n 的 job 记录 | quant_aihub_submit · quant_aihub_profile |
| S0:s 特征上重训板球两个头(5 seed) | quant_build_delivery_heads(FP32 模式) |
| S6:网球校准集 | quant_build_calibset(加网球数据源) |
racketeer_v3.0(n,960 输入,微调过的检测器)→
hitting_head_v0/coco(冻结官方 n,1536 维)→ tennis_pose_score_v0(冻结官方 s,3072 维)。
上端侧的话,网球要么量化两个骨干,要么统一到一个:把击球头搬到 s,或者把姿态打分头搬到 n。S0 应该把这个问题一起回答了。