728x90
반응형

보스턴 주택 가격 데이터셋

  • 1970년 중반 보스턴 외곽 지역의 범죄율, 지방세율 등의 데이터
  • 데이터 포인트가 506개로 404개 훈련 샘플, 102개가 테스트 샘플로 나뉘어 있다.
  • 입력 데이터에 있는 특성(feature)은 스케일이 서로 다르다.
    • 0과1사이, 1과12사이, 1과 100사이의 값도 있다.
# 보스턴 주택 가격 데이터셋

from tensorflow.keras.datasets import boston_housing

(train_data, train_targets), (test_data, test_targets) = boston_housing.load_data()

print("train_data.shape : ",train_data.shape, "test_data.shape : ",test_data.shape)

print("train_targets: ", train_targets[:10]) # 대략 1만 달러에서 5만 달러 사이 - 70년대라서 인플레이션에 영향을 받지 않았다.

[그림1] 보스턴 주택 가격 데이터셋 훈련, 테스트 샘플, 주택 가격 확인

  • 13개의 수치 특성(feature)가 있다.
    • 1인당 범죄율, 주택당 편균 방의 개수, 고속도로 접근성 등이다.
  • 주택 가격은 1970년대에서는 인플레이션에 영향을 받지 않아서 그렇다.

 

데이터 준비

  • 상이한 스케일을 가진 값을 신경망에 주입하면 문제가 된다.
  • 특성별로 정규화를 하는 방법이 있다.
    • 입력 데이터에 있는 각 특성(입력 데이터 행렬의 열)에 대해서 특성의 평균을 빼고 표준 편차로 나눈다.
    • 특성의 중앙이 0근처로 표준 편차가 1이 된다.
# 데이터 정규화하기

mean = train_data.mean(axis=0) # 열
train_data -= mean # 평균을 빼기
std = train_data.std(axis = 0) # 표준편차
train_data /= std # 표준 편차로 나누기

test_data -= mean # 테스트 샘플도 똑같이 평균 빼기
test_data /= std # 표준 편차로 나누기

 

 

모델 정의

# 모델 정의
from tensorflow.keras import models,layers

def build_model(): #동일한 모델 여러 번 생성할 예정
    model = models.Sequential()
    model.add(layers.Dense(64, activation='relu',
                          input_shape=(train_data.shape[1],)))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(1)) # 활성화 함수가 없다. 선형층이라고도 부른다.
    # 전형적인 스칼라 회귀(하나의 연속적인 값을 예측하는 회귀)를 위한 구성이다.
    # 활성화 함수를 사용시 제한된 값을 예측하므로 x
    model.compile(optimizer = 'rmsprop',
                loss='mse', metrics=['mae'])
    return model
  • mse 손실 함수를 사용해 컴파일
  • 평균 제곱 오차(mean squared error)의 약어로 예측과 타깃 사이 거리의 제곱이다.
    • 회귀문제에서 널리 사용되는 손실 함수
  • 훈련동안에는 평균 절대 오차(Mean Absolute Error, MAE)를 측정한다.
    • 예측과 타깃 사이 거리의 절댓값이다.
    • 0.5면 500달러의 차이

 

K-겹 검증을 사용한 훈련 검증

  • 데이터 샘플이 얼마 없을 경우 K-겹 교차 검증(K-fold cross-validation)을 사용하는 방법이 있다.
  • 데이터를 K개의 분할(즉 폴드(fold))로 나누고(일반적으로 K = 4 or 5), K개의 모델을 각각 만들어 K-1개의 분할에서 훈련하고 나머지 분할에서 평가하는 방법이다.

 

K=5 일 경우의 K-겹 교차 검증

[그림1] 5-겹 교차 검증 

  • 데이터를 5개의 분할로 나누고 훈련4 검증1로 나오게 만들고 결과 5개를 합쳐 최종 점수 : 평균을 만든다.

 

K-겹 검증

# K-겹 검증

import numpy as np
k=4

num_val_samples = len(train_data) // k
num_epochs = 100
all_scores = []

for i in range(k):
    print('처리중인 폴드 #',i)
    val_data = train_data[i * num_val_samples : (i+1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples : (i+1) * num_val_samples]
    
    partial_train_data = np.concatenate( # 훈련 데이터 준비 : 다른 분할 전체
        [train_data[:i * num_val_samples],
        train_data[(i+1) * num_val_samples:]],
        axis = 0
    )
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
        train_targets[(i+1) * num_val_samples:]],
         axis = 0
    )
    
    model = build_model() # 케라스 모델 구성 컴파일 포함
    model.fit(partial_train_data, partial_train_targets,
             epochs = num_epochs, batch_size =1, verbose = 0) # 모델 훈련(vervose=0)과정이 출력되지 않는다.
    val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)
    all_scores.append(val_mae)
    
print(all_scores)
print(np.mean(all_scores))

[그림2] 폴드 과정과 결과 

  • 평균 2550달러정도 차이가 난다.
    • 주택 가격은 1만~5만 달러이므로 비교적 큰 값이다.

 

검증 점수 로그에 저장

num_epochs = 500
all_mae_histories = []
for i in range(k):
    print('처리중인 폴드 #', i)
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]  #검증 데이터 준비: k번째 분할    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]
    partial_train_data = np.concatenate(  # 훈련 데이터 준비: 다른 분할 전체
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

model = build_model()  # 케라스 모델 구성(컴파일 포함)
history = model.fit(partial_train_data, partial_train_targets,  # 모델 훈련(verbose=0이므로 훈련 과정이 출력되지 않습니다.)
                    validation_data=(val_data, val_targets),
                    epochs=num_epochs, batch_size=1, verbose=0)
mae_history = history.history['mae']
all_mae_histories.append(mae_history)

 

평균 기록

# 평균 기록
average_mae_history = [
    np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

 

검증 점수 그래프

# 검증 점수 그래프

import matplotlib.pyplot as plt

plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)

plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()

[그림3] 검증 점수 그래프

  • 변동이 심해 보기 어려울 경우
  • 곡선의 다른 부분과 스케이링 많이 다른 첫 10개의 데이터 포인트를 제외시킨다.
  • 부드러운 곡선을 얻기 위해 각 포인트를 이전 포인트를 이전 포인트의 지수 이동 평균(exponential moving average)으로 대체한다.

 

# 처음 10개 데이터 포인트 제외한 검증 점수 그리기

def smooth_curve(points, factor=0.9):
    smoothed_points = []
    for point in points:
        if smoothed_points:
            previous = smoothed_points[-1]
            smoothed_points.append(previous * factor + point * (1-factor))
        else:
            smoothed_points.append(point)
    return smoothed_points
    
smooth_mae_history = smooth_curve(average_mae_history[10:])

plt.plot(range(1, len(smooth_mae_history)+1), smooth_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()

[그림4] 처음 10개 제외

 

# 최종 모델 훈련

model = build_model()
model.fit(train_data, train_targets,
         epochs = 80, batch_size = 16, verbose=0)

test_mse_score, test_mae_score = model.evaluate(test_data, test_targets)

print("test_mae_score : ",test_mae_score, "test mse_score : ", test_mse_score)

[그림5] 최종 모델 훈련

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기