tensorflow中文社區(qū)對官方文檔進行了完整翻譯哑梳。鑒于官方更新不少內(nèi)容,而現(xiàn)有的翻譯基本上都已過時拙徽。故本人對更新后文檔進行翻譯工作刨沦,紕漏之處請大家指正。(如需了解其他方面知識膘怕,可參閱以下Tensorflow系列文章)想诅。
Tensorflow系列文章
- Tensorflow- MNIST機器學習入門
- Tensorflow- CNN卷積神經(jīng)網(wǎng)絡的MNIST手寫數(shù)字識別
- Tensorflow- 循環(huán)神經(jīng)網(wǎng)絡(LSTM)
這個教程的目標讀者是對機器學習和TensorFlow都不太了解的新手。如果你已經(jīng)了解MNIST和softmax回歸(softmax regression)的相關(guān)知識岛心,你可以直接閱讀這個faster paced tutorial来破。在學習教程之前,請確保已經(jīng)安裝Install TensorFlow忘古。
當我們開始學習編程的時候讳癌,第一件事往往是學習打印"Hello World"。就好比編程入門有Hello World存皂,機器學習入門則是MNIST晌坤。
MNIST是一個入門級的計算機視覺數(shù)據(jù)集,它包含各種手寫數(shù)字圖片:
它也包含每一張圖片對應的標簽旦袋,告訴我們這個是數(shù)字幾骤菠。比如,上面這四張圖片的標簽分別是5疤孕,0商乎,4,1祭阀。
在此教程中鹉戚,我們將訓練一個機器學習模型用于預測圖片里面的數(shù)字鲜戒。我們的目的不是要設計一個世界一流的復雜模型 -- 盡管我們會在之后給你源代碼去實現(xiàn)一流的預測模型 -- 而是要介紹下如何使用TensorFlow。所以抹凳,我們這里會從一個很簡單的數(shù)學模型開始遏餐,它叫做Softmax Regression。
對應這個教程的實現(xiàn)代碼很短赢底,而且真正有意思的內(nèi)容只包含在三行代碼里面失都。但是,去理解包含在這些代碼里面的設計思想是非常重要的:TensorFlow工作流程和機器學習的基本概念幸冻。因此粹庞,這個教程會很詳細地介紹這些代碼的實現(xiàn)原理。
關(guān)于本教程
本教程將對mnist_softmax.py代碼的逐行進行解釋洽损。
你可以采取不同的方式學習本教程庞溜,包括:
- 復制、粘貼每一行代碼段到Python環(huán)境碑定,同時通讀每一行的解釋
- 直接運行mnist_softmax.py文件流码,然后使用本教程來理解代碼中你還不清楚的部分
我們將在本教程中實現(xiàn):
- 了解MNIST數(shù)據(jù)集和softmax回歸
- 實現(xiàn)一個函數(shù)來識別MNIST手寫數(shù)字集,這是個基于圖像中每個像素點的模型
- 用Tensorflow通過上萬個樣本的數(shù)據(jù)集訓練出識別數(shù)字的模型
- 用測試數(shù)據(jù)集驗證模型的準確率
MNIST數(shù)據(jù)集
MNIST數(shù)據(jù)集的官網(wǎng)是Yann LeCun's website不傅。如果你打算復制旅掂、粘貼本教程的代碼,從這兩行代碼開始访娶,這段代碼會自動下載商虐、讀入數(shù)據(jù)集:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
下載下來的數(shù)據(jù)集被分成兩部分:60000行的訓練數(shù)據(jù)集(mnist.train)和10000行的測試數(shù)據(jù)集(mnist.test)。這樣的切分很重要崖疤,在機器學習模型設計時必須有一個單獨的測試數(shù)據(jù)集不用于訓練而是用來評估這個模型的性能秘车,從而更加容易把設計的模型推廣到其他數(shù)據(jù)集上(泛化)。
下載下來的數(shù)據(jù)集被分成三部分:55000個的訓練樣本(mnist.train)和10000個的測試樣本(mnist.test)劫哼,還有5000個驗證樣本(mnist.validation)叮趴。這樣的切分很重要,在機器學習模型設計時必須有一個單獨的測試數(shù)據(jù)集不用于訓練而是用來評估這個模型的性能权烧,從而更加容易把設計的模型推廣到其他數(shù)據(jù)集上(泛化)眯亦。
正如前面提到的一樣,每一個MNIST數(shù)據(jù)單元有兩部分組成:一張包含手寫數(shù)字的圖片和一個對應的標簽般码。我們把這些圖片設為“x”妻率,把這些標簽設為“y”。訓練數(shù)據(jù)集和測試數(shù)據(jù)集都包含x和y板祝,比如訓練數(shù)據(jù)集的圖片是 mnist.train.images 宫静,訓練數(shù)據(jù)集的標簽是 mnist.train.labels。
每一張圖片包含28像素X28像素。我們可以用一個數(shù)字數(shù)組來表示這張圖片:
我們把這個數(shù)組展開成一個向量孤里,長度是 28x28 = 784伏伯。如何展開這個數(shù)組(數(shù)字間的順序)不重要,只要保持各個圖片采用相同的方式展開捌袜。從這個角度來看说搅,MNIST數(shù)據(jù)集的圖片就是在784維向量空間里面的點, 并且擁有比較very rich structure (提醒: 此類數(shù)據(jù)的可視化是計算密集型的)。
展平圖片的數(shù)字數(shù)組會丟失圖片的二維結(jié)構(gòu)信息琢蛤。這顯然是不理想的蜓堕,最優(yōu)秀的計算機視覺方法會挖掘并利用這些結(jié)構(gòu)信息抛虏,我們會在后續(xù)教程中介紹博其。但是在這個教程中我們忽略這些結(jié)構(gòu),所介紹的簡單數(shù)學模型迂猴,softmax回歸(softmax regression)慕淡,不會利用這些結(jié)構(gòu)信息。
因此沸毁,在MNIST訓練數(shù)據(jù)集中峰髓,mnist.train.images 是一個形狀為 [55000, 784] 的張量,第一個維度數(shù)字用來索引圖片息尺,第二個維度數(shù)字用來索引每張圖片中的像素點携兵。在此張量里的每一個元素,都表示某張圖片里的某個像素的強度值搂誉,值介于0和1之間徐紧。
相對應的MNIST數(shù)據(jù)集的標簽是介于0到9的數(shù)字,用來描述給定圖片里表示的數(shù)字炭懊。為了用于這個教程并级,我們使標簽數(shù)據(jù)是"one-hot vectors"。 一個one-hot向量除了某一位的數(shù)字是1以外其余各維度數(shù)字都是0侮腹。所以在此教程中嘲碧,數(shù)字n將表示成一個只有在第n維度(從0開始)數(shù)字為1的10維向量。比如父阻,標簽3將表示成([0,0,0,1,0,0,0,0,0,0,0])愈涩。因此, mnist.train.labels 是一個 [55000, 10] 的數(shù)字矩陣加矛。
現(xiàn)在履婉,我們準備好可以開始構(gòu)建我們的模型啦!
softmax回歸
我們知道MNIST的每一張圖片都表示一個數(shù)字荒椭,從0到9谐鼎。我們希望得到給定圖片代表每個數(shù)字的概率。比如說,我們的模型可能推測一張包含9的圖片代表數(shù)字9的概率是80%但是判斷它是8的概率是5%(因為8和9都有上半部分的小圓)狸棍,然后給予它代表其他數(shù)字的概率更小的值身害。
這是一個使用softmax回歸(softmax regression)模型的經(jīng)典案例。softmax模型可以用來給不同的對象分配概率草戈。即使在之后塌鸯,我們訓練更加精細的模型時,最后一步也需要用softmax來分配概率唐片。
softmax回歸(softmax regression)分兩步:第一步我們把輸入判定為某個特定類別的證據(jù)(evidence)加起來丙猬,然后把證據(jù)轉(zhuǎn)化為概率。
為了得到一張給定圖片屬于某個特定數(shù)字類的證據(jù)(evidence)费韭,我們對圖片像素值進行加權(quán)求和茧球。如果這個像素具有很強的證據(jù)說明這張圖片不屬于該類,那么相應的權(quán)值為負數(shù)星持,相反如果這個像素擁有有利的證據(jù)支持這張圖片屬于這個類抢埋,那么權(quán)值是正數(shù)。
下面的圖片顯示了一個模型學習到的圖片上每個像素對于特定數(shù)字類的權(quán)值督暂。紅色代表負數(shù)權(quán)值揪垄,藍色代表正數(shù)權(quán)值。
我們也需要加入一個額外的偏置量(bias)逻翁,因為輸入往往會帶有一些無關(guān)的干擾量饥努。因此對于給定的輸入圖片 x 它代表的是數(shù)字 i 的證據(jù)可以表示為
其中 Wi 代表權(quán)重,bi 代表數(shù)字 i 類的偏置量八回,j 代表給定圖片 x 的像素索引用于像素求和酷愧。然后用softmax函數(shù)可以把這些證據(jù)轉(zhuǎn)換成概率 y:
這里的softmax可以看成是一個激勵(activation)函數(shù)或者鏈接(link)函數(shù),把我們定義的線性函數(shù)的輸出轉(zhuǎn)換成我們想要的格式辽社,也就是關(guān)于10個數(shù)字類的概率分布伟墙。因此,給定一張圖片滴铅,它對于每一個數(shù)字的吻合度可以被softmax函數(shù)轉(zhuǎn)換成為一個概率值戳葵。softmax函數(shù)可以定義為:
展開等式右邊的子式,可以得到:
但是更多的時候把softmax模型函數(shù)定義為前一種形式:把輸入值當成冪指數(shù)求值汉匙,再歸一化這些結(jié)果值拱烁。這個冪運算表示,更大的證據(jù)對應更大的假設模型(hypothesis)里面的乘數(shù)權(quán)重值噩翠。反之戏自,擁有更少的證據(jù)意味著在假設模型里面擁有更小的乘數(shù)系數(shù)。假設模型里的權(quán)值不可以是0值或者負值伤锚。Softmax然后會歸一化這些權(quán)重值擅笔,使它們的總和等于1,以此構(gòu)造一個有效的概率分布。(更多的關(guān)于Softmax函數(shù)的信息猛们,可以參考Michael Nieslen的書里面的這個section念脯,其中有關(guān)于softmax的可交互式的可視化解釋。)
對于softmax回歸模型可以用下面的圖解釋弯淘,對于輸入的xs加權(quán)求和绿店,再分別加上一個偏置量,最后再輸入到softmax函數(shù)中:
如果把它寫成一個等式庐橙,我們可以得到:
我們也可以用向量表示這個計算過程:用矩陣乘法和向量相加假勿。這有助于提高計算效率。(也是一種更有效的思考方式)
實現(xiàn)回歸模型
為了用python實現(xiàn)高效的數(shù)值計算转培,我們通常會使用函數(shù)庫,比如NumPy郁惜,會把類似矩陣乘法這樣的復雜運算使用其他外部語言實現(xiàn)堡距。不幸的是甲锡,從外部計算切換回Python的每一個操作兆蕉,仍然是一個很大的開銷。如果你用GPU來進行外部計算缤沦,這樣的開銷會更大虎韵。用分布式的計算方式,也會花費更多的資源用來傳輸數(shù)據(jù)缸废。
TensorFlow也把復雜的計算放在python之外完成包蓝,但是為了避免前面說的那些開銷,它做了進一步完善企量。Tensorflow不單獨地運行單一的復雜計算测萎,而是讓我們可以先用圖描述一系列可交互的計算操作,然后全部一起在Python之外運行届巩。(這樣類似的運行方式硅瞧,可以在不少的機器學習庫中看到。)
使用TensorFlow之前恕汇,首先導入它:
import tensorflow as tf
我們通過操作符號變量來描述這些可交互的操作單元腕唧,可以用下面的方式創(chuàng)建一個:
x = tf.placeholder(tf.float32, [None, 784])
x不是一個特定的值,而是一個占位符placeholder瘾英,我們在TensorFlow運行計算時輸入這個值枣接。我們希望能夠輸入任意數(shù)量的MNIST圖像,每一張圖展平成784維的向量缺谴。我們用2維的浮點數(shù)張量來表示這些圖但惶,這個張量的形狀是[None,784 ]。(這里的None表示此張量的第一個維度可以是任何長度的)
我們的模型也需要權(quán)重值和偏置量膀曾,當然我們可以把它們當做是另外的輸入(使用占位符)片拍,但TensorFlow有一個更好的方法來表示它們:Variable 。 一個Variable代表一個可修改的張量妓肢,存在在TensorFlow的用于描述交互性操作的圖中捌省。它們可以用于計算輸入值,也可以在計算中被修改碉钠。對于各種機器學習應用纲缓,一般都會有模型參數(shù),可以用Variable表示喊废。
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
我們賦予tf.Variable不同的初值來創(chuàng)建不同的Variable:在這里祝高,我們都用全為零的張量來初始化W和b。因為我們要學習W和b的值污筷,它們的初值可以隨意設置工闺。注意,W的維度是[784瓣蛀,10]陆蟆,因為我們想要用784維的圖片向量乘以它以得到一個10維的證據(jù)值向量,每一位對應不同數(shù)字類惋增。b的形狀是[10]叠殷,所以我們可以直接把它加到輸出上面。
現(xiàn)在诈皿,我們可以實現(xiàn)我們的模型啦林束。只需要一行代碼!
y = tf.nn.softmax(tf.matmul(x,W) + b)
首先稽亏,我們用tf.matmul(??X壶冒,W)表示x乘以W,對應之前等式里面的Wx截歉,這里x是一個2維張量擁有多個輸入胖腾。然后再加上b
,把和輸入到tf.nn.softmax函數(shù)里面怎披。至此胸嘁,我們先用了幾行簡短的代碼來設置變量,然后只用了一行代碼來定義我們的模型凉逛。TensorFlow不僅僅可以使softmax回歸模型計算變得特別簡單性宏,它也用這種非常靈活的方式來描述其他各種數(shù)值計算,從機器學習模型對物理學模擬仿真模型状飞。一旦被定義好之后毫胜,我們的模型就可以在不同的設備上運行:計算機的CPU书斜,GPU,甚至是手機酵使!
訓練
為了訓練我們的模型荐吉,我們首先需要定義一個指標來評估這個模型是好的。其實口渔,在機器學習样屠,我們通常定義指標來表示一個模型是壞的,這個指標稱為成本(cost)或損失(loss)缺脉,這代表著我們的模型與期望結(jié)果差距多大痪欲。我盡量最小化這個指標,錯誤幅度越小表示模型越好攻礼。
一個非常常見的业踢,非常好的成本函數(shù)是“交叉熵”(cross-entropy)。交叉熵產(chǎn)生于信息論里面的信息壓縮編碼技術(shù)礁扮,但是它后來演變成為從博弈論到機器學習等其他領(lǐng)域里的重要技術(shù)手段知举。它的定義如下:
為了計算交叉熵遮糖,我們首先需要添加一個新的占位符用于輸入正確值:
y_ = tf.placeholder(tf.float32, [None,10])
然后,我實現(xiàn)交叉熵的函數(shù):
cross_entropy = tf.reduce_mean( -tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]) )
首先叠赐,用 tf.log 計算 y 的每個元素的對數(shù)。接下來屡江,我們把 y_ 的每一個元素和 tf.log(y_) 的對應元素相乘芭概。然后,用 tf.reduce_sum 計算張量的y第2維度(因為傳入?yún)?shù)reduction_indices=[1])的所有元素的總和惩嘉。最后罢洲,tf.reduce_mean計算出所有樣本的均值。
注意文黎,在源碼中惹苗,我們沒有使用這個計算式,因為其在數(shù)學上不穩(wěn)定耸峭。作為替代桩蓉,我們將tf.nn.softmax_cross_entropy_with_logits用在logits上,建議在你的代碼里也用這個劳闹。
現(xiàn)在我們知道我們需要我們的模型做什么了院究,用TensorFlow來訓練它是非常容易的洽瞬。因為TensorFlow擁有一張描述你各個計算單元的圖,它可以自動地使用backpropagation algorithm來有效地確定你的變量是如何影響你想要最小化的那個成本值的业汰。然后伙窃,TensorFlow會用你選擇的優(yōu)化算法來不斷地修改變量以降低成本。
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
在這里样漆,我們要求TensorFlow用梯度下降算法(gradient descent algorithm)以0.5的學習速率最小化交叉熵为障。梯度下降算法(gradient descent algorithm)是一個簡單的學習過程,TensorFlow只需將每個變量一點點地往使成本不斷降低的方向移動放祟。當然TensorFlow也提供了many other optimization algorithms:只要簡單地調(diào)整一行代碼就可以使用其他的算法产场。
TensorFlow在這里實際上所做的是,它會在后臺給描述你的計算的那張圖里面增加一系列新的計算操作單元用于實現(xiàn)反向傳播算法和梯度下降算法舞竿。然后京景,它返回給你的只是一個單一的操作,當運行這個操作時骗奖,它用梯度下降算法訓練你的模型确徙,微調(diào)你的變量,不斷減少成本执桌。
現(xiàn)在我們可以在一個InteractiveSession里面啟動我們的模型鄙皇,并且初始化變量:
sess = tf.InteractiveSession()
我們首先初始化創(chuàng)建的所有變量:
tf.global_variables_initializer().run()
然后開始訓練模型,這里我們讓模型循環(huán)訓練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})
該循環(huán)的每個步驟中伴逸,我們都會隨機抓取訓練數(shù)據(jù)中的100個批處理數(shù)據(jù)點,然后我們用這些數(shù)據(jù)點作為參數(shù)替換之前的占位符來運行train_step膘壶。
使用一小部分的隨機數(shù)據(jù)來進行訓練被稱為隨機訓練(stochastic training)- 在這里更確切的說是隨機梯度下降訓練错蝴。在理想情況下,我們希望用我們所有的數(shù)據(jù)來進行每一步的訓練颓芭,因為這能給我們更好的訓練結(jié)果顷锰,但顯然這需要很大的計算開銷。所以亡问,每一次訓練我們可以使用不同的數(shù)據(jù)子集官紫,這樣做既可以減少計算開銷,又可以最大化地學習到數(shù)據(jù)集的總體特性州藕。
評估我們的模型
那么我們的模型性能如何呢束世?
首先讓我們找出那些預測正確的標簽。tf.argmax 是一個非常有用的函數(shù)床玻,它能給出某個tensor對象在某一維上的其數(shù)據(jù)最大值所在的索引值毁涉。由于標簽向量是由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))
這行代碼會給我們一組布爾值严嗜。為了確定正確預測項的比例粱檀,我們可以把布爾值轉(zhuǎn)換成浮點數(shù)享郊,然后取平均值悠菜。例如它碎,[True, False, True, True] 會變成 [1,0,1,1] 推掸,取平均值后得到 0.75。
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float))
最后佃扼,我們計算所學習到的模型在測試數(shù)據(jù)集上面的正確率兴枯。
print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
這個最終結(jié)果值應該大約是92%由缆。
這個結(jié)果好嗎汗盘?嗯皱碘,并不太好。事實上隐孽,這個結(jié)果是很差的癌椿。這是因為我們僅僅使用了一個非常簡單的模型。不過菱阵,做一些小小的改進踢俄,我們就可以得到97%的正確率。最好的模型甚至可以獲得超過99.7%的準確率G缂啊(想了解更多信息都办,可以看看這個關(guān)于各種模型的list of results。)
比結(jié)果更重要的是虑稼,我們從這個模型中學習到的設計思想琳钉。不過,如果你仍然對這里的結(jié)果有點失望动雹,可以查看CNN卷積神經(jīng)網(wǎng)絡的MNIST手寫數(shù)字識別槽卫,在那里你可以學習如何用FensorFlow構(gòu)建更加復雜的模型以獲得更好的性能!
原文地址:MNIST For ML Beginners 翻譯:周乘