PyTorch 笔记(11)— Tensor内部存储结构(头信息区 Tensor,存储区 Storage)
1. Tensor 內部存儲結構
tensor 數據結構如下圖所示,tensor 分為頭信息區(Tensor)和存儲區 (Storage),信息區主要保存著 Tensor 的形狀(size)、步長(stride)、數據類型(type )等信息,而真正的數據則保存成連續的數組。
由于數據動輒成千數萬,因此信息區占用內存較少,主要內存占用取決于 tensor 中元素數目,即存儲區大小。
2. 存儲區
一般來說,一個 tensor 有著與之對應的 storage , storage 是在 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]: 012345
[torch.LongStorage of size 6]In [28]: a.storage_offset()
Out[28]: 0In [29]: a.storage_type()
Out[29]: torch.LongStorageIn [30]: b = a.view(2,3)In [31]: b.storage()
Out[31]: 012345
[torch.LongStorage of size 6]In [32]:
可以通過 Python 的 id 值來判斷它們在內存中的地址是否相等。
In [32]: id(a) == id(b)
Out[32]: FalseIn [33]: id(a.storage) == id(b.storage)
Out[33]: TrueIn [34]:
可以看到 a 和 b 的 storage 是相等的。
a 改變,b 也跟著改變,因為它們是共享 storage 的。
In [34]: a[1] = 100In [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]: 01002345
[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 首元素的內存地址,c 和 a 的內存地址相差 16,也就是兩個元素,即每個元素占用 8 個字節(LongStorage)。
c[0] 的內存地址對應 a[2] 內存地址。
In [44]: c[0] = -100In [45]: a
Out[45]: tensor([ 0, 100, -100, 3, 4, 5])
a.storage、b.storage 、c.storage 三者的內存地址是相等的。
In [49]: id(a.storage) == id(b.storage) == id(c.storage)
Out[49]: TrueIn [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]: TrueIn [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 ,是因為普通索引可以通過修改 tensor 的 offset 、stride 和 size 實現,不修改 storage 的數據,而高級索引則不行。
總結
以上是生活随笔為你收集整理的PyTorch 笔记(11)— Tensor内部存储结构(头信息区 Tensor,存储区 Storage)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学跆拳道多少钱啊?
- 下一篇: PyTorch 笔记(12)— Tens