之前学习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/