網(wǎng)站首頁 編程語言 正文
pytorch forwod函數(shù)在父類中的調(diào)用
問題背景
最近在研究Detetron2的代碼結(jié)構(gòu)時(shí),發(fā)現(xiàn)有些網(wǎng)絡(luò)代碼里面沒有forward函數(shù),卻照樣可以推理,深入挖掘之后,發(fā)現(xiàn)其將forword函數(shù)都寫在了同一個(gè)父類里面。
這就牽涉到了下面這個(gè)問題,子類中沒有forward函數(shù),只有父類中有forward函數(shù),這樣能不能正常調(diào)用網(wǎng)絡(luò)。
import torch.nn as nn
class Network1(nn.Module):
? ? def __init__(self):
? ? ? ? super().__init__()
? ? def forward(self,x):
? ? ? ? return x
class Network2(Network1):
? ? def __init__(self):
? ? ? ? super().__init__()
data = [1,2,3]
model = Network2().eval()
output = model(data)
print(output)
輸出結(jié)果如下:
[1,2,3]
pytorch forward方法調(diào)用原理
在使用Pytorch自定義網(wǎng)絡(luò)模型的時(shí)候,我們需要繼承nn.Module這個(gè)類,然后定義forward方法來實(shí)現(xiàn)前向轉(zhuǎn)播。
如下圖的一個(gè)自定義的網(wǎng)絡(luò)模型
首先該網(wǎng)絡(luò)模型的初始化方法__init__需要繼承父類nn.Module的初始化方法,用語句super().init()實(shí)現(xiàn)。
并在初始化方法里面,定義了卷積、BN、激活函數(shù)等。接下來定義forward方法,將整個(gè)網(wǎng)絡(luò)連接起來。
有了上面的定義,我們可以實(shí)例化一個(gè)對象,例如:
fire2 = Fire(96, 128,16,64,64)
實(shí)現(xiàn)前向傳播,使用?y= fire2(x)?其中x是該網(wǎng)絡(luò)的輸入,y是輸出,實(shí)現(xiàn)了forward方法的額功能。
這里就會有人感到奇怪,forward作為Fire這個(gè)類的方法,使用的時(shí)候不應(yīng)該是?y= fire2.forward(x)嗎。
這里為什么一個(gè)類的實(shí)例可以當(dāng)做方法直接使用?這是因?yàn)檫@個(gè)Fire類繼承的父類nn.Module里面定義了__call__方法。
一個(gè)類如果定義了__call__方法,則該類的實(shí)例就可以作為一個(gè)方法那樣直接使用。
例如下列代碼[1]
class A():
def __call__(self):
print('i can be called like a function')
a = A()
a()
就會執(zhí)行print函數(shù),打印其中搞的文字。這里需要區(qū)別的是,實(shí)例化的時(shí)候,類的名稱后面括號可以傳遞參數(shù),例如前面實(shí)例化Fire的時(shí)候,傳遞in_channel,out_channel等參數(shù)。
但是要利用__call__的特性,是在實(shí)例名后面的括號中傳遞參數(shù),例如上面的例子a(),這里雖然沒有參數(shù),但是也可以改變__call__的定義使之可以傳遞參數(shù)。
回到網(wǎng)絡(luò)模型的內(nèi)容上來。翻看nn.Module的部分源碼[2],可以發(fā)現(xiàn),nn.Module里面果然定義了__call__,并且傳遞了參數(shù)*input。在__call__的定義中國,調(diào)用了self.forward。
這里其實(shí)還有一個(gè)點(diǎn)值得注意。其實(shí)nn.Module里面并沒有定義forward,但他卻調(diào)用self.forward,嚴(yán)格來說,他是“想要”調(diào)用self.forward。
如果我們沒有定義一個(gè)類,例如Fire,來繼承nn.Module,并且在這個(gè)類里面定義forward,那么nn.Module中__call__下面的self.forward就是無效的。
這意味著,父類中__call__下面調(diào)用的函數(shù),可以在繼承他的子類中定義。
下面給出一個(gè)簡單的例子。
class father():
def __call__(self):
self.forward()
print('I''m the father!')
class child(father):
def forward(self):
print('Forward!')
F=father()
C=child()
這里定義了父類father,并定義了繼承他的一個(gè)子類child。此外還進(jìn)行了他們的實(shí)例化。
顯然,在father的__call__方法下面,調(diào)用了self.forward,但是沒有定義。child在繼承了father之后,定義了forward。
首先,這段代碼不會報(bào)錯(cuò),即使father的__call__下面的self.forward并沒有定義,這也是前面我說的,雖然沒有定義forward,但是可以理解為他“想要”調(diào)用self.forward。
那么在child記成了father之后,進(jìn)行了forward的定義,這使得child本身可以調(diào)用forward。
在上面這段代碼的基礎(chǔ)上,如果我們執(zhí)行F(),匯報(bào)下面這一段錯(cuò)誤,這解釋了forward沒有定義,只是“想要”調(diào)用self.forward。
如果我們執(zhí)行C(),則如下圖輸出。
顯然,在child中補(bǔ)充了forward的定義,就可以成功調(diào)用。
總結(jié)
原文鏈接:https://blog.csdn.net/ahhhhhh520/article/details/124437247
相關(guān)推薦
- 2022-03-23 CentOS7防火墻和端口相關(guān)命令介紹_Linux
- 2022-12-10 ijkplayer打包支持https的so使用詳解_Android
- 2022-05-18 React?Hook之使用Effect?Hook的方法_React
- 2022-02-16 mac 使用launchctl 開機(jī)時(shí)加速vim、emacs
- 2024-03-04 layui樹形組件獲取復(fù)選框選中的id,禁用選中父節(jié)點(diǎn)后自動選中子節(jié)點(diǎn)功能
- 2022-07-16 windows下的SDL開發(fā)環(huán)境搭建(基于mingw編譯運(yùn)行)
- 2022-04-26 jQuery實(shí)現(xiàn)表格的數(shù)據(jù)拖拽_jquery
- 2022-12-26 Python中獲取圖片的大小問題_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支