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

Pytorch:view()、permute()和contiguous()

pytorch contiguous

1 官方中英文doc:

torch.Tensor.contiguous (Python method, in torch.Tensor)
torch.Tensor.is_contiguous (Python method, in torch.Tensor)

1.1 contiguous() → Tensor

Returns a contiguous tensor containing the same data as self tensor. If self tensor is contiguous, this function returns the self tensor.

1.2 contiguous() → Tensor

返回一个内存连续的有相同数据的tensor,如果原tensor内存连续,则返回原tensor;

2 pytorch contiguous的使用

contiguous一般与transpose,permute,view搭配使用:使用transpose或permute进行维度变换后,调用contiguous,然后方可使用view对维度进行变形(如:tensor_var.contiguous().view() ),

示例如下:

x = torch.Tensor(2,3)
y = x.permute(1,0)         # permute:二维tensor的维度变换,此处功能相当于转置transpose
y.view(-1)                 # 报错,view使用前需调用contiguous()函数
y = x.permute(1,0).contiguous()
y.view(-1)                 # 不报错

具体原因有两种说法:

  • 1 transpose、permute等维度变换操作后,tensor在内存中不再是连续存储的,而view操作要求tensor的内存连续存储,所以需要contiguous来返回一个contiguous copy;
  • 2 维度变换后的变量是之前变量的浅拷贝,指向同一区域,即view操作会连带原来的变量一同变形,这是不合法的,所以也会报错;也即contiguous返回了tensor的深拷贝contiguous copy数据;

view()、permute()和contiguous() 具体用法和区别

1. view()

view() 变换维度,把原先tensor中的数据按行优先的顺序排成一维数据,然后按照输入的参数组合成其他维度的tensor。

import torch
a=torch.Tensor([[[1,2,3],[4,5,6]]]) # torch.Size([1, 2, 3])
print(a.view(3,2))                  # torch.Size([3, 2])

输出:

tensor([[1., 2.],[3., 4.],[5., 6.]])

2. permute()

permute() 利用索引将tensor中的维度进行调换
b=a.permute(2,0,1) permute里的参数对应的是张量a的维度索引,利用索引来对内部数据调换。
a.permute(2,0,1):把 a 的最后一个维度放到最前面。

import torch
inputs = torch.Tensor([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print("inputs:", inputs, inputs.shape)

输出:

inputs: tensor([[[ 1.,  2.,  3.],[ 4.,  5.,  6.]],[[ 7.,  8.,  9.],[10., 11., 12.]]]) torch.Size([2, 2, 3])outputs tensor([[[ 1.,  4.],[ 2.,  5.],[ 3.,  6.]],[[ 7., 10.],[ 8., 11.],[ 9., 12.]]]) torch.Size([2, 3, 2])

3. contiguous()

在pytorch中只有很少几个操作是不改变tensor内容本身的,大多数操作不进行数据拷贝和数据的改变,变的是原数据。例如:narrow()、view()、expand()和transpose()等。

例如使用transpose()进行转置操作时,pytorch并不会创建新的、转置后的tensor,而是修改了tensor中的一些属性(也就是原数据),使得此时的offset和stride是与转置tensor相对应的。转置的tensor和原tensor的内存是共享的

举个栗子:

import torchx = torch.randn(3, 2)
y = torch.transpose(x, 0, 1)print("修改前:")
print("x:", x)
print("y:", y)y[0, 0] = 11
print("\n修改后:")
print("x:", x)
print("y:", y)

运行结果:

原数据:

x: tensor([ [ 0.5287,  0.8814],[ 1.2752,  1.9832],[ 1.9872, -1.2719]])
y: tensor([[ 0.5287,  1.2752,  1.9872],[ 0.8814,  1.9832, -1.2719]])

重定义后:

x: tensor([[11.0000,  0.8814],[ 1.2752,  1.9832],[ 1.9872, -1.2719]])
y: tensor([[11.0000,  1.2752,  1.9872],[ 0.8814,  1.9832, -1.2719]])

重点!重点!重点!!

可以看到,我们重新定义了 y 元素值的同时,x元素的值也发生了变化。因此tensor中数据还是在内存中一块区域里,只是布局的问题!为什么这么说:因为,**y里面数据布局的方式和从头开始创建一个常规的tensor布局的方式是不一样的。**这个可能只是python中之前常用的浅拷贝,y还是指向x变量所处的位置,只是说记录了transpose这个变化的布局。

如果想要断开这两个变量之间的依赖(x本身是contiguous的),就要使用contiguous()针对x进行变化,感觉上就是我们认为的深拷贝

当调用contiguous()时,会强制拷贝一份tensor,让它的布局和从头创建的一模一样,但是两个tensor完全没有联系。还是上面的栗子:

import torchx = torch.randn(3, 2)
y = torch.transpose(x, 0, 1).contiguous()
print("原数据:")
print("x:", x)
print("y:", y)y[0, 0] = 11
print("\n重定义后:")
print("x:", x)
print("y:", y)

运行结果:

原数据:

x: tensor([[ 2.5966, -0.7265],[ 0.0200,  0.5726],[-0.8865, -0.4727]])
y: tensor([[ 2.5966,  0.0200, -0.8865],[-0.7265,  0.5726, -0.4727]])

重定义后:

x: tensor([[ 2.5966, -0.7265],[ 0.0200,  0.5726],[-0.8865, -0.4727]])
y: tensor([[11.0000,  0.0200, -0.8865],[-0.7265,  0.5726, -0.4727]])

可以看到对y使用了contiguous()后,改变y的值,对x没有任何影响!

参考:
https://zhuanlan.zhihu.com/p/545769141
https://zhuanlan.zhihu.com/p/64376950

相关文章:

  • 景联文科技加入中国人工智能产业联盟(AIIA)数据委员会
  • 详细学习Pyqt5的9种显示控件
  • 风控交易系统跟单系统资管软件都有哪些功能特点?
  • vue七牛云上传图片
  • leetcode 202 快乐数
  • AcWing 3555:二叉树(北京大学考研机试题)→公共父结点
  • PRCD-1229 : An attempt to access configuration of database
  • String转Date,Date转String
  • Python 潮流周刊#29:Rust 会比 Python 慢?!
  • 腾讯云双十二优惠活动有哪些?详细攻略来了!
  • Docker 安装部署 Sentinel Dashboard
  • enable_shared_from_this使用介绍
  • 【征稿倒计时十天,ACM独立出版,有确定的ISBN号,ei检索稳且快】
  • 时间序列数据压缩算法简述
  • SocialSelling社交销售1+5+1方法论系列:社交销售价值何在
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • cookie和session
  • CSS实用技巧干货
  • docker-consul
  • JavaScript 奇技淫巧
  • Javascript设计模式学习之Observer(观察者)模式
  • Laravel5.4 Queues队列学习
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • Python 反序列化安全问题(二)
  • V4L2视频输入框架概述
  • 初识 beanstalkd
  • 对超线程几个不同角度的解释
  • 给github项目添加CI badge
  • 基于web的全景—— Pannellum小试
  • 力扣(LeetCode)21
  • 山寨一个 Promise
  • 通过npm或yarn自动生成vue组件
  • 想使用 MongoDB ,你应该了解这8个方面!
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • #define 用法
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (十五)使用Nexus创建Maven私服
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • **PHP分步表单提交思路(分页表单提交)
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET 命令行参数包含应用程序路径吗?
  • .NET中GET与SET的用法
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [.NET]桃源网络硬盘 v7.4
  • [2019/05/17]解决springboot测试List接口时JSON传参异常
  • [2021 蓝帽杯] One Pointer PHP