經典卷積神經網路演算法(2):AlexNet

 

上文中實現了LeNet-5卷積網路,不可否認這是一個十分經典的網路結構,但是迫於種種複雜的現實場景限制,只能在一些領域應用,所以在接下來的10年間,卷積網路的鋒芒一度被SVN演算法覆蓋,直到2012年AlexNet的提出。2012年Imagenet影像識別大賽中,Alext提出的AlexNet網路模型一鳴驚人,引爆了神經網路的應用熱潮,並且贏得了2012屆影像識別大賽的冠軍,這也使得卷積神經網路真正意義上成為影像處理上的核心演算法。AlexNet網路相比於之前的卷積網路模型有以下幾點創新:
(1)使用relu作為激活函數。在上世紀末,神經網路大多還是使用sigmod或tanh作為激活函數,使用relu作為激活函數是AlexNet網路開創的先河。
(2)使用GPU並行運算。AlexNet使用兩張GPU同時訓練模型,大大加快了模型訓練的速度。
(3)最大池化。在AlexNet出現以前,大多使用平均池化。
(4)dropout操作。隨機殺死部分神經元,防止過擬合。
(5)數據增強。從原始圖片中隨機截取固定大小的子圖,構建更大規模數據集。

 

AlexNet網路結構如下圖所示(註:圖片來源於部落格)。

 

 

接下來,我們使用TensorFlow實現AlexNet,數據集為cifar100。

In [1]:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers, Sequential ,metrics
 

載入數據並查看數據情況:

In [2]:
(x, y), (x_test, y_test) = datasets.cifar100.load_data()
In [3]:
print(x.shape, y.shape)
print(x_test.shape, y_test.shape)
 
(50000, 32, 32, 3) (50000, 1)
(10000, 32, 32, 3) (10000, 1)
In [4]:
index = 1
fig, axes = plt.subplots(4, 3, figsize=(8, 4), tight_layout=True)
for row in range(4):
    for col in range(3):
        axes[row, col].imshow(x[index])
        axes[row, col].axis('off')
        axes[row, col].set_title(y[index][0])
        index += 1
plt.show()
 
 

從上述y值shape可出,其元素也是是數組形式,進行squeeze對元素轉換為具體值,方便後續操作:

In [5]:
y = tf.squeeze(y, axis=1)
y_test = tf.squeeze(y_test, axis=1)
 

定義預處理函數:

In [6]:
def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32) / 255.  # 將每個像素值映射到[0, 1]內
    y = tf.cast(y, dtype=tf.float32)
    return x, y
In [7]:
train_db = tf.data.Dataset.from_tensor_slices((x, y))
train_db = train_db.shuffle(1000).map(preprocess).batch(64)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.shuffle(1000).map(preprocess).batch(64)
 

開始創建模型:

In [14]:
model = Sequential([
    layers.Conv2D(96,(11,11),strides=(2,2),# input_shape=(in_shape[1],in_shape[2],in_shape[3]),
                padding='same',activation='relu',kernel_initializer='uniform'),
    layers.MaxPooling2D(pool_size=(3,3),strides=(2,2)),
    layers.Conv2D(256,(5,5),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'),
    layers.MaxPooling2D(pool_size=(3,3),strides=(2,2)),
    layers.Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'),
    layers.Conv2D(384,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'),
    layers.Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'),
    layers.MaxPooling2D(pool_size=(2,2),strides=(2,2)),
    layers.Flatten(),
    layers.Dense(2048,activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(2048,activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(100,activation='softmax')
])
In [15]:
model.compile(optimizer=keras.optimizers.Adam(),loss='sparse_categorical_crossentropy', metrics=['accuracy'])
In [16]:
model.build(input_shape=[None, 32, 32, 3])  # 指定輸入
 

檢測一下輸出shape是否正常:

In [17]:
x = tf.random.normal([1, 32, 32, 3])  # 1是指輸入一張影像,兩個32是影像長寬,3是指3通道
out = model(x)
out.shape
Out[17]:
TensorShape([1, 100])
In [19]:
model.fit(train_db,epochs=5, validation_data=test_db)  # 訓練模型
 
Train for 782 steps, validate for 157 steps
Epoch 1/5
782/782 [==============================] - 301s 386ms/step - loss: 4.3788 - accuracy: 0.0253 - val_loss: 4.2012 - val_accuracy: 0.0426
Epoch 2/5
782/782 [==============================] - 301s 385ms/step - loss: 4.1368 - accuracy: 0.0516 - val_loss: 4.0282 - val_accuracy: 0.0688
Epoch 3/5
782/782 [==============================] - 301s 385ms/step - loss: 4.0186 - accuracy: 0.0690 - val_loss: 3.9264 - val_accuracy: 0.0859
Epoch 4/5
782/782 [==============================] - 301s 385ms/step - loss: 3.9193 - accuracy: 0.0870 - val_loss: 3.8942 - val_accuracy: 0.0957
Epoch 5/5
782/782 [==============================] - 301s 385ms/step - loss: 3.8103 - accuracy: 0.1084 - val_loss: 3.7646 - val_accuracy: 0.1143
Out[19]:
<tensorflow.python.keras.callbacks.History at 0x7f7a0c223710>
 

從上面訓練過程輸出看一看出,每一次迭代loss都在降低而準確率逐漸升高,經過5輪迭代之後準確率達到11.43%。