본문 바로가기
Programming/Machine Learning

Tensorflow: regression 기본 예제 (연료 효율성 예측)

by a voyager 2020. 11. 14.
728x90
반응형

Tensorflow: regression 기본 예제 (연료 효율성 예측)

 

이 포스트는 텐서플로우를 이용한 기본적인 regression을 공부한 것을 정리한 것이다. 사용한 데이터는 엔진의 연료 효율성이다. 실린더의 개수, 이동거리, 마력, 가속력, 출시년도, 출시 국가 등의 feature 데이터가 있고, MPG(miles per gallon)가 예측값 (label)이다. 우선 데이터를 다운로드하여 신경망에 대입할 수 있는 형태로 처리할 것이다. linear regression와 뉴럴 네트워크 모델을 이용해서 MPG를 예측해 볼 것이다. 그리고 두 모델의 결과를 비교해본다. 내용은 텐서플로우 튜토리얼을 참고하였다. 

 

목표 

  • Multiple feature를 이용한 예측 모델을 공부한다.

  • Linear regression(LR)과 DNN 모델로 예측하고 두 결과를 비교해 본다. 

  • 두 방법 (LR and DNN)에서 single feature를 사용했을 때와 multiple feature를 사용했을 때의 결과를 비교한다. 

 

필요한 라이브러리들을 import한다. 

import numpy as np 
import tensorflow as tf
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns 

 

반드시 필요한 것은 아니지만 결과 출력을 알아보기 쉽게 하기 위해 소수점 이하 세째자리까지만 출력하도록 설정해 주었다. 

np.set_printoptions(precision=3, suppress=True)

 

텐서플로어 관련 라이브러리도 import 주었다. 각각의 모듈에 대한 내용은 아래에서 사용될 때 알아보도록 하자. 

from tensorflow import keras 
from tensorflow.keras import layers 
from tensorflow.keras.layers.experimental import preprocessing
print(tf.__version__)

사용된 tensorflow 버전은 2.3.0 이다. 

 

1. Get the Auto MPG (miles per gallon) data 

모델의 훈련시키기 위한 데이터를 다음의 주소로부터 다운로드하여 pandas dataframe으로 저장한다. 저장 시 각 데이터의 이름을 칼럼으로 지정해준다. 

url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data'

column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight',
                'Acceleration', 'Model Year', 'Origin']

raw_dataset = pd.read_csv(url, names=column_names,
                          na_values='?', comment='\t',
                          sep=' ', skipinitialspace=True)

 

데이터를 확인해본다. 

display(raw_dataset.head())
display(raw_dataset.tail())

출력 결과

 

칼럼명을 보면, MPG는 miles per gallon이고, displacement는 이동거리, Horsepower는 마력이 되겠다. 마지막에 Origin은 엔진을 만든 국가를 나타낸다. 1은 USA, 2는 Europe, 그리고 3은 Japan이다. 이것은 preprocessing 과정에서 원 핫 형태로 변형시킬 것이다. 

 

2. Clean the data 

raw데이터를 새 변수로 복사하고, shape으로 dimension을 확인한다.

dataset = raw_dataset.copy()
dataset.head()
print("before cleaning dataset:", dataset.shape)

이 dataset에 NA와 같은 값을 가지는 요소가 있는지 확인한다. 이것은 타당한 값을 가지는 데이터를 모델 훈련에 쓰기 위함이다. isna() 매소드를 이용해 NA 데이터를 찾아내고 dropna()으로 드롭시킨다. 

display(dataset.isna().sum())
dataset = dataset.dropna()
print("after cleaning dataset:", dataset.shape)

그리고 dataset의 크기가 398에서 392로 줄었다. 즉, NA를 포함하는 6개의 열이 삭제되었다. 

 

3.  Expand 'Origin' to three countries 

Origin 컬럼의 index를 국가명으로 map을 이용해 바꾸어준다. 

dataset['Origin'] = dataset['Origin'].map({1: 'USA', 2: 'Europe', 3: 'Japan'})
display(dataset.head())

 

위의 결과와 같이 바뀐 것을 확인한 후, get_dummies를 이용해 Origin을 3개의 feature를 갖는 one-hot encoding 형태로 변환해준다. 

dataset = pd.get_dummies(dataset, prefix='', prefix_sep='')
dataset.tail()

위 결과에서 가장 오른쪽에 유럽 일본 미국의 세 칼럼이 생긴 것을 확인한다. 

 

4. Split the data into train and test 

자 다음으로는 데이타를 훈련과 검증 세트로 나누어 준다. 대개 훈련과 검증 각각 80%과 20%의 비율로 나눈다. 여기에서는 pandas dataframe의 sample 매서드를 이용해 dataset의 80%를 train_dataset으로 할당하였고, 이때 random_state는 0으로 주었다. 따라서 dataset의 앞 80%가 훈련 세트로 지정된다. 나머지 20%은 검증을 위한 세트가 된다. 

train_dataset = dataset.sample(frac=0.8, random_state=0)
test_dataset = dataset.drop(train_dataset.index)
print("size of train_dataset is ", train_dataset.shape)
print("size of test_dataset is ",test_dataset.shape)

dataset['Origin'] = dataset['Origin'].map({1: 'USA', 2: 'Europe', 3: 'Japan'})

 

다음으로는 feature와 예측하는 label를 나누어준다.

# separate target values and the label from the features 
train_features = train_dataset.copy()
test_features = test_dataset.copy()

train_labels = train_features.pop('MPG')
test_labels = test_features.pop('MPG')

 

 

5. Create a normalization layer 

 

데이터를 훈련과 검증셋으로 나누고 feature와 label 셋으로 분리했으면, 이제 feature 데이터를 규격화만 하면 훈련 준비가 모두 끝이 난다.

 

입력 데이터의 규격화는 preprocessing.Normalization()을 이용해할 것이다. 이것에 대한 설명은 이 링크를 참고하기 바란다. 

 

우선 normalizer layer를 만든다. 

normalizer = preprocessing.Normalization()

그리고 train_features 데이타를 layer에 adapt(적용) 시켜준다. 이 과정에서 각 feature별 평균과 표준편차 값이 계산된다. 

normalizer.adapt(np.array(train_features))

 

Linear regression

1. Single inputs 

horsepower만을 이용해 MPG를 예측하는 모델을 만들고 결과를 확인한다. 신경망 모델을 만들기 전에 규격화 layer를 정의하고, horsepower 데이터로 adapt 해준다. 

horsepower = np.array(train_features['Horsepower'])
horsepower_normalizer = preprocessing.Normalization(input_shape=[1,])
horsepower_normalizer.adapt(horsepower)

 

단일 뉴런을 가지는 모델을 만들고 summary()로 구조를 확인한다. 

horsepower_model = tf.keras.Sequential([horsepower_normalizer,layers.Dense(units=1)])
horsepower_model.summary()

아래의 결과에서 Dense layer에서 훈련 가능한 매개변수가 2개인 것을 확인할 수 있다. 이것은 weight과 bias이다. 또한, normalization layer에 3개의 훈련 대상이 아닌 변수를 확인할 수 있다. 규격화 층에서 변수의 개수가 어떻게 정해지에 대해서는 나중에 공부하기로 하자. 

 

 

모델을 만들었으니 최적화 방법과 loss함수를 정의하여 컴파일한다. Adam를 optimizer로 사용하고, loss 함수는 'mean_absolute_error'로 주었다. 

horsepower_model.compile(
    optimizer=tf.optimizers.Adam(learning_rate=0.1),
    loss='mean_absolute_error')

 

이제 모델을 훈련시킬 수 있다. validation_split을 20%로 주어 훈련과 검증이 동시에 진행되도록 한다. 100번의 반복으로 모델을 훈련시켰고 verbose=0을 주어 훈련 중간 과정 출력을 생략하도록 한다. 

%%time
history = horsepower_model.fit(
    train_features['Horsepower'], train_labels,
    epochs=100,
    verbose=0,
    validation_split = 0.2)

훈련이 끝났다. 

결과를 확인한다. loss와 validation loss가 epoch에 대해서 어떻게 변했는지 확인하기 위해 다음의 함수를 만들고 두 값을 그려본다. 

def plot_loss(history):
      plt.plot(history.history['loss'], label='loss')
      plt.plot(history.history['val_loss'], label='val_loss')
      plt.ylim([0, 10])
      plt.xlabel('Epoch')
      plt.ylabel('Error [MPG]')
      plt.legend()
      plt.grid(True)

plot_loss(history)

loss와 validation loss 모두 안정적으로 감소하여 최소화 되었다. 

 

 

훈련 결과를 horsepower vs. MPG 데이타에 피팅을 통해 확인해 볼 수 있다. 

def plot_horsepower(x, y):
    plt.figure(figsize=(10,5))
    
    plt.subplot(1,2,1)
    plt.scatter(train_features['Horsepower'], train_labels, label='Data')
    plt.plot(x, y, color='k', label='Predictions')
    plt.xlabel('Horsepower')
    plt.ylabel('MPG')
    plt.legend()
    
    plt.subplot(1,2,2)
    test_predictions = horsepower_model.predict(test_features['Horsepower']).flatten()
    plt.scatter(test_labels, test_predictions)
    plt.xlabel('True Values [MPG]')
    plt.ylabel('Predictions [MPG]')
    lims = [0, 50]
    plt.xlim(lims)
    plt.ylim(lims)
    _ = plt.plot(lims, lims)

   

x = tf.linspace(0.0, 250, 251)
y = horsepower_model.predict(x)

plot_horsepower(x,y)        

(왼쪽) 피팅 결과 (오른쪽) 예측과 정답과 비교 

위 두 결과로부터 단일 feature로는 MPG의 예측의 정확도가 떨어지는 것을 확인할 수 있다. 

 

 

2. Multiple inputs 

이제는 다운 받은 데이터의 모든 feature를 이용해 MPG를 예측해 보도록 하자. 우선 모든 feature를 규격화 층에서 읽어 들이는 모델을 만든다. 

linear_model = tf.keras.Sequential([
    normalizer, 
    layers.Dense(units=1)
])

여기에서 normalizer는 앞에서 만들어 두었던 규격화 층이다. 

linear_model.summary()

 

위와 같이 모델의 구조를 보면 규격화 층의 출력 변수의 개수가 9개이고 변수는 19로 늘어났다. 이것은 총 9개의 feature를 사용한다는 것이고 19개의 훈련하지 않아도 되는 변수가 생성되었음을 뜻한다. 

 

이제 모델을 컴파일 하고 훈련시킨다.

linear_model.compile(
    optimizer=tf.optimizers.Adam(learning_rate=0.1),
    loss='mean_absolute_error')
    
%%time
history = linear_model.fit(
    train_features, train_labels, 
    epochs=100,
    verbose=0,
    validation_split = 0.2)

 

 

(왼쪽) loss 함수 profile (오른쪽) 예측값과 정답 비교 

 

위의 결과로 부터 훈련이 안정적으로 이루어졌으며, 검증 데이터를 이용한 예측 결과도 정답과 비교적 잘 맞는 것을 확인하였다. 비록 몇 개의 outlier가 보이지만 단일 feature 모델 결과에 비해 정확도가 크게 향상한 것을 알 수 있다. 

 

 

A DNN regression

이번엔 여러층으로 이루어진 Deep Neural Network 모델로 MPG를 예측해보도록 하자. 이것은 많은 뉴런을 가지는 모델로써 예측 정확도를 크게 향상 시킬 것이다. 

 

def build_and_compile_model(norm):
      model = keras.Sequential([
          norm,
          layers.Dense(64, activation='relu'),
          layers.Dense(64, activation='relu'),
          layers.Dense(1)
      ])

      model.compile(loss='mean_absolute_error',
                    optimizer=tf.keras.optimizers.Adam(0.001))
      return model

 

위와 같이 모델을 만들고 컴파일까지 한꺼번에 해주는 함수를 정의한다. 모델은 세 개의 layer로 이루어져 있고 첫 두 층엔 64개의 unit이 있고 마지막은 출력층으로 1개의 unit을 가진다. 

 

모든 feature를 이용하는 모델을 만들고 구조를 확인한다. 

dnn_model = build_and_compile_model(normalizer)
dnn_model.summary()

모델의 변수가 굉장히 많아진 것을 볼 수 있다. 약 5천개의 훈련해야 할 변수가 있다. 

 

 

모델을 훈련 시키고 결과를 확인해 보자

%%time
history = dnn_model.fit(
    train_features, train_labels,
    validation_split=0.2,
    verbose=0, epochs=100)

 

다음의 결과에서 볼 수 있듯이 훈련이 안정적으로 이루어졌으며, 예측 정확도도 향상되었다. 

 

 

 

마지막으로 모델을 평가로 앞선 linear regression 결과와 loss 값을 비교해 본다. 

test_results['dnn_model'] = dnn_model.evaluate(test_features, test_labels, verbose=0)

많은 층과 뉴런을 가지는 DNN_model의 성능이 가장 좋은 것을 확인할 수 있다. 

 

이 모델을 저장했다가, 나중에 다시 불러와 사용할 수 있다.

dnn_model.save('dnn_model')

다시 불러와 검증해 본다. 

reloaded = tf.keras.models.load_model('dnn_model')

test_results['reloaded'] = reloaded.evaluate(
    test_features, test_labels, verbose=0)

저장전과 동일한 결과를 준다. 

pd.DataFrame(test_results, index=['Mean absolute error [MPG]']).T

 

728x90
반응형

댓글