TensorFlow张量的维度伸缩与交换

TensorFlow张量的维度伸缩与交换

张量的维度伸缩与交换

张量中的轴方向

TensorFlow 中,通常情况下,张量具有多个维度,有时需要对维度进行操作,此时需要指明操作的维度,通常用 Axis (轴)来表示。

对于一维张量而言,它只有一个轴,称为 axis 0;对于二维张量而言,它有两个轴,一个为 axis 0(表示行),另一个为 axis 1(表示列);三维张量有三个轴,分别为 axis 0(表示深度或样本数量),axis 1(表示行) 和 axis 2(表示列)。

张量维度的增加与删除

我们可以利用 tf.expand_dims() 方法来增加张量的维度:

import tensorflow as tf
import os

os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"

a = tf.random.normal([5, 20, 7]) #  构建三维张量,维度为 5*20*7
print(a.shape) # 输出张量的形状
(5, 20, 7)
a = tf.expand_dims(a, axis=0) # 在第 0 维上添加一个维度
print(a.shape)
(1, 5, 20, 7)

我们也可以利用 tf.concat() 方法对多个张量进行合并:

b = tf.random.normal([1, 5, 20, 7])
c = tf.concat([a, b], axis=0) # 在第 0 维度上合并张量 a 和 b
print(c.shape)
(2, 5, 20, 7)

对于冗余的维度,我们可以利用 tf.squeeze() 方法来删除(降维):

a = tf.squeeze(a, axis=0) # 删除第 0 维
print(a.shape)
(5, 20, 7)

张量的合并、分割与复制

张量合并

有两种方法可以来实现张量的合并,一个是之前提到的 tf.concat() 方法,另一个是 tf.stack() 方法。
tf.concat() 方法实现的拼接操作不会创建新的维度;而 tf.stack() 方法会创建新的维度,并实现张量的拼接。

tf.concat() 方法的具体语法如下:

tf.concat(
    values, # 拼接的张量
    axis, # 在哪个轴上进行拼接
    name='concat' # 操作名称
)

其中,values 是要拼接的张量;axis 是拼接的轴,表示在第几个维度上进行拼接,取值范围为 0 ~ n - 1n 为该张量的维度;name 是操作名称。

我们来看一个例子:

t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
t3 = tf.concat([t1, t2], 0) # 张量拼接(垂直方向)
print(t3)
tf.Tensor(
    [[ 1  2  3]
     [ 4  5  6]
     [ 7  8  9]
     [10 11 12]], shape=(4, 3), dtype=int32)

上述代码实现了垂直方向上的张量拼接,我们也可以令 axis=1 来实现水平方向上的拼接:

t4 = tf.concat([t1, t2], 1) # 张量拼接(水平方向)
print(t4)
tf.Tensor(
    [[ 1  2  3  7  8  9]
     [ 4  5  6 10 11 12]], shape=(2, 6), dtype=int32)

axis 也可以为负值,-1 表示倒数第一个轴,-2 表示倒数第二个轴,以此类推。

tf.stack(tensors, axis) 方法可以合并多个张量,并且创建新的维度,但需要合并的张量的维度必须相同,如下所示:

m = tf.stack([t1, t2], axis=0)
print(m)
tf.Tensor(
    [[[ 1  2  3]
      [ 4  5  6]]

     [[ 7  8  9]
      [10 11 12]]], shape=(2, 2, 3), dtype=int32)

张量分割

tf.split() 方法可以用来实现张量的分割,它的语法如下:

tf.split(
    value, # 要分割的张量
    num_or_size_splits, # 分割方案
    axis=0, # 在哪个轴上进行分割
    name='split' # 操作名称
)

其中:

  • value 表示要分割的张量。
  • num_or_size_splits 表示分割方案,可以是单个数值,当 num_or_size_splits5 时,表示将张量等分为 5 份;也可以是列表,例如 [1, 2, 2],表示将张量分为 3 份(列表的长度),长度分别为 122(列表的元素)。
  • axis 表示要在哪个轴(维度)上进行分割,默认为 0
  • name 表示操作的名称。

我们来看一个例子:

scores = tf.random.normal([5, 3, 2])
result = tf.split(scores, num_or_size_splits=5) # 将张量等分为 5 份
print(result)
[<tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[ 0.04288249, -0.19643487],
            [ 1.1040841 ,  0.37403035],
            [ 0.2968676 ,  0.40126628]]], dtype=float32)>, <tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[ 1.4905819 ,  1.072397  ],
            [-0.7560552 ,  0.63848513],
            [-0.26322153,  1.9187034 ]]], dtype=float32)>, <tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[0.2913646 , 0.57758117],
            [0.36280274, 1.2159098 ],
            [0.07694758, 1.2456622 ]]], dtype=float32)>, <tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[ 0.3552603 ,  1.5969112 ],
            [-0.60505086, -0.02659673],
            [-0.52903736, -1.3919442 ]]], dtype=float32)>, <tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[-0.6123017 ,  1.624879  ],
            [ 1.9365473 ,  1.8205245 ],
            [ 0.15557216,  0.03250924]]], dtype=float32)>]

我们再利用列表 [1, 2, 2] 在第 0 个维度上来实现张量的分割:

result_2 = tf.split(scores, num_or_size_splits=[1, 2, 2], axis=0) # 将张量等分为 1 份,2 份,2 份
print(result_2)
[<tf.Tensor: shape=(1, 3, 2), dtype=float32, numpy=
    array([[[ 0.04288249, -0.19643487],
            [ 1.1040841 ,  0.37403035],
            [ 0.2968676 ,  0.40126628]]], dtype=float32)>, <tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
    array([[[ 1.4905819 ,  1.072397  ],
            [-0.7560552 ,  0.63848513],
            [-0.26322153,  1.9187034 ]],

           [[ 0.2913646 ,  0.57758117],
            [ 0.36280274,  1.2159098 ],
            [ 0.07694758,  1.2456622 ]]], dtype=float32)>, <tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
    array([[[ 0.3552603 ,  1.5969112 ],
            [-0.60505086, -0.02659673],
            [-0.52903736, -1.3919442 ]],

           [[-0.6123017 ,  1.624879  ],
            [ 1.9365473 ,  1.8205245 ],
            [ 0.15557216,  0.03250924]]], dtype=float32)>]

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://cangmang.xyz/articles/dimension-scaling-and-swapping-of-tensors