??Tensor Flow也提供了許多用于多張量的形狀進行變換拆合的方法,主要分為維度變換和拆分合并兩個方面,其中維度變換主要是對一個張量的形狀進行改變,而拆分合并主要用于將一個張量按要求拆分成多個張量,或者將多個張量按某種方式合并成一個張量。下面分別從維度變換和拆分合并兩個方面簡單介紹一下張量在形狀上的變換操作。
一、維度變換
??維度變換主要包括:形狀改變、維度擴張、維度縮減以及維度交換,TensorFlow中提供的維度變換相關函數主要有: tf.reshape
,tf.expand_dims
,tf.squeeze
以及tf.transpose
。其中:
-
tf.reshape
用來對張量的進行形狀改變。 -
tf.expand_dims
用于對張量進行維度擴張。 -
tf.squeeze
用于對張量進行維度縮減。 -
tf.transpose
用于張量內部維度間的維度交換。
下面我們用代碼實例的方式,演示集中方法的具體作用,在上述功能之前,我們需要先引入Numpy和TensorFlow的包,代碼如下:
import numpy as np
import tensorflow as tf
print(np.__version__)
print(tf.__version__)
結果如下:
1.23.5
2.11.0
tf.reshape
??tf.reshape
可以改變張量的形狀,但是其本質上不會改變底層張量元素的存儲順序和結構,所以該操作性能較高。代碼如下:
#創建一個三維的形狀為[3,3,3]的張量
a = tf.random.uniform(shape=[3, 3, 3], minval=0, maxval=10, dtype=tf.int32)
tf.print("a.shape:", a.shape)
print("a:")
tf.print(a)
print("----------------------------------")
#利用reshape生成一個[3,9]的二維張量
b = tf.reshape(a, [3, 9])
print("resize之后的b:")
tf.print(b)
print("----------------------------------")
#利用reshape生成一個[9,3]的二維張量
c = tf.reshape(b, [9, 3])
print("resize之后的c:")
tf.print(c)
print("----------------------------------")
#利用reshape生成一個[9,3,1]的三維張量
d = tf.reshape(c, [9, 3, 1])
print("resize之后的d:")
tf.print(d)
print("----------------------------------")
#原始張量不變
print("resize之后的a:")
tf.print(a)
print("----------------------------------")
結果如下:
a.shape: TensorShape([3, 3, 3])
a:
[[[3 5 2]
[2 1 0]
[2 8 9]]
[[3 4 5]
[7 1 3]
[1 6 3]]
[[5 1 1]
[5 5 5]
[6 0 8]]]
----------------------------------
resize之后的b:
[[3 5 2 ... 2 8 9]
[3 4 5 ... 1 6 3]
[5 1 1 ... 6 0 8]]
----------------------------------
resize之后的c:
[[3 5 2]
[2 1 0]
[2 8 9]
...
[5 1 1]
[5 5 5]
[6 0 8]]
----------------------------------
resize之后的d:
[[[3]
[5]
[2]]
[[2]
[1]
[0]]
[[2]
[8]
[9]]
...
[[5]
[1]
[1]]
[[5]
[5]
[5]]
[[6]
[0]
[8]]]
----------------------------------
resize之后的a:
[[[3 5 2]
[2 1 0]
[2 8 9]]
[[3 4 5]
[7 1 3]
[1 6 3]]
[[5 1 1]
[5 5 5]
[6 0 8]]]
----------------------------------
??通過上述示例我們可以發現,tf.reshape
不僅可以實現同維度間張量的形狀變換,還能實現不同維度間張量的形狀變換。
tf.expand_dims 和 tf.squeeze
??tf.expand_dims
主要用于在原張量的基礎上,向第幾個維度插入一個新維度,從而實現張量的維度擴張,而tf.squeeze
用于自動識別張量中長度為1的維度,并將該維度消除,以實現對原張量的維度縮減的目的。實例代碼如下:
#創建一個三維的形狀為[3,3,3]的張量
a = tf.random.uniform(shape=[3, 3, 3], minval=0, maxval=10, dtype=tf.int32)
print("a.ndim:", a.ndim)
print("a.shape:", a.shape)
print("a:")
tf.print(a)
print("----------------------------------")
#在第axis = 1維插入一個新的維度
b = tf.expand_dims(a, axis=1)
print("b.ndim:", b.ndim)
print("b.shape:", b.shape)
tf.print(b)
print("----------------------------------")
#將某個維度上長度為1的維度進行消除
c = tf.squeeze(b)
print("c.ndim:", c.ndim)
print("c.shape:", c.shape)
tf.print(c)
print("----------------------------------")
結果如下:
a.ndim: 3
a.shape: (3, 3, 3)
a:
[[[7 8 7]
[7 3 3]
[4 0 6]]
[[8 4 5]
[6 9 1]
[4 4 9]]
[[3 4 5]
[1 1 2]
[6 1 9]]]
----------------------------------
b.ndim: 4
b.shape: (3, 1, 3, 3)
[[[[7 8 7]
[7 3 3]
[4 0 6]]]
[[[8 4 5]
[6 9 1]
[4 4 9]]]
[[[3 4 5]
[1 1 2]
[6 1 9]]]]
----------------------------------
c.ndim: 3
c.shape: (3, 3, 3)
[[[7 8 7]
[7 3 3]
[4 0 6]]
[[8 4 5]
[6 9 1]
[4 4 9]]
[[3 4 5]
[1 1 2]
[6 1 9]]]
----------------------------------
tf.transpose
??與tf.reshape
不同tf.transpose
可以交換張量的維度進而改變張量元素的存儲順序。示例代碼如下:
a = tf.random.uniform(shape=[2,3,4], minval=0, maxval=10, dtype=tf.int32)
print("a.shape:", a.shape)
print("a:")
tf.print(a)
print("----------------------------------")
# 轉換成將形狀轉換成[4,2,3],
# 原張量中4對應于第2維,2對應于第0維,3對應于第1維,故perm=[2,0,1]
# 相比較原始張量的perm=[0,1,2],perm=[2,0,1]相當于先對第0維和第2維進行了維度交換,
# 然后對維度1和0進行交換
b = tf.transpose(a, perm=[2, 0, 1])
print("b.shape:", b.shape)
print("b:")
tf.print(b)
print("----------------------------------")
# 不對維度進行交換
c = tf.transpose(a, perm=[0, 1, 2])
print("c.shape:", c.shape)
print("c:")
tf.print(c)
print("----------------------------------")
結果如下:
a.shape: (2, 3, 4)
a:
[[[0 0 5 3]
[2 5 3 8]
[3 9 6 1]]
[[5 7 3 0]
[2 5 0 2]
[4 3 8 0]]]
----------------------------------
b.shape: (4, 2, 3)
b:
[[[0 2 3]
[5 2 4]]
[[0 5 9]
[7 5 3]]
[[5 3 6]
[3 0 8]]
[[3 8 1]
[0 2 0]]]
----------------------------------
c.shape: (2, 3, 4)
c:
[[[0 0 5 3]
[2 5 3 8]
[3 9 6 1]]
[[5 7 3 0]
[2 5 0 2]
[4 3 8 0]]]
----------------------------------
??以上關于TensorFlow中張量的形狀變換進行了簡單的示例,下面我們繼續了解一下TensorFlow中張量的拆分合并。
二、拆分合并
??針對張量的拆分,TensorFlow提供了tf.split
方法來實現,而針對多個張量和合并,TensorFlow也提供了類似于Numpy和Pandas的tf.concat
及tf.stack
等方法。
??首先我們先對張量的拆分進行簡單的示例,tf.split
主要用于將某個張量按照某個維度平均拆分成若干份,從而得到多個拆分后的張量。代碼如下:
a = tf.random.uniform(shape=[2,3,4], minval=0, maxval=10, dtype=tf.int32)
print("a.shape:", a.shape)
print("a:")
tf.print(a)
print("----------------------------------")
#基于維度0,將a張量平均拆分成兩個
splits = tf.split(a, 2, axis = 0)
print("基于維度0,將a張量平均拆分成2個,拆分后的每個張量如下:")
for split in splits:
tf.print(split)
print("==================")
print("----------------------------------")
print("基于維度1,將a張量平均拆分成3個,拆分后的每個張量如下:")
splits = tf.split(a, 3, axis = 1)
for split in splits:
tf.print(split)
print("==================")
print("----------------------------------")
print("基于維度2,將a張量平均拆分成2個,拆分后的每個張量如下:")
splits = tf.split(a, 2, axis = 2)
for split in splits:
tf.print(split)
print("==================")
print("----------------------------------")
結果如下:
a.shape: (2, 3, 4)
a:
[[[8 3 4 2]
[4 7 2 8]
[9 9 9 1]]
[[3 9 1 6]
[4 7 5 9]
[8 5 6 8]]]
----------------------------------
基于維度0,將a張量平均拆分成2個,拆分后的每個張量如下:
[[[8 3 4 2]
[4 7 2 8]
[9 9 9 1]]]
==================
[[[3 9 1 6]
[4 7 5 9]
[8 5 6 8]]]
==================
----------------------------------
基于維度1,將a張量平均拆分成3個,拆分后的每個張量如下:
[[[8 3 4 2]]
[[3 9 1 6]]]
==================
[[[4 7 2 8]]
[[4 7 5 9]]]
==================
[[[9 9 9 1]]
[[8 5 6 8]]]
==================
----------------------------------
基于維度2,將a張量平均拆分成2個,拆分后的每個張量如下:
[[[8 3]
[4 7]
[9 9]]
[[3 9]
[4 7]
[8 5]]]
==================
[[[4 2]
[2 8]
[9 1]]
[[1 6]
[5 9]
[6 8]]]
==================
----------------------------------
??上面我們講完了張量的拆分,下面我們介紹一下張量的合并。TensorFlow提供了兩種方法來實現張量和合并,分別是tf.concat
和tf.stack
,其中tf.concat
是從某個維度上對兩個張量進行連接,形成新的結果張量,結果張量的維度和原張量的維度是一致的,不會增加結果張量的維度。而tf.stack
是堆疊,會增加結果張量維度。我們先來看一下tf.concat
的合并效果,代碼如下:
a = tf.constant([[1, 2, 3], [4, 5, 6]])
b = tf.constant([[7, 8, 9], [10, 11,12]])
print("原始張量a:")
tf.print(a)
print("----------------------------------")
print("原始張量b:")
tf.print(b)
print("----------------------------------")
# 按照維度0對張量a和張量b進行合并
c = tf.concat([a, b], axis = 0)
print("按照維度0合并后的張量:")
print("c.shape:", c.shape)
print("c: ")
tf.print(c)
print("----------------------------------")
# 按照維度1對張量a和張量b進行合并
d = tf.concat([a, b], axis = 1)
print("按照維度1合并后的張量:")
print("d.shape:", d.shape)
print("d: ")
tf.print(d)
print("----------------------------------")
結果如下:
原始張量a:
[[1 2 3]
[4 5 6]]
----------------------------------
原始張量b:
[[7 8 9]
[10 11 12]]
----------------------------------
按照維度0合并后的張量:
c.shape: (4, 3)
c:
[[1 2 3]
[4 5 6]
[7 8 9]
[10 11 12]]
----------------------------------
按照維度1合并后的張量:
d.shape: (2, 6)
d:
[[1 2 3 7 8 9]
[4 5 6 10 11 12]]
----------------------------------
我們再看一下tf.stack
的合并效果,代碼如下:
a = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8]])
b = tf.constant([[9, 10, 11, 12], [13, 14, 15, 16]])
print("原始張量a:")
print("a.shape:", a.shape)
tf.print(a)
print("----------------------------------")
print("原始張量b:")
print("b.shape:", b.shape)
tf.print(b)
print("----------------------------------")
# 按照維度0對張量a和張量b進行合并
c = tf.stack([a, b], axis = 0)
print("按照維度0合并后的張量:")
print("c.shape:", c.shape)
print("c: ")
tf.print(c)
print("----------------------------------")
# 按照維度1對張量a和張量b進行合并
d = tf.stack([a, b], axis = 1)
print("按照維度1合并后的張量:")
print("d.shape:", d.shape)
print("d: ")
tf.print(d)
print("----------------------------------")
結果如下:
原始張量a:
a.shape: (2, 4)
[[1 2 3 4]
[5 6 7 8]]
----------------------------------
原始張量b:
b.shape: (2, 4)
[[9 10 11 12]
[13 14 15 16]]
----------------------------------
按照維度0合并后的張量:
c.shape: (2, 2, 4)
c:
[[[1 2 3 4]
[5 6 7 8]]
[[9 10 11 12]
[13 14 15 16]]]
----------------------------------
按照維度1合并后的張量:
d.shape: (2, 2, 4)
d:
[[[1 2 3 4]
[9 10 11 12]]
[[5 6 7 8]
[13 14 15 16]]]
----------------------------------
??關于TensorFlow中張量的變換拆合就簡單介紹到這里,其實TensorFlow中的張量操作很大程度上參考了Numpy中對ndarray的操作,因此上手起來還是比較容易的。