在上一節中,我們安裝 TensorFlow 並運行了最簡單的應用,這節我們熟悉 TensorFlow 中的張量。
張量是 TensorFlow 的核心數據類型。數學里面也有張量的概念,但是 TensorFlow 的張量其實不一樣,更像是一個 n 維數組。
不能在常規 Python 例程中訪問張量,因此 TensorFlow API 提供了很多張量的操作函數。
張量的創建
張量是一個 n 維數組。當 $n=0$ 時它就是標量;當 $n=1$ 時它就是向量;當 $n=2$ 時它就是矩陣。
所有的張量都是 Tensor 類的實例。
張量可以包含數字、字符串和布爾類型。但是一個張量包含的的元素必須是相同類型的。
創建常數
constant 函數簽名:
constant(value, dtype=None, shape=None, name='Const', verify_shape=False)
代碼示例:
1 # 創建常數 2 t1 = tf.constant('hello world') 3 t2 = tf.constant([1, 2, 3]) 4 t3 = tf.constant([[1, 2], [3, 4]]) 5 t4 = tf.constant([6, 66, 666], tf.int16, [3], 'very_6', True) 6 7 # 發起一個會話 8 with tf.Session() as sess: 9 print(sess.run(t1)) 10 print(sess.run(t2)) 11 print(sess.run(t3)) 12 print(sess.run(t4))
b'hello world' [1 2 3] [[1 2] [3 4]] [ 6 66 666]
zeros/ones/fill
zeros 函數簽名:
zeros(shape, dtype=tf.float32, name=None)
ones 函數簽名:
ones(shape, dtype=tf.float32, name=None)
fill 函數簽名:
fill(dims, value, name=None)
代碼示例:
1 # 創建零值張量 2 t1 = tf.zeros([2]) 3 # 創建一值張量 4 t2 = tf.ones([2, 3]) 5 # 填值 6 t3 = tf.fill([3, 2], 666) 7 8 # 發起一個會話 9 with tf.Session() as sess: 10 print(sess.run(t1)) 11 print(sess.run(t2)) 12 print(sess.run(t3))
[0. 0.] [[1. 1. 1.] [1. 1. 1.]] [[666 666] [666 666] [666 666]]
創建序列
linspance 函數簽名:
linspace(start, stop, num, name=None)
range 函數簽名:
range(start, limit, delta=1, dtype=None, name='range')
range(limit, delta=1, dtype=None, name='range')
代碼示例:
1 # 創建序列 2 t1 = tf.linspace(0., 1., 10) 3 t2 = tf.range(-1., 1., delta=0.1) 4 t3 = tf.range(-2., delta=-0.5) 5 6 # 發起一個會話 7 with tf.Session() as sess: 8 print(sess.run(t1)) 9 print(sess.run(t2)) 10 print(sess.run(t3))
[0. 0.11111111 0.22222222 0.33333334 0.44444445 0.5555556 0.6666667 0.7777778 0.8888889 1. ] [-1.00000000e+00 -8.99999976e-01 -7.99999952e-01 -6.99999928e-01 -5.99999905e-01 -4.99999911e-01 -3.99999917e-01 -2.99999923e-01 -1.99999928e-01 -9.99999270e-02 7.45058060e-08 1.00000076e-01 2.00000077e-01 3.00000072e-01 4.00000066e-01 5.00000060e-01 6.00000083e-01 7.00000107e-01 8.00000131e-01 9.00000155e-01] [ 0. -0.5 -1. -1.5]
創建隨機值:正態分布
很多時候機器學習需要創建隨機值。正態分布有兩種:random_normal 和 truncated_normal。對於一般意義的正態分布,大約 95.4% 的概率會落在 2 倍標准方差的范圍之內。
random_normal 是一般意義的正態分布,有可能有小概率會選擇 2 倍標准方差的范圍之外。而 truncated_normal 會有截斷,保證所有值都落在 2 倍標准方差的范圍之內。
函數簽名:
random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
代碼示例:
1 # 創建隨機值:正態分布 2 t1 = tf.random_normal([10], dtype=tf.float64) 3 t2 = tf.random_normal([20], 0, 2, dtype=tf.float64, seed=60) 4 t3 = tf.truncated_normal([20], 0, 2, dtype=tf.float32, seed=60) 5 6 # 發起一個會話 7 with tf.Session() as sess: 8 print(sess.run(t1)) 9 print(sess.run(t2)) 10 print(sess.run(t3))
[-0.30217352 -0.01353907 0.11583214 0.7693184 -2.03386255 0.74505956 -1.57310053 1.16255292 1.87307555 1.1607303 ] [ 0.43070572 1.78930951 1.90006543 -0.08042026 -2.3744852 1.88272049 1.56724792 1.37002113 -0.12527277 4.5297854 -0.82256769 0.87545214 0.85278266 -0.14404349 0.93608167 -2.59733351 -0.33442825 1.19330448 4.15318877 -3.12805352] [ 0.74157673 -0.9606577 0.46180212 -3.2753797 0.16152781 -2.189441 -0.09013904 -2.1726682 -1.2061952 0.5147551 -3.3902223 1.843447 -0.83136135 -2.4879968 3.2793632 2.9981675 -3.217487 -0.13496129 1.7222887 -3.1599777 ]
觀察第 2 個輸出中的 4.15318877,已經超過了 2 倍標准方差(標准方差為 2),這有將近 4.6% 的概率發生。
而對於 truncated_normal 函數,不管輸出多少數,也不可能有這樣的輸出。
創建隨機值:均勻分布
random_uniform 創建最大值和最小值之間的均勻分布。
函數簽名:
random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)
代碼示例:
1 # 創建隨機值:均勻分布 2 t1 = tf.random_uniform([20], 0, 10, dtype=tf.int32, seed=66) 3 4 # 發起一個會話 5 with tf.Session() as sess: 6 print(sess.run(t1))
[0 7 5 3 2 7 7 5 1 7 9 9 0 3 0 1 4 7 3 4]
隨機打亂某張量
random_shuffle 可以對張量沿着一維方向,隨機打亂順序。
函數簽名:
random_shuffle(tensor, seed=None, name=None)
代碼示例:
1 # 隨機打亂張量(沿第一維方向) 2 t1 = tf.constant([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) 3 t2 = tf.random_shuffle(t1, seed=66) 4 5 # 發起一個會話 6 with tf.Session() as sess: 7 print(sess.run(t1)) 8 print(sess.run(t2))
[[ 1 2] [ 3 4] [ 5 6] [ 7 8] [ 9 10]] [[ 1 2] [ 5 6] [ 3 4] [ 9 10] [ 7 8]]
設置隨機種子
前面的隨機函數都有一個 seed 參數,我們其實可以直接設置,讓所有隨機函數都會用同一個隨機種子。
set_random_seed(seed)
代碼示例:
1 # 隨機種子 2 tf.set_random_seed(66)
創建張量的運算
基本的數學運算
代碼示例:
1 # 基本的數學運算 2 x1 = tf.constant([2, 2, 2]) 3 x2 = tf.constant([4, 4, 4]) 4 my_sum1 = tf.add(x1, x2) 5 my_diff1 = tf.subtract(x1, x2) 6 my_prod1 = tf.multiply(x1, x2) 7 my_quot1 = tf.divide(x1, x2) 8 # 發起一個會話 9 with tf.Session() as sess: 10 print(sess.run(my_sum1)) 11 print(sess.run(my_diff1)) 12 print(sess.run(my_prod1)) 13 print(sess.run(my_quot1)) 14 print('-' * 20) 15 # 還可以使用 Python 運算符 16 my_sum2 = x1 + x2 17 my_diff2 = x1 - x2 18 my_prod2 = x1 * x2 19 my_quot2 = x1 / x2 20 # 發起一個會話 21 with tf.Session() as sess: 22 print(sess.run(my_sum2)) 23 print(sess.run(my_diff2)) 24 print(sess.run(my_prod2)) 25 print(sess.run(my_quot2)) 26 print('-' * 20) 27 # 除和整除 28 my_quot3 = x1 / x2 29 my_quot4 = x1 // x2 30 my_quot5 = tf.divide(x1, x2) 31 my_quot6 = tf.div(x1, x2) 32 # 發起一個會話 33 with tf.Session() as sess: 34 print(sess.run(my_quot3)) 35 print(sess.run(my_quot4)) 36 print(sess.run(my_quot5)) 37 print(sess.run(my_quot6))
[6 6 6] [-2 -2 -2] [8 8 8] [0.5 0.5 0.5] -------------------- [6 6 6] [-2 -2 -2] [8 8 8] [0.5 0.5 0.5] -------------------- [0.5 0.5 0.5] [0 0 0] [0.5 0.5 0.5] [0 0 0]
湊整和比較運算
代碼示例:
1 # 湊整和比較運算 2 # 湊整 3 t = tf.constant([-1.5, -1.4, 1.4, 1.5]) 4 r1 = tf.round(t) 5 r2 = tf.rint(t) 6 r3 = tf.ceil(t) 7 r4 = tf.floor(t) 8 # 發起一個會話 9 with tf.Session() as sess: 10 print(sess.run(r1)) 11 print(sess.run(r2)) 12 print(sess.run(r3)) 13 print(sess.run(r4)) 14 print('-' * 20) 15 # 比較 16 t1 = tf.constant([1., 2.]) 17 t2 = tf.constant([1.5, 3.]) 18 my_max = tf.maximum(t1, t2) 19 my_min = tf.minimum(t1, t2) 20 t3 = tf.constant([[6., 2.], [4., -6.]]) 21 min_index = tf.argmin(t3) 22 max_index = tf.argmax(t3) 23 # 發起一個會話 24 with tf.Session() as sess: 25 print(sess.run(my_max)) 26 print(sess.run(my_min)) 27 print(sess.run(min_index)) 28 print(sess.run(max_index))
[-2. -1. 1. 2.] [-2. -1. 1. 2.] [-1. -1. 2. 2.] [-2. -2. 1. 1.] -------------------- [1.5 3. ] [1. 2.] [1 1] [0 0]
指數和對數
機器學習經常要用到指數和對數來計算概率。
1 # 指數和對數 2 x = tf.constant([0., 1., 2.]) 3 y = tf.constant([-1., -1., -1.]) 4 t1 = tf.square(x) 5 t2 = tf.squared_difference(x, y) 6 t3 = tf.sqrt(x) 7 t4 = tf.rsqrt(x) # tf.sqrt(x)的倒數 8 t5 = tf.pow(x, 3) 9 t6 = tf.exp(x) 10 t7 = tf.expm1(x) # exp(x)-1 11 t8 = tf.log(x) # ln(x) 12 t9 = tf.log1p(x) # log(x+1) 13 t10 = tf.erf(x) # 誤差函數 14 t11 = tf.erfc(x) # 互補誤差函數 15 16 # 發起一個會話 17 with tf.Session() as sess: 18 print(sess.run(t1)) 19 print(sess.run(t2)) 20 print(sess.run(t3)) 21 print(sess.run(t4)) 22 print(sess.run(t5)) 23 print(sess.run(t6)) 24 print(sess.run(t7)) 25 print(sess.run(t8)) 26 print(sess.run(t9)) 27 print(sess.run(t10)) 28 print(sess.run(t11))
[0. 1. 4.] [1. 4. 9.] [0. 1. 1.4142135] [ inf 1. 0.70710677] [0. 1. 8.] [1. 2.7182817 7.389056 ] [0. 1.7182819 6.389056 ] [ -inf 0. 0.6931472] [0. 0.6931472 1.0986123] [0. 0.8427008 0.9953223] [1. 0.1572992 0.00467773]
向量和矩陣運算
機器學習中有很多向量(一維張量)和矩陣(二維張量)的運算。
代碼示例:
1 # 向量和矩陣運算 2 # 點乘 3 t1 = tf.constant([0., 1., 2.]) 4 t2 = tf.constant([1., 2., 3.]) 5 dot0 = tf.tensordot(t1, t2, axes=0) 6 dot1 = tf.tensordot(t1, t2, axes=1) 7 # 發起一個會話 8 with tf.Session() as sess: 9 print(sess.run(dot0)) 10 print(sess.run(dot1)) 11 print('-' * 20) 12 # 矩陣乘法 13 t3 = tf.constant([[0., 1., 2.]]) 14 t4 = tf.constant([[1., 2., 3.]]) 15 dot3 = tf.matmul(t3, tf.transpose(t4)) 16 # 交叉內積 17 cross = tf.cross(t3, t4) 18 # 對角矩陣 19 t5 = tf.diag([1, 2, 3]) 20 # 跡 21 trace = tf.trace(t5) 22 # 單位矩陣 23 eye = tf.eye(4) 24 # 范數 25 t6 = tf.constant([[1., 2.], [3., 4.]]) 26 norm = tf.norm(t6) 27 # 求解Ax = b 28 A = tf.constant([[1., 1.], [2., 3.]]) 29 b = tf.constant([[10.], [23.]]) 30 x = tf.matrix_solve(A, b) 31 # 特征向量 32 t7 = tf.constant([[1., 2.], [3., 4.]]) 33 qr = tf.qr(t7) 34 # 矩陣分解 35 svd = tf.svd(t7) 36 # 發起一個會話 37 with tf.Session() as sess: 38 print(sess.run(dot3)) 39 print(sess.run(cross)) 40 print(sess.run(t5)) 41 print(sess.run(trace)) 42 print(sess.run(eye)) 43 print(sess.run(norm)) 44 print(sess.run(x)) 45 print(sess.run(qr)) 46 print(sess.run(svd)) 47 print('-' * 20) 48 # 自定義運算 49 m1 = tf.constant([[1, 2], [3, 4]]) 50 m2 = tf.constant([[5, 6], [7, 8]]) 51 e1 = tf.einsum('ij->ji', m1) 52 e2 = tf.einsum('ij,jk->ik', m1, m2) 53 # 發起一個會話 54 with tf.Session() as sess: 55 print(sess.run(e1)) 56 print(sess.run(e2))
[[0. 0. 0.] [1. 2. 3.] [2. 4. 6.]] 8.0 -------------------- [[8.]] [[-1. 2. -1.]] [[1 0 0] [0 2 0] [0 0 3]] 6 [[1. 0. 0. 0.] [0. 1. 0. 0.] [0. 0. 1. 0.] [0. 0. 0. 1.]] 5.477226 [[7.] [3.]] Qr(q=array([[-0.3162278 , -0.9486833 ], [-0.9486833 , 0.31622773]], dtype=float32), r=array([[-3.1622777 , -4.4271884 ], [ 0. , -0.63245535]], dtype=float32)) (array([5.4649854 , 0.36596614], dtype=float32), array([[ 0.4045535, -0.9145143], [ 0.9145143, 0.4045535]], dtype=float32), array([[ 0.5760484, 0.8174156], [ 0.8174156, -0.5760484]], dtype=float32)) -------------------- [[1 3] [2 4]] [[19 22] [43 50]]
總結
張量是 TensorFlow 中核心的數據類型。本文揭開了 TensorFlow 中張量的神秘面紗,包括張量的創建和張量的運算。
張量類似於 N 維數組。0 維張量就是標量,1 維張量就是向量,2 維張量就是矩陣。
我們只是熟悉了張量基本的創建和運算(很多 API 和我們熟悉的 Numpy 很類似),更多的技巧知識還需要不斷在實踐中總結和提升。