一文读懂CRNN+CTC文字识别

    技术2022-07-16  74

    转载自:https://zhuanlan.zhihu.com/p/43534801

    文字识别也是图像领域一个常见问题。然而,对于自然场景图像,首先要定位图像中的文字位置,然后才能进行识别。

    所以一般来说,从自然场景图片中进行文字识别,需要包括2个步骤:

    文字检测:解决的问题是哪里有文字,文字的范围有多少文字识别:对定位好的文字区域进行识别,主要解决的问题是每个文字是什么,将图像中的文字区域进转化为字符信息。 图1 文字识别的步骤

    对于文字检测不了解的读者,请参考本专栏文章:

    场景文字检测—CTPN原理与实现​ zhuanlan.zhihu.com

    本文的重点是如何对已经定位好的文字区域图片进行识别。

    最简单的文字识别基于单字符定位+分类,即定位单个文字区域后直接进行分类。

    图2 文字检测定位文字图像区域

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

    图3 基于RNN文字识别2种基本算法框架 CNN+RNN+CTC(CRNN+CTC)CNN+Seq2Seq+Attention

    本文主要介绍第一种框架CRNN+CTC,对应代码(tf1.15实现)如下,本文介绍的CRNN网络结构都基于此代码。另外该代码已经支持不定长英文识别。

    bai-shang/crnn_ctc_ocr_tf​ github.com

    CRNN基本网络结构

    图4 CRNN网络结构(此图按照本文给出的github实现代码画的)

    整个CRNN网络可以分为三个部分:

    假设输入图像大小为 ,注意提及图像都是 形式。

    Convlutional Layers

    这里的卷积层就是一个普通的CNN网络,用于提取输入图像的Convolutional feature maps,即将大小为 的图像转换为 大小的卷积特征矩阵,网络细节请参考本文给出的实现代码。

    Recurrent Layers

    这里的循环网络层是一个深层双向LSTM网络,在卷积特征的基础上继续提取文字序列特征。对RNN不了解的读者,建议参考:

    完全解析RNN, Seq2Seq, Attention注意力机制​ zhuanlan.zhihu.com

    所谓深层RNN网络,是指超过两层的RNN网络。对于单层双向RNN网络,结构如下:

    图5 单层双向RNN网络

    而对于深层双向RNN网络,主要有2种不同的实现:

    tf.nn.bidirectional_dynamic_rnn 图6 深层双向RNN网络 tf.contrib.rnn.stack_bidirectional_dynamic_rnn 图7 stack形深层双向RNN网络

    在CRNN中显然使用了第二种stack形深层双向结构。

    由于CNN输出的Feature map是大小,所以对于RNN最大时间长度 (即有25个时间输入,每个输入 列向量有 )。

    Transcription Layers

    将RNN输出做softmax后,为字符输出。

    关于代码中输入图片大小的解释:

    在本文给出的实现中,为了将特征输入到Recurrent Layers,做如下处理:

    首先会将图像在固定长宽比的情况下缩放到 大小( 代表任意宽度)然后经过CNN后变为 针对LSTM设置 ,即可将特征输入LSTM。

    所以在处理输入图像的时候,建议在保持长宽比的情况下将高缩放到 ,这样能够尽量不破坏图像中的文本细节(当然也可以将输入图像缩放到固定宽度,但是这样由于破坏文本的形状,肯定会造成性能下降)。

    考虑训练Recurrent Layers时的一个问题:

    图8 感受野与RNN标签的关系

    对于Recurrent Layers,如果使用常见的Softmax cross-entropy loss,则每一列输出都需要对应一个字符元素。那么训练时候每张样本图片都需要标记出每个字符在图片中的位置,再通过CNN感受野对齐到Feature map的每一列获取该列输出对应的Label才能进行训练,如图9。

    在实际情况中,标记这种对齐样本非常困难(除了标记字符,还要标记每个字符的位置),工作量非常大。另外,由于每张样本的字符数量不同,字体样式不同,字体大小不同,导致每列输出并不一定能与每个字符一一对应。

    当然这种问题同样存在于语音识别领域。例如有人说话快,有人说话慢,那么如何进行语音帧对齐,是一直以来困扰语音识别的巨大难题。

    图9

    所以CTC提出一种对不需要对齐的Loss计算方法,用于训练网络,被广泛应用于文本行识别和语音识别中。

    Connectionist Temporal Classification(CTC)详解

    在分析过程中尽量保持和原文符号一致。

    Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurrent Neural Networks​ ftp.idsia.ch

    整个CRNN的流程如图10。先通过CNN提取文本图片的Feature map,然后将每一个channel作为 的时间序列输入到LSTM中。

    图10 CRNN+CTC框架

    为了说明问题,我们定义:

    CNN Feature map

    Feature map的每一列作为一个时间片输入到LSTM中。设Feature map大小为 (图11中 , )。下文中的时间序列 都从 开始,即 。

    定义为:

    其中 每一列 为:

    LSTM

    LSTM的每一个时间片后接softmax,输出 是一个后验概率矩阵,定义为:

    其中, 的每一列 为:

    其中 代表需要识别的字符集合长度。由于 是概率,所以服从概率假设:

    对 每一列进行 操作,即可获得每一列输出字符的类别。

    那么LSTM可以表示为:

    其中 代表LSTM的参数。LSTM在输入和输出间做了如下变换:

    图11 空白blank符号

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

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

    关于 变换

    定义变换 如下(原文是大写的 ,知乎没这个符号):

    其中 是上述加入blank的长度为 的字符集合,经过 变换后得到原始 ,显然对于的最大长度有 。

    举例说明,当 时:

    对于字符间有blank符号的则不合并:

    当获得LSTM输出后进行变换,即可获得输出结果。显然 变换不是单对单映射,例如对于不同的都可获得英文单词state。同时 成立。

    那么CTC怎么做?

    对于LSTM给定输入 的情况下,输出为 的概率为:

    其中 代表所有经过 变换后是 的路径 。

    其中,对于任意一条路径 有:

    注意这里的 中的 ,下标 表示 路径的每一个时刻;而上面 的下标表示不同的路径。两个下标含义不同注意区分。

    *注意上式 成立有条件,此项不做进一步讨论,有兴趣的读者请自行研究。

    如对于 的路径 来说:

    实际情况中一般手工设置 ,所以有非常多条 路径,即 非常大,无法逐条求和直接计算 。所以需要一种快速计算方法。

    CTC的训练目标

    图14

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

    例如下面图14的训练样本,目标都是使得 时的输出 变大。

    图14

    CTC借用了HMM的“向前—向后”(forward-backward)算法来计算

    要计算 ,由于有blank的存在,定义路径 为在路径 每两个元素以及头尾插入blank。那么对于任意的 都有 (其中 )。如:

    显然 ,其中 是路径的最大长度,如上述例子中 。

    定义所有经 变换后结果是 且在 时刻结果为 (记为 )的路径集合为 。

    求导:

    注意上式中第二项与 无关,所以:

    而上述 就是恰好与概率 相关的路径,即 时刻都经过 ( )。

    举例说明,还是看上面的例子 (这里的下标 代表不同的路径):

    图15

    蓝色路径 :

    红色路径 :

    还有 没有画出来。

    而 在 时恰好都经过 (此处下标代表路径 的 时刻的字符)。所有类似于 经过 变换后结果是 且在 的路径集合表示为 。

    观察 。记 蓝色为 , 红色路径为 , 可以表示:

    那么 可以表示为:

    计算:

    为了观察规律,单独计算 。

    不妨令:

    那么可以表示为:

    推广一下,所有经过 变换为 且 的路径(即 )可以写成如下形式:

    进一步推广,所有经过 变换为 且 的路径(即 )也都可以写作:

    所以,定义前向递推概率和

    对于一个长度为 的路径 ,其中 代表该路径前 个字符, 代表后 个字符。

    其中 表示前 个字符 经过 变换为的 的前半段子路径。 代表了 时刻经过 的路径概率中 概率之和,即前向递推概率和。

    由于当 时路径只能从blank或 开始,所以 有如下性质:

    如上面的例子中 , , 。对于所有 路径,当 时只能从blank和 字符开始。

    图16

    图16是 时经过压缩路径后能够变为 的所有路径 。观察图15会发现对于 有如下递推关系:

    也就是说,如果 时刻是字符 ,那么 时刻只可能是字符 三选一,否则经过 变换后无法压缩成 。

    那么更一般的:

    同理,定义反向递推概率和

    其中 表示后 个字符 经过 变换为的 的后半段子路径。 代表了 时刻经过 的路径概率中 概率之和,即反向递推概率和。

    由于当 时路径只能以blank或 结束,所以有如下性质:

    如上面的例子中 , , , 。对于所有 路径,当 时只能以 (blank字符)或 字符结束。

    观察图15会发现对于 有如下递推关系

    与 同理,对于 有如下递推关系:

    那么forward和backward相乘有:

    或:

    注意, 可以通过图16的关系对应,如 ,。

    对比 :

    可以得到 与forward和backward递推公式之间的关系:

    * 为什么有上式 成立呢?

    回到图15,为了方便分析,假设只有 共4条在 时刻经过字符 且 变换为 的路径,即 :

    那么此时(注意虽然表示路径用 加法,但是由于 和 两件独立事情同时发生,所以 路径的概率 是乘法):

    则有:

    训练CTC

    对于LSTM,有训练集合 ,其中 是图片经过CNN计算获得的Feature map, 是图片对应的OCR字符label(label里面没有blank字符)。

    现在我们要做的事情就是:通过梯度调整LSTM的参数,使得对于输入样本为时有 取得最大。所以如何计算梯度才是核心。

    单独来看CTC输入(即LSTM输出) 矩阵中的某一个值 (注意 与 含义相同,都是在 时 的概率):

    上式中的 是通过递推计算的常数,任何时候都可以通过递推快速获得,那么即可快速计算梯度 ,之后梯度上升算法你懂的。

    CTC编程接口

    在Tensorflow中官方实现了CTC接口:

    tf.nn.ctc_loss( labels, inputs, sequence_length, preprocess_collapse_repeated=False, ctc_merge_repeated=True, ignore_longer_outputs_than_inputs=False, time_major=True )

    在Pytorch中需要使用针对框架编译的warp-ctc:github.com/SeanNaren/wa

    2020.4更新,目前Pytorch已经有CTC接口:

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

    CTC总结

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

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

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

    图17 MFCC+CTC在语音识别中的应用

    CRNN+CTC总结

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

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

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

    特别说明

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

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

    本文介绍的CRNN框架只是步骤2的一种识别算法,其他非本文内容。CTC你学会(fei)了么?

    想了解其他文字识别方法,请点这里:

    文字识别方法整理​ zhuanlan.zhihu.com

    求求你们点个赞吧!

    本文章只是介绍ctc原理,不包含1v1辅导服务。个人工程问题切勿提问和私聊:

    如何做毕设如何识别中文领导要求识别身份证和发票在xxx数据集效果关于xxx代码的xxx问题

    Processed: 0.011, SQL: 9