CRNN原理及实现
近期了解了一下文本识别,在CRNN的学习过程,包括CRNN原理、CTC Loss、代码实现、bug调试等问题也进行了一些调研,将自己的一些看法尽可能简洁地总结记录下来,如有错误,欢迎指出。
CRNN使用CNN提取图像特征,RNN进行序列推理,配合CTC的不定长字符识别,是文本和语音识别的一个重要模型。

推理过程
以测试阶段一张图像输入为例(batch_size为1),对crnn的整个过程进行输入输出的尺寸的描述,

首先要将图片Resize到[200,32]大小,200为图片宽度,这个参数与我们要预测的字符长度息息相关,经过CNN提取特征,这里的CNN可以任意设置,较常用的是VGG,当然是截取VGG的一部分,要保证输出的特征图高度为1,如果原有的VGG无法保证图片输入到输入恰好使得高为1,我们可以手动加一层卷积,特征图的宽此时变为50,相应的如果我们一开始resize输入的宽较大,这里的特征图的宽也会较大;这里的维度发生了一些变化,是为了便于输入到RNN以及后续ctcloss的调用,上图虚线可以看出,特征图的这个50可以认为是对应原图的50份纵向分割,也就是这张图片要被从左到右预测的次数,将其作为一个时序输入RNN,RNN一般使用双向LSTM网络,文章认为序列的前向信息和后向信息都有助于序列的预测,输出的时候,也就是RNN最后的嵌入层的输出维度为我们总共要预测的字符数+1(blank),最后的输出可以认为是一种概率,最后进行解码即可。
编解码过程
上述说到图像resize的宽在CNN输出的特征图的宽度对应了预测的时序,也就是我们挨着图像自左向右预测多少次,显然我们分隔的次数越多,就越不会漏掉其中某个字符,当然大多数情况下是预测多了的,比如图片中写的是”book“,我们的预测可能就是“bbbbbbooooooooooooookkkk”。还有就是我们的“book”作为标签如何去在网络的输出进行表示呢?当然是要做一个码本,将我们的字符用索引0-25表示。比如我们要预测26个英文字母,那“cat”就可以表示成[2,0,19],预测(序列长度为10)就可能是[2,2,2,0,0,0,0,19,19,19]或者[2,2,0,0,0,0,0,0,0,19]。问题来了,我们预测的输出是明显是多于实际标签的,中间的重复我怎么知道最后该保留一个还是多个呢,比如"book",如果按照上述规则得到的可是"bok"。
于是人们用一个占位符"-“来处理这个问题,用于解决到底留几个重复字符,注意,如果我们的预测中有"-"这个字符,要注意与占位符区别开,这和处理空格问题一样,在实际操作中可以使用其他符号暂时代替“-”或者空格进行码本制作,以避免码本无法表示,待解码之后统一替换即可。在编码的时候,所有的重复字符都要用”-“隔开,这样编码肯定是没有疑问了,解码的时候,凡是相同字符间没有”-"的,统统只要一个。将“-”放在码本的0号位,预测26个英文字符就用索引1-26表示,如果我们有输出[2,2,0,0,0,15,15,0,15,11],则解码为“book”,如果是[0,0,2,15,15,15,15,0,0,11],则解码为“bok”。
编解码的代码实现:
#编码过程,lexicon为字符标签,character为码本
label = [self.characters.find(c) for c in lexicon]
#解码过程,只解码一个输出列表,若解码矩阵,可分解出单个样本后进行调用
char_list = []
for i in range(len(str_index)):
if str_index[i] != 0 and (not (i > 0 and str_index[i - 1] == str_index[i])):
char_list.append(characters[str_index[i]])
return ''.join(char_list)
CTCLoss与Pytorch实现
关于ctcloss,还是https://distill.pub/2017/ctc/写得最好,也是大部分博客的参考。前面我们说过RNN的输出为[50,1,11],也就是针对batch_size个样本,我们要对11(码本大小)个字符预测50(RNN输入时序长度)次,假设我们的输入为X,对应的标签为Y,每个时刻可能预测的字符用a表示,则每个时刻t在给定样本X的情况下预测字符a的概率为 p t ( a t ∣ X ) p_t(a_t|X) pt(at∣X),t个时刻的预测概率相乘是在给定样本X情况下预测标签Y的条件概率的一部分。

为什么说是一部分呢?因为,在这个阵列中,我们从左到右每个时刻取一个字符的话,在化简成最后的标签后,可以看到有多个path对应同一种标签,比如下面的三种路径就对应了同一个标签"hello":

也就是说预测矩阵(概率)与标签是多对一的关系,每条路径对应了多个连乘积,要将这些连乘积加起来才能与某标签划等号,Deep System给出的示意图如下:

于是我们知道在给定某样本X,要得到标签Y的条件概率为
p ( Y ∣ X ) = ∑ A ∈ A X , Y ∏ t = 1 T p t ( a t ∣ X ) p(Y \mid X)=\sum_{A \in \mathcal{A}_{X, Y}} \prod_{t=1}^{T} p_{t}\left(a_{t} \mid X\right) p(Y∣X)=A∈AX,Y∑t=1∏T</

本文深入探讨了CRNN模型在文本识别领域的应用,详细解析了其核心组件:CNN、RNN和CTC Loss的工作原理。文章通过实例展示了CRNN的推理流程,包括图像预处理、特征提取、序列建模及CTC损失计算。此外,提供了CRNN模型的PyTorch实现代码,并分享了在训练过程中遇到的常见问题及解决方案。
1万+

被折叠的 条评论
为什么被折叠?



