Hy-SimulMT 音频分块影响延迟、推理批次影响吞吐

文章导读
音频分块和推理批次是两个方向的旋钮:分块决定系统多快能拿到“够用的一段音频”并开始出字,影响的是首字延迟和断句手感;推理批次决定一次前向能并多少路请求,影响的是多路并发时的整体吞吐和显存占用。想同时优化,先别两个一起改——先用日志确认当前瓶颈是首字延迟偏长,还是并发上来后排队明显,再动对应参数。混着调,日志里分不清是谁起的作用。
📋 目录
  1. 壹 固定推理批次,只改音频分块并记录首字延迟
  2. 贰 固定音频分块,只改推理批次并记录吞吐
  3. 叁 用同一段音频重复两组对照测试
  4. 肆 记录显存占用随两个参数的变化
  5. 伍 按优化目标画出参数选择决策表
A A

音频分块和推理批次是两个方向的旋钮:分块决定系统多快能拿到“够用的一段音频”并开始出字,影响的是首字延迟和断句手感;推理批次决定一次前向能并多少路请求,影响的是多路并发时的整体吞吐和显存占用。想同时优化,先别两个一起改——先用日志确认当前瓶颈是首字延迟偏长,还是并发上来后排队明显,再动对应参数。混着调,日志里分不清是谁起的作用。

先分清瓶颈方向:首字慢,优先调音频分块,用小分块换更低的首字延迟,代价是断句更碎、请求更密;多路并发跟不上,优先调推理批次,用更大的批上限换取更饱满的计算利用率,代价是显存占用上升、单句等待可能变长。两个参数分开做单变量对照,用同一段音频重复测试,并同时记录显存,才能确认收益来自哪个旋钮。所有数字都要以你机器上的日志为准,不套用别人的配置。

固定推理批次,只改音频分块并记录首字延迟

音频分块的参数通常在音频前端或会话配置里,常见字段形如 audio.chunk_ms、audio.min_chunk_ms、vad.tail_silence_ms、audio.max_segment_ms,也可能以命令行启动参数 `--chunk-ms` 的形式出现。先在你自己的配置文件里定位到这些键,记下默认值作为基线。测试期间把推理批次相关参数显式写死成同一个值,不要靠默认值漂移。

每改一档分块,都要从同一条请求链路里取首字延迟:在日志里打上音频到达时刻和第一个稳定输出时刻,两者相减。建议日志至少包含下面这些字段,方便后续用 awk 汇总:

ts=2024-01-01T10:00:00 chunk_ms=320 batch=4 concurrency=1
audio_in_ms=320 first_token_ms=... utt_end_ms=... gpu_mem_mib=...

记录表头按下面这张表来填,每次只改一列,其余列保持不变:

音频分块(ms)推理批次(固定值)首字延迟中位数(ms)首字延迟P90(ms)整句结束延迟(ms)断句次数/句备注
基线值固定
更小一档固定观察是否变碎
更大一档固定观察首字是否变慢

判断方法很直接:分块变小后首字延迟是否跟着下降、整句结束延迟是否反而变差。如果首字没明显变化、只有请求数量变多,说明瓶颈不在切分粒度上,回头去看推理批次或排队策略。分块过小的风险是断句碎片化、上下文被切碎,翻译质量要靠人工听读一遍确认,不能只看延迟数字。

固定音频分块,只改推理批次并记录吞吐

推理批次的参数一般落在模型服务侧,常见字段形如 inference.max_batch_size、inference.max_batch_tokens、inference.batch_timeout_ms。其中 batch_timeout_ms 是攒批的等待上限,调大批次上限却忘了看这个值,会出现“批次没攒满但请求已经在等”的情况。

这一组测试把音频分块写死在上一步选定的值,只改批次上限,同时把并发路数固定住(例如固定 4 路或 8 路,按你实际业务规模选)。吞吐不要用主观感受描述,用日志计数:统计单位时间内完成输出的句子数,再换算成实时率。

# 按分钟统计完成句数,字段名按实际日志调整
grep "utt_done" logs/hy-simulmt.log \
  | awk -F'ts=' '{split($2,a," "); print substr(a[1],1,16)}' \
  | sort | uniq -c
批次上限音频分块(固定值)并发路数完成句数输入音频总秒数墙钟秒数实时率
基线值固定固定
上调一档固定固定
上调两档固定固定

实时率 = 输入音频总秒数 ÷ 墙钟秒数。它超过 1 表示处理快于播放,但不要把这个数当成能力上限,只能在同一台机器、同一段音频下横向比较。批次上调后如果单句结束延迟明显变长,说明攒批等待吃掉了延迟收益,需要在 batch_timeout_ms 上做取舍。

Hy-SimulMT 音频分块影响延迟、推理批次影响吞吐

用同一段音频重复两组对照测试

两组测试必须共用同一段音频,否则语速、停顿、专名密度不同,延迟差异根本说不清是参数带来的还是内容带来的。建议自备一段覆盖典型场景的音频:包含正常语速、至少一处停顿、若干数字和专名,长度控制在几十秒量级,复制到固定路径反复使用。

for i in $(seq 1 5); do
  curl -s -X POST http://127.0.0.1:8080/translate \
    -F "audio=@/data/test/sample_a.wav" \
    -F "lang=zh-en" >> logs/run_${i}.jsonl
done

每一档参数建议重复 5 次以上,取中位数看趋势,不取单次最好值。如果解码带采样,把温度或随机性参数固定成同一值,避免两次输出长度不同反过来影响延迟统计。测试前清空上一轮日志,或用不同的日志文件名区分,否则 awk 汇总会把两档参数的数据混在一起。

记录显存占用随两个参数的变化

分块变小会抬高请求频率,批次变大直接抬高单次前向的显存峰值,两个方向都可能把显存推高。调参时同步跑一个采样循环,把显存曲线和参数变更时间对上。

while true; do
  nvidia-smi `--query-gpu`=timestamp,memory.used,memory.total,utilization.gpu \
             `--format`=csv,noheader >> logs/gpu_mem.csv
  sleep 1
done

记录字段建议固定为:采样时间、当前音频分块、当前批次上限、并发路数、显存占用 MiB、显存总量 MiB、GPU 利用率、是否出现 OOM 或服务重启。显存占用取每档参数的峰值而不是均值;出现 OOM 时先回退到上一个能稳定跑完测试的档位,再考虑分批下调,不要把降批次当成“优化”写进结论,它只是把风险挪走。

按优化目标画出参数选择决策表

做完上面两组单变量测试后,把结论落到一张决策表里,根据自己的首要目标选项,而不是同时拉满两个参数。表里只填方向,不填固定数值,具体档位以你的日志为准。

优化目标先调哪个参数观察指标判断依据风险边界
首字延迟优先音频分块首字延迟中位数与 P90分块变小后首字是否随之下降断句变碎、请求变密
多路吞吐优先推理批次实时率、完成句数批次上调后实时率是否上升显存峰值上升、单句等待变长
两者都要,但显存有限先定分块,再小步抬批次显存峰值、单句结束延迟显存先到顶就停,延迟先劣化就退不要用降批次掩盖分块过碎
并发路数还会继续涨预留批次余量排队时长、超时计数排队明显增长说明批次或实例不足单机堆批次有上限,需评估扩容

填表时把“参数位置、日志字段名、测试音频路径、显存采样文件”一并写进备注,下次换机器或换模型版本,直接按同一套流程重跑单变量对照,比凭记忆调参可靠。