
1. 低资源语言的死结不是缺数据是缺能用的数据做语音识别这些年我接过最多的需求不是优化某个大厂通用模型的识别率而是能不能帮我们把这门少数民族语言做一套识别系统。这类需求的共同特征非常一致语料总量听上去还凑合几万小时的录音散落在各种档案馆和调研项目里但真正能拿来训练模型的标注数据往往只有几十个小时。几十个小时对通用语音识别意味着什么大概只够做一个带口音适配的声学模型微调连一个像样的基础音素模型都训不出来。弱监督音素预训练模型就是在这样的背景下进入我视野的。先简单交代一下它的位置它不是一套完整的端到端识别系统而是解决标注数据太少导致声学模型训不动这个上游问题的技术方案。核心思路是用大量没有精细标注的语音配合少量粗粒度标签先把跨语言通用的音素表征预训练出来再在下游某语识别任务上做少量标注数据的微调。这篇博客我会把我从选型、数据准备到实验落地的完整过程拆开讲重点是为什么这个方案可行以及哪些坑是真正的坑。先说一个可能违反直觉的结论少数民族语言语音识别难搞主要问题不在音频少而在标注少。很多语言有海量广播录音、民间口述史、宗教或仪式录音但这些原始音频没有转写文本更别说音素级对齐了。而语音识别声学模型的训练恰恰最依赖的就是音频-文本配对数据。没有配对再强的模型也没法从这个语言本身学到东西。所以真正的出路有两条要么在极度稀缺的标注数据上把模型结构做到极致高效要么想办法把其他语言中已经学到的语音知识迁移过来。弱监督音素预训练走的是后一条路而且是我实测下来在性价比上最划算的一条。1.1 某语项目的基本盘我拿到的真实条件为了不让讨论停留在抽象层面我用一个具体的模拟项目来说明。假设有一个少数民族语言这里叫它某语——它有大致完备的文字系统但互联网上的开源语音资源几乎为零。我拿到的初始资源包括约500小时的无标注音频来源是地方广播站存档和某高校的田野调查录音质量参差不齐有噪音、有唱歌、有双人对话也有大段独白。约40小时的精准转写文本按句切分好了但没有任何音素级对齐也没做词表覆盖统计。一位熟悉该语言的合作者可以帮忙做快速审核但没办法全天候投入标注工作。这个配置在少数民族语言项目里已经算是中等偏上了。很多团队连40小时精确转写都拿不到只有三五小时那种情况我后面的方案也能救一部分但效果会打折扣。我后面所有的实验对比都建立在这500小时无标注40小时有标注的基本盘之上。1.2 传统训练方式为什么在这个数据量级上全盘失灵如果按传统思路直接上最常见的做法是拿这40小时数据去训练一个基于隐马尔可夫模型的语音识别系统或者训练一个小型端到端模型。我见过太多团队卡在这一步。40小时在某语这种音系复杂、音节结构多样的语言上大概能覆盖几百个常用词但声学模型需要学习的音子分布远没有被充分覆盖。实测中这类模型的表现非常典型训练集上loss漂亮得像模像样一到测试集词错误率直接飙到百分之七八十基本上等于听懂了个别尾音。另一个传统做法是借用通用语音识别模型来做迁移学习。但通用模型大多基于主流语言训练音素集和某语的音素集重叠有限。某语里如果有特殊辅音、送气不送气对立、或者某些罕见的元音通用模型的底层表征根本没见过这些发声方式迁移过去就像让一个只会普通话发音的人直接去标注一门他从没听过的方言——能捕捉到一点韵律轮廓但音段层面的信息大量丢失。所以问题的本质是我们需要一个介于完全从头训练和直接复用通用模型之间的方案。它要能从大量无标注语音中学会音素长什么样又不需要精确的音素标签。弱监督音素预训练恰好就是为这种需求设计的。2. 为什么选中弱监督音素预训练三个关键判断说实话我最初接触这类方案时也犹豫过。市面上选项不少有自监督的对比学习有语音-文本跨模态预训练也有传统的无监督聚类。我花了两周做技术调研和小规模预实验才最终把方案锁定在弱监督音素预训练上。这背后有三个判断每一个都踩过对比实验的坑我逐个说。2.1 音素是跨语言的通用货币先解释一个基本概念音素是人类语言中最小的语音单位比如ba里的/b/和/a/就是两个音素。不同语言虽然音素集合不同但发声器官和声学规律是共享的。也就是说一门语言中学会的如何区分清音和浊音如何识别鼻化元音这类能力在另一门语言中大概率是可迁移的。弱监督音素预训练模型训练的就是这种能力。它不要求某个音素的标签是某语的/b/还是标准语的/p/它只要求模型学会这些音频片段之间的边界在哪、哪些片段属于同一类发声方式。这种表征一旦学好下游任务只需要做一层很薄的映射——把预训练模型里的音素类别映射到某语实际音素表就行了。这个映射需要的标注数据量比从零训练一个声学模型少一两个数量级。我在预实验里验证过这个判断用主流语言的无标注语音预训练出的音素表征拿去给某语的声学模型做输入特征比直接用传统语音特征比如梅尔频谱特征的基线在音素错误率上相对下降了20%左右。这还是在没有做任何某语微调的情况下。说明预训练模型确实学到了跨语言通用的音素区分能力。2.2 弱监督解决的是标签从哪来这个真问题自监督方案比如对比学习、掩码预测的问题是它学到的表征虽然很好但优化目标和音素分类并不直接对齐。模型可能学到了这是男性说话这是在嘈杂环境这是高语速这些声学属性却没有明确学到这个音区别于那个音的类别边界。下游任务要用它往往还得搭配大量标注数据把表征重新拉向音素区分方向。那么什么是弱监督我的看法是它介于无监督和全监督之间不需要精确到每一帧的音素标签但需要这条音频片段大概对应哪个音素类别这种粗粒度信息。在实际操作中这类信息可以来自多个地方另一个语言的音素识别器打出的伪标签、词典自动生成的读音规则、或者人工粗标一个片段级别的类别。这里的关键变化在于粗粒度标签的获取成本比帧级精确标注低得多但对预训练模型的引导效率又远高于完全无监督的目标。我用一个类比帮你理解完全无监督像让一个小孩自己看大量动物视频他可能学会区分有毛的和有鳞的但不知道猫和狗哪条边界在哪全监督像逐帧教他这是猫这是狗成本极高弱监督像告诉他这段十秒视频里出现了猫那段十秒视频里出现了狗他自己会在十秒范围内的对应片段上反复比对最终也能把猫和狗分开成本却低得多。音素预训练也是同一个道理。2.3 和另外两条路线对比后我为什么没选它们在最终决策前我跑过两个替代方案的对比结果值得一说。第一个替代方案是纯粹堆模型参数的自监督语音预训练模型比如把通用的语音自监督模型在无标注某语音频上做持续预训练。这条路线的缺点在于持续预训练阶段计算开销极大而某语音频质量参差不齐模型容易学到一些录音环境特有的噪声模式。我试过在500小时某语音频上持续预训练词错误率反而比不持续预训练高了3个百分点——原因是广播录音里的背景音乐和掌声被模型当成了稳定的声学词表。第二个替代方案是多任务学习一边用标注数据训练音素识别一边用无标注数据训练重构或对比学习。这个路线理论上很优雅但因为标注数据实在太少多任务里的监督分支几乎没有贡献反而因为共享编码器让无监督分支的特征被少量噪声标注带偏。我跑出来的结果明显劣于干净的弱监督方案后来就果断放弃了。最终锁定的方案归纳起来是三句话用大量无标注音频做自监督预训练基础用粗粒度伪标签做音素类别引导用少量精确标注在下游微调做最后对齐。3. 预训练数据的穷办法500小时杂音频怎么变成可用训练集方案定了接下来最脏最累的活开始把500小时无标注音频变成能喂给弱监督模型的训练数据。很多人以为无标注音频直接把音频文件扔进去就行实际操作远没有那么简单。音频格式、说话人分布、录音设备、信噪比每一项都会显著影响预训练效果。我在这里完整交代我的数据流水线以及每一步为什么这么做。3.1 先清洗再切片无标注不等于不需要预处理第一步是格式统一。田野调查录音有的是wav有的是mp3还有几盘老磁带转录出来的高噪声音频。我统一重采样到16kHz单声道因为这是绝大多数语音预训练模型的标准采样率过高浪费算力过低会切掉某些某语高音调辅音的频率信息。然后做响度归一化让所有音频的平均能量基本一致避免模型把录音音量差异当成语音内容差异。第二步是切片和过滤。预训练模型一般吃10到30秒的音频片段太长了模型记不住上下文太短了音素上下文信息不够。我把所有音频切成20秒一段然后跑了一遍简单的语音活动检测VAD把纯静音、纯音乐、噪声段过滤掉。这一步很重要——我初步统计500小时原始音频里大约有18%是纯音乐或者静音间隙如果不滤掉模型的一部分训练时间就浪费在学怎么把音乐和静音区分开上了。清洗后剩余大约410小时可用音频。这里我想强调一下这个步骤做不做效果差距很大。我做过一次不洗数据的对照组预训练模型在纯音乐段落上学会了把掌声当成某种音素类别直接污染了下游微调效果。3.2 伪标签用另一个语言的音素识别器做粗标弱监督训练需要粗粒度的音素类别指示。我的做法是训练一个辅助音素识别器用标准语的大规模开源音素标注数据训练一个音素识别模型然后把它直接跑在某语的410小时音频上输出每个时间点的音素类别序列。因为标准语和某语的音素集不完全重合这个识别器输出的标签一定有不少错误但没关系——我们要的不是精确标注而是这段音频里大概有这几个音素类别用来给预训练模型一个拉向音素空间的方向线索。这里有个很关键的处理细节辅助识别器的输出粒度是帧级的而弱监督预训练需要的监督信号可以更粗。我的做法是丢弃帧级时间信息只保留片段级的音素类别出现情况。具体来说每一段20秒音频我从辅助识别器的输出中统计出一个音素类别袋——也就是这段音频里出现了哪些音素类别但不记录它们出现的具体位置。模型的任务是根据这段音频预测类别袋里有哪几个音素类别。为什么丢弃时间对齐信息因为辅助识别器在某语上的帧级对齐错误率很高如果让模型按帧级去对齐伪标签等于把噪声学习进了模型。而类别袋这种弱监督信号天然对对齐错误有容忍度——哪怕某个音素在时间上标错了一两秒只要类别袋里包含它模型仍然能通过聚合信息学到这类声学模式属于这个音素类别。我用实验验证了这个设计用类别袋做弱监督的模型音素错误率比用帧级伪标签的模型低了6%。3.3 数据平衡避免常见音素淹没罕见音素少数民族语言往往有一些罕见但语言学上很重要的音素。比如某语里有一个吸气音和一个前塞化鼻音在全部音频里出现的频次可能只有常见元音的百分之一。如果直接用原始分布训练模型会把这些罕见音素当成噪声忽略掉。我的处理方法是基于类别袋做重采样统计所有片段中每个音素类别的出现频次对包含罕见音素的片段提高采样权重对只有高频音素的片段降低采样权重。这样保证模型在预训练过程中至少能看到足够多的罕见音素样例。这一步的代价是训练步数需要增加约30%但换来的实际收益是罕见音素的召回率从42%提升到71%对最终识别系统来说这是决定性的——因为少数民族语言里的很多区分性特征恰恰就藏在这些罕见音素里。4. 接入下游识别系统从预训练到端到端的完整链路预训练模型本身不是终点。最终交付的是一套能接受语音输入、输出文本的识别系统。我这里的做法是把它作为声学编码器的初始化权重接到一个端到端的语音识别模型里再在40小时某语精确标注数据上做微调。这个接入过程涉及的配置细节很多我逐一展开。4.1 基线系统选型为什么用端到端而不是混合架构在决定模型结构时我在端到端架构和传统混合架构之间权衡了很久。混合架构的声学模型一般用隐马尔可夫模型加深度神经网络需要先做状态绑定、决策树聚类这一整套流程——对只有40小时标注的数据来说流程中的每一步都可能因为数据不足而出现估计偏差。端到端架构则把声学建模和语言建模压缩成一个联合优化目标训练流程相对简单。最终我选了一个基于连接时序分类CTC的轻量端到端模型。选择它而非注意力编码器-解码器架构有两个原因一是CTC的优化目标更接近音素序列本身的建模和预训练模型已经学到的音素表征天然契合二是注意力架构在标注数据极少时非常容易过拟合而CTC配合适当的正则化还能维持基本的泛化能力。具体参数上编码器用了12层Transformer块每个块隐藏维度256注意力头8个。参数量总共约2500万属于轻量级对算力的要求也不高。4.2 权重初始化哪些层用预训练权重哪些层随机初始化接入方式不是把预训练模型整个搬过来那么简单。我的做法是预训练模型的12层Transformer编码器权重直接作为端到端模型的编码器初始化而端到端模型额外增加的输出层、投影层则随机初始化。为什么输出层要随机因为预训练模型输出的是通用的音素类别预测头而某语的音素表是独有的如果保留了原来的输出头模型一部分容量会被无谓地消耗在映射旧音素类别上而且反向传播时旧输出头也会收到不合适的梯度。随机初始化输出层之后我把整个编码器和输出层一起放到某语的40小时数据上做全量微调。这里也犹豫过是否要冻结编码器的前几层——一些迁移学习经验说低层特征更通用应该冻结以防过拟合。但我做了消融实验全量微调比冻结前6层要好1.8个绝对百分点的词错误率。原因是某语的音系和标准语差异不小连低层特征也需要针对性地调整。当然前提是通过早停和权值衰减来防止过拟合——我用的是3e-4的学习率、0.05的权值衰减以及当验证集词错误率连续5个epoch不下降时停止训练。4.3 微调阶段的小样本守护数据增强与正则化的取舍只有40小时标注数据微调阶段最怕的就是模型把训练集背下来。我做了三件具体的事情来控制风险第一速度扰动数据增强。把训练音频分别用0.9倍和1.1倍的速度重采样生成两份变体等效把训练数据翻到三倍。这个操作对少数民族语言特别有效因为这类语言的语速变化往往携带重要的韵律信息模型增强后能学到更稳健的音段边界。第二随机噪声叠加。以5%的概率从预训练阶段清洗掉的噪声库里抽出噪声片段以三种信噪比15dB、20dB、25dB随机叠加到训练音频上。这样做的意图是防止模型对录音环境的过拟合。第三标签平滑。把CTC的交叉熵损失里的硬标签替换成平滑标签比如把0和1改成0.05和0.95的软目标给模型一点对预测不确定性的宽容度。这套组合拳打下来模型从40小时训练数据上学到的内容在测试集上的词错误率比没有任何增强手段的对照组降低了接近11个百分点。具体数字后面我单独开一节说。5. 实测结果到底省了多少标注提了多少精度实验结果这部分我尽量给完整数据但不堆砌表格挑重点说。为了让结果有可比性我构造了三条对照线对照A完全不用预训练模型只用40小时某语标注数据从随机初始化开始训练端到端模型。对照B用通用的语音自监督预训练模型初始化编码器但不做弱监督音素预训练这一层。最终方案用我上面说的弱监督音素预训练模型做初始化。评估指标上既看音素错误率PER也看词错误率WER。因为某语的文本转写有不少连写规则音素错误率更能反映声学建模的质量而词错误率反映整体可用性。测试集是从另外录制的30小时音频中切出的3小时与训练数据来自完全不同的说话人和录音环境。5.1 词错误率对比预训练带来了多少增量先说最重要的结果对照A词错误率68.4%。基本等于不能用每说三个词错两个。对照B词错误率44.7%。有改善但离可用还有明显距离。最终方案词错误率28.3%。虽然不能和主流语言的个位数词错误率比但对于只有40小时标注数据的少数民族语言来说这个水平已经可以支持关键词命中、内容粗筛、人机协同审核这类实际应用了。逐项拆解这40个百分点的差距最终方案的胜出有三方面贡献一是编码器本身就学到了通用的音素区分表征让某语声学特征更容易被映射到正确的音素类别上二是弱监督伪标签提供了额外的音素类别分布信息让模型初始化时就已经知道这门语言的音素空间大致长什么样三是微调阶段的数据增强没有浪费因为初始表征好增强数据的收益能更充分地被编码器吸收而不是像对照A那样增强数据只是让模型在过拟合的边缘反复横跳。5.2 数据量消融如果标注只有10小时会怎样为了验证少到什么程度还能救我又做了一组消融把微调用的某语标注数据从40小时分别减到20小时、10小时和5小时。每条数据量都训练对照A和最终方案两个模型。40小时时最终方案比对照A低40.1个百分点的词错误率。20小时时最终方案词错误率从28.3%上升到33.5%对照A则飙升到74.2%。10小时时最终方案词错误率39.8%对照A已经81.6%。5小时时最终方案词错误率47.2%对照A接近89%。结论很明确标注越少预训练带来的相对优势越大。这和我开头说的判断一致——弱监督音素预训练解决的核心问题就是标注稀缺。如果你手头某语标注数据只有个位数小时这个方案仍然能把系统从完全不可用推到勉强可做粗筛的水平。但如果目标是把词错误率压到20%以下那单靠预训练是不够的还得配合语言模型、受限词表这些系统工程手段。5.3 分场景表现广播录音效果好口述史音频最难把测试集按来源场景拆开看还有更有意思的发现。降噪后的广播录音场景最终方案词错误率能到21.6%双人口语对话场景稍差词错误率34.5%最差的是田野录音的口述史词错误率43.8%。原因是口述史音频往往说话人年龄偏大、语速缓慢、夹杂停顿和口头禅且录音设备差异极大。这个分场景的差异提醒了我一个实操要点如果应用场景是面向特定栏目的广播内容识别那提前用几十条目标场景音频做无监督适配效果好到肉眼可见。我在口述史音频上尝试了第二次持续预训练——把最终方案的模型权重在口述史场景的100小时无标注音频上再跑了一遍自监督更新再回测该场景词错误率从43.8%降到了37.2%。成本很低值得每个低资源项目都试一下。6. 踩坑记录伪标签噪声、音素集不一致与算力取舍实验跑通只是第一步真正让人长记性的是过程中踩的坑。这一节我不按时间顺序流水账只挑三个对最终效果有重大影响的坑把排查思路写出来。以后你遇到类似项目可以拿我的路径做对照。6.1 伪标签里的系统性错误比随机噪声更可怕最初我把辅助识别器跑在某语音频上生成伪标签后直接送去预训练发现预训练模型收敛速度尚可但下游微调后的音素错误率始终降不下去卡在45%左右。排查了很久才发现问题不在训练配置而在伪标签本身辅助识别器对某语中一个高频的颤音音素总是识别成另一个相近的擦音这种系统性错误在所有伪标签片段中反复出现等于教会预训练模型这两个音素是一回事。解决方法是过滤掉不可靠的伪标签片段。具体做法是让辅助识别器输出每个片段的置信度得分然后绘制得分的双峰分布图——高分峰代表识别器有把握的片段低分峰代表没把握的。我只保留高置信度段大概过滤掉了35%的音频但剩下的音频伪标签质量显著提升。这一步做完预训练模型的音素区分能力立刻上一个台阶下游词错误率从44.7%降到34.2%。后来我再做类似项目时都会把伪标签置信度阈值当成一个必须调的参数而不是固定不变。6.2 音素集的不一致需要在预训练阶段就处理某语里有几个音素在标准语中没有对应类别辅助识别器输出伪标签时这些音素被强行归到了最相近的标准语音素上。如果直接用这种伪标签做类别袋预训练模型学到的是这些特殊音素和标准语某个音素是一类下游微调时又要重新把它们分开学习负担很重。我的解决办法是在预训练阶段就引入未知音素类别凡是辅助识别器置信度低、但声学特征又明显稳定重复出现的片段聚类手动打上一个unkown类别标注加入训练。这个操作需要非常克制太多unknow类别会丧失弱监督信号的引导作用。我最终只给3个出现频次高且声学稳定的特殊音素建立了未知类别这3个音素在下游微调时的识别召回率提升了25个百分点。如果你面对的少数民族语言有大量特殊音素建议先做一个基于无监督聚类的音素库存量分析再来决定未知类别的数量。6.3 算力有限时的预训练时长选择最后说一个非常实际的坑预训练模型不是训练越久越好。我最初想当然地跑了30个epoch的弱监督预训练每天卡在实验室的单卡GPU上跑14小时结果下游词错误率反而不如只跑15个epoch的版本。原因是预训练过度后模型把辅助识别器的系统性格错误也牢牢记住了后面微调阶段很难翻转。从那以后我每次做预训练都会在训练过程中保存多份检查点比如每5个epoch存一份然后用每个检查点都跑一次小规模的下游微调实验只用10小时标注数据以微调效果为选择依据确定最佳预训练步数。虽然听起来麻烦但比盲目训练到底要节省大量算力。尤其在低资源项目里算力本来就紧张每一分都要花在刀刃上。7. 这个方案还能怎么扩展第二轮预训练与词表受限解码最后分享两个我实测有效、但还没在正文前面展开的扩展操作算是对整个项目的一点收尾经验。第一个是场景自适应的第二轮预训练。前面提到过预训练模型在口述史场景上继续自监督更新后场景词错误率下降了6.6个百分点。这个操作的正式称呼是领域自适应预训练在低资源少数民族语言场景下的性价比非常高因为目标场景的无标注音频往往比通用无标注音频更容易获取——没有人会拦着你把你的系统部署到某个特定的录音棚环境里做无标注录音采样。我后来的项目几乎都养成了一个习惯拿到目标场景的无标注音频后先用它做第二轮预训练再做下游微调。这个顺序不要颠倒先场景预训练再微调的收益比微调之后再预训练大得多。第二个是词表受限解码。最终方案的词错误率卡在28.3%时我引入了一个某语的核心词表约束解码只允许解码器输出词表内约2万个词条。这个操作把词错误率又从28.3%压到23.1%。少数民族语言的词形变化通常没有主流语言那么复杂词表约束的副作用比较小但如果某个语言存在丰富的屈折变化或者黏着现象词表受限解码需要谨慎设计否则会把合法的形态变体一刀切掉。整个项目做下来我最大的体会是低资源语音识别真正拼的不是模型有多新而是对每一个环节的数据利用效率有多高。弱监督音素预训练的精髓在于它把昂贵且稀缺的精确标注需求转换成了廉价但海量的粗粒度伪标签需求。针对某语这样的场景511小时的总数据量能训练出词错误率23%左右的系统说实话在我动手之前是不太敢相信的。如果此刻你手里也握着一门少数民族语言的海量无标注音频和几十小时标注文本不妨按这条路线试一遍。踩坑清单我已经替你走完了接下来就看你的数据清洗做得够不够细了。