PyTorch - 09 - Flatten, Reshape, 和Squeeze说明 - 使用PyTorch进行深度学习的张量

Reshaping Operations - Tensors For Deep Learning

在深入研究特定的张量操作之前,让我们通过查看主要操作类别(包括我们将要介绍的操作)来快速了解情况。我们有以下高级操作类别:

  1. 重塑操作 (Reshaping operations)
  2. 按元素操作 (Element-wise operations)
  3. 还原操作 (Reduction operations)
  4. 访问操作 (Access operations)

那里有很多单独的操作,以至于您刚开始时有时会令人生畏,但是根据相似性将相似的操作分组为几类,有助于使对张量操作的了解更加易于管理。

之所以显示这些类别,是为了使您能够在本系列文章的最后部分了解所有这四个类别。

在这里插入图片描述

这些关于张量操作的文章的目的不仅是展示常用的特定张量操作,而且还描​​述操作情况。知道现有的操作类型比知道或记住单个操作要长得多。

请牢记这一点,并在我们探索每个类别时努力理解这些类别。现在让我们开始进行整形操作。

Reshaping Operations For Tensors

重整操作可能是张量操作最重要的类型。 这是因为,就像我们在介绍张量的帖子中提到的那样,张量的形状为我们提供了一些具体的东西,可用来为张量形成直觉。

An Analogy For Tensors

假设我们是神经网络程序员,因此,我们通常会花费很多时间来构建神经网络。为了完成我们的工作,我们使用各种工具。

我们使用微积分和线性代数等数学工具,Python和PyTorch等计算机科学工具,CPU和GPU等物理和工程工具以及神经网络,层,激活函数等机器学习工具。

在这里插入图片描述

我们的任务是建立可将输入数据转换或映射到我们正在寻找的正确输出的神经网络。我们用来生产产品的主要成分是数据,该函数将输入映射到正确的输出。

数据在某种程度上是一个抽象的概念,因此当我们想实际使用数据的概念来实现某些东西时,我们使用一种称为张量的特定数据结构,该结构可以在代码中有效实现。张量具有数学和其他方面的属性,使我们能够进行工作。

张量是神经网络程序员用来生产其产品智能的主要成分。

在这里插入图片描述
这与面包师使用面团来制作比萨饼的方式非常相似。面团是用于创建输出的输入,但是在生产披萨之前,通常需要对输入进行某种形式的重塑。

作为神经网络程序员,我们必须对张量执行相同的操作,通常对张量进行整形和重塑是一项常见的任务。

毕竟,我们的网络在张量上运行,这就是为什么了解张量的形状和可用的整形操作非常重要的原因。
我们不是在生产比萨,而是在生产智能!这可能很la脚,但无论如何。让我们开始重塑操作。

Tensor Shape Review

假设我们有以下张量:

> t = torch.tensor([
    [1,1,1,1],
    [2,2,2,2],
    [3,3,3,3]
], dtype=torch.float32)

为了确定该张量的形状,我们首先查看第3行,然后查看第4列,因此该张量是3 x 4的2级张量。请记住,等级是一个常用的词,仅表示张量中存在的维数。

在PyTorch中,我们有两种获取形状的方法:

> t.size()
torch.Size([3, 4])

> t.shape
torch.Size([3, 4])

在PyTorch中,张量的大小和形状表示相同的意思。

通常,在知道张量的形状之后,我们可以推断出几件事。首先,我们可以得出张量的等级。张量的秩等于张量形状的长度。

> len(t.shape)
2

我们还可以推断出张量中包含的元素数量。张量内的元素数量(在我们的示例中为12)等于形状成分值的乘积。

> torch.tensor(t.shape).prod()
tensor(12)

在PyTorch中,有一个专用的功能:

> t.numel()
12

张量中包含的元素数量对于重塑很重要,因为重塑必须考虑存在的元素总数。重塑会更改张量的形状,但不会更改基础数据。我们的张量包含12个元素,因此任何重塑都必须恰好包含12个元素。

Reshaping A Tensor In PyTorch

现在让我们看一下在不改变等级的情况下可以重塑此张量t的所有方法:

> t.reshape([1,12])
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])

> t.reshape([2,6])
tensor([[1., 1., 1., 1., 2., 2.],
        [2., 2., 3., 3., 3., 3.]])

> t.reshape([3,4])
tensor([[1., 1., 1., 1.],
        [2., 2., 2., 2.],
        [3., 3., 3., 3.]])

> t.reshape([4,3])
tensor([[1., 1., 1.],
        [1., 2., 2.],
        [2., 2., 3.],
        [3., 3., 3.]])

> t.reshape(6,2)
tensor([[1., 1.],
        [1., 1.],
        [2., 2.],
        [2., 2.],
        [3., 3.],
        [3., 3.]])

> t.reshape(12,1)
tensor([[1.],
        [1.],
        [1.],
        [1.],
        [2.],
        [2.],
        [2.],
        [2.],
        [3.],
        [3.],
        [3.],
        [3.]])

使用reshape()函数,我们可以指定要搜索的行x列的形状。 注意,所有形状都必须考虑张量中的元素数量。 在我们的示例中,这是:

行*列= 12个元素

在处理2级张量时,我们可以使用直觉的行和列。 即使我们可能无法使用高维空间中的行和列的直觉,对于高维男高音,基本逻辑也是相同的。 例如:

> t.reshape(2,2,3)
tensor(
[
    [
        [1., 1., 1.],
        [1., 2., 2.]
    ],

    [
        [2., 2., 3.],
        [3., 3., 3.]
    ]
])

在此示例中,我们将等级提高到3,因此我们失去了行和列的概念。 但是,形状的分量(2,2,3)的乘积仍必须等于原始张量(12)中的元素数。

请注意,PyTorch还有另一个函数,您可能会看到它称为view(),它与reshape()函数具有相同的作用,但是不要让这些名称通过您。 无论我们使用哪种深度学习框架,这些概念都是相同的。

Changing Shape By Squeezing And Unsqueezing

我们可以改变张量形状的另一种方法是挤压和松开它们。

  1. 压缩 (Squeezing)张量将删除长度为1的尺寸或轴。
  2. 松开(Unsqueezing)张量会添加一个长度为1的尺寸。

这些功能使我们可以扩大或缩小张量的等级(维数)。 让我们来看看实际情况。

> print(t.reshape([1,12]))
> print(t.reshape([1,12]).shape)
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])
torch.Size([1, 12])

> print(t.reshape([1,12]).squeeze())
> print(t.reshape([1,12]).squeeze().shape)
tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.])
torch.Size([12])

> print(t.reshape([1,12]).squeeze().unsqueeze(dim=0))
> print(t.reshape([1,12]).squeeze().unsqueeze(dim=0).shape)
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])
torch.Size([1, 12])

注意,当我们挤压和放松张量时,形状是如何变化的。

让我们看一下通过构建展平 (flatten) 函数来压缩张量的常见用例。

Flatten A Tensor

对张量进行展平操作会将张量整形,使其形状等于张量中包含的元素数量。这与一维元素数组相同。

展平张量意味着除去除一个以外的所有尺寸。

让我们创建一个称为flatten()的Python函数:

def flatten(t):
    t = t.reshape(1, -1)
    t = t.squeeze()
    return t

flatten()函数将张量t作为参数。

由于参数t可以是任何张量,因此我们将-1作为第二个参数传递给reshape()函数。在PyTorch中,-1告诉reshape()函数根据张量中包含的元素数量来确定值。请记住,形状必须等于形状的组件值的乘积。在第一个参数为1的情况下,PyTorch就是这样来计算出该值应该是多少。

由于我们的张量t具有12个元素,因此reshape()函数能够计算出第二个轴的长度需要12。

挤压后,将第一个轴(轴-0)移开,我们获得了所需的结果,长度为12的1d数组。

这是一个实际的例子:

> t = torch.ones(4, 3)
> t
tensor([[1., 1., 1.],
    [1., 1., 1.],
    [1., 1., 1.],
    [1., 1., 1.]])

> flatten(t)
tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

在以后的文章中,当我们开始构建卷积神经网络时,我们将看到此flatten()函数的用法。我们将看到,当将输出张量从卷积层传递到线性层时,需要进行扁平化操作。

在这些示例中,我们已经拉平了整个张量,但是,可以仅拉平张量的特定部分。例如,假设我们有一个CNN形状为[2,1,28,28]的张量。这意味着我们有一批2张灰度图像,其高度和宽度尺寸分别为28 x 28

在这里,我们可以专门展平两个图像。得到以下形状:[2,1,784]。我们还可以挤压通道轴以获得以下形状:[2,784]

Concatenating Tensors

我们使用cat()函数组合张量,并且所得张量的形状将取决于两个输入张量的形状。

假设我们有两个张量:

> t1 = torch.tensor([
    [1,2],
    [3,4]
])
> t2 = torch.tensor([
    [5,6],
    [7,8]
])

我们可以按以下方式逐行组合t1t2(轴0):

> torch.cat((t1, t2), dim=0)
tensor([[1, 2],
        [3, 4],
        [5, 6],
        [7, 8]])

我们可以像这样按列组合(第1轴):

> torch.cat((t1, t2), dim=1)
tensor([[1, 2, 5, 6],
        [3, 4, 7, 8]])

当我们连接张量时,我们增加了包含在结果张量中的元素的数量。 这将导致形状(轴的长度)内的组件值进行调整以考虑其他元素。

> torch.cat((t1, t2), dim=0).shape
torch.Size([4, 2])

> torch.cat((t1, t2), dim=1).shape
torch.Size([2, 4])

Conclusion About Reshaping Tensors

现在,我们应该对重塑张量有一个很好的了解。 每当我们改变张量的形状时,据说我们正在重塑张量。

记住比喻: 面包师与面团一起工作,而神经网络程序员与张量一起工作。 即使塑造的概念是相同的,我们也没有创造烘焙食品,而是创造了智慧。 下一个见。

猜你喜欢

转载自blog.csdn.net/weixin_48367136/article/details/112465734