一、綜述:
本篇將介紹AlexNet網絡的基本結構。AlexNet網絡是12年Alex Krizhevsky提出的深度網絡模型,故網絡用他的名字命名。該網絡一共有8個訓練參數的網絡(不包括池化層和LRN層),前5層爲卷積層,後3層爲全連接層。最後一個全連接層爲1000類輸出的Softmax分類層。LRN層出現在第1個及第2個卷積層後,最大池化層出現在LRN層及最後一個卷積層。每一層都有ReLu激活函數。
圖片來源:《ImageNet Classification with Deep ConvolutionalNeural Networks》
論文作者訓練網絡時,用了兩塊GPU顯卡,故網絡結構有兩條路徑組成,最後一層合二爲一。
AlexNet網絡參數(此表展示了一個GPU網絡參數)
二、網絡結構(AlexNet_model.py):
1.定義print_activations函數,用來展示卷積層和池化層的輸出tensor尺寸。這個函數的入口接受一個Tensor的作爲輸入,並且顯示結構尺寸:
def print_activations(t):
print(t.op.name, ' ', t.get_shape().as_list())
2.第一個卷積層conv1。TensorFlow的name_scope函數可以區分不同層的組件。用法是
with tf.name_scope('conv1') as scope:能夠將scope中生成的變量自動命名爲conv1/xxxx (後同)。使用tf.truncated_normal截斷的正態分佈函數,標準差爲0.1,初始化卷積核參數kernel;[11, 11, 3, 64]:卷積核的尺寸爲11x11,3個顏色通道,64個卷積核;使用tf.nn.conv2d對輸入的images進行卷積操作,[1, 4, 4, 1]:卷積的核移動步長爲4(橫豎),padding模式選取“SAME”,即全畫幅掃描(最終不改變圖片尺寸);用tf.constant將卷積層的bias全部初始化爲常數0,trainable=True設置bias可以被訓練改變;使用tf.nn.bias_add把conv和biases加起來,用tf.nn.relu做非線性操作;最後使用預先定義的print_activations函數把這一層的conv1的tensor打印出來,並將這層的可訓練參數kernel和biases添加到parameters列表中;使用tf.nn.lrn對輸出的conv1參數進行LRN處理,depth_radius爲4,bias爲1,alpha爲0.001/9,beta爲0.75(基本是論文中的推薦值),LRN層的作用是對局部神經活動創建競爭機制,使得其中響應比較大的值變得相對更大,並抑制其他反饋較小的神經元,增強模型泛化能力(但是目前的神經網絡已經不再使用LRN層操作了,主要是效果不太明顯,反而會一直前饋和反饋的速度(整體速度下降1/3));使用tf.nn.max_pool對前面得到的LRN值做最大池化操作,[1, 3, 3, 1]池化尺寸爲3x3,[1, 2, 2, 1]橫豎移動步長爲2(這種池化尺寸大於移動步長,會有特徵得重複,可以增加特徵的豐富性),padding模式爲“VALID”(不填充,取樣不能超過邊框);最後將輸出結果結構參數pool1打印出來:
# conv1
with tf.name_scope('conv1') as scope:
kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 64], dtype=tf.float32,
stddev=1e-1), name='weights')
conv = tf.nn.conv2d(images, kernel, [1, 4, 4, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),
trainable=True, name='biases')
bias = tf.nn.bias_add(conv, biases)
conv1 = tf.nn.relu(bias, name=scope)
print_activations(conv1)
parameters += [kernel, biases]
# pool1
lrn1 = tf.nn.lrn(conv1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn1')
pool1 = tf.nn.max_pool(lrn1,
ksize=[1, 3, 3, 1],
strides=[1, 2, 2, 1],
padding='VALID',
name='pool1')
print_activations(pool1)
3.第二個卷積層。和第一個卷積層基本一樣,區別在於[5, 5, 64, 192]:卷積核爲5x5,輸入通道數爲第一個卷積層的卷積核數量64,卷積核數量擴充爲192,卷積的步長爲1(全圖像素掃描):
# conv2
with tf.name_scope('conv2') as scope:
kernel = tf.Variable(tf.truncated_normal([5, 5, 64, 192], dtype=tf.float32,
stddev=1e-1), name='weights')
conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[192], dtype=tf.float32),
trainable=True, name='biases')
bias = tf.nn.bias_add(conv, biases)
conv2 = tf.nn.relu(bias, name=scope)
parameters += [kernel, biases]
print_activations(conv2)
# pool2
lrn2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn2')
pool2 = tf.nn.max_pool(lrn2,
ksize=[1, 3, 3, 1],
strides=[1, 2, 2, 1],
padding='VALID',
name='pool2')
print_activations(pool2)
4.第三個卷積層。基本和一、二層卷積類似。區別在[3, 3, 192, 384]:卷積核尺寸爲3x3,輸入通道數爲第二層卷積核數量192,卷積核數量繼續擴充到384,卷積步長爲1,padding爲‘SAME’即:全畫像素掃描,不改變圖像尺寸:
# conv3
with tf.name_scope('conv3') as scope:
kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384],
dtype=tf.float32,
stddev=1e-1), name='weights')
conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
trainable=True, name='biases')
bias = tf.nn.bias_add(conv, biases)
conv3 = tf.nn.relu(bias, name=scope)
parameters += [kernel, biases]
print_activations(conv3)
5.第四個卷積層。和之前的卷積層類似,區別是[3, 3, 384, 256]:卷積核爲3x3,輸入通道數爲384,輸出通道數爲256:
# conv4
with tf.name_scope('conv4') as scope:
kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256],
dtype=tf.float32,
stddev=1e-1), name='weights')
conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
trainable=True, name='biases')
bias = tf.nn.bias_add(conv, biases)
conv4 = tf.nn.relu(bias, name=scope)
parameters += [kernel, biases]
print_activations(conv4)
6.第五個卷積層。[3, 3, 256, 256]:卷積核爲3x3,輸入通道數爲256,輸出通道數爲256:
# conv5
with tf.name_scope('conv5') as scope:
kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256],
dtype=tf.float32,
stddev=1e-1), name='weights')
conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),name='biases')
bias = tf.nn.bias_add(conv, biases)
conv5 = tf.nn.relu(bias, name=scope)
parameters += [kernel, biases]
print_activations(conv5)
# pool5
pool5 = tf.nn.max_pool(conv5,
ksize=[1, 3, 3, 1],
strides=[1, 2, 2, 1],
padding='VALID',
name='pool5')
print_activations(pool5)
7.第一個全連接層。把第五個卷積層輸出結果pool5用tf.reshape函數扁平化成一維向量;用get_shape函數獲取數據扁平化後的數據長度;使用tf.truncated_normal初始化weight,正態分佈標準差定爲0.1,隱藏層節點爲4096,bias初始化爲0;使用tf.nn.relu函數進行非線性化操作;將weights和bias添加到parameters參數列表中;打印fc1的結構參數:
# fc1
with tf.name_scope('fc1') as scope:
reshape = tf.reshape(pool5, [batch_size,-1])
dim = reshape.get_shape()[-1].value
weights = tf.Variable(tf.truncated_normal([dim,4096],dtype=tf.float32,
stddev=1e-1), name='weights')
bias = tf.Variable(tf.constant(0.0, shape=[4096], dtype=tf.float32),name='biases')
fc1 = tf.nn.relu(tf.matmul(reshape,weights) + bias,name=scope)
parameters += [weights, bias]
print_activations(fc1)
8.第二個全連接層。和第一個全連接層基本類似,唯一區別是[4096,4096]:輸入節點爲4096:
# fc2
with tf.name_scope('fc2') as scope:
weights = tf.Variable(tf.truncated_normal([4096,4096],dtype=tf.float32,stddev=1e-1)
,name='weights')
bias = tf.Variable(tf.constant(0.0,shape=[4096], dtype=tf.float32),name='biases')
fc2 = tf.nn.relu(tf.matmul(fc1,weights) + bias,name=scope)
parameters += [weights, bias]
print_activations(fc2)
9.第三個全連接層。和前兩個全連接層基本類似,唯一區別是[4096,1000]:輸出爲1000個分類:
# fc3
with tf.name_scope('fc3') as scope:
weights = tf.Variable(tf.truncated_normal([4096,1000], dtype=tf.float32, stddev=1e-1)
, name='weights')
bias = tf.Variable(tf.constant(0.0, shape=[1000], dtype=tf.float32),name='biases')
logits = tf.nn.relu(tf.matmul(fc2,weights) + bias,name=scope)
parameters += [weights, bias]
print_activations(logits)
一直嘗試着在IMageNet數據集上覆現AlexNet等一些列工作,但硬件設備不允許。故,退而求其次:學習AlexNet的思想,在Cifar-10數據集上,展現經典網絡的威力。
AlexNet網絡的幾點總結:
1.網絡的整體思路架構是:卷積層+池化層+非線性變化層,然後到全連接層將輸入歸結到不同 類別的概率值;
2.LRN層的效果在之後的網絡中表現不佳,故漸漸淡出了人們的視野;
AlexNet思想實現:
1.數據集:CIFAR-10 and CIFAR-100 datasets
2.參考代碼:python+tensorflow1.13