Processing math: 100%
Liu Shouda coder

ctc

2018-02-04

本文介绍ctc算法1。之前有了解过大致细节,发现还是很容易忘记。还是需要自己啃一下论文。以下是论文笔记。有一些疑问,待看了源码再做补充。

介绍

ctc用在语音识别,取得不错的效果。最近学术界以及我自己在ocr的实践也证明了其可行性。

语音识别

对于传统的语音识别来说,一般需要先对语音进行分帧处理。每帧10ms。一般需要使用”强制对齐“的方式,使得语音和标签一一对应,然后再训练这个预测关系。

这样预测是前后文独立的,这个对齐结果对最后结果也会有较大影响。

ocr

传统的文字识别一般分为检测,分割,识别三个步骤。先检测到文字位置,再将每个文字切割出来,放到svm等分类器进行分类。但分割本身是非常麻烦的问题。对于手写字有黏连的情况,或者验证码这种故意扭曲的图片,很难有很好的结果。

基于ctc的文字识别就是直接把整张图片和对应的文本标签扔进来,由算法学习里面的对齐关系。并按照概率最大,输出对应的标签。

下文主要以ctc在语音识别上的应用进行举例。改天再专门介绍ctc在ocr上的应用实例。

工作原理

以上图片来自这篇一篇很好的博客2

我们先用上面这张图来说明ctc的基本工作原理。第一行是输入的波形。第二行是分帧预测结果。第三行是对结果进行合并。合并规则如下:

  • 合并相同的标签
  • 去除blank符号

blank符号用于表示一种犹豫不定的状态。后文用ϵ 表示。

那么大家可能心里就会问,多了一个ϵ有啥特殊的吗?跟分帧预测有什么区别吗?

我们先来看一张图。在这张图中,可以看到ctc预测结果和分帧有明显的不同。

上图第一行是波形,第二行是分帧预测结果,第三行是ctc的结果。(岂不是说,使用ctc很难准确获取每个音素的起始结束时间?待确定todo

从上图可以看到对于分帧预测来说,需要在一个音素持续的时间内,持续地保持该音素是最大的概率。如果不是,则会导致最后结果不对。(当然,可以通过语言模型进行修正)

而最后一行的ctc预测则完全不一样。在整个预测过程大部分时间都是blank状态,在少数位置上输出对应的音素。与rnn进行结合,有前后文信息,进一步提高预测的准确性。

预测

ctc其实是一种损失函数。在预测的时候,可以使用跟分帧完全一样的方式进行处理。

符号

为了方便表达,我们先引入一些符号。

  • L: 原来的标签集合
  • L: 原本的标签 + blank
  • ytk: 第t帧是k标签的观测概率
  • π: 路径
  • B: 用来表示多对一映射。比如说: B(aab)=B(aaabb)=aab

那么:

p(lx)=πB1(l)p(πx)(1)

上式的意思是,对于给定输入x, 输出l的概率是:所有可能通过B映射而获得l的路径π的概率和。

一听到路径概率和,有没有一种冲动:用vertebi算法 :)。额,这里用不了。与hmm和crf不同,这里没有转移概率。

这里比较复杂的是有个映射。通常使用prefix search(待细化)来搞。但比较耗时。也有按照高于一定阈值的blank来划分成多个段来减少耗时。

常用的方法就是直接取每个位置最大概率的标签。

那么现在剩下的问题就是训练了。

训练

前向后向

训练使用前向后向算法。(可以先复习一下hmm的前向后向训练,对于理解ctc有帮助。)

αt(s)表示在第t帧,前面的预测序列是l1:s的概率。

at(s)=πNT,B(π1:t)=l1:stt=1ytπt

后面我们会看到,αt(s)可以表示成αt1(s)αt1(s1). 从而大大节约计算量。

在训练的时候会将标签从l改成l。主要是在每个标签之间插入blank。使得总长度是2l+1.

如下图所示,横向表示时间帧。纵向表示标签序列(白色是blank,黑色是正常标签)。cat的概率是所有可能路径之和。

对于一个序列,可以从blank开始,也可以用正确的标签开始,所以有以下初始条件:

  • α1(1)=y1ϵ
  • α1(2)=y1l1
  • α1(s)=0,s>2
αt(s)={ˉαt(s)ytlsif ls=ϵ or ls2=ls(ˉαt(s)+αt1(s2))ytlsotherwise

其中 ˉαt(s)=αt1(s)+αt1(s1)

解释一下为什么这里需要分这两种情况考虑。

比如对于abb这样的序列,对应的l是: -a-b-b-

  • 第一种情况
    • 在预测到ϵ的时候,必须保证前面一个是ϵ或者前面已经是正确的标签了
    • 预测第二个b的时候,必须保证前面一个是ϵ或者b
  • 第二种情况
    • 在预测第一个b时,前面一个是a,b,ϵ都是可以的。

同理或者后向 βst

最大似然训练

p(lx)=ls=1αt(s)βt(s)ytls

对于ytk,只需要考虑标签k就可以了。

因为会有重复,所以我们需要几下标签k出现的位置(todo:论文这里没有说清楚这个k指的是当前这个k,还是所有跟k相同标签的位置。回头看下mxnet ctc代码再做补充):

lab(l,k)={s:ls=k}

与hmm的区别

hmm的训练参考之前的文章. 待补充

mxnet ctc 实现

todo

​ 参考文献:

​ ​ ​

  1. Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks 

  2. https://distill.pub/2017/ctc/ 


上一篇 python vim jedi