케라스 창시자에게 배우는 딥러닝 - 5장

Jajuna_99·2022년 10월 20일
0

5장 컴퓨터 비전을 위한 딥러닝

합성곱 신경망 소개

개인공부에 따로 정리!

소규모 데이터셋에서 밑바닥부터 컨브넷 훈련하기

강아지 사진 2000개, 고양이 사진 2000개로 구성된 데이터셋에서 강아지와 고양이 이미지를 분류하는 모델을 만든다.

2000개는 훈련용, 1000개는 테스트, 1000개는 검증용으로 사용.

어떤 규제 방법도 사용하지 않고, 과대적합을 방지할 수 있는 데이터 증식(data augmentation)을 이 모델에 사용한다.

딥러닝의 근본적인 특징은 훈련 데이터에서 특성 공학의 수작업 없이 흥미로운 특성을 찾을 수 있는 것이다. 이는 훈련 샘플이 많아야 가능하다. 특히 이미지 같은 고차원 데이터들은 특히 그렇다.

캐글에 dogs-vs-cat에서 원본 데이터셋을 받을 수 있다.

큰 데이터셋을 위에 설명한 것처럼 작게 나누는 작업은 넘어가고 컨브넷 구현부터 하자.

## 강아지 고양이 분류를 위한 소규모 컨브넷
from keras import layers
from keras import models

model = models.Sequntial()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid')) # 확률 인코딩

model.summary()

## 모델 훈련 설정 단계
from keras import optimizers

model.compile(loss='binary_crossentrophy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['acc'])

이미지(JPEG) 파일은 네트워크에 넣기 전에 전처리 과정이 필요하다. 과정은 다음과 같다.

  • 사진 파일을 읽는다.
  • JPEG 콘텐츠를 RGB 픽셀 값으로 디코딩한다.
  • 그 다음 부동 소수 타입의 텐서로 변환한다.
  • 픽셀 값(0~255사이)의 스케일을 [0,1] 사이로 조정한다. (신경망은 작은 값을 선호한다.)

keras.preprocessing.image 유틸리티 도구를 사용하면 편하다.
특히, ImageDataGenerator 클래스는 디스크에 있는 이미지 파일을 전처리된 배치 텐서로 자동으로 바꾸어 주는 파이썬 제네레이터를 만들어준다.

## 이미지 데이터 전처리
from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(resclae=1./255)
test_datagen = ImageDataGenerator(resclae=1./255)

train_generator = train_datagen.flow_from_directoty(
  train_dir,
  target_size=(150, 150),
  batch_size=20,
  class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
  validation_dir,
  target_size=(150, 150),
  batch_size=20,
  class_mode='binary')

generator에 관한 내용은 p.190에 있다.

데이터 전처리도 했고, 훈련 세팅도 했으니 훈련만 하면 되겠다.

## 훈련
history = model.fit_generator(
  train_generator,
  steps_per_epoch=100,
  epochs=30,
  validation_data=validation_generator,
  validation_steps=50
)

## 모델 저장
model.save('cats_and_dogs_small_1.h5')

특이한 점은 제네레이터를 사용해서 훈련을 했다는 점이다.

fit_generator 클래스와 매개변수에 대한 설명은 (p.191)에 있다.

모델 저장하는 것이 항상 좋은 습관이라고 한다.

이어서 정확도와 손실률을 그래프로 나타내 보자.

# 훈련 정확도, 손실 그래프 그리기
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epoch = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

정확도와 손실을 확인했다면 아까 언급했던 데이터 증식을 사용해보자.

## 데이터 증식 설정
datagen = ImageDataGenerator(
  rotation_range=20,
  width_shift_range=0.1,
  height_shift_range=0.1,
  shear_range=0.1,
  zoom_range=0.1,
  horizontal_flip=True,
  fill_mode='nearest'
)

책에서는 위와 같은 방법으로 (imagedatagenerator 클래스를 사용해) 데이터를 증식하고, 다시 전처리하고 훈련 시키고 저장했다.

사전 훈련된 컨브넷 사용하기

이 장에서는 사전 훈련된 네트워크와 그 가중치를 사용해서 모델을 학습시키는 방법이다.

사전 훈련된 네트워크를 사용하는 두 가지 방법이 있는데, 특성 추출미세 조정이다.

특성 추출(feature extraction)

사전에 학습된 네트워크의 표현을 사용하여 새로운 샘플에서 흥미로운 특성을 뽑아내는 것이다.
이런 특성을 사용하여 새로운 분류기를 처음부터 훈련한다.

컨브넷의 경우 특성 추출은 사전에 훈련된 네트워크의 합성곱 기반 층을 선택하여 새로운 데이터를 통과시키고, 그 출력으로 새로운 분류기를 훈련한다.

합성곱 기반 층(convolutional base) : 합성곱과 풀링 층 부분, 완전 연결 분류기와 구별하기 위해 나눴다.

컨브넷의 특성 맵은 사진에 대한 일반적인 콘셉트 존재 여부를 기록한 맵이기 때문에 완전 연결 층보다 합성곱 층이 더 일반적으로 여러 문제에 적용하기에 적합하다.

그리고 분류기에서 학습한 표현은 모델이 훈련된 클래스 집합에 특화되었다. -> 분류기는 전체 사진에 어떤 클래스가 존재할 확률에 관한 정보만 담고 있다.

그리고 합성곱 층에서 추출한 표현의 일반성 수준은 모델에 있는 층의 깊이에 달려 있다.

모델의 하위 층은 (에지, 색깔, 질감 등) 지역적이고 일반적인 특징 맵을 추출하는 반면, 상위 층은 (강아지 눈, 고양이 귀 등) 좀 더 추상적인 개념을 추출한다.

그럼 다른 데이터셋에 적용하려먼 네트워크의 하위 층 명개만 특성 추출에 사용하는 것이 좋다.

이를 위해 동결(freezing) 기법을 사용해서 상위 계층은 가중치가 업데이트 되는 것을 막는다. trainable 속성을 False로 설정해서 동결할 수 있다.

미세 조정(fine tuning)

특성 추출에 사용했던 동결 모델의 상위 층 몇 개를 동결에서 해제하고 모델에 새로 추가한 층(완전 연결 분류기)과 함께 훈련하는 것을 미세 조정 기법이라 한다.

주어진 문제에 조금 더 밀접하게 재사용 모델의 표현을 일부 조정하기 때문에 미세 조정이라고 한다.

주의할 점으로 분류기가 미리 훈련되지 않으면 훈련되는 동안 너무 큰 오차 신호가 네트워크에 전파되어 미세 조정될 층들이 사전에 학습한 표현들을 망가뜨리게 된다.

미세 조정 단계

  • 사전에 훈련된 기반 네트워크 위에 새로운 네트워크를 추가
  • 기반 네트워크를 동결
  • 새로 추가한 네트워크 훈련
  • 기반 네트워크에서 일부 층 동결 해제
  • 동결 해제 층과 새로 추가한 층 함께 훈련

미리 훈련 시키고 훈련시키면 된다.

사전 훈련 컨브넷 구현은 크게 바뀌는 것이 없으니 책을 참고하자...

컨브넷 학습 시각화

이 파트에서는 컨븐젯에서 가장 사용이 편하고 유용한 세 가지 기법을 알아본다.

컨트넷 중간층의 출력(중간층에 있는 활성화)을 시각화하기
연속된 컨브넷 층이 입력을 어떻게 변형시키는지 이해하고 개별적인 컨브넷 필터의 의미를 파악하는 데 도움이 된다.

중간층 활성화 시각화란 어떤 입력이 주어졌을 때 네트워크에 있는 여러 합성곱과 풀링 층이 출력하는 특성 맵을 그리는 것이다. (출력을 활성화라고도 한다.)

이를 통해 학습된 필터들이 어떻게 입력을 분해하는지 보여준다.

케라스의 model 클래스를 사용해 이미지 배치를 입력으로 받아 모든 합성곱과 풀링 층의 활성화를 출력하는 케라스 모델을 만든다.

#데이터 시각화
##중간층의 활성화 시각화
from keras import models

layer_outputs = [layer.output for layer in model.layers[:8]]  # 하위 8개 층의 출력을 추출한다.
activation_model = models.Model(inputs=model.input, outputs=layer=outputs)  #입력에 대해 8개 층의 출력을 반환하는 모델을 만든다.
activations = activation_model.predict(img_tenser)  # 층의 활성화마다 하나씩 8개의 넘파이 배열로 이루어진 리스트를 반환한다.

plt.matshow(first_layer_activation[0, :, :, 19], cmap='viridis') # 첫 번째 층 활성화 중에서 20번째 채널 그리기
plt.matshow(first_layer_activation[0, :, :, 15], cmap='viridis') # 16번째 채널, 사진을 보면서 어떻게 인코딩 됐는지 볼 수 있다.

# 그래프 제목을 층의 이름으로
layer_name = []
for layer in model.layers[:8]:
  layer_names.append(layer.name)

images_per_row = 16

for layer_name, layer_activation in zip(layer_names, activations):
  n_features = layer_activation.shape[-1]

  size = layer_activation.shape[-1]  # 특성 맵의 크기는 (1, size, size, n_features)입니다

  # 활성화 채널을 위한 그리드 크기를 구합니다
  n_cols = n_features // images_per_row
  display_grid = np.zeros((size * n_cols, images_per_row * size))

  # 각 활성화를 하나의 큰 그리드에 채웁니다
  for col in range(n_cols):
    for row in range(images_per_row):
      channel_image = layer_activation[0, :, :, col * images_per_row + row]
      # 그래프로 나타내기 좋게 특성을 처리합니다
      channel_image -= channel_image.mean()
      channel_image /= channel_image.std()
      channel_image *= 64
      channel_image += 128
      channel_image = np.clip(channel_image, 0, 255).astype('uint8')
      display_grid[col * size : (col + 1) * size, row * size : (row + 1) * size] = channel_image

  # 그리드를 출력합니다
  scale = 1. / size
  plt.figure(figsize=(scale * display_grid.shape[1],
                        scale * display_grid.shape[0]))
  plt.title(layer_name)
  plt.grid(False)
  plt.imshow(display_grid, aspect='auto', cmap='viridis')

plt.show()

컨브넷 필터를 시각화하기
컨브넷의 필터가 찾으려는 시각적인 패턴과 개념이 무엇인지 상세하게 이해하는 데 도움이 됩니다.

빈 입력 이미지에서 시작해서 특정 필터의 응답을 최대화하기 위해 컨브넷 입력 이미지에 경사 상승법을 적용해서 필터가 반응하는 시각적 패턴을 그려본다.

결과적으로 입력 이미지는 선택된 필터가 최대로 응답하는 이미지가 된다.

자세한 설명은 (p.235)

for layer_name in ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1']:
    size = 64
    margin = 5

    # 결과를 담을 빈 (검은) 이미지
    results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3), dtype='uint8')

    for i in range(8):  # results 그리드의 행을 반복합니다
        for j in range(8):  # results 그리드의 열을 반복합니다
            # layer_name에 있는 i + (j * 8)번째 필터에 대한 패턴 생성합니다
            filter_img = generate_pattern(layer_name, i + (j * 8), size=size)

            # results 그리드의 (i, j) 번째 위치에 저장합니다
            horizontal_start = i * size + i * margin
            horizontal_end = horizontal_start + size
            vertical_start = j * size + j * margin
            vertical_end = vertical_start + size
            results[horizontal_start: horizontal_end, vertical_start: vertical_end, :] = filter_img

    # results 그리드를 그립니다
    plt.figure(figsize=(20, 20))
    plt.imshow(results)

클르스 활성화에 대한 히트맵(heatmap)을 이미지에 시각화하기
이미지의 어느 부분이 주어진 클래스에 속하는 데 기여했는지 이해하고 이미지에서 객체 위치를 추정(localization)하는데 도움이 된다.

히트맵을 시각화하면 이미지의 어느 부분이 컨브넷의 최종 분류 결정에 기여하는지 이해하는데 유용하다.

분류에 실수가 있는 경우 컨브넷의 결정 과정을 디버깅하는 데 도움이 된다.

또 이미지에 특정 물체가 있는 위치를 파악하는데 사용도 가능하다. (분할)

이 기법의 종류를 일반적으로 클래스 활성화 맵(class activation map, CAM) 시각화라고 한다.

요약

많다 많아...

profile
Learning bunch, mostly computer and language

0개의 댓글