第 22 天 · 一个网络听懂两种语言:靠的是规模和工程
一句话
百度团队用一个从频谱图直接输出字符的深度网络,配合 CTC 损失、约 1.2 万小时英语和 9400 小时普通话数据,以及高性能训练系统,让同一套方法在两种差别很大的语言上都接近人类转写水平。
论文讲了什么
结论先行:这篇论文的核心观点是,语音识别不需要按语言手工设计流水线。只要模型足够深、数据足够多、训练系统足够快,同一个端到端网络就能处理英语和普通话。论文一半篇幅讲模型,另一半讲如何把训练速度和部署延迟做上去。
问题。传统语音识别由多个独立模块组成:声学模型、发音词典、语言模型,以及大量手工特征。每换一种语言,都要请专家重做词典和音素集。普通话还有声调和分词问题,迁移成本更高。
模型。输入是音频的频谱图(spectrogram),输出是每一帧上的字符概率分布。网络结构自下而上是:
- 1 到 3 层卷积,同时在时间和频率方向上卷积。
- 1 到 7 层双向循环层,使用简单 RNN 或 GRU。
- 1 层全连接层,再接 softmax。英语输出字母,普通话直接输出汉字。
最深的配置共 11 层(3 层卷积 + 7 层循环 + 1 层全连接)。训练用连接时序分类(CTC)损失,它不需要知道每个字符对应哪一帧。解码时用束搜索(beam search)结合 n-gram 语言模型。
让深网络训得动的技巧。
- 序列级批归一化:只对循环层的"层间输入"做批归一化,不碰时间方向的循环连接。统计量在整个小批次的所有时间步上计算。
- SortaGrad:第 1 个 epoch 按语音长度从短到长训练,之后再随机打乱。短句先学,训练更稳定。
- 行卷积(row convolution):部署时改用单向 RNN,再在顶部用一个只看未来少量帧的卷积层,弥补看不到后文的损失,保证实时性。
- 步长与双字母输出:英语用较大的时间步长减少计算,同时让每一步输出两个字母的组合,避免输出序列比输入还长。
系统工程。作者用同步随机梯度下降在多块 GPU 上做数据并行,自己实现了 all-reduce 通信和 GPU 版 CTC。部署时提出批调度(Batch Dispatch):把同时到达的多个用户请求合成一批送进 GPU,兼顾吞吐和延迟。
关键结果。英语训练数据为 11,940 小时,普通话为 9,400 小时。训练数据每增加 10 倍,词错误率(WER)相对下降约 40%。在 WSJ 和 LibriSpeech clean 等清晰朗读语音上,模型超过了众包转写员。在嘈杂环境和口音语音上,模型仍落后于人类。普通话短语音查询上,模型的错误率低于普通母语转写员。
关键概念
- 端到端(end-to-end)
- 用一个网络直接从原始输入映射到最终输出,中间不插入人工设计的模块。这里指从频谱图直接输出字符,不需要发音词典和音素。
- 连接时序分类(Connectionist Temporal Classification, CTC)
- 一种序列损失。它引入空白符,对所有可能的帧对齐方式求和,因此训练时只需要转写文本,不需要逐帧标注。
- 频谱图(spectrogram)
- 对音频按短时间窗做傅里叶变换得到的二维图,横轴是时间,纵轴是频率,值是能量。它让语音可以用处理图像的卷积来处理。
- 序列级批归一化(sequence-wise batch normalization)
- 只对循环层的层间输入做批归一化,统计量覆盖整个小批次的全部时间步。它让 7 层以上的循环网络收敛更快。
- SortaGrad
- 论文提出的课程学习策略:第 1 个 epoch 按语音长度从短到长排序训练,之后恢复随机顺序。它减少了训练早期的不稳定。
- 行卷积(row convolution)
- 放在单向 RNN 顶部、只看未来少量帧的卷积层。它用很小的延迟换回双向模型的大部分准确率,适合流式识别。
历史位置:为什么值得读
这篇论文是"规模派"在语音领域的宣言。2014 年的 Deep Speech 1 已经证明端到端可行,但只做了英语。Deep Speech 2 把同一套方法扩展到普通话,并用系统化实验说明:数据量、模型深度和训练算力一起增长时,错误率会稳定下降。论文里"训练数据每增加 10 倍、WER 下降约 40%"这类曲线,正是后来缩放定律研究的早期形态。
作者名单本身就是一段历史。第一作者 Dario Amodei 之后去了 OpenAI,再后来创立了 Anthropic。百度同一实验室的研究者 2017 年发表了《Deep Learning Scaling is Predictable, Empirically》,系统测量了多个任务的幂律缩放。第 25 天的缩放定律论文延续了这条思路。
它和清单里其他论文的关系:
- 第 1、2、3 天的 RNN 与 LSTM 是它的主干。
- 第 8 天 AlexNet 开启了"用 GPU 训练大网络",这篇把 GPU 工程推进到多机同步训练。
- 第 24 天 GPipe 继续回答同一个问题:模型和数据变大以后,训练系统怎样跟上。
学前准备
- 理解 RNN 和双向 RNN 的前向计算(先看第 1、2 天)
- 知道傅里叶变换把信号分解成频率成分
- 理解批归一化在训练时如何计算均值和方差
- 会算编辑距离,理解词错误率的定义
在原仓库怎么学
- 运行 setup.py:检查依赖,并确认实现可以正常导入。
- 阅读 data/README.md:了解仓库用合成音频代替真实语料。
- 阅读 implementation.py:找出频谱图提取、卷积前端、双向 RNN、CTC 输出 4 部分。
- 按顺序做 exercises/ 里的 5 个练习:
exercise_01_spectrogram.py计算频谱图,exercise_02_ctc_loss.py实现 CTC 损失,exercise_03_rnn_batchnorm.py实现循环层批归一化,exercise_04_sortagrad.py实现 SortaGrad 排序,exercise_05_end_to_end.py组装完整模型。 - 对照 exercises/solutions/ 检查实现。
- 运行 train_minimal.py:它在合成数据上跑完整流程,包括 CTC、首个 epoch 的 SortaGrad、贪心解码和 WER 统计。可以改
--n-conv、--n-rnn、--rnn-hidden比较深度和宽度。 - 运行 visualization.py:生成频谱图、CTC 输出概率热力图、深度与宽度对比图、WER 与数据量关系图。
- 最后用 notebook.ipynb 复习全流程。
今天再看
"端到端 + 大数据"的路线完全胜出,但具体模型已经换代。2022 年 OpenAI 的 Whisper 用约 68 万小时弱标注数据训练编码器-解码器 Transformer,覆盖近百种语言。RNN 主干基本被 Transformer 和 Conformer 取代。
仍然活着的部分有 3 个:
- CTC 仍是常用损失。wav2vec 2.0 微调、Conformer-CTC 和 NVIDIA 的 Parakeet 系列都用它。
- 对数梅尔频谱图仍是 Whisper 等模型的输入。
- 流式识别仍要面对"能看多少未来帧"的取舍,行卷积的思路在 RNN-T 和分块注意力里延续。
和大语言模型的联系:今天的语音大模型把音频切成离散 token,直接交给语言模型处理。这是端到端思想的下一步,连"识别文字"这个中间步骤也去掉了。
容易卡住的地方
- CTC 解码结果总是重复字母:解码规则是先合并相邻重复字符,再删除空白符。顺序反了会把 hello 里的两个 l 合成一个。
- CTC 损失变成 inf 或 NaN:输出帧数小于标签长度时没有合法对齐。检查卷积步长,确保下采样后的帧数不少于转写字符数。
- 循环层批归一化把填充帧也算进统计量:计算均值和方差时用掩码排除填充位置,否则短句较多的批次统计会失真。
- 合成数据上 WER 很低就以为复现成功:仓库用合成音频演示流程,数字不能和论文比较。重点检查每个模块的输入输出形状和损失下降趋势。
延伸阅读
- 原论文:Deep Speech 2: End-to-End Speech Recognition in English and Mandarin
- 原仓库第 22 天目录:22_deep_speech_2/ —— 代码、笔记本、练习与答案(英文)
- Deep Speech: Scaling up end-to-end speech recognition —— 前作 Deep Speech 1,只做英语
- Sequence Modeling With CTC —— Distill 上图解 CTC 的长文
- Deep Learning Scaling is Predictable, Empirically —— 同一实验室的早期缩放定律研究
- Robust Speech Recognition via Large-Scale Weak Supervision —— Whisper 论文,端到端路线的后继