PyTorch 笔记(11)— Tensor内部存储结构(头信息区 Tensor,存储区 Storage)
1. Tensor 內(nèi)部存儲(chǔ)結(jié)構(gòu)
tensor 數(shù)據(jù)結(jié)構(gòu)如下圖所示,tensor 分為頭信息區(qū)(Tensor)和存儲(chǔ)區(qū) (Storage),信息區(qū)主要保存著 Tensor 的形狀(size)、步長(stride)、數(shù)據(jù)類型(type )等信息,而真正的數(shù)據(jù)則保存成連續(xù)的數(shù)組。
由于數(shù)據(jù)動(dòng)輒成千數(shù)萬,因此信息區(qū)占用內(nèi)存較少,主要內(nèi)存占用取決于 tensor 中元素?cái)?shù)目,即存儲(chǔ)區(qū)大小。
2. 存儲(chǔ)區(qū)
一般來說,一個(gè) tensor 有著與之對(duì)應(yīng)的 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 值來判斷它們?cè)趦?nèi)存中的地址是否相等。
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 也跟著改變,因?yàn)樗鼈兪枪蚕?storage 的。
In [34]: a[1] = 100In [35]: b
Out[35]:
tensor([[ 0, 100, 2],[ 3, 4, 5]])
數(shù)據(jù)和存儲(chǔ)區(qū)的差異,c 的數(shù)據(jù)是切片之后的值,而存儲(chǔ)區(qū)仍然是整體的值。
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 首元素的內(nèi)存地址,c 和 a 的內(nèi)存地址相差 16,也就是兩個(gè)元素,即每個(gè)元素占用 8 個(gè)字節(jié)(LongStorage)。
c[0] 的內(nèi)存地址對(duì)應(yīng) a[2] 內(nèi)存地址。
In [44]: c[0] = -100In [45]: a
Out[45]: tensor([ 0, 100, -100, 3, 4, 5])
a.storage、b.storage 、c.storage 三者的內(nèi)存地址是相等的。
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
由此可見,絕大多數(shù)操作并不修改 tensor 的數(shù)據(jù),只是修改了 tensor 的頭信息,這種做法更節(jié)省內(nèi)存,同時(shí)提升了處理速度。此外,有些操作會(huì)導(dǎo)致 tensor 不連續(xù),這時(shí)需要調(diào)用 torch.contiguous 方法將其變成連續(xù)的數(shù)據(jù),該方法會(huì)復(fù)制數(shù)據(jù)到新的內(nèi)存,不在與原來的數(shù)據(jù)共享 storage。
高級(jí)索引一般不共享 storage ,而普通索引共享 storage ,是因?yàn)槠胀ㄋ饕梢酝ㄟ^修改 tensor 的 offset 、stride 和 size 實(shí)現(xiàn),不修改 storage 的數(shù)據(jù),而高級(jí)索引則不行。
總結(jié)
以上是生活随笔為你收集整理的PyTorch 笔记(11)— Tensor内部存储结构(头信息区 Tensor,存储区 Storage)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学跆拳道多少钱啊?
- 下一篇: PyTorch 笔记(12)— Tens