케라스를 사용해 직접 ResNet-34를 구현해보자. 구현할 모델의 구조는 다음과 같다.
class ResidualUnit(keras.layers.Layer):
def __init__(self, filters, strides=1, activation="relu", **kwargs):
super().__init__(**kwargs)
self.activation = keras.activations.get(activation)
self.main_layers = [
DefaultConv2D(filters, strides=strides),
keras.layers.BatchNormalization(),
self.activation,
DefaultConv2D(filters),
keras.layers.BatchNormalization()]
self.skip_layers = []
if strides > 1:
self.skip_layers = [
DefaultConv2D(filters, kernel_size=1, strides=strides),
keras.layers.BatchNormalization()]
def call(self, inputs):
Z = inputs
for layer in self.main_layers:
Z = layer(Z)
skip_Z = inputs
for layer in self.skip_layers:
skip_Z = layer(skip_Z)
return self.activation(Z + skip_Z)
model = keras.models.Sequential()
model.add(DefaultConv2D(64, kernel_size=7, strides=2,
input_shape=[224, 224, 3]))
model.add(keras.layers.BatchNormalization())
model.add(keras.layers.Activation("relu"))
model.add(keras.layers.MaxPool2D(pool_size=3, strides=2, padding="SAME"))
prev_filters = 64
for filters in [64] * 3 + [128] * 4 + [256] * 6 + [512] * 3:
strides = 1 if filters == prev_filters else 2
model.add(ResidualUnit(filters, strides=strides))
prev_filters = filters
model.add(keras.layers.GlobalAvgPool2D())
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(10, activation="softmax"))
현재 만들어 본 몇 줄 안되는 코드가 ILSVRC 2015년 대회 우승 모델이다!
그러나 사실 GoogLeNet, ResNet 과 같은 표준 모델을 직접 구현할 필요가 없다.
사전 훈련된 모델을 keras.applications 패키지에서 불러오는 방식!
model = keras.applications.resnet50.ResNet50(weights="imagenet")
images_resized = tf.image.resize(images, [224, 224])
inputs = keras.applications.resnet50.preprocess_input(images_resized * 255)
Y_proba = model.predict(inputs)
이미지를 가져온 후, 이미지의 사이즈를 재조정하고 인풋을 만드는 코드이다. 인풋을 만든 후에는 간단한 예측을 수행한다!
단순한 분류 이외에도 사진에 있는 꽃이 어디에 있는지 > 회귀 문제이다.
base_model = keras.applications.xception.Xception(weights="imagenet",
include_top=False)
avg = keras.layers.GlobalAveragePooling2D()(base_model.output)
class_output = keras.layers.Dense(n_classes, activation="softmax")(avg)
loc_output = keras.layers.Dense(4)(avg)
model = keras.models.Model(inputs=base_model.input,
outputs=[class_output, loc_output])
model.compile(loss=["sparse_categorical_crossentropy", "mse"],
loss_weights=[0.8, 0.2], # 어떤 것을 중요하게 생각하느냐에 따라
optimizer=optimizer, metrics=["accuracy"])
객체 탐지 문제를 Object detection 이라 하고, 하나의 이미지에 여러 물체가 등장한다면 분류도 하고, 위치도 추정해보는 것이다.
그래서 등장한 것이 Fully convolutional network 라는 FCN!
기존 CNN과 차이가 되는 가장 핵심이 되는 아이디어는 CNN위의 밀집층을 합성곱 층으로 바꾸는 것이다!
7X7 맵 크기, 100개의 특성 맵 > 200개 뉴런의 밀집 층
7X7 맵 크기, 100개의 특성 맵 > 7X7 크기 필터 200개와 valid 패딩을 사용하는 합성곱 층 > 1 X 1 특성 맵 200개 출력
중요한 차이점은 다음과 같다.
이전 작업에서(바운딩 박스를 그리는) 나아가 픽셀 단위에서 속한 객체의 클래스를 나타내는 것을 Semantic Segmentation 이라 한다.
보통의 CNN은 점진적으로 위치 정보를 잃어(그래서 RNN이 등장했었다.) 정확도가 떨어진다.
단순한 해결책으로 여기서도 역시나 FCN을 사용한다
CNN이 이미지에 적용하는 스트라이드의 전체는 32로 최종 해상도가 너무 떨어진다
해상도를 늘리기 위해 업샘플링 층을 추가한다
전치 합성곱 층(transposed convolutional layer) 을 사용
이미지에 빈 행, 열을 삽입하여 늘린다음 합성곱을 수행하는 것.
정리하면, CNN에 2배 업샘플링, 동일한 크기의 아래층 스킵 연결, 8배 업샘플링하는 단계 추가
CV분야에서 연구, 구조를 나열하면 다음과 같다.