转自:https://zhuanlan.zhihu.com/p/43534801
文字识别也是图像领域一个常见问题。然而,对于自然场景图像,首先要定位图像中的文字位置,然后才能进行识别。
所以一般来说,从自然场景图片中进行文字识别,需要包括2个步骤:
- 文字检测:解决的问题是哪里有文字,文字的范围有多少
- 文字识别:对定位好的文字区域进行识别,主要解决的问题是每个文字是什么,将图像中的文字区域进转化为字符信息。
图1 文字识别的步骤
文字检测类似于目标检测,即用 box 标识出图像中所有文字位置。对于文字检测不了解的读者,请参考本专栏文章:
场景文字检测—CTPN原理与实现zhuanlan.zhihu.com
本文的重点是如何对已经定位好的文字区域图片进行识别。假设之前已经文字检测算法已经定位图中的“subway”区域(红框),接下来就是文字识别。
图2 文字检测定位文字图像区域
基于RNN文字识别算法主要有两个框架:
图3 基于RNN文字识别2种基本算法框架
- CNN+RNN+CTC(CRNN+CTC)
- CNN+Seq2Seq+Attention
本文主要介绍第一种框架CRNN+CTC,对应TensorFlow 1.15实现代码如下。本文介绍的CRNN网络结构都基于此代码。另外该代码已经支持不定长英文识别。
bai-shang/crnn_ctc_ocr_tfgithub.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)详解
在分析过程中尽量保持和原文符号一致。
整个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输出) 矩阵中的某一个值
(注意
与
含义相同,都是在
时
的概率):
上式中的 是通过递推计算的常数,任何时候都可以通过递推快速获得,那么即可快速计算梯度
,之后梯度上升算法你懂的。