본문 바로가기

이론/모두의 딥러닝

< 넷째 마당 > 딥러닝 기본기 다지기

10장 딥러닝 모델 설계하기

모델

실습| 폐암 수술 환자의 생존율 예측하기

# 텐서플로 라이브러리 안에 있는 케라스 API에서 필요한 함수들을 불러옵니다.
from tensorflow.keras.models import Sequential  
from tensorflow.keras.layers import Dense   

# 데이터를 다루는 데 필요한 라이브러리를 불러옵니다.
import numpy as np
# 깃허브에 준비된 데이터를 가져옵니다.
!git clone https://github.com/taehojo/data.git   

# 준비된 수술 환자 데이터를 불러옵니다.
Data_set = np.loadtxt("./data/ThoraricSurgery3.csv", delimiter=",")  
X = Data_set[:,0:16]    # 환자의 진찰 기록을 X로 지정합니다.
y = Data_set[:,16]      # 수술 1년 후 사망/생존 여부를 y로 지정합니다.
# 딥러닝 모델의 구조를 결정합니다.
model = Sequential()                                                   
model.add(Dense(30, input_dim=16, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 딥러닝 모델을 실행합니다.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) 
history=model.fit(X, y, epochs=5, batch_size=16)
 
첫 번째 Dense는 입력층과 첫 번째 은닉층을 , 두 번째 Dense는 출력층을 의미

대표적인 오차 함수

모델 컴파일

- metrics () 함수: 모델이 컴파일될 때 모델 수행의 결과를 나타내게끔 설정하는 부분입니다. accuracy라고 설정한 것은 학습셋에 대한 정확도에 기반해 결과를 출력하라는 의미입니다. loss는 손실 값, val_acc는 테스트셋에 대한 정확도, val_loss는 테스트셋에 대한 손실 값을 나타낸다.

 

모델 실행하기

 주어진 폐암 수술 환자의 수술 후 생존 여부 데이터는 총 470명의 환자에게서 16개의 정보를 정리한 것입니다. 이때 각 정보를 '속성'이라고 합니다. 그리고 생존 여부를 클래스, 가로 한 줄에 해당하는 각 환자의 정보를 각각 '샘플'이라고 합니다. 주어진 데이터에는 총 470개의 샘플이 각각 16개씩의 속성을 가지고 있습니다.

* 이 용어는 출처마다 조금씩 다르다. 예를 들어 샘플을 instance 또는 example이라고도 하며, 속성 대신 피처 또는 특성이라고도 합니다.

 

- batch_size: 샘플을 한 번에 몇 개씩 처리할지 정하는 부분.(컴퓨터 메모리가 감당할 만큼의 사이즈를 찾아 설정해 주는 것이 좋습니다.)

 

12장 다중 분류 문제 해결하기

다중 분류 문제

: 여러 개의 답 중 하나를 고르는 분류 문제

 

데이터의 구조

 

상관도 그래프

pandas 이용

seaborn 이용

- pairplot() 함수 설정 중 hue 옵션은 주어진 데이터 중 어떤 카테고리를 중심으로 그래프를 그릴지 정해줌.

- 대각선 위치에 있는 그림은 가로축과 세로축이 같으므로 단순히 해당 속성에 따라 각 품종들이 어떻게 분포하는지 보여줌.

 

원-핫 인코딩

 딥러닝 계산을 위해 문자를 모두 숫자형으로 바꾸어 주어야 한다.

 먼저 아이리스 꽃의 종류는 1 처럼 세 종류입니다. 그러면 2 처럼 각각의 이름으로 세 개의 열을 만든 후 3 처럼 자신의 이름이 일치하는 경우 1로, 나머지는 0으로 바꾸어 줍니다.

 여러 개의 값으로 된 문자열을 0과 1로만 이루어진 형태로 만들어 주는 과정을 원-핫 인코딩이라고 합니다.

 get_dummies() 함수를 사용하면 간단하게 해낼 수 있다.

소프트맥스

 출력 값이 하나면 되는 이항 분류와 다르게 다항 분류는 각 샘플마다의 확률을 따로따로 구해야 합니다. 예를 들어 예측 결과는 다음과 같습니다.

 소프트맨스 함수는 각 항목당 예측 확률을 0과 1 사이의 값으로 나타내 주는데, 이때 각 샘플당 예측 확률의 총합이 1인 형태로 바꾸어 주게 됩니다. 다항 분류에서는 손실 함수도 categorical_crossentropy를 사용합니다.

 

아이리스 품종 예측의 실행

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

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# 깃허브에 준비된 데이터를 가져옵니다. 앞에서 이미 가져왔으므로 주석 처리합니다. 5번 예제만 별도 실행 시 주석을 해제한 후 실행해주세요.

# 아이리스 데이터를 불러옵니다.
df = pd.read_csv('./data/iris3.csv')

# 속성을 X, 클래스를 y로 저장합니다.
X = df.iloc[:,0:4]
y = df.iloc[:,4]

# 원-핫 인코딩 처리를 합니다.
y = pd.get_dummies(y)

# 모델 설정
model = Sequential()
model.add(Dense(12,  input_dim=4, activation='relu'))
model.add(Dense(8,  activation='relu'))
model.add(Dense(3, activation='softmax'))
model.summary()

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

# 모델 실행
history=model.fit(X, y, epochs=30, batch_size=5)

13장 모델 성능 검증하기

데이터의 확인과 예측 실행

 일반 암석일 경우 0, 광석일 경우 1.

 일반 광석과 광석이 각각 몇 개나 포함되어 있는지 알아보자.

실습| 초음파 광물 예측하기: 데이터 확인과 실행

import pandas as pd

# 깃허브에 준비된 데이터를 가져옵니다.
!git clone https://github.com/taehojo/data.git

# 광물 데이터를 불러옵니다.
df = pd.read_csv('./data/sonar3.csv', header=None)

# 첫 5줄을 봅니다. 
df.head()
# 일반 암석(0)과 광석(1)이 몇 개 있는지 확인합니다.
df[60].value_counts()
# 음파 관련 속성을 X로, 광물의 종류를 y로 저장합니다.
X = df.iloc[:,0:60]
y = df.iloc[:,60]
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

# 모델을 설정합니다.
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'])

# 모델을 실행합니다.
history=model.fit(X, y, epochs=200, batch_size=10)

과적합 이해하기

: 모델이 학습 데이터셋 안에서는 일정 수준 이상의 예측 정확도를 보이지만, 새로운 데이터에 적용하면 잘 맞지 않는 것을 의미합니다.

- 층이 너무 많거나 변수가 복잡하거나 테스트셋과 학습셋이 중복될때 생기기도 한다.

 

학습셋과 테스트셋

- 과적합을 방지하려면?

  먼저 학습을 하는 데이터셋과 이를 테스트할 데이터셋을 완전히 구분한 후 학습과 동시에 테스트를 병행하며 진행하는 것입니다.

 

- 학습셋과 테스트셋의 구분

- 학습이 계속되면 학습셋에서의 에러는 계속해서 작아지지만, 테스트셋에서는 과적합이 발생(학습을 진행해도 테스트 결과가 더 이상 좋아지지 않는 지점에서 학습을 멈추어야 한다.)

정확도 측정의 예

 식이 복잡해지고 학습량이 늘어날수록 학습 데이터를 통한 예측률은 계속해서 올라가지만, 적절하게 조절하지 않을 경우 테스트셋을 이용한 예측률은 오히려 떨어지는 것을 확인할 수 있습니다.

 

 다음은 사이킷런의 train_test_split() 함수를 사용한 예시입니다.

 만들어진 모델을 테스트셋에 적용하려면 model.evaluate() 함수(loss와 accuracy 두 가지를 계산해 출력합니다.)를 사용하면 됩니다.

실습| 초음파 광물 예측하기: 학습셋과 테스트셋 구분

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

import pandas as pd
# 깃허브에 준비된 데이터를 가져옵니다. 앞에서 이미 데이터를 가져왔으므로 추석 처리합니다. 3번 예제만 별도 실행 시 주석을 해제하여 실습하세요.
# 광물 데이터를 불러옵니다.
df = pd.read_csv('./data/sonar3.csv', header=None)
# 음파 관련 속성을 X로, 광물의 종류를 y로 저장합니다.
X = df.iloc[:,0:60]
y = df.iloc[:,60]
# 학습셋과 테스트셋을 구분합니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True)
# 모델을 설정합니다.
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'])

# 모델을 실행합니다.
history=model.fit(X_train, y_train, epochs=200, batch_size=10)
# 모델을 테스트셋에 적용해 정확도를 구합니다. 
score=model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])

딥러닝 성능 올리는 방법

- 데이터 추가하기

- 데이터 적절히 보완하기

- 다른 구조로 모델을 바꾸어 가며 최적의 구조를 찾는 것입니다.

 

모델 저장과 재사용

 학습 결과를 저장하려면 model.save() 함수를 이용해 모델 이름을 적어 저장한다.

 모델 불러오기

from tensorflow.keras.models import Sequential, load_model
# 테스트를 위해 조금 전 사용한 모델을 메모리에서 삭제합니다.
del model 
# 모델을 새로 불러옵니다.
model = load_model('./data/model/my_model.hdf5') 

# 불러온 모델을 테스트셋에 적용해 정확도를 구합니다. 
score=model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])

k겹 교차 검증

: 데이터셋을 여러 개로 나누어 하나씩 테스트셋으로 사용하고 나머지를 모두 합해서 학습셋으로 사용하는 방법.

 데이터를 원하는 수만큼 나누어 각각 학습셋과 테스트셋으로 사용되게 하는 함수는 사이킷런 라이브러리의 KFold() 함수입니다.

 먼저 몇개의 파일로 나눌 것인지 정해 1의 k 변수에 넣습니다. 사이킷런의 2 kFold() 함수를 불러옵니다. 샘플이 어느 한쪽에 치우치지 않도록 shuffle 옵션을 True로 설정해 줍니다. 정확도가 채워질 3 acc_score라는 이름의 빈 리스트를 준비합니다. 4 split()에 의해 k개의 학습셋, 테스트셋으로 분리되며 for 문에 의해 k번 반복됩니다.

 

실습| 초음파 광물 예측하기: k겹 교차 검증

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

# 깃허브에 준비된 데이터를 가져옵니다. 앞에서 이미 데이터를 가져왔으므로 추석 처리합니다. 3번 예제만 별도 실행 시 주석을 해제하여 실습하세요.

# 광물 데이터를 불러옵니다.
df = pd.read_csv('./data/sonar3.csv', header=None)

# 음파 관련 속성을 X로, 광물의 종류를 y로 저장합니다.
X = df.iloc[:,0:60]
y = df.iloc[:,60]
# 몇 겹으로 나눌 것인지를 정합니다. 
k=5

# KFold 함수를 불러옵니다. 분할하기 전에 샘플이 치우치지 않도록 섞어 줍니다.
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번의 학습을 실행합니다. 
for train_index , test_index in kfold.split(X):  # for 문에 의해서 k번 반복합니다. spilt()에 의해 k개의 학습셋, 테스트셋으로 분리됩니다.
    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=0) 
    
    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)

*verbose = 0 옵션을 주면 학습 과정의 출력을 생략합니다.*

 

14장 모델 성능 향상시키기

데이터의 확인과 검증셋

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

# 깃허브에 준비된 데이터를 가져옵니다.
!git clone https://github.com/taehojo/data.git

# 와인 데이터를 불러옵니다.
df = pd.read_csv('./data/wine.csv', header=None)

# 데이터를 미리 보겠습니다.
df

 각 속성의 정보는 다음과 같습니다.

x, y 정하기

# 와인의 속성을 X로 와인의 분류를 y로 저장합니다.
X = df.iloc[:,0:12]
y = df.iloc[:,12]

학습셋, 테스트셋, 검증셋(최적의 학습 파라미터를 찾기 위해 학습 과정에서 사용하는 것이 검증셋이다.)

: 검증셋을 설정하면 검증셋에 테스트한 결과를 추적하면서 최적의 모델을 만들 수 있습니다. 검증셋은 model.fit() 함수 안에 validation_split이라는 옵션을 주면 만들어집니다.

실습| 와인의 종류 예측하기: 데이터 확인과 실행

# 학습셋과 테스트셋으로 나눕니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)

# 모델 구조를 설정합니다.
model = Sequential()
model.add(Dense(30,  input_dim=12, activation='relu'))
model.add(Dense(12, activation='relu'))
model.add(Dense(8, activation='relu'))
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])

모델 업데이트하기

 에포크마다 모델의 정확도를 함께 기록하면서 저장하는 방법.

50번째 에포크의 검증셋 정확도가 0.9346이라면 50-0.9346.hdf5라는 이름으로 저장됩니다.

학습 중인 모델을 저장하는 함수는 케라스 API의 Modelcheckpoint() 입니다. 모델이 저장될 곳을 정하고 진행되는 현황을 모니터할 수 있도록 verbose는 1(True)로 설정합니다.

추가되는 코드는 아래와 같습니다.

그래프로 과적합 확인하기

  적절한 학습 횟수를 정하기 위해서는 검증셋과 테스트셋의 결과를 그래프로 보는 것이 가장 좋다.

- loss: 학습을 통해 구한 예측 값과 실제 값의 차이(=오차)

- accuracy: 전체 샘플 중에서 정답을 맞춘 샘플이 몇 개인지의 비율

- val_loss: 학습한 모델을 검증셋에 적용해얻은 오차

- val_accuracy: 검증셋으로 얻은 정확도

 

  이 값이 저장된 history는 model.fit()의 결과를 가진 파이썬 객체로, history.params에는 model.fit()의 설정 값들이, history.epoch에는 에포크 정보가 들어 있게 됩니다. 우리에게 필요한 loss, accuracy, val_loss, val_accuracy는 history.history에 들어 있습니다.

 학습셋에서 얻은 오차는 파란색으로, 검증셋에서 얻은 오차는 빨간색으로 표시하겠습니다.

# y_vloss에 테스트셋(여기서는 검증셋)의 오차를 저장합니다.
y_vloss=hist_df['val_loss']

# y_loss에 학습셋의 오차를 저장합니다.
y_loss=hist_df['loss']

#x 값을 지정하고 테스트셋(검증셋)의 오차를 빨간색으로, 학습셋의 오차를 파란색으로 표시합니다.
x_len = np.arange(len(y_loss))
plt.plot(x_len, y_vloss, "o", c="red", markersize=2, label='Testset_loss')
plt.plot(x_len, y_loss, "o", c="blue", markersize=2, label='Trainset_loss')

plt.legend(loc='upper right')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

실습| 와인의 종류 예측하기: 그래프 표현

# 그래프 확인을 위한 긴 학습 
history=model.fit(X_train, y_train, epochs=2000, batch_size=500, validation_split=0.25)
# history에 저장된 학습 결과를 확인해 보겠습니다. 
hist_df=pd.DataFrame(history.history)
hist_df
# y_vloss에 테스트셋(여기서는 검증셋)의 오차를 저장합니다.
y_vloss=hist_df['val_loss']

# y_loss에 학습셋의 오차를 저장합니다.
y_loss=hist_df['loss']

#x 값을 지정하고 테스트셋(검증셋)의 오차를 빨간색으로, 학습셋의 오차를 파란색으로 표시합니다.
x_len = np.arange(len(y_loss))
plt.plot(x_len, y_vloss, "o", c="red", markersize=2, label='Testset_loss')
plt.plot(x_len, y_loss, "o", c="blue", markersize=2, label='Trainset_loss')

plt.legend(loc='upper right')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

학습의 자동 중단

- EarlyStopping() 함수: 학습이 진행되어도 테스트셋 오차가 줄어들지 않으면 학습을 자동으로 멈추게 하는 함수.

monitor 옵션은 model.fit()의 실행 결과 중 어떤 것을 이용할지 정합니다. 

patience 옵션은 지정된 값이 몇 번 이상 향상되지 않으면 학습을 종료시킬지 정합니다.

 

 최고의 모델 하나만 저장되게끔 해보겠습니다. ModelCheckpoint()의 save_best_only 옵션을 True로 설정합니다.

 모델을 실행합니다.

 앞서 만든 기본 코드에 다음과 같이 새로운 코드를 불러와 덧붙여 실행해 보겠습니다.

# 학습이 언제 자동 중단될지를 설정합니다.
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=20)

# 최적화 모델이 저장될 폴더와 모델의 이름을 정합니다.
modelpath="./data/model/Ch14-4-bestmodel.hdf5"

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

# 모델을 실행합니다.
history=model.fit(X_train, y_train, epochs=2000, batch_size=500, validation_split=0.25, verbose=1, callbacks=[early_stopping_callback,checkpointer])