一、計算模型----計算圖
1.1 計算圖的概念:TensorFlow就是通過圖的形式繪制出張量節點的計算過程,例如下圖執行了一個a+b的操作。
1.2 計算圖的使用
TensorFlow程序一般分為兩個階段。第一個階段定義計算圖中的所有計算,第二個階段執行計算(執行會話)。
階段一
>>> import tensorflow as tf >>> a = tf.constant([1,2],name = 'a') >>> b = tf.constant([2,4],name = 'b') >>> result = a + b
階段二
>>> ses = tf.Session() 2018-06-06 20:16:14.770712: I T:\src\github\tensorflow\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 >>> ses.run(result) array([3, 6]) >>>
在TF中,系統會自動維護一個默認的計算圖,通過tf.get_default_graph函數可以獲取當前默認的計算圖。
a.graph可以查看當前張量所屬的計算圖。沒有特殊指定的情況下,一般為默認計算圖。
>>> tf.get_default_graph() <tensorflow.python.framework.ops.Graph object at 0x0000020774910828> >>> a.graph <tensorflow.python.framework.ops.Graph object at 0x0000020774910828>
#(兩個對象的內存地址相同)
TF可以通過tf.Graph函數來生成一個新的計算圖。不同計算圖上的張量不會共享。
import tensorflow as tf #創建新的計算圖,並且在計算圖的上下文管理器中定義變量v,初始化為0 g1 = 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]) #在計算圖g1中讀取變量V的取值 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"))) #在計算圖g2中讀取變量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")))
可以通過tf.Graph.device()指定運行計算的設備,例如GPU。
g = tf.Graph()
with g.device("gpu/0") :
result = a + b
二、數據模型------張量
2.1張量的概念
從功能的角度,張量可以被理解成一個N維數組。零階張量表示標量,一階張量表示向量,也就是一個以為數組,第n階張量為矩陣,也就是一個n維數組。
但張量在tf中並不是采用數組的形式,只是對TF的運算結果的引用。
import tensorflow as tf #tf.constant是一個計算,這個計算的結果為一個張量,保存在變量a中 a = tf.constant([1,2],name="a") b = tf.constant([1,3],name="b") result = tf.add(a,b,name="add") print(result) #輸出結果 Tensor("add:0", shape=(2,), dtype=int32)
TF的計算結果是一個張量結構。一個張量包含三個屬性:名字name ,維度shape,類型 dtype。
name :張量的唯一標識。命名規范:“node:src_input” 。node 表示圖的節點的名稱,src_input 表示張量來自節點的第幾個輸入(從0開始)
shape:描述張量的維度信息。
dtype;每一個張量有一個唯一的類型。不同類型計算會報錯。
import tensorflow as tf #tf.constant是一個計算,這個計算的結果為一個張量,保存在變量a中 a = tf.constant([1,2],name="a") b = tf.constant([1.0,3.0],name="b") result = tf.add(a,b,name="adds") print(result) TypeError: Input 'y' of 'Add' Op has type float32 that does not match type int32 of argument 'x'.
tf有14中數值類型
2.2張量的使用。
張量的使用分為兩大類:
第一類,對中間計算結果的引用。提高代碼的可讀性。
import tensorflow as tf #使用張量記錄計算結果 a = tf.constant([1.0,2.0],name="a") b = tf.constant([1.0,3.0],name="b") result = a+b #直接計算向量的和,可讀性很差 result = tf.constant([1.0,2.0],name="a") + tf.constant([1.0,2.0],name="b")
第二類情況,當計算圖構造完成后,張量可以用來獲取計算結果,得到真實的數字。(利用Session)
三、TF運行模型----會話
會話用來執行定義好的計算。會話可以調用和管理TF的所有資源。會話用完后需要關閉釋放資源。
會話的模式有兩種:
第一種、顯式調用會話生成函數和關閉會話函數。
#創建一個會話 sess = tf.Session() #運行會話得到計算結果 sess.run(result) #關閉會話,釋放資源 sess.close()
第二種,運用上下文管理器來使用會話
with tf.Session() as session:
session.run(result)
設置默認會話
TF可以手動指定默認的會話,當默認的會話被指定之后可以通過tf.Tensor.eval函數來計算一個張量的取值。
以下兩種代碼均可以完成這種功能。
import tensorflow as tf a = tf.constant([1.0,2.0],name="a") b = tf.constant([1.0,3.0],name="b") result = a+b #方法一 sess = tf.Session() with sess.as_default(): print(result.eval()) #方法二 sess = tf.Session() print(sess.run(result)) print(result.eval(session=sess))
設置交互式默認會話
在交互環境下,通過設置默認會話的方式來獲取張量的取值更方便。TF提供了在交互環境下直接構建默認會話的函數。這個函數就是tf.InteractiveSession。可以省略將會話注冊為默認會話的過程
sess = tf.InteractiveSession() print(result.eval()) sess.close()
通過ConfigProto Protocol Buffer 來配置需要生成的會話。
config = tf.ConfigProto(allow_soft_placement = True,log_device_placement = True) sess1 = tf.Session(config=config) sess2 = tf.InteractiveSession(config=config)
ConfigProto的功能:配置類似並行的線程數、GPU分配策略、運行超時時間參數等。
第一個常用的參數allow_soft_placement。為True的時候,在某些條件成立時下,GPU運算可以放在CPU上進行;
第二個常用參數log_device_placement。當為True的時候,日志會記錄每個節點被安排在哪個節點上以方便調試。生產環境中設為False,以減少日志量。
四、TF實現神經網絡
4.1神經網絡簡介
使用神經網絡解決分類問題主要有以下四個步驟:
1、提取問題中實體的特征向量作為神經網絡的輸入。
2.定義神經網絡的結構,並定義如何從神經網絡的輸入得到輸出。這就是神經網絡的前向傳播算法。
3.通過訓練數據來調整神經網絡中參數的取值,這就是訓練神經網絡的過程。主要利用反向傳播算法。
4.使用訓練好的神經網絡來預測未知的數據。
4.2 前向傳播算法簡介以及TF實現前向傳播算法。
將輸入x1和x2組織成一個1X2的矩陣x = [x1,x2],而w1組織成一個2X3的矩陣:
TF實現前向傳播
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
其中malmul函數實現了矩陣乘法的功能。
4.3 神經網絡參數與TensorFlow變量
TF聲明一個2X3矩陣變量的方法:
weights = tf.Variable(tf.random_normal([2,3],stddev =2))
其中tf.random_normal([2,3],stddev =2會產生一個2X3的矩陣,矩陣中元素均值為0,標准差為2的隨機數。
TF支持的隨機數生成器
TF也支持通過常數來初始化變量。
bias(偏置項)通常會使用常數來初始化。
baises = tf.Variable(tf.zeros([3]))
TF還支持通過其他其他變量的初始值來初始化新的變量
w2 = Variable(weights.initiialized_values() )
w3 = Variable(weights.initiialized_values() *2.0 )
一個前向傳播算法的樣例:
import tensorflow as tf #聲明w1,w2 兩個變量,通過seed設定隨機種子 w1 = tf.Variable(tf.random_normal([2,3],stddev=1.0 ,seed =1 )) w2 = tf.Variable(tf.random_normal([3,1],stddev=1.0 ,seed =1 )) #暫時將輸入的謄正向量定義為一個常量,這里的X是一個【1,2】矩陣 x = tf.constant([[0.7,0.9]]) #通過前向傳播算法得到輸出y hd = tf.matmul(x,w1) y = tf.matmul(hd,w2) sess = tf.Session() #初始化w1和w2 sess.run(w1.initializer) sess.run(w2.initializer) print(sess.run(y)) sess.close()
這里調用變量的初始化過程比較麻煩,TF提供了一種便捷的方法:initialize_all_variables()
init_op = tf.initialize_all_variables()
sess.run(init_op)
4.4 通過TensorFlow訓練神經網絡模型
網絡訓練的流程圖
為了避免大量的存放輸入的常量,可以用placeholder
import tensorflow as tf #聲明w1,w2 兩個變量,通過seed設定隨機種子 w1 = tf.Variable(tf.random_normal([2,3],stddev=1.0 ,seed =1 )) w2 = tf.Variable(tf.random_normal([3,1],stddev=1.0 ,seed =1 )) #用placeholder定義存放輸入數據的地方,維度可以不用定義,但維度確定,可減少出錯率 x = tf.placeholder(tf.float32,shape=(1,2),name= 'input') #通過前向傳播算法得到輸出y hd = tf.matmul(x,w1) y = tf.matmul(hd,w2) sess = tf.Session() #初始化w1和w2 init_op = tf.global_variables_initializer() sess.run(init_op) #計算過程,需要feed_dict來制定x的值 print(sess.run(y,feed_dict={x:[[0.7,0.9]]})) sess.close()
定義反向傳播算法
#定義損失函數來刻畫預測值和真實值的差距 cross_entropy = tf.reduce_mean(y* tf.log(tf.clip_by_value(y,1e-10,1.0))) #定義學習率 learning_rate = 0.001 #定義反向傳播算法來優化神經網絡中的參數 train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy) sess.run(train_step)
4.5跑一個完整的NN的樣例
在模擬數據集上訓練神經網絡,實現一個二分類的問題
import tensorflow as tf from numpy import random as rd #定義batch的大小 batch_size = 8 #定義神經網絡的參數 w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1)) # shape的一個維度用None方便使用不大的batch。在訓練時需要把數據分成較少的batch,測試時可以一次性使用全部數據 x = tf.placeholder(tf.float32,shape=(None,2),name='x_input') y_ = tf.placeholder(tf.float32,shape=(None,1),name='y_input') #學習率 lr = 0.001 #定義前向傳播過程 a = tf.matmul(x,w1) y = tf.matmul(a,w2) # 定義loss和bp cross_entropy = -tf.reduce_mean(y_* tf.log(tf.clip_by_value(y,1e-10,1))) train_step = tf.train.AdamOptimizer(lr).minimize(cross_entropy) #生成模擬數據集 rdm = rd.RandomState(1) dataset_size = 128 X = rdm.rand(dataset_size,2) Y = [[int(x1+x2 < 1)] for( x1,x2) in X ] print(X,Y) #創建會話來運行TF with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) print(sess.run(w1)) print(sess.run(w2)) #設定訓練次數 epho = 5000 for i in range(epho): #每次選取batch個樣本進行訓練 start = i*batch_size % dataset_size end = min(start + batch_size,dataset_size) #用樣本訓練神經網絡,更新參數 sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]}) if i %1000 ==0: #每隔一段時間計算在所有數據上的交叉熵斌輸出 total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y}) print("After %s epho ,total_cross_entropy is %s"%(i,total_cross_entropy)) print(sess.run(w1)) print(sess.run(w2))