8장 합성곱 신경망: 컴퓨터 비전

감사말: 프랑소와 숄레의 Deep Learning with Python, Second Edition 8장에 사용된 코드에 대한 설명을 담고 있으며 텐서플로우 2.6 버전에서 작성되었습니다. 소스코드를 공개한 저자에게 감사드립니다.

tensorflow 버전과 GPU 확인

주요 내용

8.1 합성곱 신경망 소개

예제: MNIST 데이터셋 분류

convnet 모델 구성

모델 구성 요약

MNIST 이미지 분류 훈련

모델 훈련은 이전과 동일하다.

훈련된 convnet 평가

테스트셋에 대한 성능이 이전에 사용한 Sequential 모델보다 좋아졌다.

합성곱 연산

Conv2D 모델의 장점 1: 위치 독립성

한 번 인식한 패턴을 다른 위치에서 인실할 수 있다. 적은 수의 샘플을 이용하여 좋은 성능의 일반화 모델 훈련 가능해진다.

그림 출처: Deep Learning with Python(Manning MEAP)

Conv2D 모델의 장점 2: 패턴 공간 계층 파악

위 층으로 진행할 수록 보다 복잡한 패턴을 파악한다. 이를 패턴 공간 계층(spatial hierarchy of patterns)이라 부른다.

그림 출처: Deep Learning with Python(Manning MEAP)

특성맵, 채널, 필터

합성곱 연산의 작동법을 이해하려면 아래 세 개념을 이해해야 한다.

아래 그림은 MNIST 데이터 샘플에 대해 하나의 필터가 작동하여 하나의 출력맵을 생성하는 과정을 보여준다.

그림 출처: Deep Learning with Python(Manning MEAP)

아래 그림은 세 개의 필터를 작동시켜 출력 특성맵을 생성하는 과정을 보여주며 사용된 예제는 다음과 같다.

그림 출처: Deep Learning with Python(Manning MEAP)

합성곱 커널과 합성곱 신경망

필터는 입력 특성맵을 출력 특성맵으로 변환하는 과정에서 사용되는 가중치 행렬이며, 이런 필터를 출력 특성맵의 깊이(채널 수)만큼 모아놓은 (4D) 텐서가 합성곱 커널이다. 합성곱 신경망은 바로 이 합성곱 커널(필터)을 학습시키는 모델을 가리킨다.

패딩과 보폭

입력 특성맵의 높이와 너비가 출력 특성맵의 높이와 너비랑 다를 수 있다. 이는 패딩(padding) 사용여부와 보폭(stride)의 크기에 의에 결정된다. 다음 세 개의 그림은 입력 특성맵의 높이와 너비가 5x5일 때 패딩 여부와 보폭의 크기에 따라 출력 특성맵의 높이와 너비가 어떻게 달라지는가를 보여준다.

그림 출처: Deep Learning with Python(Manning MEAP)

그림 출처: Deep Learning with Python(Manning MEAP)

그림 출처: Deep Learning with Python(Manning MEAP)

맥스 풀링 연산

맥스 풀링(max-pooling) 연산은 일정 크기의 영역에서 최댓값만을 선택하여 특성맵의 깊이와 너비를 일정 비율로 줄인다. 예를 들어, 아래 맥스 풀링 층은 2x2영역에서 최댓값 하나만을 남기고 나머지는 버리며, 이 연산을 보폭 2만큼씩 이동하며 특성맵의 모든 영역(높이x너비)에 대해 실행한다. 맥스 풀링 연산은 특성맵, 즉 채녈 별로 별도로 이루어지기에 채널 수는 변하지 않는다. 따라서 만약 x(26, 26, 32) 모양의 3D 텐서이면 다음 맥스 풀링 층의 출력값은 (13, 13, 32) 모양의 3D 텐서가 된다.

layers.MaxPooling2D(pool_size=2)(x)

그림 출처: GeeksforGeeks: Introduction to Pooling Layer

맥스 풀링 층을 합성곱 층(Conv2D)와 함께 사용하는 이유는 두 가지이다.

아래 코드는 맥스 풀링 층을 사용하지 않는 경우 가중치 파라미터의 수가 엄청나게 증가함을 잘 보여준다.

적절한 kernel_size, stride, pool_size

다른 설정 또는 최댓값 대신에 평균값을 사용하는 AveragePooling2D를 활용할 수 있으나 케라스의 기본 설정이 가장 좋은 성능을 보인다.

합성곱 신경망의 전형적인 모습

그림 출처: 핸즈온 머신러닝(2판)

8.2 합성곱 신경망 실전 활용 예제

개와 고양이 사진을 대상으로 이항분류를 구현하는 모델을 합성곱 신경으로 구현한다. 실전 상황을 묘사하기 위해 5천 개의 이미지로 이루어진 작은 데이터셋을 훈련, 검증, 테스트 용도로 사용한다. 실제로 훈련셋의 크기가 수 백에서 수 천인 경우가 매우 일반적으로 발생한다.

모델 훈련 과정은 다음과 같다.

데이터 다운로드

훈련에 필요한 데이터를 다운로드한다. 하지만 이어지는 데이터 다운로드 관련 코드의 실행은 주의를 기울여야 한다.

다음 네 개의 이어지는 코드셀은 구글 코랩에서만 실행해야 한다. 현재 구글 코랩을 사용하고 있는지 여부는 아래와 같이 확인할 수 있다.

if 'google.colab' in str(get_ipython()):
    print('구글 코랩 사용중!')
else:
    print('구글 코랩 환경 아님!')

개인 PC에서 실행하고자 할 경우 다음 사항들을 고려해야 한다.

다운로드된 데이터셋 전체는 총 25,000장의 강아지와 고양이 사진으로 구성되었으며 570MB 정도로 꽤 크다. 강아지와 고양이 각각 12,500 장씩 포함되어 있으며, 사진들의 크기가 다음과 같이 일정하지 않다.

그림 출처: Deep Learning with Python(Manning MEAP)

훈련셋, 검증셋, 테스트셋 준비

25,000 장의 사진 중에서 총 5,000 장의 사진만 사용해서 합성곱 신경을 훈련시키려 한다.

아래 코드는 앞서 지정한 대로 총 5,000 장의 사진으로 이루어진 데이터셋을 추출해서 각각의 디렉토리에 저장한다. 디렉토리의 구성은 다음과 같다.

cats_vs_dogs_small/
...train/
......cat/
......dog/
...validation/
......cat/
......dog/
...test/
......cat/
......dog/

모델 구성

convnet(합성곱 신경망) 모델은 앞서 설명한대로 Conv2DMaxPooling2D 레이어를 연속에서 쌓는 방식을 사용한다. 다만, 보다 복잡한 모델 구성을 위해 보다 높은 층 스택을 쌓는다.

강아지와 고양이의 비율이 동일하기에 정확도를 평가지표로 사용한다.

데이터 전처리

샘플 사진의 크기가 제 각각이기에 모델의 입력값으로 지정된 크기인 (180, 180, 3) 모양의 텐서로 변환을 해주어야 한다. 케라스의 image_dataset_from_directory() 함수를 이용하면 변환 뿐만 아니라 지정된 배치 크기의 배치로 구성된 훈련셋, 검증셋, 테스트셋을 쉽게 생성할 수 있다.

생성된 train_dataset, validation_dataset, test_dataset은 모두 BatchDataset 클래스의 객체이다.

생성된 데이터셋 항목 확인

참고

다음 네 개의 코드셀은 BatchDataet의 부모 클래스인 Dataset 자료형의 간단한 기능과 활용법을 보여준다.

모델 훈련

훈련 과정 확인

모델 평가

데이터 증식

데이터 증식 기법을 사용하여 훈련셋의 크기를 키우면, 과대 적합이 보다 늦게 발생하고 따라서 보다 좋은 성능의 모델을 얻게 된다. 케라스의 데이터 증식 층을 이용하여 쉽게 데이터 증식을 구현할 수 있다. 아래 코드는 Sequential 모델을 이용하여 간단하게 데이터 증식 층을 구현한다.

훈련셋의 첫째 이미지를 대상으로 9번 데이터 증식 기법을 적용한 결과를 아래와 같이 확인할 수 있다.

모델 구성을 다시 한다.

모델 훈련은 동일하다. 다만 에포크 수를 100으로 늘린다. 이유는 과대적합이 보다 늦게 발생할 것이기 때문이다.

과대 적합이 보다 늦게 발생함을 확인할 수 있다.

테스트셋에 대한 성능은 83% 정도로 올라갔다.

Conv2DMaxPooling2D 층을 더 쌓거나 층에 사용된 필터수를 늘리는 방식으로 모델의 성능을 90% 정도까지 끌어올릴 수는 있지만 그 이상은 어려울 것이다.

참고

convnet_from_scratch_with_augmentation.keras 모델을 나중에 재활용하고자 한다. 이를 위해 구글 코랩을 사용하는 경우 모델을 저장해 두어야 한다.

8.3 모델 재활용

적은 양의 데이터셋을 대상으로 훈련하는 것보다 대용량의 데이터셋을 이용하여 훈련하면 보다 좋은 성능의 모델을 구현할 수 있다. 하지만 대용량의 데이터를 구하기는 매우 어렵거나 아예 불가능할 수 있다. 대신 유사한 목적으로 대용량의 훈련 데이터셋을 이용하여 훈련된 모델을 재활용할 수 있으며 이를 통해 모델의 성능을 향상시킬 수 있다. 여기서는 기존에 잘 훈련된 모델 VGG16을 재활용하여 강아지와 고양이 사진을 잘 분류하는 모델을 구현하는 두 가지 방식을 소개한다.

모델 재활용 기본 아이디어

기존에 잘 훈련된 모델은 새롭게 구현하고자 하는 모델과 일반적으로 다른 목적으로 구현되었다. 하지만 예를 들어 강아지와 고양이를 포함한 동물 및 기타 여러 사물을 대상으로 다중클래스 분류를 목적으로 훈련된 모델은 기본적으로 강아지와 고양이를 분류하는 능력을 갖고 있어야 한다.

반면에 이항 분류 모델과 다중클래스 분류 모델은 기본적으로 출력층에서 서로 다른 종류의 값을 출력한다. 고양이와 강아지를 포함해서 총 1000개의 사물 클래스로 이미지를 분류하는 모델의 출력층은 1000개의 유닛과 softmax 등과 같은 활성화 함수를 사용할 것이지만 고양이-강아지 분류 모델은 1개의 유닛과 sigmoid 등과 같은 활성화 함수를 사용해야 한다. 따라서 기존 모델의 출력층을 포함하여 분류값을 직접적으로 예측하는 마지막 몇 개의 층 (일반적으로 밀집층)을 제외시킨 나머지 합성곱 층으로 이루어진 기저(베이스, base)만을 가져와서 그 위에 원하는 목적에 맞는 층을 새롭게 구성한다(아래 그림 참조).

그림 출처: Deep Learning with Python(Manning MEAP)

VGG16 모델

VGG16 모델은 ILSVRC 2014 경진대회에 참여해서 5등 안에 든 모델이다. 당시 훈련에 사용된 데이터셋은 120만 장의 이미지와 1,000개의 클래스로 구성되었으며 훈련은 여러 주(weeks)에 걸쳐서 진행되었다.

그림 출처: ILSVRC 2014

VGG16 모델 구성은 Conv2DMaxPooling2D의 조합으로 이루어졌다(아래 그림 참조).

그림 출처: https://neurohive.io/en/popular-networks/vgg16/

유명 합성곱 신경망 모델

ketas.applications 에 포함된 유명 합성곱 신경모델은 다음과 같다.

이미지넷(ImagNet) 소개

이미지넷(Imagenet)은 대용량의 이미지 데이터셋이며, ILSVRC 이미지 분류 경진대회에 사용된다. 이미지넷의 전체 데이터셋은 총 2만2천 개 정도의 클래스로 구분되는 동물, 사물 등의 객체를 담은 고화질 사진 1500만장 정도로 구성된다. 2017년까지 진행된 ILSVRC 경진대회는 보통 1000 개의 클래스로 구분되는 사물을 담은 1백만장 정도 크기의 데이터셋을 이용한다.

그림 출처: https://cs.stanford.edu/people/karpathy/cnnembed/

재활용 방식 1: 특성 추출

VGG16 합성곱 모델에서 밀집층(dense 층)을 제외한 나머지 합성곱 층으로만 이루어진 모델을 가져온다.

가져온 모델을 요약하면 다음과 같다.

특성 추출(feature extraction)은 재활용할 모델을 적용하여 입력 데이터를 변환하여 새로운 입력 데이터셋을 얻는 과정을 의미한다.

1) 데이터 증식 없는 특성 추출

함수 get_features_and_labels()는 이전에 준비해 놓은 강아지-고양이 훈련 데이터셋(train_dataset)에 VGG16 베이스 모델을 적용하여 변환된 데이터셋을 생성한다. 단, 레이블은 그대로 재활용한다.

변환된 데이터는 이제 (5, 5, 512) 모양을 갖는다.

변환된 데이터셋을 훈련 데이터셋으로 사용하는 간단한 분류 모델을 구성하여 훈련만 하면 된다.

검증셋에 대한 정확도가 97% 정도까지 향상된다.

훈련 결과를 시각화하면 다음과 같으며, 과대적합이 매우 빠르게 발생함을 확인할 수 있다. 데이터셋의 크기가 너무 작기 때문이며 데이터 증식 기법을 활용할 필요가 있음을 의미한다.

2) 데이터 증식 포함 재활용

데이터 증식 기법을 활용하려면 VGG16 합성곱 기저(베이스)를 구성요소로 사용하는 모델을 직접 정의해야 한다. 다만 앞서 설명한 방식과는 달리 가져온 VGG16 기저에 포함된 파라미터가 새로운 모델의 훈련 과정동안 함께 훈련되지 않도록 설정해야 함에 주의해야 한다. 이런 설정을 동결(freezing)이라 한다.

동결 해제(trainable=True)로 설정하는 경우와 그렇지 않은 경우 학습되어야 하는 파라미터의 수가 달라짐을 다음처럼 확인할 수 있다.

>>> conv_base.trainable = True
>>> print("합성곱 기저의 학습을 허용하는 경우 학습 가능한 파라미터 수: ", 
          len(conv_base.trainable_weights))

합성곱 기저의 학습을 허용하는 경우 학습 가능한 파라미터 : 26

동결 설정(trainable=False)인 경우에 학습되는 파라미터 수가 0이 된다.

>>> conv_base.trainable = True
>>> print("합성곱 기저의 학습을 금지하는 경우 학습 가능한 파라미터 수: ", 
          len(conv_base.trainable_weights))

합성곱 기저의 학습을 허용하는 경우 학습 가능한 파라미터 : 0

아래 모델은 데이터 증식을 위한 층과 VGG16 기저를 함께 이용한다.

이렇게 훈련하면 재활용된 합성곱 기저에 속한 층은 학습하지 않으며 두 개의 밀집층에서만 파라미터 학습이 이뤄진다.

과대적합이 보다 늦게 이루어지며 성능도 향상되었다.

테스트셋에 대한 정확도가 97.7%까지 향상된다.

재활용 방식 2: 모델 미세 조정

모델 미세 조정(파인 튜닝, fine-tuning)은 특성 추출 방식과는 달리 기존 합성곱 모델의 최상위 합성곱 층 몇 개를 동결 해제해서 새로운 모델에 맞추어 학습되도록 하는 모델 훈련기법이다.

여기서는 아래 그림에처럼 노락색 배경을 가진 상자 안에 포함된 합성곱 층을 동결 해제해서 함께 학습되도록 한다.

그림 출처: Deep Learning with Python(Manning MEAP)

아래 코드는 모든 층에 대해 동결해제를 진행한 후에 마지막 4개 층을 제외한 나머지 층에 대해 다시 동결을 설정한다.

상위 4개 층만 동결 해제하는 이유는 합성곱 신경망의 하위층은 보다 일반적인 형태의 패턴을 학습하는 반면에 최상위층은 주어진 문제 해결에 특화된 패턴을 학습하기 때문이다. 따라서 이미지넷으로 훈련된 모델 전체를 대상으로 훈련하기 보다는 최상위층만 훈련시키는 것이 보다 유용하다.

모델 컴파일과 훈련 과정은 이전과 동일하게 진행한다.

기존 모델을 재활용하여 98%($\pm\!$ 1%)에 육박하는 정확도 성능을 갖는 합성곱 신경망 모델을 2,0000개의 이미지만으로 학습시켰음을 확인할 수 있다.