【Python】TensorFlow學習筆記(一):TensorBoard 的浪漫

夏恩第一個 DL 模型是用 MATLAB 做的,它的優點太多,一時半刻說不完。
但過於依賴某種工具,總歸是件高風險的事情。

所以還是趁著空閒時來學習新東西吧!

目次

【Python】TensorFlow學習筆記(一):TensorBoard 的浪漫
【Python】TensorFlow學習筆記(二):初探 TFRecord
【Python】TensorFlow學習筆記(三):再探 TFRecord
【Python】TensorFlow學習筆記(四):用 TFRecord 餵食 Softmax Model
【Python】TensorFlow學習筆記(五):存檔 & 讀檔
【Python】TensorFlow學習筆記(六):卷積的那些小事​
【Python】TensorFlow學習筆記(完):卷積深深深幾許

什麼是 TensorFlow?

網路上針對TensorFlow的介紹有很多,這也是近幾年開始流行起來的一個深度學習架構。
會讓夏恩選擇TensorFlow的最主要原因 — 因為他有Google在後面撐腰啊!

不然好不容易學起來怎麼用這個傢伙,然後他就死掉了,那真是白忙一場。

以下先附上一些參考資料。
https://www.tensorflow.org/programmers_guide/graphs​

TensorFlow 是一個採用資料流程圖(data flow graphs),用於數值計算的開源軟體庫。

節點(Nodes):在流程圖中表示數學操作,資料輸出和輸入,或是讀寫變數。
線(edges):表示在節點間相互聯繫的多維資料陣列,即張量。

TensorFlow 最初由 Google brain 小組的研究員和工程師們開發出來,
用於機器學習和深度神經網路方面的研究,但這個系統的通用性使其也可廣泛用於其他計算領域。
一旦輸入端的所有張量準備好,節點將被分配到各種計算設備完成非同步並行地執行運算。

張量從圖中流過的直觀圖就是這個工具取名為 Tensorflow 的原因。

上圖參考:https://www.tensorflow.org/images/tensors_flowing.gif

TensorFlow

這次的任務主要是記錄些學習 TensorFlow 的過程。
先簡介一下夏恩的作業環境:

環境:CentOS 7
Python版本:python-3.5
TensorFlow版本:tensorflow-1.5.0

夏恩的執行環境是在Linux下,之前有提到本恩把 python2.7 升級成 3.6,
後來發現有許多套件在3.6版本都不支援,於是只好利用虛擬環境的方式,重新建立 python3.5 的環境。

TensorFlow 的安裝方法很簡單,請直接在指令列輸入:

# pip install --ignore-installed --upgrade tensorflow            或是
# pip install --ignore-installed --upgrade tensorflow-gpu

若是 Anaconda 的使用者,還是請使用相同的指令,因為 google 團隊表示 不負責 conda的相關更新。

詳細的安裝過程可以參考他們的官網:
https://www.tensorflow.org/install/

使用 Windows10 的朋友,可以參考夏恩另外一篇建立工作環境的文章:
【Python】在 Win10 系統下建立影像處理及深度學習環境

若說到夏恩對於 Tensorflow 的理解,其大部分的知識都來自於他們的官網,以及網路上的教學分享。
坦白說,TensorFlow 的官網不太友善,原因是雖然 TensorFlow 提出了計算圖的概念,
但對於每個節點的操作,或是一些函數用法之類的,常常用簡單的文字幾筆帶過,讓初學者的眉頭通通皺成一坨麻花捲。

因為,看不懂!

可是就算看不懂還是得看,多看幾次就懂了。
夏恩就是這麼走過來的。

好啦,話不多說,想必剛才閒聊時,環境都已經弄好了對吧!

安裝好 TensorFlow 之後,就來寫個簡單的程式吧。

import tensorflow as tf

# constant可以視為tf專用的變數型態
# 其他包括Variable,placeholder
A = tf.constant('Hello World!')

# 使用 with 可以讓Session自動關閉
with tf.Session() as sess:

    # 在 tensorflow內要使用run,才會讓計算圖開始執行
    B = sess.run(A)

    print(B)

這個程式執行後,應該可以看到這樣的畫面:

黑字就是程式碼內的 "Hello World!",紅字是警告訊息,提醒我們可以加速 TensorFlow 的執行速度之類的,
有時候會秀出其他的警告內容,大家看看就好,不會影響執行結果的。

一般夏恩都選擇在程式碼內加兩句話,直接關閉警告訊息。

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

到這邊,已經可以確認程式能正常運作,
接著我們先來看看在 TensorFlow 的架構下,幾個常用的資料型態:constant、Variable、Placeholder。

tf.constant

這代表常數,給定初始值之後即無法再更改。

# -*- coding: utf-8 -*-

import tensorflow as tf

# 宣告常數
A = tf.constant(10, dtype=tf.int64)

with tf.Session() as sess:
    print( A ) 
    # Tensor("Const_42:0", shape=(), dtype=int64)
    
    print( sess.run(A) ) 
    # 10

    # 使用 sess.run() 才能取得 A 的值

tf.Variable

這代表變數,以下展示如何用它來顯示 0 ~ 4。
您可以不斷地更改變數的值,直到您滿意為止。

# -*- coding: utf-8 -*-

import tensorflow as tf

# 宣告變數    
B = tf.Variable(0, dtype=tf.int64)
with tf.Session() as sess:
    # 變數需要初始化
    sess.run( tf.global_variables_initializer() )

    # 使用 assign 更改變數值
    for i in range(5):
        print( sess.run(B.assign(i)) )
    
    '''
    執行結果:
    0
    1
    2
    3
    4
    '''

其中,請特別注意 assign 這個函數,此函數需要經過 sess.run() 之後,才會賦予新值。
若是把上面的迴圈改成這樣:

for i in range(5):
    B.assign(i)
    print( sess.run(B) )

這樣 B 值是不會改變的,因為 assign 未被執行。
這裡非常容易用錯,請小心。

tf.placeholder

這代表...占位符。

好吧,我知道初學者對於這個傢伙十分困惑。
意思大概就像:這三個字我都看得懂,但是合在一起就不行了。

其實這只是 TensorFlow 為了讓我們更方便的導入資料而設計的函數。

先重複一次剛才的問題,用它來顯示 0 ~ 4。

# -*- coding: utf-8 -*-

import tensorflow as tf

# 宣告占位符
C = tf.placeholder(dtype=tf.int64)

with tf.Session() as sess
    for i in range(5):
        result = sess.run(C, feed_dict={C:i})
        print(result)

我們可以看到,上面比較特別的地方是,占位符可以使用 feed_dict 來賦值,
這項功能,可以讓我們在訓練模型時能輕鬆地輸入資料。

再來看看另外一個情況:

# -*- coding: utf-8 -*-

import tensorflow as tf

# 宣告占位符
C = tf.placeholder(dtype=tf.int64)
D = tf.placeholder(dtype=tf.int64)
E = tf.placeholder(dtype=tf.int64)

F = D + E

with tf.Session() as sess:
    # 可以一次填充所有的占位符
    result = sess.run(F, feed_dict={C:10, D:20, E:30})
    print(result) # 50
    
    # 或者只填充計算所需要的
    result = sess.run(F, feed_dict={D:20, E:30})
    print(result) # 50
    
    # 這段程式會使系統報錯!
    # 計算所需的占位符不能為空,每次執行 sess.run() 都要填充,
    # 占位符不是變數,不會留存上次填充的資料。
    result = sess.run(F, feed_dict={E:30})
    print(result)

我們可以一次填充所有的占位符,也可以只填充計算所需要的。
舉凡計算會用到的占位符每次執行都需要填充,因為占位符不會保存上次填充的結果。

如果您真要逼著夏恩舉個例子......大概就像是夾娃娃機吧!

假設每次玩要投 10 元,累積到 200 元就保證取物,其中 200 元的設定是常數
投 10 元這個動作,就是填充占位符,投一次就玩一次。

每投一次錢,都會更新機器內的變數
直到該變數累積至 200 元,就改變系統的狀態:也就是保證取物。

當然了,這只是一種比喻,占位符通常代表了更多的意義,
像是輸入值、外部參數等,不會僅單純地表達啟動或是不啟動兩種狀態。

恩,好吧,不管您對這個例子是否滿意...
總之,我們接著下去吧。

TensorBoard

關於打開 TensorBoard 的方法,TensorFlow 的官網把他放在很後面的地方。
明明從一開始就一直介紹他們的 TensorBoard 有多厲害,但就是不在前面先講清楚!

所以夏恩就把這個東西拿到前面來了!

抱怨歸抱怨,TensorBoard 真的是一個好厲害的工具,難怪 TensorFlow 市占率可以這麼高!
試想,工程師熬了整晚的夜,好不容易做出模型,在簡報時展示程式碼...
不過卻因為沒人懂這是什麼,於是被棄置一旁。

這時,不要猶豫!

打開 TensorBoard,那精美的作圖瞬間讓自己的格調拔高幾個檔次!
連老闆都會走過來拍拍您的肩膀,道:「小子,之後加班加量不加錢,好好幹啊!」

...扯遠了。

言歸正傳,想要使用 TensorBoard 來展示自己所設計的架構,需要幾個步驟:

1. 把欲顯示出來的步驟使用 " tf.name_scope " 包起來。

2. 接著使用 tf.summary.FileWriter 函數輸出到目標資料夾。

請看範例程式:

import tensorflow as tf

# 宣告常數A&B,後面的name參數,是要繪製tensorboard時所使用的名稱。
# 若沒有指定,或是重複名稱,則tensorboard會自動修改。
A = tf.constant(50, name='const_A')
B = tf.constant(100, name='const_B')

with tf.Session() as sess:
    # 就是這邊!
    # 使用 "with tf.name_scope('Run'):" 這句話可以畫出Run這個步驟。
    with tf.name_scope('Run'):
        B = sess.run(A+B)
    print(B)
    
    # 畫好步驟之後,要使用"tf.summary.FileWriter"把檔案寫到目標資料夾,
    # 第二個參數表示要把整個圖層放到graph參數內,這樣才能用tensorboard畫出來。
    train_writer = tf.summary.FileWriter('/home/shayne/tfboard_Test', sess.graph)
    train_writer.close()

這樣子就可以把計算圖畫出來了!
最後一步,就是離開Python,回到Linux內,找到剛才輸出的資料夾,會有一個檔案叫做:

events.out.tfevents.xxxxxxxxxx(一連串的數字).(主機名稱)

確認沒問題後,在指令列下命令:
$ tensorboard --logdir=/home/shayne/tfboard_Test

這個指令的格式是:
$ tensorboard --logdir=(your path)
剛才輸出的路徑是"/home/shayne/tfboard_Test",所以就用他代換(your path)。

按下確認後,tensorboard就會把你專屬的計算圖輸出到網頁,網址是:

"http://(your ip):6006"

假設夏恩的主機的IP是192.168.100.100的話,這時候就開啟google瀏覽器,
鍵入網址,就可以看到計算圖了!

如果網頁打不開,可以懷疑是防火牆的問題。
要打開防火牆,請使用以下指令,把防火牆關了:
# firewall-cmd --zone=public --add-port=6006/tcp
# service firewalld restart

這個計算圖是可以點開來看的,在Run的圖示上雙擊,可以看到下圖:

看到了剛才的兩個變數了嗎?
他們還做了一個相加的動作!

我們可以把剛才的程式稍微複雜化,像這樣:

import tensorflow as tf

A = tf.constant(50, name='const_A')
B = tf.constant(100, name='const_B')

with tf.name_scope('Add'):
    C = A+B

with tf.Session() as sess:
    with tf.name_scope('Run'):
        D = sess.run(C*3)
    print(D)

    train_writer = tf.summary.FileWriter('/home/shayne/tfboard_Test', sess.graph)
    train_writer.close()

把相加的動作單獨放在一個區塊,然後在Run區塊內做相乘。
這張計算圖畫起來就是這樣:

欸?怎麼明明就是簡單的加法和乘法,在 TensorBoard 裡面看起來怎麼這麼複雜!?
別怕,看習慣就好。

到這邊 TensorBoard 的用法大致介紹完畢。
TensorBoard 除了可以繪製計算圖之外,還能夠記錄在訓練過程中的參數變化及展示訓練資料庫的影像。

更詳細的功能請直接去看他們網站的教學,以下附上連結:
https://www.tensorflow.org/get_started/summaries_and_tensorboard

TensorFlow 真的是一個又難搞又功能強大的東西,讓人又愛又恨的!
這篇就先到這兒,第二篇的難度跳躍會有點大。
因為夏恩不會把官網的教學全部複製貼上過來,基礎的東西還請讀者自行研讀。

下一篇要來聊聊張量、流、還有官網上未曾提到的 —
該怎麼把 jpg、png...等圖片檔轉成可以讓 TensorFlow 讀取的 TFRecord 格式。

【Python】TensorFlow學習筆記(二):初探 TFRecord