原论文:https://arxiv.org/pdf/1507.05717v1.pdf
代码:https://github.com/meijieru/crnn.pytorch
1 OCR基本概念
很多视频和图像中都包含了大置的文字,比妇新闻视频中的文本标题、体盲视频中的比分牌、电影视频中内嵌的字幕等。这些图像文字携带了大量的文本信息,如果能将它们挖掘出来′就可以更好地理解视频及图像的内容′从而促进很多应用的发展如国像/视频的搜索和推荐。挖掘图像中的文本信息需要对图像中的文字进行检测和识别,这也称作光学字符识别(OpticalCharacterRecognition,OCR)。
2 技术路线
一次OCR任务需要做下面这些事情:
深度学习一般优化的是目标检测和目标识别两个地方。文本检测类似目标检测,即用 box 标识出图像中所有文字位置。文本识别,对利用文本检测模型定位好的文字区域图片进行识别(CRNN属于端到端的文本识别模型)
3 网络结构
CRNN是一种卷积循环神经网络,解决了图像序列的识别问题。
整个CRNN分为三层:
- 1. ConvLutional Layers:卷积层,一个普通的CNN网络,用于特征提取,AlexNet、ResNet、MobileNet都可以。
- 2. Recurrent Layers:循环层,一个深层双向LSTM网络,在卷积特征的基础上继续提取文字序列特征。
- 3. Transcription Layers:转录层,把从循环层获取的标签分布通过去重整合等操作转换成最终的识别结果。
4 ConvLutional Layers
网络结构图如下所示:
根据代码,具象化化图表中的网络结构如下:
假设输入的大小为(W, 32, 3),其中高度32是固定的。经过被框起来的部分后变成((W/4-1), 1, 512)。这是ConvLutional Layers做的全部事情。
但是不能直接把CNN得到的特征图送入RNN进行训练的,需要根据特征图提取RNN需要的特征向量序列,这就是Map-to-Sequence需要做的事情。随后该特征向量序列送入循环层。
4.1 Map-to-Sequence
该层需要利用卷积层中提取的特征图提取特征序列向量。
假设上图中,原图大小为(3x32x160),经过卷积层得到的特征图大小为(512x1x40)。在特征图上按照从左到右生成特征向量,每一个特征向量维度都是512。
卷积层,最大池化层和激活函数在局部区域上执行,具有平移不变性。因此,特征图的每列(即一个特征向量)对应于原始图像的一个矩形区域,并且这些矩形区域与特征图上从左到右的相应列具有相同的顺序。特征序列中的每个向量关联一个感受野。
最终这些特征向量中的每个特征向量作为循环层的一个时间步的输入。
5 Recurrent Layers
因为RNN有梯度消失的问题,因此这里采用的是LSTM。
单向LSTM只关注过去的信息。在基于图像的序列中,两个方向的上下文是相互有用且互补的。为了利用上下文信息,采用双向LSTM。即将两个LSTM,一个向前和一个向后组合到一个双向LSTM中。除此之外,可以堆叠多层双向LSTM,深层结构允许比浅层抽象更高层次的抽象。
假设我们的特征图为512x1x40,通过Map-to-Sequence得到40个特征序列向量。需要检测的字符类别数为C:
每个特征序列向量通过双向LSTM输出所有字符的概率分布,是一个维度为C的向量。最终将40个特征序列向量的输出结果(40xC)送到转录层。
6 Transcription Layers
转录层的工作是把从循环层获取的标签概率分布通过去重整合等操作转换成最终的识别结果。
假设我们想要识别标签为ab的手写图像,经过CNN和RNN后输出的特征向量长度为5,再通过取每个特征向量最大值,得到t0到t4最终预测为aabb。此时如果简单将相同的字符合并,结果是ab。这里看起来结果与标签一致,但是如果我们想要识别的字体是hello,假设RNN输出的特征向量映射为hheeelllo,那么简单合并相同字符会使我们的结果变成helo。为了解决这个问题CTC使用了blank机制。
6.1 基于blank的序列合并机制
以"-"来代替blank。在RNN预测时,同时预测blank的概率,那么RNN输出的特征向量通过映射结果可能就变成了hheeel-llo,这时候再合并,结果就是hello。
到这里就得到了结果,但是又有了一个疑问,RNN的输出结果是如何映射的呢?这里涉及到的是CTC Loss的计算,下面进行总结:
6.2 CTC Loss
假设RNN共输出了3个特征向量(t0-t2),可能预测到字符类别为3(以ab-为例),训练集的标签为ab,RNN输出的某样本的特征向量如下:
我们注意到映射结果为ab可以有多条路线:
R(- a b) = ab
R(a - b) = ab
R(a b -) = ab
其中R(x)代表路线x经过合并后的结果。
那么此时该样本映射结果为ab的概率为:
从上面我们了解到如何通过RNN输出的特征序列向量计算某映射结果的概率。将上述问题一般化,在RNN输出的某样本的特征序列向量为x的条件下映射结果为l的概率为:
其中是所有经过合并后结果为l的路线。
对于所有样本而言,(CTC Loss)损失函数定义为负的最大似然,公式为:
通过对损失函数的计算,就可以对之前的神经网络进行反向传播,神经网络的参数根据所使用的优化器进行更新,从而找到最可能的像素区域对应的字符。
这种通过映射变换和所有可能路径概率之和的方式也使得CTC不需要对原始的输入字符序列进行准确的切分。
6.3 测试
上述均为训练时需要做的事情。测试时不计算损失函数,通过合并得到预测结果。
如果我们去计算每种结果的路径,计算量非常庞大。
对此,我们输出序列特征向量中每一个向量的最大值对应的字符:
比如RNN输出了上面的特征序列向量,我们的输出结果是bb。因为t0时刻字符-对应的概率最大,t1时刻字符b对应的概率最大,t2时刻字符b对应的概率最大。
7 局限性
7.1 计算复杂度高
由于CRNN结构中同时包括CNN和RNN模型,因此计算成本较高,需要大量计算资源来训练和推断。
可以尝试使用更加轻量化的网络(CNN,RNN网络等),使用注意力机制和硬件加速等技术来降低复杂度并提高性能。
7.2 难以处理长序列
由于RNN模型的局限性,CRNN难以处理过长的序列,可能导致梯度消失或爆炸,影响模型的训练效果。
7.2.1 RNN难以处理长序列问题的原因
- 1. 梯度消失或爆炸:在RNN模型中,每一个时刻的输出会作为下一个时刻的输入,通过反向传播得到的梯度会一直传递到最开始的时刻。如果序列长度较长,反向传播时梯度可能会变得非常小或非常大,导致模型难以训练,出现梯度消失或爆炸的问题。
- 2. 记忆力不足:RNN模型是基于"循环"的结构,每一个时刻的状态包含了前面所有时刻的信息。但是,随着时间步的增加,模型只能记忆最近几个时刻的信息,并不能很好地捕捉序列的长期依赖关系,导致模型对于长序列的建模能力较差。
7.2.2 解决办法
设计网络时,将RNN替换成LSTM或者Transformer。
7.3 难以处理不同长度的输入序列
CRNN难以处理不同长度的输入序列问题,主要基于两个方面的原因:一是卷积层处理的特征是定长的,而输入序列长度是可变的;二是RNN模型本质上只能够接受固定长度的序列输入。
当输入序列长度较短时,可以采用padding的方式,将短序列补全到固定长度。当输入序列长度较长时,可以可以考虑对输入序列进行截断。
或者使用transformer等其它模型处理可变长度的问题。
7.4 其它局限
对输入数据的依赖较强:CRNN结构中的卷积层对输入数据的尺寸和通道数有特定的要求,而且需要进行归一化和预处理等操作,这些都需要较强的先验知识和领域专业知识。
对语音干扰或其他噪声较为敏感:由于RNN模型的记忆性质,CRNN对语音干扰或其他噪声较为敏感,可能会影响模型的预测结果。
8 参考文章
https://blog.csdn.net/qq_36816848/article/details/121723891
https://blog.csdn.net/qq_24819773/article/details/104605994
https://blog.csdn.net/cengjing12/article/details/109656710