Pytorch中reshape,view,transpose以及permute的详细原理及应用

news2024/11/13 9:31:30

在深度学习中,我们经常会遇到需要对张量进行形状变换的情况。PyTorch 提供了多种方法来改变张量的形状,包括 reshape, view, transposepermute 。本文总结了其它博客的精华,详细介绍这些方法的原理和应用场景。

目录

一、张量的存储方式

二、 reshape

三、view

四、transpose

五、 permute

一、张量的存储方式

在理解这些方法之前,我们需要先了解张量在内存中的存储方式。张量的数据存储分为两部分:头信息区(Tensor)存储区(Storage)头信息区包含张量的形状(size)、步长(stride)等信息;而存储区则存放实际的数据。
如果我们对A进行截取、转置或修改等操作后赋值给B,则B的数据共享A的存储区,存储区的数据数量没变,变化的只是B的头信息区对数据的索引方式。如果听说过浅拷贝和深拷贝的话,很容易明白这种方式其实类似浅拷贝

步长(Stride):步长是指从一个元素跳转到下一个元素所需的偏移量,通常以字节数表示。
例如,在二维张量中,第一个维度的步长表示从一行跳转到下一行的偏移量,第二个维度的步长表示在同一行内从一个元素跳转到下一个元素的偏移量。


假设我们有一个形状为 (2, 3) 的张量 a,包含元素 [1, 2, 3, 4, 5, 6]

import torch

# 创建一个 (2, 3) 的张量
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
print("原始张量 a:")
print(a)

输出结果类似于:

原始张量 a:
tensor([[1, 2, 3],
        [4, 5, 6]])

张量 a 的形状:(2, 3),张量 a 的步长:a.stride() 返回 (3, 1)

  • 第一个维度的步长(行):3,意味着从第一行到第二行需要跳过 3 个元素。这是因为每个元素占据一定的内存空间(例如 4 字节),因此从第一行跳转到第二行需要跳过 3 * 4 字节。
  • 第二个维度的步长(列):1,意味着在同一行内从一个元素到下一个元素只需要跳过 1 个元素。这意味着从一个元素到下一个元素只需要跳过 1 * 4 字节。

之所以提及步长是因为底层的实现是利用了这种方式,适当了解一下,后续的讲解不会涉及太多步长的知识。

二、 reshape

reshape 方法会尝试在不复制数据的情况下改变张量的形状。如果新的形状与原始形状的元素总数相同,那么 reshape 会改变张量的步长,使得新的形状可以正确地访问数据。
reshape()在新形状满足一定条件时会共享相同一份数据,否则会复制一份新的数据。(reshape操作可以作用在连续非连续数据上,如果作用在非连续数据上也会带来内存拷贝,变成内存连续的数据。连续的知识点在view中会讲到
下面默认讲解reshape满足条件下的共享情况

reshape是如何实现改变尺度操作的呢,参考了一篇帖子,总结了下面这些知识点。

import torch

# 使用torch.arange生成值从0开始,步长为2的张量,直到22(不包括22)
a = torch.arange(0, 24, 2)

# 输出张量a
print(a)  # 输出: tensor([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22])

这个a非常简单, 就是一个数组, 但是其内部其实是这样组织的

a行代表内存中数组的存储状态, 上面的i行代表辅助的索引轴,借助这个轴, 就可以访问到数组的任何一个元素, 比如a[3], 就是索引到元素6。

import torch

# 假设a是之前创建的一维张量
a = torch.tensor([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22])

# 使用reshape方法重塑a为2x6的二维张量
b = torch.reshape(a, (2, 6))

# 输出b
print(b)

# 输出
tensor([[ 0,  2,  4,  6,  8, 10],
        [12, 14, 16, 18, 20, 22]])

 此时貌似是a里面的元素改变了, 变成了2维, 其实改变的只是轴。 此时pytorch会建立两个轴,假设两轴为 i、ji 的取值为 0 - 1,j 的取值为 0 - 5,示意图如下:

此时使用b[1][2]就可以获取到元素16(这时候的两个轴取值为1,2)

无论shape如何变化, 变化的是视图而已, 底下的缓冲区数据始终未变。
现在进阶一下看看三个轴的例子:

c = a.reshape(2,3,2)
print(c)

# 输出
array([[[ 0,  2],
        [ 4,  6],
        [ 8, 10]],

       [[12, 14],
        [16, 18],
        [20, 22]]])

数组 c 形状为(2, 3, 2)有三个轴,取值分别为 0 - 1,0 - 2,0 - 1,示意图如下所示:

下一个轴的循环范围是以上一轴的同一元素为边界,图中我框出来了,应该能看明白。
此时c[0,2,1]可以得到元素10,跟代码里输出的维度进行比较,确实是10.
reshape 后的张量,仅仅是原来张量的视图 view,并没有发生复制元素的行为,这样才能保证 reshape 操作更为高效。 也就是说即使reshape了, 两者指向的是底层数据还是一样如果改变其中一个, 另一个也会跟着改变

import torch

a = torch.tensor([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22])

# 使用reshape方法改变a的形状为2x6的二维张量b
b = a.reshape(2, 3, 2)

# 修改b中的一个元素
b[1][2] = 99

# 输出a
print("修改后的a:", a)

修改后的a: tensor([ 0,  2,  4,  6,  8, 10, 12, 14, 99, 18, 20, 22])

三、view

view类似于reshape,将tensor转换为指定的shape,原始的data不改变。返回的tensor与原始的tensor共享存储区。返回的tensor的size和stride必须与原始的tensor兼容。每个新的tensor的维度必须是原始维度的子空间,或满足连续条件。view操作只作用在连续内存上,仅仅按照行重新排列下标,不改变数据的内存分布。
否则需要先使用contiguous()方法将原始tensor转换为满足连续条件的tensor,然后就可以使用view方法进行shape变换了。(这就是我们在深度学习代码中常见到在view之前使用contiguous()的原因。contiguous()方法开辟了一个新的存储区,并改变了原始存储区数据的存放顺序,类似于深拷贝。
或直接使用reshape方法进行维度变换,但在不连续情况下,这种方法变换后的tensor就不是与原始tensor共享内存了,而是被重新开辟了一个空间

这部分的详细内容可以参考下面的链接,讲得很好。
PyTorch:view() 与 reshape() 区别详解_pytorch view reshape-CSDN博客

四、transpose

transpose 方法用于交换张量的两个维度。与 permute 不同,transpose 只能交换两个维度。transpose 方法接收两个整数参数,表示要交换的维度。

举个例子

import torch

# 创建形状为 (2, 3, 2) 的三维张量
x = torch.arange(12).view(2, 3, 2)
print("原始张量 x:")
print(x)

# 使用 transpose 方法交换第0维和第1维
x_transposed = x.transpose(0, 1)
print("\n交换第0维和第1维后的张量 x_transposed:")
print(x_transposed)

# 输出
原始张量 x:
tensor([[[ 0,  1],
         [ 2,  3],
         [ 4,  5]],

        [[ 6,  7],
         [ 8,  9],
         [10, 11]]])

交换第0维和第1维后的张量 x_transposed:
tensor([[[ 0,  1],
         [ 6,  7]],

        [[ 2,  3],
         [ 8,  9]],

        [[ 4,  5],
         [10, 11]]])



使用transpose ()进行变换,其实就是交换了坐标轴。如:x.transpose(0,1),其实就是将x的第一维与第二维索引数字交换。最后的shape为:(3,2,2)。

原理如下

原先的数据的索引和数据对应情况为:

x[0][0][0] = 0				x[1][0][0] = 6
x[0][0][1] = 1				x[1][0][1] = 7
x[0][1][0] = 2				x[1][1][0] = 8
x[0][1][1] = 3				x[1][1][1] = 9
x[0][2][0] = 4				x[1][2][0] = 10
x[0][2][1] = 5				x[1][2][1] = 11

交换数据的索引,对应的值还是不变,即交换了坐标轴,如[0][2][1] —>[2][0][1]

x[0][0][0] = 0				x[0][1][0] = 6
x[0][0][1] = 1				x[0][1][1] = 7
x[1][0][0] = 2				x[1][1][0] = 8
x[1][0][1] = 3				x[1][1][1] = 9
x[2][0][0] = 4				x[2][1][0] = 10
x[2][0][1] = 5				x[2][1][1] = 11

此时变换坐标后和上面打印的张量一致。

例子中,我们使用的shape是(2, 3, 2),可以理解成:2通道的图片,每张图层是3 * 2大小正常渲染是把第一个通道的图片把3 * 2个像素点绘制,绘制第二个通道的3 * 2像素。
在使用transpose(0, 1)后,新的数据是shape是(3,2,2),可以理解成每张图层是3 * 2大小,2通道的图片,原先的是先绘制一个通道数据,如今变换后的数据是每次将一个坐标的不同通道的像素进行一次性绘制。
如图:

五、 permute

permute 方法用于交换张量的维度。与 transpose 类似,但可以处理任意数量的维度
permute() 函数一次可以进行多个维度的交换或者可以成为维度重新排列,参数是 0, 1, 2, 3, … ,随着待转换张量的阶数上升参数越来越多,本质上可以理解为多个 transpose() 操作的叠加,因此理解 permute() 函数的关键在于理解 transpose() 函数。

例如,对于一个三维张量,使用permute(1, 2, 0)意味着:

  • 原始张量的第二维(索引1)将成为新张量的第一维。
  • 原始张量的第三维(索引2)将成为新张量的第一维。
  • 原始张量的第一维(索引0)将成为新张量的第三维。

这相当于先执行一个将第一维和第二维互换,然后再将结果张量的第一维和第三维互换,最终达到重新排列维度的目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957410.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Elasticsearch 和 LlamaIndex 保护 RAG 中的敏感信息和 PII 信息

作者:来自 Elastic Srikanth Manvi 在这篇文章中,我们将研究在 RAG(检索增强生成)流程中使用公共 LLMs 时保护个人身份信息 (personal identifiable information - PII) 和敏感数据的方法。我们将探索使用开源库和正则表达式屏蔽 …

探索 Redis 不同集群架构的性能与应用

1. 引言 Redis的集群配置成为了提高数据可靠性和服务可用性的关键。本文将带领大家了解Redis的四种主要集群架构,并重点分析哨兵模式和Redis Cluster架构和优势。 2. Redis的四种集群架构 2.1 单实例Redis 使用单个 Redis 实例提供服务。适用于小规模应用&#…

C语言 #具有展开功能的排雷游戏

文章目录 前言 一、整个排雷游戏的思维梳理 二、整体代码分布布局 三、游戏主体逻辑实现--test.c 四、整个游戏头文件的引用以及函数的声明-- game.h 五、游戏功能的具体实现 -- game.c 六、老六版本 总结 前言 路漫漫其修远兮,吾将上下而求索。 一、整个排…

WEB前端开发中如何实现大文件上传?

大文件上传是个非常普遍的场景,在面试中也会经常被问到,大文件上传的实现思路和流程。在日常开发中,无论是云存储、视频分享平台还是企业级应用,大文件上传都是用户与服务器之间交互的重要环节。随着现代网络应用的日益复杂化&…

实况照片怎么转换成gif动图?分享5种方法!

在当今这个视觉为王的时代,静态的照片已经难以满足我们追求生动、有趣的表达需求。你是否也曾想过,将那些精彩瞬间的实况照片转换成动感十足的GIF动图,为社交分享增添一抹亮色?今天,就让我们一起来探索实况照片转换成G…

自闭症怎么才能摘帽?

作为星贝育园自闭症康复中心的老师,经常会有家长满怀期待又焦虑地问我:“自闭症怎么才能摘帽?”今天,我就来为大家详细说一说。 首先,我们要明确,自闭症的“摘帽”并非一蹴而就,而是一个…

U盘目录损坏:诊断、恢复与防范全解析

U盘目录损坏:数据安全的隐形挑战 在数字化生活日益普及的今天,U盘作为便携式数据存储设备,几乎成为了每个人工作、学习和生活中不可或缺的一部分。然而,U盘目录损坏问题却时常发生,给数据安全和用户体验带来了巨大挑战…

Python数值计算(10)

继续说多项式的数值及拟合,这次主要讨论关于多项式拟合的函数fit。定义如下: classmethod polynomial.polynomial.Polynomial.fit (x, y, deg, domainNone, rcondNone, fullFalse, wNone, windowNone, symbolx) Polynomial类下面有一个函数fit&#xf…

弄懂这5条深层逻辑,你也将通透豁达

01 如果正面解决不了问题,不妨试试从侧面或者反面进行解决。 比如,食堂的锅破了一个洞,如果你多次反映都没能解决破洞的问题,那不妨直接把锅捅穿,让锅没有办法使用,进而升级问题,把做饭不方便…

深入源码:解析SpotBugs (3) Detector

文章目录 OpcodeStackDetector常用套路调用栈visit code类检测方法检测代码行检测 前面的博客也提到过,Spotbugs 里面 Detector2 与 Detector,FindBugs2 与 FindBugs,GUI2与GUI,可以视为 Spotbugs 与 FindBugs 新老技术的碰撞&…

基于微信小程序+SpringBoot+Vue的网络安全科普系统(带1w+文档)

基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 优质的网络安全科普系统不仅可以单纯的满足工作人员管理的日常工作需求,还可以满足用户的需求。可以降低工作人员的工作压力,提高效…

课程制作及教学体验革命,AI视频生成工具如何落地教育行业?

“大力发展数字教育”,这是2024年政府工作报告中提到的教育任务之一。同时,“人工智能”行动首次写入政府工作报告,意味着各行各业均有新的发展空间。那么,数字教育应该怎么做?此前,2024年全国教育工作会议…

MySQL查询执行(三):显示随机消息

假设有如下表结构&#xff1a; -- 创建表words CREATE TABLE words (id int(11) NOT NULL AUTO_INCREMENT,word varchar(64) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB;--数据生成存储过程 delimiter ;; create procedure idata() begindeclare i int;set i0;while i<…

计算机毕业设计选题推荐-财会信息管理系统-Java项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

算法通关:011:分隔链表

文章目录 题目思路代码 leetcode 86 题目 思路 左边一个往进插数字 &#xff0c;右边一个往进插数字 &#xff0c;整个队列都完了以后让左边的尾指针指向右边的头指针&#xff0c;将两个链表连起来再返回即可。代码 /*** Definition for singly-linked list.* public class L…

STM32_RTOS学习笔记——1(列表与列表项)

总体RTOS笔记目录 一&#xff0c;列表与列表项&#xff08;本文&#xff09; 二&#xff0c;待定 视频参考&#xff1a;B站野火 一&#xff0c;C语言列表概念 列表就是C语言中的链表&#xff0c;链表就如同下面的衣架一样&#xff0c;需要的各种内容可以参考 C语言链表可…

软件测试必备 - 14个接口与自动化测试练习网站

随着互联网和移动应用的快速发展,接口和自动化测试的重要性日益凸显。越来越多的企业开始重视API测试,因为它不仅能提升开发效率,还能确保系统的稳定性和安全性。这些练习网站为测试人员提供了宝贵的资源,帮助他们掌握必要的技能,应对日益复杂的测试需求。 在软件测试的世…

非关系型数据库MongoDB的基础操作

MongoDB优点: 1.MongoDB的提供了一个面向文档存储&#xff0c;操作起来比较简单和容易。 2.如果负载的增加&#xff0c;它可以分布在计算机网络中的其他节点上这就是所 谓的分片。 3. MongoDB支持各种编程语言:RUBY&#xff0c;PYTHON&#xff0c;JAVA&#xff0c;C&#xf…

昇思25天学习打卡营第11天|xiaoyushao

今天分享ResNet50迁移学习。 在实际应用场景中&#xff0c;由于训练数据集不足&#xff0c;所以很少有人会从头开始训练整个网络。普遍的做法是&#xff0c;在一个非常大的基础数据集上训练得到一个预训练模型&#xff0c;然后使用该模型来初始化网络的权重参数或作为固定特征提…

git 推送时出现错误 Locking support detected on remote “origin“

背景&#xff1a;代码托管是局域网搭建的gitlab 按照提示配置 lfs.locksverify true 还是没有用。 网上搜索了一番&#xff0c;其中有人提到可能时服务器磁盘满了&#xff0c;连到服务器上 df -h 查看&#xff0c; 发现根目录已经写满了&#xff1a; 使用命令行&#xff1a; d…