Pytorch: view()和reshape()的区别?他们与continues()的关系是什么? 2023-01-05 03:56 509阅读 0赞 ### 一、概要 ### #### 1. 两者相同之处 #### view()和reshape()在pytorch中都可以用来重新调整tensor的形状。 #### 2. 两者不同之处 #### 1). view()产生的tensor总是和原来的tensor共享一份相同的数据,而reshape()在新形状满足一定条件时会共享相同一份数据,否则会复制一份新的数据。 2). 两者对于原始tensor的连续性要求不同。reshape()不管tensor是否是连续的,都能成功改变形状。而view()对于不连续的tensor(),需要新形状shape满足一定条件才能成功改变形状,否则会报错。 transpose, permute 等操作会改变 tensor的连续性,在新形状shape不满足一定的情况下会报错。(注:有的人说view()函数只用于连续的tensor,事实上这是不准确的,可看下面解释) #### 3. 使用指南 #### 如果你想要新的tensor和旧的tensor始终共享一份数据,使用view() 若只是单纯的改变形状,不要求共享数据,reshape()不容易出错 大部分情况下,了解以上即足够了,如果想要知道: > view(shape)在新形状shape满足哪些情况下才能成功改变形状 > view和reshape的工作机制 你可以接着看下面的介绍。 ### 二、Tensor的连续性 ### tensor的连续性是指逻辑上相邻的元素在内存中是否是连续存储的,如是,则称其是连续的,反之则是不连续的。我们可以调用tensor.is\_contiguous()判断该tensor是否是连续的。下面通过举例说明。 当我们构造一个tensor如下: a = torch.arange(12).reshape(3,4) **在没有任何transpose的情况下** 逻辑上,它看起来是这样的: ![在这里插入图片描述][20210111154932312.png_pic_center] 实际上,在电脑内存中,a的存储是下面这样的: ![在这里插入图片描述][20210111155026848.png_pic_center] 由于逻辑上相邻的元素, 在内存上也是相邻的,我们称这个tensor是连续的(contiguous tensor),此时a.is\_contiguous() 为True. **在调用b=a.T之后** 逻辑上,他看起来是这样的: ![在这里插入图片描述][20210111155554958.png_pic_center] 但实际上,在电脑内存中,b的存储仍然是下面这样的: ![在这里插入图片描述][20210111155026848.png_pic_center] 为什么存储跟a是一样的呢?这是由转置函数本身的机制决定的, ![在这里插入图片描述][20210111155955184.png] 也就是说转置之后的tensor b和原来的tensor a共享一份数据,只是访问的方式改变了。由于此时b逻辑上相邻的两个元素在内存中并不连续存储,于是我们称tensor b是不连续的,此时b.is\_contiguous() 为False. ### 三、 view()和reshape()的工作机制 ### #### 1. view()的工作机制 #### 这里的view和数据库中的视图(view)概念上十分类似,其本质就是不会复制一份新的数据,而是与原来的tensor或原来的数据库表共享一份相同的数据。 所以b=a.view(shape)中,tensor b与tensor a共享一份数据,修改b中的数据,a的相应元素也会改变。 上面我们说到view()对于不连续的tensor,需要新形状shape满足一定条件才能成功改变形状。那这里的条件是什么呢? 首先我们需要知道view()改变形状改的是什么,我们知道它与原tensor共享一份数据,所以数据存放顺序并没改变,它改变的是tensor的步幅(stride),步幅的改变使得新tensor有他自己的访问方式和访问顺序。 如下例所示,a = torch.tensor(\[1,2,3,4\]), 当访问下一个数据的时候,指针每次移动1,我们将这个移动距离定义为stride,而在view之后,这个步幅会变为(2,1),从而支持在原始内存数据上用新的访问方式b\[i,j\]而不是a\[i\]来访问数据。 >>>a = torch.tensor([1,2,3,4]) >>>a.stride() (1,) >>>b = a.view((2,2)) >>>b.stride() (2,1) 这里核心就在于b = a.view(shape)中的新形状shape基于不变的内存数据仍能以**固定**的步幅访问下一个元素,这样才能成功改变形状,否则若没有固定的步幅,我们无法实现元素的顺序访问,这种情况下程序会报错。 举例:比如说在第二部分中经过转置得到的tensor b, ![在这里插入图片描述][20210111155554958.png_pic_center] 我们知道它是不连续的,当我们执行b.view((12,))时就会出错 RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead. 这是因为假设我们希望通过b.view((12,))得到逻辑上连续的1维tensor(\[0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11\]) ![在这里插入图片描述][20210111181216652.png_pic_center] 而其内存上的排列顺序仍为: ![在这里插入图片描述][20210111155026848.png_pic_center] 此时假设我们逻辑上顺序访问数组,那么内存指针应当这样移动 4, 4, -7, 4, 4, -7, 4, 4, 7, 4, 4,然而此时计算机只能支持固定的步幅,无法记忆-7,7,故这样的逻辑数组是不被支持的,无法做到基于不变的内存数据仍以**固定**的步幅访问下一个元素,遂报错。 在[pytorch中文文档][pytorch]说到一个tensor必须是连续的,才能使用view函数。事实上是不对的,根据最新的英文文档和笔者的实际实践,非连续的tensor也可以使用view函数。比如: >>>a = torch.arange(12).reshape(3,4) >>>a tensor([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>>b = a.T >>>b tensor([[ 0, 4, 8], [ 1, 5, 9], [ 2, 6, 10], [ 3, 7, 11]]) >>>c = b.view((2,2,3)) >>>c tensor([[[ 0, 4, 8], [ 1, 5, 9]], [[ 2, 6, 10], [ 3, 7, 11]]]) >>>b.shape, b.stride() (torch.Size([4, 3]), (1, 4)) >>>c.shape,c.stride() (torch.Size([2, 2, 3]), (2, 1, 4)) 在英文文档中,一个tensor b,能否成功执行b.view(shape), 它归纳出以下条件: 新的shape中的各个维度的值, 1. 要么就是原始tensor的shape中的值(如上面的3) 2. 要么满足下面的条件,剩下的维度 d 0 , d 1 . . . d k d\_0,d\_1...d\_k d0,d1...dk,∀i=0,…,k−1, 相应的步幅满足: s t r i d e \[ i \] = s t r i d e \[ i + 1 \] × s i z e \[ i + 1 \] stride\[i\]=stride\[i+1\]×size\[i+1\] stride\[i\]=stride\[i\+1\]×size\[i\+1\] 比如上面c的shape,3排除后,剩下\[2,2\],只需要第一个2对应的stride满足stride\[i\]=stride\[i+1\]×size\[i+1\]即可。 所以非连续的tensor能不能进行view,要看在新的shape的条件下,我们能不能求得新的步幅支持顺序访问目标形状的tensor。在某些情况下非连续的tensor b不能进行view的症结就在于目前的tensor b已经是逻辑顺序和物理顺序不匹配,在目前的逻辑顺序上再做一次逻辑抽象,就可能会得不到一个线性映射。 #### 2. reshape()的工作机制 #### reshape()本着尽量节省内存的原件进行形状的调整。 如果新形状满足view函数所要求的条件(即基于不变的内存数据仍能以固定的新步幅访问该数据),那么这时候reshape()跟view()等价,不会复制一份新的数据。 如果新的形状不满足view函数所要求的条件(即无法求得满足条件的新步幅),这时候reshape也能工作,这时候它会将原来非连续性的tensor按逻辑顺序copy到新的内存空间(即使得要使用view函数的tensor b其逻辑数据顺序和物理数据顺序一致),然后再改变tensor b形状。 ### 四、参考资料 ### \[1\] [pytorch document][] \[2\] [PyTorch中文文档][PyTorch] \[3\] [What is the difference between contiguous and non-contiguous arrays?][What is the difference between contiguous and non-contiguous arrays] \[4\] [What’s the difference between reshape and view in pytorch?][What_s the difference between reshape and view in pytorch] \[5\] [PyTorch view和reshape的区别][PyTorch view_reshape] [20210111154932312.png_pic_center]: /images/20221119/a59fd27d23ef4292913b9eb322dc9133.png [20210111155026848.png_pic_center]: /images/20221119/519816266b114f1eb542eff52fff51d6.png [20210111155554958.png_pic_center]: https://img-blog.csdnimg.cn/20210111155554958.png#pic_center [20210111155955184.png]: https://img-blog.csdnimg.cn/20210111155955184.png [20210111181216652.png_pic_center]: https://img-blog.csdnimg.cn/20210111181216652.png#pic_center [pytorch]: https://pytorch-cn.readthedocs.io/zh/latest/package_references/Tensor/#viewargs-tensor [pytorch document]: https://pytorch.org/docs/stable/torch.html [PyTorch]: https://pytorch-cn.readthedocs.io/zh/latest/ [What is the difference between contiguous and non-contiguous arrays]: https://stackoverflow.com/questions/26998223/what-is-the-difference-between-contiguous-and-non-contiguous-arrays/26999092#26999092 [What_s the difference between reshape and view in pytorch]: https://stackoverflow.com/questions/49643225/whats-the-difference-between-reshape-and-view-in-pytorch [PyTorch view_reshape]: https://blog.csdn.net/HuanCaoO/article/details/104794075/
相关 break和continue的作用和区别是什么? 一、break和continue的作用 break和continue都是用来控制循环结构的,主要作用是停止循环。 二、break和continue的区别 1、br - 日理万妓/ 2023年09月27日 14:17/ 0 赞/ 50 阅读
相关 Pytorch: view()和reshape()的区别?他们与continues()的关系是什么? 一、概要 1. 两者相同之处 view()和reshape()在pytorch中都可以用来重新调整tensor的形状。 2. 两者不同之处 1). view 布满荆棘的人生/ 2023年01月05日 03:56/ 0 赞/ 510 阅读
相关 pytorch | transpose、permute、view、contiguous、is_contiguous、reshape transpose、contiguous、view a = torch.randn(2,3) 随机产生的23的tensor,内存是连续的,所以打印出“真” 悠悠/ 2023年01月02日 14:22/ 0 赞/ 191 阅读
相关 pytorch reshape view clone的区别 reshape view作为pytorch中torch的常用操作,有一些小细节需要注意一下。 x = torch.arange(12) print('x') 太过爱你忘了你带给我的痛/ 2022年11月18日 08:28/ 0 赞/ 179 阅读
相关 php与html的关系与区别,PHP与HTML的关系是什么? 不少来我们网站自学的小白童鞋还是有很多地方不明白,HTML和PHP有什么区别吗?为什么学习PHP要先掌握点HTML的基础知识呢?下面小编就告诉大家它们之间的关系。 ![9e6 - 日理万妓/ 2022年10月22日 09:26/ 0 赞/ 206 阅读
相关 break与continue的区别是什么? 1、break:终止,跳出,结束循环(可以作用在任何地方)。常与switch分支结构合用。 2、continue:结束本次的循环,进入下一次的循环(只能运 「爱情、让人受尽委屈。」/ 2022年05月22日 11:42/ 0 赞/ 224 阅读
相关 什么是PHP-fpm?什么是fastcgi?他们之间有什么关系? 要理解fastcgi和PHP-fpm都是干什么的,首先要明白PHP的几种运行模式: 参考上一篇[https://mp.csdn.net/postedit/81302818][ 桃扇骨/ 2022年05月18日 06:29/ 0 赞/ 585 阅读
相关 AMD是什么?CMD是什么?他们之间有哪些区别 AMD是什么?CMD是什么?他们之间有哪些区别 AMD 是 RequireJS 在推广过程中对模块定义提出的概念。 CMD 是 SeaJS 在推广过程中对模块定义提出的 男娘i/ 2021年08月13日 17:08/ 0 赞/ 1121 阅读
相关 pytorch 在sequential中使用view来reshape pytorch中view是tensor方法,然而在sequential中包装的是nn.module的子类,因此需要自己定义一个方法: import torch.nn 待我称王封你为后i/ 2021年06月24日 15:59/ 0 赞/ 484 阅读
相关 什么是get/post?怎么样理解和他们?他们之间的区别又是什么? get请求不安全的,而且有长度限制。而post请求安全的且没有长度限制。get请求参数可以放在地址栏中,当下次在请求时,参数依旧可以再次携带。而post参数只在当前请求携... 朱雀/ 2021年05月10日 02:40/ 0 赞/ 114910 阅读
还没有评论,来说两句吧...