前言

CTC全称Connectionist temporal classification,是一种常用在语音识别、文本识别等领域的算法,用来解决输入和输出序列长度不一、无法对齐的问题。在CRNN中,它实际上就是模型对应的损失函数。CRNN的模型结构如下图所示:
preview

其中的Feature sequence即为下文所说的x输入变量,Predicted sequence即为下文所说的y输出变量,此时x和y的长度是不一样的,所以CTC主要做的工作就是x和y的对齐。

再进行进一步叙述前,这里需要做几点说明。不管是在语音识别还是文本识别领域,CTC通常接在RNN的后面,与RNN结合使用,就像CRNN中一样。所以后面除非特别说明,否则提到的CTC均是将RNN和CTC当整体看待。

RNN在CRNN模型中代表的就是BiLSTM,它接受经过CNN提取的特征向量,大小为 [公式][公式] 即上文提到的特征图的宽度,由于高度为1,所以被去掉了, [公式] 即为特征图的通道数。为了便于理解,后面将 [公式] 也记作 [公式] ,也可以简写为 [公式] ,即CTC中常涉及的概念——时间步。输出序列的大小为 [公式] ,序列长度与输入一致。而每个分量(向量)的维度均为 [公式] ,在这里等于字符字典的个数,表示字典个数的概率分布。概率分布经过变换便可以得到最终的预测结果。

为方便叙述,假设输入的序列为 [公式] ,对应的输出序列为 [公式] ,在这里希望找到 [公式][公式] 的映射关系。

如果使用一般的监督学习算法,会面临诸多的问题,主要可以概括为以下几点:

  • [公式][公式] 的长度是可变的。
  • [公式][公式] 的长度比例也是可变的。
  • [公式][公式] 对应元素之间不能找到严格的对齐关系。

而CTC正是一种可以解决这些问题的算法。对于一个给定的输入 [公式] ,它可以计算对应所有可能的 [公式] 的概率分布。通过该概率分布,可以预测最大概率对应的输出或者某个特定输出的概率

由此可以引出损失函数的定义。对于一个给定的输入 [公式] ,转录层需要最大化对应 [公式] 的后验概率 [公式] 。当然为了能够正常地训练模型, [公式] 应该是可导的。由于训练模型通常以最小化损失函数为目标,所以将优化目标转为最小化 [公式] 的负对数似然值,即:

[公式]

其中 [公式] 表示训练集。

而在预测阶段,每给定一个输入x,CRNN要找到最大概率对应的输出,即

[公式]

不难想到,如果序列长度稍长,所有概率分布的计算量是及其巨大的,因此这里需要一个速度更快的算法。

前面说过,对于给定的输入 [公式] ,转录层需要计算所有可能的 [公式] 的概率分布,而关键的问题在于如何处理 [公式][公式] 间的对齐问题。所以下面先分析CTC的对齐方式。

CTC的训练目标

CTC的训练过程,本质上是通过梯度 [公式] 调整LSTM的参数 [公式] ,使得对于输入样本为 [公式] 时使得 [公式] 取得最大。

例如下面图14的训练样本,目标都是使得 [公式] 时的输出 [公式] 变大。所以CTC额本质是替代softmaxloss的损失函数,并采用BPTT算法更新LSTM的参数。

图14

2. 对齐

要说明的是,CTC是不需要输入输出进行对齐的。但是对于给定的输入,为了计算对应 [公式] 的概率,仍需要对所有可能对齐的概率进行求和,因为可能同一个输出有多个输出路径对应。下面举例进行说明。

例如CRNN的输入 [公式] 是一张包含单词“cat”的图片,所以对应的输出序列应该为 [公式] 。那么一种对齐 [公式][公式] 的方式是先对输入的每个分量 [公式] 对应一个输出字符,然后将相邻的重复字符进行合并,具体如下图所示。

图1 单词cat对齐过程 [1]

当然这里很容易发现这种对应方式是不合理的。第一个问题是输入的图片可能根本不包含任何字符,即输出的结果应该为空,而强制每个输入分量 [公式] 对应一个字符显然得不到这样的结果。第二个问题是如果将所有相邻重复字符都进行合并处理的话,将不能产生连续相同字符,导致结果可能是错误的。比如如果将单词tooth进行合并处理,那么最终的输出将是toth而不是tooth。

所以考虑上述问题,CTC算法又引入了一个特殊的字符——占位符,记作 [公式][公式] 。它表示一个占位,不对应任何字符,因此在最终的输出时要将其删除。这样以后这里仍可以采用上述的对齐规则,并同时避免以上的问题,当然最后不要忘了在输出中去掉 。单词hello的对齐过程如下图所示。

图2 单词hello对齐过程 [1]

可以看出,如果单词存在两个相同的字符,为了能够处理这种情况,需要在这两个字符间插入 [公式] 。这样就能区分诸如“toth”和“tooth”的对齐方式了。

这样的规则具有以下几种特征。第一,输入 [公式] 与输出 [公式] 的对齐是单调的,即当 [公式] 前进至下一个时间片对应的输入分量 [公式] 时,[公式] 既可以保持不动,也可以移动至下一个时间片对应的输出分量 [公式] 。第二,输入与最终的输出是一对多的关系,即多个输入分量可能只对应一个输出分量。

所以,输出 [公式] 的长度一定不大于 [公式]

3. 后验概率

回顾CTC的优化目标,对于一个给定的输入 [公式] ,需要最大化 [公式] 对应 [公式] 的后验概率 [公式] ,所以显然需要先得到后验概率的值。通过上面定义的对齐规则,已经解决了最后序列合并的对齐问题。接下来说明具体如何根据每个时间片的概率,推算出最终输出序列的后验概率 [公式]

具体地,对于一个输入 [公式] ,每一时间步对应分量 [公式] 的特征维度,记为 [公式][公式] 经过BiLSTM输出 [公式] ,每个分量 [公式] 的维度记为 [公式] ,表示 [公式] 个概率。 [公式] 实际上等于字符集合 [公式] 的个数,假如需要预测的字符对应的字段包含52个英文字母(包括大小写),考虑之前加入的占位符,则 [公式] 的值就是53。

对于每个分量 [公式] ,都选取一个元素,便可以组成一条输出路径,记为 [公式] ,输出路径的空间可表示为 [公式]

定义一个映射 [公式] ,表示对中间输出路径进行变换,得到最后的输出 [公式] 。注意这里的路径不是最终的输出 [公式] ,需要经过合并相邻字符以及删除占位符的处理,才会得到 [公式] ,所以相当于中间结果。下面举例说明。

假设识别的序列为"taste", [公式] 时,那么以下几种路径均满足条件:

[公式]

因此求taste最终输出对输入的后验概率时 ,就是求这四条路径对应概率之和。进一步推广,给定输入 [公式] ,中间结果对应的路径 [公式] ,最终输出 [公式] ,则 [公式][公式] 的后验概率可以表示为:

[公式]

假设不同时间步的输出变量相互独立,那么对于输出路径 [公式][公式] 的后验概率可表示为:

[公式]

[公式] 表示路径 [公式][公式] 时间步时对应的输出字符,而 [公式] 表示在 [公式] 时间步时选取的字符为 [公式] 的概率。因此,综合上述两式可得:

[公式]

简单来说,公式表示的含义为 [公式][公式] 的后验概率等于所有对应路径的概率之和,而每条路径对 [公式] 的后验概率又等于组成该路径的字符出现概率的乘积。

由于连续重复字符以及占位符的存在,每一个特定的输出 [公式] 都会对应相当多的路径。如果这里逐一遍历进行求解,那么时间的复杂度可达到 [公式][公式] 为前面定义的字符集的个数, [公式] 为时间步总长。这是因为有 [公式] 个步长,而每个步长输出的字符又有 [公式] 种可能性。所以需要对算法进行改进,这里便借鉴了动态规划的思想。

4. 前向后向算法

对于一个最终输出序列 [公式] ,实际上也表示中间路径合并后的结果。定义 [公式] 表示在序列 [公式] 所有相邻元素之间插入占位符后的序列。比如:

[公式]

依然拿上述例子进行说明,如下图所示。

图3 单词state的可取路径 [3]

从上图可以看出,四条中间路径 [公式][公式][公式][公式] 合并处理后都可以得到state,并且他们都经过字符 [公式] 。如果将路径蓝色部分记为 [公式] ,红色部分记为 [公式] ,则不难推出:

[公式]

由于4条路径都经过 [公式] ,所以都包含 [公式] 项,提取公因式进行合并,令

[公式]

则公式 [公式] 可以写成:

[公式]

当然,这只是包含4条路径的结果,实际上序列state应该对应更多的路径,如下图所示。

图4 单词state所有可能路径 [3]

所以上述公式可推广为:

[公式]

进一步地,这里可以定义 [公式] , 表示时间步为 [公式] 时经过字符 [公式] 的所有路径在 [公式] 时刻的概率和,即:

[公式]

不难分析, [公式] 时字符只能占位符或 [公式] ,所以可得:

[公式]


进一步观察可以发现,由于 [公式] 的限制,[公式]时对应的字符只能为 [公式][公式][公式] 。所以可得递推公式:

[公式]

进一步推广可得一般式如下:

[公式]

类似地,这里可以定义 [公式] ,表示时间步为 [公式] 时经过字符 [公式] 的所有路径在 [公式] 时刻的概率和,即:

[公式]

不难分析,[公式] 时字符只能占位符或 [公式] ,所以可得初始条件:

[公式]

类似地,可得 [公式] 的递推公式为:

[公式]

由于 [公式][公式] 求导时,只与经过 [公式] 的路径有关,所以在反向传播对 [公式] 进行梯度计算时,便可以将公式进行简化:

[公式]

而由于

[公式]

所以将其带入可得:

[公式]

由上面的推导可知, [公式][公式] 都可以利用动态规划的思想通过递推公式求出,而不用从头开始计算,复杂度从 [公式] 变为了 [公式] ,大大简化了计算。而 [公式] 只涉及乘法和加法运算,显然是可导的,所以就可以通过上式进行反向传播计算了。

5. 预测

前面提到,在预测阶段,给定一个输入 [公式] ,计算最大概率对应的输出序列。如果假设时间片之间相互独立,那么只需将每一时间片对应概率最大的字符作为预测值,然后组成序列,最后做去重等处理得到最终结果。不过这样并没有考虑多个序列经过对齐对应同一个输出结果。例如,假如 [公式][公式] 各自的概率都低于 [公式] ,而二者的概率之和高于后者。前者对齐后的结果均为 [公式] ,而后者对齐的结果仍为 [公式] ,显然输出 [公式][公式] 更合理些。

所以为了避免这一问题的发生,又引入了另一种算法,称为Beam Search。

里面有个参数 [公式] ,用来指定每次保留的前缀序列的个数。假如设置 [公式] ,则每次选取概率最大的3个前缀序列,比如 [公式] 时选取概率最大的3个字符, [公式] 时也选取概率最大的3个字符,这样便有9种组合方式。当然对齐之后可能会对应相同的输出,所以要将结果相同的前缀序列进行合并(概率也要相加),然后挑出概率最大的3个作为下一次的输出,以此类推。以序列 [公式] 为例,具体过程如下图所示。

图5 Beam Search示意图 [1]

这里要注意的是,当前缀序列的末尾字符与下一个字符相同时,合并可以产生两种有效输出。

比如上图中 [公式] 时前缀序列为 [公式] , 而合并的字符同样为 [公式] ,这样既可以输出 [公式] ,也可以输出 [公式] ,二者都是可能的。因为在 [公式] 时,其中一个结果占位符 [公式] 在对齐时被移除了,但是在这里后面又遇到了相同的字符,按照前面定义的规则,此时合并的结果应该为 [公式][公式] 的两种计算情况如下图所示。

图6 [\epsilon,a,b] 的预测过程 [1]

所以,这两种结果应作为两种序列分别进行概率计算。当然,为了能够计算这两种情况对应的概率,需要分别记录以 [公式] 结尾的前缀序列的概率,以及不以 [公式] 结尾的前缀序列的概率。

6. 总结

以上便是CTC计算的所有过程。最后,总结CTC的几个特点。

  • 条件独立。回顾上面的计算过程,可以发现在进行路径概率计算时,CTC直接将每个时间片对应的概率值进行相乘,也就是说CTC默认每个时间片都是相互独立的。但是,在文本识别中,文本显然是包含上下文信息的,所以模型中才引入了RNN层。当然,结果表明这并没有妨碍到CTC在文本识别领域的优异表现。不过,假如能够在CTC中将输入数据的上下文信息考虑进去,效果应该能得到进一步的提升。


  • 单调对齐。CTC的规则决定了输入 与输出 的对齐是单调的。这也导致了CTC无法应用在机器翻译等不符合该约束的领域。


  • 多对一映射。输入与最终的输出是一对多的关系,即多个输入分量可能只对应一个输出分量。所以输出 的长度一定不大于 。所以如果遇到 的长度大于 长度的情况,CTC便无法处理了。

参考资料

[1] Sequence Modeling With CTC

[2] CTC(Connectionist Temporal Classification)介绍

[3] 一文读懂CRNN+CTC文字识别

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐