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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

PyTorch基础(二)-----自动求导Autograd

發布時間:2025/3/15 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PyTorch基础(二)-----自动求导Autograd 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

上一篇文章中提到PyTorch提供了兩個重要的高級功能,分別是:

  • 具有強大的GPU加速的張量計算(如NumPy)
  • 包含自動求導系統的的深度神經網絡

第一個特性我們會在之后的學習中用到,這里暫且按下不表,我們首先來探討研究一下什么是自動求導Autograd、自動求導Autograd的原理是怎樣的等問題。

  • 當然首先我們要保證正確導入了torch包
import torch # 打印一下PyTorch的版本 torch.__verson__

PyTorch的Autograd模塊實現了深度學習算法中的反向傳播求梯度,在張量(Tensor類)上的所有操作,Autograd都能為它們自動提供微分,簡化了手動計算導數的復雜過程。

在張量創建時,通過設置 requires_grad 標識為Ture來告訴Pytorch需要對該張量進行自動求導,PyTorch會記錄該張量的每一步操作歷史并自動計算。

  • 首先我們新建一個張量x
# requires_grad = True表示告訴Pytorch需要對該張量進行自動求導, # 并且PyTorch會記錄該張量的每一步操作歷史并自動計算。 x = torch.rand(5,5,requires_grad = True) x

PyTorch會自動追蹤和記錄對于張量的所有操作,當計算完成后調用.backward()方法自動計算梯度并且將計算結果保存到grad屬性中。

  • 然后我們另建一個張量y
y = torch.rand(5,5,requires_grad = True) y

二、什么是自動求導Autograd

  • 1.當涉及到大型神經網絡時,我們都不擅長微積分,這是事實,我們不可能隨時隨地的高效的計算一個很復雜的微積分。因此通過顯式求解數學方程來計算這樣大的復合函數的梯度是不現實的,特別是這些曲線存在于大量的維數中,是無法理解的。這就是PyTorch的Autograd發揮作用的地方。它抽象了復雜的數學,幫助我們“神奇地”計算高維曲線的梯度,只需要幾行代碼。
  • 2.每個張量都有一個.grad_fn屬性,如果這個張量是用戶手動創建的那么這個張量的grad_fn是None
  • 3.在張量進行操作后,grad_fn已經被賦予了一個新的函數,這個函數引用了一個創建了這個Tensor類的Function對象。 Tensor和Function互相連接生成了一個非循環圖,它記錄并且編碼了完整的計算歷史。

2.1 簡單的自動求導

  • 案例1
z = torch.sum(x+y) z
  • 自動求導
z.backward() print(x.grad,y.grad)

如果Tensor類表示的是一個標量(即它包含一個元素的張量),則不需要為backward()指定任何參數,但是如果它有更多的元素,則需要指定一個gradient參數,它是形狀匹配的張量。 以上的 z.backward()相當于是z.backward(torch.tensor(1.))的簡寫。 這種參數常出現在圖像分類中的單標簽分類,輸出一個標量代表圖像的標簽。

2.2 復雜的自動求導

  • 案例2
x = torch.rand(5, 5, requires_grad=True) y = torch.rand(5, 5, requires_grad=True) z= x**2+y**3 z

  • 自動求導
#我們的返回值不是一個標量,所以需要輸入一個大小相同的張量作為參數,這里我們用ones_like函數根據x生成一個張量 z.backward(torch.ones_like(x)) print(x.grad)


我們可以使用with torch.no_grad()上下文管理器臨時禁制對已設置requires_grad = True的張量進行自動求導,這個方法在測試集計算準確率的時候會經常用到。

with torch.no_grad():print((x + y**2).requires_grad)# 會打印False,說明臨時禁制對已設置requires_grad = True的張量進行自動求導

三、自動求導Autograd過程的簡單解析

為了說明Pytorch的自動求導原理,我們來嘗試分析一下PyTorch的源代碼,雖然Pytorch的 Tensor和 TensorBase都是使用CPP來實現的,但是可以使用一些Python的一些方法查看這些對象在Python的屬性和狀態。 Python的 dir() 函數返回參數的屬性、方法列表。上述案例2中的z是一個Tensor變量,看看里面有哪些成員變量。

dir(z)

會打印處一大串東西來,返回很多,我們直接排除掉一些Python中特殊方法(以__開頭和結束的)和私有方法(以_開頭的,直接看幾個比較主要的屬性:

  • .is_leaf:記錄是否是葉子節點。通過這個屬性來確定這個變量的類型 在官方文檔中所說的“graph leaves”,“leaf variables”,都是指像x,y這樣的手動創建的、而非運算得到的變量,這些變量稱為創建變量。 像z這樣的,是通過計算后得到的結果稱為結果變量
  • 判斷一個Tensor變量是創建變量還是結果變量可以通過.is_leaf
print('x.is_leaf=' + str(x.is_leaf)) # 打印True print('z.is_leaf=' + str(z.is_leaf)) # 打印False

x是手動創建的沒有通過計算,所以他被認為是一個葉子節點也就是一個創建變量,而z是通過x與y的一系列計算得到的,所以不是葉子結點也就是結果變量。

  • grad_fn:每個張量都有一個grad_fn屬性用于保存張量的操作,如果這個張量為用戶自己創建的,則grad_fn為None。
    為什么我們執行z.backward()方法的時候會更新x.grad和y.grad呢? .grad_fn屬性記錄的就是這部分的操作,雖然.backward()方法也是CPP實現的,但是可以通過Python來進行簡單的探索。
z.grad_fn


grad_fn是一個AddBackward0類型的變量 AddBackward0這個類也是用Cpp來寫的,但是我們從名字里就能夠大概知道,他是加法(ADD)的反反向傳播(Backward),看看里面有些什么東西。

dir(z.grad_fn)
  • 輸出結果
['__call__','__class__','__delattr__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','_register_hook_dict','metadata','name','next_functions','register_hook','requires_grad']

next_functions就是grad_fn的精華

z.grad_fn.next_functions


next_functions是一個tuple of tuple of PowBackward0 and int。
為什么是2個tuple ? 因為我們的操作是z= x**2+y**3 剛才的AddBackward0是相加,而前面的操作是乘方 PowBackward0。tuple第一個元素就是x相關的操作記錄

  • 查看z的grad_fn屬性next_functions的第一個元組的第一個元素
xg = z.grad_fn.next_functions[0][0] dir(xg)
  • 輸出結果
['__call__','__class__','__delattr__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','_register_hook_dict','metadata','name','next_functions','register_hook','requires_grad']
  • 繼續剖析,查看xg的next_functions
x_leaf=xg.next_functions[0][0] type(x_leaf)
  • 輸出結果
AccumulateGrad

在PyTorch的反向圖計算中,AccumulateGrad類型代表的就是葉子節點類型,也就是計算圖終止節點。AccumulateGrad類中有一個.variable屬性指向葉子節點。

x_leaf.variable

這個.variable的屬性就是我們的生成的變量x

這樣整個規程就很清晰了:

  • 1.當我們執行z.backward()的時候。這個操作將調用z里面的grad_fn這個屬性,執行求導的操作。

  • 2.這個操作將遍歷grad_fn的next_functions,然后分別取出里面的Function(AccumulateGrad),執行求導操作。這部分是一個遞歸的過程直到最后類型為葉子節點。

  • 3.計算出結果以后,將結果保存到他們對應的variable 這個變量所引用的對象(x和y)的 grad這個屬性里面。

  • 4.求導結束。所有的葉節點的grad變量都得到了相應的更新
    最終當我們執行完c.backward()之后,a和b里面的grad值就得到了更新。

  • 首先我們來剖析一下這個案例,通過這個案例來進一步理解Autograd的工作流程

# 導入相應的包 import torch import torch.autograd# 創建張量x、y x = torch.tensor([1.0],requires_grad = True) y =torch.tensor([2.0],requires_grad = False) z = x * y# 求解x的梯度 z.backward(torch.ones_like(x)) x.grad
  • 輸出結果
x.grad = tensor([2.])


圖片來源:https://zhuanlan.zhihu.com/p/148669484

從計算圖中可以看出,一個張量中:

  • data中保存著所存有的數據
  • grad中保存這梯度
  • requires_grad表示是否開始追蹤所有的操作歷史

Autograd具體工作流程:
x、y是我們自己創建的張量,讓x、y執行相乘操作,生成張量z。

  • 1.當我們調用.backward()方法時,該操作會調用張量z中的grad_fn屬性,前面我們說過,grad_fn屬性用來保存張量的操作。如果張量是創建張量,那么該張量的grad_fn屬性為None。
  • 2.這個操作將遍歷grad_fn的next_functions,然后分別取出里面的Function(AccumulateGrad),執行求導操作。這部分是一個遞歸的過程直到最后類型為葉子節點。
  • 3.計算出結果以后,將結果保存到他們對應的variable 這個變量所引用的對象(x)的 grad屬性里面。
    求導結束。所有的葉節點的grad變量都得到了相應的更新。
  • 4.最終當我們執行完z.backward()之后,x中的grad值就得到了更新。

四、擴展Autograd

如果需要自定義autograd擴展新的功能,就需要擴展Function類。因為Function使用autograd來計算結果和梯度,并對操作歷史進行編碼。 在Function類中最主要的方法就是forward()和backward()他們分別代表了前向傳播和反向傳播。

一個自定義的Function需要一下三個方法:

  • __init__ (optional):如果這個操作需要額外的參數則需要定義這個Function的構造函數,不需要的話可以忽略。

  • forward():執行前向傳播的計算代碼

  • backward():反向傳播時梯度計算的代碼。 參數的個數和forward返回值的個數一樣,每個參數代表傳回到此操作的梯度。

# 引入Function便于擴展 from torch.autograd.function import Function # 定義一個乘以常數的操作(輸入參數是張量) # 方法必須是靜態方法,所以要加上@staticmethod class MulConstant(Function):@staticmethod def forward(ctx, tensor, constant):# ctx 用來保存信息這里類似self,并且ctx的屬性可以在backward中調用ctx.constant=constantreturn tensor *constant@staticmethoddef backward(ctx, grad_output):# 返回的參數要與輸入的參數一樣.# 第一個輸入為3x3的張量,第二個為一個常數# 常數的梯度必須是 None.return grad_output, None

定義完我們的新操作后,我們來進行測試

a=torch.rand(3,3,requires_grad=True) b=MulConstant.apply(a,5) print("a:"+str(a)) print("b:"+str(b)) # b為a的元素乘以5

反向傳播,返回值不是標量,所以backward方法需要參數

b.backward(torch.ones_like(a)) a.grad

參考文獻

  • https://github.com/zergtant/pytorch-handbook/blob/master/chapter2/2.1.2-pytorch-basics-autograd.ipynb
  • https://zhuanlan.zhihu.com/p/148669484

總結

以上是生活随笔為你收集整理的PyTorch基础(二)-----自动求导Autograd的全部內容,希望文章能夠幫你解決所遇到的問題。

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