- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
导读
ESPnet2 采用「任务级统一 Recipe」的设计思路:不再像 ESPnet1 那样为每个语料单独编写全套脚本,而是为 ASR、TTS、增强、翻译等每个任务维护一份通用模板脚本(如asr.sh),通过命令行参数吸收不同语料的差异。本文以仓库中的 Recipe Template 文档 为主体,结合 egs2/TEMPLATE/asr1/ 下的setup.sh、asr.sh、db.sh等真实源码,系统讲解如何用模板在自有语料上快速跑通端到端训练、如何手工构造 Kaldi 风格的data/目录,以及开发者如何把 ESPnet1/Kaldi 的老 Recipe 移植为 ESPnet2 新 Recipe。读完本文,你将掌握从「一份原始音频 + 标注」到「可训练、可解码、可评分」的完整落地路径。
一、Recipe Template 是什么
Recipe(配方/流程脚本)是 ESPnet 中把「数据准备 → 特征提取 → 词表构建 → 语言模型训练 → ASR 模型训练 → 解码 → 评分 → 打包 → 上传」等步骤串联起来的可执行流水线。egs2/TEMPLATE/README.md指出,模板被设计为支持每个任务常见且通用的功能与需求,从而让用户无需修改 Recipe 主体,只需补充语料相关的一小段数据准备脚本即可。
仓库中模板按任务划分在 egs2/TEMPLATE/ 下,每个任务一个目录,例如:
asr1:语音识别(核心示例,脚本名为asr.sh)enh1:语音增强(enh.sh)tts1/tts2:语音合成(tts.sh)mt1:机器翻译(mt.sh)st1:语音翻译(st.sh)s2t1:语音到文本(s2t.sh)enh_asr1、enh_diar1、sds1、ssl1、spk1等更多任务
以asr1为例,模板目录包含以下关键内容(见 egs2/TEMPLATE/asr1/):
| 文件/目录 | 作用 |
|---|---|
setup.sh | 一键把模板复制到新语料目录的引导脚本 |
asr.sh | 通用 ASR 主流水线(15 个 stage,约 1800 行) |
path.sh | 设置 PATH、Python 环境、工具路径 |
cmd.sh | 选择本地执行 / SLURM / PBS 等运行队列方式 |
db.sh | 集中登记各语料的下载路径或本地路径 |
local/ | 语料相关的数据准备与评分脚本(每个 Recipe 需要自定义的部分) |
conf/ | 特征、训练、解码、队列配置(fbank.conf、train_asr_*.yaml、decode_asr_*.yaml等) |
scripts/、pyscripts/、steps/、utils/ | 公共工具脚本(通常以符号链接指向模板) |
从源码看,setup.sh(见 egs2/TEMPLATE/asr1/setup.sh)做的事非常明确:
- 复制
cmd.sh、conf、local三个部分到目标目录(这些是需要按语料定制的内容); - 符号链接
asr.sh、path.sh、db.sh、scripts、pyscripts、steps、utils到模板(这些是公共内容,软链可保证升级模板时自动同步)。
这样设计的好处是:同一份asr.sh被所有语料共享,任何 bug 修复或新特性只需改模板一处。
二、用自有语料运行 ESPnet:三步上手
原文档给出了最核心的三步流程,下面结合源码逐一展开。
第 1 步:复制模板到自己的语料目录
% task=asr1 # enh1, tts1, mt1, st1 % egs2/TEMPLATE/${task}/setup.sh egs2/foo/${task}执行后,egs2/foo/${task}下会生成可直接修改的工作目录:cmd.sh、conf/、local/被真实复制,其余公共文件以符号链接形式存在。setup.sh还做了两项校验(源码第 18-31 行):必须恰好传入 1 个目标目录参数,且目标目录的上级须存在TEMPLATE目录,否则报错退出。
第 2 步:创建egs2/foo/${task}/data目录
data/是训练、验证、测试数据的存放处,采用 Kaldi 风格结构(下一节详解)。如果你的语料在egs2下已有对应 Recipe(如mini_an4、librispeech),也可以直接参考其local/data.sh的实现。
第 3 步:运行主脚本
原文档以 ASR 为例给出了最小启动命令:
cd egs2/foo/${task} # 官方约定:所有脚本都在该目录下执行 # 假设 Stage1 已经生成 data,可直接从 Stage2 开始 ./asr.sh \ --stage 2 \ --ngpu 1 \ --train_set train \ --valid_set valid \ --test_sets "test" \ --lm_train_text "data/train/text"要点说明:
- 必须
cd到 Recipe 目录执行。asr.sh依赖相对路径(如./path.sh、utils/parse_options.sh、conf/*.yaml),离开该目录会导致解析失败。 --stage 2表示跳过 Stage 1(数据准备,假定data/已就绪),从速度扰动阶段开始。--ngpu 1指定使用 1 块 GPU;设为0则纯 CPU 运行(见 asr.sh 中ngpu=1 # The number of gpus ("0" uses cpu, otherwise use gpu))。--train_set/--valid_set/--test_sets是必填项:asr.sh在进入主流程前会做严格校验(源码第 301-331 行),未指定--train_set/--valid_set直接报错退出,train_set与valid_set不允许相同,test_sets中不允许出现train_set。- 若遇到 CUDA 显存不足(OOM),应调小
batch_bins(或batch_size),而不是盲目增大nj。 - 指定 GPU 设备号可使用环境变量
CUDA_VISIBLE_DEVICES。
下面这张表汇总了asr.sh中最常用的参数(默认值均来自 asr.sh 的源码),便于按需调整:
| 参数 | 默认值 | 说明 |
|---|---|---|
--stage/--stop_stage | 1/10000 | 流水线起止阶段 |
--skip_stages | 空 | 指定要跳过的阶段 |
--ngpu | 1 | GPU 数量,0表示 CPU |
--num_nodes | 1 | 分布式训练的节点数 |
--nj | 32 | 数据/特征阶段的并行任务数 |
--inference_nj | 32 | 解码阶段的并行任务数 |
--gpu_inference | false | 是否用 GPU 解码 |
--dumpdir/--expdir | dump/exp | 特征与实验输出目录 |
--feats_type | raw | raw、raw_copy、fbank_pitch、fbank、extracted |
--audio_format | flac | wav、flac、wav.ark、flac.ark(仅raw系列有效) |
--fs | 16k | 采样率(需与语料实际采样率匹配) |
--min_wav_duration/--max_wav_duration | 0.1/20 | 训练音频时长过滤区间(秒) |
--token_type | bpe | bpe、char、word、whisper_en、whisper_multilingual、hugging_face |
--nbpe | 30 | BPE 词表大小 |
--bpemode | unigram | unigram或bpe |
--use_lm | true | 解码时是否使用语言模型 |
--lm_config/--lm_args | 空 | LM 训练配置与覆盖参数 |
--asr_config/--asr_args | 空 | ASR 训练配置与覆盖参数 |
--inference_config/--inference_args | 空 | 解码配置与覆盖参数 |
--inference_asr_model | valid.acc.ave.pth | 解码所用模型快照,也常用valid.loss.ave.pth |
--download_model | 空 | 直接从 Model Zoo 下载预训练模型用于解码 |
--use_ngram | false | 是否训练并使用 n-gram 语言模型 |
--feats_normalize | global_mvn | 特征归一化方式 |
--use_streaming/--use_maskctc | false | 流式解码 / Mask-CTC 解码 |
--train_set/--valid_set/--test_sets | 空(必填) | 训练/验证/测试数据目录名 |
几个值得注意的源码细节:
--lm_train_text未指定时,会自动复用训练集文本(源码第 374 行Use the same text as ASR for lm training if not specified),所以最小启动命令里即使不写它也通常没问题。- 指定
--feats_type raw时,特征目录为${dumpdir}/raw(源码第 334-349 行);选择不支持的feats_type会直接报错退出。 --token_type支持多种词表策略:bpe(SentencePiece)、char、word、whisper_*(复用 Whisper 词表)以及hugging_face(需配合--hugging_face_model_name_or_path),源码第 402-424 行逐一分支处理。- 通过
--lm_args/--asr_args/--inference_args传入的覆盖参数会自动拼进实验目录的 tag 中(源码第 452-455 行),保证不同参数组合的产物目录不互相覆盖,这也是推荐「先用 yaml 配置,再在命令行覆盖」的原因。
三、Kaldi 风格 data 目录:格式与构造详解
训练集、开发集、测试集各自拥有完全相同的目录结构(详见原文档「About Kaldi style data directory」一节)。data/train、data/dev、data/test三者并列,内部文件格式完全一致。
3.1 目录结构总览
data/ train/ - text # 转写文本 - wav.scp # 音频文件路径 - utt2spk # 发音单元(utterance) id 到说话人(spk) id 的映射 - spk2utt # 说话人 id 到发音单元 id 列表的映射 - segments # [可选] 指定每条发音的起止时间 dev/ ... test/ ...3.2 各文件格式
text:转写文件
uttidA <transcription> uttidB <transcription> ...wav.scp:音频路径文件
uttidA /path/to/uttidA.wav uttidB /path/to/uttidB.wav ...utt2spk:发音单元 → 说话人
uttidA speakerA uttidB speakerB uttidC speakerA uttidD speakerB ...spk2utt:说话人 → 发音单元列表
speakerA uttidA uttidC ... speakerB uttidB uttidD ... ...原文档特别强调:spk2utt可由utt2spk生成,反之亦然,因此手工创建时二选一即可,用模板自带的 Perl 工具互转:
utils/utt2spk_to_spk2utt.pl data/train/utt2spk > data/train/spk2utt utils/spk2utt_to_utt2spk.pl data/train/spk2utt > data/train/utt2spk没有说话人信息怎么办?原文档给出两种兜底方案:把说话人 id 设成与发音单元 id 相同,或全部填同一个dummyid。它同时指出:「(对于 asr recipe)我们实际上并不使用说话人信息」,所以这种占位做法不会影响 ASR 训练。
uttidA uttidA uttidB uttidB ...或
uttidA dummy uttidB dummy ...3.3 可选文件segments:长音频切分
如果原始录音很长(约 > 1 小时),且一个音频文件里包含多段语音,就需要segments指定每条发音的起止时间,格式为<utterance_id> <wav_id> <start_time> <end_time>:
sw02001-A_000098-001156 sw02001-A 0.98 11.56 ...关键约定:使用segments时,wav.scp中的键是<wav_id>而非<utterance_id>(sw02001-A对应整段录音,而sw02001-A_000098-001156是切出的某条发音):
sw02001-A /path/to/sw02001-A.wav ...从asr.shStage 3 的注释(源码第 643-649 行)可以印证这条约定:segments用于把wav.scp中的整段录音按<segment_id> <record_id> <start_time> <end_time>切分为发音单元,时间单位为秒。
3.4 目录校验:validate_data_dir.sh
手工构造完data/后,强烈建议用官方校验脚本检查格式是否合法:
utils/validate_data_dir.sh --no-feats data/train utils/validate_data_dir.sh --no-feats data/dev utils/validate_data_dir.sh --no-feats data/test--no-feats表示跳过特征文件检查(因为我们只有wav.scp,没有预提取的feats.scp)。该校验脚本能及时发现wav.scp键不一致、text缺失、时间戳格式错误等常见问题。
3.5 推荐实践:先跑 mini_an4 感受数据结构
原文档建议通过mini_an4亲自检查data/的实际内容:
cd egs2/mini_an4/asr1 ./run.shegs2/mini_an4/asr1/run.sh 展示了run.sh的真实形态——它只是asr.sh的一层薄封装,把数据集名称与配置文件集中传递:
./asr.sh \ --nj 2 \ --inference_nj 2 \ --lang en \ --asr_config conf/train_asr_rnn_debug.yaml \ --lm_config conf/train_lm_rnn_debug.yaml \ --inference_config conf/decode_asr_debug.yaml \ --train_set train_nodev \ --valid_set train_dev \ --test_sets "train_dev test test_seg" \ --lm_train_text "data/train_nodev/text" "$@"跑完run.sh后查看data/train_nodev/下的text、wav.scp、utt2spk、spk2utt,就能直观理解上述格式约定。
四、(开发者向)如何制作 / 移植一个新的 Recipe
原文档第三部分是给开发者看的「How to make/port new recipe」。ESPnet2 与 ESPnet1 最大的不同在于:不为每个语料准备不同 Recipe,而是每个任务一套通用 Recipe(asr.sh、enh.sh、tts.sh等)。这些通用脚本被精心设计为适用于任意语料,理想情况下你几乎不需要修改 Recipe 主体,唯一必须自己做的是local/data.sh。
4.1 建立目录与 run.sh
% task=asr1 # enh1, tts1, mt1, st1 % egs2/TEMPLATE/${task}/setup.sh egs2/foo/${task} % cd egs2/foo/${task} % cp ../../mini_an4/${task}/run.sh . % vi run.shrun.sh是通用 Recipe 的薄封装,内容形如:
# The contents of run.sh ./asr.sh \ --train_set train \ --valid_set dev \ --test_sets "dev test1 test2" \ --lm_train_text "data/train/text" "$@"注意末尾的"$@":它把用户在命令行额外传入的--xxx参数原样转发给asr.sh,这是run.sh保持灵活性的关键设计。
4.2 local/data.sh:唯一的必写脚本
原文档给出四条核心原则:
- 语料差异必须通过
asr.sh的命令行参数吸收,不要擅自修改公共脚本。 local/data.sh负责生成 Kaldi 风格的data/train(训练)、data/dev(验证)以及多个data/test1、data/test2(测试)目录(对应asr.sh的 Stage 1,源码第 572-576 行直接调用local/data.sh ${local_data_opts})。- 特征提取、速度扰动(Speed Perturbation)、长短句过滤都由公共阶段完成,
local/data.sh中不需要(也不应该)重复实现这些步骤(见原文档对「Feature extraction, Speed Perturbation, Removing long/short utterances」的说明)。 - 从 ESPnet1 或 Kaldi 移植时,只需把原 Recipe 的数据准备部分嵌入
local/data.sh。
4.3 关于验证集与测试集的几条约定
- 验证集必须只有一份:训练期间的验证集(
--valid_set)必须是单个数据目录。如果有多个验证目录,用utils/combine_data.sh合并。 - 测试集可以有多份:推理阶段(
--test_sets)接受多个测试目录,因此可以顺手把验证集也纳入评估。 - 部分语料没有官方 dev 集:此时可以从训练数据中切出一部分作为验证集,其余仍作训练集(原文档举例
egs2/csj/asr1/local/data.sh就是这么做的)。 asr.sh的自动去重逻辑(源码第 316-331 行):若test_sets里包含valid_set,脚本会自动把eval_valid_set置为true,并把验证集从test_sets中剔除,避免重复评估;test_sets内部的重复项也会被自动去重。
4.4 在 db.sh 登记语料路径
如果 Recipe 依赖的语料尚未在 egs2/TEMPLATE/asr1/db.sh 中登记,则需要补充一行:
... YOUR_CORPUS= ...db.sh中已登记了大量语料,值有三种形态,从文件头注释「"downloads"means the corpus can be downloaded by the recipe automatically」可以确认:
downloads:表示 Recipe 能自动下载该语料(如LIBRISPEECH=downloads、AN4=downloads);- 空值:等待用户填写本地路径;
- 绝对路径:某些机构环境预置的路径(
db.sh底部还有针对 CMU TIR、JHU CLSP 等特定环境的hostname分支,自动覆盖对应语料路径)。
因此新增语料时,把YOUR_CORPUS=改成你的本地路径或downloads即可。
4.5 特殊工具依赖写入 local/path.sh
如果 Recipe 依赖某些特殊命令行工具,在local/path.sh中声明:
# e.g. flac command is required if ! which flac &> /dev/null; then echo "Error: flac is not installed" return 1 fipath.sh会在主流程加载时执行(asr.sh源码第 296 行. ./path.sh),工具缺失会提前暴露,避免跑到一半才失败。注意path.sh面向的是「配方所需的外部命令」,而 Python 解释器等公共环境由模板级path.sh统一处理。
五、asr.sh 的 15 阶段流水线:一次跑通全流程
结合源码(asr.sh 中各log "Stage N: ..."语句),asr.sh从数据到部署的完整流水线如下,这也是理解模板设计的最直观方式:
| Stage | 内容 | 源码位置 |
|---|---|---|
| 1 | 数据准备:调用local/data.sh生成data/{train,valid,test} | asr.sh#L572-L576 |
| 2 | 速度扰动:对train_set按speed_perturb_factors生成train_sp | asr.sh#L579-L599 |
| 3 | 特征处理:raw模式下格式化wav.scp(统一格式与采样率);fbank_pitch等模式下提取特征 | asr.sh#L615-L760 |
| 4 | 长短句过滤:按min/max_wav_duration清洗dump/数据 | asr.sh#L801 |
| 5 | 词表构建:按token_type生成 BPE / char / word / whisper / hugging_face 的token_list | asr.sh#L879-L1008 |
| 6 | LM 统计量收集(collect stats) | asr.sh#L1009 |
| 7 | LM 训练 | asr.sh#L1086 |
| 8 | LM 困惑度(perplexity)评估 | asr.sh#L1162 |
| 9 | n-gram 训练(需use_ngram=true) | asr.sh#L1181 |
| 10 | ASR 统计量收集(collect stats) | asr.sh#L1191 |
| 11 | ASR 模型训练 | asr.sh#L1310 |
| 12 | 解码(含 k2 / streaming / Mask-CTC / n-best 重打分等可选路径) | asr.sh#L1513 |
| 13 | 评分(默认走sclite,可通过score_opts/local_score_opts定制) | asr.sh#L1654 |
| 14 | 打包模型(pack) | asr.sh#L1760 |
| 15 | 上传模型到 HuggingFace(hf_repo指定仓库) | asr.sh#L1793 |
几个与阶段编排直接相关的参数组合:
--skip_data_prep true:自动跳过 Stage 1-5(源码第 544-546 行)。--skip_train true:跳过训练相关阶段(2/4/5/6/7/8/9/10/11),只做数据与解码评估。--use_lm false:跳过 LM 相关阶段 6/7/8。--use_ngram false(默认):跳过 Stage 9。--skip_eval true:跳过 Stage 12/13。--skip_packing(默认true)与--skip_upload_hf(默认true):默认不执行打包与上传,需要时手动打开。
特征配置方面,conf/fbank.conf 提供了 fbank 提取的默认参数(--sample-frequency=16000、--num-mel-bins=80),conf/pitch.conf 提供 pitch 特征参数;队列配置则在 conf/ 下的queue.conf(本地/多机)、slurm.conf(SLURM 集群)、pbs.conf(PBS 集群)中选择,并由cmd.sh切换。实际语料通常在 egs2/librispeech/asr1/conf/ 这类目录中提供更完整的train_asr_*.yaml与decode_asr_*.yaml参考配置。
六、总结:模板使用的完整心智模型
把原文档与仓库源码合起来看,Recipe Template 的使用可以归结为三层:
- 普通用户(跑通自有语料):
setup.sh复制模板 → 构造 Kaldi 风格data/(text+wav.scp+utt2spk/spk2utt,长音频加segments)→utils/validate_data_dir.sh校验 → 从--stage 2起跑asr.sh,必要时调整batch_bins解决显存问题。 - 格式细节:四个核心文件(
text/wav.scp/utt2spk/spk2utt)的键值约定、segments的<utterance_id> <wav_id> <start> <end>四列格式、以及「用segments时wav.scp以wav_id为键」的隐含规则。 - 开发者(制作/移植 Recipe):只写
local/data.sh(生成train/dev/test的 Kaldi 目录)、在run.sh中传参、在db.sh登记语料路径、在local/path.sh声明特殊工具依赖;特征提取、速度扰动、长短句过滤、训练与解码全部复用公共流水线。验证集只能有一份(多个则combine_data.sh合并),测试集可以有多个,asr.sh会自动处理test_sets与valid_set重叠的情况。
掌握这套模板机制后,无论是跑通一个新的开源语料,还是把 ESPnet1/Kaldi 时代的老 Recipe 迁移到 ESPnet2,都能以最小的代码量完成——这也是 ESPnet2 以「通用 Recipe + 参数化差异」替代「每语料一套脚本」的核心设计意图。
- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
相关推荐
ESPnet2 端到端语音处理实战教程:Recipe 体系、训练配置、流式 ASR 与 Transducer 模型全解析
ESPnet2 端到端语音处理实战教程:Recipe 体系、训练配置、流式 ASR 与 Transducer 模型全解析 导读 本文是基于 ESPnet 仓库
人工智能语音音频深度学习NLPFairseq 语音识别(ASR)实战指南:LibriSpeech 数据准备、VGG-Transformer 训练与 Flashlight 解码
Fairseq 语音识别(ASR)实战指南:LibriSpeech 数据准备、VGG Transformer 训练与 Flashlight 解码 本指南以 ex
人工智能深度学习预训练NLP语音WinUtil 完整指南:用免费 Windows 系统优化工具完成批量装软件、一键调优与更新管理
WinUtil 完整指南:用免费 Windows 系统优化工具完成批量装软件、一键调优与更新管理 刚装好的 Windows 11,四件事几乎躲不掉:软件要挨个官
桌面应用运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考