使用腾讯云 GPU 学习深度学习系列之五:文字的识别与定位-深蓝源码网


时间: 2020-09-03 00:08:26 人气: 2271 评论: 0

这是《使用腾讯云GPU学习深度学习》系列文章的第五篇,以车牌识别和简单OCR为例,谈了谈如何进行字母、数字的识别以及定位。本系列文章主要介绍如何使用腾讯云GPU服务器进行深度学习运算,前面主要介绍原理部分,后期则以实践为主。

往期内容:

  1. 使用腾讯云 GPU 学习深度学习系列之一:传统机器学习的回顾
  2. 使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理
  3. 使用腾讯云 GPU 学习深度学习系列之三:搭建深度神经网络
  4. 使用腾讯云 GPU 学习深度学习系列之四:深度学习的特征工

上一节,我们简要介绍了一些与深度学习相关的数据预处理方法。其中我们特别提到,使用 基于深度学习的 Spatial Transform 方法,可以让“草书” 字体的手写数字同样也可以被高效识别。

但无论是工整书写的 Tensorflow 官网上的 MNIST 教程,还是上节提到“草书”数字,都是 单一的数字识别问题。 但是,在实际生活中,遇到数字、字母识别问题时,往往需要识别一组数字。这时候一个简单的深度神经网络可能就做不到了。本节内容,就是在讨论遇到这种情况时,应该如何调整深度学习模型。

1. 固定长度

固定长度的字符、数字识别,比较常见的应用场景包括:

  • 识别验证码
  • 识别机动车车牌

识别验证码的方法,这篇文章 有详细介绍。不过该文章使用的是版本较早的 Keras1,实际使用时会有一些问题。如果想尝试,根据Jupyter 的提示更改就好,最终效果也是相当不错:

我们这里要识别的内容,是中华人民共和国机动车车牌。相比上面例子的 4 位验证码,车牌长度更长,达到了 7 位,并且内容也更加丰富,第一位是各省的汉字简称,第二位是 A-Z 的大写字母,3-7位则是数字、字母混合。

由于车牌涉及个人隐私,我们使用了用户 szad670401 在 Github 上开源的一个车牌生成器,随机的生成一些车牌的图片,用于模型训练。当然这个项目同样提供了完整的 MXNet 深度学习框架编写的代码,我们接下来会用 Keras 再写一个。

首先做些准备工作,从 szad670401 的开源项目中获取必要的文件:

### 从 szad670401 github 项目下载车牌生成器以及字体文件
!git clone https://github.com/szad670401/end-to-end-for-chinese-plate-recognition
!cp -r end-to-end-for-chinese-plate-recognition/* ./
!sed 's/for i in range(batchSize):/l_plateStr = []\n        l_plateImg = []\n        for i in range(batchSize):/g' ./genplate.py  | sed 's/cv2.imwrite(outputPath/l_plateStr.append(plateStr)\n                l_plateImg.append(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n                #cv2.imwrite(outputPath/g' | sed 's/img);/img);\n        return l_plateStr,l_plateImg/g'  >genplateRev.py

来看看生成器的效果:

from keras.models import Model
from keras.callbacks import ModelCheckpoint
from keras.layers import Conv2D, MaxPool2D, Flatten, Dropout, Dense, Input
from keras.optimizers import Adam
from keras.backend.tensorflow_backend import set_session
from keras.utils.vis_utils import model_to_dot
import tensorflow as tf
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

from IPython.display import SVG

from genplate import *

%matplotlib inline

np.random.seed(5)
config = tf.ConfigProto()
config.gpu_options.allow_growth=True
set_session(tf.Session(config=config))

chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂",
             "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
             "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
             "Y", "Z"
             ];

M_strIdx = dict(zip(chars, range(len(chars))))

n_generate = 100
rows = 20
cols = int(n_generate/rows)

G = GenPlate("./font/platech.ttf",'./font/platechar.ttf',"./NoPlates")
l_plateStr,l_plateImg = G.genBatch(100,2,range(31,65),"./plate",(272,72))

l_out = []
for i in range(rows):
    l_tmp = []
    for j in range(cols):
        l_tmp.append(l_plateImg[i*cols+j])

    l_out.append(np.hstack(l_tmp))

    fig = plt.figure(figsize=(10, 10))
    ax  = fig.add_subplot(111)
    ax.imshow( np.vstack(l_out), aspect="auto" )

看来 szad670401 开源的车牌生成器,随机生成的车牌确实达到了以假乱真的效果。于是我们基于这个生成器,再自己写一个生成器,用于深度神经网络的数据输入:

def gen(batch_size=32):
    while True:
        l_plateStr,l_plateImg = G.genBatch(batch_size, 2, range(31,65),"./plate",(272,72))
        X = np.array(l_plateImg, dtype=np.uint8)
        ytmp = np.array(list(map(lambda x: [M_strIdx[a] for a in list(x)], l_plateStr)), dtype=np.uint8)
        y = np.zeros([ytmp.shape[1],batch_size,len(chars)])
        for batch in range(batch_size):
            for idx,row_i in enumerate(ytmp[batch]):
                y[idx,batch,row_i] = 1

        yield X, [yy for yy in y]

因为是固定长度,所以我们有个想法,就是既然我们知道识别七次,那就可以用七个模型按照顺序识别。这个思路没有问题,但实际上根据之前卷积神经网络的原理,实际上卷积神经网络在扫描整张图片的过程中,已经对整个图像的内容以及相对位置关系有所了解,所以,七个模型的卷积层实际上是可以共享的。我们实际上可以用一个 一组卷积层+7个全链接层 的架构,来对应输入的车牌图片:

adam = Adam(lr=0.001)

input_tensor = Input((72, 272, 3))
x = input_tensor
for i in range(3):
    x = Conv2D(32*2**i, (3, 3), activation='relu')(x)
    x = Conv2D(32*2**i, (3, 3), activation='relu')(x)
    x = MaxPool2D(pool_size=(2, 2))(x)
x = Flatten()(x)
x = Dropout(0.25)(x)

n_class = len(chars)
x = [Dense(n_class, activation='softmax', name='c%d'%(i+1))(x) for i in range(7)]
model = Model(inputs=input_tensor, outputs=x)
model.compile(loss='categorical_crossentropy',
              optimizer=adam,
              metrics=['accuracy'])

SVG(model_to_dot(model=model, show_layer_names=True, show_shapes=True).create(prog='dot', format='svg'))

训练模型:

best_model = ModelCheckpoint("chepai_best.h5", monitor='val_loss', verbose=0, save_best_only=True)

model.fit_generator(gen(32), steps_per_epoch=2000, epochs=5,
                    validation_data=gen(32), validation_steps=1280,
                    callbacks=[best_model]
)

Epoch 1/5
2000/2000 [==============================] - 547s - loss: 11.1077 - c1_loss: 1.3878 - c2_loss: 0.7512 - c3_loss: 1.1270 - c4_loss: 1.3997 - c5_loss: 1.7955 - c6_loss: 2.3060 - c7_loss: 2.3405 - c1_acc: 0.6157 - c2_acc: 0.7905 - c3_acc: 0.6831 - c4_acc: 0.6041 - c5_acc: 0.50										

技术沙龙 教程文章 热点综合

评论