(代碼基於tensorflow 1.14 cpu版本,讀者須要具備良好的python基礎和線性代數知識)html
第三章主要介紹TensorFlow的計算模型、數據模型和運行模型,對TensorFlow的工做原理能有一個大體瞭解。node
TensorFlow程序通常分爲兩個階段。第一階段:定義計算圖中全部的計算,而後定義一個計算來獲得他們的和;第二階段:執行計算。python
TensorFlow這個單詞由兩部分組成:tensor表明張量,是數據模型;flow表明流,是計算模型。下面就引出Flow的具體內涵。數組
流動的事務具備有向性,計算圖就是一個具備 「每個節點都是計算圖上的一個節點,而節點之間的邊描述了計算之間的依賴關係」 性質的有向圖。(計算圖和數據結構這門課程中的有向圖具備高度的類似性,如今能夠回憶一下這段記憶)promise
計算圖由邊(表示依賴關係,又被叫作「張量」)和節點(又被叫作「神經元」、「算子」)組成。若是tensorflow程序只定義了一個Graph,那其內部包含了全部的op和tensor緩存
在TensorFlow程序中,系統會自動維護一個默認的計算圖,經過tf.get_default_graph()函數能夠獲取這個默認的計算圖。數據結構
import tensorflow as tf a = tf.constant([1.0, 2.0], name='a') b = tf.constant([1.0, 2.0], name='b') result = a + b #經過a.graph屬性能夠查看這個張量所屬的計算圖。由於沒有特地指定,因此這個計算圖應該等於當前默認的計算圖 print(a.graph is tf.get_default_graph()) ''' 輸出>>> True '''
Tensorflow經過計算圖把張量和算子等組合在一塊兒,而在不少TensorFlow程序中,看不到Graph,這是爲什麼?這是由於TensorFlow有個默認缺省的graph
(即Graph.as_default()),咱們添加的tensor和op等都會自動添加到這個缺省計算圖中,若是沒有特別要求,使用這個默認缺省的Graph便可。固然,若是須要一些更復雜的計算,好比須要建立兩個相互之間沒有交互的模型,就須要自定義計算圖。
除了使用默認的計算圖,TensorFlow支持經過tf.Graph函數來生成新的計算圖。TensorFlow中的計算圖不只能夠隔絕張量和計算,它還提供了管理張量和計算的機制,不一樣計算圖上的張量和運算不會共享。
如下代碼示意瞭如何經過在不一樣的計算圖上定義和使用變量。函數
import tensorflow as tf g1 = tf.Graph() with g1.as_default(): v = tf.get_variable('v', shape=[1], initializer=tf.zeros_initializer) g2 = tf.Graph() with g2.as_default(): v = tf.get_variable('v', shape=[1], initializer=tf.ones_initializer) ''' tf.Graph()沒有實現__enter__()方法,作不到下面那優雅pythonic的寫法。 with tf.Graph() as g2: v = tf.get_variable('v', shape=[1], initializer=tf.ones_initializer) 這樣寫了就會拋出AttributeError異常 Traceback (most recent call last): File "D:/bb/TensorFlow/Untitled1.py", line 7, in <module> with tf.Graph() as g2: AttributeError: __enter__ ''' with tf.Session(graph=g1) as sess: tf.global_variables_initializer().run() with tf.variable_scope("", reuse=True): print(sess.run(tf.get_variable('v'))) with tf.Session(graph=g2) as sess: tf.global_variables_initializer().run() with tf.variable_scope("", reuse=True): print(sess.run(tf.get_variable('v'))) ''' 輸出>>> [0.] [1.] 注:先不要管代碼是什麼含義,繼續往下看 '''
若是有多個Graph,建議不使用默認的Graph,直接無視或者爲其分配一個句柄,避免發生混亂優化
import tensorflow as tf graph1 = tf.Graph() graph2 = tf.Graph() # 直接無視默認缺省的Graph # graph2 = tf.get_default_graph() 爲其分配一個句柄 with graph1.as_default(): pass with graph2.as_default(): pass
在TensorFlow的程序中,全部的數據都經過張量(tensor)的形式表示。ui
張量(tensor)理解爲多維數組(multidimensional array),0階張量是標量(scalar),1階是向量(vector)(即一維數組),2階是二維數組,n階爲n維數組。
TensorFlow的運算結果不是一個數,而是一個張量結構。(運算和運行在tensorflow語境中不一樣,運算就是用過運算符操做,運行就和會話有關,3.3會提到)
import tensorflow as tf a = tf.constant([1.0, 2.0], name='a') b = tf.constant([1.0, 2.0], name='b') result = tf.add(a, b, name='add') print(result) ''' 輸出>>> Tensor("add:0", shape=(2,), dtype=float32) '''
一個張量保存了三個屬性:名字(name)、維度(shape)和類型(type)
張量的命名形式:「node:src_output」,node爲節點的名稱,src_output表示當前張量來自來自節點的第幾個輸出。
好比上面的代碼的輸出"add:0"說明張量result是計算節點「add」輸出的第一個結果(編號從0開始)
張量和計算圖上節點的計算結果是一一對應的。
上面樣例的shape(2,)表示一個一維數組,這個數組的長度是2。
TensorFlow支持的14種數據類型
有符號整型
tf.int8:8位整數
tf.int16:16位整數
tf.int32:32位整數
tf.int64:64位整數
無符號整型
tf.uint8:8位無符號整數
tf.uint16:16位無符號整數
浮點型
tf.float16:16位浮點數
tf.float32:32位浮點數
tf.float64:64位浮點數
tf.double:等同於tf.float64
字符串型
tf.string:字符串
布爾型
tf.bool:布爾型
複數型
tf.complex64:64位複數
tf.complex128:128位複數
TensorFlow數據類型和Python原生數據類型的關係
TensorFlow接受了Python本身的原生數據類型,例如Python中的布爾值類型,數值數據類型(整數,浮點數)和字符串類型。單一值將轉換爲0維張量(標量),列表值將轉換爲1維張量(向量),列表套列表將被轉換成2維張量(矩陣)
你可能已經注意到了Numpy和TensorFlow有不少類似之處。TensorFlow在設計之初就但願可以與Numpy有着很好的集成效果。Numpy軟件包如今已經成爲數據科學的通用語言。
TensorFlow數據類型不少也是基於Numpy的,事實上,若是你令 np.int32==tf.int32將會返回True.你也能夠直接傳遞Numpy數據類型直接給TensorFlow中的ops。
tf.ones([2, 2], np.float32) ==> [[1.0 1.0], [1.0 1.0]]
請記得,咱們的好朋友會話tf.Session.run(),要求的輸入對象是一個Tensor可是它的輸出是一個Numpy數組。事實上,在絕大多數場合,你能夠同時混合使用TensorFlow類型和Numpy類型。
張量使用能夠歸結爲兩大類。
1.第一類對中間計算結果的引用,提高代碼的可讀性
使用張量和不使用張量的對比
import tensorflow as tf #使用張量記錄 a = tf.constant([1.0, 2.0], name='a') b = tf.constant([1.0, 2.0], name='b') result1 = a + b #不使用張量,簡潔可是可讀性下降 result2 = tf.constant([1.0, 2.0], name='a') + tf.constant([1.0, 2.0], name='b') #jie'guo'xiang't print(result1) print(result2) ''' 輸出>>> Tensor("add:0", shape=(2,), dtype=float32) Tensor("add_1:0", shape=(2,), dtype=float32) '''
2.第二類狀況是計算圖構造完成後,張量能夠用來獲取計算結果
使用tf.Session().run(result)語句能夠獲得計算結果
計算圖描述計算
張量是組織數據
會話執行定義好的運算
會話管理TensorFlow程序運行時的全部資源,並在運行結束後釋放全部的資源。
會話機制相似於計算圖機制:
計算圖:在一開始就有一個默認的計算圖存在,而且沒有特別指定,運算會自動加入到這個默認的計算圖中
會話:會要手動建立,張量自動添加。
TensorFlow使用會話模式有兩種方式
1.普通模式
import tensorflow as tf # 加入了一個異常處理機制,確保釋放資源 try: sess = tf.Session() # 建立一個會話 sess.run(...) # 運行,獲得計算結果 except Exception: pass finally: sess.close() # 關閉會話,釋放資源
2.上下文模式
這纔是pythonic的寫法,極力推薦
import tensorflow as tf with tf.Session as sess: sess.run() #運行到這個位置會自動釋放sess的資源,優雅尼克
這是2.2程序的引用,會話的寫法多種多樣,咱們應用最優雅、最pythinc的代碼去闡述。
import tensorflow as tf a = tf.constant([1.0, 2.0], name='a') b = tf.constant([1.0, 2.0], name='b') result = tf.add(a, b, name='add') with tf.Session() as sess: # tf.Session.run(),要求的輸入對象是一個Tensor可是它的輸出是一個Numpy數組 print(sess.run(result)) ''' 輸出>>> [2. 4.] '''
Python中使用常量很簡單,如a=123,b='python'。TensorFlow表示常量稍微麻煩一點,須要使用tf.constant這個類,具體格式以下:
tf.constant(value, dtype=None, shape=None, name="Const", verify_shape=False)
其中各參數說明以下:
示例以下:
import tensorflow as tf # 構建計算圖 a = tf.constant('something', name='a') print(a) with tf.Session() as sess: # 創造會話 result = sess.run(a) # 在會話中執行張量a print(result) ''' 輸出>>> Tensor("a:0", shape=(2,), dtype=float32) b'something' '''
變量是TensorFlow中的核心概念,建立一個類使用tf.Variable,具體格式以下:
tf.Variable(initial_value=None,trainable=None,collections=None,validate_shape=True,caching_device=None,name=None,variable_def=None,dtype=None,expected_shape=None,import_scope=None,constraint=None,use_resource=None,synchronization=VariableSynchronization.AUTO, aggregation=VariableAggregation.NONE,shape=None)
主要參數說明:
1.如今讓咱們使用tf.Variable()建立變量,這是最簡單的、最經常使用的變量建立方法。用的最多的兩個參數initial_value和name
import tensorflow as tf girl = tf.Variable('安靜宇', name='big') # 這個name大有做用,後面會講到,須要注意的是,name的值不能夠是中文,中文會報錯 god = tf.Variable('安靜宇', name='big') # 使用tf.Variable()建立的實例,實例名是惟一標識符( Variable()內的參數均可以重複 ) # 寫做girl = tf.Variable('安靜宇', name='big'),就會覆蓋第一個girl print('initializer', girl.initializer) print('initial_value', girl.initial_value) print('graph', girl.graph) print('shape', girl.shape) print('name', girl.name) print('dtype', girl.dtype) print('value', girl.value()) ''' 輸出>>> initializer name: "big/Assign" op: "Assign" input: "big" input: "big/initial_value" attr { key: "T" value { type: DT_STRING } } attr { key: "_class" value { list { s: "loc:@big" } } } attr { key: "use_locking" value { b: true } } attr { key: "validate_shape" value { b: true } } initial_value Tensor("big/initial_value:0", shape=(), dtype=string) graph <tensorflow.python.framework.ops.Graph object at 0x000001DF1B542EF0> shape () name big:0 dtype <dtype: 'string_ref'> value Tensor("big/read:0", shape=(), dtype=string) '''
2.除了使用tf.Variable()建立變量,還有一個孿生兄弟,tf.get_variable(),他兩的業務邏輯仍是很不同的,使用的惟一標識符不同,前者使用實例名做爲惟一標誌,後者使用name參數做爲惟一標誌。
具體用法能夠參考這篇博客Variable和get_variable的用法以及區別
按照習慣,get開頭的函數都是「查詢」、「獲取」的意思,可是tf.get_variable()是建立變量,get取的是「建立」的意思
tensorflow中,程序存在變量,在使用前必須初始化
初始化變量有兩個方法
手動初始化就是
ses.run(var1.initializer) ses.run(var2.initializer) ses.run(var3.initializer)
一次性全局初始化只要使用一個函數 tf.global_variables_initializer()
init_op = tf.global_variables_initializer() sess.run(init_op)
貼一個完整代碼
import tensorflow as tf girl = tf.Variable('安靜宇', name='cute') god = tf.Variable('安靜宇', name='pretty') with tf.Session() as sess: # 必須先初始化變量才能使用,tf.global_variables_initializer()能夠初始化全部的變量 sess.run(girl.initializer) sess.run(god.initializer) # 等價於 sess.run(tf.global_variables_initializer()) print(sess.run(girl).decode()) print(sess.run(god).decode()) ''' 輸出>>> 安靜宇 安靜宇 '''
最後給大家看看安靜宇