Deep MNIST for Experts
TensorFlow는 대규모 수치 계산을 수행하기 위한 강력한 라이브러리입니다. 이 라이브러리가 가속하는 작업 중 하나는 심층 신경망 (Deep neural network) 을 구현하고 학습하는 것입니다. 이 연습에서 우리는 심층 합성곱 MNIST 분류기 (deep convolutional MNIST classifier) 를 만들면서 TensorFlow 모델의 기본 빌딩 블록에 대해 배울 것입니다.
이 소개는 당신이 신경망 및 MNIST 데이터 모음에 익숙하다고 가정하고 있습니다. 만약 이들에 대한 배경 지식이 없다면, 초보자를 위한 소개를 확인하세요. 시작하기 전에 TensorFlow를 설치해야 합니다.
Note
CodeOnWeb에서는 TensorFlow 및 딥러닝 관련 실습 준비가 되어 있으므로 따로 설치하지 않고 내용을 바로 따라가면 됩니다.
설정
모델을 만들기 전에 먼저 MNIST 데이터 집합을 불러온 후 TensorFlow 세션을 시작합니다.
MNIST 데이터 불러오기
편향을 위해 우리가 MNIST 데이터 모음을 자동으로 다운로드하고 설치하는 스크립트를 포함해 놓았습니다. 이 스크립트는 데이터 파일을 보관하기 위하여 ‘MNIST_data' 디렉토리를 만들겁니다.
mnist
는 NumPy 배열의 형태로 훈련, 검증 및 테스트를 저장하는 가벼운 클래스입니다. 또한 아래에서 사용할, 데이터 미니배치들을 따라가며 반복하는 함수를 제공합니다.
TensorFlow 대화형 세션 (InteractiveSession)
TensorFlow는 계산을 하기 위해 아주 효율적인 C ++ 백엔드에 의존합니다. 이 백엔드로의 연결을 세션(session)이라고 합니다. TensorFlow 프로그램들의 일반적인 사용법은 먼저 그래프를 만든 후 세션 안에서 그걸 실행하는 것입니다.
여기서 우리는 간편한 InteractiveSession
클래스를 대신 사용할 것인데, 이 클래스는 당신이 TensorFlow로 코드를 설계하는 방법을 훨씬 유연하게 만들어 줍니다. 계산 그래프(Computation Graph)와 그래프를 실행하는 작업들 사이에 당신이 끼어 들어갈 수 있게 해 줍니다. 이것은 IPython 등과 같은 상호작용하는 상황에서 일할때 특히 유용합니다. 여러분이 InteractiveSession
을 사용하지 않는 경우에는 세션을 시작하고 그래프를 실행하기 전에 반드시 전체 계산 그래프를 모두 만들어야 합니다.
계산 그래프
Python 으로 효율적인 수치 연산을 하기 위해서 우리는 보통 행렬곱 등의 무거운 연산을 Python 외부에서 처리하는 NumPy등의 라이브러리들을 사용하는데, 이들은 다른 언어로 구현한 고도로 최적화된 코드를 이용합니다. 불행히도 모든 작업 단계에서 Python으로 도로 스위칭하는 과정에서도 아주 큰 오버헤드가 여전히 발생할 수 있습니다. 이러한 오버헤드는 GPU를 이용하거나 분산 처리를 이용하는 데이터 전송에 큰 비용을 지불하는 환경에서 계산을 실행할 경우 특히 큽니다.
TensorFlow 또한 Python 외부에서 무거운 작업들을 실행하지만, 이러한 오버헤드를 피하기 위해 한 단계의 일을 더 수행합니다. Python과 독립된 큰 단일 작업을 실행하는 대신, TensorFlow는 완전히 Python 밖에서 실행되는 서로 상호작용하는 작업들의 그래프를 기술하도록 합니다. 이 접근법은 Theano 나 Torch 에서 사용하는 것과 유사합니다.
따라서 Python 코드의 역할은 이 외부 계산 그래프를 만들고, 계산 그래프의 어떤 부분이 실행되어야 하는지 명령하는 것입니다. 기본 사용 항목의 계산 그래프 에서 더 자세한 내용을 확인하세요.
소프트맥스 회귀 모델 만들기
이 장에서 우리는 단일 선형 계층로 된 소프트맥스 회귀 모델을 만들 것입니다. 다음 장에서, 우리는 이 모델을 다중 계층 합성곱 네트워크로 된 소프트맥스 회귀로 확장할 것입니다.
Placeholders
입력 이미지와 목표 출력 클래스를 위한 노드를 만들어서 계산 그래프를 만드는 것을 시작합니다.
x
와 y_
는 특정한 값이 아닙니다. 실은 그것들은 placeholder
-- 우리가 TensorFlow 에게 계산을 실행할 때 입력할 값들 — 입니다.
입력 이미지들 x
는 부정소수들로 된 2d 텐서로 구성될 것입니다. 여기서 우리는 [None, 784]
의 형태를 할당했는데, 784
는 평탄화된 MNIST 이미지 하나의 차원이고, 첫번째 차원인 None
은 배치 크기에 해당되는데 어떤 크기도 될 수 있다는 의미입니다. 목표 출력 클래스 y_
또한 2d 텐서인데, 각 행은 대응되는 MNIST 이미지가 어떤 숫자 클래스에 속하는지를 나타내는 one-hot 10차원 벡터입니다.
placeholder
의 형태 인수는 선택 사항입니다만, TensorFlow가 자동으로 잘못된 텐서 형태에 대한 오류를 잡을 수 있도록 해줍니다.
Variables
우리는 또한 가중치와 편향값이 필요합니다. 이런 것들을 추가적인 입력으로 다루는 것을 생각해 볼 수 있습니다. 그러나 TensorFlow는 더 나은 방법을 갖고 있습니다: Variable
이죠. Variable
은 TensorFlow의 상호작용하는 작업 그래프들간에 유지되는 변경 가능한 텐서입니다. 계산 과정에서 사용되거나 심지어 변경될 수도 있습니다. 기계학습 응용 사례들을 위해 일반적으로 모델 파라미터 Variables
를 사용합니다.
우리는 각 파라미터의 초기값을 tf.Variable
에 주었습니다. 이 경우는 W
와 b
둘 모두 0으로 채워진 텐서로 초기화했습니다. W
는 784x10 행렬 (우리가 784개의 입력 특징(이미지의 픽셀수)과 10개의 출력이 있으므로) 이며, b
는 10차원 벡터입니다. (10개의 클래스가 있으니까요)
Variables
가 세션 안에서 사용되기 전에 반드시 그 세션을 사용하여 초기화되어야 합니다. 이 단계는 이미 지정되어 있는 초기값을 (이 경우 0으로 채워진 텐서) 사용하고, 각 Variable
에 할당해야 합니다. 이 과정은 모든 Variables
에 대하여 한 번에 수행할 수 있습니다.
예측 클래스 및 비용 함수(Cost Function)
이제 우리 회귀 모델을 만들 수 있습니다. 딱 한 줄만 필요합니다! 벡터화된 입력 이미지 x
를 가중치 행렬 W
로 곱하고, 편향(bias) b
를 더한 다음 각 클래스에 지정된 소프트맥스 확률들을 계산합니다.
훈련 과정에서 최소화될 비용 함수들은 간단하게 지정할 수 있습니다. 여기서 비용함수는 목표와 모델 예측간의 교차 엔트로피가 될 것입니다.
tf.reduce_sum
는 미니배치 안의 모든 이미지들에 걸쳐 합을 구할 뿐 아니라 클래스에 대해 수행됩니다. 우리는 교차 엔트로피를 전체 미니배치에 대해 계산하고 있습니다.
모델 훈련시키기
이제 모델과 훈련 비용 함수를 정의했으므로, TensorFlow를 사용하여 모델을 훈련하는 것은 간단합니다. TensorFlow는 전체 계산 그래프를 알고 있으므로, 각 변수들에 대하여 비용 그라디언트를 찾기 위해 자동 미분을 사용할 수 있습니다. TensorFlow에는 다양한 내장 최적화 알고리즘들 이 있습니다. 이 예제에서는 교차 엔트로피를 하강시키기 위해 가파른 그라디언트 하강법 (steepest gradient descent) 을 0.01의 보폭으로 사용할 것입니다.
이 한 줄에서 TensorFlow가 진짜로 하는 일은 계산 그래프에 새 작업을 추가하는 일입니다. 이러한 작업들에는 그라디언트를 계산하고, 매개 변수가 갱신 보폭을 계산하고, 갱신된 보폭을 매개 변수에 반영하는 단계를 포함하고 있습니다.
결과로 받은 작업인 train_step
는 실행할 때 그라디언트 하강법 업데이트를 매개 변수들에 반영할 것입니다. 따라서 모델 훈련은 train_step
을 반복 실행하여 할 수 있습니다.
각 훈련 반복에서 우리는 50개의 훈련 예제를 불러옵니다. 그 다음 feed_dict
를 사용하여 placeholder
텐서 x
와 y_
를 훈련 예제로 변경한 후 train_step
작업을 실행합니다. feed_dict
를 사용하여 계산 그래프 내의 어떠한 텐서도 대체할 수 있음을 알아두세요 — placeholders
에만 제한된 것이 아닙니다.
모델 평가하기
우리 모델이 얼마나 좋을까요?
첫번째로 우리가 맞는 라벨을 예측했는지를 확인할 것입니다.. tf.argmax
는 특정한 축을 따라 가장 큰 원소의 색인을 알려주는 엄청나게 유용한 함수입니다. 예를 들어 tf.argmax(y,1)
는 진짜 라벨이 tf.argmax(y_,1)
일때 우리 모델이 각 입력에 대하여 가장 정확하다고 생각하는 라벨입니다. 우리는 tf.equal
을 이용해 예측이 실제와 맞았는지 확인할 수 있습니다.
이 결과는 부울 리스트를 줍니다. 얼마나 많은 비율로 맞았는지 확인하려면, 부정소숫점으로 캐스팅한 후 평균값을 구하면 됩니다. 예를 들어, [True, False, True, True]
는 [1,0,1,1]
이 되고 평균값은 0.75가 됩니다.
마지막으로, 테스트 데이터를 대상으로 정확도를 확인해 볼 수 있습니다. 결과는 약 91% 정확도여야 합니다.
다중 계층 합성곱 네트워크
MNIST에서 91%의 정확도는 나쁩니다. 부끄러울 정도로 나쁩니다. 이 장에서 우리는 아주 간단한 모델에서 적당히 세련된 모델 -작은 합성곱 신경망-으로 바꿔 타서 고칠 것입니다. 이건 99.2%정도의 정확도를 보일겁니다 — 예술적이진 않지만, 훌륭하죠.
가중치 초기화
이 모델을 만들기 위해서, 우리는 많은 가중치 및 편향을 만들 필요가 있습니다. 일반적으로 작은 크기의 노이즈로 가중치를 초기화해서 대칭성을 파괴하고, 그라디언트가 0이 되는 경우를 방지합니다. 우리가 ReLU 뉴런을 사용할 것이므로, 그것들을 약간 양수의 편향을 주어 초기화해서 "죽은 뉴런" 이 되는 것을 막는 것도 좋은 시도입니다. 모델을 만들 때 마다 이 과정을 반복하는 대신, 우리를 위해 이걸 해줄 편리한 두 함수를 만듭시다.
합성곱과 풀링 (Pooling)
TensorFlow는 또한 합성곱과 풀링 작업을 위한 많은 유연성을 제공합니다. 어떻게 경계를 다룰까요? 이동 (stride) 크기는 얼마인가요? 이 예시에서, 우리는 언제나 가장 기본적인 버전을 선택할 것입니다. 합성곱은 하나의 이동 크기를 사용하고, 0로 패딩되어 결과적으로 출력의 크기가 입력의 크기와 같게 됩니다. 풀링은 2x2 블럭의 평범한 max pooling 입니다. 코드를 깨끗하게 유지하기 위해 이러한 작업들을 함수로 추상화합시다.
첫 합성곱 계층
이제 첫번째 계층를 구현할 수 있습니다. 이 계층는 합성곱과 max pooling 으로 구성될 것입니다. 합성곱은 5x5 조각 각각마다 32개의 특징을 계산할 것입니다. 가중치 텐서는 [5, 5, 1, 32]
형태가 될 것입니다. 앞의 2 차원은 패치 크기이며, 뒷부분은 출력 채널의 숫자입니다. 또한 각 출력 채널에 대하여 구성 요소 편향 벡터가 있을 것입니다.
계층를 적용하기 위하여 우선 x
를 4차원 텐서의 형태로 변환하는데, 두번째와 세번째 차원을 이미지의 폭과 높이에 해당하고, 마지막 차원은 색깔 채널의 수에 대응하는 차원입니다.
그리고 x_image
를 가중치 텐서와 합성곱하고, 편향을 더한 후, ReLU 함수를 적용한 후, 마지막으로 max pool 합니다.
두번째 합성곱 계층
심층 네트워크를 만들기 위해 이 유형의 여러 계층를 쌓습니다. 두번째 계층는 각각 5x5 조각으로 된 64개의 특징들을 갖고 있습니다.
Densely Connected Layer
이제 이미지 크기는 7x7로 줄어 들었습니다. 전체 이미지를 처리할 수 있도록 1024개 뉴런이 있는 전부 연결된 계층를 추가합니다. 풀링 계층로부터의 텐서를 벡터들의 배치로 형태를 바꾸고, 가중치 행렬을 곱하고, 편향을 더하고, ReLU를 적용합니다.
탈락 (Dropout)
오버피팅을 줄이기 위해 우리는 판독 계층 전에 탈락을 적용합니다. 뉴런의 출력이 탈락 동안 유지될 확률에 대한 placeholder
를 만듭니다. 이건 훈련 도중에는 탈락을 설정하고 테스트 기간동안에는 해제할 수 있게 해 줍니다. TensorFlow의 tf.nn.dropout
작업은 자동으로 뉴런 출력에 마스킹을 할 뿐 아니라 스케일을 조정해 주므로, 탈락은 어떠한 추가적인 스케일링 없이 동작합니다.
판독 계층
마지막으로, 위에서 소프트맥스 회귀에서 사용했던것과 같은 소프트맥스 계층를 추가합니다.
모델 훈련 및 평가
이 모델이 얼마나 좋을까요? 훈련 및 평가를 하기 위해 간단한 단일 계층 소프트맥스 네트워크에서 사용한것과 거의 같은 코드를 사용할 것입니다. 차이점은 다음과 같습니다: 가파른 그라디언트 하강 최적화 모듈을 더 세련된 ADAM 최적화 모듈로 교체할 것이고, keep_prob
인수를 feed_dict
에 포함하여 낙오율을 조정할 것입니다. 그리고 훈련 과정중 100번의 반복마다 기록 (logging)을 추가할 것입니다.
Note
위의 CodeOnWeb 샌드박스에서 예제를 테스트해 볼 수 있습니다. 원래 실행 시간이 오래 걸리지만 캐시되어 있으므로 빠르게 확인할 수 있습니다.
이 코드를 실행한 후 최종 테스트 세트의 정확도는 약 99.2%여야 합니다.
이제 적당히 세련된 딥러닝 모델을 TensorFlow를 사용하여 어떻게 빠르고 간단하게 만들고, 훈련시키고 평가하는지 배웠습니다.
토론이 없습니다