Tensorflow-低级接口说明-LowLevelApis-翻译整理
這篇文章介紹使用Tensorflow'低級api編程的方法,包括:
- 管理你的tensorflow程序(運算圖graph)和運行時(會話session),不依賴Estimators
- 使用tf.Session運行tensorflow操作
- 在低級編程中使用高級元素(dataset,layer,feature columns)
- 搭建自定義的train loop訓練周期,不依賴于Estimators
推薦優先使用高級接口。了解低級接口的意義在于:
- 實驗和調試更加簡單
- 更好的理解高級接口的運作模式
張量值
張量tensor是tensorflow的核心數據單元,它是由數值構成的多維數組。張量的等級rank就是維度,整數元組shape表示了每個維度的長度。
3. # rank 0 ,shape [],標量 [1., 2., 3.] # rank 1,shape [3],向量 [[1., 2., 3.], [4., 5., 6.]] # rank 2,shape [2, 3],2x3矩陣 [[[1., 2., 3.]], [[7., 8., 9.]]] # rank 3,shape [2, 1, 3],2行1列3層深
維數rank等于方括號的層數,等于shape內數字個數。
Tensorflow使用Numpy arrays表示張量值。
瀏覽Tensorflow核心
Tensorflow核心編程就是兩個事情:
- 構建計算圖tf.graph
- 使用tf.Session執行計算圖
Graph
計算圖computational graph就是一系列Tensorflow操作單元的排列組合。
計算圖由兩部分構成:
- ops,操作。這是計算圖的節點,它消耗張量,也產生張量。
- tensor,張量。這是圖的邊線edges,它展示了數值如何在圖內流動。絕大多數tensorflow函數都返回tf.Tensor。
tf.Tensor并不包含數值,它只是控制計算圖里面的元素
import tensorflow as tf a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) #也是tf.float32 total = a + b print(a) print(b) print(total)
運行得到的不是7.0,而是三個張量,因為這里只是構建了計算圖graph,而沒有運行它。
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32) Tensor("add:0", shape=(), dtype=float32
graph中的每個操作都有唯一自動賦予的名字,比如上面的'add:0',如果有更多add操作,就會是'add_1:0','add_2:0'等。
Tensorboard
信息板提供了視覺化的計算效果,使用步驟:
- 把計算圖graph保存到Tensorboard的摘要文件,這將產生一個event事件文件。
import os import tensorflow as tf
#存儲event文件夾
dir_path = os.path.dirname(os.path.realpath(__file__)) sum_path=os.path.join(dir_path,'models')
#不要使用斜杠 #構造計算圖
a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) total = a + b
#寫入tensorboard該要
writer = tf.summary.FileWriter(sum_path) writer.add_graph(tf.get_default_graph())
#運行圖
sess=tf.Session() sess.run(total)
運行上面的代碼,將在.py所在文件夾內產生一個models文件夾,文件夾里面又一個events開頭的文件,里面記錄著tensorflow的運行情況,然后命令行cd進入當.py所在文件,執行以下命令啟動tensorboard服務(按ctrl+C兩次退出):
tensorboard --logdir models
然后打開瀏覽器,輸入地址http://localhost:6006/就打開了Tensorboard頁面,點擊頂部的GRAPHS可以看到我們的加法運算操作,類似下圖

Session
建造計算圖graph之后,必須使用會話```session=tf.Session()``來運行它。如果說graph是.py文件,那么session就是讓它變為可執行程序。
當使用session.run()來運行最終輸出的張量節點的時候,tensorflow會自動反向跟蹤整個graph并計算所有節點,如上面的代碼中,最終輸出是7.0。
也可以一次運行run多個張量:
import tensorflow as tf a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) total = a + b sess=tf.Session() v=sess.run({'ab':(a,b),'total':total}) print(v)
得到一個字典:
{'ab': (3.0, 4.0), 'total': 7.0}
同樣的graph使用tf.Session().run()都是全新的運算,可能得到不同的結果,例如:
import tensorflow as tf sess=tf.Session() vec = tf.random_uniform(shape=(3,))
out1 = vec + 1 out2 = vec + 2
print(sess.run(vec))
print(sess.run(vec))
print(sess.run(out1))
print(sess.run(out2))
print(sess.run((out1, out2)))
輸出不同的隨機值,注意((out1,out2))的結果:
[0.82387817 0.65216887 0.32529306]
[0.10036051 0.535251 0.38202 ]
[1.2352179 1.8258253 1.4338707]
[2.6720245 2.1600003 2.9119837]
(array([1.4428363, 1.3376999, 1.7375625],
dtype=float32),
array([2.4428363, 2.3377 , 2.7375627],
dtype=float32))
有些tensorflow函數返回的不是tf.Tensor而是tf.Operations,運行run一個operation操作會返回None。但可以使用這個技巧獲得一些特別作用,比如:
init = tf.global_variables_initializer()
sess.run(init)
Feeding
標準格式下,graph總是產生相對固定的運行結果,這沒有什么意義。但是graph可以接收外部的placeholder傳入的變化的輸入,placeholder就像一個promise承諾稍后提供數據,像一個函數那樣。
import tensorflow as tf sess=tf.Session()
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
z = x + y
print(sess.run(z, feed_dict={x: 3, y: 4.5}))
print(sess.run(z, feed_dict={x: [1, 3], y: [2, 4]}))
輸出
7.5
[3. 7.]
這段代碼可以看作定義了一個函數,然后運行了它:
def zfunc(x,y): return x+y print(zfunc(3,4.5))
Datasets
Placeholder用于簡單的實驗,Datasets才是將數據輸入模型的更好方法。
要從數據集datasets得到一個可運行的tf.tensor,需要先把它轉為tf.data.Iterator迭代器,然后使用迭代器的get_next()方法。
如下示例代碼,使用了try...catch...捕獲異常,避免超過終點的錯誤:
import tensorflow as tf sess=tf.Session() my_data = [ [0, 1,], [2, 3,], [4, 5,], [6, 7,], ]
dataset = tf.data.Dataset.from_tensor_slices(my_data)
next_item = dataset.make_one_shot_iterator().get_next()
while True:
try:
print(sess.run(next_item))
except tf.errors.OutOfRangeError: break
Layers
可訓練的模型必須能夠改變graph的值,從而在在相同輸入數據的時候獲得新的輸出。層Layer是推薦的方法,用來像graph里面添加可訓練的參數。
Layers將變量和操作打包。比如密集連接層densely-connected-layer為所有的輸入執行加權求和操作到每個輸出,以及可選的激活函數activation function,由圖層對象管理連接權重weighted和偏移值bias。
層的使用流程包括:
- 創建
- 初始
- 運行
import tensorflow as tf sess=tf.Session()
#創建一個節點的密集層,傳入n個三元數組,units=2輸出二維數組
x = tf.placeholder(tf.float32, shape=[None, 3])
linear_model = tf.layers.Dense(units=2) y = linear_model(x)
#初始化所有變量 init = tf.global_variables_initializer() sess.run(init)
#運行層,通過x傳入數據
v=sess.run(y, {x: [[1, 2, 3],[4, 5, 6]]}) print(v)
注意,tf.global_variables_inistializer方法只初始化以上的graph,所以應該在graph建造完成之后運行。
打印出的結果
[[-2.037472 3.9676275] [-5.741477 10.678923 ]]
每個layer在創建的時候可以直接傳遞placeholder,比如上面的代碼可以簡化成下面
import tensorflow as tf sess=tf.Session()
x = tf.placeholder(tf.float32, shape=[None, 3])
y = tf.layers.dense(x, units=1)
#簡寫
init = tf.global_variables_initializer() sess.run(init)
print(sess.run(y, {x: [[1, 2, 3], [4, 5, 6]]}))
這次會打印出兩個1元數組
[[-3.4608526] [-8.070822 ]]
Feature Columns
可以使用tf.feature_column.input_layer快速實驗特征列,它只接受dense column密集列,如果是分類列Catergorical column,就必須經過指示列tf.feature_column.indicator_column包裹,示例代碼如下。
import tensorflow as tf sess=tf.Session()
#特征數據
features = { 'sales' : [[5], [10], [8], [9]], 'department': ['sports', 'sports', 'gardening', 'gardening']}
#特征列
department_column = tf.feature_column.categorical_column_with_vocabulary_list( 'department', ['sports', 'gardening'])
department_column = tf.feature_column.indicator_column(department_column)
#組合特征列
columns = [ tf.feature_column.numeric_column('sales'), department_column ]
#輸入層(數據,特征列)
inputs = tf.feature_column.input_layer(features, columns)
#初始化并運行
init = tf.global_variables_initializer() sess.run(tf.tables_initializer()) sess.run(init) v=sess.run(inputs)
print(v)
上面代碼輸出如下結果,可以看到input輸入層將每個商品的features轉為3維矢量,前兩個0,1獨熱表示分類運動sport或園藝gardening,第三個數字表示銷售數量salse。
[[ 1. 0. 5.] [ 1. 0. 10.] [ 0. 1. 8.] [ 0. 1. 9.]]
Training
最簡單的訓練流程包括:
-
構建計算圖
- 定義數據
- 定義模型
- 損失函數
- 優化方法
- 初始化
- 多次訓練
- 進行預測
下面來看一段完整的代碼,嘗試根據給定的線性數據推算線性函數模型并進行預測:
import tensorflow as tf
#兩個輸入數據,yi=-xi+1
xi =[[1,], [2,], [3,], [4,]] yi =[[0,], [-1,], [-2,], [-3,]]
#兩個浮點占位器,不能使用整數,那將產生稀疏值
x = tf.placeholder(tf.float32, shape=[None, 1])
y_true = tf.placeholder(tf.float32, shape=[None, 1])
#定義模型,一個線性的密集層
y_pred = tf.layers.dense(x, units=1)
#設定損失函數,使用均方差,MSE=sum(squar(x-x'))/n
loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)
#設定優化器,梯度下降優化器
optimizer = tf.train.GradientDescentOptimizer(0.1) train = optimizer.minimize(loss)
#初始化以上全部變量
init = tf.global_variables_initializer()
sess = tf.Session() sess.run(init)
#進行訓練 for i in range(1000): sess.run((train, loss),feed_dict={x:xi,y_true:yi})
#進行預測,正確結果應該輸出-11
print(sess.run(y_pred,feed_dict={x:[[12,]],y_true:[[None]]}))
輸出結果,非常接近我們正確值了。
[[-10.999997]]
如果降低訓練次數1000到100,或者將優化器梯度下降參數從0.1降為0.01,那么都將產生稍大的誤差。
本篇小結
- 張量值的等級rank和形狀shape
-
Tensorflow的核心:
- 計算圖graph:ops,tensor
- 會話運行時session:run,init
- 信息板tensorboard:summary,event文件
- 喂食數據feed:placeholder,feed_dict
- 數據集Datasets:iterator,get_next()
-
層Layer:
- 創建
- 初始化
- 運行
-
特征列Feature columns:
- input_layer(features,columns)
- indicator_column(categorical_column)
-
訓練Train:features-graph-init-train-predict
sess.run((train, loss),feed_dict={x:xi,y_true:yi})