Fork me on GitHub

CNN识别验证码1

之前学习python的时候,想尝试用requests实现自动登陆,但是现在网站登陆都会有验证码保护,主要是为了防止暴力破解,任意用户注册。最近接触深度学习,cnn能够进行图像识别,能够进行验证码识别。

主要步骤:

1、采样制作样本文件

2、根据样本文件类型创建识别模型

3、对样本文件分为训练样本和测试样本来训练识别模型

4、保存识别模型和验证

第一步生成验证码,保存文件为generate_captcha.py:

 1 #-*- coding:utf-8 -*-
 2 from captcha.image import ImageCaptcha
 3 from PIL import Image
 4 import numpy as np
 5 import random
 6 import string
 7 
 8 class generateCaptcha():
 9     def __init__(self,
10                  width = 160,#验证码图片的宽
11                  height = 60,#验证码图片的高
12                  char_num = 4,#验证码字符个数
13                  characters = string.digits + string.ascii_uppercase + string.ascii_lowercase):#验证码组成,数字+大写字母+小写字母
14         self.width = width
15         self.height = height
16         self.char_num = char_num
17         self.characters = characters
18         self.classes = len(characters)  #10+26+26=62
19 
20     def gen_captcha(self,batch_size = 50):
21         X = np.zeros([batch_size,self.height,self.width,1])
22         img = np.zeros((self.height,self.width),dtype=np.uint8)
23         Y = np.zeros([batch_size,self.char_num,self.classes])
24         image = ImageCaptcha(width = self.width,height = self.height)
25 
26         while True:
27             for i in range(batch_size):
28                 captcha_str = ''.join(random.sample(self.characters,self.char_num))
29                 img = image.generate_image(captcha_str).convert('L')
30                 img = np.array(img.getdata())
31                 X[i] = np.reshape(img,[self.height,self.width,1])/255.0
32                 for j,ch in enumerate(captcha_str):
33                     Y[i,j,self.characters.find(ch)] = 1
34             Y = np.reshape(Y,(batch_size,self.char_num*self.classes))
35             yield X,Y
36 
37     def decode_captcha(self,y):
38         y = np.reshape(y,(len(y),self.char_num,self.classes))
39         return ''.join(self.characters[x] for x in np.argmax(y,axis = 2)[0,:])
40 
41     def get_parameter(self):
42         return self.width,self.height,self.char_num,self.characters,self.classes
43 
44     def gen_test_captcha(self):
45         image = ImageCaptcha(width = self.width,height = self.height)
46         captcha_str = ''.join(random.sample(self.characters,self.char_num))
47         img = image.generate_image(captcha_str)
48         img.save(captcha_str + '.jpg')
49 
50         X = np.zeros([1,self.height,self.width,1])
51         Y = np.zeros([1,self.char_num,self.classes])
52         img = img.convert('L')
53         img = np.array(img.getdata())
54         X[0] = np.reshape(img,[self.height,self.width,1])/255.0
55         for j,ch in enumerate(captcha_str):
56             Y[0,j,self.characters.find(ch)] = 1
57         Y = np.reshape(Y,(1,self.char_num*self.classes))
58         return X,Y

返回参数的含义:

  • X:一个 mini-batch 的训练数据,其 shape 为 [ batch_size, height, width, 1 ],batch_size 表示每批次多少个训练数据,height 表示验证码图片的高,width 表示验证码图片的宽,1 表示图片的通道。
  • Y:X 中每个训练数据属于哪一类验证码,其形状为 [ batch_size, class ] ,对验证码中每个字符进行 One-Hot 编码,所以 class 大小为 4*62。

调用这个类的时候会生成这样的验证码图片:

第二步创建识别模型

这里用到了 5 层网络,前 3 层为卷积层,第 4、5 层为全连接层。对 4 层隐藏层都进行 dropout。网络结构如下所示: input——>conv——>pool——>dropout——>conv——>pool——>dropout——>conv——>pool——>dropout——>fully connected layer——>dropout——>fully connected layer——>output

主要代码(captcha_model.py):

 1 # -*- coding: utf-8 -*
 2 import tensorflow as tf
 3 import math
 4 
 5 class captchaModel():
 6     def __init__(self,
 7                  width = 160,
 8                  height = 60,
 9                  char_num = 4,
10                  classes = 62):
11         self.width = width
12         self.height = height
13         self.char_num = char_num
14         self.classes = classes
15 
16     def conv2d(self,x, W):
17         return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')  #步长是1,卷积的时候图片大小没有缩小。最大池化的时候图片减为一半。
18 
19     def max_pool_2x2(self,x):
20         return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],                      #用2*2的过滤器
21                               strides=[1, 2, 2, 1], padding='SAME')       #最大池化步长是2
22 
23     def weight_variable(self,shape):
24         initial = tf.truncated_normal(shape, stddev=0.1)
25         return tf.Variable(initial)
26 
27     def bias_variable(self,shape):
28         initial = tf.constant(0.1, shape=shape)
29         return tf.Variable(initial)
30 
31     def create_model(self,x_images,keep_prob):
32         #first layer
33         w_conv1 = self.weight_variable([5, 5, 1, 32])   #通过过滤器计算权重值5*5*32
34         b_conv1 = self.bias_variable([32])               #32是[5,5,1,32]中的32的输出。a[1]=Relu(w[1]a[0]+b[1]),因为w[1]a[0]是32,矩阵相加。
35         h_conv1 = tf.nn.relu(tf.nn.bias_add(self.conv2d(x_images, w_conv1), b_conv1))
36         h_pool1 = self.max_pool_2x2(h_conv1)
37         h_dropout1 = tf.nn.dropout(h_pool1,keep_prob)
38         conv_width = math.ceil(self.width/2)
39         conv_height = math.ceil(self.height/2)
40 
41         #second layer
42         w_conv2 = self.weight_variable([5, 5, 32, 64])
43         b_conv2 = self.bias_variable([64])
44         h_conv2 = tf.nn.relu(tf.nn.bias_add(self.conv2d(h_dropout1, w_conv2), b_conv2))
45         h_pool2 = self.max_pool_2x2(h_conv2)
46         h_dropout2 = tf.nn.dropout(h_pool2,keep_prob)
47         conv_width = math.ceil(conv_width/2)
48         conv_height = math.ceil(conv_height/2)
49 
50         #third layer
51         w_conv3 = self.weight_variable([5, 5, 64, 64])
52         b_conv3 = self.bias_variable([64])
53         h_conv3 = tf.nn.relu(tf.nn.bias_add(self.conv2d(h_dropout2, w_conv3), b_conv3))
54         h_pool3 = self.max_pool_2x2(h_conv3)
55         h_dropout3 = tf.nn.dropout(h_pool3,keep_prob)
56         conv_width = math.ceil(conv_width/2)
57         conv_height = math.ceil(conv_height/2)
58 
59         #first fully layer
60         conv_width = int(conv_width)
61         conv_height = int(conv_height)
62         w_fc1 = self.weight_variable([64*conv_width*conv_height,1024])  #64*20*8
63         b_fc1 = self.bias_variable([1024])
64         h_dropout3_flat = tf.reshape(h_dropout3,[-1,64*conv_width*conv_height])
65         h_fc1 = tf.nn.relu(tf.nn.bias_add(tf.matmul(h_dropout3_flat, w_fc1), b_fc1))
66         h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
67 
68         #second fully layer
69         w_fc2 = self.weight_variable([1024,self.char_num*self.classes])
70         b_fc2 = self.bias_variable([self.char_num*self.classes])
71         y_conv = tf.add(tf.matmul(h_fc1_drop, w_fc2), b_fc2)
72 
73         return y_conv

第三步,有了样本和模型可以训练识别模型

每 100 次循环采用 100 个测试样本检查识别准确度,当准确度大于 99% 时,训练结束,采用 GPU 需要 4-5 个小时左右,CPU 大概需要 20 个小时左右。

主要代码(train_captcha.py):

 1 #-*- coding:utf-8 -*-
 2 import tensorflow as tf
 3 import numpy as np
 4 import string
 5 import generate_captcha
 6 import captcha_model
 7 
 8 if __name__ == '__main__':
 9     captcha = generate_captcha.generateCaptcha()
10     width,height,char_num,characters,classes = captcha.get_parameter()
11 
12     x = tf.placeholder(tf.float32, [None, height,width,1]) #占位符
13     y_ = tf.placeholder(tf.float32, [None, char_num*classes])
14     keep_prob = tf.placeholder(tf.float32)
15 
16     model = captcha_model.captchaModel(width,height,char_num,classes)
17     y_conv = model.create_model(x,keep_prob)
18     cross_entropy = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y_,logits=y_conv))#將tensor取平均,第二個參數代表沿著那一維取平均
19     train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)  #优化器
20 
21     predict = tf.reshape(y_conv, [-1,char_num, classes])    #y_conv通过模型获得的
22     real = tf.reshape(y_,[-1,char_num, classes])
23     correct_prediction = tf.equal(tf.argmax(predict,2), tf.argmax(real,2))
24     correct_prediction = tf.cast(correct_prediction, tf.float32)
25     accuracy = tf.reduce_mean(correct_prediction)
26 
27     saver = tf.train.Saver()
28     with tf.Session() as sess:
29         sess.run(tf.global_variables_initializer())
30         step = 1
31         while True:
32             batch_x,batch_y = next(captcha.gen_captcha(64))
33             _,loss = sess.run([train_step,cross_entropy],feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.75})
34             print ('step:%d,loss:%f' % (step,loss))
35             if step % 100 == 0:
36                 batch_x_test,batch_y_test = next(captcha.gen_captcha(100))
37                 acc = sess.run(accuracy, feed_dict={x: batch_x_test, y_: batch_y_test, keep_prob: 1.})
38                 print ('###############################################step:%d,accuracy:%f' % (step,acc))
39                 if acc > 0.99:                      #准确率
40                     saver.save(sess,"capcha_model.ckpt")  #保存模型文件
41                     break
42             step += 1

进行训练,查看训练过程(这里为了快速得到模型,我们将acc改的很小。训练模型也不准确):

当训练好后会生成以下模型文件,其中checkpoint保存模型路劲和一些模型信息,方便下次训练:

第四步,进行预测:

主要代码(predict_captcha.py):

 1 #-*- coding:utf-8 -*-
 2 from PIL import Image, ImageFilter
 3 import tensorflow as tf
 4 import numpy as np
 5 import string
 6 import sys
 7 import generate_captcha
 8 import captcha_model
 9 
10 if __name__ == '__main__':
11     captcha = generate_captcha.generateCaptcha()
12     width,height,char_num,characters,classes = captcha.get_parameter()
13 
14     gray_image = Image.open('./captcha/0hwn.jpg').convert('L')        #要预测的验证码图片位置
15 #     gray_image = Image.open(sys.argv[1]).convert('L')
16     img = np.array(gray_image.getdata())
17     test_x = np.reshape(img,[height,width,1])/255.0
18     x = tf.placeholder(tf.float32, [None, height,width,1])
19     keep_prob = tf.placeholder(tf.float32)
20 
21     model = captcha_model.captchaModel(width,height,char_num,classes)
22     y_conv = model.create_model(x,keep_prob)
23     predict = tf.argmax(tf.reshape(y_conv, [-1,char_num, classes]),2)
24     init_op = tf.global_variables_initializer()
25     saver = tf.train.Saver()
26     gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.95)
27     with tf.Session(config=tf.ConfigProto(log_device_placement=False,gpu_options=gpu_options)) as sess:
28         sess.run(init_op)
29         saver.restore(sess, "./capcha_model.ckpt")   #训练好模型文件的位置
30         pre_list =  sess.run(predict,feed_dict={x: [test_x], keep_prob: 1})
31         for i in pre_list:
32             s = ''
33             for j in i:
34                 s += characters[j]
35             print(s)

查看结果:

参考链接:

https://xianzhi.aliyun.com/forum/topic/1470/

https://xianzhi.aliyun.com/forum/topic/1505/

https://xianzhi.aliyun.com/forum/topic/1552/

https://cloud.tencent.com/developer/labs/lab/10325

posted @ 2017-12-12 22:39  Afant1  阅读(1313)  评论(0编辑  收藏  举报