ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

弱监督音素预训练:低资源语言语音识别的破局之道

弱监督音素预训练:低资源语言语音识别的破局之道

语音识别做了几年,最深的体会是:大语种拼的是算力和资源,小语种拼的是“耐心和方法”。少数民族语言,或者说任何低资源语种,最尴尬的不是模型不够强,而是连“拿来训练的数据”都凑不齐。这几年把普通话、英语这些主流语种的识别做到接近天花板之后,我开始把不少精力放在某民族语言的手写识别和语音识别上,过程中最有效的一套思路,就是用弱监督音素预训练模型先撑起声学建模的骨架,再往具体语种上迁移。这篇文章把这套方法从思路到实操完整讲清楚,适合正在做低资源语音识别、想做多语种预训练,或者对端到端语音模型感兴趣的朋友。

先说结论:弱监督音素预训练,并不是什么神秘的新架构,它本质上是在“标签不好好标”的前提下,先用跨语言的音素共享单元把语音信号里的发音结构学出来,再通过少量标注数据微调。这种方法对少数民族语言特别有效,因为这些语言往往没有足够的成文规范,但发音层面却有很多跨语言共性。抓住“音素”这个中间表达,比直接硬怼“字”或“词”要稳得多。

1. 项目概述与核心问题

1.1 少数民族语言语音识别的困境

少数民族语言语音识别,难处不只是数据少。数据少是表面,深层次的问题有三个:第一,书面语使用率低,很多语言没有统一的拼写系统,有的是近几十年才由语言学家设计出文字,有的干脆以口传文化为主。这意味着即使你收集到了音频,也没有对应的“标准文本”可以做监督。第二,方言差异巨大,同一语言在不同村寨、不同流域的发音差别可能比普通话和某些方言的距离还远。第三,缺乏现成的发音词典和语言学资源,传统语音识别里的“音素→词典→语言模型”链条,在少数民族语言上第一环就断掉了。

有人会想,那直接上端到端模型,音频对汉字或音节输出不就行了。实际问题在于,端到端模型需要大量配对数据才能学出稳定的映射。几百小时的数据在主流语种面前不算什么,但对一个少数民族语言来说已经是几年攒下来的家底,直接喂给大模型很容易过拟合,或者学到的只是“背训练集”。这时候需要一个能在数据不足情况下依然学到普遍语音规律的中间层,音素预训练就是干这件事的。

1.2 为什么是弱监督音素预训练

弱监督的核心,是“不完全依赖精确标签”。传统音素识别需要每一段音频对应一个准确的时间边界和音素序列,这在少数民族语言里几乎不可能大规模获得。弱监督允许我们使用几种不完美但成本很低的信号来训练模型,比如从词典生成的部分音素标注、通过跨语言借用得到的近似音素标签,甚至是某些语言中用自动对齐工具生成的“有噪声”音素序列。模型不会被这些噪声引入太大偏差,因为预训练阶段的目标不是“精确到帧”,而是学到“发音单元在声学空间里的分布形态”。

音素作为中间单元有什么好处?拿普通话和某少数民族语言对比,两者可能完全没有共享的词根,但很多辅音、元音在发声方式上是类似的。让模型先在一个数据相对充足的“高资源语言”或“伪标注语言”上学音素,再把学到的底层表征迁移到目标语言,等于把“人的发音器官共性”先固化到模型里。到目标语言微调时,只需要手里十几小时的数据就能学得有模有样,比从零开始训练稳很多。

2. 模型设计与技术选型

2.1 整体架构

我这里采用的是一个比较通用的“卷积编码器 + 序列编码器 + 音素预测头”结构。前面两层实质上是把原始波形逐步下采样,把声学特征转换成隐层表征;后面的序列编码器捕获上下文依赖;音素预测头则负责把隐层表征映射到一组音素类别上。

你会问,这和直接语音识别有什么区别?区别在于训练任务。识别模型要预测“词”或“char”,音素预训练模型只预测音素序列,所以它需要的监督信号对语言Orthography的依赖更低,甚至完全可以用“模糊音素序列”来监督。模型的第一个编码器也可以预料训练——但这里的关键,是预测头的设计:它在预训练阶段输出音素后验概率,在微调阶段可以被扔掉,换成目标语言的建模单元输出头。

预训练阶段用弱监督而非纯自监督,还有一个好处:纯自监督(比如对比预测编码)学到的是“音频片段之间的时间结构”,不包含发音单元类别语义;而音素级弱监督,即使标签不太准,也能强约束模型去区分辅音和元音、送气和不送气这些真正对识别有用的发音属性。实测下来,弱监督预训练模型在做低资源语言微调时,收敛速度和最终准确率都比纯自监督有明显的优势。

2.2 弱监督信号的产生策略

既然叫“弱监督”,那信号本身怎么造?我实践下来有三种可落地的办法,你的项目里可以根据手头资源组合使用。

第一种是靠“跨语言近似音素标注”:选一个数据量大的相关语种,或者用国际音标体系作为中间表达,把目标语言的音频用其他语言的音素集强行标注。听起来很粗糙,但音素本身就存在“发音近似合并”的情况,比如某民族语言里有的清塞音,和高资源语言里的对应音位差别很小,用近似音素标签可以接受。

第二种是“词典+对齐算法”:如果目标语言有一些单词表和发音词典,虽然不全,也能用强制对齐工具先把音素边界粗略对齐出来。对齐结果会有不少边界漂移,甚至部分位置完全错位,但这不妨碍预训练阶段学习粗糙的声学-音素分布。

第三种是“半自动修正”:在几个小时的种子数据上手动校准音素标签,然后训练一个初始音素模型,用它去预测剩余数据,再把置信度高的预测结果当作标签加入训练集。这种做法是迭代式的,每次增补数据后模型都会更准,下一轮预测的置信度也会更高。这里唯一的风险是自举偏差,如果初始种子质量太差,模型会把错误当成真理一直放大,后面会讲怎么避开这个坑。

这三种策略可以混合用。我的经验是:先用第三种搞出几百小时“还可以”的伪音素标签,再用第一种来丰富音素集覆盖,最后用第二种做边界修正。三种标签的噪声类型不一样,混合之后反而因为相互抵消,让模型更鲁棒。

2.3 音素单元的跨语言共享

音素单元怎么定义,直接影响预训练的有效性。最直接的做法是用国际音标符号作为共享单元集,但这样做有两个问题:一是国际音标细粒度太高,很多语言之间的“同一音素”实际发音有细微差别,模型很难学到稳定的跨语言映射;二是音标符号里包含大量像“送气”“鼻化”“卷舌”这种特征性标记,如果直接当成离散符号,数据稀疏问题会被放大。

所以我在实践里会做一个“音素归纳”的步骤。拿某民族语言的高元音来说,它的闭音程度可能和标准参照语言里的某个元音不完全一样,但在声学特征上是连续过渡的。我会把发音最接近的一类音素归并成一个“宽式音素单元”,比如“i类元音”,而不是非要区分多个变体。具体操作上,可以先看语言学家给出的音位表,再根据混淆矩阵和声学距离做聚类,最后定一个100到200个单元的宽式音素表。这个数量比完整的国际音标小得多,又比纯字符(比如几十个字)更能覆盖发音共性。

跨语言共享的另一层含义,是模型输入侧可以使用一个多语种共享的声学特征。常用做法是提取线性频谱特征或梅尔频谱,不做说话人归一化,反而刻意保留说话人差异,让模型学会“不同人发同一个音素时有哪些不变属性”。手头的低资源语言数据往往来自不同录制环境,这种“对抗”其实会让音素表征更稳。

3. 数据准备与预处理实操

3.1 音频数据整理

先说最基础但最容易被忽视的:数据清洗。少数民族语言语音通常来源复杂,有田野录音.设有安静环境下手机录音,还有广播新闻。我的处理原则是“宁缺毋滥”,因为弱监督本身已经容忍噪声标签,但容忍不了五花八门的信道失配。第一步统一采样率为16kHz、单声道,16bit编码;第二步用VAD切掉大段静音,避免训练时无意义的空白被当成学习对象;第三步做响度归一化,把音频峰值拉到-3dBFS到-1dBFS之间,不然模型对不同录音设备的电平差异会过度敏感。

这还不够,我会特别检查音频里有没有重复片段。有些田野录音数据集里存在同一段话被录了多遍但文本没区分的情况,这种“隐形重复”会造成训练集和验证集重叠,指标虚高。建议把音频按频谱相似度做一次去重,特别是那些时长在1到2秒的碎片,非常容易出现复制。

另外,如果你的数据里混着不同方言口音,先别急着合并。我会先按说话人或者地域来源做一个硬聚类,然后在划分训练、验证、测试集时确保同一来源的数据不跨集合。否则微调阶段模型很容易通过记住“说话人特征”来作弊,在真正面对陌生说话人时直接崩掉。

3.2 弱标签生成流程

有了清洗好的音频,下一步就是给每段音频生成一个“弱音素标签”。我按前面的三种策略拆开说明。

如果用跨语言近似标注,具体流程是:把参照语言的音素集与目标语言音素集做映射表,比如“参照语言里的pʰ对应目标语言的pʰ”,然后直接用现有ASR模型解码出参照语言的音素序列,再通过映射表转换成目标语言音素标签。这个映射表可以减少因为语言间音位空缺造成的误差,但不会完全消除。

如果用词典+对齐,你需要先维护一个“词-音素”对照表,哪怕只有几百个词也行。接着用对齐工具把每句话的每个词边界和音素边界强制对齐出来。在没有语言模型的情况下,先做扁平起步对齐,再做两轮迭代对齐。得到的标签里会有大量插入、删除和替换错误,但对预训练来说够用了。我们甚至可以故意在训练时施加少量随机位移,防止模型对边界过度自信。

如果用半自动修正,先手动标注一个小时的音频作为种子集,这个种子集要有代表性,覆盖尽量多的说话人和音素。然后训练一个人工音素识别小模型,在剩余数据上做预测,取得分大于阈值的片段作为伪标签。阈值可以先用0.8,数据量不够时慢慢降到0.6,但别低于0.5,否则噪声大到会把模型带坏。

3.3 数据增强细节

低资源语音识别里,数据增强基本是必需品。我这里用三种增强方式的组合:加噪、变速、随机频段掩蔽。加噪用的是从实际田野录音里截出来的环境噪声,不是纯白噪音,这样模型学到的是“在鸡鸣狗叫、风吹树叶的环境下依然能识别音素”的鲁棒性。变速会改变音素的时长结构,所以变速比例别太激进,控制在0.85到1.15倍之间,不然某些语言的声调或长短音对立会被破坏。

随机频段掩蔽是参考了视觉领域掩蔽的做法,在频谱图上随机遮蔽一部分频带,强迫模型从剩余频带重建音素信息。这里注意:不要把低频段(比如200Hz以下)全掩了,很多民族语言的声调辨别依赖基频,低频被完全遮掉,等于让模型做“听力测试”,训练会变得极其困难。我一般把掩蔽频段宽度限制在整条频谱的10%到20%范围内。

最后特别提醒一点:数据增强只应该在预训练和微调的“音频侧”做,绝对不要对标签做拉伸。弱监督标签本来就不准,再随增强变化,模型会找不到优化方向。保持标签固定,只让音频变,是保证弱监督稳定性的前提。

4. 模型训练过程

4.1 预训练阶段配置

预训练阶段的目标,是让模型学会把一段音频变成一组能区分上下文的音素表征。输入我一般取10到30秒的原始音频片段,做在线特征提取和增强。网络不用特别深,但通道宽度要够,否则跨语言音素分类的表征容量不够。

预训练时使用“音素序列损失”加“对比辅助损失”的联合目标。音素序列损失是主头,直接让模型预测每帧音素类别;对比辅助损失用来拉近同一音素类别在不同说话人之间的表征,推开不同音素类别的表征。联合训练的好处是:一方面允许弱标签错误存在,另一方面又通过对比约束让表征聚类得更干净。实测下来,辅助损失的权重设在0.1到0.3之间比较合适,太高会把分类损失带偏。

预训练数据量不用太大,50到200小时就能见效。我在这里有个心得:预训练的“多语种混合比例”比“总量”重要得多。理想配比是让目标语言和若干高资源语言的数据混合,目标语言占比不要超过40%。因为目标语言数据少、容易过拟合,多语种混合可以让模型接触更多发音分布,同时避免模型仅仅学会“死记”目标语言音素。

预训练的学习率要低,建议用余弦退火从1e-4降到1e-5。手头算力紧张的话,也可以用“冻结前半层 + 只更新后半层”的方式分阶段训练。我自己踩过的一个坑是:一开始就把所有层解冻,结果模型在几百小时内把高资源语言学得很好,但目标语言几乎没学到什么,因为它的样本占比太小。后来改成前30步只训练解码层和顶部编码层,再逐步解冻,目标语言的效果才明显起来。

4.2 微调阶段配置

预训练完成后,把音素预测头丢掉,换上目标语言的建模单元头。这里“建模单元”可以是字、音节或者更细的“半音节”,看你对目标语言语言学结构的了解程度。如果完全不了解,就用音节或字符,配合一个简单的语言模型。如果了解一些音系规则,用“声母+韵母”甚至“音素+声调”这样的复合单元,效果通常比整词好。

微调数据的量级在2到20小时之间。数据量少的时候,微调层的初始化很重要。我建议只随机初始化新加的输出层,其余所有层都保留预训练权重,然后全模型一起微调。但为了防止微调时灾难性遗忘,学习率要用比预训练更小的值,比如1e-5或5e-6。微调时的batch size也别太大,小batch更有利于低资源情况下稳定收敛。

另外一个容易忽略的点:微调阶段一定要固定音频特征的统计分布。如果预训练时用了在线频谱归一化,微调时也要用一模一样的归一化参数。我看到不少项目直接换一套特征提取代码,微调结果莫名其妙差很多,八成就是这个原因。

微调阶段依然可以做噪声增强和速度扰动,但要比预训练轻。因为微调数据的标注是相对准确的,加太多增强反而会增加拟合难度。一般只加轻量级的加噪和速度扰动,噪声幅度在-15dB到-20dB就够。

4.3 损失函数与调参经验

弱监督预训练的主要损失函数,我用的是“逐帧音素分类的交叉熵”,但并不会对每一帧都强求一致。具体做法是在时间轴上对标签做“展宽”,也就是把每个音素标签的有效范围前后各扩展几帧,这样对齐误差不会立刻变成训练损失惩罚。这招对弱监督标签特别有效,我之前不知道为什么,后来想通了:模型不需要精确到帧边界,只需要在某个宽泛区间内输出对应音素,损失就平滑很多,优化过程也不容易震荡。

再加上“多任务学习”的另一个头:用一个二分类头预测“当前帧是否是音素边界”。这个辅助任务能让中间表征保留时间注意力信息,对后续解码很有帮助。这个头的权重不用太高,0.05就够。

调参上遇到过很别扭的问题:预训练loss下降得很快,但微调后目标语言识别率一直不涨。后来排查发现,是因为预训练时用的音素集太高细,大量目标语言音素被映射到同一个高资源语言符号,导致模型没有真正区分目标语言内部的音素对立。解决方法是回到音素集设计,把容易混淆的目标语言音素在预训练时就单独设类,不让它们共享同一个符号。这算是“标签设计”的问题,比调学习率更关键。

5. 常见问题与排查套路

5.1 问题现象、原因与对策速查表

症状可能原因解决思路
预训练loss正常下降,微调后识别率不涨音素集粒度不匹配,目标语言关键对立被合并重新设计音素集,给目标语言特有音素单独类别
微调后模型狂输出同一音节微调数据过少或输出层初始化过大调小输出层初始化尺度,使用标签平滑,加入简单语言模型约束
验证集和训练集效果差异巨大数据划分泄露(同人同段重复)做说话人维度的数据去重和跨集划分
伪标签置信度很高但模型越学越差半自动修正自举偏差把种子集比例提高,或对伪标签加入随机丢弃
增强后效果反而变差增强强度过大,破坏了声调信息减小频段掩蔽比例,去掉激进的变速
多语种预训练只学到了高资源语言目标语言占比太低提高目标语言采样权重到30%~40%
微调时输出头收敛慢预训练头与微调头之间表征偏差异常在微调头上加一个线性温度缩放,稳定概率分布

5.2 避坑笔记

最隐蔽的一个坑是“标签噪声分布不对称”。弱监督标签往往倾向于把难分的音素标成出现频率更高的那个,比如某个语言的清浊音对立已经被词库里少数高频词带偏。这种不对称噪声会让即使置信度阈值很高,伪标签也整体偏向某个类别方向。一个有效的做法是加一个“类别均衡损失”,让辅助分类头预测的全局音素频率和先验分布尽量接近,这样能一定程度上修正偏向。

还有一次,我在预训练后微调时发现模型在无意义的高频音节上迷之自信,说白了就是置信度很高但完全错。排查到最后发现是softmax温度问题。预训练时的音素头输出概率比较分散,微调的新输出层则很容易被一个大数值“带偏”。我会在微调输出层后加一层LayerNorm,并在损失函数里加一点标签平滑,置信度虚高的问题立刻缓解。

最后一个常见坑:混合精度的使用。低资源数据往往很小,模型很容易因为浮点误差在训练后期出现loss抖动。我不是说不能用混合精度,而是要在预训练阶段先用FP32跑少量步数确认基线,再切到FP16做大批量训练。切换后如果看到梯度暴增,就把loss缩放因子调低一格。这个细节看起来不起眼,却救回过我一次连续三天loss不下降的项目。

6. 效果评估与后续扩展

6.1 评估指标选择

语音识别不能只看字错误率,尤其少数民族语言,很多地方没有统一分词规范。我通常用三个指标一起看:音素错误率、词错误率/字符错误率、以及“可理解率”。音素错误率最能反映声学模型本身的好坏,因为它跳过了词典和语言模型的干扰;词错误率反映最终可用性;可理解率是找几本地熟悉语言的人来听写判断,虽然主观,但对低资源语言特别有参考价值。

数据划分建议:至少保证测试集与训练集无说话人重叠。如果条件允许,再专门抽一个“野外环境”测试集,包括不同地区口音和不同采集设备。弱监督模型如果只在一个干净测试集上表现好,很难说真的学到了泛化的音素表征。我在项目中通常把测试集分成三个子集:标准朗读、即兴会话、嘈杂场景,分别统计错误率,这样能快速定位是声学问题还是文本匹配问题。

6.2 优化方向

目前这套流程还有几个可以明显改进的方向。第一,音素单元集可以加入声调和长短音信息,如果目标语言有音位性声调,不要把声调当成额外的离散音素,而是用一组“声调嵌入”和音素嵌入联合预测,这样能在不膨胀分类类别的前提下保留超音段信息。第二,在预训练阶段引入多语言文本自回归任务,把“音素序列到文本字符”的映射也作为一个弱监督目标,长句识别会有增益。第三,把说话人特征单独用对抗学习剥离掉,避免模型把说话人身份和音素混在一起,这样对多方言混合场景更友好。

这些优化不需要推到重来,只是在现有模型头上加辅助任务。我个人的经验是,每加一个辅助头都要先回到预训练阶段验证对目标语言微调的提升,而不是只看辅助任务自身loss。不然很容易出现“预训练指标更好了,识别反而更差”的反直觉情况。好的预训练,一定是让目标语言的微调变得更容易,而不是让预训练自身的分数变得漂亮。

最后说点实在的体会:做少数民族语言语音识别,不要执着于攒高三四百小时的“完美标注”数据才开工,用弱监督音素预训练把手里那几十个小时先跑起来,边训边补数据,效果往往比等数据快得多。我在实际项目中,第一次用这套流程只用了15小时标注数据和80小时无标签数据,就把某个民族语言的语音识别词错误率从纯端到端模型的高位降了下来,同时模型对陌生说话人的鲁棒性也明显增强。音素这个中间层并不神秘,但它确实是低资源语音识别里最值得花心思打磨的地方。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进