当前位置: 首页 > article >正文

深度学习中PyTorch张量的重塑操作

深度学习中PyTorch张量的重塑操作

张量操作类型

在我们深入具体的张量操作之前,让我们先快速浏览一下主要的操作类别,这些类别包括我们将要介绍的操作。我们有以下高级类别的操作:

  1. 重塑操作
  2. 元素级操作
  3. 归约操作
  4. 访问操作

有很多单独的操作,有时候当你刚开始时可能会感到有些吓人,但是将类似的操作根据它们的相似性分组,可以帮助我们更容易地学习张量操作。

展示这些类别的目的是让你在本系列的这一部分结束时,理解所有这四种操作。

在这里插入图片描述

这些关于张量操作的文章的目标不仅是展示常用的特定张量操作,而且还要描述操作的整体情况。了解存在的操作类型比仅仅了解或记忆单个操作能让我们更长久地保持知识。

请记住这一点,在我们探索每个类别时,努力理解这些类别。现在让我们开始重塑操作。

张量的重塑操作

_重塑操作_可能是最重要的张量操作类型。这是因为,正如我们在介绍张量的文章中提到的,张量的形状给我们提供了一些具体的东西,可以用来为我们的张量形成直观的感觉。

张量的类比

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

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

在这里插入图片描述

我们的任务是构建能够转换或映射输入数据到我们寻求的正确输出的神经网络。

我们用来生产产品的主要原料,一个将输入映射到正确输出的函数,是数据。

数据是一个相当抽象的概念,所以当我们想要实际使用数据的概念来实现某事时,我们使用一个可以高效实现在代码中的特定数据结构,称为张量。张量具有数学和其他属性,允许我们完成工作。

张量是神经网络程序员用来生产产品的主要原料,即智能。

这与面包师使用面团生产,比如说,比萨非常相似。面团是用来创建输出的输入,但在生产比萨之前,通常需要对输入进行某种形式的重塑。

在这里插入图片描述

作为神经网络程序员,我们必须对我们的张量做同样的事情,通常塑造和重塑我们的张量是一个频繁的任务。

我们的网络毕竟是建立在张量上的,这就是为什么理解张量的形状和可用的重塑操作非常重要。

我们不是在生产比萨,而是在生产智能!这可能有点俗气,但不管怎样。让我们开始重塑操作。

张量形状回顾

假设我们有以下张量:

> 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中,张量的_size_和_shape_意味着同一件事。

通常,在我们了解张量的形状后,我们可以推断出一些东西。首先,我们可以推断出张量的秩。张量的秩等于张量形状的长度。

> len(t.shape)
2

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

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

在PyTorch中,有一个专门的函数来做这件事:

> t.numel()
12

张量内部包含的元素数量对于重塑很重要,因为重塑必须考虑存在的总元素数量。重塑改变了张量的形状,但没有改变底层数据。我们的张量有12​个元素,所以任何重塑都必须考虑恰好12​个元素。

在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()​函数做同样的事情,但不要让这些名字迷惑你。无论我们使用哪个深度学习框架,这些概念都将是相同的。

通过压缩和解压改变形状

接下来的改变张量形状的方法是通过压缩(squeezing)和解压(unsqueezing)它们。

  • 压缩张量会移除长度为一的维度或轴。
  • 解压张量会添加一个长度为一的维度。

这些函数允许我们扩展或缩小张量的秩(维度的数量)。让我们看看这在实际操作中的样子。

> 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()​的Python函数:

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

flatten()​函数接收一个张量t​作为参数。

由于参数t​可以是任何张量,我们传递-1​作为reshape()​函数的第二个参数。在PyTorch中,-1​告诉reshape()​函数根据张量中包含的元素数量来确定值。记住,形状必须等于形状组成部分值的乘积。这就是PyTorch如何根据第一个参数为1​来确定值的方法。

由于我们的张量t​有12​个元素,reshape()​函数能够确定第二个轴的长度需要是12​。

压缩后,第一个轴(轴-0)被移除,我们得到了期望的结果,一个长度为12​的一维数组。

这里有一个实际操作的例子:

> 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.])

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

在这些例子中,我们扁平化了整个张量,然而,可以只扁平化张量的特定部分。例如,假设我们有一个形状为[2,1, 28, 28]​的张量,用于CNN。这意味着我们有一批2​个灰度图像,高度和宽度的维度分别为28 x 28​。

在这里,我们可以特别扁平化这两个图像。得到以下形状:[2, 1, 784]​。我们也可以压缩掉通道轴,得到以下形状:[2, 784]​。

连接张量

我们使用cat()​函数连接张量,生成的张量形状取决于两个输入张量的形状。

假设我们有两个张量:

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

我们可以按行(轴0)连接t1​和t2​:

> 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])

关于重塑张量的结论

现在我们应该对重塑张量有了很好的理解。每当我们改变张量的形状时,我们就说是在重塑张量。

记住这个类比。面包师使用面团,神经网络程序员使用张量。尽管塑形的概念相同,但我们不是在制作烘焙食品,而是在创造智能。


http://www.kler.cn/a/505553.html

相关文章:

  • 下载文件,浏览器阻止不安全下载
  • 前端如何设计一个回溯用户操作的方案
  • c++ 手写queue循环队列
  • Windows 上的 MySQL 8.4.3 和 WSL(Ubuntu)的 MySQL 8.0.40 之间配置 主从同步
  • linux系统监视(centos 7)
  • 数据结构9——二叉搜索树
  • 使用Struts2遇到的Context[项目名称]启动失败问题解决(Java Web学习笔记)
  • 虚拟线程JDK与Spring Core Reactor
  • 2025windows环境下安装RabbitMQ
  • Frida调试il2cpp的程序打印原生c#对象为json
  • Qt 5.14.2 学习记录 —— 십이 QLineEdit、QTextEdit
  • win32汇编环境,窗口程序中组合框的应用举例
  • 如何将一个数组转换为字符串?
  • 01、kafka知识点综合
  • [Linux]Docker快速上手操作教程
  • LevelDB 源码阅读:如何优雅地合并写入和删除操作
  • 【MySQL学习笔记】MySQL存储过程
  • 通信与网络安全管理之ISO七层模型与TCP/IP模型
  • 计算机后端学习路径(精华版)
  • 仪式感在会员体系建设中的重要性及AI智能名片2+1链动模式S2B2C商城小程序的应用研究