CNN識別學庫寶的驗證碼
前言
背景
- 最近在看深度學習相關知識,正好手上一個爬蟲外包有個需求:爬取 學庫寶 的全站數據。官方傳言題目有一千多萬道,其中每道題要查看答案和解析,都需要識別驗證碼(數字+字母,四個字元)。一般的,打碼平台一塊錢可以識別200張,算下來得要5萬的打碼費用,還沒算失敗率。
圖片示例
參考
- 本文參考了《CNN破解簡單驗證碼(Tensorflow實現)》。網上一搜」驗證碼 CNN」,大部分都是類似的文章,用captcha模塊生成驗證碼進行訓練、識別,甚至代碼都是一樣的,真沒意思。後來發現51CTO視頻課程里也有講這個案例,我把它上傳到雲盤了(鏈接: https://pan.baidu.com/s/1iuMfSlWyTm8SbxHYeDoBSQ 密碼: shjm),感覺視頻里的講解比其他博客詳細多了。
代碼
- GitHub地址:cnn_on_captcha、captcha_identify。
正確率
- 訓練樣本6500,測試樣本500,識別率達92.4%。
以往的,識別驗證碼的流程一般是先去噪,再切割,然後用最近鄰去分類識別。但是去噪和切割這兩個步驟,經常都不那麼好做。而CNN不需要去噪和切割,直接整張驗證碼拿去訓練和識別。不用做針對性的去噪和切割,可以省去很大工作量。
正文
採集樣本
CNN識別驗證碼有優點也有不足,它其中的一個缺陷就是需要更多的樣本做訓練。文章《識彆扭曲干擾性驗證碼》中提到94%的識別率需要400W張圖片,不知真假,但確實嚇人。
難怪網上一搜」CNN 驗證碼識別」,出來的全都是用captcha模塊生成的驗證碼做訓練,敢情他們是找不到訓練樣本呀。
然而我的任務是識別學庫寶的驗證碼,就算不能收集這麼多的驗證碼,也要試一試。採集驗證碼的流程是下載驗證碼 —> 打碼平台打碼 —> 返回給學庫寶判別正誤。有些博客說人工識別並標註驗證碼,有些原始,我用的是雲打碼,採集了7000張驗證碼,費用還不到40元,何苦為難自己。另外,打碼平台識別的結果並不一定百分百正確,必須返回給原網站,根據反饋判斷識別正誤。
採集驗證碼圖片的代碼:crawl_captcha.py,如果要採集其他網站的驗證碼,稍加修改即可。
(圖片可以自行跑上面的代碼採集,我將我採集到的放在雲盤了,可以拿來直接用,鏈接
訓練和測試
模型的訓練和測試,這個沒什麼好說的,CSDN上一搜,千篇一律。我這裡只是將圖片源換成了本地採集好的驗證碼,代碼中調一下圖片大小。
嘗試和改進
嗯,好玩的在這裡。無知的初學者,瞎搗鼓系列。
(注意,要先把訓練樣本和測試樣本(captchas文件夾和test文件夾)放到項目目錄。除了captcha01,其他都要先運行crop_captcha.py將圖片切割成單字元,再進行訓練。)
初版本
- 代碼:captcha01 。
- 最初,6500張圖片,不做任何處理,每次隨機抽取64張,訓練2W批次。耗時80分鐘,
準確率3.4%
,低的可憐,不忍直視。 切割
- 代碼:captcha02 。
- 看來這點數據量,基本上是沒法直接訓練了。網路模型還沒能學習到驗證碼的特徵,那我們就清除一些無用的雜質和邊緣,將更清楚、更精準的樣本餵給它。去噪我是不想做的,但切割還是比較容易的,把四個字元單獨切割出來,把不必要的圖片邊緣清除掉。這樣可以很大程度地降低模型學習的壓力,而且樣本量也變成原來的四倍了。
- 切割以後總共2.6萬張圖,訓練2W批次,耗時23分鐘,
準確率82.2%
(四個字元同時正確)。這準確率立馬上來了,基本上可以拿來用了。 - (註:因打碼平台經常將大小寫忽略,故訓練的時候將全部大寫字母作小寫看待。)
除去pooling層
- 代碼:captcha03 。
- 切割後的圖片大小為6*18,字元已經精細到1個像素上去了,已經不能再縮減了。而pooling層很重要的一個作用就是在保留主要特徵的同時降低參數(緯度)和計算量,此時這個作用並不大,所以可以考慮把pooling層去掉。
- 訓練2W批次,耗時37分鐘,
準確率89.2%
。 新增一層網路
- 代碼:captcha04 。
- 驗證碼的識別,一般的選擇三層卷積就已經有比較好的效果,但我還是好奇四層卷積,識別率將會升降多少。
- 訓練2W批次,耗時44分鐘,
準確率91.2%
。
- 訓練6W批次,耗時135分鐘,
準確率91.6%
。 將第三層的厚度64變成128
- 代碼:captcha05 。
- 訓練2W批次,耗時53分鐘,
準確率88.8%
。 - 訓練6W批次,耗時207分鐘,
準確率92.4%
。
開啟驗證碼識別服務
好了,模型已經訓練好了。接下來就是使用了。我使用了Django開了一個服務,需要識別驗證碼的時候只需將驗證碼post過去就能返回識別結果了。代碼:captcha_identify 。
啟動命令:python manage.py runserver 127.0.0.1:8000
在爬蟲中,只需要調用下面的方法即可。
def identify(filename):
try:
r = requests.post("http://127.0.0.1:8000/captcha_identify/", files={"image": (filename, open(filename, "rb"), "image/png")})
return r.content
except Exception as e:
return ""
1
2
3
4
5
6
結語
92.4%的識別率,這已經算比較高了,畢竟訓練樣本才這麼些。而且識別率跟雜訊有關,這個網站有些驗證碼的雜訊線條,已經讓字元完全無法識別了。所以識別率提高到一定程度就很難再提高了。
本文借鑒captcha驗證碼的識別案例,記錄識別學庫寶驗證碼的過程,目的是總結和分享,學藝不精,純屬搗鼓,錯誤之處各位多批評指出。
TAG:程序員小新人學習 |