신경망의 수학적 구성요소에는 어떤 것이 있을까?
작성자 : 박정현
Ch02. 신경망의 수학적 구성 요소
신경망 만드는 예제와 텐서와 연산의 개념을 이해한다. 마지막으로 역전파와 경사 하강법을 사용하여 신경망이 학습되는 방법을 소개한다.
2.1 신경망과의 첫 만남
케라스 파이썬 라이브러리를 사용해서 손글씨 숫자 분류를 학습하는 구체적인 신경망 예제를 살펴본다. 만약 케라스, 파이토치 등의 라이브러리 사용 경험이 없다면 지금 당장 첫 예제를 이해하기 힘들 것이다.
하지만 괜찮다. 이후에 상세히 설명을 하니까 포기하지말자!!
우선, 예제의 데이터 설명을 하자면 흑백 손글씨 숫자 이미지(28 X 28 픽셀)를 10개의 범주(0부터 9까지)로 분류를 하는 것이다. 손글씨 데이터로 아주 유명한 MNIST를 사용한다. 이 데이터는 6만 개의 훈련 이미지와 1만 개의 테스트 이미지로 구성되어 있다.
클래스(class)와 레이블(label)?
머신 러닝에서 분류 문제의 범주(category) 를 클래스(class) 라고 한다. 데이터 포인트는 샘플(sample) 이라고 한다.
이번에는 MNIST 데이터를 이용해 ‘이렇게 하는구나’ 정도 전체적인 흐름만 파악해보자!
# 케라스에서 MNIST 데이터셋 적재하기
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images
와 train_labels
가 모델이 학습해야 할 훈련 세트(training set)를 구성한다. 모델은 test_images
와 teset_labels
로 구성된 테스트 세트(test set) 에서 테스트될 것이다. 이미지는 넘파이 배열로 인코딩되어 있고 레이블은 0부터 9까지 숫자 배열이다. 이미지와 레이블은 일대일 관계이다.
훈련 데이터를 살펴보자
train_images.shape
len(train_labels)
(60000, 28, 28) array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)
다음은 테스트 데이터
test_images.shape
len(test_labels)
(10000, 28, 28) array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)
먼저 훈련 데이터 train_images와 train_labels를 네트워크에 주입한다. 그러면 네트워크는 이미지와 레이블을 연관시킬 수 있도록 학습한다. 마지막으로 test_images에 대한 예측을 네트워크에 요청한다. 그리고 이 예측이 test_labels와 맞는지 확인하는 작업을 한다.
이제 본격적으로 신경망을 만들어보자!
from tensorflow import keras
from tensorflow.keras import layers
# 모델 : Sequential
# fully connected (Dense)
model = keras.Sequential([
layers.Dense(512, activation="relu"),
layers.Dense(10, activation="softmax") # 분류 할 범주가 10개(0부터 9까지)라서 값이 10으로 들어감.
])
신경망의 핵심 구성 요소는 층(layer) 이다. 층은 데이터를 위한 필터로 생각할 수 있다. 구체적으로 층은 주어진 문제에 더 의미 있는 표현(Representation) 을 입력된 데이터로부터 추출한다. 대부분의 딥러닝은 간단한 층을 연결하여 구성되어 있고, 점진적으로 데이터를 정제하는 형태를 띠고 있다.
점진적으로 데이터를 정제하는 형태??
신경망의 핵심 구성 요소인 층을 거쳐 지나가면서 의미 있는 표현을 추출하기 때문에 이러한 표현을 사용함.
이 예시에는 완전 연결(fully connected) 된 신경망 층인 Dense 층 2개가 연속 되어 있다. (Dense 가 fully connected 의미함) 두 두번째 층은 10개의 확률 점수가 들어 있는 배열(전체 합 = 1)을 반환하는 소프트맥스(softmax) 분류 층이다.
신경망이 훈련 준비를 마치기 위해 컴파일 단계에 포함될 세 가지가 더 필요하다.
- 옵티마이저(Optimizer) : 성능을 향상시키기 위해 입력된 데이터를 기반으로 모델을 업데이트하는 메커니즘이다.
- 손실 함수(loss function) : 훈련 데이터에서 모델의 성능을 측정하는 방법으로 모델이 옳은 방향으로 학습될 수 있도록 돕는다.
- 훈련과 테스트 과정을 모니티링할 지표 : 여기에서는 정확도(정확히 분류된 비율)만 고려한다.
손실 함수, 옵티마이저는 뒤에서 상세히 설명한다.
model.compile(optimizer="rmsprop", # 옵티마이저
loss="sparse_categorical_crossentropy", # 손실 함수
metrics=["accuracy"]) # 평가 지표
훈련을 시작하기 전에 데이터를 모델에 맞는 크기로 바꾸고 모든 값을 0과 1사이즈로 스케일을 조정해야한다. 앞서 훈련 이미지는 uint8
타입임을 알 수 있었다.
uint8은 부호가 없는 8비트 정수형을 의미함. 그 범위는 0~255를 갖는다.
스케일을 위해 데이터를 0과 1 사이의 값을 가지는 float32 타입으로 변경한다.(나중엔 정규화를 사용하겠지)
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype("float32") / 255 # 변환
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype("float32") / 255 # 변환
이제 모델을 훈련시킬 준비가 되었다. 케라스에서는 모델의 fit() 메서드를 호출하여 학습한다.
model.fit(train_images, train_labels, epochs=5, batch_size=128)
Epoch 1/5 469/469 [==============================] - 6s 6ms/step - loss: 0.2588 - accuracy: 0.9247 Epoch 2/5 469/469 [==============================] - 3s 6ms/step - loss: 0.1034 - accuracy: 0.9697
훈련하는 동안 2개의 정보가 출력되고 있다. 훈련 데이터에 대한 모델의 손실과 정확도를 의미한다. 훈련 데이터에 대해 98.9%의 정확도를 금방 달성함을 볼 수 있다.
이제 훈련된 모델이 있으니 모델을 사용해 새로운 숫자 이미지에 대한 클래스 확률을 예측할 수 있다. 새로운 이미지는 테스트 세트처럼 훈련 데이터가 아닌 이미지를 말한다.
test_digits = test_images[0:10]
predictions = model.predict(test_digits)
predictions[0]
1/1 [==============================] - 0s 77ms/step array([3.4203225e-08, 1.6164263e-11, 8.7611403e-07, 2.1882904e-06, 1.2826421e-13, 1.6922105e-08, 4.0968890e-14, 9.9999678e-01, 3.0504875e-08, 1.4110856e-07], dtype=float32)
이미지 분류 모델을 만들었는데 왠 숫자..? 라고 생각할 수 있지만 출력된 array의 의미는 인덱스 i에 있는 숫자는 숫자 이미지 test_digits[0]이 클래스 i에 속할 확률에 해당한다.
즉, array의 인덱스가 숫자 0~9를 의미하고 요소의 값이 해당 숫자와 일치하는 정도? 라고 생각하면 될 것 같다.
보면 7번 인덱스의 값이 가장 높음을 알 수 있다. 따라서 예측 결과는 7 이다! 그럼 평균적으로 이전에 본 적 없는 숫자를 얼마나 잘 분류할지 계산해보자.
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"테스트 정확도: {test_acc}")
테스트 정확도: 0.9789999723434448
대략 97.8%로 나온 것을 확인할 수 있다. fit() 메서드 실행 결과에서 본 훈련 세트 정확도(98.9%) 보다는 약간 낮음을 보인다. 훈련 정확도와 테스트 정확도 사이의 차이는 과대 적합(overfitting) 때문이다. 과대 적합은 3장에서 다룬다.
오늘은 여기까지 소개하고 다음엔 데이터 표현에 대해 소개하겠다!