Как изменить уровень активации в предварительно обученном модуле Pytorch?

Как изменить уровень активации предварительно обученной сети Pytorch? Вот мой код:

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)

Вот мой результат:

All modules
ReLU(inplace=True)
Before changing activation
ReLU(inplace=True)
SELU()
after changing activation
ReLU(inplace=True)

person Hamdard    schedule 09.10.2019    source источник
comment
вы должны проверить это, чтобы получить более общее решение, которое работает для любого уровня: Discussion.pytorch.org/t/how-to-modify-a-pretrained-model/60509/   -  person Charlie Parker    schedule 01.10.2020
comment
Отвечает ли это на ваш вопрос? Как удалить последний FC слой из модели ResNet в PyTorch?   -  person iacob    schedule 14.04.2021


Ответы (4)


Я предполагаю, что вы используете интерфейс модуля 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(
person zihaozhihao    schedule 09.10.2019
comment
Распечатайте архитектуру сети, в моем случае не сработало. - person Hamdard; 20.10.2019

._modules решает проблему для меня.

for name,child in net.named_children():
    if isinstance(child,nn.ReLU) or isinstance(child,nn.SELU):
        net._modules['relu'] = nn.SELU()
person Hamdard    schedule 09.10.2019

вот общая функция для замены любого слоя

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 осуществляется доступ к различным типам слоев / модулей.

person Ankur Singh    schedule 27.05.2021

Я предложу более общее решение, которое работает для любого уровня (и избегает других проблем, таких как изменение словаря при его циклическом просмотре или когда есть рекурсивные 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 (после нормы партии), определяющего, нужно ли вам рекурсировать и рекурсивно, если это так. Вышеупомянутое работает, но сначала меняет пакетную норму на внешнем слое (то есть в первом цикле), а затем с другим циклом, чтобы убедиться, что никакой другой объект, который должен быть повторен, не пропущен (а затем повторяется).

Исходное сообщение: https://discuss.pytorch.org/t/how-to-modify-a-pretrained-model/60509/10

кредиты: https://discuss.pytorch.org/t/replacing-convs-modules-with-custom-convs-then-notimplementederror/17736/3?u=brando_miranda

person Charlie Parker    schedule 01.10.2020