11 분 소요

본 글은 [케라스 창시자에게 배우는 딥러닝] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다.
전체 코드는 https://github.com/ingu627/deep-learning-with-python-notebooks에 기재했습니다.(원본 코드 fork)
뿐만 아니라 책에서 설명이 부족하거나 이해가 안 되는 것들은 외부 자료들을 토대로 메꿔 놓았습니다. 즉, 딥러닝은 이걸로 끝을 내보는 겁니다.
오타나 오류는 알려주시길 바라며, 도움이 되길 바랍니다.


5_1. 합성곱 신경망 소개

  • 일반 DNN은 기본적으로 1차원 형태의 데이터를 사용한다. 때문에 이미지가 입력값이 되는 경우, 이것을 flatten시켜서 한줄 데이터로 만들어야 하는데 이 과정에서 이미지의 공간적/지역적 정보(spatial/topological information)가 손실된다.
  • 추상화과정 없이 바로 연산과정으로 넘어가 버리기 때문에 학습시간과 능률의 효율성이 저하된다.
  • CNN은 이미지를 날것(raw input) 그대로 받음으로써 공간적/지역적 정보를 유지한 채 특성(feature)들의 계층을 빌드업한다.
  • CNN의 중요 포인트는 이미지 전체보다는 부분을 보는 것, 그리고 이미지의 한 픽셀과 주변 픽셀들의 연관성을 살리는 것이다.

image


image

  • 합성곱 신경망은 크게 합성곱층 (Convolution layer)풀링층 (Pooling layer)으로 구성


image

  • CONV는 합성곱 연산을 의미하고, 합성곱 연산의 결과가 활성화 함수 ReLU를 지난다. 이 두 과정을 합성곱층이라고 한다. 그 후에 POOL이라는 구간을 지나는데 이는 풀링 연산을 의미하며 풀링층이라고 한다.

image


image

  • Conv2DMaxPooling2D층의 출력은 (height, width, channels) 크기의 3D 텐서이다.
    • 높이와 너비 차원은 네트워크가 깊어질수록 작아지는 경향이 있다.
    • 채널의 수는 Conv2D 층에 전달된 첫 번째 매개변수에 의해 조절된다.(32개 또는 64개)

image

  • 위와 같이 결과는 변환 전에 가지고 있던 공간적인 구조(spatial structure) 정보가 유실된 상태이다.
    • 여기서 공간적인 구조 정보라는 것은 거리가 가까운 어떤 픽셀들끼리는 어떤 연관이 있고, 어떤 픽셀들끼리는 값이 비슷하거나 등을 포함하고 있다.
  • 결국 이미지의 공간적인 구조 정보를 보존하면서 학습할 수 있는 방법이 필요해졌고, 이를 위해 사용하는 것이 합성곱 신경망이다.

image

  • CNN - activation - Pooling 과정을 통해 이미지 부분 부분의 주요한 Feature 들을 추출한다.


5_1_1. 합성곱 연산

  • Dense층은 입력 특성 공간에 있는 전역 패턴을 학습한다.
  • 합성곱층은 입력 특성 공간에 있는 지역 패턴을 학습한다.
    • 이미지일 경우 작은 2D 윈도우(window)로 입력에서 패턴을 찾는다.
    • 이미지는 에지(edge), 질감(texture) 등 지역 패턴으로 분해될 수 있다.


특징

  1. 학습된 패턴은 평행 이동 불변성을 가진다.
    • 컨브넷이 이미지의 오른쪽 아래 모서리에서 어떤 패턴을 학습했다면 다른 곳에서도 이 패턴을 인식할 수 있다.
    • (완전 연결 네트워크는 새로운 위치에 나타난 것은 새로운 패턴으로 학습해야 한다.)
    • 적은 수의 훈련 샘플을 사용해서 일반화 능력을 가진 표현을 학습할 수 있다.
  2. 컨브넷패턴의 공간적 계층 구조를 학습할 수 있다.
    • 첫 번째 합성곱 층이 에지 같은 작은 지역 패턴을 학습한다.
    • 두 번째 합성곱 층은 첫 번째 층의 특성으로 구성된 더 큰 패턴을 학습한다.
    • 이런 방식을 사용하여 컨브넷은 매우 복잡하고 추상적인 시각적 개념을 효과적으로 학습할 수 있다.


image

image

  • 합성곱 연산은 특성 맵(feature map)이라고 부르는 3D 텐서에 적용된다.
    • 이 텐서는 2개의 공간(높이와 너비)과 깊이 축(=채널)으로 구성된다.
    • RGB 이미지는 3개의 컬러채널을 가지므로 깊이 축의 차원이 3이 된다.
    • 흑백 이미지는 깊이 축의 차원이 1.
  • 합성곱 연산은 입력 특성 맵에서 작은 패치들을 추출하고 이런 모든 패치에 같은 변환을 적용하여 출력 특성 맵을 만든다.

image

  • 특성 맵 : 입력으로부터 커널을 사용하여 합성곱 연산을 통해 나온 결과


  • 필터 (filter) : 입력 데이터의 어떤 특성을 인코딩한다.
    • 필터 하나의 크기는 (patch_height, patch_width, input_depth)이다.
    • ex. (26, 26, 32) 크기의 특성 맵은 32개의 출력 채널 각각은 26 x 26 크기의 배열 값을 가진다.
    • 입력에 대해 32개의 필터를 적용 (Conv2D의 첫 번째 매개변수(필터 또는 채널 수)가 추력 특성 맵의 깊이 차원을 결정)

image


2개의 파라미터 정의

  1. 입력으로부터 뽑아낼 패치의 크기 : 전형적으로 3x3 또는 5x5 크기를 사용한다.
  2. 특성 맵의 출력 깊이 : 합성곱으로 계산할 필터의 수
  • 특성맵 (feature map) : 입력으로부터 커널을 사용하여 합성곱 연산을 통해 나온 결과

  • 케라스의 Conv2D 층에서 이 파라미터는 Conv2D(output_depth, (window_height, window_width)) 처럼 첫 번째와 두 번째 매개변수로 전달된다.
  • 3D 특성 맵 위를 3x3 또는 5x5 크기의 윈도우가 슬라이딩(sliding)하면서 모든 위치에서 3D 특성 패치를 추출하는 방식으로 합성곱이 작동한다.
  • 패딩 (padding) : 입력 특성 맵의 가장자리에 적절한 개수의 행과 열을 추가
    • 합성곱 연산 이후에도 특성 맵의 크기가 입력의 크기와 동일하게 유지되도록 하고 싶을 때 패딩을 쓴다.

image

  • 스트라이드 (stride) : 필터를 적용하는 위치의 간격 (이동 범위)

image


5_1_2. 최대 풀링 연산

  • 최대 풀링의 역할 : 강제적으로 특성 맵을 다운샘플링하는 것
    • 다운샘플링을 하는 이유는 처리할 특성 맵의 가중치 개수를 줄이기 위해서
  • 최대 풀링 (Max pooling) : 입력 특성 맵에서 윈도우에 맞는 패치를 추출하고 각 채널별로 최댓값을 출력한다.
  • CNN에서는 padding을 이용해서 사이즈를 보존해주되, 동시에 사이즈를 점점 줄어나가는 것이 중요하다.


image


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

  • os.mkdir() : 해당 주소에 폴더를 만든다.
  • shutil.rmtree : 재귀적으로 폴더를 지운다. (존재하면)


  • os.path.join : str들을 붙여준다.
  • shutil.copyfile(src, dst) : 파일을 src에서 dst로 복사한다.



5_2_3. 네트워크 구성하기

  • Conv2DMaxPooling2D층을 번갈아 쌓은 컨브넷을 만든다.
  • Conv2DMaxPooling2D 단계를 하나 더 추가하면 네트워크의 용량을 늘리고 Flatten 층의 크기가 너무 커지지 않도록 특성 맵의 크기를 줄일 수 있다.
  • 150x150 크기(임의로 선택)의 입력으로 시작해서 Flatten 층 이전에 7x7 크기의 특성 맵으로 줄어든다.
  • 특성 맵의 깊이는 네트워크에서 점진적으로 증가하지만(32에서 128까지), 특성 맵의 크기는 감소한다.(150x150에서 7x7)


강아지 vs 고양이 분류를 위한 소규모 컨브넷 만들기

image


컨브넷 코드 파헤치기

cnn1

cnn2

  1. model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape=(150,150,3))) -> (None, 148, 148, 32), param : 896
    • Convolution : 이미지에 kernel이나 필터를 적용하는 과정
    • input_shape=(150, 150 ,3): image_height=150, image_width=150, 그리고 color_channels 는 3을 의미
    • activation='relu': relu 는 (Rectified Linear Unit의 약자). 보통 활성화 함수로 쓰이고, input값이 0이하이면 0으로 나타내고, input값이 양수이면 input값을 그대로 나타낸다.
      • 비선형 문제를 해결하기 위해.
    • 인풋값(150,150)이 no-padding을 통해 (148,148)로 줄어들었다.
    • (3,3): kernel이 3x3 격자무늬
    • 32 : kernel 필터의 개수 (feature map이라고도 불리는 convolution 채널을 총 32개 가지게 된다.)
    • Param의 의미 : R, G, B각각에 3x3 픽셀 kernel을 적용시켰는데, 3x3x3=27개의 픽셀과, bias kernel을 하나 가진다. 따라서 (27+1)x32=896
      • parameter 수 : (노드의 수) * (input의 차원) + (노드의 수)
  2. model.add(layers.MaxPooling2D((2,2))) -> (None,74,74,32)
    • MaxPooling : convoluted 이미지의 최댓값을 줄이는 것(=downsampling)
      • 2X2 kernel을 활용해 최댓값을 뽑는 작업
      • feature 개수는 그대로 32개. 이미지의 크기는 반으로 된다.
  3. model.add(layers.Conv2D(64, (3,3), activation='relu')) -> (None,72,72,64), param : 18496
    • MaxPooling을 적용한 74x74 feature map은 convoltion 필터를 통과하며 가장자리가 삭제되어 72x72으로 크기가 줄어든다.
    • convolution layer는 3x3픽셀로 구성된 kernel을 64개 갖는다.
    • Param의 의미 : 필터의 사이즈가 3x3이고 개수는 32개 -> (3332+1)*64=18496
    • 이 과정을 반복
  4. model.add(layers.Flatten())
    model.add(layers.Dense(512, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    • 분류하기 위해 dense layer가 필요. 이 레이어는 1차원 벡터를 갖기 때문에, 앞의 convolutional 레이어의 output을 조개야 한다. (=layers.Flatten())
    • 고양이와 강아지를 분류하기 때문에 sigmoid 함수 사용


모델의 훈련 선택


5_2_4. 데이터 전처리

  • JPEG 데이터가 네트워크에 주입하는 과정
    1. 사진 파일을 읽는다.
    2. JPEG 콘텐츠를 RGB 픽세 값으로 디코딩한다.
    3. 그다음 부동 소수 타입의 센서로 변환한다.
    4. 픽셀 값의 스케일을 [0,1] 사이로 조정한다. (신경망은 작은 입력 값을 선호한다.)

-> keras.preprocessing.image가 이런 단계를 자동으로 처리해준다.

  • ImageDataGenerator 클래스는 디크스에 있는 이미지 파일을 전처리된 배치 텐처로 자동으로 바꾸어 주는 파이썬 제너레이터(generator)를 만들어 준다.
    • 파이썬 제너레이터(generator) : 특수한 반복자이며 yield 문을 사용하여 만든 경우를 제너레이터 함수, 소괄호와 리스트 내포 구문을 사용하는 경우를 제너레이터 표현식이라고 한다.


ImageDataGenerator

  • ImageDataGenerator : 이미지를 학습시킬 때 학습데이터의 양이 적을 경우 학습데이터를 조금씩 변형시켜서 학습데이터의 양을 늘리는 방식중에 하나이다.
    • ImageDataGenerator() - 객체 생성
  • flow_from_directory() 메서드는 서브 디렉터리의 순서대로 레이블을 할당한다.
    • datagen 이라는 틀에 flow 함수를 사용해서 실제 데이터를 파라미터를 넣어주면 이미지 변형이 완료된다.
  • target_size : 이미지 사이즈
  • batch_size : 배치사이즈
  • class_mode : Y 값 변화방법 ex) ‘categorical’
  • color_mode : 이미지 채널 수 ex) ‘rgb’
  • shuffle : 랜덤 여부


제너레이터를 사용한 데이터에 모델을 훈련시키기

  • fit_generator 메서드는 fit 메서드와 동일하되 데이터 제너레이터를 사용할 수 있다.
  • 이 메서드는 첫 번째 매개변수로 입력과 타깃의 배치를 끝없이 반환하는 파이썬 제너레이터를 기대한다.
  • 데이터가 끝없이 생성되기 때문에 케라스 모델에 하나의 에포크를 정의하기 위해 제너레이터로부터 얼마나 많은 샘플을 뽑을 것인지 알려주어야 한다.
    • steps_per_epoch 매개변수에서 이를 설정한다.
  • 제러네이터부터 steps_per_epoch개의 배치만큼 뽑은 후, 즉 steps_per_epoch 횟수만큼 경사 하강법 단계를 실행한 후에 훈련 프로세스는 다음 에포크로 넘어간다.
  • validation_data로 제너레이터를 전달하면 검증 데이터의 배치를 끝없이 반환한다.
  • 따라서 검증 데이터 제너레이터에서 얼마나 많은 배치를 추추하여 평가할지 validation_steps 매개변수에 지정해야 한다.
  • 훈련이 끝나면 항상 모델을 저장하는 것이 좋다.

image


내용 정리

  • 비교적 훈련 샘플의 수(2000개)가 적기 때문에 과대적합이 가장 중요한 문제이다.
  • 드롭아웃이나 가중치 감소(L2 규제)처럼 과대적합을 감소시킬 수 있는 방법들이 있다.
  • 다음에서는 데이터 증식을 시도해 본다.


5_2_5. 데이터 증식 사용하기

  • 과대적합은 학습할 샘플이 너무 적어 새로운 데이터에 일반화할 수 있는 모델을 훈련시킬 수 없기 때문에 발생한다.
  • 데이터 증식은 기존 훈련 샘플로부터 더 많은 훈련 데이터를 생성하는 방법이다.
    • 이 방법은 그럴듯한 이미지를 생성하도록 여러 가지 랜덤한 변환을 적용하여 샘플을 늘린다.
    • 훈련할 때 모델이 정확히 같은 데이터를 두 번 만나지 않도록 하는 것이 목표이다.
    • 모델이 데이터의 여러 측면을 학습하면 일반화에 도움이 된다.
  • 케라스에서는 ImageDataGenerator가 읽은 이미지에 여러 종류의 랜덤 변환을 적용하도록 설정할 수 있다.
  • 여기까진 똑같이 해준다.


ImageDataGenerator를 사용하여 데이터 증식 설정하기

  • rotation_range : 랜덤하게 사진을 회전시킬 각도 범위 (0~180사이)
  • width_shift_range or height_shift_range : 사진을 수평과 수직으로 랜덤하게 평행 이동 시킬 범위 (전체 너비높이에 대한 비율)
  • shear_range : 랜덤하게 전단 변환(shearing transformation)을 적용할 각도 범위 (이미지 굴절)
    • 전담 변환은 rotation_range로 회전할 때 y축 방향으로 각도를 증가시켜 이미지를 변형시킨다.
  • zoom_range : 랜덤하게 사진을 확대할 범위
  • horizontal_flip : 랜덤하게 이미지를 수평으로 뒤집는다. (반전)
    • 수평 대칭을 가정할 수 있을 때 사용한다.
  • fill_mode : 회전이나 가로/세로 이동으로 인해 새롭게 생성해야 할 픽셀을 채울 전략
    • nearest는 인접한 픽셀 사용
    • constant는 cval 매개변수 값 사용
    • reflect는 wrap 사용


그외 파라미터 설정

  • rescale: 이미지의 픽셀 값을 조정
  • featurewise_center: 데이터 세트에 대해 입력 평균을 0으로 설정여부
  • samplewise_center: 각 샘플 평균을 0으로 설정 여부
  • featurewise_std_normalization: 데이터 세트의 표준으로 입력을 나눌지 여부
  • samplewise_std_normalization: 각 입력을 표준으로 나눌지 여부


랜덤하게 증식된 훈련 이미지 그리기

  • os.listdir : 경로를 가져와 리스트형식으로 불러옴
  • 파이썬에서 튜플이나 리스트 2개를 더하면 하나의 튜플로 연결된다.
  • flow() 메서드는 배치 데이터를 기대하기 때문에 샘플 데이터에 배치 차원을 추가하여 4D 텐서로 만든다.


드롭아웃을 포함한 새로운 컨브넷 정의하기

  • 적은 수의 원본 이미지는 새로운 정보를 만들어 낼 수 없고 단지 기존 정보의 재조합만 가능하다.
  • 과대적합을 더 억제하기 위해 완전 연결 분류기 직전에 Dropout 층을 추가한다.

image


데이터 증식 제너레이터를 사용하여 컨브넷 훈련하기

  • flow() 또는 flow_from_directory() 또는 flow_from_dataframe() 함수로 Numpy Array Iterator 객체를 만들어줌


모델 저장하기


데이터 증식을 사용했을 때 훈련 정확도와 검증 정확도

  • 다른 규제 기법을 더 사용하고 네트워크의 파라미터를 튜닝하면(합성곱 층의 필터 수나 네트워크 층의 수 등) 더 높은 정확도를 얻을 수 있다.

5_3. 사전 훈련된 컨브넷 사용하기

  • 작은 이미지 데이터셋에 딥러닝을 적용하는 일반적이고 매우 효과적인 방법은 사전 훈련된 네트워크를 사용하는 것이다.
  • 사전 훈련된 네트워크(pretrained network) : 대규모 이미지 분류 문제를 위해 대량의 데이터셋에서 미리 훈련되어 저장된 네트워크
  • 학습된 특성을 다른 문제에 적용할 수 있는 유연성은 딥러닝의 핵심 장점이다.
  • ImageNet 데이터셋 : 1400만 개의 레이블된 이미지와 1000개의 클래스로 이루어진 데이터셋
  • VGG16 : 간단하고 ImageNet 데이터셋에 널리 사용되는 컨브넷 구조이다.
  • 사전 훈련된 네트워크를 사용하는 두 가지 방법 : 특성 추출(feature extraction) & 미세 조정(fine tuning)

image 이미지출처: [^1]


5_3_1. 특성 추출

  • 특성 추출 (Feature extraction) : 사전에 학습된 네트워크의 표현을 사용하여 새로운 샘플에서 흥미로운 특성을 뽑아 내는 것
    • 케라스에서 지원하는 모듈: VGG16, VGG19, Inception V3, ResNet50, Xception, MobilNet
  • 이런 특성을 사용하여 새로운 분류기를 처음부터 훈련한다.


  • 컨브넷은 이미지 분류를 위해 두 부분으로 구성된다.
  • 먼저 연속된 합성곱과 풀링 층으로 시작해서 완전 연결 분류기로 끝난다.
  • 첫 번째 부분을 합성곱 기반 층이라고 부른다.
  • 컨브넷의 경우 특성 추출은 사전에 훈련된 네트워크의 합성곱 기반 층을 선택하여 새로운 데이터를 통과시키고, 그 출력으로 새로운 분류기를 훈련한다.

cnn3

  • 합성곱 층에 의해 학습된 표현이 더 일반적이어서 재사용이 가능하다.
  • 컨브넷의 특성 맵은 사진에 대한 일반적인 콘셉트의 존재 여부를 기록한 맵
  • (완전 연결 층들은 공간 개념을 제거하지만 합성곱의 특성 맵은 객체 위치를 고려한다.)
  • 특성 합성곱 층에서 추출한 표현의 일반성(그리고 재사용성) 수준은 모델에 있는 층의 깊이에 달려 있다.
    • 모델의 하위 층은 (에지, 색깔, 질감 등) 지역적이고 매우 일반적인 특성 맵을 추출한다.
    • 모델의 상위 층은 좀 더 추상적인 개념을 추출한다.


VGG16 합성곱 기반 층 만들기

  • weights : 모델을 초기화할 가중치 체크포인트를 지정
  • include_top : 네트워크의 최상위 완전 연결 분류기를 포함할지 안 할지 지정한다.
    • 기본값은 ImageNet의 클래스 1000개에 대응되는 완전 연결 분류기를 포함한다.
  • input_shape : 네트워크에 주입할 이미지 텐서의 크기
    • 이 매개변수는 선택 사항. 이 값을 지정하지 않으면 네트워크가 어떤 크기의 입력도 처리할 수 있다.

image


데이터 증식을 사용하지 않는 빠른 특성 추출


사전 훈련된 합성곱 기반 층을 사용한 특성 추출하기

  • rescale = 1./255 : 값을 0과 1 사이로 변경
  • 제너레이터는 루프 안에서 무한하게 데이터를 만들어 내므로 모든 이미지를 한 번씩 처리하고 나면 중지한다. (break)
  • 추출된 크기는 (samples, 4, 4, 512)이다. 완전 연결 분류기에 주입하기 위해서 먼저 (samples, 8192) 크기로 펼친다.


완전 연결 분류기를 정의하고 훈련하기

  • 완전 연결 분류기를 정의하고(규제를 위해 드롭아웃을 사용한다) 저장된 데이터와 레이블을 사용하여 훈련한다.


결과 그래프 그리기

image


데이터 증식을 사용한 특성 추출

  • 이 방법은 훨씬 느리고 비용이 많이 들지만 훈련하는 동안 데이터 증식 기법 을 사용할 수 있다.
  • conv_base 모델을 확장하고 입력 데이터를 사용하여 엔드-투-엔드로 실행한다.


합성곱 기반 층 위에 완전 연결 분류기 추가하기

  • 모델은 층과 동일하게 작동하므로 층을 추가하듯이 Sequential 모델에 다른 모델을 추가할 수 있다.

image

  • 모델을 컴파일하고 훈련하기 전에 합성곱 기반 층을 동결하는 것이 중요하다.
    • 동결 : 훈련하는 동안 가중치가 업데이트되지 않도록 막는다는 의미
  • 이렇게 하지 않으면 합성곱 기반 층에 의해 사전에 학습된 표현이 훈련하는 동안 수정될 것이다.
  • 맨 위의 Dense 층은 랜덤하게 초기화되었기 때문에 매우 큰 가중치 업데이트 값이 네트워크에 전파될 것이다.
  • 이는 사전에 학습된 표현을 크게 훼손한다.
  • 케라스에서는 trainable 속성을 False로 설정하여 네트워크를 동결할 수 있다.
  • 이렇게 설정하면 추가한 2개의 Dense 층 가중치만 훈련된다.
  • 층마다 2개씩 총 4개의 텐서가 훈련된다.
  • 변경 사항을 적용하려면 먼저 모델을 컴파일해야 한다.
  • 컴파일 단계 후에 trainable 속성을 변경하면 반드시 모델을 다시 컴파일해야 한다.


동결된 합성곱 기반 층과 함께 모델을 엔드-투-엔드로 훈련하기

  • GPU 사용 권장

image


5_3_2. 미세 조정

  • 미세 조정 (Fine tuning) : 특성 추출에 사용했던 동결 모델의 상위 층 몇 개를 동결에서 해제하고 모델에 새로 추가한 층(여기서는 완전 연결 분류기)과 함께 훈련하는 의미.
    • 주어진 문제에 조금 더 밀접하게 재사용 모델의 표현을 일부 조정하기 때문에 미세 조정이라고 부른다.

cnn5


네트워크를 미세 조정하는 단계

  1. 사전에 훈련된 기반 네트워크 위에 새로운 네트워쿼를 추가한다.
  2. 기반 네트워크를 동결한다.
  3. 새로 추가한 네트워크를 훈련한다.
  4. 기반 네트워크에서 일부 층의 동결을 해제한다.
  5. 동결을 해제한 층과 새로 추가한 층을 함께 훈련한다.

conv_base.summary()

image

  • 마지막 3개의 합성곱 층을 미세 조정해본다.
  • 즉, block4_pool까지 모든 층은 동결되고 block5_con1, block5_conv2, block5_conv3 층은 학습 대상이 된다.


특정 층까지 모든 층 동결하기

image


GPU 사용


모델 미세 조정하기

  • 학습률을 낮춘 RMSProp 옵티마이저를 사용한다.
  • 학습률을 낮추는 이유는 미세 조정하는 3개의 층에서 학습된 표현을 조금씩 수정하기 위해서
  • 변경량이 너무 크면 학습된 표현에 나쁜 영향을 끼칠 수 있다.

image


부드러운 그래프 그리기

  • 그래프를 보기 쉽게 하기 위해 지수 이동 평균으로 정확도와 손실 값을 부드럽게 표현할 수 있다.

image

  • 그래프는 개별적인 손실 값의 평균을 그린 것. 정확도에 영향을 미치는 것은 손실 값의 분포이지 평균이 아님을 유의.


테스트 데이터로 모델 평가

image

  • 정확도 : 약 93.6%


정리

  • 컨브넷은 컴퓨터 비전 작업에 가장 뛰어난 머신 러닝 모델이다. 아주 작은 데이터셋에서도 처음부터 훈련해서 괜찮은 성능을 낼 수 있다.
  • 작은 데이터셋에서는 과대적합이 큰 문제이다. 데이터 증식은 이미지 데이터를 다룰 때 과대적합을 막을 수 있는 강력한 방법
  • 특성 추출 방식으로 새로운 데이터셋에 기존 컨브넷을 쉽게 재사용할 수 있다.
  • 특성 추출을 보완하기 위해 미세 조정을 사용할 수 있다.


5_4. 컨브넷 학습 시각화

시각화 기법

  1. 컨브넷 중간층의 출력(중간층에 있는 활성화)을 시각화하기 : 연속된 컨브넷 층이 입력을 어떻게 변형시키는지 이해하고 개별적인 컨브넷 필터의 의미를 파악하는 데 도움이 된다.
  2. 컨브넷 필터를 시각화하기 : 컨브넷의 필터가 찾으려는 시각적인 패턴과 개념이 무엇인지 상세하게 이해하는 데 도움이 된다.
  3. 클래스 활성화에 대한 히트맵을 이미지에 시각화하기 : 이미지의 어느 부분이 주어진 클래스에 속하는 데 기여했는지 이해하고 이미지에서 객체 위치를 추정(localization)하는 데 도움이 된다.


5_4_1. 중간층의 활성화 시각화하기

  • 중간층의 활성화 시각화는 어떤 입력이 주어졌을 때 네트워크에 있는 여러 합성곱과 풀링 층이 출력하는 특성 맵을 그리는 것이다.
  • 이 방법은 네트워크에 의해 학습된 필터들이 어떻게 입력을 분해하는지 보여 준다.
  • 너비, 높이, 깊이(채널) 3개의 차원에 대해 특성 맵을 시각화하는 것이 좋다.
  • 각 채널은 비교적 독립적인 특성을 인코딩하므로 특성 맵의 각 채널 내용을 독립적인 2D 이미지로 그리는 것이 방법


모델 로드

image


개별 이미지 전처리하기


테스트 사진 출력하기

image


입력 텐서와 출력 텐서의 리스트로 모델 객체 만들기

  • 확인하고 싶은 특성 맵을 추출하기 위해 이미지 배치를 입력으로 받아 모든 합성곱과 풀링 층의 활성화를 출력하는 케라스 모델을 만든다.
  • Model 클래스로 반환되는 객체는 Sequential과 같은 케라스 모델이지만 특정 입력과 특정 출력을 매핑한다.
  • Model 클래스를 사용하면 Sequential과는 달리 여러 개의 출력을 가진 모델을 만들 수 있다.
  • 이 모델은 하나의 입력과 층의 활성화마다 하나씩 총 8개의 출력을 가진다.


예측 모드로 모델 실행하기

  • 층의 활성화마다 하나씩 8개의 넘파이 배열로 이루어진 리스트를 반환한다.


20번째 채널 시각화하기

  • 32개의 채널을 가진 148x148 크기의 특성 맵이다.
  • 이 채널은 대각선 에지를 감지하도록 인코딩되었다.

Image


16번째 채널 시각화하기

  • 이 채널은 밝은 녹색 점을 감지하는 거 같아 고양이 눈을 인코딩하기 좋다.

image


중간층의 모든 활성화에 있는 채널 시각화하기

image

  • 상위 층으로 갈수록 활성화는 점점 더 추상적으로 되고 시각적으로 이해하기 어려워 진다.
  • 비어 있는 활성화가 층이 깊어짐에 따라 늘어난다. 첫 번째 층에서는 모든 필터가 입력 이미지에 활성화되었지만 층을 올라가면서 활성화되지 않는 필터들이 생긴다.
    • 필터에 인코딩된 패턴이 입력 이미지에 나타나지 않았다는 것을 의미한다.


5_4_2. 컨브넷 필터 시각화하기

  • 컨브넷이 학습한 필터를 조사하는 또 다른 간편한 방법은 각 필터가 반응하는 시각적 패턴을 그려 보는 것이다.
  • 빈 입력 이미지에서 시작해서 특정 필터의 응답을 최대화하기 위해 컨브넷 입력 이미지에 경사 상승법을 적용한다.
  • 결과적으로 입력 이미지는 선택된 필터가 최대로 응답하는 이미지가 될 것이다.
  • 경사 상승법을 적용하여 이미지의 필터가 무엇을 인식하고 있는지 보는 것


  • 전체 과정
    1. 특정 합성곱 층의 한 필터 값을 최대화하는 손실 함수를 정의한다.
    2. 이 활성화 값을 최대화하기 위해 입력 이미지를 변경하도록 확률적 경사 상승법을 사용한다.


피터 시각화를 위한 손실 텐서 정의하기


그래이던트 정규화하기

  • 경사 하강법 과정을 부드럽게 하기 위해 사용하는 한 가지 기법은 그래디언트 텐서를 L2 노름으로 나누어 정규화하는 것.
  • 이렇게 하면 입력 이미지에 적용할 수정량의 크기를 항상 일정 범위 안에 놓을 수 있다.


입력 값에 대한 넘파이 출력 값 추출하기

  • iterate는 넘파이 텐서(크기가 1인 텐서의 리스트)를 입력으로 받아 손실과 그래디언트 2개의 넘파이 텐서를 반환한다.


확률적 경사 상승법을 사용한 손실 최대화하기

  • 이미지 텐서는 (1, 150, 150, 3) 크기의 부동 소수 텐서이다.


텐서를 이미지 형태로 변환하기 위한 유틸리티 함수

  • numpy.clip(a, a_min, a_max, out=None, **kwargs) : min ~ max 범위 이외의 값은 모두 자른다. (범위에 맞춰준다.)


필터 시각화 이미지를 만드는 함수

  • 위의 코드들을 모아서 층의 이름과 필터 번호를 입력으로 받는 함수를 만든다.

image

  • block3_conv1 층의 필터 0은 물방울 패턴에 반응했다.


층에 있는 각 필터에 반응하는 패턴 생성하기 (수정)

image

  • 에러가 났다. (이부분)

  • 컨브넷의 각 층은 필터의 조합으로 입력을 표현할 수 있는 일련의 필터를 학습한다.


5_4_3. 클래스 활성화의 히트맵 시각화하기

  • 클래스 활성화 맵(Class Activation Map, CAM) : ‘입력 이미지가 각 채널을 활성화하는 정도’에 대한 공간적인 맵을 ‘클래스에 대한 각 채널의 중요도’로 가중치를 부여하여 ‘입력 이미지가 클래스를 활성화하는 정도’에 대한 공간적인 맵을 만드는 것
    • 입력 이미지가 주어지면 합성곱 층에 있는 특성 맵의 출력을 추출한다.
    • 그다음 특성 맵의 모든 채널 출력에 채널에 대한 클래스의 그래디언트 평균을 곱한다.


사전 훈련된 가중치로 VGG16 네트워크 로드하기


VGG16을 위해 입력 이미지 전처리하기

image

  • 이 이미지에서 사전 훈련된 네트워크를 실행하고 예측 벡터를 이해하기 쉽게 디코딩한다.
  • 아프리카 코끼리 (90%), 코끼리 (7%), 인도 코끼리 (0.4%) 예측
  • 예측 벡터에서 최대로 활성화된 항목은 ‘아프리카 코끼리’클래스에 대한 것으로 386번 인덱스이다.


Grad-CAM 알고리즘 설정하기

image


원본 이미지에 히트맵 덧붙이기

image


References

댓글남기기