ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AISHELL-2中文语音数据集实战:从下载到训练端到端ASR全指南

AISHELL-2中文语音数据集实战:从下载到训练端到端ASR全指南 做中文语音识别这些年我经常被人问一个问题想入门 ASR到底该拿什么数据练手我的答案里十有八九会出现 AISHELL-2。这套由 AISHELL 团队开源的中文语音数据库累计约 1000 小时普通话语音来自大约 2000 名不同地域的说话人16kHz 采样、手机录制标注统一领域覆盖智能家居、车载、金融、医疗、教育等常见场景。它既能用来从零训练一个端到端 ASR 模型也能做说话人识别、唤醒词、语音合成甚至前端增强评测对初学者和工业界预训练都非常友好。这篇文章我会把 AISHELL-2 从下载到落地的完整链路拆开来讲包括数据格式、目录结构、训练 baseline 的实操步骤以及我在真实项目里踩过的各种坑。不管你是准备毕业设计还是要快速验证一个新的模型结构这篇都能给你一个比较可靠的起点。1. AISHELL-2 到底是什么一个语音数据集的全景拆解1.1 技术规格不是所有中文数据库都能叫“大规模”所谓“大规模”从来不是只把音频文件堆多就行。AISHELL-2 的核心规格放在今天看依然很能打项目规格语言中文普通话总时长约 1000 小时说话人数约 2000 人男女比例接近均衡采样率16kHz / 16bit / 单声道录音设备智能手机涵盖 Android 和 iOS 多个型号录音环境相对安静的室内但不是严格消声室标注内容汉字级转写另提供词表、拼音、音素相关文件覆盖领域智能家居、车载、金融、医疗、教育、娱乐等数据划分训练 / 开发 / 测试大体按比例划分这些参数里最值得注意的就是“手机录音”和“约 1000 小时”。16kHz 采样是语音识别任务事实上最通用的采样率ASR 学术界大部分 baseline 都以 16kHz 音频为准拿到数据后基本不用做采样率转换可以直接进特征提取。手机录音则意味着数据里带有真实场景的底噪、麦克风差异、说话距离变化这些恰恰是落地最常遇到的干扰。很多人刚接触语音数据时会觉得“安静录音棚里录的数据才是好数据”实际做项目久了你会发现太干净的数据训练出的模型到了会议室、车里、路边这些真实环境效果会掉得很厉害。AISHELL-2 这种“半受控环境”的数据反而更容易挑出模型在真实场景里的毛病。1.2 和 AISHELL-1 以及主流中文数据集对比AISHELL 系列不止有一个版本前面还有 AISHELL-1外面还经常被拿来对比的有 THCHS-30、MagicData、Common Voice 中文部分。把它们放在一起看才能理解为什么 AISHELL-2 经常被选中作为主力训练集。数据集时长说话人采样率录音方式主要适用场景THCHS-30约 30 小时50 人左右16kHz安静环境麦克风小规模验证、教学AISHELL-1约 178 小时400 余人16kHziOS 设备入门级 ASR 训练AISHELL-2约 1000 小时约 2000 人16kHz多种智能手机大规模训练、预训练MagicData约 755 小时1000 余人16kHz手机等设备商业场景、领域定制Common Voice 中文众包持续增长大量众包用户不统一网络录音多口音、噪声鲁棒研究如果你只是想在两天内跑通一个模型流程THCHS-30 和 AISHELL-1 都够用但如果想认真调一组结果或者验证一个端到端模型在“还过得去”的数据量下能到多少AISHELL-2 是更合适的起步选择。它的标注风格和 AISHELL-1 一脉相承从 1 迁移到 2 的成本很低但数据量上了一个量级训练出来的模型明显更稳定也不会像小数据集那样一换随机种子结果就剧烈波动。MagicData 这类商业数据集的优势是准确率更高、错误标注更少但获取成本和授权条件不是每个人都能接受。Common Voice 中文是众包数据口音丰富但噪声和错误也多清洗成本很高。相比之下AISHELL-2 在“开源可获取、规模足够大、标注相对规范”这三个维度上做到了一个很好的平衡。1.3 为什么手机录音反而是这套数据的核心优势刚用 AISHELL-2 的时候我一度嫌它“脏”某些句子有明显的环境底噪个别说话人口音还比较重。但后来拿它做前端增强实验再用改造后的模型接远程麦克风阵列的数据效果反而比用纯消声室数据训练出来的模型要稳。原因很简单真实场景里的语音从来不是安静环境里那种“波形干净得像教科书”的状态。手机录音带来的底噪和混响实际上会给模型一种天然的扰动让模型不至于过度依赖某一个固定的声学特征模式。这也解释了为什么很多在 AISHELL-2 上训练出来的模型迁移到实际 APP 或智能硬件上反而比某些录音棚数据集训练的模型更耐用。当然这不代表可以完全不做数据清洗而是说“有噪数据”经过合理处理后是可以变成优势的。2. 数据格式与目录结构下载后第一件事看什么2.1 下载渠道与压缩包内容AISHELL-2 的常见下载渠道是官方的 OpenSLR 发布页和 AISHELL 官网。打开后你会发现它通常不是单个大文件而是按内容拆成音频包和标注包。音频包是核心里面是 wav 文件部分渠道也会提供 m4a 压缩版方便传输入门阶段做文本分析用但真正训练之前还是要转回 wav或者用工具直接解成 PCM 读入。这里有一个非常实际的建议下载这种大体积数据集尽量不要用浏览器直接拖拽下载。文件一多、体积一上来网络波动导致的断点、丢包很容易让压缩包损坏。推荐用支持断点续传和校验的下载工具下完之后再做一次 md5 校验。我见过不止一个朋友辛辛苦苦下完几十 GB解压到一半报错最后只能从头再来的情况浪费时间不说心态也会崩。解压完成后的目录结构大体上是这样的data_aishell2/ ├── wav/ │ ├── BAC009S0001/ │ │ ├── BAC009S0001W0001.wav │ │ ├── BAC009S0001W0002.wav │ │ └── ... │ ├── BAC009S0002/ │ │ ├── ... │ └── ... ├── transcript/ │ └── aishell_transcript_v2.txt └── ...不同的发布版本顶层目录和批次前缀可能会略有差异但整体逻辑是一致的音频按说话人分组每个说话人一个目录目录里是该说话人的若干条句子。这种组织方式对后续生成说话人信息、做说话人相关实验都非常方便。2.2 文件命名与转录文本格式AISHELL-2 的文件名看起来像一串“无意义”的字符实际上编码了关键信息。以BAC009S0001W0001.wav为例BAC009是采集批次信息S0001是说话人 IDW0001是该说话人下的句子序号。你要是做过 Kaldi 数据准备就会知道这种命名方式简直是天赐良机解析文件名就能直接得到 utterance 和 speaker 的对应关系几乎不需要额外维护元数据表。转录文本文件的格式也非常简洁每一行两段音频文件名加空格后面跟着中文转写文本。文本里的汉字之间用空格隔开类似这样BAC009S0001W0001 在 这 个 月 的 例 会 上 我们 讨论 了 预算 问题 BAC009S0001W0002 请 您 输 入 银 行 卡 号 后 四 位为什么要用空格隔开汉字这是为了兼容各种语音识别工具链的习惯。Kaldi、WeNet、ESPnet 在构建词典和计算标签序列时通常希望文本是一个“token 序列”汉字之间用空格可以省去很多用户侧的分词和处理麻烦。你如果准备写自定义数据加载器直接用split()就能切出干净的字符序列非常舒服。需要注意一点AISHELL-2 的文本里偶尔会出现英文单词、数字、单位符号比如“iPhone”“2022年”“3G”。官方在这类内容上的处理是尽量转成中文读音但多少会存在一些漏网之鱼。做训练之前最好自己写一个文本归一化规则把英文、数字统一转成中文表达否则模型很容易学到“照着读英文”的错误习惯。2.3 词典、拼音与音素标注光有汉字转写还不够做端到端模型时很多 pipeline 需要词典或拼音信息。AISHELL-2 官方在发布标注时会附带词表、音节标注和音素映射之类的文件具体文件名在不同渠道略有区别但用途都一样让你能把中文文本映射成模型可用的输出标签。举个例子银行这个词在词典里可能会被标注为yin2 hang2这样的带声调拼音序列再往下一层是音素序列比如y i n h a ng。做中文识别时你可以选择字符级建模直接用汉字作为输出单元也可以选择拼音级或音素级建模配合语言模型去还原汉字。AISHELL-2 提供的这些映射文件省去了你自己从零做 G2P文字转音素的功夫。不过词典覆盖不了的低频词、人名地名还是需要额外处理这一点后面会单独讲。2.4 训练、开发、测试集怎么划分语音数据集的划分比图像数据更讲究。图像任务你随机打乱图片就行语音数据集如果按句子随机划分同一个说话人的不同句子可能同时出现在训练集和测试集模型就会“记住”这个人说话的音色特征测试时占便宜导致指标虚高。AISHELL-2 在划分时是考虑到了这一点的但在自己写脚本时还是要检查一下。我的习惯是拿到数据后先按说话人粒度查一下重叠关系确保开发集和测试集里的说话人不出现在训练集里或者至少做一个合理的隔离策略。如果你是做说话人识别这个点尤其重要不做说话人隔离的实验基本没有参考价值。3. 从原始音频到可训练数据完整实操流程3.1 准备 Kaldi / WeNet / ESPnet 标准数据格式不管最后用哪个框架训练第一步几乎都是把原始数据整理成wav.scp、text、utt2spk、spk2utt这四个文件。它们是 Kaldi 系工具的通用数据格式WeNet 和 ESPnet 也沿用这一套。wav.scp每一行是utt_id加制表符或空格再加 wav 文件路径。text每一行是utt_id加文本标签序列。utt2spk每一行是utt_id加说话人 ID。spk2utt反过来每个说话人一行后面跟该说话人的所有句子 ID。这个步骤用 Python 写脚本最顺手。核心逻辑就是遍历wav目录解析文件名里的说话人信息然后读取转录文件做匹配import os from pathlib import Path wav_root Path(data_aishell2/wav) trans_path transcript/aishell_transcript_v2.txt trans_map {} with open(trans_path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) 2: continue trans_map[parts[0]] .join(parts[1:]) with open(wav.scp, w, encodingutf-8) as fw, \ open(text, w, encodingutf-8) as ft, \ open(utt2spk, w, encodingutf-8) as fu: for wav_file in sorted(wav_root.rglob(*.wav)): utt_id wav_file.stem if utt_id not in trans_map: continue speaker_id wav_file.parent.name fw.write(f{utt_id} {wav_file}\n) ft.write(f{utt_id} {trans_map[utt_id]}\n) fu.write(f{utt_id} {speaker_id}\n)跑完这个脚本spk2utt可以由utt2spk用框架自带的工具生成不需要自己再写一遍。这一步是整个数据准备的“地基”地基没打牢后面所有实验都会跟着出问题所以哪怕脚本很简单也建议在生成后抽几条音频和文本人工核对一下。3.2 音频预处理与质量检查数据格式整理好之后别急着扔进模型。AISHELL-2 虽然整体质量不错但毕竟是手机录音混进去一些异常样本再正常不过。我每次拿到新数据集都会先跑一遍质量检查主要看三个维度采样率、时长分布、能量异常。先把所有 wav 的格式信息拉出来。假设你已经装了 sox可以用soxi批量检查find data_aishell2/wav -name *.wav | head -20 | xargs -I {} soxi {}重点看Sample Rate是否都是 16000Channels是否为 1Sample Encoding是否为 16-bit。如果有不满足的样本最好统一转一下格式避免训练时 dataloader 报错或特征计算结果不一致。时长分布检查同样简单写个命令统计即可find data_aishell2/wav -name *.wav | xargs -I {} soxi -D {} | awk {sum $1; if($1 0.5) short; if($1 15) long} END {print total_hours:, sum/3600, short:, short, long:, long}我个人会做一轮轻量清洗把时长过短小于 0.5 秒和过长大于 15 秒的样本过滤掉。过短的样本往往是误触发或者静音片段对训练没什么帮助过长的样本则会拉长 batch 内 padding降低训练效率。至于中间那些“有点噪声”的样本除非噪声大到完全盖过人声否则我倾向于保留——它们对提升模型鲁棒性是有价值的。清洗时还有一个容易踩的坑请不要用激进的 VAD 把静音段全切掉。VAD 切完音频之后文本标签和音频之间的对齐关系很容易错位而语音识别训练又特别依赖这种对齐一旦错了模型学到的东西就是错的。3.3 用 WeNet 训练一个端到端 ASR 基线AISHELL-2 训练模型的选择很多Kaldi、ESPnet、WeNet、FunASR 都可以。如果要我推荐一个最容易出结果、新手也友好的方案我会选 WeNet。原因有三一是它的数据格式和 Kaldi 兼容前面的数据准备工作直接复用二是它把流式和非流式模型统一在一个框架里实验对比方便三是它提供了完整的run.sh脚本不用自己拼装各种训练、解码、打分流程。安装和数据处理不多说直接看核心。我们先用 AISHELL-2 生成的数据转换成 WeNet 期望的格式一般就是把你整理好的wav.scp、text、utt2spk、spk2utt放进对应目录。然后用它自带的脚本做特征统计和 CMVN 计算。模型配置方面我会选一个基于 Conformer 的模型。下面是一个简化版的 YAML 配置思路实际使用时要根据显存和显卡数量调整 batch sizemodel: cmvn: true encoder: conformer encoder_conf: output_size: 256 attention_heads: 4 linear_units: 2048 num_blocks: 12 dropout_rate: 0.1 positional_dropout_rate: 0.1 attention_dropout_rate: 0.1 decoder: bitransformer decoder_conf: attention_heads: 4 linear_units: 2048 num_blocks: 6 dropout_rate: 0.1 dataset_conf: batch_type: bucket batch_size: 32 max_length: 2048 spec_aug: true training: max_epoch: 200 save_epoch: 5 optimizer: adam scheduler: warmuplr warmup_steps: 25000 ctc_weight: 0.3这种配置在那个年代其实是现在也依然算是非常标准的端到端中文 ASR baseline。ctc_weight: 0.3的意思是训练时把 CTC loss 和注意力 loss 按 0.3 / 0.7 的权重混合CTC 这一路能帮模型更快收敛注意力这一路则负责更精细的对齐和生成。实际跑起来之后在 AISHELL-2 训练集上训练一个 Conformer大概 150 到 260 个 epoch 就能看到比较稳定的结果。以我自己和身边人复现的公开经验来看开发集上的 CER 一般能做到 5% 上下测试集会高一点在 6% 到 7% 左右。这个数字会因为你的数据清洗策略、随机种子、batch size 和音频后端实现略有浮动不用太纠结具体某一个数关键是你的实验设置要固定方便横向对比不同改动。训练完成后解码和打分可以直接用 WeNet 提供的recognize.py和打分工具。如果发现 CER 偏高先看是不是文本归一化没做好比如数字、英文符号没有被正确转成中文。这类问题在 AISHELL-2 这种带领域多样性的数据集上很常见也是最容易被忽略的“指标杀手”。3.4 如果不做 ASRAISHELL-2 还能干很多事很多人以为语音数据集只能用来训“语音转文字”其实 AISHELL-2 这类大规模中文语料的价值远不止于此。做 TTS 的人可以把 AISHELL-2 用来做数据增强和预训练让合成模型在音色多样性上更有底气做说话人识别的人可以利用里面清晰的说话人目录结构直接构造训练、注册和测试样本做唤醒词和语音命令识别的人可以从中筛出“你好小X”“请打开空调”这类命令句式当作负样本或正样本使用。甚至做语音增强的人也可以拿 AISHELL-2 当干净参考语料和各类噪声库混合后构造带噪训练数据。总之这套数据就像一块积木放在不同的研究拼图里都能用。4. 常见问题与排查技巧实录4.1 典型错误与解决方案速查表我用 AISHELL-2 期间踩过的和见过别人踩过的坑基本可以总结成一张表现象可能原因解决办法解压到一半报错压缩包下载损坏核对 md5重新下载用支持断点校验的工具训练时某些 wav 读不出来文件头损坏用 ffmpeg 重转一次或从原始包重新提取soxi显示的采样率不统一混入非标准文件批量重采样为 16kHz 单声道transcript 里有英文和数字未做文本归一化写规则将英文、数字转为中文读法部分生僻汉字 OOV词典覆盖不足使用字符级建模或扩充词典开发集 CER 远低于测试集划分未做说话人隔离按说话人重新划分数据训练中期 loss 突然上涨数据混入异常、学习率过大清理数据、降低峰值学习率解码结果全是重复字符CTC 对齐没学好检查文本是否错位增大ctc_weight或调整 batch这些问题的共性是大多数都不是模型结构本身的错而是数据或流程里的某一个“小毛病”积累成了大问题。遇到指标异常先怀疑数据和格式再怀疑模型能省去大量无意义的时间。4.2 数据质量方面踩过的坑AISHELL-2 整体标注质量在开源数据里算好的但不是完美。我印象最深的一类问题是“吞音”。手机录音时很多人说话语速偏快句尾的尾音经常被吞掉尤其是轻声和语气词。这对人工听懂没有影响但模型的标签序列是标准文本音频里却没有对应的清晰发音训练时模型就会被“逼”着学习一种带有偏差的映射。遇到这种样本我通常不会删除而是把它当作一种自然存在的发音变体因为它们恰恰反映了真实场景的分布。第二个常见问题是同音字错误。中文识别评估用的是字错误率CER一个字错了就算一个错。当我们不加语言模型或语言模型比较弱时模型输出的“查询”和标注里的“查寻”这类同音异形替换会很多。这种错误并不是模型完全不认识音频而是字的概率分布里多个候选都很高。遇到这种情况与其调声学模型不如花时间在语言模型或解码策略上。第三个问题是极少量的“标注错字”。AISHELL-2 虽经过审核但一千小时的文本量出现个别错字在所难免。我建议在正式训练前抽几百条人工听一下感受一下数据标注风格和文本匹配程度并记录发现的问题类型。这个抽检过程不用太复杂目的只是让你心里有底知道这套数据在哪些地方可能拖累最终指标。4.3 提升训练效果的几条可行路径如果你不满足于跑通 baseline想在 AISHELL-2 上把指标再往上提我按投入产出比排一下序。第一优先是数据增强。SpecAugment 几乎是必须开的它在频谱图上随机遮蔽部分时间步和频率通道相当于免费给模型加扰动对降低过拟合特别有效。WeNet 和 ESPnet 的默认配置里都有记得确认没关掉。第二优先是文本归一化和词典扩充。把训练集里所有数字、英文统一转成中文读法能减少模型输出单元的混乱再构造一个覆盖人名、地名、网络新词的扩展词典或者直接采用字符级建模能有效降低 OOV。第三优先才是换更大的模型。很多人一上来就想上超大模型和大 batch但其实在 AISHELL-2 这个量级上一个 12 层 Conformer encoder 已经能跑出不错的结果。想再进一步提升可以考虑用公开的预训练模型做初始化或者在训练后期加入外部语言模型做联合解码。另外数据清洗上多做一点功课往往比扩大模型尺寸更有效率。我在实际使用中还有一个特别深的体会实验记录的规范性比跑模型本身更重要。AISHELL-2 可以衍生出非常多的对比实验如果换一次随机种子、改一个增强参数都不记录最后你很可能分不清哪个改动真正带来了提升。建议每次实验固定一个编号配置文件、数据列表、训练日志、评估结果放在同一个目录下这样回看时一目了然。最后再分享一个小技巧。很多人训练完只看 CER 一个数字我习惯把误识别样本按“替换 / 删除 / 插入”三类分开统计再抽几条典型的错误做听力分析。替换多说明声学模型分得不够细删除多说明音频里有吞音或静音被识别空了插入多则往往和前后端噪声有关。这种分析不会直接提升指标但能帮你判断下一步该优化哪个环节比盲目换模型结构要靠谱得多。AISHELL-2 作为一套开源数据真正值得挖掘的远不止“跑通”这个层面你把它用到什么深度决定了你能从它身上学到多少。
返回列表