tensorflow實現AlexNet
AlexNet是Hinton的學生Alex Krizhevsky在2012年提出的深度卷積神經網路,它是LeNet一種更深更寬的版本。在AlexNet上首次應用了幾個trick,ReLU、Dropout和LRN。AlexNet包含了6億3000萬個連線,6000萬個引數和65萬個神經元,有5個卷積層,3個全連線層。在ILSVRC 2012比賽中,AlexNet以top-5的錯誤率為16.4%的顯著優勢奪得冠軍,第二名的成績是26.2%。AlexNet的trick主要包括:
1、成功使用RELU作為CNN的啟用函式,並驗證其效果在較深的網路中的效果超過了sigmoid,解決了sigmoid在深層的網路中的梯度彌散的問題。
2、使用Dropout來隨機使得一部分神經元失活,來避免模型的過擬合,在AlexNet中,dropout主要應用在全連線層。
3、使用重疊的最大池化,以前在卷積神經網路中大部分都採用平均池化,在AlexNet中都是使用最大池化,最大池化可以避免平均池化的模糊化效果。重疊的最大池化是指卷積核的尺寸要大於步長,這樣池化層的輸出之間會有重疊和覆蓋,提升特徵的豐富性。在AlexNet中使用的卷積核大小為3×3,橫向和縱向的步長都為2。
4、使用LRN層,對區域性神經元的活動建立有競爭機制,讓響應較大的值變得相對更大,並抑制反饋較小的神經元,來增強模型的泛化能力。
5、使用了CUDA來加速深度神經網路的訓練。
6、資料增強,隨機從256×256的原始影象中擷取224×224的影象以及隨機翻轉。如果沒有資料增強,在引數眾多的情況下,卷積神經網路會陷入到過擬閤中,使用資料增強可以減緩過擬合,提升泛化能力。進行預測的時候,提取圖片的四個角加中間位置,並進行左右翻轉,一共10張圖片,對它們進行預測並取10次結果的平均值。在AlexNet論文中也提到了,對影象的RGB資料進行PCA處理,並做一個標準差為0.1的高斯擾動,增加一些噪聲,可以降低1%的錯誤率。
1、第一層卷積層
第一層卷積一共有64個11×11×3大小的卷積核,橫向和縱向的步長都為4,初始化權重使用截斷的正態分佈進行初始化,經過ReLU啟用函式之後,再通過LRN層,再使用重疊的最大池化。
#第一層卷積層
with tf.name_scope("conv1") as scope:
#設定卷積核11×11,3通道,64個卷積核
kernel1 = tf.Variable(tf.truncated_normal([11,11,3,64],mean=0,stddev=0.1,
dtype=tf.float32),name="weights")
#卷積,卷積的橫向步長和豎向步長都為4
conv = tf.nn.conv2d(images,kernel1,[1,4,4,1],padding="SAME")
#初始化偏置
biases = tf.Variable(tf.constant(0,shape=[64],dtype=tf.float32),trainable=True,name="biases")
bias = tf.nn.bias_add(conv,biases)
#RELU啟用函式
conv1 = tf.nn.relu(bias,name=scope)
#輸出該層的資訊
print_tensor_info(conv1)
#統計引數
parameters += [kernel1,biases]
#lrn處理
lrn1 = tf.nn.lrn(conv1,4,bias=1,alpha=1e-3/9,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_tensor_info(pool1)
2、第二層卷積層
第二層卷積層的結構和第一層大致相似,卷積層的大小由11×11變成了5×5,有192個卷積核。
#第二層卷積層
with tf.name_scope("conv2") as scope:
#初始化權重
kernel2 = tf.Variable(tf.truncated_normal([5,5,64,192],dtype=tf.float32,stddev=0.1)
,name="weights")
conv = tf.nn.conv2d(pool1,kernel2,[1,1,1,1],padding="SAME")
#初始化偏置
biases = tf.Variable(tf.constant(0,dtype=tf.float32,shape=[192])
,trainable=True,name="biases")
bias = tf.nn.bias_add(conv,biases)
#RELU啟用
conv2 = tf.nn.relu(bias,name=scope)
print_tensor_info(conv2)
parameters += [kernel2,biases]
#LRN
lrn2 = tf.nn.lrn(conv2,4,1.0,alpha=1e-3/9,beta=0.75,name="lrn2")
#最大池化
pool2 = tf.nn.max_pool(lrn2,[1,3,3,1],[1,2,2,1],padding="VALID",name="pool2")
print_tensor_info(pool2)
3、第三層卷積層
第三層卷積層卷積核的個數是第二層的一倍,第三層卷積層沒有使用LRN層和最大池化。
#第三層卷積層
with tf.name_scope("conv3") as scope:
#初始化權重
kernel3 = tf.Variable(tf.truncated_normal([3,3,192,384],dtype=tf.float32,stddev=0.1)
,name="weights")
conv = tf.nn.conv2d(pool2,kernel3,strides=[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)
#RELU啟用層
conv3 = tf.nn.relu(bias,name=scope)
parameters += [kernel3,biases]
print_tensor_info(conv3)
4、第四層卷積層
#第四層卷積層
with tf.name_scope("conv4") as scope:
#初始化權重
kernel4 = tf.Variable(tf.truncated_normal([3,3,384,256],stddev=0.1,dtype=tf.float32),
name="weights")
#卷積
conv = tf.nn.conv2d(conv3,kernel4,strides=[1,1,1,1],padding="SAME")
biases = tf.Variable(tf.constant(0.0,dtype=tf.float32,shape=[256]),trainable=True,name="biases")
bias = tf.nn.bias_add(conv,biases)
#RELU啟用
conv4 = tf.nn.relu(bias,name=scope)
parameters += [kernel4,biases]
print_tensor_info(conv4)
5、第五層卷積層
#第五層卷積層
with tf.name_scope("conv5") as scope:
#初始化權重
kernel5 = tf.Variable(tf.truncated_normal([3,3,256,256],stddev=0.1,dtype=tf.float32),
name="weights")
conv = tf.nn.conv2d(conv4,kernel5,strides=[1,1,1,1],padding="SAME")
biases = tf.Variable(tf.constant(0.0,dtype=tf.float32,shape=[256]),name="biases")
bias = tf.nn.bias_add(conv,biases)
#REUL啟用層
conv5 = tf.nn.relu(bias)
parameters += [kernel5,bias]
#最大池化
pool5 = tf.nn.max_pool(conv5,[1,3,3,1],[1,2,2,1],padding="VALID",name="pool5")
print_tensor_info(pool5)
6、最後三層全連線層和softmax層
#第六層全連線層
pool5 = tf.reshape(pool5,(-1,6*6*256))
weight6 = tf.Variable(tf.truncated_normal([6*6*256,4096],stddev=0.1,dtype=tf.float32),
name="weight6")
ful_bias1 = tf.Variable(tf.constant(0.0,dtype=tf.float32,shape=[4096]),name="ful_bias1")
ful_con1 = tf.nn.relu(tf.add(tf.matmul(pool5,weight6),ful_bias1))
#第七層第二層全連線層
weight7 = tf.Variable(tf.truncated_normal([4096,4096],stddev=0.1,dtype=tf.float32),
name="weight7")
ful_bias2 = tf.Variable(tf.constant(0.0,dtype=tf.float32,shape=[4096]),name="ful_bias2")
ful_con2 = tf.nn.relu(tf.add(tf.matmul(ful_con1,weight7),ful_bias2))
#
#第八層第三層全連線層
weight8 = tf.Variable(tf.truncated_normal([4096,1000],stddev=0.1,dtype=tf.float32),
name="weight8")
ful_bias3 = tf.Variable(tf.constant(0.0,dtype=tf.float32,shape=[1000]),name="ful_bias3")
ful_con3 = tf.nn.relu(tf.add(tf.matmul(ful_con2,weight8),ful_bias3))
#softmax層
weight9 = tf.Variable(tf.truncated_normal([1000,10],stddev=0.1),dtype=tf.float32,name="weight9")
bias9 = tf.Variable(tf.constant(0.0,shape=[10]),dtype=tf.float32,name="bias9")
output_softmax = tf.nn.softmax(tf.matmul(ful_con3,weight9)+bias9)
7、評估模型效能
通過使用模擬出來的圖片來評估模型在訓練過程中的耗時。
#主函式
def run_bechmark():
with tf.Graph().as_default():
image_size = 224
#以高斯分佈產生一些圖片
images = tf.Variable(tf.random_normal([batch_size,image_size,image_size,3],
dtype=tf.float32,stddev=0.1))
output,parameters = inference(images)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
time_tensorflow_run(sess,output,"Forward")
objective = tf.nn.l2_loss(output)
grad = tf.gradients(objective,parameters)
time_tensorflow_run(sess,grad,"Forward-backward")