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









??圖片和標(biāo)簽預(yù)處理都做完之后,就可以建立數(shù)據(jù)集了。我選擇的是使用tf.Dataset,從指定文件路徑下創(chuàng)建數(shù)據(jù)管道。封裝成一個(gè)類(lèi)的形式:


??這樣調(diào)用build方法我們就可以同時(shí)拿到訓(xùn)練集和驗(yàn)證集啦。
??接下來(lái)建立模型,模型選的是4層卷積+2層全連接層的結(jié)構(gòu)。自定義模型,繼承自tensorflow.keras.Model。





??這里loss我選擇的交叉熵,交叉熵也是常用于多分類(lèi)問(wèn)題的loss函數(shù)。優(yōu)化器是老大哥Adam,學(xué)習(xí)率后面可能需要讓他隨訓(xùn)練次數(shù)的增加而減小,在剛開(kāi)始訓(xùn)練時(shí),學(xué)習(xí)率大一些,讓loss收斂快一些,訓(xùn)練達(dá)到一定次數(shù)時(shí)降低學(xué)習(xí)率,防止過(guò)擬合。

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

??然后自定義訓(xùn)練循環(huán):



??接下來(lái)需要加入測(cè)試集、tensorboard的支持,以及對(duì)一些配置字段的提取。這時(shí)我們可以把代碼挪到Pycharm里封裝一下了。
??前面model和dataset的地方不用變,先寫(xiě)一個(gè)測(cè)試的邏輯,很簡(jiǎn)單,傳入一個(gè)step的數(shù)據(jù),預(yù)測(cè)并計(jì)算loss與準(zhǔn)確率,這里不需要計(jì)算梯度。同時(shí)在傳入特征時(shí),需要設(shè)置training為False,否則會(huì)影響到BN層與Dropout層的權(quán)重更新。


然后在訓(xùn)練的地方添加上。另外再加一個(gè),訓(xùn)練集準(zhǔn)確率達(dá)到99%就結(jié)束訓(xùn)練:


??完成之后的訓(xùn)練過(guò)程:



??訓(xùn)練集的字符準(zhǔn)確率與圖片準(zhǔn)確率曲線:



??看起來(lái)還不錯(cuò),最后寫(xiě)個(gè)預(yù)測(cè)類(lèi)的代碼就結(jié)束了:




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