[Do it 딥러닝 입문] 04장
퍼셉트론
-
이진 분류 문제(임의의 샘플 데이터를 True False로 구분하는 문제)에서 최적의 가중치를 학습하는 알고리즘
-
선형함수를 통과한 값 z를 계단 함수로 보내 0보다 큰지, 작은지 검사하여 1과 -1로 분류하는 알고리즘
-
마지막 단계에서 샘플을 이진 분류하기 위해 계단함수를 사용 → 계단 함수를 통과한 값을 다시 가중치와 절편을 업데이트 하는데 사용 ⇒ 계단 함수의 값을 학습에 사용
-
계단 함수는 z≥0이면 1(양성 클래스)로, z<0이면 -1(음성 클래스)로 분류
선형 함수
아달린
- 퍼셉트론을 개선한 적응형 선형 뉴런
- 선형 함수의 결과를 학습에 사용, 계단 함수의 결과는 예측에만 사용 → 역방향 계산이 계단 함수 출력 이전, 선형 함수 출력 이후에 진행
로지스틱 회귀
- 아달린에 활성화 함수를 추가한 것
- 마지막 단계에서 임계함수를 사용하여 예측을 수행; 임계 함수는 활성화 함수의 출력값을 사용
활성화 함수
- 선형 함수를 통과시켜 얻은 z를 임계 함수에 보내기 전에 변형
- 보통 비선형 함수를 사용
시그모이드 함수 = 로지스틱 함수
- 로지스틱 회귀의 활성화 함수
- 선형함수의 출력값 z를 0~1사이의 확률값으로 변환시켜줌
- 오즈 비 > 로짓 함수 > 시그모이드 함수 의 과정을 통해 만들어짐
- 오즈 비 : 성공 확률과 실패 확률의 비율을 나타내는 통계. p/(1-p) ; p:성공확률
- 로짓 함수 : 오즈 비에 로그 함수를 취하여 만든 함수. p가 0.5일때 0이 되고 p가 0,1일때 각각 무한대로 음수와 양수가 됨. log(p/(1-p)) = z
로지스틱 손실 함수를 경사하강법에 적용하기
- 로직스틱 회귀와 같은 분류의 목표 : 올바르게 분류된 샘플 데이터의 비율 자체를 높이는 것 → 올바르게 분류된 샘플 데이터의 비율은 미분가능한 함수가 아님 → 경사하강법의 손실 함수로 쓰일 수 없음 → 로지스틱 손실 함수 사용
로지스틱 손실 함수
- 다중 분류를 위한 손실 함수인 크로스 엔트로피 손실 함수를 이진 분류 버전으로 만든 것
a : 활성화 함수가 출력한 값
y : 타깃
이진 분류 → 그렇다(1)과 아니다(0)으로 나뉨 → y가 1(양성 클래스)의 경우 L=-log(a), y가 -1(음성 클래스)인 경우 L=-log(1-a)
유방암 데이터 세트
- 유방암 데이터 샘플이 악성 종양(True)인지, 양성 종양(False)인지 구분하는 이진 분류
유방암 데이터 세트 준비하기
- load_breast_cancer() 함수 호출하기
- 사이킷런의 datasets 모듈의 load_breast_cancer() 함수를 호출해 Bunch 클래스의 객체 가져오기
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
- 입력 데이터 확인하기
- cancer의 data와 target 확인
print(cancer.data.shape, cancer.target.shape)
=> (569,30) (569,)
특성이 30개, 산점도로 표현하기 어려움 → 박스 플롯을 이용하여 각 특성의 사분위 값을 나타내기
- 박스 플롯으로 특성의 사분위 관찰하기
- 박스 플롯 : 1사분위와 3사분위의 값으로 상자를 그린 다음 그 안에 2사분위(중간값) 표시, 1사분위와 3사분위 사이의 거리(interquartile range)의 1.5배만큼 위아래 거리에서 각각 가장 큰 값과 가장 작은 값까지 수염을 그림
import matplotlib.pyplot as plt
import numpy as np
plt.boxplot(cancer.data)
plt.xlabel('feature')
plt.ylabel('value')
plt.show()
- 타깃 데이터 확인하기
np.unique(cancer.target, return_counts=True)
- 넘파이의 unique()함수를 사용해 고유한 값을 찾아 반환
- return_counts 매개변수를 True로 지정해 고유한 값의 개수를 셀 수 있음
⇒ 타깃 데이터에 212개의 음성 클래스(정상 종양)과 357개의 양성 클래스(악성 종양)이 있음
- 훈련 데이터 세트 저장
x = cancer.data
y = cancer.target
모델이 성능 평가를 위해 훈련 세트와 테스트 세트로 나누기
- 일반화 성능 : 훈련된 모델의 실전 성능
- ‘과도하게 낙관적으로 일반화 성능을 추정한다 ‘ : 모델을 학습시킨 데이터로 모델의 성능을 평가하면 당연히 좋은 성능이 나옴
- 훈련 데이터 세트를 나눌 때는 테스트 세트보다 훈련 세트가 많아야 하며, 훈련 데이터 세트를 나누기 전에 양성/음성 클래스가 어느 한 쪽에 몰리지 않도록 골고루 섞어야 함
훈련 세트와 데이터 세트로 나누기
- train_test_split() 함수로 훈련 데이터 세트 나누기
- train_test_split() 함수는 훈련 데이터 세트를 훈련 세트 75%, 테스트 세트 25%의 비율로 나눔
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x,y, stratify=y, test_size=0.2, random_state=42)
- stratify=y : 훈련 데이터를 나눌 때 stratify가 클래스 비율을 동일하게 만듬, 일부 클래스 비율이 불균형할 경우 stratify를 y로 지정해야 함
- test_size=0.2 : 테스트 세트를 20%로 조정함
- random_state=42 : 데이터 세트를 섞은 다음 결과가 항상 일정하도록 random_state 매개변수에 난수 초깃값 42 지정
- 결과 확인하기, unique()함수로 훈련 세트의 타깃 확인하기
print(x_train.shape, x_test.shape)
np.unique(y_tarin, return_counts = True)
로지스틱 회귀, 훈련하는 메서드, 에측하는 메서드 구현하기
class LogisticNeuron:
def __init__(self):
#1.__init__() 메서드 작성
self.w = None
self.b = None #초기화하지 않음; 입력 데이터의 특성이 많아 #5에서 입력 데이털르 보고 특성 개수에 맞게 결정
#2.정방향 계산
def forpass(self,x):
z = np.sum(x*self.w)+self.b #직선 방정식 계산, np.sum() : 함수의 인자로 전달하면 각 요소를 모두 더한 값을 반환
return z
#3.역방향 계산
def backprop(self,x,err):
w_grad = x*err #가중치에 대한 그레디언트 계산
b_grad = 1*err #절편에 대한 그레디언트 계산
return w_grad, b_grad
#4.activation()메서드 구현;시그모이드 계산
def activation(self,z):
a = 1/(1+np.exp(-z))
return a
#5.훈련을 위한 fit()메서드 구현
def fit(self, x, y, epochs=100):
self.w=np.ones(x.shape[1]) #가중치 초기화
self.b=0 #절편 초기화
for i in range(epochs): #에포크만큼 반복
for x_i,y_i in zip(x,y): #모든 샘플에 대하여 반복
z = self.forpass(x_i) #정방향 계산
a = self.activation(z) #활성화함수 계산
err = -(y_i-a) #오차 계산
w_grad, b_grad = self.backprop(x_i,err) #역방향 계산
self.w -= w_grad #가중치 업데이트
self.b -= b_grad #절편 업데이트
#6.에측하는 메서드 구현
def perdict(self,x):
z = [self.forpass(x_i) for x_i in x] #선형 함수 적용
a = self.activation(np.array(z)) #활성화 함수 적용
return a > 0.5 #계단함수 적용
로지스틱 회귀 모델 훈련시키기
neuron = LogisticNeuron()
neuron.fit(x_train, y_train)
테스트 세트 사용해 모델의 정확도 평가하기
np.mean(neuron.predict(x_test)==y_test)
0.8245614035087719
로지스틱 회귀 뉴런으로 단일층 신경망 만들기
단일층 신경망
- 입력층과 출력층만 가지는 신경망. 은닉층이 없음 (ex>로지스틱 회귀)
경사 하강법의 종류
-
확률적 경사 하강법 : 샘플 데이터 1개마다 그레디언트를 계산하여 가중치를 업데이트
- 1개 샘플을 중복되지 않도록 무작위로 선택 → 그레디언트 계산
- 계산 비용은 적으나 가중치가 최적값에 수렴하는 과정이 불안정
-
배치 경사 하강법 : 전체 훈련 세트를 사용하여 한 번에 그레디언트를 계산
- 전체 샘플을 모두 선택 → 여러 에포크를 반복해 그레디언트 계산
- 가중치가 최적값에 수렴하는 과정은 안정적, 그러나 계산 비용이 많이 듬
-
미니 배치 경사 하강법 : 배치 크기를 작게 하여(훈련 세트를 여러번 나눠) 처리
- 전체 샘플 중 몇 개의 샘플을 중복되지 않도록 무작위로 선택 → 그레디언트 계산
- 확률적 경사 하강법과 배치 경사 하강법의 장점을 절충한 것
-
위의 경사 하강법들은 매 에포크마다 훈련 세트의 샘플 순서를 섞어 가중치의 최적값을 계산해야 함 → 훈련 세트의 샘플을 섞으면 가중치 최적값의 탐색 과정이 다양해져 가중치 최적값을 제대로 찾을 수 있음
- 넘파이 배열의 인덱스를 섞은 후 인덱스 순서대로 샘플을 뽑는 방법으로 훈련 세트의 샘플 순서를 섞을 수 있음 ⇒ np.random.permutation()함수 사용
class SingleLayer:
def __init__(self):
#1.__init__() 메서드 작성
self.w = None
self.b = None
self.losses=[] #손실함수의 결과값을 저장할 리스트. 샘플마다 손실 함수를 계산하고 그 결괏값을 모두 더해 샘플 개수로 나눈 평균값을 저장
#2.정방향 계산
def forpass(self,x):
z = np.sum(x*self.w)+self.b
return z
#3.역방향 계산
def backprop(self,x,err):
w_grad = x*err
b_grad = 1*err
return w_grad, b_grad
def add_bias(self,x):
return np.c_[np.ones((x.shpae[0],1)),x] #행렬의 맨 앞에 1로 채워진 열 벡터를 추가
#5.activation()메서드 구현;시그모이드 계산
def activation(self,z):
a = 1/(1+np.exp(-z))
return a
#6.훈련을 위한 fit()메서드 구현
def fit(self, x, y, epochs=100):
self.w = np.ones(x.shape[1])
self.b = 0
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)
err = -(y[i]-a)
w_grad, b_grad = self.backprop(x[i],err)
self.w -= w_grad
self.b -= b_grad
#안전한 로그 계산을 위해 클리핑한 후 손실을 누적
a = np.clip(a, 1e-10, 1-1e-10) #np.clip() : 주어진 범위 밖의 값을 범위 양 끝의 값으로 잘라냄.
loss +=-(y[i]*np.log(a)+(1-y[i])*np.log(1-a))
self.losses.append(loss/len(y)) #에포크마다 평균 손실 저장
#7.에측하는 메서드 구현
def predict(self,x):
z = [self.forpass(x_i) for x_i in x]
return np.array(z) > 0
#8.정확도 계산을 위한 score()메서드 구현
def score(self,x,y):
return np.mean(self.predict(x)==y)
단일층 신경망 훈련하기
layer = SingleLayer()
layer.fit(x_train,y_train)
layer.score(x_test,y_test)
사이킷런으로 로지스틱 회귀 수행하기
사이킷런으로 경사하강법 적용하기
from sklearn.linear_model import SGDClassifier
sgd = SGDClassifier(loss='log', max_iter=100, tol=1e-3, random_state=42)
#loss 매개변수에 손실함수로 log 지정, max_iter로 반복회수 100으로 지정, 난수 초깃값 42로 설정, 반복할 때 마다 로지스틱 손실함수의 값이 tol에 저장된 값만큼 감소하지 않으면 반복을 중단하도록 설정
sgd.fit(x_train,y_train) #사이킷런의 fit()메서드로 훈련
sgd.score(x_test,y_test) #사이킷런의 score()메서드로 정확도 계산
sgd.predict(x_test[0:10]) #사이킷런의 predict()메서드로 예측
Author And Source
이 문제에 관하여([Do it 딥러닝 입문] 04장), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hjiwoo0914/Do-it-딥러닝-입문-04장저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)