首页 / 资讯中心 / 文章详情

基于 wenet 的 VKW 挑战赛端到端语音关键词唤醒(KWS)方案:Conformer 基线配置、训练流程与评测解析

基于 wenet 的 VKW 挑战赛端到端语音关键词唤醒(KWS)方案:Conformer 基线配置、训练流程与评测解析 ★ FEATURED ARTICLE
人工智能语音深度学习预训练模型推理服务【免费下载链接】wenetProduction First and Production Ready End-to-End Speech Recognition Toolkit项目地址https://gitcode.com/gh_mirrors/we/wenet点击查看免费下载本文以 wenet 仓库中的 VKWVoice Keyword Wakeup语音关键词唤醒挑战赛基线为例系统讲解如何用 Conformer 双向编码器 Bi-Transformer 双向解码器搭建端到端关键词唤醒系统。读者将掌握该基线的完整模型配置含 12 层 Conformer、双向解码器、CTC/Attention 混合训练、从数据准备到 F4DE 打分的全流程脚本用法、5 小时微调提点技巧以及 KWS 结果生成背后的 CTC 对齐时间戳原理。一、任务背景VKW 挑战赛与端到端 KWSVKWVoice Keyword Wakeup挑战赛聚焦语音关键词唤醒任务——从连续语音流中检测预先指定的关键词如唤醒词、热词是否出现及其出现位置。仓库中的对应基线位于 examples/vkw2021/s0其目标不是泛化语音识别而是精准定位关键词出现的时间段评测指标因此采用信息检索领域的 Precision / Recall / F1 与 ATWVActual Term Weighted Value。该基线对应三个评测场景从 run.sh 与 run_finetune_5h.sh 中可以看到lgv以TV1开头的评测音频liv以sph_live开头的直播流音频stv以sph_video开头的视频流音频。三个场景的 5 小时开发dev数据会被合并为combine_dev训练/评测集另有三场景各 5 小时的combine_finetune_5h微调集合计 15 小时用以进一步适配各场景的声学分布。二、模型结构双向 Conformer 编码器 Bi-Transformer 解码器原文档给出的基线是Conformer without speed perturb and lm即不启用变速扰动、不使用语言模型纯粹依靠端到端声学模型完成关键词检索。核心配置参数如下configtrain_vkw_bidirect_12conformer_hs2048_output256_att4_conv2d_char.yamlbeam10GPU 数量8平均模型数量5average_numctc weight用于 attention rescoring 解码0.5配置文件名本身就是超参清单bidirect_12conformer_hs2048_output256_att4_conv2d_char表示双向解码器、12 层 Conformer、FFN 隐层 2048、注意力输出维度 256、4 个注意力头、conv2d 输入下采样、字符char建模单元。2.1 编码器12 层因果 Conformer# encoder related encoder: conformer encoder_conf: output_size: 256 # dimension of attention attention_heads: 4 linear_units: 2048 # the number of units of position-wise feed forward num_blocks: 12 # the number of encoder blocks dropout_rate: 0.1 positional_dropout_rate: 0.1 attention_dropout_rate: 0.1 input_layer: conv2d # encoder input type, you can chose conv2d, conv2d6 and conv2d8 normalize_before: true cnn_module_kernel: 8 use_cnn_module: True activation_type: swish pos_enc_layer_type: rel_pos selfattention_layer_type: rel_selfattn causal: true use_dynamic_chunk: false cnn_module_norm: layer_norm # using nn.LayerNorm makes model converge faster use_dynamic_left_chunk: false要点解析causal: true配合use_dynamic_chunk: false、use_dynamic_left_chunk: false编码器按因果模式前向为流式解码预留基础pos_enc_layer_type: rel_pos与selfattention_layer_type: rel_selfattn使用相对位置编码与相对自注意力对较长序列更稳健input_layer: conv2d采用 2 维卷积子采样对应 wenet 的Conv2dSubsampling子采样因子通常为 4get_subsample会据此换算帧时间戳见 vkw_kws_results.pycnn_module_norm: layer_norm使模型收敛更快。2.2 解码器双向 Bi-Transformer# decoder related decoder: bitransformer decoder_conf: attention_heads: 4 linear_units: 2048 num_blocks: 3 r_num_blocks: 3 dropout_rate: 0.1 positional_dropout_rate: 0.1 self_attention_dropout_rate: 0.1 src_attention_dropout_rate: 0.1bitransformer在 wenet 中由 BiTransformerDecoder 实现内部同时维护左向解码器left_decodernum_blocks 层与右向解码器right_decoderr_num_blocks 层二者共享词嵌入。右向解码器通过对目标序列逆序建模在解码时提供从右往左的互补打分信息。2.3 混合 CTC/Attention 模型配置# hybrid CTC/attention model_conf: ctc_weight: 0.3 lsm_weight: 0.1 # label smoothing option length_normalized_loss: false reverse_weight: 0.3ctc_weight: 0.3训练损失中 CTC 分支的权重loss ctc_weight * loss_ctc (1 - ctc_weight) * loss_att对应 asr_model.py 的实现reverse_weight: 0.3右向解码器的权重注意力损失按loss_att * (1 - reverse_weight) r_loss_att * reverse_weight加权求和asr_model.pylsm_weight: 0.1标签平滑系数。值得注意的是训练时 ctc_weight 为 0.3而解码时attention rescoring使用的 ctc weight 是 0.5。二者作用位置不同——训练权重决定 CTC 与注意力两个分支的监督强度解码权重则决定 CTC 前缀束搜索的 n-best 候选与注意力解码器重打分之间的融合比例详见 search.py 中attention_rescoring的score ctc_scores[i] * ctc_weight。2.4 数据集与训练超参# use raw_wav or kaldi feature raw_wav: false 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 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 # sort_size should be less than shuffle_size batch_conf: batch_type: static # static or dynamic batch_size: 16 grad_clip: 5 accum_grad: 1 max_epoch: 100 log_interval: 400 optim: adam optim_conf: lr: 0.001 scheduler: warmuplr # pytorch v1.1.0 required scheduler_conf: warmup_steps: 25000输入采用 80 维 fbank16 kHz 重采样、10 ms 帧移、25 ms 帧长、dither 0.1训练中开启speed_perturb变速扰动与 SpecAugment2 个时间掩码、2 个频率掩码批大小静态 16shuffle_size 1500 与 sort_size 500 的搭配需保持sort_size 小于 shuffle_size以兼顾效率与批次内长度均衡优化器 Adamlr 0.001 warmuplr 调度器warmup_steps 25000最大训练 100 轮。该配置文件即为 run_finetune_5h.sh 中微调所用 combine_finetune_5h 配置 的同一套结构微调时仅在数据侧替换为combine_finetune_5h。三、完整训练流水线run.sh 各 stage 详解run.sh 以 stage 机制串联数据准备到评测的完整链路stop_stage默认为 0跑完全部流程需将stop_stage设为 6。stage -1数据准备调用 vkw_data_prep.sh 下载并解压 VKW 官方数据vkw_v1.1.zip校验data/train/text是否存在。数据需置于data/vkw目录下包含label/lab_{lgv,liv,stv}三场景标签、keyword/kwlist关键词列表与score评测元数据ecf、utter_map、rttm 等。stage 0合并多场景数据并清洗文本对 lgv/liv/stv 三场景的dev_5h数据将原始wav.scp改名保留为wav_ori.scp再用cut -d -f 1,4提取首列utt id与第 4 列wav 路径生成新的wav.scp合并三场景的text/wav.scp/segments得到combine_dev开发集与combine_train对应的combine_*目录对普通话数据去除文本标签中的空格paste -d (cut -f 1 -d text.org) (cut -f 2- -d text.org | tr -d ) text将逐字空格标注压缩为连续中文字符串。stage 1分段 wav 与 CMVNpython tools/segment.py --segments $data/$x/segments \ --input $data/$x/wav.scp \ --output $data/$x/segmented_wav.scp tools/compute_cmvn_stats.py --num_workers 12 --train_config $train_config \ --in_scp $data/${train_set}/segmented_wav.scp \ --out_cmvn $data/$train_set/global_cmvn用tools/segment.py按 segments 切分长音频生成分段 wav 列表并用训练集计算全局 CMVN训练时 Fbank 在数据管线内实时抽取。stage 2生成字符字典echo blank 0 ${dict} # 0 用于 CTC blank echo unk 1 ${dict} # unk 必须为 1 tools/text2token.py -s 1 -n 1 $data/${train_set}/text | cut -f 2- -d | \ tr \n | sort | uniq | grep -a -v -e ^\s*$ | grep -P [\p{Han}] \ | awk {print $0 NR1} ${dict} echo sos/eos $num_token ${dict}以汉字为建模单元grep -P [\p{Han}]过滤非汉字字符生成data/dict/lang_char.txt。stage 3生成 data.listtools/make_raw_list.py --segments $data/$x/segments \ $data/$x/wav.scp $data/$x/text $data/$x/data.list生成训练/开发集的 raw 格式数据清单供 wenet/bin/train.py 读取。stage 4DDP 分布式训练自动探测 GPU 数量并设置CUDA_VISIBLE_DEVICES然后通过torchrun启动多卡训练torchrun --nnodes$num_nodes --nproc_per_node$num_gpus --rdzv_endpoint$HOST_NODE_ADDR \ --rdzv_id2023 --rdzv_backendc10d \ wenet/bin/train.py \ --train_engine ${train_engine} \ --config $train_config \ --data_type $data_type \ --symbol_table $dict \ --train_data $data/$train_set/data.list \ --cv_data $data/${dev_set}/data.list \ ${checkpoint:--checkpoint $checkpoint} \ --model_dir $dir \ --ddp.dist_backend $dist_backend \ --num_workers 4 \ $cmvn_opts \ --pin_memory \ --deepspeed_config ${deepspeed_config} \ --deepspeed.save_states ${deepspeed_save_states}训练采用 torch DDP默认train_enginetorch_ddpdist_backendnccl若开启cmvntrue则将global_cmvn复制到模型目录并传入--cmvn。train.py会把train_config连同模型输入/输出维度写入$dir/train.yaml供后续解码与导出使用。基线文档标注该任务使用8 张 GPU。stage 5模型平均、KWS 结果生成与 F4DE 打分先做 checkpoint 平均average_checkpointtrue时取val_best的average_num10个模型平均得到avg_10.pt再依次完成关键词检出与评测详见下一节。stage 6场景微调echo adding 5h finetune data for each scenario to obtain better results local/run_finetune_5h.sh调用微调脚本将各场景 5 小时数据并入训练是原文档中train finetune set结果的来源。四、KWS 结果生成与评测vkw_kws_results.py 原理关键词唤醒的评测并非直接使用 ASR 转录而是由 local/vkw_kws_results.py 完成从帧级 CTC 对齐到关键词命中断言keyword hit的转换关键词字典映射map_words2charL37-L47将kwlist中每行形如id keyword的条目拆成关键词 → 字符序列与关键词 → id两份映射编码器 CTC 前向L226-L239调用model._forward_encoder得到编码器输出再经model.ctc.log_softmax取 top-1 得到每个下采样帧的字符对齐路径padding 位置填 eos用remove_duplicates_and_blank去重去 blank 后写入ctc_results帧时间戳换算L50-L97get_frames_timestamp将 CTC 对齐切分为连续的 token 段get_labformat_frames再依据子采样因子subsample get_subsample(configs)把帧数换算为实际时间区间[begin, beginduration)关键词匹配L254-L264在字符时间戳序列上滑窗若某个关键词的字符序列恰好匹配则输出一行五元组keyword_id utt_id start_time end_time 0.0写入keyword_results。随后脚本按场景切分结果并调用官方打分工具python3 local/vkw_kws_results.py --gpu 0 \ --config $dir/train.yaml \ --data_type $data_type \ --symbol_table $dict \ --num_workers 4 \ --prefetch 32 \ --input_data $input_data \ --checkpoint $checkpoint \ --keyword_unit_dict $keywords_list \ --keyword_results $keyword_results \ --ctc_results $ctc_resultsif [ $y lgv ]; then grep TV1 $keyword_results $dir/dev_${y}/kws_results elif [ $y liv ]; then grep sph_live $keyword_results $dir/dev_${y}/kws_results elif [ $y stv ]; then grep sph_video $keyword_results $dir/dev_${y}/kws_results fi ./data/vkw/scripts/bin/results_to_score.sh \ data/vkw/score/dev_${y}/ecf \ data/vkw/label/lab_${y}/dev_5h/segments \ data/vkw/score/dev_${y}/utter_map \ $dir/dev_${y}/kws_results \ data/vkw/keyword/kwlist.xml \ data/vkw/score/dev_${y}/rttm ./data/vkw/scripts/bin/F1.sh \ $dir/dev_${y}/kws_outputs/f4de_scores_unnormalized/alignment.csv注意事项打分前需预先安装 F4DE 工具脚本中明确标注### attention: install the F4DE tool before testing脚本通过软链接scripts - data/vkw/scripts使用官方results_to_score.sh与F1.sh最终产出各场景的 Precision / Recall / F1。五、5 小时微调用少量场景数据显著提点run_finetune_5h.sh 与主脚本结构一致但训练数据替换为combine_finetune_5h三场景各 5 小时合并、共 15 小时其关键差异在于从预训练基线初始化[ ! -f exp/train_vkw_bidirect_12conformer_hs2048_output256_att4_conv2d_char_new/avg_5.pt ] \ echo Please use a pretrained model for finetuning exit 0 [ ! -f $checkpoint ] \ cp exp/train_vkw_bidirect_12conformer_hs2048_output256_att4_conv2d_char_new/avg_5.pt $checkpoint \ cp exp/train_vkw_bidirect_12conformer_hs2048_output256_att4_conv2d_char_new/0.yaml $dir/0.yaml微调前需先完成主模型训练并得到avg_5.pt对应文档中num of averaged model: 5将其复制为微调 checkpoint同时复用其0.yaml微调阶段使用dist_backendgloo、average_num10。值得注意的是微调脚本中只合并了finetune_5h场景数据xfinetune_5h并以combine_finetune为合并目录评测集合仍沿用combine_dev。六、官方基线实验结果原文档给出四组评测结果覆盖 dev/test 两套评测集与仅训练集 / 训练集微调集两种训练方案指标包含 Precision、Recall、F1 与 ATWVdev 集785 个关键词仅用 1505 小时训练集scenarioPrecisionRecallF1ATWVlgv0.92810.64200.75900.5183liv0.88860.65150.75180.6050stv0.91200.74710.82130.6256dev 集785 个关键词1505 小时训练集 15 小时微调集scenarioPrecisionRecallF1ATWVlgv0.94780.73110.82550.6352liv0.91770.83980.87700.7412stv0.93200.82070.87290.7120test 集384 个关键词仅用 1505 小时训练集scenarioPrecisionRecallF1ATWVlgv0.62620.56480.59390.5825liv0.87970.62820.73300.6061stv0.91020.72210.80530.6682test 集384 个关键词1505 小时训练集 15 小时微调集scenarioPrecisionRecallF1ATWVlgv0.64690.62760.63710.6116liv0.92780.75600.83310.6927stv0.94340.80610.86930.7275从结果中可以提炼出三个对实践有直接参考价值的结论微调带来的提升显著且普遍dev 集上三场景 F1 分别从 0.7590 / 0.7518 / 0.8213 提升到 0.8255 / 0.8770 / 0.8729Recall 提升尤为明显如 liv 从 0.6515 到 0.8398说明 15 小时场景内数据即可大幅修复漏检stv视频流始终是最容易的场景lgv 与 liv 在 test 集上召回率明显偏低存在明显的场景泛化差距关键词数量越多任务越难dev 集 785 词、test 集 384 词但 test 集未见数据整体指标仍低于同配置的 dev 集lgv 场景在 test 上 F1 仅 0.5939说明测试分布与开发分布存在差异。七、源码级原理补充attention rescoring 与双向解码理解 KWS 全流程后可以回到 wenet 源码进一步看清两个关键机制1. 解码权重如何参与重打分。ASRModel.decodeasr_model.py中attention_rescoring依赖ctc_prefix_beam_search先产出 beam 候选再逐候选累加注意力解码器得分与 CTC 得分score ctc_scores[i] * ctc_weightsearch.py。这就是原文档标注ctc weight (used for attention rescoring): 0.5的原因——该值越大最终排序越偏向 CTC 分支给出的候选。2. 右向解码器的双向融合。训练阶段_calc_att_loss会将目标序列逆序reverse_pad_list送入右向解码器并按其权重融合损失解码阶段attention_rescoring对每个候选同样累加右向得分并按(1 - reverse_weight)与reverse_weight加权search.py。双向解码是 VKW 基线的核心卖点之一对短关键词与中文逐字建模尤其有利。八、运行前提与复现要点工作目录下需先执行path.sh设置PYTHONPATH指向仓库根目录与 Kaldi/FST 相关路径见 path.sh训练数据为 1505 小时训练集约data/train开发/微调数据由三场景各 5 小时合并而来完整复现顺序先以stop_stage5训练并评测主模型再以stop_stage6触发 5 小时微调脚本得到训练集微调集版本的结果评测依赖官方 F4DE 工具链data/vkw/scripts/bin/results_to_score.sh、F1.sh需按脚本提示提前安装若需导出部署模型可复用$dir/train.yaml含模型输入输出维度配合 wenet/bin/export_jit.py 等导出工具将训练好的 PyTorch 模型转换为 TorchScript / ONNX 格式用于 runtime 部署。综上该基线以因果 12 层 Conformer 双向 Bi-Transformer 混合 CTC/Attention为核心配合帧级 CTC 对齐时间戳做关键词滑窗匹配在无需语言模型与外部解码图的前提下即可获得可观的 KWS 指标而 15 小时场景微调带来的显著提点也为实际业务中通用模型 场景少量数据适配的落地路径提供了直接范本。赞分享人工智能语音深度学习预训练模型推理服务【免费下载链接】wenetProduction First and Production Ready End-to-End Speech Recognition Toolkit项目地址https://gitcode.com/gh_mirrors/we/wenet点击查看免费下载相关推荐PaddleSpeech 关键词唤醒KWS实战基于 HeySnips 数据集的 MDTC 模型训练与 DET 评估PaddleSpeech 关键词唤醒KWS实战基于 HeySnips 数据集的 MDTC 模型训练与 DET 评估 本篇技术指南聚焦 PaddleSpee人工智能语音音频PaddleSpeech 关键词识别KWS实战基于 MDTC 的Hey Snips唤醒词检测PaddleSpeech 关键词识别KWS实战基于 MDTC 的Hey Snips唤醒词检测 关键词识别Keyword SpottingKWS用人工智能语音音频PaddleSpeech 关键词唤醒KWSMDTC 训练模块深度解析paddlespeech.kws.exps.mdtc.trainPaddleSpeech 关键词唤醒KWSMDTC 训练模块深度解析paddlespeech.kws.exps.mdtc.train PaddleSpee人工智能语音音频NLP媒体生成上一篇MusicFree 插件音乐播放器3 步装好音源完整指南下一篇Streamline源码编译从源代码构建框架的完整流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站