【TensorFlow2.0】(4) 维度变换、广播
各位同學好,今天我和大家分享一下TensorFlow2.0中有關數學計算的相關操作,主要內容有:?
(1) 改變維度:reshape();(2) 維度轉置:transpose();(3) 增加維度:expand_dims();(4) 減少維度:squeeze();(5) 廣播:broadcasting_to()
那我們開始吧。
1. 維度變換
假設一張圖像有四個維度: [ batch, row, width, channel ]
batch:理解為幾張圖像
row:圖像的行
width:圖像的列
channel:通道
圖像維度的表示形式也有如下幾種:
[b,28,28]? ?圖像b有28行28列
[b,28*28]? ?不考慮行列信息,考慮整個圖像的像素
[b,2,14*28]? ?將圖片分成上下兩個部分
[b,28,28,1]? ?增加一個channel通道,和第一種一樣,只是增加一個通道
都沒有改變原圖像的數據點個數,只是換了一種理解方式
1.1 重新塑造維度
改變維度: tf.reshape(tensor, shape)
根據指定的shape改變tensor的維度。不會改變原tensor的維度,需要有變量去接收。改變圖像的shape時,需要保證改變后的圖像和原圖像的數據點個數相同。
# 創建一個四維正態分布tensor
a = tf.random.normal([4,28,28,3])
# 查看形狀
a.shape
# 按指定shape改變原形狀
tf.reshape(a,[4,28*28,3]).shape
# 如果不想計算28*28可寫成-1,-1這一項自動計算
tf.reshape(a,[4,-1,3]).shape
對創建的四維tensor改變形狀,指定形狀為 [4,28*28,3],這三個軸可以理解為 [圖像, 像素, 通道],該變換,抹除了行和列的概念,變成784個像素去考慮,這時圖像失去了二維信息。
如果不想計算28*28的值,還可以使用?'-1'?代替計算,函數碰到-1會自動計算兩個數的乘積,注意,一個函數中只能出現一個-1,不然計算機不知道怎么去分配。
將原tensor從[4, 28, 28, 3],轉換到 [4, 28*28*3],抹除行和列的概念,同時抹除通道的概念。將這種shape理解為[圖像, 數據點],即有4幅圖像,每幅圖像有2352個數據點。若不想計算28*28*3,可以用-1代替計算。
a = tf.random.normal([4,28,28,3])
a.shape # 查看形狀
# 抹除通道概念。理解為4個圖像,每個圖象有2352個數據點
tf.reshape(a,[4,28*28*3]).shape
# 用-1代替計算
tf.reshape(a,[4,-1]).shape
1.2 重新排列維度
轉置: tf.transpose(tensor, perm)
tensor代表需要轉置的變量,perm代表重新排列尺寸,不指定perm,默認為全部轉置。
該方法會直接改變原圖像的尺寸,不需要新變量去接收。
# 定義一個四維tensor
a = tf.random.normal([4,3,2,1])
a.shape
# 不傳參數,全部轉置
tf.transpose(a).shape
# 指定參數,新shape的0維度放原來的0維度,新shape的2維度放原來的3維度
tf.transpose(a,perm=[0,1,3,2]).shape
若不傳參數,默認將tensor全部轉置,如在矩陣中的行列互換,從三行兩列變成兩行三列。
若指定參數,perm=[0,1,3,2] 代表重新指定排列的順序,新shape的第0個維度放原來的第0個維度,新shape的第1個維度放原來的第1個維度,新shape的第2個維度放原來的第3個維度,新shape的第3個維度放原來的第2個維度。也就是說從原來的[b,h,w,c] 變成 [b,h,c,w]
我們再看一例,加深理解。
# 從b維度轉到[4,28,28,2]
b = tf.random.normal([28,2,4,28]) # [w,c,b,h]
tf.transpose(b,perm=[2,3,0,1]).shape # [b,h,w,c]
1.3 增加維度
指定位置增加一個維度: tf.expand_dims(tensor, axis)
tensor為需要增加維度的變量;axis為在哪個軸前面增加維度
不改變原始數據,需要有新變量去接收
# 4個班級35個學生8門課
a = tf.ones([4,35,8])
# 在最前面增加一個維度
tf.expand_dims(a,axis=0).shape
# 在指定位置前面添加一個維度,在課目前加一個維度
tf.expand_dims(a,axis=2).shape
axis=0代表指定第0個軸,即班級維度,在前面添加一個軸,理解為學校維度
如果軸axis為整數時,在指定軸前面增加一個新維度;若軸axis為負數時,在指定軸后面增加一個新維度。
b = tf.zeros([4,35,8]) # 下標為(-3,-2,-1)
# 理解為,在學生維度35后面增加一個維度
tf.expand_dims(b,axis=-2).shape
# 理解為,在課目維度8后面增加一個維度
tf.expand_dims(b,axis=-1).shape
1.4 減少維度
刪除當前shape為1的維度: tf.squeeze(tensor, axis)
tensor代表需要減少維度的變量;axis代表指定刪除哪一個軸的維度,如果存在多個shape為1的軸,不指定axis時,默認刪除所有axis為1的軸。axis指定的軸必須是存在的且該軸的shape為1
不改變原數據,需要有新變量接收
# 創建一個五維tensor
a = tf.ones([1,2,1,1,3])
a.shape
# 不指定軸,默認刪除所有維度為1的軸
tf.squeeze(a).shape
# 指定刪除第0個軸
tf.squeeze(a,axis=0).shape
# 刪除倒數第2個軸
tf.squeeze(a,axis=-2).shape
2. 廣播
利用廣播將原始tensor成倍增加: tf.broadcasting_to(tensor, shape)
tensor代表需要擴張的變量,shape代表需要擴張成什么樣的
是一種張量維度擴張的手段,某一個維度重復n多次,但是沒有真正的復制一個數據。是一種優化手段,沒有復制數據,但是呈現出數據已經被擴張。
不會改變原數據,需要有變量來接收
舉個例子說明一下:
計算時,如果a維度和b維度不一致時,在相應的維度上添加一個維度
a.shape = [4,16,16,32] ? 大維度? ? ? ? ? ??b.shape = [32] ? 小維度
先將小維度和大維度的右端對齊,如果小維度在大維度的相應維度上沒有維度,就插入一個維度?
b.shape = [1,1,1,32]
把插入的一維度擴張成相同的size,最終b通過broadcasting會輸出
b.shape = [4,16,16,32]
broadcasting沒有復制數據,把它理解成已經復制了,用于優化計算
小維度某個軸的shape為1時可以擴張成大維度對應軸的shape,如果為其他shape不可以擴張
如在計算a維度和b維度,a.shape = [4,32,14,14],b.shape = [2,32,14,14],在軸axis=0處,b的shape為2,不可以進行擴張,如果是1可以進行擴張,因此,這兩個tensor不可以運算。
下面,我們看一下代碼
#(1)不調用函數自動計算
# 定義一個四維tensor
a = tf.random.normal([4,32,32,3])
# 大維度加小維度,先對小維度擴張
(a + tf.random.normal([32,32,1])).shape
# 由于軸axis=1對應的shape不同且不為1,不能擴張
(a + tf.random.normal1([1,4,1,1])).shape # 不能計算
在計算時,我們選擇可以不用調用廣播的函數,計算時,計算機會自動執行廣播的方法,對小維度擴張。因此,shape為[32,32,1]被擴張成[1,32,32,1],再變成[4,32,32,3],然后這兩個tensor就可以進行計算了。
而第二個計算,shape為[1,4,1,1],由于小維度的axis=1對應的shape為4,大維度shape為32,無法進行廣播擴張,只有shape是1時才能擴張。
我們也可以調用廣播函數tf.broadcast_to(input, shape)進行擴張
# 定義2個需要計算的tensor
a = tf.random.normal([4,32,32,3])
b = tf.random.normal([32,32,1])
# 利用廣播函數將b擴張成a,利用新變量x接收擴張后的結果
x = tf.broadcast_to(b,a.shape)
x.shape
對變量a和b計算前,需要將a和b的維度變成一樣的,因此需要將小維度的b擴張成和變量a一樣的維度。又因為廣播函數不會改變原值,所以用新變量x來接收廣播完成后的b。
總結
以上是生活随笔為你收集整理的【TensorFlow2.0】(4) 维度变换、广播的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【TensorFlow2.0】(3) 索
- 下一篇: 【TensorFlow2.0】(5) 数