[英]How to change activation layer in Pytorch pretrained module?
如何更改 Pytorch pretrained.network 的激活層? 這是我的代碼:
print("All modules")
for child in net.children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
print(child)
print('Before changing activation')
for child in net.children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
print(child)
child=nn.SELU()
print(child)
print('after changing activation')
for child in net.children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
print(child)
這是我的 output:
All modules
ReLU(inplace=True)
Before changing activation
ReLU(inplace=True)
SELU()
after changing activation
ReLU(inplace=True)
使用默認 pytorch API 對我來說效果很好:
def replace_layer(module: nn.Module, old: nn.Module, new: nn.Module, full_name=""):
for name, m in module.named_children():
full_name = f"{full_name}.{name}"
if isinstance(m, old):
setattr(module, name, new)
print(f"replaced {full_name}: {old}->{new}")
elif len(list(m.children())) > 0:
replace_layer(m, old, new, full_name)
model.apply(lambda m: replace_layer(m, nn.Relu, nn.Hardswish(True)))
將替換圖層並打印“trace”:
replaced ._model.norm_layer.0.1.2: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.0.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.0.1.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.0.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.0.1.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.2.0.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.2.0.1.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.2.3.0.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.2.3.0.1.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
replaced ._model.norm_layer.backbone.encoder.blocks.0.1.2.3.4.0.conv1.bn1.relu: <class 'torch.nn.modules.activation.ReLU'>->Hardswish()
我假設您使用模塊接口nn.ReLU
來創建激活層,而不是使用功能接口F.relu
。 如果是這樣, setattr
對我有用。
import torch
import torch.nn as nn
# This function will recursively replace all relu module to selu module.
def replace_relu_to_selu(model):
for child_name, child in model.named_children():
if isinstance(child, nn.ReLU):
setattr(model, child_name, nn.SELU())
else:
replace_relu_to_selu(child)
########## A toy example ##########
net = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1),
nn.ReLU(inplace=True),
nn.Conv2d(3, 32, kernel_size=3, stride=1),
nn.ReLU(inplace=True)
)
########## Test ##########
print('Before changing activation')
for child in net.children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
print(child)
# Before changing activation
# ReLU(inplace=True)
# ReLU(inplace=True)
print('after changing activation')
for child in net.children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
print(child)
# after changing activation
# SELU()
# SELU(
._modules
為我解決了這個問題。
for name,child in net.named_children():
if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
net._modules['relu'] = nn.SELU()
這是用於更換任何層的通用 function
def replace_layers(model, old, new):
for n, module in model.named_children():
if len(list(module.children())) > 0:
## compound module, go inside it
replace_layers(module, old, new)
if isinstance(module, old):
## simple module
setattr(model, n, new)
replace_layer(model, nn.ReLU, nn.ReLU6())
我為此掙扎了幾天。 所以,我做了一些挖掘並寫了一個kaggle 筆記本,解釋了如何在 pytorch 中訪問不同類型的層/模塊。
我將提供一個適用於任何層的更通用的解決方案(並避免其他問題,例如在循環遍歷字典時或相互之間存在遞歸nn.modules
時修改字典)。
def replace_bn(module, name):
'''
Recursively put desired batch norm in nn.module module.
set module = net to start code.
'''
# go through all attributes of module nn.module (e.g. network or layer) and put batch norms if present
for attr_str in dir(module):
target_attr = getattr(m, attr_str)
if type(target_attr) == torch.nn.BatchNorm2d:
print('replaced: ', name, attr_str)
new_bn = torch.nn.BatchNorm2d(target_attr.num_features, target_attr.eps, target_attr.momentum, target_attr.affine,
track_running_stats=False)
setattr(module, attr_str, new_bn)
# iterate through immediate child modules. Note, the recursion is done by our code no need to use named_modules()
for name, immediate_child_module in module.named_children():
replace_bn(immediate_child_module, name)
replace_bn(model, 'model')
關鍵是您需要遞歸地不斷更改層(主要是因為有時您會遇到本身具有模塊的屬性)。 我認為比上面更好的代碼是添加另一個 if 語句(在批處理規范之后)檢測是否必須遞歸,如果是,則遞歸。 上面的方法首先改變了外層的批處理規范(即第一個循環),然后用另一個循環確保沒有其他應該遞歸的 object 被遺漏(然后遞歸)。
原帖: https://discuss.pytorch.org/t/how-to-modify-a-pretrained-model/60509/10
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.