但无论是工整书写的 Tensorflow 官网上的 MNIST 教程,还是上节提到“草书”数字,都是 单一的数字识别问题。 但是,在实际生活中,遇到数字、字母识别问题时,往往需要识别一组数字。这时候一个简单的深度神经网络可能就做不到了。本节内容,就是在讨论遇到这种情况时,应该如何调整深度学习模型。
1. 固定长度
固定长度的字符、数字识别,比较常见的应用场景包括:
- 识别验证码
- 识别机动车车牌
识别验证码的方法,使用 Keras搭建一个深度卷积神经网络来识别 c验证码 有详细介绍。
我们这里要识别的内容,是国内机动车车牌。相比上面例子的 4 位验证码,车牌长度更长,达到了 7 位,并且内容也更加丰富,第一位是各省的汉字简称,第二位是 A-Z 的大写字母,3-7位则是数字、字母混合。
由于车牌涉及个人隐私,我们使用了用户 szad670401 在 Github 上开源的一个车牌生成器,
https://github.com/szad670401/end-to-end-for-chinese-plate-recognition/blob/master/genplate.py
随机的生成一些车牌的图片,用于模型训练。当然这个项目同样提供了完整的 MXNet
深度学习框架编写的代码,我们接下来会用 Keras
再写一个。
关注微信公众号datayx 然后回复“文字识别”即可获取。
来看看生成器的效果:
看来开源的车牌生成器,随机生成的车牌确实达到了以假乱真的效果。于是我们基于这个生成器,再自己写一个生成器,用于深度神经网络的数据输入:
因为是固定长度,所以我们有个想法,就是既然我们知道识别七次,那就可以用七个模型按照顺序识别。这个思路没有问题,但实际上根据之前卷积神经网络的原理,实际上卷积神经网络在扫描整张图片的过程中,已经对整个图像的内容以及相对位置关系有所了解,所以,七个模型的卷积层实际上是可以共享的。我们实际上可以用一个 一组卷积层 7个全链接层 的架构,来对应输入的车牌图片:
训练模型:
可见预测的其实相当不错,很多字体已经非常模糊,模型仍然可以看出来。图中一个错误是 皖TQZ680 被预测成了 皖TQZG8D,当然这也和图片裁剪不当有一定的关系。
2. 不固定长度
车牌的应用场景中,我们固定了长度为7位,并且基于这个预设设计了卷积神经网络。但是在实际运用中,可能长度并不固定。此时如果长度过长,用这个架构也将会导致参数过多,占用过多显存。
针对这种情况,Keras 的案例中,提供了一种基于循环神经网络的方法,在 Keras Example 中有写到。
https://github.com/fchollet/keras/blob/master/examples/image_ocr.py
具体而言,就是数据首先通过卷积神经网络部分扫描特征,然后通过循环神经网络部分,同时从左到右、从右到左扫描特征,最后基于扫描的结果,通过计算 Conectionist Temporal Classification(CTC) 损失函数,完成模型训练。
2.1. 循环神经网络
使用循环神经网络,是因为循环神经网络有一个很重要的特点,就是相邻的节点之间,可以相互影响。这里相邻节点,既可以是时间上的(前一秒数据和后一秒数据),也可以是位置关系上的,比如我们这里从左向右扫描,左边一列的扫描结果会影响右边一列的扫描结果。
2.2. CTC 损失函数
同时,对于循环神经网络的结果,由于长度不固定,可能会有空间上的“错配”:
但由于这种错配实际上并没有什么严重的影响,如上图所示, __TH____E
和 _T__H__EE
其实都是 THE 这个单词,因此这里这种错配在损失函数的优化环节中,是需要被忽略掉的。于是这里就使用了CTC
优化函数。CTC
可以在计算过程中,通过综合所有可能情况的排列组合,进而忽略相对的位置关系。
Keras 的 CTC loss 函数位于 https://github.com/fchollet/keras/blob/master/keras/backend/tensorflow_backend.py 这个文件中,内容如下:
模型完整架构如下图所示:
执行训练:
代码语言:javascript复制model.fit_generator(generator=img_gen.next_train(),
steps_per_epoch=(words_per_epoch - val_words),
epochs=stop_epoch,
validation_data=img_gen.next_val(), validation_steps=val_words,
callbacks=[EarlyStopping(patience=10),
viz_cb, img_gen], initial_epoch=start_epoch)
完成一个 Epoch 后,输出文件夹 image_ocr
里,可以看到,一轮训练后,我们模型训练效果如下: