tensorFlow(六)應用-基於CNN破解驗證碼

TensorFlow基礎見前博客python

簡介

傳統的驗證碼識別算法通常須要把驗證碼分割爲單個字符,而後逐個識別。本教程將驗證碼識別問題轉化爲分類的問題,實現對驗證碼進行總體識別。

步驟簡介

本教程一共分爲四個部分
  • generate_captcha.py - 利用 Captcha 庫生成驗證碼;
  • captcha_model.py - CNN 模型;
  • train_captcha.py - 訓練 CNN 模型;
  • predict_captcha.py - 識別驗證碼。

數據學習

安裝 captcha 庫

pip install captcha

獲取訓練數據

本教程使用的驗證碼由數字、大寫字母、小寫字母組成,每一個驗證碼包含 4 個字符,總共有 62^4 種組合,因此一共有 62^4 種不一樣的驗證碼。

generate_captcha.pygit

#-*- coding:utf-8 -*-
from captcha.image import ImageCaptcha
from PIL import Image
import numpy as np
import random
import string

class generateCaptcha():
    def __init__(self,
                 width = 160,#驗證碼圖片的寬
                 height = 60,#驗證碼圖片的高
                 char_num = 4,#驗證碼字符個數
                 characters = string.digits + string.ascii_uppercase + string.ascii_lowercase):#驗證碼組成,數字+大寫字母+小寫字母
        self.width = width
        self.height = height
        self.char_num = char_num
        self.characters = characters
        self.classes = len(characters)

    def gen_captcha(self,batch_size = 50):
        X = np.zeros([batch_size,self.height,self.width,1])
        img = np.zeros((self.height,self.width),dtype=np.uint8)
        Y = np.zeros([batch_size,self.char_num,self.classes])
        image = ImageCaptcha(width = self.width,height = self.height)

        while True:
            for i in range(batch_size):
                captcha_str = ''.join(random.sample(self.characters,self.char_num))
                img = image.generate_image(captcha_str).convert('L')
                img = np.array(img.getdata())
                X[i] = np.reshape(img,[self.height,self.width,1])/255.0
                for j,ch in enumerate(captcha_str):
                    Y[i,j,self.characters.find(ch)] = 1
            Y = np.reshape(Y,(batch_size,self.char_num*self.classes))
            yield X,Y

    def decode_captcha(self,y):
        y = np.reshape(y,(len(y),self.char_num,self.classes))
        return ''.join(self.characters[x] for x in np.argmax(y,axis = 2)[0,:])

    def get_parameter(self):
        return self.width,self.height,self.char_num,self.characters,self.classes

    def gen_test_captcha(self):
        image = ImageCaptcha(width = self.width,height = self.height)
        captcha_str = ''.join(random.sample(self.characters,self.char_num))
        img = image.generate_image(captcha_str)
        img.save(captcha_str + '.jpg')

        X = np.zeros([1,self.height,self.width,1])
        Y = np.zeros([1,self.char_num,self.classes])
        img = img.convert('L')
        img = np.array(img.getdata())
        X[0] = np.reshape(img,[self.height,self.width,1])/255.0
        for j,ch in enumerate(captcha_str):
            Y[0,j,self.characters.find(ch)] = 1
        Y = np.reshape(Y,(1,self.char_num*self.classes))
        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。
執行:
  • 獲取驗證碼和對應的分類
cd /home/ubuntu;
python
from generate_captcha import generateCaptcha
g = generateCaptcha()
X,Y = g.gen_test_captcha()
  • 查看訓練數據
X.shape
Y.shape

能夠在 /home/ubuntu 目錄下查看生成的驗證碼,jpg 格式的圖片能夠點擊查看。算法

模型學習

CNN 模型

  總共 5 層網絡,前 3 層爲卷積層,第 四、5 層爲全鏈接層。對 4 層隱藏層都進行 dropout。網絡結構以下所示: input——>conv——>pool——>dropout——>conv——>pool——>dropout——>conv——>pool——>dropout——>fully connected layer——>dropout——>fully connected layer——>output
 
示例代碼:
# -*- coding: utf-8 -*
import tensorflow as tf
import math

class captchaModel():
    def __init__(self,
                 width = 160,
                 height = 60,
                 char_num = 4,
                 classes = 62):
        self.width = width
        self.height = height
        self.char_num = char_num
        self.classes = classes

    def conv2d(self,x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def max_pool_2x2(self,x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                              strides=[1, 2, 2, 1], padding='SAME')

    def weight_variable(self,shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(self,shape):
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial)

    def create_model(self,x_images,keep_prob):
        #first layer
        w_conv1 = self.weight_variable([5, 5, 1, 32])
        b_conv1 = self.bias_variable([32])
        h_conv1 = tf.nn.relu(tf.nn.bias_add(self.conv2d(x_images, w_conv1), b_conv1))
        h_pool1 = self.max_pool_2x2(h_conv1)
        h_dropout1 = tf.nn.dropout(h_pool1,keep_prob)
        conv_width = math.ceil(self.width/2)
        conv_height = math.ceil(self.height/2)

        #second layer
        w_conv2 = self.weight_variable([5, 5, 32, 64])
        b_conv2 = self.bias_variable([64])
        h_conv2 = tf.nn.relu(tf.nn.bias_add(self.conv2d(h_dropout1, w_conv2), b_conv2))
        h_pool2 = self.max_pool_2x2(h_conv2)
        h_dropout2 = tf.nn.dropout(h_pool2,keep_prob)
        conv_width = math.ceil(conv_width/2)
        conv_height = math.ceil(conv_height/2)

        #third layer
        w_conv3 = self.weight_variable([5, 5, 64, 64])
        b_conv3 = self.bias_variable([64])
        h_conv3 = tf.nn.relu(tf.nn.bias_add(self.conv2d(h_dropout2, w_conv3), b_conv3))
        h_pool3 = self.max_pool_2x2(h_conv3)
        h_dropout3 = tf.nn.dropout(h_pool3,keep_prob)
        conv_width = math.ceil(conv_width/2)
        conv_height = math.ceil(conv_height/2)

        #first fully layer
        conv_width = int(conv_width)
        conv_height = int(conv_height)
        w_fc1 = self.weight_variable([64*conv_width*conv_height,1024])
        b_fc1 = self.bias_variable([1024])
        h_dropout3_flat = tf.reshape(h_dropout3,[-1,64*conv_width*conv_height])
        h_fc1 = tf.nn.relu(tf.nn.bias_add(tf.matmul(h_dropout3_flat, w_fc1), b_fc1))
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

        #second fully layer
        w_fc2 = self.weight_variable([1024,self.char_num*self.classes])
        b_fc2 = self.bias_variable([self.char_num*self.classes])
        y_conv = tf.add(tf.matmul(h_fc1_drop, w_fc2), b_fc2)

        return y_conv

 

訓練 CNN 模型

每批次採用 64 個訓練樣本,每 100 次循環採用 100 個測試樣本檢查識別準確度,當準確度大於 99% 時,訓練結束,採用 GPU 須要 4-5 個小時左右,CPU 大概須要 20 個小時左右。

示例代碼:

如今您能夠在  /home/ubuntu 目錄下 建立源文件 train_captcha.py,內容可參考:
#-*- coding:utf-8 -*-
import tensorflow as tf
import numpy as np
import string
import generate_captcha
import captcha_model

if __name__ == '__main__':
    captcha = generate_captcha.generateCaptcha()
    width,height,char_num,characters,classes = captcha.get_parameter()

    x = tf.placeholder(tf.float32, [None, height,width,1])
    y_ = tf.placeholder(tf.float32, [None, char_num*classes])
    keep_prob = tf.placeholder(tf.float32)

    model = captcha_model.captchaModel(width,height,char_num,classes)
    y_conv = model.create_model(x,keep_prob)
    cross_entropy = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y_,logits=y_conv))
    train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

    predict = tf.reshape(y_conv, [-1,char_num, classes])
    real = tf.reshape(y_,[-1,char_num, classes])
    correct_prediction = tf.equal(tf.argmax(predict,2), tf.argmax(real,2))
    correct_prediction = tf.cast(correct_prediction, tf.float32)
    accuracy = tf.reduce_mean(correct_prediction)

    saver = tf.train.Saver()
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        step = 1
        while True:
            batch_x,batch_y = next(captcha.gen_captcha(64))
            _,loss = sess.run([train_step,cross_entropy],feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.75})
            print ('step:%d,loss:%f' % (step,loss))
            if step % 100 == 0:
                batch_x_test,batch_y_test = next(captcha.gen_captcha(100))
                acc = sess.run(accuracy, feed_dict={x: batch_x_test, y_: batch_y_test, keep_prob: 1.})
                print ('###############################################step:%d,accuracy:%f' % (step,acc))
                if acc > 0.99:
                    saver.save(sess,"./capcha_model.ckpt")
                    break
            step += 1

而後執行:ubuntu

cd /home/ubuntu;
python train_captcha.py

執行結果:網絡

step:75193,loss:0.010931
step:75194,loss:0.012859
step:75195,loss:0.008747
step:75196,loss:0.009147
step:75197,loss:0.009351
step:75198,loss:0.009746
step:75199,loss:0.010014
step:75200,loss:0.009024
###############################################step:75200,accuracy:0.992500
View Code

使用訓練好的模型:

做爲實驗,你能夠經過調整  train_captcha.py 文件中  if acc > 0.99: 代碼行的準確度節省訓練時間(好比將 0.99 爲 0.01),體驗訓練過程;咱們已經經過長時間的訓練獲得了一個訓練好的模型,能夠經過以下命令將訓練集下載到本地。
 
wget http://tensorflow-1253902462.cosgz.myqcloud.com/captcha/capcha_model.zip
unzip -o capcha_model.zip

 

識別驗證碼

測試數據集:

咱們在騰訊雲的 COS 上準備了 100 個驗證碼做爲測試集,使用  wget 命令獲取:
wget http://tensorflow-1253902462.cosgz.myqcloud.com/captcha/captcha.zip
unzip -q captcha.zip

而後執行:dom

cd /home/ubuntu;
python predict_captcha.py captcha/0hWn.jpg

執行結果:ide

0hWn
相關文章
相關標籤/搜索