PyTorch框架学习四——计算图与动态图机制
PyTorch框架學習四——計算圖與動態圖機制
- 一、計算圖
- 二、動態圖與靜態圖
- 三、torch.autograd
- 1.torch.autograd.backward()
- 2.torch.autograd.grad()
- 3.autograd小貼士
- 4.代碼演示理解
- (1)構建計算圖并反向求導:
- (2)grad_tensors的理解:
- (3)autograd.gard與create_graph的結合:
- (4)小貼士1
- (5)小貼士2
- (6)小貼士3
一、計算圖
計算圖是用來描述運算的有向無環圖,它包含了兩個主要元素:結點(Node)與邊(Edge)。其中結點表示數據,如向量、矩陣、張量等,而邊表示運算,如加減乘除卷積等。
下面用計算圖來表示:y=(x+w)×(w+1)這樣的一個運算。
令 a = x + w,b = w + 1,則y = a×b。
計算圖如下圖所示:
構建這樣的計算圖是很方便求解梯度的,以對w求偏導為例,假設x和w的初始值為2和1:
強調兩個概念:
二、動態圖與靜態圖
| 實現方式 | 運算與搭建同時進行 | 先搭建計算圖,后計算 |
| 特點 | 靈活易調節 | 高效但不靈活 |
| 框架 | PyTorch | TensorFlow |
三、torch.autograd
這是一個自動求導系統,提供了類和函數用來對任意標量函數進行求導。
下面介紹autograd中兩個自動求導的函數:
1.torch.autograd.backward()
沒有返回值,但是已經對數據進行了自動求導。
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)構建計算圖并反向求導:
# 設置 x 和 w 的初始值 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) # 反向求導 y.backward() print(w.grad, x.grad)結果如下,與手動計算結果一致:
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的作用就類似于一個權重,當要求導的對象有多個梯度時,它就是各個梯度加和的權重,比如這里 dy0 / dw = 5,dy1/dw = 2,那么w的總梯度值為 5×1 + 2×2 = 9。
結果如下:
(3)autograd.gard與create_graph的結合:
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就是用于求導的張量,x就是需要梯度的張量,grad_1就是第一次求導后x的梯度,因為create_graph為True,所以已經構建了導數的計算圖,可以對grad_1再次求導,得到第二次求導后x的梯度grad_2:
(tensor([6.], grad_fn=<MulBackward0>),) (tensor([2.]),)(4)小貼士1
這里我們構建了四次計算圖,四次一模一樣的計算:
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)若我們不對梯度手動清零,結果就如下所示:
tensor([5.]) tensor([10.]) tensor([15.]) tensor([20.])因為每次的梯度都一樣都為5,所以若不手動清零,則梯度會疊加起來。
我們在原來的基礎上添加上手動清零:
結果為:
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)結果為:
True True True(6)小貼士3
a = torch.ones((1, )) print(id(a), a)a += torch.ones((1, )) print(id(a), a)結果為:
2379593847576 tensor([1.]) 2379593847576 tensor([2.])可見加等操作是in-place操作,是在原始內存中改變數據的操作。
而加法操作就不是,如下所示:
內存不一樣:
3019154559688 tensor([1.]) 3019156480632 tensor([2.])如果我們對葉子結點進行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)會報如下錯誤提示:
總結
以上是生活随笔為你收集整理的PyTorch框架学习四——计算图与动态图机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 统计学基本知识二
- 下一篇: 如何让学习变得像游戏一样好玩