黑科技教你一招如何解除 生活中烦人的验证码问题
前言
驗證碼相信大家都遇到過,不勝其煩的一次次輸入錯誤是不是讓你一度崩潰過,今天就教大家如何用黑科技解決驗證碼的問題。
按照國際慣例,在這里先喂自己袋鹽,可視化(tableau)和畢業設計(matlab)的小伙伴,可訂閱以下博主精心整理的三個專欄。
tableau可視化數據分析高級教程
https://blog.csdn.net/wenyusuran/category_9596753.html
MATLAB深入理解高級教程(附源碼)
https://blog.csdn.net/wenyusuran/category_2239265.html
深度學習100例全系列詳細教程
https://blog.csdn.net/wenyusuran/category_9596890.html
在博主的資源中也有各種算法的應用實例源代碼,需要的小伙伴自取喲。
captcha
captcha 是用 python 寫的生成驗證碼的庫,它支持圖片驗證碼和語音驗證碼,我們使用的是它生成圖片驗證碼的功能。
首先我們設置我們的驗證碼格式為數字加大寫字母,生成一串驗證碼試試看:
數據生成器
訓練模型的時候,我們可以選擇兩種方式來生成我們的訓練數據,一種是一次性生成幾萬張圖,然后開始訓練,一種是定義一個數據生成器,然后利用 fit_generator 函數來訓練。
第一種方式的好處是訓練的時候顯卡利用率高,如果你需要經常調參,可以一次生成,多次使用;第二種方式的好處是你不需要生成大量數據,訓練過程中可以利用 CPU 生成數據,而且還有一個好處是你可以無限生成數據。
我們的數據格式如下:
X
X 的形狀是 (batch_size, height, width, 3),比如一批生成32個樣本,圖片寬度為170,高度為80,那么形狀就是 (32, 80, 170, 3),取第一張圖就是 X[0]。
y
y 的形狀是四個 (batch_size, n_class),如果轉換成 numpy 的格式,則是 (n_len, batch_size, n_class),比如一批生成32個樣本,驗證碼的字符有36種,長度是4位,那么它的形狀就是4個 (32, 36),也可以說是 (4, 32, 36),解碼函數在下個代碼塊。
上面就是一個可以無限生成數據的例子,我們將使用這個生成器來訓練我們的模型。
使用生成器
生成器的使用方法很簡單,只需要用 next 函數即可。下面是一個例子,生成32個數據,然后顯示第一個數據。當然,在這里我們還對生成的 One-Hot 編碼后的數據進行了解碼,首先將它轉為 numpy 數組,然后取36個字符中最大的數字的位置,因為神經網絡會輸出36個字符的概率,然后將概率最大的四個字符的編號轉換為字符串。
構建深度卷積神經網絡
模型結構很簡單,特征提取部分使用的是兩個卷積,一個池化的結構,這個結構是學的 VGG16 的結構。之后我們將它 Flatten,然后添加 Dropout ,盡量避免過擬合問題,最后連接四個分類器,每個分類器是36個神經元,輸出36個字符的概率。
模型可視化
得益于 Keras 自帶的可視化,我們可以使用幾句代碼來可視化模型的結構:
這里需要使用 pydot 這個庫,以及 graphviz 這個庫,在 macOS 系統上安裝方法如下:
brew install graphviz pip install pydot-ng我們可以看到最后一層卷積層輸出的形狀是 (1, 6, 256),已經不能再加卷積層了。
訓練模型
訓練模型反而是所有步驟里面最簡單的一個,直接使用 model.fit_generator 即可,這里的驗證集使用了同樣的生成器,由于數據是通過生成器隨機生成的,所以我們不用考慮數據是否會重復。注意,這段代碼在筆記本上可能要耗費一下午時間。如果你想讓模型預測得更準確,可以將 nb_epoch改為 10 或者 20,但它也將耗費成倍的時間。注意我們這里使用了一個小技巧,添加 nb_worker=2 參數讓 Keras 自動實現多進程生成數據,擺脫 python 單線程效率低的缺點。如果不添加,耗時120秒,添加則只需80秒。
測試模型
當我們訓練完成以后,可以識別一個驗證碼試試看:
計算模型總體準確率
模型在訓練的時候只會顯示第幾個字符的準確率,為了統計模型的總體準確率,我們可以寫下面的函數:
這里用到了一個庫叫做 tqdm,它是一個進度條的庫,為的是能夠實時反饋進度。然后我們通過一些 numpy 計算去統計我們的準確率,這里計算規則是只要有一個錯,那么就不算它對。經過計算,我們的模型的總體準確率在經過五代訓練就可以達到 90%,繼續訓練還可以達到更高的準確率。
模型總結
模型的大小是16MB,在我的筆記本上跑1000張驗證碼需要用20秒,當然,顯卡會更快。對于驗證碼識別的問題來說,哪怕是10%的準確率也已經稱得上破解,畢竟假設100%識別率破解要一個小時,那么10%的識別率也只用十個小時,還算等得起,而我們的識別率有90%,已經可以稱得上完全破解了這類驗證碼。
改進
對于這種按順序書寫的文字,我們還有一種方法可以使用,那就是循環神經網絡來識別序列。下面我們來了解一下如何使用循環神經網絡來識別這類驗證碼。
CTC Loss
這個 loss 是一個特別神奇的 loss,它可以在只知道序列的順序,不知道具體位置的情況下,讓模型收斂。在這方面百度似乎做得很不錯,利用它來識別音頻信號。(warp-ctc)
那么在 Keras 里面,CTC Loss 已經內置了,我們直接定義這樣一個函數,即可實現 CTC Loss,由于我們使用的是循環神經網絡,所以默認丟掉前面兩個輸出,因為它們通常無意義,且會影響模型的輸出。
-
y_pred 是模型的輸出,是按順序輸出的37個字符的概率,因為我們這里用到了循環神經網絡,所以需要一個空白字符的概念;
-
labels 是驗證碼,是四個數字;
-
input_length 表示 y_pred 的長度,我們這里是15;
-
label_length 表示 labels 的長度,我們這里是4。
模型結構
我們的模型結構是這樣設計的,首先通過卷積神經網絡去識別特征,然后經過一個全連接降維,再按水平順序輸入到一種特殊的循環神經網絡,叫 GRU,它具有一些特殊的性質,為什么用 GRU 而不用 LSTM 呢?總的來說就是它的效果比 LSTM 好,所以我們用它。
模型可視化
可視化的代碼同上,這里只貼圖。
可以看到模型比上一個模型復雜了許多,但實際上只是因為輸入比較多,所以它顯得很大。還有一個值得注意的地方,我們的圖片在輸入的時候是經過了旋轉的,這是因為我們希望以水平方向輸入,而圖片在 numpy 里默認是這樣的形狀:(height, width, 3),因此我們使用了 transpose 函數將圖片轉為了(width, height, 3)的格式,然后經過各種卷積和降維,變成了 (17, 32),這里的每個長度為32的向量都代表一個豎條的圖片的特征,從左到右,一共有17條。然后我們兵分兩路,一路從左到右輸入到 GRU,一路從右到左輸入到 GRU,然后將他們輸出的結果加起來。再兵分兩路,還是一路正方向,一路反方向,只不過第二次我們直接將它們的輸出連起來,然后經過一個全連接,輸出每個字符的概率。
數據生成器
評估模型
我們會通過這個函數來評估我們的模型,和上面的評估標準一樣,只有全部正確,我們才算預測正確,中間有個坑,就是模型最開始訓練的時候,并不一定會輸出四個字符,所以我們如果遇到所有的字符都不到四個的時候,就不計算了,相當于加0,遇到多于4個字符的時候,只取前四個。
評估回調
因為 Keras 沒有針對這種輸出計算準確率的選項,因此我們需要自定義一個回調函數,它會在每一代訓練完成的時候計算模型的準確率。
訓練模型
由于 CTC Loss 收斂很慢,所以我們需要設置比較大的代數,這里我們設置了100代,然后添加了一個早期停止的回調和我們上面定義的回調,但是第一次訓練只訓練37代就停了,測試準確率才95%,我又在這個基礎上繼續訓練了一次,停在了25代,得到了98%的準確率,所以一共訓練了62代。
測試模型
這次隨機出來的驗證碼很厲害,是O0OP,不過更厲害的是模型認出來了。
有趣的問題
我又用之前的模型做了個測試,對于 O0O0 這樣喪心病狂的驗證碼,模型偶爾也能正確識別,這讓我非常驚訝,它是真的能識別 O 與 0 的差別呢,還是猜出來的呢?這很難說。
總結
模型的大小是4.7MB,在我的筆記本上跑1000張驗證碼需要用14秒,平均一秒識別71張,估計可以拼過網速。至于深度學習到底能不能識別雙胞胎,相信各位已經有了答案。
喜歡博主的小伙伴,請一鍵三連喲。
總結
以上是生活随笔為你收集整理的黑科技教你一招如何解除 生活中烦人的验证码问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: R语言实战应用精讲50篇(一)-万字长文
- 下一篇: 深度学习核心技术精讲100篇(二十八)-