TensorFlow(2) 運行MNIST

一.目的

類似學習開發語言的第一個代碼,Hello World!

機器學習中,我們通過MNIST來學習手寫輸入法的圖片來驗證機器學習算法。

本片中我會嘗試第一將MNIST庫跑起來,并計算出成功驗證的概率。

二.準備工作


到以下GITHUB中下載mnist的例子程序(MNIST例子的所有文件)

https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/tutorials/mnist

復制到

Python的安裝目錄。

我的環境中,將Python安裝在D盤的。

所以路徑為D:\Python35\Lib\site-packages\tensorflow\examples\tutorials\mnist


三.下載手寫字庫

到Yann LeCun's MNIST page將訓練樣本包下載到自定義的文件夾。

下載以下四個文件。下載完直接復制就好。

train-images-idx3-ubyte.gz:? training set images (9912422 bytes)

train-labels-idx1-ubyte.gz:? training set labels (28881 bytes)

t10k-images-idx3-ubyte.gz:?? test set images (1648877 bytes)

t10k-labels-idx1-ubyte.gz:?? test set labels (4542 bytes)

四.編寫執行代碼

from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("Z:\MSE\DeepLearning\Train\MNIST", one_hot=True)

import tensorflow as tf

x = tf.placeholder("float",[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("float", [None,10])

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

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

init = tf.initialize_all_variables()

sess = tf.Session()

sess.run(init)

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})

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

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

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

五.執行代碼后結果

D:\Python35\python.exe Z:/MSE/DeepLearning/Code/MNIST/MNIST.pyExtracting Z:\MSE\DeepLearning\Train\MNIST\train-images-idx3-ubyte.gzExtracting Z:\MSE\DeepLearning\Train\MNIST\train-labels-idx1-ubyte.gzExtracting Z:\MSE\DeepLearning\Train\MNIST\t10k-images-idx3-ubyte.gzExtracting Z:\MSE\DeepLearning\Train\MNIST\t10k-labels-idx1-ubyte.gzWARNING:tensorflow:From Z:/MSE/DeepLearning/Code/MNIST/MNIST.py:12 in.: initialize_all_variables (from tensorflow.python.ops.variables) is deprecated and will be removed after 2017-03-02.

Instructions for updating:

Use `tf.global_variables_initializer` instead.

0.9188

Process finished with exit code 0


這里的 0.9188為結果。

六.補充學習資料

MNIST機器學習入門

這個教程的目標讀者是對機器學習和TensorFlow都不太了解的新手。如果你已經了解MNIST和softmax回歸(softmax regression)的相關知識,你可以閱讀這個快速上手教程。

當我們開始學習編程的時候,第一件事往往是學習打印"Hello World"。就好比編程入門有Hello World,機器學習入門有MNIST。

MNIST是一個入門級的計算機視覺數據集,它包含各種手寫數字圖片:

它也包含每一張圖片對應的標簽,告訴我們這個是數字幾。比如,上面這四張圖片的標簽分別是5,0,4,1。

在此教程中,我們將訓練一個機器學習模型用于預測圖片里面的數字。我們的目的不是要設計一個世界一流的復雜模型 -- 盡管我們會在之后給你源代碼去實現一流的預測模型 -- 而是要介紹下如何使用TensorFlow。所以,我們這里會從一個很簡單的數學模型開始,它叫做Softmax Regression。

對應這個教程的實現代碼很短,而且真正有意思的內容只包含在三行代碼里面。但是,去理解包含在這些代碼里面的設計思想是非常重要的:TensorFlow工作流程和機器學習的基本概念。因此,這個教程會很詳細地介紹這些代碼的實現原理。

MNIST數據集

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

import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

下載下來的數據集被分成兩部分:60000行的訓練數據集(mnist.train)和10000行的測試數據集(mnist.test)。這樣的切分很重要,在機器學習模型設計時必須有一個單獨的測試數據集不用于訓練而是用來評估這個模型的性能,從而更加容易把設計的模型推廣到其他數據集上(泛化)。

正如前面提到的一樣,每一個MNIST數據單元有兩部分組成:一張包含手寫數字的圖片和一個對應的標簽。我們把這些圖片設為“xs”,把這些標簽設為“ys”。訓練數據集和測試數據集都包含xs和ys,比如訓練數據集的圖片是 mnist.train.images ,訓練數據集的標簽是 mnist.train.labels。

每一張圖片包含28像素X28像素。我們可以用一個數字數組來表示這張圖片:

我們把這個數組展開成一個向量,長度是 28x28 = 784。如何展開這個數組(數字間的順序)不重要,只要保持各個圖片采用相同的方式展開。從這個角度來看,MNIST數據集的圖片就是在784維向量空間里面的點, 并且擁有比較復雜的結構 (提醒: 此類數據的可視化是計算密集型的)。

展平圖片的數字數組會丟失圖片的二維結構信息。這顯然是不理想的,最優秀的計算機視覺方法會挖掘并利用這些結構信息,我們會在后續教程中介紹。但是在這個教程中我們忽略這些結構,所介紹的簡單數學模型,softmax回歸(softmax regression),不會利用這些結構信息。

因此,在MNIST訓練數據集中,mnist.train.images 是一個形狀為 [60000, 784] 的張量,第一個維度數字用來索引圖片,第二個維度數字用來索引每張圖片中的像素點。在此張量里的每一個元素,都表示某張圖片里的某個像素的強度值,值介于0和1之間。

相對應的MNIST數據集的標簽是介于0到9的數字,用來描述給定圖片里表示的數字。為了用于這個教程,我們使標簽數據是"one-hot vectors"。 一個one-hot向量除了某一位的數字是1以外其余各維度數字都是0。所以在此教程中,數字n將表示成一個只有在第n維度(從0開始)數字為1的10維向量。比如,標簽0將表示成([1,0,0,0,0,0,0,0,0,0,0])。因此, mnist.train.labels 是一個 [60000, 10] 的數字矩陣。

現在,我們準備好可以開始構建我們的模型啦!

Softmax回歸介紹

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

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

softmax回歸(softmax regression)分兩步:第一步

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

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

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

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

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

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

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

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

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

我們也可以用向量表示這個計算過程:用矩陣乘法和向量相加。這有助于提高計算效率。(也是一種更有效的思考方式)

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

實現回歸模型

為了用python實現高效的數值計算,我們通常會使用函數庫,比如NumPy,會把類似矩陣乘法這樣的復雜運算使用其他外部語言實現。不幸的是,從外部計算切換回Python的每一個操作,仍然是一個很大的開銷。如果你用GPU來進行外部計算,這樣的開銷會更大。用分布式的計算方式,也會花費更多的資源用來傳輸數據。

TensorFlow也把復雜的計算放在python之外完成,但是為了避免前面說的那些開銷,它做了進一步完善。Tensorflow不單獨地運行單一的復雜計算,而是讓我們可以先用圖描述一系列可交互的計算操作,然后全部一起在Python之外運行。(這樣類似的運行方式,可以在不少的機器學習庫中看到。)

使用TensorFlow之前,首先導入它:

import tensorflow as tf

我們通過操作符號變量來描述這些可交互的操作單元,可以用下面的方式創建一個:

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

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

我們的模型也需要權重值和偏置量,當然我們可以把它們當做是另外的輸入(使用占位符),但TensorFlow有一個更好的方法來表示它們:Variable 。 一個Variable代表一個可修改的張量,存在在TensorFlow的用于描述交互性操作的圖中。它們可以用于計算輸入值,也可以在計算中被修改。對于各種機器學習應用,一般都會有模型參數,可以用Variable表示。

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

b = tf.Variable(tf.zeros([10]))

我們賦予tf.Variable不同的初值來創建不同的Variable:在這里,我們都用全為零的張量來初始化W和b。因為我們要學習W和b的值,它們的初值可以隨意設置。

注意,W的維度是[784,10],因為我們想要用784維的圖片向量乘以它以得到一個10維的證據值向量,每一位對應不同數字類。b的形狀是[10],所以我們可以直接把它加到輸出上面。

現在,我們可以實現我們的模型啦。只需要一行代碼!

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

首先,我們用tf.matmul(??X,W)表示x乘以W,對應之前等式里面的,這里x是一個2維張量擁有多個輸入。然后再加上b,把和輸入到tf.nn.softmax函數里面。

至此,我們先用了幾行簡短的代碼來設置變量,然后只用了一行代碼來定義我們的模型。TensorFlow不僅僅可以使softmax回歸模型計算變得特別簡單,它也用這種非常靈活的方式來描述其他各種數值計算,從機器學習模型對物理學模擬仿真模型。一旦被定義好之后,我們的模型就可以在不同的設備上運行:計算機的CPU,GPU,甚至是手機!

訓練模型

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

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

y 是我們預測的概率分布, y' 是實際的分布(我們輸入的one-hot vector)。比較粗糙的理解是,交叉熵是用來衡量我們的預測用于描述真相的低效性。更詳細的關于交叉熵的解釋超出本教程的范疇,但是你很有必要好好理解它。

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

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

然后我們可以用? 計算交叉熵:

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

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

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

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

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

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

現在,我們已經設置好了我們的模型。在運行計算之前,我們需要添加一個操作來初始化我們創建的變量:

init = tf.initialize_all_variables()

現在我們可以在一個Session里面啟動我們的模型,并且初始化變量:

sess = tf.Session()

sess.run(init)

然后開始訓練模型,這里我們讓模型循環訓練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})

該循環的每個步驟中,我們都會隨機抓取訓練數據中的100個批處理數據點,然后我們用這些數據點作為參數替換之前的占位符來運行train_step。

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

評估我們的模型

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

首先讓我們找出那些預測正確的標簽。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))

這行代碼會給我們一組布爾值。為了確定正確預測項的比例,我們可以把布爾值轉換成浮點數,然后取平均值。例如,[True, False, True, True] 會變成 [1,0,1,1] ,取平均值后得到 0.75.

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

最后,我們計算所學習到的模型在測試數據集上面的正確率。

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

這個最終結果值應該大約是91%。

這個結果好嗎?嗯,并不太好。事實上,這個結果是很差的。這是因為我們僅僅使用了一個非常簡單的模型。不過,做一些小小的改進,我們就可以得到97%的正確率。最好的模型甚至可以獲得超過99.7%的準確率!(想了解更多信息,可以看看這個關于各種模型的性能對比列表。)

比結果更重要的是,我們從這個模型中學習到的設計思想。不過,如果你仍然對這里的結果有點失望,可以查看下一個教程,在那里你可以學習如何用FensorFlow構建更加復雜的模型以獲得更好的性能!

原文地址:MNIST For ML Beginners 翻譯:linbojin 校對:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容