Rylah's Study & Daily Life

[TensorFlow] 02. DNN - Boston House Value 본문

Study/Deep Learning

[TensorFlow] 02. DNN - Boston House Value

Rylah 2022. 1. 23. 12:25
# 파이썬 패키지 가져오기
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

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

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# 하이퍼 파라미터
MY_EPOCH = 500
MY_BATCH = 64


########## 데이터 준비 ##########

# 데이터 파일 읽기
# 결과는 pandas의 데이터 프레임 형식
heading = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM',
           'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO',
           'LSTAT', 'MEDV']

raw = pd.read_csv('housing.csv')

# CRIM 삭제
# raw = raw.drop('CRIM', axis=1)
# raw = raw.drop('ZN', axis=1)
# heading.pop(0)
# heading.pop(1)

# 데이터 원본 출력
print('원본 데이터 샘플 10개')
print(raw.head(10))

print('원본 데이터 통계')
print(raw.describe())

# Z-점수 정규화
# 결과는 numpy의 n-차원 행렬 형식

scalar = StandardScaler()
z_data = scalar.fit_transform(raw)

# numpy 에서 pandas로 전환
# header 정보 복구 필요
z_data = pd.DataFrame(z_data, columns=heading)

# 정규화 된 데이터 출력
print('정규화 된 데이터 샘플 10개')
print(z_data.head(10))

print('정규화 된 데이터 통계')
print(z_data.describe())

# Boston 데이터 사분할
# 학습용 입력값 || 학습용 출력값
# -------------------------
# 평가용 입력값 || 평가용 출력값

# 데이터를 입력과 출력으로 분리
print('\n 분리 전 데이터 모양: ',z_data.shape)
x_data = z_data.drop('MEDV', axis=1)
y_data = z_data['MEDV']
# x_data = z_data.drop('AGE', axis=1)
# y_data = z_data['AGE']
# x_data = z_data.drop('CHAS', axis=1)
# y_data = z_data['CHAS']



# 데이터를 학습용과 평가용으로 분리
x_train, x_test, y_train, y_test = \
    train_test_split(x_data,
                     y_data,
                     test_size=0.3)

# 데이터 줄이기
# x_train = x_train.drop(x_train.index[177:])
# y_train = y_train.drop(y_train.index[177:])

print('\n학습용 입력 데이터 모양:', x_train.shape)
print('학습용 출력 데이터 모양:', y_train.shape)
print('평가용 입력 데이터 모양:', x_test.shape)
print('평가용 출력 데이터 모양:', y_test.shape)

# 상자 그림 출력
sns.set(font_scale=2)
#sns.boxplot(data=z_data, palette='dark')
#plt.show()

########## 인공 신경망 구현 ##########

# 케라스 DNN 구현
model = Sequential()
input = x_train.shape[1]
model.add(Dense(200,
                input_dim=input,
                activation='relu'))
model.add(Dense(1000,
                activation='relu'))

model.add(Dense(1))

print('\nDNN 요약')
model.summary()

########## 인공 신경망 학습 ##########

# 최적화 함수와 손실 함수 지정
model.compile(optimizer='sgd',
              loss='mse')

print('\nDNN 학습 시작')
begin = time()

model.fit(x_train,
          y_train,
          epochs=MY_EPOCH,
          batch_size=MY_BATCH,
          verbose=0)
end = time()
print('총 학습시간 : {:.1f}초'.format(end - begin))


########## 인공 신경망 평가 및 활용 ##########


# 신경망 평가 및 손실값 계산
loss = model.evaluate(x_test,
                      y_test,
                      verbose=0)

print('\nDNN 평균 제곱 오차 (MSE): {:.2f}'.format(loss))


# 신경망 활용 및 산포도 출력
pred = model.predict(x_test)
sns.regplot(x=y_test, y=pred)

plt.xlabel("Actual Values")
plt.ylabel("Predicted Values")
plt.show()

PyCharm이 keras를 default로 설정하는 버전이 2.3.1이라서 2.4.3 이상부터 잘 돌아가는 것이었다.

 

정작 가장 최신버전인 keras 2.6.0은 설치도 되지 않는다.. 유머다 유머

 

삽질을 하루정도 한거 같다. 재설치도 몇번해보고

 

예제일뿐이지만 DNN과 가장 기본적인 선형회귀, 인공신경망을 활용한 24만개 뉴런 학습을 해볼 수 있었다.

 

os 옵션은 아마 cpu avx 연산 관련 옵션을 설정해야 안나오는 것으로 추가해줬다.

 

결과는 다음과 같다.

 

더보기

원본 데이터 샘플 10개
      CRIM    ZN  INDUS  CHAS    NOX  ...  RAD  TAX  PTRATIO  LSTAT  MEDV
0  0.00632  18.0   2.31     0  0.538  ...    1  296     15.3   4.98  24.0
1  0.02731   0.0   7.07     0  0.469  ...    2  242     17.8   9.14  21.6
2  0.02729   0.0   7.07     0  0.469  ...    2  242     17.8   4.03  34.7
3  0.03237   0.0   2.18     0  0.458  ...    3  222     18.7   2.94  33.4
4  0.06905   0.0   2.18     0  0.458  ...    3  222     18.7   5.33  36.2
5  0.02985   0.0   2.18     0  0.458  ...    3  222     18.7   5.21  28.7
6  0.08829  12.5   7.87     0  0.524  ...    5  311     15.2  12.43  22.9
7  0.14455  12.5   7.87     0  0.524  ...    5  311     15.2  19.15  27.1
8  0.21124  12.5   7.87     0  0.524  ...    5  311     15.2  29.93  16.5
9  0.17004  12.5   7.87     0  0.524  ...    5  311     15.2  17.10  18.9
[10 rows x 13 columns]
원본 데이터 통계
             CRIM          ZN       INDUS  ...     PTRATIO       LSTAT        MEDV
count  506.000000  506.000000  506.000000  ...  506.000000  506.000000  506.000000
mean     3.613524   11.363636   11.136779  ...   18.455534   12.653063   22.532806
std      8.601545   23.322453    6.860353  ...    2.164946    7.141062    9.197104
min      0.006320    0.000000    0.460000  ...   12.600000    1.730000    5.000000
25%      0.082045    0.000000    5.190000  ...   17.400000    6.950000   17.025000
50%      0.256510    0.000000    9.690000  ...   19.050000   11.360000   21.200000
75%      3.677083   12.500000   18.100000  ...   20.200000   16.955000   25.000000
max     88.976200  100.000000   27.740000  ...   22.000000   37.970000   50.000000
[8 rows x 13 columns]
정규화 된 데이터 샘플 10개
       CRIM        ZN     INDUS  ...   PTRATIO     LSTAT      MEDV
0 -0.419782  0.284830 -1.287909  ... -1.459000 -1.075562  0.159686
1 -0.417339 -0.487722 -0.593381  ... -0.303094 -0.492439 -0.101524
2 -0.417342 -0.487722 -0.593381  ... -0.303094 -1.208727  1.324247
3 -0.416750 -0.487722 -1.306878  ...  0.113032 -1.361517  1.182758
4 -0.412482 -0.487722 -1.306878  ...  0.113032 -1.026501  1.487503
5 -0.417044 -0.487722 -1.306878  ...  0.113032 -1.043322  0.671222
6 -0.410243  0.048772 -0.476654  ... -1.505237 -0.031268  0.039964
7 -0.403696  0.048772 -0.476654  ... -1.505237  0.910700  0.497082
8 -0.395935  0.048772 -0.476654  ... -1.505237  2.421774 -0.656595
9 -0.400729  0.048772 -0.476654  ... -1.505237  0.623344 -0.395385
[10 rows x 13 columns]
정규화 된 데이터 통계
               CRIM            ZN  ...         LSTAT          MEDV
count  5.060000e+02  5.060000e+02  ...  5.060000e+02  5.060000e+02
mean  -8.513173e-17  3.306534e-16  ... -1.595123e-16 -4.247810e-16
std    1.000990e+00  1.000990e+00  ...  1.000990e+00  1.000990e+00
min   -4.197819e-01 -4.877224e-01  ... -1.531127e+00 -1.908226e+00
25%   -4.109696e-01 -4.877224e-01  ... -7.994200e-01 -5.994557e-01
50%   -3.906665e-01 -4.877224e-01  ... -1.812536e-01 -1.450593e-01
75%    7.396560e-03  4.877224e-02  ...  6.030188e-01  2.685231e-01
max    9.933931e+00  3.804234e+00  ...  3.548771e+00  2.989460e+00
[8 rows x 13 columns]
 분리 전 데이터 모양:  (506, 13)
학습용 입력 데이터 모양: (354, 12)
학습용 출력 데이터 모양: (354,)
평가용 입력 데이터 모양: (152, 12)
평가용 출력 데이터 모양: (152,)

DNN 요약
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 200)               2600      
_________________________________________________________________
dense_1 (Dense)              (None, 1000)              201000    
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 1001      
=================================================================
Total params: 204,601
Trainable params: 204,601
Non-trainable params: 0
_________________________________________________________________
DNN 학습 시작
총 학습시간 : 3.4초
DNN 평균 제곱 오차 (MSE): 0.14

현재 목표는 기본적인 학습 방법을 익히고 나중에는 방법을 고안하고 데이터셋을 짜고 하는 것이 필요한 분야로 느껴진다.

 

Relu, SGN 등이 사용되었다.

 

위에 결과는 학습을 500번 정도 수행한 결과이다.

 

MY_EPOCH를 0으로 바꾸면 산포도가 이렇게 변한다.

 

또한 MSE도 이렇게 변했다.

 

DNN 평균 제곱 오차 (MSE): 0.14 (이전 : 500)

DNN 평균 제곱 오차 (MSE): 1.03 (이후 : 0)

 

학습을 안하는 것은 이렇게 의미가 적다.

 

또한 EPOCH를 2000으로 올리니 변화가 이렇다.

 

MSE 또한 이렇게 달라졌다.

총 학습시간 : 12.7초
DNN 평균 제곱 오차 (MSE): 0.09

 

결과만 요약하면 다음과 같다.

 

사용한 PC의 사양은 다음과 같다.

Ryzen 9 5900X

GTX3070 8GB

  EPOCH = 0 / BATCH = 16 EPOCH = 500 / BATCH = 16 EPOCH = 2000 / BATCH = 16
total_time 0.1 sec 8.4 sec 32.5 sec
MSE 1.14 0.14 0.16
  EPOCH = 0 / BATCH = 64 EPOCH = 500 / BATCH = 64 EPOCH = 2000 / BATCH = 64
total_time 0.1 sec 3.4 sec 11.9 sec
MSE 0.94 0.20 0.20

64개씩 메모리 연산을 진행하는 것과 16개를 진행하는 것은 데이터 셋의 차이가 4배 차이나는 만큼의 시간은 아니지만 약 3배의 시간이 연산이 더 수행되었고, 오차 MSE는 그만큼 줄어든 것을 알 수 있다.

 

데이터 셋에서 유의미한 변화가 느껴지는 구간 이후에는 MSE가 줄어들지는 않는다.

 

이 것은 원본 데이터셋에서 나올 수 있는 오차 한계에 들어갔다고 봐도 될 것이다.

 

여기서 은닉층을 확대하면 

 

240000개의 학습 뉴런이 95만개까지 늘려봤다.

 

결과는 학습 시간은 3.4초 -> 13.4초  MSE는 0.2 -> 0.1로 줄었다.