TensorFlow框架(1)之Computational Graph詳解


1. Getting Start

1.1 import

  TensorFlow應用程序需要引入編程架包,才能訪問TensorFlow的類、方法和符號。如下所示的方法:

import tensorflow as tf

2. Tensor

  TensorFlow用Tensor這種數據結構來表示所有的數據。可以把一個Tensor想象成一個n維的數組或列表。Tensor有一個靜態的類型和動態的維數。Tensor可以在圖中的節點之間流通。

2.1 秩(Rank)

  Tensor對象由原始數據組成的多維的數組,Tensor的rank(秩)其實是表示數組的維數,如下所示的tensor例子:

Rank

數學實例

Python 例子

0

常量 (只有大小)

s = 483

1

向量(大小和方向)

v = [1.1, 2.2, 3.3]

2

矩陣(數據表)

m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

3

3階張量 (數據立體)

t = [[[2], [4], [6]], [[8], [10], [12]], [[14], [16], [18]]]

n

n (自己想想看)

2.2 形狀(Shape)

  TensorFlow為了描述Tensor每一維的長度,相當於描述每一維數組的長度,所以定義了Shape概念。其可以描述Tensor的維數,又可以描述每一維的長度。

Rank

Shape

Dimension number

Example

0

[]

0-D

一個常量.

1

[D0]

1-D

[5]:表示一個向量有5個元素

2

[D0, D1]

2-D

[3, 4]:表示一個矩陣,共有3*4個元素

3

[D0, D1, D2]

3-D

[2, 4, 3]:總共有2*4*3個元素

n

[D0, D1, D2,… DN-1]

n-D

….

2.3 類型(Data type)

  除了維度,Tensor有一個數據類型屬性,你可以為一個張量指定下列數據類型中的任意一個類型,但是一個Tensor所有元素的類型必須相同。

數據類型

Python 類型

描述

DT_FLOAT

tf.float32

32 位浮點數.

DT_DOUBLE

tf.float64

64 位浮點數.

DT_INT64

tf.int64

64 位有符號整型.

DT_INT32

tf.int32

32 位有符號整型.

DT_INT16

tf.int16

16 位有符號整型.

DT_INT8

tf.int8

8 位有符號整型.

DT_UINT8

tf.uint8

8 位無符號整型.

DT_STRING

tf.string

可變長度的字節數組.每一個張量元素都是一個字節數組.

DT_BOOL

tf.bool

布爾型.

DT_COMPLEX64

tf.complex64

由兩個32位浮點數組成的復數:實數和虛數.

DT_QINT32

tf.qint32

用於量化Ops32位有符號整型.

DT_QINT8

tf.qint8

用於量化Ops8位有符號整型.

DT_QUINT8

tf.quint8

用於量化Ops8位無符號整型.

 

3. Computational graph

3.1 定義

  Computational graph 是由一系列邊(Tensor)和節點(operation)組成的數據流圖。每個節點都是一種操作,其有0個或多個Tensor作為輸入邊,且每個節點都會產生0個或多個Tensor作為輸出邊。即節點是將多條輸入邊作為操作的數據,然后通過操作產生新的數據。可以將這種操作理解為模型,或一個函數,如加減乘除等操作。

  簡單地說,可以將Computational graph理解為UML的活動圖,活動圖和Computational graph都是一種動態圖形。TensorFlow的節點(操作)類似活動圖的節點(動作),TensorFlow每個節點都有輸入(Tensor),可以將用戶創建的起始Tensor看做是活動圖的起始節點,而TensorFlow最終產生的Tensor看做是活動圖的終止節點,如圖 31所示。

 

圖 31

  圖 31所示,常量3和常量4.5兩個起始Tensor通過add操作后產生了一個新Tensor(值7.5);接着新Tensor(值7.5)和常量3經multi操作后產生一個新Tensor(值22.5),因為22.5是TensorFlow最后產生的Tensor,所以其是終止節點。

3.2 Session

  TensorFlow通過一個對象(Session)來管理Computational graph 節點動態變換。由於Tensor是一種數據結構,為了獲取Tensor存儲的數據,需要手動調用Session對象的run方法獲得。

  實現一個TensorFlow應用程序,用戶需要進行兩個步驟:

  1) 建立計算圖(Building the computational graph

    Computational Graph建立其實是建立節點和邊的一些依賴關系,這個過程是建立一種靜態結構。

  2) 執行計算圖(Running the computational graph

    Computational Graph執行其實就是調用session.run()方法。由於Computational Graph是有邊和節點組成,所以可以向run方法傳遞的兩種參數:

  • 邊( Tensor ):若傳遞的是 Tensor 對象,則是獲取 Tensor 對象的數據;
  • 節點:若傳遞的是節點,則會先獲取節點返回的 Tensor 對象,然后再獲取 Tensor 對象的數據。

  綜上所述執行Computational Graph其實是獲取Tensor的數據。在執行Tensor對象數據時,會根據節點的依賴關系進行計算,直至初始節點。

如下建立兩個TensorFlow節點,節點的類型是constant,然后通過add操作后產生一個新節點,如下所示:

##1.建立computational graph

node1 = tf.constant(3., tf.float32)

node2 = tf.constant(4.5)

tensor = tf.add(node1, node2)

 

print(node1)

print(node2)

 

##2.執行computational graph

session = tf.Session()

print(session.run(node1))

print(session.run(node2))

print(session.run(tensor))

輸出:

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

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

3.0

4.5

7.5

圖 32

注意:

  • 在執行 computational graph 之前, TensorFlow 節點是一種靜態結構,所以輸出的並不是 3.0 4.0 ,而是 tensor 對象;
  • 在執行 computational graph 之后,才輸出了節點的值,即為了讓某個節點從初始節點開始變換,需要通過 Session 對象的 run 方法手動變換。

3.3 InteractiveSession

  文檔中的 Python 示例使用一個會話 Session 來 啟動圖, 並調用 Session.run() 方法執行操作.為了便於使用諸如 IPython 之類的 Python 交互環境, 可以使用 InteractiveSession 代替 Session 類, 使用 Tensor.eval() 和 Operation.run() 方法代替 Session.run(). 這樣可以避免使用一個變量來持有會話.

# 進入一個交互式 TensorFlow 會話.

import tensorflow as tf

sess = tf.InteractiveSession()

 

x = tf.Variable([1.0, 2.0])

a = tf.constant([3.0, 3.0])

 

# 使用初始化器 initializer op run() 方法初始化 'x'

x.initializer.run()

 

# 增加一個減法 sub op, 'x' 減去 'a'. 運行減法 op, 輸出結果

sub = tf.sub(x, a)

print sub.eval()

# ==> [-2. -1.]

4. 起始節點

  目前了解的,TensorFlow有三種類型的起始節點:constant(常量)、placeholder(占位符)、Variable(變量)。

4.1 常量 (constant)

  TensorFlow的常量節點是通過constant方法創建,其是Computational Graph中的起始節點,在圖中以一個圓點表示,如圖 32所示。

如下述程序中所示,直接創建,但創建的節點不會開始執行,需要由Session對象的run方法開始啟動。

tensor1 = tf.constant(3., tf.float32)

print(tensor1)

 

tensor2 = tf.constant([1, 2, 3, 4, 5, 6, 7])

print(tensor2)

 

tensor3 = tf.constant(-1.0, shape=[2, 3])

print(tensor3)

 

session = tf.Session()

print(session.run(tensor1))

print(session.run(tensor2))

print(session.run(tensor3))

輸出:

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

Tensor("Const_1:0", shape=(7,), dtype=int32)

Tensor("Const_2:0", shape=(2, 3), dtype=float32)

3.0

[1 2 3 4 5 6 7]

[[-1. -1. -1.]

[-1. -1. -1.]]

4.2 占位符 (placeholder)

  TensorFlow的placeholder節點是由placeholder方法創建,其也是一種常量,但是由用戶在調用run方法是傳遞的,也可以將placeholder理解為一種形參。即其不像constant那樣直接可以使用,需要用戶傳遞常數值。

如下所示在執行node3:

import tensorflow as tf

 

node1 = tf.placeholder(tf.float32)

node2 = tf.placeholder(tf.float32)

tensor = tf.add(node1, node2)

 

print(node1)

print(node2)

 

session = tf.Session()

print(session.run(tensor, {node1:3,node2:4} ))

輸出:

Tensor("Placeholder:0", dtype=float32)

Tensor("Placeholder_1:0", dtype=float32)

7.0

注意:

    由於在執行node3節點時,需要node1和node2作為輸入節點,所以此時需要傳遞"實參",即3和4.

圖 41

4.3 變量 (Variable)

  TensorFlow的Variable節點是通過Variable方法創建,並且需要傳遞初始值。常量在執行過程中無法修改值,變量可以在執行過程修改其值。但是TensorFlow的變量在創建之后需要再進行手動初始化操作,而TensorFlow常量在創建時就已進行了初始化,無需再進行手動初始化。

如下示例,創建兩個變量,分別初始化為0.3和-0.3,然后傳入一個向量值,最后計算出一個新的向量:

from __future__ import print_function

import tensorflow as tf

 

w = tf.Variable([.3], tf.float32)

b = tf.Variable([-.3], tf.float32)

x = tf.placeholder(tf.float32)

 

linear = w * x + b

 

session = tf.Session()

init = tf.global_variables_initializer()

session.run(init)

 

print(session.run(linear, {x: [1, 2, 3, 4]}))

輸出:

[ 0. 0.30000001 0.60000002 0.90000004]

圖 42

從W展開細節看,變量其實只是一個命名空間,其內部由一系列的節點和邊組成。同時有一個常量節點,即初始值節點。

5. 模型評估

  模型評估是指比較期望值和模型產生值之間的差異,若差異越大,則性能越差;差異越小,性能越好。模型評估有很多種方法,如均分誤差或交差熵。

如下以常用的"均分誤差"法舉例說明,其等式為:

Y為期望向量,X為輸入向量,f(X)為計算向量,如下所示:

from __future__ import print_function

import tensorflow as tf

#1. 構建計算流圖

w = tf.Variable([.3], tf.float32)

b = tf.Variable([-.3], tf.float32)

x = tf.placeholder(tf.float32)

y = tf.placeholder(tf.float32) #期望向量

linear_model = w * x + b

 

squared_deltas = tf.square(linear_model - y) #對兩個向量的每個元素取差並平方,最后得出一個新的向量

loss = tf.reduce_sum(squared_deltas) #對向量取總和

 

#2. 執行計算流圖

session = tf.Session()

init = tf.global_variables_initializer()

session.run(init)

 

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

輸出:

          23.66

注意:

loss的值是依賴W、B和Y三個向量的值,所以計算loss Tensor會根據依賴關系獲取W、B和Y三個Tensor的值,其計算流程圖如圖 51所示:

圖 51

6. 優化

  優化是指減少期望值與模型產生值之間的差異,即減少均分誤差或交差熵的計算結果,如減少上述的loss變量值。

6.1 手動優化

  我們可以通過修改上述的w和b的變量值,來手動優化上述的模型。由於TensorFlow的變量是通過tf.Variable方法創建,而重新賦值是通過tf.assign方法來實現。注意修改變量的動作需要執行Session.run方法來開始執行。

比如可以修改w=-1,b=1參數來優化模型,如下

from __future__ import print_function

import tensorflow as tf

 

w = tf.Variable([.3], tf.float32)

b = tf.Variable([-.3], tf.float32)

x = tf.placeholder(tf.float32)

y = tf.placeholder(tf.float32 ")

linear_model = w * x + b

 

squared_deltas = tf.square(linear_model - y)

loss = tf.reduce_sum(squared_deltas)

 

session = tf.Session()

init = tf.global_variables_initializer()

session.run(init)

 

#1.變量wb初始值為3-3時,計算loss

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

 

#2.重置變量wb值為-11時,再計算loss

fixw = tf.assign(w,[-1.])

fixb = tf.assign(b,[1.])

session.run(fixw)

session.run(fixb)

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

輸出:

23.66

0.0

注意:

    loss的值是依賴W、B和Y三個向量的值來計算,即每次計算loss都需要上述三個變量的值進行計算。由於通過調用Session.run()方法來執行某個節點(Computational graph的節點為操作)時,會自動根據節點前后依賴關系,自動從初始節點開始計算到該節點。在第一次執行session.run(loss)時,W和B的值是3和-3;第二次執行session.run(loss)時,W和B的值被修改為-1和1后。所以session.run(loss)時會自動根據W和B的不同進行計算。

 

圖 61

6.2 自動優化

  上述通過手動調整變量w和b的值來改善模型的執行性能,雖然也行的通,但是非常單調且工作量太大。所以TensorFlow提供一些優化器(optimizers)來提高用戶的工作效率,可以自動完成優化,即可以自動更新相關變量的值。

如下所示,以最簡單的優化器gradient descent為例,其可以根據執行loss值逐漸修改每個變量值,:

import numpy as np

import tensorflow as tf

w = tf.Variable([.3], tf.float32)

b = tf.Variable([-.3], tf.float32)

x = tf.placeholder(tf.float32)

linear_model = w * x + b

y = tf.placeholder(tf.float32)

 

squared_deltas = tf.square(linear_model - y)

loss = tf.reduce_sum(squared_deltas)

 

#1. optimizer

optimizer = tf.train.GradientDescentOptimizer(0.01)

train = optimizer.minimize(loss)

 

#2. training loop

init = tf.global_variables_initializer()

session = tf.Session()

session.run(init)

 

for i in range(1000):

session.run(train, {x:[1,2,3,4], y:[0, -1, -2, -3]})

 

#3. evaluate training accuracy

curr_w, curr_b, curr_loss = session.run([w,b,loss], {x:[1, 2, 3, 4], y:[0, -1, -2, -3]})

print("w:%s b:%s loss:%s"%(curr_w,curr_b,curr_loss))

輸出:

w:[-0.9999969] b:[ 0.99999082] loss:5.69997e-11

注意:

  1) optimizer :創建一個優化器,並指定優化的方向;優化器的優化過程是:對於方程中的權值( w )和偏置( b )對跟進 loss 值進行調整, v 是泛指 w b 參數,則每趟優化過程都會按如下方程更改 w b 的值:

則dV是參數調整數幅度,如若v是權值w,則

  2) training :執行優化器,在執行過程中會不斷更新涉及的變量,即會更新 W B 兩個 Tensor 值;
  3) evaluate W B 在優化前就有初始值;在優化后會更新兩個值;所以再執行 loss 時,會根據 W B Y 三個 Tensor 值來計算。

如圖 62所示是產生的Computational graph圖變換:

圖 62

圖中帶有箭頭的邊緣是指依賴,如節點b有一個指向tain_min節點,表明b的值依賴tain_min節點。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM