<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【小白學(xué)PyTorch】9.tensor數(shù)據(jù)結(jié)構(gòu)與存儲(chǔ)結(jié)構(gòu)

          共 6970字,需瀏覽 14分鐘

           ·

          2020-09-21 18:04

          【機(jī)器學(xué)習(xí)煉丹術(shù)】的學(xué)習(xí)筆記分享
          <<小白學(xué)PyTorch>>

          小白學(xué)PyTorch | 8 實(shí)戰(zhàn)之MNIST小試牛刀

          小白學(xué)PyTorch | 7 最新版本torchvision.transforms常用API翻譯與講解

          小白學(xué)PyTorch | 6 模型的構(gòu)建訪問遍歷存儲(chǔ)(附代碼)

          小白學(xué)PyTorch | 5 torchvision預(yù)訓(xùn)練模型與數(shù)據(jù)集全覽

          小白學(xué)PyTorch | 4 構(gòu)建模型三要素與權(quán)重初始化

          小白學(xué)PyTorch | 3 淺談Dataset和Dataloader

          小白學(xué)PyTorch | 2 淺談?dòng)?xùn)練集驗(yàn)證集和測試集

          小白學(xué)PyTorch | 1 搭建一個(gè)超簡單的網(wǎng)絡(luò)

          小白學(xué)PyTorch | 動(dòng)態(tài)圖與靜態(tài)圖的淺顯理解

          上一節(jié)課,講解了MNIST圖像分類的一個(gè)小實(shí)戰(zhàn),現(xiàn)在我們繼續(xù)深入學(xué)習(xí)一下pytorch的一些有的沒的的小知識(shí)來作為只是儲(chǔ)備。

          參考目錄:

          • 1 pytorch數(shù)據(jù)結(jié)構(gòu)

            • 1.1 默認(rèn)整數(shù)與浮點(diǎn)數(shù)

            • 1.2 dtype修改變量類型

            • 1.3 變量類型有哪些

            • 1.4 數(shù)據(jù)類型轉(zhuǎn)換

          • 2 torch vs numpy

            • 2.1 兩者轉(zhuǎn)換

            • 2.2 兩者區(qū)別

          • 3 張量

            • 3.1 張量修改尺寸

            • 3.2 張量內(nèi)存存儲(chǔ)結(jié)構(gòu)

            • 3.3 存儲(chǔ)區(qū)

            • 3.4 頭信息區(qū)

          1 pytorch數(shù)據(jù)結(jié)構(gòu)

          1.1 默認(rèn)整數(shù)與浮點(diǎn)數(shù)

          【pytorch默認(rèn)的整數(shù)是int64】

          pytorch的默認(rèn)整數(shù)是用64個(gè)比特存儲(chǔ),也就是8個(gè)字節(jié)(Byte)存儲(chǔ)的。

          【pytorch默認(rèn)的浮點(diǎn)數(shù)是float32】

          pytorch的默認(rèn)浮點(diǎn)數(shù)是用32個(gè)比特存儲(chǔ),也就是4個(gè)字節(jié)(Byte)存儲(chǔ)的。

          import torch
          import numpy as np
          #----------------------
          print('torch的浮點(diǎn)數(shù)與整數(shù)的默認(rèn)數(shù)據(jù)類型')
          a = torch.tensor([1,2,3])
          b = torch.tensor([1.,2.,3.])
          print(a,a.dtype)
          print(b,b.dtype)

          輸出:

          torch的浮點(diǎn)數(shù)與整數(shù)的默認(rèn)數(shù)據(jù)類型
          tensor([1,?2,?3])?torch.int64
          tensor([1.,?2.,?3.])?torch.float32

          1.2 dtype修改變量類型

          print('torch的浮點(diǎn)數(shù)與整數(shù)的默認(rèn)數(shù)據(jù)類型')
          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)

          輸出結(jié)果:

          torch的浮點(diǎn)數(shù)與整數(shù)的默認(rèn)數(shù)據(jù)類型
          tensor([1,?2,?3],?dtype=torch.int8)?torch.int8
          tensor([1.,?2.,?3.],?dtype=torch.float64)?torch.float64

          1.3 變量類型有哪些

          張量的數(shù)據(jù)類型其實(shí)和numpy.array基本一一對(duì)應(yīng),除了不支持str,主要有下面幾種形式:

          torch.float64?#?等同于(torch.double)
          torch.float32?#?默認(rèn),FloatTensor
          torch.float16
          torch.int64???#?等同于torch.long
          torch.int32???#?默認(rèn)
          torch.int16
          torch.int8
          torch.uint8???#?二進(jìn)制碼,表示0-255
          torch.bool

          在創(chuàng)建變量的時(shí)候,想要?jiǎng)?chuàng)建指定的變量類型,上文中提到了用dtype關(guān)鍵字來控制,但是我個(gè)人更喜歡使用特定的構(gòu)造函數(shù):

          print('torch的構(gòu)造函數(shù)')
          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)

          輸出結(jié)果:

          torch的構(gòu)造函數(shù)
          torch.int32
          torch.int64
          torch.float32
          torch.float64
          torch.int64
          torch.float32

          因此我們可以得到結(jié)果:

          • torch.IntTensor對(duì)應(yīng)torch.int32
          • torch.LongTensor對(duì)應(yīng)torch.int64,LongTensor常用在深度學(xué)習(xí)中的標(biāo)簽值 ,比方說分類任務(wù)中的類別標(biāo)簽0,1,2,3等,要求用ing64的數(shù)據(jù)類型;
          • torch.FloatTensor對(duì)應(yīng)torch.float32。FloatTensor常用做深度學(xué)習(xí)中可學(xué)習(xí)參數(shù)或者輸入數(shù)據(jù)的類型
          • torch.DoubleTensor對(duì)應(yīng)torch.float64
          • torch.tensor則有一個(gè)推斷的能力,加入輸入的數(shù)據(jù)是整數(shù),則默認(rèn)int64,相當(dāng)于LongTensor;假如輸入數(shù)據(jù)是浮點(diǎn)數(shù),則默認(rèn)float32,相當(dāng)于FLoatTensor。剛好對(duì)應(yīng)深度學(xué)習(xí)中的標(biāo)簽和參數(shù)的數(shù)據(jù)類型,所以一般情況下,直接使用tensor就可以了,但是假如出現(xiàn)報(bào)錯(cuò)的時(shí)候,也要學(xué)會(huì)使用dtype或者構(gòu)造函數(shù)來確保數(shù)據(jù)類型的匹配

          1.4 數(shù)據(jù)類型轉(zhuǎn)換

          【使用torch.float()方法】

          print('數(shù)據(jù)類型轉(zhuǎn)換')
          a?=?torch.tensor([1,2,3])
          b?=?a.float()
          c?=?a.double()
          d?=?a.long()
          print(b.dtype)
          print(c.dtype)
          print(d.dtype)
          >>>?數(shù)據(jù)類型轉(zhuǎn)換
          >>>?torch.float32
          >>>?torch.float64
          >>>?torch.int64

          我個(gè)人比較習(xí)慣這個(gè)的方法。

          【使用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.int64

          2 torch vs numpy

          PyTorch是一個(gè)python包,目的是加入深度學(xué)習(xí)應(yīng)用, torch基本上是實(shí)現(xiàn)了numpy的大部分必要的功能,并且tensor是可以利用GPU進(jìn)行加速訓(xùn)練的。

          2.1 兩者轉(zhuǎn)換

          轉(zhuǎn)換時(shí)非常非常簡單的:

          import?torch
          import?numpy?as?np

          a?=?np.array([1.,2.,3.])
          b?=?torch.tensor(a)
          c?=?b.numpy()
          print(a)
          print(b)
          print(c)

          輸出結(jié)果:

          [1.?2.?3.]
          tensor([1.,?2.,?3.],?dtype=torch.float64)
          [1.?2.?3.]

          下面的內(nèi)容就變得有點(diǎn)意思了,是內(nèi)存復(fù)制相關(guān)的。假如a和b兩個(gè)變量共享同一個(gè)內(nèi)存,那么改變a的話,b也會(huì)跟著改變;如果a和b變量的內(nèi)存復(fù)制了,那么兩者是兩個(gè)內(nèi)存,所以改變a是不會(huì)改變b的。下面是講解numpy和torch互相轉(zhuǎn)換的時(shí)候,什么情況是共享內(nèi)存,什么情況下是內(nèi)存復(fù)制 (其實(shí)這個(gè)問題,也就是做個(gè)了解罷了,無用的小知識(shí))

          【Tensor()轉(zhuǎn)換】當(dāng)numpy的數(shù)據(jù)類型和torch的數(shù)據(jù)類型相同時(shí),共享內(nèi)存;不同的時(shí)候,內(nèi)存復(fù)制

          print('numpy?和torch互相轉(zhuǎn)換1')
          a?=?np.array([1,2,3],dtype=np.float64)
          b?=?torch.Tensor(a)
          b[0]?=?999
          print('共享內(nèi)存'?if?a[0]==b[0]?else?'不共享內(nèi)存')
          >>>?不共享內(nèi)存

          因?yàn)閚p.float64和torch.float32數(shù)據(jù)類型不同

          print('numpy?和torch互相轉(zhuǎn)換2')
          a?=?np.array([1,2,3],dtype=np.float32)
          b?=?torch.Tensor(a)
          b[0]?=?999
          print('共享內(nèi)存'?if?a[0]==b[0]?else?'不共享內(nèi)存')
          >>>?共享內(nèi)存

          因?yàn)閚p.float32和torch.float32數(shù)據(jù)類型相同

          【from_numpy()轉(zhuǎn)換】

          print('from_numpy()')
          a?=?np.array([1,2,3],dtype=np.float64)
          b?=?torch.from_numpy(a)
          b[0]?=?999
          print('共享內(nèi)存'?if?a[0]==b[0]?else?'不共享內(nèi)存')
          >>>?共享內(nèi)存
          a?=?np.array([1,2,3],dtype=np.float32)
          b?=?torch.from_numpy(a)
          b[0]?=?999
          print('共享內(nèi)存'?if?a[0]==b[0]?else?'不共享內(nèi)存')
          >>>?共享內(nèi)存

          如果你使用from_numpy()的時(shí)候,不管是什么類型,都是共享內(nèi)存的。

          【tensor()轉(zhuǎn)換】

          更常用的是這個(gè)tensor(),注意看T的大小寫, 如果使用的是tensor方法,那么不管輸入類型是什么,torch.tensor都會(huì)進(jìn)行數(shù)據(jù)拷貝,不共享內(nèi)存。

          【.numpy()】tensor轉(zhuǎn)成numpy的時(shí)候,.numpy方法是內(nèi)存共享的哦。如果想改成內(nèi)存拷貝的話,可以使用.numpy().copy()就不共享內(nèi)存了?;蛘呤褂?code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">.clone().numpy()也可以實(shí)現(xiàn)同樣的效果。clone是tensor的方法,copy是numpy的方法。

          【總結(jié)】

          記不清的話,就記住,tensor()數(shù)據(jù)拷貝了,.numpy()共享內(nèi)存就行了。

          2.2 兩者區(qū)別

          【命名】

          雖然PyTorch實(shí)現(xiàn)了Numpy的很多功能,但是相同的功能卻有著不同的命名方式,這讓使用者迷惑。

          例如創(chuàng)建隨機(jī)張量的時(shí)候:

          print('命名規(guī)則')
          a?=?torch.rand(2,3,4)
          b?=?np.random.rand(2,3,4)

          【張量重塑】

          這部分會(huì)放在下一章節(jié)詳細(xì)說明~

          3 張量

          • 標(biāo)量:數(shù)據(jù)是一個(gè)數(shù)字
          • 向量:數(shù)據(jù)是一串?dāng)?shù)字,也是一維張量
          • 矩陣:數(shù)據(jù)二維數(shù)組,也是二維張量
          • 張量:數(shù)據(jù)的維度超過2的時(shí)候,就叫多維張量

          3.1 張量修改尺寸

          • pytorch常用reshape和view
          • numpy用resize和reshape
          • pytorch也有resize但是不常用

          【reshape和view共享內(nèi)存(常用)】

          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)

          輸出結(jié)果:

          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三個(gè)變量其實(shí)是共享同一個(gè)內(nèi)存,遷一而動(dòng)全身。而且要求遵旨規(guī)則:原始數(shù)據(jù)有6個(gè)元素,所以可以修改成的形式,但是無法修改成的形式 ,我們來試試:

          a?=?torch.arange(0,6)
          b?=?a.reshape((2,4))

          會(huì)拋出這樣的錯(cuò)誤:

          【torch的resize_(不常用)】

          但是pytorch有一個(gè)不常用的函數(shù)(對(duì)我來說用的不多),resize,這個(gè)方法可以不遵守這個(gè)規(guī)則:

          a?=?torch.arange(0,6)
          a.resize_(2,4)
          print(a)

          輸出結(jié)果為:自動(dòng)的補(bǔ)充了兩個(gè)元素。雖然不知道這個(gè)函數(shù)有什么意義。。。。。。

          這里可以看到函數(shù)resize后面有一個(gè)_,這個(gè)表示inplace=True的意思,當(dāng)有這個(gè)_或者參數(shù)inplace的時(shí)候,就是表示所作的修改是在原來的數(shù)據(jù)變量上完成的,也就不需要賦值給新的變量了。

          【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)

          兩個(gè)代碼塊的輸出都是下面的,區(qū)別在于numpy的resize是沒有返回值的,相當(dāng)于inplace=True了,直接在原變量的進(jìn)行修改,而reshape是有返回值的,不在原變量上修改(但是呢reshape是共享內(nèi)存的):

          [[0?1?2]
          ?[3?4?5]]

          3.2 張量內(nèi)存存儲(chǔ)結(jié)構(gòu)

          tensor的數(shù)據(jù)結(jié)構(gòu)包含兩個(gè)部分:

          • 頭信息區(qū)Tensor:保存張量的形狀size,步長stride,數(shù)據(jù)類型等信息
          • 存儲(chǔ)區(qū)Storage:保存真正的數(shù)據(jù)

          頭信息區(qū)Tensor的占用內(nèi)存較小,主要的占用內(nèi)存是Storate。

          每一個(gè)tensor都有著對(duì)應(yīng)的storage,一般不同的tensor的頭信息可能不同,但是卻可能使用相同的storage。(這里就是之前共享內(nèi)存的view、reshape方法,雖然頭信息的張量形狀size發(fā)生了改變,但是其實(shí)存儲(chǔ)的數(shù)據(jù)都是同一個(gè)storage)

          3.3 存儲(chǔ)區(qū)

          我們來查看一個(gè)tensor的存儲(chǔ)區(qū):

          import?torch
          a?=?torch.arange(0,6)
          print(a.storage())

          輸出為:

          ?0
          ?1
          ?2
          ?3
          ?4
          ?5
          [torch.LongStorage?of?size?6]

          然后對(duì)tensor變量做一個(gè)view的變換:

          b?=?a.view(2,3)

          這個(gè)b.storage()輸出出來時(shí)和a.storate(),相同的,這也是為什么view變換是內(nèi)存共享的了。

          #?id()是獲取對(duì)象的內(nèi)存地址
          print(id(a)==id(b))?#?False
          print(id(a.storage)==id(b.storage))?#?True

          可以發(fā)現(xiàn),其實(shí)a和b雖然存儲(chǔ)區(qū)是相同的,但是其實(shí)a和b整體式不同的。自然,這個(gè)不同就不同在頭信息區(qū),應(yīng)該是尺寸size改變了。這也就是頭信息區(qū)不同,但是存儲(chǔ)區(qū)相同,從而節(jié)省大量內(nèi)存

          我們更進(jìn)一步,假設(shè)對(duì)tensor切片了,那么切片后的數(shù)據(jù)是否共享內(nèi)存,切片后的數(shù)據(jù)的storage是什么樣子的呢?

          print('研究tensor的切片')
          a?=?torch.arange(0,6)
          b?=?a[2]
          print(id(a.storage)==id(b.storage))

          輸出結(jié)果為:

          >>>?True

          沒錯(cuò),就算切片之后,兩個(gè)tensor依然使用同一個(gè)存儲(chǔ)區(qū),所以相比也是共享內(nèi)存的,修改一個(gè)另一個(gè)也會(huì)變化。

          #.data_ptr(),返回tensor首個(gè)元素的內(nèi)存地址。
          print(a.data_ptr(),b.data_ptr())
          print(b.data_ptr()-a.data_ptr())

          輸出為:

          2080207827328?2080207827344
          16

          這是因?yàn)閎的第一個(gè)元素和a的第一個(gè)元素內(nèi)存地址相差了16個(gè)字節(jié),因?yàn)槟J(rèn)的tesnor是int64,也就是8個(gè)字節(jié)一個(gè)元素,所以這里相差了2個(gè)整形元素

          3.4 頭信息區(qū)

          依然是上面那兩個(gè)tensor變量,a和b

          a?=?torch.arange(0,6)
          b?=?a.view(2,3)
          print(a.stride(),b.stride())

          輸出為:

          (1,)?(3,?1)

          變量a是一維數(shù)組,并且就是[0,1,2,3,4,5],所以步長stride是1;而b是二維數(shù)組,是[[0,1,2],[3,4,5]],所以就是先3個(gè)3個(gè)分成第一維度的,然后再1個(gè)1個(gè)的作為第二維度。

          由此可見,絕大多數(shù)操作并不修改 tensor 的數(shù)據(jù),只是修改了 tensor 的頭信息,這種做法更節(jié)省內(nèi)存,同時(shí)提升了處理速度。


          - END -


          往期精彩回顧





          獲取一折本站知識(shí)星球優(yōu)惠券,復(fù)制鏈接直接打開:

          https://t.zsxq.com/662nyZF

          本站qq群704220115。

          加入微信群請(qǐng)掃碼進(jìn)群(如果是博士或者準(zhǔn)備讀博士請(qǐng)說明):

          瀏覽 96
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线观看国产一区 | 干欧美老女人 | 俺也去吧色影院 | 啊啊啊啊啊啊啊网站 | 黄色毛片学生妹免费看视频 |