tensorflow的向量操作
向量
向量在程式語言中就是最常用的一維陣列。
二維陣列叫做矩陣,三維以上叫做張量。
向量雖然簡單,高效,且容易理解。但是與操作0維的標量資料畢竟還是不同的。比如向量經常用於表示一個序列,生成序列像標量一樣一個一個手工寫就不划算了。當然可以用迴圈來寫。在向量中這樣還好,如果是在矩陣或者是張量中就強烈建議不要用迴圈來做了。系統提供的函式一般都是經過高度優化的,而且可以使用GPU資源來進行加速。
我們一方面儘可能地多使用系統的函式,另一方面也不要迷信它們,程式碼優化是一個實踐的過程,可以實際比較測量一下。
快速生成向量的方法
range函式生成等差數列
tf.range函式用來快速生成一個等差數列。相當於之前我們講numpy時的np.arange函式。
原型:
tf.range(start, limit, delta=1, dtype=None, name='range')
例:
>>> b11 = tf.range(1,100,1) >>> b11 <tf.Tensor 'range:0' shape=(99,) dtype=int32> >>> sess.run(b11) array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], dtype=int32)
linspace生成浮點等差陣列
tf.linspace與tf.range的區別在於,資料型別不同。
tf.lin_space(
start,
stop,
num,
name=None
)
其中,start和stop必須是浮點數,且型別必須相同。num必須是整數。
例:
>>> a2 = tf.linspace(1.0,10.0,4) >>> a2 <tf.Tensor 'LinSpace_2:0' shape=(4,) dtype=float32> >>> sess.run(a2) array([ 1., 4., 7., 10.], dtype=float32)
拼瓷磚
就是將一段向量重複若干次。
>>> a10 = tf.range(1,4,1)
>>> sess.run(a10)
array([1, 2, 3], dtype=int32)
>>> a11 = tf.tile(a10,[3])
>>> sess.run(a11)
array([1, 2, 3, 1, 2, 3, 1, 2, 3], dtype=int32)
向量操作
將向量反序
可以使用tf.reverse函式。
原型:
tf.reverse(
tensor,
axis,
name=None
)
tensor是向量,axis軸對於向量不重要,給個[-1]就可以了。折騰軸是張量時間的事情,暫時還用不到。
>>> a2 = tf.linspace(1.0,10.0,4)
>>> a3 = tf.reverse(a2,[-1])
>>> sess.run(a3)
array([10., 7., 4., 1.], dtype=float32)
切片
切片也是向量的常用操作之一,就是取陣列的一部分。
例:
>>> a5 = tf.linspace(1.0,100.0, 10)
>>> sess.run(a5)
array([ 1., 12., 23., 34., 45., 56., 67., 78., 89., 100.],
dtype=float32)
>>> a6 = tf.slice(a5, [2],[4])
>>> sess.run(a6)
array([23., 34., 45., 56.], dtype=float32)
將來處理張量時,我們從一個矩陣切一塊,或從一個張量中切一塊,就好玩得多了。但是原理跟向量上是一樣的。
連線
tf.concat也是需要給定軸資訊的。對於兩個線性的向量,我們給0或者-1就好。
>>> a20 = tf.linspace(1.0,2.0,10)
>>> sess.run(a20)
array([1. , 1.1111112, 1.2222222, 1.3333334, 1.4444444, 1.5555556,
1.6666667, 1.7777778, 1.8888888, 2. ], dtype=float32)
>>> a21 = tf.linspace(2.0,3.0,5)
>>> sess.run(a22)
array([1. , 1.1111112, 1.2222222, 1.3333334, 1.4444444, 1.5555556,
1.6666667, 1.7777778, 1.8888888, 2. , 2. , 2.25 ,
2.5 , 2.75 , 3. ], dtype=float32)
>>> a23 = tf.concat([a20,a21],-1)
>>> sess.run(a23)
array([1. , 1.1111112, 1.2222222, 1.3333334, 1.4444444, 1.5555556,
1.6666667, 1.7777778, 1.8888888, 2. , 2. , 2.25 ,
2.5 , 2.75 , 3. ], dtype=float32)
向量計算
向量加減法
同樣長度的向量之間可以進行加減操作。
例:
>>> a40 = tf.constant([1,1])
>>> a41 = tf.constant([2,2])
>>> a42 = a40 + a41
>>> sess.run(a42)
array([3, 3], dtype=int32)
>>> a43 = a40 - a41
>>> sess.run(a43)
array([-1, -1], dtype=int32)
>>> a43
<tf.Tensor 'sub:0' shape=(2,) dtype=int32>
向量乘除標量
向量乘除標量也非常好理解,就是針對向量中的每個數都做乘除法。
例:
>>> a44 = a40 * 2
>>> sess.run(a44)
array([2, 2], dtype=int32)
>>> a45 = a44 / 2
>>> sess.run(a45)
array([1., 1.])
>>> a44
<tf.Tensor 'mul:0' shape=(2,) dtype=int32>
>>> a45
<tf.Tensor 'truediv_1:0' shape=(2,) dtype=float64>
廣播運算
如果針對向量和標量進行加減運算,也是會對向量中的每個數進行加減運算。這種操作稱為廣播操作。
例:
>>> a46 = a40 + 1
>>> sess.run(a46)
array([2, 2], dtype=int32)
>>> a46
<tf.Tensor 'add_1:0' shape=(2,) dtype=int32>
向量乘法
兩個向量相乘,預設的運算是求元素對應乘積(element-wise product),也叫做Hadamard積。
例:
>>> b1 = tf.constant([1,2])
>>> b2 = tf.constant([2,1])
>>> b3 = b1 * b2
>>> b3
<tf.Tensor 'mul_7:0' shape=(2,) dtype=int32>
>>> sess.run(b3)
array([2, 2], dtype=int32)
直接呼叫tf.multiply也是同樣的效果,例:
>>> b4 = tf.multiply(b1,b2)
>>> b4
<tf.Tensor 'Mul_2:0' shape=(2,) dtype=int32>
>>> sess.run(b4)
array([2, 2], dtype=int32)
如果要計算點積(dot product)的話,我們得提前劇透一下矩陣的內容了。
首先,用向量是沒法做矩陣計算的。
例:
>>> a21 = tf.constant([2,3])
>>> a22 = tf.constant([4,5])
>>> a21
<tf.Tensor 'Const_20:0' shape=(2,) dtype=int32>
>>> a22
<tf.Tensor 'Const_21:0' shape=(2,) dtype=int32>
這樣(2,)的形狀是向量,我們得先把它轉換成(2,1)這樣的單行矩陣,如下:
>>> a31 = tf.constant(sess.run(tf.reshape(a21,[2,1])))
>>> a32 = tf.constant(sess.run(tf.reshape(a22,[2,1])))
>>> a31
<tf.Tensor 'Const_22:0' shape=(2, 1) dtype=int32>
>>> a32
<tf.Tensor 'Const_23:0' shape=(2, 1) dtype=int32>
下面我們終於可以計算點積了,我們知道點積A.B相當於A的轉置乘以B,我們可以通過matmul函式來進行矩陣乘法。
>>> a31 = tf.matmul(a31,a32,transpose_a=True)
>>> sess.run(a31)
array([[23]], dtype=int32)
我們也可以用tf.tensordot函式來計算點積。我們剛才為什麼沒用呢?答案是tensordot要求是浮點型矩陣。
例:
第一步,需要浮點數:
>>> f01 = tf.constant([1,1],dtype=tf.float32)
>>> f02 = tf.constant([1,2],dtype=tf.float32)
第二步,reshape成單行矩陣:
>>> f11 = tf.constant(sess.run(tf.reshape(f01,[2,1])))
>>> f12 = tf.constant(sess.run(tf.reshape(f02,[2,1])))
>>> f11
<tf.Tensor 'Const_26:0' shape=(2, 1) dtype=float32>
>>> f12
<tf.Tensor 'Const_27:0' shape=(2, 1) dtype=float32>
第三步,呼叫tensordot
>>> f13 = tf.tensordot(f11,f12,2)
>>> sess.run(f13)
3.0
tf.mutiply=a*b(element-wise product)
tf.matmul=tf.tensordot(矩陣乘法)
小結
從上面我們學習的函式我們可以看到,與普通語言中提供的函式多是為一維陣列操作不同,Tensorflow中的切片、拼接等操作也是基於張量的。
當我們後面學到張量遇到困難時,不妨回來看下這一節。不管後面張量多麼複雜,其實也只是從一維向二維和多維推廣而己。
作者:Jtag特工
連結:https://www.jianshu.com/p/d7cddf6ea156
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。