语音识别:隐马尔可夫模型、深度学习与序列转导

目录

  • 第一部分:语音信号基础
    • 第一章:绪论------语音识别的理论框架
    • 第二章:语音信号的产生与感知
    • 第三章:语音特征提取------从波形到特征向量
  • 第二部分:声学建模
    • 第四章:隐马尔可夫模型(HMM)理论
    • 第五章:高斯混合模型与 HMM 训练
    • 第六章:深度神经网络声学模型
  • 第三部分:序列建模与解码
    • 第七章:语言模型
    • 第八章:解码与搜索
    • 第九章:序列判别训练
  • 第四部分:端到端模型
    • 第十章:CTC(连接时序分类)
    • 第十一章:注意力机制与编码器-解码器
    • 第十二章:RNN-T(循环神经网络变换器)
  • 第五部分:理论分析与前沿
    • 第十三章:语音识别的信息论视角
    • 第十四章:SSM 与语音识别
    • 第十五章:多任务学习与自监督
    • 第十六章:完整可运行代码实现
  • 附录

第一部分:语音信号基础


第一章:绪论------语音识别的理论框架

1.1 语音识别问题的数学形式化

语音识别的核心问题是:

给定声学观测序列 O=(o1,o2,...,oT)O = (o_1, o_2, \dots, o_T)O=(o1,o2,...,oT),找到最可能的词序列 W∗=(w1,w2,...,wM)W^* = (w_1, w_2, \dots, w_M)W∗=(w1,w2,...,wM)。

用贝叶斯公式表示:

W∗=arg⁡max⁡WP(W∣O)=arg⁡max⁡WP(O∣W)P(W)P(O)W^* = \arg\max_W P(W|O) = \arg\max_W \frac{P(O|W) P(W)}{P(O)}W∗=argWmaxP(W∣O)=argWmaxP(O)P(O∣W)P(W)

由于 P(O)P(O)P(O) 与 WWW 无关,可以简化为:

W∗=arg⁡max⁡WP(O∣W)⋅P(W)W^* = \arg\max_W P(O|W) \cdot P(W)W∗=argWmaxP(O∣W)⋅P(W)

这个公式将语音识别分解为三个独立的模块:

模块 数学表示 作用
声学模型 $P(O W)$
语言模型 P(W)P(W)P(W) 词序列的先验概率
解码器 arg⁡max⁡W\arg\max_WargmaxW 搜索最可能的词序列

1.2 语音识别的层次结构

语音识别涉及多个层次的映射:

复制代码
声波 → 帧特征 → 音素 → 子词 → 词 → 句子
(波形)  (MFCC)  (HMM)  (BPE)  (词典) (语言模型)

每个层次对应不同的理论工具:

层次 输入 输出 理论工具
信号处理 波形 特征向量 傅里叶变换、滤波器组
声学建模 特征序列 音素/子词 HMM、DNN
语言建模 历史词 下一个词 N-gram、Transformer
解码 所有信息 词序列 动态规划、束搜索

1.3 语音识别的历史脉络

年份 里程碑 贡献者 贡献
1952 Audrey Bell Labs 第一个数字语音识别系统
1960s 动态时间规整 Vintsyuk DTW 算法
1970s 隐马尔可夫模型 Baker, Jelinek HMM 用于语音
1980s 统计方法 IBM, CMU 大词汇量连续语音识别
1990s 最大熵模型 多位学者 判别训练
2000s 深度学习 Hinton et al. DNN-HMM 混合系统
2012 端到端 CTC Graves et al. CTC 损失函数
2015 注意力机制 Chan et al. Listen, Attend and Spell
2018 自监督预训练 Schneider et al. Wav2Vec
2020+ 大规模预训练 OpenAI, Meta Whisper, Wav2Vec 2.0

1.4 本文的组织

本文从语音信号的物理特性出发,逐步构建出现代语音识别的完整理论体系。我们特别关注:

  1. HMM 的数学理论:为什么 HMM 适合语音识别?
  2. CTC 的理论基础:如何解决输入输出不对齐问题?
  3. 注意力机制:如何学习输入输出之间的对齐?
  4. SSM 与语音:状态空间模型如何用于语音?

第二章:语音信号的产生与感知

2.1 语音的产生机制

2.1.1 语音产生模型

人类语音的产生可以建模为源-滤波器模型

s(t)=e(t)∗h(t)s(t) = e(t) * h(t)s(t)=e(t)∗h(t)

其中:

  • s(t)s(t)s(t):语音信号
  • e(t)e(t)e(t):激励源(声门脉冲或噪声)
  • h(t)h(t)h(t):声道滤波器(传递函数)
  • ∗*∗:卷积

浊音 (voiced):声带振动产生准周期脉冲,如 /a/, /i/, /u/

清音(unvoiced):气流通过狭窄通道产生噪声,如 /s/, /f/, /sh/

2.1.2 声道的共振特性

声道(咽腔、口腔、鼻腔)是一个非均匀的声学管道,具有多个共振峰(formants)。

共振峰频率 F1,F2,F3,...F_1, F_2, F_3, \dotsF1,F2,F3,... 决定了不同的元音:

元音 F1F_1F1 (Hz) F2F_2F2 (Hz) 位置
/i/ 270 2290 前高
/e/ 530 1840 前中
/a/ 730 1090 中低
/o/ 570 840 后中
/u/ 300 870 后高

2.1.3 语音的时变特性

语音信号是非平稳的------声道形状随时间变化,导致频谱特性变化。

但在短时间内(10-30 ms),语音可以近似为平稳的------这是短时分析的基础。

2.2 语音的感知特性

2.2.1 人耳的频率感知

人耳对频率的感知是对数 的,而非线性的。这导致了梅尔尺度(Mel scale)的引入:

mel(f)=2595⋅log⁡10(1+f700)\text{mel}(f) = 2595 \cdot \log_{10}\left(1 + \frac{f}{700}\right)mel(f)=2595⋅log10(1+700f)

在梅尔尺度上,等距的频率间隔在感知上是等距的。

2.2.2 掩蔽效应

同时掩蔽:一个强信号会掩蔽同一时间的弱信号(频率接近时更明显)。

时序掩蔽:一个强信号会掩蔽其前后的弱信号。

2.2.3 响度感知

响度与强度的关系近似为对数关系------这是分贝(dB)标度的基础:

L=10log⁡10II0L = 10 \log_{10} \frac{I}{I_0}L=10log10I0I

2.3 语音的统计特性

2.3.1 短时平稳性

语音信号在短时间内(10-30 ms)可以近似为平稳随机过程。

2.3.2 非高斯性

语音信号的幅度分布通常是非高斯的------存在尖峰和重尾。

2.3.3 长时依赖

语音存在长时依赖------音素、音节、词之间有复杂的时序关系。这正是 SSM 和 Transformer 的优势所在。


第三章:语音特征提取------从波形到特征向量

3.1 预处理

3.1.1 预加重

高频部分通常能量较低,预加重滤波器提升高频:

yn=xn−αxn−1,α≈0.97yn = xn - \alpha xn-1, \quad \alpha \approx 0.97yn=xn−αxn−1,α≈0.97

这使得频谱更平坦,有利于后续分析。

3.1.2 分帧加窗

将连续信号分成短帧(通常 20-30 ms),每帧乘以窗函数:

xmn=xn+mH⋅wn,n=0,1,...,N−1x_mn = xn + mH \cdot wn, \quad n = 0, 1, \dots, N-1xmn=xn+mH⋅wn,n=0,1,...,N−1

其中 HHH 是帧移(hop size),wnwnwn 是窗函数(通常为 Hamming 窗)。

3.1.3 端点检测

检测语音的起始和结束点,去除静音段。

3.2 短时傅里叶变换(STFT)

3.2.1 定义

Xmk=∑n=0N−1xmne−j2πkn/NX_mk = \sum_{n=0}^{N-1} x_mn e^{-j2\pi kn/N}Xmk=n=0∑N−1xmne−j2πkn/N

STFT 给出了信号在时间和频率上的二维表示------语谱图(spectrogram)。

3.2.2 语谱图

语谱图是 ∣Xmk∣2|X_mk|^2∣Xmk∣2 的时频表示:

  • 横轴:时间
  • 纵轴:频率
  • 亮度:能量

语谱图是语音识别中最重要的可视化工具。

3.3 梅尔频率倒谱系数(MFCC)

3.3.1 计算流程

MFCC 的计算流程:

复制代码
波形 → 预加重 → 分帧加窗 → FFT → 梅尔滤波器组 → 对数 → DCT → MFCC

3.3.2 梅尔滤波器组

梅尔滤波器组是一组三角形带通滤波器,在梅尔尺度上均匀分布:

Hmk={0k<fm−1k−fm−1fm−fm−1fm−1≤k≤fmfm+1−kfm+1−fmfm≤k≤fm+10k>fm+1H_mk = \begin{cases} 0 & k < fm-1 \\ \frac{k - fm-1}{fm - fm-1} & fm-1 \leq k \leq fm \\ \frac{fm+1 - k}{fm+1 - fm} & fm \leq k \leq fm+1 \\ 0 & k > fm+1 \end{cases}Hmk=⎩ ⎨ ⎧0fm−fm−1k−fm−1fm+1−fmfm+1−k0k<fm−1fm−1≤k≤fmfm≤k≤fm+1k>fm+1

3.3.3 对数能量

对每个滤波器的输出取对数:

Sm=log⁡(∑k∣Xk∣2Hmk)Sm = \log\left(\sum_k |Xk|^2 H_mk\right)Sm=log(k∑∣Xk∣2Hmk)

取对数的原因:

  1. 人耳对响度的感知是对数的
  2. 使特征分布更接近高斯
  3. 便于后续的倒谱分析

3.3.4 离散余弦变换(DCT)

对对数能量进行 DCT:

cn=∑m=0M−1Smcos⁡(πn(m+0.5)M)cn = \sum_{m=0}^{M-1} Sm \cos\left(\frac{\pi n (m + 0.5)}{M}\right)cn=m=0∑M−1Smcos(Mπn(m+0.5))

DCT 的作用:

  1. 去相关:将相关的滤波器输出转换为近似独立的系数
  2. 压缩:大部分信息集中在前几个系数
  3. 降维:通常只保留前 13 个系数

3.3.5 MFCC 的物理意义

  • c0c_0c0:对数能量(语音/非语音检测)
  • KaTeX parse error: Expected '}', got 'EOF' at end of input: c_1 - c_{12:频谱包络的低频变化(共振峰信息)
  • 高阶系数:频谱细节(通常被丢弃)

3.4 动态特征

3.4.1 一阶差分(Delta)

Δcn=∑k=1Kk(cn+k−cn−k)2∑k=1Kk2\Delta cn = \frac{\sum_{k=1}^{K} k(cn+k - cn-k)}{2\sum_{k=1}^{K} k^2}Δcn=2∑k=1Kk2∑k=1Kk(cn+k−cn−k)

一阶差分捕捉特征的变化率------近似于速度信息。

3.4.2 二阶差分(Delta-Delta)

ΔΔcn=∑k=1Kk(Δcn+k−Δcn−k)2∑k=1Kk2\Delta\Delta cn = \frac{\sum_{k=1}^{K} k(\Delta cn+k - \Delta cn-k)}{2\sum_{k=1}^{K} k^2}ΔΔcn=2∑k=1Kk2∑k=1Kk(Δcn+k−Δcn−k)

二阶差分捕捉特征的加速度信息。

3.4.3 完整特征向量

标准 MFCC 特征向量通常包含:

ot=c0,c1,...,c12,Δc0,...,Δc12,ΔΔc0,...,ΔΔc12T\mathbf{o}_t = c_0, c_1, \\dots, c_{12}, \\Delta c_0, \\dots, \\Delta c_{12}, \\Delta\\Delta c_0, \\dots, \\Delta\\Delta c_{12}^Tot=c0,c1,...,c12,Δc0,...,Δc12,ΔΔc0,...,ΔΔc12T

维度:39(13 静态 + 13 一阶差分 + 13 二阶差分)

3.5 滤波器组特征(Fbank)

3.5.1 与 MFCC 的区别

Fbank 特征跳过 DCT 步骤,直接使用对数梅尔滤波器组能量:

ot=S1,S2,...,SMT\mathbf{o}_t = S_1, S_2, \\dots, S_M^Tot=S1,S2,...,SMT

3.5.2 为什么深度学习偏爱 Fbank

  • DCT 是线性变换,深度网络可以自己学习
  • Fbank 保留了更多信息
  • DCT 假设特征独立,但深度网络可以处理相关特征

3.6 特征归一化

3.6.1 倒谱均值减(CMS)

c^n=cn−1T∑t=1Tctn\hat{c}n = cn - \frac{1}{T}\sum_{t=1}^{T} c_tnc^n=cn−T1t=1∑Tctn

去除录音环境的影响(假设环境影响是加性的)。

3.6.2 方差归一化

c^n=cn−μnσn\hat{c}n = \frac{cn - \mu_n}{\sigma_n}c^n=σncn−μn

使不同维度的特征具有相同的尺度。

3.6.3 CMVN(倒谱均值方差归一化)

结合均值减和方差归一化,是最常用的特征归一化方法。


第二部分:声学建模


第四章:隐马尔可夫模型(HMM)理论

4.1 HMM 的定义

4.1.1 模型结构

隐马尔可夫模型(Hidden Markov Model, HMM) 由以下参数定义:

λ=(π,A,B)\lambda = (\pi, A, B)λ=(π,A,B)

其中:

  • π={πi}\pi = \{\pi_i\}π={πi}:初始状态概率,πi=P(q1=si)\pi_i = P(q_1 = s_i)πi=P(q1=si)
  • A={aij}A = \{a_{ij}\}A={aij}:状态转移概率,aij=P(qt+1=sj∣qt=si)a_{ij} = P(q_{t+1} = s_j | q_t = s_i)aij=P(qt+1=sj∣qt=si)
  • B={bj(o)}B = \{b_j(o)\}B={bj(o)}:观测概率,bj(o)=P(ot∣qt=sj)b_j(o) = P(o_t | q_t = s_j)bj(o)=P(ot∣qt=sj)

4.1.2 两个基本假设

马尔可夫假设:当前状态只依赖于前一个状态:

P(qt∣qt−1,qt−2,...,q1)=P(qt∣qt−1)P(q_t | q_{t-1}, q_{t-2}, \dots, q_1) = P(q_t | q_{t-1})P(qt∣qt−1,qt−2,...,q1)=P(qt∣qt−1)

输出独立假设:当前观测只依赖于当前状态:

P(ot∣qt,qt−1,...,ot−1,... )=P(ot∣qt)P(o_t | q_t, q_{t-1}, \dots, o_{t-1}, \dots) = P(o_t | q_t)P(ot∣qt,qt−1,...,ot−1,...)=P(ot∣qt)

4.1.3 HMM 的三个基本问题

问题 数学描述 算法
评估 $P(O \lambda)$
解码 $\arg\max_Q P(Q O, \lambda)$
学习 $\arg\max_\lambda P(O \lambda)$

4.2 前向算法

4.2.1 前向变量定义

αt(i)=P(o1,o2,...,ot,qt=si∣λ)\alpha_t(i) = P(o_1, o_2, \dots, o_t, q_t = s_i | \lambda)αt(i)=P(o1,o2,...,ot,qt=si∣λ)

4.2.2 递推公式

初始化

α1(i)=πibi(o1)\alpha_1(i) = \pi_i b_i(o_1)α1(i)=πibi(o1)

递推

αt+1(j)=∑i=1Nαt(i)aijbj(ot+1)\alpha_{t+1}(j) = \left\\sum_{i=1}\^{N} \\alpha_t(i) a_{ij}\\right b_j(o_{t+1})αt+1(j)=i=1∑Nαt(i)aijbj(ot+1)

终止

P(O∣λ)=∑i=1NαT(i)P(O|\lambda) = \sum_{i=1}^{N} \alpha_T(i)P(O∣λ)=i=1∑NαT(i)

4.2.3 计算复杂度

前向算法的复杂度为 O(N2T)O(N^2 T)O(N2T),其中 NNN 是状态数,TTT 是序列长度。

直接计算 P(O∣λ)P(O|\lambda)P(O∣λ) 需要 O(NT)O(N^T)O(NT)------前向算法将指数复杂度降为多项式!

4.3 后向算法

4.3.1 后向变量定义

βt(i)=P(ot+1,ot+2,...,oT∣qt=si,λ)\beta_t(i) = P(o_{t+1}, o_{t+2}, \dots, o_T | q_t = s_i, \lambda)βt(i)=P(ot+1,ot+2,...,oT∣qt=si,λ)

4.3.2 递推公式

初始化

βT(i)=1\beta_T(i) = 1βT(i)=1

递推

βt(i)=∑j=1Naijbj(ot+1)βt+1(j)\beta_t(i) = \sum_{j=1}^{N} a_{ij} b_j(o_{t+1}) \beta_{t+1}(j)βt(i)=j=1∑Naijbj(ot+1)βt+1(j)

4.3.3 前向-后向关系

P(O∣λ)=∑i=1Nαt(i)βt(i),∀tP(O|\lambda) = \sum_{i=1}^{N} \alpha_t(i) \beta_t(i), \quad \forall tP(O∣λ)=i=1∑Nαt(i)βt(i),∀t

4.4 Viterbi 算法

4.4.1 问题定义

找到最可能的状态序列:

Q∗=arg⁡max⁡QP(Q∣O,λ)Q^* = \arg\max_Q P(Q|O, \lambda)Q∗=argQmaxP(Q∣O,λ)

4.4.2 Viterbi 变量

δt(i)=max⁡q1,...,qt−1P(q1,...,qt−1,qt=si,o1,...,ot∣λ)\delta_t(i) = \max_{q_1, \dots, q_{t-1}} P(q_1, \dots, q_{t-1}, q_t = s_i, o_1, \dots, o_t | \lambda)δt(i)=q1,...,qt−1maxP(q1,...,qt−1,qt=si,o1,...,ot∣λ)

4.4.3 递推公式

初始化

δ1(i)=πibi(o1)\delta_1(i) = \pi_i b_i(o_1)δ1(i)=πibi(o1)

递推

δt+1(j)=max⁡iδt(i)⋅aij⋅bj(ot+1)\delta_{t+1}(j) = \max_i \\delta_t(i) \\cdot a_{ij} \cdot b_j(o_{t+1})δt+1(j)=imaxδt(i)⋅aij⋅bj(ot+1)

回溯

qt∗=ψt+1(qt+1∗)q_t^* = \psi_{t+1}(q_{t+1}^*)qt∗=ψt+1(qt+1∗)

其中 ψt(j)=arg⁡max⁡iδt−1(i)⋅aij\psi_t(j) = \arg\max_i \\delta_{t-1}(i) \\cdot a_{ij}ψt(j)=argmaxiδt−1(i)⋅aij

4.4.4 Viterbi 与前向的关系

Viterbi 算法将前向算法中的求和替换为取最大值------这是动态规划的经典应用。

4.5 Baum-Welch 算法

4.5.1 期望最大化(EM)框架

Baum-Welch 算法是 EM 算法在 HMM 上的特例。

E 步:计算期望的统计量

γt(i)=P(qt=si∣O,λ)=αt(i)βt(i)∑jαt(j)βt(j)\gamma_t(i) = P(q_t = s_i | O, \lambda) = \frac{\alpha_t(i) \beta_t(i)}{\sum_j \alpha_t(j) \beta_t(j)}γt(i)=P(qt=si∣O,λ)=∑jαt(j)βt(j)αt(i)βt(i)

ξt(i,j)=P(qt=si,qt+1=sj∣O,λ)=αt(i)aijbj(ot+1)βt+1(j)∑i,jαt(i)aijbj(ot+1)βt+1(j)\xi_t(i,j) = P(q_t = s_i, q_{t+1} = s_j | O, \lambda) = \frac{\alpha_t(i) a_{ij} b_j(o_{t+1}) \beta_{t+1}(j)}{\sum_{i,j} \alpha_t(i) a_{ij} b_j(o_{t+1}) \beta_{t+1}(j)}ξt(i,j)=P(qt=si,qt+1=sj∣O,λ)=∑i,jαt(i)aijbj(ot+1)βt+1(j)αt(i)aijbj(ot+1)βt+1(j)

M 步:更新参数

π^i=γ1(i)\hat{\pi}_i = \gamma_1(i)π^i=γ1(i)

a^ij=∑t=1T−1ξt(i,j)∑t=1T−1γt(i)\hat{a}{ij} = \frac{\sum{t=1}^{T-1} \xi_t(i,j)}{\sum_{t=1}^{T-1} \gamma_t(i)}a^ij=∑t=1T−1γt(i)∑t=1T−1ξt(i,j)

b^j(o)=∑t:ot=oγt(j)∑t=1Tγt(j)\hat{b}j(o) = \frac{\sum{t: o_t = o} \gamma_t(j)}{\sum_{t=1}^{T} \gamma_t(j)}b^j(o)=∑t=1Tγt(j)∑t:ot=oγt(j)

4.5.2 收敛性

定理 4.1:Baum-Welch 算法保证对数似然单调递增:

log⁡P(O∣λk+1)≥log⁡P(O∣λk)\log P(O|\lambda_{k+1}) \geq \log P(O|\lambda_k)logP(O∣λk+1)≥logP(O∣λk)

但只能保证收敛到局部最优。


第五章:高斯混合模型与 HMM 训练

5.1 高斯混合模型(GMM)

5.1.1 定义

高斯混合模型是多个高斯分布的加权和:

bj(o)=∑k=1KwjkN(o;μjk,Σjk)b_j(o) = \sum_{k=1}^{K} w_{jk} \mathcal{N}(o; \mu_{jk}, \Sigma_{jk})bj(o)=k=1∑KwjkN(o;μjk,Σjk)

其中:

  • wjkw_{jk}wjk:第 kkk 个分量的权重
  • μjk\mu_{jk}μjk:均值向量
  • Σjk\Sigma_{jk}Σjk:协方差矩阵
  • N(o;μ,Σ)\mathcal{N}(o; \mu, \Sigma)N(o;μ,Σ):多元高斯分布

5.1.2 GMM 的表达能力

定理 5.1(通用逼近):足够多分量的 GMM 可以以任意精度逼近任何连续概率密度函数。

这使得 GMM 成为 HMM 观测概率的强大参数化工具。

5.2 GMM-HMM 系统

5.2.1 模型结构

在 GMM-HMM 系统中:

  • 每个 HMM 状态对应一个 GMM
  • GMM 建模该状态的观测分布

bj(o)=∑k=1KjwjkN(o;μjk,Σjk)b_j(o) = \sum_{k=1}^{K_j} w_{jk} \mathcal{N}(o; \mu_{jk}, \Sigma_{jk})bj(o)=k=1∑KjwjkN(o;μjk,Σjk)

5.2.2 三音素建模

上下文相关的三音素(triphone)建模:

bl−c+r(o)=GMM for center phone c in context l-c-rb_{l-c+r}(o) = \text{GMM for center phone } c \text{ in context } l \text{-}c\text{-}rbl−c+r(o)=GMM for center phone c in context l-c-r

三音素的数量远大于单音素,需要状态绑定(tying)来减少参数。

5.2.3 决策树绑定

使用决策树对相似的三音素状态进行绑定:

复制代码
                    根节点
                   /      \
              元音?        辅音?
             /    \        /    \
           F1>500?  ...  VOT>30?  ...

5.3 GMM 参数估计

5.3.1 EM 算法

GMM 参数通过 EM 算法估计:

E 步:计算后验概率

γjk(t)=wjkN(ot;μjk,Σjk)∑lwjlN(ot;μjl,Σjl)\gamma_{jk}(t) = \frac{w_{jk} \mathcal{N}(o_t; \mu_{jk}, \Sigma_{jk})}{\sum_{l} w_{jl} \mathcal{N}(o_t; \mu_{jl}, \Sigma_{jl})}γjk(t)=∑lwjlN(ot;μjl,Σjl)wjkN(ot;μjk,Σjk)

M 步:更新参数

w^jk=∑tγjk(t)∑t∑lγjl(t)\hat{w}{jk} = \frac{\sum_t \gamma{jk}(t)}{\sum_t \sum_l \gamma_{jl}(t)}w^jk=∑t∑lγjl(t)∑tγjk(t)

μ^jk=∑tγjk(t)ot∑tγjk(t)\hat{\mu}{jk} = \frac{\sum_t \gamma{jk}(t) o_t}{\sum_t \gamma_{jk}(t)}μ^jk=∑tγjk(t)∑tγjk(t)ot

Σ^jk=∑tγjk(t)(ot−μ^jk)(ot−μ^jk)T∑tγjk(t)\hat{\Sigma}{jk} = \frac{\sum_t \gamma{jk}(t) (o_t - \hat{\mu}{jk})(o_t - \hat{\mu}{jk})^T}{\sum_t \gamma_{jk}(t)}Σ^jk=∑tγjk(t)∑tγjk(t)(ot−μ^jk)(ot−μ^jk)T

5.3.2 分量分裂

训练 GMM 的常用策略:

  1. 先训练少量分量的 GMM
  2. 将每个分量分裂为两个
  3. 继续训练
  4. 重复直到达到目标分量数

第六章:深度神经网络声学模型

6.1 DNN-HMM 混合系统

6.1.1 基本思想

用深度神经网络(DNN)替代 GMM 来估计 HMM 的观测概率:

bj(ot)=P(sj∣ot)=softmax(DNN(ot))jb_j(o_t) = P(s_j | o_t) = \text{softmax}(\text{DNN}(o_t))_jbj(ot)=P(sj∣ot)=softmax(DNN(ot))j

注意:DNN 直接估计后验概率 P(state∣observation)P(\text{state}|\text{observation})P(state∣observation),而不是似然 P(observation∣state)P(\text{observation}|\text{state})P(observation∣state)。

通过贝叶斯规则转换:

P(ot∣sj)=P(sj∣ot)P(ot)P(sj)P(o_t | s_j) = \frac{P(s_j | o_t) P(o_t)}{P(s_j)}P(ot∣sj)=P(sj)P(sj∣ot)P(ot)

6.1.2 上下文窗口

DNN 的输入不是单帧,而是上下文窗口:

xt=ot−L,...,ot,...,ot+L\mathbf{x}_t = o_{t-L}, \\dots, o_t, \\dots, o_{t+L}xt=ot−L,...,ot,...,ot+L

典型窗口大小:L=5L = 5L=5(共 11 帧)。

6.1.3 DNN 架构

标准 DNN 声学模型:

  • 输入:d×(2L+1)d \times (2L+1)d×(2L+1)(特征维度 × 窗口大小)
  • 隐藏层:3-7 层,每层 1024-2048 个神经元
  • 激活函数:ReLU, sigmoid
  • 输出层:softmax(状态数)

6.2 卷积神经网络(CNN)

6.2.1 时频卷积

在语谱图上应用 2D 卷积:

ht,f=σ(∑m∑nwm,nxt+m,f+n+b)h_{t,f} = \sigma\left(\sum_{m}\sum_{n} w_{m,n} x_{t+m, f+n} + b\right)ht,f=σ(m∑n∑wm,nxt+m,f+n+b)

  • 时间轴卷积:捕捉时序模式
  • 频率轴卷积:捕捉频率模式

6.2.2 TDNN(时延神经网络)

TDNN 在时间轴上使用卷积:

ht=σ(∑τ=−TTwτxt+τ+b)h_t = \sigma\left(\sum_{\tau=-T}^{T} w_\tau x_{t+\tau} + b\right)ht=σ(τ=−T∑Twτxt+τ+b)

TDNN 可以看作 1D CNN 的特例。

6.3 循环神经网络(RNN)

6.3.1 基本 RNN

ht=σ(Whht−1+Wxxt+b)h_t = \sigma(W_h h_{t-1} + W_x x_t + b)ht=σ(Whht−1+Wxxt+b)

问题:梯度消失/爆炸,难以捕捉长时依赖。

6.3.2 LSTM

ft=σ(Wfht−1,xt+bf)(遗忘门)f_t = \sigma(W_f h_{t-1}, x_t + b_f) \quad \text{(遗忘门)}ft=σ(Wfht−1,xt+bf)(遗忘门)

it=σ(Wiht−1,xt+bi)(输入门)i_t = \sigma(W_i h_{t-1}, x_t + b_i) \quad \text{(输入门)}it=σ(Wiht−1,xt+bi)(输入门)

c~t=tanh⁡(Wcht−1,xt+bc)(候选)\tilde{c}_t = \tanh(W_c h_{t-1}, x_t + b_c) \quad \text{(候选)}c~t=tanh(Wcht−1,xt+bc)(候选)

ct=ft⊙ct−1+it⊙c~t(细胞状态)c_t = f_t \odot c_{t-1} + i_t \odot \tilde{c}_t \quad \text{(细胞状态)}ct=ft⊙ct−1+it⊙c~t(细胞状态)

ot=σ(Woht−1,xt+bo)(输出门)o_t = \sigma(W_o h_{t-1}, x_t + b_o) \quad \text{(输出门)}ot=σ(Woht−1,xt+bo)(输出门)

ht=ot⊙tanh⁡(ct)h_t = o_t \odot \tanh(c_t)ht=ot⊙tanh(ct)

LSTM 通过门控机制和线性记忆通路,有效缓解了梯度消失问题。

6.3.3 双向 RNN

h→t=f(h→t−1,xt)\overrightarrow{h}t = f(\overrightarrow{h}{t-1}, x_t)h t=f(h t−1,xt)

h←t=f(h←t+1,xt)\overleftarrow{h}t = f(\overleftarrow{h}{t+1}, x_t)h t=f(h t+1,xt)

ht=h→t;h←th_t = \\overrightarrow{h}_t; \\overleftarrow{h}_tht=h t;h t

双向 RNN 可以利用未来信息(非流式场景)。

6.4 注意力机制

6.4.1 自注意力

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)=softmax(dk QKT)V

6.4.2 多头注意力

MultiHead(Q,K,V)=Concat(head1,...,headh)WO\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^OMultiHead(Q,K,V)=Concat(head1,...,headh)WO

其中 headi=Attention(QWiQ,KWiK,VWiV)\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)headi=Attention(QWiQ,KWiK,VWiV)。

6.4.3 位置编码

由于自注意力是位置无关的,需要添加位置信息:

PE(pos,2i)=sin⁡(pos/100002i/d)PE_{(pos, 2i)} = \sin(pos / 10000^{2i/d})PE(pos,2i)=sin(pos/100002i/d)

PE(pos,2i+1)=cos⁡(pos/100002i/d)PE_{(pos, 2i+1)} = \cos(pos / 10000^{2i/d})PE(pos,2i+1)=cos(pos/100002i/d)


第三部分:序列建模与解码


第七章:语言模型

7.1 N-gram 语言模型

7.1.1 定义

N-gram 语言模型假设当前词只依赖于前 N−1N-1N−1 个词:

P(w1,w2,...,wM)=∏i=1MP(wi∣wi−N+1,...,wi−1)P(w_1, w_2, \dots, w_M) = \prod_{i=1}^{M} P(w_i | w_{i-N+1}, \dots, w_{i-1})P(w1,w2,...,wM)=i=1∏MP(wi∣wi−N+1,...,wi−1)

7.1.2 参数估计

最大似然估计:

P(wi∣wi−N+1,...,wi−1)=C(wi−N+1,...,wi)C(wi−N+1,...,wi−1)P(w_i | w_{i-N+1}, \dots, w_{i-1}) = \frac{C(w_{i-N+1}, \dots, w_i)}{C(w_{i-N+1}, \dots, w_{i-1})}P(wi∣wi−N+1,...,wi−1)=C(wi−N+1,...,wi−1)C(wi−N+1,...,wi)

其中 C(⋅)C(\cdot)C(⋅) 是计数函数。

7.1.3 平滑技术

问题:许多 N-gram 从未在训练数据中出现(零概率问题)。

解决方法

  • 加一平滑(Laplace):所有计数加一
  • Good-Turing 平滑 :用出现 r+1r+1r+1 次的 N-gram 来估计出现 rrr 次的概率
  • Kneser-Ney 平滑:考虑词的上下文多样性

7.2 神经语言模型

7.2.1 前馈神经网络

P(wi∣wi−N+1,...,wi−1)=softmax(Wh+b)P(w_i | w_{i-N+1}, \dots, w_{i-1}) = \text{softmax}(Wh + b)P(wi∣wi−N+1,...,wi−1)=softmax(Wh+b)

其中 h=ReLU(Weewi−N+1;... ;ewi−1+b1)h = \text{ReLU}(W_e e_{w_{i-N+1}}; \\dots; e_{w_{i-1}} + b_1)h=ReLU(Weewi−N+1;...;ewi−1+b1),ewe_wew 是词嵌入。

7.2.2 RNN 语言模型

ht=f(ht−1,ewt)h_t = f(h_{t-1}, e_{w_t})ht=f(ht−1,ewt)

P(wt+1∣w1,...,wt)=softmax(Wht+b)P(w_{t+1} | w_1, \dots, w_t) = \text{softmax}(W h_t + b)P(wt+1∣w1,...,wt)=softmax(Wht+b)

RNN 可以利用任意长度的历史(理论上)。

7.2.3 Transformer 语言模型

使用因果注意力(causal attention):

P(wt+1∣w1,...,wt)=Transformer(w1,...,wt)P(w_{t+1} | w_1, \dots, w_t) = \text{Transformer}(w_1, \dots, w_t)P(wt+1∣w1,...,wt)=Transformer(w1,...,wt)

现代大语言模型(GPT, LLaMA 等)都是 Transformer 语言模型。

7.3 困惑度(Perplexity)

7.3.1 定义

语言模型的困惑度定义为:

PPL=exp⁡(−1M∑i=1Mlog⁡P(wi∣w1,...,wi−1))\text{PPL} = \exp\left(-\frac{1}{M}\sum_{i=1}^{M} \log P(w_i | w_1, \dots, w_{i-1})\right)PPL=exp(−M1i=1∑MlogP(wi∣w1,...,wi−1))

7.3.2 解释

  • PPL 越小,模型越好
  • PPL = VVV(词汇表大小)对应均匀分布
  • PPL = 1 对应完美预测

第八章:解码与搜索

8.1 解码问题

8.1.1 数学形式

W∗=arg⁡max⁡WP(O∣W)⋅P(W)α⋅∣W∣βW^* = \arg\max_W P(O|W) \cdot P(W)^\alpha \cdot |W|^\betaW∗=argWmaxP(O∣W)⋅P(W)α⋅∣W∣β

其中:

  • α\alphaα:语言模型权重
  • β\betaβ:长度奖励

8.1.2 搜索空间

搜索空间是指数级 的------词汇表大小 VVV,序列长度 MMM,组合数为 VMV^MVM。

8.2 Viterbi 解码

8.2.1 词级 Viterbi

在词级网络上运行 Viterbi 算法:

δt(w)=max⁡w′δt−1(w′)⋅aw′w⋅bw(ot)\delta_t(w) = \max_{w'} \\delta_{t-1}(w') \\cdot a_{w'w} \\cdot b_w(o_t)δt(w)=w′maxδt−1(w′)⋅aw′w⋅bw(ot)

8.2.2 帧同步解码

在每个时间步,扩展所有活跃的假设。

8.3 束搜索(Beam Search)

8.3.1 算法

维护一个大小为 BBB 的 (beam),每步只保留得分最高的 BBB 个假设:

复制代码
对于每个时间步 t:
    对于束中的每个假设 h:
        对于词汇表中的每个词 w:
            计算新假设的得分
    保留得分最高的 B 个假设

8.3.2 束搜索的近似性

束搜索不保证找到全局最优解------它是一种贪心搜索策略。

束大小 BBB 的权衡:

  • BBB 大:更接近最优,但计算量大
  • BBB 小:计算快,但可能丢失正确答案

8.4 格(Lattice)解码

8.4.1 格的定义

是一个有向无环图(DAG),节点表示时间-状态对,边表示词假设。

8.4.2 格的优势

  • 紧凑地表示多个假设
  • 支持后验概率计算
  • 便于多遍搜索和重打分

第九章:序列判别训练

9.1 最大似然训练的局限

9.1.1 最大似然目标

LML=∑rlog⁡P(Or∣Wr)\mathcal{L}_{ML} = \sum_r \log P(O_r | W_r)LML=r∑logP(Or∣Wr)

最大似然训练最大化正确词序列的似然,但不直接最小化识别错误率。

9.1.2 判别训练的动机

判别训练直接优化与错误率相关的目标:

Ldisc=∑rlog⁡P(Or∣Wr)∑W′P(Or∣W′)γ\mathcal{L}{disc} = \sum_r \log \frac{P(O_r | W_r)}{\sum{W'} P(O_r | W')^{\gamma}}Ldisc=r∑log∑W′P(Or∣W′)γP(Or∣Wr)

9.2 最大互信息(MMI)

9.2.1 目标函数

LMMI=∑rlog⁡P(Wr∣Or)P(Wr)=∑rlog⁡P(Or∣Wr)∑W′P(Or∣W′)\mathcal{L}{MMI} = \sum_r \log \frac{P(W_r | O_r)}{P(W_r)} = \sum_r \log \frac{P(O_r | W_r)}{\sum{W'} P(O_r | W')}LMMI=r∑logP(Wr)P(Wr∣Or)=r∑log∑W′P(Or∣W′)P(Or∣Wr)

9.2.2 梯度计算

MMI 的梯度涉及对所有词序列的求和------这需要前向-后向算法在词格上运行。

9.3 最小贝叶斯风险(MBR)

9.3.1 目标函数

W∗=arg⁡min⁡W∑W′R(W,W′)P(W′∣O)W^* = \arg\min_W \sum_{W'} R(W, W') P(W' | O)W∗=argWminW′∑R(W,W′)P(W′∣O)

其中 R(W,W′)R(W, W')R(W,W′) 是风险函数(如词错误率)。

9.3.2 近似

由于 P(W∣O)P(W|O)P(W∣O) 的计算困难,通常在格上近似。


第四部分:端到端模型


第十章:CTC(连接时序分类)

10.1 对齐问题

10.1.1 传统方法的对齐

传统 HMM 系统需要强制对齐(forced alignment)来建立帧和标签之间的对应关系。

10.1.2 CTC 的动机

问题:能否在不需要显式对齐的情况下训练序列模型?

CTC 的答案 :引入一个特殊的空白符 (blank)ϵ\epsilonϵ,将输入和输出序列长度对齐。

10.2 CTC 的数学理论

10.2.1 CTC 变换

给定输入序列 X=(x1,...,xT)X = (x_1, \dots, x_T)X=(x1,...,xT) 和输出序列 Y=(y1,...,yU)Y = (y_1, \dots, y_U)Y=(y1,...,yU)(T≥UT \geq UT≥U),CTC 定义了一个多对一 的映射 B\mathcal{B}B:

B:(a1,...,aT)→(y1,...,yU)\mathcal{B}: (a_1, \dots, a_T) \to (y_1, \dots, y_U)B:(a1,...,aT)→(y1,...,yU)

映射规则:

  1. 合并相邻的重复字符
  2. 删除空白符 ϵ\epsilonϵ

例子

  • (a,a,ϵ,b,b)→(a,b)(a, a, \epsilon, b, b) \to (a, b)(a,a,ϵ,b,b)→(a,b)
  • (ϵ,a,a,b,ϵ)→(a,b)(\epsilon, a, a, b, \epsilon) \to (a, b)(ϵ,a,a,b,ϵ)→(a,b)
  • (a,a,a,b,b)→(a,b)(a, a, a, b, b) \to (a, b)(a,a,a,b,b)→(a,b)

10.2.2 CTC 条件概率

CTC 将输出概率定义为所有可能对齐的概率之和:

P(Y∣X)=∑π∈B−1(Y)P(π∣X)P(Y|X) = \sum_{\pi \in \mathcal{B}^{-1}(Y)} P(\pi|X)P(Y∣X)=π∈B−1(Y)∑P(π∣X)

其中 B−1(Y)\mathcal{B}^{-1}(Y)B−1(Y) 是所有映射到 YYY 的对齐序列。

由于 CTC 的条件独立假设:

P(π∣X)=∏t=1TP(πt∣X)=∏t=1TP(πt∣xt)P(\pi|X) = \prod_{t=1}^{T} P(\pi_t | X) = \prod_{t=1}^{T} P(\pi_t | x_t)P(π∣X)=t=1∏TP(πt∣X)=t=1∏TP(πt∣xt)

10.2.3 前向-后向算法

前向变量

αt(s)=P(y1,...,ys/t,x1,...,xt)\alpha_t(s) = P(y_1, \dots, y_{s/t}, x_1, \dots, x_t)αt(s)=P(y1,...,ys/t,x1,...,xt)

其中 ys/ty_{s/t}ys/t 表示输出序列的前 sss 个字符在时间 ttt 处。

递推

αt(s)={αt−1(s)⋅yϵtif ys=ϵαt−1(s−1)⋅yyst+αt−1(s)⋅yϵtif ys≠ϵ,ys=ys−1αt−1(s−1)⋅yyst+αt−1(s−2)⋅yϵtif ys≠ϵ,ys≠ys−1\alpha_t(s) = \begin{cases} \alpha_{t-1}(s) \cdot y_{\epsilon}^t & \text{if } y_s = \epsilon \\ \alpha_{t-1}(s-1) \cdot y_{y_s}^t + \alpha_{t-1}(s) \cdot y_{\epsilon}^t & \text{if } y_s \neq \epsilon, y_s = y_{s-1} \\ \alpha_{t-1}(s-1) \cdot y_{y_s}^t + \alpha_{t-1}(s-2) \cdot y_{\epsilon}^t & \text{if } y_s \neq \epsilon, y_s \neq y_{s-1} \end{cases}αt(s)=⎩ ⎨ ⎧αt−1(s)⋅yϵtαt−1(s−1)⋅yyst+αt−1(s)⋅yϵtαt−1(s−1)⋅yyst+αt−1(s−2)⋅yϵtif ys=ϵif ys=ϵ,ys=ys−1if ys=ϵ,ys=ys−1

其中 ykt=P(πt=k∣xt)y_k^t = P(\pi_t = k | x_t)ykt=P(πt=k∣xt) 是模型在时间 ttt 输出字符 kkk 的概率。

10.2.4 CTC 损失

LCTC=−log⁡P(Y∣X)=−log⁡∑π∈B−1(Y)∏t=1TP(πt∣xt)\mathcal{L}{CTC} = -\log P(Y|X) = -\log \sum{\pi \in \mathcal{B}^{-1}(Y)} \prod_{t=1}^{T} P(\pi_t | x_t)LCTC=−logP(Y∣X)=−logπ∈B−1(Y)∑t=1∏TP(πt∣xt)

10.3 CTC 的理论性质

10.3.1 条件独立假设

CTC 假设不同时间步的输出是条件独立的:

P(πt∣X)=P(πt∣xt)P(\pi_t | X) = P(\pi_t | x_t)P(πt∣X)=P(πt∣xt)

这意味着 CTC 无法建模输出之间的依赖关系。

10.3.2 单调对齐

CTC 只考虑单调对齐------输入和输出的时间顺序相同。

这适合语音识别(发音顺序与文字顺序一致),但不适合机器翻译(词序可能不同)。

10.3.3 CTC 的峰值现象

CTC 的输出概率通常在某些时间步出现尖锐的峰值------这对应于"决定"输出一个字符的时刻。

10.4 CTC 的解码

10.4.1 贪心解码

π^t=arg⁡max⁡kP(πt=k∣xt)\hat{\pi}_t = \arg\max_k P(\pi_t = k | x_t)π^t=argkmaxP(πt=k∣xt)

然后应用 B\mathcal{B}B 变换得到输出序列。

10.4.2 前缀束搜索

维护一个前缀的束,每步扩展并剪枝。

10.4.3 基于语言模型的解码

Y^=arg⁡max⁡Ylog⁡PCTC(Y∣X)+αlog⁡PLM(Y)+β∣Y∣\hat{Y} = \arg\max_Y \log P_{CTC}(Y|X) + \alpha \log P_{LM}(Y) + \beta |Y|Y^=argYmaxlogPCTC(Y∣X)+αlogPLM(Y)+β∣Y∣


第十一章:注意力机制与编码器-解码器

11.1 编码器-解码器框架

11.1.1 基本结构

编码器:将输入序列编码为隐状态序列

h1,h2,...,hT=Encoder(x1,x2,...,xT)h_1, h_2, \dots, h_T = \text{Encoder}(x_1, x_2, \dots, x_T)h1,h2,...,hT=Encoder(x1,x2,...,xT)

解码器:基于隐状态序列生成输出序列

P(yt∣y<t,X)=Decoder(y<t,h1,...,hT)P(y_t | y_{<t}, X) = \text{Decoder}(y_{<t}, h_1, \dots, h_T)P(yt∣y<t,X)=Decoder(y<t,h1,...,hT)

11.1.2 注意力机制

注意力机制计算解码器当前状态与编码器各位置的"相关性":

et,i=score(st−1,hi)e_{t,i} = \text{score}(s_{t-1}, h_i)et,i=score(st−1,hi)

αt,i=exp⁡(et,i)∑jexp⁡(et,j)\alpha_{t,i} = \frac{\exp(e_{t,i})}{\sum_j \exp(e_{t,j})}αt,i=∑jexp(et,j)exp(et,i)

ct=∑iαt,ihic_t = \sum_i \alpha_{t,i} h_ict=i∑αt,ihi

其中 st−1s_{t-1}st−1 是解码器前一时刻的状态,ctc_tct 是上下文向量。

11.1.3 评分函数

评分函数 公式 名称
内积 sThs^T hsTh Dot
双线性 sTWhs^T W hsTWh General
拼接 vTtanh⁡(W1s+W2h)v^T \tanh(W_1 s + W_2 h)vTtanh(W1s+W2h) Concat

11.2 LAS(Listen, Attend and Spell)

11.2.1 模型结构

LAS 是第一个端到端的注意力语音识别模型:

Listener(编码器):多层 RNN 或 Transformer

Speller(解码器):基于注意力的 RNN

11.2.2 训练目标

LLAS=−∑tlog⁡P(yt∣y<t,X)\mathcal{L}{LAS} = -\sum_t \log P(y_t | y{<t}, X)LLAS=−t∑logP(yt∣y<t,X)

这是标准的交叉熵损失。

11.2.3 注意力对齐

注意力权重 αt,i\alpha_{t,i}αt,i 自动学习输入和输出之间的对齐关系------不需要强制对齐。

11.3 Transformer 语音识别

11.3.1 编码器

复制代码
输入特征 → 线性变换 → 位置编码 → N × (自注意力 → FFN)

11.3.2 解码器

复制代码
输出嵌入 → 位置编码 → N × (掩码自注意力 → 交叉注意力 → FFN)

11.3.3 优势

  • 并行计算(训练快)
  • 长距离依赖建模能力强
  • 注意力对齐可解释

第十二章:RNN-T(循环神经网络变换器)

12.1 RNN-T 的动机

12.1.1 CTC 的局限

  • 条件独立假设
  • 无法建模输出依赖

12.1.2 注意力模型的局限

  • 需要整个输入序列(非流式)
  • 注意力对齐可能不稳定

12.1.3 RNN-T 的设计目标

  • 建模输出依赖
  • 支持流式处理
  • 稳定的对齐

12.2 RNN-T 的数学理论

12.2.1 模型结构

RNN-T 包含三个组件:

编码器(Encoder)

h1enc,...,hTenc=Encoder(x1,...,xT)h_1^{\text{enc}}, \dots, h_T^{\text{enc}} = \text{Encoder}(x_1, \dots, x_T)h1enc,...,hTenc=Encoder(x1,...,xT)

预测网络(Prediction Network)

hupred=PredNet(y1,...,yu−1)h_u^{\text{pred}} = \text{PredNet}(y_1, \dots, y_{u-1})hupred=PredNet(y1,...,yu−1)

联合网络(Joint Network)

P(k∣t,u)=softmax(Joint(htenc,hupred))kP(k | t, u) = \text{softmax}(\text{Joint}(h_t^{\text{enc}}, h_u^{\text{pred}}))_kP(k∣t,u)=softmax(Joint(htenc,hupred))k

12.2.2 RNN-T 概率

RNN-T 将所有可能的对齐路径求和:

P(Y∣X)=∑π∈B−1(Y)∏t=1TP(πt∣t,ut)P(Y|X) = \sum_{\pi \in \mathcal{B}^{-1}(Y)} \prod_{t=1}^{T} P(\pi_t | t, u_t)P(Y∣X)=π∈B−1(Y)∑t=1∏TP(πt∣t,ut)

其中 utu_tut 是在时间 ttt 处对应的输出位置。

12.2.3 前向-后向算法

RNN-T 的前向变量:

α(t,u)=∑all paths to (t,u)∏P(πt′∣t′,ut′)\alpha(t, u) = \sum_{\text{all paths to } (t,u)} \prod P(\pi_{t'} | t', u_{t'})α(t,u)=all paths to (t,u)∑∏P(πt′∣t′,ut′)

递推关系:

α(t,u)=α(t−1,u)⋅P(ϵ∣t−1,u)+α(t,u−1)⋅P(yu∣t,u−1)\alpha(t, u) = \alpha(t-1, u) \cdot P(\epsilon | t-1, u) + \alpha(t, u-1) \cdot P(y_u | t, u-1)α(t,u)=α(t−1,u)⋅P(ϵ∣t−1,u)+α(t,u−1)⋅P(yu∣t,u−1)

12.2.4 RNN-T 损失

LRNN−T=−log⁡P(Y∣X)=−log⁡α(T,U)\mathcal{L}_{RNN-T} = -\log P(Y|X) = -\log \alpha(T, U)LRNN−T=−logP(Y∣X)=−logα(T,U)

12.3 RNN-T 与 CTC 的比较

性质 CTC RNN-T
输出依赖 无(条件独立) 有(通过预测网络)
对齐 单调 单调
流式 支持 支持
计算复杂度 O(TU)O(TU)O(TU) O(TU)O(TU)O(TU)
解码 前缀束搜索 前缀束搜索

12.4 Conformer 编码器

12.4.1 Conformer 块

Conformer 结合了卷积和注意力:

复制代码
输入 → FFN/2 → 多头自注意力 → 卷积模块 → FFN/2 → 输出

12.4.2 卷积模块

复制代码
输入 → 1D 点卷积 → GLU → 深度可分离卷积 → BatchNorm → Swish → 1D 点卷积

卷积模块捕捉局部模式,注意力模块捕捉全局依赖。


第五部分:理论分析与前沿


第十三章:语音识别的信息论视角

13.1 信息熵与语音

13.1.1 语音的熵

语音信号的信息熵:

H(X)=−∑xP(x)log⁡P(x)H(X) = -\sum_x P(x) \log P(x)H(X)=−x∑P(x)logP(x)

英语的熵估计约为 1.0-1.5 bits/字符(考虑上下文后)。

13.1.2 互信息

输入特征 XXX 和输出标签 YYY 之间的互信息:

I(X;Y)=H(Y)−H(Y∣X)I(X; Y) = H(Y) - H(Y|X)I(X;Y)=H(Y)−H(Y∣X)

好的声学模型应该最大化 I(X;Y)I(X; Y)I(X;Y)。

13.2 贝叶斯决策理论

13.2.1 最大后验决策

W∗=arg⁡max⁡WP(W∣O)W^* = \arg\max_W P(W|O)W∗=argWmaxP(W∣O)

13.2.2 最小贝叶斯风险

W∗=arg⁡min⁡W∑W′R(W,W′)P(W′∣O)W^* = \arg\min_W \sum_{W'} R(W, W') P(W'|O)W∗=argWminW′∑R(W,W′)P(W′∣O)

13.2.3 0-1 损失

当 R(W,W′)=1W≠W′R(W, W') = \mathbb{1}W \\neq W'R(W,W′)=1W=W′ 时,最小贝叶斯风险等价于最大后验。

13.3 信道模型

13.3.1 语音识别作为信道解码

语音识别可以看作一个噪声信道问题:

W→信道→OW \to \text{信道} \to OW→信道→O

  • 发送端:词序列 WWW
  • 信道:语音产生过程(含噪声)
  • 接收端:声学观测 OOO

解码就是从接收信号恢复发送信号。


第十四章:SSM 与语音识别

14.1 SSM 用于语音的动机

14.1.1 语音信号的特性

  • 长序列:1 分钟音频 = 60,000 帧(10ms 帧移)
  • 长时依赖:音素、音节、词之间的依赖
  • 时变性:语音信号是非平稳的

14.1.2 SSM 的优势

  • 线性复杂度:处理长序列高效
  • 长程记忆:HiPPO 理论保证
  • 选择性机制:适应语音的时变特性

14.2 S4 用于语音

14.2.1 S4 的特性

S4(Structured State Space for Sequences)具有:

  • 卷积和递推的对偶性
  • 高效的长程依赖建模
  • 稳定的梯度传播

14.2.2 语音识别中的 S4

将 S4 用作声学模型的骨干网络:

ht=S4(x1,...,xt)h_t = \text{S4}(x_1, \dots, x_t)ht=S4(x1,...,xt)

14.3 Mamba 用于语音

14.3.1 选择性机制的优势

Mamba 的选择性机制特别适合语音:

  • 重要的语音帧(如音素边界)获得更大的 Δ\DeltaΔ
  • 静音或噪声帧被快速遗忘
  • 模型可以自适应地调整"记忆策略"

14.3.2 流式处理

Mamba 的递推模式天然支持流式处理------这对实时语音识别至关重要。

14.4 SSM 与注意力的混合

14.4.1 混合架构

结合 SSM 和注意力的优势:

  • SSM 层:捕捉长程依赖
  • 注意力层:精确的对齐和建模

14.4.2 理论分析

SSM 和注意力可以互补:

  • SSM:高效但固定的衰减模式
  • 注意力:灵活但 O(n2)O(n^2)O(n2) 复杂度

混合架构可以在效率和表达能力之间取得平衡。


第十五章:多任务学习与自监督

15.1 多任务学习

15.1.1 联合 CTC-Attention

同时使用 CTC 和注意力损失:

L=λLCTC+(1−λ)LAtt\mathcal{L} = \lambda \mathcal{L}{CTC} + (1-\lambda) \mathcal{L}{Att}L=λLCTC+(1−λ)LAtt

CTC 提供单调对齐约束,注意力提供灵活的上下文建模。

15.1.2 多任务目标

除了转录任务,还可以加入:

  • 说话人识别
  • 语言识别
  • 情感识别
  • 语音分离

15.2 自监督预训练

15.2.1 Wav2Vec 2.0

预训练任务:预测被遮盖的语音片段

Lw2v=−log⁡exp⁡(sim(qt,ct)/τ)∑kexp⁡(sim(qt,ck)/τ)\mathcal{L}{w2v} = -\log \frac{\exp(\text{sim}(q_t, c_t)/\tau)}{\sum{k} \exp(\text{sim}(q_t, c_k)/\tau)}Lw2v=−log∑kexp(sim(qt,ck)/τ)exp(sim(qt,ct)/τ)

其中 qtq_tqt 是量化的目标,ctc_tct 是对比样本。

15.2.2 HuBERT

预训练任务:预测伪标签(通过聚类得到)

Lhubert=−∑t∈Mlog⁡P(zt∣x\M)\mathcal{L}{hubert} = -\sum{t \in M} \log P(z_t | x_{\backslash M})Lhubert=−t∈M∑logP(zt∣x\M)

其中 MMM 是被遮盖的位置,ztz_tzt 是伪标签。

15.2.3 Whisper

预训练任务:多任务序列到序列

  • 语音识别
  • 语音翻译
  • 语言识别
  • 时间戳预测

15.3 预训练的理论分析

15.3.1 表示学习

预训练学习到的表示应该:

  • 不变性:对不相关的变化(如说话人)不变
  • 等变性:对相关的变化(如音素)等变

15.3.2 信息最大化

预训练可以理解为最大化输入和表示之间的互信息:

max⁡I(X;Z)\max I(X; Z)maxI(X;Z)


第十六章:完整可运行代码实现

16.1 MFCC 特征提取

python 复制代码
"""
MFCC 特征提取的完整实现。
包含: 预加重、分帧、FFT、梅尔滤波器组、DCT。
"""

import numpy as np


def pre_emphasis(signal, coeff=0.97):
    """预加重滤波器。"""
    return np.append(signal[0], signal[1:] - coeff * signal[:-1])


def framing(signal, frame_size, frame_shift, fs):
    """分帧。

    Args:
        signal: 输入信号
        frame_size: 帧长 (秒)
        frame_shift: 帧移 (秒)
        fs: 采样率

    Returns:
        frames: (num_frames, frame_length) 帧矩阵
    """
    frame_length = int(frame_size * fs)
    shift_length = int(frame_shift * fs)
    num_frames = (len(signal) - frame_length) // shift_length + 1

    indices = np.arange(0, num_frames)[:, None] * shift_length + np.arange(frame_length)
    frames = signal[indices]

    return frames


def hamming_window(N):
    """Hamming 窗。"""
    return 0.54 - 0.46 * np.cos(2 * np.pi * np.arange(N) / (N - 1))


def mel_filterbank(num_filters, fft_size, fs, low_freq=0, high_freq=None):
    """梅尔滤波器组。

    Args:
        num_filters: 滤波器数量
        fft_size: FFT 大小
        fs: 采样率
        low_freq: 最低频率
        high_freq: 最高频率

    Returns:
        filterbank: (num_filters, fft_size//2+1) 滤波器组
    """
    if high_freq is None:
        high_freq = fs / 2

    # 梅尔尺度转换
    def hz2mel(f):
        return 2595 * np.log10(1 + f / 700)

    def mel2hz(m):
        return 700 * (10**(m / 2595) - 1)

    # 滤波器中心频率 (梅尔尺度均匀分布)
    mel_low = hz2mel(low_freq)
    mel_high = hz2mel(high_freq)
    mel_points = np.linspace(mel_low, mel_high, num_filters + 2)
    hz_points = mel2hz(mel_points)

    # FFT 频率 bin
    bin_points = np.floor(hz_points / (fs / fft_size)).astype(int)

    # 构造滤波器组
    filterbank = np.zeros((num_filters, fft_size // 2 + 1))

    for m in range(num_filters):
        left = bin_points[m]
        center = bin_points[m + 1]
        right = bin_points[m + 2]

        for k in range(left, center):
            filterbank[m, k] = (k - left) / (center - left)
        for k in range(center, right):
            filterbank[m, k] = (right - k) / (right - center)

    return filterbank


def mfcc(signal, fs, num_coeffs=13, num_filters=26, frame_size=0.025,
         frame_shift=0.01, pre_emph=0.97):
    """计算 MFCC 特征。

    Args:
        signal: 输入信号
        fs: 采样率
        num_coeffs: MFCC 系数数量
        num_filters: 梅尔滤波器数量
        frame_size: 帧长 (秒)
        frame_shift: 帧移 (秒)
        pre_emph: 预加重系数

    Returns:
        mfcc_features: (num_frames, num_coeffs) MFCC 特征
    """
    # 预加重
    signal = pre_emphasis(signal, pre_emph)

    # 分帧
    frames = framing(signal, frame_size, frame_shift, fs)
    num_frames, frame_length = frames.shape

    # 加窗
    window = hamming_window(frame_length)
    frames = frames * window

    # FFT
    fft_size = 1
    while fft_size < frame_length:
        fft_size *= 2
    X = np.fft.rfft(frames, n=fft_size)
    power = np.abs(X)**2 / fft_size

    # 梅尔滤波器组
    fb = mel_filterbank(num_filters, fft_size, fs)

    # 滤波器组能量
    filterbank_energy = power @ fb.T

    # 对数能量
    log_energy = np.log(filterbank_energy + 1e-10)

    # DCT
    num_frames, num_filters = log_energy.shape
    dct_matrix = np.zeros((num_coeffs, num_filters))
    for n in range(num_coeffs):
        for m in range(num_filters):
            dct_matrix[n, m] = np.cos(np.pi * n * (m + 0.5) / num_filters)

    mfcc_features = dct_matrix @ log_energy.T

    return mfcc_features.T


def demonstrate_mfcc():
    """演示 MFCC 特征提取。"""
    print("=" * 60)
    print("MFCC 特征提取演示")
    print("=" * 60)

    np.random.seed(42)

    # 生成模拟语音信号
    fs = 16000
    duration = 1.0
    t = np.arange(0, duration, 1/fs)

    # 模拟语音: 基频 + 共振峰
    f0 = 100  # 基频
    signal = (0.5 * np.sin(2*np.pi*f0*t) +
              0.3 * np.sin(2*np.pi*500*t) +  # F1
              0.2 * np.sin(2*np.pi*1500*t) +  # F2
              0.1 * np.random.randn(len(t)))   # 噪声

    print(f"\n信号参数:")
    print(f"  采样率: {fs} Hz")
    print(f"  时长: {duration} s")
    print(f"  样本数: {len(signal)}")

    # 提取 MFCC
    mfcc_features = mfcc(signal, fs, num_coeffs=13)

    print(f"\nMFCC 特征:")
    print(f"  帧数: {mfcc_features.shape[0]}")
    print(f"  特征维度: {mfcc_features.shape[1]}")
    print(f"  特征均值: {np.mean(mfcc_features, axis=0)[:5]}")
    print(f"  特征标准差: {np.std(mfcc_features, axis=0)[:5]}")

    return mfcc_features


if __name__ == "__main__":
    demonstrate_mfcc()

16.2 HMM 前向-后向算法

python 复制代码
"""
HMM 前向-后向算法的完整实现。
包含: 前向算法、后向算法、Viterbi 算法、Baum-Welch 算法。
"""

import numpy as np


class HMM:
    """离散 HMM 模型。"""

    def __init__(self, num_states, num_obs):
        """
        Args:
            num_states: 状态数
            num_obs: 观测符号数
        """
        self.N = num_states
        self.M = num_obs

        # 随机初始化参数
        self.pi = np.random.dirichlet(np.ones(num_states))
        self.A = np.random.dirichlet(np.ones(num_states), size=num_states)
        self.B = np.random.dirichlet(np.ones(num_obs), size=num_states)

    def forward(self, O):
        """前向算法。

        Args:
            O: (T,) 观测序列

        Returns:
            alpha: (T, N) 前向变量
            log_prob: 对数似然
        """
        T = len(O)
        alpha = np.zeros((T, self.N))

        # 初始化
        alpha[0] = self.pi * self.B[:, O[0]]

        # 递推
        for t in range(1, T):
            alpha[t] = (alpha[t-1] @ self.A) * self.B[:, O[t]]

        # 终止
        log_prob = np.log(np.sum(alpha[-1]) + 1e-10)

        return alpha, log_prob

    def backward(self, O):
        """后向算法。

        Args:
            O: (T,) 观测序列

        Returns:
            beta: (T, N) 后向变量
        """
        T = len(O)
        beta = np.zeros((T, self.N))

        # 初始化
        beta[-1] = 1.0

        # 递推
        for t in range(T-2, -1, -1):
            beta[t] = self.A @ (self.B[:, O[t+1]] * beta[t+1])

        return beta

    def viterbi(self, O):
        """Viterbi 算法。

        Args:
            O: (T,) 观测序列

        Returns:
            path: (T,) 最优状态序列
            log_prob: 对数概率
        """
        T = len(O)
        delta = np.zeros((T, self.N))
        psi = np.zeros((T, self.N), dtype=int)

        # 初始化
        delta[0] = np.log(self.pi + 1e-10) + np.log(self.B[:, O[0]] + 1e-10)

        # 递推
        for t in range(1, T):
            for j in range(self.N):
                scores = delta[t-1] + np.log(self.A[:, j] + 1e-10)
                psi[t, j] = np.argmax(scores)
                delta[t, j] = scores[psi[t, j]] + np.log(self.B[j, O[t]] + 1e-10)

        # 回溯
        path = np.zeros(T, dtype=int)
        path[-1] = np.argmax(delta[-1])
        for t in range(T-2, -1, -1):
            path[t] = psi[t+1, path[t+1]]

        log_prob = delta[-1, path[-1]]

        return path, log_prob

    def baum_welch(self, O_list, max_iter=100):
        """Baum-Welch 算法。

        Args:
            O_list: 观测序列列表
            max_iter: 最大迭代次数
        """
        for iteration in range(max_iter):
            # 初始化统计量
            pi_acc = np.zeros(self.N)
            A_acc = np.zeros((self.N, self.N))
            B_acc = np.zeros((self.N, self.M))

            total_log_prob = 0

            for O in O_list:
                T = len(O)

                # 前向-后向
                alpha, log_prob = self.forward(O)
                beta = self.backward(O)
                total_log_prob += log_prob

                # gamma 和 xi
                gamma = alpha * beta
                gamma = gamma / (gamma.sum(axis=1, keepdims=True) + 1e-10)

                xi = np.zeros((T-1, self.N, self.N))
                for t in range(T-1):
                    xi[t] = alpha[t][:, None] * self.A * self.B[:, O[t+1]] * beta[t+1]
                    xi[t] = xi[t] / (xi[t].sum() + 1e-10)

                # 累积统计量
                pi_acc += gamma[0]
                A_acc += xi.sum(axis=0)
                for t in range(T):
                    B_acc[:, O[t]] += gamma[t]

            # 更新参数
            self.pi = pi_acc / len(O_list)
            self.A = A_acc / (A_acc.sum(axis=1, keepdims=True) + 1e-10)
            self.B = B_acc / (B_acc.sum(axis=1, keepdims=True) + 1e-10)

            print(f"  Iteration {iteration+1}: log_prob = {total_log_prob:.4f}")


def demonstrate_hmm():
    """演示 HMM 算法。"""
    print("=" * 60)
    print("HMM 算法演示")
    print("=" * 60)

    np.random.seed(42)

    # 创建 HMM
    hmm = HMM(num_states=3, num_obs=5)

    print(f"\nHMM 参数:")
    print(f"  状态数: {hmm.N}")
    print(f"  观测数: {hmm.M}")

    # 生成观测序列
    T = 20
    O = np.random.randint(0, hmm.M, T)
    print(f"  观测序列: {O}")

    # 前向算法
    alpha, log_prob = hmm.forward(O)
    print(f"\n前向算法:")
    print(f"  对数似然: {log_prob:.4f}")

    # Viterbi 算法
    path, viterbi_prob = hmm.viterbi(O)
    print(f"\nViterbi 算法:")
    print(f"  最优路径: {path}")
    print(f"  对数概率: {viterbi_prob:.4f}")

    # Baum-Welch 训练
    print(f"\nBaum-Welch 训练:")
    O_list = [np.random.randint(0, hmm.M, T) for _ in range(10)]
    hmm.baum_welch(O_list, max_iter=10)

    return hmm


if __name__ == "__main__":
    demonstrate_hmm()

16.3 CTC 前向-后向算法

python 复制代码
"""
CTC 前向-后向算法的完整实现。
"""

import numpy as np


def ctc_forward(log_probs, targets, blank=0):
    """CTC 前向算法。

    Args:
        log_probs: (T, V) 对数概率矩阵
        targets: (U,) 目标序列 (已扩展,包含 blank)
        blank: blank 符号的索引

    Returns:
        log_alpha: (T, S) 对数前向变量
        log_prob: 对数概率
    """
    T, V = log_probs.shape
    U = len(targets)
    S = 2 * U + 1  # 扩展后的序列长度

    # 构建扩展序列 (插入 blank)
    extended = [blank]
    for t in targets:
        extended.append(t)
        extended.append(blank)

    # 初始化对数前向变量
    log_alpha = np.full((T, S), -np.inf)

    # 初始条件
    log_alpha[0, 0] = log_probs[0, blank]
    if S > 1:
        log_alpha[0, 1] = log_probs[0, targets[0]]

    # 递推
    for t in range(1, T):
        for s in range(S):
            # 从 blank 转移
            if s >= 0:
                log_alpha[t, s] = np.logaddexp(log_alpha[t, s],
                                                 log_alpha[t-1, s] + log_probs[t, extended[s]])
            # 从同一字符转移
            if s >= 1 and extended[s] != blank:
                log_alpha[t, s] = np.logaddexp(log_alpha[t, s],
                                                 log_alpha[t-1, s-1] + log_probs[t, extended[s]])
            # 从不同字符转移
            if s >= 2 and extended[s] != extended[s-2]:
                log_alpha[t, s] = np.logaddexp(log_alpha[t, s],
                                                 log_alpha[t-1, s-2] + log_probs[t, extended[s]])

    # 终止
    log_prob = np.logaddexp(log_alpha[T-1, S-1], log_alpha[T-1, S-2])

    return log_alpha, log_prob


def ctc_backward(log_probs, targets, blank=0):
    """CTC 后向算法。"""
    T, V = log_probs.shape
    U = len(targets)
    S = 2 * U + 1

    extended = [blank]
    for t in targets:
        extended.append(t)
        extended.append(blank)

    log_beta = np.full((T, S), -np.inf)

    # 初始条件
    log_beta[T-1, S-1] = 0
    if S > 1:
        log_beta[T-1, S-2] = 0

    # 递推
    for t in range(T-2, -1, -1):
        for s in range(S):
            if s < S:
                log_beta[t, s] = np.logaddexp(log_beta[t, s],
                                               log_beta[t+1, s] + log_probs[t+1, extended[s]])
            if s+1 < S and extended[s+1] != blank:
                log_beta[t, s] = np.logaddexp(log_beta[t, s],
                                               log_beta[t+1, s+1] + log_probs[t+1, extended[s+1]])
            if s+2 < S and extended[s+2] != extended[s]:
                log_beta[t, s] = np.logaddexp(log_beta[t, s],
                                               log_beta[t+1, s+2] + log_probs[t+1, extended[s+2]])

    return log_beta


def demonstrate_ctc():
    """演示 CTC 算法。"""
    print("=" * 60)
    print("CTC 前向-后向算法演示")
    print("=" * 60)

    np.random.seed(42)

    # 参数
    T = 10  # 输入序列长度
    V = 5   # 词汇表大小 (包含 blank)
    blank = 0

    # 生成随机对数概率
    log_probs = np.random.randn(T, V)
    log_probs = log_probs - np.log(np.sum(np.exp(log_probs), axis=1, keepdims=True))

    # 目标序列
    targets = [1, 2, 3]  # 不包含 blank

    print(f"\n参数:")
    print(f"  输入长度: {T}")
    print(f"  词汇表大小: {V}")
    print(f"  目标序列: {targets}")

    # 前向算法
    log_alpha, log_prob = ctc_forward(log_probs, targets, blank)

    print(f"\n前向算法:")
    print(f"  对数概率: {log_prob:.4f}")
    print(f"  前向变量形状: {log_alpha.shape}")

    return log_alpha, log_prob


if __name__ == "__main__":
    demonstrate_ctc()

16.4 注意力机制

python 复制代码
"""
注意力机制的完整实现。
包含: 缩放点积注意力、多头注意力。
"""

import numpy as np


def scaled_dot_product_attention(Q, K, V, mask=None):
    """缩放点积注意力。

    Args:
        Q: (N_q, d_k) 查询矩阵
        K: (N_k, d_k) 键矩阵
        V: (N_k, d_v) 值矩阵
        mask: (N_q, N_k) 掩码矩阵

    Returns:
        output: (N_q, d_v) 注意力输出
        weights: (N_q, N_k) 注意力权重
    """
    d_k = Q.shape[-1]

    # 计算注意力分数
    scores = Q @ K.T / np.sqrt(d_k)

    # 应用掩码
    if mask is not None:
        scores = scores + mask * (-1e9)

    # Softmax
    exp_scores = np.exp(scores - np.max(scores, axis=-1, keepdims=True))
    weights = exp_scores / np.sum(exp_scores, axis=-1, keepdims=True)

    # 加权求和
    output = weights @ V

    return output, weights


def multi_head_attention(Q, K, V, num_heads, d_model, mask=None):
    """多头注意力。

    Args:
        Q: (N_q, d_model) 查询矩阵
        K: (N_k, d_model) 键矩阵
        V: (N_k, d_model) 值矩阵
        num_heads: 注意力头数
        d_model: 模型维度
        mask: 掩码矩阵

    Returns:
        output: (N_q, d_model) 注意力输出
    """
    d_k = d_model // num_heads

    # 线性变换
    W_Q = np.random.randn(d_model, d_model) * 0.01
    W_K = np.random.randn(d_model, d_model) * 0.01
    W_V = np.random.randn(d_model, d_model) * 0.01
    W_O = np.random.randn(d_model, d_model) * 0.01

    Q_proj = Q @ W_Q
    K_proj = K @ W_K
    V_proj = V @ W_V

    # 分头
    N_q = Q.shape[0]
    N_k = K.shape[0]

    Q_heads = Q_proj.reshape(N_q, num_heads, d_k).transpose(1, 0, 2)
    K_heads = K_proj.reshape(N_k, num_heads, d_k).transpose(1, 0, 2)
    V_heads = V_proj.reshape(N_k, num_heads, d_k).transpose(1, 0, 2)

    # 每个头独立计算注意力
    outputs = []
    for h in range(num_heads):
        out, _ = scaled_dot_product_attention(Q_heads[h], K_heads[h], V_heads[h], mask)
        outputs.append(out)

    # 拼接
    concat = np.concatenate(outputs, axis=-1)

    # 输出投影
    output = concat @ W_O

    return output


def demonstrate_attention():
    """演示注意力机制。"""
    print("=" * 60)
    print("注意力机制演示")
    print("=" * 60)

    np.random.seed(42)

    # 参数
    N_q = 5
    N_k = 10
    d_model = 64
    num_heads = 8

    # 随机输入
    Q = np.random.randn(N_q, d_model)
    K = np.random.randn(N_k, d_model)
    V = np.random.randn(N_k, d_model)

    print(f"\n参数:")
    print(f"  查询长度: {N_q}")
    print(f"  键/值长度: {N_k}")
    print(f"  模型维度: {d_model}")
    print(f"  注意力头数: {num_heads}")

    # 缩放点积注意力
    output, weights = scaled_dot_product_attention(Q, K, V)

    print(f"\n缩放点积注意力:")
    print(f"  输出形状: {output.shape}")
    print(f"  注意力权重形状: {weights.shape}")
    print(f"  权重行和: {np.sum(weights, axis=-1)[:3]}")

    # 多头注意力
    output_mha = multi_head_attention(Q, K, V, num_heads, d_model)

    print(f"\n多头注意力:")
    print(f"  输出形状: {output_mha.shape}")

    return output, weights


if __name__ == "__main__":
    demonstrate_attention()

附录

A. 数学符号表

符号 含义 维度
O=(o1,...,oT)O = (o_1, \dots, o_T)O=(o1,...,oT) 声学观测序列 RT×d\mathbb{R}^{T \times d}RT×d
W=(w1,...,wM)W = (w_1, \dots, w_M)W=(w1,...,wM) 词序列 词表
Q=(q1,...,qT)Q = (q_1, \dots, q_T)Q=(q1,...,qT) 状态序列 状态集
π\piπ 初始状态概率 RN\mathbb{R}^NRN
AAA 状态转移矩阵 RN×N\mathbb{R}^{N \times N}RN×N
BBB 观测概率 状态 × 观测
αt(i)\alpha_t(i)αt(i) 前向变量 R\mathbb{R}R
βt(i)\beta_t(i)βt(i) 后向变量 R\mathbb{R}R
γt(i)\gamma_t(i)γt(i) 状态后验 R\mathbb{R}R
ξt(i,j)\xi_t(i,j)ξt(i,j) 转移后验 R\mathbb{R}R
B\mathcal{B}B CTC 映射 序列 → 序列
α(t,s)\alpha(t,s)α(t,s) CTC 前向变量 R\mathbb{R}R

B. 关键公式速查

贝叶斯公式

P(W∣O)=P(O∣W)P(W)P(O)P(W|O) = \frac{P(O|W)P(W)}{P(O)}P(W∣O)=P(O)P(O∣W)P(W)

HMM 前向递推

αt+1(j)=∑iαt(i)aijbj(ot+1)\alpha_{t+1}(j) = \left\\sum_i \\alpha_t(i) a_{ij}\\right b_j(o_{t+1})αt+1(j)=i∑αt(i)aijbj(ot+1)

Viterbi 递推

δt+1(j)=max⁡iδt(i)aijbj(ot+1)\delta_{t+1}(j) = \max_i \\delta_t(i) a_{ij} b_j(o_{t+1})δt+1(j)=imaxδt(i)aijbj(ot+1)

Baum-Welch 更新

a^ij=∑tξt(i,j)∑tγt(i)\hat{a}_{ij} = \frac{\sum_t \xi_t(i,j)}{\sum_t \gamma_t(i)}a^ij=∑tγt(i)∑tξt(i,j)

CTC 概率

P(Y∣X)=∑π∈B−1(Y)∏tP(πt∣xt)P(Y|X) = \sum_{\pi \in \mathcal{B}^{-1}(Y)} \prod_t P(\pi_t | x_t)P(Y∣X)=π∈B−1(Y)∑t∏P(πt∣xt)

注意力

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)=softmax(dk QKT)V

MFCC

cn=∑mSmcos⁡(πn(m+0.5)M)cn = \sum_m Sm \cos\left(\frac{\pi n(m+0.5)}{M}\right)cn=m∑Smcos(Mπn(m+0.5))

Mel 尺度

mel(f)=2595log⁡10(1+f/700)\text{mel}(f) = 2595 \log_{10}(1 + f/700)mel(f)=2595log10(1+f/700)

C. 参考文献

  1. Rabiner, L. R. (1989). A Tutorial on Hidden Markov Models and Selected Applications in Speech Recognition. Proceedings of the IEEE.

  2. Graves, A., Fernández, S., Gomez, F., & Schmidhuber, J. (2006). Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks. ICML 2006.

  3. Chan, W., Jaitly, N., Le, Q., & Vinyals, O. (2016). Listen, Attend and Spell. ICASSP 2016.

  4. Graves, A. (2012). Sequence Transduction with Recurrent Neural Networks. ICML Workshop.

  5. Gulati, A., et al. (2020). Conformer: Convolution-augmented Transformer for Speech Recognition. Interspeech 2020.

  6. Baevski, A., et al. (2020). Wav2Vec 2.0: A Framework for Self-Supervised Learning of Speech Representations. NeurIPS 2020.

  7. Radford, A., et al. (2023). Robust Speech Recognition via Large-Scale Weak Supervision. ICML 2023. (Whisper)

  8. Gu, A., Goel, K., & Ré, C. (2022). Efficiently Modeling Long Sequences with Structured State Spaces. ICLR 2022. (S4)

  9. Gu, A., & Dao, T. (2023). Mamba: Linear-Time Sequence Modeling with Selective State Spaces. arXiv:2312.00752.

  10. Jelinek, F. (1997). Statistical Methods for Speech Recognition. MIT Press.


本文涵盖了语音识别从声学建模到端到端模型的完整理论体系,特别强调了 HMM、CTC、注意力机制和 SSM 的数学理论。

相关推荐
码农小白AI1 小时前
实验室数智化转型的真正起点:AI 报告审核如何成为第一道“质量闸门”,IACheck重构审核逻辑
人工智能·重构
PNP机器人1 小时前
基于视觉运动扩散与 AR 遥操作的多指灵巧手在手操控学习研究
人工智能·遥操作·灵巧手
一点一木1 小时前
让 Codex 用上 DeepSeek:Moon Bridge 配置完全指南「零门槛上手」
人工智能·ai编程·deepseek
AI搅拌机1 小时前
提示词大师全新升级——无论Ollama、远程API还是本地模型,都能反推、扩写你的提示词!
人工智能
是有头发的程序猿1 小时前
AI Agent电商自动化实战:淘宝商品详情API无人化采集与分析教程
运维·人工智能·自动化
EAIReport1 小时前
边缘计算EdgeAI:从云端下沉到终端的智能革命
人工智能·边缘计算
在繁华处1 小时前
Java从零到熟练(十二):Java与AI工具整合
java·人工智能·python
csdn小瓯1 小时前
告别 Value Model:深度解析 GRPO 与 PPO 的核心差异
人工智能
库拉大叔1 小时前
GPT-5.5办公落地全解析:四大场景实测+避坑指南+多模型策略
人工智能·gpt