1 분 소요

널리 알려진 ResNet 34,50,101 등과 같은 모델을 그대로 가져와서 fine-tuning 할 수도 있지만
다른 모델 구조로 실험하고 싶거나 기타 등등의 이유로 직접 구현이 필요한 경우도 존재한다.
resnet 뒤의 34,101과 같은 숫자는 모델 안의 컨볼루션 레이어의 개수이다.
레이어의 개수가 작을 때는 3x3 컨볼루션을 두 번 사용하고 레이어의 개수가 많으면 bottleneck 구조(1x1-3x3-1x1)를 사용한다.(계산 파라미터 수 감소)
resnet의 구조에는 batch normalization의 위치나 컨볼루션 레이어의 위치 등에 따라 구조가 미세하게 다른데,
저자는 full-pre activation구조가 일반적으로 성능이 좋다고 이야기한다.
아래는 full-pre activation 구조의 tensorflow 기반 resnet 구현 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import tensorflow as tf
from tensorflow.keras.layers import *
from tensorflow.keras.models import *

def res_identity(x, filters): 
    #full pre-activation

    x_skip = x 
    f1, f2 = filters

    x = BatchNormalization()(x)
    x = ReLU()(x)
    x = Conv2D(f1, kernel_size=(3, 3), strides=(1, 1), padding='same')(x)

    x = BatchNormalization()(x)
    x = ReLU()(x)
    x = Conv2D(f2, kernel_size=(3, 3), strides=(1, 1), padding='same')(x)

    x = Add()([x, x_skip])

    return x

def res_conv(x, s, filters):
    '''
    here the input size changes''' 
    x_skip = x
    f1, f2 = filters

    # first block
    x = BatchNormalization()(x)
    x = ReLU()(x)   
    x = Conv2D(f1, kernel_size=(3, 3), strides=(s, s), padding='same')(x)
       
    x = BatchNormalization()(x)
    x = ReLU()(x)    
    x = Conv2D(f1, kernel_size=(3, 3), strides=(1, 1), padding='same')(x)
    
    x_skip = Conv2D(f2, kernel_size=(1, 1), strides=(s, s), padding='same')(x_skip)

    x = Add()([x, x_skip])

    return x

실제로 256x256x3의 이미지를 받는 간단한 분류 모델을 아래와 같이 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def resnet22():
    input_im = Input(shape=(256,256,3)) 

    x = Conv2D(16, kernel_size=(3, 3), strides=2, padding='same')(input_im)
    x = BatchNormalization()(x)
    x = ReLU()(x)    

    x = res_conv(x, s=2, filters=(16, 16))
    x = res_identity(x, filters=(16, 16))

    x = res_conv(x, s=2, filters=(32, 32))
    x = res_identity(x, filters=(32, 32))

    x = res_conv(x, s=2, filters=(64, 64))
    x = res_identity(x, filters=(64, 64))

    x = res_conv(x, s=2, filters=(128, 128))
    x = res_identity(x, filters=(128, 128))
    
    # 여기에 conv layer 추가해도 됨.

    x = Flatten()(x)
    x = Dense(128, activation='relu')(x)
    x = Dense(4, activation='softmax')(x)

    model = Model(inputs=input_im, outputs=x)

    return model
model = resnet22()

댓글남기기