티스토리 뷰

Study/AI

[DL] 해보면서 배우는 딥러닝 - ANN 평가하기

생각많은 소심남 2017. 5. 9. 18:01

( 이 포스트는 Udemy에서 진행되는 DeepLearning A-Z 강의를 요약, 정리한 내용입니다.) 

 지난 포스트까지 ANN을 구현해보고 실제로 84% 가량의 결과를 얻은 것을 확인했다. 그런데 실제로 해본 사람이라면 알겠지만, 할때마다 결과가 달라지는 것을 알 수 있을 것이다. 나같은 경우에도 처음 할때는 86% 정도의 Accuracy를 얻을 수 있었지만, 하면 할수록 낮아지는 것을 확인할 수 있었다. 그럼 내가 얻은 결과가 과연 신뢰할 수 있을만한 결과일까? 혹은 우연치않게 맞은 결과일까? 결국 확인해보는 수밖에 없다. 먼저 살펴보기에 앞서 왜 이럴 수 밖에 없는지를 보고자 한다.

<Bias-Variance Tradoff - DeepLearning A-Z에서 발췌>

우리가 처음 Dataset을 생성할 때, 학습을 시킬 Training Set과 검증을 할 Test Set으로 구분했다. 물론 그때는 random_state=0으로 지정해 그냥 순차적으로 분리했었지만, 이런 경우가 발생할 수 있다. 만약 우연치 않게 학습을 시킬 집단과 검증을 할 집단의 성향이 확연한 차이를 나타냈다면? 그걸 표현한 것이 위의 Bias-Variance Tradeoff이다. 우리가 가장 이상적으로 생각하는 결과는 아래 왼쪽에 있는 Bias가 적고, Variance도 낮은 케이스다. 그런데 지금까지 한 경우는 위 오른쪽 같은 Bias도 크고, Variance도 높은 형태이다. 이건 인위적으로 일부러 이렇게 만든게 아니라 어쩔 수없이 Dataset을 Training Set과 Test Set으로 나누면서 발생하는 현상이다. 

 이걸 해소하기 위해서 도입하는 방법이 Cross Validation(상호 검증)이라는 기법이다. 간단히 말해 상호 검증을 위한 절차를 만들자는 것이다. 이전에 구현한 방법에 적용하자면 학습을 시킬때도 내부적으로 검증할 수 있는 방안을 마련해 그만큼 Bias와 Variance를 줄이자는 것이다. 

그 중에서 Training Set을 잘게 쪼개 그 중 Training 시킬 종류와 Test 시킬 종류를 분류해서 교차검증하는 방식을 K-fold Cross Validation이라고 한다. 추후에 자세한 원리에 대해서 다뤄보겠지만, 일단 해보면서 배우는 거니까, 이런식으로 학습을 시키는 중에도 검증의 과정을 거쳐 조금이라도 Variance를 줄이는 과정이라고 이해하면 좋을거 같다. 

 우선 지난번과 같이 코드를 진행하되 Training set과 Test set을 분리하는 부분까지만 진행한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
 
# Importing the dataset
dataset = pd.read_csv('Churn_Modelling.csv')
= dataset.iloc[:, 3:13].values
= dataset.iloc[:, 13].values
                
# Encodeing Categorical data
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X_1 = LabelEncoder()
X[:, 1= labelencoder_X_1.fit_transform(X[:, 1])
labelencoder_X_2 = LabelEncoder()
X[:, 2= labelencoder_X_2.fit_transform(X[:, 2])
onehotencoder = OneHotEncoder(categorical_features=[1])
= onehotencoder.fit_transform(X).toarray()
 
# To avoid Dummy variable Trap
= X[:, 1:]
                
# Spitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2
                                                    random_state=0)
 
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
cs

 사실 이전에 한 ANN 생성 작업이 Keras에서 제공하는 Sequential package와 Dense package를 이용해서 Layer를 생성하고 그걸 합치는 과정을 수행한 것인데, 이걸 하나의 KerasClassifier라는 wrapper로 묶어서 다룰 수 있다. 물론 이에 필요한 package를 추가해야 한다. 더불어 cross validation을 위한 package를 scikit에서 불러온다.

33
34
35
# Cross Validation
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score
cs

 Wrapper로 묶는 방법은 간단하다. Layer를 생성하고 합치는 과정을 하나의 함수로 만들면 되는 것이다. 이렇게 만들면 된다. 참고로 optimizer를 User 취향대로 변화시키고 싶다 하면 이 함수의 인자로 optimizer를 받아 그걸 넣으면 된다. 함수 형태는 다음과 같다.

37
38
39
40
41
42
43
44
# Classifier function
def build_classifier(optimizer):
    classifier = Sequential()
    classifier.add(Dense(units=6, kernel_initializer='uniform', activation='relu', input_dim=11))
    classifier.add(Dense(units=6, kernel_initializer='uniform', activation='relu'))
    classifier.add(Dense(units=1, kernel_initializer='uniform', activation='sigmoid'))
    classifier.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    return classifier
cs

위에서 만든 함수를 Wrapper속의 인자로 삽입해준다.

46
47
48
# Wrapping the classifier
classifier = KerasClassifier(build_fn = build_classifier, 
                             batch_size = 10, epochs = 100)
cs

cross validation이 아닌 일반 학습으로는 Sequential package의 Fit 함수를 사용했지만, cross validation을 사용하는 경우, 앞에서 포함시킨 cross_val_score를 사용한다. 잠깐 cross_val_score에 대한 help 를 살펴보면 다음과 같다.

여기서 우리가 유심히 볼 인자는 Estimator, X, Y, cv, n_jobs 정도이다. X, Y는 아마 다들 알다시피 학습시킬 dataset이다. Estimator는 help에 언급되어 있는 바와 같이 Fit이 구현되어 있는 object인데, 앞에서 우리가 Wrapper로 만들어놓은 KerasClassifier도 여기에 속한다. cv는 한 epoch당 몇개의 fold로 나눠서 교차검증을 할건지 정하는 상수인데, 일단 10으로 지정을 한다. 물론 여기에 정하는 값도 규칙이 있긴하지만, 여기서는 넘어가겠다.
 그리고 마지막으로 n_jobs 정도인데, 요거는 CPU내의 thread를 몇개 사용해서 처리할 것인가를 지정하는 것이다.

 그런데 이 인자에 대한 문제가 좀 있는거 같다. 포럼이나 github를 좀만 찾아보면 n_jobs 인자를 지정해도 CPU가 놀고 있다는 이슈가 보인다. 해당 이슈의 공통적인 상황은 Windows 환경에서 구동할 경우 n_job 설정이 먹히지 않는다는 것이고, 나 역시도 그런 문제가 보이는 거 같다. 그래서 windows에서 실습하는 사람이 있다면 이 인자에는 값을 주지 말것을 권한다. 기타 MacOS나 Linux를 쓰면 상관없는거 같다.

46
47
48
49
50
51
# Wrapping the classifier
classifier = KerasClassifier(build_fn = build_classifier, 
                             batch_size = 10, epochs = 100)
accuracies = cross_val_score(estimator= classifier, 
                             X= X_train, y= y_train, 
                             cv= 10,verbose=2)
cs

 이걸 수행하게 되면 10번에 거쳐서 Cross Validation을 수행하게 된다. 나같은 경우는 1 iteration을 수행할때마다 45초정도가 걸렸는데, 이 값은 컴퓨터 성능에 따라서 다른거 같다. 

 이에 대한 결과를 확인하려면 cross_val_score의 결과인 accuracies의 평균과 표준편차를 확인해보면 된다. 

53
54
55
# Mean & variance
mean = accuracies.mean()
variance = accuracies.std()
cs

나같은 경우는 위의 값들이 다음과 같이 나왔다.

이렇게 되면 표준편차가 대략 1.2%, 즉 다른 자료간의 편차가 얼마 차이나지 않는다는 것을 확인할 수 있다. 맨 처음에 소개했던 그림중 아래 왼쪽에 있던 Low-bias low-variance의 형태를 취하게 되는 것이다.

 물론 여기서 끝이 아니다. 지금까지 한 작업은 Cross Validation이라는 기법을 통해 Bias를 줄임으로써 정확성이 어느정도 수렴하는 형태로 갔다는 것이지, 여기서 더 개선을 해서 정확성을 더 높힐 수 있다. 가령 optimizer를 지금은 adam optimizer를 사용한 상태인데 이걸 다른 optimizer를 사용해서 다른 결과를 볼수도 있다. 

댓글