인공지능을 좋아하는 곧미남

Python 내장함수 setattr()와 getattr() 본문

code_study/python 내장함수

Python 내장함수 setattr()와 getattr()

곧미남 2022. 1. 13. 11:28

python 문법 중 setattr()와 getattr()에 관해 알아보겠습니다.

 

우선 setattr()와 getattr()는 "__builtin__" module에 포함된 function이며 python의 내장함수이다.

 

오늘의 내용은 setattr()와 getattr()를 이용한 Deep Learning model layer를 구성하는 방법을 간략히 설명하겠습니다.

 

오늘의 내용은 아래의 목차와 같습니다.

 

< INDEX >

1. setattr()의 사용법 및 역할

 

2. getattr()의 사용법 및 역할

 

3. DNN Layer 구성 코드 설명


1. setattr(object, name, value)의 사용법 및 역할

     - object에 존재하는 속성의 값을 바꾸거나, 새로운 속성을 생성하여 값을 부여할수있습니다.

       1) 새로운 속성 생성하고 값 부여

       2) 속성의 값 변경

       * 코드 예제는 아래에서 설명하겠습니다.


2. getattr(name)의 사용법 및 역할

     - Getattr 은 instance 에 object name에 해당하는 변수의 값을 가져옵니다.

       * 코드 예제는 아래에서 설명하겠습니다.


3. DNN Layer 구성 코드 설명

- Multi Layer의 parameters Dictionary -

convlstm_encoder_params = [
    [
        OrderedDict({'conv1_leaky_1': [1, 16, 3, 1, 1]}),
        OrderedDict({'conv2_leaky_1': [64, 64, 3, 2, 1]}),
        OrderedDict({'conv3_leaky_1': [96, 96, 3, 2, 1]}),
    ],

    [
        CLSTM_cell(shape=(64,64), input_channels=16, filter_size=5, num_features=64),
        CLSTM_cell(shape=(32,32), input_channels=64, filter_size=5, num_features=96),
        CLSTM_cell(shape=(16,16), input_channels=96, filter_size=5, num_features=96)
    ]
]

convlstm_decoder_params = [
    [
        OrderedDict({'deconv1_leaky_1': [96, 96, 4, 2, 1]}),
        OrderedDict({'deconv2_leaky_1': [96, 96, 4, 2, 1]}),
        OrderedDict({
            'conv3_leaky_1': [64, 16, 3, 1, 1],
            'conv4_leaky_1': [16, 1, 1, 1, 0]
        }),
    ],

    [
        CLSTM_cell(shape=(16,16), input_channels=96, filter_size=5, num_features=96),
        CLSTM_cell(shape=(32,32), input_channels=96, filter_size=5, num_features=96),
        CLSTM_cell(shape=(64,64), input_channels=96, filter_size=5, num_features=64),
    ]
]

- setattr(), getattr() 사용 -

class Encoder(nn.Module):
    def __init__(self, subnets, rnns):
        super().__init__()
        assert len(subnets) == len(rnns)
        self.blocks = len(subnets)

        for index, (params, rnn) in enumerate(zip(subnets, rnns), 1):
            # index sign from 1
            setattr(self, 'stage' + str(index), make_layers(params))
            setattr(self, 'rnn' + str(index), rnn)

    def forward_by_stage(self, inputs, subnet, rnn):
        seq_number, batch_size, input_channel, height, width = inputs.size()
        inputs = torch.reshape(inputs, (-1, input_channel, height, width))
        inputs = subnet(inputs)
        inputs = torch.reshape(inputs, (seq_number, batch_size, inputs.size(1),
                                        inputs.size(2), inputs.size(3)))
        outputs_stage, state_stage = rnn(inputs, None)
        return outputs_stage, state_stage

    def forward(self, inputs):
        inputs = inputs.transpose(0, 1)  # to S,B,1,64,64
        hidden_states = []
        logging.debug(inputs.size())
        for i in range(1, self.blocks + 1):
            inputs, state_stage = self.forward_by_stage(
                inputs, getattr(self, 'stage' + str(i)),
                getattr(self, 'rnn' + str(i)))
            hidden_states.append(state_stage)
        return tuple(hidden_states)

     - setattr(self, 'stage' + str(index), make_layers(params)) -> setattr()를 이용한 Conv Layer Object 생성
     - setattr(self, 'rnn' + str(index), rnn) -> setattr()를 이용한 RNN Layer Object 생성

     - getattr(self, 'stage' + str(i)) -> 위에서 생성한 stage(i)의 make_layers(params)에 의해 생성된 value(layer)을 불러옴
     - getattr(self, 'rnn' + str(i))) -> 위에서 생성한 rnn(i)의 make_layers(params)에 의해 생성된 value(layer)을 불러옴

 

Instance 에 str 이란 변수명이 있으면 rnn 을 거기에 대입하는 거고

     - 

- Parameters 받아서 nn.Sequential Layer 구성 -

def make_layers(block):
    layers = []
    for layer_name, v in block.items():
        if 'pool' in layer_name:
            layer = nn.MaxPool2d(kernel_size=v[0], stride=v[1], padding=v[2])
            layers.append((layer_name, layer))
        elif 'deconv' in layer_name:
            transposeConv2d = nn.ConvTranspose2d(in_channels=v[0],
                                                 out_channels=v[1],
                                                 kernel_size=v[2],
                                                 stride=v[3],
                                                 padding=v[4])
            layers.append((layer_name, transposeConv2d))
            if 'relu' in layer_name:
                layers.append(('relu_' + layer_name, nn.ReLU(inplace=True)))
            elif 'leaky' in layer_name:
                layers.append(('leaky_' + layer_name,
                               nn.LeakyReLU(negative_slope=0.2, inplace=True)))
        elif 'conv' in layer_name:
            conv2d = nn.Conv2d(in_channels=v[0],
                               out_channels=v[1],
                               kernel_size=v[2],
                               stride=v[3],
                               padding=v[4])
            layers.append((layer_name, conv2d))
            if 'relu' in layer_name:
                layers.append(('relu_' + layer_name, nn.ReLU(inplace=True)))
            elif 'leaky' in layer_name:
                layers.append(('leaky_' + layer_name,
                               nn.LeakyReLU(negative_slope=0.2, inplace=True)))
        else:
            raise NotImplementedError
    return nn.Sequential(OrderedDict(layers))

 

Comments