<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Hook
被成為勾點機制,這不是pytorch的首創,在Windows
的程式設計中已經被普遍採用,包括程序內勾點和全域性勾點。按照自己的理解,hook的作用是通過系統來維護一個連結串列,使得使用者攔截(獲取)通訊訊息,用於處理事件。
pytorch中包含forward
和backward
兩個勾點註冊函數,用於獲取forward和backward中輸入和輸出,按照自己不全面的理解,應該目的是“不改變網路的定義程式碼,也不需要在forward函數中return某個感興趣層的輸出,這樣程式碼太冗雜了”。
register_forward_hook()
函數必須在forward()函數呼叫之前被使用,因為這個函數原始碼註釋顯示這個函數“ it will not have effect on forward since this is called after :func:`forward` is called”,也就是這個函數在forward()之後就沒有作用了!!!):
作用:獲取forward過程中每層的輸入和輸出,用於對比hook是不是正確記錄。
def register_forward_hook(self, hook): r"""Registers a forward hook on the module. The hook will be called every time after :func:`forward` has computed an output. It should have the following signature:: hook(module, input, output) -> None or modified output The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called after :func:`forward` is called. Returns: :class:`torch.utils.hooks.RemovableHandle`: a handle that can be used to remove the added hook by calling ``handle.remove()`` """ handle = hooks.RemovableHandle(self._forward_hooks) self._forward_hooks[handle.id] = hook return handle
如果隨機的初始化每個層,那麼就無法測試出自己獲取的輸入輸出是不是forward
中的輸入輸出了,所以需要將每一層的權重和偏置設定為可識別的值(比如全部初始化為1)。網路包含兩層(Linear有需要求導的引數被稱為一個層,而ReLU沒有需要求導的引數不被稱作一層),__init__()
中呼叫initialize
函數對所有層進行初始化。
注意:在forward()函數返回各個層的輸出,但是ReLU6沒有返回,因為後續測試的時候不對這一層進行註冊hook。
class TestForHook(nn.Module): def __init__(self): super().__init__() self.linear_1 = nn.Linear(in_features=2, out_features=2) self.linear_2 = nn.Linear(in_features=2, out_features=1) self.relu = nn.ReLU() self.relu6 = nn.ReLU6() self.initialize() def forward(self, x): linear_1 = self.linear_1(x) linear_2 = self.linear_2(linear_1) relu = self.relu(linear_2) relu_6 = self.relu6(relu) layers_in = (x, linear_1, linear_2) layers_out = (linear_1, linear_2, relu) return relu_6, layers_in, layers_out def initialize(self): """ 定義特殊的初始化,用於驗證是不是獲取了權重""" self.linear_1.weight = torch.nn.Parameter(torch.FloatTensor([[1, 1], [1, 1]])) self.linear_1.bias = torch.nn.Parameter(torch.FloatTensor([1, 1])) self.linear_2.weight = torch.nn.Parameter(torch.FloatTensor([[1, 1]])) self.linear_2.bias = torch.nn.Parameter(torch.FloatTensor([1])) return True
hook()
函數是register_forward_hook()
函數必須提供的引數,好處是“使用者可以自行決定攔截了中間資訊之後要做什麼!”,比如自己想單純的記錄網路的輸入輸出(也可以進行修改等更加複雜的操作)。
首先定義幾個容器用於記錄:
定義用於獲取網路各層輸入輸出tensor的容器:
# 並定義module_name用於記錄相應的module名字 module_name = [] features_in_hook = [] features_out_hook = [] hook函數需要三個引數,這三個引數是系統傳給hook函數的,自己不能修改這三個引數:
hook函數負責將獲取的輸入輸出新增到feature列表中;並提供相應的module名字
def hook(module, fea_in, fea_out): print("hooker working") module_name.append(module.__class__) features_in_hook.append(fea_in) features_out_hook.append(fea_out) return None
註冊勾點必須在forward()函數被執行之前,也就是定義網路進行計算之前就要註冊,下面的程式碼對網路除去ReLU6以外的層都進行了註冊(也可以選定某些層進行註冊):
註冊勾點可以對某些層單獨進行:
net = TestForHook() net_chilren = net.children() for child in net_chilren: if not isinstance(child, nn.ReLU6): child.register_forward_hook(hook=hook)
由於前面的forward()函數返回了需要記錄的特徵,這裡可以直接測試:
out, features_in_forward, features_out_forward = net(x) print("*"*5+"forward return features"+"*"*5) print(features_in_forward) print(features_out_forward) print("*"*5+"forward return features"+"*"*5)
得到下面的輸出是理所當然的:
*****forward return features*****
(tensor([[0.1000, 0.1000],
[0.1000, 0.1000]]), tensor([[1.2000, 1.2000],
[1.2000, 1.2000]], grad_fn=<AddmmBackward>), tensor([[3.4000],
[3.4000]], grad_fn=<AddmmBackward>))
(tensor([[1.2000, 1.2000],
[1.2000, 1.2000]], grad_fn=<AddmmBackward>), tensor([[3.4000],
[3.4000]], grad_fn=<AddmmBackward>), tensor([[3.4000],
[3.4000]], grad_fn=<ThresholdBackward0>))
*****forward return features*****
hook通過list結構進行記錄,所以可以直接print
測試features_in是不是儲存了輸入:
print("*"*5+"hook record features"+"*"*5) print(features_in_hook) print(features_out_hook) print(module_name) print("*"*5+"hook record features"+"*"*5)
得到和forward一樣的結果:
*****hook record features*****
[(tensor([[0.1000, 0.1000],
[0.1000, 0.1000]]),), (tensor([[1.2000, 1.2000],
[1.2000, 1.2000]], grad_fn=<AddmmBackward>),), (tensor([[3.4000],
[3.4000]], grad_fn=<AddmmBackward>),)]
[tensor([[1.2000, 1.2000],
[1.2000, 1.2000]], grad_fn=<AddmmBackward>), tensor([[3.4000],
[3.4000]], grad_fn=<AddmmBackward>), tensor([[3.4000],
[3.4000]], grad_fn=<ThresholdBackward0>)]
[<class 'torch.nn.modules.linear.Linear'>,
<class 'torch.nn.modules.linear.Linear'>,
<class 'torch.nn.modules.activation.ReLU'>]
*****hook record features*****
如果害怕會有小數點後面的數值不一致,或者資料型別的不匹配,可以對hook
記錄的特徵和forward記錄的特徵做減法:
測試forward返回的feautes_in是不是和hook記錄的一致:
print("sub result'") for forward_return, hook_record in zip(features_in_forward, features_in_hook): print(forward_return-hook_record[0])
得到的全部都是0,說明hook沒問題:
sub result tensor([[0., 0.], [0., 0.]]) tensor([[0., 0.], [0., 0.]], grad_fn=<SubBackward0>) tensor([[0.], [0.]], grad_fn=<SubBackward0>)
import torch import torch.nn as nn class TestForHook(nn.Module): def __init__(self): super().__init__() self.linear_1 = nn.Linear(in_features=2, out_features=2) self.linear_2 = nn.Linear(in_features=2, out_features=1) self.relu = nn.ReLU() self.relu6 = nn.ReLU6() self.initialize() def forward(self, x): linear_1 = self.linear_1(x) linear_2 = self.linear_2(linear_1) relu = self.relu(linear_2) relu_6 = self.relu6(relu) layers_in = (x, linear_1, linear_2) layers_out = (linear_1, linear_2, relu) return relu_6, layers_in, layers_out def initialize(self): """ 定義特殊的初始化,用於驗證是不是獲取了權重""" self.linear_1.weight = torch.nn.Parameter(torch.FloatTensor([[1, 1], [1, 1]])) self.linear_1.bias = torch.nn.Parameter(torch.FloatTensor([1, 1])) self.linear_2.weight = torch.nn.Parameter(torch.FloatTensor([[1, 1]])) self.linear_2.bias = torch.nn.Parameter(torch.FloatTensor([1])) return True
定義用於獲取網路各層輸入輸出tensor
的容器,並定義module_name
用於記錄相應的module名字
module_name = [] features_in_hook = [] features_out_hook = []
hook函數負責將獲取的輸入輸出新增到feature列表中,並提供相應的module名字
def hook(module, fea_in, fea_out): print("hooker working") module_name.append(module.__class__) features_in_hook.append(fea_in) features_out_hook.append(fea_out) return None
定義全部是1的輸入:
x = torch.FloatTensor([[0.1, 0.1], [0.1, 0.1]])
註冊勾點可以對某些層單獨進行:
net = TestForHook() net_chilren = net.children() for child in net_chilren: if not isinstance(child, nn.ReLU6): child.register_forward_hook(hook=hook)
測試網路輸出:
out, features_in_forward, features_out_forward = net(x)
print("*"*5+"forward return features"+"*"*5)
print(features_in_forward)
print(features_out_forward)
print("*"*5+"forward return features"+"*"*5)
測試features_in是不是儲存了輸入:
print("*"*5+"hook record features"+"*"*5) print(features_in_hook) print(features_out_hook) print(module_name) print("*"*5+"hook record features"+"*"*5)
測試forward返回的feautes_in是不是和hook記錄的一致:
print("sub result")
for forward_return, hook_record in zip(features_in_forward, features_in_hook):
print(forward_return-hook_record[0])
到此這篇關於pytorch中的hook機制register_forward_hook的文章就介紹到這了,更多相關pytorch中的hook機制內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45