相信你对验证码肯定不陌生
学校的教务系统老让我填验证码
而且明明填写正确却不让我进入
这就很头疼了
严重影响我选课的体验
不如,让机器帮我填写?
流程简介
1、准备工作
验证码数据集以及本篇示例等 链接:https://pan.baidu.com/s/1XbzNBwFwJn7VT-IwcrS7WQ 提取码:n8z0
2、导入关键模块
import paddle.fluid as fluid
import paddle
import numpy as np
from PIL import Image
import os
3、参数初始化
cpu = fluid.CPUPlace()#创建执行器
exe = fluid.Executor(cpu)
4、生成数据集索引表
# 加载数据
datatype = 'float32'
with open(path + "data/ocrData.txt", 'rt') as f:
a = f.read()#打开标签数据集文件
def data_reader():
def reader():
for i in range(1, 1501):
im = Image.open(path + "data/" + str(i) + ".jpg").convert('L')
im = np.array(im).reshape(1, 30, 15).astype(np.float32)
im = im / 255.0 * 2.0 - 1.0
'''
img = paddle.dataset.image.load_image(path + "data/" + str(i+1) + ".jpg")'''
labelInfo = a[i - 1]
yield im, labelInfo
return reader
此处使用PaddlePaddle中的Reader来生成索引表
关于Reader的细节可以参考PaddlePaddle官方文档
http://paddlepaddle.org/documentation/docs/zh/1.2/user_guides/howto/prepare_data/reader_cn.html
为了直观一点,贴出数据集的结构截图
5、定义数据类型以及网络
#定义数据类型
x = fluid.layers.data(name="x",shape=[1,30,15],dtype=datatype)
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
因为读取的是灰度图像,所以此处x的shape参数设置为[单通道 30 x 15]
定义网络(这个网络是从PaddlePaddle-Book中拿来的)
传送门:https://github.com/PaddlePaddle/book
def multilayer_perceptron(img):
"""
定义多层感知机分类器:
含有两个隐藏层(全连接层)的多层感知器
其中前两个隐藏层的激活函数采用 ReLU,输出层的激活函数用 Softmax
Return:
predict_image -- 分类的结果
"""
# 第一个全连接层,激活函数为ReLU
hidden = fluid.layers.fc(input=img, size=200, act='relu')
# 第二个全连接层,激活函数为ReLU
hidden = fluid.layers.fc(input=hidden, size=200, act='relu')
# 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
prediction = fluid.layers.fc(input=hidden, size=10, act='softmax')
return prediction
#网络调用
net = multilayer_perceptron(x)#多层感知机
6、定义损失函数和优化方法
# 定义损失函数
cost = fluid.layers.cross_entropy(input=net,label=label)#交叉熵损失函数
avg_cost = fluid.layers.mean(cost)#求平均损失
acc = fluid.layers.accuracy(input=net, label=label, k=1)#准确率函数
#定义优化方法
sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.01)#依旧是随机梯度下降
sgd_optimizer.minimize(avg_cost)
此时的cost输入的是net
,可不是x
,是最终输出网络的那个变量名
7、数据读取设定
# 数据传入设置
batch_reader = paddle.batch(reader=data_reader(), batch_size=1024)
feeder = fluid.DataFeeder(place=cpu, feed_list=[x, label])
paddle.batch(reader=数据集列表读取函数, batch_size=每次读取图像数据的数量)
feeder = fluid.DataFeeder(place=cpu, feed_list=[传入数据类型, 标签类型])
8、定义项目开始训练
prog = fluid.default_startup_program()
exe.run(prog)
trainNum = 30 # 训练数量设定
for i in range(trainNum):
for batch_id,data in enumerate(batch_reader()): # 使用枚举类型读取数据集每一项
outs = exe.run(
feed=feeder.feed(data),
fetch_list=[label,avg_cost]) # feed为数据表 输入数据和标签数据
pross=float(i)/trainNum
# 打印输出面板
print(str(i+1)+"次训练后损失值为:"+str(outs[1]))
print("当前训练进度百分比为:"+str(pross*100)[:3].strip(".")+"%")
可以看到训练输出的损失值在理想之内,这次训练是成功的!
赶紧把模型保存了
# 保存模型
fluid.io.save_inference_model(params_dirname, ['x'],[net], exe)
要注意的是这里第3个参数是[net],可不是label
8、预测验证码
def data_reader(i):
im = Image.open(path + "data/" + str(i) + ".jpg").convert('L')
im = numpy.array(im).reshape(1, 1, 30, 15).astype(numpy.float32)
im = im / 255.0 * 2.0 - 1.0
#im = numpy.expand_dims(im, axis=0)
return im
# 参数初始化
cpu = fluid.CPUPlace()
exe = fluid.Executor(cpu)
# prog = fluid.default_startup_program()
# exe.run(prog)
# 加载模型
[inference_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(params_dirname, exe)
for i in range(1951,2001):
img = data_reader(i)
results = exe.run(inference_program,
feed={feed_target_names[0]: img},
fetch_list=fetch_targets)
lab = np.argsort(results)[0][0][-1]
print(i,"预测结果为:"+str(lab))
除了上节加载模型外多了一行lab = np.argsort(results)[0][0][-1]
意思是取最大概率的那个标签进行输出
关于 np.argsort
可以自行百度获取最新的解释
准确率杠杠的!
如果读取图片时候出现问题 请参考下一节读取图片数据