Pytorch中.detach()與.data的用法小結(jié)
Pytorch中.detach()與.data的用法
這里是官方文檔對(duì)detach的定義

實(shí)際上,detach()就是返回一個(gè)新的tensor,并且這個(gè)tensor是從當(dāng)前的計(jì)算圖中分離出來(lái)的。但是返回的tensor和原來(lái)的tensor是共享內(nèi)存空間的。
import torch a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True) a = a.detach() # 會(huì)將requires_grad 屬性設(shè)置為False print(a.requires_grad)
舉個(gè)例子來(lái)說(shuō)明一下detach有什么用。 如果A網(wǎng)絡(luò)的輸出被喂給B網(wǎng)絡(luò)作為輸入, 如果我們希望在梯度反傳的時(shí)候只更新B中參數(shù)的值,而不更新A中的參數(shù)值,這時(shí)候就可以使用detach()
a = A(input) a = a.deatch() # 或者a.detach_()進(jìn)行in_place操作 out = B(a) loss = criterion(out, labels) loss.backward()
如果希望修改A的參數(shù), 而不希望修改B的參數(shù), 那么就需要手動(dòng)將B中參數(shù)的requires_grad屬性設(shè)置為False
for param in B.parameters():
param.requires_grad = False還有一點(diǎn)需要注意的是Tensor.detach()和Tensor.data的區(qū)別
Tensor.data和Tensor.detach()一樣, 都會(huì)返回一個(gè)新的Tensor, 這個(gè)Tensor和原來(lái)的Tensor共享內(nèi)存空間,一個(gè)改變,另一個(gè)也會(huì)隨著改變,且都會(huì)設(shè)置新的Tensor的requires_grad屬性為False。這兩個(gè)方法只取出原來(lái)Tensor的tensor數(shù)據(jù), 丟棄了grad、grad_fn等額外的信息。區(qū)別在于Tensor.data不能被autograd追蹤到,如果你修改了Tensor.data返回的新Tensor,原來(lái)的Tensor也會(huì)改變, 但是這時(shí)候的微分并沒(méi)有被追蹤到,那么當(dāng)你執(zhí)行l(wèi)oss.backward()的時(shí)候并不會(huì)報(bào)錯(cuò),但是求的梯度就是錯(cuò)誤的!因此, 如果你使用了Tensor.data,那么切記一定不要隨便修改返回的新Tensor的值。如果你使用的是Tensor.detach()方法,當(dāng)你修改他的返回值并進(jìn)行求導(dǎo)操作,會(huì)報(bào)錯(cuò)。 因此,Tensor.detach()是安全的。
pytorch中的.detach和.data深入詳解
前言:這兩個(gè)方法都可以用來(lái)從原有的計(jì)算圖中分離出某一個(gè)tensor,有相似的地方,也有不同的地方,下面來(lái)比較性的看一看。PyTorch0.4以及之后的版本中,.data 仍保留,但建議使用 .detach()
一、tensor.data的使用
先直接看一段代碼:
import torch
a = torch.tensor([1,2,3.], requires_grad = True)
out = a.sigmoid()
c = out.data # 需要走注意的是,通過(guò).data “分離”得到的的變量會(huì)和原來(lái)的變量共用同樣的數(shù)據(jù),而且新分離得到的張量是不可求導(dǎo)的,c發(fā)生了變化,原來(lái)的張量也會(huì)發(fā)生變化
c.zero_() # 改變c的值,原來(lái)的out也會(huì)改變
print(c.requires_grad)
print(c)
print(out.requires_grad)
print(out)
print("----------------------------------------------")
out.sum().backward() # 對(duì)原來(lái)的out求導(dǎo),
print(a.grad) # 不會(huì)報(bào)錯(cuò),但是結(jié)果卻并不正確
'''運(yùn)行結(jié)果為:
False
tensor([0., 0., 0.])
True
tensor([0., 0., 0.], grad_fn=<SigmoidBackward>)
----------------------------------------------
tensor([0., 0., 0.])
'''tensor.data的兩點(diǎn)總結(jié):
(1)tensor .data 返回和 x 的相同數(shù)據(jù) tensor,而且這個(gè)新的tensor和原來(lái)的tensor是共用數(shù)據(jù)的,一者改變,另一者也會(huì)跟著改變,而且新分離得到的tensor的require s_grad = False, 即不可求導(dǎo)的。(這一點(diǎn)其實(shí)detach是一樣的)
(2)使用tensor.data的局限性。文檔中說(shuō)使用tensor.data是不安全的, 因?yàn)?x.data 不能被 autograd 追蹤求微分 。什么意思呢?從上面的例子可以看出,由于我更改分離之后的變量值c,導(dǎo)致原來(lái)的張量out的值也跟著改變了,但是這種改變對(duì)于autograd是沒(méi)有察覺(jué)的,它依然按照求導(dǎo)規(guī)則來(lái)求導(dǎo),導(dǎo)致得出完全錯(cuò)誤的導(dǎo)數(shù)值卻渾然不知。它的風(fēng)險(xiǎn)性就是如果我再任意一個(gè)地方更改了某一個(gè)張量,求導(dǎo)的時(shí)候也沒(méi)有通知我已經(jīng)在某處更改了,導(dǎo)致得出的導(dǎo)數(shù)值完全不正確,故而風(fēng)險(xiǎn)大。
二、tensor.detach()的使用
同樣是使用上面的案例代碼,將.data 更改成 .detach,如下:
import torch
a = torch.tensor([1,2,3.], requires_grad = True)
out = a.sigmoid()
c = out.detach() # 需要走注意的是,通過(guò).detach() “分離”得到的的變量會(huì)和原來(lái)的變量共用同樣的數(shù)據(jù),而且新分離得到的張量是不可求導(dǎo)的,c發(fā)生了變化,原來(lái)的張量也會(huì)發(fā)生變化
c.zero_() # 改變c的值,原來(lái)的out也會(huì)改變
print(c.requires_grad)
print(c)
print(out.requires_grad)
print(out)
print("----------------------------------------------")
out.sum().backward() # 對(duì)原來(lái)的out求導(dǎo),
print(a.grad) # 此時(shí)會(huì)報(bào)錯(cuò),錯(cuò)誤結(jié)果參考下面,顯示梯度計(jì)算所需要的張量已經(jīng)被“原位操作inplace”所更改了。
'''
False
tensor([0., 0., 0.])
True
tensor([0., 0., 0.], grad_fn=<SigmoidBackward>)
----------------------------------------------
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
'''tensor.detach()的兩點(diǎn)總結(jié):
(1)tensor .detach() 返回和 x 的相同數(shù)據(jù) tensor,而且這個(gè)新的tensor和原來(lái)的tensor是共用數(shù)據(jù)的,一者改變,另一者也會(huì)跟著改變,而且新分離得到的tensor的require s_grad = False, 即不可求導(dǎo)的。(這一點(diǎn)其實(shí) .data是一樣的)
(2)使用tensor.detach()的優(yōu)點(diǎn)。從上面的例子可以看出,由于我更改分離之后的變量值c,導(dǎo)致原來(lái)的張量out的值也跟著改變了,這個(gè)時(shí)候如果依然按照求導(dǎo)規(guī)則來(lái)求導(dǎo),由于out已經(jīng)更改了,所以不會(huì)再繼續(xù)求導(dǎo)了,而是報(bào)錯(cuò),這樣就避免了得出完全牛頭不對(duì)馬嘴的求導(dǎo)結(jié)果。
三、總結(jié)
相同點(diǎn):tensor.data和tensor.detach() 都是變量從圖中分離,但而這都是“原位操作 inplace operation”。
不同點(diǎn):
(1).data 是一個(gè)屬性,二.detach()是一個(gè)方法;
(2).data 是不安全的,.detach()是安全的。
到此這篇關(guān)于Pytorch中.detach()與.data的用法的文章就介紹到這了,更多相關(guān)Pytorch中.detach()與.data內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python基于xml parse實(shí)現(xiàn)解析cdatasection數(shù)據(jù)
這篇文章主要介紹了python基于xml parse實(shí)現(xiàn)解析cdatasection數(shù)據(jù)的方法,是非常實(shí)用技巧,需要的朋友可以參考下2014-09-09
web.py在SAE中的Session問(wèn)題解決方法(使用mysql存儲(chǔ))
這篇文章主要介紹了web.py在SAE中的Session問(wèn)題解決方法(使用mysql存儲(chǔ)),本文直接給出實(shí)現(xiàn)代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下2015-06-06
python判斷一組數(shù)呈上升還是下降趨勢(shì)的操作方法
要判斷一組數(shù)(數(shù)列)是呈上升趨勢(shì)、下降趨勢(shì)還是無(wú)明顯趨勢(shì),我們可以比較數(shù)列中相鄰元素的差值,這篇文章主要介紹了python?如何判斷一組數(shù)呈上升還是下降趨勢(shì),需要的朋友可以參考下2024-06-06
python?turtle庫(kù)畫(huà)圣誕樹(shù)詳細(xì)代碼教程
這篇文章主要介紹了python?turtle庫(kù)畫(huà)圣誕樹(shù)詳細(xì)代碼教程,圣誕節(jié)快到了,下面小編就來(lái)利用python?turtle庫(kù)畫(huà)一顆圣誕樹(shù),?主要成分有圣誕樹(shù)的本體、大小蝴蝶結(jié)、星星、圣誕帽和襪子,需要的朋友可以參考一下2021-12-12
Django與遺留的數(shù)據(jù)庫(kù)整合的方法指南
這篇文章主要介紹了Django與遺留的數(shù)據(jù)庫(kù)整合的方法指南,Django是最具人氣的Python開(kāi)發(fā)框架,需要的朋友可以參考下2015-07-07
解決pandas中讀取中文名稱的csv文件報(bào)錯(cuò)的問(wèn)題
今天小編就為大家分享一篇解決pandas中讀取中文名稱的csv文件報(bào)錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Django中文件上傳和文件訪問(wèn)微項(xiàng)目的方法
這篇文章主要介紹了Django中文件上傳和文件訪問(wèn)微項(xiàng)目的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
python 通過(guò)字符串調(diào)用對(duì)象屬性或方法的實(shí)例講解
下面小編就為大家分享一篇python 通過(guò)字符串調(diào)用對(duì)象屬性或方法的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
Python Web程序搭建簡(jiǎn)單的Web服務(wù)器
這篇文章主要介紹了Python Web程序搭建簡(jiǎn)單的Web服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

