2020年2月7日 星期五

筆記:TensorFlow語法與使用


  • 深度學習概念(連結)
  • CNN及眾多應用(連結)
  • RNN及眾多應用(連結)
  • TensorFlow安裝(連結)
  • TensorFlow語法與使用(連結)
  • Porting AI ( QCS605 QCS603 Android )(連結)

基本語法

初始化

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

執行訓練

sess.run(tf.train.GradientDescentOptimizer(learning_rate = 0.5)
.minimize(tf.reduce_mean(tf.square(y - y_data))))
y_data是初始設定固定值,y是每次不同變數 可以由
tf.Variable(tf.random_uniform([1], -1.0, 1.0)) 變數會變動產生


取得運作資料

sess.run(W)  中間放入要取得的名稱


Graphs 建立運算元

繼續是引入layer也就是類神經網路的概念。
每一個層的單元類型如下
weights_l1 = tf.Variable(tf.random_normal([1, 10]))#10个神经元
biases_l1 = tf.Variable(tf.zeros([1, 10]))
wx_plust_b_l1 = tf.matmul(x, weights_l1) + biases_l1
l1 = tf.nn.sigmoid(wx_plust_b_l1)
程式化這範例,狀況如下

def add_layer(inputs, input_tensors, output_tensors, activation_function = None):
    W = tf.Variable(tf.random_normal([input_tensors, output_tensors]))
    b = tf.Variable(tf.zeros([1, output_tensors]))
    formula = tf.add(tf.matmul(inputs, W), b)
    if activation_function is None:
        outputs = formula
    else:
        outputs = activation_function(formula)
    return outputs
實際程式化,就如同下述
# 添加 1 個隱藏層  有十個節點,由一對應十
hidden_layer = add_layer(x_feeds, input_tensors = 1, output_tensors = 10, activation_function = None)
# 添加 1 個輸出層  有一個節點,由十對應一
output_layer = add_layer(hidden_layer, input_tensors = 10, output_tensors = 1, activation_function = None)
test5.py是test1.py的改編版本。只不過兩層的activation function都是null。
單純比較test1和test5會發現,兩者的梯度數字明顯不同,在同樣iterator下,正確率也不同。但已經可以驗證神經網路層是有用處的。

test3.py是莫凡test2.py的改編版本,兩者概念相似,只是第一層的activation function稍有不同 l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)。




矩陣運算概念

test27.py


變數

(1) 常數張量:
一開始來看看「常數張量」,常數指的是在Model中不會改變的數值。
tensor = tf.constant([1, 2, 3, 4, 5, 6, 7], dtype=tf.int32)
Random的使用方式 test4.py

(2) 變數張量:
與常數截然不同的就是變數,「變數張量」是指在訓練當中可以改變的值,一般「變數張量」會用作於Machine Learning需要被訓練的參數,如果你沒有特別設定,在最佳化的過程中,Tensorflow會自動調整「變數張量」的數值來最佳化。
tensor = tf.Variable(tf.truncated_normal(shape=(3, 5)))
因為變數通常是未知且待優化的參數,所以我們一般會使用Initalizer來設定它的初始值,tf.truncated_normal(shape=(3,5))會隨機產生大小3x5的矩陣,它的值呈常態分佈但只取兩個標準差以內的數值。
如果今天你想要有一個「變數張量」但是又不希望它因為最佳化而改變,這時你要特別指定trainable為False。
tensor = tf.Variable(5, trainable=False)
Variable 則是在訓練神經網路時,儲存可更新參數的容器。

(3) 置放張量:
另外有一些張量負責擔任輸入窗口的角色,稱為Placeholder。
tensor = tf.placeholder(tf.float32, shape=(None, 1000))
因為我們在訓練之前還尚未知道Data的數量,所以這裡使用None來表示未知。tf.placeholder在Graph階段是沒有數值的,必須等到Session階段才將數值給輸入進去。
x_feeds = tf.placeholder(tf.float32, shape = [None, 1])
sess.run(train, feed_dict = {x_feeds: x_data, y_feeds: y_data})
test29.py
placeholder 是 TensorFlow 中一個很有趣的用法,可以預先在神經網路中 佔位,而不用事先定義好輸入的資料,這也是 TensorFlow 中計算圖(Computing Graph)的概念,之後再使用 Session 將資料傳入計算圖中。
在 placeholder 中定義節點的形狀 shape=(None, 2),None 的意思是二維矩陣的 row 事先尚未定義,也就是「不定義輸入資料的筆數」,隨著透過 Session 將資料傳入計算圖時,動態符合輸入資料的筆數。
往後在訓練神經網路時,可以透過設定超參數 batch_size 決定每次訓練資料的筆數,保持神經網路的彈性。
placeholder 用於在計算圖中傳入 feature 與 label

(4) 操作型張量:
這類張量並不含有實際數值,而是一種操作,常用的「操作型張量」有兩種,第一種是作為最佳化使用,
loss = ...
train_op = tf.train.GradientDescentOptimizer(learning_rate=0.5).minimize(loss)
選擇Optimizer和最佳化的方式來定義最佳化的操作方法,上述的例子是使用learning_rate為0.5的Gradient Descent來降低loss。
另外一種是初始化的操作,
init_op = tf.global_variables_initializer()
這一個步驟是必要的但常常被忽略,還記得剛剛我們定義「變數張量」時有用到Initalizer,這些Initalizer在Graph完成時還不具有數值,必須使用init_op來給予數值,所以記住一定要放init_op進去Graph裡頭,而且必須先定義完成所有會用到的Initalizer再來設定這個init_op。

命名

模組化的程式中使用 with tf.name_scope(): 為每個運算元命名(連結



TensorBoard


神經網絡運算初始之後,利用 tf.summary.FileWriter() 將視覺化檔案輸出。測試為test6.py。
產生的檔案位置在TensorBoard這個目錄中(自動生成的)
執行 $ tensorboard --logdir="TensorBoard/"


打開瀏覽器,在網址列輸入:http://localhost:6006,就可以在 Graphs 頁籤下看到神經網絡圖。


除了可以使用 with tf.name_scope(): 為每個運算元命名,我們還可以在使用 tf.Variable() 或者 tf.placeholder() 建立變數或輸入資料時,利用 name = 參數進行命名。test7.py

參考資料

我們利用 tf.summary.histogram() 與 tf.summary.scalar() 將訓練過程記錄起來,然後在 Scalars 與 Histograms 頁籤檢視。test8.py

Scalars

Histograms

資料儲存格式


TensorFlow 的模型格式有很多種,針對不同場景可以使用不同的格式,只要符合規範的模型都可以輕易部署到線上服務或移動裝置上,這裡簡單列舉。 
* Checkpoint: 用於儲存模型的權重,主要用於模型訓練過程中引數的備份和模型訓練熱啟動。 
* GraphDef:用於儲存模型的Graph,不包含模型權重,加上checkpoint後就有模型上線的全部資訊。 
* ExportModel:使用 exportor 介面匯出的模型檔案,包含模型 Graph 和權重可直接用於上線,但官方已經標記為 deprecated 推薦使用 SavedModel。 
* SavedModel:使用 saved_model 介面匯出的模型檔案,包含模型 Graph 和許可權可直接用於上線,TensorFlow 和 Keras 模型推薦使用這種模型格式。
 * FrozenGraph:使用 freeze_graph.py 對 checkpoint 和 GraphDef 進行整合和優化,可以直接部署到 Android、iOS 等移動裝置上。 
* TFLite:基於 flatbuf 對模型進行優化,可以直接部署到 Android、iOS 等移動裝置上,使用介面和 FrozenGraph 有些差異。
參考

PB

通常我們使用 TensorFlow時保存模型都使用 ckpt 格式的模型文件,使用類似的語句來保存模型
tf.train.Saver().save(sess,ckpt_file_path,...)
使用如下語句來恢復所有變量信息
saver.restore(sess,tf.train.latest_checkpoint('./ckpt'))
但是這種方式有幾個缺點,首先這種模型文件是依賴TensorFlow 的,只能在其框架下使用;其次,在恢復模型之前還需要再定義一遍網絡結構,然後才能把變量的值恢復到網絡中。
google推薦的保存模型的方式是保存模型為PB 文件,它具有語言獨立性,可獨立運行,封閉的序列化格式,任何語言都可以解析它,它允許其他語言和深度學習框架讀取、繼續訓練和遷移TensorFlow 的模型。它的主要使用場景是實現創建模型與使用模型的解耦, 使得前向推導 inference的代碼統一。另外的好處是保存為 PB 文件時候,模型的變量都會變成固定的,導致模型的大小會大大減小,適合在手機端運行。

根目錄執行test13.py,會執行train和test,並且在最後產生graph.pb檔案。並且用test14.py觀察graph.pb檔案(用TensorBoard打開它)
步驟一,python test14.py --model_dir graph.pb --log_dir tensor/logs/convnet/
步驟二,tensorboard --logdir=tensor/logs/convnet/
步驟三,由瀏覽器開啟http://localhost:6006/。透過瀏覽器的互動觀察,可發現pb檔案中,不僅包含input到conv2d等等的處理過程,也包括teain時設定的各層和降階方式。所以測試程式難度比想像要單純,會寫訓練程式就一定能寫測試程式。

以pb為資料中心的範例test22 這裡直接把資料存graph.pb讀取動作
python train.py  python test.py

這裡有三個項目要討論
1.pb格式, 都是binary形式,如果要產生成txt格式,可以用
tf.train.write_graph(graph, '.', 'graph.pbtxt', as_text=True)
讀取也能夠直接讀取txt但是要例外考慮一些技巧(連結

2.利用tf.train.write_graph()預設情況下只匯出了網路的定義(並沒有權重),上面test22是因為使用了convert_variables_to_constants,上面test13是因為各個變數都使用constant。如果沒有這兩種,就會變成只有一個空殼。 連結

資料正規化


已訓練完畢的資料集,動則數百M,資料傳送耗時,也無法放入IOT有限的記憶體中。所以第一步驟就是,以較小檔案容量,換取些微準確率。技術上來說,訓練時的確需要大量伺服器協助產生訓練資料。但在測試階段,卻可以藉由犧牲部份準確率,換取減少訓練資料一半以上,讓手持裝置也可以執行分析程式。

沒有留言:

張貼留言