KNOU STUDYREAD

한국방송통신대학교 통계데이터과학과 블로그

CS & Department of Statistics and Data Science

통계데이터과학과 및 컴퓨터과학 독서

08. 딥러닝 13-15장

Harryㅤ 2023. 12. 11.

 

과적합(Overfitting) : 훈련에 사용한 데이터에 진행된 학습이 지나치게 진행된 것을 의미. 이는 일반화 오류를 크게 할 수 있으며 복잡도가 오히려 증가할 수 있다.

1) 층이 너무  많을 때 발생
2) 변수가 복잡할 때 발생
3) 테스트와 학습 데이터의 중복일때 발생

과적합(Overfitting) 방지 방법 : 학습을 할 때 사용할 데이터셋과 테스트 전용 데이터셋을 구분. 주로 학습셋과 테스트셋을 분리하기 위해 사이킷런을 사용하고 여기서 train_test_split() 함수를 적용한다.

from sklearn.model_selection import train_test_split

# 학습셋과 테스트셋을 각각 구분, 0.3은 전체 데이터의 30%를 테스트셋으로, 나머지 70(0.7)은 학습셋으로 나눔
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True)


암석과 광물 구분하기

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split

import pandas as pd

# 깃허브 데이터 import
!git clone https://github.com/taehojo/data.git

# 광물 데이터 import
df = pd.read_csv('./data/sonar3.csv', header=None)

# X = 음파 관련 속성, Y = 광물의 종류
X = df.iloc[:,0:60]
y = df.iloc[:,60]

# 학습셋과 테스트셋을 사이킷런의 train_test_split() 함수 사용해 분리
# 전체 데이터의 30%는 테스트셋, 나머지 70%는 학습셋 데이터로 지정
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True)

# 모델 설정(Sequential())
model = Sequential()
model.add(Dense(24, input_dim=60, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

# 모델을 컴파일
# 손실함수, 옵티마이저, 정확도 여부 설정
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# 모델 실행(model.fit())
# 시행횟수는 200회, 각 반복 회당 배치 사이즈 크기는 10 단위로 시행
history = model.fit(X_train, y_train, epochs=200, batch_size=10)

# 모델을 테스트셋 적용후 결과 값 출력
score = model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])

 

모델 성능 향상 방법 : 데이터 보강과 알고리즘 최적화 방식

데이터 보강 방법알고리즘 최적화 방법
데이터가 많이 필요. 샘플 수가 많아질 수록 성능이 좋아짐

* 데이터의 크기가 크거나 추가가 어려울 경우 가진 데이터를 적절히 보완하는 방법 사용(시그모이드 함수를 사용해 0~1 사이의 값으로 변환하여 낮은 이상치 배제 혹은 사진 데이터의 경우 사진 크기 축소확대한 것으로도 데이터 인식 대체. 또는 교차 검증 방법이 있음)
다른 구조로 모델을 변경하며 가장 맞는 최적 구조를 찾는 방법.

 

5겹 교차 검증 예시


K겹 교차 검증 : 데이터셋을 여러개로 나눈 뒤 하나씩 테스트셋으로 사용하고 나머지를 모두 합한 뒤 학습셋으로 사용
* 주어진 데이터의 100%를 학습셋과 데이터셋으로 모두 사용 가능.


암석과 광물 구분하기 5겹 교차 검증

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score

import pandas as pd

# 깃허브 데이터 import
!git clone https://github.com/taehojo/data.git

# 광물 데이터 import
df = pd.read_csv('./data/sonar3.csv', header=None)

# X = 음파 관련 속성, Y = 광물의 종류
X = df.iloc[:,0:60]
y = df.iloc[:,60]

# K겹 교차 검증 수 설정
# 5겹인 경우 4개를 학습셋, 나머지 하나를 테스트셋으로 나누어 반복 실시
k = 5

# KFold 함수설정
# 데이터를 원하는 수 만큼 나누어 테스트와 학습셋으로 나누는 사이킷런 제공함수 => KFold()
# 샘플의 치우침 방지를 위해 Shuffle 옵션에 트루값 설정
kfold = KFold(n_splits=k, shuffle=True)

# 반복될 때마다 구한 정확도를 각 정확도 리스트에 설정
acc_score = []

def model_fn():
    model = Sequential() # 딥러닝 모델 구조 설계
    model.add(Dense(24, input_dim=60, activation='relu'))
    model.add(Dense(10, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    return model

# k겹 교차 검증을 이용해 k번의 학습을 실행
# split()함수로 학습셋, 테스트셋으로 분리
for train_index, test_index in kfold.split(X): 
    X_train, X_test = X.iloc[train_index,:], X.iloc[test_index,:]  
    y_train, y_test = y.iloc[train_index], y.iloc[test_index]

    model = model_fn()
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    history = model.fit(X_train, y_train, epochs=200, batch_size=10, verbose=1) 
    # verbose 옵션은 학습 과정 출력을 생략(0) 할 것인지 말 것인지(1) 결정
    
    accuracy = model.evaluate(X_test, y_test)[1] # 정확도 산출
    acc_score.append(accuracy)                   # 정확도 리스트에 저장

# k번 실시된 정확도의 평균 산출
avg_acc_score = sum(acc_score) / k

# 결과 출력
print('정확도: ', acc_score)
print('정확도 평균: ', avg_acc_score)

5번 시행에 따라 각각 산출된 정확도가 각 리스트에 저장되고, 저장된 5개의 최종 정확도의 평균이 83% 정도로 나온 것을 알 수 있다.
K겹 교차 검증은 기존에 학습셋 30%, 테스트셋 70%로 나눴을 때보다 모든 데이터를 한 번씩 학습셋과 테스트셋으로 데이터를 활용함으로써 미사용될 데이터 세트에 대한 문제를 해결하고, 보다 더 정확한 정확도를 검출할 수 있다는 장점이 있다.


와인 종류 예측하기
학습셋과 테스트셋을 나누고 여기에 검증셋 데이터를 추가하는 방법 : model.fit() 함수 내에 validation_split 옵션을 추가해 만들 수 있음.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split

# 깃허브에 준비된 데이터 import
!git clone https://github.com/taehojo/data.git

# 와인 데이터 불러와 df 라는 변수에 저장
df = pd.read_csv('./data/wine.csv', header=None)

# X = 와인의 속성, Y = 와인의 분류 저장
X = df.iloc[:,0:12]
y = df.iloc[:,12]

# 학습셋과 테스트셋으로 분리
# shuffle 옵션 True 설정
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)

# 모델 구조 설정
model = Sequential()
# 3개의 은닉층 설정. 30, 12, 8개의 노드 생성. 활성화 함수 Relu
model.add(Dense(30, input_dim=12, activation='relu'))
model.add(Dense(12, activation='relu'))
model.add(Dense(8, activation='relu'))
# 1개의 출력층 설정. 활성화 함수 시그모이드
model.add(Dense(1, activation='sigmoid'))
model.summary()

# 모델 컴파일
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# 모델 실행
history = model.fit(X_train, y_train, epochs=50, batch_size=500, 
validation_split=0.25) # 0.8 x 0.25 = 0.2

# 테스트 결과 출력
score = model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])

에포크(epochs) : 흔히 수행하는 학습 단위를 말하지만, 에포크를 항상 많이 한다해서 이것이 정확도와 비례하지는 않는다.

에포크 실행도중 중간에 가장 높은 정확도가 산출되고 이때의 모델을 중간저장하고 싶다면 케라스에서 제공하는 ModelCheckpoint() 함수를 통해 저장할 수 있다. 이때 verbose 옵션을 True(1) 값을 설정해서 저장되는 현황을 출력할 수 있다.

학습 자동중단 : 학습 도중 테스트셋의 오차가 커지는 경우, 줄어들지 않는 경우 임의로 학습을 자동중단해서 멈추게 할 수 있다.

케라스에서 제공하는 EarlyStopping() 함수를 통해서 수행한다.

자동중단을 사용해 전체 2000회의 에포크 시행 도중 394번째까지만 학습 후 중단된 결과를 확인할 수 있다.


주택 가격 예측하기

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.callbacks import EarlyStopping
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
import seaborn as sns

import pandas as pd
import numpy as np

# 깃허브 데이터 import
!git clone https://github.com/taehojo/data.git

# 집 값 데이터를 불러와 df 변수에 저장
df = pd.read_csv("./data/house_train.csv")

# 카테고리형 변수를 0과 1로 이루어진 변수로 변환
df = pd.get_dummies(df)

# 결측치를 전체 칼럼의 평균으로 대체
df = df.fillna(df.mean())

# 데이터 사이의 상관관계(correlation 저장)
df_corr = df.corr()

# 집 값과 관련이 큰 것부터 나열
df_corr_sort = df_corr.sort_values('SalePrice', ascending=False)

# 집 값을 제외한 나머지 열을 저장
cols_train = ['OverallQual','GrLivArea','GarageCars','GarageArea','TotalBsmtSF']
X_train_pre = df[cols_train]

# 집 값을 저장
y = df['SalePrice'].values

# 전체의 80%를 학습셋으로, 20%를 테스트셋으로 분리
X_train, X_test, y_train, y_test = train_test_split(X_train_pre, y, test_size=0.2)

# 모델 구조 설정
model = Sequential()
model.add(Dense(10, input_dim=X_train.shape[1], activation='relu'))
model.add(Dense(30, activation='relu'))
model.add(Dense(40, activation='relu'))
model.add(Dense(1))
model.summary()

# 모델 실행
# 손실함수 mean_squared_error(이하 MSE)사용 -> 선형회귀이므로 평균 제곱 오차 손실함수 사용
model.compile(optimizer='adam', loss='mean_squared_error')

# 20번 이상 결과가 향상되지 않으면 자동중단 설정
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=20)

# 모델의 이름설정
modelpath = "./data/model/Ch15-house.hdf5"

# 최적화 모델을 업데이트후 저장
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='val_loss', verbose=0, save_best_only=True)

# 전체의 20%를 검증셋으로 설정
history = model.fit(X_train, y_train, validation_split=0.25, epochs=2000, batch_size=32, callbacks=[early_stopping_callback,checkpointer])

훈련 도중 145번째에서 학습을 중단했으며 이를 바탕으로 상관관계 도출 가능

real_prices = [] # 실제가격 리스트
pred_prices = [] # 예상가격 리스트
X_num = []

n_iter = 0
Y_prediction = model.predict(X_test).flatten()
for i in range(25):
    real = y_test[i]
    prediction = Y_prediction[i]
    print("실제가격: {:.2f}, 예상가격: {:.2f}".format(real, prediction))
    real_prices.append(real)
    pred_prices.append(prediction)
    n_iter = n_iter + 1
    X_num.append(n_iter)

실제가격과 예상가격의 결과를 바탕으로 그래프로 시각화(plot() 사용)

plt.plot(X_num, pred_prices, label='predicted price')
plt.plot(X_num, real_prices, label='real price')
plt.legend() # 범례표시
plt.show()

집 값이 추정치와 실제값이 유사한 것을 확인 가능

'통계데이터과학과 및 컴퓨터과학 독서' 카테고리의 다른 글

10. 딥러닝 19-21장  (0) 2023.12.25
09. 딥러닝 16-18장  (1) 2023.12.18
07. 딥러닝 10-12장  (0) 2023.12.04
06. 딥러닝 7-9장  (0) 2023.11.27
05. 딥러닝 6장  (0) 2023.11.20