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

tensor 内部存储结构

1、数据区域和元数据

PyTorch 中的 tensor 内部结构通常包含了 数据区域(Storage) 和 元数据(Metadata) :

  • 数据区域 : 存储了 tensor 的实际数据,且数据被保存为连续的数组。比如: a = torch.tensor([[1, 2, 3], [4, 5, 6]]),它的数据在存储区的保存形式为 [1, 2, 3, 4, 5, 6]

  • 元数据 :包含了 tensor 的一些描述性信息,比如 : 尺寸(Size)、步长(Stride)、数据类型(Data Type) 等信息

占用内存的主要是 数据区域,且取决于 tensor 中元素的个数, 而元数据占用内存较少。

采用这种 【数据区域 + 元数据】 的数据存储方式,主要是因为深度学习的数据动辄成千上万,数据量巨大,所以采取这样的存储方式以节省内存


2、查看 tensor 的存储区数据: storage() 

a = torch.tensor([[1, 2, 3],[4, 5, 6]])print(a.storage())


3、查看 tensor 的步长: stride() 

stride() : 在指定维度 (dim) 上,存储区中的数据元素,从一个元素跳到下一个元素所必须的步长

a = torch.randn(3, 2)
print(a.stride())  # (2, 1)

解读:

在第 0 维,想要从一个元素跳到下一个元素,比如从 a[0][0] 到 a[1][0] ,需要经过 2个元素,步长是 2

在第 1 维,想要从一个元素跳到下一个元素,比如从 a[0][0] 到 a[0][1], 需要经过 1个元素,步长是 1


4、查看 tensor 的偏移量:storage_offset()

表示 tensor 的第 0 个元素与真实存储区的第 0 个元素的偏移量 

a = torch.tensor([1, 2, 3, 4, 5])
b = a[1:]   # tensor([2, 3, 4, 5])
c = a[3:]   # tensor([4, 5])
print(b.storage_offset())   # 1
print(c.storage_offset())   # 3
  • b 的第 0 个元素与 a 的第 0 个元素之间的偏移量是 1

  • c 的第 0 个元素与 a 的第 0 个元素之间的偏移量是 3


5、观察存储区

一般来说,一个 tensor 有着与之对应的 storage, storage 是在 data 之上封装的接口。

不同 tensor 的元数据一般不同,但却可能使用相同的 storage。

1)观察一

import torcha = torch.arange(0, 6)
print('a = {}\n'.format(a))
print('tensor a 存储区的数据内容 :{}\n'.format(a.storage()))
print('tensor a 相对于存储区数据的偏移量 :{}\n'.format(a.storage_offset()))print('*'*20, '\n')b = a.view(2,3)
print('b = {}\n'.format(b))
print('tensor b 存储区的数据内容 :{}\n'.format(b.storage()))
print('tensor b 相对于存储区数据的偏移量 :{}\n'.format(b.storage_offset()))

 

2)观察二

import torcha = torch.tensor([1, 2, 3, 4, 5, 6])
b = a.view(2, 3)print(a.data_ptr())   # 140623757700864
print(b.data_ptr())   # 140623757700864print(id(a))   # 4523755392
print(id(b))   # 4602540464

  • a.data_ptr()b.data_ptr() 一样,说明 tensor a 和 tensor b 共享相同的存储区,即,它们指向相同的底层数据存储对象。

  • id(a)id(b) 不一样,是因为虽然 a 和b 共享storage 数据,但是 它们 有不同的 size 或者 strides 、 storage_offset 等其他属性

 

  3)观察三

import torcha = torch.tensor([1, 2, 3, 4, 5, 6])
c = a[2:]print(c.storage())print('\n', '*'*20, '\n')print('tensor a 首元素的内存地址 : {}'.format(a.data_ptr()))
print('tensor c 首元素的内存地址 : {}'.format(c.data_ptr()))
print(c.data_ptr() - a.data_ptr())print('\n', '*'*20, '\n')c[0] = -100
print(a)

  • data_ptr() 返回 tensor 首元素的内存地址

  • c 和 a 的首元素内存地址相差 16,每个元素占用 8 个字节(LongStorage), 也就是首元素相差两个元素

  • 改变 c 的首元素, a 对应位置的元素值也被改变

 6、总结

  1. 由上可知,绝大多数操作并不修改 tensor 的数据,只是修改了 tensor 的元数据,比如修改 tensor 的 offset 、stride 和 size ,这种做法更节省内存,同时提升了处理速度。

  2. 有些操作会导致 tensor 不连续,这时需要调用 torch.contiguous 方法将其变成连续的数据,该方法会复制数据到新的内存,不再与原来的数据共享 storage。

相关文章:

  • FastAPI 零基础入门指南:10 分钟搭建高性能 API
  • 365打卡第R3周: RNN-心脏病预测
  • YOLOv5修改检测框颜色,粗细,标签大小,标签名称
  • AI编程案例拆解|基于机器学习XX评分系统-后端篇
  • 深入理解算力:从普通电脑到宏观计算世界
  • 【Docker项目实战】使用Docker部署Caddy+vaultwarden密码管理工具(详细教程)
  • 如何在项目中使用双token机制?
  • 代码随想录算法训练营Day36
  • MyBatis XML 配置完整示例(含所有核心配置项)
  • 单片机-89C51部分:4、固件烧录
  • MAVLink协议:原理、应用与实践
  • Pytorch(无CPU搭建)+Jupyter
  • 代码随想录算法训练营第二十八天
  • Pygame入门:零基础打造你的第一个游戏窗口
  • 二、UI自动化测试02--元素定位方法
  • Leetcode刷题 由浅入深之哈希法——202. 快乐数
  • Adruino:传感器及步进电机
  • 我们分析前端生活。
  • 驱动开发硬核特训 · Day 21(上篇加强版):深入理解子系统机制与实战初探
  • 微服务架构下 MySQL 大表分库分表方案
  • 洛阳原副市长收礼品消费卡,河南通报6起违反八项规定典型问题
  • 一周观展|五一假期将到,特展大展陆续开幕
  • 锚定“双一流”战略坐标,福建农林大学向全球英才“伸出橄榄枝”
  • 2025全国知识产权宣传周:用AI生成的图片要小心什么?
  • 钱学森数据服务中心在沪上线,十万个数字资源向公众开放
  • 2025年两院院士增选工作启动,名额均不超过100名