资讯动态

PaddleSpeech SentencePiece 子词建模实战:从零训练 unigram/BPE 分词器并接入 ASR 全流程

发布时间:2026/9/25 5:59:06 来源:尧图企业网站定制
人工智能语音音频NLP媒体生成【免费下载链接】PaddleSpeechEasy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.项目地址https://gitcode.com/paddlepaddle/PaddleSpeech点击查看免费下载导读本文围绕 PaddleSpeech 仓库中 examples/other/spm 提供的 SentencePieceSPM训练示例完整讲解如何为英文语音识别任务训练一个 unigram/BPE 子词模型、生成词表与 BPE 编码文本并深入剖析该流程在 LibriSpeech 等真实 ASR 示例中的落地方式——包括unit_type: spm的配置接入、TextFeaturizer的底层调用链以及blank/unk/sos/eos等特殊符号在 CTC 与序列建模中的约定。读完本文你将能够独立完成语料 → spm 模型 → 词表 → 编码/解码的完整子词建模管线并把产出的模型接入 PaddleSpeech 的 ASR 数据准备与训练流程。为什么 ASR 需要 SentencePiece从字符到子词语音识别模型的输出单元token直接决定词表大小、OOV 覆盖率和建模粒度。PaddleSpeech 的文本前端 paddlespeech/s2t/frontend/featurizer/text_featurizer.py 明确支持三种unit_typechar、word、spm。其中char按字符切分词表小但序列长且无法直接复用英文的词根/词缀信息word按空格切分序列短但词表庞大、OOV 问题严重spm基于 SentencePiece 的无监督子词切分在词表规模与序列长度之间取得平衡天然支持 BPE 与 unigram 两种建模方式是 Conformer、Transformer 等主流 ASR 模型的常用选择。examples/other/spm示例正是用来训练一个英文 spm 模型的最小可运行闭环它从一行行文本语料出发产出.model、.vocab和带编号的词表文件供后续build_vocab.py/format_data.py/TextFeaturizer直接消费。示例目录结构与运行入口examples/other/spm目录只有四个文件职责非常清晰文件作用README.md运行说明与结果展示path.sh初始化环境变量MAIN_ROOT、PATH、PYTHONPATH等run.sh主流程脚本训练、编码、构建词表text输入语料样例utt-id 文本两列格式运行方式非常简单. path.sh bash run.shpath.sh的核心作用是把仓库根目录与utils加入PATH保证脚本中直接调用的spm_train、spm_encode、spm_decode仓库在 utils 目录下提供的可执行文件以及utils/parse_options.sh可以被找到export MAIN_ROOTrealpath ${PWD}/../../../ export PATH${MAIN_ROOT}:${MAIN_ROOT}/utils:${PATH} export LC_ALLC # Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALLC export PYTHONIOENCODINGUTF-8 export PYTHONPATH${MAIN_ROOT}:${PYTHONPATH}这里有一个值得注意的细节脚本同时设置了LC_ALLC与PYTHONIOENCODINGUTF-8——前者保证 shell 管道行为可预期后者则避免 Python 在处理含 UTF-8 字符的文本时抛出UnicodeDecodeError两者缺一不可。逐步拆解 run.shspm 训练全流程examples/other/spm/run.sh 遵循 PaddleSpeech 示例一贯的stage/stop_stage分段模式并通过 utils/parse_options.sh 支持--nbpe 200 --bpemode bpe这类命令行覆盖。脚本开头定义了三个关键参数stage0 stop_stage100 # bpemode (unigram or bpe) nbpe100 bpemodeunigramnbpe100目标子词piece数量即词表规模bpemodeunigram建模方式可选unigram或bpetrain_settrain训练集标识会拼进输出文件名。基于这些参数脚本推导出两个产物路径dictdata/lang_char/${train_set}_${bpemode}${nbpe}_units.txt bpemodeldata/lang_char/${train_set}_${bpemode}${nbpe}即默认输出data/lang_char/train_unigram100.model模型与data/lang_char/train_unigram100_units.txt词表。Stage 2词表与编码数据准备echo blank 0 ${dict} # 0 will be used for blank in CTC echo unk 1 ${dict} # unk must be 1 # we borrowed these code and scripts which are related bpe from ESPnet. cut -f 2- -d text data/lang_char/input.txt ${MAIN_ROOT}/utils/spm_train --inputdata/lang_char/input.txt --vocab_size${nbpe} --model_type${bpemode} --model_prefix${bpemodel} --input_sentence_size100000000 ${MAIN_ROOT}/utils/spm_encode --model${bpemodel}.model --output_formatpiece data/lang_char/input.txt | tr \n | sort | uniq | awk {print $0 NR1} ${dict} num_token$(cat $dict | wc -l) echo sos/eos $num_token $dict # eos wc -l ${dict}这段脚本对应了子词建模管线的四个关键步骤初始化词表头blank 0固定给 CTC 的 blank 符号ID 必须为 0unk 1固定给未知词unigram 模型训练时由 SentencePiece 预留。这两个约定在训练与解码侧必须保持一致。剥离说话人 IDcut -f 2- -d text把输入语料text中每行的第一列utt-id去掉只保留纯文本写入data/lang_char/input.txt。注释也说明这部分代码与脚本借鉴自 ESPnet 的 BPE 数据准备流程。训练 spm 模型调用spm_train关键参数包括--input训练语料文件--vocab_size100目标子词数--model_typeunigram建模算法可选unigram/bpe--model_prefix模型输出前缀会生成prefix.model与prefix.vocab--input_sentence_size100000000参与训练的句子采样上限此处设为极大值等价于使用全部语料。从模型生成带编号词表用spm_encode把训练文本切成 piece再经tr/sort/uniq去重后用awk {print $0 NR1}从 2 开始依次编号追加到blank/unk之后最后把sos/eos追加到词表末尾编号为num_token为序列建模预留开始/结束符。编码与解码验证stage 2 完成之后脚本无条件执行最后两行用刚训好的模型对全部语料做编码与解码往返验证${MAIN_ROOT}/utils/spm_encode --model${bpemodel}.model --output_formatpiece data/lang_char/input.txt data/lang_char/input.bpe ${MAIN_ROOT}/utils/spm_decode --model${bpemodel}.model --input_formatpiece data/lang_char/input.bpe | sed -e s/▁/ /g data/lang_char/input.decodeinput.bpepiece 级别的编码结果每条 token 之间用空格分隔句子开头带▁SentencePiece 的空白标记表示词边界input.decode对编码结果解码并用sed把▁还原为空格后的文本应与原始input.txt一致用于验证编码→解码无损。输入语料格式text 文件examples/other/spm/text 展示了输入格式——utt-id与文本之间以空格分隔脚本用cut -f 2- -d 取第 2 列及之后的所有内容text-1 mister quilter is the apostle of the middle classes and we are glad to welcome his gospel test-2 nor is mister quilters manner less interesting than his matter test-3 he tells us that at this festive season of the year with christmas and roast beef looming before us ...注意示例中 id 与真实文本列之间是单个空格如果语料中的 id 与文本之间包含制表符或多空格应相应调整cut的分隔符参数。运行结果解读6 个产物的完整含义示例运行完成后data/lang_char/下会生成 6 个文件data/ └── lang_char ├── input.bpe ├── input.decode ├── input.txt ├── train_unigram100.model ├── train_unigram100_units.txt └── train_unigram100.vocab 1 directory, 6 filesREADME 中同时给出了各文件的 MD5 校验值可作为复现成功与否的比对依据b5a230c26c61db5c36f34e503102f936 data/lang_char/input.bpe ec5a9b24acc35469229e41256ceaf77d data/lang_char/input.decode ec5a9b24acc35469229e41256ceaf77d data/lang_char/input.txt 124bf3fe7ce3b73b1994234c15268577 data/lang_char/train_unigram100.model 0df2488cc8eaace95eb12713facb5cf0 data/lang_char/train_unigram100_units.txt 46360cac35c751310e8e8ffd3a034cb5 data/lang_char/train_unigram100.vocab各文件含义如下input.txt剥离 id 后的纯文本语料input.bpepiece 切分结果例如▁mi ster ▁quilter ▁ is ▁the ▁a p ost le ...——可见 unigram 模型把mister切成了▁mi ster把apostle切成了▁a p ost le这正是子词建模压缩序列长度、控制词表规模的直观体现input.decode解码还原后的文本与input.txt逐行对应可用于人工核对train_unigram100.model训练好的 spm 模型文件后续推理、解码均依赖它train_unigram100_units.txt带编号的 token 词表是 ASR 训练真正使用的词表文件。其头部为blank 0 unk 1 2 a 3 all 4 and 5 ar 6 ason 7 at 8 b 9可见blank与unk占据 0/1 号位其余子词从 2 开始编号文件末尾还会追加sos/eos。这个顺序与 paddlespeech/s2t/frontend/utility.py 中定义的SOS eos、UNK unk、BLANK blank等特殊符号约定一一对应保证TextFeaturizer在加载词表时能正确找到blank_id、unk_id、eos_id。train_unigram100.vocabspm 自带的词表含负对数概率分数是.model的伴生产物例如unk 0 s 0 /s 0 ▁ -2.01742 e -2.7203 s -2.82989训练脚本并不直接消费它但可用来检查各 piece 的先验概率分布。从示例到实战spm 在 LibriSpeech ASR 中的完整接入examples/other/spm是一个最小演示而 PaddleSpeech 的真实 ASR 示例如 examples/librispeech/asr1把同一套子词建模管线放大到了工业级规模。以 examples/librispeech/asr1/local/data.sh 为例# bpemode (unigram or bpe) nbpe5000 bpemodeunigram bpeprefix${dict_dir}/bpe_${bpemode}_${nbpe}LibriSpeech 的nbpe从 100 提升到5000模型前缀变为data/lang_char/bpe_unigram_5000但其建模方式同样是unigram。在数据准备阶段build_vocab.py直接以 spm 为单元类型构建词表python3 ${MAIN_ROOT}/utils/build_vocab.py \ --unit_type spm \ --spm_vocab_size${nbpe} \ --spm_mode ${bpemode} \ --spm_model_prefix ${bpeprefix} \ --vocab_path${dict_dir}/vocab.txt \ --manifest_pathsdata/manifest.train.raw随后format_data.py同样以--unit_type spm与--spm_model_prefix把文本转成 token id写入 manifestpython3 ${MAIN_ROOT}/utils/format_data.py \ --cmvn_path data/mean_std.json \ --unit_type spm \ --spm_model_prefix ${bpeprefix} \ --vocab_path${dict_dir}/vocab.txt \ --manifest_pathdata/manifest.${sub}.raw \ --output_pathdata/manifest.${sub}而模型配置如 examples/librispeech/asr1/conf/conformer.yaml只需两行即可把解码单元切换到 spmunit_type: spm spm_model_prefix: data/lang_char/bpe_unigram_5000这说明spm 模型一旦训练好从数据准备build_vocab / format_data到模型配置再到推理全程只靠spm_model_prefix这一个路径串起来这正是examples/other/spm示例希望让使用者掌握的核心概念。源码视角TextFeaturizer 如何消费 spm 模型训练好的 spm 模型最终由 paddlespeech/s2t/frontend/featurizer/text_featurizer.py 加载使用。该类在初始化时根据unit_type决定处理方式当unit_type spm时加载 SentencePiece 模型if unit_type spm: spm_model spm_model_prefix .model self.sp spm.SentencePieceProcessor() self.sp.Load(spm_model)其 tokenize/detokenize 分支对应 spm 的实现为text_featurizer.pyspm_tokenize调用self.sp.EncodeAsPieces(text)得到 piece 列表spm_detokenizeinput_formatpiece时调用DecodePiecesinput_formatid时调用DecodeIds把 token 序列还原成文本featurize对每个 piece 查词表vocab_dict未登录词映射为unk对应的 id最终返回 token id 列表供模型训练/推理使用。这条调用链印证了前面 stage 2 的词表构建逻辑units.txt的编号顺序必须与vocab_dict的加载顺序一致否则 token id 会错位。这也是为什么blank必须为 0、unk必须为 1、sos/eos必须追加在末尾——它们是 CTC 与序列模型约定俗成的锚点。参数调优与注意事项综合示例脚本与源码实际使用时建议关注以下要点关注点说明nbpe词表大小决定模型粒度与词表规模。LibriSpeech 等大规模英文任务常用 5000 左右examples/other/spm的 100 仅用于演示流程。词表过小会导致切分碎片化、序列过长过大会引入大量低频 piece、增加解码开销bpemodeunigram默认基于 unigram 语言模型 EM 训练或bpe基于字节对合并。run.sh注释与 LibriSpeech 示例均默认unigram--input_sentence_size限制训练采样的句子数示例设为100000000近似全量语料极大时可调小以加速特殊符号位置blank 0、unk 1必须固定sos/eos追加在词表末尾编号由wc -l动态计算不能手动写死环境变量必须同时设置LC_ALLC与PYTHONIOENCODINGUTF-8否则含 UTF-8 字符的语料可能在 Python 侧触发编码错误参数覆盖run.sh通过 utils/parse_options.sh 支持命令行覆盖例如bash run.sh --nbpe 200 --bpemode bpe该解析器同时支持--config 文件形式批量导入配置复现校验可对照 README 给出的 6 个文件 MD5 值验证流程正确性若语料或参数不同MD5 会变化属于正常现象小结examples/other/spm用不到百行的脚本把语料 → spm 训练 → piece 编码 → 词表构建 → 解码还原这条子词建模链路完整打通。它的价值不止于一个演示通过nbpe、bpemode两个参数同一套脚本即可平滑迁移到examples/librispeech/asr1、examples/ted_en_zh/st1等大规模任务的词表构建而TextFeaturizer的unit_typespm分支则保证了训练、验证、推理全阶段对词表与模型路径的复用。若你的任务需要引入自定义语言或词表规模这套流程就是最直接、最可靠的起点。赞分享人工智能语音音频NLP媒体生成【免费下载链接】PaddleSpeechEasy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.项目地址https://gitcode.com/paddlepaddle/PaddleSpeech点击查看免费下载相关推荐SpeechBrain Switchboard 子词分词器训练指南基于 SentencePiece 训练 2K Unigram/BPE TokenizerSpeechBrain Switchboard 子词分词器训练指南基于 SentencePiece 训练 2K Unigram/BPE Tokenizer 本人工智能深度学习语音音频NLP预训练SentencePiece 子词分词完全指南语言无关的 BPE / Unigram 分词器实战SentencePiece 子词分词完全指南语言无关的 BPE / Unigram 分词器实战 SentencePiece 是 Google 开源的 语言无关AI 技能人工智能大模型深度学习Transformers 分词算法深入解析BPE、WordPiece、Unigram 与 SentencePiece 原理与实战Transformers 分词算法深入解析BPE、WordPiece、Unigram 与 SentencePiece 原理与实战 本文依据仓库中的 分词器概述人工智能深度学习机器学习预训练微调NLP计算机视觉语音多模态上一篇探索AltSnap重新定义Windows窗口操作的效率工具下一篇被Node.js版本折磨这款工具让多项目开发效率提升300%创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑