前言
本文是阅读论文《Connectionist Temporal Classification: Labelling UnsegmentedSequence Data with Recurrent Neural Networks》1 的笔记,讨论Connectionist Temporal Classification(CTC)算法在语音识别(ASR)中的应用。
一、CTC简介
1.1 为什么学CTC?
Connectionist Temporal Classification(CTC)有道词典翻译成“联结主义时间分类”,这个概念乍一看让人迷糊,为简洁易懂,我们称其为连接时序分类,是 Alex Graves 等人在 2006 年提出的。

图1 语音识别举例
CTC 除了训练简便外,近些年(约2015年之后),以 CTC 为代表的端到端模型,性能逐渐超过了基于 HMM 的传统 ASR 模型,其中的原因是多样的:深度神经网络强大的海量数据拟合能力,E2E 模型简单易部署(相近识别能力的传统 ASR 模型有声学模型、语言模型、词典,这些内存加起来要远大于一个 E2E 模型), NLP 等领域的成果更容易迁移过来等等。导致各家公司舍弃了传统 ASR 算法转向 E2E ASR,使得 E2E ASR 的研究更加丰富。CTC 算法是 E2E ASR 的里程碑式成果。
1.2 CTC要解决的问题
我们想用一个模型来解决语音识别。ASR 本身是一个分类问题,以 20ms 为一帧,常用汉字 4000 个的话,我们想知道第 1 帧应该转写为哪个汉字,便是 4000 分类问题,将每一帧都转写一个汉字,最后整合一下,问题就解决了。可否用图像分类的方式来解决,给每一帧打上标签,然后交叉熵损失直接训练就好。这种思路便是混合 DNN-HMM 模型的思路,先用 GMM-HMM 生成每一帧的标签,然后用神经网络进行分类训练。问题是这样就需要训练两个模型(GMM-HMM 和 NN模型),不用 GMM-HMM 的话,每一帧的标签如何得到。
有人会问,为啥你要 20ms 作为一帧,正常人说一个字大概 200ms,用 200ms 作为建模单元长度不行吗?因为语音信号是连续变量,你不清楚哪 200ms 刚好对应一个字,且每个人吐字时长都不同,有人讲话快,有人慢,这便是“连续时序分类”的“连续”难题。所以,只能尽可能让建模单元(帧长)短一些,最后将代表同一个字的单元拼接起来。
那么帧长足够小,每一帧也能识别出对应的字,比如有 5 帧,我们识别出 打 打 打 开 开,合并多余的字后,得到 打开,看似问题得到了解决。但如果这句话是哈哈哈,谢谢哥哥呢,按照上述方法合并多余的字后,得到哈谢哥,不知所云。所以说,这种方法在处理叠字时是有缺陷的。
1.3 CTC的思想
为了解决叠字的问题,CTC 引入了一个记号 “-”,读做 “空”,用其当做占位符。还是用哈哈哈,谢谢哥哥来举例,引入 “-” 后,语音经过解码后会得到如--哈---哈-哈哈----谢-谢--哥----哥哥---这样的序列,先将重复的字合并,然后将“-”去掉,就得到哈哈哈,谢谢哥哥。
另一个就是训练问题,如何得到这样一个模型。我们先列出描述 CTC 的数学记号。
观测序列
x
=
(
x
1
,
x
2
,
⋯
,
x
T
)
∈
X
x = (x_1, x_2, \cdots, x_T)\in X
x=(x1,x2,⋯,xT)∈X 是每一帧音频信号,
l
=
(
l
1
,
l
2
,
⋯
,
l
U
)
∈
Z
l= (l_1, l_2, \cdots, l_U )\in Z
l=(l1,l2,⋯,lU)∈Z 是其对应的标签,其中
U
≤
T
U \le T
U≤T,这里的
l
i
∈
L
l_i\in L
li∈L,
L
L
L 代表不带 {-} 的常规标签集合,如果是中文就是汉字,英文就是 26 个英文字母(为简化,只讨论大写字母),
L
′
=
L
⋃
{
−
}
L' = L \bigcup \{-\}
L′=L⋃{−}。这是多对一问题,多帧对应一个标签。我们的目标是训一个模型
h
h
h,使得
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x) 最大,本质还是极大似然估计。
回顾 HMM2 ,我们用前向后向算法算概率,用极大似然估计训模型,用 Viterbi 算法估计解码路径。CTC 和 HMM 算法是很相似的,我们依然按照这 3 个基本问题来说明 CTC。
CTC 的 3 个基本问题:
(1)概率计算问题:在时刻
T
T
T,给定标签
l
∈
L
≤
T
l\in L^{\le T}
l∈L≤T和观测序列
x
=
(
x
1
,
x
2
,
⋯
,
x
T
)
x = (x_1, x_2, \cdots, x_T)
x=(x1,x2,⋯,xT),计算概率
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x)。不过这里不同于 HMM 计算
P
(
O
∣
λ
)
\mathbb{P}(O|\lambda)
P(O∣λ),CTC 计算
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x) 纯粹是为了训模型。
(2)学习问题:已知标签
l
∈
L
≤
T
l\in L^{\le T}
l∈L≤T和观测序列
x
=
(
x
1
,
x
2
,
⋯
,
x
T
)
x = (x_1, x_2, \cdots, x_T)
x=(x1,x2,⋯,xT),估计模型
h
h
h 的参数。
(3)预测问题:也称为解码问题,或是对齐问题。已知模型
h
h
h 和观测序列
x
=
(
x
1
,
x
2
,
⋯
,
x
T
)
x = (x_1, x_2, \cdots, x_T)
x=(x1,x2,⋯,xT),求使
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x) 最大的标签(路径)
l
∈
L
≤
T
l\in L^{\le T}
l∈L≤T。即给定观测序列,求最有可能的对应的标签序列。
二、概率计算算法
训模型采用的是极大似然估计,要使得
h
(
x
)
=
arg
max
l
∈
L
≤
T
P
(
l
∣
x
)
(1)
h(x) = \arg\max\limits_{l \in L^{\le T}}\mathbb{P}(l|x) \tag{1}
h(x)=argl∈L≤TmaxP(l∣x)(1)
首先要算出
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x).
不同于 HMM 的学习问题用的是无监督的 Baum-Welch 算法,CTC 是要通过神经网络(反向传播算法)来训练模型参数。神经网络的 softmax 层输出
y
k
t
y_k^t
ykt,
t
t
t 时刻第
k
k
k 个节点输出的概率,即
t
t
t 时刻观测到标签
k
k
k 的概率
P
(
l
t
=
k
∣
x
)
\mathbb{P}(l_t = k|x)
P(lt=k∣x),这样将神经网络与概率建模联系起来。
神经网络的输入输出节点数是固定的,模型为
N
:
(
R
m
)
T
⟼
(
R
n
)
T
x
⟶
y
(2)
\begin{aligned} N: (\mathbb{R}^m)^T &\longmapsto (\mathbb{R}^n)^T \\ x &\longrightarrow y \end{aligned} \tag{2}
N:(Rm)Tx⟼(Rn)T⟶y(2)
原文中,将网络输出的标签序列称为路径
π
\pi
π,给定观测序列
x
x
x,输出
π
\pi
π 的概率为
P
(
π
∣
x
)
=
P
(
π
T
∣
π
T
−
1
,
⋯
,
π
1
,
x
)
P
(
π
T
−
1
∣
π
T
−
2
,
⋯
,
π
1
,
x
)
⋯
P
(
π
2
∣
π
1
,
x
)
P
(
π
1
∣
x
)
=
P
(
π
T
∣
x
)
P
(
π
T
−
1
∣
x
)
⋯
P
(
π
1
∣
x
)
=
∏
t
=
1
T
y
π
t
t
,
∀
π
∈
L
′
T
(3)
\begin{aligned} \mathbb{P}(\pi|x) &= \mathbb{P}(\pi_T|\pi_{T-1}, \cdots,\pi_1, x) \mathbb{P}(\pi_{T-1}|\pi_{T-2}, \cdots,\pi_1, x)\cdots\mathbb{P}(\pi_2|\pi_1, x) \mathbb{P}(\pi_1|x) \\ &= \mathbb{P}(\pi_T|x) \mathbb{P}(\pi_{T-1}|x)\cdots\mathbb{P}(\pi_1|x) \\ &= \prod_{t=1}^T y_{\pi_t}^t, \ \ \ \ \ \ \ \forall \pi \in L'^T \end{aligned} \tag{3}
P(π∣x)=P(πT∣πT−1,⋯,π1,x)P(πT−1∣πT−2,⋯,π1,x)⋯P(π2∣π1,x)P(π1∣x)=P(πT∣x)P(πT−1∣x)⋯P(π1∣x)=t=1∏Tyπtt, ∀π∈L′T(3)
公式
(
3
)
(3)
(3) 有两个点需要注意:(1)第二个等号成立,是假设每个时刻输出的值是条件独立的,这其实是 CTC 算法被诟病的一个主要原因。因为这个假设不合理,语音相邻发音,连读、吞音等情况是很常见的,下一时刻的语音是与上一时刻相关的,比如哈哈和嘿哈,前一个字的开口大小不同,发下一个音也会受到影响。这也催生了后来的 RNN-T、LAS 算法。(2)注意这里是
∀
π
∈
L
′
T
\forall \pi \in L'^T
∀π∈L′T,
L
′
=
L
⋃
{
−
}
L' = {L\bigcup \{-\}}
L′=L⋃{−},是带了空记号的。虽然加入了空记号可以解决叠字问题,但也引入了新的问题,生成
l
l
l 的路径会非常多。
比如
x
=
(
x
1
,
x
2
,
x
3
,
x
4
)
x=(x_1, x_2, x_3, x_4)
x=(x1,x2,x3,x4),标签为
l
=
l =
l= 打开 ,则对应的可能得解码路径有 打打开-,-打开开, 打开开开,打开--,打-开-,打--开,-打开-,-打-开,--打开……即存在多对一映射
B
:
L
′
T
⟼
L
≤
T
π
⟶
l
\begin{aligned} B: L'^T &\longmapsto L^{\le T} \\ \pi &\longrightarrow l \end{aligned}
B:L′Tπ⟼L≤T⟶l
将神经网络解码出的路径,映射到最终的标签上。根据公式
(
3
)
(3)
(3),我们能算出
P
(
π
∣
x
)
\mathbb{P}(\pi|x)
P(π∣x),那么
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x) 便是将所有能产生
l
l
l 的路径
π
\pi
π 的概率全都加起来:
P
(
l
∣
x
)
=
∑
π
∈
B
−
1
(
l
)
P
(
π
∣
x
)
(4)
\mathbb{P}(l|x) = \sum_{\pi \in B^{-1}(l)}\mathbb{P}(\pi|x) \tag{4}
P(l∣x)=π∈B−1(l)∑P(π∣x)(4)
2.1 前向算法
要利用
(
4
)
(4)
(4) 计算
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x),和 HMM 的概率计算相似,仍然是采用基于动态规划的前向后向算法,有这样4个步骤:(1)确定递推变量的物理意义,(2)初始化,(3)确定递推公式,(4)终止。
(1)前向变量
α
t
(
s
)
=
def
∑
π
∈
L
′
T
:
B
(
π
1
:
t
)
=
l
1
:
s
∏
t
′
=
1
t
y
π
t
′
t
′
∀
1
≤
t
≤
T
,
0
≤
s
≤
T
(5)
\alpha_t(s) \overset{\text{def}}{=} \sum_{\pi \in L'^T:B(\pi_{1:t}) = l_{1:s}} \prod_{t'=1}^t y_{\pi_t'}^{t'} \ \ \ \ \ \forall 1\le t \le T,0 \le s \le T \tag{5}
αt(s)=defπ∈L′T:B(π1:t)=l1:s∑t′=1∏tyπt′t′ ∀1≤t≤T,0≤s≤T(5)
其中
π
1
:
t
\pi_{1:t}
π1:t 表示
π
\pi
π 从下标
1
1
1 到
t
t
t 的子序列,
l
1
:
s
l_{1:s}
l1:s 同理。公式
(
5
)
(5)
(5) 是前向变量的定义,表示给定
x
x
x,能映射到
l
1
:
s
l_{1:s}
l1:s 的
π
\pi
π 的子路径的概率和。
这里引入
l
′
l'
l′, 如果
l
=
l =
l=CAT,那么
l
′
=
l' =
l′= -C-A-T-,
l
l
l 的长度为3,
∣
l
∣
=
3
|l| = 3
∣l∣=3,
∣
l
′
∣
=
2
∣
l
∣
+
1
=
7
|l'| = 2|l| + 1 = 7
∣l′∣=2∣l∣+1=7. 即
l
′
l'
l′ 也是一条标签序列,是在
l
l
l 的首尾以及每两个标签中间都插入 - 得到的。如图
2
2
2 所示,前向算法,都是从左上角出发,一直到右下角,白色的圈代表-,黑色圈是
l
l
l 中的标签。
图2 前向算法
(2)初始化
如图
2
2
2 所示,
t
=
1
t=1
t=1初始化,要解码出CAT,第
1
1
1 行出发也行(如--C-A-T,以
∣
l
′
∣
=
7
|l'| = 7
∣l′∣=7 举例),从第
2
2
2 行出发也行(如C--A-T-),但不能从第
3
3
3 行出发,那样就解不出C了。于是
α
1
(
1
)
=
y
b
1
α
1
(
2
)
=
y
l
1
1
α
1
(
s
)
=
0
,
∀
s
>
2
\begin{aligned} \alpha_1(1) &= y_b^1 \\ \alpha_1(2) &= y_{l1}^1 \\ \alpha_1(s) &= 0, \ \ \ \forall s>2 \end{aligned}
α1(1)α1(2)α1(s)=yb1=yl11=0, ∀s>2
其中
y
b
1
y_b^1
yb1 下标
b
b
b 表示-。
(3)递推公式
我们接下来要推出
t
>
1
t>1
t>1 时刻的
α
t
(
s
)
\alpha_t(s)
αt(s),观察图
2
2
2,除了刚出发的前两行,基本上黑色圈都有 3 个箭头指向它,白色圈是 2 个箭头指向它,比如当
l
s
′
=
b
l_s' = b
ls′=b,代表此刻是白色圈,它来自左边的状态和左上的状态,于是有
α
t
(
s
)
=
α
t
−
1
(
s
)
y
l
s
′
t
+
α
t
−
1
(
s
−
1
)
y
l
s
′
t
,
i
f
l
s
′
=
b
\alpha_t(s) = \alpha_{t-1}(s) y_{l'_s}^t + \alpha_{t-1}(s-1) y_{l'_s}^t, \ \ \ if l_s' = b
αt(s)=αt−1(s)yls′t+αt−1(s−1)yls′t, ifls′=b
同理若
l
s
′
!
=
b
l_s' != b
ls′!=b,则有
α
t
(
s
)
=
α
t
−
1
(
s
)
y
l
s
′
t
+
α
t
−
1
(
s
−
1
)
y
l
s
′
t
+
α
t
−
1
(
s
−
2
)
y
l
s
′
t
,
i
f
l
s
′
!
=
b
&
l
s
−
2
′
≠
l
s
′
\alpha_t(s) = \alpha_{t-1}(s) y_{l'_s}^t + \alpha_{t-1}(s-1) y_{l'_s}^t+ \alpha_{t-1}(s-2) y_{l'_s}^t, \ \ \ if l_s' != b\ \ \& \ \ l'_{s-2}\neq l'_{s}
αt(s)=αt−1(s)yls′t+αt−1(s−1)yls′t+αt−1(s−2)yls′t, ifls′!=b & ls−2′=ls′
我们看到上式后面还有一个约束
l
s
−
2
′
≠
l
s
′
l'_{s-2} \neq l'_{s}
ls−2′=ls′,这代表一种特殊情况,并不是所有的黑色圈都有三条箭头指向,比如SEE,如果解码图是---S-EE,对应的标签序列为SE,这是因为我们的标签中本身有叠字,我们希望解码路径是-S-E--E,这样得到标签序列为SEE,所以我们不允许两个相同标签直接跳转。
综合起来,就有
α
t
(
s
)
=
{
(
α
t
−
1
(
s
)
+
α
t
−
1
(
s
−
1
)
)
y
l
s
′
t
i
f
l
s
′
=
b
o
r
l
s
−
2
′
=
l
s
′
(
α
t
−
1
(
s
)
+
α
t
−
1
(
s
−
1
)
+
α
t
−
1
(
s
−
2
)
)
y
l
s
′
t
o
t
h
e
r
w
i
s
e
(6)
\alpha_t(s) =\begin{cases} (\alpha_{t-1}(s) + \alpha_{t-1}(s-1)) y_{l'_s}^t \ \ \ \ \ \ \ if\ l'_s=b\ or\ l'_{s-2}=l'_s \\ (\alpha_{t-1}(s) + \alpha_{t-1}(s-1) + \alpha_{t-1}(s-2)) y_{l'_s}^t \ \ \ otherwise \end{cases} \tag{6}
αt(s)={(αt−1(s)+αt−1(s−1))yls′t if ls′=b or ls−2′=ls′(αt−1(s)+αt−1(s−1)+αt−1(s−2))yls′t otherwise(6)
注意到
α
t
(
s
)
=
0
∀
s
<
∣
l
∣
−
(
T
−
t
)
\alpha_t(s) = 0 \ \ \forall s<|l|-(T-t)
αt(s)=0 ∀s<∣l∣−(T−t),因为如果剩下的时间
T
−
t
T-t
T−t 太短,来不及解出剩下的标签
∣
l
∣
−
u
|l|-u
∣l∣−u,即
T
−
t
<
∣
l
∣
−
s
T-t < |l|-s
T−t<∣l∣−s,那概率就是
0
0
0 了,表示图
2
2
2 右上角的那部分没有箭头。 并且有
α
t
(
s
)
=
0
∀
s
<
1
\alpha_t(s) = 0 \ \ \forall s<1
αt(s)=0 ∀s<1.
(4)终止
结尾指向右下角的白色圈或黑色圈都可以,故有
P
(
l
∣
x
)
=
α
T
(
∣
l
′
∣
)
+
α
T
(
∣
l
′
∣
−
1
)
(7)
\mathbb{P}(l|x) = \alpha_{T}(|l'|) + \alpha_{T}(|l'|-1) \tag{7}
P(l∣x)=αT(∣l′∣)+αT(∣l′∣−1)(7)
2.2 后向算法
只用前向算法已经可以算出
P
(
l
∣
x
)
\mathbb{P}(l|x)
P(l∣x) 了,我们对称写出后向算法,在反向传播训练算偏导数时能用到。
(1)后向变量表示给定
x
x
x,能映射到
l
s
:
∣
l
∣
l_{s:|l|}
ls:∣l∣ 的
π
\pi
π 的子路径的概率和。
β
t
(
s
)
=
def
∑
π
∈
L
′
T
:
B
(
π
t
:
T
)
=
l
s
:
∣
l
∣
∏
t
′
=
t
T
y
π
t
′
t
′
∀
1
≤
t
≤
T
,
0
≤
s
≤
T
(8)
\beta_t(s) \overset{\text{def}}{=} \sum_{\pi \in L'^T:B(\pi_{t:T}) = l_{s:|l|}} \prod_{t'=t}^T y_{\pi_t'}^{t'} \ \ \ \ \ \forall 1\le t \le T,0 \le s \le T \tag{8}
βt(s)=defπ∈L′T:B(πt:T)=ls:∣l∣∑t′=t∏Tyπt′t′ ∀1≤t≤T,0≤s≤T(8)
(2)初始化
第
T
T
T 列初始化
β
T
(
∣
l
′
∣
)
=
y
b
T
β
T
(
∣
l
′
∣
−
1
)
=
y
l
∣
l
∣
T
β
T
(
s
)
=
0
,
∀
s
<
∣
l
′
∣
−
1
\begin{aligned} \beta_T(|l'|) &= y_b^T \\ \beta_T(|l'|-1) &= y_{l_|l|}^T \\ \beta_T(s) &= 0, \ \ \ \forall s<|l'|-1 \end{aligned}
βT(∣l′∣)βT(∣l′∣−1)βT(s)=ybT=yl∣l∣T=0, ∀s<∣l′∣−1
(3)递推公式
β
t
(
s
)
=
{
(
β
t
+
1
(
s
)
+
α
t
+
1
(
s
+
1
)
)
y
l
s
′
t
i
f
l
s
′
=
b
o
r
l
s
+
2
′
=
l
s
′
(
β
t
+
1
(
s
)
+
α
t
+
1
(
s
+
1
)
+
α
t
+
1
(
s
+
2
)
)
y
l
s
′
t
o
t
h
e
r
w
i
s
e
(9)
\beta_t(s) =\begin{cases} (\beta_{t+1}(s) + \alpha_{t+1}(s+1)) y_{l'_s}^t \ \ \ \ \ \ \ if\ l'_s=b\ or\ l'_{s+2}=l'_s \\ (\beta_{t+1}(s) + \alpha_{t+1}(s+1) + \alpha_{t+1}(s+2)) y_{l'_s}^t \ \ \ otherwise \end{cases} \tag{9}
βt(s)={(βt+1(s)+αt+1(s+1))yls′t if ls′=b or ls+2′=ls′(βt+1(s)+αt+1(s+1)+αt+1(s+2))yls′t otherwise(9)
(4)终止
结尾指向左上角的白色圈或黑色圈都可以,故有
P
(
l
∣
x
)
=
β
1
(
1
)
+
β
1
(
2
)
(10)
\mathbb{P}(l|x) = \beta_{1}(1) + \beta_{1}(2) \tag{10}
P(l∣x)=β1(1)+β1(2)(10)
三、学习算法
已知训练集
S
S
S,
N
w
N_w
Nw 代表权重为
w
w
w 的神经网络,整体误差是全体样本负对数似然的总和,即
O
M
L
(
S
,
N
w
)
=
−
∑
(
x
,
l
)
∈
S
l
n
(
P
(
l
∣
x
)
)
(11)
O^{ML}(S, N_w) = - \sum_{(x,l)\in S} ln(\mathbb{P}(l|x)) \tag{11}
OML(S,Nw)=−(x,l)∈S∑ln(P(l∣x))(11)
我们通过反向传播算法来更新参数
w
w
w,要求误差对输出变量
y
k
t
y_k^t
ykt 的偏导数
∂
O
M
L
(
S
,
N
w
)
∂
y
k
t
=
−
∂
l
n
(
P
(
l
∣
x
)
)
∂
y
k
t
(12)
\frac{\partial O^{ML}(S, N_w)}{\partial y_k^t} = - \frac{\partial ln(\mathbb{P}(l|x))}{\partial y_k^t} \tag{12}
∂ykt∂OML(S,Nw)=−∂ykt∂ln(P(l∣x))(12)
(
12
)
(12)
(12) 中求和号没了是因为独立性假设。
下面就是学习算法中核心的表达式,根据前向变量和后向变量的定义,有
α
t
(
s
)
β
t
(
s
)
=
∑
π
∈
B
−
1
(
l
)
:
π
t
=
l
s
y
l
s
t
∏
t
=
1
T
y
π
t
t
(13)
\alpha_t(s) \beta_t(s) = \sum_{\pi \in B^{-1}(l): \pi_t = l_s} y_{l_s}^t \prod_{t=1}^T y_{\pi_t}^t \tag{13}
αt(s)βt(s)=π∈B−1(l):πt=ls∑ylstt=1∏Tyπtt(13)
α
t
(
s
)
\alpha_t(s)
αt(s) 代表时刻
t
t
t 映射到
l
1
:
s
l_{1:s}
l1:s 的概率,且
π
t
=
l
s
\pi_t = l_s
πt=ls; 同理,
β
t
(
s
)
\beta_t(s)
βt(s) 代表时刻
t
t
t 映射到
l
s
:
T
l_{s:T}
ls:T 的概率,且
π
t
=
l
s
\pi_t = l_s
πt=ls。两者相乘,右边项就会多出
y
l
s
t
y_{l_s}^t
ylst. 将
y
l
s
t
y_{l_s}^t
ylst 除到左边,两边遍历
t
t
t 和
s
s
s 相加,利用公式
(
3
)
(3)
(3) 和公式
(
4
)
(4)
(4) 可以得到
P
(
l
∣
x
)
=
∑
t
=
1
T
∑
s
=
1
∣
l
∣
α
t
(
s
)
β
t
(
s
)
y
l
s
t
(14)
\mathbb{P}(l|x) = \sum_{t=1}^T \sum_{s=1}^{|l|} \frac{\alpha_t(s) \beta_t(s)}{y_{l_s}^t} \tag{14}
P(l∣x)=t=1∑Ts=1∑∣l∣ylstαt(s)βt(s)(14)
设
l
a
b
(
l
,
k
)
=
{
s
:
l
s
=
k
}
lab(l,k) = \{s: l_s = k\}
lab(l,k)={s:ls=k},利用条件独立性假设,有
∂
P
(
l
∣
x
)
∂
y
k
t
=
−
1
y
k
t
2
∑
s
∈
l
a
b
(
l
,
k
)
α
t
(
s
)
β
t
(
s
)
(15)
\frac{\partial \mathbb{P}(l|x)}{\partial y_k^t} = -\frac{1}{{y_k^t}^2} \sum_{s\in lab(l,k)} \alpha_t(s) \beta_t(s) \tag{15}
∂ykt∂P(l∣x)=−ykt21s∈lab(l,k)∑αt(s)βt(s)(15)
我们的最终目标是求
∂
l
n
(
P
(
l
∣
x
)
)
∂
y
k
t
=
1
P
(
l
∣
x
)
∂
P
(
l
∣
x
)
∂
y
k
t
(16)
\frac{\partial ln(\mathbb{P}(l|x))}{\partial y_k^t} = \frac{1}{\mathbb{P}(l|x)} \frac{\partial \mathbb{P}(l|x)}{\partial y_k^t} \tag{16}
∂ykt∂ln(P(l∣x))=P(l∣x)1∂ykt∂P(l∣x)(16)
将公式
(
7
)
(7)
(7) 和 公式
(
15
)
(15)
(15) 带入
(
12
)
(12)
(12),可得误差对输出变量
y
k
t
y_k^t
ykt 的偏导数。
设 softmax 层之前,时刻
t
t
t 节点
k
k
k 的输出是
u
k
t
u_k^t
ukt,反向传播是对偏导数
∂
l
n
(
P
(
l
∣
x
)
)
∂
u
k
t
\frac{\partial ln(\mathbb{P}(l|x))}{\partial u_k^t}
∂ukt∂ln(P(l∣x)) 进行回传。
已知 softmax 层,
y
k
t
=
e
u
k
t
∑
k
′
e
u
k
′
t
y_k^t = \frac{e^{u_k^t}}{\sum_{k'} e^{u_{k'}^t}}
ykt=∑k′euk′teukt
其中
∑
k
′
\sum_{k'}
∑k′ 代表
k
′
k'
k′ 求和遍历所有的输出层节点。
那么
∂
y
k
′
t
∂
u
k
t
=
e
u
k
′
t
δ
k
′
k
∑
k
′
e
u
k
′
t
−
e
u
k
′
t
e
u
k
t
(
∑
k
′
e
u
k
′
t
)
2
=
y
k
′
t
δ
k
′
k
−
y
k
′
t
y
k
t
(17)
\frac{\partial y_{k'}^t}{\partial u_k^t} = \frac{e^{u_{k'}^t}\delta_{k'k} \sum_{k'}e^{u_{k'}^t}- e^{u_{k'}^t}e^{u_k^t}}{(\sum_{k'}e^{u_{k'}^t})^2} = y_{k'}^t\delta_{k'k} - y_{k'}^t y_k^t \tag{17}
∂ukt∂yk′t=(∑k′euk′t)2euk′tδk′k∑k′euk′t−euk′teukt=yk′tδk′k−yk′tykt(17)
其中
δ
k
′
k
=
{
1
i
f
k
′
=
k
0
o
t
h
e
r
w
i
s
e
\delta_{k'k} = \begin{cases} 1 \ \ \ \ \ \ \ if\ k' = k \\ 0\ \ \ \ \ \ \ \ otherwise \end{cases}
δk′k={1 if k′=k0 otherwise
根据链式法则
∂
l
n
(
P
(
l
∣
x
)
)
∂
u
k
t
=
∑
k
′
∂
l
n
(
P
(
l
∣
x
)
)
∂
y
k
′
t
∂
y
k
′
t
∂
u
k
t
(18)
\frac{\partial ln(\mathbb{P}(l|x))}{\partial u_k^t} = \sum_{k'} \frac{\partial ln(\mathbb{P}(l|x))}{\partial y_{k'}^t} \frac{\partial y_{k'}^t}{\partial u_k^t} \tag{18}
∂ukt∂ln(P(l∣x))=k′∑∂yk′t∂ln(P(l∣x))∂ukt∂yk′t(18)
将
(
16
)
(16)
(16) 和
(
17
)
(17)
(17) 带入
(
18
)
(18)
(18),可得
∂
l
n
(
P
(
l
∣
x
)
)
∂
u
k
t
=
y
k
t
−
1
y
k
t
P
(
l
∣
x
)
∑
s
∈
l
a
b
(
l
,
k
)
α
t
(
s
)
β
t
(
s
)
(19)
\frac{\partial ln(\mathbb{P}(l|x))}{\partial u_k^t} = y_k^t - \frac{1}{y_k^t\mathbb{P}(l|x)} \sum_{s\in lab(l,k)} \alpha_t(s) \beta_t(s) \tag{19}
∂ukt∂ln(P(l∣x))=ykt−yktP(l∣x)1s∈lab(l,k)∑αt(s)βt(s)(19)
其中用到了
P
(
l
∣
x
)
=
∑
k
′
∑
s
∈
l
a
b
(
l
,
k
′
)
α
t
(
s
)
β
t
(
s
)
y
k
′
t
\mathbb{P}(l|x) = \sum_{k'}\sum_{s\in lab(l,k')} \frac{\alpha_t(s) \beta_t(s)}{y_{k'}^t}
P(l∣x)=∑k′∑s∈lab(l,k′)yk′tαt(s)βt(s).

图3 CTC训练过程
将
∂
l
n
(
P
(
l
∣
x
)
)
∂
u
k
t
\frac{\partial ln(\mathbb{P}(l|x))}{\partial u_k^t}
∂ukt∂ln(P(l∣x)) 作为误差量(即图
3
3
3 中的error),如图
3
3
3 所示,左边是 CTC 训练过程中神经网络的概率输出,不同颜色代表不同的标签,虚线代表空记号的概率。可以看到 CTC 对各个标签的预测呈现尖峰形状,大部分时刻都预测为空记号-。右边是回传的倒数,开始时参数随机初始化,训练初期(如(a)所示),各个颜色曲线相对平缓,随着训练时间变长,偏导数往预测点附近集中,水平线之上的使得概率变大,水平线之下的让概率变小(如(b)所示)。训练快结束时(如(c)所示),左边各尖峰已经确定,右边偏导数也很小了,模型参数基本确定。
四、预测算法
模型训练好后,需要根据输入音频,解码得到对应的标签序列,即选择
l
∗
l^*
l∗,使得
l
∗
=
arg
max
l
P
(
l
∣
x
)
l^* = \arg\max_l \mathbb{P}(l|x)
l∗=arglmaxP(l∣x)
论文中给出了两种解码算法。
4.1 最佳路径解码(best path decoding)
和 HMM 中的近似算法一样,选择每个时刻
t
t
t 概率最大的标签,挨个组合起来即可。

图4 best path decoding3
| 时间步 | P(-) | P(A) |
|---|---|---|
| t=1 | 0.7 | 0.3 |
| t=2 | 0.6 | 0.4 |
举个例子,如图
4
4
4 所示,当
t
=
1
t=1
t=1 时,概率最大的是
P
(
π
1
=
b
l
a
n
k
)
=
0.7
\mathbb{P}(\pi_1 = blank) = 0.7
P(π1=blank)=0.7,当
t
=
2
t=2
t=2 时,概率最大的是
P
(
π
2
=
b
l
a
n
k
)
=
0.6
\mathbb{P}(\pi_2 = blank) = 0.6
P(π2=blank)=0.6,所以根据最佳路径解码,最优路径为 -。其实如图
4
4
4 所示,最优路径是
l
=
A
l = A
l=A.
最佳路径解码是一种近似解法,优点是速度快,大部分情况下也能解码出不错的结果。缺点是,结果可能不一定是全局最优的,如图
4
4
4 所示,最佳路径解码与全局最优路径差别较大。
4.2 前缀搜索解码(prefix search decoding)
将每一步最可能的前缀路径保存下来,在此基础上继续解码。
举个例子4:
| 时间步 | P(-) | P(A) | P(B) |
|---|---|---|---|
| t=1 | 0.3 | 0.2 | 0.5 |
| t=2 | 0.1 | 0.5 | 0.4 |
| t=3 | 0.3 | 0.1 | 0.6 |
- 初始化:维护一个候选前缀记号,初始时仅包含空序列
"",其累计概率为 1.0 1.0 1.0;每个时间步保留概率最高的那个,即束宽(Beam Width)设为 1。 - 时间步
t
=
1
t=1
t=1
- 对初始前缀
"",生成可能得扩展:- 添加字符
A,概率为 0.2,路径为A。 - 添加字符
B,概率为 0.5,路径为B。 - 添加字符
-,概率为 0.3,路径为""。
- 添加字符
- 合并相同前缀,不变。
- 剪枝(保留概率最大的前缀),即
B
- 对初始前缀
- 时间步
t
=
2
t=2
t=2
- 对前缀
B,生成可能得扩展:- 添加字符
A,概率为 0.25,路径为BA,合并路径后不变。 - 添加字符
B,概率为 0.2,路径为BB,合并路径后得B。 - 添加字符
-,概率为 0.05,路径为B-,合并路径后得B。
- 添加字符
- 合并相同前缀
- 路径
BA, 总概率 0.25。 - 路径
B, 总概率 0.25。
- 路径
- 剪枝
- 由于
BA和B概率一样,都保留。
- 由于
- 对前缀
- 时间步
t
=
3
t=3
t=3
- 前缀
BA,生成可能扩展- 添加字符
A,概率为 0.025,路径为BAA,合并路径后得到BA。 - 添加字符
B,概率为 0.15,路径为BAB,合并路径后不变。 - 添加字符
-,概率为 0.075,路径为BA-,合并路径后得到BA。
- 添加字符
- 前缀
B,生成可能扩展- 添加字符
A,概率为 0.025,路径为BA,合并路径后得到BA。 - 添加字符
B,概率为 0.15,路径为BB,合并路径后得到B。 - 添加字符
-,概率为 0.075,路径为B-,合并路径后得到B。
- 添加字符
- 合并相同前缀
- 路径
BA, 总概率 = 0.025 + 0.075 + 0.025 = 0.125。 - 路径
BAB, 总概率 = 0.15。 - 路径
B, 总概率 = 0.15 + 0.075 = 0.225。
- 路径
- 前缀
所以概率最高的路径是 B,这个结果是对的,但与全遍历的概率相比
P
(
l
=
B
)
=
P
(
B
−
−
)
+
P
(
−
B
−
)
+
P
(
−
−
B
)
+
P
(
B
B
−
)
+
P
(
−
B
B
)
+
P
(
B
B
B
)
=
0.5
×
0.1
×
0.3
+
0.3
×
0.4
×
0.3
+
0.3
×
0.1
×
0.6
+
0.5
×
0.4
×
0.3
+
0.3
×
0.4
×
0.6
+
0.5
×
0.4
×
0.6
=
0.321
\begin{aligned} \mathbb{P}(l = B) &= \mathbb{P}(B--)+\mathbb{P}(-B-)+\mathbb{P}(--B)+\mathbb{P}(BB-)+\mathbb{P}(-BB)+\mathbb{P}(BBB) \\ &= 0.5\times0.1\times0.3+0.3\times0.4\times0.3+0.3\times0.1\times0.6+0.5\times0.4\times0.3+0.3\times0.4\times0.6+0.5\times0.4\times0.6 \\ &= 0.321 \end{aligned}
P(l=B)=P(B−−)+P(−B−)+P(−−B)+P(BB−)+P(−BB)+P(BBB)=0.5×0.1×0.3+0.3×0.4×0.3+0.3×0.1×0.6+0.5×0.4×0.3+0.3×0.4×0.6+0.5×0.4×0.6=0.321
还是有差距的,所以前缀搜索解码也是一种相似算法。
总结
本文介绍了 CTC 算法,包括 CTC 的 3 个基本问题。为了行文与 HMM2 对应,罗列了 3 个基本问题,问题 1 是利用前向后向算法算似然函数。问题 2 算出偏导数,利用反向传播算法更新模型参数。问题 3 利用训好的模型解码最优路径。Pytorch 官方已经实现了 CTCLoss5 。
参考文献
Alex Graves, et al. Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks. 2006. ↩︎
隐马尔科夫模型(HMM), 2025. https://blog.csdn.net/weixin_45234741/article/details/147023021?spm=1001.2014.3001.5501 ↩︎ ↩︎
Alex Graves, Supervised Sequence Labelling with Recurrent Neural Networks.(第七章), Springer, 2012 ↩︎
洪青阳,李琳, 《语音识别原理与应用》, 2020. ↩︎
https://pytorch.org/docs/stable/generated/torch.nn.CTCLoss.html ↩︎
4488

被折叠的 条评论
为什么被折叠?



