pytorchOCR之CRNN
这里就不做crnn的原理解释了,网上一大堆。这里按照代码的思路梳理一遍crnn的流程。
crnn 流程
首先,网络的输入是 b a t c h s i z e ∗ c h a n n e l ∗ h ∗ w batchsize*channel*h*w batchsize∗channel∗h∗w,这里我们举个例子,假设输入为 64 ∗ 3 ∗ 32 ∗ 280 64*3*32*280 64∗3∗32∗280,先经过backbone,一般backbone设计是在高度方向向下pooling 32倍,也就是5个stride 为2 ,将图片高度变成1。在宽度方向pooling了4倍,将图片宽度变成了70. 所以经过backbone后输出变为 64 ∗ c h a n n n e l ∗ 1 ∗ 70 64*channnel*1*70 64∗channnel∗1∗70.接下来可以有两种操作:
- 第一种直接一个全连接层将输出变为 64 ∗ c l a s s e s ∗ 70 64*classes*70 64∗classes∗70,其中classes是你识别的类别数。这就是cnn+ctc的实现方式,实验证明这样的效果也很好
- 第二种是先过rnn,再接一个全连接层,输出 64 ∗ c l a s s e s ∗ 70 64*classes*70 64∗classes∗70,这就是cnn+rnn+ctc的实现方式。
部分解释
- 对于crnn直观的理解就是相当于把 32 ∗ 280 32*280 32∗280的图片卷积成 1 ∗ 70 1*70 1∗70,即在宽度方向,以每份为4的长度分成了70份,预测这70份每一份属于classes里的哪一类。
- 对宽度方向做rnn,即以宽度方向为time_step,将这分成的70份做所谓的上下文联系。
- 其实是否加rnn效果好,个人认为还是有些争议,感觉跟数据集类型和训练集大小有关。
- 为什么设置pooling为4,pooling了4倍,代表步长为4,将宽度分成了280/4=70,可以分成70份,也就是说最多可以预测一行70个字,基本能覆盖全部的长文本了,而且适当加大time_step,可以防止漏字。
- 关于如何通过识别结果倒推文字的位置,其实这个不一定能成立,因为图片位置和ctc的识别解码不一定能对的上。至于如何做,其实很简单,举个例子,假设输入你的图片宽为40,,pooling4倍最后输出为10,那么你的识别结果输出可能是[0,3,0,0,0,4,0,0,0,10],是一个长度为10的矩阵,可以看出3,4,10一共是3个字,其中0是背景类,那么这三个字的位置就是:3的位置是
1
∗
4
到
2
∗
4
1*4到2*4
1∗4到2∗4,因为3的位置在第二份,每份步长为4.其余类似。最后会得到如图所示: