2. PyTorch——Tensor和Numpy

2.1Tensor和Numpy

Tensor和Numpy数组之间具有很高的相似性,彼此之间的互操作也非常简单高效。需要注意的是,Numpy和Tensor共享内存。由于Numpy历史悠久,支持丰富的操作,所以当遇到Tensor不支持的操作时,可先转成Numpy数组,处理后再转回tensor,其转换开销很小。

import numpy as np
a = np.ones([2, 3],dtype=np.float32)
a
array([[1., 1., 1.],
       [1., 1., 1.]], dtype=float32)
b = t.from_numpy(a)
b
tensor([[1., 1., 1.],
        [1., 1., 1.]])
b = t.Tensor(a) # 也可以直接将numpy对象传入Tensor
b
tensor([[1., 1., 1.],
        [1., 1., 1.]])
a[0, 1]=100
b
tensor([[  1., 100.,   1.],
        [  1.,   1.,   1.]])
c = b.numpy() # a, b, c三个对象共享内存
c
array([[  1., 100.,   1.],
       [  1.,   1.,   1.]], dtype=float32)

注意: 当numpy的数据类型和Tensor的类型不一样的时候,数据会被复制,不会共享内存。

a = np.ones([2, 3])
# 注意和上面的a的区别(dtype不是float32)
a.dtype
dtype('float64')
b = t.Tensor(a) # 此处进行拷贝,不共享内存
b.dtype
torch.float32
c = t.from_numpy(a) # 注意c的类型(DoubleTensor)
c
tensor([[1., 1., 1.],
        [1., 1., 1.]], dtype=torch.float64)
a[0, 1] = 100
b # b与a不共享内存,所以即使a改变了,b也不变
tensor([[1., 1., 1.],
        [1., 1., 1.]])
c # c与a共享内存
tensor([[  1., 100.,   1.],
        [  1.,   1.,   1.]], dtype=torch.float64)

注意: 不论输入的类型是什么,t.tensor都会进行数据拷贝,不会共享内存

tensor = t.tensor(a) 
tensor[0,0]=0
a
array([[  1., 100.,   1.],
       [  1.,   1.,   1.]])

广播法则(broadcast)是科学运算中经常使用的一个技巧,它在快速执行向量化的同时不会占用额外的内存/显存。
Numpy的广播法则定义如下:

  • 让所有输入数组都向其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐
  • 两个数组要么在某一个维度的长度一致,要么其中一个为1,否则不能计算
  • 当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状

PyTorch当前已经支持了自动广播法则,但是笔者还是建议读者通过以下两个函数的组合手动实现广播法则,这样更直观,更不易出错:

  • unsqueeze或者view,或者tensor[None],:为数据某一维的形状补1,实现法则1
  • expand或者expand_as,重复数组,实现法则3;该操作不会复制数组,所以不会占用额外的空间。

注意,repeat实现与expand相类似的功能,但是repeat会把相同数据复制多份,因此会占用额外的空间。

a = t.ones(3, 2)
b = t.zeros(2, 3,1)
# 自动广播法则
# 第一步:a是2维,b是3维,所以先在较小的a前面补1 ,
#               即:a.unsqueeze(0),a的形状变成(1,3,2),b的形状是(2,3,1),
# 第二步:   a和b在第一维和第三维形状不一样,其中一个为1 ,
#               可以利用广播法则扩展,两个形状都变成了(2,3,2)
a+b
tensor([[[1., 1.],
         [1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.],
         [1., 1.]]])
# 手动广播法则
# 或者 a.view(1,3,2).expand(2,3,2)+b.expand(2,3,2)
a[None].expand(2, 3, 2) + b.expand(2,3,2)
tensor([[[1., 1.],
         [1., 1.],
         [1., 1.]],

        [[1., 1.],
         [1., 1.],
         [1., 1.]]])
# expand不会占用额外空间,只会在需要的时候才扩充,可极大节省内存
e = a.unsqueeze(0).expand(10000000000000, 3,2)

2.2 内部结构

tensor的数据结构如图1-1所示。tensor分为头信息区(Tensor)和存储区(Storage),信息区主要保存着tensor的形状(size)、步长(stride)、数据类型(type)等信息,而真正的数据则保存成连续数组。由于数据动辄成千上万,因此信息区元素占用内存较少,主要内存占用则取决于tensor中元素的数目,也即存储区的大小。

一般来说一个tensor有着与之相对应的storage, storage是在data之上封装的接口,便于使用,而不同tensor的头信息一般不同,但却可能使用相同的数据。下面看两个例子。

在这里插入图片描述

a = t.arange(0, 6)
a.storage()
 0
 1
 2
 3
 4
 5
[torch.storage.TypedStorage(dtype=torch.int64, device=cpu) of size 6]
b = a.view(2, 3)
b.storage()
 0
 1
 2
 3
 4
 5
[torch.storage.TypedStorage(dtype=torch.int64, device=cpu) of size 6]
# 一个对象的id值可以看作它在内存中的地址
# storage的内存地址一样,即是同一个storage
id(b.storage()) == id(a.storage())
True
# a改变,b也随之改变,因为他们共享storage
a[1] = 100
b
tensor([[  0, 100,   2],
        [  3,   4,   5]])
c = a[2:] 
c.storage()
 0
 100
 2
 3
 4
 5
[torch.storage.TypedStorage(dtype=torch.int64, device=cpu) of size 6]
c.data_ptr(), a.data_ptr() # data_ptr返回tensor首元素的内存地址
# 可以看出相差8,这是因为2*4=8--相差两个元素,每个元素占4个字节(float)
(4478820552016, 4478820552000)
c[0] = -100 # c[0]的内存地址对应a[2]的内存地址
a
tensor([   0,  100, -100,    3,    4,    5])
d = t.LongTensor(c.storage())
d[0] = 6666
b
tensor([[6666,  100, -100],
        [   3,    4,    5]])
# 下面4个tensor共享storage
id(a.storage()) == id(b.storage()) == id(c.storage()) == id(d.storage())
True
a.storage_offset(), c.storage_offset(), d.storage_offset()
(0, 2, 0)
e = b[::2, ::2] # 隔2行/列取一个元素
id(e.storage()) == id(a.storage())
True
b.stride(), e.stride()
((3, 1), (6, 2))
e.is_contiguous()
False

可见绝大多数操作并不修改tensor的数据,而只是修改了tensor的头信息。这种做法更节省内存,同时提升了处理速度。在使用中需要注意。
此外有些操作会导致tensor不连续,这时需调用tensor.contiguous方法将它们变成连续的数据,该方法会使数据复制一份,不再与原来的数据共享storage。
另外读者可以思考一下,之前说过的高级索引一般不共享stroage,而普通索引共享storage,这是为什么?(提示:普通索引可以通过只修改tensor的offset,stride和size,而不修改storage来实现)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

获取和移除cookie的方法

下载npm的cookie插件, 在utils.js文件中引入插件: 封装原始的Cookies.get()方法: 在xxxx.vue文件中引入方法: 使用getCookie方法获取cookie: 封装 移除cookie: export const removeCookie name>{ const options { path: /, domain: xxx.com }; Cookies.remove(name, opti…

18 5G - NR物理层解决方案支持6G非地面网络中的高移动性

文章目录 非地面网络场景链路仿真参数实验仿真结果 非地面网络场景 链路仿真参数 实验仿真结果 Figure 5 && Figure 6:不同信噪比下的BER和吞吐量 变量 SISO 2x2MIMO 2x4MIMO 2x8MIMOReyleigh衰落、Rician衰落、多径TDL-A(NLOS) 、TDL-E(LOS)(a)QPSK (b)16…

玩期货,千万要注意不同软件的设置啊

参加某公司的期货交易模拟选拔,用的是博易大师,结果这个软件的止损线巨坑,当天下午设置的止损线,在收盘之后软件关闭的情况下就自动作废了,到了晚上夜盘如果价格超相反方向走了,那可能导致巨亏。 幸亏是模拟…

nginx的location与rewrite

目录 一.location 二.rewrite rewrite跳转实现: 语法格式:rewrite [flag]; flag标记说明: 三.基于域名跳转 四.基于ip跳转 五.基于旧域名跳转到新域名后面加目录 六.基于参数匹配的跳转 可以同过全局变量来匹配: 基于目…

最高级别认可!喂车科技荣获国际CMMI5级认证

近日,喂车科技顺利通过全球软件领域最高级别认证CMMI 5级(简称CMMI5)认证! 此次荣获CMMI5级认证,意味着喂车科技在研发管理体系、项目实施交付服务以及项目管理水平等方面均已达到国际领先水平,能够为客户…

如何远程访问Axure RP制作的本地web站点实现协同办公

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

在windows系统搭建LVGL模拟器(codeblock工程)

1.codeblock准备 下载codeblock(mingw),安装。可参考网上教程。 2.pc_simulator_win_codeblocks 工程获取 仓库地址:lvgl/lv_port_win_codeblocks: Windows PC simulator project for LVGL embedded GUI Library (github.com) 拉取代码到本地硬盘&…

机器学习算法应用场景与评价指标

机器学习算法(一)——分类 机器学习算法(二)——回归 机器学习算法(三)——异常检测 一、应用场景 机器学习的算法选择大部分依赖于具体的问题类型和数据特征。下面是一些典型的场景以及对应的常用算法&am…

面对知识经济的发展,企业该如何做好知识管理?

面对知识经济的发展,企业犹如逆水行舟,不进则退,而知识管理已经成为了企业赖以生存和发展的关键。大家可能对知识经济这个词比较陌生,简单来说,知识经济就是指在经济活动中,知识的产生、获取、传播和应用成…

点石成金》》》从“沙粒”蜕变到“芯片”

每个半导体产品的制造都需要数百个工艺,Lam Research将整个制造过程分为八个步骤:晶圆加工-氧化-光刻-刻蚀-薄膜沉积-互连-测试-封装。 01 晶圆加工 所有半导体工艺都始于一粒沙子!因为沙子所含的硅是生产晶圆所需要的原材料。晶圆是…

C++ Qt开发:DateTime日期时间组件

Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QDateTime日期与时间组件的常用方法及灵活运用…

【评测脚本】agent资源监控

背景 在之前的文章中提到过,我们在测试过程中需要对机器的资源进行评测。在实际工作中,我们还会经常遇到的场景就是对于agent-server类型的业务,当部署完成后,需要对部署在机器上的agent进行资源占用的观测,不能舍本逐末,由于agent的异常资源占用,导致原有业务受机器资…

直播美颜SDK开发实战:从入门到精通

直播美颜SDK的应用已经成为许多直播平台和开发者关注的焦点。本文将带领读者深入探讨直播美颜SDK的开发实战,从入门到精通的过程。 1.引言 直播美颜SDK是一种集成了图像处理、人脸识别、滤镜算法等技术的开发工具包。通过使用该SDK,开发者能够为直播应…

酸奶店怎么做营销活动来引流,才能吸引顾客进店

今天我想和大家分享的是酸奶店怎么做营销活动来引流,才能吸引顾客进店。 本人经营酸奶店5年时间,以下活动方式都是我亲身经历过的,希望能给大家一些参考。 随着人们对健康饮食的追求不断提高,酸奶作为一种营养丰富、口感独特的食…

IDEA调整内存大小

一、IDEA开启内存显示 双击shift,搜索show memory indicator 打开后重启,右下角显示IDEA内存占用情况 开启后右下角会显示 二、调整内存 双击shift,搜索vmoption 修改-Xms和-Xmx参数,如下: -Xms:最小内存 -Xmx:最大内存 设置完成后&…

apt-mark工具介绍(标记或取消标记软件包,防止特定软件包被自动更新或删除)

文章目录 apt-mark工具深度解析1. apt-mark概述1.1 apt-mark定义1.2 apt-mark作用 2. apt-mark常用命令2.1 标记软件包为手动安装2.2 标记软件包为自动安装2.3 阻止软件包更新2.4 允许软件包更新 3. 疑难技术点解析3.1 如何查看软件包的标记状态3.2 如何解决软件包依赖性问题 4…

Python | 高斯分布拟合示例

什么是正态分布或高斯分布? 当我们绘制一个数据集(如直方图)时,图表的形状就是我们所说的分布。最常见的连续值形状是钟形曲线,也称为高斯分布或正态分布。 它以德国数学家卡尔弗里德里希高斯的名字命名。遵循高斯分布…

IDEA debug窗口左边工具栏隐藏与显示

今天在debug排查代码的时候一不小心点到哪里,结果变成这样 我们可以这样恢复,右键Debug 点击show Toolbar

python中else的细节

if-else 首先我们都知道else可以和if共同使用,如果if条件没有执行,就会去执行else语句 a100 if a100:print("if 语句执行了") else:print("else语句执行了") a10 if a100:print("if 语句执行了") else:print("else…

联想笔记本如何安装Vmware ESXi

环境: Vmware ESXi 8.0 Vmware ESXi 6.7 联想E14笔记本 问题描述: 联想笔记本如何安装Vmware ESXi 解决方案: 1.官网下载镜像文件 https://customerconnect.vmware.com/en/downloads/search?queryesxi%208 下载 2.没有账户注册一个 …