TensorFlow 學習(5)——進一步了解MNIST
接TensorFlow(3)
我們構建一個多層卷積網絡,以提升MNIST的識別性能
權重初始化
為了創建這個模型,我們需要創建大量的權重和偏執項。這個模型中的權重在初始化是應該加入少量的噪聲來打破對稱性以及避免0梯度。由於我們使用的是ReLU神經元,因此比較好的做法是用一個較小的正數來初始化偏執項。以避免神經元節點輸出恒為0 的問題(dead neurons)。為了不在建立模型的時候反復做初始化操作,我們定義兩個函數用於初始化。
# 初始化權重
def weight_variable(shape):
initial = tf.truncated_normal(shape,sddev = 0.1)
return tf.Variable(initial)
# 初始化偏差
def bias_variable(shape):
initial = tf.constant(0.1,shape = shape)
return tf.Variable(initial)
W = weight_variable([784,10])
b = bias_variable(tf.zeros([10]))
#Variable 表示一個可以修改的張量。它們可以用於計算輸入值,也可以在計算中被修改。
卷積和池化
TensorFlow在卷積和池化上有很強的靈活性。我們怎麽處理邊界?步長應該設為多大?這裏我們使用vanilla版本。我們的卷積使用1步長(stride size),0邊距(padding size)(就是上一章說的填充值)的模板,保證輸出和輸入是同一個大小。我們的池化用簡單傳統的2*2大小的模板做maxpooling。我們這倆抽象成函數。
# 卷積,1步長(stride size),0邊距(padding size),保證輸入和輸出是同一個大小
def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding=‘SAME‘)#‘SAME’表示填充後,保證輸出和輸入的大小相同
# 池化,2*2
def max_pool_2x2(x) :
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding=‘SAME‘)
第一層卷積
現在我們可以開始實現第一層了。它由一個卷積接一個max pooling完成。卷積在每個5*5的patch中算出32個特征。卷積的權重張量形狀是[5,5,1,32],表示patch的大小,輸入的通道數目和輸出的通道數目。而對於每一個輸出通道都就一個對應的偏置量。
W_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])
為了用這一層,我們把x變成一個4d向量,其第2,3維分別對應圖片的寬和高,最後一維代表圖片的顏色通道數(灰度圖為1,gbr圖為3)
x_image = tf.reshape(x,[-1,28,28,1])
我們把x_image和權值向量進行卷積,加上偏置項,然後應用ReLU激活函數,最後進行max pooling。
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
第二層卷積
為了構建更深的網絡,我們會把幾個類似的層堆疊起來。第二層中,每個5*5的patch會得到64個特征。
W_conv2 = weight_variable([5.5.32,64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
密集連接層
現在圖片尺寸減小到了7*7(第一部輸入28*28輸出28*28,池化後除2,14*14;第二層輸入14*14輸出14*14,池化後7*7),我們加入一個有1024個神經元(即又1024個輸出)的全連接層,用於處理整個圖片。我們把池化層輸出的張量reshape成一些向量,乘上權重矩陣,加上偏置,然後對其使用ReLU。
W_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1) + b_fc1)
dropout
為了減少過擬合,我們在輸出層之前加入dropout。我們用一個placeholder來代表一個神經元的輸出在dropout中保持不變的概率。這樣我們可以在訓練過程中啟用dropout,在測試過程中關閉dropout。TensorFlow的tf.nn.dropout操作處理可以屏蔽神經元的輸出外,還會自動處理神經元輸出值的scale。所以用dropout的時候不用考慮scale。
# dropout
keep_prob = tf.placeholder(‘float‘)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
輸出層
最後我們加一個softmax層。就像前面的單層softmax regression一樣
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)
訓練和評估模型
這個模型的效果如何呢?
為了進行訓練和評估,我們使用與之前簡單的單層SoftMax神經網絡模型幾乎相同的一套代碼,只是我們會用更加復雜的ADAM優化器來做梯度最速下降,在feed_dict
中加入額外的參數keep_prob
來控制dropout比例。然後每100次叠代輸出一次日誌。
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0})
print "step %d, training accuracy %g"%(i, train_accuracy)
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print "test accuracy %g"%accuracy.eval(feed_dict={
x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0})
TensorFlow 學習(5)——進一步了解MNIST