一、載入MNIST資料
TensorFlow已經準備了一個指令碼來自動下載和匯入MNIST資料集。它會自動建立一個'MNIST_data'的目錄來儲存資料。
import tensorflow as tf
import numpy as np
import random
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)
# one_hot介紹 :https://blog.csdn.net/lanhaier0591/article/details/78702558
複製程式碼
這裡,mnist是一個輕量級的類。它以Numpy陣列的形式儲存著訓練、校驗和測試資料集。同時提供了一個函式,用於在迭代中獲得minibatch,後面我們將會用到。
原文連結:http://www.tensorfly.cn/tfdoc/tutorials/mnist_download.html
二、輸入與佔位符
placeholder_inputs()函式將生成兩個tf.placeholder操作,定義傳入圖表中的shape引數,shape引數中包括batch_size值,後續還會將實際的訓練用例傳入圖表。
imageInput = tf.placeholder(tf.float32,[None,784])
# 訓練影象
labeInput = tf.placeholder(tf.float32,[None,10])
# 訓練標籤
複製程式碼
三、構建一個多層卷積網路
1、權重初始化
reshape(tensor, shape, name=None)
引數
- tensor,被調整維度的張量
- shape,要調整為的形狀
imageInputReshape = tf.reshape(imageInput,[-1,28,28,1])
# 2維轉變為4維
複製程式碼
tf.truncated_normal(shape, mean, stddev)
引數
- shape表示生成張量的維度,
- mean是均值,
- stddev是標準差。
w0 = tf.Variable(tf.truncated_normal([5,5,1,32],stddev = 0.1))
# 求標準差
b0 = tf.Variable(tf.constant(0.1,shape=[32]))
# 生成一個32維的張量
複製程式碼
2、激勵函式+卷積運算
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
引數
- input:指需要做卷積的輸入影象,它要求是一個Tensor,具有[batch, in_height, in_width, in_channels]這樣的shape,具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 影象通道數],注意這是一個4維的Tensor,要求型別為float32和float64其中之一
- filter:相當於CNN中的卷積核,它要求是一個Tensor,具有[filter_height, filter_width, in_channels, out_channels]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,影象通道數,卷積核個數],要求型別與引數input相同,有一個地方需要注意,第三維in_channels,就是引數input的第四維
- strides:卷積時在影象每一維的步長,這是一個一維的向量,長度4
- padding:string型別的量,只能是"SAME","VALID"其中之一,這個值決定了不同的卷積方式
- use_cudnn_on_gpu:bool型別,是否使用cudnn加速,預設為true
輸出:
- 結果返回一個Tensor,這個輸出,就是我們常說的feature map,shape仍然是[batch, height, width, channels]這種形式。
tf.nn.max_pool(value, ksize, strides, padding, name=None)
引數
- value:池化的輸入,一般池化層接在卷積層的後面,所以輸出通常為feature map。feature map依舊是[batch, in_height, in_width, in_channels]這樣的引數。
- ksize:池化視窗的大小,引數為四維向量,通常取[1, height, width, 1],因為我們不想在batch和channels上做池化,所以這兩個維度設為了1。ps:估計面tf.nn.conv2d中stries的四個取值也有 相同的意思。
- stries:步長,同樣是一個四維向量。
- padding:填充方式同樣只有兩種不重複了。
layer1 = tf.nn.relu(tf.nn.conv2d(imageInputReshape,w0,strides=[1,1,1,1],padding='SAME')+b0)
# layer1:激勵函式+卷積運算
# imageInputReshape : M*28*28*1 w0:5,5,1,32
# layer1:M*28*28*32
複製程式碼
3、池化
layer1_pool = tf.nn.max_pool(layer1,ksize=[1,4,4,1],strides=[1,4,4,1],padding='SAME')
# pool取樣:資料量減少很多M*28*28*32 => M*7*7*32
複製程式碼
4、激勵函式+乘加運算
# layer2 out : softmax(激勵函式 + 乘加運算)
w1 = tf.Variable(tf.truncated_normal([7*7*32,1024],stddev=0.1))
b1 = tf.Variable(tf.constant(0.1,shape=[1024]))
h_reshape = tf.reshape(layer1_pool,[-1,7*7*32])
h1 = tf.nn.relu(tf.matmul(h_reshape,w1)+b1)
# [N*7*7*32] [7*7*32,1024] = N*1024
複製程式碼
5、輸出層
最後,我們新增一個softmax層
w2 = tf.Variable(tf.truncated_normal([1024,10],stddev=0.1))
b2 = tf.Variable(tf.constant(0.1,shape=[10]))
pred = tf.nn.softmax(tf.matmul(h1,w2)+b2)
# N*1024 1024*10 = N*10
複製程式碼
6、損失函式
loss0 = labeInput*tf.log(pred)
loss1 = 0
for m in range(0,500):
for n in range(0,10):
loss1 = loss1 - loss0[m,n]
loss = loss1/500
複製程式碼
7、訓練和評估模型
train = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
# 讓誤差儘可能縮小
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(100):
images,labels = mnist.train.next_batch(500)
sess.run(train,feed_dict={imageInput:images,labeInput:labels})
pred_test = sess.run(pred,feed_dict={imageInput:mnist.test.images,labeInput:labels})
acc = tf.equal(tf.arg_max(pred_test,1),tf.arg_max(mnist.test.labels,1))
acc_float = tf.reduce_mean(tf.cast(acc,tf.float32))
acc_result = sess.run(acc_float,feed_dict={imageInput:mnist.test.images,labeInput:mnist.test.labels})
print(acc_result)
複製程式碼