PyTorch框架学习四——计算图与动态图机制
PyTorch框架學(xué)習(xí)四——計(jì)算圖與動(dòng)態(tài)圖機(jī)制
- 一、計(jì)算圖
- 二、動(dòng)態(tài)圖與靜態(tài)圖
- 三、torch.autograd
- 1.torch.autograd.backward()
- 2.torch.autograd.grad()
- 3.autograd小貼士
- 4.代碼演示理解
- (1)構(gòu)建計(jì)算圖并反向求導(dǎo):
- (2)grad_tensors的理解:
- (3)autograd.gard與create_graph的結(jié)合:
- (4)小貼士1
- (5)小貼士2
- (6)小貼士3
一、計(jì)算圖
計(jì)算圖是用來(lái)描述運(yùn)算的有向無(wú)環(huán)圖,它包含了兩個(gè)主要元素:結(jié)點(diǎn)(Node)與邊(Edge)。其中結(jié)點(diǎn)表示數(shù)據(jù),如向量、矩陣、張量等,而邊表示運(yùn)算,如加減乘除卷積等。
下面用計(jì)算圖來(lái)表示:y=(x+w)×(w+1)這樣的一個(gè)運(yùn)算。
令 a = x + w,b = w + 1,則y = a×b。
計(jì)算圖如下圖所示:
構(gòu)建這樣的計(jì)算圖是很方便求解梯度的,以對(duì)w求偏導(dǎo)為例,假設(shè)x和w的初始值為2和1:
強(qiáng)調(diào)兩個(gè)概念:
二、動(dòng)態(tài)圖與靜態(tài)圖
| 實(shí)現(xiàn)方式 | 運(yùn)算與搭建同時(shí)進(jìn)行 | 先搭建計(jì)算圖,后計(jì)算 |
| 特點(diǎn) | 靈活易調(diào)節(jié) | 高效但不靈活 |
| 框架 | PyTorch | TensorFlow |
三、torch.autograd
這是一個(gè)自動(dòng)求導(dǎo)系統(tǒng),提供了類和函數(shù)用來(lái)對(duì)任意標(biāo)量函數(shù)進(jìn)行求導(dǎo)。
下面介紹autograd中兩個(gè)自動(dòng)求導(dǎo)的函數(shù):
1.torch.autograd.backward()
沒(méi)有返回值,但是已經(jīng)對(duì)數(shù)據(jù)進(jìn)行了自動(dòng)求導(dǎo)。
torch.autograd.backward(tensors: Union[torch.Tensor, Sequence[torch.Tensor]], grad_tensors: Union[torch.Tensor, Sequence[torch.Tensor], None] = None, retain_graph: Optional[bool] = None, create_graph: bool = False, grad_variables: Union[torch.Tensor, Sequence[torch.Tensor], None] = None)2.torch.autograd.grad()
torch.autograd.grad(outputs: Union[torch.Tensor, Sequence[torch.Tensor]], inputs: Union[torch.Tensor, Sequence[torch.Tensor]], grad_outputs: Union[torch.Tensor, Sequence[torch.Tensor], None] = None, retain_graph: Optional[bool] = None, create_graph: bool = False, only_inputs: bool = True, allow_unused: bool = False)3.autograd小貼士
4.代碼演示理解
(1)構(gòu)建計(jì)算圖并反向求導(dǎo):
# 設(shè)置 x 和 w 的初始值 w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True) # 構(gòu)建計(jì)算圖 a = torch.add(w, x) b = torch.add(w, 1) y = torch.mul(a, b) # 反向求導(dǎo) y.backward() print(w.grad, x.grad)結(jié)果如下,與手動(dòng)計(jì)算結(jié)果一致:
tensor([5.]) tensor([2.])(2)grad_tensors的理解:
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True)a = torch.add(w, x) # retain_grad() b = torch.add(w, 1)y0 = torch.mul(a, b) # y0 = (x+w) * (w+1) y1 = torch.add(a, b) # y1 = (x+w) + (w+1) dy1/dw = 2loss = torch.cat([y0, y1], dim=0) # [y0, y1] grad_tensors = torch.tensor([1., 2.])loss.backward(gradient=grad_tensors) # gradient 傳入 torch.autograd.backward()中的grad_tensorsprint(w.grad)grad_tensors的作用就類似于一個(gè)權(quán)重,當(dāng)要求導(dǎo)的對(duì)象有多個(gè)梯度時(shí),它就是各個(gè)梯度加和的權(quán)重,比如這里 dy0 / dw = 5,dy1/dw = 2,那么w的總梯度值為 5×1 + 2×2 = 9。
結(jié)果如下:
(3)autograd.gard與create_graph的結(jié)合:
x = torch.tensor([3.], requires_grad=True) y = torch.pow(x, 2) # y = x**2grad_1 = torch.autograd.grad(y, x, create_graph=True) # grad_1 = dy/dx = 2x = 2 * 3 = 6 print(grad_1)grad_2 = torch.autograd.grad(grad_1[0], x) # grad_2 = d(dy/dx)/dx = d(2x)/dx = 2 print(grad_2)其中y就是用于求導(dǎo)的張量,x就是需要梯度的張量,grad_1就是第一次求導(dǎo)后x的梯度,因?yàn)閏reate_graph為True,所以已經(jīng)構(gòu)建了導(dǎo)數(shù)的計(jì)算圖,可以對(duì)grad_1再次求導(dǎo),得到第二次求導(dǎo)后x的梯度grad_2:
(tensor([6.], grad_fn=<MulBackward0>),) (tensor([2.]),)(4)小貼士1
這里我們構(gòu)建了四次計(jì)算圖,四次一模一樣的計(jì)算:
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True)for i in range(4):a = torch.add(w, x)b = torch.add(w, 1)y = torch.mul(a, b)y.backward()print(w.grad)若我們不對(duì)梯度手動(dòng)清零,結(jié)果就如下所示:
tensor([5.]) tensor([10.]) tensor([15.]) tensor([20.])因?yàn)槊看蔚奶荻榷家粯佣紴?,所以若不手動(dòng)清零,則梯度會(huì)疊加起來(lái)。
我們?cè)谠瓉?lái)的基礎(chǔ)上添加上手動(dòng)清零:
結(jié)果為:
tensor([5.]) tensor([5.]) tensor([5.]) tensor([5.])這樣才是正確的。
(5)小貼士2
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True)a = torch.add(w, x) b = torch.add(w, 1) y = torch.mul(a, b)print(a.requires_grad, b.requires_grad, y.requires_grad)結(jié)果為:
True True True(6)小貼士3
a = torch.ones((1, )) print(id(a), a)a += torch.ones((1, )) print(id(a), a)結(jié)果為:
2379593847576 tensor([1.]) 2379593847576 tensor([2.])可見加等操作是in-place操作,是在原始內(nèi)存中改變數(shù)據(jù)的操作。
而加法操作就不是,如下所示:
內(nèi)存不一樣:
3019154559688 tensor([1.]) 3019156480632 tensor([2.])如果我們對(duì)葉子結(jié)點(diǎn)進(jìn)行in-place操作:
w = torch.tensor([1.], requires_grad=True) x = torch.tensor([2.], requires_grad=True)a = torch.add(w, x) b = torch.add(w, 1) y = torch.mul(a, b)w += torch.ones((1,)) # w.add_(1)y.backward()print(w.grad)會(huì)報(bào)如下錯(cuò)誤提示:
總結(jié)
以上是生活随笔為你收集整理的PyTorch框架学习四——计算图与动态图机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 统计学基本知识二
- 下一篇: 如何让学习变得像游戏一样好玩