1. 程式人生 > >【深度學習】Alexnet網路分析及程式碼實現

【深度學習】Alexnet網路分析及程式碼實現

簡介

Alexnet是2012年ImageNet比賽的冠軍Hinton及其學生Alex Krizhevsky提出,並以其姓名命名的網路。Alexnet的提出也正式掀起了深度學習的熱潮,激發了研究者對深度學習的熱情。雖然後面出現了更為優秀的VGGNet、GooLeNet、ResNet等網路,但是Alexnet的地位是不可撼動的,因此我們有必要去花些時間瞭解一下這一深度學習史上的偉大傑作。

網路結構

上圖為論文中的網路結構圖。因為論文中使用了兩塊GPU進行訓練,所以有兩個分支。為了使網路結構看起來更加直觀,將網路結構簡化為下圖,

Alexnet共包含5個卷積層和3個全連線層,其中第1,2,5個卷積層後接最大池化和LRN操作。

主要貢獻

1. 使用ReLU代替Sigmoid作為啟用函式,成功解決了Sigmoid在網路較深時的梯度彌散問題;

2. 最後幾個全連線層使用Dropout,避免過擬合;

3. 使用了重疊最大池化操作,即池化步長比池化核尺寸小,提升了特徵的豐富性。此前CNN普遍採用平均池化,最大池化能夠避免平均池化的模糊化效果;

4. 提出了LRN層。LRN全稱Local Response Normalization,對區域性神經元建立競爭機制,增大響應大的單元,抑制反饋小的神經元,增強了模型的泛化能力。(VGGNet沒有使用LRN,作者表示LRN對模型沒有提升,而且引數量大,當然不能以偏概全);

5. 使用CUDA利用GPU加速深度卷積網路的訓練。

6. 資料增強。通過隨機裁剪、旋轉、翻轉等操作,減輕過擬合,提升模型泛化效能。

程式碼實現

本文使用Keras實現Alexnet網路。

from keras.layers import Input
from keras.layers import Conv2D, MaxPool2D, Dense, Flatten, Dropout, Lambda
from keras.models import Model
from keras import optimizers
from keras.utils import plot_model
from keras import backend as K


def LRN(alpha=1e-4, k=2, beta=0.75, n=5):
    """
    LRN for cross channel normalization in the original Alexnet
    parameters default as original paper.
    """
    def f(X):
        b, r, c, ch = X.shape
        half = n // 2
        square = K.square(X)
        extra_channels = K.spatial_2d_padding(square, ((0, 0), (half, half)), data_format='channels_first')
        scale = k
        for i in range(n):
            scale += alpha * extra_channels[:,:,:,i:i+int(ch)]
        scale = scale ** beta
        return X / scale

    return Lambda(f, output_shape=lambda input_shape: input_shape)


def alexnet(input_shape=(224,224,3), nclass=1000):
    """
    build Alexnet model using keras with TensorFlow backend.
    :param input_shape: input shape of network, default as (224,224,3)
    :param nclass: numbers of class(output shape of network), default as 1000
    :return: Alexnet model
    """
    input_ = Input(shape=input_shape)

    x = Conv2D(96, kernel_size=(11, 11), strides=(4, 4), activation='relu')(input_)
    x = LRN()(x)
    x = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(x)

    x = Conv2D(256, kernel_size=(5, 5), strides=(1, 1), activation='relu', padding='same')(x)
    x = LRN()(x)
    x = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(x)

    x = Conv2D(384, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same')(x)
    x = Conv2D(384, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same')(x)
    x = Conv2D(256, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same')(x)
    x = MaxPool2D(pool_size=(3, 3), strides=(2, 2))(x)

    x = Flatten()(x)
    x = Dense(4096, activation='relu')(x)
    x = Dropout(0.5)(x)
    x = Dense(4096, activation='relu')(x)
    x = Dropout(0.5)(x)

    output_ = Dense(nclass, activation='softmax')(x)

    model = Model(inputs=input_, outputs=output_)
    model.summary()

    opti_sgd = optimizers.sgd(lr=0.01, momentum=0.9, nesterov=True)

    model.compile(loss='categorical_crossentropy', optimizer=opti_sgd, metrics=['accuracy'])

    return model

if __name__ == '__main__':
    model = alexnet()
    plot_model(model, 'Alexnet.png', show_shapes=True)  # 儲存模型圖