上节我们讲了第一部分,如何用生成简易的车牌,这节课中我们会用PaddlePaddle来识别生成的车牌。


数据读取

  在上一节生成车牌时,我们可以分别生成训练数据和测试数据,方法如下(完整代码在这里):

 # 将生成的车牌图片写入文件夹,对应的label写入label.txt
def genBatch(self, batchSize,pos,charRange, outputPath,size):
if (not os.path.exists(outputPath)):
os.mkdir(outputPath)
outfile = open('label.txt','w')
for i in xrange(batchSize):
plateStr,plate = G.genPlateString(-1,-1)
print plateStr,plate
img = G.generate(plateStr);
img = cv2.resize(img,size);
cv2.imwrite(outputPath + "/" + str(i).zfill(2) + ".jpg", img);
outfile.write(str(plate)+"\n")

  生成好数据后,我们写一个reader来读取数据 ( reador.py )

 def reader_creator(data,label):
def reader():
for i in xrange(len(data)):
yield data[i,:],int(label[i])
return reader

  灌入模型时,我们需要调用paddle.batch函数,将数据shuffle后批量灌入模型中:

 # 读取训练数据
train_reader = paddle.batch(paddle.reader.shuffle(
reador.reader_creator(X_train,Y_train),buf_size=200),
batch_size=16) # 读取验证数据
val_reader = paddle.batch(paddle.reader.shuffle(
reador.reader_creator(X_val,Y_val),buf_size=200),
batch_size=16)
trainer.train(reader=train_reader,num_passes=20,event_handler=event_handler)

构建网络模型

  因为我们训练的是端到端的车牌识别,所以一开始构建了两个卷积-池化层训练,训练完后同步训练7个全连接层,分别对应车牌的7位字符,最后将其拼接起来,与原始的label计算Softmax值,预测训练结果。 

 def get_network_cnn(self):
# 加载data和label
x = paddle.layer.data(name='x', type=paddle.data_type.dense_vector(self.data))
y = paddle.layer.data(name='y', type=paddle.data_type.integer_value(self.label))
# 构建卷积-池化层-1
conv_pool_1 = paddle.networks.simple_img_conv_pool(
input=x,
filter_size=12,
num_filters=50,
num_channel=1,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
drop_1 = paddle.layer.dropout(input=conv_pool_1, dropout_rate=0.5)
# 构建卷积-池化层-2
conv_pool_2 = paddle.networks.simple_img_conv_pool(
input=drop_1,
filter_size=5,
num_filters=50,
num_channel=20,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
drop_2 = paddle.layer.dropout(input=conv_pool_2, dropout_rate=0.5) # 全连接层
fc = paddle.layer.fc(input = drop_2, size = 120)
fc1_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc1 = paddle.layer.fc(input = fc1_drop,size = 65,act = paddle.activation.Linear()) fc2_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc2 = paddle.layer.fc(input = fc2_drop,size = 65,act = paddle.activation.Linear()) fc3_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc3 = paddle.layer.fc(input = fc3_drop,size = 65,act = paddle.activation.Linear()) fc4_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc4 = paddle.layer.fc(input = fc4_drop,size = 65,act = paddle.activation.Linear()) fc5_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc5 = paddle.layer.fc(input = fc5_drop,size = 65,act = paddle.activation.Linear()) fc6_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc6 = paddle.layer.fc(input = fc6_drop,size = 65,act = paddle.activation.Linear()) fc7_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc7 = paddle.layer.fc(input = fc7_drop,size = 65,act = paddle.activation.Linear()) # 将训练好的7个字符的全连接层拼接起来
fc_concat = paddle.layer.concact(input = [fc21, fc22, fc23, fc24,fc25,fc26,fc27], axis = 0)
predict = paddle.layer.classification_cost(input = fc_concat,label = y,act=paddle.activation.Softmax())
return predict

训练模型

   构建好网络模型后,就是比较常见的步骤了,譬如初始化,定义优化方法, 定义训练参数,定义训练器等等,再把第一步里我们写好的数据读取的方式放进去,就可以正常跑模型了。

 class NeuralNetwork(object):
def __init__(self,X_train,Y_train,X_val,Y_val):
paddle.init(use_gpu = with_gpu,trainer_count=1) self.X_train = X_train
self.Y_train = Y_train
self.X_val = X_val
self.Y_val = Y_val def get_network_cnn(self): x = paddle.layer.data(name='x', type=paddle.data_type.dense_vector(self.data))
y = paddle.layer.data(name='y', type=paddle.data_type.integer_value(self.label))
conv_pool_1 = paddle.networks.simple_img_conv_pool(
input=x,
filter_size=12,
num_filters=50,
num_channel=1,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
drop_1 = paddle.layer.dropout(input=conv_pool_1, dropout_rate=0.5)
conv_pool_2 = paddle.networks.simple_img_conv_pool(
input=drop_1,
filter_size=5,
num_filters=50,
num_channel=20,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
drop_2 = paddle.layer.dropout(input=conv_pool_2, dropout_rate=0.5) fc = paddle.layer.fc(input = drop_2, size = 120)
fc1_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc1 = paddle.layer.fc(input = fc1_drop,size = 65,act = paddle.activation.Linear()) fc2_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc2 = paddle.layer.fc(input = fc2_drop,size = 65,act = paddle.activation.Linear()) fc3_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc3 = paddle.layer.fc(input = fc3_drop,size = 65,act = paddle.activation.Linear()) fc4_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc4 = paddle.layer.fc(input = fc4_drop,size = 65,act = paddle.activation.Linear()) fc5_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc5 = paddle.layer.fc(input = fc5_drop,size = 65,act = paddle.activation.Linear()) fc6_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc6 = paddle.layer.fc(input = fc6_drop,size = 65,act = paddle.activation.Linear()) fc7_drop = paddle.layer.dropout(input = fc,dropout_rate = 0.5)
fc7 = paddle.layer.fc(input = fc7_drop,size = 65,act = paddle.activation.Linear()) fc_concat = paddle.layer.concact(input = [fc21, fc22, fc23, fc24,fc25,fc26,fc27], axis = 0)
predict = paddle.layer.classification_cost(input = fc_concat,label = y,act=paddle.activation.Softmax())
return predict # 定义训练器
def get_trainer(self): cost = self.get_network() #获取参数
parameters = paddle.parameters.create(cost) optimizer = paddle.optimizer.Momentum(
momentum=0.9,
regularization=paddle.optimizer.L2Regularization(rate=0.0002 * 128),
learning_rate=0.001,
learning_rate_schedule = "pass_manual") # 创建训练器
trainer = paddle.trainer.SGD(
cost=cost, parameters=parameters, update_equation=optimizer)
return trainer # 开始训练
def start_trainer(self,X_train,Y_train,X_val,Y_val):
trainer = self.get_trainer() result_lists = []
def event_handler(event):
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 10 == 0:
print "\nPass %d, Batch %d, Cost %f, %s" % (
event.pass_id, event.batch_id, event.cost, event.metrics)
if isinstance(event, paddle.event.EndPass):
# 保存训练好的参数
with open('params_pass_%d.tar' % event.pass_id, 'w') as f:
parameters.to_tar(f)
# feeding = ['x','y']
result = trainer.test(
reader=val_reader)
# feeding=feeding)
print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics) result_lists.append((event.pass_id, result.cost,
result.metrics['classification_error_evaluator'])) # 开始训练
train_reader = paddle.batch(paddle.reader.shuffle(
reador.reader_creator(X_train,Y_train),buf_size=200),
batch_size=16) val_reader = paddle.batch(paddle.reader.shuffle(
reador.reader_creator(X_val,Y_val),buf_size=200),
batch_size=16)
# val_reader = paddle.reader(reador.reader_creator(X_val,Y_val),batch_size=16) trainer.train(reader=train_reader,num_passes=20,event_handler=event_handler)

输出结果

  上一步训练完以后,保存训练完的模型,然后写一个test.py进行预测,需要注意的是,在预测时,构建的网络结构得和训练的网络结构相同。

#批量预测测试图片准确率
python test.py /Users/shelter/test ##输出结果示例
output:
预测车牌号码为:津 K 4 2 R M Y
输入图片数量:100
输入图片行准确率:0.72
输入图片列准确率:0.86

  如果是一次性只预测一张的话,在终端里会显示原始的图片与预测的值,如果是批量预测的话,会打印出预测的总准确率,包括行与列的准确率。


总结

   车牌识别的方法有很多,商业化落地的方法也很成熟,传统的方法需要对图片灰度化,字符进行切分等,需要很多数据预处理的过程,端到端的方法可以直接将原始的图片灌进去进行训练,最后出来预测的车牌字符的结果,这个方法在构建了两层卷积-池化网络结构后,并行训练了7个全连接层来进行车牌的字符识别,可以实现端到端的识别。但是在实际训练过程中,仍然有一些问题,譬如前几个训练的全连接层的准确率要比最后一两个的准确率高,大家可以分别打印出每一个全连接层的训练结果准确率对比一下,可能是由于训练还没有收敛导致的,也可能有其他原因,如果在做的过程中发现有什么问题,或者有更好的方法,欢迎留言~

参考文献:

1.我的github:https://github.com/huxiaoman7/mxnet-cnn-plate-recognition

【深度学习系列】用PaddlePaddle进行车牌识别(二)的更多相关文章

  1. 【深度学习】用PaddlePaddle进行车牌识别(二)

    上节我们讲了第一部分,如何用生成简易的车牌,这节课中我们会用PaddlePaddle来识别生成的车牌. 数据读取 在上一节生成车牌时,我们可以分别生成训练数据和测试数据,方法如下(完整代码在这里): ...

  2. 【深度学习系列】PaddlePaddle垃圾邮件处理实战(二)

    PaddlePaddle垃圾邮件处理实战(二) 前文回顾   在上篇文章中我们讲了如何用支持向量机对垃圾邮件进行分类,auc为73.3%,本篇讲继续讲如何用PaddlePaddle实现邮件分类,将深度 ...

  3. 【深度学习系列】PaddlePaddle之手写数字识别

    上周在搜索关于深度学习分布式运行方式的资料时,无意间搜到了paddlepaddle,发现这个框架的分布式训练方案做的还挺不错的,想跟大家分享一下.不过呢,这块内容太复杂了,所以就简单的介绍一下padd ...

  4. 【深度学习系列】手写数字识别卷积神经--卷积神经网络CNN原理详解(一)

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  5. 【深度学习系列】PaddlePaddle垃圾邮件处理实战(一)

    PaddlePaddle垃圾邮件处理实战(一) 背景介绍   在我们日常生活中,经常会受到各种垃圾邮件,譬如来自商家的广告.打折促销信息.澳门博彩邮件.理财推广信息等,一般来说邮件客户端都会设置一定的 ...

  6. 【深度学习系列】PaddlePaddle之数据预处理

    上篇文章讲了卷积神经网络的基本知识,本来这篇文章准备继续深入讲CNN的相关知识和手写CNN,但是有很多同学跟我发邮件或私信问我关于PaddlePaddle如何读取数据.做数据预处理相关的内容.网上看的 ...

  7. 【深度学习系列】PaddlePaddle可视化之VisualDL

    上篇文章我们讲了如何对模型进行可视化,用的keras手动绘图输出CNN训练的中途结果,本篇文章将讲述如何用PaddlePaddle新开源的VisualDL来进行可视化.在讲VisualDL之前,我们先 ...

  8. 【AI开发】基于深度学习的卡口车型、车牌识别

    服务端代码后面给出 卡口车型.车牌识别demo截图 服务器:

  9. 【深度学习系列】关于PaddlePaddle的一些避“坑”技巧

    最近除了工作以外,业余在参加Paddle的AI比赛,在用Paddle训练的过程中遇到了一些问题,并找到了解决方法,跟大家分享一下: PaddlePaddle的Anaconda的兼容问题 之前我是在服务 ...

  10. 【深度学习系列】用PaddlePaddle进行车牌识别(一)

    小伙伴们,终于到了实战部分了!今天给大家带来的项目是用PaddlePaddle进行车牌识别.车牌识别其实属于比较常见的图像识别的项目了,目前也属于比较成熟的应用,大多数老牌厂家能做到准确率99%+.传 ...

随机推荐

  1. sql查询优化策略

    Sql语句执行顺序: 查询的逻辑执行顺序 (1) FROM left_table (3) join_type JOIN right_table (2) ON join_condition (4) WH ...

  2. Java for Android 第二周课上实验一

    (一)命令行下程序开发 (二)IDEA下程序开发调试 Mac OS系统下使用的IDEA为 Netbeans (三)测试题我的学号后两位为10 使用简单的PHP小程序得我的题目为2:实现简单四则运算(能 ...

  3. Java课堂笔记(一):Java基础

    本篇博客将对Java中的数据类型.操作符,常量与变量和数组进行介绍.这些内容都是Java中最基本的知识,也是初学Java时最开始就需要了解的东西. Java数据类型 Java是一种强类型的语言,这就意 ...

  4. nodejs内存溢出

    npm-v 报错,错误信息如下: FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScri ...

  5. unittest中的Empty suite错误

    import unittest from selenium import webdriver class ibdata(unittest.TestCase): @classmethod def set ...

  6. 使用cloudreve搭建个人网盘

    这次将腾迅的对象存储cos挂载到了服务器上,就想自己搭建个网盘,虽然每月50G的空间和10G流量,也够用了 之前写过使用owncloud来搭建个人网盘,使用起来挺方便,就是不知道为什么感觉打开速度慢, ...

  7. [Swift]LeetCode940. 不同的子序列 II | Distinct Subsequences II

    Given a string S, count the number of distinct, non-empty subsequences of S . Since the result may b ...

  8. Docker 搭建pxc集群 + haproxy + keepalived 高可用(二)

    上一节我们有了两个分片的pxc集群,这一节我们接着安装haproxy和keepalived的实现集群的高可用 一.先下载haproxy的镜像 [root@localhost ~]# docker pu ...

  9. Unable to preventDefault inside passive event listener due to target being treated as passive

    Unable to preventDefault inside passive event listener due to target being treated as passive 今天在做项目 ...

  10. 想成为Python全栈开发工程师必须掌握的技能

    什么是Python全栈工程师? 即从前端页面的实现,到后台代码的编写,再到数据库的管理,一人可以搞定一个公司网站的所有事情,真正实现全栈开发. 全栈只是个概念 也分很多种类 真正的全栈工程师涵盖了we ...