2017年11月29日 星期三

TensorFlow 基礎篇〈下〉

TensorFlow 基礎篇〈下〉2017-08-01

前言

經過前面兩篇關於 TensorFlow 的介紹,相信大家已經對這個深度學習框架有了基本的認識。接下來,我們將會運用 TensorFlow 架構出 MNIST 手寫數字辨識回歸模型(regression model),並利用訓練產生的模型(model)對測試資料(test data)進行預測,檢視這個方式得到的準確率(accuracy)如何。
本篇文章的內容大部份翻譯自 TensorFlow 官網 ,文章中使用的圖片也取自於相同來源。

認識 MNIST 手寫數字辨識

對於剛開始接觸 TensorFlow 、 Keras 等深度學習框架的人而言,「MNIST 手寫數字辨識」是非常適合入門的練習項目,其角色就好比剛學習程式語言時所印出的 " Hello world ! " 一樣,讓新手初步認識與練習 TensorFlow。
而 MNIST 手寫數字辨識,顧名思義,便是讓機器辨識出手寫數字影像是 0 到 9 之間的哪一個數字,究竟這種對於人類看似輕而易舉的事情,交由機器來做的表現又會如何呢?接下來,我們將會簡單介紹如何利用 TensorFlow 完成這項練習,藉此熟悉 TensorFlow 的基本運用。

MNIST 手寫數字資料集介紹

在開始實作之前,我們需要先瞭解,到底什麼是 MNIST 手寫數字資料集?
MNIST 資料集是由 Yann LeCun 等人提供在 THE MNIST DATABASE 上面的手寫數字資料,這些資料包含圖片標籤兩種形式的內容。其中, training data(共 55000 筆)與 validation data(共 5000 筆)皆具有圖片及標籤,而 test data(共 10000 筆)則是只有圖片,而沒有標籤。每一筆資料的照片是由 28 pixels x 28 pixels ,總共 784 個 pixels 所組成,圖片顯示的是 0 到 9 之中的一個阿拉伯數字;資料的標籤則表示該手寫數字圖片所呈現的數字為何,也就是 0 到 9 中一個數值。
下面所顯示的是 MNIST 資料集中,幾張圖片經過視覺化之後的範例,我們可以由肉眼看出每張圖片所代表的數字。

圖片資料形式與讀取

MNIST 資料集是一個適合拿來當作 TensotFlow 的練習素材,在 TensorFlow 的現有套件中,也已經有內建好的 MNIST 資料集,我們只要在安裝好 TensorFlow 的 Python 環境中執行以下程式碼,即可將 MNIST 資料成功讀取進來。
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
根據文章前段所述,每一筆 MNIST 資料的照片由 784 個 pixels 組成,因此,我們可以把它視為一個大型矩陣(array),矩陣裡每一項的資料則是代表每個 pixel 顏色深淺的數值,如下圖所示。
每一筆 MNIST 資料的標籤,則是以 one-hot encoding 的形式呈現,每一個標籤都是一個 one-hot vector。
所謂 one-hot vector 的形式,代表該 vector 第一個維度對應數字 0 ,第二個維度對應數字 1 ,以此類推,總共有十個維度。一個標籤數值為 n 的標籤,只有其對應之維度的數值為 1 ,其他維度的數值皆為 0 ,而如此就是 one-hot vector 的特性。
舉例來說,代表標籤數字為 0 的 one-hot vector 為 [ 1 0 0 0 0 0 0 0 0 0 ] 、代表標籤數字為 1 的則是 [ 0 1 0 0 0 0 0 0 0 0 ] ,諸如此類。將這些 one-hot vector 串聯(concatenate)起來,就會形成 one-hot array ,MNIST 資料集中的標籤資料即是用這種方式表示。
經過以上解說,我們已經大致認識 MNIST 資料集的內容,此外,以此資料集中的 training data 為例,我們可以從下面這兩張示意圖瞭解 MNIST 資料集的大致資料格式。

softmax 回歸模型介紹

前言中提到,我們要實作的是一個回歸模型,對於 MNIST 這種複數類別的資料, softmax 回歸模型是一個較為常見且基本的模型, sotfmax 模型會將輸入(input)的資訊,透過乘上權重(weight)與加上偏差(bias),再經由 softmax 函式轉換成機率的方式,得到每一種類別所代表的可能性並作為輸出(output),進而決定輸入的資訊是屬於哪一種類別。
對於電腦的運算而言,我們可以把上面這張圖化作以下這個矩陣運算的形式。
說明完 softmax 回歸模型的大致原理,接著,我們將把這些觀念轉換成程式碼吧!

softmax 回歸模型實作

首先,因為接下來許多我們需要使用功能的函式都在 TensorFlow 裡面可以找到,所以先將 TensorFlow 匯入進來。
import tensorflow as tf
然後,讓我們來創造一個代表輸入資料的佔位符號(placeholder),名稱為 x ,可以將它視作盛裝輸入資料的「容器」,並設定好它的維度資訊。因為我們要輸入的資料是維度為 784 個 pixels 的圖片,所以這個佔位符號的形狀是 [None, 784], None 可以是一個任何大小的維度,取決於輸入資料圖片數多寡。
x = tf.placeholder(tf.float32, [None, 784])
softmax 回歸模型所使用到的權重與偏差,則是分別以 W 及 b 表示,而它們是可以更改數值的張量(tensor),因此我們以 Variable 這個類別創造出所需形狀的 W 和 b ,並且先將張量的初始值全都設定為零。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
再來我們只要使用 TensorFlow 內建的函數,將輸入資料 x 和權重 W 矩陣相乘,並加上偏差 b 後,放到 softmax 函數中,便將這個 softmax 回歸模型定義出來了。
y = tf.nn.softmax(tf.matmul(x, W) + b)

訓練模型

建構好模型的雛型之後,我們要開始訓練這個模型,讓它能夠達到我們所希望的預測能力。至於應該用什麼方式評估模型的好或壞呢?我們會以預測結果跟正確答案做比較,得到兩者的差異大小,也就是 loss ,作為判斷模型好壞的評斷依據。
TensorFlow 的套件中有一個我們經常拿來計算 loss 的函式,叫作 cross-entropy ,其較深入的細節在這篇文章中不會細談。當計算出來的 loss 愈小,就代表目前模型的預測結果愈接近正確答案,而我們的目標是讓訓練模型時算出來的 loss 逐漸下降。
為了能使用 cross-entropy 比較預測結果和正確答案,我們需要先創造一個存取正確答案的 placeholder ,名為 y_ 。
y_ = tf.placeholder(tf.float32, [None, 10])
如果要將上面 cross-entropy 的數學式實作出來,可以參考下面這段程式碼。
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
不過,直接用這種方式實作 cross-entropy ,因為數值計算上會不夠精確與穩定,所以通常我們會使用 tf.nn.softmax_cross_entropy_with_logits 取代前面提到的方法,並透過 backpropagation 演算法,追蹤 W 、 b 這些變數跟 loss 之間的關聯。
我們可以藉由 Optimizer 來計算 loss 的梯度(gradient)。在這裡以許多 Optimizers 其中之一的 GradientDescentOptimizer 為例,關於 Gradient Descent 的原理,可以參考維基百科的資料。
learning_rate = 0.05
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy)
當 Graph 的內容都已經設定完成之後,接著就可以將 TensorFlow 的運算指定給 Session 了。
sess = tf.Session()
一開始,要先將 Variables 初始化。
tf.global_variables_initializer().run()
如果我們要讓訓練過程跑 1000 次,每次取 100 筆資料進行訓練,只要按照下面這段程式碼所寫的去執行即可。
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})

評估模型

在實際執行程式之前,我們還需要一些程式碼來評估,最後訓練出來的模型,拿來預測 test data 的準確率如何。
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
最後,我們開始執行整個 Session ,並顯示出以訓練完的模型預測 test data 的準確率。
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
根據 TensorFlow 官網所寫,利用這一篇所使用的方法,可以得到大約 92 % 的準確率。
就筆者查到的資料,目前(西元 2017 年 7 月)準確率最高的方法是由 Li Wan 等人在西元 2013 年所提出,利用各種 deep learning 的技巧,達到了高達 99.79 % 的準確率!如果想要瞭解關於這個方法的詳細內容,請參考這個連結

結語

到此為止, TensorFlow 基礎篇的教學終於告一段落了!
總結來說, TensorFlow 是一個廣受歡迎的深度學習框架,和其他套件相比,它在自由度相對比較高。此外,又因為是由 Google Brain 所開發,以及有廣大的使用社群,縱使使用者在操作上遇到問題,也能從網路上找到許多可以參考的資源。

TensorFlow 基礎篇〈中〉

TensorFlow 基礎篇〈中〉2017-08-01

前言

暸解完tensorflow的特點後,我們要開始正式介紹tensorflow的內容,這回會先教大家Tensorflow會用到的基礎元件還有如何使用,幫助各位在真正開始訓練一個屬於自己的模型之前,先對tensorflow運作的原理有基礎的認識。

張量(Tensor)

tensorflow運算中最基本的單位,通常是高維度的矩陣,舉個例子如果我們需要一個可以拿來做圖像辨識的Model,Input的圖片即可用一個2維的tensor表示,圖上的每個像素(pixel)都是tensor中的element,同樣的方式也可以用三維的張量來表示一張彩色的圖,第三個維度長度就是3分別代表RGB三原色在現在這個(x,y)位置的pixel的值。
張量的型態主要有三種Constant、Variable、Placeholder
如果有寫過其他程式語言的應該可以很輕易地了解Constant 和 Variable的意義,沒學過也沒關係,可以就如字面上的意義了解Constant就是不可變的常數、Variable即是變數,Placeholder則是tensorflow中比較特別的概念,我們就留到與Graph一起講。
創建Tensor的方式也很簡單
import tensorflow as tf
node1 = tf.constant(3) # 常數3的tensor
node2 = tf.constant(4) # 常數4的tensor
print(node1, node2)
我們來看看print出來的結果
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
node1node2 分別代表了兩個Const和Tensor,還可以注意到如果我們沒有特別指定data type,default是使用float32作為初始值,但為什麼我們看不到我們賦予這兩個tensor的值(3、4)呢?
這時候我們就必須執行下面這段程式碼
sess = tf.Session() # 創建一個tensorflow session
print(sess.run([node1, node2])) # 把node1 node2丟進session中run
大家現階段可能對於這段程式碼的功用不太理解,沒關係這我們在下個階段就會有詳細的解說,這邊就當作是把Tensor中的值取出吧。

運算圖(Computational Graph)

在開始之前我們先理解一下Tensorflow主要的運作流程分為以下兩個部分

建立運算圖(Build)

其實這個部分就是所謂的建立模型(Build Model),決定整個運算流程,這也是tensorflow和其他框架最大的不同,我們必須事先定義好Graph的長相,舉下圖為例,如果想用tensorflow算 3+4=7 那我們該怎麼做呢?首先我們要先建立一個用來做加法運算的Graph如下圖,就是把兩個Constant的tensor做一個加法的運算。
node3 = tf.add(node1, node2) # 把前面創建的const tensor node1、node2相加
print("node3: ", node3) # node3就是相加後的結果
print("sess.run(node3): ",sess.run(node3)) 

執行運算圖(Run)

相信看完上面那段程式碼,大家一定很好奇第三行又再度出現的 sess 是在做甚麼,我不是做完第一行以後 node3 就會是相加後的結果了嗎?
那我們就來看一下 node3 print出來的結果會是甚麼。
node3:  Tensor("Add:0", shape=(), dtype=float32) # node3 print結果
看到這邊可以發現node3其實和上面的node1、node2都一樣是一個Tensor差別只是名字被命為add也就是加法產生的Tensor,那我們加法加出來的值又去哪了呢?聰明的你們應該可以想到第三行print出來的結果就會是加法的結果了。
sess.run(node3):  7.0 # sess.run(node3) print結果
好那到底為什麼我們需要session才會有值呢?這就牽涉到了tensorflow設計的原理,顧名思義Tensorflow就是讓Tensor流動,就像是我們在第一回所看到的圖一樣,我們在前面建立Graph的過程其實只是定義好Tensor如何流動並運算的過程,但真正的資料其實並沒有被運算,所以我們需要session。
session幫助我們定義我們所需要run的Graph的input和output,在上面的例子由於我們已經先定義好constant Tensor所以並不需要給Graph任何Input我們就可以得到node3的output,但如果我們要的不是兩個常數相加呢?在一般程式設計中我們常常會寫c = a + b,a和b兩個變數又是由其他運算所得來,那在Tensorflow中會是長怎樣呢?

Placeholder

正如上面所提到,在Tensorflow中我們都是先建好Graph再決定資料的input與output,這時候我們就需要Placeholder來幫助我們在還沒有資料的時候先佔個位子(正如其名)。
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b  # 這行等效於 adder_node = tf.add(a, b)

以上就是我們將加法改為兩個變數相加,用Placeholder實作的程式碼,跟前面用兩個Const Tensor相加最大的區別就是我們這邊並沒有賦予a、b任何值,而只是建立了一個讓a跟b兩個Tensor相加的Graph。
print(sess.run(adder_node, {a: 3, b:4.5}))
>> 7.5
接著我們當然又是找session幫我們執行這個Graph,可以看到在sess.run的參數中我們除了第一個參數指定了這次要run的Output外,在第二個參數我們給了一個dictionary,這就是我們這次run的過程賦予a和b兩個Placeholder的值,因此adder_node的計算就會根據我們feed進去的資料作改變,在這邊很顯然的答案就是3+4.5=7.5
print(sess.run(adder_node, {a: [1,3], b: [2, 4]}))
>> [ 3.  7.]
但在真正機器學習的任務中當然不可能都是做這種簡單的兩個數相加,稍微有上過課或者有點概念的讀者應該就會知道其實在機器學習中大部分的運算都是高維度的矩陣運算,這也是為什麼基本單位叫做Tensor(高維度矩陣),我們其實可以餵給placeholder任何維度任何長度的data。
這邊示範了一個餵給a跟b兩個一維的向量,那加法出來的結果就會是這兩個向量相加,那當然也不是隨便餵給Placeholder甚麼data都可以的,至少在這個例子中如果餵給a跟b兩個不同維度的Data那在sess.run之後便後產生Runtime Error,所以其實我們所有要餵進Graph的Data都必須先想好之後會遇到甚麼運算,譬如矩陣相乘就必須在要相乘的維度上要有相同的長度等等各種不同的限制。

Variable

到最後大家可能會有一個疑問:那Variable在Tensorflow中的功用是甚麼呢?其實所有除了Placeholder跟Constant以外Tensor都屬於Variable,也就是剛剛做加法運算的Graph中的adder_node也屬於一個Variable,Variable就是會因為Placeholder所Input的Data不同會隨之改變,這也是在整個Model中最重要的部分。
大家應該知道Deep Learning的Training過程就是針對輸出(Output)與事實(Ground Truth)的差別,去更新Model中的參數,而這些可以被更新的參數就是Variable,在下篇我們回提到怎麼建立一個簡單的模型,讀者看完以後應該能對於整個Model最後到底是怎麼被Train出來的更有概念。

TensorFlow 基礎篇〈上〉

TensorFlow 基礎篇〈上〉2017-08-01
隨著深度學習的蓬勃發展,各式各樣的開源學習框架也層出不窮,theano、 tensorflow、 caffe、 keras、torch還有最近新出的pytorch等等,其中由Google Brain團隊開源的tensorflow在2015年年底一出現就受到極大的關注,目前的使用率也是數一數二。
在之後的文章中,我們將為大家帶來完整的tensorflow基礎教學,然而,還是希望讀者能夠
  • 看得懂python的程式,並能夠撰寫簡單的程式
  • 有使用命令列(command line)的經驗
此系列文章目的是教大家如何使用tensorflow,沒有介紹深度學習的原理,如果對深度學習完全不了解,也可以照著教學做出訓練模型,不過還是建議先看台大電機系李宏毅教授的機器學習教學影片,再來學習tensorflow會比較有效益。

為何要用tensorflow

在進入tensorflow的hello world之前,我們先來簡單介紹一下tensorflow的優勢及其它套件相較之下的差異性,tensorflow在所有學習框架當中,不算是最容易上手的,對一個機器學習初新者,只是想要瞭解一下並自己實作一些簡單例子的話,我會建議先從keras開始學起,因為keras設計目標就是從簡、高度模組化,tensorflow則比較偏向於研究用,和其它套件比起來具有以下特點:
  • 開發自由度高
    對於一個想更深入研究機器學習的使用者來說,tensorflow就是一個自由度很高又不會過於麻煩的工具,在機器學習中頻繁出現的複雜數學計算在tensorflow中只要幾行程式碼就能解決,又不會像keras一樣過於模組化而無法實現太多變形,而且有python接口和C++接口可以選擇,此系列文章主要就是用python教學。
  • 遇到問題較容易搜尋到解決辦法
    寫程式最可怕的就debug,由於使用tensorflow的社群很大又很熱心,又是Google開源,各種問題都會在網路上被熱烈討論,跟其他工具比起來,很容易在網路上google到解決方法,這是tensorflow很大的優勢。
  • 會隨著新的機器學習演算法衍生而更新
    在這個深度學習快速成長的時代,新的論文不斷推陳出新,而tensorflow更新也很快速,會將可靠的論文直接寫成function提供給使用者可以方便使用,在開發上也會更輕鬆快速。
  • 具有高度可視化工具tensorBoard
    最後一點是tensorflow很特別的一點,tensorBoard是tensorflow專屬的視覺化工具,在開發自己的模型的時候,容易因為訓練狀況不如預期而陷入迷惑,這時tensorBoard就非常有用,除了可以視覺化你的模型以外,也可以將我們關心的指標視覺化來幫助瞭解訓練狀況,是非常強大的工具。

tensorflow 安裝教學

看完了tensorflow的一些特點後,我們接下來將教大家如何安裝tensorflow 在windows上以及linux(Ubuntu)上,本篇文章只有教CPU版本的安裝方法,如果要用GPU訓練的話要另外安裝GPU版本以及CuDNN,有興趣可以參考tensorflow官網

Linux(Ubuntu) 安裝

對於linux(Ubuntu)系統的同學,最快也最簡單的安裝方法就是透過pip3,所以如果還沒裝過python3和pip3,建議從 step 1. 開始,如果已經裝好python3和pip3以上,也可以從 step 3. 開始,一步一步輸入以下指令。
step 1.
先打開command line
step 2.
使用apt-get安裝python3,輸入以下指令
sudo apt-get update
sudo apt-get install python3
step 3.
python3 安裝完成,接下來輸入以下指令安裝pip3
sudo apt-get install python3-pip
step 4.
安裝完pip3後,我們就可以用pip3來裝tensorflow了,輸入以下指令
sudo pip3 install tensorflow 
step 5.
安裝完成!!!在command line輸入以下指令打開python3
python3
step 6.
接著輸入以下指令測試一下tensorflow是否安裝完成
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
如果出現以下字元就是代表安裝成功
Hello, TensorFlow!

Windows 安裝

windows版本也會透過pip3進行安裝,在python3.4+後,安裝python3就會附有pip3,如果已經有安裝過python3以上的同學,就可以直接從step 5開始,如果還沒安裝過python3,建議從step 1. 開始。
step 1.
前往 python官網
step 2.
前往Download頁面選擇3.5.2下載。

step 3.
在點下Download後,會需要選擇x86-64還是amd64的installer,推薦選擇 Windows x86-64 executable installer下載。
step 4.
點開下載下來的安裝檔開始安裝,安裝過程要記得選擇Add Python 3.5 to PATH。當你看到Setup was successful後,就是python3安裝完成了。
step 5.
有了python3後,我們可以開始安裝tensorflow,先用工作管理員打開命令提示字元。

step 6.
打開命令提示字元後打入以下指令。
C:\> pip3 install --upgrade tensorflow
step 7.
安裝完成!!先在命令提示字元輸入以下指令打開python3。
C:\> python3
輸入以下指令測試一下tensorflow是否安裝完成。
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
如果出現以下字元就是代表安裝成功。
Hello, TensorFlow!

小結

測試的時候,還不了解tensorflow的運作原理沒關係,下一篇文章將會詳細介紹tensorflow各元件,看完就能知道tensorflow怎麼印出Hello, TensorFlow!的,以下的教學將會以python3、tensorflow1.2為主。

Git 新手入門教學

Git新手入門教學 – part 1 GIT  •  程式 WRITTEN BY:  LYNN 2017-01-18 –[WARNING]學習Git之前請先熟悉UNIX的Command Line指令– 身為一位整日埋頭苦幹實幹的工...