需要理解在TensorFlow中,是如何:
- 將計算流程表示成圖;
- 通過Sessions來執行圖計算;
- 將數據表示爲tensors;
- 使用Variables來保持狀態信息;
- 分別使用feeds和fetches來填充數據和抓取任意的操作結果;
接下來看具體概念:
- TensorFlow 用圖來表示計算任務,圖中的節點被稱之爲operation,縮寫成op。
- 一個節點獲得 0 個或者多個張量 tensor,執行計算,產生0個或多個張量。
圖必須在會話(Session)裏被啓動,會話(Session)將圖的op分發到CPU或GPU之類的設備上,同時提供執行op的方法,這些方法執行後,將產生的張量(tensor)返回。
概念描述
張量(Tensor)
其實就是指矩陣。也可以理解爲tensorflow中矩陣的表示形式。Tensor的生成方式有很多種,最簡單的就如
port tensorflow as tf # 在下面所有代碼中,都去掉了這一行,默認已經導入
a = tf.zeros(shape=[1,2])
不過要注意,因爲在訓練開始前,所有的數據都是抽象的概念,也就是說,此時a只是表示這應該是個1*5的零矩陣,而沒有實際賦值,也沒有分配空間,所以如果此時print,就會出現如下情況:
print(a) #===>Tensor("zeros:0",shape=(1, 2), dtype=float32)
只有在訓練過程開始後,才能獲得a的實際值
sess = tf.InteractiveSession()
print(sess.run(a))
#===>[[ 0. 0.]]
這邊設計到Session概念,後面會提到
變量(Variable)
一般用來表示圖中的各計算參數,包括矩陣,向量等。例如,要表示線性相關的數據模型,那表達式就是
y=Relu(Wx+b)
這裏W和b是要用來訓練的參數,Relu()是激活函數,那麼此時這兩個值就可以用Variable來表示。Variable的初始函數有很多其他選項,這裏先不提,只輸入一個Tensor也是可以的
W = tf.Variable(tf.zeros(shape=[1,2]))
注意,此時W一樣是一個抽象的概念,而且與Tensor不同,Variable必須初始化以後纔有具體的值。
tensor = tf.zeros(shape=[1,2])
variable = tf.Variable(tensor)
sess = tf.InteractiveSession()
#print(sess.run(variable)) # 會報錯
sess.run(tf.initialize_all_variables())
# 對variable進行初始化
print(sess.run(variable))
#===>[[ 0. 0.]]
佔位符(placeholder)
是一個抽象的概念。用於表示輸入輸出數據的格式。告訴系統:這裏有一個值/向量/矩陣,現在沒法給你具體數值,不過在正式運行的時候會補上的!例如上式中的x和y。因爲沒有具體數值,所以只要指定尺寸即可
x = tf.placeholder(tf.float32,[1, 5],name='input')
y = tf.placeholder(tf.float32,[None,5],name='input')
上面有兩種形式,第一種x,表示輸入是一個[1,5]的橫向量。
而第二種形式,表示輸入是一個[?,5]的矩陣。那麼什麼情況下會這麼用呢?就是需要輸入一批[1,5]的數據的時候。比如我有一批共10個數據,那我可以表示成[10,5]的矩陣。如果是一批5個,那就是[5,5]的矩陣。tensorflow會自動進行批處理。
會話(Session)
session是抽象模型的實現者。爲什麼之前的代碼多處要用到session?因爲模型是抽象的嘛,只有實現了模型以後,才能夠得到具體的值。同樣,具體的參數訓練,預測,甚至變量的實際值查詢,都要用到session,看後面就知道了。
用法說明
構造階段(construction phase)
組裝計算圖
計算圖(graph):要組裝的結構。由許多操作組成。
操作(ops):接受零個或多個輸入,返回零個或多個輸出。
數據類型:主要分爲張量(tensor)、變量(variable)和常量(constant)
張量:多維array或list
創建語句:
tensor_name=tf.placeholder(type,shape, name)
placeholder叫佔位符,同樣是一個抽象的概念。用於表示輸入輸出數據的格式。告訴系統:這裏有一個值/向量/矩陣,現在沒法給出具體數值,不過在正式運行的時候會補上的!
變量:在同一時刻對圖中所有其他操作都保持靜態的數據
創建語句:
name_variable = tf.Variable(value, name)
初始化語句:
#個別變量
init_op=variable.initializer()
#所有變量
init_op=tf.initialize_all_variables()
#注意:init_op的類型是操作(ops),加載之前並不執行
更新語句:
update_op=tf.assign(variable to be updated, new_value)
常量:無需初始化的變量
創建語句:
name_constant=tf.constant(value)
執行階段(execution phase)
使用計算圖
會話:執行(launch)構建的計算圖。可選擇執行設備:單個電腦的CPU、GPU,或電腦分佈式甚至手機。
創建語句:
#常規
sess = tf.Session()
#交互
sess = tf.InteractiveSession()
#交互方式可用tensor.eval()獲取值,ops.run()執行操作
#關閉
sess.close()
執行操作:使用創建的會話執行操作
執行語句:
sess.run(op)
送值(feed):輸入操作的輸入值
語句:
sess.run([output],feed_dict={input1:value1, input2:value1})
取值(fetch):獲取操作的輸出值
語句:
#單值獲取
sess.run(one op)
#多值獲取
sess.run([a list of ops])
創建一個 Session 對象, 如果無任何創建參數, 會話構造器將啓動默認圖。
會話負責傳遞 op 所需的全部輸入,op 通常是併發執行的。
# 啓動默認圖.
sess = tf.Session()
# 調用sess 的 'run()' 方法,傳入 'product' 作爲該方法的參數,
# 觸發了圖中三個op (兩個常量 op 和一個矩陣乘法op),
# 向方法表明,希望取回矩陣乘法op 的輸出.
result = sess.run(product)
# 返回值'result' 是一個 numpy `ndarray` 對象.
print result
# ==> [[ 12.]]
# 任務完成,需要關閉會話以釋放資源。
sess.close()
下面代碼中有tf.initialize_all_variables,是預先對變量初始化,Tensorflow 的變量必須先初始化,然後纔有值!而常值張量是不需要的。即使是assign() 操作和 add() 操作,在調用 run() 之前,
它並不會真正執行賦值和相加操作。
上面的代碼定義了一個如下的計算圖:
總結一下,來一個清晰的代碼:
過程就是:建圖->啓動圖->運行取值
計算矩陣相乘:
import tensorflow as tf
# 建圖
matrix1 = tf.constant([[3.,3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
# 啓動圖
sess = tf.Session()
# 取值
result = sess.run(product)print
resultsess.close()
常用函數
算術操作函數
tf.add(x, y, name=None) 求和
tf.sub(x, y, name=None) 減法
tf.mul(x, y, name=None) 乘法
tf.div(x, y, name=None) 除法
tf.mod(x, y, name=None) 取模
tf.abs(x, name=None) 求絕對值
tf.neg(x, name=None) 取負 (y = -x).
tf.sign(x, name=None) 返回符號 y = sign(x)= -1 if x < 0; 0 if x == 0; 1 if x > 0.
tf.inv(x, name=None) 取反
tf.square(x, name=None) 計算平方 (y = x * x = x^2).
tf.round(x, name=None) 舍入最接近的整數
tf.sqrt(x, name=None) 開根號 (y = \sqrt{x} = x^{1/2}).
tf.pow(x, y, name=None) 冪次方
tf.exp(x, name=None) 計算e的次方
tf.log(x, name=None) 計算log,一個輸入計算e的ln,兩輸入以第二輸入爲底
tf.maximum(x, y, name=None) 返回最大值 (x > y ? x : y)
tf.minimum(x, y, name=None) 返回最小值 (x < y ? x : y)
數據類型轉換
tf.string_to_number(string_tensor, out_type=None, name=None) 字符串轉爲數字
tf.to_double(x, name=’ToDouble’) 轉爲64位浮點類型–float64
tf.to_float(x, name=’ToFloat’) 轉爲32位浮點類型–float32
tf.to_int32(x, name=’ToInt32’) 轉爲32位整型–int32
tf.to_int64(x, name=’ToInt64’) 轉爲64位整型–int64
tf.cast(x, dtype, name=None) 將x或者x.values轉換爲dtype
# tensor a is [1.8, 2.2],dtype=tf.float
tf.cast(a, tf.int32) ==> [1, 2] # dtype=tf.int32
矩陣操作
tf.ones | tf.zeros
tf.ones(shape,type=tf.float32,name=None)
tf.zeros([2, 3], int32)
用法類似,都是產生尺寸爲shape的張量(tensor)。
tf.ones_like | tf.zeros_like
tf.ones_like(tensor,dype=None,name=None)
tf.zeros_like(tensor,dype=None,name=None)
新建一個與給定的tensor類型大小一致的tensor,其所有元素爲1和0。
tf.fill
tf.fill(shape,value,name=None)
創建一個形狀大小爲shape的tensor,其初始值爲value
print(sess.run(tf.fill([2,3],2))) #[[2 2 2], # [2 2 2]]
tf.constant
tf.constant(value,dtype=None,shape=None,name=’Const’)
創建一個常量tensor,按照給出value來賦值,可以用shape來指定其形狀。value可以是一個數,也可以是一個list。
如果是一個數,那麼這個常亮中所有值的按該數來賦值。
如果是list,那麼len(value)一定要小於等於shape展開後的長度。賦值時,先將value中的值逐個存入。不夠的部分,則全部存入value的最後一個值。
tf.random_normal | tf.truncated_normal | tf.random_uniform
tf.random_normal(shape,mean=0.0,stddev=1.0,dtype=tf.float32,seed=None,name=None)
tf.truncated_normal(shape, mean=0.0,
stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_uniform(shape,minval=0,maxval=None,dtype=tf.float32,seed=None,name=None)
這幾個都是用於生成隨機數tensor的。尺寸是shape
random_normal: 正太分佈隨機數,均值mean,標準差stddev
truncated_normal:截斷正態分佈隨機數,均值mean,標準差stddev,不過只保留[mean-2stddev,mean+2stddev]範圍內的隨機數
random_uniform:均勻分佈隨機數,範圍爲[minval,maxval]。
tf.get_variable
get_variable(name, shape=None, dtype=dtypes.float32, initializer=None, regularizer=None, trainable=True, collections=None, caching_device=None, partitioner=None, validate_shape=True, custom_getter=None):
如果在該命名域中之前已經有名字=name的變量,則調用那個變量;如果沒有,則根據輸入的參數重新創建一個名字爲name的變量。
name: 這個不用說了,變量的名字
shape: 變量的形狀,[]表示一個數,[3]表示長爲3的向量,[2,3]表示矩陣或者張量(tensor)
dtype: 變量的數據格式,主要有tf.int32, tf.float32, tf.float64等等
initializer: 初始化工具,有tf.zero_initializer, tf.ones_initializer, tf.constant_initializer, tf.random_uniform_initializer, tf.random_normal_initializer, tf.truncated_normal_initializer等
tf.shape
tf.shape(Tensor)
Returns the shape of a tensor.返回張量的形狀。但是注意,tf.shape函數本身也是返回一個張量。而在tf中,張量是需要用sess.run(Tensor)來得到具體的值的。
tf.expand_dims
tf.expand_dims(Tensor, dim) 爲張量 +1維。
tf.pack
tf.pack(values,axis=0, name=”pack”)
Packs a list of rank-R tensors into one rank-(R+1) tensor
將一個R維張量列表沿着axis軸組合成一個R+1維的張量。
tf.concat
tf.concat(concat_dim, values, name=”concat”)
Concatenates tensors along one dimension.
將張量沿着指定維數拼接起來。
tf.sparse_to_dense
稀疏矩陣轉密集矩陣
定義爲:
def sparse_to_dense(sparse_indices, output_shape, sparse_values, default_value=0, validate_indices=True, name=None):
幾個參數的含義:
sparse_indices: 元素的座標[[0,0],[1,2]]表示(0,0),和(1,2)處有值
output_shape:得到的密集矩陣的shape
sparse_values: sparse_indices座標表示的點的值,可以是0D或者1D張量。若0D,則所有稀疏值都一樣。若是1D,則len(sparse_values)應該等於len(sparse_indices)
default_values: 缺省點的默認值
tf.random_shuffle
tf.random_shuffle(value,seed=None,name=None)
沿着value的第一維進行隨機重新排列。
tf.argmax | tf.argmin
tf.argmax(input=tensor,dimention=axis)
找到給定的張量tensor中在指定軸axis上的最大值/最小值的位置。
tf.equal
tf.equal(x, y, name=None):
判斷兩個tensor是否每個元素都相等。返回一個格式爲bool的tensor
tf.cast
cast(x, dtype, name=None)
將x的數據格式轉化成dtype.例如,原來x的數據格式是bool,那麼將其轉化成float以後,就能夠將其轉化成0和1的序列。反之也可以。
tf.matmul
用來做矩陣乘法。若a爲lm的矩陣,b爲mn的矩陣,那麼通過tf.matmul(a,b)
結果就會得到一個l*n的矩陣
不過這個函數還提供了很多額外的功能。我們來看下函數的定義:
matmul(a, b, transpose_a=False, transpose_b=False, a_is_sparse=False, b_is_sparse=False, name=None):
可以看到還提供了transpose和is_sparse的選項。
如果對應的transpose項爲True,例如transpose_a=True,那麼a在參與運算之前就會先轉置一下。
而如果a_is_sparse=True,那麼a會被當做稀疏矩陣來參與運算。
tf.reshape
reshape(tensor, shape, name=None)
顧名思義,就是將tensor按照新的shape重新排列。一般來說,shape有三種用法:
如果 shape=[-1], 表示要將tensor展開成一個list
如果 shape=[a,b,c,…] 其中每個a,b,c,…均>0,那麼就是常規用法
如果 shape=[a,-1,c,…] 此時b=-1,a,c,…依然>0。這表示tf會根據tensor的原尺寸,自動計算b的值。
其他常用操作
tf.linspace | tf.range
tf.linspace(start,stop,num,name=None)
tf.range(start,limit=None,delta=1,name=’range’)
這兩個放到一起說,是因爲他們都用於產生等差數列,不過具體用法不太一樣。
tf.linspace在[start,stop]範圍內產生num個數的等差數列。不過注意,start和stop要用浮點數表示,不然會報錯
tf.range在[start,limit)範圍內以步進值delta產生等差數列。注意是不包括limit在內的。
tf.assign
tf.assign(ref, value, validate_shape=None, use_locking=None, Name=None)
tf.assign是用來更新模型中變量的值的。ref是待賦值的變量,value是要更新的值。即效果等同於 ref = value 。
簡單實例
通過幾個例子瞭解了基本的用法。
生成三維數據後使用平面擬合
import tensorflow as tf
import numpy as np
# 用NumPy 隨機生成 100 個數據
x_data = np.float32(np.random.rand(2, 100))
y_data = np.dot([0.100, 0.200], x_data) + 0.300
# 構造一個線性模型
b = tf.Variable(tf.zeros([1]))
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0))
y = tf.matmul(W, x_data) + b
# 最小化方差
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
# 初始化變量
init = tf.initialize_all_variables()
# 啓動圖 (graph)
sess = tf.Session()
sess.run(init)
# 擬合平面
for step in xrange(0, 201):
sess.run(train)
if step % 20 == 0:
print step, sess.run(W), sess.run(b)
# 輸出結果爲:
0 [[-0.14751725 0.75113136]] [ 0.2857058]
20 [[ 0.06342752 0.32736415]] [ 0.24482927]
40 [[ 0.10146417 0.23744738]] [ 0.27712563]
60 [[ 0.10354312 0.21220125]] [ 0.290878]
80 [[ 0.10193551 0.20427427]] [ 0.2964265]
100 [[ 0.10085492 0.201565 ]] [ 0.298612]
120 [[ 0.10035028 0.20058727]] [ 0.29946309]
140 [[ 0.10013894 0.20022322]] [ 0.29979277]
160 [[ 0.1000543 0.20008542]] [ 0.29992008]
180 [[ 0.10002106 0.20003279]] [ 0.29996923]
200 [[ 0.10000814 0.20001261]] [ 0.29998815]
計算矩陣相乘
import tensorflow as tf
# 創建一個 常量op, 返回值 'matrix1' 代表這個1x2 矩陣.
matrix1 = tf.constant([[3.,3.]])
# 創建另外一個 常量op, 返回值 'matrix2' 代表這個2x1 矩陣.
matrix2 = tf.constant([[2.],[2.]])
# 創建一個矩陣乘法 matmul op , 把 'matrix1' 和 'matrix2' 作爲輸入.
# 返回值 'product' 代表矩陣乘法的結果.
product = tf.matmul(matrix1, matrix2)
計算 ‘x’ 減去 ‘a’
# 進入一個交互式 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.]
使用變量實現一個簡單的計數器
# -創建一個變量,初始化爲標量 0. 初始化定義初值
state = tf.Variable(0, name="counter")
# 創建一個op, 其作用是使 state 增加1
one = tf.constant(1)
new_value = tf.add(state,one)
update = tf.assign(state,new_value)
# 啓動圖後,變量必須先經過`初始化`(init) op 初始化, 才真正通過Tensorflow的#initialize_all_variables對這些變量賦初值
init_op = tf.initialize_all_variables()
# 啓動默認圖,運行 op
with tf.Session() as sess:
# 運行'init' op
sess.run(init_op)
# 打印 'state' 的初始值
# 取回操作的輸出內容,可以在使用 Session 對象的run() 調用 執行圖時, 傳入一些 #tensor, 這些 tensor 會幫助你取回結果.此處只取回了單個節點state,也可以在運行一次 op 時一起取回多個 tensor: result =sess.run([mul, intermed])
print sess.run(state)
# 運行 op, 更新 'state', 並打印 'state'
for_in range(3):
sess.run(update)
print sess.run(state)
# 輸出:
# 0
# 1
# 2
# 3