‘Deep Learning with Python’ 세미나 5, 3장. Getting started with neural networks (2/2)
3.5 Classifying newswires: a multiclass classification example
뉴스 기사를 46개의 상호배타적인 주제로 분류하는 신경망을 만들어봅니다.
3.5.1 The Reuters dataset
케라스는 뉴스 기사 분류 데이터셋을 제공합니다.
from keras.datasets import reuters
데이터셋을 다루는 방법은 영화평에서와 같습니다.
3.5.2 Preparing the data
뉴스 기사를 입력으로 다루는 방법은 영화평을 다루는 방법과 같습니다.
출력은 영화평이 이진 분류인 반면 뉴스기사 분류는 다중 분류입니다. 다중 분류 레이블을 다루는 방법 중 자주 사용되는 것이 원핫인코딩입니다. 하나의 뉴스기사에 대한 분류 레이블을 표현하기 위해 46개의 요소로 된 벡터를 사용합니다. 46개의 요소 중 분류에 해당하는 요소 값만 1로 작성하고, 나머지는 모두 0으로 작성합니다. to_one_hot 함수를 이를 구현한 것입니다.
to_one_hot을 직접 구현할 필요는 없습니다. 케라스에서는 유틸로 이러한 기능을 제공하는 함수를 제공합니다.
from keras.utils.np_utils import to_categorical
3.5.3 Building your network
입력의 input_shape은 영화평과 같고, units은 64로 영화평보다 많은 수를 갖습니다. 영화평은 이진 분류이고 기사 분류는 다중 분류이다보니 좀 더 풍부한 표현이 필요하다고 생각한거죠. 영화평에서와 마찬가지로 입력층에 연결되는 중간층으로 완전결합 레이어(Dense)를 사용하고, 활성화 함수로 relu를 사용합니다. 영화평에서도 언급했지만 케라스에서는 입력층에 해당하는 레이어는 작성하지 않습니다. 입력층에 연결된 레이어의 input_shape 값 설정만으로 충분하기 때문입니다.
model.add(layers.Dense(64, activation=’relu’, input_shape=(10000,)))
출력 텐서는 원핫인코딩을 적용한 46개의 요소를 갖는 벡터이기 때문에 46개의 units을 갖도록 설정합니다. 활성화 함수로 softmax를 사용합니다. softmax 함수는 해당 샘플이 어떤 레이블일지에 대한 확률 분포를 출력합니다. 46개의 각각의 unit에 확률 분포 값이 작성됩니다. 모든 units의 값을 합하면 1이 됩니다.
model.add(layers.Dense(46, activation=’softmax’))
units이 64이고, 활성화 함수로 relu를 사용하는 중간층을 하나 둡니다.
model.add(layers.Dense(64, activation=’relu’))
최적화 함수로 rmsprop을 사용하고, 손실 함수로는 확률 분포 값으로 출력이 작성될 때에 사용할 수 있는 categorical_crossentropy를 사용합니다. 지표로는 accuracy를 사용합니다.
model.compile(optimizer=’rmsprop’, loss=’categorical_crossentropy’, metrics=[‘accuracy’])
3.5.4 Validating your approach
1000개의 샘플을 따로 떼어서 검증셋으로 사용합니다. 배치사이즈 521, epochs 20을 사용합니다.
history = model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512, validation_data=(x_val, y_val))
history를 사용해서 그래프를 작성해 보고, 어디에서 과적합이 발생하는지 파악해 봅니다.
테스트셋으로 훈련한 모델을 평가합니다.
results = model.evaluate(x_test, one_hot_test_labels)
3.5.5 Generating predictions on new data
원하는 수준으로 평가 결과가 나왔다면 새로운 데이터셋을 입력으로 받아 결과를 예측합니다. 예제에서는 테스트셋을 사용하고 있는데 실전에서는 실제 데이터를 사용합니다.
predictions = model.predict(x_test)
예측 결과는 46개의 units으로 구성된 확률분포 값으로 나오기 때문에, 분류 결과를 얻기 위해서는 가장 큰 값을 갖는(가장 확률이 높은) unit을 구해야 합니다. 넘파이 argmax 함수를 사용합니다.
np.argmax(predictions[0])
3.5.6 A different way to handle the labels and the loss
레이블을 원핫인코딩 방식으로 변환하지 않고 직접 사용할 수도 있습니다. 0~45 값을 직접 사용합니다. 이럴 경우 손실 함수로 sparse_categorical_crossentropy를 사용합니다.
3.5.7 The importance of having sufficiently large intermediate layers
Now let’s see what happens when you introduce an information bottleneck by having intermediate layers that are significantly less than 46-dimensional.
표현력이라는 관점에서 살펴면, 중간층의 units 수가 출력 층의 units 수 보다는 커야 함을 쉽게 생각할 수 있습니다. 코드 3-23에서 중간층의 units을 4로 설정해서 모델을 실행해 보면 정확도가 떨어짐을 볼 수 있습니다.
3.6 Predicting house prices: a regression example
보스턴 주택 가격을 예측하는 신경망을 만들어 봅니다.
분류와 회귀는 기계학습의 대표적인 두 가지 문제 유형입니다. 회귀 문제는 입력 데이터에서 수치를 예측하는 것입니다. 보스턴 주택 가격 예측은 회귀 문제입니다.
3.6.1 The Boston Housing Price dataset
케라스는 보스턴 주택 가격 예측 문제를 다룰 수 있는 데이터셋을 제공합니다.
from keras.datasets import boston_housing
하나의 입력 데이터는 1인당 범죄율, 주택당 평균 방의 개수, 고속도로 접근성과 같은 13개의 수치 특성으로 구성됩니다.
3.6.2 Preparing the data
특성에 따라 수치 단위가 다르기 때문에 정규화를 해 줄 필요가 있습니다. 다수의 특성들로 데이터가 구성될 때 이 점에 주의해야 합니다.
코드 3.25는 데이터를 정규화하는 코드입니다. 코드에서 테스트셋을 정규화할 때 훈련셋의 평균값과 표준편차를 사용하고 있음에 주의합니다.
3.6.3 Building your network
입력 텐서는 13개의 특성을 갖는 벡터이므로 (13, )이 됩니다. 예제에서는 train_data의 shape을 통해 input_shape을 구하고 있습니다. 입력층에 연결된 중간층은 units을 64로, 활성화 함수로 relu를 사용합니다.
model.add(layers.Dense(64, activation=’relu’, input_shape=(train_data.shape[1],)))
출력 값은 하나의 unit 값으로 작성되기 때문에 출력 레이어의 unit은 1로 작성됩니다. 구한 값을 직접 작성하기 때문에 특별한 활성화 함수를 사용할 필요가 없습니다.
model.add(layers.Dense(1))
중간층은 units을 64로, 활성화 함수로 relu를 사용하는 층을 하나만 둡니다.
model.add(layers.Dense(64, activation=’relu’))
최적화 함수는 rsmprop을 사용하고, 손실 함수는 mse(평균 제곱 오차; mean squard error)를 사용하고, 지표는 mae(평균 절대 오차; mean absolute error)를 사용합니다. mse는 회귀 문제에 널리 사용되는 손실 함수입니다.
3.6.4 Validating your approach using K-fold validation
데이터셋이 적은 경우 훈련셋과 검증셋을 나누는 것은 부담스럽습니다. 안 그래도 적은 데이터를 더 쪼개야 하니까요. 이런 경우에 사용할 수 있는 것이 그림 3.1이 설명하는 방법입니다.
데이터를 K개의 그룹으로 분할합니다. 분할된 그룹들 중 하나를 검증셋으로, 나머지는 훈련셋으로 사용합니다. 모든 그룹이 돌아가면서 검증셋으로 사용되도록 합니다. 이렇게 하면 검증셋과 훈련셋이 다르게 해서 훈련(fit)을 K번 할 수 있습니다. 훈련된 모델을 평가(evaluate)하고 평가 점수를 구합니다. K 번째 실행을 마치고 평가 점수의 평균 값을 구합니다.
코드 3.27은 이를 구현한 것입니다. 모델 훈련 시 검증 데이터를 설정하지 않고, 모델 평가에 사용하고 있음에 주의합니다. batch_size가 1로 설정되었고, verbose가 0으로 설정되었음에 주의합니다. verbose를 0으로 설정할 경우 훈련 과정이 출력되지 않습니다.
코드 3.28은 검증셋을 모델 훈련 시 설정하고, 매 훈련 시 마다 history의 val_mean_absolute_error 값을 모읍니다. 코드 3.29는 그것을 사용해 검증셋의 mae의 평균 값을 구합니다. 코드 3.30은 이를 그래프로 작성합니다.
mae 값들 중에 다른 값들과 차이가 큰 것이 있어서 그림 3.12처럼 그래프로 보기 어렵습니다. 값이 차이가 큰 것들 몇 개를 제외시키고, 지수 이동 평균하면 그림 3.13처럼 좀 더 보기 쉽습니다. 지수 이동 평균하면 이전 값들이 현재 값에 영향을 미치게 되어 평균하는 것과 같은 효과를 얻을 수 있습니다.
코드 3.31은 이를 구현한 것으로, 이전 값들의 영향 비중을 0.9로 높게 설정하고 있습니다. 따라서 현재 값이 다른 값들에 비해 큰 차이를 보이더라도 지수 이동 평균된 값은 크게 차이가 나지 않도록 만듭니다. 그래프로 표현되었을 때 부드러운 곡선을 얻을 수 있습니다.