NLP 之自然场景文字识别 2 CRNN tensorflow

96
涛涛江水向坡流
2018.08.01 18:51* 字数 1525

这篇博客主要讨论CRNN 的工作原理, 主要讨论的论文是 An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Application to Scene Text Recognition

https://arxiv.org/abs/1507.05717

使用的开开源代码如下

https://github.com/solivr/tf-crnn

这里讨论这篇PAMI 的文章主要的原因有两个

1. 端到端的训练, 而且模型非常通俗易懂

2. 性能比较好,而且模型小 (参数少)

这个模型作为一个基础的入门 自然场景文字识别 是非常好的, 涉及的方方面面也很全。  接下来就会讨论模型+代码复现。

CRNN 的模型介绍



图上的Figure 1, 是从下往上看的。 输入是截好图的 图片, 然后通过卷积, 卷积层, 再输入到两层的bi-directional  LSTM, 然后是 transcription 层, 把多余的字母融合成一个。 这个模型会和对应的开源 代码一起讨论。

卷积层

这个卷积层的实现并不复杂, 就从源代码 model.py 里截图做简短说明

这个卷积 层的实现和VGG 基本一样, 就是3x3 kernel, 然后激活函数, 然后pool。

RNN 层

RNN 层的实现也是中规中矩, 很容易理解。 但是这里有个重点就是RNN 需要有时间方向的信息, 但是我们输出的结果其实是  一个 image features 的张量 (tensor)。这个张量的维度是 batch, width, height, features. 在这里, 作者 将  height , features 融合在一起, 把 width 当做LSTM 的时间 time steps,  这样就变成了 [batch, width, height*features] 对应LSTM 的输入 [batch_size, n_steps, n_input]. 这个假设是有代价的。

这个代价要从 作者提出的神经网络里来计算。 下图就是详细的神经网络架构。


Table 1. Network configuration summary. The first row is the top layer. ‘k’, ‘s’ and ‘p’ stand for kernel size, stride and padding size respectively

看见四个 max pooling 了嘛, 他们会导致 张量的维度变化。 而卷积层,因为有padding 的存在, feature map 的大小是不变的. 当然, 有个例外, 这个就是L13  层, padding 是0 ,所以维度有一点点变化。 batch normalizaiton 就更不会导致维度的变化了。

按照这篇论文, 图片的大小都被re-scale 100 X 32 的大小, 其中32 大概相当于图片中文字的高度。  这样一个神经网络输出的维度 就如 Table 1 的第三列了。

这里高亮了, L14 层的输出, 因为这个是有物理含义的。 相当于有24 个单词 (包含CTC 中的空格), 每个单词的word vector  512.  根据CTC loss 的工作原理, 输出的sequence label 的长度必须小于或等于 input sequence 的长度。 所以  安装目前的网络, 最多能识别的单词长度 就是 24 个。 当然了, 一个英文单词长度超过24 的也很少了。

Transcription 层

Transcription  就是把每个width 的预测 (per-frame prediction) 变成 标记序列。 这里边有两个方法。

1. 没有词库的方法

2. 有词库的方法

没有词库的话, 这个过程就是 Connectionist Temporal Classification (CTC) Loss 计算的过程。我以前的博客有详细讨论这个 loss function.

https://www.jianshu.com/p/e073c9d91b20

有词库呢,  就会把预测的结果 和词库中相似的词一一计算概率, 然后选择概率最大的那一个。 但是这个方法实在太简单粗暴了,  当词库的单词很多的时候, 就会花很多时间来计算概率。 而paper作者发现, 可以先用没有词库的方法, 也就是CTC loss 算出一个sequence label,  然后寻找最相近的方法来确定单词 (search the nearest neighbour hood method)。

CRNN 的 代码复现

数据集

CRNN 训练使用的数据集是 Synthetic Word Dataset, 链接如下

http://www.robots.ox.ac.uk/~vgg/data/text/

这个数据集解压后 大概35 G 的大小 。 先截个图让大家感受一下 他的样子。

每个图的名字就是他的label, 然后前面有标号。

但是这个数据集有坑。

这个数据集里的 label 并不是完全正确的, 很有可能图片里写着 I am very happy,  然而label 里却只写着happy.

这种情况我想到了一个比较简单的筛选方法, 就是比较图片的宽度(W)和 label sequence 的长度 L。 如果L * 100/24  > W,  就说明这个图片的宽度是足够预测对应的文字的。 其中100, 24 , 有在模型 RNN 层中解释。

开源代码 解读

这个github 的开源代码 我本身是跑过的。 代码写的非常棒, 这里主要解释了模型如何训练。 首先是输入数据, 读者需要自己准备一个csv 文件。  这个文件的内容就是图片路径+图片文字(label), label 需要用 “|” 隔开。



其次是要设计 configuration file,就是config_template.json , 截图如下

这个文件比较好理解, 里面确定了 learing_rate,  还有其他。 其中csv_files_train, csv_file_test 就是我们上面讨论的csv 文件。    还有一件文件 lookup_letters_digits_symbols.json 没介绍。这个很好理解, 就是用数字做label, 给每个字母和数字。 


CRNN 的 代码复现

最后放一个我跑的训练结果, 用ICDAR 2003 做测试 集, 用  Synthetic Word Dataset 做训练集。

我的准确率 用了四个 GPU 训练了三天, 没用词库, 达到大约 86.5%的准确率, CER 0.055。 这里边准确率 是指成功预测 一个sequence lable,  而 CER 就是character error rate.

原稿笔记链接如下

https://shimo.im/docs/oDFzLoOXmYsAypwR/

NLP 从入门到放弃