[이 글은 "Do it 딥러닝 입문" 책을 보고 공부한 내용을 복습하고자 정리한 글입니다.]
목표 - 주어진 데이터 셋으로 어떻게 훈련했을 때 가장 효율이 좋은지 알아본다.
[배운 점]
모듈
- sklean.linear_model 모듈을 통해 모델을 임포트 할 수 있다. (ex. SGDClassifier)
- model의 하이퍼파라미터로 loss함수를 지정해줄 수 있다. (ex. hinge, log)
훈련데이터 세트
- 테스트 세트로 모델을 튜닝하면 테스트 세트에 대해서만 좋은 성능을 낼 수 있으므로 실전에서 좋은 성능을 기대하기 어렵다.(실전 투입 마지막 한 번만 사용하는 게 좋다.)
- 훈련세트를 훈련세트와 검증세트로 나눠서 활용한다. (비율은 80 20 20)
스케일(Scale)
- 우리는 잘 가공되어있는 데이터만 활용할 수는 없다. 그러므로 어떤 데이터들을 적절히 가공하는 '데이터 전처리'과정이 필요하다.
- 그중 각 특성의 스케일을 조정하는 것이 있는데, 두 특성의 스케일 차이가 크게 나게 되면 모델 성능에 영향을 준다.
- 스케일을 조정하는 방법 중 하나에 '표준화(standardization)'이 있다. 특성 값에서 평균을 빼고 표준편차로 나눈 값을 사용한다.
- 넘파이의 mean(), std()를 사용하면 평균과 표준 편차를 계산해준다.
- 스케일을 맞춘 데이터의 가중치는 빠르게 최적 값으로 근접한다.
- 훈련 세트와 검증 세트의 전처리 즉, 스케일을 조정할 경우 훈련세트를 조정한 평균과 표준편차를 이용해서 조정해준다.
[코드]
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
x = cancer.data
y = cancer.target
x_train_all, x_test, y_train_all, y_test = train_test_split(x,y, stratify=y, test_size=0.2, random_state=42)
from sklearn.linear_model import SGDClassifier #SGDClassifier 모델을 가져옴
sgd = SGDClassifier(loss='log', random_state=42) #loss함수를 log로 함
sgd.fit(x_train_all,y_train_all)
sgd.score(x_test,y_test) #정확도
from sklearn.linear_model import SGDClassifier #위와 똑같은 방식
sgd = SGDClassifier(loss='hinge', random_state=42) #SVM문제를 푸는 모델로 만들어짐(hinge)
sgd.fit(x_train_all,y_train_all) #SVM? : 훈련데이터의 클래스를 구분하는 경계선을 찾는 작업
sgd.score(x_test,y_test) #정확도
### 검증세트
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
x = cancer.data
y = cancer.target
x_train_all, x_test, y_train_all, y_test = train_test_split(x,y, stratify=y, test_size=0.2, random_state=42)
###우리는 훈련데이터를 가지고 또 한번 훈련데이터와 검증데이터로 나눈다.
x_train, x_val, y_train, y_val = train_test_split(x_train_all, y_train_all, stratify = y_train_all, test_size=0.2, random_state= 42)
print(len(x_train),len(x_val))
sgd= SGDClassifier(loss='log',random_state=42) #샘플 데이터가 너무 적기 때문에 성능이 더 안좋아짐.
sgd.fit(x_train,y_train)
sgd.score(x_val,y_val)
print(cancer.feature_names[[2,3]]) #feature_namse는 특성의 이름을 확인한다.
plt.boxplot(x_train[:, 2:4]) #서로 스케일이 너무 다르다.
plt.show()
class SingleLayer():
def __init__(self, learning_rate=0.1):
self.w = None # 데이터 특성이 많기 때문에 가중치를 미리 초기화하지 않음.
self.b = None
self.losses = []
self.w_history=[] #가중치를 기록
self.lr=learning_rate
def forpass(self, x):
z = np.sum(x * self.w) + self.b # 직선의 방정식 즉 hypothesis #np.sum을 사용하면 1차원 넘파이배열에서 배열의 요소끼리 사칙연산을 할 수 있음.
return z
def backprop(self, x, err):
w_grad = x * err #가중치에 대한 그레이디언트 계산
b_grad = 1 * err #절편에 대한 그레이디언트 계산
return w_grad, b_grad
def fit(self, x, y, epochs=100):
self.w = np.ones(x.shape[1]) #가중치를 초기화하는데 x의 shape과 똑같고 1채움 즉 각 행값
self.b = 0
self.w_history.append(self.w.copy()) #가중치를 기록한다.
np.random.seed(42) #무작위로 시드를 지정한다.
for i in range(epochs):
loss = 0
indexes = np.random.permutation(np.arange(len(x))) #인덱스를 섞음. 데이터가 섞여서 훈련될수록 손실 함수의 값이 효율적으로 줄어듬
for i in indexes:
z = self.forpass(x[i]) #정방향 계산
a = self.activation(z) #activation함수 적용
err = -(y[i] - a) #실제값과 예측값 오차계산
w_grad, b_grad = self.backprop(x[i], err) #역방향 계산
self.w -= w_grad * self.lr #업데이트(학습률 적용)
self.b -= b_grad
self.w_history.append(self.w.copy()) #w값을 카피 한 뒤 변화율을 보기위해 append해준다.
a = np.clip(a, 1e-10, 1-1e-10) #인잔힌 로그 계산을 위해 클리핑 한 후 손실을 누적
loss += -(y[i] * np.log(a) + (1-y[i]) * np.log(1-a)) #에포크마다 평균 손실을 저장
self.losses.append(loss/len(y)) #에포크마다 평균 손실을 저장
def activation(self, z):
a = 1 / (1 + np.exp(-z))
return a
def predict(self, x):
z = [self.forpass(x_i) for x_i in x] #hypothesis를 구해 반환
return np.array(z) > 0 #스텝 함수 적용
def score(self, x, y):
return np.mean(self.predict(x)==y)
layer1 = SingleLayer()
layer1.fit(x_train,y_train)
layer1.score(x_val,y_val)
w2 = [] #mean perimeter비해 mean area스케일이 크므로 w3값(area)이 학습과정이 큰폭으로 흔들림
w3 = []
for w in layer1.w_history:
w2.append(w[2])
w3.append(w[3])
plt.plot(w2,w3)
plt.plot(w2[-1], w3[-1],'ro')
plt.xlabel("w[2]")
plt.ylabel("w[3]")
train_mean = np.mean(x_train, axis=0) #표준화는 특성값에서 평균을 빼고 표준편차로 나눈다.
train_std = np.std(x_train, axis=0) #스케일 조정 방법 중 하나
x_train_scaled= (x_train-train_mean) / train_std
layer2 = SingleLayer() #스케일을 조정해준 뒤 w값의 변화량을 본다.
layer2.fit(x_train_scaled,y_train)
w2 = []
w3 = []
for w in layer2.w_history:
w2.append(w[2])
w3.append(w[3])
plt.plot(w2,w3)
plt.plot(w2[-1],w3[-1],'ro')
layer2.score(x_val,y_val) #검증세트도 전처리과정을 거쳐야한다.
val_mean = np.mean(x_val, axis=0)
val_std = np.std(x_val, axis=0)
x_val_scaled= (x_val-val_mean)/val_std
layer2.score(x_val_scaled,y_val)
plt.plot(x_train[:50,0], x_train[:50,1],'bo')
plt.plot(x_val[:50,0],x_val[:50,1],'ro')
plt.xlabel("feture1")
plt.ylabel("feture2")
plt.legend(['train set', 'val. set'])
plt.show()
plt.plot(x_train_scaled[:50,0], x_train_scaled[:50,1],'bo')
plt.plot(x_val_scaled[:50,0],x_val_scaled[:50,1],'ro')
plt.xlabel("feture1")
plt.ylabel("feture2")
plt.legend(['train set', 'val. set'])
plt.show()
#위 아래의 그래프가 다른이유는 각자의 표준편차와 평균을 이용했기 떄문이다.
x_val_scaled = (x_val-train_mean)/train_std #훈련 데이터로 전처리하기
plt.plot(x_train_scaled[:50,0], x_train_scaled[:50,1],'bo')
plt.plot(x_val_scaled[:50,0],x_val_scaled[:50,1],'ro')
plt.xlabel("feture1")
plt.ylabel("feture2")
plt.legend(['train set', 'val. set'])
plt.show()
layer2.score(x_val_scaled,y_val) #검증 세트로 정확도 확인하기.
'빅데이터 | 머신러닝 | 딥러닝 > 딥러닝' 카테고리의 다른 글
[딥러닝 기초] 다층 신경망 (MLPClassifier) (0) | 2020.05.08 |
---|---|
[딥러닝 기초] k-fold 교차 검증(cross validation) (0) | 2020.05.02 |
[딥러닝 기초] Neural Network (L1, L2 규제) (0) | 2020.04.25 |
[딥러닝 기초] Neural Network (use cancer dataset/classfication) (0) | 2020.04.19 |
[jupyter notebook] Neural Network (use mnist dataset) (0) | 2020.04.18 |