TensorFlow 2.0 | Tensor的維度變換整理

 

目錄

1. 張量變形(reshape)

2. 維度增減

2.1 維度增加(expand_dims)

2.2 維度刪除(squeeze)

3. 維度交換(transpose)

4. 張量合併

4.1 張量拼接(concat)

4.2 張量堆疊(stack)

5. 張量分割(split)


神經網絡搭建過程中,維度變換是最重要的操作之一,通過切換數據形式,從而滿足不同場景的運算需求。本文對所有維度處理的方式進行了整理。

1. 張量變形(reshape)

在總數據量不變的情況下,將其變換爲不同的組合形式,且將此數據平鋪時排列順序不改變

舉個例子:

>>> import tensorflow as tf
>>> x = tf.range(24)	# 生成一組連續整數向量
>>> x = tf.reshape(x, [2, 3, 4])	# 改變x的視圖,得到3D張量
>>> x
<tf.Tensor: id=11, shape=(2, 3, 4), dtype=int32, numpy=
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])>
>>> y = tf.reshape(x, [3, 2, 2, 2])    # 將x變形爲4D張量
>>> y
<tf.Tensor: id=13, shape=(3, 2, 2, 2), dtype=int32, numpy=
array([[[[ 0,  1],
         [ 2,  3]],

        [[ 4,  5],
         [ 6,  7]]],


       [[[ 8,  9],
         [10, 11]],

        [[12, 13],
         [14, 15]]],


       [[[16, 17],
         [18, 19]],

        [[20, 21],
         [22, 23]]]])>

數據在創建時按着初始的維度順序寫入,改變張量的視圖僅僅是改變了張量的理解方式,並不需要改變張量的存儲順序,張量只需要滿足新視圖的元素總量與存儲區域大小相等即可

像上面:2∗3∗4=3∗2∗2∗22*3*4 = 3*2*2*22∗3∗4=3∗2∗2∗2,總量沒變;且張量的存儲順序始終沒有改變,數據仍是按照0,1,2,...,230,1,2,...,230,1,2,...,23的順序保存

 

2. 維度增減

2.1 維度增加(expand_dims)

增加一個長度爲 1 的維度相當於給原有的數據添加一個新維度的概念,因爲維度長度爲 1,所以數據並沒有改變

舉個例子:

>>> x = tf.random.normal([5, 5])	# 建立正態隨機數據
>>> x
<tf.Tensor: id=19, shape=(5, 5), dtype=float32, numpy=
array([[ 0.4133979 ,  1.0672395 ,  2.5727544 , -0.0975351 ,  0.73670894],
       [-1.429659  , -0.3630027 , -0.11651681, -1.108655  ,  1.494843  ],
       [ 2.884822  , -0.3095457 , -0.6037164 ,  2.190964  , -0.38418463],
       [ 1.1569734 ,  0.1284009 , -0.24746007,  0.17708912,  0.4348358 ],
       [ 0.06045027, -0.9997665 , -0.43566772, -0.56748384, -1.4990594 ]],
      dtype=float32)>
>>> y = tf.expand_dims(x, axis=2)	# 在特定位置增加維度
>>> y
<tf.Tensor: id=21, shape=(5, 5, 1), dtype=float32, numpy=
array([[[ 0.4133979 ],
        [ 1.0672395 ],
        [ 2.5727544 ],
        [-0.0975351 ],
        [ 0.73670894]],

       [[-1.429659  ],
        [-0.3630027 ],
        [-0.11651681],
        [-1.108655  ],
        [ 1.494843  ]],

       [[ 2.884822  ],
        [-0.3095457 ],
        [-0.6037164 ],
        [ 2.190964  ],
        [-0.38418463]],

       [[ 1.1569734 ],
        [ 0.1284009 ],
        [-0.24746007],
        [ 0.17708912],
        [ 0.4348358 ]],

       [[ 0.06045027],
        [-0.9997665 ],
        [-0.43566772],
        [-0.56748384],
        [-1.4990594 ]]], dtype=float32)>

插入一個新維度後,數據的存儲順序並沒有變化,只改變了數據的視圖

2.2 維度刪除(squeeze)

是增加維度的逆操作,只能刪除長度爲 1 的維度,也不會改變張量的存儲

舉個例子(接上一節數據):

>>> z = tf.squeeze(y, axis=2)
>>> z
<tf.Tensor: id=22, shape=(5, 5), dtype=float32, numpy=
array([[ 0.4133979 ,  1.0672395 ,  2.5727544 , -0.0975351 ,  0.73670894],
       [-1.429659  , -0.3630027 , -0.11651681, -1.108655  ,  1.494843  ],
       [ 2.884822  , -0.3095457 , -0.6037164 ,  2.190964  , -0.38418463],
       [ 1.1569734 ,  0.1284009 , -0.24746007,  0.17708912,  0.4348358 ],
       [ 0.06045027, -0.9997665 , -0.43566772, -0.56748384, -1.4990594 ]],
      dtype=float32)>

如果不指定維度參數 axis,那麼它會默認刪除所有長度爲 1 的維度,例如:

>>> w = tf.squeeze(y)
>>> w
<tf.Tensor: id=23, shape=(5, 5), dtype=float32, numpy=
array([[ 0.4133979 ,  1.0672395 ,  2.5727544 , -0.0975351 ,  0.73670894],
       [-1.429659  , -0.3630027 , -0.11651681, -1.108655  ,  1.494843  ],
       [ 2.884822  , -0.3095457 , -0.6037164 ,  2.190964  , -0.38418463],
       [ 1.1569734 ,  0.1284009 , -0.24746007,  0.17708912,  0.4348358 ],
       [ 0.06045027, -0.9997665 , -0.43566772, -0.56748384, -1.4990594 ]],
      dtype=float32)>

3. 維度交換(transpose)

前面的操作都不會影響張量的存儲,而交換維度操作可以改變張量的存儲順序,同時也改變了張量的視圖

舉個例子:

>>> x = tf.random.normal([2, 3])
>>> x
<tf.Tensor: id=44, shape=(2, 3), dtype=float32, numpy=
array([[ 1.5357795 , -1.3758559 ,  0.6500945 ],
       [-0.6790089 ,  0.04826049,  0.8853354 ]], dtype=float32)>
>>> y = tf.transpose(x, perm=[1, 0])	# 將0維度與1維度互換
>>> y
<tf.Tensor: id=46, shape=(3, 2), dtype=float32, numpy=
array([[ 1.5357795 , -0.6790089 ],
       [-1.3758559 ,  0.04826049],
       [ 0.6500945 ,  0.8853354 ]], dtype=float32)>

4. 張量合併

將多個張量在某個維度上合併爲一個張量,可以使用拼接和堆疊操作實現,拼接操作並不會產生新的維度,僅在現有的維度上合併,而堆疊會創建新維度。

4.1 張量拼接(concat)

>>> import tensorflow as tf
>>> a = tf.constant([[1, 2, 3], [4, 5, 6]])
>>> b = tf.constant([[7, 8, 9], [10, 11, 12]])
>>> c1 = tf.concat([a, b], 0)
>>> c1
<tf.Tensor: id=3, shape=(4, 3), dtype=int32, numpy=
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])>
>>> c2 = tf.concat([a, b], 1)
>>> c2
<tf.Tensor: id=7, shape=(2, 6), dtype=int32, numpy=
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])>

4.2 張量堆疊(stack)

>>> z1 = tf.stack([a, b])	# axis默認爲 0
>>> z1
<tf.Tensor: id=12, shape=(2, 2, 3), dtype=int32, numpy=
array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [10, 11, 12]]])>
>>> z2 = tf.stack([a, b],axis=-1)
>>> z2
<tf.Tensor: id=13, shape=(2, 3, 2), dtype=int32, numpy=
array([[[ 1,  7],
        [ 2,  8],
        [ 3,  9]],

       [[ 4, 10],
        [ 5, 11],
        [ 6, 12]]])>

5. 張量分割(split)

>>> x = tf.random.normal([10,35,8])
>>> result1 = tf.split(x, num_or_size_splits=10, axis=0)
>>> len(result1)
10
>>> result1[0].shape
TensorShape([1, 35, 8])
>>> result2 = tf.split(x, num_or_size_splits=[4,2,2,2], axis=0)
>>> len(result2)
4
>>> result2[1].shape
TensorShape([2, 35, 8])

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章