框架

基于RNN文字识别算法主要有两个框架:
image.png

  1. CNN+RNN+CTC(CRNN+CTC)
  2. CNN+Seq2Seq+Attention

    CNN+RNN+CTC(CRNN+CTC)

    Label:字符集合+Blank_label

    CNN+Seq2Seq+Attention

    Label:字符集合+(填补部分不计入loss)
    https://github.com/koibiki/CRNN-ATTENTION/blob/master/net/net.py

    CTC

    训练时候每张样本图片都需要标记出每个字符在图片中的位置,再通过CNN感受野对齐到Feature map的每一列获取该列输出对应的Label才能进行训练。
    在实际情况中,标记这种对齐样本非常困难(除了标记字符,还要标记每个字符的位置),工作量非常大。另外,由于每张样本的字符数量不同,字体样式不同,字体大小不同,导致每列输出并不一定能与每个字符一一对应。
    所以CTC提出一种对不需要对齐的Loss计算方法,用于训练网络,被广泛应用于文本行识别和语音识别中。

Blank符号

如果要进行 OCR - 图3 的26个英文字符识别,考虑到有的位置没有字符,定义插入blank的字符集合:

OCR - 图4
其中blank表示当前列对应的图像位置没有字符(下文以OCR - 图5符号表示blank)。

关于OCR - 图6 变换

定义变换 OCR - 图7 如下(原文是大写的 OCR - 图8 ,没这个符号):
OCR - 图9
其中 OCR - 图10 是上述加入blank的长度为 OCR - 图11 的字符集合,经过 OCR - 图12 变换后得到原始 OCR - 图13 ,显然对于OCR - 图14的最大长度有 OCR - 图15
举例说明,当 OCR - 图16 时:
OCR - 图17 OCR - 图18 OCR - 图19 OCR - 图20
对于字符间有blank符号的则不合并:
OCR - 图21
当获得LSTM输出OCR - 图22后进行OCR - 图23变换,即可获得输出结果。显然 OCR - 图24 变换不是单对单映射,例如对于不同的OCR - 图25都可获得英文单词state。同时 OCR - 图26 成立。
那么CTC怎么做?
对于LSTM给定输入 OCR - 图27 的情况下,输出为 OCR - 图28 的概率为:
OCR - 图29
其中 OCR - 图30 代表所有经过 OCR - 图31 变换后是 OCR - 图32 的路径 OCR - 图33
其中,对于任意一条路径 OCR - 图34 有:
OCR - 图35
注意这里的 OCR - 图36 中的 OCR - 图37 ,下标 OCR - 图38 表示 OCR - 图39 路径的每一个时刻;而上面 OCR - 图40 的下标表示不同的路径。两个下标含义不同注意区分。
*注意上式 OCR - 图41 成立有条件,此项不做进一步讨论,有兴趣的读者请自行研究。
如对于 OCR - 图42 的路径 OCR - 图43 来说:
OCR - 图44 OCR - 图45
实际情况中一般手工设置 OCR - 图46 ,所以有非常多条 OCR - 图47 路径,即 OCR - 图48 非常大,无法逐条求和直接计算 OCR - 图49 。所以需要一种快速计算方法。

CTC的训练目标
OCR - 图50图14
CTC的训练过程,本质上是通过梯度 OCR - 图51 调整LSTM的参数 OCR - 图52 ,使得对于输入样本为 OCR - 图53 时使得 OCR - 图54 取得最大。
例如下面图14的训练样本,目标都是使得 OCR - 图55 时的输出 OCR - 图56 变大。
OCR - 图57
图14
CTC借用了HMM的“向前—向后”(forward-backward)算法来计算 OCR - 图58
要计算 OCR - 图59 ,由于有blank的存在,定义路径 OCR - 图60 为在路径 OCR - 图61 每两个元素以及头尾插入blank。那么对于任意的 OCR - 图62 都有 OCR - 图63 (其中 OCR - 图64 )。如:
OCR - 图65 OCR - 图66
显然 OCR - 图67 ,其中 OCR - 图68 是路径的最大长度,如上述例子中 OCR - 图69
定义所有经 OCR - 图70 变换后结果是 OCR - 图71 且在 OCR - 图72 时刻结果为 OCR - 图73(记为OCR - 图74 )的路径集合为 OCR - 图75
求导:
OCR - 图76
注意上式中第二项与 OCR - 图77 无关,所以:
OCR - 图78
而上述 OCR - 图79 就是恰好与概率 OCR - 图80 相关的路径,即 OCR - 图81 时刻都经过 OCR - 图82 (OCR - 图83 )。
举例说明,还是看上面的例子 OCR - 图84 (这里的下标 OCR - 图85 代表不同的路径):
OCR - 图86图15
蓝色路径 OCR - 图87
OCR - 图88 OCR - 图89
红色路径 OCR - 图90
OCR - 图91 OCR - 图92
还有 OCR - 图93 没有画出来。
OCR - 图94OCR - 图95 时恰好都经过 OCR - 图96 (此处下标代表路径 OCR - 图97OCR - 图98 时刻的字符)。所有类似于 OCR - 图99 经过 OCR - 图100 变换后结果是 OCR - 图101 且在 OCR - 图102 的路径集合表示为 OCR - 图103
观察 OCR - 图104 。记 OCR - 图105 蓝色为 OCR - 图106OCR - 图107 红色路径为 OCR - 图108OCR - 图109 可以表示:
OCR - 图110 OCR - 图111
那么 OCR - 图112 可以表示为:
OCR - 图113 OCR - 图114
计算:
OCR - 图115
为了观察规律,单独计算 OCR - 图116
OCR - 图117
OCR - 图118
OCR - 图119
OCR - 图120
OCR - 图121
不妨令:
OCR - 图122
OCR - 图123
那么OCR - 图124可以表示为:
OCR - 图125
推广一下,所有经过 OCR - 图126 变换为 OCR - 图127OCR - 图128 的路径(即 OCR - 图129 )可以写成如下形式:
OCR - 图130
进一步推广,所有经过 OCR - 图131 变换为 OCR - 图132OCR - 图133 的路径(即 OCR - 图134 )也都可以写作:
OCR - 图135
所以,定义前向递推概率和 OCR - 图136
对于一个长度为 OCR - 图137 的路径 OCR - 图138 ,其中 OCR - 图139 代表该路径前 OCR - 图140 个字符, OCR - 图141 代表后 OCR - 图142 个字符。
OCR - 图143
其中 OCR - 图144 表示前 OCR - 图145 个字符 OCR - 图146 经过 OCR - 图147 变换为的 OCR - 图148 的前半段子路径。 OCR - 图149 代表了 OCR - 图150 时刻经过 OCR - 图151 的路径概率中 OCR - 图152 概率之和,即前向递推概率和。
由于当 OCR - 图153 时路径只能从blank或 OCR - 图154 开始,所以 OCR - 图155 有如下性质:
OCR - 图156 OCR - 图157 OCR - 图158
如上面的例子中 OCR - 图159 , OCR - 图160 , OCR - 图161 。对于所有 OCR - 图162 路径,当 OCR - 图163 时只能从blank和 OCR - 图164 字符开始。
OCR - 图165图16
图16是 OCR - 图166 时经过压缩路径后能够变为 OCR - 图167 的所有路径 OCR - 图168 。观察图15会发现对于 OCR - 图169 有如下递推关系:
OCR - 图170
也就是说,如果 OCR - 图171 时刻是字符 OCR - 图172 ,那么 OCR - 图173 时刻只可能是字符 OCR - 图174 三选一,否则经过 OCR - 图175 变换后无法压缩成 OCR - 图176
那么更一般的:
OCR - 图177
同理,定义反向递推概率和 OCR - 图178
OCR - 图179
其中 OCR - 图180 表示后 OCR - 图181 个字符 OCR - 图182 经过 OCR - 图183 变换为的 OCR - 图184 的后半段子路径。 OCR - 图185 代表了 OCR - 图186 时刻经过 OCR - 图187 的路径概率中 OCR - 图188 概率之和,即反向递推概率和。
由于当 OCR - 图189 时路径只能以blank或 OCR - 图190 结束,所以有如下性质:
OCR - 图191 OCR - 图192 OCR - 图193
如上面的例子中 OCR - 图194 , OCR - 图195 , OCR - 图196 , OCR - 图197 。对于所有 OCR - 图198 路径,当 OCR - 图199 时只能以 OCR - 图200 (blank字符)或 OCR - 图201 字符结束。
观察图15会发现对于 OCR - 图202 有如下递推关系
OCR - 图203
OCR - 图204 同理,对于 OCR - 图205 有如下递推关系:
OCR - 图206
那么forward和backward相乘有:
OCR - 图207
或:
OCR - 图208
注意, OCR - 图209 可以通过图16的关系对应,如 OCR - 图210OCR - 图211
对比 OCR - 图212 :
OCR - 图213
可以得到 OCR - 图214 与forward和backward递推公式之间的关系:
OCR - 图215

* 为什么有上式 OCR - 图216 成立呢?
回到图15,为了方便分析,假设只有 OCR - 图217 共4条在 OCR - 图218 时刻经过字符 OCR - 图219OCR - 图220 变换为 OCR - 图221 的路径,即 :
OCR - 图222
那么此时(注意虽然表示路径用 OCR - 图223 加法,但是由于 OCR - 图224OCR - 图225 两件独立事情同时发生,所以 OCR - 图226 路径的概率 OCR - 图227 是乘法):
OCR - 图228
则有:
OCR - 图229
训练CTC
对于LSTM,有训练集合 OCR - 图230 ,其中 OCR - 图231 是图片经过CNN计算获得的Feature map, OCR - 图232 是图片对应的OCR字符label(label里面没有blank字符)。
现在我们要做的事情就是:通过梯度OCR - 图233调整LSTM的参数OCR - 图234,使得对于输入样本为OCR - 图235时有 OCR - 图236 取得最大。所以如何计算梯度才是核心。
单独来看CTC输入(即LSTM输出) OCR - 图237 矩阵中的某一个值 OCR - 图238 (注意 OCR - 图239OCR - 图240 含义相同,都是在 OCR - 图241OCR - 图242 的概率):
OCR - 图243
上式中的 OCR - 图244 是通过递推计算的常数,任何时候都可以通过递推快速获得,那么即可快速计算梯度 OCR - 图245 ,之后梯度上升算法你懂的。
CTC编程接口
在Tensorflow中官方实现了CTC接口:

  1. tf.nn.ctc_loss(
  2. labels,
  3. inputs,
  4. sequence_length,
  5. preprocess_collapse_repeated=False,
  6. ctc_merge_repeated=True,
  7. ignore_longer_outputs_than_inputs=False,
  8. time_major=True
  9. )

在Pytorch中需要使用针对框架编译的warp-ctc:https://github.com/SeanNaren/warp-ctc
2020.4更新,目前Pytorch已经有CTC接口:

  1. torch.nn.CTCLoss(blank=0,reduction='mean',zero_infinity=False

CTC总结
CTC是一种Loss计算方法,用CTC代替Softmax Loss,训练样本无需对齐。CTC特点:

  • 引入blank字符,解决有些位置没有字符的问题
  • 通过递推,快速计算梯度

看到这里你也应该大致了解MFCC+CTC在语音识别中的应用了(图17来源)。
OCR - 图246
图17 MFCC+CTC在语音识别中的应用

CRNN+CTC总结

这篇文章的核心,就是将CNN/LSTM/CTC三种方法结合:

  • 首先CNN提取图像卷积特征
  • 然后LSTM进一步提取图像卷积特征中的序列特征
  • 最后引入CTC解决训练时字符无法对齐的问题

即提供了一种end2end文字图片识别算法,也算是方向的简单入门。

特别说明

一般情况下对一张图像中的文字进行识别需要以下步骤

  1. 定位文稿中的图片,表格,文字区域,区分文字段落(版面分析)
  2. 进行文本行识别(识别)
  3. 使用NLP相关算法对文字识别结果进行矫正(后处理)