Tensorflow-低級接口說明-LowLevelApis-翻譯整理

這篇文章介紹使用Tensorflow'低級api編程的方法,包括:

  • 管理你的tensorflow程序(運(yùn)算圖graph)和運(yùn)行時(shí)(會話session),不依賴Estimators
  • 使用tf.Session運(yùn)行tensorflow操作
  • 在低級編程中使用高級元素(dataset,layer,feature columns)
  • 搭建自定義的train loop訓(xùn)練周期,不依賴于Estimators

推薦優(yōu)先使用高級接口。了解低級接口的意義在于:

  • 實(shí)驗(yàn)和調(diào)試更加簡單
  • 更好的理解高級接口的運(yùn)作模式

張量值

張量tensor是tensorflow的核心數(shù)據(jù)單元,它是由數(shù)值構(gòu)成的多維數(shù)組。張量的等級rank就是維度,整數(shù)元組shape表示了每個(gè)維度的長度。

3. # rank 0 ,shape [],標(biāo)量
[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層深

維數(shù)rank等于方括號的層數(shù),等于shape內(nèi)數(shù)字個(gè)數(shù)。

Tensorflow使用Numpy arrays表示張量值。


瀏覽Tensorflow核心

Tensorflow核心編程就是兩個(gè)事情:

  • 構(gòu)建計(jì)算圖tf.graph
  • 使用tf.Session執(zhí)行計(jì)算圖

Graph

計(jì)算圖computational graph就是一系列Tensorflow操作單元的排列組合。
計(jì)算圖由兩部分構(gòu)成:

  • ops,操作。這是計(jì)算圖的節(jié)點(diǎn),它消耗張量,也產(chǎn)生張量。
  • tensor,張量。這是圖的邊線edges,它展示了數(shù)值如何在圖內(nèi)流動。絕大多數(shù)tensorflow函數(shù)都返回tf.Tensor。

tf.Tensor并不包含數(shù)值,它只是控制計(jì)算圖里面的元素

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)

運(yùn)行得到的不是7.0,而是三個(gè)張量,因?yàn)檫@里只是構(gòu)建了計(jì)算圖graph,而沒有運(yùn)行它。

Tensor("Const:0", shape=(), dtype=float32)
Tensor("Const_1:0", shape=(), dtype=float32)
Tensor("add:0", shape=(), dtype=float32

graph中的每個(gè)操作都有唯一自動賦予的名字,比如上面的'add:0',如果有更多add操作,就會是'add_1:0','add_2:0'等。

Tensorboard

信息板提供了視覺化的計(jì)算效果,使用步驟:

  1. 把計(jì)算圖graph保存到Tensorboard的摘要文件,這將產(chǎn)生一個(gè)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') #不要使用斜杠

#構(gòu)造計(jì)算圖
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())

#運(yùn)行圖
sess=tf.Session()
sess.run(total)

運(yùn)行上面的代碼,將在.py所在文件夾內(nèi)產(chǎn)生一個(gè)models文件夾,文件夾里面又一個(gè)events開頭的文件,里面記錄著tensorflow的運(yùn)行情況,然后命令行cd進(jìn)入當(dāng).py所在文件,執(zhí)行以下命令啟動tensorboard服務(wù)(按ctrl+C兩次退出):

tensorboard --logdir models

然后打開瀏覽器,輸入地址http://localhost:6006/就打開了Tensorboard頁面,點(diǎn)擊頂部的GRAPHS可以看到我們的加法運(yùn)算操作,類似下圖

Session

建造計(jì)算圖graph之后,必須使用會話```session=tf.Session()``來運(yùn)行它。如果說graph是.py文件,那么session就是讓它變?yōu)榭蓤?zhí)行程序。

當(dāng)使用session.run()來運(yùn)行最終輸出的張量節(jié)點(diǎn)的時(shí)候,tensorflow會自動反向跟蹤整個(gè)graph并計(jì)算所有節(jié)點(diǎn),如上面的代碼中,最終輸出是7.0。

也可以一次運(yùn)行run多個(gè)張量:

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)

得到一個(gè)字典:

{'ab': (3.0, 4.0), 'total': 7.0}

同樣的graph使用tf.Session().run()都是全新的運(yùn)算,可能得到不同的結(jié)果,例如:

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)))

輸出不同的隨機(jī)值,注意((out1,out2))的結(jié)果:

[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函數(shù)返回的不是tf.Tensor而是tf.Operations,運(yùn)行run一個(gè)operation操作會返回None。但可以使用這個(gè)技巧獲得一些特別作用,比如:

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

Feeding

標(biāo)準(zhǔn)格式下,graph總是產(chǎn)生相對固定的運(yùn)行結(jié)果,這沒有什么意義。但是graph可以接收外部的placeholder傳入的變化的輸入,placeholder就像一個(gè)promise承諾稍后提供數(shù)據(jù),像一個(gè)函數(shù)那樣。

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.]

這段代碼可以看作定義了一個(gè)函數(shù),然后運(yùn)行了它:

 def zfunc(x,y):
    return x+y
print(zfunc(3,4.5))

Datasets

Placeholder用于簡單的實(shí)驗(yàn),Datasets才是將數(shù)據(jù)輸入模型的更好方法。
要從數(shù)據(jù)集datasets得到一個(gè)可運(yùn)行的tf.tensor,需要先把它轉(zhuǎn)為tf.data.Iterator迭代器,然后使用迭代器的get_next()方法。

如下示例代碼,使用了try...catch...捕獲異常,避免超過終點(diǎn)的錯(cuò)誤:

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

可訓(xùn)練的模型必須能夠改變graph的值,從而在在相同輸入數(shù)據(jù)的時(shí)候獲得新的輸出。層Layer是推薦的方法,用來像graph里面添加可訓(xùn)練的參數(shù)。

Layers將變量和操作打包。比如密集連接層densely-connected-layer為所有的輸入執(zhí)行加權(quán)求和操作到每個(gè)輸出,以及可選的激活函數(shù)activation function,由圖層對象管理連接權(quán)重weighted和偏移值bias。

層的使用流程包括:

  • 創(chuàng)建
  • 初始
  • 運(yùn)行
import tensorflow as tf
sess=tf.Session()

#創(chuàng)建一個(gè)節(jié)點(diǎn)的密集層,傳入n個(gè)三元數(shù)組,units=2輸出二維數(shù)組
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)

#運(yùn)行層,通過x傳入數(shù)據(jù)
v=sess.run(y, {x: [[1, 2, 3],[4, 5, 6]]})
print(v)

注意,tf.global_variables_inistializer方法只初始化以上的graph,所以應(yīng)該在graph建造完成之后運(yùn)行。
打印出的結(jié)果

[[-2.037472   3.9676275]
 [-5.741477  10.678923 ]]

每個(gè)layer在創(chuàng)建的時(shí)候可以直接傳遞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]]}))

這次會打印出兩個(gè)1元數(shù)組

[[-3.4608526]
 [-8.070822 ]]

Feature Columns

可以使用tf.feature_column.input_layer快速實(shí)驗(yàn)特征列,它只接受dense column密集列,如果是分類列Catergorical column,就必須經(jīng)過指示列tf.feature_column.indicator_column包裹,示例代碼如下。

import tensorflow as tf
sess=tf.Session()

#特征數(shù)據(jù)
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
]

#輸入層(數(shù)據(jù),特征列)
inputs = tf.feature_column.input_layer(features, columns)

#初始化并運(yùn)行
init = tf.global_variables_initializer()
sess.run(tf.tables_initializer())
sess.run(init)

v=sess.run(inputs)
print(v)

上面代碼輸出如下結(jié)果,可以看到input輸入層將每個(gè)商品的features轉(zhuǎn)為3維矢量,前兩個(gè)0,1獨(dú)熱表示分類運(yùn)動sport或園藝gardening,第三個(gè)數(shù)字表示銷售數(shù)量salse。

[[ 1.  0.  5.]
 [ 1.  0. 10.]
 [ 0.  1.  8.]
 [ 0.  1.  9.]]

Training

最簡單的訓(xùn)練流程包括:

  1. 構(gòu)建計(jì)算圖
    • 定義數(shù)據(jù)
    • 定義模型
    • 損失函數(shù)
    • 優(yōu)化方法
  2. 初始化
  3. 多次訓(xùn)練
  4. 進(jìn)行預(yù)測

下面來看一段完整的代碼,嘗試根據(jù)給定的線性數(shù)據(jù)推算線性函數(shù)模型并進(jìn)行預(yù)測:

import tensorflow as tf

#兩個(gè)輸入數(shù)據(jù),yi=-xi+1
xi =[[1,], [2,], [3,], [4,]]
yi =[[0,], [-1,], [-2,], [-3,]]

#兩個(gè)浮點(diǎn)占位器,不能使用整數(shù),那將產(chǎn)生稀疏值
x = tf.placeholder(tf.float32, shape=[None, 1])
y_true = tf.placeholder(tf.float32, shape=[None, 1])

#定義模型,一個(gè)線性的密集層
y_pred = tf.layers.dense(x, units=1)

#設(shè)定損失函數(shù),使用均方差,MSE=sum(squar(x-x'))/n
loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)

#設(shè)定優(yōu)化器,梯度下降優(yōu)化器
optimizer = tf.train.GradientDescentOptimizer(0.1)
train = optimizer.minimize(loss)

#初始化以上全部變量
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

#進(jìn)行訓(xùn)練
for i in range(1000):
  sess.run((train, loss),feed_dict={x:xi,y_true:yi})

#進(jìn)行預(yù)測,正確結(jié)果應(yīng)該輸出-11
print(sess.run(y_pred,feed_dict={x:[[12,]],y_true:[[None]]}))

輸出結(jié)果,非常接近我們正確值了。

[[-10.999997]]

如果降低訓(xùn)練次數(shù)1000到100,或者將優(yōu)化器梯度下降參數(shù)從0.1降為0.01,那么都將產(chǎn)生稍大的誤差。


本篇小結(jié)

  • 張量值的等級rank和形狀shape
  • Tensorflow的核心:
    • 計(jì)算圖graph:ops,tensor
    • 會話運(yùn)行時(shí)session:run,init
    • 信息板tensorboard:summary,event文件
    • 喂食數(shù)據(jù)feed:placeholder,feed_dict
  • 數(shù)據(jù)集Datasets:iterator,get_next()
  • 層Layer:
    • 創(chuàng)建
    • 初始化
    • 運(yùn)行
  • 特征列Feature columns:
    • input_layer(features,columns)
    • indicator_column(categorical_column)
  • 訓(xùn)練Train:features-graph-init-train-predict
    sess.run((train, loss),feed_dict={x:xi,y_true:yi})

探索人工智能的新邊界

如果您發(fā)現(xiàn)文章錯(cuò)誤,請不吝留言指正;
如果您覺得有用,請點(diǎn)喜歡;
如果您覺得很有用,感謝轉(zhuǎn)發(fā)~


END

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容