国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Pytorch中的forward的理解

這篇具有很好參考價值的文章主要介紹了Pytorch中的forward的理解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

0. 前言

按照國際慣例,首先聲明:本文只是我自己學(xué)習(xí)的理解,雖然參考了他人的寶貴見解,但是內(nèi)容可能存在不準(zhǔn)確的地方。如果發(fā)現(xiàn)文中錯誤,希望批評指正,共同進步。

1. 關(guān)于forward的兩個小問題

1.1 為什么都用def forward,而不改個名字?

在Pytorch建立神經(jīng)元網(wǎng)絡(luò)模型的時候,經(jīng)常用到forward方法,表示在建立模型后,進行神經(jīng)元網(wǎng)絡(luò)的前向傳播。說的直白點,forward就是專門用來計算給定輸入,得到神經(jīng)元網(wǎng)絡(luò)輸出的方法。

在代碼實現(xiàn)中,也是用def forward來寫forward前向傳播的方法,我原來以為這是一種約定熟成的名字,也可以換成任意一個自己喜歡的名字。

但是看的多了之后發(fā)現(xiàn)并非如此:Pytorch對于forward方法賦予了一些特殊“功能”

(這里不禁再吐槽,一些看起來挺厲害的Pytorch“大神”,居然不知道這個。。。只能草草解釋一下:“就是這樣的。。?!?

1.2 forward有什么特殊功能?
第一條:.forward()可以不寫

我最開始發(fā)現(xiàn)forward()的與眾不同之處就是在此,首先舉個例子:

import torch.nn as nn
class test(nn.Module):
    def __init__(self, input):
        super(test,self).__init__()
        self.input = input

    def forward(self,x):
        return self.input * x

T = test(8)
print(T(6))

# print(T.forward(6))
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:/Users/Lenovo/Desktop/DL/pythonProject/tt.py
48

Process finished with exit code 0

可以發(fā)現(xiàn),T(6)是可以輸出的!而且不用指定,默認了調(diào)用forward方法。當(dāng)然如果非要寫上.forward()這也是可以正常運行的,和不寫是一樣的。

如果不調(diào)用Pytorch(正常的Python語法規(guī)則),這樣肯定會報錯的

# import torch.nn as nn  #不再調(diào)用torch
class test():
    def __init__(self, input):
        self.input = input

    def forward(self,x):
        return self.input * x

T = test(8)
print(T.forward(6))
print("************************")
print(T(6))
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:/Users/Lenovo/Desktop/DL/pythonProject/tt.py
48
************************
Traceback (most recent call last):
  File "C:\Users\Lenovo\Desktop\DL\pythonProject\tt.py", line 77, in <module>
    print(T(6))
TypeError: 'test' object is not callable

Process finished with exit code 1

這里會報:‘test’ object is not callable
因為class不能被直接調(diào)用,不知道你想調(diào)用哪個方法。

第二條:優(yōu)先運行forward方法

如果在class中再增加一個方法:

import torch.nn as nn
class test(nn.Module):
    def __init__(self, input):
        super(test,self).__init__()
        self.input = input

    def byten(self):
        return self.input * 10

    def forward(self,x):
        return self.input * x

T = test(8)
print(T(6))
print(T.byten())
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:/Users/Lenovo/Desktop/DL/pythonProject/tt.py
48
80

Process finished with exit code 0

可以見到,在class中有多個method的時候,如果不指定method,forward是會被優(yōu)先執(zhí)行的。

2. 總結(jié)

在Pytorch中,forward方法是一個特殊的方法,被專門用來進行前向傳播。

20230605 更新

應(yīng)評論要求,增加forward的官方定義,這塊我就不搬運PyTorch官網(wǎng)的內(nèi)容了,直接傳送門走你:nn.Module.forward。

20230919 大更新

首先非常感謝大家喜歡本文!這篇文章本來是我自己的“隨手記”沒想到有這么多C友瀏覽過!

其實在寫完本文后我是有些遺憾的,因為本文僅是用了實驗的方法探索出了.forward()的表象,而它的運作機理卻沒有說明白,知其然不知其所以然!

在此感謝下面 Mr·小魚 的評論給了我啟迪,因為魔術(shù)方法__call__()的特性確實很符合.forward()的表象,但是我對著nn.Module的源碼一臉茫然,因為源碼中壓根沒有__call__()方法的定義!!

于是我抱著試試的心態(tài),在PyTorch官網(wǎng)上查了下PyTorch的歷史版本,這一查確實查到了線索:
Pytorch中的forward的理解
下面是從PyTorch的上古版本v0.1.12中截取forward()__call__()方法的源碼:

class Module(object):
#...中間不相關(guān)代碼省略...
    def forward(self, *input):
        """Defines the computation performed at every call.

        Should be overriden by all subclasses.
        """
        raise NotImplementedError
#...中間不相關(guān)代碼省略...
    def __call__(self, *input, **kwargs):
        result = self.forward(*input, **kwargs)
        for hook in self._forward_hooks.values():
            hook_result = hook(self, input, result)
            if hook_result is not None:
                raise RuntimeError(
                    "forward hooks should never return any values, but '{}'"
                    "didn't return None".format(hook))
        var = result
        while not isinstance(var, Variable):
            var = var[0]
        creator = var.creator
        if creator is not None and len(self._backward_hooks) > 0:
            for hook in self._backward_hooks.values():
                wrapper = functools.partial(hook, self)
                functools.update_wrapper(wrapper, hook)
                creator.register_hook(wrapper)
        return result

我們可以看到在__call__()方法中直接把方法self.forward()作為函數(shù)的返回值,由于魔術(shù)方法__call__()可以被自動調(diào)用,這也就解釋了為什么forward()可以自動運行。

至于該方法中的其他內(nèi)容,都是與hook鉤子函數(shù)的操作相關(guān),這部分暫不做探索。。。

那我們回到現(xiàn)在的版本(我現(xiàn)在使用的是1.8.1):
Pytorch中的forward的理解
通過源碼可以看到經(jīng)歷了多個版本的更迭,forward()__call__()居然改名字了!!

    forward: Callable[..., Any] = _forward_unimplemented
    ...
    __call__ : Callable[..., Any] = _call_impl

這也就是為什么我之前在源碼中沒找到這兩個方法定義的原因。。。準(zhǔn)確來說這里也不能說是改名字了,而是多了一個名字,至于PyTorch為什么會有這樣的更改,我確實也沒想到原因。。。

其中_forward_unimplemented()倒是沒變:

def _forward_unimplemented(self, *input: Any) -> None:
    r"""Defines the computation performed at every call.

    Should be overridden by all subclasses.

    .. note::
        Although the recipe for forward pass needs to be defined within
        this function, one should call the :class:`Module` instance afterwards
        instead of this since the former takes care of running the
        registered hooks while the latter silently ignores them.
    """
    raise NotImplementedError

_call_impl()相比于上古版本,已經(jīng)復(fù)雜到了令人發(fā)指的地步!

    def _call_impl(self, *input, **kwargs):
        # Do not call functions when jit is used
        full_backward_hooks, non_full_backward_hooks = [], []
        if len(self._backward_hooks) > 0 or len(_global_backward_hooks) > 0:
            full_backward_hooks, non_full_backward_hooks = self._get_backward_hooks()

        for hook in itertools.chain(
                _global_forward_pre_hooks.values(),
                self._forward_pre_hooks.values()):
            result = hook(self, input)
            if result is not None:
                if not isinstance(result, tuple):
                    result = (result,)
                input = result

        bw_hook = None
        if len(full_backward_hooks) > 0:
            bw_hook = hooks.BackwardHook(self, full_backward_hooks)
            input = bw_hook.setup_input_hook(input)

        if torch._C._get_tracing_state():
            result = self._slow_forward(*input, **kwargs)
        else:
            result = self.forward(*input, **kwargs)
        for hook in itertools.chain(
                _global_forward_hooks.values(),
                self._forward_hooks.values()):
            hook_result = hook(self, input, result)
            if hook_result is not None:
                result = hook_result

        if bw_hook:
            result = bw_hook.setup_output_hook(result)

        # Handle the non-full backward hooks
        if len(non_full_backward_hooks) > 0:
            var = result
            while not isinstance(var, torch.Tensor):
                if isinstance(var, dict):
                    var = next((v for v in var.values() if isinstance(v, torch.Tensor)))
                else:
                    var = var[0]
            grad_fn = var.grad_fn
            if grad_fn is not None:
                for hook in non_full_backward_hooks:
                    wrapper = functools.partial(hook, self)
                    functools.update_wrapper(wrapper, hook)
                    grad_fn.register_hook(wrapper)
                self._maybe_warn_non_full_backward_hook(input, result, grad_fn)

        return result

其變復(fù)雜的原因是各種鉤子函數(shù)_hook的調(diào)用,有興趣的童鞋可以參考這篇文章:pytorch 中_call_impl()函數(shù)。這部分絕對是超綱了!

最后我想再做幾個實驗加深理解:
實驗①

import torch.nn as nn
class test(nn.Module):
    def __init__(self, input):
        super(test,self).__init__()
        self.input = input

    def forward(self,x):
        return self.input * x

T = test(8)
print(T.__call__(6))
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:\Users\Lenovo\Desktop\DL\Pytest\calc_graph\test.py 
48

Process finished with exit code 0

這里T.__call__(6)寫法等價于T(6)

實驗②

import torch.nn as nn
class test(nn.Module):
    def __init__(self, input):
        super(test,self).__init__()
        self.input = input

    def forward(self,x):
        return self.input * x

T = test(8)
print(T.forward(6))
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:\Users\Lenovo\Desktop\DL\Pytest\calc_graph\test.py 
48

Process finished with exit code 0

這里T.forward(6)的寫法雖然也能正確地計算出結(jié)果,但是不推薦這么寫,因為這會導(dǎo)致__call__()調(diào)用一遍forward(),然后手動又調(diào)用了一遍forward(),造成forward()的重復(fù)計算,浪費計算資源。

實驗③

import torch.nn as nn
class test(nn.Module):
    def __init__(self, input):
        super(test,self).__init__()
        self.input = input

    # def forward(self,x):
    #     return self.input * x

T = test(8)
print(T())
--------------------------運行結(jié)果-------------------------
D:\Users\Lenovo\anaconda3\python.exe C:\Users\Lenovo\Desktop\DL\Pytest\calc_graph\test.py 
Traceback (most recent call last):
  File "C:\Users\Lenovo\Desktop\DL\Pytest\calc_graph\test.py", line 11, in <module>
    print(T())
  File "D:\Users\Lenovo\anaconda3\lib\site-packages\torch\nn\modules\module.py", line 889, in _call_impl
    result = self.forward(*input, **kwargs)
  File "D:\Users\Lenovo\anaconda3\lib\site-packages\torch\nn\modules\module.py", line 201, in _forward_unimplemented
    raise NotImplementedError
NotImplementedError

forward()是必須要寫的,因為__call__()要自動調(diào)用forward()。如果壓根不寫forward(),__call__()將無方法可以調(diào)用。按照forward()的源碼,這里會raise NotImplementedError。

至此,我覺得PyTorch中的forward應(yīng)該算是全說明白了。。。文章來源地址http://www.zghlxwxcb.cn/news/detail-401864.html

到了這里,關(guān)于Pytorch中的forward的理解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • cuda+anaconda+pytorch按照教程

    cuda+anaconda+pytorch按照教程

    1、查看當(dāng)前顯卡支持的最高版本,有兩種方式: 1)NVIDIA控制面板—幫助—系統(tǒng)信息—組件—NVCUDA.dll對應(yīng)版本 請注意,12.2為本機CUDA支持的最高版本 nvidia-smi顯示的同上,也表示cuda支持的最高版本 安裝cuda后在cmd窗口使用nvcc -V命令看到的是自己安裝的cuda版本,這個安裝后不

    2024年02月12日
    瀏覽(14)
  • 從零開始理解Linux中斷架構(gòu)(1)-前言

    前言 ???? ? ?前段時間在轉(zhuǎn)行手擼WIFI路由器,搞wifi路由器需要理解網(wǎng)絡(luò)驅(qū)動程序,以太網(wǎng)卡驅(qū)動程序,無線WIFI驅(qū)動程序,而網(wǎng)卡驅(qū)動的關(guān)鍵路徑就在中斷程序中,需要了解NIC設(shè)備驅(qū)動程序如何收發(fā)數(shù)據(jù),為了徹底的知道數(shù)據(jù)包是如何二層傳遞上來的,又需要了解一點Lin

    2024年02月09日
    瀏覽(31)
  • 深入理解PyTorch中的train()、eval()和no_grad()

    深入理解PyTorch中的train()、eval()和no_grad()

    ??覺得內(nèi)容不錯的話,歡迎點贊收藏加關(guān)注??????,后續(xù)會繼續(xù)輸入更多優(yōu)質(zhì)內(nèi)容?? ??有問題歡迎大家加關(guān)注私戳或者評論(包括但不限于NLP算法相關(guān),linux學(xué)習(xí)相關(guān),讀研讀博相關(guān)......)?? (封面圖由文心一格生成) 在PyTorch中,train()、eval()和no_grad()是三個非常重

    2023年04月08日
    瀏覽(17)
  • OpenCV讀取圖像時按照BGR的順序HWC排列,PyTorch按照RGB的順序CHW排列

    OpenCV讀取圖像時按照BGR的順序HWC排列,PyTorch按照RGB的順序CHW排列

    在OpenCV中,讀取的圖片默認是HWC格式,即按照高度、寬度和通道數(shù)的順序排列圖像尺寸的格式。我們看最后一個維度是C,因此最小顆粒度是C。 例如,一張形狀為256×256×3的RGB圖像,在OpenCV中讀取后的格式為[256, 256, 3],其中最后一個維度表示圖像的通道數(shù)。在OpenCV中,可以通

    2024年02月04日
    瀏覽(25)
  • forward函數(shù)——淺學(xué)深度學(xué)習(xí)框架中的forward

    (本應(yīng)該出一篇貫穿神經(jīng)網(wǎng)絡(luò)的文章的,但是由于時間關(guān)系,就先淺淺記錄一下,加深自己的理解吧吧)。 forward 函數(shù)是深度學(xué)習(xí)框架中常見的一個函數(shù),用于定義神經(jīng)網(wǎng)絡(luò)的前向傳播過程。 在訓(xùn)練過程中,輸入數(shù)據(jù)會被傳入神經(jīng)網(wǎng)絡(luò)的 forward 函數(shù),然后經(jīng)過一系列的計算和

    2023年04月27日
    瀏覽(18)
  • 【Pytorch】提取模型中間層輸出(hook, .register_forward_hook(hook=hook))

    需要轉(zhuǎn)換的對象 模型 損失函數(shù) 數(shù)據(jù)(特征數(shù)據(jù)、標(biāo)簽) 4.3.1 單進程多GPU訓(xùn)練(DP)模式 torch.nn.DataParallel 并行的多卡都是由一個進程進行控制,在進行梯度的傳播時,是在主GPU上進行的。 將模型布置到多個指定GPU上 model = torch.nn.DataParallel(model,device_ids=device_list) 指定模型布置的

    2024年02月13日
    瀏覽(14)
  • PyTorch的CUDA錯誤:Error 804: forward compatibility was attempted on non supported HW

    宿主機為Ubuntu20.04 + gtx1060,Nvidia driver版本為510.85.02。 安裝環(huán)境為:tensorrt8.4 安裝完成后,一當(dāng)調(diào)用cuda環(huán)境就會報錯:Error 804: forward compatibility was attempted on non supported HW。 檢查問題原因 在Linux宿主機上使用docker(版本= 19.3)之前,請確保安裝了nvidia-container-runtime和nvidia-cont

    2023年04月08日
    瀏覽(39)
  • 31 對集合中的字符串,按照長度降序排列

    31 對集合中的字符串,按照長度降序排列

    ? ? ? ? 思路:使用集合的sort方法,新建一個Comparator接口,泛型是String,重寫里面的compare方法。 ? ? ? ? 運行結(jié)果: ? ? ? ? ?擴充:點擊Comparator,查看接口內(nèi)部:發(fā)現(xiàn)加了@FunctionalInterface,說明可以使用箭頭函數(shù),直接使用箭頭函數(shù)就能表示Comparator接口以及它的compara

    2024年02月14日
    瀏覽(18)
  • 神經(jīng)網(wǎng)絡(luò)中的前向傳播(Forward Propagation)和后向傳播(Backward Propagation)

    有時候會搞混這兩個概念。什么是前向傳播?不是只有后向傳播嗎?后向傳播好像是用來更新模型參數(shù)的,前向傳播是什么東西? 帶著疑問再次梳理一遍: 前向傳播是神經(jīng)網(wǎng)絡(luò)進行預(yù)測的過程。在這個過程中,輸入數(shù)據(jù)沿著神經(jīng)網(wǎng)絡(luò)從輸入層經(jīng)過隱藏層(如果有的話)最終

    2024年02月20日
    瀏覽(20)
  • nginx負載轉(zhuǎn)發(fā)源請求http/https:X-Forwarded-Proto及nginx中的轉(zhuǎn)發(fā)報頭

    今天在排查服務(wù)器的問題時最后定位到服務(wù)器因為經(jīng)過了運維這一層的處理,轉(zhuǎn)發(fā)過來的請求不管用戶請求的是https還是http,我們的proxy服務(wù)器收到的都是80端口上的http。于是聯(lián)系相關(guān)部門了解有沒有現(xiàn)成的可用的這樣一個字段來獲得這個值。公司用的也是標(biāo)準(zhǔn)報頭,即X-Fo

    2024年02月16日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包