자연어처리(NLP) 10일차 (소프트맥스 회귀)

Source: Deep Learning on Medium


Go to the profile of 정민수

2019.06.13

본 글은 https://wikidocs.net/book/2155을 참고하여 작성되었음을 밝힙니다.

핵심키워드

  • 소프트맥스(Softmax)
  • 시그모이드(Sigmoid)
  • 크로스-엔트로피(Cross-entropy)

소프트맥스 회귀(Softmax Regression)

이번 실습은 iris 데이터를 이용해 회귀문제를 풀어보도록 한다.

https://wikidocs.net/35476 의 내용 중, one-hot encoding 을 하는 과정과, Keras의 사용 때문에 이 부분만 실습을 해봤고, 나중에 도움이 될지도 몰라 정리해놓는다.

import pandas as pd
from sklearn.datasets import load_iris
data = load_iris()
data = pd.DataFrame(data = np.c_[data['data'], data['target']], columns=data['feature_names'] + ['target'])
data.head()
col_list = list(data.columns)
from sklearn.model_selection import train_test_split
data_X = data[col_list[:-1]].values
data_y = data['target'].values
data_X[:5]
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2]])
data_y[:5]
array([0., 0., 0., 0., 0.])
(X_train, X_test, y_train, y_test) = train_test_split(data_X, data_y, train_size=0.8, random_state=1)
# 훈련 데이터와 테스트 데이터를 8:2로 나누고 데이터의 순서를 섞음.

원-핫 인코딩 적용

from keras.utils import np_utils
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
y_train[:5]
array([[0., 1., 0.],
[0., 0., 1.],
[0., 1., 0.],
[0., 0., 1.],
[0., 0., 1.]], dtype=float32)
y_test[:5]
array([[1., 0., 0.],
[0., 1., 0.],
[0., 1., 0.],
[1., 0., 0.],
[0., 0., 1.]], dtype=float32)

소프트맥스 회귀 적용

from keras.models import Sequential
from keras.layers import Dense
from keras import optimizers
model = Sequential()
model.add(Dense(3, input_dim=4, activation='softmax'))
sgd = optimizers.SGD(lr=0.01)
# 학습률(learning rate, lr)은 0.01로 적용
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# 옵티마이저는 경사하강법의 일종인 adam을 사용한다.
# 손실 함수(loss function)은 평균제곱오차 크로스 엔트로피 함수를 사용
history = model.fit(X_train, y_train, batch_size=1, epochs=200, validation_data=(X_test, y_test))
# 주어진 X와 y 데이터에 대해서 오차를 최소화하는 작업을 200번 시도함.

입력의 차원은 4, 출력의 차원은 3이고, activation 함수가 softmax이다.

오차 함수로는 크로스 엔트로피 함수를 사용했다. 이진 분류 문제에서는 binary_crossentropy를 사용해야하지만, 다중 클래스 분류 문제에서는 ‘categorical_crossentropy’를 기재해줘야 한다. 옵티마이저는 경사 하강법의 일종인 adam을 사용한다. 전체 데이터에 대한 훈련 횟수는 200회로 줬다. 테스트 데이터를 별도로 분리해서 평가에 사용했는데, validation_data=()에 테스트 데이터를 기재해주면 실제로는 훈련에 반영되지 않으면서 각 훈련 횟수마다 테스트 데이터에 대한 정확도를 출력한다. 즉, 정확도가 전체 데이터에 대한 훈련 1회(1 에포크)마다 측정되고는 있지만 기계는 저 데이터를 가지고는 가중치 업데이트를 하지 않는다.

Train on 120 samples, validate on 30 samples
Epoch 1/200
120/120 [==============================] - 0s 2ms/step - loss: 2.4839 - acc: 0.6333 - val_loss: 1.2302 - val_acc: 0.80003
...
Epoch 200/200
120/120 [==============================] - 0s 1ms/step - loss: 0.1612 - acc: 0.9583 - val_loss: 0.1973 - val_acc: 1.0000

acc은 훈련 데이터에 대한 정확도이고, val_acc는 테스트 데이터에 대한 정확도를 의미한다. 훈련 데이터에서는 95%의 정확도를 보이고, 테스트 데이터에 대해서는 100%의 정확도를 보인다. 이번에는 각 에포크당 훈련 데이터와 테스트 데이터에 대한 정확도를 측정했으므로 한 번 에포크에 따른 정확도를 그래프로 출력해보자.

epochs = range(1, len(history.history['acc'])+1)
plt.plot(epochs, history.history['loss'])
plt.plot(epochs, history.history['val_loss'])
plt.title('model_loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper left')
plt.show()

에폭이 증가함에 따라 정확도가 점차적으로 줄어드는 것을 볼 수 있다. 이미 테스트 데이터에 대한 정확도를 validation_data = ()를 통해 알고는 잇지만 케라스에서 테스트 데이터의 정확도를 측정하는 용도로 제공하고 있는 evaluate()를 통해 테스트 데이터에 대한 정확도를 다시 출력해본다.

print("\n 테스트 정확도: %.4f" % (model.evaluate(X_test, y_test)[1]))
30/30 [==============================] - 0s 66us/step

테스트 정확도: 1.0000

테스트 데이터에 대해서 100%의 정확도를 얻었다.