計算模型——圖
數據模型——張量
運行模型——會話
TensorFlow計算模型——計算圖
計算圖是TF中最基本的一個概念,TF中的所有計算都會被轉化為計算圖上的結點。
TF是一個通過計算圖的形式來表述計算的編程系統。TF中的每一個計算都是計算圖上的一個節點,節點之間的邊描述了計算之間的依賴關系。
TensorBoard是TensorFlow的可視化工具。
TensorFlow程序一般可分為兩個階段:
第一階段:定義計算圖中的所有計算;
第二階段:執行計算。
import tensorflow as tf
a = tf.constant([1.0, 2.0], name="a")
b = tf.constant([2.0, 3.0], name="b")
result = a + b
此過程會自動將定義的計算轉化為計算圖上的節點。
系統默認維護一個默認的計算圖,通過tf.get_default_graph函數可以獲取當前默認的計算圖。
print(a.graph is tf.get_default_graph())
import tensorflow as tfg1 = tf.Graph()
with g1.as_default():v = tf.get_variable("v", initializer=tf.zeros_initializer(shape=[1]))g2 = tf.Graph()
with g2.as_default():v = tf.get_variable("v", initializer=tf.ones_initializer(shape=[1]))with tf.Session(graph=g1) as sess:tf.initialize_all_variables().run()with tf.variable_scope("", result=True):print(sess.run(tf.get_variable("v")))with tf.Session(graph=g2) as sess:tf.initialize_all_variables().run()with tf.variable_scope("", result=True):print(sess.run(tf.get_variable("v")))
TensorFlow中的計算圖不僅僅可以用來隔離張量和計算,還提供了管理張量和計算的機制。
計算圖可以通過tf.Graph.device函數來指定運行計算的設備。這為TensorFlow使用GPU提供了機制。
g = tf.Graph()with g.device('/gpu:0'):result = a + b
有效的整理TensorFlow程序中的資源也是計算圖的一個重要功能。
在一個計算圖中,可以通過集合(collection)來管理不同類別的資源。
比如通過tf.add_to_collection函數可以將資源加入一個或多個集合中,然后通過tf.get_collection獲取一個集合里面的所有資源。
這里的資源可以是張量、變量或者運行TensorFlow程序所需要的隊列資源,等等。
為了方便使用,TensorFlow也自動管理了一些最常用的集合:
集合名稱 | 集合內容 | 使用場景 |
tf.GraphKeys.VARIABLES | 所有變量 | 持久化TensorFlow模型 |
tf.GraphKeys.TRAINABLE_VARIABLES | 可學習變量(一般指神經網絡中的參數) | 模型訓練、生成模型可視化內容 |
tf.GraphKeys.SUMMARIES | 日志生成相關的張量 | TensorFlow計算可視化 |
tf.GraphKeys.QUEUE_RUNNERS | 處理輸入的QueueRunner | 輸入處理 |
tf.GraphKeys.MOVING_AVERAGE_VARIABLES | 所有計算了滑動平均值的變量 | 計算變量的滑動平均值 |
TensorFlow數據模型——張量
張量是TensorFlow管理數據的形式。
張量可以被簡單理解為多維數組:
零階張量表示標量(scalar);
一階張量表示向量(vector);
n階張量表示一個n維數組。
張量在TensorFlow中的實現并不是直接采用數組的形式,它只是對TensorFlow中運算結果的引用。
在張量中并沒有真正保存數字,它保存的是如何得到這些數字的計算過程。
import tensorflow as tfa = tf.constant([1.2, 2.0], name="a")
b = tf.constant([2.0, 3.0], name="b")
result = tf.add(a, b, name="add")
print result
'''
輸出:
Tensor("add:0", shape=(2,), dtype=float32)
'''
TensorFlow計算的結果不是一個具體的數字,而是一個張量的結構。一個張量主要保存了三個屬性:名字(name)、維度(shape)、類型(type)。
名字不僅是一個張量唯一標識符,同樣給出了這個張量是如何計算出來的。
TensorFlow的計算通過計算圖模型來建立,計算圖上的每一個節點代表了一個計算,計算的結果就保存在張量中。即張量和計算圖上節點所代表的計算結果是對應的。
張量的命名規則:node:src_oput
node為節點的名稱,src_output表示節點的第幾個輸出。
a=tf.constant([1,2], name="a", dtype=tf.float32)
TF支持14種不同的類型,主要包括:
實數:tf.float32 ?tf.float64
整數:tf.int8 ?tf.int16 ?tf.int32 ?tf.int64 ?tf.unit8
布爾:tf.bool
復數:tf.complex64 ?tf.complex128
張量的用途:
一、對中間計算結果的引用。當一個計算包含很多中間結果時,使用張量可以大大提高代碼的可讀性。result.get_shape函數可以獲得結果張量的維度信息;
二、當計算圖構造完成之后,張量可以用來獲得計算結果,即得到真實數字:tf.Session().run(result)。
TensorFlow運行模型——會話
會話(session)用來執行定義好的運算。
會話擁有并管理TensorFlow程序運行時的所有資源。
當所有計算完成之后需要關閉會話來幫助系統回收資源,否則就可能出現資源泄露的問題。
使用會話的模式一般有兩種:
一、明確調用會話生成函數和關閉會話函數:
sess = tf.Session()
sess.run(...)
sess.close()
當程序因為異常而退出時,關閉會話的函數可能就不會被執行從而導致資源泄露。二、為了解決異常退出時資源釋放的問題,TensorFlow可以通過Python的上下文管理器來使用會話:
with tf.Session() as sess:sess.run(...)
只要將所有的計算放在with的內部就可以,當上下文管理器退出時會自動釋放所有資源。TensorFlow需要手動指定默認會話。當默認會話被指定后,可通過tf.Tensor.eval函數來計算一個張量的取值。
sess = tf.Session()
with sess.as_default():print(result.eval())
或sess = tf.Session()
print(sess.run(result))
print(result.eval(session=sess))
在交互式環境下,通過設置默認會話的方式來獲取張量的取值更加方便。
tf.InteractiveSession函數自動將生成的會話注冊為默認會話。
sess = tf.InteractiveSession()
print(result.eval())
sess.close()
通過tf.InteractiveSession函數可以省去將產生的會話注冊為默認會話的過程。無論使用哪種方法都可以通過ConfigProto Protocol Buffer來配置需要生成的會話。
config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
sess1 = tf.InteractiveSession(config=config)
sess2 = tf.Session(config=config)
通過ConfigProto可以配置類似并行的線程數、GPU分配策略、運算超時時間等參數。在這些參數中,常用的有兩個:
allow_soft_placement,為True時,當一下任意一個條件成立時,GPU上的運算可以放到CPU上進行:
1 運算無法在GPU上執行;
2 沒有GPU資源;
3 運算輸入包含對CPU計算結果的引用。
這個參數的默認值為False,但為了使代碼的可移植性更強,在由GPU的環境下,這個參數一般會被設置為True。
這個參數的默認值為False,但為了使代碼的可移植性更強,在由GPU的環境下,這個參數一般會被設置為True。
不同的GPU驅動版本可能對計算的支持有略微的區別,通過將allow_soft_placement設置為True,當某些運算無法被當前GPU支持時,可以自動調整到CPU上,而不是報錯。
類似的,通過將這個參數設置為True,可以讓程序在擁有不同數量的GPU機器上順利運行。
log_device_placement,為True時,日志中將會記錄每個節點被安排在了哪個設備上方便調試,而在生產環境中將這個參數設置為False可以減少日志量。
log_device_placement,為True時,日志中將會記錄每個節點被安排在了哪個設備上方便調試,而在生產環境中將這個參數設置為False可以減少日志量。
TensorFlow游樂場(http://playground.tensorflow.org)是一個通過網頁瀏覽器就可以訓練簡單神經網絡并實現了可視化訓練過程的工具。
神經網絡概述
使用神經網絡解決分類問題主要可以分為以下4個步驟:
1、提取問題中實體的特征向量作為神經網絡的輸入;
2、定義神經網絡結構,并定義如何從神經網絡的輸入得到輸出,這個過程就是神經網路的前向傳播算法;
3、通過訓練數據來調整神經網絡中參數的值,這就是訓練神經網絡的過程;
4、使用訓練好的神經網絡來預測未知的數據。
一個神經元有多個輸入和一個輸出。
每個神經元的輸入既可以是其他神經元的輸出,也可以是整個神經網絡的輸入。
神經網絡的結構就是指不同神經元之間的連接結構。
一個最簡單的神經元結構的輸出就是所有輸入的加權和,不同輸入的權重就是神經元的參數。
神經網絡的優化過程就是優化神經元中參數取值的過程。
全連接神經網絡:相鄰兩層之間任意兩個節點之間都有連接。
神經網絡中的神經元也可以稱之為節點。
前向傳播算法可以表示為矩陣的乘法。
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
神經網絡中的參數是神經網絡實現分類或者回歸問題中重要的部分。
在TensorFlow中,變量(tf.Variable)的作用就是保存和更新神經網絡中的參數。
TensorFlow中的變量需要指定初始值。因為在神經網絡中,給參數賦予隨機初始值最為常見,所以一般也使用隨機數給TensorFlow中的變量初始化。
weights = tf.Variable(tf.random_normal([2, 3], stddev=2))
產生一個2*3的矩陣,矩陣中的元素是均值為0,標準差為2的隨機數。tf.random_normal函數可通過參數mean來指定平均值,默認為0。
隨機數生成函數:
函數名稱 ? ?隨機數分布 ? ?主要參數
tf.random_normal ? ?正太分布 ? ?平均值、標準差、取值類型
tf.truncated_normal ? ?正太分布,如果隨機出來的值偏離平均值超過2個標準差,這個數將會被重新隨機 ? ?平均值、標準差、取值類型
tf.random_uniform ? ?平均分布 ? ?最小、最大取值,取值類型
tf.random_gamma ? ?Gamma分布 ? ?形狀參數alpha、尺度參數beta、取值類型
常數生成函數:
函數名稱 ? ?隨機數分布 ? ?主要參數
tf.zeros ? ?全0數組 ? ?tf.zeros([2,3], int32) --> [[0,0,0], [0,0,0]]tf.ones ? ?全1數組 ? ?tf.ones([2,3], int32) --> [[1,1,1], [1,1,1]]
tf.fill ? ?全部為給定數字的數組 ? ?tf.fill([2,3], int32) --> [[9,9,9], [9,9,9]]
tf.constant ? ?給定值的常量 ? ?tf.constant([1,2,3], int32) --> [1,2,3]
在神經網絡中,偏置項(bias)通常會使用常數來設置初始值。
biases = tf.variable(tff.zeros([3]))
除了使用隨機數或者常數,TensorFlow也支持通過其他變量的初始值來初始化新的變量。
w2 = tf.Variable(weights.initialized_value())
w3 = tf.Variable(weights.initialized_value() * 2.0)
一個變量的值在被使用之前,這個變量的初始化過程需要明確的被調用。import tensorflow as tfw1 = tf.Variable(tf.random_normal([2,3], stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal([3,1], stddev=1, seed=1))x = tf.Constant([[0.7, 0.9]])a = tf.matmul(x, w1);
y = tf.matmul(a, w2);sess = tf.Session()
sess.run(w1.initializer)
sess.run(w2.initializer)
print(sess.run(y))
sess.close()
上述代碼實現了神經網絡的前向傳播過程。在計算y之前,需要將所有用到的變量初始化。
變量初始化快捷方式:
init_op = tf.initialize_all_variables()
sess.run(init_op)
通過tf.initialize_all_variables函數,就不需要將變量一個一個初始化了。這個函數也會自動處理變量之間的依賴關系。
變量的聲明函數tf.Variable是一個運算,這個運算的輸出結果就是一個張量。
所有的變量都會被自動的加入到GraphKeys.VARIABLES這個集合。通過tf.all_variables函數可以拿到當前計算圖上的所有變量。
拿到計算圖上所有的變量有助于持久化整個計算圖的運行狀態。
當構建機器學習模型時,比如神經網絡,可以通過變量聲明函數中的trainable參數來區分需要優化的參數(比如神經網絡的參數)和其他參數(比如迭代的輪數)。
如果聲明變量時參數trainable為True,那么這個變量將會被加入GraphKeys.TRAINABLE_VARIABLES集合。
可通過tf.trainable_variables函數得到所有需要優化的參數。
TensorFlow中提供的神經網絡優化算法會將GraphKeys.TRAINABLE_VARIBLES集合中的變量作為默認的優化對象。
維度(shape)和類型(type)也是變量最重要的兩個屬性。
變量是不可改變的,一個變量在構建之后,它的類型就不能再改變了。
維度在程序運行中是有可能改變的,但是需要設置參數validate_shape=False。這種用法在實踐中比較罕見。
設置神經網絡參數的過程就是神經網絡的訓練過程,只有經過有效訓練的神經網絡模型才可以真正的解決分類或者回歸問題。
使用監督學習的方式設置神經網絡參數需要一個標注好的訓練數據集。
顏色越深,表示神經網絡模型對它的判斷越有信心。
一般來說,一個神經網絡的訓練過程需要幾百萬甚至幾億輪的迭代。
TensorFlow的placeholder機制用于提供數據。它定義了一個位置,這個位置中的數據在程序運行時再指定。
在定義placeholder時,數據類型需要指定。
placeholder的數據類型不可改變,維度信息可以根據提供的數據推導得出。
import tensorflow as tfw1 = tf.Variable(tf.random_normal([2,3], stddev=1))
w2 = tf.Variable(tf.random_normal([3,1], stddev=1))x = tf.placeholder(tf.float32, shape=(1,2), name="input")
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)sess = tf.Session()
init_op = tf.initialize_all_variables()
sess.run(init_op)
print(sess.run(y, feed_dict={x:[[0.7, 0.9]]}))
feed_dict是一個字典(map),在字典中需要給出每個用到的placeholder的取值。訓練神經網絡的過程可分為以下3個步驟:
1、定義神經網絡的結構和前向傳播算法的輸出;
2、定義損失函數以及選擇反向傳播的優化的算法;
3、生成會話(tf.Session)并且在訓練數據上反復運行反向傳播優化算法。