https://colab.research.google.com/drive/1wTIybwm-TPa7335iLtItjKW8aLhkBEFr?usp=sharing

ResNet 50 구현 해보기

Untitled

  1. Residual Block

ResNet-50/101/152에 대해서는 Bottelneck 구조를 사용함

ResNet-50/101/152에 대해서는 Bottelneck 구조를 사용함

# 필요한것을 import
from tensorflow.keras import Model
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, Add, Dense, MaxPooling2D, AveragePooling2D, Flatten, ZeroPadding2D
# resnet의 핵심인 residual block을 구성한다.
# input_data, ouput feature map의 수, layer 이름을 parameter로 받는다
def residual_block(input_tensor, num_filters, naming):
    x = Conv2D(kernel_size = (1, 1), filters = num_filters//4, kernel_initializer = 'he_normal', name=naming + '_a')(input_tensor)
    x = BatchNormalization(name = naming + '_BN' +  '_a')(x)
    x = Activation('relu')(x)

    x = Conv2D(kernel_size = (3, 3), filters = num_filters//4, kernel_initializer = 'he_normal', padding='same', name=naming + '_b')(x)
    x = BatchNormalization(name = naming + '_BN' +  '_b')(x)
    x = Activation('relu')(x)

    x = Conv2D(kernel_size = (1, 1), filters = num_filters, kernel_initializer = 'he_normal', name=naming + '_c')(x)
    x = BatchNormalization(name = naming + '_BN' +  '_c')(x)

    # input의 크기를 맞춰주기 위해
    x_ = Conv2D(kernel_size= (1, 1), filters = num_filters)(input_tensor)
    x_ = BatchNormalization()(x_)

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

    x = Activation('relu')(x)

    return x
  1. 모델 구현
# 예측하려는 class의 개수를 받음
class MyResNet50(Model):
  def __init__(self, num_classes):
    super(MyResNet50, self).__init__()
    self.num_cnn_list=[3,4,6,3]
    self.channel_list=[256, 512, 1024, 2048]
    self._num_classes = num_classes

  def call(self, input_data):
    x = ZeroPadding2D(padding= (3, 3))(input_data)
    
    # conv1
    x = Conv2D(filters=64, kernel_size = (7,7), strides = 2, name='conv1')(x)
    x = BatchNormalization(name='conv1_BN')(x)

    # conv2
    x = ZeroPadding2D(padding= (1, 1))(x)
    x = MaxPooling2D(pool_size = (2,2), strides = 2, name='conv2_maxpool')(x)
    
    for i in range(3):
      x = residual_block(x, 256, 'conv2')

    # conv3
    for i in range(4):
      x = residual_block(x, 512, 'conv3')

    # conv4
    for i in range(6):
      x = residual_block(x, 1024, 'conv4')

    # conv5
    for i in range(3):
      x = residual_block(x, 2048, 'conv5')

    # last
    x = AveragePooling2D(padding = 'same', name='AvgPool')(x) # avg pooling 하고
    x = Flatten(name='flatten')(x)                            # flatten 하고
    x = Dense(self._num_classes, activation='softmax', name='fc')(x)        # Fully connected

    return x
  1. 데이터 처리
from tensorflow.keras.preprocessing.image import ImageDataGenerator
data_dir = './101_ObjectCategories'

# 이미지 데이터를 위한 이미지 제너레이터 생성
image_generator = ImageDataGenerator(rescale=1./255,      # 픽셀 값을 0~1사이로 조정
                                     validation_split=0.2 # 검증 데이터셋을 자동으로 준비
                                     )

# 학습 데이터셋 및 검증 데이터셋 로드

# flow_from_directory 메서드를 사용하여 데이터셋을 배치로 생성하고 클래스 레이블을 원-핫 인코딩된 벡터 형태로 반환
# flow_from_directory()는 인자로 전달해줌 directory의 하위 디렉토리 이름들을 레이블이라 간주.
# 레이블이라고 간주한 디렉토리 아래의 파일들을 해당 레이블의 이미지들이라고 알아서 추측하여 numpy array iterator 생성
train_generator = image_generator.flow_from_directory(
    data_dir,
    target_size=(224, 224),# 추후에 설계할 모델에 들어갈 input 이미지 사이즈를 (224, 224) 로 설정
    batch_size=256,       # 배치 사이즈
    class_mode='categorical', # multi-label 인데 one-hot, 'spars'로하면 멀티-레이블인데 레이블 인코딩
    subset='training'
)

validation_generator = image_generator.flow_from_directory(
    data_dir,
    target_size=(224, 224),
    batch_size=32,
    class_mode='categorical',
    subset='validation'
)
  1. 학습
model = MyResNet50(train_generator.num_classes)

# optimzier, loss_function 등을 설정해준다.
model.compile(optimizer = 'sgd', loss = 'categorical_crossentropy', metrics=['accuracy'])

# 모델을 실제 학습한다.
model.fit(train_generator, epochs=10, validation_data=validation_generator)