一步一步學(xué)用Tensorflow構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)
2.3 創(chuàng)建一個簡單的一層神經(jīng)網(wǎng)絡(luò)
本文引用地址:http://butianyuan.cn/article/201711/371373.htm神經(jīng)網(wǎng)絡(luò)最簡單的形式是一層線性全連接神經(jīng)網(wǎng)絡(luò)(FCNN, Fully Connected Neural Network)。 在數(shù)學(xué)上它由一個矩陣乘法組成。
最好是在Tensorflow中從這樣一個簡單的NN開始,然后再去研究更復(fù)雜的神經(jīng)網(wǎng)絡(luò)。 當(dāng)我們研究那些更復(fù)雜的神經(jīng)網(wǎng)絡(luò)的時候,只是圖的模型(步驟2)和權(quán)重(步驟3)發(fā)生了改變,其他步驟仍然保持不變。
我們可以按照如下代碼制作一層FCNN:
image_width = mnist_image_width
image_height = mnist_image_height
image_depth = mnist_image_depth
num_labels = mnist_num_labels
#the dataset
train_dataset = mnist_train_dataset
train_labels = mnist_train_labels
test_dataset = mnist_test_dataset
test_labels = mnist_test_labels
#number of iterations and learning rate
num_steps = 10001
display_step = 1000
learning_rate = 0.5
graph = tf.Graph()
with graph.as_default():
#1) First we put the input data in a Tensorflow friendly form.
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_width, image_height, image_depth))
tf_train_labels = tf.placeholder(tf.float32, shape = (batch_size, num_labels))
tf_test_dataset = tf.constant(test_dataset, tf.float32)
#2) Then, the weight matrices and bias vectors are initialized
#as a default, tf.truncated_normal() is used for the weight matrix and tf.zeros() is used for the bias vector.
weights = tf.Variable(tf.truncated_normal([image_width image_height image_depth, num_labels]), tf.float32)
bias = tf.Variable(tf.zeros([num_labels]), tf.float32)
#3) define the model:
#A one layered fccd simply consists of a matrix multiplication
def model(data, weights, bias):
return tf.matmul(flatten_tf_array(data), weights) + bias
logits = model(tf_train_dataset, weights, bias)
#4) calculate the loss, which will be used in the optimization of the weights
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=tf_train_labels))
#5) Choose an optimizer. Many are available.
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
#6) The predicted values for the images in the train dataset and test dataset are assigned to the variables train_prediction and test_prediction.
#It is only necessary if you want to know the accuracy by comparing it with the actual values.
train_prediction = tf.nn.softmax(logits)
test_prediction = tf.nn.softmax(model(tf_test_dataset, weights, bias))
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
print('Initialized')
for step in range(num_steps):
_, l, predictions = session.run([optimizer, loss, train_prediction])
if (step % display_step == 0):
train_accuracy = accuracy(predictions, train_labels[:, :])
test_accuracy = accuracy(test_prediction.eval(), test_labels)
message = "step {:04d} : loss is {:06.2f}, accuracy on training set {:02.2f} %, accuracy on test set {:02.2f} %".format(step, l, train_accuracy, test_accuracy)
print(message)
>>> Initialized
>>> step 0000 : loss is 2349.55, accuracy on training set 10.43 %, accuracy on test set 34.12 %
>>> step 0100 : loss is 3612.48, accuracy on training set 89.26 %, accuracy on test set 90.15 %
>>> step 0200 : loss is 2634.40, accuracy on training set 91.10 %, accuracy on test set 91.26 %
>>> step 0300 : loss is 2109.42, accuracy on training set 91.62 %, accuracy on test set 91.56 %
>>> step 0400 : loss is 2093.56, accuracy on training set 91.85 %, accuracy on test set 91.67 %
>>> step 0500 : loss is 2325.58, accuracy on training set 91.83 %, accuracy on test set 91.67 %
>>> step 0600 : loss is 22140.44, accuracy on training set 68.39 %, accuracy on test set 75.06 %
>>> step 0700 : loss is 5920.29, accuracy on training set 83.73 %, accuracy on test set 87.76 %
>>> step 0800 : loss is 9137.66, accuracy on training set 79.72 %, accuracy on test set 83.33 %
>>> step 0900 : loss is 15949.15, accuracy on training set 69.33 %, accuracy on test set 77.05 %
>>> step 1000 : loss is 1758.80, accuracy on training set 92.45 %, accuracy on test set 91.79 %
在圖中,我們加載數(shù)據(jù),定義權(quán)重矩陣和模型,從分對數(shù)矢量中計算損失值,并將其傳遞給優(yōu)化器,該優(yōu)化器將更新迭代“num_steps”次數(shù)的權(quán)重。
在上述完全連接的NN中,我們使用了梯度下降優(yōu)化器來優(yōu)化權(quán)重。然而,有很多不同的優(yōu)化器可用于Tensorflow。 最常用的優(yōu)化器有GradientDescentOptimizer、AdamOptimizer和AdaGradOptimizer,所以如果你正在構(gòu)建一個CNN的話,我建議你試試這些。
Sebastian Ruder有一篇不錯的博文介紹了不同優(yōu)化器之間的區(qū)別,通過這篇文章,你可以更詳細(xì)地了解它們。
2.4 Tensorflow的幾個方面
Tensorflow包含許多層,這意味著可以通過不同的抽象級別來完成相同的操作。這里有一個簡單的例子,操作
logits = tf.matmul(tf_train_dataset, weights) + biases,
也可以這樣來實現(xiàn)
logits = tf.nn.xw_plus_b(train_dataset, weights, biases)。
這是layers API中最明顯的一層,它是一個具有高度抽象性的層,可以很容易地創(chuàng)建由許多不同層組成的神經(jīng)網(wǎng)絡(luò)。例如,conv_2d()或fully_connected()函數(shù)用于創(chuàng)建卷積和完全連接的層。通過這些函數(shù),可以將層數(shù)、過濾器的大小或深度、激活函數(shù)的類型等指定為參數(shù)。然后,權(quán)重矩陣和偏置矩陣會自動創(chuàng)建,一起創(chuàng)建的還有激活函數(shù)和丟棄正則化層(dropout regularization laye)。
例如,通過使用 層API,下面這些代碼:
import Tensorflow as tf
w1 = tf.Variable(tf.truncated_normal([filter_size, filter_size, image_depth, filter_depth], stddev=0.1))
b1 = tf.Variable(tf.zeros([filter_depth]))
layer1_conv = tf.nn.conv2d(data, w1, [1, 1, 1, 1], padding='SAME')
layer1_relu = tf.nn.relu(layer1_conv + b1)
layer1_pool = tf.nn.max_pool(layer1_pool, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
可以替換為
from tflearn.layers.conv import conv_2d, max_pool_2d
layer1_conv = conv_2d(data, filter_depth, filter_size, activation='relu')
layer1_pool = max_pool_2d(layer1_conv_relu, 2, strides=2)
可以看到,我們不需要定義權(quán)重、偏差或激活函數(shù)。尤其是在你建立一個具有很多層的神經(jīng)網(wǎng)絡(luò)的時候,這樣可以保持代碼的清晰和整潔。
然而,如果你剛剛接觸Tensorflow的話,學(xué)習(xí)如何構(gòu)建不同種類的神經(jīng)網(wǎng)絡(luò)并不合適,因為tflearn做了所有的工作。
因此,我們不會在本文中使用層API,但是一旦你完全理解了如何在Tensorflow中構(gòu)建神經(jīng)網(wǎng)絡(luò),我還是建議你使用它。
2.5 創(chuàng)建 LeNet5 卷積神經(jīng)網(wǎng)絡(luò)
下面我們將開始構(gòu)建更多層的神經(jīng)網(wǎng)絡(luò)。例如LeNet5卷積神經(jīng)網(wǎng)絡(luò)。
LeNet5 CNN架構(gòu)最早是在1998年由Yann Lecun(見論文)提出的。它是最早的CNN之一,專門用于對手寫數(shù)字進行分類。盡管它在由大小為28 x 28的灰度圖像組成的MNIST數(shù)據(jù)集上運行良好,但是如果用于其他包含更多圖片、更大分辨率以及更多類別的數(shù)據(jù)集時,它的性能會低很多。對于這些較大的數(shù)據(jù)集,更深的ConvNets(如AlexNet、VGGNet或ResNet)會表現(xiàn)得更好。
但由于LeNet5架構(gòu)僅由5個層構(gòu)成,因此,學(xué)習(xí)如何構(gòu)建CNN是一個很好的起點。
Lenet5架構(gòu)如下圖所示:
我們可以看到,它由5個層組成:
第1層:卷積層,包含S型激活函數(shù),然后是平均池層。
第2層:卷積層,包含S型激活函數(shù),然后是平均池層。
第3層:一個完全連接的網(wǎng)絡(luò)(S型激活)
第4層:一個完全連接的網(wǎng)絡(luò)(S型激活)
第5層:輸出層
這意味著我們需要創(chuàng)建5個權(quán)重和偏差矩陣,我們的模型將由12行代碼組成(5個層 + 2個池 + 4個激活函數(shù) + 1個扁平層)。
由于這個還是有一些代碼量的,因此最好在圖之外的一個單獨函數(shù)中定義這些代碼。
LENET5_BATCH_SIZE = 32
LENET5_PATCH_SIZE = 5
LENET5_PATCH_DEPTH_1 = 6
LENET5_PATCH_DEPTH_2 = 16
LENET5_NUM_HIDDEN_1 = 120
LENET5_NUM_HIDDEN_2 = 84
def variables_lenet5(patch_size = LENET5_PATCH_SIZE, patch_depth1 = LENET5_PATCH_DEPTH_1,
patch_depth2 = LENET5_PATCH_DEPTH_2,
num_hidden1 = LENET5_NUM_HIDDEN_1, num_hidden2 = LENET5_NUM_HIDDEN_2,
image_depth = 1, num_labels = 10):
w1 = tf.Variable(tf.truncated_normal([patch_size, patch_size, image_depth, patch_depth1], stddev=0.1))
b1 = tf.Variable(tf.zeros([patch_depth1]))
w2 = tf.Variable(tf.truncated_normal([patch_size, patch_size, patch_depth1, patch_depth2], stddev=0.1))
b2 = tf.Variable(tf.constant(1.0, shape=[patch_depth2]))
w3 = tf.Variable(tf.truncated_normal([55patch_depth2, num_hidden1], stddev=0.1))
b3 = tf.Variable(tf.constant(1.0, shape = [num_hidden1]))
w4 = tf.Variable(tf.truncated_normal([num_hidden1, num_hidden2], stddev=0.1))
b4 = tf.Variable(tf.constant(1.0, shape = [num_hidden2]))
w5 = tf.Variable(tf.truncated_normal([num_hidden2, num_labels], stddev=0.1))
b5 = tf.Variable(tf.constant(1.0, shape = [num_labels]))
variables = {
'w1': w1, 'w2': w2, 'w3': w3, 'w4': w4, 'w5': w5,
'b1': b1, 'b2': b2, 'b3': b3, 'b4': b4, 'b5': b5
}
return variables
def model_lenet5(data, variables):
layer1_conv = tf.nn.conv2d(data, variables['w1'], [1, 1, 1, 1], padding='SAME')
layer1_actv = tf.sigmoid(layer1_conv + variables['b1'])
layer1_pool = tf.nn.avg_pool(layer1_actv, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
layer2_conv = tf.nn.conv2d(layer1_pool, variables['w2'], [1, 1, 1, 1], padding='VALID')
layer2_actv = tf.sigmoid(layer2_conv + variables['b2'])
layer2_pool = tf.nn.avg_pool(layer2_actv, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
flat_layer = flatten_tf_array(layer2_pool)
layer3_fccd = tf.matmul(flat_layer, variables['w3']) + variables['b3']
layer3_actv = tf.nn.sigmoid(layer3_fccd)
layer4_fccd = tf.matmul(layer3_actv, variables['w4']) + variables['b4']
layer4_actv = tf.nn.sigmoid(layer4_fccd)
logits = tf.matmul(layer4_actv, variables['w5']) + variables['b5']
return logits
由于變量和模型是單獨定義的,我們可以稍稍調(diào)整一下圖,以便讓它使用這些權(quán)重和模型,而不是以前的完全連接的NN:
#parameters determining the model size
image_size = mnist_image_size
num_labels = mnist_num_labels
#the datasets
train_dataset = mnist_train_dataset
train_labels = mnist_train_labels
test_dataset = mnist_test_dataset
test_labels = mnist_test_labels
#number of iterations and learning rate
num_steps = 10001
display_step = 1000
learning_rate = 0.001
graph = tf.Graph()
with graph.as_default():
#1) First we put the input data in a Tensorflow friendly form.
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_width, image_height, image_depth))
tf_train_labels = tf.placeholder(tf.float32, shape = (batch_size, num_labels))
tf_test_dataset = tf.constant(test_dataset, tf.float32)
#2) Then, the weight matrices and bias vectors are initialized
variables = variables_lenet5(image_depth = image_depth, num_labels = num_labels)
#3. The model used to calculate the logits (predicted labels)
model = model_lenet5
logits = model(tf_train_dataset, variables)
#4. then we compute the softmax cross entropy between the logits and the (actual) labels
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=tf_train_labels))
#5. The optimizer is used to calculate the gradients of the loss function
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
# Predictions for the training, validation, and test data.
train_prediction = tf.nn.softmax(logits)
test_prediction = tf.nn.softmax(model(tf_test_dataset, variables))
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
print('Initialized with learning_rate', learning_rate)
for step in range(num_steps):
#Since we are using stochastic gradient descent, we are selecting small batches from the training dataset,
#and training the convolutional neural network each time with a batch.
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
batch_data = train_dataset[offset:(offset + batch_size), :, :, :]
batch_labels = train_labels[offset:(offset + batch_size), :]
feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels}
_, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict=feed_dict)
if step % display_step == 0:
train_accuracy = accuracy(predictions, batch_labels)
test_accuracy = accuracy(test_prediction.eval(), test_labels)
message = "step {:04d} : loss is {:06.2f}, accuracy on training set {:02.2f} %, accuracy on test set {:02.2f} %".format(step, l, train_accuracy, test_accuracy)
print(message)
>>> Initialized with learning_rate 0.1
>>> step 0000 : loss is 002.49, accuracy on training set 3.12 %, accuracy on test set 10.09 %
>>> step 1000 : loss is 002.29, accuracy on training set 21.88 %, accuracy on test set 9.58 %
>>> step 2000 : loss is 000.73, accuracy on training set 75.00 %, accuracy on test set 78.20 %
>>> step 3000 : loss is 000.41, accuracy on training set 81.25 %, accuracy on test set 86.87 %
>>> step 4000 : loss is 000.26, accuracy on training set 93.75 %, accuracy on test set 90.49 %
>>> step 5000 : loss is 000.28, accuracy on training set 87.50 %, accuracy on test set 92.79 %
>>> step 6000 : loss is 000.23, accuracy on training set 96.88 %, accuracy on test set 93.64 %
>>> step 7000 : loss is 000.18, accuracy on training set 90.62 %, accuracy on test set 95.14 %
>>> step 8000 : loss is 000.14, accuracy on training set 96.88 %, accuracy on test set 95.80 %
>>> step 9000 : loss is 000.35, accuracy on training set 90.62 %, accuracy on test set 96.33 %
>>> step 10000 : loss is 000.12, accuracy on training set 93.75 %, accuracy on test set 96.76 %
我們可以看到,LeNet5架構(gòu)在MNIST數(shù)據(jù)集上的表現(xiàn)比簡單的完全連接的NN更好。
評論