Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

專案簡介

在之前的文章

keras入門(三)搭建CNN模型破解網站驗證碼

中,筆者介紹介紹瞭如何用Keras來搭建CNN模型來破解網站的驗證碼,其中驗證碼含有字母和數字。

讓我們一起回顧一下

keras入門(三)搭建CNN模型破解網站驗證碼

的處理思路:

利用OpenCV對影象進行單個字元的切割,大概400多張圖片;

對切割好的單個字元進行人工手動標記;

搭建合適的CNN模型,對標記好的資料集進行訓練;

對於新的驗證碼,先切割單個字元,再對單個字元進行預測,組成總的預測結果。

這一次,筆者將會換種思路,使用CNN模型來破解網站的驗證碼。我們的資料集如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

驗證碼資料集

一共是946張圖片,這裡只展示了一部分,可以看到,這些驗證碼全部由數字組成。那麼,新的破解驗證碼的思路是什麼呢?如下:

直接對驗證碼進行標記,標記的結果見上圖;

搭建合適的CNN模型對標記好的資料集進行訓練;

對新驗證碼進行預測。

這種思路的好處是,不需要對驗證碼進行繁瑣的預處理,只需要簡單的資料標記即可。

下面,筆者將會具體展示這個過程。

資料標記

資料標記絕對是個累活,當我想到要對946張圖片進行標記並重命名,而且還要保證標記的準確性的時候,我開始是有點拒絕的心態,畢竟這項工作費時費力,而且能不能保證識別的效果還是個未知數。

就這麼糾結了一段時間,原本年前就想做的專案一直拖到了現在,後來我想,能不能寫個指令碼,能夠幫助我快速地進行資料標註,並自動儲存呢?這麼想著,我就動手自己做了一個由Tornado實現的前端頁面,可以幫助我快速地標記資料並儲存圖片,頁面如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

資料標註介面

介面雖然簡陋,卻能幫助我很好地提升資料標記的速度,只需要在value文字框中輸入自己識別的結果,程式就能自動儲存標記好的圖片,並切換至下一張未標記的驗證碼。有了如此好的工具,結果我用了不到一小時就標記完了這946張驗證碼(其實是1000張,因為標記好的結果會有重複)。有機會筆者會介紹這個驗證碼標記的專案~

模型訓練

標記完驗證碼後,我們就利用這946張驗證碼作為訓練資料,訓練CNN模型。我們使用Keras框架,CNN模型的結構圖如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

模型結構圖

模型訓練的Python程式碼如下:

# CNN模型訓練# -*- coding: utf-8 -*-import cv2import osimport randomimport numpy as npfrom keras。models import *from keras。layers import *from keras import callbackscharacters = ‘0123456789’width, height, n_len, n_class = 50, 22, 4, 10# 產生訓練的一批圖片,預設是32張圖片def gen(dir, batch_size=32):    X = np。zeros((batch_size, height, width, 3), dtype=np。uint8)    y = [np。zeros((batch_size, n_class), dtype=np。uint8) for _ in range(n_len)]    files = os。listdir(dir)    while True:        for i in range(batch_size):            path = random。choice(files)            imagePixel = cv2。imread(dir+‘/’+path, 1)            filename = path[:4]            X[i] = imagePixel            for j, ch in enumerate(filename):                y[j][i, :] = 0                y[j][i, characters。find(ch)] = 1        yield X, yinput_tensor = Input((height, width, 3))x = input_tensor# 產生有四個block的卷積神經網路for i in range(4):    # 卷積層    x = Conv2D(32 * 2 ** i, (3, 3), activation=‘relu’, padding=‘same’)(x)    x = Conv2D(32 * 2 ** i, (3, 3), activation=‘relu’, padding=‘same’)(x)    # 池化層    x = MaxPooling2D((2, 2))(x)x = Flatten()(x)x = Dropout(0。25)(x)# 多輸出模型,使用了4個‘softmax’來分別預測4個字母的輸出x = [Dense(n_class, activation=‘softmax’, name=‘c%d’ % (i + 1))(x) for i in range(4)]model = Model(inputs=input_tensor, outputs=x)model。summary()# 儲存模型結構圖from keras。utils。vis_utils import plot_modelplot_model(model, to_file=“。/model。png”, show_shapes=True)model。compile(loss=‘categorical_crossentropy’,              optimizer=‘adadelta’,              metrics=[‘accuracy’])# 儲存效果最好的模型cbks = [callbacks。ModelCheckpoint(“best_model。h5”, save_best_only=True)]dir = ‘。/result’history = model。fit_generator(gen(dir, batch_size=8),      # 每次生成器會產生8張小批次的圖片                    steps_per_epoch=120,    # 每次的epoch要訓練120批圖片                    epochs=50,                # 總共訓練50次                    callbacks=cbks,          # 儲存最好的模型                    validation_data=gen(dir),   # 驗證資料也是用生成器來產生                    validation_steps=10      # 用10組圖片來進行驗證                   )# 繪製損失值影象import matplotlib。pyplot as pltdef plot_train_history(history, train_metrics, val_metrics):    plt。plot(history。history。get(train_metrics), ‘-o’)    plt。plot(history。history。get(val_metrics), ‘-o’)    plt。ylabel(train_metrics)    plt。xlabel(‘Epochs’)    plt。legend([‘train’, ‘validation’])# 列印整體的loss與val_loss,並儲存圖片plot_train_history(history, ‘loss’, ‘val_loss’)plt。savefig(‘。/all_loss。png’)plt。figure(figsize=(12, 4))# 第一個數字的正確率plt。subplot(2, 2, 1)plot_train_history(history, ‘c1_acc’, ‘val_c1_acc’)# 第二個數字的正確率plt。subplot(2, 2, 2)plot_train_history(history, ‘c2_acc’, ‘val_c2_acc’)# 第三個數字的正確率plt。subplot(2, 2, 3)plot_train_history(history, ‘c3_acc’, ‘val_c3_acc’)# 第四個數字的正確率plt。subplot(2, 2, 4)plot_train_history(history, ‘c4_acc’, ‘val_c4_acc’)# 儲存圖片plt。savefig(‘。/train。png’)

在這個程式碼中,我們總共訓練了50個epoch,每個epoch共120次批次,每個批次是8張驗證碼,每張驗證碼的大小為50*22。

執行該訓練模型,後幾個epoch的輸出結果如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

總的損失值影象如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

總的損失值影象

四個數字每個數字的損失值影象如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

四個數字每個數字的損失值影象

訓練完後,程式會將訓練效果最好的epoch儲存為best_model。h5檔案,便於後續的模型預測。由輸出的結果及影象來看,該CNN模型的訓練效果應該是相當好的,下面,我們來看看對新驗證碼的預測效果。

模型預測

新的驗證碼共有20張,如下:

Keras入門(四)之利用CNN模型輕鬆破解網站驗證碼

新的驗證碼

模型預測的Python程式碼如下:

# 使用訓練好的CNN模型對新圖片進行預測# -*- coding: utf-8 -*-from keras。models import load_modelimport cv2import numpy as np# 匯入訓練好的模型model = load_model(‘best_model。h5’)batch_size = 20width, height, n_len, n_class = 50, 22, 4, 10# 匯入驗證碼資料並進行預測X = np。zeros((batch_size, height, width, 3), dtype=np。uint8)for i in range(batch_size):    X_test = cv2。imread(‘。/new_image/code%d。png’ %(i+1), 1)    X[i] = X_testy_pred = model。predict(X)y_pred = np。argmax(y_pred, axis=2)# 輸出每張驗證碼的預測結果for i in range(batch_size):    print(‘第%d張驗證碼的識別結果為:’ %(i+1), end=‘’)    print(‘’。join(map(str, y_pred[:, i]。tolist())))

執行該模型,得到的輸出結果如下:

第1張驗證碼的識別結果為:3568第2張驗證碼的識別結果為:5402第3張驗證碼的識別結果為:6051第4張驗證碼的識別結果為:6769第5張驗證碼的識別結果為:2675第6張驗證碼的識別結果為:2450第7張驗證碼的識別結果為:2364第8張驗證碼的識別結果為:6879第9張驗證碼的識別結果為:3702第10張驗證碼的識別結果為:3459第11張驗證碼的識別結果為:5895第12張驗證碼的識別結果為:8042第13張驗證碼的識別結果為:6897第14張驗證碼的識別結果為:6558第15張驗證碼的識別結果為:9428第16張驗證碼的識別結果為:5662第17張驗證碼的識別結果為:5431第18張驗證碼的識別結果為:4981第19張驗證碼的識別結果為:0567第20張驗證碼的識別結果為:5239

對這20張新的驗證碼,預測完全正確!不得不說,CNN模型的識別效果非常好!

總結

本文采用了一種新的思路,搭建CNN模型來實現驗證碼的識別,取得了不錯的識別效果,而且識別的驗證碼是從網頁中下載下來的,具有實際背景,增強了該專案的應用性。

本專案已放至Github,地址為:https://github。com/percent4/CAPTCHA-Recognizition 。

注意:本人現已開通微信公眾號: NLP奇幻之旅(微訊號為:easy_web_scrape), 歡迎大家關注哦~~