學(xué)號:17020110019? ? 姓名:高少魁
【嵌牛導(dǎo)讀】在深度學(xué)習(xí)領(lǐng)域,手寫數(shù)字識別是一個較為基礎(chǔ)的案例实辑,筆者通過深度學(xué)習(xí)框架pytorch,使用卷積神經(jīng)網(wǎng)絡(luò)設(shè)計了一個基本的網(wǎng)絡(luò)結(jié)構(gòu)镊讼,使用MINST數(shù)據(jù)集作為實驗數(shù)據(jù)集匹舞,訓(xùn)練了40個輪次,識別率(在訓(xùn)練集上的)達(dá)到了99.95%似芝,最終識別率(在測試集上的)達(dá)到了99.13%那婉,取得了比較良好的識別效果。
【嵌牛鼻子】深度學(xué)習(xí)? ? 卷積神經(jīng)網(wǎng)絡(luò)? ? 手寫數(shù)字識別? ? pytorch
【嵌牛正文】
一党瓮、測試環(huán)境
筆者使用的操作系統(tǒng)為windows7详炬,開發(fā)語言選擇python,版本為3.7.3,使用開發(fā)工具IDE為pycharm呛谜。根據(jù)神經(jīng)網(wǎng)路的要求在跳,使用了深度學(xué)習(xí)框架pytorch。使用的相關(guān)工具與依賴庫有pytorch(torch)隐岛、torchvision猫妙、matplotlib、time等聚凹。
考慮到筆者的設(shè)備性能對卷積神經(jīng)網(wǎng)絡(luò)的限制割坠,本人在pycharm上進(jìn)行網(wǎng)絡(luò)設(shè)計與初步實現(xiàn),對于更精確的妒牙、需要更多訓(xùn)練輪次的程序彼哼,使用了谷歌的深度學(xué)習(xí)工具colab,該平臺可以以優(yōu)異的性能運行深度學(xué)習(xí)代碼湘今,平臺還提供了Tesla K80作為GPU加速敢朱,可以取得理想的實驗結(jié)果。
二摩瞎、基本原理
卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Networks, CNN)是一種包含卷積計算的拴签,具有深度結(jié)構(gòu)的前饋神經(jīng)網(wǎng)絡(luò),是深度學(xué)習(xí)中具有代表性的一種神經(jīng)網(wǎng)絡(luò)愉豺,卷積神經(jīng)網(wǎng)絡(luò)可以對格點化特征(如圖片的像素點)進(jìn)行學(xué)習(xí)篓吁,具有穩(wěn)定的效果,因此在計算機(jī)視覺領(lǐng)域應(yīng)用十分廣泛蚪拦。卷積神經(jīng)網(wǎng)絡(luò)主要包括輸入層杖剪、隱含層和輸出層,如下:
輸入層:CNN的輸入層可以處理多維數(shù)據(jù)驰贷,在計算機(jī)視覺領(lǐng)域通常輸入三維數(shù)組(即圖像上的RGB像素值與二維像素點位置)盛嘿。一般來說,其輸入數(shù)據(jù)需要進(jìn)行預(yù)處理括袒,如標(biāo)準(zhǔn)化次兆,將分布在[0,255]上的像素灰度值轉(zhuǎn)化為[0,1]上的值,這樣做有利于提高卷積神經(jīng)網(wǎng)絡(luò)的效率锹锰。
隱含層:隱含層通常主要包含卷積層芥炭、池化層和全連接層三種結(jié)構(gòu),其中
(1)卷積層(convolutional layer)可以對輸入數(shù)據(jù)進(jìn)行特征提取恃慧。它包含多個卷積核园蝠,卷積核的大小、步長痢士、填充方式都決定了輸出特征圖像的尺寸彪薛,它在圖像上進(jìn)行掃描,可以提取不同的特征。對圖像進(jìn)行不斷地卷積善延,可以得到邊緣少态、線條甚至更加復(fù)雜的特征。
(2)線性整流層(Rectified Linear Units layer, ReLU layer)易遣,該層主要使用ReLU函數(shù)或其變形來作為激活函數(shù)彼妻,其中,ReLU函數(shù)為:f(x)=max(0,x)训挡。使用ReLU函數(shù)主要是為了使神經(jīng)網(wǎng)絡(luò)非線性化澳骤。
(3)池化層(Pooling layer)歧强,該層主要是為了解決卷積層之后數(shù)據(jù)特征維度過大的問題澜薄,特征圖送到池化層以進(jìn)行信息過濾。池化層主要是將圖中單個點或多點運算的一個結(jié)果替換為其鄰域部分摊册,池化層也有池化大小肤京、步長、填充等參數(shù)茅特。常見的池化有均勻池化(在池化區(qū)域內(nèi)取均值)忘分、極大池化(在區(qū)域內(nèi)取極大值)、隨機(jī)池化白修、混合池化等妒峦。經(jīng)過池化之后,特征維度減小兵睛。
(4)全連接層(Fully-Connected layer)肯骇,經(jīng)過卷積層和池化層對輸入數(shù)據(jù)進(jìn)行的特征提取之后,全連接層主要是對特征進(jìn)行非線性組合得到輸出祖很,即利用已有的高階特征完成學(xué)習(xí)目標(biāo)笛丙。
輸出層:對于手寫數(shù)字圖像分類問題,輸出層使用邏輯函數(shù)或歸一化指數(shù)函數(shù)softmax輸出分類標(biāo)簽假颇。
三胚鸯、數(shù)據(jù)集
筆者使用了MNIST數(shù)據(jù)集作為實驗數(shù)據(jù)集。MNIST數(shù)據(jù)集是一個手寫數(shù)字?jǐn)?shù)據(jù)集笨鸡,如下圖姜钳。該數(shù)據(jù)集由四部分組成,分別是訓(xùn)練圖片集形耗、訓(xùn)練標(biāo)簽集哥桥、測試圖片集和測試標(biāo)簽集,其中趟脂,訓(xùn)練集包含了60000張圖片泰讽,測試集有10000張圖片,數(shù)據(jù)集足夠大,可以提高訓(xùn)練性能已卸。
在MNIST數(shù)據(jù)集中的數(shù)字具有不同的形態(tài)佛玄,并且還有少部分殘缺數(shù)據(jù),這樣有利于提高模型的魯棒性與泛化能力累澡。
四梦抢、神經(jīng)網(wǎng)絡(luò)設(shè)計
1、網(wǎng)絡(luò)結(jié)構(gòu)的設(shè)計如下
根據(jù)上圖神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)可知愧哟,數(shù)據(jù)輸入時奥吩,首先經(jīng)過一個卷積核大小為3×3的卷積層,由于MNIST數(shù)據(jù)集是灰度圖像蕊梧,因此輸入通道為1霞赫,輸出通道設(shè)定為8,步長為1肥矢;之后經(jīng)過一個池化層端衰,大小為2×2,步長為2甘改,使用的池化策略為極大池化旅东;在激活函數(shù)上,使用了ReLU作為激活函數(shù)十艾,以使網(wǎng)絡(luò)非線性化抵代;之后再通過一個輸入8通道,輸出16通道忘嫉,卷積核為3×3荤牍,步長為1的卷積層以及一個與之前一模一樣的池化層;該網(wǎng)絡(luò)運算結(jié)束后通過一個ReLU激活函數(shù)并將其轉(zhuǎn)化(reshape)為大小15×25的張量榄融;接下來是一個全連接層参淫,輸入的張量大小是16×25,輸出為1024愧杯,在經(jīng)過一個ReLU激活函數(shù)后涎才,使用Dropout網(wǎng)絡(luò)來抑制過擬合,Dropout策略為0.2力九,即該層神經(jīng)元在每次迭代訓(xùn)練后有20%的可能性被丟棄耍铜,不參與訓(xùn)練,最后是一個全連接層跌前,由于手寫數(shù)字有10類(0~9)棕兼,因此輸入張量大小為1024,輸出大小為10抵乓,在網(wǎng)絡(luò)的最后伴挚,由于該項目屬于分類任務(wù)靶衍,使用softmax激活函數(shù)來將多個神經(jīng)元的輸出映射到[0,1]區(qū)間內(nèi),并且預(yù)測結(jié)果的概率累積和為1茎芋。
2颅眶、one-hot編碼設(shè)計
基于卷積神經(jīng)網(wǎng)絡(luò)的手寫數(shù)字識別,本質(zhì)上是分類問題田弥,而在神經(jīng)網(wǎng)絡(luò)中有大量的加權(quán)平均運算涛酗,如果使用圖片標(biāo)簽編碼的類別值,如數(shù)字“1”偷厦、“2”商叹,那么模型的預(yù)測會有大量的誤差,因此要使用one-hot編碼對類別進(jìn)行“二進(jìn)制”操作只泼。例如數(shù)字“3”剖笙,它的one-hot編碼為“0001000000”。
3辜妓、數(shù)據(jù)預(yù)處理與加載
對于數(shù)據(jù)的預(yù)處理枯途,筆者使用了torchvision中的transforms忌怎,它含有很多對數(shù)據(jù)與處理的函數(shù)籍滴,本人使用的是transforms.Normalize(mean=[0.5], std=[0.5]),即將[0,1]映射到[-1,1]中榴啸,由于MNIST中的數(shù)據(jù)為圖片孽惰,因此使用了transforms.ToTensor()將其轉(zhuǎn)化為張量。
對于數(shù)據(jù)集的定義鸥印,首先使用了torchvision中的datasets.MNIST()來進(jìn)行MNIST數(shù)據(jù)集的加載勋功,筆者定義了兩組數(shù)據(jù),即訓(xùn)練集和測試集库说,分別是data_train與data_test狂鞋。之后使用torch.utils.data中的DataLoader來加載數(shù)據(jù)。
4潜的、訓(xùn)練神經(jīng)網(wǎng)絡(luò)與測試
在神經(jīng)網(wǎng)絡(luò)定義結(jié)束后骚揍,就可以聲明一個網(wǎng)絡(luò)對象,將之前加載的數(shù)據(jù)標(biāo)簽進(jìn)行one-hot編碼啰挪,將數(shù)據(jù)傳入網(wǎng)絡(luò)進(jìn)行計算信不。使用torch.argmax()可以得到數(shù)字標(biāo)簽的索引(由于使用one-hot編碼,因此返回的結(jié)果非1即0亡呵,最大的數(shù)的索引即為數(shù)字標(biāo)簽)抽活,將通過網(wǎng)絡(luò)訓(xùn)練的數(shù)字標(biāo)簽與真實的數(shù)字標(biāo)簽做對比,計算出正確個數(shù)锰什,以此計算精確度下硕。在優(yōu)化器和損失函數(shù)方面丁逝,使用了optim.zero_grad()進(jìn)行梯度歸零,使用了二分類交叉熵?fù)p失函數(shù)(nn.BCELoss())梭姓,經(jīng)過一次反向傳播后使用optim.step()更新網(wǎng)絡(luò)參數(shù)果港。筆者設(shè)計了40個訓(xùn)練輪次,每個輪次一次加載200個數(shù)據(jù)糊昙,MNIST數(shù)據(jù)集共有60000個辛掠,因此一個訓(xùn)練輪次要加載數(shù)據(jù)60000/200=300次,一共有12000次循環(huán)释牺。在訓(xùn)練結(jié)束后萝衩,將測試集通過神經(jīng)網(wǎng)絡(luò),進(jìn)行手寫數(shù)字的預(yù)測没咙,通過預(yù)測標(biāo)簽與真實標(biāo)簽的對比猩谊,即可統(tǒng)計正確預(yù)測數(shù)量,以計算識別準(zhǔn)確率祭刚。
為了使運行者可以看到實際識別的圖片牌捷,筆者設(shè)計了另一個版本的程序,與之前程序不同的是涡驮,該程序在測試集測試部分暗甥,只加載了16個數(shù)據(jù),使用matplotlib.pyplot中的方法將加載的16個數(shù)字圖片與識別的標(biāo)簽輸出捉捅,使運行者可以清楚的看到識別的效果撤防。具體可見訓(xùn)練結(jié)果。
五棒口、訓(xùn)練結(jié)果
結(jié)果分為兩個部分寄月,一個是40個輪次的訓(xùn)練,結(jié)果輸出測試集識別手寫數(shù)字的準(zhǔn)確度无牵,另一個部分只訓(xùn)練10個輪次漾肮,但著重于輸出使用網(wǎng)絡(luò)識別的16張手寫數(shù)字圖片。
1茎毁、識別準(zhǔn)確度結(jié)果
在google的colab平臺上進(jìn)行測試克懊,選擇訓(xùn)練輪次為40輪,運行結(jié)果如下:
分析結(jié)果可知充岛,在訓(xùn)練了40輪之后保檐,訓(xùn)練集的識別精確度提高到了99.94%左右,損失函數(shù)也在不斷的降低崔梗,可見該模型對于手寫數(shù)字識別的準(zhǔn)確率很高夜只;在測試集上進(jìn)行測試,得到的精確度為99.13%蒜魄,已經(jīng)可以滿足日常生產(chǎn)生活需求扔亥;另外场躯,程序總運行時間約為938.9秒,主要耗費在訓(xùn)練模型上旅挤,而在測試集上運行的時間僅僅只有2.467秒踢关,由于測試集一共有10000張手寫數(shù)字圖片,平均識別一張圖片僅需約0.25ms粘茄,識別速度非城┪瑁快。
通過分析后兩張圖柒瓣,可以直觀的看到訓(xùn)練過程中一些指標(biāo)的變化儒搭,識別精確度在前面的訓(xùn)練輪次增長速度非常快芙贫,而在后續(xù)的訓(xùn)練輪次搂鲫,增長速度開始變得緩慢,并且最后基本穩(wěn)定在一個精確度上磺平;而對于損失函數(shù)魂仍,它的下降趨勢和精確度的增長趨勢基本上是互補的,也是不斷地下降拣挪,最后穩(wěn)定在0.01附近擦酌,但與識別精確度不同的是,損失函數(shù)的下降過程中有明顯的波動媒吗。
2仑氛、手寫數(shù)字識別結(jié)果實例
在pycharm上運行另一個程序,選擇訓(xùn)練輪次為10輪闸英,運行結(jié)果如下圖:
根據(jù)第一張圖的運行結(jié)果可以看出,精確度不斷提高介袜,在訓(xùn)練了10輪之后甫何,精確度達(dá)到了99.52%,并穩(wěn)定在99.52%左右遇伞,已經(jīng)可以滿足正常的使用辙喂。從第二張圖可以看出,16張手寫數(shù)字圖片全部被識別出鸠珠,一些形態(tài)各異的數(shù)字也能很好的識別巍耗,可見該神經(jīng)網(wǎng)絡(luò)可以實際應(yīng)用到生產(chǎn)生活中去。