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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

PyTorch框架学习四——计算图与动态图机制

發布時間:2024/7/23 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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:

強調兩個概念:

  • 葉子結點:用戶創建的結點,如x與w,tensor中的is_leaf屬性就是指示張量是否為葉子結點。非葉子結點運算后會被釋放,葉子結點的梯度會被保留,若想保留非葉子結點的梯度,可以用retain_grad()。
  • grad_fn:記錄創建張量時所用的方法(函數),在梯度的反向傳播時會用到,以上述的計算為例:y.grad_fn = <MulBackward 0>,a.grad_fn = <AddBackward 0>。
  • 二、動態圖與靜態圖

    動態圖靜態圖
    實現方式運算與搭建同時進行先搭建計算圖,后計算
    特點靈活易調節高效但不靈活
    框架PyTorchTensorFlow

    三、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)

  • tensors:用于求導的張量們。
  • grad_tensors:多梯度權重,下面用例子理解。
  • retain_graph:(布爾,可選)若為False,計算圖計算完之后就會被釋放,若為True,則會保留。
  • create_graph:(布爾,可選)若為True,會創建導數的計算圖,用于更高階的求導,默認為False。
  • 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小貼士

  • 梯度不會自動清零,若不清零,則會疊加上原來的數據,需要手動清零:grad.zero_()。
  • 依賴于葉子結點的結點,requires_grad默認為True。
  • 葉子結點不可執行in-place操作,in-place操作為在原始內存中改變數據的操作,如a += torch.ones((1, )) (加等操作a的內存地址不變,所以對張量不能做這項操作)。這是因為,在前向傳播時,會記錄葉子結點的地址,反向求導時是會依據記錄的地址去取值進行運算的,若在中途用in-place操作改變了值,則梯度求解會出錯。
  • 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。
    結果如下:

    tensor([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,所以若不手動清零,則梯度會疊加起來。
    我們在原來的基礎上添加上手動清零:

    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)w.grad.zero_()

    結果為:

    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操作,是在原始內存中改變數據的操作。
    而加法操作就不是,如下所示:

    a = torch.ones((1, )) print(id(a), a)a = a + torch.ones((1, )) print(id(a), a)

    內存不一樣:

    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框架学习四——计算图与动态图机制的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。