計算機視覺—CNN識別手寫數字(11)

Kervin_Chan發表於2018-06-08

一、載入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)
複製程式碼

相關文章