【深度学习】Cifar-10-探究不同的改进策略对分类准确率提高
cifar10數(shù)據(jù)集上進(jìn)行圖片分類,基于tensorflow框架,
旨在探究不同的改進(jìn)策略對(duì)分類準(zhǔn)確率的影響,如何一步步得提高準(zhǔn)確率?
?
一、問題描述
當(dāng)我們?cè)谔幚韴D像識(shí)別或者圖像分類或者其他機(jī)器學(xué)習(xí)任務(wù)的時(shí)候,我們總是迷茫于做出哪些改進(jìn)能夠提升模型的性能(識(shí)別率、分類準(zhǔn)確率)。。。或者說我們?cè)诼L(zhǎng)而苦惱的調(diào)參過程中到底調(diào)的是哪些參數(shù)。。。所以,我花了一部分時(shí)間在公開數(shù)據(jù)集CIFAR-10 [1] 上進(jìn)行探索,來總結(jié)出一套方法能夠快速高效并且有目的性地進(jìn)行網(wǎng)絡(luò)訓(xùn)練和參數(shù)調(diào)整。
CIFAR-10數(shù)據(jù)集有60000張圖片,每張圖片均為分辨率為32*32的彩色圖片(分為RGB3個(gè)信道)。CIFAR-10的分類任務(wù)是將每張圖片分成青蛙、卡車、飛機(jī)等10個(gè)類別中的一個(gè)類別。本文主要使用基于卷積神經(jīng)網(wǎng)絡(luò)的方法(CNN)來設(shè)計(jì)模型,完成分類任務(wù)。
首先,為了能夠在訓(xùn)練網(wǎng)絡(luò)的同時(shí)能夠檢測(cè)網(wǎng)絡(luò)的性能,我對(duì)數(shù)據(jù)集進(jìn)行了訓(xùn)練集/驗(yàn)證集/測(cè)試集的劃分。訓(xùn)練集主要用戶進(jìn)行模型訓(xùn)練,驗(yàn)證集主要進(jìn)行參數(shù)調(diào)整,測(cè)試集主要進(jìn)行模型性能的評(píng)估。因此,我將60000個(gè)樣本的數(shù)據(jù)集分成了,45000個(gè)樣本作為訓(xùn)練集,5000個(gè)樣本作為驗(yàn)證集,10000個(gè)樣本作為測(cè)試集。接下來,我們一步步來分析,如果進(jìn)行模型設(shè)計(jì)和改進(jìn)。
?
二、搭建最簡(jiǎn)單版本的CNN
對(duì)于任何的機(jī)器學(xué)習(xí)問題,我們一上來肯定是采用最簡(jiǎn)單的模型,一方面能夠快速地run一個(gè)模型,以了解這個(gè)任務(wù)的難度,另一方面能夠有一個(gè)baseline版本的模型,利于進(jìn)行對(duì)比實(shí)驗(yàn)。所以,我按照以往經(jīng)驗(yàn)和網(wǎng)友的推薦,設(shè)計(jì)了以下的模型。
模型的輸入數(shù)據(jù)是網(wǎng)絡(luò)的輸入是一個(gè)4維tensor,尺寸為(128, 32, 32, 3),分別表示一批圖片的個(gè)數(shù)128、圖片的寬的像素點(diǎn)個(gè)數(shù)32、高的像素點(diǎn)個(gè)數(shù)32和信道個(gè)數(shù)3。首先使用多個(gè)卷積神經(jīng)網(wǎng)絡(luò)層進(jìn)行圖像的特征提取,卷積神經(jīng)網(wǎng)絡(luò)層的計(jì)算過程如下步驟:
參數(shù)初始化,所有權(quán)重矩陣使用random_normal(0.0, 0.001),所有偏置向量使用constant(0.0)。使用cross entropy作為目標(biāo)函數(shù),使用Adam梯度下降法進(jìn)行參數(shù)更新,學(xué)習(xí)率設(shè)為固定值0.001。
該網(wǎng)絡(luò)是一個(gè)有三層卷積層的神經(jīng)網(wǎng)絡(luò),能夠快速地完成圖像地特征提取。全連接層用于將圖像特征整合成分類特征,分類層用于分類。cross entropy也是最常用的目標(biāo)函數(shù)之一,分類任務(wù)使用cross entropy作為目標(biāo)函數(shù)非常適合。Adam梯度下降法也是現(xiàn)在非常流行的梯度下降法的改進(jìn)方法之一,學(xué)習(xí)率過大會(huì)導(dǎo)致模型難以找到較優(yōu)解,設(shè)置過小則會(huì)降低模型訓(xùn)練效率,因此選擇適中的0.001。這樣,我們最基礎(chǔ)版本的CNN模型就已經(jīng)搭建好了,接下來進(jìn)行訓(xùn)練和測(cè)試以觀察結(jié)果。
訓(xùn)練5000輪,觀察到loss變化曲線、訓(xùn)練集準(zhǔn)確率變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線如下圖。測(cè)試集準(zhǔn)確率為69.36%。
結(jié)果分析:首先我們觀察訓(xùn)練loss(目標(biāo)函數(shù)值)變化,剛開始loss從200不斷減小到接近0,但是在100輪左右開始出現(xiàn)震蕩,并且隨著訓(xùn)練幅度越來越大,說明模型不穩(wěn)定。然后觀察訓(xùn)練集和驗(yàn)證集的準(zhǔn)確率,發(fā)現(xiàn)訓(xùn)練集準(zhǔn)確率接近于1,驗(yàn)證集準(zhǔn)確率穩(wěn)定在70%左右,說明模型的泛化能力不強(qiáng)并且出現(xiàn)了過擬合情況。最后評(píng)估測(cè)試集,發(fā)現(xiàn)準(zhǔn)確率為69.36%,也沒有達(dá)到很滿意的程度,說明我們對(duì)模型需要進(jìn)行很大的改進(jìn),接下來進(jìn)行漫長(zhǎng)的調(diào)參之旅吧!
?
三、數(shù)據(jù)增強(qiáng)有很大的作用
使用數(shù)據(jù)增強(qiáng)技術(shù)(data augmentation),主要是在訓(xùn)練數(shù)據(jù)上增加微小的擾動(dòng)或者變化,一方面可以增加訓(xùn)練數(shù)據(jù),從而提升模型的泛化能力,另一方面可以增加噪聲數(shù)據(jù),從而增強(qiáng)模型的魯棒性。主要的數(shù)據(jù)增強(qiáng)方法有:翻轉(zhuǎn)變換 flip、隨機(jī)修剪(random crop)、色彩抖動(dòng)(color jittering)、平移變換(shift)、尺度變換(scale)、對(duì)比度變換(contrast)、噪聲擾動(dòng)(noise)、旋轉(zhuǎn)變換/反射變換 (rotation/reflection)等,可以參考Keras的官方文檔 [2] 。獲取一個(gè)batch的訓(xùn)練數(shù)據(jù),進(jìn)行數(shù)據(jù)增強(qiáng)步驟之后再送入網(wǎng)絡(luò)進(jìn)行訓(xùn)練。
我主要做的數(shù)據(jù)增強(qiáng)操作有如下方面:
為了進(jìn)行對(duì)比實(shí)驗(yàn),觀測(cè)不同數(shù)據(jù)增強(qiáng)方法的性能,實(shí)驗(yàn)1只進(jìn)行圖像切割,實(shí)驗(yàn)2只進(jìn)行圖像翻轉(zhuǎn),實(shí)驗(yàn)3只進(jìn)行圖像白化,實(shí)驗(yàn)4同時(shí)進(jìn)行這三種數(shù)據(jù)增強(qiáng)方法,同樣訓(xùn)練5000輪,觀察到loss變化曲線、訓(xùn)練集準(zhǔn)確率變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線對(duì)比如下圖。
結(jié)果分析:我們觀察訓(xùn)練曲線和驗(yàn)證曲線,很明顯地發(fā)現(xiàn)圖像白化的效果好,其次是圖像切割,再次是圖像翻轉(zhuǎn),而如果同時(shí)使用這三種數(shù)據(jù)增強(qiáng)技術(shù),不僅能使訓(xùn)練過程的loss更穩(wěn)定,而且能使驗(yàn)證集的準(zhǔn)確率提升至82%左右,提升效果十分明顯。而對(duì)于測(cè)試集,準(zhǔn)確率也提升至80.42%。說明圖像增強(qiáng)確實(shí)通過增加訓(xùn)練集數(shù)據(jù)量達(dá)到了提升模型泛化能力以及魯棒性的效果,從準(zhǔn)確率上看也帶來了將近10%左右的提升,因此,數(shù)據(jù)增強(qiáng)確實(shí)有很大的作用。但是對(duì)于80%左右的識(shí)別準(zhǔn)確率我們還是不夠滿意,接下來繼續(xù)調(diào)參。
?
四、從模型入手,使用一些改進(jìn)方法
接下來的步驟是從模型角度進(jìn)行一些改進(jìn),這方面的改進(jìn)是誕生論文的重要區(qū)域,由于某一個(gè)特定問題對(duì)某一個(gè)模型的改進(jìn)千變?nèi)f化,沒有辦法全部去嘗試,因此一般會(huì)實(shí)驗(yàn)一些general的方法,比如批正則化(batch normalization)、權(quán)重衰減(weight decay)。我這里實(shí)驗(yàn)了4種改進(jìn)方法,接下來依次介紹。
為了進(jìn)行對(duì)比實(shí)驗(yàn),實(shí)驗(yàn)1只使用權(quán)重衰減,實(shí)驗(yàn)2使用權(quán)重衰減+dropout,實(shí)驗(yàn)3使用權(quán)重衰減+dropout+批正則化,實(shí)驗(yàn)4使用權(quán)重衰減+dropout+批正則化+LRN,同樣都訓(xùn)練5000輪,觀察到loss變化曲線、訓(xùn)練集準(zhǔn)確率變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線對(duì)比如下圖。
結(jié)果分析:我們觀察訓(xùn)練曲線和驗(yàn)證曲線,隨著每一個(gè)模型提升的方法,都會(huì)使訓(xùn)練集誤差和驗(yàn)證集準(zhǔn)確率有所提升,其中,批正則化技術(shù)和dropout技術(shù)帶來的提升非常明顯,而如果同時(shí)使用這些模型提升技術(shù),會(huì)使驗(yàn)證集的準(zhǔn)確率從82%左右提升至88%左右,提升效果十分明顯。而對(duì)于測(cè)試集,準(zhǔn)確率也提升至85.72%。我們?cè)僮⒁饪醋髨D,使用batch normalization之后,loss曲線不再像之前會(huì)出現(xiàn)先下降后上升的情況,而是一直下降,這說明batch normalization技術(shù)可以加強(qiáng)模型訓(xùn)練的穩(wěn)定性,并且能夠很大程度地提升模型泛化能力。所以,如果能提出一種模型改進(jìn)技術(shù)并且從原理上解釋同時(shí)也使其適用于各種模型,那么就是非常好的創(chuàng)新點(diǎn),也是我想挑戰(zhàn)的方向。現(xiàn)在測(cè)試集準(zhǔn)確率提升至85%左右,接下來我們從其他的角度進(jìn)行調(diào)參。
?
五、變化的學(xué)習(xí)率,進(jìn)一步提升模型性能
在很多關(guān)于神經(jīng)網(wǎng)絡(luò)的論文中,都采用了變化學(xué)習(xí)率的技術(shù)來提升模型性能,大致的想法是這樣的:
為了進(jìn)行對(duì)比實(shí)驗(yàn),實(shí)驗(yàn)1只使用0.01的學(xué)習(xí)率訓(xùn)練,實(shí)驗(yàn)2前10000個(gè)batch使用0.01的學(xué)習(xí)率,10000個(gè)batch之后學(xué)習(xí)率降到0.001,實(shí)驗(yàn)3前10000個(gè)batch使用0.01的學(xué)習(xí)率,10000~20000個(gè)batch使用0.001的學(xué)習(xí)率,20000個(gè)batch之后學(xué)習(xí)率降到0.0005。同樣都訓(xùn)練5000輪,觀察到loss變化曲線、訓(xùn)練集準(zhǔn)確率變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線對(duì)比如下圖。
結(jié)果分析:我們觀察到,當(dāng)10000個(gè)batch時(shí),學(xué)習(xí)率從0.01降到0.001時(shí),目標(biāo)函數(shù)值有明顯的下降,驗(yàn)證集準(zhǔn)確率有明顯的提升,而當(dāng)20000個(gè)batch時(shí),學(xué)習(xí)率從0.001降到0.0005時(shí),目標(biāo)函數(shù)值沒有明顯的下降,但是驗(yàn)證集準(zhǔn)確率有一定的提升,而對(duì)于測(cè)試集,準(zhǔn)確率也提升至86.24%。這說明,學(xué)習(xí)率的變化確實(shí)能夠提升模型的擬合能力,從而提升準(zhǔn)確率。學(xué)習(xí)率在什么時(shí)候進(jìn)行衰減、率減多少也需要進(jìn)行多次嘗試。一般在模型基本成型之后,使用這種變化的學(xué)習(xí)率的方法,以獲取一定的改進(jìn),精益求精。
?
六、加深網(wǎng)絡(luò)層數(shù),會(huì)發(fā)生什么事情?
現(xiàn)在深度學(xué)習(xí)大熱,所以,在計(jì)算資源足夠的情況下,想要獲得模型性能的提升,大家最常見打的想法就是增加網(wǎng)絡(luò)的深度,讓深度神經(jīng)網(wǎng)絡(luò)來解決問題,但是簡(jiǎn)單的網(wǎng)絡(luò)堆疊不一定就能達(dá)到很好地效果,抱著深度學(xué)習(xí)的想法,我按照plain-cnn模型 [6],我做了接下來的實(shí)驗(yàn)。
為了進(jìn)行對(duì)比實(shí)驗(yàn),進(jìn)行4組實(shí)驗(yàn),每組的網(wǎng)絡(luò)層數(shù)分別設(shè)置8,14,20和32。同樣都訓(xùn)練5000輪,觀察到loss變化曲線、訓(xùn)練集準(zhǔn)確率變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線對(duì)比如下圖。
結(jié)果分析:我們驚訝的發(fā)現(xiàn),加深了網(wǎng)絡(luò)層數(shù)之后,性能反而下降了,達(dá)不到原來的驗(yàn)證集準(zhǔn)確率,網(wǎng)絡(luò)層數(shù)從8層增加到14層,準(zhǔn)確率有所上升,但從14層增加到20層再增加到32層,準(zhǔn)確率不升反降,這說明如果網(wǎng)絡(luò)層數(shù)過大,由于梯度衰減的原因,導(dǎo)致網(wǎng)絡(luò)性能下降,因此,需要使用其他方法解決梯度衰減問題,使得深度神經(jīng)網(wǎng)絡(luò)能夠正常work。
?
七、終極武器,殘差網(wǎng)絡(luò)
2015年,Microsoft用殘差網(wǎng)絡(luò) [7] 拿下了當(dāng)年的ImageNet,這個(gè)殘差網(wǎng)絡(luò)就很好地解決了梯度衰減的問題,使得深度神經(jīng)網(wǎng)絡(luò)能夠正常work。由于網(wǎng)絡(luò)層數(shù)加深,誤差反傳的過程中會(huì)使梯度不斷地衰減,而通過跨層的直連邊,可以使誤差在反傳的過程中減少衰減,使得深層次的網(wǎng)絡(luò)可以成功訓(xùn)練,具體的過程可以參見其論文[7]。
通過設(shè)置對(duì)比實(shí)驗(yàn),觀察殘差網(wǎng)絡(luò)的性能,進(jìn)行4組實(shí)驗(yàn),每組的網(wǎng)絡(luò)層數(shù)分別設(shè)置20,32,44和56。觀察到loss變化曲線和驗(yàn)證集準(zhǔn)確率變化曲線對(duì)比如下圖。
同的改進(jìn)策略對(duì)分類準(zhǔn)確率的影響,如何一步步得提高準(zhǔn)確率。
?
代碼:
import numpy as np # 序列化和反序列化 import pickle from sklearn.preprocessing import OneHotEncoder import warnings warnings.filterwarnings('ignore') import tensorflow as tf#數(shù)據(jù)加載def unpickle(file):import picklewith open(file, 'rb') as fo:dict = pickle.load(fo, encoding='ISO-8859-1')return dict labels = [] X_train = [] for i in range(1,6):data = unpickle('./cifar-10-batches-py/data_batch_%d'%(i))labels.append(data['labels'])X_train.append(data['data']) # 將list類型轉(zhuǎn)換為ndarray X_train = np.array(X_train)X_train = np.transpose(X_train.reshape(-1,3,32,32),[0,2,3,1]).reshape(-1,3072)y_train = np.array(labels).reshape(-1)# reshape X_train = X_train.reshape(-1,3072)# 目標(biāo)值概率 one_hot = OneHotEncoder() y_train =one_hot.fit_transform(y_train.reshape(-1,1)).toarray()# 測(cè)試數(shù)據(jù)加載 test = unpickle('./cifar-10-batches-py/test_batch') X_test = test['data'] X_test = np.transpose(X_test.reshape(-1,3,32,32),[0,2,3,1]).reshape(-1,3072) y_test = one_hot.transform(np.array(test['labels']).reshape(-1,1)).toarray()# 從總數(shù)據(jù)中獲取一批數(shù)據(jù) index = 0 def next_batch(X,y):global indexbatch_X = X[index*128:(index+1)*128]batch_y = y[index*128:(index+1)*128]index+=1if index == 390:index = 0return batch_X,batch_y# 構(gòu)建神經(jīng)網(wǎng)絡(luò)X = tf.placeholder(dtype=tf.float32,shape = [None,3072]) y = tf.placeholder(dtype=tf.float32,shape = [None,10]) kp = tf.placeholder(dtype=tf.float32)### !!!變量 def gen_v(shape,std = 5e-2):return tf.Variable(tf.truncated_normal(shape = shape,stddev=std))def conv(input_,filter_,b):conv = tf.nn.conv2d(input_,filter_,strides=[1,1,1,1],padding='SAME') + bconv = tf.layers.batch_normalization(conv,training=True)conv = tf.nn.relu(conv)return tf.nn.max_pool(conv,[1,3,3,1],[1,2,2,1],'SAME')def net_work(X,kp): # 形狀改變,4維input_ = tf.reshape(X,shape = [-1,32,32,3]) # 第一層filter1 = gen_v(shape = [3,3,3,64])b1 = gen_v(shape = [64])pool1 = conv(input_,filter1,b1)# 第二層filter2 = gen_v([3,3,64,128])b2 = gen_v(shape = [128])pool2 = conv(pool1,filter2,b2)# 第三層filter3 = gen_v([3,3,128,256])b3 = gen_v([256])pool3 = conv(pool2,filter3,b3)# 第一層全連接層dense = tf.reshape(pool3,shape = [-1,4*4*256])fc1_w = gen_v(shape = [4*4*256,1024])fc1_b = gen_v([1024])bn_fc_1 = tf.layers.batch_normalization(tf.matmul(dense,fc1_w) + fc1_b,training=True)relu_fc_1 = tf.nn.relu(bn_fc_1) # fc1.shape = [-1,1024]# dropoutdp = tf.nn.dropout(relu_fc_1,keep_prob=kp)# fc2 輸出層out_w = gen_v(shape = [1024,10])out_b = gen_v(shape = [10])out = tf.matmul(dp,out_w) + out_breturn out# 損失函數(shù)準(zhǔn)確率&最優(yōu)化out = net_work(X,kp) loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y,logits=out)) # 準(zhǔn)確率 y_ = tf.nn.softmax(out) # equal 相當(dāng)于 == equal = tf.equal(tf.argmax(y,axis = -1),tf.argmax(y_,axis = 1)) accuracy = tf.reduce_mean(tf.cast(equal,tf.float32))opt = tf.train.AdamOptimizer(0.01).minimize(loss) opt# 開啟訓(xùn)練saver = tf.train.Saver()# config = tf.ConfigProto(allow_soft_placement=True) # config.gpu_options.allocator_type = 'BFC' # config.gpu_options.per_process_gpu_memory_fraction = 0.80epoches = 100 with tf.Session() as sess:sess.run(tf.global_variables_initializer())for i in range(epoches):batch_X,batch_y = next_batch(X_train,y_train)opt_,loss_ ,score_train= sess.run([opt,loss,accuracy],feed_dict = {X:batch_X,y:batch_y,kp:0.5})print('iter count:%d。mini_batch loss:%0.4f。訓(xùn)練數(shù)據(jù)上的準(zhǔn)確率:%0.4f。測(cè)試數(shù)據(jù)上準(zhǔn)確率:...'%(i+1,loss_,score_train ))if score_train > 0.6:saver.save(sess,'./model/estimator',i+1)saver.save(sess,'./model/estimator',i+1)for i in range(77):X_test1,y_test1= next_batch(X_test,y_test)score_test = sess.run([accuracy],feed_dict = {X:X_test1,y:y_test1,kp:1.0})print('測(cè)試數(shù)據(jù)上的準(zhǔn)確率:',score_test,y_[0],y[0])epoches = 1100 with tf.Session() as sess:saver.restore(sess,'./model/estimator-100')for i in range(100,epoches):batch_X,batch_y = next_batch(X_train,y_train)opt_,loss_ ,score_train= sess.run([opt,loss,accuracy],feed_dict = {X:batch_X,y:batch_y,kp:0.5})print('iter count:%d。mini_batch loss:%0.4f。訓(xùn)練數(shù)據(jù)上的準(zhǔn)確率:%0.4f。測(cè)試數(shù)據(jù)上準(zhǔn)確率:%0.4f'%(i+1,loss_,score_train,score_test))if score_train > 0.6:saver.save(sess,'./model/estimator',i+1)saver.save(sess,'./model/estimator',i+1)if (i%100 == 0) and (i != 100):score_test = sess.run(accuracy,feed_dict = {X:X_test,y:y_test,kp:1.0})print('----------------測(cè)試數(shù)據(jù)上的準(zhǔn)確率:---------------',score_test)?
總結(jié)
以上是生活随笔為你收集整理的【深度学习】Cifar-10-探究不同的改进策略对分类准确率提高的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文笔记:微表情识别综述1
- 下一篇: 【机器学习】opencv-视频中的人脸检