【小白学PyTorch】9.tensor数据结构与存储结构
【機器學習煉丹術】的學習筆記分享
<<小白學PyTorch>>
小白學PyTorch | 8 實戰之MNIST小試牛刀
小白學PyTorch | 7 最新版本torchvision.transforms常用API翻譯與講解
小白學PyTorch | 6 模型的構建訪問遍歷存儲(附代碼)
小白學PyTorch | 5 torchvision預訓練模型與數據集全覽
小白學PyTorch | 4 構建模型三要素與權重初始化
小白學PyTorch | 3 淺談Dataset和Dataloader
小白學PyTorch | 2 淺談訓練集驗證集和測試集
小白學PyTorch | 1 搭建一個超簡單的網絡
小白學PyTorch | 動態圖與靜態圖的淺顯理解
上一節課,講解了MNIST圖像分類的一個小實戰,現在我們繼續深入學習一下pytorch的一些有的沒的的小知識來作為只是儲備。
參考目錄:
1 pytorch數據結構
1.1 默認整數與浮點數
1.2 dtype修改變量類型
1.3 變量類型有哪些
1.4 數據類型轉換
2 torch vs numpy
2.1 兩者轉換
2.2 兩者區別
3 張量
3.1 張量修改尺寸
3.2 張量內存存儲結構
3.3 存儲區
3.4 頭信息區
1 pytorch數據結構
1.1 默認整數與浮點數
【pytorch默認的整數是int64】
pytorch的默認整數是用64個比特存儲,也就是8個字節(Byte)存儲的。
【pytorch默認的浮點數是float32】
pytorch的默認浮點數是用32個比特存儲,也就是4個字節(Byte)存儲的。
import torch import numpy as np #---------------------- print('torch的浮點數與整數的默認數據類型') a = torch.tensor([1,2,3]) b = torch.tensor([1.,2.,3.]) print(a,a.dtype) print(b,b.dtype)輸出:
torch的浮點數與整數的默認數據類型 tensor([1,?2,?3])?torch.int64 tensor([1.,?2.,?3.])?torch.float321.2 dtype修改變量類型
print('torch的浮點數與整數的默認數據類型') a = torch.tensor([1,2,3],dtype=torch.int8) b = torch.tensor([1.,2.,3.],dtype = torch.float64) print(a,a.dtype) print(b,b.dtype)輸出結果:
torch的浮點數與整數的默認數據類型 tensor([1,?2,?3],?dtype=torch.int8)?torch.int8 tensor([1.,?2.,?3.],?dtype=torch.float64)?torch.float641.3 變量類型有哪些
張量的數據類型其實和numpy.array基本一一對應,除了不支持str,主要有下面幾種形式:
torch.float64?#?等同于(torch.double) torch.float32?#?默認,FloatTensor torch.float16 torch.int64???#?等同于torch.long torch.int32???#?默認 torch.int16 torch.int8 torch.uint8???#?二進制碼,表示0-255 torch.bool在創建變量的時候,想要創建指定的變量類型,上文中提到了用dtype關鍵字來控制,但是我個人更喜歡使用特定的構造函數:
print('torch的構造函數') a = torch.IntTensor([1,2,3]) b = torch.LongTensor([1,2,3]) c = torch.FloatTensor([1,2,3]) d = torch.DoubleTensor([1,2,3]) e = torch.tensor([1,2,3]) f = torch.tensor([1.,2.,3.]) print(a.dtype) print(b.dtype) print(c.dtype) print(d.dtype) print(e.dtype) print(f.dtype)輸出結果:
torch的構造函數 torch.int32 torch.int64 torch.float32 torch.float64 torch.int64 torch.float32因此我們可以得到結果:
torch.IntTensor對應torch.int32
torch.LongTensor對應torch.int64,LongTensor常用在深度學習中的標簽值 ,比方說分類任務中的類別標簽0,1,2,3等,要求用ing64的數據類型;
torch.FloatTensor對應torch.float32。FloatTensor常用做深度學習中可學習參數或者輸入數據的類型
torch.DoubleTensor對應torch.float64
torch.tensor則有一個推斷的能力,加入輸入的數據是整數,則默認int64,相當于LongTensor;假如輸入數據是浮點數,則默認float32,相當于FLoatTensor。剛好對應深度學習中的標簽和參數的數據類型,所以一般情況下,直接使用tensor就可以了,但是假如出現報錯的時候,也要學會使用dtype或者構造函數來確保數據類型的匹配
1.4 數據類型轉換
【使用torch.float()方法】
print('數據類型轉換') a?=?torch.tensor([1,2,3]) b?=?a.float() c?=?a.double() d?=?a.long() print(b.dtype) print(c.dtype) print(d.dtype) >>>?數據類型轉換 >>>?torch.float32 >>>?torch.float64 >>>?torch.int64我個人比較習慣這個的方法。
【使用type方法】
b?=?a.type(torch.float32) c?=?a.type(torch.float64) d?=?a.type(torch.int64) print(b.dtype)?#?torch.float32 print(c.dtype)?#?torch.float64 print(d.dtype)?#?torch.int642 torch vs numpy
PyTorch是一個python包,目的是加入深度學習應用, torch基本上是實現了numpy的大部分必要的功能,并且tensor是可以利用GPU進行加速訓練的。
2.1 兩者轉換
轉換時非常非常簡單的:
import?torch import?numpy?as?npa?=?np.array([1.,2.,3.]) b?=?torch.tensor(a) c?=?b.numpy() print(a) print(b) print(c)輸出結果:
[1.?2.?3.] tensor([1.,?2.,?3.],?dtype=torch.float64) [1.?2.?3.]下面的內容就變得有點意思了,是內存復制相關的。假如a和b兩個變量共享同一個內存,那么改變a的話,b也會跟著改變;如果a和b變量的內存復制了,那么兩者是兩個內存,所以改變a是不會改變b的。下面是講解numpy和torch互相轉換的時候,什么情況是共享內存,什么情況下是內存復制 (其實這個問題,也就是做個了解罷了,無用的小知識)
【Tensor()轉換】當numpy的數據類型和torch的數據類型相同時,共享內存;不同的時候,內存復制
print('numpy?和torch互相轉換1') a?=?np.array([1,2,3],dtype=np.float64) b?=?torch.Tensor(a) b[0]?=?999 print('共享內存'?if?a[0]==b[0]?else?'不共享內存') >>>?不共享內存因為np.float64和torch.float32數據類型不同
print('numpy?和torch互相轉換2') a?=?np.array([1,2,3],dtype=np.float32) b?=?torch.Tensor(a) b[0]?=?999 print('共享內存'?if?a[0]==b[0]?else?'不共享內存') >>>?共享內存因為np.float32和torch.float32數據類型相同
【from_numpy()轉換】
print('from_numpy()') a?=?np.array([1,2,3],dtype=np.float64) b?=?torch.from_numpy(a) b[0]?=?999 print('共享內存'?if?a[0]==b[0]?else?'不共享內存') >>>?共享內存 a?=?np.array([1,2,3],dtype=np.float32) b?=?torch.from_numpy(a) b[0]?=?999 print('共享內存'?if?a[0]==b[0]?else?'不共享內存') >>>?共享內存如果你使用from_numpy()的時候,不管是什么類型,都是共享內存的。
【tensor()轉換】
更常用的是這個tensor(),注意看T的大小寫, 如果使用的是tensor方法,那么不管輸入類型是什么,torch.tensor都會進行數據拷貝,不共享內存。
【.numpy()】tensor轉成numpy的時候,.numpy方法是內存共享的哦。如果想改成內存拷貝的話,可以使用.numpy().copy()就不共享內存了。或者使用.clone().numpy()也可以實現同樣的效果。clone是tensor的方法,copy是numpy的方法。
【總結】
記不清的話,就記住,tensor()數據拷貝了,.numpy()共享內存就行了。
2.2 兩者區別
【命名】
雖然PyTorch實現了Numpy的很多功能,但是相同的功能卻有著不同的命名方式,這讓使用者迷惑。
例如創建隨機張量的時候:
print('命名規則') a?=?torch.rand(2,3,4) b?=?np.random.rand(2,3,4)【張量重塑】
這部分會放在下一章節詳細說明~
3 張量
標量:數據是一個數字
向量:數據是一串數字,也是一維張量
矩陣:數據二維數組,也是二維張量
張量:數據的維度超過2的時候,就叫多維張量
3.1 張量修改尺寸
pytorch常用reshape和view
numpy用resize和reshape
pytorch也有resize但是不常用
【reshape和view共享內存(常用)】
a?=?torch.arange(0,6) b?=?a.reshape((2,3)) print(b) c?=?a.view((2,3)) print(c) a[0]?=?999 print(b) print(c)輸出結果:
tensor([[0,?1,?2],[3,?4,?5]]) tensor([[0,?1,?2],[3,?4,?5]]) tensor([[999,???1,???2],[??3,???4,???5]]) tensor([[999,???1,???2],[??3,???4,???5]])上面的a,b,c三個變量其實是共享同一個內存,遷一而動全身。而且要求遵旨規則:原始數據有6個元素,所以可以修改成的形式,但是無法修改成的形式 ,我們來試試:
a?=?torch.arange(0,6) b?=?a.reshape((2,4))會拋出這樣的錯誤:
【torch的resize_(不常用)】
但是pytorch有一個不常用的函數(對我來說用的不多),resize,這個方法可以不遵守這個規則:
a?=?torch.arange(0,6) a.resize_(2,4) print(a)輸出結果為:自動的補充了兩個元素。雖然不知道這個函數有什么意義。。。。。。
這里可以看到函數resize后面有一個_,這個表示inplace=True的意思,當有這個_或者參數inplace的時候,就是表示所作的修改是在原來的數據變量上完成的,也就不需要賦值給新的變量了。
【numpy的resize與reshape(常用)】
import?numpy?as?np a?=?np.arange(0,6) a.resize(2,3) print(a) import?numpy?as?np a?=?np.arange(0,6) b?=?a.reshape(2,3) print(b)兩個代碼塊的輸出都是下面的,區別在于numpy的resize是沒有返回值的,相當于inplace=True了,直接在原變量的進行修改,而reshape是有返回值的,不在原變量上修改(但是呢reshape是共享內存的):
[[0?1?2][3?4?5]]3.2 張量內存存儲結構
tensor的數據結構包含兩個部分:
頭信息區Tensor:保存張量的形狀size,步長stride,數據類型等信息
存儲區Storage:保存真正的數據
頭信息區Tensor的占用內存較小,主要的占用內存是Storate。
每一個tensor都有著對應的storage,一般不同的tensor的頭信息可能不同,但是卻可能使用相同的storage。(這里就是之前共享內存的view、reshape方法,雖然頭信息的張量形狀size發生了改變,但是其實存儲的數據都是同一個storage)
3.3 存儲區
我們來查看一個tensor的存儲區:
import?torch a?=?torch.arange(0,6) print(a.storage())輸出為:
?012345 [torch.LongStorage?of?size?6]然后對tensor變量做一個view的變換:
b?=?a.view(2,3)這個b.storage()輸出出來時和a.storate(),相同的,這也是為什么view變換是內存共享的了。
#?id()是獲取對象的內存地址 print(id(a)==id(b))?#?False print(id(a.storage)==id(b.storage))?#?True可以發現,其實a和b雖然存儲區是相同的,但是其實a和b整體式不同的。自然,這個不同就不同在頭信息區,應該是尺寸size改變了。這也就是頭信息區不同,但是存儲區相同,從而節省大量內存
我們更進一步,假設對tensor切片了,那么切片后的數據是否共享內存,切片后的數據的storage是什么樣子的呢?
print('研究tensor的切片') a?=?torch.arange(0,6) b?=?a[2] print(id(a.storage)==id(b.storage))輸出結果為:
>>>?True沒錯,就算切片之后,兩個tensor依然使用同一個存儲區,所以相比也是共享內存的,修改一個另一個也會變化。
#.data_ptr(),返回tensor首個元素的內存地址。 print(a.data_ptr(),b.data_ptr()) print(b.data_ptr()-a.data_ptr())輸出為:
2080207827328?2080207827344 16這是因為b的第一個元素和a的第一個元素內存地址相差了16個字節,因為默認的tesnor是int64,也就是8個字節一個元素,所以這里相差了2個整形元素
3.4 頭信息區
依然是上面那兩個tensor變量,a和b
a?=?torch.arange(0,6) b?=?a.view(2,3) print(a.stride(),b.stride())輸出為:
(1,)?(3,?1)變量a是一維數組,并且就是[0,1,2,3,4,5],所以步長stride是1;而b是二維數組,是[[0,1,2],[3,4,5]],所以就是先3個3個分成第一維度的,然后再1個1個的作為第二維度。
由此可見,絕大多數操作并不修改 tensor 的數據,只是修改了 tensor 的頭信息,這種做法更節省內存,同時提升了處理速度。
- END -往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/662nyZF本站qq群704220115。加入微信群請掃碼進群(如果是博士或者準備讀博士請說明): 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【小白学PyTorch】9.tensor数据结构与存储结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【论文解读】无需额外数据、Tricks、
- 下一篇: 【Python基础】50个令人大开眼界的