PyTorch 笔记(11)— Tensor内部存储结构(头信息区 Tensor,存储区 Storage)

1. Tensor 内部存储结构

tensor 数据结构如下图所示,tensor 分为头信息区(Tensor)和存储区 (Storage),信息区主要保存着 Tensor 的形状(size)、步长(stride)、数据类型(type )等信息,而真正的数据则保存成连续的数组。

由于数据动辄成千数万,因此信息区占用内存较少,主要内存占用取决于 tensor 中元素数目,即存储区大小。

Tensor数据结构

2. 存储区

一般来说,一个 tensor 有着与之对应的 storagestorage 是在 data 之上封装的接口。不同 tensor 的头信息一般不同,但却可能使用相同的 storage

In [25]: a = t.arange(0, 6)

In [26]: a
Out[26]: tensor([0, 1, 2, 3, 4, 5])

In [27]: a.storage()
Out[27]: 
 0
 1
 2
 3
 4
 5
[torch.LongStorage of size 6]

In [28]: a.storage_offset()
Out[28]: 0

In [29]: a.storage_type()
Out[29]: torch.LongStorage

In [30]: b = a.view(2,3)

In [31]: b.storage()
Out[31]: 
 0
 1
 2
 3
 4
 5
[torch.LongStorage of size 6]

In [32]:

可以通过 Pythonid 值来判断它们在内存中的地址是否相等。

In [32]: id(a) == id(b)
Out[32]: False

In [33]: id(a.storage) == id(b.storage)
Out[33]: True

In [34]: 

可以看到 abstorage 是相等的。

a 改变,b 也跟着改变,因为它们是共享 storage 的。

In [34]: a[1] = 100

In [35]: b
Out[35]: 
tensor([[  0, 100,   2],
        [  3,   4,   5]])

数据和存储区的差异,c 的数据是切片之后的值,而存储区仍然是整体的值。

In [36]: c = a[2:]

In [37]: c
Out[37]: tensor([2, 3, 4, 5])

In [43]: c.data
Out[43]: tensor([2, 3, 4, 5])

In [38]: c.storage()
Out[38]: 
 0
 100
 2
 3
 4
 5
[torch.LongStorage of size 6]

In [39]: c.data_ptr(), a.data_ptr()
Out[39]: (132078864, 132078848)

In [40]: c.data_ptr() - a.data_ptr()
Out[40]: 16

data_ptr() 返回 tensor 首元素的内存地址,ca 的内存地址相差 16,也就是两个元素,即每个元素占用 8 个字节(LongStorage)。

c[0] 的内存地址对应 a[2] 内存地址。

In [44]: c[0] = -100

In [45]: a
Out[45]: tensor([   0,  100, -100,    3,    4,    5])

a.storageb.storagec.storage 三者的内存地址是相等的。

In [49]: id(a.storage) == id(b.storage) == id(c.storage)
Out[49]: True

In [51]: a.storage_offset(), b.storage_offset(), c.storage_offset()
Out[51]: (0, 0, 2)

In [52]: 

查看偏移位。

In [55]: d = b[::2, ::2]

In [56]: d
Out[56]: tensor([[   0, -100]])

In [57]: b
Out[57]: 
tensor([[   0,  100, -100],
        [   3,    4,    5]])

In [58]: id(d.storage) == id(b.storage)
Out[58]: True

In [59]: b.stride()
Out[59]: (3, 1)

In [60]: d.stride()
Out[60]: (6, 2)

In [61]: d.is_contiguous()
Out[61]: False

由此可见,绝大多数操作并不修改 tensor 的数据,只是修改了 tensor 的头信息,这种做法更节省内存,同时提升了处理速度。此外,有些操作会导致 tensor 不连续,这时需要调用 torch.contiguous 方法将其变成连续的数据,该方法会复制数据到新的内存,不在与原来的数据共享 storage

高级索引一般不共享 storage ,而普通索引共享 storage ,是因为普通索引可以通过修改 tensoroffsetstridesize 实现,不修改 storage 的数据,而高级索引则不行。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值