ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

FunASR 流式 Paraformer Triton GPU 部署实战:从模型仓库到实时 ASR 服务的全链路解析

2026/9/13 6:50:17 拓冰建站 浏览量
FunASR 流式 Paraformer Triton GPU 部署实战:从模型仓库到实时 ASR 服务的全链路解析 FunASR 流式 Paraformer Triton GPU 部署实战从模型仓库到实时 ASR 服务的全链路解析【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR本篇基于 FunASR 仓库中 runtime/triton_gpu/README_paraformer_online.md 的部署指南结合 model_repo_paraformer_large_online 中五个子模型的完整配置与 Python 后端实现讲解如何把流式 ParaformerParaformer-Large Online以 ONNX Triton Inference Server 的形式部署为 GPU 实时中文 ASR 服务。读完后你将掌握模型仓库的准备与目录结构、Docker 镜像构建与服务启动参数、feature_extractor → lfr_cmvn_pe → encoder → cif_search/decoder 四级 ensemble 流水线的每一级输入输出契约与状态管理机制以及单卡 A10 上的吞吐/时延基准结果与调优依据。一、部署总览一个 Ensemble 编排四个子模型流式 Paraformer 在 Triton 中不是一个单一模型而是由 streaming_paraformer/config.pbtxt 定义的ensemble平台模型。它对外只暴露WAVFP32[-1]和WAV_LENSINT32[1]两个输入、TRANSCRIPTSSTRING一个输出内部按ensemble_scheduling定义的顺序串联四个子模型WAV → feature_extractor → lfr_cmvn_pe → encoder → cif_search → (异步子调用 decoder) → TRANSCRIPTS各子模型的设备与后端分配如下均来自各子目录下的config.pbtxt子模型backend设备实例数核心职责feature_extractorpythonGPU1fbank 提帧 LFR 左上下文补齐按 0.6s chunk 切分lfr_cmvn_peonnxruntimeGPU1LFR(m7, n6) 帧叠叠、CMVN 归一化、位置编码跨 chunk 缓存encoderonnxruntimeGPU1流式 SANM encoder输出enc特征与 CIF 置信度alphascif_searchpythonCPU6CIF 累积积分找 token 边界异步调用 decoder 出文本decoderonnxruntimeGPU1自回归解码 16 层 KV cache输出sample_ids这种编排的核心价值在于把计算密集的 encoder/decoder 放在 GPU ONNX Runtime 上把逐帧循环的 CIF 搜索放在 CPU6 个实例并行并让四级共享同一套 sequence batching 会话从而支持多路并发流式会话。二、步骤 1准备模型仓库按原文档步骤准备工作分三步从 ModelScope 模型仓库克隆流式版模型模型 IDdamo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online-onnx获得encoder/1/model.onnx与decoder/1/decoder.onnx等 ONNX 权重。转换 LFR 前端模块在lfr_cmvn_pe目录下运行python export_lfr_cmvn_pe_onnx.py生成lfr_cmvn_pe.onnx。最终${MODEL_DIR}下应得到如下目录树与仓库中已提供的骨架一致├── README.md └── model_repo_paraformer_large_online ├── cif_search │ ├── 1 │ │ └── model.py │ └── config.pbtxt ├── decoder │ ├── 1 │ │ └── decoder.onnx │ └── config.pbtxt ├── encoder │ ├── 1 │ │ └── model.onnx │ └── config.pbtxt ├── feature_extractor │ ├── 1 │ │ └── model.py │ ├── config.pbtxt │ └── config.yaml ├── lfr_cmvn_pe │ ├── 1 │ │ └── lfr_cmvn_pe.onnx │ ├── am.mvn │ ├── config.pbtxt │ └── export_lfr_cmvn_pe_onnx.py └── streaming_paraformer ├── 1 └── config.pbtxt其中lfr_cmvn_pe/1/lfr_cmvn_pe.onnx与两个大模型 ONNX 需要你自己准备仓库提供骨架与导出脚本streaming_paraformer/1目录可留空ensemble 模型无需模型文件。2.1 lfr_cmvn_pe ONNX 导出的实现细节export_lfr_cmvn_pe_onnx.py 定义了LFR_CMVN_PE模块L10-L71它是 LFR CMVN 位置编码三合一的前端算子LFRunfold(1, m7, stepn6)把相邻 7 帧 fbank 横向拼成80 × 7 560维特征即encoder_input_sizesubsample (m-1)//2 3帧作为左上下文。CMVN从 am.mvn 用load_cmvnL74-L99解析出mean/istd两个 buffer执行x (x mean) * istd。PE位置编码预计算max_len5000个位置的 sin/cos 编码按offset arange索引后加到特征上offset随 chunk 累加保证跨 chunk 的绝对位置正确。状态输出forwardL48-L71返回(r_x, r_x_len, r_cache, r_offset)其中r_cache是保留给下一 chunk 做左上下文的 10 帧特征[10, 560]r_offset是累计帧偏移。导出时以opset_version11、dynamic_axes对 batch 维开放L129-L140输入输出签名[chunk_xs, cache, offset] → [chunk_xs_out, chunk_xs_out_len, r_cache, r_offset]与 lfr_cmvn_pe/config.pbtxt 中的 input/state 声明一一对应。三、步骤 2构建镜像并启动 Triton Server3.1 构建与运行容器原文档给出的完整命令# using docker image Dockerfile/Dockerfile.server docker build . -f Dockerfile/Dockerfile.server -t triton-paraformer:23.01 docker run -it --rm --name paraformer_triton_server --gpus all -v path_host/model_repo_paraformer_large_online:/workspace/ --shm-size 1g --net host triton-paraformer:23.01 # launch the service cd /workspace tritonserver --model-repository model_repo_paraformer_large_online \ --pinned-memory-pool-byte-size512000000 \ --cuda-memory-pool-byte-size0:1024000000关键点说明--model-repository指向宿主机挂载的model_repo_paraformer_large_online目录--pinned-memory-pool-byte-size512000000分配约 512MB 锁页内存池用于 CPU↔GPU 的高速拷贝Python 后端与 ONNX 后端之间传张量--cuda-memory-pool-byte-size0:1024000000为 0 号 GPU 预留 1GB 显存池供 ONNX Runtime 的 CUDA 工作区复用避免反复分配--shm-size 1g与--net host分别支撑容器共享内存通信与 gRPC 客户端直连宿主机网络客户端默认连localhost:10086见 client/client.py 的--url默认值。Dockerfile/Dockerfile.server 基于nvcr.io/nvidia/tritonserver:23.01-py3官方镜像额外安装torch2.4.1、pyyaml以及适配 CUDA 12.1 / torch 2.4.1 的kaldifeat预编译 wheel供 feature_extractor 做 fbank以及客户端依赖soundfile、grpcio-tools、tritonclient。Dockerfile 中还设置了zh_CN.UTF-8语言环境避免中文文本在容器内出现编码问题。四、逐级解析流水线实现源码级证据4.1 feature_extractor0.6s chunk 的会话式提帧feature_extractor/config.pbtxt 声明了两个参数chunk_size_s 0.6与config_path指向 feature_extractor/config.yaml即训练用 paraformer_s2 LFR6 配置的快照内含frontend_conf与token_list。输出speech的形状固定为[61, 80]80 是 fbank 维数61 是每个 chunk 产出的解码窗口帧数。Python 后端 feature_extractor/1/model.py 的实现逻辑initializeL78-L149从config.yaml读取frontend_conf的window/n_mels/frame_shift/frame_length/fs构造kaldifeat.FbankOptions算出chunk_size 0.6s × 16000采样、frame_stride (0.6×1000)//10 60帧offset_ms 15msframe_length 25ms − frame_shift 10ms。executeL151-L213处理每个请求不足一个 chunk 的尾包会零填充到chunk_size用kaldifeat批量提 fbankFeat.add_framesL58-L65在序列首帧前重复垫入(lfr_m-1)//2 3帧左上下文get_frames(61)取出 61 帧窗口并推进 60 帧——这正是流式场景下60 帧新帧 1 帧重叠的滑窗切分。会话状态用LimitedDict(1024)按CORRID维护最多缓存 1024 路并发会话收到END即释放L211-L212。四级模型全部启用 sequence batching并通过START/READY/CORRID/END四个控制输入管理会话生命周期见 feature_extractor/config.pbtxt L40-L77max_sequence_idle_microseconds: 1500000015s 无活动回收会话、preferred_batch_size: [32, 64, 128]凑批策略、max_queue_delay_microseconds: 300最多等 300μs 凑批把排队时延压到最低。4.2 lfr_cmvn_pe带状态的 ONNX 前端lfr_cmvn_pe/config.pbtxt 声明固定输入chunk_xs [61, 80]与两个序列状态cache → r_cacheFP32[10, 560]初值为零保存上一 chunk 末尾 10 个 LFR 帧作为本 chunk 的左上下文对应导出脚本中r_x cat((cache, r_cache), dim1)offset → r_offsetINT32[1]累计帧偏移供位置编码索引使用。输出chunk_xs_out [-1, 560]与chunk_xs_out_len61 帧 fbank 经 m7/n6 的 unfold 后产出约 10 帧 560 维特征正好与 encoder 的 chunk 长度对齐。4.3 encoder流式 SANM CIF 双输出encoder/config.pbtxt 中 ONNX 图输入为speech [-1, 560]与speech_lengths输出三个张量enc [-1, 512]编码器隐状态512 维alphas [-1]CIFContinuous Integrate-and-Fire的累积置信度是后续 token 边界搜索的依据enc_len有效帧数。配置里cudnn_conv_algo_search 2EXHAUSTIVE开启 cuDNN 卷积算子穷举搜索用一次性构建开销换取推理期的算法最优。4.4 cif_searchCPU 上的 token 搜索与 decoder 异步子调用cif_search/1/model.py 是全仓库中最能体现流式 Paraformer 解码机制的部分CIFSearch.__init__L24-L36定义了三个核心超参chunk_size [5, 10, 5]左上下文 5 帧、本 chunk 10 帧、右上下文 5 帧与 lfr_cmvn_pe 每 chunk 约 10 帧的输出对齐、tail_threshold 0.45流结束时对残留积分的收尾阈值、cif_threshold 1.0每累积满 1.0 置信度发射一个 token。inferL38-L104先屏蔽首尾各 5 帧的alphas拼接上一 chunk 缓存的cif_hidden/cif_alphas逐帧累加alpha积分达到 1.0 时切出一个 token 的加权隐帧并把frames / integrate的残余隐状态缓存到下一 chunk实现跨 chunk 的连续 CIF 积分。会话结束END控制输入时代码追加一帧tail_threshold的伪 alphasL51-L56把最后不足一个 token 的尾巴冲出来。得到acoustic_embeds后executeL153-L241并不直接出文本而是构造一个指向decoder的异步子推理请求pb_utils.InferenceRequestasync_execL233-L241并用 flags 标记会话阶段1首个 chunkdecoder 侧 sequence start、2末 chunksequence end、3首尾同帧、0普通帧最后asyncio.gather汇总各 decoder 返回的sample_ids经config.yaml中的token_list转回中文文本L253-L254。词表规模 8404与模型名vocab8404及 decoder/config.pbtxt 中logits [-1, 8404]输出维一致可交叉印证三级配置的同源性。4.5 decoder16 层 KV cache 的自回归解码decoder/config.pbtxt 声明了in_cache_0…in_cache_15共 16 个序列状态每个[512, 10]初值全零对应 decoder 16 层注意力对最近 10 帧编码帧的 KV 缓存——这是流式 Paraformer 编码器帧对齐解码结构的直接体现解码器每个时间步只看当前 chunk 的 acoustic embeds跨 chunk 记忆完全由这 16 组 cache 承载。输入为enc、acoustic_embeds及各自长度输出logits [-1, 8404]与采样后的sample_ids。其 sequence batching 采用preferred_batch_size: [16, 32, 64]与 feature_extractor 的[32, 64, 128]形成梯度凑批降低解码器的单请求延迟。4.6 端到端数据流小结以一路 16kHz 流式音频为例客户端每 0.6s 发送一块 PCM → feature_extractor 产出 61×80 fbank 窗口 → lfr_cmvn_pe 产出约 10×560 归一化特征并滚动 10 帧左上下文 cache→ encoder 产出 10×512 隐状态与 alphas → cif_search 积分出 0~2 个 token 的 acoustic embeds → decoder 采样出 token id → 拼成文本返回。四级共享CORRID会话START/END控制输入保证各级的缓存fbank 队列、LFR cache、CIF 积分、16 层 KV cache同生共死。五、单卡 A10 性能基准原文档给出的实测基准FP32、ONNX、Paraformer-Large Onlinechunk 为 10 帧 × 960 采样 / 16000Hz 0.6s因此实时性要求单次请求时延显著低于 600msConcurrencyThroughputLatency_p50 (ms)Latency_p90 (ms)Latency_p95 (ms)Latency_p99 (ms)20309.25256.91376.26785.598138.46240391.05897.911145.509150.545185.39960426.269138.244185.855201.016236.52880431.781170.991227.983252.453412.273100473.351206.205262.612288.964463.337从表格可以读出两点工程结论单卡 A10 在 20~60 并发路下即可稳定满足实时约束p95 时延 85~200ms仅为 600ms chunk 周期的 1/7 ~ 1/3RTF 远小于 1吞吐拐点出现在约 80 并发从 60→100 并发吞吐仅从 426 提升到 473而 p99 从 236ms 恶化到 463ms说明此时 GPU encoder 与 CPU cif_search 均已接近饱和盲目加并发只会推高尾延迟。若需更高并发应横向扩卡或增加 encoder 实例数instance_group.count而非堆叠单路请求。5.1 基准的复现方式manifest 并行压测客户端仓库提供了两套客户端可用于复现上述时延指标client/decode_manifest_triton.py基于 lhotse manifest 的并行解码脚本。--streaming模式下它把每条音频切成首块 若干等长 chunk 依次发送通过 gRPC 的sequence_start/sequence_end标记会话边界L344-L351逐 chunk 记录latency_data最后输出latency_50/90/99_percentile、方差与 RTFL485-L493并落盘recogs-*.txt与errs-*.txt配合--compute-cer计算中文 CER--simulate-streaming还会按真实语速 sleep模拟真实说话场景。client/client.py轻量 gRPC 客户端支持--audio_file单文件、--wavscp批处理目录下附 client/aishell_test.txt 清单--streaming时按--chunk_size/--sample_rate分块推送。复现压测时的注意事项sequence_id每任务独立脚本以task_index 10086生成并发任务数即表中 Concurrency 列客户端需与容器同网段容器使用--net host直接连localhost:10086。六、实操要点与排查清单目录名必须与 config.pbtxt 中的相对参数一致feature_extractor/config.pbtxt的config_path写的是model_repo_paraformer_large_online/feature_extractor/config.yaml相对--model-repository的上级路径而cif_search/config.pbtxt的vocabulary参数同样指向该 yaml 以加载token_list。因此启动时必须cd到包含model_repo_paraformer_large_online的目录即容器内/workspace与原文档命令一致。ONNX 文件缺失会导致模型加载失败encoder/1/model.onnx、decoder/1/decoder.onnx、lfr_cmvn_pe/1/lfr_cmvn_pe.onnx三个文件必须就位lfr_cmvn_pe.onnx可用仓库自带脚本重新导出python export_lfr_cmvn_pe_onnx.py导出前确保当前目录下有am.mvn。CUDA 驱动不匹配时降级 Triton 镜像Dockerfile 顶部注释明确提示若遇 CUDA driver mismatch可改选更低版本的tritonserver:xx.xx基础镜像。会话回收与并发上限各级max_candidate_sequences: 1024与 Python 后端LimitedDict(1024)共同把单实例并发会话上限定在 1024 路max_sequence_idle_microseconds为 15s长空闲客户端需保证心跳 chunk 或及时发END。量化与 TensorRT 不在本文档范围内本部署全链路 FP32 ONNX同目录的 README.mdSenseVoice 最佳实践与 README_paraformer_offline.md 分别覆盖了其他模型的部署与离线版 paraformer 的模型仓库可作横向参考。七、小结FunASR 的流式 Paraformer Triton 部署方案把训练侧的流式建模完整映射到了生产级推理框架上sequence batching 的START/READY/CORRID/END控制输入承载多路会话生命周期ONNX 侧的state声明承载 LFR 左上下文与 16 层 KV cachePython 侧的LimitedDict会话字典承载 fbank 队列与 CIF 积分状态而 cif_search 通过异步子调用把 CPU token 搜索与 GPU 解码解耦。配合 0.6s chunk 与 300μs 级凑批等待单卡 A10 即可支撑数十路并发、p95 时延低于 200ms 的实时中文语音识别服务。完整参考实现与配置见 model_repo_paraformer_large_online 与 runtime/triton_gpu/client。【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考