高斯拟合原理_AlexNet原理和实现
本文是讀深度學習的開山之作《ImageNet Classification with Deep Convolutional Neural Networks》所作的筆記。
論文筆記
1.解決了什么問題
大規模圖像分類的問題。2.使用的方法
搭建深度卷積神經網絡進行圖像分類,被稱為AlexNet在GPU上實現了高度優化的卷積神經網絡的訓練過程
使用了ReLU激活函數,局部響應歸一化,重疊池化等trick。
使用了數據增強、Dropout防止過擬合。
3.實驗結果
該模型讓深度學習成為最主流的機器學習算法在ImageNet LSVRC-2010數據集上達到state of the art,模型的top5錯誤率為17.0%
在ILSVRC-2012比賽中獲得冠軍,測試集top5錯誤率降低到15.3%
4.待解決的問題
由于當時計算資源的缺乏,該網絡不夠深,不夠寬,因此準確率仍有很大的提升空間。論文細節
AlexNet:這個神經網絡擁有6000w個參數和65w的神經元,由5層卷積池化層組成,后面接3層全連接層,輸出層有1000個神經元。
模型架構:
如上圖所示,模型由5個卷積層和3個全連接層組成,其中最后一個全連接層是softmax層,在ImageNet-1k數據集上訓練,故輸出1000個分類,使用分類交叉熵作為損失函數。
可以看到模型分為兩部分,因為該模型在兩個GPU上訓練,其中按照圖像數據的通道切分為兩部分,兩部分在特定的層通信。卷積層的第二、第四、第五層直接和同一個GPU的前一層相連,第三層則與兩個GPU上的第二層相連。全連接層都和上一層的所有神經元相連。
卷積層的第一層使用96個卷積核,size=(11,11),stride=4。第二卷積層使用256個卷積核,size=(5,5)。第三卷積層使用3x3的384個卷積核,第四卷積層使用3x3的384個卷積核,第五卷積層使用3x3的256個卷積核。全連接有兩層有4096個神經元。
局部響應歸一化應用在第一和第二卷積層之后,所有層的激活函數是ReLU,Dropout應用在全連接層。
在模型中用到的技術:
1.ReLU非線性激活函數
這篇論文之前激活函數一般選擇飽和非線性函數f(x)=tanh(x)或者sigmoid函數:f(x)=(1+e^(-x))^(-1),與之相比,非飽和非線性的ReLU f(x)=max(0,x)使用梯度下降訓練的速度要快幾倍。
2.在多GPUs上面訓練
Alex模型在兩個GPU上并行訓練,加快了訓練速度,兩部分只在特定的層通信。
3.局部響應歸一化(LRN,Local Response Normalization)
因為使用了ReLU,則不需要對輸入進行標準化防止過擬合。對ReLU輸出后的數據進行LRN的公式如下:
ai是像素坐標為(x,y),第i通道的輸出值,bi是將a歸一化后的值,N是通道的總數,k、alpha、beta、n都是參數。公式疊加通道方向的值,n表示疊加的范圍,示意圖如下:
LRN的原理 :局部歸一的動機:在神經生物學有-一個概念叫做側抑制(lateral inhibitio) ,指的是被激活的神經元抑制相鄰神經元。歸一化(normalization)的目的是“抑制”,局部響應歸一化就是借鑒側抑制的思想來實現局部抑制,尤其當我們使用ReLU的時候這種“側抑制”很管用。LRN的優點:增加范化能力。LRN層模仿生物神經系統的側抑制機制,對局部神經元的活動創建競爭機制,使得響應比較大的值相對更大,提高模型范化能力。
論文使用的超參數為k=2,n=5,alpha=10^-4,beta=0.75
4.重疊池化(Overlapping Pooling)
重疊池化即池化步長<池化窗口,重疊池化可以減小過擬合。這里使用最大池化步長=2,池化窗口大小=3。
防止過擬合的方法
1.數據增強
使用兩種方式進行數據增強:
第一種方法是圖像平移和水平翻轉和裁切。裁切過程先將圖片的短邊縮放至256,然后在中間裁切出256x256的圖片。256x256的圖片在四個角和中間裁切出5張224x224的圖片,就是我們的訓練數據。
第二種方法是改變圖片RGB通道的亮度。在ImageNet數據集上面執行PCA,對每個訓練圖片,將找到的主成分的倍數相加,與特征值成比例的模量乘以一個隨機變量,隨機變量來自均值為0標準差為0.1的高斯分布。對于每個像素Ixy=[Ixy_R, Ixy_G, Ixy_B],公式如下:
pi是特征向量,lambdai是特征值,pi和lambdai都來源于RGB像素值的3x3的協方差矩陣的,alphai是隨機變量。
2.使用Dropout
在兩個全連接層使用了0.5比率的dropout,這種技術減少了神經元之間復雜的相互適應。因為神經元不能依賴于其他神經元的存在,它被迫學習與其他神經元的許多不同隨機子集結合使用的更健壯的特征。
模型訓練
AlexNet在ImageNet LSVRC-2010上面訓練,該數據集有1000個分類,120w的數據。用GTX580 3GB GPU跑了5、6天。模型的輸入為224x224大小,對于各種分辨率的圖片,先將圖片的短邊縮放至224,再從中間進行裁剪中224x224的圖片。對于圖片的每個像素,減去訓練集上的平均像素值。
模型使用SGD訓練,batch_size=128,動量是0.9,權重衰減因子為0.0005,權重更新的公式如下:
v是動量變量。權重初始化采用高斯隨機數,均值為0標準差為0.01,偏置初始化為0,學習是手動調整的,初始學習率為0.01當驗證錯誤率不再提高時學習減小10倍。
效果:在ImageNet LSVRC-2010數據集上達到state of the art,模型的top5錯誤率為17.0% ,ILSVRC-2012比賽中獲得冠軍,測試集top5錯誤率降低到15.3%。ps:在ImageNet競賽中,通常用top-1和top-5錯誤率表示模型的性能,top-5錯誤率表示正確的標簽不在最可能的5個標簽的比率。
代碼實現
鑒于我的計算資源十分缺乏,因此我不打算在論文作者使用的數據集上跑一邊。剛好我有一個mini的ImageNet數據集,包含100個分類總共6w個樣本,勉強滿足測試要求。數據集鏈接:https://pan.baidu.com/s/17mX1c_Xteaw7B9dr9elhng 提取碼:qkmh
首先把訓練圖片縮放裁剪至224x224,并按分類保存到不同的文件夾便于調用Keras的數據增強API,代碼如下:
import os import cv2 import tqdmIMG_SIZE=224def ReadAndCutPicture(r_path,w_path):img = cv2.imread(r_path) #讀到圖片為BGRh=img.shape[0]w=img.shape[1]if(h<=w):new_h=IMG_SIZEnew_w=int(w/h*IMG_SIZE)img=cv2.resize(img,(new_w,new_h)) #輸出圖片尺寸為(寬,高)cut_w=int((new_w-new_h)/2)img=img[:,cut_w:cut_w+IMG_SIZE,:]else:new_w=IMG_SIZEnew_h=int(h/w*IMG_SIZE)img=cv2.resize(img,(new_w,new_h))cut_h=int((new_h-new_w)/2)img=img[cut_h:cut_h+IMG_SIZE,:,:]cv2.imwrite(w_path, img)normal_path=r'F:BaiduNetdiskDownloadmini-imagenetimages_normal' #裁剪后圖片所在的位置 base_path=r'F:BaiduNetdiskDownloadmini-imagenetimages' #數據集所在位置for name in tqdm.tqdm(os.listdir(base_path)):r_path=os.path.join(base_path,name)w_dir=os.path.join(normal_path,name[:9])w_path=os.path.join(w_dir,name)if(os.path.exists(w_dir)==False):os.makedirs(w_dir)ReadAndCutPicture(r_path,w_path)2.搭建網絡
Keras官方沒有給出LRN層的實現,我在github上找了一個現成的LRN實現,但是放上去就報錯了,這個代碼是這樣的:
from keras.layers.core import Layer from keras import backend as K import tensorflow as tf import numpy as np class LRN(Layer):def __init__(self, alpha=0.0001,k=1,beta=0.75,n=5, **kwargs):self.alpha = alphaself.k = kself.beta = betaself.n = nsuper(LRN, self).__init__(**kwargs)def call(self, x, mask=None):b, ch, r, c = x.shapehalf_n = self.n // 2 # half the local region# orig keras code#input_sqr = T.sqr(x) # square the inputinput_sqr = K.square(x) # square the input# orig keras code#extra_channels = T.alloc(0., b, ch + 2 * half_n, r,c) # make an empty tensor with zero pads along channel dimension#input_sqr = T.set_subtensor(extra_channels[:, half_n:half_n+ch, :, :],input_sqr) # set the center to be the squared inputextra_channels = K.zeros((b, int(ch) + 2 * half_n, r, c))input_sqr = K.concatenate([extra_channels[:, :half_n, :, :],input_sqr, extra_channels[:, half_n + int(ch):, :, :]],axis = 1)scale = self.k # offset for the scalenorm_alpha = self.alpha / self.n # normalized alphafor i in range(self.n):scale += norm_alpha * input_sqr[:, i:i+int(ch), :, :]scale = scale ** self.betax = x / scalereturn xdef get_config(self):config = {"alpha": self.alpha,"k": self.k,"beta": self.beta,"n": self.n}base_config = super(LRN, self).get_config()return dict(list(base_config.items()) + list(config.items())) class PoolHelper(Layer):def __init__(self, **kwargs):super(PoolHelper, self).__init__(**kwargs)def call(self, x, mask=None):return x[:,:,1:,1:]def get_config(self):config = {}base_config = super(PoolHelper, self).get_config()return dict(list(base_config.items()) + list(config.items()))由于使用的數據集跟原文的并不相同,因此這里對AlexNet做了微調,網絡如下:
from keras.models import * from keras.layers import * from keras import models from keras import initializers from keras.utils import plot_model normal_init=initializers.RandomNormal(mean=0.0, stddev=0.01, seed=None) X=Input(shape=(224,224,3)) conv1=Conv2D(96,(11,11),strides=(4,4),padding='same',activation='relu',kernel_initializer=normal_init,bias_initializer='zeros',name='conv1')(X) maxpooling1=MaxPooling2D(pool_size=(3,3),strides=2,name='maxpooling1')(conv1) #lrn1=LRN(alpha=0.0001,k=2,beta=0.75,n=5)(maxpooling1) conv2=Conv2D(256,(5,5),strides=(1,1),padding='same',activation='relu',kernel_initializer=normal_init,bias_initializer='zeros',name='conv2')(maxpooling1) maxpooling2=MaxPooling2D(pool_size=(3,3),strides=2,name='maxpooling2')(conv2) #lrn2=LRN(alpha=0.0001,k=2,beta=0.75,n=5)(maxpooling2) conv3=Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer=normal_init,bias_initializer='zeros',name='conv3')(maxpooling2) conv4=Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer=normal_init,bias_initializer='zeros',name='conv4')(conv3) conv5=Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer=normal_init,bias_initializer='zeros',name='conv5')(conv4) maxpooling3=MaxPooling2D(pool_size=(3,3),strides=2,name='maxpooling3')(conv5) flatten=Flatten(name='flatten')(maxpooling3) dense1=Dense(512,activation='relu',kernel_initializer=normal_init,name='dense1')(flatten) dropout1=Dropout(0.5)(dense1) dense2=Dense(512,activation='relu', kernel_initializer=normal_init,name='dense2')(dropout1) dropout2=Dropout(0.5)(dense2) outputs=Dense(100,activation='sigmoid',kernel_initializer=normal_init,name='output')(dropout2) model = Model(X, outputs) model.summary() plot_model(model,to_file='AlexNet.png',show_shapes=True)計算圖:
3.訓練網絡
這里使用Keras官方帶數據增強的數據生成器,代碼如下:
#定義數據生成器 from keras.preprocessing import image from keras import optimizers train_gen=image.ImageDataGenerator(featurewise_center=True,#輸入數據數據減去數據集均值width_shift_range=0.2,#水平平移height_shift_range=0.2,#垂直平移horizontal_flip=True,#水平翻轉brightness_range=[-0.1,0.1] #亮度變化范圍 ) #編譯模型 model.compile(loss='categorical_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc']) #訓練圖片路徑 train_dir=r'F:BaiduNetdiskDownloadmini-imagenetimages_normal' tg=train_gen.flow_from_directory(train_dir,target_size=(224,224),batch_size=128,class_mode='categorical' ) tg.class_indices開始訓練。。。
history=model.fit_generator(tg,#訓練數據生成器steps_per_epoch=10,#從生成器中抽取100個批次,epochs=5,#進行30輪訓練shuffle=True, )因為是使用數據放在磁盤上,訓練實在是太慢了,所以意思意思就得了。
參考文獻
[1]Alex Krizhevsky,Ilya Sutskever,Geoffrey E. Hinton.ImageNet Classification with Deep Convolutional
Neural Networks.2012
[2] yangdashi888. 深度學習的局部響應歸一化LRN(Local Response Normalization)理解. https://blog.csdn.net/yangdashi888/article/details/77918311. 2017-09-09
[3] Microstrong0305. 在AlexNet中LRN 局部響應歸一化的理解. https://blog.csdn.net/program_developer/article/details/79430119. 2018-03-03
總結
以上是生活随笔為你收集整理的高斯拟合原理_AlexNet原理和实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 故障模块名称kernelbase.dll
- 下一篇: python能做什么脚本_Python能