1. 程式人生 > >[TensorFlow深度學習深入]實戰二·使用CNN網路識別破解數字驗證碼

[TensorFlow深度學習深入]實戰二·使用CNN網路識別破解數字驗證碼

[TensorFlow深度學習深入]實戰二·使用CNN網路識別破解數字驗證碼

參考部落格
在此基礎上做了小修改。
其中CNN網路部分仿照我們入門實戰六的內容,如果不太清楚CNN可以再去回顧一下。
本博文資料集

程式碼部分

import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

import tensorflow as tf
import numpy as np
from PIL import Image
import os
import random
import time
 
#驗證碼圖片的存放路徑
CAPTCHA_IMAGE_PATH =
'./1CNN/Number_app/datas/train/' #驗證碼圖片的寬度 CAPTCHA_IMAGE_WIDHT = 160 #驗證碼圖片的高度 CAPTCHA_IMAGE_HEIGHT = 60 CHAR_SET_LEN = 10 CAPTCHA_LEN = 4 #60%的驗證碼圖片放入訓練集中 TRAIN_IMAGE_PERCENT = 0.8 #訓練集,用於訓練的驗證碼圖片的檔名 TRAINING_IMAGE_NAME = [] #驗證集,用於模型驗證的驗證碼圖片的檔名 VALIDATION_IMAGE_NAME = [] #存放訓練好的模型的路徑 MODEL_SAVE_PATH =
'./1CNN/Number_app/models/' def get_image_file_name(imgPath=CAPTCHA_IMAGE_PATH): fileName = [] for filePath in os.listdir(imgPath): captcha_name = filePath.split('/')[-1] fileName.append(captcha_name) return fileName #將驗證碼轉換為訓練時用的標籤向量,維數是 40 #例如,如果驗證碼是 ‘0296’ ,則對應的標籤是 # [1 0 0 0 0 0 0 0 0 0
# 0 0 1 0 0 0 0 0 0 0 # 0 0 0 0 0 0 0 0 0 1 # 0 0 0 0 0 0 1 0 0 0] def name2label(name): label = np.zeros(CAPTCHA_LEN * CHAR_SET_LEN) for i, c in enumerate(name): idx = i*CHAR_SET_LEN + ord(c) - ord('0') label[idx] = 1 return label #取得驗證碼圖片的資料以及它的標籤 def get_datas_and_labels(fileName, filePath=CAPTCHA_IMAGE_PATH): train_images = [] train_labels= [] for e in fileName: pathName = os.path.join(CAPTCHA_IMAGE_PATH, e) img = Image.open(pathName) #轉為灰度圖 img = img.convert("L") image_array = np.array(img) image_data = image_array/255 image_label = name2label(e[0:CAPTCHA_LEN]) #image_label = image_label.reshape(-1,10) train_images.append(image_data) train_labels.append(image_label) train_images = np.array(train_images) train_labels = np.array(train_labels) return train_images, train_labels x = tf.placeholder("float", shape=[None,60,160],name="x") #訓練標籤資料 y_ = tf.placeholder("float", shape=[None, 40],name="y_") x_image = tf.reshape(x, [-1,60,160,1]) conv1_weights = tf.get_variable("conv1_weights", [5, 5, 1, 16], initializer=tf.truncated_normal_initializer(stddev=0.1)) #過濾器大小為5*5, 當前層深度為1, 過濾器的深度為32 conv1_biases = tf.get_variable("conv1_biases", [16], initializer=tf.constant_initializer(0.0)) conv1 = tf.nn.conv2d(x_image, conv1_weights, strides=[1, 1, 1, 1], padding='SAME') #移動步長為1, 使用全0填充 relu1 = tf.nn.relu( tf.nn.bias_add(conv1, conv1_biases) ) #啟用函式Relu去線性化 #第二層:最大池化層 #池化層過濾器的大小為2*2, 移動步長為2,使用全0填充 pool1 = tf.nn.max_pool(relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') #第三層:卷積層 conv2_weights = tf.get_variable("conv2_weights", [5, 5, 16, 32], initializer=tf.truncated_normal_initializer(stddev=0.1)) #過濾器大小為5*5, 當前層深度為32, 過濾器的深度為64 conv2_biases = tf.get_variable("conv2_biases", [32], initializer=tf.constant_initializer(0.0)) conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME') #移動步長為1, 使用全0填充 relu2 = tf.nn.relu( tf.nn.bias_add(conv2, conv2_biases) ) #第四層:最大池化層 #池化層過濾器的大小為2*2, 移動步長為2,使用全0填充 pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') #第五層:卷積層 conv3_weights = tf.get_variable("conv3_weights", [5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=0.1)) #過濾器大小為5*5, 當前層深度為32, 過濾器的深度為64 conv3_biases = tf.get_variable("conv3_biases", [64], initializer=tf.constant_initializer(0.0)) conv3 = tf.nn.conv2d(pool2, conv3_weights, strides=[1, 1, 1, 1], padding='SAME') #移動步長為1, 使用全0填充 relu3 = tf.nn.relu(tf.nn.bias_add(conv3, conv3_biases) ) #第六層:最大池化層 #池化層過濾器的大小為2*2, 移動步長為2,使用全0填充 pool3 = tf.nn.max_pool(relu3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') #第七層:全連線層 fc1_weights = tf.get_variable("fc1_weights", [8 * 20 * 64, 1024], initializer=tf.truncated_normal_initializer(stddev=0.1)) #7*7*64=3136把前一層的輸出變成特徵向量 fc1_baises = tf.get_variable("fc1_baises", [1024], initializer=tf.constant_initializer(0.1)) pool3_vector = tf.reshape(pool3, [-1, 8 * 20 * 64]) fc1 = tf.nn.relu(tf.matmul(pool3_vector, fc1_weights) + fc1_baises) #為了減少過擬合,加入Dropout層 keep_prob = tf.placeholder(tf.float32,name="keep_prob") fc1_dropout = tf.nn.dropout(fc1, keep_prob) #第八層:全連線層 fc2_weights = tf.get_variable("fc2_weights", [1024, 40], initializer=tf.truncated_normal_initializer(stddev=0.1)) #神經元節點數1024, 分類節點10 fc2_biases = tf.get_variable("fc2_biases", [40], initializer=tf.constant_initializer(0.1)) fc2 = (tf.matmul(fc1_dropout, fc2_weights) + fc2_biases) loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y_, logits=fc2)) predict = tf.reshape(fc2, [-1, CAPTCHA_LEN, CHAR_SET_LEN], name='predict') labels = tf.reshape(y_, [-1, CAPTCHA_LEN, CHAR_SET_LEN], name='labels') #預測結果 #請注意 predict_max_idx 的 name,在測試model時會用到它 predict_max_idx = tf.argmax(predict, axis=2, name='predict_max_idx') labels_max_idx = tf.argmax(labels, axis=2, name='labels_max_idx') predict_correct_vec = tf.equal(predict_max_idx, labels_max_idx) accuracy = tf.reduce_mean(tf.cast(predict_correct_vec, tf.float32)) #第七層:輸出層 train_step = tf.train.AdamOptimizer(0.002).minimize(loss) if __name__ == '__main__': image_filename_list = get_image_file_name(CAPTCHA_IMAGE_PATH) np.random.shuffle(image_filename_list)#window 平臺這條語句一定不能少。。 lens = len(image_filename_list) seq = 0.8 lens1 = int(seq*lens) train_filename_list = image_filename_list[:lens1] test_filename_list = image_filename_list[lens1:] print(lens,lens1) train_images, train_labels = get_datas_and_labels(fileName=train_filename_list) print(train_filename_list[0],train_images.shape, np.argmax(train_labels[0,:10]),np.argmax(train_labels[0,10:20]),np.argmax(train_labels[0,20:30]),np.argmax(train_labels[0,30:])) with tf.Session() as sess: #開始訓練 srun = sess.run srun(tf.global_variables_initializer()) saver = tf.train.Saver() for i in range(3001): start_step = i*100 % 7960 stop_step = start_step+100 batch_x, batch_y = train_images[start_step:stop_step], train_labels[start_step:stop_step] srun(train_step,feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.8}) #訓練階段使用80%的Dropout if i%10 == 0: loss_val = srun(loss,{x: batch_x, y_: batch_y, keep_prob: 1.0}) acc_val = sess.run(accuracy, feed_dict={x:train_images[:200], y_: train_labels[:200], keep_prob:1.0}) print(i,loss_val,acc_val) if acc_val > 0.6: saver.save(sess, MODEL_SAVE_PATH+"crack_captcha.model", global_step=i)

執行結果

0 7.2514677 0.0975
10 0.3490238 0.09375
20 0.32853785 0.11125
30 0.3260678 0.0975
...
150 0.32142633 0.14
160 0.3182468 0.145
170 0.30834803 0.24
180 0.2962727 0.3125
190 0.29101092 0.33
200 0.2805277 0.3525
210 0.26561457 0.385
220 0.2575577 0.40375
230 0.24210992 0.43375
240 0.23269977 0.47625
250 0.22842664 0.4925
260 0.21917553 0.5425
270 0.22002003 0.52875
280 0.20558219 0.54375
290 0.21356806 0.54125
300 0.2039287 0.56
310 0.20335045 0.55625
320 0.19401187 0.5975
330 0.19049801 0.65625
...
1480 0.0026436544 0.9925
1490 0.0020101557 0.99375
...
1680 0.0016069501 1.0
1690 0.0010696264 0.99875
1700 0.0016226814 0.99125
1710 0.0021925105 0.99375
1720 0.0012222779 0.99875

結果分析
在訓練1000步後,訓練集200組資料的準確率到達99%,表明此網路結構的優異性,可以在此基礎上做數字驗證碼的破解工作。