日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

tensorflow学习笔记——使用TensorFlow操作MNIST数据(1)

發布時間:2024/6/21 综合教程 22 生活家
生活随笔 收集整理的這篇文章主要介紹了 tensorflow学习笔记——使用TensorFlow操作MNIST数据(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  續集請點擊我:tensorflow學習筆記——使用TensorFlow操作MNIST數據(2)

  本節開始學習使用tensorflow教程,當然從最簡單的MNIST開始。這怎么說呢,就好比編程入門有Hello World,機器學習入門有MNIST。在此節,我將訓練一個機器學習模型用于預測圖片里面的數字。

  開始先普及一下基礎知識,我們所說的圖片是通過像素來定義的,即每個像素點的顏色不同,其對應的顏色值不同,例如黑白圖片的顏色值為0到255,手寫體字符,白色的地方為0,黑色為1,如下圖。

  MNIST 是一個非常有名的手寫體數字識別數據集,在很多資料中,這個數據集都會被用做深度學習的入門樣例。而Tensorflow的封裝讓MNIST數據集變得更加方便。MNIST是NIST數據集的一個子集,它包含了60000張圖片作為訓練數據,10000張圖片作為測試數據。在MNIST數據集中的每一張圖片都代表了0~9中的一個數字。圖片的大小都為28*28,且數字都會出現在圖片的正中間,如下圖:

  在上圖中右側顯示了一張數字1的圖片,而右側顯示了這個圖片所對應的像素矩陣,MNIST數據集提供了四個下載文件,在tensorflow中可以將這四個文件直接下載放到一個目錄中并加載,如下代碼input_data.read_data_sets所示,如果指定目錄中沒有數據,那么tensorflow會自動去網絡上進行下載。下面代碼介紹了如何使用tensorflow操作MNIST數據集。

  MNIST數據集的官網是Yann LeCun's website。在這里,我們提供了一份python源代碼用于自動下載和安裝這個數據集。你可以下載這份代碼,然后用下面的代碼導入到你的項目里面,也可以直接復制粘貼到你的代碼文件里面。

  注意:MNIST數據集包括訓練集的圖片和標記數據,以及測試集的圖片和標記數據,在測試集包含的10000個樣例中,前5000個樣例取自原始的NIST訓練集,后5000個取自原始的NIST測試集,因此前5000個預測起來更容易些。

import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

  當one-hot變為為TRUE,則只要對應的位置的值為1,其余都是0。

  這里,我直接下載了數據集,并放在了我的代碼里面。測試如下:

# _*_coding:utf-8_*_

from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
print("OK")
# 打印“Training data size: 55000”
print("Training data size: ", mnist.train.num_examples)
# 打印“Validating data size: 5000”
print("Validating data size: ", mnist.validation.num_examples)
# 打印“Testing data size: 10000”
print("Testing data size: ", mnist.test.num_examples)
# 打印“Example training data: [0. 0. 0. ... 0.380 0.376 ... 0.]”
print("Example training data: ", mnist.train.images[0])
# 打印“Example training data label: [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]”
print("Example training data label: ", mnist.train.labels[0])

batch_size = 100
# 從train的集合中選取batch_size個訓練數據
xs, ys = mnist.train.next_batch(batch_size)
# 輸出“X shape:(100,784)”
print("X shape: ", xs.shape)
# 輸出"Y shape:(100,10)"
print("Y shape: ", ys.shape)

  結果如下:

Extracting MNIST_data	rain-images-idx3-ubyte.gz
Extracting MNIST_data	rain-labels-idx1-ubyte.gz
Extracting MNIST_data	10k-images-idx3-ubyte.gz
Extracting MNIST_data	10k-labels-idx1-ubyte.gz
OK
Training data size:  55000
Validating data size:  5000
Testing data size:  10000
X shape:  (100, 784)
Y shape:  (100, 10)

  從上面的代碼可以看出,通過input_data.read_data_sets函數生成的類會自動將MNIST數據集劃分成train,validation和test三個數據集,其中train這個集合內含有55000張圖片,validation集合內含有5000張圖片,這兩個集合組成了MNIST本身提供的訓練數據集。test集合內有10000張圖片,這些圖片都來自與MNIST提供的測試數據集。處理后的每一張圖片是一個長度為784的一維數組,這個數組中的元素對應了圖片像素矩陣中的每一個數字(28*28=784)。因為神經網絡的輸入是一個特征向量,所以在此把一張二維圖像的像素矩陣放到一個一維數組中可以方便tensorflow將圖片的像素矩陣提供給神經網絡的輸入層。像素矩陣中元素的取值范圍為[0, 1],它代表了顏色的深淺。其中0表示白色背景,1表示黑色前景。

Softmax回歸的再復習

  我們知道MNIST的每一張圖片都表示一個數字,從0到9。我們希望得到給定圖片代表每個數字的概率。比如說,我們的模型可能推測一張包含9的圖片代表數字9 的概率為80%但是判斷它是8 的概率是5%(因為8和9都有上半部分的小圓),然后給予它代表其他數字的概率更小的值。

  這是一個使用softmax regression模型的經典案例。softmax模型可以用來給不同的對象分配概率。即使在之后,我們訓練更加精細的模型的時候,最后一步也是需要softmax來分配概率。

  Softmax回歸可以解決兩種以上的分類,該模型是Logistic回歸模型在分類問題上的推廣。對于要識別的0~9這10類數字,首選Softmax回歸。MNIST的Softmax回歸源代碼位于Tensorflow-1.1.0/tensorflow.examples/tutorials/mnist/mnist_softmax.py

softmax回歸第一步

  為了得到一張給定圖片屬于某個特定數字類的證據(evidence),我們對圖片像素值進行加權求和。如果這個像素具有很強的證據說明這種圖片不屬于該類,那么相應的權值為負數,相反如果這個像素擁有很強的證據說明這張圖片不屬于該類,那么相應的權值為負數,相反如果這個像素擁有有力的證據支持這張圖片屬于這個類,那么權值是正數。

  下面的圖片顯示了一個模型學習到的圖片上每個像素對于特定數字類的權值,紅色代表負數權值,藍色代表正數權值。

  我們也需要加入一個額外的偏置量(bias),因為輸入往往會帶有一些無關的干擾量。因為對于給定的輸入圖片 x 它代表的是數字 i 的證據可以表示為:

  其中,Wi代表權重,bi代表數字 i 類的偏置量, j 代表給定圖片 x 的像素索引用于像素求和。然后用 softmax 函數可以把這些證據轉換成概率 y:

  這里的softmax可以看成是一個激勵(activation)函數或者鏈接(link)函數,把我們定義的線性函數的輸出轉換成我們想要的格式,也就是關于10個數字類的概率分布。因此,給定一張圖片,它對于每一個數字的吻合度可以被softmax函數轉換成一個概率值。softmax函數可以定義為:

  展開等式右邊的子式,可以得到:

  但是更多的時候把softmax模型函數定義為前一種形式:把輸入值當做冪指函數求值,再正則化這些結果值。這個冪運算表示,更大的證據對應更大的假設模型(hypothesis)里面的乘數權重值。反之,擁有更少的證據意味著在假設模型里面擁有更小的乘數系數。假設模型里面的權值不可以是0值或者負值。Softmax然后會正則化這些權重值,使他們的總和等于1,以此構造一個有效的概率分布。

  對于softmax回歸模型可以用下面的圖解釋,對于輸入的 xs 加權求和,再分別加上一個偏置量,最后再輸入到 softmax 函數中:

  如果把它寫成一個等式,我們可以得到:

  我們也可以用向量表示這個計算過程:用矩陣乘法和向量相加。這有助于提高計算效率:

  更進一步,可以寫成更加緊湊的方式:

  接下來就是使用Tensorflow實現一個 Softmax Regression。其實在Python中,當還沒有TensorFlow時,通常使用Numpy做密集的運算操作。因為Numpy是使用C和一部分 fortran語言編寫的,并且調用了 openblas,mkl 等矩陣運算庫,因此效率很好。其中每一個運算操作的結果都要返回到Python中,但不同語言之間傳輸數據可能會帶來更大的延遲。TensorFlow同樣將密集的復雜運算搬到Python外面執行,不過做的更徹底。

  首先載入TensorFlow庫,并創建一個新的 InteractiveSession ,使用這個命令會將這個session 注冊為默認的session,之后的運算也默認跑在這個session里,不同session之間的數據和運算應該都是相互獨立的。接下來創建一個 placeholder,即輸入數據的地方。Placeholder 的第一個參數是數據類型,第二個參數 [None, 784] 代表 tensor 的 shape,也就是數據的尺寸,這里的None代表不限條數的輸入, 784代表每條數據的是一個784維的向量。

sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])

  接下來要給Softmax Regression模型中的 weights和 biases 創建 Variable 對象,Variable是用來存儲模型參數的,不同于存儲數據的 tensor 一旦使用掉就會消失,Variable 在模型訓練迭代中是持久的,它可以長期存在并且在每輪迭代中被更新。我們把 weights 和 biases 全部初始化為0,因為模型訓練時會自動學習適合的值,所以對這個簡單模型來說初始值不太重要,不過對于復雜的卷積網絡,循環網絡或者比較深的全連接網絡,初始化的方法就比較重要,甚至可以說至關重要。注意這里的W的shape是 [784, 10] 中 , 784是特征的維數,而后面的10 代表有10類,因為Label在 one-hot編碼后是10維的向量。

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

  接下來要實現 Softmax Regression 算法,我們將上面提到的 y = softmax(Wx+b),改為 TensorFlow的語言就是下面的代碼:

y = tf.nn.softmax(tf.matmul(x, W) + b)

  Softmax是 tf.nn 下面的一個函數,而 tf.nn 則包含了大量的神經網絡的組件, tf.matmul是TensorFlow中矩陣乘法函數。我們就定義了簡單的 Softmax Regression,語法和直接寫數學公式很像。然而Tensorflow最厲害的地方還不是定義公式,而是將forward和backward的內容都自動實現。所以我們接下來定義好loss,訓練時將會自動求導并進行梯度下降,完成對 Softmax Regression模型參數的自動學習。

回歸模型訓練的步驟

  構建回歸模型,我們需要輸入原始真實值(group truth),計算采用softmax函數擬合后的預測值,并定義損失函數和優化器。

  為了訓練模型,我們首先需要定義一個指標來評估這個模型是好的。其實,在機器學習中,我們通常定義指標來表示一個模型是壞的,這個指標稱為成本(cost)或者損失(loss),然后近鄰最小化這個指標。但是這兩種方式是相同的。

  一個非常常見的的成本函數是“交叉熵(cross-entropy)”。交叉熵產生于信息論里面的信息壓縮編碼技術,但是后來他演變為從博弈論到機器學習等其他領域里的重要技術手段,它的定義如下:

  Y是我們預測的概率分布, y' 是實際的分布(我們輸入的 one-hot vector)。比較粗糙的理解是,交叉熵是用來衡量我們的預測用于描述真相的低效性。

  為了計算交叉熵,我們首先需要添加一個新的占位符用于輸入正確值:

y_ = tf.placeholder("float", [None,10])

  然后我們可以用交叉熵的公式計算交叉熵:

cross_entropy = -tf.reduce_sum(y_*tf.log(y))

  或者

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
                                              reduction_indices=[1]))

  (這里我們 y_ * tf.log(y)是前面公式的交叉熵公式,而 tf.reduce_sum就是求和,而tf.reduce_mean則是用來對每個 batch 的數據結果求均值。)

  首先,用 tf.log 計算 y 的每個元素的對數。接下來,我們把 y_ 的每一個元素 和 tf.log(y) 的對應元素相乘。最后用 tf.reduce_sum 計算張量的所有元素總和。(注意:這里的交叉熵不僅僅用來衡量單一的一對預測和真實值,而是所有的圖片的交叉熵的總和。對于所有的數據點的預測表現比單一數據點的表現能更好的描述我們的模型的性能)。

  當我們知道我們需要我們的模型做什么的時候,用TensorFlow來訓練它是非常容易的。因為TensorFlow擁有一張描述我們各個計算單元的圖,它可以自動的使用反向傳播算法(backpropagation algorithm)來有效的確定變量是如何影響想要最小化的那個成本值。然后TensorFlow會用選擇的優化算法來不斷地修改變量以降低成本。

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

  在這里,我們要求TensorFlow用梯度下降算法(gradient descent alogrithm)以0.01的學習速率最小化交叉熵。梯度下降算法(gradient descent algorithm)是一個簡單的學習過程,TensorFlow只需將每個變量一點點地往使成本不斷降低的方向移動。當然TensorFlow也提供了其他許多優化算法:只要簡單地調整一行代碼就可以使用其他的算法。

  TensorFlow在這里實際上所做的是,它會在后臺給描述你的計算的那張圖里面增加一系列新的計算操作單元用于實現反向傳播算法和梯度下降算法。然后,它返回給你的只是一個單一的操作,當運行這個操作時,它用梯度下降算法訓練你的模型,微調你的變量,不斷減少成本。

  現在,我們已經設置好了我們的模型,在運行計算之前,我們需要添加一個操作來初始化我們創建的變量并初始化,但是我們可以在一個Session里面啟動我們的模型:

with tf.Session() as sess:
    tf.global_variables_initializer().run()

  然后開始訓練模型,這里我們讓模型訓練訓練1000次:

for i in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

  或者

for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    train_step.run({x: batch_xs, y:batch_ys})

  該訓練的每個步驟中,我們都會隨機抓取訓練數據中的100個批處理數據點,然后我們用這些數據點作為參數替換之前的占位符來運行 train_step。而且我們可以通過 feed_dict 將 x 和 y_ 張量 占位符用訓練數據替代。(注意:在計算圖中,我們可以用 feed_dict 來替代任何張量,并不僅限于替換占位符)

  使用一小部分的隨機數據來進行訓練被稱為隨機訓練(stochastic training)- 在這里更確切的說是隨機梯度下降訓練。在理想情況下,我們希望用我們所有的數據來進行每一步的訓練,因為這能給我們更好的訓練結果,但顯然這需要很大的計算開銷。所以,每一次訓練我們可以使用不同的數據子集,這樣做既可以減少計算開銷,又可以最大化地學習到數據集的總體特性。

  現在我們已經完成了訓練,接下來就是對模型的準確率進行驗證,下面代碼中的 tf.argmax是從一個 tensor中尋找最大值的序號, tf.argmax(y, 1)就是求各個預測的數字中概率最大的一個,而 tf.argmax(y_, 1)則是找到樣本的真實數字類別。而 tf.equal方法則是用來判斷預測數字類別是否就是正確的類別,最后返回計算分類是否正確的操作 correct_predition。

訓練模型的步驟

  已經設置好了模型,在訓練之前,需要先初始化我們創建的變量,以及在會話中啟動模型。

# 這里使用InteractiveSession() 來創建交互式上下文的TensorFlow會話
# 與常規會話不同的時,交互式會話成為默認會話方法
# 如tf.Tensor.eval 和 tf.Operation.run 都可以使用該會話來運行操作(OP
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

  我們讓模型循環訓練1000次,在每次循環中我們都隨機抓取訓練數據中100個數據點,來替代之前的占位符。

# Train
for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x:batch_xs, y_:batch_ys})

  這種訓練方式成為隨機訓練(stochastic training),使用SGD方法進行梯度下降,也就是每次從訓練數據集中抓取一小部分數據進行梯度下降訓練。即與每次對所有訓練數據進行計算的BGD相比,SGD即能夠學習到數據集的總體特征,又能夠加速訓練過程。

保存檢查點(checkpoint)的步驟

  為了得到可以用來后續恢復模型以進一步訓練或評估的檢查點文件(checkpoint file),我們實例化一個 tf.train.Saver。

saver = tf.train.Saver()

  在訓練循環中,將定期調用 saver.save() 方法,向訓練文件夾中寫入包含了當前所有可訓練變量值的檢查點文件。

saver.save(sess, FLAGS.train_dir, global_step=step)

  這樣,我們以后就可以使用 saver.restore() 方法,重載模型的參數,繼續訓練。

saver.restore(sess, FLAGS.train_dir)

  這里不多講,具體請參考博客:TensorFlow學習筆記:模型持久化的原理。。

評估模型的步驟

  那么我們的模型性能如何呢?

  首先讓我們找出那些預測正確的標簽。tf.argmax 是一個非常有用的函數,它能給出某個 tensor 對象在某一維上的其數據最大值所在的索引值。由于標簽向量是由0, 1 組成,所以最大值1所在的索引位置就是類別標簽,比如 tf.argmax(y, 1) 返回的是模型對于任一輸入 x 預測到的標簽值,而 tf.argmax(y_, 1) 代表正確的標簽,我們可以用 tf.equal 來檢測我們的預測是否真實標簽匹配(索引位置一樣表示匹配)。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

  這里返回一個布爾數組,為了計算我們分類的準確率,我們使用cast將布爾值轉換為浮點數來代表對,錯,然后取平均值。例如: [True, False, True, True] 變為 [1, 0, 1, 1],計算出平均值為 0.75。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

  最后,我們可以計算出在測試數據上的準確率,大概是91%。

print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

  完整代碼如下:

  下面我們總結一下實現了上面簡單機器學習算法 Softmax Regression,這可以算作是一個沒有隱含層的最淺的神經網絡,我們來總結一下整個流程,我們做的事情分為下面四部分:

1,定義算法公式,也就是神經網絡forward時的計算
2,定義loss,選定優化器,并指定優化器優化loss
3,迭代地對數據進行訓練
4,在測試集或驗證集上對準確率進行評測

  這幾個步驟是我們使用Tensorflow進行算法設計,訓練的核心步驟,也將會貫穿所有神經網絡。

  代碼如下:

#_*_coding:utf-8_*_
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# 首先我們直接加載TensorFlow封裝好的MNIST數據   28*28=784
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.test.images.shape, mnist.test.labels.shape)
print(mnist.validation.images.shape, mnist.validation.labels.shape)
'''
(55000, 784) (55000, 10)
(10000, 784) (10000, 10)
(5000, 784) (5000, 10)
'''

sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)

y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
                                              reduction_indices=[1]))

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

tf.global_variables_initializer().run()

for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    train_step.run({x: batch_xs, y_: batch_ys})

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

  

傳統神經網絡訓練MNIST數據

1,訓練步驟

輸入層:拉伸的手寫文字圖像,維度為 [-1, 28*28]
全連接層:500個節點,維度為[-1, 500]
輸出層:分類輸出,維度為 [-1, 10]

2,訓練代碼及其結果

  傳統的神經網絡訓練代碼:

# _*_coding:utf-8_*_
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

BATCH_SIZE = 100  # 訓練批次
INPUT_NODE = 784  # 784=28*28 輸入節點
OUTPUT_NODE = 10  # 輸出節點
LAYER1_NODE = 784  # 層級節點
TRAIN_STEP = 10000  # 訓練步數
LEARNING_RATE = 0.01
L2NORM_RATE = 0.001


def train(mnist):
    # define input placeholder
    # None表示此張量的第一個維度可以是任何長度的
    input_x = tf.placeholder(tf.float32, [None, INPUT_NODE], name='input_x')
    input_y = tf.placeholder(tf.float32, [None, OUTPUT_NODE], name='input_y')

    # define weights and biases
    w1 = tf.Variable(tf.truncated_normal(shape=[INPUT_NODE, LAYER1_NODE], stddev=0.1))
    b1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))

    w2 = tf.Variable(tf.truncated_normal(shape=[LAYER1_NODE, OUTPUT_NODE], stddev=0.1))
    b2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))

    layer1 = tf.nn.relu(tf.nn.xw_plus_b(input_x, w1, b1))
    y_hat = tf.nn.xw_plus_b(layer1, w2, b2)
    print("1 step ok!")

    # define loss
    cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=y_hat, labels=input_y)
    cross_entropy_mean = tf.reduce_mean(cross_entropy)
    regularization = tf.nn.l2_loss(w1) + tf.nn.l2_loss(w2) + tf.nn.l2_loss(b1) + tf.nn.l2_loss(b2)
    loss = cross_entropy_mean + L2NORM_RATE * regularization
    print("2 step ok")

    # define accuracy
    correct_predictions = tf.equal(tf.argmax(y_hat, 1), tf.argmax(input_y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_predictions, tf.float32))
    print("3 step ok")

    # train operation
    global_step = tf.Variable(0, trainable=False)
    train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(loss, global_step=global_step)
    print("4 step ok ")

    with tf.Session() as sess:
        tf.global_variables_initializer().run()  # 初始化創建的變量
        print("5 step OK")

        # 開始訓練模型
        for i in range(TRAIN_STEP):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            feed_dict = {
                input_x: xs,
                input_y: ys,
            }
            _, step, train_loss, train_acc = sess.run([train_op, global_step, loss, accuracy], feed_dict=feed_dict)
            if (i % 100 == 0):
                print("After %d steps, in train data, loss is %g, accuracy is %g." % (step, train_loss, train_acc))

        test_feed = {input_x: mnist.test.images, input_y: mnist.test.labels}
        test_acc = sess.run(accuracy, feed_dict=test_feed)
        print("After %d steps, in test data, accuracy is %g." % (TRAIN_STEP, test_acc))


if __name__ == '__main__':
    mnist = input_data.read_data_sets("data", one_hot=True)
    print("0 step ok!")
    train(mnist)

  結果如下:

Extracting data	rain-images-idx3-ubyte.gz
Extracting data	rain-labels-idx1-ubyte.gz
Extracting data	10k-images-idx3-ubyte.gz
Extracting data	10k-labels-idx1-ubyte.gz
0 step ok!
1 step ok!
2 step ok
3 step ok
4 step ok 
5 step OK
After 1 steps, in train data, loss is 5.44352, accuracy is 0.03.
After 101 steps, in train data, loss is 0.665012, accuracy is 0.95.

...  ...

After 9901 steps, in train data, loss is 0.304703, accuracy is 0.96.
After 10000 steps, in test data, accuracy is 0.9612.

  

3,部分代碼解析:

占位符

  我們通過為輸入圖像和目標輸出類別創建節點,來開始構建計算圖:

x = tf.placeholder("float", [None, 784])

  x 不是一個特定的值,而是一個占位符 placeholder,我們在TensorFlow運行計算時輸入這個值我們希望能夠輸入任意數量的MNIST圖像,每張圖展平為784維(28*28)的向量。我們用二維的浮點數張量來表示這些圖,這個張量的形狀是 [None, 784],這里的None表示此張量的第一個維度可以是任意長度的。

  雖然palceholder 的shape參數是可選的,但是有了它,TensorFlow能夠自動捕捉因數據維度不一致導致的錯誤。

變量

  一個變量代表著TensorFlow計算圖中的一個值,能夠在計算過程中使用,甚至進行修改。在機器學習的應用過程中,模型參數一般用Variable來表示。

w1 = tf.Variable(tf.truncated_normal(shape=[INPUT_NODE, LAYER1_NODE], stddev=0.1))
b1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))

  我們的模型也需要權重值和偏置量,當然我們可以將其當做是另外的輸入(使用占位符),這里使用Variable。一個Variable代表一個可修改的張量,它可以用于計算輸入值,也可以在計算中被修改。對于各種機器學習英語,一般都會有模型參數,可以用Variable來表示。

  變量需要通過session初始化后,才能在session中使用,這一初始化的步驟為,為初始化指定具體值,并將其分配給每個變量,可以一次性為所有變量完成此操作。

sess.run(tf.initialize_all_variables())

  

卷積神經網絡-CNN訓練MNIST數據

  在MNIST上只有96%的正確率是在是糟糕,所以這里我們用一個稍微復雜的模型:卷積神經網絡來改善效果,這里大概會達到100%的準確率。

  同樣,構建的流程也是先加載數據,再構架網絡模型,最后訓練和評估模型。

1,訓練步驟

輸入層:手寫文字圖像,維度為[-1, 28, 28, 1]
卷積層1:filter的shape為5*5*32,strides為1,padding為“SAME”。卷積后維度為 [-1, 28, 28, 32]
池化層2:max-pooling,ksize為2*2, 步長為2,池化后維度為 [-1, 14, 14, 32]
卷積層3:filter的shape為5*5*64,strides為1,padding為“SAME”。卷積后維度為 [-1, 14, 14, 64]
池化層4:max-pooling,ksize為2*2, 步長為2。池化后維度為 [-1, 7, 7, 64]
池化后結果展開:將池化層4 feature map展開, [-1, 7, 7, 64] ==> [-1, 3136]
全連接層5:輸入維度 [-1, 3136],輸出維度 [-1, 512]
全連接層6:輸入維度 [-1, 512],輸出維度[-1, 10]。經過softmax后,得到分類結果。

2,構建模型

  構建一個CNN模型,需要以下幾步。

  (1)定義輸入數據并預處理數據。這里,我們首先讀取數據MNIST,并分別得到訓練集的圖片和標記的矩陣,以及測試集的圖片和標記的矩陣。代碼如下:

# _*_coding:utf-8_*_
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
trX, trY = mnist.train.images, mnist.train.labels
teX, teY = mnist.test.images, mnist.test.labels

  其中,mnist是TensorFlow的TensorFlow.contrib.learn中的Datasets,其值如下:

  trX, trY, teX, teY 是數據的矩陣表現,其值類似于:

  接著,需要處理輸入的數據,把上面 trX 和 teX 的形狀變為 [-1, 28, 28, 1], -1表示不考慮輸入圖片的數量,28*28表示圖片的長和寬的像素數,1是通道(channel)數量,因為MNIST的圖片是黑白的,所以通道為1,如果是RGB彩色圖像,則通道為3 。

trX = trX.reshape(-1, 28, 28, 1)   # 28*28*1  input image
teX = teX.reshape(-1, 28, 28, 1)   # 28*28*1  input image

X = tf.placeholder('float', [None, 28, 28, 1])
Y = tf.placeholder('float', [None, 10])

  (2)初始化權重與定義網絡結構。這里,我們將要構建一個擁有3個卷積和3個池化層,隨后一個全連接層,再接一個輸出層的卷積神經網絡。

  首先定義初始化權重的函數:

def init_weights(shape):
    return tf.Variable(tf.random_normal(shape, stddev=0.01))


# 初始化權重方法如下,我們設置卷積核的大小為3*3
w = init_weights([3, 3, 1, 32])  # patch大小為3*3,輸入維度為1,輸出維度為32
w2 = init_weights([3, 3, 32, 64])  # patch大小為3*3,輸入維度為32,輸出維度為64
w3 = init_weights([3, 3, 64, 128])  # patch大小為3*3,輸入維度為64,輸出維度為128
# 全連接層,輸入維度為128*4*4,是上一層的輸出數據又三維的轉變成一維,輸出維度為625
w4 = init_weights([128 * 4 * 4, 625])
# 輸出層,輸入維度為625  輸出維度為10, 代表10類
w_o = init_weights([625, 10])

  隨后,定義一個模型函數,代碼如下:

# 神經網絡模型的構建函數,傳入以下參數
# X:輸入數據
# w:每一層的權重
# p_keep_conv , p_keep_hidden, dropout 要保留的神經元比例

def model(X, w, w2, w3, w4, w_0, p_keep_conv, p_keep_hidden):
    # 第一組卷積層以及池化層,最后dropout一些神經元
    l1a = tf.nn.relu(tf.nn.conv2d(X, w, strides=[1, 1, 1, 1], padding='SAME'))
    # l1a  shape=(?, 28, 28, 32)
    l1 = tf.nn.max_pool(l1a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l1 shape=(?, 14, 14, 32)
    l1 = tf.nn.dropout(l1, p_keep_conv)

    # 第二組卷積層以及池化層,最后dropout一些神經元
    l2a = tf.nn.relu(tf.nn.conv2d(l1, w2, strides=[1, 1, 1, 1], padding='SAME'))
    # l2a  shape=(?, 14, 14, 64)
    l2 = tf.nn.max_pool(l2a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l2  shape=(?, 7, 7, 64)
    l2 = tf.nn.dropout(l2, p_keep_conv)

    # 第三組卷積層以及池化層,最后dropout一些神經元
    l3a = tf.nn.relu(tf.nn.conv2d(l2, w3, strides=[1, 1, 1, 1], padding='SAME'))
    # l3a  shape=(?, 7, 7, 128)
    l3 = tf.nn.max_pool(l3a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l3  shape=(?, 4, 4, 128)
    l3 = tf.reshape(l3, [-1, w4.get_shape().as_list()[0]])  # reshape to (?, 2048)
    l3 = tf.nn.dropout(l3, p_keep_conv)
    
    # 全連接層,最后dropout一些神經元
    l4 = tf.nn.relu(tf.matmul(l3, w4))
    l4 = tf.nn.dropout(l4, p_keep_hidden)
    
    # 輸出層
    pyx = tf.matmul(l4, w_o)
    return pyx   # 返回預測值

  我們定義dropout的占位符——keep_conv,它表示在一層中有多少比例的神經元被保留下來,生成網絡模型,得到預測值,如下:

p_keep_cobv = tf.placeholder('float')
p_keep_hidden = tf.placeholder('float')
# 得到預測值
py_x = model(X, w, w2, w3, w4, w_o, p_keep_cobv, p_keep_hidden)

  接下來,定義頓時函數,這里我們仍然采用 tf.nn.softmax_cross_entropy_with_logits 來作比較預測值和真實值的差異,并做均值處理,定義訓練的操作(train_op),采用實現 RMSProp算法的優化器 tf.train.RMSPropOptimizer,學習率為0.001,衰減值為0.9,使損失最小;定義預測的操作(predict_op)。具體如下:

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=py_x, labels=Y))
train_op = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cost)
predict_op = tf.argmax(py_x, 1)

  (3)定義訓練時的批次大小和評估時的批次大小,如下:

batch_size = 128
test_size = 256

# 在一個會話中啟動圖,開始訓練和評估
# Launch the graph in a session
with tf.Session() as sess:
    # you need to initilaize all variables
    tf.global_variables_initializer().run()

    for i in range(100):
        training_batch = zip(range(0, len(trX), batch_size),
                             range(batch_size, len(trX) + 1, batch_size))
        for start, end in training_batch:
            sess.run(train_op, feed_dict={
                X: trX[start:end], Y: trY[start:end],
                p_keep_conv: 0.8,
                p_keep_hidden: 0.5
            })

        test_indices = test_indices[0: test_size]
        print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
                         sess.run(predict_op, feed_dict={X: teX[test_indices],
                                                         p_keep_conv: 1.0,
                                                         p_keep_hidden: 1.0})))

  完整代碼如下:

# _*_coding:utf-8_*_
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
trX, trY = mnist.train.images, mnist.train.labels
teX, teY = mnist.test.images, mnist.test.labels

trX = trX.reshape(-1, 28, 28, 1)  # 28*28*1  input image
teX = teX.reshape(-1, 28, 28, 1)  # 28*28*1  input image

X = tf.placeholder('float', [None, 28, 28, 1])
Y = tf.placeholder('float', [None, 10])


def init_weights(shape):
    return tf.Variable(tf.random_normal(shape, stddev=0.01))


# 初始化權重方法如下,我們設置卷積核的大小為3*3
w = init_weights([3, 3, 1, 32])  # patch大小為3*3,輸入維度為1,輸出維度為32
w2 = init_weights([3, 3, 32, 64])  # patch大小為3*3,輸入維度為32,輸出維度為64
w3 = init_weights([3, 3, 64, 128])  # patch大小為3*3,輸入維度為64,輸出維度為128
# 全連接層,輸入維度為128*4*4,是上一層的輸出數據又三維的轉變成一維,輸出維度為625
w4 = init_weights([128 * 4 * 4, 625])
# 輸出層,輸入維度為625  輸出維度為10, 代表10類
w_o = init_weights([625, 10])


# 神經網絡模型的構建函數,傳入以下參數
# X:輸入數據
# w:每一層的權重
# p_keep_conv , p_keep_hidden, dropout 要保留的神經元比例

def model(X, w, w2, w3, w4, w_0, p_keep_conv, p_keep_hidden):
    # 第一組卷積層以及池化層,最后dropout一些神經元
    l1a = tf.nn.relu(tf.nn.conv2d(X, w, strides=[1, 1, 1, 1], padding='SAME'))
    # l1a  shape=(?, 28, 28, 32)
    l1 = tf.nn.max_pool(l1a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l1 shape=(?, 14, 14, 32)
    l1 = tf.nn.dropout(l1, p_keep_conv)

    # 第二組卷積層以及池化層,最后dropout一些神經元
    l2a = tf.nn.relu(tf.nn.conv2d(l1, w2, strides=[1, 1, 1, 1], padding='SAME'))
    # l2a  shape=(?, 14, 14, 64)
    l2 = tf.nn.max_pool(l2a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l2  shape=(?, 7, 7, 64)
    l2 = tf.nn.dropout(l2, p_keep_conv)

    # 第三組卷積層以及池化層,最后dropout一些神經元
    l3a = tf.nn.relu(tf.nn.conv2d(l2, w3, strides=[1, 1, 1, 1], padding='SAME'))
    # l3a  shape=(?, 7, 7, 128)
    l3 = tf.nn.max_pool(l3a, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # l3  shape=(?, 4, 4, 128)
    l3 = tf.reshape(l3, [-1, w4.get_shape().as_list()[0]])  # reshape to (?, 2048)
    l3 = tf.nn.dropout(l3, p_keep_conv)

    # 全連接層,最后dropout一些神經元
    l4 = tf.nn.relu(tf.matmul(l3, w4))
    l4 = tf.nn.dropout(l4, p_keep_hidden)

    # 輸出層
    pyx = tf.matmul(l4, w_o)
    return pyx  # 返回預測值


p_keep_conv = tf.placeholder('float')
p_keep_hidden = tf.placeholder('float')
# 得到預測值
py_x = model(X, w, w2, w3, w4, w_o, p_keep_conv, p_keep_hidden)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=py_x, labels=Y))
train_op = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cost)
predict_op = tf.argmax(py_x, 1)

batch_size = 128
test_size = 256

# 在一個會話中啟動圖,開始訓練和評估
# Launch the graph in a session
with tf.Session() as sess:
    # you need to initilaize all variables
    tf.global_variables_initializer().run()

    for i in range(100):
        training_batch = zip(range(0, len(trX), batch_size),
                             range(batch_size, len(trX) + 1, batch_size))
        for start, end in training_batch:
            sess.run(train_op, feed_dict={
                X: trX[start:end], Y: trY[start:end],
                p_keep_conv: 0.8,
                p_keep_hidden: 0.5
            })

        test_indices = test_indices[0: test_size]
        print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
                         sess.run(predict_op, feed_dict={X: teX[test_indices],
                                                         p_keep_conv: 1.0,
                                                         p_keep_hidden: 1.0})))

  

3,部分代碼解析:

初始化權重

  為了不在建立模型的時候反復做初始化的操作,我們定義兩個函數用于初始化。

# 定義W初始化函數
def get_weights(shape):
    form = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(form)


# 定義b初始化函數
def get_biases(shape):
    form = tf.constant(0.1, shape=shape)
    return tf.Variable(form)

  為了創建此模型,我們需要創建大量的權重和偏置項。這個模型中的權重在初始化時應該加入少量的噪聲來打破對稱性以及避免0梯度。由于我們使用的是ReLU神經元,因此比較好的做法是用一個較小的正數來初始化偏置項,以避免神經元節點輸出恒為0 的問題(dead neurons)。為了不在建立模型的時候反復做初始化操作,我們定義兩個函數用于初始化。

卷積和池化

  TensorFlow在卷積和池化上有很強的靈活性,那么如何處理邊界?步長應該設置多大?這里我們卷積使用的是1步長(stride size),0邊距(padding size)。保證輸出和輸出的大小相同,我們的池化是用簡單的2*2大小的模板做 max pooling 。

第一層卷積

  現在我們開始實現第一層卷積,它是由一個卷積接一個 max pooling 完成。卷積在每個5*5的patch中算出 32個特征。卷積的權重張量形狀是 [5, 5, 1, 32],前兩個維度是patch的大小,接著是輸出通道的數目,最后是輸出的通道數目。為了使用這一層卷積,我們將x 變成一個4d向量,其第二,第三對應圖片的寬,高。最后一維代表輸出的通道數目。

  最后我們將x 和權重向量進行卷積,加上偏置項,然后應用ReLU激活函數,代碼如下:

# 第一層:卷積層conv1
'''
input: [-1, 28, 28, 1]
filter: [5, 5, 32]
output: [-1, 28, 28, 32]
'''
with tf.name_scope("conv1"):
    w = get_weights([FILTER1_SIZE, FILTER1_SIZE, 1, FILTER1_NUM])
    b = get_biases([FILTER1_NUM])
    conv1_op = tf.nn.conv2d(
        input=input_x,
        filter=w,
        strides=[1, 1, 1, 1],
        padding="SAME",
        name='conv1_op'
    )

    conv1 = tf.nn.relu(tf.nn.bias_add(conv1_op, b), name='relu')

  

第二層池化

   前面也說過,我們的池化用簡單傳統的2*2大小模板做 max pooling .

# 第二層:池化層pooling2
'''
input: [-1, 28, 28, 32]
output: [-1. 14, 14, 32]
'''
with tf.name_scope('pooling2'):
    pooling2 = tf.nn.max_pool(
        value=conv1,
        ksize=[1, 2, 2, 1],
        strides=[1, 2, 2, 1],
        padding='SAME',
        name='pooling1'
    )

  

第三層卷積

  為了構建一個更深的網絡,我們會把幾個類似的層堆疊起來,第二層中,每個5*5的patch 會得到64個特征,代碼如下:

# 第三次:卷積層conv3
'''
input" [-1, 14, 14, 32]
filter: [5, 5, 64]
output: [-1, 14, 14, 64]
'''
with tf.name_scope('conv3'):
    w = get_weights([FILTER3_SIZE, FILTER3_SIZE, FILTER1_NUM, FILTER3_NUM])
    b = get_biases([FILTER3_NUM])
    conv3_op = tf.nn.conv2d(
        input=pooling2,
        filter=w,
        strides=[1, 1, 1, 1],
        padding="SAME",
        name='conv3_op'
    )
    conv3 = tf.nn.relu(tf.nn.bias_add(conv3_op, b), name='relu')

  

第四層池化

  然后進行池化,隨機減少特征:

# 第四層:池化層pooling4
    '''
    input: [-1, 14, 14, 64]
    output: [-1, 7, 7, 64]
    '''
    with tf.name_scope("pooling4"):
        pooling4 = tf.nn.max_pool(
            value=conv3,
            ksize=[1, 2, 2, 1],
            strides=[1, 2, 2, 1],
            padding="SAME",
            name="pooling4"
        )

  

全連接層

  現在圖片的尺寸減少到7*7,我們加入一個3136個神經元的全連接層,用于處理整個圖片。我們先把池化層輸出的張量reshape成一些向量,也就是展開它。然后輸入其權重公式,偏置項公式,然后求其L2_Loss函數,最后代碼如下:

# 池化結果展開
'''
input: [-1, 7,7,64]
output: [-1, 3136]
'''
pooling4_flat = tf.reshape(pooling4, [-1, FLAT_SIZE])
print("5 step ok!")

# 第五層:全連接層 FC5
'''
input: [-1, 3136]  (56*56=3136)
output: [-1, 512]
'''
with tf.name_scope('fc5'):
    w = get_weights([FLAT_SIZE, FC5_SIZE])
    b = get_biases([FC5_SIZE])
    fc5 = tf.nn.relu(tf.nn.xw_plus_b(pooling4_flat, w, b, name='fc5'), name='relu')
    fc5_drop = tf.nn.dropout(fc5, droput_keep_prob)
    l2_loss += tf.nn.l2_loss(w) + tf.nn.l2_loss(b)
print("6 step OK")

# 第六層:全連接層(輸出)
'''
input: [-1, 512]
output: [-1, 10]
'''
with tf.name_scope('fc6'):
    w = get_weights([FC5_SIZE, OUTPUT_SIZE])
    b = get_biases([OUTPUT_SIZE])
    y_hat = tf.nn.xw_plus_b(fc5_drop, w, b, name='y_hat')
    l2_loss += tf.nn.l2_loss(w) + tf.nn.l2_loss(b)
print("7 step ok!")

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=y_hat, labels=input_y)
cross_entropy_mean = tf.reduce_mean(cross_entropy)
loss = cross_entropy_mean + L2NORM_RATE * l2_loss

  

簡易前饋神經網絡訓練MNIST數據

  下面利用TensorFlow使用MNIST數據集訓練并評估一個用于識別手寫數字的簡易前饋神經網絡(feed-forward neural network)。

1,代碼如下:

  其中說明一下下面兩個文件的目的:

1,full_connected_mnist.py 構建一個完全連接(fully connected)的MNIST模型所需的代碼
2,full_connected_feed.py 利用下載的數據集訓練構建好的MNIST模型的主要代碼

  full_connected_mnist.py代碼如下:

# _*_coding:utf-8_*_
"""Builds the MNIST network.
# 為模型構建實現推理 損失 訓練的模型
Implements the inference/loss/training pattern for model building.
# 推理  根據運行網絡的需要 構建模型向前做預測
1. inference() - Builds the model as far as required for running the network forward to make predictions.
#  將生成loss所需的層添加到推理模型中
2. loss() - Adds to the inference model the layers required to generate loss.
# 訓練  將生成和所需的ops添加到損失模型中并應用梯度
3. training() - Adds to the loss model the Ops required to generate and apply gradients.
This file is used by the various "fully_connected_*.py" files and not meant to
be run.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import math

import tensorflow as tf

# The MNIST dataset has 10 classes representing the digits 0 through 9
NUM_CLASSES = 10

# The MNIST images are always 28*28 pixels
IMAGES_SIZE = 28
IMAGES_PIXELS = IMAGES_SIZE * IMAGES_SIZE


def inference(images, hidden1_units, hidden2_units):
    """Build the MNIST model up to where it may be used for inference.
  Args:
    images: Images placeholder, from inputs().
    hidden1_units: Size of the first hidden layer.
    hidden2_units: Size of the second hidden layer.
  Returns:
    softmax_linear: Output tensor with the computed logits.
  """
    # hidden1
    with tf.name_scope('hidden1'):
        weights = tf.Variable(
            tf.truncated_normal([IMAGES_PIXELS, hidden1_units],
                                stddev=1.0 / math.sqrt(float(IMAGES_PIXELS))),
            name='weights'
        )
        biases = tf.nn.relu(tf.matmul([hidden1_units]),
                            name='weights')
        hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
    # hidden2
    with tf.name_scope('hidden2'):
        weights = tf.Variable(
            tf.truncated_normal([hidden1_units, hidden2_units],
                                stddev=1.0 / math.sqrt(float(hidden1_units))),
            name='weights'
        )
        biases = tf.Variable(tf.zeros([hidden2_units]),
                             name='biases')
        hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
    # Linear
    with tf.name_scope('softmax_linear'):
        weights = tf.Variable(
            tf.truncated_normal([hidden2_units, NUM_CLASSES],
                                stddev=1.0 / math.sqrt(float(hidden2_units))),
            name='weights'
        )
        biases = tf.nn.relu(tf.zeros([NUM_CLASSES]),
                            name='biases')
        logits = tf.matmul(hidden2, weights) + biases
    return logits


def loss(logits, labels):
    """Calculates the loss from the logits and the labels.
  Args:
    logits: Logits tensor, float - [batch_size, NUM_CLASSES].
    labels: Labels tensor, int32 - [batch_size].
  Returns:
    loss: Loss tensor of type float.
  """
    labels = tf.to_int64(labels)
    return tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)


def training(loss, learning_rate):
    """Sets up the training Ops.
  Creates a summarizer to track the loss over time in TensorBoard.
  Creates an optimizer and applies the gradients to all trainable variables.
  The Op returned by this function is what must be passed to the
  `sess.run()` call to cause the model to train.
  Args:
    loss: Loss tensor, from loss().
    learning_rate: The learning rate to use for gradient descent.
  Returns:
    train_op: The Op for training.
  """
    # add a scalar summary for the snapshot loss
    tf.summary.scalar('loss', loss)
    # create the gradient descent optimizer with the given learning rate
    optimizer = tf.train.GradientDescentOptimizer(learning_rate)
    # create a variable to track the global step
    global_step = tf.Variable(0, name='global_step', trainable=False)
    # Use the optimizer to apply the gradients that minimize the loss
    # (and also increment the global step counter) as a single training step.
    train_op = optimizer.minimize(loss, global_step=global_step)
    return train_op


def evaluation(logits, labels):
    """Evaluate the quality of the logits at predicting the label.
    Args:
      logits: Logits tensor, float - [batch_size, NUM_CLASSES].
      labels: Labels tensor, int32 - [batch_size], with values in the
        range [0, NUM_CLASSES).
    Returns:
      A scalar int32 tensor with the number of examples (out of batch_size)
      that were predicted correctly.
    """
    # For a classifier model, we can use the in_top_k Op.
    # It returns a bool tensor with shape [batch_size] that is true for
    # the examples where the label is in the top k (here k=1)
    # of all logits for that example.
    correct = tf.nn.in_top_k(logits, labels, 1)
    # Return the number of true entries.
    return tf.reduce_sum(tf.cast(correct, tf.int32))

  full_connected_feed.py代碼如下:

#_*_coding:utf-8_*_
'''Trains and Evaluates the MNIST  network using a feed dictionary'''
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pulint:disable=missing-docstring
import argparse
import os
import sys
import time

from six.moves import xrange   # pylint: disable=redefined-builtin
import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.examples.tutorials.mnist import mnist

# Basic model parameters as external flags
FLAGS = None

def placeholder_inputs(batch__size):
    '''
        生成一個占位符變量來表述輸入張量
        這些占位符被模型構建的其余部分用作輸入代碼,并將從下面 .run() 循環中下載數據提供
    :param batch__size:
    :return: 返回一個 圖像的占位符,一個標簽占位符
    '''
    # Note that the shapes of the placeholders match the shapes of the full
    # image and label tensors, except the first dimension is now batch_size
    # rather than the full size of the train or test data sets.
    images_placeholder = tf.placeholder(tf.float32, shape=(batch__size, mnist.IMAGE_PIXELS))
    labels_placeholder = tf.placeholder(tf.int32, shape=(batch__size))
    return images_placeholder, labels_placeholder

def fill_feed_dict(data_set, images_pl, labels_pl):
    """Fills the feed_dict for training the given step.
      A feed_dict takes the form of:
      feed_dict = {
          <placeholder>: <tensor of values to be passed for placeholder>,
          ....
      }
      Args:
        data_set: The set of images and labels, from input_data.read_data_sets()
        images_pl: The images placeholder, from placeholder_inputs().
        labels_pl: The labels placeholder, from placeholder_inputs().
      Returns:
        feed_dict: The feed dictionary mapping from placeholders to values.
      """
    # Create the feed_dict for the placeholders filled with the next
    # `batch size` examples.
    images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size, FLAGS.fake_data)
    feed_dict = {
        images_pl: images_feed,
        labels_pl: labels_feed,
    }
    return feed_dict

def do_evaluation(sess, eval_correct, images_placeholder, labels_placeholder, data_set):
    '''
        對陣個數據進行評估
    :param sess: The session in which the model has been trained.
    :param eval_correct: The Tensor that returns the number of correct predictions.
    :param images_placeholder: The images placeholder.
    :param labels_placeholder: The labels placeholder.
    :param data_set: The set of images and labels to evaluate, from
      input_data.read_data_sets().
    :return:
    '''
    # and run one epoch of eval
    true_count = 0  # counts the number of correct predictions
    steps_per_epoch = data_set.num_examples // FLAGS.batch_size
    num_examples = steps_per_epoch * FLAGS.batch_size
    for step in range(steps_per_epoch):
        feed_dict = fill_feed_dict(data_set, images_placeholder, labels_placeholder)
        true_count += sess.run(eval_correct, feed_dict=feed_dict)
    precision = float(true_count) / num_examples
    print('Num examples: %d  Num correct: %d  Precision @ 1: %0.04f' %
          (num_examples, true_count, precision))

def run_training():
    '''Train MNIST for  a number of steps'''
    # get the sets of images and labels for training  validation and test on MNIST
    data_sets = input_data.read_data_sets(FLAGS.input_data_dir, FLAGS.fake_data)

    # Tell Tensorflow that the model will be built into the default graph
    with tf.Graph().as_default():
        #Generate placeholders for the images and labels
        images_placeholder, labels_placeholder = placeholder_inputs(FLAGS.batch_size)

    # build a graph that computes predictions from the inference model
    logits = mnist.inference(images_placeholder, FLAGS.hidden1, FLAGS.hidden2)

    # add to graph the ops for loss calculation
    loss = mnist.loss(logits, labels_placeholder)

    # add to the graph the ops that calculate and apply gradients
    train_op = mnist.training(loss, FLAGS.learning_rate)

    # add the Op to compare the logits to the labels during evaluation
    eval_correct = mnist.evaluation(logits, labels_placeholder)

    # bulid the summary Tensor based on the TF collection of Summaries
    summary = tf.summary.merge_all()

    # add the variable initializer Op
    init = tf.global_variables_initializer()

    # create a saver fro writing training checkpoint
    saver = tf.train.Saver()

    # create a session for running Ops on the Graph
    sess = tf.compat.v1.Session()

    # Instantiate a SummaryWriter to output summaries and the graph
    summary_writer = tf.summary.FileWriter(FLAGS.log_dir, sess.graph)

    # and then after everything is built

    # run the Op to initialize the variables
    sess.run(init)

    # start the training loop
    for step in range(FLAGS.max_steps):
        start_time = time.time()

        # Fill a feed dictionary with the actual set of images and labels
        # for this particular training step.
        feed_dict = fill_feed_dict(data_sets.train,
                                   images_placeholder,
                                   labels_placeholder)

        # Run one step of the model.  The return values are the activations
        # from the `train_op` (which is discarded) and the `loss` Op.  To
        # inspect the values of your Ops or variables, you may include them
        # in the list passed to sess.run() and the value tensors will be
        # returned in the tuple from the call.
        _, loss_value = sess.run([train_op, loss],
                                 feed_dict=feed_dict)

        duration = time.time() - start_time

        # write the summaries and print an overview fairly often
        if step % 100 == 0:
            # Print status to stdout.
            print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
            # Update the events file.
            summary_str = sess.run(summary, feed_dict=feed_dict)
            summary_writer.add_summary(summary_str, step)
            summary_writer.flush()

        # Save a checkpoint and evaluate the model periodically.
        if (step + 1) % 1000 == 0 or (step + 1) == FLAGS.max_steps:
            checkpoint_file = os.path.join(FLAGS.log_dir, 'model.ckpt')
            saver.save(sess, checkpoint_file, global_step=step)
            # Evaluate against the training set.
            print('Training Data Eval:')
            do_evaluation(sess,
                    eval_correct,
                    images_placeholder,
                    labels_placeholder,
                    data_sets.train)
            # Evaluate against the validation set.
            print('Validation Data Eval:')
            do_evaluation(sess,
                    eval_correct,
                    images_placeholder,
                    labels_placeholder,
                    data_sets.validation)
            # Evaluate against the test set.
            print('Test Data Eval:')
            do_evaluation(sess,
                    eval_correct,
                    images_placeholder,
                    labels_placeholder,
                    data_sets.test)


def main():
    if tf.gfile.Exists(FLAGS.log_dir):
        tf.gfile.DeleteRecursively(FLAGS.log_dir)
    tf.gfile.MakeDirs(FLAGS.log_dir)
    run_training()


def main(_):
  if tf.gfile.Exists(FLAGS.log_dir):
    tf.gfile.DeleteRecursively(FLAGS.log_dir)
  tf.gfile.MakeDirs(FLAGS.log_dir)
  run_training()


if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--learning_rate',
      type=float,
      default=0.01,
      help='Initial learning rate.'
  )
  parser.add_argument(
      '--max_steps',
      type=int,
      default=2000,
      help='Number of steps to run trainer.'
  )
  parser.add_argument(
      '--hidden1',
      type=int,
      default=128,
      help='Number of units in hidden layer 1.'
  )
  parser.add_argument(
      '--hidden2',
      type=int,
      default=32,
      help='Number of units in hidden layer 2.'
  )
  parser.add_argument(
      '--batch_size',
      type=int,
      default=100,
      help='Batch size.  Must divide evenly into the dataset sizes.'
  )
  parser.add_argument(
      '--input_data_dir',
      type=str,
      default=os.path.join(os.getenv('TEST_TMPDIR', ''),
                           'input_data'),
      help='Directory to put the input data.'
  )
  parser.add_argument(
      '--log_dir',
      type=str,
      default=os.path.join(os.getenv('TEST_TMPDIR', ''),
                           'fully_connected_feed'),
      help='Directory to put the log data.'
  )
  parser.add_argument(
      '--fake_data',
      default=False,
      help='If true, uses fake data for unit testing.',
      action='store_true'
  )

  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

  注意事項:

此處參數注意修改!!

  結果展示:

Extracting data	rain-images-idx3-ubyte.gz
Extracting data	rain-labels-idx1-ubyte.gz
Extracting data	10k-images-idx3-ubyte.gz
Extracting data	10k-labels-idx1-ubyte.gz
Step 0: loss = 2.30 (0.114 sec)
Step 100: loss = 2.11 (0.002 sec)
Step 200: loss = 1.92 (0.002 sec)
Step 300: loss = 1.49 (0.002 sec)
Step 400: loss = 1.22 (0.002 sec)
Step 500: loss = 0.95 (0.003 sec)
Step 600: loss = 0.73 (0.003 sec)
Step 700: loss = 0.58 (0.004 sec)
Step 800: loss = 0.58 (0.002 sec)
Step 900: loss = 0.50 (0.002 sec)
Training Data Eval:
Num examples: 55000  Num correct: 47310  Precision @ 1: 0.8602
Validation Data Eval:
Num examples: 5000  Num correct: 4365  Precision @ 1: 0.8730
Test Data Eval:
Num examples: 10000  Num correct: 8628  Precision @ 1: 0.8628
Step 1000: loss = 0.51 (0.017 sec)
Step 1100: loss = 0.46 (0.104 sec)
Step 1200: loss = 0.50 (0.002 sec)
Step 1300: loss = 0.40 (0.003 sec)
Step 1400: loss = 0.57 (0.003 sec)
Step 1500: loss = 0.40 (0.003 sec)
Step 1600: loss = 0.42 (0.003 sec)
Step 1700: loss = 0.44 (0.003 sec)
Step 1800: loss = 0.41 (0.002 sec)
Step 1900: loss = 0.37 (0.000 sec)
Training Data Eval:
Num examples: 55000  Num correct: 49375  Precision @ 1: 0.8977
Validation Data Eval:
Num examples: 5000  Num correct: 4529  Precision @ 1: 0.9058
Test Data Eval:
Num examples: 10000  Num correct: 8985  Precision @ 1: 0.8985

  準確率比起卷積神經網絡還是差點,但是效果還是不錯的。這里我們主要是學習這個過程,了解深度學習訓練模型的過程,所以還好。

2,部分代碼解析

下載

  在run_training() 方法的一開始, input_data.read_data_sets() 函數會確保我們的本地訓練文件夾中,是否已經下載了正確的數據,然后將這些數據解壓并返回一個含有DataSet實例的字典。

data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)

  注意:fake_data標記是用于單元測試的。

  數據展示如下:

輸入與占位符(inputs and placeholders)

  placeholder_inputs() 函數將生成兩個 tf.placeholder 操作,定義傳入圖表中的 shape 參數, shape參數中包括 batch_size 值,后續還會將實際的訓練用例傳入圖表。

images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,
                                                       IMAGE_PIXELS))

labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))

  在訓練循環(training loop)的后續步驟中,傳入的整個圖像和標簽數據集會被切片,以符合每一個操作所設置的batch_size值,占位符操作將會填補以符合這個batch_size值。然后使用feed_dict參數,將數據傳入sess.run()函數。

構建圖表(Build the Graph)

  在為數據創建占位符之后,就可以運行full_connected_mnist.py文件,經過三階段的模式函數操作: inference() loss() training() 圖表就構建完成了。

inference():盡可能的構建好圖表,滿足促使神經網絡向前反饋并作出預測的要求。
loss():往inference 圖表中添加生成損失(loss)所需要的操作(ops)
training() :往損失函數中添加計算并應用梯度(gradients)所需要的操作

推理(Inference)

  inference()函數會盡可能的構建圖表,做到返回包含了預測結果(output prediction)的Tensor。

  它接受圖像占位符為輸入,在此基礎上借助ReLU(Rectified Linear Units)激活函數,構建一對完全連接層(layers),以及一個有著十個節點(node),指明了輸出 logits 模型的線性層。

  每一層都創建于一個唯一的 tf.name_scope之下,創建于該作用域之下的所有元素都將帶有其前綴。

with tf.name_scope('hidden1') as scope:

  在定義的作用域中,每一層所使用的權重和偏差都在 tf.Variable實例中生成,并且包含了各自期望的shape。

weights = tf.Variable(
    tf.truncated_normal([IMAGE_PIXELS, hidden1_units],
                        stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))),
    name='weights')

biases = tf.Variable(tf.zeros([hidden1_units]),
                     name='biases')

  例如,當這些層是在hidden1 作用域下生成時,賦予權重變量的獨特名稱將會是“hidden1/weights”。

  每個變量在構建時,都會獲得初始化操作(initializer ops)。

  在這種最常見的情況下,通過tf.truncated_normal函數初始化權重變量,給賦予的shape則是一個二維tensor,其中第一個維度代表該層中權重變量所連接(connect from)的單元數量,第二個維度代表該層中權重變量所連接到的(connect to)單元數量。對于名叫hidden1的第一層,相應的維度則是[IMAGE_PIXELS, hidden1_units],因為權重變量將圖像輸入連接到了hidden1層。tf.truncated_normal初始函數將根據所得到的均值和標準差,生成一個隨機分布。

  然后,通過tf.zeros函數初始化偏差變量(biases),確保所有偏差的起始值都是0,而它們的shape則是其在該層中所接到的(connect to)單元數量。

  圖表的三個主要操作,分別是兩個tf.nn.relu操作,它們中嵌入了隱藏層所需的tf.matmul;以及logits模型所需的另外一個tf.matmul。三者依次生成,各自的tf.Variable實例則與輸入占位符或下一層的輸出tensor所連接。

hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)

hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)

logits = tf.matmul(hidden2, weights) + biases

  最后,程序會返回包含了輸出結果的logits Tensor。

損失(loss)

  loss()函數通過添加所需要的損失操作,進一步構建圖表。

  首先,labels_placeholder中的值,將被編碼為一個含有1-hot values 的Tensor。例如,如果類標識符為“3”,那么該值就會被轉換為:[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

batch_size = tf.size(labels)
labels = tf.expand_dims(labels, 1)
indices = tf.expand_dims(tf.range(0, batch_size, 1), 1)
concated = tf.concat(1, [indices, labels])
onehot_labels = tf.sparse_to_dense(
    concated, tf.pack([batch_size, NUM_CLASSES]), 1.0, 0.0)

  之后,又添加一個 tf.nn.softmax_cross_entropy_with_logits操作,用來比較 inference() 函數與 1-hot 標簽所輸出的 logits Tensor。

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits,
                                                        onehot_labels,
                                                        name='xentropy')

  然后,使用tf.reduce_mean() 函數,計算 batch 維度(第一維度)下交叉熵(cross entropy)的平均值,將該值作為總損失。

loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')

  最后程序會返回包含了損失值的Tensor。

訓練training()

  training() 函數添加了通過梯度下降(gradient descent)將損失最小化所需要的操作。

  首先,該函數從loss() 函數中獲得損失Tensor,將其交給 tf.scalar_summary,后者在于SummaryWriter配合使用時,可以向事件文件(events file)中生成匯總值(summary values)。每次寫入匯總值時,它都會釋放損失Tensor的當前值(snapshot value)。

tf.scalar_summary(loss.op.name, loss)

  接下來,我們實例化一個tf.train.GradientDescentOptimizer,負責按照所要求的學習效率(learning rate)應用梯度下降法(gradients)。

optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)

  之后,我們生成一個變量用于保存全局訓練步驟(global training step)的數值,并使用minimize()函數更新系統中的三角權重(triangle weights)、增加全局步驟的操作。根據慣例,這個操作被稱為train_op,是TensorFlow會話(session)誘發一個完整訓練步驟所必須運行的操作(見下文)。

global_step = tf.Variable(0, name='global_step', trainable=False)
train_op = optimizer.minimize(loss, global_step=global_step)

  最后,程序返回包含了訓練操作(training op)輸出結果的Tensor。

圖表

  在 run_training() 這個函數的一開始,是一個python語言的with命令,這個命令表明所有已經構建的操作都要與默認的 tf.Graph 全局實例關聯起來。

with tf.Graph().as_default():

  tf.Graph實例是一系列可以作為整體執行的操作。TensorFlow的大部分場景只需要依賴默認圖表一個實例即可。

會話

  完成全部的構建準備,生成全部所需的操作之后,我們就可以創建一個tf.Session,用于運行圖表。

sess = tf.Session()

  當然,我們也可以利用with 代碼塊生成Session,限制作用域:

with tf.Session() as sess:

  Session函數中沒有傳入參數,表明該代碼將會依附于(如果還沒有創建會話,則會創建新的會話)默認的本地會話。

  生成會話之后,所有tf.Variable實例都會立即通過調用各自初始化操作中的sess.run()函數進行初始化。

init = tf.initialize_all_variables()
sess.run(init)

  sess.run()方法將會運行圖表中與作為參數傳入的操作相對應的完整子集。在初次調用時,init操作只包含了變量初始化程序tf.group。圖表的其他部分不會在這里,而是在下面的訓練循環運行。

訓練循環

  完成會話中變量的初始化之后,就可以開始訓練了。

  訓練的每一步都是通過用戶代碼控制,而能實現有效訓練的最簡單循環就是:

for step in range(max_steps):
    sess.run(train_op)

  但是我們這里需要更復雜一點,因為我們必須把輸入的數據根據每一步的情況進行切分,以匹配之前生成的占位符。

向圖表提供反饋

  執行每一步時,我們的代碼會生成一個反饋字典(feed dictionary),其中包含對應步驟中訓練所要使用的例子,這些例子的哈希鍵就是其所代表的占位符操作。

  fill_feed_dict函數會查詢給定的DataSet,索要下一批次batch_size的圖像和標簽,與占位符相匹配的Tensor則會包含下一批次的圖像和標簽。

images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size)

  然后,以占位符為哈希鍵,創建一個python字典對象,鍵值則是其代表的反饋Tensor。

feed_dict = {
    images_placeholder: images_feed,
    labels_placeholder: labels_feed,
}

  這個字典隨后作為feed_dict參數,傳入sess.run()函數中,為這一步的訓練提供輸入樣例。

檢查狀態

  在運行sess.run函數時,要在代碼中明確其需要獲取的兩個值:[train_op, loss]

for step in range(FLAGS.max_steps):
    feed_dict = fill_feed_dict(data_sets.train,
                               images_placeholder,
                               labels_placeholder)
    _, loss_value = sess.run([train_op, loss],
                             feed_dict=feed_dict)

  因為要獲取這兩個值,sess.run()會返回一個有兩個元素的元組。其中每一個Tensor對象,對應了返回的元組中的numpy數組,而這些數組中包含了當前這步訓練中對應Tensor的值。由于train_op并不會產生輸出,其在返回的元祖中的對應元素就是None,所以會被拋棄。但是,如果模型在訓練中出現偏差,lossTensor的值可能會變成NaN,所以我們要獲取它的值,并記錄下來。

  假設訓練一切正常,沒有出現NaN,訓練循環會每隔100個訓練步驟,就打印一行簡單的狀態文本,告知用戶當前的訓練狀態。

if step % 100 == 0:
    print 'Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration)

  

狀態可視化

  為了釋放TensorBoard所使用的事件文件(events file),所有的即時數據(在這里只有一個)都要在圖表構建階段合并至一個操作(op)中。

summary_op = tf.merge_all_summaries()

  在創建好會話(session)之后,可以實例化一個tf.train.SummaryWriter,用于寫入包含了圖表本身和即時數據具體值的事件文件。

summary_writer = tf.train.SummaryWriter(FLAGS.train_dir,
                                        graph_def=sess.graph_def)

  最后,每次運行summary_op時,都會往事件文件中寫入最新的即時數據,函數的輸出會傳入事件文件讀寫器(writer)的add_summary()函數。

summary_str = sess.run(summary_op, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)

  

執行sess會話的下面代碼報錯:

    sess = tf.compat.v1.Session()

AttributeError: module 'tensorflow.python.util.compat' has no attribute 'v1'

  解決方法:

    sess = tf.Session()

  

參考文獻:https://blog.csdn.net/GeForce_GTX1080Ti/article/details/80119194

TensorFlow官網(http://www.tensorfly.cn/tfdoc/tutorials/mnist_beginners.html)

http://wiki.jikexueyuan.com/project/tensorflow-zh/tutorials/mnist_tf.html

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/mnist/fully_connected_feed.py

此處是做以筆記,記錄學習過程,若有侵權,請聯系我

總結

以上是生活随笔為你收集整理的tensorflow学习笔记——使用TensorFlow操作MNIST数据(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。