1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        PyTorch學(xué)習(xí)系列教程:Tensor如何實(shí)現(xiàn)自動(dòng)求導(dǎo)

        共 4355字,需瀏覽 9分鐘

         ·

        2022-03-16 08:16

        導(dǎo)讀

        今天本文繼續(xù)PyTorch學(xué)習(xí)系列。雖然前幾篇推文閱讀效果不是很好(大體可能與本系列推文是新開的一個(gè)方向有關(guān)),但自己選擇的路也要堅(jiān)持走下去?。?/span>

        前篇推文介紹了搭建一個(gè)深度學(xué)習(xí)模型的基本流程,通過若干個(gè)Epoch即完成了一個(gè)簡(jiǎn)單的手寫數(shù)字分類模型,效果還不錯(cuò)。在這一過程中,一個(gè)重要的細(xì)節(jié)便是模型如何學(xué)習(xí)到最優(yōu)參數(shù),答案是通過梯度下降法。實(shí)際上,梯度下降法是一類優(yōu)化方法,是深度學(xué)習(xí)中廣泛應(yīng)用甚至可稱得上是深度學(xué)習(xí)的基石。本篇不打算講解梯度下降法,而主要來談一談Tensor如何實(shí)現(xiàn)自動(dòng)求導(dǎo),明白這一過程方能進(jìn)一步理解各種梯度下降法的原理。


        講解Tensor如何實(shí)現(xiàn)自動(dòng)求導(dǎo),本文分別從理論分析和代碼實(shí)踐的角度加以陳述:
        • Tensor中的自動(dòng)求導(dǎo):與梯度相關(guān)的屬性,前向傳播和反向傳播

        • 自動(dòng)求導(dǎo)探索實(shí)踐:以線性回歸為例,探索自動(dòng)求導(dǎo)過程


        01 Tensor中的自動(dòng)求導(dǎo)分析

        Tensor是PyTorch中的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),構(gòu)成了深度學(xué)習(xí)的基石,其本質(zhì)上是一個(gè)高維數(shù)組。在前序推文中,實(shí)際上提到過在創(chuàng)建一個(gè)Tensor時(shí)可以指定其是否需要梯度。那么是否指定需要梯度(requires_grad)有什么區(qū)別呢?實(shí)際上,這個(gè)參數(shù)設(shè)置True/False將直接決定該Tensor是否支持自動(dòng)求導(dǎo)并參與后續(xù)的梯度更新。具體來說,Tensor數(shù)據(jù)結(jié)構(gòu)中,與梯度直接相關(guān)的幾個(gè)重要屬性間的關(guān)系如下:

        原創(chuàng)拙圖,權(quán)當(dāng)意會(huì)


        透過上面這個(gè)類圖,大概想表達(dá)以下含義:
        • 在一個(gè)Tensor數(shù)據(jù)結(jié)構(gòu)中,最核心的屬性是data,這里面存儲(chǔ)了Tensor所代表的高維數(shù)組(當(dāng)然,這里雖然稱之為高維,但實(shí)際上可以是從0維開始的任意維度);

        • 通過requires_grad參數(shù)控制兩個(gè)屬性,grad和grad_fn,其中前者代表當(dāng)前Tensor的梯度,后者代表經(jīng)過當(dāng)前Tensor所需求導(dǎo)的梯度函數(shù);當(dāng)requires_grad=False時(shí),grad和grad_fn都為None,且不會(huì)存在任何取值,而只有當(dāng)requires_grad=True時(shí),此時(shí)grad和grad_fn初始取值仍為None,但在后續(xù)反向傳播中可以予以賦值更新

        • backward(),是一個(gè)函數(shù),僅適用于標(biāo)量Tensor,即維度為0的Tensor

        • is_leaf:標(biāo)記了當(dāng)前Tensor在所構(gòu)建的計(jì)算圖中的位置,其中計(jì)算圖既可看做是一個(gè)有向無環(huán)圖(DAG),也可視作是一個(gè)樹結(jié)構(gòu)。當(dāng)Tensor是初始節(jié)點(diǎn)時(shí),即為葉子節(jié)點(diǎn),is_leaf=True,否則為False。

        目前,Tensor支持自動(dòng)求導(dǎo)功能對(duì)數(shù)據(jù)類型的要求是僅限于浮點(diǎn)型:"?As of now, we only support autograd for floating point?Tensor?types ( half, float, double and bfloat16) and complex?Tensor?types (cfloat, cdouble). "——引自PyTorch官方文檔


        了解了Tensor所具有上述屬性和方法,那么它是如何實(shí)現(xiàn)自動(dòng)求導(dǎo)的呢?這就又要涉及到前向傳播和反向傳播這兩個(gè)重要概念。簡(jiǎn)單來說,如果將神經(jīng)網(wǎng)絡(luò)的每層比作一系列函數(shù)映射(f1, f2, ..., fn)的話,那么:
        • 前向傳播,就是依據(jù)計(jì)算流程實(shí)現(xiàn)數(shù)據(jù)(data)的計(jì)算和計(jì)算圖的構(gòu)建:
        • 反向傳播,反向傳播就是依據(jù)所構(gòu)建計(jì)算圖的反方向遞歸求導(dǎo)和賦值梯度:


        而如果用圖形化描述這一過程,則是:


        其中,在前向傳播過程中,是按照流程完成從初始輸入(一般是訓(xùn)練數(shù)據(jù)+網(wǎng)絡(luò)權(quán)重)直至最終輸出(一般是損失函數(shù))的計(jì)算過程,同步完成計(jì)算圖的構(gòu)建;而在反向傳播過程中,則是通過調(diào)用loss.backward()函數(shù),依據(jù)計(jì)算圖的相反方向遞歸完成各級(jí)求導(dǎo)(本質(zhì)上就是求導(dǎo)的鏈?zhǔn)椒▌t)。同時(shí),對(duì)于requires_grad=False的tensor,在反向傳播過程中實(shí)際不予以求導(dǎo)和更新,相應(yīng)的反向鏈條被切斷。


        另外值得補(bǔ)充說明的是,在PyTorch早期版本中設(shè)計(jì)用于支持自動(dòng)求導(dǎo)的數(shù)據(jù)類型為Variable,英文含義即為參數(shù),特指網(wǎng)絡(luò)中待優(yōu)化的參數(shù)。其中,Variable與Tensor的關(guān)系是:Variable是對(duì)Tensor的二次封裝,專門用于支持梯度求解。而在后來,Variable逐漸棄用(deprecated),并將其特有的自動(dòng)求導(dǎo)功能與Tensor合并,并通過Tensor的requires_grad屬性來區(qū)分一個(gè)Tensor是否支持求導(dǎo)。顯然,這樣的設(shè)計(jì)是更為合理的,對(duì)使用也更加方便統(tǒng)一。

        已進(jìn)入歷史舞臺(tái)的Variable類型


        02 Tensor中的自動(dòng)求導(dǎo)實(shí)踐

        這里,我們以一個(gè)簡(jiǎn)單的單變量線性回歸為例演示Tensor的自動(dòng)求導(dǎo)過程。


        1.創(chuàng)建訓(xùn)練數(shù)據(jù)x, y和初始權(quán)重w, b

        # 訓(xùn)練數(shù)據(jù),目標(biāo)擬合線性回歸 y = 2*x + 3x = torch.tensor([1., 2.])y = torch.tensor([5., 7.])# 初始權(quán)重,w=1.0, b=0.0w = torch.tensor(1.0, requires_grad=True)b = torch.tensor(0.0, requires_grad=True)


        此時(shí)查看w, b和x, y的梯度相關(guān)的各項(xiàng)屬性,結(jié)果如下

        # 1. 注意:x和y設(shè)置為requires_grad=Falsex.grad, x.grad_fn, x.is_leaf, y.grad, y.grad_fn, y.is_leaf# 輸出:(None, None, True, None, None, True)
        # 2. w和b初始梯度均為None,且二者均為葉子節(jié)點(diǎn)w.grad, w.grad_fn, w.is_leaf, b.grad, b.grad_fn, b.is_leaf# 輸出:(None, None, True, None, None, True)


        2.構(gòu)建計(jì)算流程,實(shí)現(xiàn)前向傳播

        # 按計(jì)算流程逐步操作,實(shí)現(xiàn)前向傳播wx = w*xwx_b = wx + bloss = (wx_b - y)loss2 = loss**2loss2_sum = sum(loss2)


        查看各中間變量的梯度相關(guān)屬性:

        # 1.查看是否葉子節(jié)點(diǎn)wx.is_leaf, wx_b.is_leaf, loss.is_leaf, loss2.is_leaf, loss2_sum.is_leaf# 輸出:(False, False, False, False, False)
        # 2.查看gradwx.grad, wx_b.grad, loss.grad, loss2.grad, loss2_sum.grad# 觸發(fā)Warning# UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at aten\src\ATen/core/TensorBody.h:417.) return self._grad# 輸出:(None, None, None, None, None)
        3.查看grad_fnwx.grad_fn, wx_b.grad_fn, loss.grad_fn, loss2.grad_fn, loss2_sum.grad_fn# 輸出:(0x23a875ee550>, 0x23a875ee8e0>, 0x23a875ee4c0>, 0x23a875ee490>, 0x23a93dde040>)


        3.對(duì)最終的loss調(diào)用backward,實(shí)現(xiàn)反向傳播

        loss2_sum.backward()


        依次查看各中間變量和初始輸入的梯度

        # 1. 中間變量(非葉子節(jié)點(diǎn))的梯度僅用于反向傳播,但不對(duì)外暴露wx.grad, wx_b.grad, loss.grad, loss2.grad, loss2_sum.grad# 輸出:(None, None, None, None, None)
        # 2. 檢查葉子節(jié)點(diǎn)是否獲得梯度:w, b均獲得梯度,x, y不支持求導(dǎo),仍為Nonew.grad, b.grad, x.grad, y.grad# 輸出:(tensor(-28.), tensor(-18.), None, None)


        至此,即通過前向傳播的計(jì)算圖和反向傳播的梯度傳遞,完成了初始權(quán)重參數(shù)的梯度賦值過程。注意,這里w和b是網(wǎng)絡(luò)待優(yōu)化參數(shù),而一旦二者有了梯度,則可進(jìn)一步應(yīng)用梯度下降法予以更新。


        那么進(jìn)一步地,這里w.grad和b.grad的數(shù)值是如何得到的呢?我們實(shí)際手動(dòng)求解一遍。首先分別推導(dǎo)loss對(duì)w和b的偏導(dǎo)公式:


        而后,帶入兩組訓(xùn)練數(shù)據(jù)(x, y)=(1, 5)和(x, y)=(2, 7),并將兩組訓(xùn)練數(shù)據(jù)對(duì)應(yīng)的梯度求和:

        # w的梯度:2*(1*1 + 0 - 5)*1 + 2*(1*2 + 0 - 7)*2 = -28# b的梯度:2*(1*1 + 0 - 5) + 2*(1*2 + 0 - 7) = -18


        顯然,手動(dòng)計(jì)算結(jié)果與上述演示結(jié)果是一致的。

        注意:在多個(gè)訓(xùn)練數(shù)據(jù)(batch_size)參與一次反向傳播時(shí),返回的參數(shù)梯度是在各訓(xùn)練數(shù)據(jù)上的求得的梯度之和。


        摘自PyTorch官網(wǎng)



        相關(guān)閱讀:

        瀏覽 50
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产肏屄 | 亚洲有码在线观看 | 免费黄色操片 | 三级影片武则天 | 人人操人人干人人操 | 女人裸体性做爰视频 | 牧神记同人淫改h文黄 | 啊轻点灬太粗嗯一路向阳 | 成人免费视频 国产免费麻豆 | 中文字幕强奸乱伦日韩无码 |