十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
這篇文章給大家介紹PyTorch 中自動求導(dǎo)機(jī)制的原理是什么,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

自動求導(dǎo)機(jī)制
從后向中排除子圖
每個變量都有兩個標(biāo)志:requires_grad和volatile。它們都允許從梯度計算中精細(xì)地排除子圖,并可以提高效率。
requires_grad
如果有一個單一的輸入操作需要梯度,它的輸出也需要梯度。相反,只有所有輸入都不需要梯度,輸出才不需要。如果其中所有的變量都不需要梯度進(jìn)行,后向計算不會在子圖中執(zhí)行。
>>> x = Variable(torch.randn(5, 5)) >>> y = Variable(torch.randn(5, 5)) >>> z = Variable(torch.randn(5, 5), requires_grad=True) >>> a = x + y >>> a.requires_grad False >>> b = a + z >>> b.requires_grad True
這個標(biāo)志特別有用,當(dāng)您想要凍結(jié)部分模型時,或者您事先知道不會使用某些參數(shù)的梯度。
autograd是專門為了BP算法設(shè)計的,所以這autograd只對輸出值為標(biāo)量的有用,因?yàn)閾p失函數(shù)的輸出是一個標(biāo)量。如果y是一個向量,那么backward()函數(shù)就會失效。
model = torchvision.models.resnet18(pretrained=True) for param in model.parameters(): param.requires_grad = False # Replace the last fully-connected layer # Parameters of newly constructed modules have requires_grad=True by default model.fc = nn.Linear(512, 100) # Optimize only the classifier optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)
上面的optim.SGD()只需要傳入需要優(yōu)化的參數(shù)即可。
volatile
純粹的inference模式(可以理解為只需要進(jìn)行前向)下推薦使用volatile,當(dāng)你確定你甚至不會調(diào)用.backward()時。它比任何其他自動求導(dǎo)的設(shè)置更有效——它將使用絕對最小的內(nèi)存來評估模型。volatile也決定了require_grad is False。
volatile不同于require_grad的傳遞。如果一個操作甚至只有有一個volatile的輸入,它的輸出也將是volatile。Volatility比“不需要梯度”更容易傳遞——只需要一個volatile的輸入即可得到一個volatile的輸出,相對的,需要所有的輸入“不需要梯度”才能得到不需要梯度的輸出。使用volatile標(biāo)志,您不需要更改模型參數(shù)的任何設(shè)置來用于inference。創(chuàng)建一個volatile的輸入就夠了,這將保證不會保存中間狀態(tài)。
>>> regular_input = Variable(torch.randn(5, 5)) >>> volatile_input = Variable(torch.randn(5, 5), volatile=True) >>> model = torchvision.models.resnet18(pretrained=True) >>> model(regular_input).requires_grad True >>> model(volatile_input).requires_grad False >>> model(volatile_input).volatile True >>> model(volatile_input).creator is None True
自動求導(dǎo)如何編碼歷史信息
每個變量都有一個.creator屬性,它指向把它作為輸出的函數(shù)。這是一個由Function對象作為節(jié)點(diǎn)組成的有向無環(huán)圖(DAG)的入口點(diǎn),它們之間的引用就是圖的邊。每次執(zhí)行一個操作時,一個表示它的新Function就被實(shí)例化,它的forward()方法被調(diào)用,并且它輸出的Variable的創(chuàng)建者被設(shè)置為這個Function。然后,通過跟蹤從任何變量到葉節(jié)點(diǎn)的路徑,可以重建創(chuàng)建數(shù)據(jù)的操作序列,并自動計算梯度。
variable和function它們是彼此不分開的,先上圖:

如圖,假設(shè)我們有一個輸入變量input(數(shù)據(jù)類型為Variable)input是用戶輸入的,所以其創(chuàng)造者creator為null值,input經(jīng)過第一個數(shù)據(jù)操作operation1(比如加減乘除運(yùn)算)得到output1變量(數(shù)據(jù)類型仍為Variable),這個過程中會自動生成一個function1的變量(數(shù)據(jù)類型為Function的一個實(shí)例),而output1的創(chuàng)造者就是這個function1。隨后,output1再經(jīng)過一個數(shù)據(jù)操作生成output2,這個過程也會生成另外一個實(shí)例function2,output2的創(chuàng)造者creator為function2。
在這個向前傳播的過程中,function1和function2記錄了數(shù)據(jù)input的所有操作歷史,當(dāng)output2運(yùn)行其backward函數(shù)時,會使得function2和function1自動反向計算input的導(dǎo)數(shù)值并存儲在grad屬性中。
creator為null的變量才能被返回導(dǎo)數(shù),比如input,若把整個操作流看成是一張圖(Graph),那么像input這種creator為null的被稱之為圖的葉子(graph leaf)。而creator非null的變量比如output1和output2,是不能被返回導(dǎo)數(shù)的,它們的grad均為0。所以只有葉子節(jié)點(diǎn)才能被autograd。
>>> from torch.autograd import Variable >>> import torch >>> x = Variable(torch.ones(2), requires_grad = >>> True) >>> z=4*x*x >>> y=z.norm() >>> y Variable containing: 5.6569 [torch.FloatTensor of size 1] >>> y.backward() >>> x.grad Variable containing: 5.6569 5.6569 [torch.FloatTensor of size 2] >>> z.grad >>> y.grad
Variable上的In-place操作
in-place計算,類似'+='運(yùn)算,表示內(nèi)部直接替換,in-place操作都使用_作為后綴。例如,x.copy_(y)
>>> a = torch.Tensor(3,4) >>> a 0 0 0 0 0 0 0 0 0 0 0 0 [torch.FloatTensor of size 3x4] >>> a.fill_(2.5) 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 [torch.FloatTensor of size 3x4] >>> b = a.add(4.0) >>> b 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 [torch.FloatTensor of size 3x4] >>> a 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 2.5000 [torch.FloatTensor of size 3x4] >>> c = a.add_(4.0) >>> c 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 [torch.FloatTensor of size 3x4] >>> a 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 6.5000 [torch.FloatTensor of size 3x4]
在自動求導(dǎo)中支持in-place操作是一件很困難的事情,我們在大多數(shù)情況下都不鼓勵使用它們。Autograd的緩沖區(qū)釋放和重用非常高效,并且很少場合下in-place操作能實(shí)際上明顯降低內(nèi)存的使用量。除非您在內(nèi)存壓力很大的情況下,否則您可能永遠(yuǎn)不需要使用它們。
限制in-place操作適用性主要有兩個原因:
1.覆蓋梯度計算所需的值。這就是為什么變量不支持log_。它的梯度公式需要原始輸入,而雖然通過計算反向操作可以重新創(chuàng)建它,但在數(shù)值上是不穩(wěn)定的,并且需要額外的工作,這往往會與使用這些功能的目的相悖。
2.每個in-place操作實(shí)際上需要實(shí)現(xiàn)重寫計算圖。不合適的版本只需分配新對象并保留對舊圖的引用,而in-place操作則需要將所有輸入的creator更改為表示此操作的Function。這就比較棘手,特別是如果有許多變量引用相同的存儲(例如通過索引或轉(zhuǎn)置創(chuàng)建的),并且如果被修改輸入的存儲被任何其他Variable引用,則in-place函數(shù)實(shí)際上會拋出錯誤。
In-place正確性檢查
每個變量保留有version counter,它每次都會遞增,當(dāng)在任何操作中被使用時。當(dāng)Function保存任何用于后向的tensor時,還會保存其包含變量的version counter。一旦訪問self.saved_tensors,它將被檢查,如果它大于保存的值,則會引起錯誤。
關(guān)于PyTorch 中自動求導(dǎo)機(jī)制的原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。