본문 바로가기
ML, DL, RL

[DL] Regression about Boston House Prices with Keras

by llHoYall 2020. 11. 14.

회귀는 특징이 있는 여러 데이터들을 기반으로 수치를 예측하는 것입니다.

여기서 사용할 또 하나의 유명 데이터세트인 보스턴 집값 데이터를 예로 들자면, 이런이런 특징이 있는 집들의 가격이 이거니까 학습해!

라고 한 후, 요렇게 학습된 모델에 이런이런 특징이 있는 집은 가격이 얼마일까? 라고 물으면 기존 집들과 비교해 봤을 때 얼마쯤 하겠네~

라고 답을 하는 것이죠.

그럼 이것을 Keras를 사용하여 DNN을 만들어서 해봅시다.

Input Dataset

Getting Dataset

역시 케라스에는 이미 포함이 되어 있어 쉽게 가져올 수 있습니다.

from keras.datasets import boston_housing

(train_data, train_labels), (test_data, test_labels) = boston_housing.load_data()

Analyzing Dataset

데이터세트를 가져왔으니 어떻게 생겼는지 분석해봐야겠죠?

print(train_data.shape, train_labels.shape)
# (404, 13) (404,)

print(test_data.shape, test_labels.shape)
# (102, 13) (102,)

13개의 특징을 가진 데이터가 학습용으로 404개, 테스트 용으로 102개가 들어있군요.

레이블은 아마도 가격이 아닐까 싶네요.

한 번 이 데이터들을 실제로 까보도록 합시다.

import pandas as pd

print(train_labels[:5])
# [15.2 42.3 50.  21.1 17.7]

column_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT']
df = pd.DataFrame(train_data, columns=column_names)
df.head()

 

데이터 분석에 주로 쓰이는 pandas를 사용했습니다.

데이터세트에 대한 설명은 이곳을 참고하세요.

 

Boston Dataset

The Boston Housing DatasetA Dataset derived from information collected by the U.S. Census Service concerning housing in the area of Boston Mass. This dataset contains information collected by the U.S Census Service concerning housing in the area of Boston

www.cs.toronto.edu

 

예상대로 레이블에는 가격이 들어있고, 데이터에는 각각의 지표들에 대한 수치 값이 들어있네요.

Preprocessing Dataset

학습을 할 때, 비슷한 데이터들을 연속해서 학습하게 되면 편항이 됩니다.

따라서 학습 데이터들을 적절하게 섞어주는 것이 필요하죠.

import numpy as np

order = np.argsort(np.random.random(train_labels.shape))
train_data = train_data[order]
train_labels = train_labels[order]

numpy 모듈을 사용해 랜덤한 순서로 뒤섞었습니다.

 

이제 데이터들을 비교하기 쉽게 표준화를 해 봅시다.

서로 다른 범위를 갖고 있다면, 직접적인 비교가 어렵기 때문에 이를 동일한 범위를 갖도록 해주는 작업입니다.

평균 0, 표준편차 1로 정규화를 시켜보겠습니다.

numpy 모듈에서 제공을 하기 때문에, 쉽게 하실 수 있습니다.

mean = train_data.mean(axis=0)
std = train_data.std(axis=0)
train_data = (train_data - mean) / std

mean = test_tata.mean(axis=0)
std = test_data.std(axis=0)
test_data = (test_data - mean) / std
표준화된 데이터 = (원래의 데이터 - 평균) / 표준편차

위와 같은 공식을 사용하였습니다.

이제 모든 처리가 완료된 데이터세트를 확인해 볼까요?

데이터 준비가 끝났으니 이젠 모델을 생성해 볼 시간이네요.

Model

Generating Model

from keras.models import Sequential
from keras.layers import Dense

model = Sequential()
model.add(Dense(64, activation='relu', input_shape=(13,)))
model.add(Dense(64, activation='relu'))
model.add(Dense(1))

입력 레이어, 히든 레이어, 출력 레이어 각 1개씩 전결합 (Fully-Connected) 레이어로 만들었습니다.

활성화 함수로는 ReLU를 사용했습니다. 가장 무난하게 좋은 성능을 낼 수 있다고 알려져있죠. ^^

많이 쓰이는 함수인 만큼 연구도 많이 되어서 Leaky-ReLU등 변종도 무수히 많아요.

저도 책만 열댓권 본거라 실무에서는 뭐가 대세인지 궁금하긴 하네요 ^^;;

Compiling Model

from keras.optimizers import Adam

model.compile(loss='mse', optimizer=Adam(lr=0.001), metrics=['mae'])

손실 함수로는 MSE (Mean Square Error) 함수를 사용했고, 최적화 함수로는 학습률 0.001의 Adam을 사용했습니다.

Adam도 상당히 자주 쓰이는 함수로 알고 있고, 변종 역시 존재하는 걸로 알고 있습니다.

평가 지표로는 MAE (Mean Absolute Error)를 사용했습니다.

Training

이제 준비한 데이터와 모델을 사용하여 학습시켜 봅시다.

from keras.callbacks import EarlyStopping

early_stop = EarlyStopping(monitor='val_loss', patience=20)
history = model.fit(train_data, train_labels, epochs=500, validation_split=0.2, callbacks=[early_stop])

중복되는 내용은 다음 포스팅을 참고하세요.

2020/11/10 - [DeepLearning] - Classifying Handwriting with Keras

EarlyStopping 함수는 아주 기특한 함수죠.

지정한 epoch만큼 반복하는 동안 학습 오차에 개선이 없다면 자동으로 학습을 종료합니다.

위 예에서는 val_loss를 모니터링하여 20번의 epoch동안 개선이 없다면 종료하게 됩니다.

이것을 fit 메소드에 넘겨주어 학습을 하는 동안 사용을 하게 됩니다.

 

이제 학습 결과를 살펴봅시다.

import matplotlib.pyplot as plt
%matplotlib inline

plt.plot(history.history['mae'], label='train mae')
plt.plot(history.history['val_mae'], label='val mae')
plt.xlabel('epoch')
plt.ylabel('mae [$1,000]')
plt.legend(loc='best')
plt.ylim([0, 5])
plt.show()

어느 정도 학습이 진행되다가 더이상 학습이 진행되지 않자 멈추었네요.

Evaluation

이제 테스트용 데이터세트로 학습이 잘 되었는지 확인을 해봐야겠죠?

test_loss, test_mae = model.evaluate(test_data, test_labels)
# 4/4 [==============================] - 0s 2ms/step - loss: 18.0921 - mae: 2.8793

Prediction

우리 모델이 어떻게 회귀 예측을 했는지 직접 눈으로 살펴봅시다.

print(np.round(test_labels[:10]))
# [ 7. 19. 19. 27. 22. 24. 31. 23. 20. 23.]

test_predictions = model.predict(test_data[:10]).flatten()
print(np.round(test_predictions))
# [ 8. 19. 23. 29. 26. 21. 26. 23. 19. 19.]

 

만족스럽진 않지만, 그럭저럭 실제 가격과 비슷한 가격을 예상하네요.

 

이제 이것저것 건드려 보면서 감을 익힐 시간입니다. ^^

즐겨보세요~ 필요한 것들은 대부분 이미 케라스에 있을거에요. ^^

댓글