版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第淺談Pytorch中autograd的若干(踩坑)總結(jié)關(guān)于Variable和Tensor
舊版本的Pytorch中,Variable是對(duì)Tensor的一個(gè)封裝;在Pytorch大于v0.4的版本后,Varible和Tensor合并了,意味著Tensor可以像舊版本的Variable那樣運(yùn)行,當(dāng)然新版本中Variable封裝仍舊可以用,但是對(duì)Varieble操作返回的將是一個(gè)Tensor。
importtorchast
fromtorch.autogradimportVariable
a=t.ones(3,requires_grad=True)
print(type(a))
#輸出:class'torch.Tensor'
a=Variable(a)
print(type(a))
#輸出仍舊是:class'torch.Tensor'
print(a.volatile)
#輸出:__main__:1:UserWarning:volatilewasremoved(Variable.volatileisalwaysFalse)
a.volatile=True
print(a.volatile)
#輸出:__main__:1:UserWarning:volatilewasremoved(Variable.volatileisalwaysFalse)
#現(xiàn)版本pytorch中移除了volatile這個(gè)屬性,即volatile總是false
葉子節(jié)點(diǎn)leaf
對(duì)于那些不是任何函數(shù)(Function)的輸出,由用戶創(chuàng)建的節(jié)點(diǎn)稱為葉子節(jié)點(diǎn),葉子節(jié)點(diǎn)的grad_fn為None。
importtorchast
a=t.ones(3,requires_grad=True)
b=t.rand(3,requires_grad=True)
a,a.is_leaf
#輸出:(tensor([1.,1.,1.],requires_grad=True),True)
#輸出:(tensor([0.4254,0.8763,0.5901],requires_grad=True),True)
c=a*b
c.is_leaf
#輸出:False.說明c不是葉子節(jié)點(diǎn)
a.grad_fn
#輸出:None.葉子節(jié)點(diǎn)的grad_fn為None.
c.grad_fn
#輸出:MulBackward0objectat0x7fa45c406278
autograd操作
首先Tensor是默認(rèn)不需要求導(dǎo)的,即requires_grad默認(rèn)為False。
importtorchast
a=t.ones(3)
a.requires_grad
#輸出:False.Tensor默認(rèn)不需要求導(dǎo)
如果某一個(gè)節(jié)點(diǎn)requires_grad被設(shè)置為True,那么所有依賴它的節(jié)點(diǎn)requires_grad都為True。
importtorchast
a=t.ones(3)
b=t.ones(3,requires_grad=True)
b.requires_grad
#輸出:True
c=a+b
c.requires_grad
#輸出:True.雖然c沒有指定需要求導(dǎo),然是c依賴于b,而b需要求導(dǎo),所以c.requires_grad=True
只有scalar才能進(jìn)行反向backward()操作,并且backward對(duì)于葉節(jié)點(diǎn)的grad的是累加的。當(dāng)只進(jìn)行計(jì)算操作不做backward,葉節(jié)點(diǎn)的grad不發(fā)生變化。
更正一下,并不是只有scaler才能進(jìn)行backward操作,矩陣和向量也可以,只不過backward()中要添加對(duì)應(yīng)維度的參數(shù)。
importtorchast
a=t.ones(3,requires_grad=True)
b=t.rand(3,requires_grad=True)
#輸出:(tensor([1.,1.,1.],requires_grad=True),
#tensor([0.9373,0.0556,0.6426],requires_grad=True))
c=a*b
#輸出:tensor([0.9373,0.0556,0.6426],grad_fn=MulBackward0)
c.backward(retain_graph=True)
#輸出:RuntimeError:gradcanbeimplicitlycreatedonlyforscalaroutputs
#只有數(shù)值scalar才能進(jìn)行backward操作
d=c.sum()
d.backward(retain_graph=True)
#retain_graph=True是為了保存中間緩存,否則再次backward的時(shí)候會(huì)報(bào)錯(cuò)
a.grad
#輸出:tensor([0.9373,0.0556,0.6426])
b.grad
#輸出:tensor([1.,1.,1.])
#backward后a和b的grad產(chǎn)生了數(shù)值
e=c.sum()
e.backward(retain_graph=True)
b.grad
#輸出:tensor([2.,2.,2.]).b的grad進(jìn)行了兩次backward后進(jìn)行了累加.
f=c.sum()
b.grad
#輸出:tensor([2.,2.,2.])
#只進(jìn)行計(jì)算不backward,梯度不更新
Tensor.data和Tensor.detach()
如過tensor的數(shù)值需要參與計(jì)算又不想?yún)⑴c到計(jì)算圖的更新中,計(jì)算的時(shí)候可以用tensor.data,這樣既能利用tensor的數(shù)值,又不會(huì)更新梯度。
importtorchast
a=t.ones(3,4,requires_grad=True)
b=t.rand(3,4,requires_grad=True)
a.data.requires_grad
#輸出:False.a.data獨(dú)立于計(jì)算圖之外
c=a.data*b.data
d=c.sum()
d.backward()
#輸出:RuntimeError:element0oftensorsdoesnotrequiregradanddoesnothaveagrad_fn
#因?yàn)楠?dú)立于計(jì)算圖之外,requires_grad=False所以不能backward()
當(dāng)tensor.data被修改的時(shí)候,tensor也會(huì)同步的被修改,此時(shí)用該tensor進(jìn)行計(jì)算并backward的時(shí)候梯度的值就不再準(zhǔn)確了,因?yàn)閠ensor已經(jīng)被修改了!
importtorchast
a=t.ones(3,4,requires_grad=True)
b=t.rand(3,4,requires_grad=True)
c=a*b
d=c.sum()
a.data.sigmoid_()
#輸出:tensor([[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311]])
#雖然對(duì)a.data進(jìn)行sigmoid操作,但是a的值已經(jīng)被修改了.
d.backward()
b.grad
#輸出:tensor([[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311]])
#b的grad不準(zhǔn)了,本來應(yīng)該都是1!
為了避免因?yàn)閷?duì)tensor.data修改導(dǎo)致grad變化的情況,可以利用tensor.detach,同樣可以保證tensor不參與到計(jì)算圖當(dāng)中,但是當(dāng)tensor的值被改變的時(shí)候,再進(jìn)行backward就會(huì)報(bào)錯(cuò)而不會(huì)有先前的因?yàn)閠ensor的值被改變而導(dǎo)致不準(zhǔn)的情況了。
importtorchast
a=t.ones(3,4,requires_grad=True)
b=t.rand(3,4,requires_grad=True)
c=a*b
d=c.sum()
a_=a.detach()
a_.sigmoid_()
#輸出:tensor([[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311],
#[0.7311,0.7311,0.7311,0.7311]],requires_grad=True)
#a的值已經(jīng)發(fā)生了改變
d.backward()
#報(bào)錯(cuò):RuntimeError:oneofthevariablesneededforgradientcomputationhasbeenmodifiedbyaninplaceoperation
#因?yàn)閍的值被修改了,所以不能再進(jìn)行backward
推薦用tensor.detach的方式而不是tensor.data的方式,因?yàn)檫@樣更保險(xiǎn)!
autograd.grad和hook
在計(jì)算的時(shí)候有時(shí)候我們可能會(huì)用到非葉節(jié)點(diǎn)的grad,但是非葉節(jié)點(diǎn)的grad在backward之后就會(huì)被自動(dòng)清空:
importtorchast
a=t.ones(3,4,requires_grad=True)
b=t.rand(3,4,requires_grad=True)
c=a*b
d=c.sum()
d.backward()
a.grad
#輸出:tensor([[0.3114,0.3017,0.8461,0.6899],
#[0.3878,0.8712,0.2406,0.7396],
#[0.6369,0.0907,0.4984,0.5058]])
c.grad
#輸出:None
#c為非葉子節(jié)點(diǎn),計(jì)算后被清空
可以用autograd.grad和hook來處理這種情況:
#利用autograd.grad獲取中間節(jié)點(diǎn)梯度
t.autograd.grad(d,c)
#輸出:(tensor([[1.,1.,1.,1.],
#[1.,1.,1.,1.],
#[1.,1.,1.,1.]]),)
#利用hook獲取中間節(jié)點(diǎn)梯度
importtorchast
a=t.ones(3,4,requires_grad=True)
b=t.rand(3,4,requires_grad=True)
c=a*b
d=c.sum()
defprint_grad(grad):
print(grad)
#給c注冊(cè)hook
c_hook=c.register_hook(print_grad)
d.backward()
#輸出:tensor([[1.,1.,1.,1.],
#[1.,1.,1.,1.],
#[1.,1.,1.,1.]])
#移除鉤子
c_hook.remove()
補(bǔ)充:關(guān)于Pytorch中autograd和backward的一些筆記
1Tensor
Pytorch中所有的計(jì)算其實(shí)都可以回歸到Tensor上,所以有必要重新認(rèn)識(shí)一下Tensor。
如果我們需要計(jì)算某個(gè)Tensor的導(dǎo)數(shù),那么我們需要設(shè)置其.requires_grad屬性為True。為方便說明,在本文中對(duì)于這種我們自己定義的變量,我們稱之為葉子節(jié)點(diǎn)(leafnodes),而基于葉子節(jié)點(diǎn)得到的中間或最終變量則可稱之為結(jié)果節(jié)點(diǎn)。
另外一個(gè)Tensor中通常會(huì)記錄如下圖中所示的屬性:
data:即存儲(chǔ)的數(shù)據(jù)信息
requires_grad:設(shè)置為True則表示該Tensor需要求導(dǎo)
grad:該Tensor的梯度值,每次在計(jì)算backward時(shí)都需要將前一時(shí)刻的梯度歸零,否則梯度值會(huì)一直累加,這個(gè)會(huì)在后面講到。
grad_fn:葉子節(jié)點(diǎn)通常為None,只有結(jié)果節(jié)點(diǎn)的grad_fn才有效,用于指示梯度函數(shù)是哪種類型。
is_leaf:用來指示該Tensor是否是葉子節(jié)點(diǎn)。
舉例:
x=torch.rand(3,requires_grad=True)
y=x**2
z=x+x
print(
'xrequiresgrad:{},isleaf:{},grad:{},grad_fn:{}.'
.format(x.requires_grad,x.is_leaf,x.grad,x.grad_fn)
print(
'yrequiresgrad:{},isleaf:{},grad:{},grad_fn:{}.'
.format(y.requires_grad,y.is_leaf,y.grad,y.grad_fn)
print(
'zrequiresgrad:{},isleaf:{},grad:{},grad_fn:{}.'
.format(z.requires_grad,z.is_leaf,z.grad,z.grad_fn)
)
運(yùn)行結(jié)果:
xrequiresgrad:True,isleaf:True,grad:None,grad_fn:None.
yrequiresgrad:True,isleaf:False,grad:None,grad_fn:PowBackward0objectat0x0000021A3002CD88.
zrequiresgrad:True,isleaf:False,grad:None,grad_fn:AddBackward0objectat0x0000021A3002CD88.
2torch.autograd.backward
如下代碼:
x=torch.tensor(1.0,requires_grad=True)
y=torch.tensor(2.0,requires_grad=True)
z=x**2+y
z.backward()
print(z,x.grad,y.grad)
tensor(3.,grad_fn=AddBackward0)tensor(2.)tensor(1.)
當(dāng)z是一個(gè)標(biāo)量,當(dāng)調(diào)用它的backward方法后會(huì)根據(jù)鏈?zhǔn)椒▌t自動(dòng)計(jì)算出葉子節(jié)點(diǎn)的梯度值。
但是如果遇到z是一個(gè)向量或者是一個(gè)矩陣的情況,這個(gè)時(shí)候又該怎么計(jì)算梯度呢?這種情況我們需要定義grad_tensor來計(jì)算矩陣的梯度。
在介紹為什么使用之前我們先看一下源代碼中backward的接口是如何定義的:
torch.autograd.backward(
tensors,
grad_tensors=None,
retain_graph=None,
create_graph=False,
grad_variables=None)
tensor:用于計(jì)算梯度的tensor。也就是說這兩種方式是等價(jià)的:torch.autograd.backward(z)==z.backward()
grad_tensors:在計(jì)算非標(biāo)量的梯度時(shí)會(huì)用到。他其實(shí)也是一個(gè)tensor,它的shape一般需要和前面的tensor保持一致。
retain_graph:通常在調(diào)用一次backward后,pytorch會(huì)自動(dòng)把計(jì)算圖銷毀,所以要想對(duì)某個(gè)變量重復(fù)調(diào)用backward,則需要將該參數(shù)設(shè)置為True
create_graph:當(dāng)設(shè)置為True的時(shí)候可以用來計(jì)算更高階的梯度
grad_variables:這個(gè)官方說法是grad_variables'isdeprecated.Use'grad_tensors'instead.也就是說這個(gè)參數(shù)后面版本中應(yīng)該會(huì)丟棄,直接使用grad_tensors就好了。
pytorch設(shè)計(jì)了grad_tensors這么一個(gè)參數(shù)。它的作用相當(dāng)于“權(quán)重”。
先看一個(gè)例子:
x=torch.ones(2,requires_grad=True)
z=x+2
z.backward()
RuntimeError:gradcanbeimplicitlycreatedonlyforscalaroutputs
上面的報(bào)錯(cuò)信息意思是只有對(duì)標(biāo)量輸出它才會(huì)計(jì)算梯度,而求一個(gè)矩陣對(duì)另一矩陣的導(dǎo)數(shù)束手無策。
x=torch.ones(2,requires_grad=True)
z=x+2
z.sum().backward()
print(x.grad)
tensor([1.,1.])
而grad_tensors這個(gè)參數(shù)就扮演了幫助求和的作用。
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年中職老年服務(wù)與管理(養(yǎng)老服務(wù))試題及答案
- 2025年高職水產(chǎn)養(yǎng)殖學(xué)(水產(chǎn)動(dòng)物養(yǎng)殖)試題及答案
- 2025年高職(新能源汽車檢測(cè)與維修)維修技術(shù)試題及答案
- 2025年高職助產(chǎn)學(xué)(產(chǎn)科護(hù)理技術(shù))試題及答案
- 禁毒安全教育內(nèi)容課件
- 口腔醫(yī)學(xué)考研就業(yè)前景
- 2026年幼兒春節(jié)故事歡歡喜喜過大年
- 光伏技術(shù)交底全套
- 光伏培訓(xùn)教學(xué)課件
- 2024黑龍江省各級(jí)機(jī)關(guān)考試錄用公務(wù)員備考題庫及參考答案詳解
- TOC基本課程講義學(xué)員版-王仕斌
- T-GDWCA 0035-2018 HDMI 連接線標(biāo)準(zhǔn)規(guī)范
- 面板堆石壩面板滑模結(jié)構(gòu)設(shè)計(jì)
- 初中語文新課程標(biāo)準(zhǔn)與解讀課件
- 無人機(jī)裝調(diào)檢修工培訓(xùn)計(jì)劃及大綱
- 中建通風(fēng)與空調(diào)施工方案
- 高考語言運(yùn)用題型之長短句變換 學(xué)案(含答案)
- 春よ、來い(春天來了)高木綾子演奏長笛曲譜鋼琴伴奏
- ARJ21機(jī)型理論知識(shí)考試題庫(匯總版)
- 2023年婁底市建設(shè)系統(tǒng)事業(yè)單位招聘考試筆試模擬試題及答案解析
- GB/T 4623-2014環(huán)形混凝土電桿
評(píng)論
0/150
提交評(píng)論