Nemotron 3.5 Transcribe 转写卡在半截 / 是音频太长还是显存不够?

文章导读
Nemotron 3.5 Transcribe 转写跑到中途没反应,音频长度和显存都可能,但这两项不用一起查。先用 GPU 采样和分段日志把「卡住」拆成三种状态:模型还在算、进程已挂、卡在加载或预处理,再看显存峰值随音频时长的变化,判断是不是长度顶到上限。
📋 目录
  1. 壹 先确认进程还活着:连续采样 GPU 利用率与显存
  2. 贰 在代码里给加载、预处理、推理三段加时间戳
  3. 叁 把音频长度和显存峰值对上
  4. 肆 显存不足时的典型报错与降载手段
  5. 伍 用短音频测一条耗时基线再线性外推
A A

Nemotron 3.5 Transcribe 转写跑到中途没反应,音频长度和显存都可能,但这两项不用一起查。先用 GPU 采样和分段日志把「卡住」拆成三种状态:模型还在算、进程已挂、卡在加载或预处理,再看显存峰值随音频时长的变化,判断是不是长度顶到上限。

判断卡点先看两个信号:nvidia-smi 的 GPU 利用率和显存占用是否还在变,以及最后一条分段日志停在 load、preprocess 还是 infer。利用率有波动、显存稳定在峰值,通常说明还在算,属于「慢」;利用率长期为 0 且进程还在,多半卡在加载、重采样或 IO;进程消失或被系统杀掉,按显存不足处理。适用前提是能拿到进程和 GPU 采样,单机单卡最容易复现,多卡或多进程场景需要结合部署方式确认。

先确认进程还活着:连续采样 GPU 利用率与显存

转写没输出时先别重启,重启会把现场抹掉。开一个终端按秒采样,看 utilization.gpu 和 memory.used 两列:

watch -n 1 'nvidia-smi `--query-gpu`=utilization.gpu,memory.used `--format`=csv,noheader'

同时确认 worker 进程是否存在、CPU 时间是否在涨:

ps -o pid,etime,pcpu,rss,cmd -p <pid>
  • GPU 利用率在 0 和较高值之间反复跳、显存占用稳定不变:模型在算,任务只是慢,别急着判死,转去测耗时基线。
  • GPU 利用率长期为 0、显存占用也不动,但进程还在且 CPU 时间在涨:卡在音频解码、重采样、特征预处理或队列等待。
  • 进程不在了,或 nvidia-smi 里看不到该 python 进程:已经挂了,常见是被 OOM 杀掉,先查显存再查系统日志(dmesg -T | grep -i oom)。

多卡机器上要确认采样的是任务实际用到的那张卡,加 -i <gpu_id> 指定会更稳。

在代码里给加载、预处理、推理三段加时间戳

光看 GPU 只能知道「在算还是不在算」,定位不到阶段。在调用链外层套一个计时函数,只改入口,不改模型代码:

import logging, time
log = logging.getLogger('asr')

def timed(stage, fn, *args, **kwargs):
    t = time.perf_counter()
    log.info('stage=%s event=start', stage)
    out = fn(*args, **kwargs)
    log.info('stage=%s event=end cost=%.3fs', stage, time.perf_counter() - t)
    return out

model = timed('load', load_model, cfg)
feats = timed('preprocess', preprocess, wav_path)
text  = timed('infer', transcribe, model, feats)

跑一条长音频后,日志大致会是这样(时间戳和耗时是占位):

Nemotron 3.5 Transcribe 转写卡在半截 / 是音频太长还是显存不够?
ts=<时间> INFO stage=load event=start
ts=<时间> INFO stage=load event=end cost=<xs>
ts=<时间> INFO stage=preprocess event=start
ts=<时间> INFO stage=preprocess event=end cost=<xs>
ts=<时间> INFO stage=infer event=start
(之后长时间没有 infer event=end)

最后一条日志停在哪,卡点就在哪。停在 infer 之前,优先怀疑音频解码和切分;停在 infer 之后没有 end,回到第 1 节的采样看是在算还是显存已经满了。日志建议带 pid 和音频时长字段,多任务并发时能分开。

把音频长度和显存峰值对上

准备一张记录表,每跑一条音频填一行,字段至少包括:

音频时长峰值显存是否成功
10s<实测>是
60s<实测>是/否
300s<实测>是/否

峰值显存可以另开一个终端后台采样后取最大值,不要把采样和转写放同一个前台窗口抢时间:

nvidia-smi `--query-gpu`=memory.used `--format`=csv,noheader -l 1 > mem.log

对比必须单变量:模型、精度、批大小、解码参数全部固定,只改音频时长。如果峰值随着时长近似线性上升、某档开始失败,说明长度顶到了显存上限;如果峰值几乎不变但耗时暴涨,问题在算力和预处理,不在显存。

Nemotron 3.5 Transcribe 转写卡在半截 / 是音频太长还是显存不够?

显存不足时的典型报错与降载手段

先认错,常见文本形如:

torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate ... MiB
(GPU 0; ... GiB total capacity; ... GiB already allocated; ... MiB free)

有的封装会把它转成 RuntimeError,有的直接表现为进程消失、前端连接断开,这种情况用系统日志确认是否被 OOM killer 处理。确认是显存问题后,按代价从低到高动手:

  1. 批大小降到 1,并关掉并发转写,先让单条音频跑通。参数名各后端不同,可能是 batch_size、max_batch_size,也可能藏在服务配置里。
  2. 长音频切分为短片段,常见做法是切成 20 到 30 秒、相邻片段留少量重叠,切点尽量落在静音处,转完再拼接。注意跨片段的上下文会丢,标点、术语和句首尾可能要后处理。
  3. 切换计算精度,如 fp16、bf16 或 int8,参数名可能是 dtype、compute_type、precision、half,是否支持取决于具体后端和显卡,需要实测确认,不能想当然。
  4. 确认没有别的进程占着显存,nvidia-smi 里残留的僵尸进程要先清掉。

降低批大小、缩短切分、切换精度都是让任务跑完的手段,不是吞吐优化方案。

用短音频测一条耗时基线再线性外推

目的是把「慢」和「死」分开。取一段 10 秒左右的音频,同一配置连跑三次,记录墙钟耗时,取中位数作为基线,同时记下这段音频的显存峰值。

再用同一配置跑目标长音频,记录实际耗时。按 长音频时长 / 基线时长 × 基线耗时 估一个期望值:实测接近估算,说明只是线性变慢,调大超时时间或改异步任务即可;实测远大于估算但显存没顶,问题在长音频的预处理、重采样或内存交换,回头看第 2 节日志哪一段变长;实测直接失败或显存峰值出现跳变,按第 4 节降载处理。三次取中位数是为了避开首次加载和缓存带来的偏差,第一次的那次结果单独记,不要混进基线。