6 분 소요

본 글은 [케라스 창시자에게 배우는 딥러닝] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다.
전체 코드는 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 객체를 만들어줌



모델 저장하기



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

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



References

댓글남기기