Pytorch的数据类型(张量)及其属性和运算方式

发布时间:2021-09-17 18:23:10

基本数据

Pytorch的基本数据类型为Tensor(张量),本质上是一种包含单一数据类型元素的多为矩阵。从使用角度看,其与numpy的ndarrays类似,两者之间也可以相互转换,区别是tensor支持在GPU上运算。


Tensor数据类型

与其他数据一样,tensor也包括多种数据类型,其中包括7种cpu tensor类型和8种gpu tensor类型。在使用时我们要根据模型所需的精度和硬件设备的条件选取合适的数据类型。


Tensor数据类型介绍
数据类型CPU TensorGPU Tensor
32位浮点torch.FloatTensortorch.cuda.FloatTensor
64位浮点torch.doubleTensortorch.cuda.doubleTensor
16位半浮点/torch.cuda.halfTensor
8位无符号整型torch.byteTensortorch.cuda.byteTensor
8位有符号整型torch.charTensortorch.cuda.charTensor
16位有符号整型torch.shortTensortorch.cuda.shortTensor
32位有符号整型torch.intTensortorch.cuda.intTensor
64位有符号整型torch.longTensortorch.cuda.longTensor

pytorch可以通过set_default_tensor_type函数设置默认全局使用的Tensor类型,但是在局部使用完后所需类型后,还需要重新设置为全局使用的Tensor类型。


Tensor的创建方式

Tensor有多种创建方法,最基础的有torch.Tensor(M, N),默认创建一个数据类型为float的M*N的矩阵;如果想要指定数据类型创建,可以使用torch.DoubleTensor(M, N)。除此之外,类似于numpy的ndarrays类似,torch.zeros(M, N)、torch.ones(M, N)、torch.eye(M, N)、torch.randn(M, N)、torch.Tensor([[1, 2], [4, 5]])以及顺序排列张量torch.arange(0, 5, 1)、随机排列张量torch.randperm(M)…


>>> a=torch.Tensor(2,2)
>>> a
tensor(1.00000e-18 * [[-8.2390, 0.0000], [ 0.0000, 0.0000]])
>>> b = torch.DoubleTensor(2,2)
>>> b
tensor(1.00000e-310 * [[ 0.0000, 0.0000], [ 6.9452, 0.0000]], dtype=torch.float64)
# 使用Python的list序列进行创建
>>> c = torch.Tensor([[1, 2], [3, 4]])
>>> c
tensor([[ 1., 2.], [ 3., 4.]])
# 使用zeros()函数,所有元素均为0
>>> d = torch.zeros(2, 2)
>>> d
tensor([[ 0., 0.], [ 0., 0.]])
# 使用ones()函数,所有元素均为1
>>> e = torch.ones(2, 2)
>>> e
tensor([[ 1., 1.], [ 1., 1.]])
# 使用eye()函数,对角线元素为1,不要求行列数相同,生成二维矩阵
>>> f = torch.eye(2, 2)
>>> f
tensor([[ 1., 0.], [ 0., 1.]])
# 使用randn()函数,生成随机数矩阵
>>> g = torch.randn(2, 2)
>>> g
tensor([[-0.3979, 0.2728], [ 1.4558, -0.4451]])
# 使用arange(start, end, step)函数,表示从start到end,间距为step,一维向量
>>> h = torch.arange(1, 6, 2)
>>> h
tensor([ 1., 3., 5.])
# 使用linspace(start, end, steps)函数,表示从start到end,一共steps份,一维向量
>>> i = torch.linspace(1, 6, 2)
>>> i
tensor([ 1., 6.])
# 使用randperm(num)函数,生成长度为num的随机排列向量
>>> j = torch.randperm(4)
>>> j
tensor([ 1, 2, 0, 3])
# PyTorch 0.4中增加了torch.tensor()方法
# 参数可以为Python的list、NumPy的ndarray等
>>> k = torch.tensor([1, 2, 3])
>>> k
>>> tensor([1, 2, 3)

在对网络模型进行设计和调试的时候,我们需要查看每层tensor的维度或者tensor中的元素总数,查看维度可以使用Tensor.shape或者size()函数实现,查看元素总个数通过Tensor.numel()或者Tensor.nelement()函数完成。


>>> a=torch.randn(2,2)
>>> a.shape # 使用shape查看Tensor维度
torch.Size([2, 2])
>>> a.size() # 使用size()函数查看Tensor维度
torch.Size([2, 2])
>>> a.numel() # 使用Tensor.numel()查看Tensor元素数量
>>> 4
>>> a.nelement() # 使用Tensor.nelement()查看Tensor元素数量
>>> 4

Tensor的组合与分块

在一些较为复杂的网络模型中,我们需要将各层网络的输入输出进行组合或者分块进行运算。
组合主要有torch.cat()和torch.stack()两个函数。torch.cat()是沿着已有数据的某一维进行拼接,操作后数据的总维度不变。在进行拼接时,除了拼接的维度外,其余维度必须相同才可以。而torch.stack()函数是指增加新的维度,并按照指定的维度进行叠加。


# 创建两个2×2的Tensor
>>> a=torch.Tensor([[1,2],[3,4]])
>>> a
tensor([[ 1., 2.], [ 3., 4.]])
>>> b = torch.Tensor([[5,6], [7,8]])
>>> b
tensor([[ 5., 6.], [ 7., 8.]])
# 以第一维进行拼接,则变成4×2的矩阵
>>> torch.cat([a,b], 0)
tensor([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]])
# 以第二维进行拼接,则变成2×4的矩阵
>>> torch.cat([a,b], 1)
tensor([[ 1., 2., 5., 6.], [ 3., 4., 7., 8.]])
# 以第0维进行stack,叠加的基本单位为序列本身,即a与b,因此输出[a, b],输出维度为2×2×2
>>> torch.stack([a,b], 0)
tensor([[[ 1., 2.], [ 3., 4.]],
[[ 5., 6.], [ 7., 8.]]])
# 以第1维进行stack,叠加的基本单位为每一行,输出维度为2×2×2
>>> torch.stack([a,b], 1)
tensor([[[ 1., 2.], [ 5., 6.]],
[[ 3., 4.], [ 7., 8.]]])
# 以第2维进行stack,叠加的基本单位为每一行的每一个元素,输出维度为2×2×2
>>> torch.stack([a,b], 2)
tensor([[[ 1., 5.], [ 2., 6.]],
[[ 3., 7.], [ 4., 8.]]])

Tensor的分块也是有两个函数实现,分别是torch.chunk(Tensor, 子张量的数量, dim)和torch.split(Tensor, 子张量的大小, dim)。


>>> a=torch.Tensor([[1,2,3],[4,5,6]])
>>> a
tensor([[ 1., 2., 3.], [ 4., 5., 6.]])
# 使用chunk,沿着第0维进行分块,一共分两块,因此分割成两个1×3的Tensor
>>> torch.chunk(a, 2, 0)
(tensor([[ 1., 2., 3.]]), tensor([[ 4., 5., 6.]]))
# 沿着第1维进行分块,因此分割成两个Tensor,当不能整除时,最后一个的维数会小于前面的
# 因此第一个Tensor为2×2,第二个为2×1
>>> torch.chunk(a, 2, 1)
(tensor([[ 1., 2.], [ 4., 5.]]), tensor([[ 3.], [ 6.]]))
# 使用split,沿着第0维分块,每一块维度为2,由于第一维维度总共为2,因此相当于没有分割
>>> torch.split(a, 2, 0)
(tensor([[ 1., 2., 3.],
[ 4., 5., 6.]]),)
# 沿着第1维分块,每一块维度为2,因此第一个Tensor为2×2,第二个为2×1
>>> torch.split(a, 2, 1)
(tensor([[ 1., 2.],
[ 4., 5.]]),
tensor([[ 3.],
[ 6.]]))
# split也可以根据输入的list进行自动分块,list中的元素代表了每一个块占的维度
>>> torch.split(a, [1,2], 1)
(tensor([[ 1.],
[ 4.]]),
tensor([[ 2., 3.],
[ 5., 6.]]))

Tensor的索引与变形

索引主要有下标索引、表达式索引、使用torch.where()和torch.clamp()进行选择性索引。这里主要介绍表达式索引和选择性索引。


>>> a = torch.Tensor([[0,1], [2, 3]])
>>> a
tensor([[ 0., 1.], [ 2., 3.]])
# 选择a中大于0的元素,返回和a相同大小的Tensor,符合条件的置1,否则置0
>>> a>0
tensor([[ 0, 1], [ 1, 1]], dtype=torch.uint8)
# 选择符合条件的元素并返回,等价于torch.masked_select(a, a>0)
>>> a[a>0]
tensor([ 1., 2., 3.])
# 选择非0元素的坐标,并返回
>>> torch.nonzero(a)
tensor([[ 0, 1], [ 1, 0], [ 1, 1]])
# torch.where(condition, x, y),满足condition的位置输出x,否则输出y
>>> torch.where(a>1, torch.full_like(a, 1), a)
tensor([[ 0., 1.], [ 1, 1.]])
# 对Tensor元素进行限制可以使用clamp()函数,示例如下,限制最小值为1,最大值为2
>>> a.clamp(1,2)
tensor([[ 1., 1.], [ 2., 2.]])

其中这些函数的参数都必须是张量,否则无法参与运算。
变形操作主要是改变Tensor的维度,以适应不同网络层结构之间的运算。Pytorch中主要有四种方法实现变形操作。


变形操作功能
view()、resize()、reshape()改变Tensor的形状,不改变元素个数
permute()、transpose()维度之间交换位置
squeeze()、unsqueeze()处理size为1的维度
expand()、expand_as()复制元素来拓展维度

view()、resize()、reshape()可以在不改变元素数量的前提下任意改变tensor的形状,而且变换之后共享内存


>>> a=torch.arange(1,5)
>>> a
tensor([ 1., 2., 3., 4.])
# 分别使用view()、resize()及reshape()函数进行维度变换
>>> b=a.view(2,2)
>>> b
tensor([[ 1., 2.], [ 3., 4.]])
>>> c=a.resize(4,1)
>>> c tensor([[ 1.], [ 2.], [ 3.], [ 4.]])
>>> d=a.reshape(4,1)
>>> d
tensor([[ 1.], [ 2.], [ 3.], [ 4.]])
# 改变了b、c、d的一个元素,a也跟着改变了,说明两者共享内存
>>> b[0,0]=0
>>> c[1,0]=0
>>> d[2,0]=0
>>> a
tensor([ 0., 0., 0., 4.])

如果想要改变元素的个数,可以使用resize_()函数,超出原tensor的元素个数,则多出来的添加0;如果少于原tensor的元素个数,则会保留隐藏剩余的元素。值得一提的是,resize_()之后得到的tensor会重新分配内存。


>>> a.resize_(5, 1)
tensor([[1],
[2],
[3],
[4],
[0]])
>>> a.resize_(2, 1)
tensor([[1],
[2]])

transpose()函数可以将指定的两个维度的元素进行转置,而 permute()函数则可以按照给定的维度进行维度变换。


>>> a=torch.randn(2,2,2)
>>> a
tensor([[[-0.9268, 0.6006],
[ 1.0213, 0.5328]],
[[-0.7024, 0.7978],
[ 1.0553, -0.6524]]])
# 将第0维和第1维的元素进行转置
>>> a.transpose(0,1)
tensor([[[-0.9268, 0.6006],
[-0.7024, 0.7978]],
[[ 1.0213, 0.5328],
[ 1.0553, -0.6524]]])
# 按照第2、1、0的维度顺序重新进行元素排列
>>> a.permute(2,1,0)
tensor([[[-0.9268, -0.7024],
[ 1.0213, 1.0553]],
[[ 0.6006, 0.7978],
[ 0.5328, -0.6524]]])

在实际的应用中,经常需要增加或减少Tensor的维度,尤其是维度为1的情况,这时候可以使用squeeze()与unsqueeze()函数,前者用于去除 size为1的维度,而后者则是将指定的维度的size变为1。


>>> a=torch.arange(1,4)
>>> a.shape
torch.Size([3])
# 将第0维变为1,因此总的维度为1、3
>>> a.unsqueeze(0).shape
torch.Size([1, 3])
# 第0维如果是1,则去掉该维度,如果不是1则不起任何作用
>>> a.unsqueeze(0).squeeze(0).shape
torch.Size([3])

有时需要采用复制元素的形式来扩展Tensor的维度,这时expand就 派上用场了。expand()函数将size为1的维度复制扩展为指定大小,也可以使用expand_as()函数指定为示例Tensor的维度。


>>> a=torch.randn(2,2,1)
>>> a
tensor([[[ 0.5379],
[-0.6294]],
[[ 0.7006],
[ 1.2900]]])
# 将第2维的维度由1变为3,则复制该维的元素,并扩展为3
>>> a.expand(2,2,3)
tensor([[[ 0.5379, 0.5379, 0.5379],
[-0.6294, -0.6294, -0.6294]],
[[ 0.7006, 0.7006, 0.7006],
[ 1.2900, 1.2900, 1.2900]]])

值得注意的是,在进行Tensor操作时,有些操作如transpose()、permute()等可能会把Tensor在内存中变得不连续,而有些操作如view()等是需要Tensor内存连续的,这种情况下需要使用contiguous()操作先将内存变为连续的。在PyTorch v0.4版本中增加了reshape()操作,可以看做是 Tensor.contiguous().view()。


Tensor的排序与取极值

tensor的排序功能主要靠sort()函数实现,可选择的沿着某一维度进行排序,并返回排序后的tensor以及对应的索引位置。max()和min()函数则是沿着指定维度选择最大与最小元素,返回该元素及其对应的索引位置。


>>> a = torch.randn(3, 3)
>>> a
tensor([[-0.2316, -0.0734, 2.1122],
[-0.2480, -0.7257, -0.2866],
[-0.2092, 0.1340, 1.5125]])
# 0是指沿着每行进行比较选择排序,True是指升序,False是指降序
>>> a.sort(0, True)
torch.return_types.sort(
values=tensor([[-0.2092, 0.1340, 2.1122],
[-0.2316, -0.0734, 1.5125],
[-0.2480, -0.7257, -0.2866]]),
indices=tensor([[2, 2, 0],
[0, 0, 2],
[1, 1, 1]]))
>>> a.max(0)
torch.return_types.max(
values=tensor([-0.2092, 0.1340, 2.1122]),
indices=tensor([2, 2, 0]))
>>> a.min(0)
torch.return_types.min(
values=tensor([-0.2480, -0.7257, -0.2866]),
indices=tensor([1, 1, 1]))
>>>

此外,还有一些元素级别的运算,例如:abs(), sqrt(), log(), pow()和三角函数等。


Tensor的自动广播机制和向量化

自动广播机制是指不同形状的tensor进行运算时,可自动扩展到较大张量的形状,在进行运算。广播机制的前提是任何一个张量至少有一个维度,且从尾部遍历tensor维度时,两者维度要么相等,要么其中一个是1或者不存在
向量化的作用是进行并行运算,避免元素级的运算,从而减少for循环带来的低效率。


Tensor的内存共享

Pytorch为了实现高校运算,提供了一些原地操作符,不经过复制,直接在原来的内存上进行计算。主要有以下三种内存共享的情况。

这里重点说一下常用的Tensor与numpy的ndarray之间的相互转换。


>>> a=torch.randn(1,2)
>>> a
tensor([[-0.3228, 1.2726]])
# Tensor转为NumPy
>>> b=a.numpy()
>>> b
array([[-0.32281783, 1.2725701 ]], dtype=float32)
# NumPy转为Tensor
>>> c=torch.from_numpy(b)
>>> c
tensor([[-0.3228, 1.2726]])
#Tensor转为list
>>> d=a.tolist()
>>> d
[[-0.3228178322315216, 1.2725701332092285]]

Tensor数据类型转换

torch.set_default_tensor_type("torch.DoubleTensor")

对于Tensor之间的类型转换,可以通过type(new_type)、type_as()、int()等多种方式进行操作。其中使用较多的有type_as()函数方法,此方法不需要指定数据类型。


# 创建新Tensor,默认类型为torch.FloatTensor
>>> a = torch.Tensor(2, 2)
>>> a
tensor(1.00000e-36 * [[-4.0315, 0.0000], [ 0.0700, 0.0000]])
# 使用int()、float()、double()等直接进行数据类型转换
>>> b = a.double()
>>> b
tensor(1.00000e-36 * [[-4.0315, 0.0000], [ 0.0700, 0.0000]], dtype=torch.float64)
# 使用type()函数
>>> c = a.type(torch.DoubleTensor)
>>> c
tensor(1.00000e-36 * [[-4.0315, 0.0000], [ 0.0700, 0.0000]], dtype=torch.float64)
# 使用type_as()函数
>>> d = a.type_as(b)
>>> d
tensor(1.00000e-36 * [[-4.0315, 0.0000], [ 0.0700, 0.0000]], dtype=torch.float64)

总结

这篇文章主要回顾了一下Pytorch的基本数据----张量,张量的数据类型,张量的创建方式,不同数据类型的张量之间可以通过int(),type(), type_as()等互相转换,张量的维度查看以及维度、形状变换,张量的组合与分块,张量的索引方式,张量的排序与取极值以及元素级别的运算等,张量的自动广播机制和向量化,还有张量的高效工作方式----内存共享。

相关文档

  • 荣耀有哪些大屏手机
  • 高三如何快速提高生物成绩生物学习方法有哪些
  • 十二星座完美分析
  • 红烧鱼块的家常做法推荐
  • 2011年4月24
  • 五子棋必胜开局
  • 关于水瓶座的伤感句子
  • 校园精彩的励志名言大全
  • 小学数学教师实习心得体会
  • 王峰记忆法解密教你轻松提升记忆力
  • 早会分享小故事
  • 农村房屋买卖合同标准版范本
  • 把JDK 6/7/8 安装到 Ubuntu 14.10/ 14.04 / 13.04 / 12.10 / 12.04 Debian / LinuxMint
  • 雪纳瑞好养吗?可以长多大呀?
  • 我们班的大明星350字
  • 学会迎难而上的格言大全
  • 考研座右铭励志51句
  • 抓实党建工作提升学校内涵——小学党支部工作总结
  • 《一代才子钱钟书》读后感
  • 中国剪纸手抄报怎么做
  • Unity 智能AI的简单例子
  • nginx启动报错(1113: No mapping for the Unicode character exists in the target multi-byte code page)
  • 唯美爱情空间说说句子
  • MySQL的information_schema数据库是什么,有什么作用
  • 毕业生在外实习请假条精选多篇
  • 使用QT连接Oracle数据库总结
  • 读《新手老师上路?——幼儿教师入门必读》有感范文
  • 结婚证朋友圈一般怎么发
  • 笔记本的D盘和E盘不见了是怎么回事
  • 【软件周刊第 37 期】Fedora 26 正式版发布;Redis 4.0.0 正式发布,4.0 系列的首个稳定版...
  • 猜你喜欢

  • 以革命精神提升大学生创新创业意识的途径探析
  • C语言 sleep wait 函数 区别
  • 开原市鑫瑞商贸有限公司(企业信用报告)- 天眼查
  • 中秋节的夜景_六年级作文
  • 新人教部编版一年级语文下册 2 我多想去看看 ppt公开课优课课件
  • 2014年6月禁毒活动简报
  • 对外汉语文化课(英文版茶道介绍)
  • 腊八节为什么要吃腊八粥
  • 高二政治感受文化影响2(新编2019)
  • 2018年大学生学*总结:奋斗不止
  • 住院病人征求意见表
  • 最新人教版初中数学九年级上册 2章 二次函数小结与复习(课时)教案(1)(1)
  • ElasticSearch48:初识搜索引擎_上机动手实战基于scroll技术滚动搜索大量数据
  • 纯植物原料籽粒苋酸乳的研制
  • (云南)人教版七年级数学下册同步练*课件第7章达标测
  • 女人自强的句子
  • Dissipative Particle Dynamics-1758825109000381
  • 2017年小学五年级上学期班主任工作计划
  • 用通俗的话说明docker是什么
  • 2018_2019学年高中物理第13章光13.7_13.8光的颜色色散激光课件新人教版选修3_42019022644
  • 欧舒丹哪个系列最好?欧舒丹蜡菊系列好用吗
  • 人教英语七下:unit4 Unit 4 Dont't eat in class单元同步练*
  • 统计局社会治安综合治理半年工作总结
  • 五年级下册英语课件-Unit 2 Vacation Plans 6广东开心英语
  • 【精品推荐】最新2017人教版2013第一学期北师大版小学五年级数学期中试卷
  • 2018年大学生干部试用期工作总结范文
  • 2009年上半年超市述职报告
  • 开运竹摆放风水禁忌
  • 留着给宝宝做饭用的
  • 上海张行印刷装订有限公司企业信用报告-天眼查
  • 小学三年级诗歌:和我们一样享受春天
  • 情绪化过于激动的辞职报告
  • 浅议智能楼宇系统集成设计的应用
  • 2019-2020学年八年级数学上册 4.1 *方根教学案1 苏科版.doc
  • 自定义View时,用到Paint Canvas的一些温故,简单的View Animation(动画二,“大大姐”的简单变动)...
  • 药物临床试验质量控制的若干思考及实践_元唯安
  • 初中英语任务型教学的思考
  • 卡西欧手表一晃分针就转是怎么回事
  • 九月份德育个人工作总结与乡(镇)长2018年度个人工作总结汇编.doc
  • 重庆恒邦卓越资产管理有限公司企业信用报告-天眼查
  • 骨科康复患者的心理护理
  • 6月8日 《金正昆谈礼仪之介绍礼仪》 金正昆
  • 电脑版