基于tensorflow2.x卷積神經(jīng)網(wǎng)絡(luò)識別字符型驗(yàn)證碼

??最近入門了下深度學(xué)習(xí),實(shí)戰(zhàn)練手寫了個(gè)定長的字符型驗(yàn)證碼識別模型祠挫。網(wǎng)上對于驗(yàn)證碼這一塊好多都是tf1的案例和解決辦法捶索,tf2的還是比較少,git上的開源項(xiàng)目也大都基于tf1.x问潭。最大的感觸果然還是,紙上得來終覺淺婚被,看書看文檔讀別人的代碼總覺得會了狡忙,自己寫還是遇到了各種各樣的問題,梯度更新的一個(gè)大坑址芯,卡了我兩天多灾茁。。記錄一下踩坑的過程谷炸。
??我這邊調(diào)試開發(fā)過程用的conda環(huán)境北专,對于我這種小白比較友好..tf版本是2.2.0 gpu版本,tensorboard 2.2.2旬陡,python是3.6.8逗余。
??首先是數(shù)據(jù)集的處理,我用的數(shù)據(jù)集是之前搞過的zxgk的驗(yàn)證碼季惩,為4位數(shù)字字母录粱,保存的圖片名字以"標(biāo)簽名_時(shí)間戳.png"命名,在處理時(shí)需要把標(biāo)簽內(nèi)容提取出來画拾,當(dāng)時(shí)搞的后面接時(shí)間戳是為了防止圖片重復(fù)啥繁。數(shù)據(jù)集我這一共差不多6萬張圖,應(yīng)該可以訓(xùn)練出一個(gè)比較滿意的準(zhǔn)確率青抛。

??先讀取旗闽,獲取指定路徑讀取路徑下的所有文件名:
將所有文件路徑隨機(jī)打散,有助于后面訓(xùn)練參數(shù)收斂
為了確定我們的操作沒問題蜜另,我們顯示幾張圖片看一看:
??OK沒問題适室,然后就到了處理圖片和標(biāo)簽了。圖片的預(yù)處理相對這個(gè)案例而言比較簡單举瑰,噪點(diǎn)比較少捣辆,干擾線也不是每張圖片都有,省了降噪的工序此迅。同時(shí)針對驗(yàn)證碼而言汽畴,顏色是無所謂的,保留顏色反而會增加沒有必要的特征耸序,加大訓(xùn)練難度忍些,所以灰度化也是需要做的。定義一個(gè)圖片預(yù)處理的函數(shù):
??這里遇到了第一個(gè)小坑坎怪,卷積層的輸入要求是四維罢坝,單純的做歸一化處理以后,圖片會是一個(gè)三維的(比如[128,70,160]搅窿,第一個(gè)代表的是圖片的數(shù)量嘁酿,第二和第三個(gè)分別是圖片的高和寬)疾棵。卷積層本身也不是一個(gè)平面,而是有厚度這一概念的痹仙,正常來講第四個(gè)維度也就是深度應(yīng)該是rgb三原色是尔,這里我們在輸入到模型的時(shí)候需要給他擴(kuò)充一個(gè)維度。

這樣就完成了圖片的預(yù)處理开仰,然后是標(biāo)簽拟枚。我是把標(biāo)簽處理成一個(gè)標(biāo)簽長度*字符數(shù)量的張量,也就是每一行都是一個(gè)ont-hot众弓,這里就是shape為4×36的張量恩溅。
測試一下輸出:
??字符集的順序是不能變的,預(yù)測的時(shí)候需要用到谓娃。
??圖片和標(biāo)簽預(yù)處理都做完之后脚乡,就可以建立數(shù)據(jù)集了。我選擇的是使用tf.Dataset滨达,從指定文件路徑下創(chuàng)建數(shù)據(jù)管道奶稠。封裝成一個(gè)類的形式:
??上面的都是讀取打亂操作,然后我按9:1對數(shù)據(jù)集進(jìn)行分割捡遍,對打亂后的前90%做訓(xùn)練集锌订,后10%做測試集。

??這樣調(diào)用build方法我們就可以同時(shí)拿到訓(xùn)練集和驗(yàn)證集啦画株。
??接下來建立模型辆飘,模型選的是4層卷積+2層全連接層的結(jié)構(gòu)。自定義模型谓传,繼承自tensorflow.keras.Model蜈项。
??卷積核還是用的比較常用的3×3,每一層卷積后面緊跟一層BN和一層最大池化層续挟。做了四層卷積以后紧卒,將張量打平,輸入到兩個(gè)全連接層庸推,每一個(gè)全連接層后接上50%的dropout常侦,防止過擬合浇冰。最后將張量reshape成字符長度×字符集長度贬媒,和前面標(biāo)簽的處理結(jié)果對應(yīng)。輸出之后使用softmax激活肘习,做四元分類际乘。
??.call方法拿到模型實(shí)例。輸出模型概覽:
??在編寫訓(xùn)練過程前漂佩,我們需要考慮訓(xùn)練的方式及各類指標(biāo)脖含。很明確的一點(diǎn)罪塔,這里訓(xùn)練評估一定是要自己編寫的,傳統(tǒng)的acc主要是針對單分類养葵。我想在指標(biāo)中輸出字符的準(zhǔn)確率和圖片的準(zhǔn)確率(圖片準(zhǔn)確率是指一張驗(yàn)證碼圖片所有字符都正確的概率)征堪,那么就需要編寫兩個(gè)自定義評估器,首先是字符準(zhǔn)確率:
將傳入的正確標(biāo)簽和預(yù)測標(biāo)簽逐個(gè)對比关拒,統(tǒng)計(jì)相同的數(shù)量佃蚜,算出比值就可以了。
??這兩個(gè)比較類似着绊,區(qū)別就在于圖片準(zhǔn)確率是四個(gè)一組的對比谐算,一個(gè)錯(cuò)全錯(cuò),字符是逐個(gè)對比归露,對一個(gè)算一個(gè)洲脂。loss和優(yōu)化器就沒有必要自己寫了,需求也不是那么復(fù)雜剧包。
??這里loss我選擇的交叉熵恐锦,交叉熵也是常用于多分類問題的loss函數(shù)。優(yōu)化器是老大哥Adam疆液,學(xué)習(xí)率后面可能需要讓他隨訓(xùn)練次數(shù)的增加而減小踩蔚,在剛開始訓(xùn)練時(shí),學(xué)習(xí)率大一些枚粘,讓loss收斂快一些馅闽,訓(xùn)練達(dá)到一定次數(shù)時(shí)降低學(xué)習(xí)率,防止過擬合馍迄。

??接下來的過程福也,可能就不太穩(wěn)了,我們保守點(diǎn)攀圈,先寫個(gè)簡單的訓(xùn)練函數(shù)暴凑,方便調(diào)試,讓他跑起來看看有沒有問題赘来。為了保持訓(xùn)練的靈活度现喳,這里沒有用fit訓(xùn)練,需要編寫梯度更新過程的代碼犬辰。
??先初始化相關(guān)參數(shù):

??然后自定義訓(xùn)練循環(huán):
??訓(xùn)練10個(gè)epoch嗦篱,每訓(xùn)練一次就更新梯度,每訓(xùn)練20次輸出一次幌缝,先跑起來看看效果:
??觀察loss值是在不斷下降灸促,代表我們優(yōu)化的方向沒問題。
??接下來需要加入測試集、tensorboard的支持浴栽,以及對一些配置字段的提取荒叼。這時(shí)我們可以把代碼挪到Pycharm里封裝一下了。
??前面model和dataset的地方不用變典鸡,先寫一個(gè)測試的邏輯被廓,很簡單,傳入一個(gè)step的數(shù)據(jù)萝玷,預(yù)測并計(jì)算loss與準(zhǔn)確率伊者,這里不需要計(jì)算梯度。同時(shí)在傳入特征時(shí)间护,需要設(shè)置training為False亦渗,否則會影響到BN層與Dropout層的權(quán)重更新。
??然后編寫提前終止訓(xùn)練的代碼汁尺,這里計(jì)算了兩個(gè)條件法精。第一個(gè)條件是傳入的loss差值(第二個(gè)loss與第一個(gè)loss的差),連續(xù)10輪保持在0.001以內(nèi)時(shí)痴突,代表loss已經(jīng)趨于穩(wěn)定不再更新搂蜓,那么就保存模型結(jié)束訓(xùn)練。第二個(gè)條件是辽装,訓(xùn)練時(shí)記錄10輪以內(nèi)最低的loss值帮碰,并保存對應(yīng)權(quán)重。如果loss在10輪內(nèi)沒有降低拾积,就將保存的權(quán)重恢復(fù)到模型中并結(jié)束訓(xùn)練殉挽。其實(shí)這兩個(gè)條件對于訓(xùn)練驗(yàn)證碼識別這種簡單的問題都不見得會觸發(fā)。拓巧。不過有還是要有的斯碌。

然后在訓(xùn)練的地方添加上。另外再加一個(gè)肛度,訓(xùn)練集準(zhǔn)確率達(dá)到99%就結(jié)束訓(xùn)練:
最后再加入一個(gè)寫入tensorboard日志的函數(shù):
這樣在每次輸出時(shí)都會記錄訓(xùn)練集及測試集的loss及準(zhǔn)確率傻唾。
??完成之后的訓(xùn)練過程:
??完成以上步驟扔茅,我們再次跑起來:
??兩三分鐘就跑完退出了哩罪!看看tensorboard中的曲線怎么樣:
??訓(xùn)練集的字符準(zhǔn)確率與圖片準(zhǔn)確率曲線:
??訓(xùn)練集loss:
測試集的準(zhǔn)確率與loss:

??看起來還不錯(cuò),最后寫個(gè)預(yù)測類的代碼就結(jié)束了:
去網(wǎng)站上重新下一張圖片:


??還可以绸贡。結(jié)束睡覺加袋。
??完整代碼的話凛辣,我已經(jīng)放在github上了,之后隨著學(xué)習(xí)的深入锁荔,我也會慢慢優(yōu)化代碼蟀给。隨后有空的話會補(bǔ)上個(gè)簡單的文檔蝙砌。
??代碼地址:https://github.com/startzm/captcha_cnn

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阳堕,一起剝皮案震驚了整個(gè)濱河市跋理,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恬总,老刑警劉巖前普,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異壹堰,居然都是意外死亡拭卿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門贱纠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來峻厚,“玉大人,你說我怎么就攤上這事谆焊』萏遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵辖试,是天一觀的道長辜王。 經(jīng)常有香客問我,道長罐孝,這世上最難降的妖魔是什么呐馆? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮莲兢,結(jié)果婚禮上汹来,老公的妹妹穿的比我還像新娘。我一直安慰自己改艇,他們只是感情好俗慈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遣耍,像睡著了一般闺阱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舵变,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天酣溃,我揣著相機(jī)與錄音,去河邊找鬼纪隙。 笑死赊豌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绵咱。 我是一名探鬼主播碘饼,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了艾恼?” 一聲冷哼從身側(cè)響起住涉,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钠绍,沒想到半個(gè)月后舆声,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柳爽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年媳握,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磷脯。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛾找,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赵誓,到底是詐尸還是另有隱情打毛,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布架曹,位于F島的核電站隘冲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏绑雄。R本人自食惡果不足惜展辞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望万牺。 院中可真熱鬧罗珍,春花似錦、人聲如沸脚粟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽核无。三九已至扣唱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間团南,已是汗流浹背噪沙。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吐根,地道東北人正歼。 一個(gè)月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像拷橘,于是被迫代替她去往敵國和親局义。 傳聞我的和親對象是個(gè)殘疾皇子喜爷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容