MOSS-Transcribe-Diarize + SGLang-Omni 推理方案:显存与解码参数详解

**类型:Explanation(理解导向)**。本文解释 temperaturemem-fraction-staticmax_new_tokens 三个参数为何影响转写质量、显存占用与可支持音频时长,帮助你在遇到重复退化、OOM 或输出截断时做出正确的调参决策。

本文只讨论上述三个参数;top_ptop_k 等其他采样参数不在讨论范围内。

1. 概述:三个参数各管什么

MOSS-Transcribe-Diarize(SGLang-Omni 引擎)在解码一段音频时,有三个独立维度的配置参数。按生效层级分两类:

参数 层级 控制维度 一句话
mem-fraction-static 启动参数 显存 / KV 容量 sglang-omni 启动时预分配多少显存给 KV cache pool,决定能支持多长的音频;改后需重启服务
max_new_tokens 请求参数 解码输出上限 单次解码最多生成多少 token,随每次转录请求下发;改即生效,无需重启
temperature 请求参数 采样质量 0=贪心(argmax);>0 采样,影响输出确定性与重复退化;随请求下发

启动参数(mem-fraction-static)在服务启动时固定,调整需重启服务;请求参数(max_new_tokenstemperature)由调用方在每次 HTTP 请求里下发,调整即时生效。

三者共同决定三类结果:转写质量(temperature)、是否 OOM(mem-fraction-static + max_new_tokens)、支持多长音频(mem-fraction-static -> KV 容量 -> input + max_new)。其中 mem-fraction-staticmax_new_tokens 通过”KV 容量”耦合,temperature 则与两者独立(只管采样)。

2. mem-fraction-static:静态 KV pool 与显存权衡

机制

sglang-omni 启动时按 mem-fraction-static × 总显存 预分配一个静态 KV cache pool(模型权重 + KV 池 + 开销),用于存放解码过程的 KV cache。这个 pool 在启动时就占住显存,不随请求变化,因此调它必须重启服务。

KV 容量公式

本模型(Qwen3 解码器:28 层 / 8 KV head / head_dim 128 / bf16):

1
2
bytes_per_token = 2(K+V) × 28 × 8 × 128 × 2 = 114688 bytes
kv_capacity = (fraction × 总显存GiB − 权重1.6 − 开销1.3) × 1024³ ÷ 114688

kv_capacity 是 pool 能容纳的最大 token 数。音频的 input token + 解码 output token 之和必须 ≤ kv_capacity,否则 OOM 或截断。

16G / 24G 取值

显存 fraction kv_capacity 说明
16G 0.80 ≈92766 本地笔记本(RTX 5080 Laptop GPU)实测可用
24G 0.55 ≈96434 推荐默认(≤60min 音频)
24G 0.60 ≈107670 >60min 才需要
24G 0.80 ≈152609 容量足够,但静态显存占用过大,可能 OOM(见下)

为什么 24G 不能用 0.80

注意:0.80 在 24G 上的 OOM 不是 KV 容量不足(容量 ≈152609,绰绰有余),而是总显存超载。0.80 × 24 = 19.2GB 静态预留,实际 idle 占用约 20.66GB,加上推理动态开销(~5.3GB,推算),峰值可能超过 24GB。

实测 0.80 在 24G 推理时触发 OOM:

1
2
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 598.00 MiB.
GPU 0 total 23.52 GiB.

音频编码器(whisper conv1)申请显存时,空闲量不足 -> OOM。降到 0.55 把静态压到约 13.2GB,峰值约 18.5GB,留出余量给动态开销,才放得下。

mem-fraction-static 不影响解码速度

实测(24G 卡,50min 音频):0.55 与 0.60 两种取值的单轮耗时完全一致(均 199.9s)。因为 pool 多余的容量不参与解码计算,只要音频”放得下”,pool 大小不影响解码耗时。所以调它是纯粹的”显存 vs 容量”权衡,不以速度为代价。

注:下文峰值显存为按 0.60 实测动态开销(~5.3GB)推算,仅 50min 音频实测过,更长音频未实测。

3. max_new_tokens:输出上限与 KV 容量约束

作用

max_new_tokens 限制单次解码最多生成的 token 数(输出文本上限)。sglang-omni 按此值预留解码空间。它是请求参数,由调用方在每次转录请求里下发。

约束:input + max_new ≤ kv_capacity

音频的 input token(与时长线性,约 13.4 token/s)加上 max_new_tokens 必须 ≤ kv_capacity(由 mem-fraction-static 决定)。否则要么 OOM(超显存),要么输出被截断。

50min 测试音频实测:

  • input ≈ 40193 token
  • output ≈ 19366 token(实际输出,远小于 max_new)
  • 取 max_new=32768:input + max_new = 72961,在 16G/0.80 的 kv_capacity(92766)内放得下,且 output(19366)< 32768 不截断。

32768(2^15)作为默认:output 余量足(50min 余 69%),KV 余量足(60min input≈48232,48232+32768=81000 < 92766,可支持至约 74min)。更大的 max_new(如 49152)在 60min 会超 kv_capacity(97384 > 92766)可能导致 OOM,故不取。

与 mem-fraction-static 的耦合

max_new_tokens 能设多大,受 mem-fraction-static 决定的 kv_capacity 限制。fraction 调小 -> kv_capacity 缩小 -> max_new 上限降低 / 可支持音频变短。两者通过 kv_capacity 耦合。

4. temperature:贪心解码与重复退化

贪心解码的确定性

转录请求默认 temperature=0.0(贪心,argmax):每步选最高概率 token,输出对同一份 logits 完全确定。实测同一 GPU 上 3 轮转写结果完全一致(段数 623/623/623 或 793/793/793)。

4090D 上的重复退化

同一份模型权重(md5 一致)、同一份 sglang-omni 代码(hash 一致)、同一 sglang(0.5.12.post1)/ torch(2.11.0+cu130)/ CUDA(13.0)版本,在两块不同 GPU 上贪心解码,产出差异巨大:

GPU 架构 段数(贪心) 连续重复段 最高重复
RTX 5080 Laptop GPU(16G) Blackwell 623 7 正常口语(最高 ×6)
4090D(24G) Ada 793 163 单字循环 ×102、短语循环 ×49

4090D 上出现严重的自回归重复退化(repetition degeneration):模型卡在单 token/短语循环里出不来(如某单字重复 102 次、某短语重复 49 次),段数虚高、质量下降。5080 Laptop 不触发。

根因:不同 GPU 架构(Blackwell vs Ada)的 tensor core / kernel 实现与累加顺序不同,产生微小但不同的 logits。贪心解码是”蝴蝶效应”过程,微小 logits 差异逐步放大,在 4090D 上把解码器推进重复循环。本质是模型对长音频的重复退化较为敏感,5080 Laptop 的数值路径恰好绕开,4090D 的触发。这不是配置或代码错误,而是模型本身的数值不稳定性在不同硬件上的表现差异。

temperature=0.1 的修复

temperature 从 0.0 提到 0.1(轻采样),给 logits 加一点随机扰动,让解码器跳出”最高概率锁死”的循环:

指标 4090D 贪心(temp=0) 4090D temp=0.1
段数 793 610 / 611
连续重复段 163 2
最高重复 单字循环 ×102 正常口语(最高 ×6)
单轮耗时 199.9s 161s

退化消除(610 段,接近 5080 Laptop 的 623 正常水平),单字循环消失,且更快(少解码了约 180 个退化小段)。

代价:采样引入非确定性,输出不再逐字可复现(temp=0.1 下两轮差 1 段,610 vs 611,近似稳定)。若需完全确定性,可设 temperature=0(但在 4090D 等卡上会退化),或改用 repetition_penalty(见下)。

备注:接口限制

转录接口 /v1/audio/transcriptions 不接受 repetition_penalty 参数, top_p / top_k 暂时不在讨论范围内。因此目前使用 temperature 缓解退化;若要”贪心 + 重复惩罚”兼顾确定性与质量, 可能需要 patch 转录接口透传 repetition_penalty(底层 SamplingParams 已支持)。

5. 三参数的相互作用

1
2
3
4
5
6
7
8
mem-fraction-static  ──->  kv_capacity  ──->  限制 input + max_new_tokens 之和
(决定支持多长音频 / 是否 OOM)

max_new_tokens ──-> 解码输出上限
(须与 input 之和 ≤ kv_capacity)

temperature ──-> 采样质量 / 是否重复退化
(与显存、容量无关,独立作用于同一段解码)
  • mem-fraction-static(启动参数)决定池子大小 -> 限制 max_new + input 能多大 -> 决定音频时长上限与 OOM 风险;改需重启服务。
  • max_new_tokens(请求参数)在 fraction 给定的容量内设定输出上限;改即时生效。
  • temperature(请求参数)独立管采样,不影响显存/容量,但影响质量与确定性;改即时生效。

调参决策表

现象 调哪个参数 方向 生效方式
OOM(显存不足) mem-fraction-static 调小(腾显存);或调小 max_new_tokens 启动参数,需重启服务
输出被截断(音频没转完) max_new_tokens / mem-fraction-static 调大 max_new(须确保 ≤ kv_capacity);或调大 fraction 增容 max_new 即时;fraction 需重启服务
重复退化(段数虚高、单字循环) temperature 从 0 提到 0.1 请求参数,即时
想要完全确定性 temperature 设 0(注意:某些 GPU 会退化,需权衡) 即时
换 GPU 后质量变差 temperature 多半是数值差异触发退化,试 0.1 即时

6. 小结

  • mem-fraction-static(启动参数):管显存与 KV 容量(音频时长上限)。16G 用 0.80,24G 用 0.55(≤60min)。不影响速度。改重启服务。
  • max_new_tokens(请求参数):管解码输出上限。须满足 input + max_new ≤ kv_capacity。默认 32768 覆盖至约 74min。
  • temperature(请求参数):管采样质量与确定性。0=贪心(确定,但 4090D 等卡可能退化);0.1=轻采样(消除退化,轻微非确定)。

决策树:看到 OOM -> 调 mem-fraction-static / max_new_tokens;看到截断 -> 调大 max_new_tokens(守 kv_capacity);看到重复退化 -> 调 temperature 到 0.1。


数据来源:50min 测试音频在 RTX 5080 Laptop GPU(16G,笔记本,Blackwell)与 RTX 4090D(24G,Ada)上的实测。两机模型权重(md5 092f865a...)、sglang-omni 代码、sglang/torch/CUDA 版本均一致,唯一变量为 GPU。峰值显存与更长音频的容量为按 KV 容量公式与 0.60 实测动态开销(~5.3GB)推算,仅 50min 音频实测过;0.80/24G 的 OOM 为实测(推理时触发)。

局限:实测仅用单一 50min 测试音频,样本单一;退化是否触发、段数、耗时、峰值显存等结论可能随音频不同(时长/内容/说话人/语种)而变化,本文结论为该样本下的观测,不代表所有输入下的普遍表现。