- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
本篇技术指南围绕 ESPnet2 的hubert1配方(以 egs2/TEMPLATE/hubert1/README.md 为骨架,结合 hubert.sh 与 LibriSpeech 实例)展开,完整讲解从原始语料下载、K-means 伪标签生成、迭代式掩码预测预训练,到模型打包、HuggingFace 发布与 SUPERB 下游评测的端到端流程。读完本文,你将掌握 hubert1 配方的全部 9 个阶段与核心参数语义、迭代机制的运作方式、DiceHuBERT 蒸馏用法,以及它与 ssl1 配方的定位差异。
配方概述:hubert1 是什么
hubert1是 ESPnet2 中专门为 HuBERT 风格自监督学习(SSL)设计的配方模板,位于 egs2/TEMPLATE/hubert1。HuBERT(Hidden-Unit BERT)的核心思想是:先用聚类(如 K-means)把连续语音特征离散化为隐藏单元(hidden units),再把离散序列当作伪标签,用 BERT 式的掩码预测目标训练 Transformer 编码器。由于预训练过程中没有任何人工标注参与,它属于自监督表征学习范畴。
在 ESPnet2 中,hubert1配方负责把上述整个离线流程工程化,包括:
- 数据准备(下载、Kaldi 风格目录组织);
- 语音扰动与音频格式化;
- K-means 伪标签生成与质量评估;
- 迭代式 HuBERT 预训练;
- 模型打包与上传发布。
该配方直接复用仓库中 espnet2/bin/hubert_train 训练入口,并调用 scripts/feats/perform_kmeans.sh 完成特征抽取、聚类与打标。模板本身不绑定具体语料,实际使用时需在egs2/<语料>/hubert1/下提供local/data.sh并配置运行参数;仓库内现成的完整示例是 egs2/librispeech/hubert1(LibriSpeech 960 小时)。
Recipe flow:九个阶段的整体脉络
hubert1配方的主控脚本是 egs2/TEMPLATE/hubert1/hubert.sh,它通过--stage/--stop_stage控制执行范围,整个流程分为 9 个阶段:
| 阶段 | 名称 | 功能 | 关键参数 |
|---|---|---|---|
| 1 | 数据下载与预处理 | 调用local/data.sh下载原始语料并整理成 Kaldi 风格data/目录 | local_data_opts |
| 2 | 语速扰动 | 按因子生成变速音频并合并,增强数据多样性 | speed_perturb_factors |
| 3 | 音频格式化 | 重采样、切段、格式转换,产出dump/raw/下的 wav.scp | feats_type、audio_format、fs |
| 4 | 时长过滤 | 剔除过短/过长音频 | min_wav_duration、max_wav_duration |
| 5 | 伪标签生成 | 特征抽取 → K-means 聚类 → 伪标签 → 质量评估 → 词典 | features_km、layers_km、n_clusters、portion_km等 |
| 6 | 统计量收集 | 收集训练/验证集 input/output shape | feats_normalize |
| 7 | HuBERT 训练 | 迭代式掩码预测预训练 | train_configs、train_start_iter、train_stop_iter |
| 8 | 模型打包 | 打包模型文件便于分发 | inference_ssl_model |
| 9 | 上传 HuggingFace | 发布模型到 HF Hub | hf_repo |
其中阶段 5~7 是迭代执行的:hubert.sh中for ((iter=${train_start_iter}; iter<=${train_stop_iter}; iter++))循环逐迭代运行伪标签生成、统计收集与训练。以 LibriSpeech 的 run.sh 为例,默认train_start_iter=0、train_stop_iter=1(base 模型 1 次迭代足够,注释明确说明),但配置中为迭代 2 预留了参数(见下文“迭代机制”一节)。
Stage 1:数据下载与预处理
本阶段调用local/data.sh ${local_data_opts}(见 hubert.sh),负责:
- 下载原始语料(不同语料通过
egs2/<语料>/hubert1/local/data.sh实现,如 LibriSpeech 的 local/data.sh); - 将语料组织为 Kaldi 风格的 data 目录,即
data/${train_set}、data/${valid_set}等,目录内含wav.scp、utt2spk、text、utt2num_samples等元数据文件。
由于hubert.sh强校验--train_set与--valid_set两个必填参数(缺失直接报错退出),模板中train_set、valid_set的默认值为空,需要用户按语料实际划分显式指定,例如 LibriSpeech 中--train_set "train_960" --valid_set "dev"。
Stage 2:语速扰动
若设置了speed_perturb_factors(空格分隔的多个因子,如"0.9 1.0 1.1"),本阶段会对训练集做时间拉伸/压缩,生成data/${train_set}_sp${factor}目录,再通过utils/combine_data.sh合并为data/${train_set}_sp,以提升数据多样性。
源码细节(hubert.sh):
- 对每个因子调用 scripts/utils/perturb_data_dir_speed.sh;
- 因子为 1.0 时直接复用原始
data/${train_set},不额外生成副本; - 若设置了扰动因子,后续阶段使用的
train_set会自动切换为data/${train_set}_sp(脚本内train_set="${train_set}_sp"),即扰动后的数据会贯穿后续特征、伪标签与训练全流程。
Stage 3:音频格式化
hubert1配方只支持--feats_type raw,hubert.sh中其他取值会直接报错退出。本阶段对每个数据集调用 scripts/audio/format_wav_scp.sh,将 Kaldi 风格、可能带有 unix-pipe(如cat /some/path |)的 wav.scp 转成真实音频文件,并可同时完成重采样、切段与格式转换,结果写入dump/raw/。
关键点:
--audio_format支持wav、flac、wav.ark、flac.ark(ark 表示 Kaldi 归档格式,源码中训练/统计阶段会据此选择kaldi_ark还是sound的输入类型);--fs默认16k,决定重采样目标采样率;- 若
data/${dset}/segments存在,则按<segment_id> <record_id> <start_time> <end_time>的格式把长音频切成句级片段; - 处理完成后写
feats_type标记文件(内容为raw)。
Stage 4:时长过滤
本阶段基于--min_wav_duration(默认 0.1 秒)与--max_wav_duration(默认 20 秒)剔除过短/过长语句。实现上(hubert.sh):
- 先把
dump/raw/org/${dset}复制为dump/raw/${dset}(保留原始副本); - 用
humanfriendly解析fs,将秒数换算成采样点数,再用 awk 按utt2num_samples过滤; - 同时过滤掉只有 utt-id 的空文本行(
NF != 1); - 最后
utils/fix_data_dir.sh只保留所有文件中同时存在的语句。
注意:此过滤只作用于训练集与验证集,测试集保持原样以保留完整评测数据。
Stage 5:伪标签生成(迭代核心)
HuBERT 训练是迭代式的:阶段 5~7 每轮迭代都要重新生成伪标签。本阶段统一调用 scripts/feats/perform_kmeans.sh(内部又细分为 5 个子步骤),由hubert.sh按当前迭代将n_clusters、feature_type、layer、datadir、featdir(dump/hubert_feats)、km_dir(exp/下)、dictdir等参数传入。
5.1 特征抽取(Feature Dumping)
抽取用于聚类的特征,特征类型可以是 MFCC,也可以是上一轮迭代训练出的 HuBERT 模型的中间层表征。用--features_km指定特征类型、--layers_km指定抽取层,两者均为空格分隔的多值参数,与迭代一一对应。默认 HuBERT 设置(见 egs2/librispeech/hubert1/run.sh):
- 第 0 轮迭代用 MFCC(无层概念,
layer=0); - 第 1 轮迭代用第 0 轮 HuBERT 模型的 transformer 第 6 层特征(
espnet_hubert+layer=6); - 第 2 轮迭代用第 1 轮模型的第 9 层特征(
espnet_hubert+layer=9)。
对应参数写法为:
--features_km "mfcc espnet_hubert espnet_hubert" --layers_km "0 6 9"抽取结果保存到dump/hubert_feats/。从 perform_kmeans.sh 源码看,特征类型支持mfcc、espnet_hubert、fairseq_hubert(后者可加载 legacy Fairseq 发布的 HuBERT checkpoint,通过hubert_url/hubert_dir_path指定)。实际抽取由pyscripts/feats/dump_ssl_feature.py完成,--use_gpu(默认 false)可切换到 GPU 抽取;hubert.sh会提示“推荐在 HuBERT 特征抽取时使用 GPU”。
5.2 训练 K-means 聚类
在抽取的特征上训练 K-means 模型。用--n_clusters设置簇数,同样空格分隔、与迭代对应(如--n_clusters "100 500 500");用--portion_km控制训练聚类的数据比例(LibriSpeech 默认 0.1,即取训练集 10% 的语句用于聚类,降低计算量)。
源码细节:聚类基于 scikit-learn,由pyscripts/utils/learn_kmeans.py执行(perform_kmeans.sh),通过--num_threads(默认 20)控制 CPU 线程,--RVQ_layers(默认 1)支持多级残差矢量量化(RVQ)。注释提示该步骤典型内存需求较高(约 120GB RAM)。训练好的模型保存为exp/kmeans_iter${iter}_${feats_km}_${train_set}_portion${portion_km}/km_${nclusters}.mdl。
5.3 生成 K-means 伪标签
用训练好的 K-means 模型为每个特征向量分配簇 ID,作为帧级伪标签,由pyscripts/feats/dump_km_label.py完成。伪标签文件格式为:
utt_id 12 15 ...其中utt_id后每个数字代表一帧所属的簇 ID。这些伪标签随后会被写回数据目录,命名为text.km.${km_tag}(km_tag类似kmeans_iter0_mfcc_train_960_portion0.1),与 wav.scp 一起作为后续训练的监督信号。
5.4 评估伪标签质量
若语料带有音素标注,可用--alignment_phoneme_dir指向音素对齐目录(tsv 文件,格式utt_id a1,a2,a3,...),评估伪标签与音素的对应质量。默认目录为data/mfa_phoneme_alignment:当该选项未给出且默认目录不存在时,本步骤自动跳过(perform_kmeans.sh 中的日志会明确提示跳过原因)。LibriSpeech 配方通过 run.sh 传入--alignment_phoneme_dir "./data/librispeech_phoneme_alignment",评估脚本为local/measure_teacher_quality.py,输出写入km_dir/phoneme_pseudo_label_quality.txt。
5.5 准备训练词典
按频次排序簇 ID,生成训练用词典data/${lang}_token_list_kmeans_iter${iter}_${feats_km}_${nclusters}clusters/${token_type}/tokens.txt。从源码看(perform_kmeans.sh),词典按“token + 频次”统计后按频次降序排列,并追加<unk>(OOV 符号)与<sos/eos>特殊符号(<blank>、<pad>同样被定义)。
Stage 6:收集 HuBERT 统计量
本阶段收集训练所需统计量:在训练集与验证集上分别收集语音(speech)与文本(text)的 shape 文件,供后续按batch_type(如 numel/folded)动态组 batch 使用。实现上通过python -m espnet2.bin.hubert_train --collect_stats true并行执行(nj个任务),再以espnet2.bin.aggregate_stats_dirs聚合。
关键点:均值/方差统计仅在--feats_normalize global_mvn时才计算;默认路径下聚合命令会带--skip_sum_stats,不生成 CMVN 统计。此外脚本还会把文本长度按词典大小拼接成text_shape.${token_type}(追加 num-tokens 维度),用于 batch-bins 计数。
Stage 7:训练 HuBERT
本阶段用掩码预测目标训练 HuBERT 编码器。训练设置通过--train_configs指定 YAML 配置,支持空格分隔的多个配置文件、每个迭代一个。LibriSpeech 示例:
--train_configs "conf/tuning/train_ssl_torchaudiohubert_base_960h_pretrain_it0.yaml conf/tuning/train_ssl_torchaudiohubert_base_960h_pretrain_it1.yaml conf/tuning/train_ssl_torchaudiohubert_large_960h_pretrain_it2.yaml"训练命令为python -m espnet2.bin.hubert_train(经由espnet2.bin.launch分发到多 GPU/多节点),并自动带上--num_classes ${n_clusters}、--token_list、--fold_length(speech_fold_length默认 800、text_fold_length默认 400)等参数。输入特征类型取决于迭代:mfcc或上一轮 HuBERT 模型输出,_type为sound或kaldi_ark。
以 base 模型第 0 轮配置 train_ssl_torchaudiohubert_base_960h_pretrain_it0.yaml 为例,核心训练要素包括:
- 编码器为
torchaudio_hubert,模型为torchaudio(复用 torchaudio 的 HuBERT 实现); - 优化器 Adam(lr=0.0005)+ warmup lr 调度(warmup_steps=32000);
batch_type: numel、batch_bins: 48000000、accum_grad: 2;collate_fn_conf中label_downsampling: 2(第 0 轮标签每 2 帧一采样)、rand_crop: True;- 开启
use_amp: true(混合精度),max_epoch: 250,keep_nbest_models: 10; - 该配置注释表明在 8×A100(40GB) 上约需 5 天。
第 1 轮配置 train_ssl_torchaudiohubert_base_960h_pretrain_it1.yaml 与第 0 轮基本一致,仅label_downsampling改为 1(不再降采样)。训练结果保存在exp/hubert_iter${iter}_${ssl_tag}/,默认最优模型文件名为valid.loss.best.pth(由inference_ssl_model指定)。
Stage 8:模型打包
本阶段调用python -m espnet2.bin.pack ssl,将训练好的模型打成一个 zip 包(默认skip_packing=true,需要显式关闭跳过),打包内容包括:
- SSL 训练配置(
config.yaml)与模型权重(valid.loss.best.pth); - 训练过程图片(
exp/${ssl_exp}/images); - 最后一轮迭代的 K-means 模型
km_${n_clusters}.mdl; - 若使用
global_mvn,还会附带feats_stats.npz。
输出路径形如exp/hubert_iter1_<tag>/<tag>_valid.loss.best.zip,可直接用于推理或上传发布。
Stage 9:上传 HuggingFace
本阶段把打包模型上传到 HuggingFace Hub(默认skip_upload_hf=true)。使用时需设置--hf_repo "<用户名>/<仓库名>",脚本会:
- 检查 git-lfs 是否安装;
git clone目标 HF 仓库;- 解压 zip 包到仓库目录;
- 基于 scripts/utils/TEMPLATE_HF_Readme.md 模板生成 README(填充
hf_task=self-supervised-learning、espnet_task=SSL等字段); git add / commit / push完成发布。
LibriSpeech 的官方预训练模型即通过此流程发布在 HuggingFace(如迭代 0、迭代 1 的 base 模型),其微调表现记录在 egs2/librispeech/hubert1/README.md:在 LibriLight-Limited 10h 微调设置下,迭代 0 模型在 dev-clean 上 WER 15.5%、迭代 1 模型降至 10.4%,体现了迭代式伪标签质量提升带来的收益。
迭代机制与多值参数详解
hubert1配方的核心工程技巧是“多值参数 + 迭代下标”:train_configs、n_clusters、features_km、layers_km都是空格分隔的多值列表,hubert.sh启动时会将它们拆分为数组,并在进入训练循环前做严格校验(hubert.sh):
- 每个列表长度必须大于
train_stop_iter(下标从 0 开始),否则报错“# xxx is less than train_stop_iter”; - 必须满足
train_start_iter <= train_stop_iter。
循环体内按iter取值:feats_km="${feature_list[iter]}"、layer="${layer_list[iter]}"、n_clusters="${n_clusters_list[iter]}"、ssl_config="${train_config_list[iter]}",从而同一套脚本驱动多次迭代。
此外,hubert.sh还支持--download_model:从 Model Zoo 下载已有预训练模型并解包到exp/${download_model}/,用于“跳过本轮训练直接生成下一轮伪标签”的场景(这也是 DiceHuBERT 蒸馏流程能省去从头训练的关键)。各迭代目录命名规则如下:
- 统计目录:
exp/hubert_iter${iter}_stats_${feats_type}; - 实验目录:
exp/hubert_iter${iter}_${ssl_tag},其中ssl_tag取配置文件名(去 .yaml)+_raw; - 词典目录:
data/${lang}_token_list_kmeans_iter${iter}_${feats_km}_${nclusters}clusters/${token_type}; - K-means 模型目录:
exp/kmeans_iter${iter}_${feats_km}_${train_set}_portion${portion_km}。
Distillation:DiceHuBERT 蒸馏
hubert1配方原生支持 DiceHuBERT 蒸馏——一种将教师模型知识迁移到更小学生的蒸馏方法。与常规回归损失不同,DiceHuBERT 直接复用标准 HuBERT 交叉熵损失做蒸馏,因此几乎不用改动配方即可训练,只需注意配置文件的替换。
完整流程如下:
1. 标准数据准备(前 4 个阶段):
./run.sh --stage 1 --stop-stage 42. 复用已有教师模型生成伪标签:学生模型按 HuBERT 迭代 2 的流程训练,但不必从头训练教师,直接从 Model Zoo 下载迭代 1 的预训练模型:
./run.sh --stage 5 --stop-stage 5 --train_start_iter 2 --train_stop_iter 2 --download_model simpleoier/simpleoier_librispeech_hubert_iter1_train_ssl_torchaudiohubert_base_960h_pretrain_it1_raw--train_start_iter 2 --train_stop_iter 2保证只执行迭代 2。
3. 用蒸馏配置训练学生模型:
./run.sh --stage 6 --stop-stage 7 --train_start_iter 2 --train_stop_iter 2 \ --train_configs "conf/tuning/train_ssl_torchaudiohubert_base_960h_pretrain_it0.yaml \ conf/tuning/train_ssl_torchaudiohubert_base_960h_pretrain_it1.yaml \ conf/tuning/train_ssl_torchaudiohubert_distill_960h_pretrain_it2.yaml"这里--train_configs必须显式给出:run.sh硬编码了标准迭代 2 配置,若不覆盖,学生会错误地使用train_ssl_torchaudiohubert_large_960h_pretrain_it2.yaml而不是蒸馏配置。同时列表需要为到--train_stop_iter为止的每个迭代各提供一个条目,因此虽然只用到最后一个,也要全部给出。默认蒸馏配置位于 egs2/librispeech/hubert1/conf/tuning/train_ssl_torchaudiohubert_distill_960h_pretrain_it2.yaml。
对比蒸馏配置与基础/大模型配置可发现关键差异:
- 蒸馏配置显式
use_amp: false,而迭代 1 基础配置为use_amp: true。注释说明这是有意为之:该蒸馏设置下开启 AMP 会造成训练不稳定; - 学生模型架构更小:
encoder_embed_dim: 384、encoder_num_layers: 12、encoder_num_heads: 6、encoder_ff_interm_features: 1536、final_dim: 128; - 对比大模型配置 train_ssl_torchaudiohubert_large_960h_pretrain_it2.yaml(
encoder_embed_dim: 1024、24 层、16 头、final_dim: 768),学生参数量大幅缩减,同时保留grad_clip: 5.0、batch_type: numel、warmup 32000 步等一致的训练超参。
Evaluation:与 SUPERB/s3prl 集成
hubert1配方本身不内置评测阶段,但训练出的 HuBERT 模型与 SUPERB 基准完全兼容,可通过 s3prl 工具包进行下游任务评测。s3prl 原生支持 HuBERT 模型,只需把上游模型指定为espnet_hubert_local,即可用 ESPnet 训练的 checkpoint 提取特征、训练下游模型:
cd s3prl/s3prl python run_downstream.py \ -m train \ -n "${TASK}_espnet_hubert" \ -d $TASK \ -c "downstream/$TASK/config.yaml" \ -u espnet_hubert_local \ -k "$CKPT" \ -g "$CONFIG"其中:
$CKPT与$CONFIG分别指exp/目录下的 HuBERT 权重(如valid.loss.best.pth)与训练配置(config.yaml);- 命令需在
s3prl/s3prl包目录下执行,因为-c是相对工作目录解析的; -n用于命名运行,建议显式设置:结果会写入result/downstream/$EXPNAME,缺省时变成result/downstream/None,不同任务会互相覆盖。
运行后 s3prl 会使用你的 HuBERT 模型提取特征,为指定任务训练并评测下游模型(如说话人验证 ASV、音素识别等 SUPERB 任务),评测细节可参考 s3prl 的 SUPERB 文档。
与其他 SSL 配方(ssl1)的差异
ESPnet2 提供两套自监督学习配方:ssl1与本篇的hubert1,二者定位不同(可对比 egs2/TEMPLATE/ssl1 与 egs2/librispeech/ssl1)。
hubert1(本文):HuBERT 预训练框架的原始实现,把预训练所需的全部离线步骤(K-means 伪标签、离散 token 评估)都收进配方,对复现非常友好;但由于 HuBERT 需要多个离线阶段,脚本较为复杂,难以快速改造以适配新的训练方法或新场景。ssl1:为代码库“面向未来”而建的新配方,旨在容纳纯端到端的新预训练技术(如 DinoSR、SpeechFlow、w2v-BERT 等),设计上更易定制、更利于大规模预训练扩展。
补充说明:ssl1代码库同样支持 HuBERT 预训练,但伪标签生成步骤不在其配方内——用户要么先用hubert1配方产出标签,要么自行生成后传入。
小结
hubert1配方是 ESPnet2 中复现 HuBERT 自监督预训练的一站式工程方案:通过hubert.sh将数据准备、语速扰动、音频格式化、时长过滤、K-means 伪标签生成、统计收集、迭代训练、模型打包与 HF 发布串成可复现的 9 阶段流水线,并以空格分隔的多值参数优雅支撑多轮迭代。无论是按模板复现 LibriSpeech 960h 预训练、基于 DiceHuBERT 做轻量化蒸馏,还是将产出模型接入 SUPERB 下游评测,都可以在本文所述框架内直接落地。对需要更灵活端到端自监督方案的用户,可转向ssl1配方对比选型。
- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
相关推荐
HuBERT 自监督语音预训练标签生成实战:fairseq simple_kmeans 分片特征提取与 K-means 聚类全流程
HuBERT 自监督语音预训练标签生成实战:fairseq simple_kmeans 分片特征提取与 K means 聚类全流程 本文基于本仓库 kosmos
人工智能大模型预训练深度学习NLP计算机视觉多模态语音音频微调NeMo TopIPL 实践指南:基于迭代伪标签(IPL)的半监督 ASR 自训练流水线
NeMo TopIPL 实践指南:基于迭代伪标签(IPL)的半监督 ASR 自训练流水线 TopIPL(Top N Pseudo Label Averaging
人工智能语音音频大模型深度学习fairseq HuBERT 语音自监督预训练实战指南:从伪标签数据准备到预训练、CTC 微调与三种解码模式
fairseq HuBERT 语音自监督预训练实战指南:从伪标签数据准备到预训练、CTC 微调与三种解码模式 本指南以 examples/hubert/READ
人工智能深度学习预训练NLP语音
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考