改變形狀
通過 tf.reshape(x, new_shape)
,可以對張量的視圖進行任意的合法改變
x=tf.range(96)
x=tf.reshape(x,[2,4,4,3])
增刪維度
增加維度:增加一個長度爲 1 的維度相當於給原有的數據增加一個新維度的概念,維度長度爲 1,故數據並不需要改變,僅僅是改變數據的理解方式,因此它其實可以理解爲改變視圖的一種特殊方式。通過 tf.expand_dims(x, axis)
可在指定的 axis 軸前可以插入一個新的維度:
x = tf.random.uniform([28,28],maxval=10,dtype=tf.int32)
x = tf.expand_dims(x,axis=2)
刪除維度:是增加維度的逆操作,與增加維度一樣,刪除維度只能刪除長度爲 1 的維度,也不會改變張量的存儲。如果希望將圖片數量維度刪除,可以通過 tf.squeeze(x, axis)
函數,axis 參數爲待刪除的維度的索引號。
x = tf.random.uniform([1,28,28,1],maxval=10,dtype=tf.int32)
tf.squeeze(x,axis=0)
當 axis = None
時,代表刪除任意長度爲 1 的維度。
交換維度
改變視圖、增刪維度都不會影響張量的存儲。在實現算法邏輯時,在保持維度順序不變的條件下,僅僅改變張量的理解方式是不夠的,有時需要直接調整的存儲順序,即交換維度(Transpose)。通過交換維度,改變了張量的存儲順序,同時也改變了張量的視圖。使用 tf.transpose(x, perm)
函數完成維度交換操作,其中 perm 表示新維度的順序 List。
x = tf.random.normal([2,32,32,3])
tf.transpose(x,perm=[0,2,1,3])
數據複製
通過 tf.tile(x, multiples)
函數可以指定數據在指定維度上的複製操作,multiples 爲每個維度上面的複製倍數的 List,對應位置爲 1 表明不復制,爲 n 表示複製爲原來的 n 倍,也就是該維度長度會變爲原來的 n 倍。
x = tf.range(4)
x = tf.reshape(x,[2,2])
x = tf.tile(x,multiples=[3,2])
廣播機制
Broadcasting 也叫廣播機制(自動擴展也許更合適),它是一種輕量級張量複製的手段,在邏輯上擴展張量數據的形狀,但是只要在需要時纔會執行實際存儲複製操作。對於大部分場景,Broadcasting 機制都能通過優化手段避免實際複製數據而完成邏輯運算,從而相對於 tf.tile
函數,減少了大量計算代價。
Broadcasting 實際上效果等同於對於長度爲 1 的維度執行 tf.tile
複製操作,都能在此維度上邏輯複製數據若干份,區別在於 tf.tile
會創建一個新的張量,執行復制 IO 操作,並保存複製後的張量數據, Broadcasting 並不會立即複製數據,它會邏輯上改變張量的形狀,使得視圖上變成了複製後的形狀。Broadcasting 會通過深度學習框架的優化手段避免實際複製數據而完成邏輯運算,至於怎麼實現的用戶不必關係,對於用於來說,Broadcasting 和 tf.tile
複製的最終效果是一樣的,操作對用戶透明,但是 Broadcasting 機制節省大量計算資源,建議在運算過程中儘可能地利用 Broadcasting 提高計算效率。
最簡單和最常見的情況是,將標量與張量相乘或相加時。在這種情況下,標量將廣播爲與其他參數相同的形狀:
x = tf.constant([1, 2, 3])
y = tf.constant(2)
z = tf.constant([2, 2, 2])
# All of these are the same computation
print(tf.multiply(x, 2))
print(x * y)
print(x * z)
結果爲:
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
同樣,可以拉伸大小爲 1 的維度以匹配其他參數。在同一計算中可以拉伸兩個參數。
以下爲例,3x1 矩陣乘以 1x4 矩陣以生成 3x4 矩陣。請注意前導 1 是可選的:y 的形狀是 [4] 或 [1,4]。
# These are the same computations
x = tf.reshape(x,[3,1])
y = tf.range(1, 5)
print(x, "\n")
print(y, "\n")
print(tf.multiply(x, y))
結果爲:
tf.Tensor(
[[1]
[2]
[3]], shape=(3, 1), dtype=int32)
tf.Tensor([1 2 3 4], shape=(4,), dtype=int32)
tf.Tensor(
[[ 1 2 3 4]
[ 2 4 6 8]
[ 3 6 9 12]], shape=(3, 4), dtype=int32)
圖片示意如下:
與以下不使用廣播的效果一樣:
x_stretch = tf.constant([[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])
y_stretch = tf.constant([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
print(x_stretch * y_stretch) # Again, operator overloading
結果爲:
tf.Tensor(
[[ 1 2 3 4]
[ 2 4 6 8]
[ 3 6 9 12]], shape=(3, 4), dtype=int32)
也就是說進行張量計算時需要全部參數或者說全部的張量的維度一致,然後相同位置的元素執行操作。