手寫數字識別 ----卷積神經網絡模型官方案例註釋(基於Tensorflow,Python)

# 手寫數字識別 ----卷積神經網絡模型
import os import tensorflow as tf #部分註釋來源於 # http://www.cnblogs.com/rgvb178/p/6052541.html

from tensorflow.examples.tutorials.mnist import input_data data = input_data.read_data_sets("/tmp/data/", one_hot=True) '''獲取程序集'''

# Multilayer Convolutional Network 多層卷積網絡
def convolutional(x, keep_prob): # 卷積過程
    def conv2d(x, W): ''' tf.nn.conv2d(input,filter,strides,padding,use_cudnn_on_gpu=True,data_format='NHWC',dilations=[1, 1, 1, 1], name=None) 計算給定的4-D input和filter張量的2-D卷積。 給定形狀爲[batch, in_height, in_width, in_channels]的輸入張量和形狀爲[filter_height, filter_width, in_channels, out_channels]的濾波器/內核張量,此操做執行如下操做: 將濾鏡展平爲具備形狀[filter_height * filter_width * in_channels, output_channels]的二維矩陣。 從輸入張量中提取圖像補丁,以造成形狀爲[batch, out_height, out_width, filter_height * filter_width * in_channels]的虛擬張量。 對於每一個補丁,右對乘濾波器矩陣和圖像補丁矢量。 參數: input:一個Tensor,必須是下列類型之一:half,bfloat16,float32,float64;一個4-D張量,維度順序根據data_format值進行解釋,詳見下文。 filter:一個Tensor,必須與input相同,形狀爲[filter_height, filter_width, in_channels, out_channels]的4-D張量。 strides:ints列表,長度爲4的1-D張量,input的每一個維度的滑動窗口的步幅;維度順序由data_format值肯定,詳見下文。 padding:string,能夠是:"SAME", "VALID",要使用的填充算法的類型。 use_cudnn_on_gpu:bool,默認爲True。 data_format:string,能夠是"NHWC", "NCHW",默認爲"NHWC";指定輸入和輸出數據的數據格式;使用默認格式「NHWC」,數據按如下順序存儲:[batch, height, width, channels];或者,格式能夠是「NCHW」,數據存儲順序爲:[batch, channels, height, width]。 dilations:ints的可選列表,默認爲[1, 1, 1, 1],長度爲4的1-D張量,input的每一個維度的擴張係數;若是設置爲k> 1,則該維度上的每一個濾鏡元素之間將有k-1個跳過的單元格;維度順序由data_format值肯定,詳見上文;批次和深度尺寸的擴張必須爲1。 name:操做的名稱(可選)。 返回:一個Tensor,與input具備相同的類型。 :return: '''
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') # 池化過程
    def max_pool_2x2(x): ''' tf.nn.max_pool(value, ksize, strides, padding, name=None) 參數是四個,和卷積很相似: 第一個參數value:須要池化的輸入,通常池化層接在卷積層後面,因此輸入一般是feature map,依然是[batch, height, width, channels]這樣的shape 第二個參數ksize:池化窗口的大小,取一個四維向量,通常是[1, height, width, 1],由於咱們不想在batch和channels上作池化,因此這兩個維度設爲了1 第三個參數strides:和卷積相似,窗口在每個維度上滑動的步長,通常也是[1, stride,stride, 1] 第四個參數padding:和卷積相似,能夠取'VALID' 或者'SAME' 返回一個Tensor,類型不變,shape仍然是[batch, height, width, channels]這種形式 :param x: :return: '''
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 初始化權重
    def weight_variable(shape): ''' tf.truncated_normal(shape,mean=0.0, stddev=1.0,dtype=tf.float32,seed=None,name=None) 從截斷的正態分佈中輸出隨機值。 生成的值遵循具備指定平均值和標準誤差的正態分佈,不一樣之處在於其平均值大於 2 個標準差的值將被丟棄並從新選擇。 函數參數: shape:一維整數張量或 Python 數組,輸出張量的形狀。 mean:dtype 類型的 0-D 張量或 Python 值,截斷正態分佈的均值。 stddev:dtype 類型的 0-D 張量或 Python 值,截斷前正態分佈的標準誤差。 dtype:輸出的類型。 seed:一個 Python 整數。用於爲分發建立隨機種子。查看tf.set_random_seed行爲。 name:操做的名稱(可選)。 函數返回值: tf.truncated_normal函數返回指定形狀的張量填充隨機截斷的正常值。 :param shape: :return: ''' initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) # 初始化偏置項
    def bias_variable(shape): ''' tf.constant(value,dtype=None,shape=None,name=’Const’) 建立一個常量tensor,按照給出value來賦值,能夠用shape來指定其形狀。value能夠是一個數,也能夠是一個list。 若是是一個數,那麼這個常亮中全部值的按該數來賦值。 若是是list,那麼len(value)必定要小於等於shape展開後的長度。賦值時,先將value中的值逐個存入。不夠的部分,則所有存入value的最後一個值。 :param shape: :return: ''' initial = tf.constant(0.1, shape=shape) return tf.Variable(initial) # First Convolutional Layer 第一次卷積層
    #首先在每一個5x5網格中,提取出32張特徵圖。其中weight_variable中前兩維是指網格的大小,第三維的1是指輸入通道數目,第四維的32是指輸出通道數目(也能夠理解爲使用的卷積核個數、獲得的特徵圖張數)。每一個輸出通道都有一個偏置項,所以偏置項個數爲32
    x_image = tf.reshape(x, [-1, 28, 28, 1])  #爲了使之能用於計算,咱們使用reshape將其轉換爲四維的tensor,其中第一維的-1是指咱們能夠先不指定,第二三維是指圖像的大小,第四維對應顏色通道數目,灰度圖對應1,rgb圖對應3.
    W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)  #利用ReLU激活函數,對其進行第一次卷積。
    h_pool1 = max_pool_2x2(h_conv1) #第一次池化
    # Second Convolutional Layer 第二個迴旋的層
    # (32 # 14x14->64 #14x14->64 #7x7)
    # 與第一層卷積、第一次池化相似的過程。
    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) # Densely Connected Layer 緊密鏈接層
    # 此時,圖片是7x7的大小。咱們在這裏加入一個有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
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # keep_prob = tf.placeholder("float")
    # h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
    # 這是一個比較新的也很是好用的防止過擬合的方法,想出這個方法的人基本屬於很是crazy的存在。在Udacity - Deep
    # Learning的課程中有提到這個方法——徹底隨機選取通過神經網絡流一半的數據來訓練,在每次訓練過程當中用0來替代被丟掉的激活值,其它激活值合理縮放。

    # Readout Layer 讀出層
    W_fc2 = weight_variable([1024, 10]) b_fc2 = bias_variable([10]) y = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) return y, [W_conv1, b_conv1, W_conv2, b_conv2, W_fc1, b_fc1, W_fc2, b_fc2] # 變量做用域 variable_scope # model
with tf.variable_scope("convolutional"): x = tf.placeholder(tf.float32, [None, 784]) keep_prob = tf.placeholder(tf.float32) y, variables = convolutional(x, keep_prob) # train
y_ = tf.placeholder(tf.float32, [None, 10]) # 計算交叉熵的代價函數
cross_entropy = -tf.reduce_sum(y_ * tf.log(y)) ''' reduce_sum (input_tensor , axis = None , keep_dims = False , name = None , reduction_indices = None) 此函數計算一個張量的各個維度上元素的總和。 函數中的input_tensor是按照axis中已經給定的維度來減小的;除非 keep_dims 是true,不然張量的秩將在axis的每一個條目中減小1;若是keep_dims爲true,則減少的維度將保留爲長度1。 若是axis沒有條目,則縮小全部維度,並返回具備單個元素的張量。 參數: input_tensor:要減小的張量。應該有數字類型。 axis:要減少的尺寸。若是爲None(默認),則縮小全部尺寸。必須在範圍[-rank(input_tensor), rank(input_tensor))內。 keep_dims:若是爲true,則保留長度爲1的縮小尺寸。 name:操做的名稱(可選)。 reduction_indices:axis的廢棄的名稱。 返回: 該函數返回減小的張量。 numpy兼容性 至關於np.sum '''

# 使用優化算法使得代價函數最小化
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) ''' class tf.train.AdamOptimizer __init__(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam') 此函數是Adam優化算法:是一個尋找全局最優勢的優化算法,引入了二次方梯度校訂。 相比於基礎SGD算法,1.不容易陷於局部優勢。2.速度更快! '''

# 找出預測正確的標籤
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) ''' tf.equal(A, B)是對比這兩個矩陣或者向量的相等的元素,若是是相等的那就返回True,反正返回False,返回的值的矩陣維度和A是同樣的 A = [[1,3,4,5,6]] B = [[1,3,4,3,2]] with tf.Session() as sess: print(sess.run(tf.equal(A, B))) [[ True True True False False]] 該函數將返回一個 bool 類型的張量。 '''

# 得出經過正確個數除以總數得出準確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) ''' cast(x, dtype, name=None) 將x的數據格式轉化成dtype.例如,原來x的數據格式是bool, 那麼將其轉化成float之後,就可以將其轉化成0和1的序列。反之也能夠 a = tf.Variable([1,0,0,1,1]) b = tf.cast(a,dtype=tf.bool) sess = tf.Session() sess.run(tf.initialize_all_variables()) print(sess.run(b)) #[ True False False True True] '''
''' 求最大值tf.reduce_max(input_tensor, reduction_indices=None, keep_dims=False, name=None) 求平均值tf.reduce_mean(input_tensor, reduction_indices=None, keep_dims=False, name=None) 參數1--input_tensor:待求值的tensor。 參數2--reduction_indices:在哪一維上求解。 參數(3)(4)可忽略 舉例說明: # 'x' is [[1., 2.] # [3., 4.]] x是一個2維數組,分別調用reduce_*函數以下: 首先求平均值: tf.reduce_mean(x) ==> 2.5 #若是不指定第二個參數,那麼就在全部的元素中取平均值 tf.reduce_mean(x, 0) ==> [2., 3.] #指定第二個參數爲0,則第一維的元素取平均值,即每一列求平均值 tf.reduce_mean(x, 1) ==> [1.5, 3.5] #指定第二個參數爲1,則第二維的元素取平均值,即每一行求平均值 ''' saver = tf.train.Saver(variables) with tf.Session() as sess: # tf.global_variables_initializer() 初始化模型的參數
 sess.run(tf.global_variables_initializer()) for i in range(20000):  # 每100次迭代輸出一第二天志,共迭代20000次
        batch = data.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)) sess.run(train_step, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}) print(sess.run(accuracy, feed_dict={x: data.test.images, y_: data.test.labels, keep_prob: 1.0})) # os.path.join(os.path.dirname(__file__), 'data', 'convolutional.ckpt') //絕對路徑包含中文字符可能致使路徑不可用 相對路徑:'mnist/data/regression.ckpt'
    path = saver.save( sess,  'mnist/data/regression.ckpt',write_meta_graph=False, write_state=False) print("Saved:", path)
相關文章
相關標籤/搜索