Tensorflow快餐教程(4) - 矩陣

weixin_34221276發表於2018-04-24

矩陣

矩陣的初始化

矩陣因為元素更多,所以初始化函式更多了。光靠tf.linspace,tf.range之類的線性生成函式已經不夠用了。

可以通過先生成一個線性序列,然後再reshape成一個矩陣的方式來初始化。

例:

>>> g1 = tf.linspace(1.0,10.0,16)
>>> g1
<tf.Tensor 'LinSpace_6:0' shape=(16,) dtype=float32>
>>> g2 = tf.constant(sess.run(tf.reshape(g1,[4,4])))
>>> sess.run(g2)
array([[ 1.       ,  1.6      ,  2.2      ,  2.8000002],
       [ 3.4      ,  4.       ,  4.6000004,  5.2000003],
       [ 5.8      ,  6.4      ,  7.       ,  7.6000004],
       [ 8.200001 ,  8.8      ,  9.400001 , 10.       ]], dtype=float32)
>>> g2
<tf.Tensor 'Const_29:0' shape=(4, 4) dtype=float32>

tf.linspace生成了(16,)的一個向量,然後被reshape成(4,4)的矩陣。

生成全0值的矩陣

tf.zeros可以生成全0的矩陣,不指定型別時,預設為float32.

>>> g7 = tf.zeros([4,5])
>>> sess.run(g7)
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]], dtype=float32)

可以指定資料型別:

>>> g8 = tf.zeros([10,10],dtype=tf.int32)
>>> sess.run(g8)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32)

生成全1的矩陣

類似地,我們可以用tf.ones生成值全為1的矩陣。
例:

>>> g9 = tf.ones([8,2],dtype=tf.int64)
>>> sess.run(g9)
array([[1, 1],
       [1, 1],
       [1, 1],
       [1, 1],
       [1, 1],
       [1, 1],
       [1, 1],
       [1, 1]])

將矩陣全部設成一個值

tf.ones和tf.zeros其實是特例,tf.fill才是更通用的功能:

>>> g10 = tf.fill([5,5],10.1)
>>> sess.run(g10)
array([[10.1, 10.1, 10.1, 10.1, 10.1],
       [10.1, 10.1, 10.1, 10.1, 10.1],
       [10.1, 10.1, 10.1, 10.1, 10.1],
       [10.1, 10.1, 10.1, 10.1, 10.1],
       [10.1, 10.1, 10.1, 10.1, 10.1]], dtype=float32)

生成對角矩陣

矩陣一個特點是經常是隻有稀疏的值。最常用的就是對角陣,只有一條對角線上有值。
例:

>>> g11 =tf.diag([1,1,2,2])
>>> sess.run(g11)
array([[1, 0, 0, 0],
       [0, 1, 0, 0],
       [0, 0, 2, 0],
       [0, 0, 0, 2]], dtype=int32)

除了生成對角陣,我們還可以從一個矩陣中將對角線值獲取成一個向量:

>>> g12 = tf.diag_part(g11)
>>> sess.run(g12)
array([1, 1, 2, 2], dtype=int32)
>>> g12
<tf.Tensor 'DiagPart:0' shape=(4,) dtype=int32>

隨機生成初始化值

除了全0,全1,全確定值和對角線值,還有一種非常常用的方式就是生成隨機值。
我們可以按正態分佈來生成初始值:

>>> g13 = tf.random_normal([5,5])
>>> sess.run(g13)
array([[ 0.21010283,  1.083522  , -2.1688387 , -1.2340024 ,  0.9230036 ],
       [ 0.43592915, -0.7187195 , -1.3310403 ,  0.27570882,  1.3831469 ],
       [-0.42430717,  2.8005996 ,  1.1899991 ,  0.6987934 ,  1.6732428 ],
       [ 0.4975314 , -1.259698  ,  1.2508341 , -1.2581793 , -0.8776101 ],
       [ 0.49039882,  0.8129552 ,  1.2836359 , -0.3732389 , -2.034603  ]],
      dtype=float32)

可以指定平均值和標準差,預設均值為0,標準差為1。預設的型別為float32,反正不支援整數。

例:

>>> g14 = tf.random_normal([3,8], mean=1.0, stddev=2.0, dtype=tf.float32)
>>> sess.run(g14)
array([[ 3.7580974 , -2.7150466 , -2.107638  ,  1.7130036 , -0.8702172 ,
        -1.0325654 ,  3.1230848 , -0.82150674],
       [-1.3860679 ,  0.03262603, -0.63146615, -0.71946084,  1.182011  ,
         0.34882843,  2.3536258 , -1.0503623 ],
       [-3.6498313 ,  0.4458651 ,  2.9859743 ,  2.153699  ,  3.8967788 ,
         1.895072  ,  3.5918627 ,  1.9855003 ]], dtype=float32)

矩陣的轉置

將矩陣中的元素基於對角線對稱交換,叫做矩陣的轉置transpose。

例:

>>> g3 = tf.transpose(g2)
>>> g3
<tf.Tensor 'transpose_1:0' shape=(4, 4) dtype=float32>
>>> sess.run(g3)
array([[ 1.       ,  3.4      ,  5.8      ,  8.200001 ],
       [ 1.6      ,  4.       ,  6.4      ,  8.8      ],
       [ 2.2      ,  4.6000004,  7.       ,  9.400001 ],
       [ 2.8000002,  5.2000003,  7.6000004, 10.       ]], dtype=float32)

1,4,7,10是對角線,在轉置時保持不變。

在非方陣的情況下,轉置後對角線仍然保持不變。
我們看一個2*3矩陣的例子:

>>> g4 = tf.linspace(1.0,10.0,6)
>>> g5 = tf.reshape(g4,[2,3])
>>> sess.run(g5)
array([[ 1.       ,  2.8      ,  4.6      ],
       [ 6.3999996,  8.2      , 10.       ]], dtype=float32)

對角線是1和8.2.
我們轉置一下:

>>> g6 = tf.constant(sess.run(tf.transpose(g5)))
>>> sess.run(g6)
array([[ 1.       ,  6.3999996],
       [ 2.8      ,  8.2      ],
       [ 4.6      , 10.       ]], dtype=float32)

雖然從一個寬矩陣變成了高矩陣,但是對角線仍然是1和8.2.

矩陣的數學運算

加減運算

兩個行列相同的矩陣可以進行加減運算。
例:

>>> h01 = tf.random_normal([4,4])
>>> h02 = tf.fill([4,4],1.0)
>>> h03 = h01 + h02
>>> sess.run(h03)
array([[ 1.959749  ,  1.2833667 ,  0.12137735,  1.0297428 ],
       [ 1.3971953 , -0.0582509 ,  1.1770982 ,  2.154177  ],
       [-1.1314301 ,  1.6063341 , -1.2442939 ,  1.2752731 ],
       [ 1.3077021 ,  0.42679614,  2.9681108 ,  1.6179581 ]],
      dtype=float32)

廣播運算

例:

>>> h04 = h02 + 2.0
>>> sess.run(h04)
array([[3., 3., 3., 3.],
       [3., 3., 3., 3.],
       [3., 3., 3., 3.],
       [3., 3., 3., 3.]], dtype=float32)

矩陣乘積

"*"運算在矩陣乘法中,跟上節所講一樣,還是Hadamard積,就是對應元素的積,例:

>>> h05 = tf.reshape(tf.linspace(1.0,10.0,16),[4,4])
>>> sess.run(h05)
array([[ 1.       ,  1.6      ,  2.2      ,  2.8000002],
       [ 3.4      ,  4.       ,  4.6000004,  5.2000003],
       [ 5.8      ,  6.4      ,  7.       ,  7.6000004],
       [ 8.200001 ,  8.8      ,  9.400001 , 10.       ]], dtype=float32)
>>> h06 = tf.reshape(tf.linspace(1.0,16.0,16),[4,4])
>>> sess.run(h06)
array([[ 1.,  2.,  3.,  4.],
       [ 5.,  6.,  7.,  8.],
       [ 9., 10., 11., 12.],
       [13., 14., 15., 16.]], dtype=float32)
>>> sess.run(h05 * h06)
array([[  1.       ,   3.2      ,   6.6000004,  11.200001 ],
       [ 17.       ,  24.       ,  32.200005 ,  41.600002 ],
       [ 52.2      ,  64.       ,  77.       ,  91.200005 ],
       [106.600006 , 123.200005 , 141.00002  , 160.       ]],
      dtype=float32)

我們也可以用matmul函式,或者"@"運算子計算矩陣相乘的結果:

>>> h05 @ h06
<tf.Tensor 'matmul:0' shape=(4, 4) dtype=float32>
>>> sess.run(h05 @ h06)
array([[ 65.200005,  72.8     ,  80.40001 ,  88.      ],
       [132.40001 , 149.6     , 166.80002 , 184.      ],
       [199.6     , 226.40002 , 253.20001 , 280.      ],
       [266.8     , 303.2     , 339.60004 , 376.      ]], dtype=float32)

"@"是高版本Python中支援的操作,在tensorflow中過載它的函式為matmul。

逆矩陣 Inverse Matrices

定義I為單位對角矩陣,如果BA=I,那麼我就說B是A的逆矩陣。可以通過matrix_inverse函式來獲得逆矩陣,例:

>>> i01 = tf.diag([1.0,2.0,3.0,4.0])
>>> sess.run(i01)
array([[1., 0., 0., 0.],
       [0., 2., 0., 0.],
       [0., 0., 3., 0.],
       [0., 0., 0., 4.]], dtype=float32)
>>> i01_rev = tf.matrix_inverse(i01)
>>> sess.run(i01_rev)
array([[1.        , 0.        , 0.        , 0.        ],
       [0.        , 0.5       , 0.        , 0.        ],
       [0.        , 0.        , 0.33333334, 0.        ],
       [0.        , 0.        , 0.        , 0.25      ]], dtype=float32)

我們來驗算一下i01_rev與i01相乘是不是單位矩陣:

>>> sess.run( i01_rev @ i01)
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]], dtype=float32)

果然是。

對角陣比較特殊,還滿足交換律:

>>> sess.run( i01 @ i01_rev)
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]], dtype=float32)

求行列式的值以判斷是否有逆矩陣

我們學習線性代數知道,如果一個矩陣要想有逆矩陣,它的行列式一定不能為0。

在Matlab和mathematica兩大著名數學軟體中,求行列式的函式名字很簡單,就是det。
Tensorflow因為是個庫,所以名字比較長,叫tf.matrix_determinant.

我們來看一個例子:

>>> A1 = [[1,1,1],[1,-1,-1],[5,-2,2]]
>>> A = tf.constant(A1, tf.float32)
>>> A
<tf.Tensor 'Const_3:0' shape=(3, 3) dtype=float32>
>>> sess.run(A)
array([[ 1.,  1.,  1.],
       [ 1., -1., -1.],
       [ 5., -2.,  2.]], dtype=float32)
>>> d = tf.matrix_determinant(A)
>>> sess.run(d)
-8.0

利用逆矩陣求解線性方程組

假設有下列方程組,求解:

x+y+z =1,
x-y-z = 2,
5x-2y+2z = 3

這個題中的係數矩陣就是我們剛才例子中的矩陣,我們已經求得行列式值為-8不等於0,所以我們可以通過用係數矩陣的逆矩陣乘以常數向量的方式求解。

>>> b = tf.constant([[1],[2],[3]],dtype=tf.float32)
>>> b
<tf.Tensor 'Const_4:0' shape=(3, 1) dtype=float32>
>>> sess.run(b)
array([[1.],
       [2.],
       [3.]], dtype=float32)
>>> sess.run(tf.matmul(tf.matrix_inverse(A),b))
array([[ 1.5000001],
       [ 0.875    ],
       [-1.3750001]], dtype=float32)

最後求得,x=1.5, y=0.875, z = -1.375.

相關文章