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