TensorFlow 機器學習軟體工具入門教學與範例實作

本篇為 TensorFlow 機器學習軟體工具的入門教學,並實作一個簡單的線性迴歸模型範例。

TensorFlow 是一套由 Google 所發展的開放原始碼機器學習函式庫,其以流程圖的概念呈現整個資料分析流程,在流程圖中的每一個節點都代表一個運算,連接不同節點的連線則代表資料的傳遞,程式設計者可以運用各種不同的運算節點(不同的演算法),組合成適用於各種問題的分析系統,運用 CPU 或 GPU 進行運算。

安裝 TensorFlow

TensorFlow 的安裝方式有很多種,這裡我使用 Docker 的安裝方式,其餘的安裝方法請參考 TensorFlow 官方的文件

CPU 版 TensorFlow

如果您的電腦沒有 NVIDIA 的 GPU 卡,則可安裝 CPU 版的 TensorFlow。首先安裝好基本的 Docker 環境,再從 Docker Hub 下載 TensorFlow 的 Docker 影像(image)來執行:

docker run -it -p 8888:8888 tensorflow/tensorflow

接著打開 http://localhost:8888/ 這個網址,就可以看到 TensorFlow 的網頁介面了。

GPU 版 TensorFlow

要使用 Docker 運行 GPU 版的 TensorFlow 之前,請先安裝好基本的 Docker 環境,再安裝 NVIDIA Docker 的環境

接著再從 Docker Hub 下載 TensorFlow 的 Docker 影像(image)來執行:

nvidia-docker run -it -p 8888:8888 tensorflow/tensorflow:latest-gpu

接著打開 http://localhost:8888/ 這個網址,就可以看到 TensorFlow 的網頁介面了。

TensorFlow 的網頁介面是採用 Jupyter Notebook 的方式呈現的,這是它的畫面。

Jupyter Notebook

如果想要比較單純的命令列操作介面,可以執行:

nvidia-docker run -it tensorflow/tensorflow:latest-gpu bash

這樣就可以直接開啟一個 bash shell,接著在這個 shell 中執行:

python

即可進入一個有 TensorFlow 的 Python 環境,這種環境適合習慣指令操作的人。

關於 Docker 版本的 TensorFlow 說明,可以參考 TensorFlow 的 GitHub 網頁

TensorFlow 入門操作

TensorFlow 提供了許多的 API,最底層的 API 就是 TensorFlow Core,其餘較高階的 API 都是以 TensorFlow Core 為基礎所建立的,低階的 TensorFlow Core API 使用上難度比較高,但是可以對模型進行細部的微調,適合機器學習的研究者使用,而較高階的 API 使用上比較簡單,適合一般的使用者來使用。

以下我們將介紹 TensorFlow Core 的用法,在了解 TensorFlow 底層的運作方式之後,再介紹高階 API 的使用方式。

Tensors

TensorFlow 中最基礎的資料類型就是 tensor,它是一種多維度的陣列,其陣列的維度稱為 rank,以下是一些 tensor 的範例:

# 一個 rank 為 0 的 tensor,形狀為 [] 的常數
3

# 一個 rank 為 1 的 tensor,形狀為 [3] 的向量
[1. ,2., 3.]

# 一個 rank 為 2 的 tensor,形狀為 [2, 3] 的矩陣
[[1., 2., 3.], [4., 5., 6.]]

# 一個 rank 為 3 的 tensor,形狀為 [2, 1, 3] 的高維度陣列
[[[1., 2., 3.]], [[7., 8., 9.]]]

在使用 TensorFlow 時,要將 tensorflow 這個 Python 模組匯入:

import tensorflow as tf

接著我們就可以透過這個 tf 使用 TensorFlow 了。

TensorFlow Core 的程式可分為兩大部分:

  1. 建立 computational graph。
  2. 執行 computational graph。

computational graph 是由許多 TensorFlow 運算節點(nodes)所組成的運算藍圖,每個節點可以接受任意個數的 tensors 作為輸入資料(或是沒有任何輸入也可以),並輸出一個 tensor。

常數節點

constant 節點是一個最簡單的常數節點,它沒有輸入資料,只會輸出其內部儲存的常數,以下是兩個浮點數常數節點範例:

node1 = tf.constant(3.0, dtype = tf.float32)
node2 = tf.constant(4.0) # 預設型別亦為 tf.float32

這裡建立了兩個常數節點,我們可以使用 dtype 來指定資料的型別,若不指定的話預設則為 tf.float32,建立好之後,將其輸出:

print(node1, node2)
(<tf.Tensor 'Const:0' shape=() dtype=float32>, <tf.Tensor 'Const_1:0' shape=() dtype=float32>)

我們將節點輸出之後,並不會直接得到節點的輸出數值,而是看到兩個節點的內部結構,如果要讓節點實際進行運算,必須先建立一個 session,然後在 session 中執行 computational graph:

sess = tf.Session()
print(sess.run([node1, node2]))

這樣就會得到我們所預期的計算結果:

[3.0, 4.0]

我們可以運用加法的節點,把 node1node2 的數值加起來:

node3 = tf.add(node1, node2)
print("node3: ", node3)
('node3: ', <tf.Tensor 'Add:0' shape=() dtype=float32>)
print("sess.run(node3): ",sess.run(node3))
('sess.run(node3): ', 7.0)

我們可以利用 TensorFlow 所附帶的 TensorBoard 功能,以圖型的方式查看 computational graph 的結構。

Placeholder

placeholder 是一種可以讓 computational graph 保留輸入欄位的節點,其允許實際的輸入值留到後來再指定。

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b  # 加號(+)等同於 tf.add(a, b) 的效果

這種方式其實有點類似定義一個函數,其接受 ab 兩個輸入參數,並且進行加法運算。

接著在執行 computational graph 時,只要在 runfeed_dict 參數指定輸入的數值,即可進行運算:

print(sess.run(adder_node, {a: 3, b:4.5}))
7.5
print(sess.run(adder_node, {a: [1,3], b: [2, 4]}))
[ 3.  7.]

接著我們再把 adder_node 的計算結果拿來再乘以 3.0

add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
22.5

此時的 computational graph 圖形是這樣:

Computational Graph 圖形

Variable

在機器學習的應用上,我們可以讓模型透過 placeholder 輸入各種的資料,而參數的部份我們可以透過 variable 的節點來指定(這樣可以讓參數可以進行訓練):

W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b

常數節點會在呼叫 tf.constant 時就進行初始化,而且其數值是固定的,而 variable 在呼叫 tf.Variable 時並不會進行初始化,若要初始化 variable 要另外執行以下的指令:

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

初始化 variables 之後,就可以將資料放進去這個模型中計算:

print(sess.run(linear_model, {x:[1,2,3,4]}))
[ 0.          0.30000001  0.60000002  0.90000004]

建立好模型之後,我們還會需要評估模型的表現好壞,所以還要定義一個 placeholder y,用於儲存正確的答案:

y = tf.placeholder(tf.float32)

接著使用 tf.square 計算每個誤差的平方,再使用 reduce_sum 把平方後的誤差加總:

squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)

最後把資料放進去,實際執行:

print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))
23.66

在學習的過程,我們可以透過調整不同的參數組合,讓誤差值更小。若要調整 variable 的值可以使用 tf.assign

fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))
0.0

W-1b1 時,可以獲得最佳解,而接下來的問題就是如何讓程式自動找出最佳解,請繼續閱讀下一頁。

程式設計, 統計學

1 Comment

  1. thomas

    解得太讚了,期待之後的教學

Leave a Reply