1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 利用深度学习(CNN)进行验证码(字母+数字)识别

利用深度学习(CNN)进行验证码(字母+数字)识别

时间:2019-02-25 07:19:44

相关推荐

利用深度学习(CNN)进行验证码(字母+数字)识别

利用深度学习(CNN)进行验证码(字母+数字)识别_helen1313的专栏-CSDN博客

本文方法针对的验证码为定长验证码,不包含中文。

本文的思路是:1. 使用keras中预训练好的模型,在python生成的验证码(5万条)上fine tune,得到python验证码模型;2. 使用python验证码模型,在实际验证码(500条)上fine tune;3. 增加样本,提高精度。

通俗的解释2个问题:

keras中预训练好的模型是什么东西?

答: keras上有很多已经训练好的图像识别模型,诸如Alex Net,google net,VGG16,VGG19,ResNet50,Xception,InceptionV3,这些都是由ImageNet训练而来。那ImageNet又是什么的?ImageNet项目是一个用于视觉对象识别软件研究的大型可视化数据库,超过1400万的图像URL被ImageNet手动注释,以指示图片中的对象。说白了,上述已经训练好的图像识别模型是用来识别大千世界的各种物品的,如气球、草莓、汽车、楼房等等。这些个模型都能识别这么复杂的东西了,那我现在要识别一个验证码数据,岂不是很简单?这就是站在巨人的肩膀上,再微微调整一下模型就可以了。这其实就是迁移学习的概念。

为什么要先使用python生成得验证码进行fine tune?

答: 虽说我们站在巨人的肩膀上,利用已有的深度神经网络来微调我们的模型,但是从大千世界迁移到验证码图片,这两个样本集还是有很大的差别的。这就要求我们用“大量“的验证码数据再去训练我们的神经网络参数。这个”大量“我为什么用引号呢,因为其实只需要数万张(下文使用了5万)验证码图片就可以了,相对于ImageNet的1400万,这个数字其实很小,但是如果需要我们手工标记数万张验证码,那就是不小的工作量了。所以,我们先用python自动生成标记好的5万张验证码图片,先进行fine tune,保存好输出的模型,注意,这个模型已经不是识别大千世界的模型了,是识别数字和英文字母的模型了,但是直接应用于实际的验证码,效果还是很差,因为两种验证码长得不一样,然后我们进行再一次的迁移学习,再在我们手工标记好的、实际要识别的验证码(500条)进行fine tune,这样就可以识别很好的识别我们要识别的验证码了。

1. 利用python生成你所需要的验证码

一般的验证码都为4位,由数字和大小写字母构成。利用python的captcha模块,生成5万张样本图片:

from captcha.image import ImageCaptcha

from random import randint

def gen_captcha(num,captcha_len):

# # 纯数字,如果目标识别是10位数字,预训练用纯数字效果更好

# list = [chr(i) for i in range(48, 58)]

# # 10数字+26大写字母+26小写字母

list = [chr(i) for i in range(48, 58)] + [chr(i) for i in range(65, 91)] + [chr(i) for i in range(97, 123)]

for j in range(num):

if j % 100 == 0:

print(j)

chars = ''

for i in range(captcha_len):

rand_num = randint(0, 61)

chars += list[rand_num]

image = ImageCaptcha().generate_image(chars)

image.save('./train/' + chars + '.jpg')

num = 50000

captcha_len = 4

gen_captcha(num,captcha_len)

这样我们就轻松的获取到了5万张样本数据

2. 使用python生成的样本进行预训练

keras_weight中Alex Net,google net,VGG16,VGG19,ResNet50,Xception,InceptionV3。都是由ImageNet训练而来。这里使用Xception模型

Xception模型

参考keras文档:https://keras.io/zh/applications/#xception

keras.applications.xception.Xception(include_top=True,

weights='imagenet', input_tensor=None,

input_shape=None, pooling=None, classes=1000)

在 ImageNet 上预训练的 Xception V1 模型。

在 ImageNet 上,该模型取得了验证集 top1 0.790 和 top5 0.945 的准确率。

注意该模型只支持 channels_last 的维度顺序(高度、宽度、通道)。

模型默认输入尺寸是 299x299

参数

include_top: 是否包括顶层的全连接层。

weights: None 代表随机初始化, 'imagenet' 代表加载在 ImageNet 上预训练的权值。

input_tensor: 可选,Keras tensor 作为模型的输入(即 layers.Input() 输出的 tensor)。

input_shape: 可选,输入尺寸元组,仅当 include_top=False 时有效(否则输入形状必须是 (299, 299, 3),因为预训练模型是以这个大小训练的)。它必须拥有 3 个输入通道,且宽高必须不小于 71。例如 (150, 150, 3) 是一个合法的输入尺寸。

pooling: 可选,当 include_top 为 False 时,该参数指定了特征提取时的池化方式。

None 代表不池化,直接输出最后一层卷积层的输出,该输出是一个 4D 张量。

'avg' 代表全局平均池化(GlobalAveragePooling2D),相当于在最后一层卷积层后面再加一层全局平均池化层,输出是一个 2D 张量。

'max' 代表全局最大池化。

classes: 可选,图片分类的类别数,仅当 include_top 为 True 并且不加载预训练权值时可用。

3. 模型训练

模型训练的代码如下:

import numpy as np

import glob

from keras.applications.xception import Xception,preprocess_input

from keras.layers import Input,Dense,Dropout

from keras.models import Model

from scipy import misc

samples = glob.glob('./train/*.jpg') # 获取所有样本图片

np.random.shuffle(samples) # 将图片打乱

nb_train = 45000 #共有5万样本,4.5万用于训练,5k用于验证

train_samples = samples[:nb_train]

test_samples = samples[nb_train:]

letter_list = [chr(i) for i in range(48, 58)] + [chr(i) for i in range(65, 91)] # 需要识别的36类

# CNN适合在高宽都是偶数的情况,否则需要在边缘补齐,把全体图片都resize成这个尺寸(高,宽,通道)

img_size = (60, 160)

input_image = Input(shape=(img_size[0],img_size[1],3))

#直接将验证码输入,做几个卷积层提取特征,然后把这些提出来的特征连接几个分类器(36分类,因为不区分大小写),

#输入图片

#用预训练的Xception提取特征,采用平均池化

base_model = Xception(input_tensor=input_image, weights='imagenet', include_top=False, pooling='avg')

#用全连接层把图片特征接上softmax然后36分类,dropout为0.5,因为是多分类问题,激活函数使用softmax。

#ReLU - 用于隐层神经元输出

#Sigmoid - 用于隐层神经元输出

#Softmax - 用于多分类神经网络输出

#Linear - 用于回归神经网络输出(或二分类问题)

predicts = [Dense(36, activation='softmax')(Dropout(0.5)(base_model.output)) for i in range(4)]

model = Model(inputs=input_image, outputs=predicts)

pile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

#misc.imread把图片转化成矩阵,

#misc.imresize重塑图片尺寸misc.imresize(misc.imread(img), img_size) img_size是自己设定的尺寸

#ord()函数主要用来返回对应字符的ascii码,

#chr()主要用来表示ascii码对应的字符他的输入时数字,可以用十进制,也可以用十六进制。

def data_generator(data, batch_size): #样本生成器,节省内存

while True:

#np.random.choice(x,y)生成一个从x中抽取的随机数,维度为y的向量,y为抽取次数

batch = np.random.choice(data, batch_size)

x,y = [],[]

for img in batch:

x.append(misc.imresize(misc.imread(img), img_size)) # 读取resize图片,再存进x列表

real_num = img[-8:-4]

y_list = []

for i in real_num:

i = i.upper()

if ord(i) - ord('A') >= 0:

y_list.append(ord(i) - ord('A') + 10)

else:

y_list.append(ord(i) - ord('0'))

y.append(y_list)

#把验证码标签添加到y列表,ord(i)-ord('a')把对应字母转化为数字a=0,b=1……z=26

x = preprocess_input(np.array(x).astype(float))

#原先是dtype=uint8转成一个纯数字的array

y = np.array(y)

yield x,[y[:,i] for i in range(4)]

#输出:图片array和四个转化成数字的字母 例如:[array([6]), array([0]), array([3]), array([24])])

model.fit_generator(data_generator(train_samples, 100), steps_per_epoch=450, epochs=5, validation_data=data_generator(test_samples, 100), validation_steps=100)

#参数:generator生成器函数,

#samples_per_epoch,每个epoch以经过模型的样本数达到samples_per_epoch时,记一个epoch结束

#step_per_epoch:整数,当生成器返回step_per_epoch次数据是记一个epoch结束,执行下一个epoch

#epochs:整数,数据迭代的轮数

#validation_data三种形式之一,生成器,类(inputs,targets)的元组,或者(inputs,targets,sample_weights)的元祖

#若validation_data为生成器,validation_steps参数代表验证集生成器返回次数

#class_weight:规定类别权重的字典,将类别映射为权重,常用于处理样本不均衡问题。

#sample_weight:权值的numpy array,用于在训练时调整损失函数(仅用于训练)。可以传递一个1D的与样本等长的向量用于对样本进行1对1的加权,或者在面对时序数据时,传递一个的形式为(samples,sequence_length)的矩阵来为每个时间步上的样本赋不同的权。这种情况下请确定在编译模型时添加了sample_weight_mode='temporal'。

#workers:最大进程数

#max_q_size:生成器队列的最大容量

#pickle_safe: 若为真,则使用基于进程的线程。由于该实现依赖多进程,不能传递non picklable(无法被pickle序列化)的参数到生成器中,因为无法轻易将它们传入子进程中。

#initial_epoch: 从该参数指定的epoch开始训练,在继续之前的训练时有用。

#保存模型

model.save('CaptchaForPython.h5')

这里只跑了5个epoch,本机电脑cpu跑的话,大概需要跑24小时左右。有条件的可以使用gpu跑。

跑的时候输出如下:Epoch 1/5表示跑第一个epoch;1/450表示跑第一个step;ETA: 6:05:12表示跑完这个epoch的剩余时间,这边显示6小时,实际4个小时左右;接下来为总的loss值和四个预测值依次的loss值;然后为4个预测值的准确率。

Epoch 1/5

1/450 [..............................] - ETA: 6:05:12 - loss: 14.6667 - dense_1_loss: 3.6935 - dense_2_loss: 3.7089 - dense_3_loss: 3.6337 - dense_4_loss: 3.6307 - dense_1_acc: 0.0400 - dense_2_acc: 0.0100 - dense_3_acc: 0.0300 - dense_4_acc: 0.0400

2/450 [..............................] - ETA: 4:58:17 - loss: 14.6598 - dense_1_loss: 3.6988 - dense_2_loss: 3.6536 - dense_3_loss: 3.6569 - dense_4_loss: 3.6505 - dense_1_acc: 0.0300 - dense_2_acc: 0.0300 - dense_3_acc: 0.0300 - dense_4_acc: 0.0450

3/450 [..............................] - ETA: 4:30:12 - loss: 14.6189 - dense_1_loss: 3.6936 - dense_2_loss: 3.6495 - dense_3_loss: 3.6589 - dense_4_loss: 3.6168 - dense_1_acc: 0.0300 - dense_2_acc: 0.0333 - dense_3_acc: 0.0267 - dense_4_acc: 0.0500

4/450 [..............................] - ETA: 4:17:47 - loss: 14.5575 - dense_1_loss: 3.6768 - dense_2_loss: 3.6342 - dense_3_loss: 3.6384 - dense_4_loss: 3.6083 - dense_1_acc: 0.0325 - dense_2_acc: 0.0325 - dense_3_acc: 0.0300 - dense_4_acc: 0.0525

5/450 [..............................] - ETA: 4:11:03 - loss: 14.5314 - dense_1_loss: 3.6617 - dense_2_loss: 3.6261 - dense_3_loss: 3.6289 - dense_4_loss: 3.6146 - dense_1_acc: 0.0340 - dense_2_acc: 0.0300 - dense_3_acc: 0.0300 - dense_4_acc: 0.0520

6/450 [..............................] - ETA: 4:05:27 - loss: 14.4945 - dense_1_loss: 3.6480 - dense_2_loss: 3.6178 - dense_3_loss: 3.6207 - dense_4_loss: 3.6080 - dense_1_acc: 0.0350 - dense_2_acc: 0.0317 - dense_3_acc: 0.0267 - dense_4_acc: 0.0467

等跑完这5个epoch,4个预测值的准确率基本上到达95%以上了,保存下来的模型权重已经可以为我们所用了。

4. 获取你要识别的验证码图片

假设我们要识别中国电信(/web/login)登录时的验证码,该验证码是4位定长,10个数字+26个大写字母。

获取你需要识别的验证码,需要利用python将图片从网站上爬取下来。下面以中国电信为例,简单介绍如何爬取图片。

打开中国电信登录页面/web/login,单击右键,选择“检查”,在跳出来的页面中,选择“Network”。

在电话号码输入框,随便输一个电话号码,输完后便会跳出验证码,点击验证码,验证码会重新加载,同时右侧”Network”也抓取到了验证码的加载地址。

单击其中一条数据,查看Headers,我们就获取到了验证码的request url地址,以及request headers。

现在我们就可以利用python爬取中国电信的验证码图片了。由于验证码图片并没有设置反爬机制,所以我们在请求的时候只用到了request url,并没有用request headers包装我们的请求头。

import urllib.request

url = '/web/captcha?undefined&source=login&width=100&height=37&0.564730904066772'

for i in range(500):

if i % 100 == 0:

print(i)

f = open('./dianxin/'+str(i)+'.jpg','wb')

f.write((urllib.request.urlopen(url)).read())

f.close()

获取到500张样本图片后呢,就要劳烦我们自个标记一下了。

5. 使用实际验证码进行再次训练

训练

现在我们使用我们手工标记的500张验证码图片,进行第二次的fine tune,代码如下。你会发现,这个代码跟上面的代码几乎一模一样,只是多了一步model.load_weights('CaptchaForPython.h5'),这就是在加载我们上一步保存的网络参数;同时Xception的weights设置为None了,就是没有加载Xception原来的网络参数,前面的过程,就是搭了一个深度网络的框架而已。

import numpy as np

from scipy import misc

from keras.applications.xception import Xception,preprocess_input

import glob

from keras.layers import Input,Dense,Dropout

from keras.models import Model

img_size = (70, 160)

input_image = Input(shape=(img_size[0],img_size[1],3))

base_model = Xception(input_tensor=input_image, weights=None, include_top=False, pooling='avg')

predicts = [Dense(36, activation='softmax')(Dropout(0.5)(base_model.output)) for i in range(4)]

model = Model(inputs=input_image, outputs=predicts)

pile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

model.load_weights('CaptchaForPython.h5')

def data_generator(data, batch_size): #样本生成器,节省内存

while True:

batch = np.random.choice(data, batch_size)

x,y = [],[]

for img in batch:

im = misc.imread(img)

im = im[:, :, :3]

im = misc.imresize(im, img_size)

x.append(im)

real_num = img[-8:-4]

y_list = []

for i in real_num:

if ord(i)-ord('A') >= 0:

y_list.append(ord(i)-ord('A')+10)

else:

y_list.append(ord(i)-ord('0'))

y.append(y_list)

x = preprocess_input(np.array(x).astype(float))

y = np.array(y)

yield x,[y[:,i] for i in range(4)]

#获取指定目录下的所有图片

samples = glob.glob('dianxin/*.jpg')

np.random.shuffle(samples)

nb_train = 450

train_samples = samples[:nb_train]

test_samples = samples[nb_train:]

#Continue training

model.fit_generator(data_generator(train_samples, 30), steps_per_epoch=15, epochs=7, validation_data=data_generator(test_samples, 10), validation_steps=5)

model.save('CaptchaForDianxin_from_python_1.h5')

模型训练的时候几个指标怎么设置?

训练样本是450个,可以看到我的batch_size(即每次batch训练的样本数量)是30,每个epoch是15步,看出来了么,30*15=450。同样,测试集是50个,所以validation的test_sample*validation_steps=30。同样适用于上面对5w张验证码进行训练的代码,大家可以翻上去看一下。

为什么保存模型'CaptchaForDianxin_from_python_1.h5'?

因为这个模型只用了450张图片进行训练,后面还需要增加样本再进一步fine tune,所以用了“_1“来命名模型。

训练结果如下,可以看到,由于训练样本小(450张),训练速度很快,一个epoch大概3分钟不到,且到第一个epoch结束,测试集的四位准确率已经到达80%左右(val_dense_1_acc: 0.8200 - val_dense_2_acc: 0.9000 - val_dense_3_acc: 0.7400 - val_dense_4_acc: 0.8400)。

Epoch 1/7

1/15 [=>............................] - ETA: 5:21 - loss: 26.9934 - dense_1_loss: 8.0300 - dense_2_loss: 5.5903 - dense_3_loss: 5.8983 - dense_4_loss: 7.4748 - dense_1_acc: 0.1667 - dense_2_acc: 0.2333 - dense_3_acc: 0.2667 - dense_4_acc: 0.1333

2/15 [===>..........................] - ETA: 3:49 - loss: 24.8148 - dense_1_loss: 7.4826 - dense_2_loss: 5.0729 - dense_3_loss: 5.8344 - dense_4_loss: 6.4249 - dense_1_acc: 0.2667 - dense_2_acc: 0.2667 - dense_3_acc: 0.2333 - dense_4_acc: 0.1667

3/15 [=====>........................] - ETA: 3:08 - loss: 22.7996 - dense_1_loss: 7.3436 - dense_2_loss: 5.0177 - dense_3_loss: 5.0447 - dense_4_loss: 5.3936 - dense_1_acc: 0.2889 - dense_2_acc: 0.2667 - dense_3_acc: 0.2556 - dense_4_acc: 0.2444

4/15 [=======>......................] - ETA: 2:41 - loss: 21.4098 - dense_1_loss: 7.0998 - dense_2_loss: 4.7698 - dense_3_loss: 4.8378 - dense_4_loss: 4.7024 - dense_1_acc: 0.2833 - dense_2_acc: 0.2917 - dense_3_acc: 0.2917 - dense_4_acc: 0.3167

5/15 [=========>....................] - ETA: 2:19 - loss: 19.5361 - dense_1_loss: 6.6055 - dense_2_loss: 4.2805 - dense_3_loss: 4.5223 - dense_4_loss: 4.1277 - dense_1_acc: 0.3000 - dense_2_acc: 0.3400 - dense_3_acc: 0.3200 - dense_4_acc: 0.3733

6/15 [===========>..................] - ETA: 2:01 - loss: 17.2208 - dense_1_loss: 5.8171 - dense_2_loss: 3.8086 - dense_3_loss: 4.0312 - dense_4_loss: 3.5639 - dense_1_acc: 0.3611 - dense_2_acc: 0.4000 - dense_3_acc: 0.3667 - dense_4_acc: 0.4500

7/15 [=============>................] - ETA: 1:45 - loss: 16.1136 - dense_1_loss: 5.5105 - dense_2_loss: 3.5737 - dense_3_loss: 3.7542 - dense_4_loss: 3.2753 - dense_1_acc: 0.3905 - dense_2_acc: 0.4333 - dense_3_acc: 0.4048 - dense_4_acc: 0.4857

8/15 [===============>..............] - ETA: 1:30 - loss: 15.0458 - dense_1_loss: 5.1275 - dense_2_loss: 3.3375 - dense_3_loss: 3.5751 - dense_4_loss: 3.0056 - dense_1_acc: 0.4250 - dense_2_acc: 0.4708 - dense_3_acc: 0.4375 - dense_4_acc: 0.5208

9/15 [=================>............] - ETA: 1:16 - loss: 14.1483 - dense_1_loss: 4.6975 - dense_2_loss: 3.2369 - dense_3_loss: 3.3625 - dense_4_loss: 2.8515 - dense_1_acc: 0.4630 - dense_2_acc: 0.4815 - dense_3_acc: 0.4630 - dense_4_acc: 0.5370

10/15 [===================>..........] - ETA: 1:02 - loss: 13.1816 - dense_1_loss: 4.3671 - dense_2_loss: 2.9939 - dense_3_loss: 3.1700 - dense_4_loss: 2.6506 - dense_1_acc: 0.4900 - dense_2_acc: 0.5067 - dense_3_acc: 0.4933 - dense_4_acc: 0.5700

11/15 [=====================>........] - ETA: 49s - loss: 12.4837 - dense_1_loss: 4.0982 - dense_2_loss: 2.8409 - dense_3_loss: 3.0433 - dense_4_loss: 2.5012 - dense_1_acc: 0.5091 - dense_2_acc: 0.5212 - dense_3_acc: 0.5091 - dense_4_acc: 0.5939

12/15 [=======================>......] - ETA: 36s - loss: 11.7352 - dense_1_loss: 3.8170 - dense_2_loss: 2.6642 - dense_3_loss: 2.8542 - dense_4_loss: 2.3998 - dense_1_acc: 0.5278 - dense_2_acc: 0.5500 - dense_3_acc: 0.5333 - dense_4_acc: 0.6139

13/15 [=========================>....] - ETA: 24s - loss: 11.1570 - dense_1_loss: 3.6193 - dense_2_loss: 2.5443 - dense_3_loss: 2.7291 - dense_4_loss: 2.2644 - dense_1_acc: 0.5410 - dense_2_acc: 0.5641 - dense_3_acc: 0.5487 - dense_4_acc: 0.6333

14/15 [===========================>..] - ETA: 12s - loss: 10.6230 - dense_1_loss: 3.4717 - dense_2_loss: 2.4350 - dense_3_loss: 2.5624 - dense_4_loss: 2.1538 - dense_1_acc: 0.5476 - dense_2_acc: 0.5857 - dense_3_acc: 0.5690 - dense_4_acc: 0.6500

15/15 [==============================] - 185s 12s/step - loss: 10.0801 - dense_1_loss: 3.2947 - dense_2_loss: 2.3047 - dense_3_loss: 2.4300 - dense_4_loss: 2.0507 - dense_1_acc: 0.5689 - dense_2_acc: 0.6022 - dense_3_acc: 0.5867 - dense_4_acc: 0.6600 - val_loss: 3.1664 - val_dense_1_loss: 0.8683 - val_dense_2_loss: 0.3158 - val_dense_3_loss: 0.7921 - val_dense_4_loss: 1.1902 - val_dense_1_acc: 0.8200 - val_dense_2_acc: 0.9000 - val_dense_3_acc: 0.7400 - val_dense_4_acc: 0.8400

Epoch 2/7

1/15 [=>............................] - ETA: 2:36 - loss: 1.3170 - dense_1_loss: 0.3431 - dense_2_loss: 0.4282 - dense_3_loss: 0.4664 - dense_4_loss: 0.0792 - dense_1_acc: 0.9000 - dense_2_acc: 0.9000 - dense_3_acc: 0.9333 - dense_4_acc: 1.0000

2/15 [===>..........................] - ETA: 2:24 - loss: 1.8133 - dense_1_loss: 0.5713 - dense_2_loss: 0.5021 - dense_3_loss: 0.5045 - dense_4_loss: 0.2354 - dense_1_acc: 0.8500 - dense_2_acc: 0.9000 - dense_3_acc: 0.9000 - dense_4_acc: 0.9667

3/15 [=====>........................] - ETA: 2:13 - loss: 1.8234 - dense_1_loss: 0.4772 - dense_2_loss: 0.4436 - dense_3_loss: 0.5648 - dense_4_loss: 0.3379 - dense_1_acc: 0.8667 - dense_2_acc: 0.8889 - dense_3_acc: 0.8778 - dense_4_acc: 0.9222

4/15 [=======>......................] - ETA: 2:02 - loss: 1.8447 - dense_1_loss: 0.4957 - dense_2_loss: 0.4421 - dense_3_loss: 0.5911 - dense_4_loss: 0.3159 - dense_1_acc: 0.8583 - dense_2_acc: 0.8917 - dense_3_acc: 0.8833 - dense_4_acc: 0.9250

等我们跑完7个epoch的时候,测试集上的准确率已经达到了90%+:val_dense_1_acc: 0.9800 - val_dense_2_acc: 1.0000 - val_dense_3_acc: 0.9600 - val_dense_4_acc: 0.9800

模型验证

那么,上面这个模型实际的效果到底怎么样呢?我们再抓取50张图片并标记,来验证这个模型:

from keras.models import load_model

import numpy as np

from scipy import misc

from keras.applications.xception import preprocess_input

import matplotlib.pyplot as plt # plt 用于显示图片

import matplotlib.image as mpimg # mpimg 用于读取图片

import glob

img_size = (60, 170)

model = load_model('./CaptchaForDianxin_from_python_1.h5')

letter_list = [chr(i) for i in range(48,58)] + [chr(i) for i in range(65,91)]

def data_generator_test(data, n): #样本生成器,节省内存

while True:

batch = np.array([data[n]])

x,y = [],[]

for img in batch:

im = misc.imread(img)

im = im[:, :, :3]

im = misc.imresize(im, img_size)

x.append(im) #读取resize图片,再存进x列表

y_list = []

real_num = img[-8:-4]

for i in real_num:

if ord(i)-ord('A') >= 0:

y_list.append(ord(i)-ord('A')+10)

else:

y_list.append(ord(i)-ord('0'))

y.append(y_list) #把验证码标签添加到y列表,ord(i)-ord('a')把对应字母转化为数字a=0,b=1……z=26

# print('real_1:',img[-8:-4])

x = preprocess_input(np.array(x).astype(float)) #原先是dtype=uint8转成一个纯数字的array

y = np.array(y)

yield x,[y[:,i] for i in range(4)]

def predict2(n):

x,y = next(data_generator_test(test_samples, n))

z = model.predict(x)

z = np.array([i.argmax(axis=1) for i in z]).T

result = z.tolist()

v = []

for i in range(len(result)):

for j in result[i]:

v.append(letter_list[j])

#输出测试结果

str = ''

for i in v:

str += i

real = ''

for i in y:

for j in i:

real += letter_list[j]

return (str,real)

test_samples = glob.glob(r'dianxin_test_sample/*.jpg')

n = 0

n_right = 0

for i in range(len(test_samples)):

n += 1

print('~~~~~~~~~~~~~%d~~~~~~~~~'%(n))

predict,real = predict2(i)

if real == predict:

n_right += 1

else:

print('real:', real)

print('predict:',predict)

image = mpimg.imread(test_samples[i])

plt.axis('off')

plt.imshow(image)

plt.show()

print(n,n_right,n_right/n)

最后的结果,50张图片,正确预测45张,错误预测5张,准确率90%。

7. 增加样本,继续fine tune

按照上述步骤,我们已经得到了一个不错的结果。

那么,如果验证码比较复杂,仅仅靠450张图片训练后,得到的结果不满意,或者我需要更高的精度呢?很简单,我们只要增加样本量,按照上述步骤,继续在新生成的模型上fine tune,就可以了,而且这个模型的训练会很快,也不需要多个epoch,基本2-3个epoch就可以了。

至于如何更加轻松的标记样本,此时我们已经由一个准确率90%的模型,可以用模型预测的结果去请求需要验证码的网址,让网站为你识别你的预测是否准确,并将预测错误的验证码手工标记,获取更多的样本。

参考:

/p/9d233a45f53b

keras官方文档:https://keras.io

————————————————

版权声明:本文为CSDN博主「helen1313」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:/helen1313/article/details/102773435

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。