相信你对验证码肯定不陌生
学校的教务系统老让我填验证码
而且明明填写正确却不让我进入
这就很头疼了
严重影响我选课的体验
不如, 让机器帮我填写?
流程简介
1, 准备工作
验证码数据集 链接: https://pan.baidu.com/s/1xM0hc0ARR_Mt8cEIWRfmkg 提取码: 7jl9
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 dataReader():
- def redaer():
- for i in range(1,1501):
- #图像读取
- im = Image.open(path + "data/" + str(i) + ".jpg").convert('L')# 转换为灰度图像 此处使用 Pillow 库
- im = np.array(im).reshape(30, 15).astype(np.float32)# 转换成 30x15 二维数据格式
- im = im / 255.0 * 2.0 - 1.0# 归一化处理优化速度
- #标签读取
- labelInfo=a[i-1]
- yield im,labelInfo# 使用迭代器返回图像, 标签数据
- return redaer
此处使用 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=dataReader(), 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, 定义项目开始训练
- 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 dataReader(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=dataReader(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 可以自行百度获取最新的解释
预测结果
实际数据集
准确率杠杠的!
如果读取图片时候出现问题 请参考下一节读取图片数据
来源: http://www.jianshu.com/p/df98fcc832ed