『PyTorch』第五彈_深入理解Tensor對象_下:從內存看Tensor


Tensor存儲結構如下,

 如圖所示,實際上很可能多個信息區對應於同一個存儲區,也就是上一節我們說到的,初始化或者普通索引時經常會有這種情況。

一、幾種共享內存的情況

view

a = t.arange(0,6)
print(a.storage())
b = a.view(2,3)
print(b.storage())
print(id(a.storage())==id(b.storage()))
a[1] = 10
print(b)

 上面代碼,我們通過.storage()可以查詢到Tensor所對應的storage地址,可以看到view雖然不是inplace的,但也僅僅是更改了對同一片內存的檢索方式而已,並沒有開辟新的內存:

 0.0
 1.0
 2.0
 3.0
 4.0
 5.0
[torch.FloatStorage of size 6]
 0.0
 1.0
 2.0
 3.0
 4.0
 5.0
[torch.FloatStorage of size 6]
True

  0  10   2
  3   4   5
[torch.FloatTensor of size 2x3]

 

簡單索引

注意,id(a.storage())==id(c.storage()) != id(a[2])==id(a[0])==id(c[0]),id(a)!=id(c)

c = a[2:]
print(c.storage())  # c所屬的storage也在這里
print(id(a[2]), id(a[0]),id(c[0]))  # 指向了同一處
print(id(a),id(c))
print(id(a.storage()),id(c.storage()))
 0.0
 10.0
 2.0
 3.0
 4.0
 5.0
[torch.FloatStorage of size 6]
2443616787576 2443616787576 2443616787576
2443617946696 2443591634888
2443617823496 2443617823496

 

通過Tensor初始化Tensor

d = t.Tensor(c.storage())
d[0] = 20
print(a)
print(id(a.storage())==id(b.storage())==id(c.storage())==id(d.storage()))
 20
 10
  2
  3
  4
  5
[torch.FloatTensor of size 6]

True

 

二、內存檢索方式查看

storage_offset():偏移量
stride():步長,注意下面的代碼,步長比我們通常理解的步長稍微麻煩一點,是有層次結構的步長

print(a.storage_offset(),b.storage_offset(),c.storage_offset(),d.storage_offset())
e = b[::2,::2]
print(id(b.storage())==id(e.storage()))
print(b.stride(),e.stride())
print(e.is_contiguous())
f = e.contiguous()  # 對於內存不連續的張量,復制數據到新的連續內存中
print(id(f.storage())==id(e.storage()))
print(e.is_contiguous())
print(f.is_contiguous())
g = f.contiguous()  # 對於內存連續的張量,這個操作什么都沒做
print(id(f.storage())==id(g.storage()))

 高級檢索一般不共享stroage,這就是因為普通索引可以通過修改offset、stride、size實現,二高級檢索出的結果坐標更加混亂,不方便這樣修改,需要開辟新的內存進行存儲。

 

三、其他有關Tensor

持久化

t.save和t.load,由於torch的為單獨Tensor指定設備的特性,實際保存時會保存設備信息,但是load是通過特定參數可以加載到其他設備,詳情help(torch.load),其他的同numpy類似

向量化計算

Tensor天生支持廣播和矩陣運算,包含numpy等其他庫在內,其矩陣計算效率遠高於python內置的for循環,能少用for就少用,換句話說python的for循環實現的效率很低。

輔助功能

設置展示位數:t.set_printoptions(precision=n)

In [13]: a = t.randn(2,3)

In [14]: a
Out[14]:

 1.1564  0.5561 -0.2968
-1.0205  0.8023  0.1582
[torch.FloatTensor of size 2x3]

In [15]: t.set_printoptions(precision=10)

In [16]: a
Out[16]:

1.1564352512 0.5561078787 -0.2968128324
-1.0205242634 0.8023245335 0.1582107395
[torch.FloatTensor of size 2x3]

out參數:

很多torch函數有out參數,這主要是因為torch沒有tf.cast()這類的類型轉換函數,也少有dtype參數指定輸出類型,所以需要事先建立一個輸出Tensor為LongTensor、IntTensor等等,再由out導入,如下:

In [3]: a = t.arange(0, 20000000)
In [4]: print(a[-1],a[-2])
16777216.0 16777216.0

可以看到溢出了數字,如果這樣處理,

In [5]: b = t.LongTensor()
In [6]: b = t.arange(0,20000000)
In [7]: b[-2]
Out[7]: 16777216.0

還是不行,只能這樣,

In [9]: b = t.LongTensor()

In [10]: t.arange(0,20000000,out=b)
Out[10]:

 0.0000e+00
 1.0000e+00
 2.0000e+00
     ⋮
 2.0000e+07
 2.0000e+07
 2.0000e+07
[torch.LongTensor of size 20000000]

In [11]: b[-2]
Out[11]: 19999998

In [12]: b[-1]
Out[12]: 19999999

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM