前言
背景
最近在看深度學習相關知識,正好手上一個爬蟲外包有個需求:爬取 學庫bao的全站數據。官方傳言題目有一千多萬道,其中每道題要查看答案和解析,都需要識別驗證碼(數字+字母,四個字符)。一般的,打碼平臺一塊錢可以識別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
模塊生成的驗證碼做訓練,敢情他們是找不到訓練樣本呀。
然而我的任務是識別學庫bao的驗證碼,就算不能收集這麼多的驗證碼,也要試一試。採集驗證碼的流程是下載驗證碼 —> 打碼平臺打碼 —> 返回給學庫bao判別正誤
。有些博客說人工識別並標註驗證碼,有些原始,我用的是雲打碼,採集了7000張驗證碼,費用還不到40元,何苦爲難自己。另外,打碼平臺識別的結果並不一定百分百正確,必須返回給原網站,根據反饋判斷識別正誤。
採集驗證碼圖片的代碼:crawl_captcha.py,如果要採集其他網站的驗證碼,稍加修改即可。
(圖片可以自行跑上面的代碼採集,我將我採集到的放在雲盤了,可以拿來直接用,鏈接: https://pan.baidu.com/s/18i2xoGth8INChhCWfROZpw 密碼: vrew 。如果百度網盤失效就用新浪微盤:http://vdisk.weibo.com/lc/3AO6EQDinZjxwfeVbuZ 密碼:L70M)
訓練和測試
模型的訓練和測試,這個沒什麼好說的,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 ''
結語
92.4%的識別率,這已經算比較高了,畢竟訓練樣本才這麼些。而且識別率跟噪聲有關,這個網站有些驗證碼的噪聲線條,已經讓字符完全無法識別了。所以識別率提高到一定程度就很難再提高了。
一年多沒寫文章了,有點生疏。本文借鑑captcha
驗證碼的識別案例,記錄識別學庫bao驗證碼的過程,目的是總結和分享,學藝不精,純屬搗鼓,錯誤之處各位多批評指出。