WeNet环境配置与aishell模型训练
1环境配置
踩坑记录: 系统使用win11,我根据wenet官方文档,使用conda虚拟环境安装了cuda12.1,安装wenet依赖库,其中deepspeed报错,根据报错信息查询github,发现缺少libaio库,它通常在Linux系统上使用,根据githubu找到解决办法,重新编译了deepspeed,成功安装依赖。分析和运行wenet时发现,仍然有很多报错。随后我尝试在本机VMware+ubuntu22.04,wenet在不进行跑数据的情况下没有问题,开始数据测试后,发现VMware基于主机的显卡虚拟映射出了一个供uhuntu系统使用的显卡,这个显卡没有合适的驱动。随后查询到一个解决办法,显卡直连,尝试好几种博主的方法,均失败告终。
解决方法: 已老实,求放过,使用带GPU的服务器,本文服务器使用ubuntu22.04。
1.1安装Miniconda
#下载
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py310_24.5.0-0-Linux-x86_64.sh
#安装:根据提示输入enter或yes
bash Miniconda3-py38_4.9.2-Linux-x86_64.sh
#验证:重启终端(必须),运行下方命令,显示版本号则安装成功
conda --version
1.2更换清华源
#在用户目录(/home/xxx)下新建.condarc文件
touch .condarc
#用vim打开.condarc文件,写入下方内容保存后退出
channels:
- defaults
show_channel_urls: true
channel_alias: https://mirrors.tuna.tsinghua.edu.cn/anaconda
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
#清除索引缓存
conda clean -i
#配置完毕,执行以下命令查看是否已经换源,可以看到已经更换为清华源了
conda config --show
1.3在服务器中安装CUDA
踩坑记录:在此之前,我一直尝试的是在虚拟环境中使用conda install进行安装cudatoolkit,如果你使用的cuda版本过高,则无法使用清华源(最高11.8.0),初次尝试使用的cudatoolkit-11.3.1,安装完成后,使用nvcc -v不能显示cuda版本,使用conda list不能显示cudatoolkit,使用conda list cuda可以显示,查阅博客,没有找到答案。于是忽略此条继续配置,根绝conda search cudnn查看对应版本cudnn,随之conda install cudnn=8.2.1安装完成。随后使用conda install pytorch1.12.1 torchvision0.13.1 torchaudio==0.12.1 cudatoolkit=11.3 -c pytorch安装成功,随后进行相关python代码验证,均失败,conda list发现没有torch。于是忽略此条继续配置,随后根据requirements.txt进行pip,出现大量不兼容情况,主要是torch版本引起的,版本过高,因为官方文档使用的是cuda12.1对应的torch>=2.1.2。我降低torch版本,使其兼容。此时再次进行python代码验证均失败。
解决方法: 采用在base环境中安装cuda,配置环境变量,即可使用nvcc。在虚拟环境中继续后续的配置,我在base环境中安装了cuda11.3和cuda12.1,wenet代码均可运行。使用cuda11.3,安装conda install pytorch1.12.1 torchvision0.13.1 torchaudio0.12.1 cudatoolkit=11.3 -c pytorch,随后使用requirements.txt进行pip时,注意torch2.1.2和torchaudio==2.1.2版本即可(已老实,求放过,这个方法我个人认为不是很完美,但是它让我的代码成功运行了起来)
本文采用wenet官方文档推荐的CUDA12.1
其他版本的CUDA配置方法可查看:CUDA and cuDNN — k2 1.24.4 documentation (k2-fsa.github.io)
#下载CUDA12.1 官方地址:https://developer.nvidia.com/cuda-toolkit-archive
wget https://developer.download.nvidia.com/compute/cuda/12.2.1/local_installers/cuda_12.2.1_535.86.10_linux.run
#安装,此处采用静默模式安装,交互模式可参考:https://blog.csdn.net/qq_46699596/article/details/134552021
sh ./cuda_12.1.1_530.30.02_linux.run \
--silent \
--toolkit \
--installpath=/s6home/lnj524/module/cuda/cuda-12.1 \
--no-opengl-libs \
--no-drm \
--no-man-page
#./cuda_12.1.1_530.30.02_linux.run:CUDA 12.1.1 的安装程序文件。
#--silent:以静默模式安装,不需要用户交互。
#--toolkit:只安装 CUDA Toolkit,而不安装其他组件(如驱动程序等)。
#--installpath=/home/xxx/module/cuda/cuda-12.1:指定安装路径。
#--no-opengl-libs:不安装 OpenGL 库。
#--no-drm:不安装 Direct Rendering Manager(DRM)模块。DRM 模块用于图形硬件加速的直接渲染。
#--no-man-page:不安装手册页。
#添加环境变量
vim ~/.bashrc
#将下方内容写入.bashrc
export CUDA_HOME=/s6home/lnj524/module/cuda/cuda-12.1
export PATH=$CUDA_HOME/bin:$PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$CUDA_HOME/extras/CUPTI/lib64:$LD_LIBRARY_PATH
export CUDAToolkit_ROOT_DIR=$CUDA_HOME
export CUDAToolkit_ROOT=$CUDA_HOME
export CUDA_TOOLKIT_ROOT_DIR=$CUDA_HOME
export CUDA_TOOLKIT_ROOT=$CUDA_HOME
export CUDA_BIN_PATH=$CUDA_HOME
export CUDA_PATH=$CUDA_HOME
export CUDA_INC_PATH=$CUDA_HOME/targets/x86_64-linux
export CFLAGS=-I$CUDA_HOME/targets/x86_64-linux/include:$CFLAGS
export CUDAToolkit_TARGET_DIR=$CUDA_HOME/targets/x86_64-linux
#更新用户环境
source ~/.bashrc
#验证
nvcc -V
#到此cuda安装完成
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Mon_Apr__3_17:16:06_PDT_2023
Cuda compilation tools, release 12.1, V12.1.105
Build cuda_12.1.r12.1/compiler.32688072_0
1.3创建虚拟环境
#创建虚拟环境
conda create -n wenet2.0 python=3.10
#启动虚拟环境
conda activate wenet2.0
1.4在虚拟环境中完成后续安装
#安装conda-forge::sox
conda install conda-forge::sox
#查看cuda对应的cudnn版本
conda search cudnn
#下载cudnn
conda install cudann=8.9.2.26
#配置pip清华源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
#查看pip源
pip config list
global.index-url='https://pypi.tuna.tsinghua.edu.cn/simple'
#安装torch和torchaudio,清华源中没有找个包,只能从官网下载,静静等待。
pip install torch==2.2.2+cu121 torchaudio==2.2.2+cu121 -f https://download.pytorch.org/whl/torch_stable.html
#根据requirements.txt安装其他其他依赖
pip install -r requirements.txt
#完成
1.5aishell
模型训练
cd /s6home/lnj524/module/wenet/examples/aishell/s0
chmod +x run.sh
./run.sh --stage -1 #采用默认配置从数据集下载到完成模型训练。
./run.sh --stage 4 --stop_stage 4 #执行模型训练
2Wenet文件分析
2.1run.sh
-
下载数据(阶段 -1)此步骤将AIShell-1数据集下载到本地路径。这可能需要几个小时。如果已经下载了数据,请在
run.sh
脚本中调整$data
变量,并从阶段0开始。请确保为$data
设置绝对路径,例如/home/username/asr-data/aishell/
。 -
准备训练数据(阶段 0)将原始的AIShell-1数据组织成两个文件:
-
wav.scp
:每行包含两列,分别是wav_id
和wav_path
。 -
text
:每行包含两列,分别是wav_id
和text_label
。
-
-
提取可选的CMVN特征(阶段 1)使用原始的WAV文件作为输入。标准化文本标签,去除空格。使用
tools/compute_cmvn_stats.py
提取全局倒谱均值和方差归一化(CMVN)统计信息。 -
生成标签令牌字典(阶段 2)创建标签令牌(AIShell-1中的字符)与整数索引之间的映射。字典包括特殊令牌,如
<blank>
(用于CTC)、<unk>
(未知令牌)和<sos/eos>
(开始/结束语音)。 -
准备数据的所需格式(阶段 3)将数据转换为模型训练所需的格式。对于小型数据集,使用原始格式raw;对于大型数据集,使用shard,将数据分片以提高读取和训练速度。
-
模型训练(阶段 4)配置并启动模型训练。根据配置,选择使用DeepSpeed或Torch DDP进行分布式训练。这一步包含了设置分布式训练的各种参数,如节点数、每个节点的进程数、训练配置文件等。
-
模型评估(阶段 5)使用训练好的模型进行推理和评估,计算WER(Word Error Rate)。如果启用了模型平均,会首先对多个检查点进行平均以得到最终的评估模型。
-
导出模型(阶段 6)导出训练好的模型,生成可用于推理的模型文件。这一步通常包括导出标准模型和量化模型,以便在不同的设备和环境中进行高效推理。
-
语言模型准备和解码(阶段 7)准备语言模型和解码工具,进行语言模型的训练和解码。这包括生成字典、训练语言模型、编译FST(Finite State Transducer)图并进行解码测试。
-
使用HLG图进行解码(阶段 8)使用HLG(HMM-Lexicon-Grammar)图进行解码,以进一步提升模型的解码性能。这一步需要预先准备HLG图并进行推理和评估。
-
使用LF-MMI进行训练(阶段 9)使用LF-MMI(Lattice-Free Maximum Mutual Information)进行模型训练,以进一步优化模型性能。这一步包括准备LF-MMI所需的FST图,并在之前的基础上进行进一步的模型训练和评估。
#!/bin/bash
# Copyright 2019 Mobvoi Inc. All Rights Reserved.
. ./path.sh || exit 1;
# 自动检测 GPU 的数量
if command -v nvidia-smi &> /dev/null; then # 检查 nvidia-smi 是否存在
num_gpus=$(nvidia-smi -L | wc -l) # 获取 GPU 的数量
gpu_list=$(seq -s, 0 $((num_gpus-1))) # 生成 GPU 列表,例如 "0,1,2,3"
else
num_gpus=-1 # 如果没有检测到 GPU,则设置 num_gpus 为 -1
gpu_list="-1" # 设置默认 GPU 列表为 "-1"
fi
# 您还可以手动指定 CUDA_VISIBLE_DEVICES
# 如果您不想使用所有可用的 GPU 资源,请手动设置 CUDA_VISIBLE_DEVICES
# export CUDA_VISIBLE_DEVICES="${gpu_list}"
export CUDA_VISIBLE_DEVICES="0,7" # 手动设置使用 GPU 0 和 7
echo "CUDA_VISIBLE_DEVICES is ${CUDA_VISIBLE_DEVICES}"
stage=0 # 从阶段0开始,如果需要从数据准备开始
stop_stage=5 # 停止阶段设置为5
# 如果进行多机训练,您需要更改以下两个参数,
# 请参阅 https://pytorch.org/docs/stable/elastic/run.html
HOST_NODE_ADDR="localhost:0" # 主节点地址
num_nodes=1 # 节点数量
job_id=2023 # 作业ID
# AIShell 数据集位置,请将此路径更改为您自己的路径
# 请确保使用绝对路径,不要使用相对路径
data=/s6home/lnj524/module/data/opensource_data/aishell
data_url=www.openslr.org/resources/33 # 数据集下载地址
nj=16 # 并行作业数量
dict=data/dict/lang_char.txt # 字典文件路径
# 数据类型可以是 `raw` 或 `shard`。通常,raw 用于小型数据集,
# shard 用于超过 1k 小时的大型数据集,shard 在读取数据和训练时更快。
data_type=raw # 数据类型设置为 raw
num_utts_per_shard=1000 # 每个 shard 包含的 utt 数量
train_set=train # 训练集名称
# 可选的训练配置文件
# 1. conf/train_transformer.yaml: 标准 transformer
# 2. conf/train_conformer.yaml: 标准 conformer
# 3. conf/train_unified_conformer.yaml: 统一动态块因果 conformer
# 4. conf/train_unified_transformer.yaml: 统一动态块 transformer
# 5. conf/train_u2++_conformer.yaml: U2++ conformer
# 6. conf/train_u2++_transformer.yaml: U2++ transformer
# 7. conf/train_u2++_conformer.yaml: U2++ lite conformer,必须加载一个训练好的模型,并冻结编码器模块,否则会出现自动梯度错误
train_config=conf/train_conformer.yaml # 选择训练配置文件
dir=exp/conformer # 模型保存目录
tensorboard_dir=tensorboard # Tensorboard 日志目录
checkpoint= # 检查点文件
num_workers=8 # 数据加载线程数
prefetch=10 # 数据预取数量
# 使用 average_checkpoint 将获得更好的结果
average_checkpoint=true # 启用检查点平均
decode_checkpoint=$dir/final.pt # 解码使用的检查点
average_num=30 # 平均的检查点数量
decode_modes="ctc_greedy_search ctc_prefix_beam_search attention attention_rescoring" # 解码模式
train_engine=torch_ddp # 训练引擎
deepspeed_config=conf/ds_stage2.json # DeepSpeed 配置文件
deepspeed_save_states="model_only" # DeepSpeed 保存状态
. tools/parse_options.sh || exit 1; # 解析脚本选项
# 阶段 -1:数据下载
if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then
echo "stage -1: Data Download"
local/download_and_untar.sh ${data} ${data_url} data_aishell # 下载并解压数据集
local/download_and_untar.sh ${data} ${data_url} resource_aishell # 下载并解压资源文件
fi
# 阶段 0:数据准备
if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then
local/aishell_data_prep.sh ${data}/data_aishell/wav \
${data}/data_aishell/transcript # 准备数据
fi
# 阶段 1:文本标签处理和计算 CMVN 统计信息
if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then
# 删除汉语数据集中文本标签之间的空格
for x in train dev test; do
cp data/${x}/text data/${x}/text.org # 备份原始文本标签文件
paste -d " " <(cut -f 1 -d" " data/${x}/text.org) \
<(cut -f 2- -d" " data/${x}/text.org | tr -d " ") \
> data/${x}/text # 删除空格后生成新文本标签文件
rm data/${x}/text.org # 删除备份文件
done
tools/compute_cmvn_stats.py --num_workers 16 --train_config $train_config \
--in_scp data/${train_set}/wav.scp \
--out_cmvn data/$train_set/global_cmvn # 计算 CMVN 统计信息
fi
# 阶段 2:生成字典文件
if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then
echo "Make a dictionary"
mkdir -p $(dirname $dict) # 创建字典目录
echo "<blank> 0" > ${dict} # 为 CTC 生成 <blank> 标签
echo "<unk> 1" >> ${dict} # 为未知标签生成 <unk>
echo "<sos/eos> 2" >> $dict # 为开始/结束生成 <sos/eos>
tools/text2token.py -s 1 -n 1 data/train/text | cut -f 2- -d" " \
| tr " " "\n" | sort | uniq | grep -a -v -e '^\s*$' | \
awk '{print $0 " " NR+2}' >> ${dict} # 生成标签令牌与整数索引的映射
fi
# 阶段 3:准备数据的所需格式
if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then
echo "Prepare data, prepare required format"
for x in dev test ${train_set}; do
if [ $data_type == "shard" ]; then
tools/make_shard_list.py --num_utts_per_shard $num_utts_per_shard \
--num_threads 16 data/$x/wav.scp data/$x/text \
$(realpath data/$x/shards) data/$x/data.list # 生成 shard 格式的数据列表
else
tools/make_raw_list.py data/$x/wav.scp data/$x/text \
data/$x/data.list # 生成 raw 格式的数据列表
fi
done
fi
# 阶段 4:模型训练
if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then
mkdir -p $dir # 创建模型保存目录
num_gpus=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') # 计算使用的 GPU 数量
# 如果可用,使用 "nccl",否则使用 "gloo"
dist_backend="nccl"
# train.py 将 $train_config 重写为 $dir/train.yaml,包括模型输入和输出维度
# $dir/train.yaml 将用于推理和导出。
if [ ${train_engine} == "deepspeed" ]; then
echo "$0: using deepspeed"
else
echo "$0: using torch ddp"
fi
# 注:torchrun 可以同时启动 ddp 和 deepspeed
# 为了统一单节点和多节点训练,我们添加了所有相关参数。
# 您应该更改 `nnodes` 和 `rdzv_endpoint` 以进行多节点训练,
# 参见 https://pytorch.org/docs/stable/elastic/run.html#usage
# 和 https://github.com/wenet-e2e/wenet/pull/2055#issuecomment-1766055406
# `rdzv_id` - 用户定义的 ID,用于唯一标识作业的工作组。
# `rdzv_endpoint` - rendezvous 后端端点,通常形式为 <host>:<port>。
# 注:在多节点训练中,一些集群需要在训练前设置特殊的 NCCL 变量。
# 例如:`NCCL_IB_DISABLE=1` + `NCCL_SOCKET_IFNAME=enp` + `NCCL_DEBUG=INFO`
# 如果没有 NCCL_IB_DISABLE=1
# 运行时错误:NCCL 错误:内部错误,NCCL 版本 xxx
# 如果没有 NCCL_SOCKET_IFNAME=enp (IFNAME 可通过 `ifconfig` 获取)
# 运行时错误:服务器套接字无法监听任何本地网络地址。服务器套接字无法绑定到 [::]:xxx
# 参考:https://github.com/google/jax/issues/13559#issuecomment-1343573764
echo "$0: num_nodes is $num_nodes, proc_per_node is $num_gpus"
torchrun --nnodes=$num_nodes --nproc_per_node=$num_gpus \
--rdzv_id=$job_id --rdzv_backend="c10d" --rdzv_endpoint=$HOST_NODE_ADDR \
wenet/bin/train.py \
--train_engine ${train_engine} \
--config $train_config \
--data_type $data_type \
--train_data data/$train_set/data.list \
--cv_data data/dev/data.list \
${checkpoint:+--checkpoint $checkpoint} \
--model_dir $dir \
--tensorboard_dir ${tensorboard_dir} \
--ddp.dist_backend $dist_backend \
--num_workers ${num_workers} \
--prefetch ${prefetch} \
--pin_memory \
--deepspeed_config ${deepspeed_config} \
--deepspeed.save_states ${deepspeed_save_states}
fi
# 阶段 5:模型测试
if [ ${stage} -le 5 ] && [ ${stop_stage} -ge 5 ]; then
# 测试模型,请通过 --checkpoint 指定要测试的模型
if [ ${average_checkpoint} == true ]; then
decode_checkpoint=$dir/avg_${average_num}.pt
echo "do model average and final checkpoint is $decode_checkpoint"
python wenet/bin/average_model.py \
--dst_model $decode_checkpoint \
--src_path $dir \
--num ${average_num} \
--val_best # 进行模型检查点平均
fi
# 请为统一流式和非流式模型指定 decoding_chunk_size。默认值为 -1,表示全块非流式推理。
decoding_chunk_size=
ctc_weight=0.3
reverse_weight=0.5
python wenet/bin/recognize.py --gpu 0 \
--modes $decode_modes \
--config $dir/train.yaml \
--data_type $data_type \
--test_data data/test/data.list \
--checkpoint $decode_checkpoint \
--beam_size 10 \
--batch_size 32 \
--blank_penalty 0.0 \
--ctc_weight $ctc_weight \
--reverse_weight $reverse_weight \
--result_dir $dir \
${decoding_chunk_size:+--decoding_chunk_size $decoding_chunk_size}
for mode in ${decode_modes}; do
python tools/compute-wer.py --char=1 --v=1 \
data/test/text $dir/$mode/text > $dir/$mode/wer # 计算词错误率(WER)
done
fi
# 阶段 6:导出模型
if [ ${stage} -le 6 ] && [ ${stop_stage} -ge 6 ]; then
# 导出最佳模型
python wenet/bin/export_jit.py \
--config $dir/train.yaml \
--checkpoint $dir/avg_${average_num}.pt \
--output_file $dir/final.zip \
--output_quant_file $dir/final_quant.zip # 导出量化模型
fi
# 可选,您可以添加语言模型(LM)并在运行时测试。
if [ ${stage} -le 7 ] && [ ${stop_stage} -ge 7 ]; then
# 7.1 准备字典
unit_file=$dict
mkdir -p data/local/dict
cp $unit_file data/local/dict/units.txt
tools/fst/prepare_dict.py $unit_file ${data}/resource_aishell/lexicon.txt \
data/local/dict/lexicon.txt # 准备词典
# 7.2 训练语言模型(LM)
lm=data/local/lm
mkdir -p $lm
tools/filter_scp.pl data/train/text \
$data/data_aishell/transcript/aishell_transcript_v0.8.txt > $lm/text
local/aishell_train_lms.sh # 训练语言模型
# 7.3 构建解码 TLG 图
tools/fst/compile_lexicon_token_fst.sh \
data/local/dict data/local/tmp data/local/lang
tools/fst/make_tlg.sh data/local/lm data/local/lang data/lang_test || exit 1;
# 7.4 运行时解码
chunk_size=-1
./tools/decode.sh --nj 16 \
--beam 15.0 --lattice_beam 7.5 --max_active 7000 \
--blank_skip_thresh 0.98 --ctc_weight 0.5 --rescoring_weight 1.0 \
--chunk_size $chunk_size \
--fst_path data/lang_test/TLG.fst \
--dict_path data/lang_test/words.txt \
data/test/wav.scp data/test/text $dir/final.zip \
data/lang_test/units.txt $dir/lm_with_runtime # 运行时解码
# 请查看 $dir/lm_with_runtime 中的 WER
fi
# 可选,您可以使用 k2 HLG 进行解码
if [ ${stage} -le 8 ] && [ ${stop_stage} -ge 8 ]; then
if [ ! -f data/local/lm/lm.arpa ]; then
echo "Please run prepare dict and train lm in Stage 7" || exit 1;
fi
# 8.1 构建解码 HLG 图
required="data/local/hlg/HLG.pt data/local/hlg/words.txt"
for f in $required; do
if [ ! -f $f ]; then
tools/k2/make_hlg.sh data/local/dict/ data/local/lm/ data/local/hlg
break
fi
done
# 8.2 使用 HLG 进行解码
decoding_chunk_size=
lm_scale=0.7
decoder_scale=0.1
r_decoder_scale=0.7
decode_modes="hlg_onebest hlg_rescore"
python wenet/bin/recognize.py --gpu 0 \
--modes $decode_modes \
--config $dir/train.yaml \
--data_type $data_type \
--test_data data/test/data.list \
--checkpoint $decode_checkpoint \
--beam_size 10 \
--batch_size 16 \
--blank_penalty 0.0 \
--dict $dict \
--word data/local/hlg/words.txt \
--hlg data/local/hlg/HLG.pt \
--lm_scale $lm_scale \
--decoder_scale $decoder_scale \
--r_decoder_scale $r_decoder_scale \
--result_dir $dir \
${decoding_chunk_size:+--decoding_chunk_size $decoding_chunk_size}
for mode in ${decode_modes}; do
python tools/compute-wer.py --char=1 --v=1 \
data/test/text $dir/$mode/text > $dir/$mode/wer # 计算词错误率(WER)
done
fi
# 可选,您可以使用 k2 进行 LF-MMI 训练
# 基于 20210601_u2++_conformer_exp/final.pt,我们训练 50 轮,学习率为 1e-5
# 平均 10 个最佳模型,使用 HLG 解码,达到 4.11 的 CER
# 实际上,通过调整 lm_scale/decoder_scale/r_decoder_scale,可以达到更低的 CER
if [ ${stage} -le 9 ] && [ ${stop_stage} -ge 9 ]; then
# 9.1 构建 LF-MMI 训练的二元 FST
tools/k2/prepare_mmi.sh data/train/ data/dev data/local/lfmmi
# 9.2 从阶段 4 开始运行 LF-MMI 训练,修改 train.yaml 中的以下参数
# model: k2_model
# model_conf:
# lfmmi_dir data/local/lfmmi
# 9.3 从阶段 8.2 运行 HLG 解码
fi
2.2训练配置文件train_conformer.yaml
# 网络架构
# 编码器相关设置
encoder: conformer
encoder_conf:
output_size: 256 # 注意力机制的输出维度
attention_heads: 4 # 注意力头的数量
linear_units: 2048 # 位置前馈网络的隐藏层单元数
num_blocks: 12 # 编码器块的数量
dropout_rate: 0.1 # Dropout 概率,用于防止过拟合
positional_dropout_rate: 0.1 # 位置编码的 Dropout 概率
attention_dropout_rate: 0.0 # 注意力机制的 Dropout 概率
input_layer: conv2d # 编码器的输入类型,可以选择 conv2d, conv2d6 和 conv2d8
normalize_before: true # 是否在每个子层之前应用层归一化
cnn_module_kernel: 15 # CNN 模块的卷积核大小
use_cnn_module: True # 是否使用 CNN 模块
activation_type: 'swish' # 激活函数类型
pos_enc_layer_type: 'rel_pos' # 位置编码层的类型
selfattention_layer_type: 'rel_selfattn' # 自注意力层的类型
# 解码器相关设置
decoder: transformer
decoder_conf:
attention_heads: 4 # 注意力头的数量
linear_units: 2048 # 位置前馈网络的隐藏层单元数
num_blocks: 6 # 解码器块的数量
dropout_rate: 0.1 # Dropout 概率,用于防止过拟合
positional_dropout_rate: 0.1 # 位置编码的 Dropout 概率
self_attention_dropout_rate: 0.0 # 自注意力机制的 Dropout 概率
src_attention_dropout_rate: 0.0 # 来源注意力机制的 Dropout 概率
# 分词器设置
tokenizer: char
tokenizer_conf:
symbol_table_path: 'data/dict/lang_char.txt' # 符号表路径
split_with_space: false # 是否以空格分割
bpe_path: null # BPE(Byte-Pair Encoding)模型路径
non_lang_syms_path: null # 非语言符号路径
is_multilingual: false # 是否支持多语言
num_languages: 1 # 语言数量
special_tokens: # 特殊符号
<blank>: 0 # 空白符
<unk>: 1 # 未知符号
<sos>: 2 # 句子开始符
<eos>: 2 # 句子结束符
# CTC(连接时间分类)相关设置
ctc: ctc
ctc_conf:
ctc_blank_id: 0 # CTC 空白符的 ID
# CMVN(倒谱均值方差归一化)设置
cmvn: global_cmvn
cmvn_conf:
cmvn_file: 'data/train/global_cmvn' # CMVN 文件路径
is_json_cmvn: true # CMVN 文件是否为 JSON 格式
# 混合 CTC/注意力模型设置
model: asr_model
model_conf:
ctc_weight: 0.3 # CTC 损失的权重
lsm_weight: 0.1 # 标签平滑(Label Smoothing)权重
length_normalized_loss: false # 是否使用长度归一化的损失
# 数据集设置
dataset: asr
dataset_conf:
filter_conf: # 数据过滤配置
max_length: 40960 # 数据最大长度
min_length: 0 # 数据最小长度
token_max_length: 200 # 令牌最大长度
token_min_length: 1 # 令牌最小长度
resample_conf: # 重采样配置
resample_rate: 16000 # 重采样率
speed_perturb: true # 是否使用语速扰动
fbank_conf: # 过滤器组配置
num_mel_bins: 80 # 梅尔频率倒谱系数(MFCC)数量
frame_shift: 10 # 帧移(毫秒)
frame_length: 25 # 帧长(毫秒)
dither: 0.1 # 添加噪声的强度
spec_aug: true # 是否使用频谱增强
spec_aug_conf: # 频谱增强配置
num_t_mask: 2 # 时间掩码数量
num_f_mask: 2 # 频率掩码数量
max_t: 50 # 最大时间掩码宽度
max_f: 10 # 最大频率掩码宽度
shuffle: true # 是否打乱数据
shuffle_conf: # 数据打乱配置
shuffle_size: 1500 # 打乱缓冲区大小
sort: true # 是否排序数据
sort_conf: # 数据排序配置
sort_size: 500 # 排序缓冲区大小,应该小于 shuffle_size
batch_conf: # 批处理配置
batch_type: 'static' # 批处理类型,可选 static 或 dynamic
batch_size: 16 # 批处理大小
grad_clip: 5 # 梯度剪裁阈值
accum_grad: 4 # 梯度累加步数
max_epoch: 240 # 最大训练轮数
log_interval: 100 # 日志间隔
optim: adam # 优化器设置
optim_conf:
lr: 0.002 # 学习率
# 学习率调度器设置
scheduler: warmuplr # 需要 pytorch v1.1.0 及以上版本
scheduler_conf:
warmup_steps: 25000 # 预热步数
3完整实践
3.1 逐步运行
cd /s6home/lnj524/module/wenet/examples/aishell/s0 # 进入文件夹
./run.sh --stage -1 --stop_stage -1 # 下载数据集到指定位置(run.sh中的data)
./run.sh --stage 0 --stop_stage 0 # AIShell-1数据组织成两个文件:wav.scp和text(位于s0/data/目录下)
# dev为训练过程中的交叉验证,local为中间结果可忽略,test为测试,train为训练
./run.sh --stage 1 --stop_stage 1 # 标准化文本标签(可查看第0步的文件进行对比,CMVN结果位于s0/data/train/global_cmvn)
./run.sh --stage 2 --stop_stage 2 # 创建字典(位于s0/data/dict/lang_char.txt)
./run.sh --stage 3 --stop_stage 3 # 将数据转换为模型训练所需的格式(默认data_type=raw,结果位于s0/data/train/data.list)
# ./run.sh --stage 3 --stop_stage 3 --data_type shard(结果位于s0/data/train/data.list和s0/data/train/shard)
./run.sh --stage 4 --stop_stage 4 # 训练(s0/conf/train_conformer.yaml中配置训练参数)
# 运行结果位于run.sh中的dir=exp/conformer目录下
#运行先注意使用的GPU数量,在run.sh中更改
./run.sh --stage 5 --stop_stage 5 # 使用训练好的模型进行推理和评估(模型平均配置位于run.sh的average_num=xxx)
# 此步骤会产生wenet/examples/aishell/s0/tensorboard,用于可视化展示(服务器用不了,转到本地主机运行,需要配置相应环境)
# 转入本机后可运行:tensorboard --logdir tensorboard/conformer/ --port 12598 --bind_all
# 预测结果位于/s0/exp/conformer/ctc_greedy_search ctc_prefix_beam_search attention attention_rescoring
./run.sh --stage 6 --stop_stage 6 # 导出标准模型和量化模型(位于s0/exp/conformer/final.zip final_quant.zip)
3.2训练
3.3预测