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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pytorch如何计算导数_PyTorch怎么用?来看这里

發(fā)布時(shí)間:2025/3/8 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pytorch如何计算导数_PyTorch怎么用?来看这里 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

構(gòu)建深度學(xué)習(xí)模型的基本流程就是:搭建計(jì)算圖,求得損失函數(shù),然后計(jì)算損失函數(shù)對(duì)模型參數(shù)的導(dǎo)數(shù),再利用梯度下降法等方法來更新參數(shù)。

搭建計(jì)算圖的過程,稱為“正向傳播”,這個(gè)是需要我們自己動(dòng)手的,因?yàn)槲覀冃枰O(shè)計(jì)我們模型的結(jié)構(gòu)。由損失函數(shù)求導(dǎo)的過程,稱為“反向傳播”,求導(dǎo)是件辛苦事兒,所以自動(dòng)求導(dǎo)基本上是各種深度學(xué)習(xí)框架的基本功能和最重要的功能之一,PyTorch也不例外。

我們今天來體驗(yàn)一下PyTorch的自動(dòng)求導(dǎo)吧,好為后面的搭建模型做準(zhǔn)備。

一、設(shè)置Tensor的自動(dòng)求導(dǎo)屬性

所有的tensor都有.requires_grad屬性,都可以設(shè)置成自動(dòng)求導(dǎo)。具體方法就是在定義tensor的時(shí)候,讓這個(gè)屬性為True:

x = tensor.ones(2,4,requires_grad=True)

In [1]: import torchIn [2]: x = torch.ones(2,4,requires_grad=True)In [3]: print(x)tensor([[1., 1., 1., 1.], [1., 1., 1., 1.]], requires_grad=True)

只要這樣設(shè)置了之后,后面由x經(jīng)過運(yùn)算得到的其他tensor,就都有equires_grad=True屬性了。

可以通過x.requires_grad來查看這個(gè)屬性。

In [4]: y = x + 2In [5]: print(y)tensor([[3., 3., 3., 3.], [3., 3., 3., 3.]], grad_fn=)In [6]: y.requires_gradOut[6]: True

如果想改變這個(gè)屬性,就調(diào)用tensor.requires_grad_()方法:

In [22]: x.requires_grad_(False)Out[22]:tensor([[1., 1., 1., 1.], [1., 1., 1., 1.]])In [21]: print(x.requires_grad,y.requires_grad)False True

這里,注意區(qū)別tensor.requires_grad和tensor.requires_grad_()兩個(gè)東西,前面是調(diào)用變量的屬性值,后者是調(diào)用內(nèi)置的函數(shù),來改變屬性。

二、求導(dǎo)

下面我們來試試自動(dòng)求導(dǎo)到底怎么樣。

我們首先定義一個(gè)計(jì)算圖(計(jì)算的步驟):

In [28]: x = torch.tensor([[1.,2.,3.],[4.,5.,6.]],requires_grad=True)In [29]: y = x+1In [30]: z = 2*y*yIn [31]: J = torch.mean(z)

這里需要注意的是,要想使x支持求導(dǎo),必須讓x為浮點(diǎn)類型,也就是我們給初始值的時(shí)候要加個(gè)點(diǎn):“.”。不然的話,就會(huì)報(bào)錯(cuò)。

即,不能定義[1,2,3],而應(yīng)該定義成[1.,2.,3.],前者是整數(shù),后者才是浮點(diǎn)數(shù)。

上面的計(jì)算過程可以表示為:

好了,重點(diǎn)注意的地方來了!

x、y、z都是tensor,但是size為(2,3)的矩陣。但是J是對(duì)z的每一個(gè)元素加起來求平均,所以J是標(biāo)量。

求導(dǎo),只能是【標(biāo)量】對(duì)標(biāo)量,或者【標(biāo)量】對(duì)向量/矩陣求導(dǎo)!

所以,上圖中,只能J對(duì)x、y、z求導(dǎo),而z則不能對(duì)x求導(dǎo)。

我們不妨試一試:

  • PyTorch里面,求導(dǎo)是調(diào)用.backward()方法。直接調(diào)用backward()方法,會(huì)計(jì)算對(duì)計(jì)算圖葉節(jié)點(diǎn)的導(dǎo)數(shù)。獲取求得的導(dǎo)數(shù),用.grad方法。

試圖z對(duì)x求導(dǎo):

In [31]: z.backward()# 會(huì)報(bào)錯(cuò):Traceback (most recent call last) in ()----> 1 z.backward()RuntimeError: grad can be implicitly created only for scalar outputs

正確的應(yīng)該是J對(duì)x求導(dǎo):

In [33]: J.backward()In [34]: x.gradOut[34]:tensor([[1.3333, 2.0000, 2.6667], [3.3333, 4.0000, 4.6667]])

檢驗(yàn)一下,求的是不是對(duì)的。

J對(duì)x的導(dǎo)數(shù)應(yīng)該是什么呢?

檢查發(fā)現(xiàn),導(dǎo)數(shù)就是:

[[1.3333, 2.0000, 2.6667],

[3.3333, 4.0000, 4.6667]]

總結(jié)一下,構(gòu)建計(jì)算圖(正向傳播,Forward Propagation)和求導(dǎo)(反向傳播,Backward Propagation)的過程就是:

三、關(guān)于backward函數(shù)的一些其他問題:

1. 不是標(biāo)量也可以用backward()函數(shù)來求導(dǎo)?

在看文檔的時(shí)候,有一點(diǎn)我半天沒搞懂:

他們給了這樣的一個(gè)例子:

我在前面不是說“只有標(biāo)量才能對(duì)其他東西求導(dǎo)”么?它這里的y是一個(gè)tensor,是一個(gè)向量。按道理不能求導(dǎo)呀。這個(gè)參數(shù)gradients是干嘛的?

但是,如果看看backward函數(shù)的說明,會(huì)發(fā)現(xiàn),里面確實(shí)有一個(gè)gradients參數(shù):

從說明中我們可以了解到:

  • 如果你要求導(dǎo)的是一個(gè)標(biāo)量,那么gradients默認(rèn)為None,所以前面可以直接調(diào)用J.backward()就行了如果你要求導(dǎo)的是一個(gè)張量,那么gradients應(yīng)該傳入一個(gè)Tensor。那么這個(gè)時(shí)候是什么意思呢?

在StackOverflow有一個(gè)解釋很好:

一般來說,我是對(duì)標(biāo)量求導(dǎo),比如在神經(jīng)網(wǎng)絡(luò)里面,我們的loss會(huì)是一個(gè)標(biāo)量,那么我們讓loss對(duì)神經(jīng)網(wǎng)絡(luò)的參數(shù)w求導(dǎo),直接通過loss.backward()即可。

但是,有時(shí)候我們可能會(huì)有多個(gè)輸出值,比如loss=[loss1,loss2,loss3],那么我們可以讓loss的各個(gè)分量分別對(duì)x求導(dǎo),這個(gè)時(shí)候就采用:

loss.backward(torch.tensor([[1.0,1.0,1.0,1.0]]))

如果你想讓不同的分量有不同的權(quán)重,那么就賦予gradients不一樣的值即可,比如:

loss.backward(torch.tensor([[0.1,1.0,10.0,0.001]]))

這樣,我們使用起來就更加靈活了,雖然也許多數(shù)時(shí)候,我們都是直接使用.backward()就完事兒了。

2. 一個(gè)計(jì)算圖只能backward一次

一個(gè)計(jì)算圖在進(jìn)行反向求導(dǎo)之后,為了節(jié)省內(nèi)存,這個(gè)計(jì)算圖就銷毀了。

如果你想再次求導(dǎo),就會(huì)報(bào)錯(cuò)。

比如你定義了計(jì)算圖:

你先求p求導(dǎo),那么這個(gè)過程就是反向的p對(duì)y求導(dǎo),y對(duì)x求導(dǎo)。

求導(dǎo)完畢之后,這三個(gè)節(jié)點(diǎn)構(gòu)成的計(jì)算子圖就會(huì)被釋放:

那么計(jì)算圖就只剩下z、q了,已經(jīng)不完整,無法求導(dǎo)了。

所以這個(gè)時(shí)候,無論你是想再次運(yùn)行p.backward()還是q.backward(),都無法進(jìn)行,報(bào)錯(cuò)如下:

RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

好,怎么辦呢?

遇到這種問題,一般兩種情況:

1. 你的實(shí)際計(jì)算,確實(shí)需要保留計(jì)算圖,不讓子圖釋放。

那么,就更改你的backward函數(shù),添加參數(shù)retain_graph=True,重新進(jìn)行backward,這個(gè)時(shí)候你的計(jì)算圖就被保留了,不會(huì)報(bào)錯(cuò)。

但是這樣會(huì)吃內(nèi)存!,尤其是,你在大量迭代進(jìn)行參數(shù)更新的時(shí)候,很快就會(huì)內(nèi)存不足,memory out了。

2. 你實(shí)際根本沒必要對(duì)一個(gè)計(jì)算圖backward多次,而你不小心多跑了一次backward函數(shù)。

通常,你要是在IPython里面聯(lián)系PyTorch的時(shí)候,因?yàn)槟銜?huì)反復(fù)運(yùn)行一個(gè)單元格的代碼,所以很容易一不小心把backward運(yùn)行了多次,就會(huì)報(bào)錯(cuò)。這個(gè)時(shí)候,你就檢查一下代碼,防止backward運(yùn)行多次即可。

文章轉(zhuǎn)自:https://zhuanlan.zhihu.com/p/51385110

總結(jié)

以上是生活随笔為你收集整理的pytorch如何计算导数_PyTorch怎么用?来看这里的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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