news 2026/9/15 13:05:24

GigaAM 俄语语音识别模型转换指南:从 NeMo/GigaAM 到 sherpa-onnx 的 CTC 与 RNNT 全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GigaAM 俄语语音识别模型转换指南:从 NeMo/GigaAM 到 sherpa-onnx 的 CTC 与 RNNT 全流程

GigaAM 俄语语音识别模型转换指南:从 NeMo/GigaAM 到 sherpa-onnx 的 CTC 与 RNNT 全流程

【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx

本指南围绕 scripts/nemo/GigaAM/README.md 所述的核心任务展开:将 SberDevices 开源的GigaAM 俄语语音识别模型(包含 CTC 与 RNNT 两类架构)转换为 sherpa-onnx 可加载的 ONNX 格式。读完本文,你将掌握从环境搭建、权重下载、ONNX 导出、INT8 量化到最终在 sherpa-onnx 中离线推理的完整实战链路,并理解转换脚本与推理端 C++ 实现之间的元数据约定。

一、背景:GigaAM 与 sherpa-onnx 的衔接

GigaAM 是一系列面向俄语语音识别的模型集合(由 salute-developers 团队开源)。本仓库的 scripts/nemo/GigaAM 目录提供了一整套转换脚本,负责将 GigaAM 模型从 PyTorch/NeMo 生态迁移到基于 onnxruntime 的 sherpa-onnx 推理框架。

这些模型之所以能无缝衔接 sherpa-onnx,核心在于转换脚本会向导出的 ONNX 模型写入一组元数据(meta data),例如model_typevocab_sizesubsampling_factoris_giga_am等。推理端在加载模型时会读取这些元数据来决定特征提取方式、词表大小与解码策略(详见后文 八、与 sherpa-onnx 推理端的集成)。

该目录覆盖两类主流模型架构:

架构导出脚本说明
CTCexport-onnx-ctc*.py字符级或 BPE 词表,单模型文件,输出logprobs
RNNTexport-onnx-rnnt*.py拆分为 encoder / decoder / joiner 三个 ONNX 文件

二、目录结构与脚本总览

scripts/nemo/GigaAM 下的脚本按"导出(export)— 运行(run)— 测试(test)"三段式组织,并存在v1 / v2 / v3 / v3-punct等多个模型版本变体:

文件用途
export-onnx-ctc.py从 NeMoEncDecCTCModel导出 CTC 模型(v1,基于 NeMo 工具链)
export-onnx-ctc-v2.py基于官方gigaamPython 包导出 v2 CTC 模型
export-onnx-ctc-v3.py导出 v3 CTC 模型(字符级,34 类输出)
export-onnx-ctc-v3-punct.py导出 v3 带标点 CTC 模型(BPE,257 类输出)
export-onnx-rnnt.py从 NeMoEncDecRNNTBPEModel导出 RNNT 三分模型(v1)
export-onnx-rnnt-v2.py/export-onnx-rnnt-v3.py/export-onnx-rnnt-v3-punct.py对应 v2 / v3 / v3-punct 的 RNNT 版本
run-ctc.sh/run-rnnt.sh及 v2/v3 变体一键执行:装环境 → 下权重 → 导出 → 测试
test-onnx-ctc.py/test-onnx-rnnt.py用 onnxruntime 验证导出结果并打印识别文本

其中test-onnx-ctc.pytest-onnx-rnnt.py对所有 CTC / RNNT 版本通用,脚本顶部注释与模型 IO 打印信息(display函数)直接反映了各版本导出的 ONNX 图结构。

三、环境准备与一键转换流程

以 v1 版本为例,run-ctc.sh 与 run-rnnt.sh 的流程完全一致,分为三步:安装依赖 → 下载模型文件 → 执行导出与测试

3.1 依赖安装(install_nemo)

CTC 与 RNNT 的 v1 脚本共用同一套环境(见run-ctc.sh第 6-21 行):

pip install torch==2.4.0 torchaudio==2.4.0 -f https://download.pytorch.org/whl/torch_stable.html pip install -qq wget text-unidecode "matplotlib>=3.3.2" onnx onnxruntime==1.17.1 \ pybind11 Cython einops kaldi-native-fbank soundfile librosa pip install -qq ipython python3 -m pip install git+https://github.com/NVIDIA/NeMo.git@main#egg=nemo_toolkit[asr] pip install numpy==1.26.4

关键点说明:

  • onnxruntime 固定为 1.17.1,与后续动态量化 API(quantize_dynamic)及导出兼容性相关;
  • kaldi-native-fbank用于测试阶段的 Fbank 特征提取(与 sherpa-onnx 推理端使用的特征提取库一致,保证数值对齐);
  • numpy==1.26.4在 NeMo 安装之后单独固定,避免依赖冲突;
  • 脚本中注释掉了apt-get install sox libsndfile1 ffmpeg,如系统缺失相关音频库可自行启用。

v2 / v3 脚本(如 run-ctc-v2.sh)不再依赖 NeMo 工具链,改为直接安装 GigaAM 官方 Python 包:

python3 -m pip install git+https://github.com/salute-developers/GigaAM.git@main#egg=gigaam python3 -m pip install -qq kaldi-native-fbank pip install numpy==1.26.4

v2/v3 脚本还直接下载了example.wav与模型仓库的LICENSE文件,说明新版模型由官方 gigaam 包内置下载与加载逻辑。

3.2 模型文件下载(download_files)

v1 的 CTC 与 RNNT 所需文件不同:

  • CTCctc_model_weights.ckptctc_model_config.yamlexample.wavlong_example.wavGigaAM License_NC.pdf
  • RNNT:除rnnt_model_weights.ckptrnnt_model_config.yaml及音频样本外,还额外需要tokenizer_all_sets.tar(BPE 分词器),下载后解压得到tokenizer_all_sets目录:
curl -SL -O <rnnt_model_weights.ckpt 下载地址> curl -SL -O <rnnt_model_config.yaml 下载地址> curl -SL -O <example.wav> && curl -SL -O <long_example.wav> curl -SL -O <tokenizer_all_sets.tar> tar -xf tokenizer_all_sets.tar && rm tokenizer_all_sets.tar

注意:GigaAM License_NC.pdf文件名中的NC代表 Non-Commercial(非商业)许可,使用前务必核对模型许可条款(详见 九、许可与注意事项)。

3.3 一键执行

# CTC v1 bash run-ctc.sh # RNNT v1 bash run-rnnt.sh

脚本末尾依次执行导出、ls -lh查看产物、运行测试脚本。其中run-rnnt.sh在测试后还会删除中间产物encoder.onnx(仅保留量化后的encoder.int8.onnx)。

四、CTC 模型导出:字符级词表与 INT8 量化

4.1 v1:基于 NeMo 工具链导出

export-onnx-ctc.py 的核心流程:

model = EncDecCTCModel.from_config_file("./ctc_model_config.yaml") ckpt = torch.load("./ctc_model_weights.ckpt", map_location="cpu") model.load_state_dict(ckpt, strict=False) model.eval() # 生成 tokens.txt:字符级词表,space 的 id 为 0,<blk> 为最后一个 token with open("tokens.txt", "w", encoding="utf-8") as f: for i, t in enumerate(model.cfg.labels): f.write(f"{t} {i}\n") f.write(f"<blk> {i+1}\n") model.export("model.onnx")

转换要点:

  • strict=False加载权重,容忍配置与 checkpoint 之间的键差异;
  • 词表规则:GigaAM CTC 模型为字符级词表,空格的 token id 固定为0<blk>(blank)追加在最后一个 id;这一约定在测试脚本中通过blank = len(id2token) - 1呼应;
  • 导出后立即为model.onnx写入元数据:
meta_data = { "vocab_size": len(model.cfg.labels) + 1, "normalize_type": "", # 特征不做归一化 "subsampling_factor": 4, # 时间维下采样 4 倍 "model_type": "EncDecCTCModel", "version": "1", "model_author": "https://github.com/salute-developers/GigaAM", "license": "https://github.com/salute-developers/GigaAM/blob/main/GigaAM%20License_NC.pdf", "language": "Russian", "is_giga_am": 1, # 标记为 GigaAM 模型,推理端据此调整特征参数 }

其中is_giga_am: 1是 sherpa-onnx 推理端识别 GigaAM 模型的关键标志(详见第八节)。随后调用 onnxruntime 的动态量化生成 INT8 版本:

quantize_dynamic( model_input="model.onnx", model_output="model.int8.onnx", weight_type=QuantType.QUInt8, )

最终目录下同时保留model.onnx(FP32)与model.int8.onnx(INT8),供不同精度需求的部署场景选用。

4.2 前处理适配:Mel 谱与 NeMo 的参数兼容

导出脚本中定义了两个子类FilterbankFeaturesTAAudioToMelSpectrogramPreprocessorexport-onnx-ctc.py第 18-54 行),用于在导出阶段注入与 sherpa-onnx 一致的 Mel 特征计算参数:

  • 丢弃 NeMo 传入的window_size/window_stride,改用显式构造的torchaudio.transforms.MelSpectrogram
  • 特征参数:n_fft=320win_length=320hop_length=160mel_scale="htk"nfilt=64
  • 将 NeMo 的features参数重映射为nfilt,保证配置兼容。

这些参数与测试脚本、C++ 推理端的特征提取配置一一对应(见第六节),是"导出即对齐"的关键。

4.3 v2 / v3 / v3-punct 变体

  • v2(export-onnx-ctc-v2.py):改用gigaam.load_model("v2_ctc"),通过model.to_onnx(".")导出,词表同样来自model.cfg["labels"],产出文件名为v2_ctc.onnx,随后量化为统一的model.int8.onnx
  • v3(export-onnx-ctc-v3.py):词表取自model.cfg["decoding"]["vocabulary"],配置注释中给出了完整的 v3 模型结构:ConformerEncoder,16 层,d_model 768,8 倍 FFN 扩展,16 头 rotary 自注意力,conv1d 下采样核 5,CTC 输出 34 类(空格 + 32 个俄语字符 + blank);
  • v3-punct(export-onnx-ctc-v3-punct.py):带标点版本v3_e2e_ctc,输出维度提升到257(BPE 词表),词表通过model.decoding.tokenizer.model(sentencepiece 模型)生成,并在元数据中额外写入"comment": "v3"以区分版本。

五、RNNT 模型导出:encoder / decoder / joiner 三分结构

RNNT(Transducer)架构与 CTC 不同,export-onnx-rnnt.py 将模型拆分为三个独立 ONNX 文件:

model = EncDecRNNTBPEModel.from_config_file("./rnnt_model_config.yaml") # ... model.encoder.export("encoder.onnx") model.decoder.export("decoder.onnx") model.joint.export("joiner.onnx")

要点:

  • 词表:RNNT 使用 BPE 词表,直接取自model.joint.vocabulary,同样把<blk>追加为最后一个 id,写入tokens.txt
  • 元数据写入 encoder.onnx,并额外包含解码器结构信息:
meta_data = { "vocab_size": model.decoder.vocab_size, # 不含 blank,C++ 端会自行加 1 "pred_rnn_layers": model.decoder.pred_rnn_layers, # 预测网络 LSTM 层数 "pred_hidden": model.decoder.pred_hidden, # 预测网络隐藏维度 "normalize_type": "", "subsampling_factor": 4, "model_type": "EncDecRNNTBPEModel", "language": "Russian", "is_giga_am": 1, ... }
  • 量化仅针对encoderencoder.int8.onnx),decoder 与 joiner 保持 FP32;
  • test-onnx-rnnt.py通过meta["pred_rnn_layers"]/meta["pred_hidden"]动态构造 decoder 的初始 LSTM 状态(见第七节)。

六、特征提取协议:Fbank 参数与模型输入输出

6.1 Fbank 特征参数(导出端、测试端、推理端三方一致)

两个测试脚本中的create_fbank()完全一致,定义了 GigaAM 系列模型的统一特征协议:

opts.frame_opts.dither = 0 opts.frame_opts.remove_dc_offset = False opts.frame_opts.preemph_coeff = 0 opts.frame_opts.window_type = "hann" opts.frame_opts.round_to_power_of_two = False opts.mel_opts.low_freq = 0 opts.mel_opts.high_freq = 8000 opts.mel_opts.num_bins = 64 # 64 维 Fbank

音频统一按16 kHz单声道处理(fbank.accept_waveform(16000, audio)),特征维度为64。这一数值与 C++ 推理端源码注释相互印证:offline-transducer-nemo-model.cc 中明确写道 "giga am uses 64",即 GigaAM 使用 64 维特征,而 parakeet-tdt-0.6b-v2 用 128 维、其余 NeMo 模型默认 80 维——推理端正是依据is_giga_am元数据动态选择特征维度。

6.2 CTC 模型的 IO 协议

test-onnx-ctc.pydisplay()打印的 ONNX 图结构(脚本第 59-65 行注释):

Input : audio_signal (float) [batch, 64, T] # 特征矩阵 [C, T] length (int64) [batch] # 帧数 Output: logprobs (float) [batch, T', 34] # T' = T / subsampling_factor

推理时需将[T, C]的特征转置为[1, C, T],并传入 int64 的帧长度:

x = torch.from_numpy(x).t().unsqueeze(0) # [1, C, T] x_lens = torch.tensor([x.shape[-1]], dtype=torch.int64) log_probs = self.model.run([output_name], {input_name: x.numpy(), length_name: x_lens.numpy()})[0]

6.3 RNNT 模型的 IO 协议

test-onnx-rnnt.py打印的三段图结构(脚本第 53-75 行注释):

  • encoder:输入audio_signal [1, 64, T]length (int64);输出outputs [1, 768, T'](d_model=768)与encoded_lengths
  • decoder(预测网络):输入targets (int32) [1, 1]target_length (int32)、两组 LSTM 状态[1, 1, 320];输出outputs [1, 320, 1]与更新后的状态——即320 维、可迭代的 RNN 状态机
  • joiner:输入 encoder 输出[1, 768, 1]与 decoder 输出[1, 320, 1],输出[1, 1, 1, 513](vocab_size 含 blank)。

七、测试脚本:验证导出的 ONNX 模型

7.1 CTC 解码测试

test-onnx-ctc.py 加载model.int8.onnxtokens.txt,用soundfile读取example.wav(多声道时取第一通道,非 16 kHz 时用librosa.resample重采样),随后:

  1. 用 kaldi-native-fbank 计算 64 维 Fbank;
  2. 前向得到log_probs [1, T', 34]
  3. 执行贪心 CTC 解码argmax取每帧最佳 token,跳过 blank 并合并相邻重复 token:
blank = len(id2token) - 1 prev = -1 for i in ids: if i != blank and i != prev: ans.append(i) prev = i

最终把 token id 序列映射回俄语字符并拼接打印。

7.2 RNNT 帧同步解码测试

test-onnx-rnnt.py 实现的是帧同步(frame-sync)贪心 Transducer 解码,流程更贴近 sherpa-onnx 的流式/离线推理逻辑:

  1. 在音频尾部拼接2 秒静音tail_padding = np.zeros(sample_rate * 2)),保证尾部 token 有足够帧触发 joiner 输出;
  2. 用全零初始化 decoder 的 LSTM 状态(pred_rnn_layers × batch × pred_hidden);
  3. 先用 blank token 走一次 decoder 获得初始decoder_out
  4. 对 encoder 输出的每一帧t:将encoder_out[:, :, t:t+1]与当前decoder_out送入 joiner,argmax后若结果不是 blank,则把新 token 追加进答案并用它更新 decoder 状态,继续下一轮;
  5. 最后移除开头的 blank,将 BPE token(下划线前缀代表词边界)还原为空格分隔的俄语文本:
text = "".join(tokens).replace("▁", " ").strip()

这套"encoder 一次性前向 + decoder 逐帧迭代"的流程,正是 sherpa-onnx 中 offline-transducer-nemo-model.cc 加载 RNNT 模型后的推理范式缩影。

八、与 sherpa-onnx 推理端的集成

导出脚本写入的元数据在推理端被显式读取:

  • offline-nemo-enc-dec-ctc-model.cc 读取vocab_sizesubsampling_factornormalize_type,并通过SHERPA_ONNX_READ_META_DATA_WITH_DEFAULT(is_giga_am_, "is_giga_am", 0)读取 GigaAM 标志;
  • offline-transducer-nemo-model.cc 对 RNNT 模型做同样处理,并依据is_giga_am决定feat_dim_取 64(见该文件第 321-324 行注释)。

is_giga_am的默认值为 0,因此只有经过本目录脚本导出的模型才会携带该标志并触发 GigaAM 专用特征参数,其余 NeMo 模型不受影响——这正是"转换脚本决定推理行为"的设计所在。

在 Python API 侧,导出的模型可直接通过OfflineRecognizer.from_nemo_ctc加载使用,参见 offline-nemo-ctc-decode-files.py:

recognizer = sherpa_onnx.OfflineRecognizer.from_nemo_ctc( model=model, # model.onnx 或 model.int8.onnx tokens=tokens, # tokens.txt debug=True, # 打印模型元数据便于核对 ) stream = recognizer.create_stream() stream.accept_waveform(sample_rate, audio) # 任意采样率均可,内部自动处理 recognizer.decode_stream(stream)

from_nemo_ctc会根据 ONNX 内的元数据自动选择 CTC 解码逻辑;RNNT 模型则对应OfflineRecognizer.from_transducer系列的 NeMo 加载路径。

九、许可与注意事项

  • 模型许可:GigaAM 模型附带GigaAM License_NC.pdf(Non-Commercial 许可),转换与部署前务必逐条核对许可条款(原始 README 亦指向模型仓库的 LICENSE 文件,见 scripts/nemo/GigaAM/README.md 末尾说明);导出脚本会把许可信息写入 ONNX 元数据的license字段,便于模型分发时追溯。
  • 版本对应关系:v1 脚本依赖 NVIDIA NeMo 工具链 + 独立 checkpoint/config 文件;v2/v3 依赖官方gigaamPython 包,模型权重由包内下载机制管理。选择脚本时请与目标模型版本严格对应,混用会导致配置与权重不匹配(加载时使用strict=False只能容忍少量键差异)。
  • 量化产物:INT8 量化仅覆盖权重(动态量化),encoder 是 RNNT 中计算量最大的部分,因此优先量化 encoder;若追求更高精度可继续使用 FP32 的model.onnx/encoder.onnx
  • 特征对齐:导出、测试、推理三端的 Fbank 参数(16 kHz、64 维、hann 窗、0–8 kHz 频带)必须保持一致,任何一端改动都会破坏识别结果;这也是is_giga_am元数据在 C++ 端被强制读取的原因。

【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 13:03:22

Windows安装Codex及接入DeepSeek-V4教程

Codex和Claude Code安装类似&#xff0c;都需要先安装git和Node.js&#xff0c;其中Node.js安装的版本需要Node.js 18以上&#xff0c;如要接入DeepSeek最好安装最新版本的&#xff0c;会省事很多。 1.Git安装 直接去git官网下载安装包进行安装即可&#xff0c;注意找与自己电…

作者头像 李华
网站建设 2026/9/15 13:00:23

OpenCut 开源视频编辑器贡献指南:2 小时合入你的第一个 PR

OpenCut 开源视频编辑器贡献指南&#xff1a;2 小时合入你的第一个 PR 【免费下载链接】OpenCut The open-source CapCut alternative 项目地址: https://gitcode.com/GitHub_Trending/ap/OpenCut OpenCut 是一个免费的开源视频编辑器&#xff0c;定位是 CapCut 的开源替…

作者头像 李华
网站建设 2026/9/15 12:59:24

开放式运动耳机选购指南:从耳廓生物力学到声学安全

1. 为什么“开放式”不是运动耳机的万能解药&#xff1f;先破除三个认知误区“开放式运动耳机怎么选&#xff1f;”——这个问题背后藏着大量被营销话术裹挟的真实困惑。我从2018年开始系统测评运动音频设备&#xff0c;累计拆解过137款标称“开放式”的产品&#xff0c;覆盖跑…

作者头像 李华