【深度學習】翻譯:60分鐘入門PyTorch(二)——Autograd自動求導
前言
原文翻譯自:Deep Learning with PyTorch: A 60 Minute Blitz
翻譯:林不清(https://www.zhihu.com/people/lu-guo-92-42-88)
目錄
60分鐘入門PyTorch(二)——Autograd自動求導
60分鐘入門Pytorch(三)——神經網絡
60分鐘入門PyTorch(四)——訓練一個分類器
Autograd:自動求導
torch.autograd是pytorch自動求導的工具,也是所有神經網絡的核心。我們首先先簡單了解一下這個包如何訓練神經網絡。
背景介紹
神經網絡(NNs)是作用在輸入數據上的一系列嵌套函數的集合,這些函數由權重和誤差來定義,被存儲在PyTorch中的tensors中。
神經網絡訓練的兩個步驟:
前向傳播:在前向傳播中,神經網絡通過將接收到的數據與每一層對應的權重和誤差進行運算來對正確的輸出做出最好的預測。
反向傳播:在反向傳播中,神經網絡調整其參數使得其與輸出誤差成比例。反向傳播基于梯度下降策略,是鏈式求導法則的一個應用,以目標的負梯度方向對參數進行調整。
更加詳細的介紹可以參照下述地址:
[3Blue1Brown]:
https://www.youtube.com/watch?v=tIeHLnjs5U8
Pytorch應用
來看一個簡單的示例,我們從torchvision加載一個預先訓練好的resnet18模型,接著創(chuàng)建一個隨機數據tensor來表示一有3個通道、高度和寬度為64的圖像,其對應的標簽初始化為一些隨機值。
%matplotlib?inline
import?torch,?torchvision
model?=?torchvision.models.resnet18(pretrained=True)
data?=?torch.rand(1,?3,?64,?64)
labels?=?torch.rand(1,?1000)
接下來,我們將輸入數據向輸出方向傳播到模型的每一層中來預測輸出,這就是前向傳播。
prediction?=?model(data)?#?前向傳播
我們利用模型的預測輸出和對應的權重來計算誤差,然后反向傳播誤差。完成計算后,您可以調用.backward()并自動計算所有梯度。此張量的梯度將累積到.grad屬性中。
loss?=?(prediction?-?labels).sum()
loss.backward()?#?反向傳播
接著,我們加載一個優(yōu)化器,在本例中,SGD的學習率為0.01,momentum 為0.9。我們在優(yōu)化器中注冊模型的所有參數。
optim?=?torch.optim.SGD(model.parameters(),?lr=1e-2,?momentum=0.9)
最后,我們調用.step()來執(zhí)行梯度下降,優(yōu)化器通過存儲在.grad中的梯度來調整每個參數。
optim.step()?#梯度下降
現在,你已經具備了訓練神經網絡所需所有條件。下面幾節(jié)詳細介紹了Autograd包的工作原理——可以跳過它們。
Autograd中的求導
先來看一下autograd是如何收集梯度的。我們創(chuàng)建兩個張量a和b并設置requires_grad = True以跟蹤它的計算。
import?torch
a?=?torch.tensor([2.,?3.],?requires_grad=True)
b?=?torch.tensor([6.,?4.],?requires_grad=True)
接著在a和b的基礎上創(chuàng)建張量Q
Q?=?3*a**3?-?b**2
假設a和b是一個神經網絡的權重,Q是它的誤差,在神經網絡訓練中,我們需要w.r.t參數的誤差梯度,即
當我們調用Q的.backward()時,autograd計算這些梯度并把它們存儲在張量的 .grad屬性中。我們需要在Q.backward()中顯式傳遞gradient,gradient是一個與Q相同形狀的張量,它表示Q w.r.t本身的梯度,即
Q聚合為一個標量并隱式向后調用,如Q.sum().backward()。external_grad?=?torch.tensor([1.,?1.])
Q.backward(gradient=external_grad)
現在梯度都被存放在a.grad和b.grad中
#?檢查一下存儲的梯度是否正確
print(9*a**2?==?a.grad)
print(-2*b?==?b.grad)
可選閱讀----用autograd進行向量計算
在數學上,如果你有一個向量值函數??? =??(??? ) ,則??? 相對于??? 的梯度是雅可比矩陣:
一般來說,torch.autograd是一個計算雅可比向量積的引擎。也就是說,給定任何向量??=(??1??2...????)??,計算乘積?????。如果??恰好是標量函數的梯度??=??(??? ),即 然后根據鏈式法則,雅可比向量乘積將是??相對于??? 的梯度
雅可比向量積的這種特性使得將外部梯度饋送到具有非標量輸出的模型中非常方便。external_grad 代表.
圖計算
從概念上講,autograd在由函數對象組成的有向無環(huán)圖(DAG)中保存數據(tensor)和所有執(zhí)行的操作(以及產生的新tensor)的記錄,在這個DAG中,葉節(jié)點是輸入數據,根節(jié)點是輸出數據,通過從根節(jié)點到葉節(jié)點跟蹤這個圖,您可以使用鏈式法則自動計算梯度。
在前向傳播中,autograd同時完成兩件事情:
運行所請求的操作來計算結果tensor 保持DAG中操作的梯度
在反向傳播中,當在DAG根節(jié)點上調用.backward()時,反向傳播啟動,autograd接下來完成:
計算每一個 .grad_fn的梯度將它們累加到各自張量的.grad屬性中 利用鏈式法則,一直傳播到葉節(jié)點
下面是DAG的可視化表示的示例。圖中,箭頭表示前向傳播的方向,節(jié)點表示向前傳遞中每個操作的向后函數。藍色標記的葉節(jié)點代表葉張量 a和b

注意
DAG在PyTorch中是動態(tài)的。值得注意的是圖是重新開始創(chuàng)建的; 在調用每一個``.backward()``后,autograd開始填充一個新圖,這就是能夠在模型中使用控制流語句的原因。你可以根據需求在每次迭代時更改形狀、大小和操作。
torch.autograd追蹤所有requires_grad為True的張量的相關操作。對于不需要梯度的張量,將此屬性設置為False將其從梯度計算DAG中排除。操作的輸出張量將需要梯度,即使只有一個輸入張量requires_grad=True。
x?=?torch.rand(5,?5)
y?=?torch.rand(5,?5)
z?=?torch.rand((5,?5),?requires_grad=True)
a?=?x?+?y
print(f"Does?`a`?require?gradients??:?{a.requires_grad}")
b?=?x?+?z
print(f"Does?`b`?require?gradients?:?{b.requires_grad}")
在神經網絡中,不計算梯度的參數通常稱為凍結參數。如果您事先知道您不需要這些參數的梯度,那么“凍結”部分模型是很有用的(這通過減少autograd計算帶來一些性能好處)。另外一個常見的用法是微調一個預訓練好的網絡,在微調的過程中,我們凍結大部分模型——通常,只修改分類器來對新的<標簽>做出預測,讓我們通過一個小示例來演示這一點。與前面一樣,我們加載一個預先訓練好的resnet18模型,并凍結所有參數。
from?torch?import?nn,?optim
model?=?torchvision.models.resnet18(pretrained=True)
#?凍結網絡中所有的參數
for?param?in?model.parameters():
????param.requires_grad?=?False
假設我們想在一個有10個標簽的新數據集上微調模型。在resnet中,分類器是最后一個線性層模型model.fc。我們可以簡單地用一個新的線性層(默認未凍結)代替它作為我們的分類器。
model.fc?=?nn.Linear(512,?10)
現在除了model.fc的參數外,模型的其他參數均被凍結,參與計算的參數是model.fc的權值和偏置。
#?只優(yōu)化分類器
optimizer?=?optim.SGD(model.fc.parameters(),?lr=1e-2,?momentum=0.9)
注意,盡管我們注冊了優(yōu)化器中所有參數,但唯一參與梯度計算(并因此在梯度下降中更新)的參數是分類器的權值和偏差。torch.no_grad()中也具有相同的功能。
拓展閱讀
[就地修改操作以及多線程Autograd]:(https://pytorch.org/docs/stable/notes/autograd.html) [反向模式autodiff的示例]:(https://colab.research.google.com/drive/1VpeE6UvEPRz9HmsHh1KS0XxXjYu533EC)
往期精彩回顧
本站知識星球“黃博的機器學習圈子”(92416895)
本站qq群704220115。
加入微信群請掃碼:
