본문 바로가기

Machine Learning

Keras를 이용한 딥러닝

이번에는 keras에 대하여 공부하고 이를 이용해 이전에 예제로 사용했던 mnist손글씨 인식을 코드를 짜 볼 것이다

 


 

 

우선 keras란 딥러닝 모델을 간편하게 만들고 훈련시킬 수 있는 파이썬을 위한 딥러닝 프레임 워크이다

 

 

케라스의 특징은 다음과 같다,

  • 동일한 코드로 CPU와 GPU에서 실행할 수 있다.
  • 사용하기 쉬운 API를 가지고 있어 딥러닝 모델의 프로토타입을 빠르게 만들 수 있다.
  • (컴퓨터 비전을 위한) CNN, (시퀀스 처리를 위한) RNN을 지원하며 이 둘을 자유롭게 조합하여 사용할 수 있다.
  • 다중 입력이나 다중 출력 모델, 층의 공유, 모델 공유 등 어떤 네트워크 구조도 만들 수 있습니다. 이 말은 GAN(Generative Adversarial Network)부터 뉴럴 튜링 머신까지 케라스는 기본적으로 어떤 딥러닝 모델에도 적합하다는 뜻이다.

 이러한 케라스는 딥러닝 모델을 위하여 고수준의 구성 요소들을 제공하는데, 케라스의 백엔드 엔진에서 제공하는 최적화된 텐서 라이브러리를 사용한다. 케라스는 모듈 구조로 구성되어 있어 하나의 텐서 라이브러리에 국한하여 구현되어 있지 않고, 여러 가지 백엔드 엔진과 매끄럽게 연동된다. 현재는 Tensor Flow, Theano, CNTK 3개를 백엔드 엔진으로 사용할 수 있다.


 

 

Tensor flow, Theano 등은 딥러닝을 위한 주요 플랫폼 중 하나이다. 또한 케라스로 작성된 모든 코드들은 아무런 변경 없이 백엔드 중 하나를 선택하여 실행시킬 수 있다. 즉 개발하는 도중 하나의 백엔드가 특정 작업에 휴율적이다 판단되면 언제든지 백엔드를 바꿀 수 있다. 

 

 

Keras를 이용해 mnist 손글씨 인식해보기


케라스를 사용한 대부분의 작업 흐름은 다음과 같다.

 

  • 입력 텐서와 타깃 텐서로 이루어진 훈련 데이터를 정의합니다.
  • 입력과 타깃을 매핑하는 층으로 이루어진 네트워크(또는 모델)를 정의합니다.
  • 손실 함수, 옵티마이저, 모니터링하기 위한 측정 지표를 선택하여 학습 과정을 설정합니다.
  • 훈련 데이터에 대해 모델의 fit() 메서드를 반복적으로 호출합니다.

 

한편, 모델을 정의하는 방법은 두 가지인데, Sequential 클래스(가장 자주 사용하는 구조인 층을 순서대로 쌓아 올린 네트워크다.) 또는 함수형 API (완전히 임의의 구조를 만들 수 있는 비순환 유향 그래프(DAG)를 만든다.)를 사용한다.

지금부터 가장 기본적인 신경망 예제인 MNIST 데이터셋을 이용해 손글씨 데이터를 분류 예측하는 모델을 만들어 보겠습니다. 다행히 keras에는 MNIST 데이터셋이 numpy 배열 형태로 포함되어 있으며, 다음과 같이 불러올 수 있다.

 

MNIST 데이터는 훈련 데이터(6만 개), 테스트 데이터(1만 개)로 구분되어 배포되고 있다. 따라서 이런 구조에 따라 데이터를 읽어 들인다.

 

데이터를 float32 자료형으로 변환하고, 정규화를 함으로써 이미지 데이터를 준비한다

 

np_utils.to_categorical() 메서드를 이용해 0~9의 카테고리를 각각의 배열로 표현한다 

 

Keras가 편리하다는 것을 한눈에 볼 수 있는 부분은 바로 이 부분이다. 모델을 정의하는 부분인데, sequential(직선적)로 딥러닝의 각 층을 add() 메서드로 추가한다. Tensor flow의 코드와 비교했을 때 굉장히 간단하다는 것을 알 수 있다.

뿐만 아니라 Dropout과 활성화 함수 또한 add() 메서드로 간단하게 추가할 수 있다.

 

 

compile() 메서드로 모델을 구축한다 이때 loss로 최적화 함수를 지정할 수 있다.  categorical_crossentropy는 손실 함수이다. 가중치 텐서를 학습하기 위한 피드백 신호로 사용되며 훈련하는 동안 최소화된다. 그리고 미니 배치 확률적 경사 하강법을 통해 손실이 감소된다. 경사 하강법을 적용하는 구체적인 방식은 첫 번째 매개변수로 전달된 'rmsprop' 옵티마이저에 의해 결정된다.

 

fit() 메서드를 호출하면 손실에 대한 가중치의 그래디언트를 계산하고, 그에 맞추어 가중치를 업데이트합니다.

 

 

정답률은 0.98%로 간단한 코드에 비하여 훌륭한 정답률을 얻어 내었다.

 

드롭아웃(Dropout)


잠시 드롭아웃에 대하여 알아보자. 

 

드롭아웃은 regularization의 효과를 위한 방법이다. 아이디어 자체는 굉장히 단순하다. 어떤 레이어에 드롭아웃을 적용하면, 그 레이어의 모든 노드에서 나가는 activation을 특정 확률로 지워버린다.

이러한 아이디어가 어떻게 사용되는지는 한 가지 간단한 예를 들어보도록 하겠다.  예를 들어, 토익 시험을 본다고 생각을 하자. 연습 문제를 가지고 공부를 하는데 연습 문제의 리스닝 셋에서 강아지 사진이 있는 문제의 답이 모두 C라고 가정하자. 어떤 학생이 연습 문제를 가지고 너무 공부를 열심히 한 나머지 강아지 사진이 있는 문제의 답은 C라고 외워버리게 되고, 실전에서 강아지 문제가 나오자마자 답을 C로 찍어버렸는데 사실 그 문제의 답은 D였던 것이다. 제삼자가 보면 말도 안 되는 이야기지만 학생 입장에서는 공부를 정말 열심히 해서 연습 문제의 답까지 외워버렸는데 막상 실전에 가서 문제를 틀려버린 상황이 된 것이다. 즉 역설적이게도 뉴럴 네트워크가 너무 똑똑해지는 것을 방지하기 위해서다.

 

이것이 바로 학습 데이터에 대한 “과적합(overfitting)” 문제이며, 드롭아웃은 이러한 상황을 방지하기 위한 장치이다. 일부러 모델을 학습할 때 일부 노드의 activation을 지워버려 다소 “멍청한(기억력이 떨어지는)” 모델을 만들어 문제에 대한 과적합(overfitting)을 막는다. 물론 검증할 때에는 모든 activation을 다시 살린다.

 

우리 예에서는 드롭아웃이 의미가 없을 수 있겠으나, ResNet과 같이 복잡하고 거대한 모델을 만들 때 드롭아웃은 유의미한 성능을 발휘한다. 모델이 “딥(deep)”해지면 해질수록 데이터에 대한 학습 과적합이 일어나기 십상이기 때문에, 이러한 경우 드롭아웃을 통해 과적합을 줄이고 검증 정확도를 높일 수 있다.

 

모델을 만들었는데 학습 정확도가 검증 정확도에 비해 지나치게 높으면 늘 과적합을 의심하고 드롭아웃을(혹은 유사한 효과를 갖는다고 하는 배치 정규화를) 적용해 보자.

 

케라스에서 드랍아웃을 적용할 때에는 일반적으로 활성 함수(Activation) 레이어 뒤에 붙이며, 인자로 activation을 드롭할 확률인 dropout_rate를 설정해 주어야 한다.