日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

(pytorch-深度学习系列)pytorch中backwards()函数对梯度的操作

發(fā)布時間:2024/8/23 pytorch 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (pytorch-深度学习系列)pytorch中backwards()函数对梯度的操作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

backwards()函數(shù)對梯度的操作

對于一個新的tensor來說,梯度是空的;但當(dāng)對這個tensor進行運算操作后,他就會擁有一個梯度:

x = torch.ones(2, 2, requires_grad=True) print(x) print(x.grad_fn)y = x + 2 print(y) print(y.grad_fn)

輸出結(jié)果:

tensor([[1., 1.],[1., 1.]], requires_grad=True) None tensor([[3., 3.],[3., 3.]], grad_fn=<AddBackward>) <AddBackward object at 0x1100477b8>

x是直接創(chuàng)建的,所以它沒有g(shù)rad_fn,, 而y是通過一個加法操作創(chuàng)建的,所以它有一個為<AddBackward>的grad_fn

像x這種直接創(chuàng)建的稱為葉子節(jié)點,葉子節(jié)點對應(yīng)的grad_fn是None。

print(x.is_leaf, y.is_leaf) # True False

對于不同的計算,會自動產(chǎn)生對應(yīng)的不同的梯度:

z = y * y * 3 out = z.mean() print(z, out)

輸出結(jié)果:

tensor([[27., 27.],[27., 27.]], grad_fn=<MulBackward>) tensor(27., grad_fn=<MeanBackward1>)

這里z由乘法計算得出,所以獲得了<MulBackward>,而out是一個mean(均值操作),所以獲得了<MeanBackward1>

通過.requires_grad_()來用in-place內(nèi)聯(lián)的方式改變requires_grad屬性
默認情況下,requires_grad的值是False,此時不會在運算時自動獲得梯度,當(dāng)設(shè)置requires_grad的值為True后,就可以自動獲得梯度

a = torch.randn(2, 2) # 缺失情況下默認 requires_grad = False a = ((a * 3) / (a - 1)) print(a.requires_grad) # False a.requires_grad_(True) print(a.requires_grad) # True b = (a * a).sum() print(b.grad_fn) #<SumBackward0 object at 0x118f50cc0>

對梯度的操作

調(diào)用backwar()函數(shù)時需要指定求導(dǎo)變量,而對于標量,不需要指定,因為其求導(dǎo)變量就是torch.tensor(1.)

out.backward() # 等價于 out.backward(torch.tensor(1.)) print(x.grad) #out關(guān)于x的梯度

輸出:

tensor([[4.5000, 4.5000],[4.5000, 4.5000]])

我們手動計算一下求導(dǎo)的結(jié)果:

因為: y = x + 2 z = y * y * 3 out = z.mean()


其實這里有更加重要的原因,就是避免向量(甚至更高維張量)對張量求導(dǎo),而轉(zhuǎn)換成標量對張量求導(dǎo)。但是pytorch不允許張量對張量求導(dǎo),只允許標量對張量求導(dǎo),求導(dǎo)結(jié)果是和自變量同形的張量。
所以必要時我們要把張量通過將所有張量的元素加權(quán)求和的方式轉(zhuǎn)換為標量

舉個例子,假設(shè)y由自變量x計算而來,w是和y同形的張量, 則y.backward(w)的含義是:先計算l = torch.sum(y * w), 則l是個標量,然后求l對自變量x的導(dǎo)數(shù)。

數(shù)學(xué)上,如果有一個函數(shù)值和自變量都為向量的函數(shù),
那么因變量關(guān)于自變量的梯度就是一個雅各比矩陣:

# 再來反向傳播一次,注意grad是累加的 # 每一次運行反向傳播,梯度都會累加之前的梯度 # 所以一般在反向傳播之前需把梯度清零 out2 = x.sum() out2.backward() print(x.grad)out3 = x.sum() x.grad.data.zero_() out3.backward() print(x.grad)

輸出:

tensor([[5.5000, 5.5000],[5.5000, 5.5000]]) tensor([[1., 1.],[1., 1.]])

我舉一個例子,為什么需要在backwards時傳入一個與指定求導(dǎo)變量同型的向量

x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True) y = 2 * x z = y.view(2, 2) print(z) tensor([[2., 4.],[6., 8.]], grad_fn=<ViewBackward>)

現(xiàn)在 z 不是一個標量,所以在調(diào)用backward時需要傳入一個和z同形的權(quán)重向量進行加權(quán)求和得到一個標量。

v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float) z.backward(v) print(x.grad) tensor([2.0000, 0.2000, 0.0200, 0.0020])

其實這里你應(yīng)該能看明白,傳入的同型張量實際上是一個權(quán)重向量,就是用來對我們的張良進行加權(quán)求和,變成一個標量,從而避免張量對張量求和。

梯度追蹤

x = torch.tensor(1.0, requires_grad=True) y1 = x ** 2 with torch.no_grad():y2 = x ** 3 y3 = y1 + y2print(x.requires_grad) print(y1, y1.requires_grad) # True print(y2, y2.requires_grad) # False print(y3, y3.requires_grad) # True True tensor(1., grad_fn=<PowBackward0>) True tensor(1.) False tensor(2., grad_fn=<ThAddBackward>) True

我們將y3對x求梯度:

y3.backward() print(x.grad) #tensor(2.)


為什么y3對x求梯度值會是2?
因為,y2是torch.no_grad()的,所以關(guān)于y2的梯度是不會回傳的,這里就相當(dāng)于對x^2進行求導(dǎo),當(dāng)然梯度為2了

如果我們想要修改tensor的數(shù)值,但是又不希望被autograd記錄(即不會影響反向傳播),那么可以對tensor.data進行操作

x = torch.ones(1,requires_grad=True)print(x.data) # 還是一個tensor print(x.data.requires_grad) # 但是已經(jīng)是獨立于計算圖之外y = 2 * x x.data *= 100 # 只改變了值,不會記錄在計算圖,所以不會影響梯度傳播y.backward() print(x) # 更改data的值也會影響tensor的值 print(x.grad)

這是什么意思?
說白了,就是tensor.data是獨立于計算圖之外的,修改tensor.data會影響tensor的值,但是這個修改操作不會回傳backwards,即不會影響反向傳播。

總結(jié)

以上是生活随笔為你收集整理的(pytorch-深度学习系列)pytorch中backwards()函数对梯度的操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。