학습규칙이란?
-신경망이 학습할때 결합 강도가 어느 정도로 변화하는지 설명한 것
-헵의 규칙과 델타 규칙이 대표적
-학습목적은 출력값과 정답(데이터의 실제값)을 일치시키는 것
헵의 규칙이란?
-앞쪽의 신경세포가 흥분하며 뒤따르는 신경세포의 흥분의 전달 효율이 강화된다는 이런
-장기간 흥분하지 않는다면 뒤쪽의 신경세포 전달 효율도 감소한다.
-△w=r*yi*yj
-△w:가중치의 변화량 , r:상수(yi,yj가 함께 커지면 같이 커진다) , yi:앞쪽 뉴런의 흥분정도 , yj:뒤쪽 뉴런의 흥분정도
델타 규칙이란?
-출력값과 정답(데이터의 실제값)의 오차가 커질수록 가중치 수정량도 증가
-입력값이 커질수록 가중치 수정량도 증가
-△w=η*(yj-t)*yi
-η:학습률이며 정답에서 멀어질수록 정답에 다가가기 위해 가중치 수정량이 커진다
-△w:가중치의 변화량
-yi:시냅스 앞쪽 뉴런의 흥분정도
-yj:시냅스 뒤쪽 뉴런의 흥분정도
역전파란?
-출력값과 정답의 오차를 네트워크에서 역전파시켜서 가중치와 편향을 최적화 시킨다.
-순전파로 얻은 출력값과 정답의 오차를 하나씩 역으로 올라가서 전파시키며 이때 오차를 이용하여 각 층의 가중치 및 편향값을 수정해 나간다. 이걸 반복하여 오차를 최소화시키도록 최적화 시킨다.
-역전파 5가지 요소->훈련 데이터와 테스트 데이터, 손실함수 , 경사하강법, 최적화 알고리즘, 배치 사이즈
원핫 인코딩이란?
-출력값중 1개만 1이고 나머지는 0인 벡터로 표현되는 수치 벡터
훈련 데이터와 테스트 데이터?
-훈련데이터는 신경망 학습에 사용되고 테스트 데이터는 학습결과 검증을 위해 사용된다.
-각각의 데이터를 입력값과 정답의 짝으로 구성된다. 이러한 한 쌍을 샘플이라고 부른다.
-보통 훈련데이터가 테스트 데이터보다 많다.
-테스트 데이터에서 결과가 x이면 신경망과 훈련방법에 오류가 있는 것을 의미
손실 함수(오차함수 or 비용함수)?
-신경망의 결과로 출력되는 값과 정답의 오차를 정의하는 함수이다.
-오차가 클수록 바람직하지 못하다.
-오차제곱합(출력값과 정답의 차이를 제곱한 후 모두 더한것)을 이용하여 출력값이 정답과 어느 정도 일치하는지 정량화가 가능하다. ----->출력값과 정답이 연속적인 수치인 경우에 잘 맞아서 주로 회귀 문제에서 사용
-교차 엔트로피 오차(출력값의 자연로그값과 정답의 곱을 모두 더한 후에 마이너스 부호를 붙힌다. x가 1일때는 0이며 x가 0에 접근할 수록 -logx는 커진다. 따라서 정답에 가까울 수록 0에 가까우며 정답에서 멀수록 1에 가깝다. 출력값과 정답의 차이가 클수록 학습속도가 빠르다.)
경사 하강법이란?
-오차를 순차적으로 역전시켜 가중치와 오차를 조금씩 수정하며 오차를 최소화 시키는 방법
-손실함수로 구한 오차값을 기점으로 신경망의 반대 방향으로 w와 bias를 수정해나간다. 이때 수정량을 경사하강법으로 정한다.
-그래프상에서 가로축은 가중치, 세로축은 오차이며 가중치,편향의 변화량은 곡선의 기울기로 결정된다.
-국소적인 최소점에 빠지는 것을 국소 최적해라고 한다. 이때 진짜 최소값을 전역 최적해라고 한다.
-순전파는 출력값을 전파시키지만 역전파는 입력 오차값의 기울기를 전파시킨다.
-회귀문제에서 손실함수는 오차제곱합, 은닉층의 활성화함수는 시그모이드 함수 , 출력층의 활성화함수는 항등함수이다.
-분류문제에서 손실함수는 교처 앤트로피 오차, 은닉층은 시그모이드함수, 출력층은 소프트맥스이다.
-최적화 알고리즘?
확률적 경사 하강법(수정할때 마다 샘플을 무작위로 선택하는 알고리즘, 기울기 수정할때 마다 훈련 데이터에서 무작위로 샘플을 선택하여 국소적 최적해에 잘 빠지지 않는다.)
모멘텀(확률적 경사 하강법에서 관성을 더한 것. 수정량이 급격히 변화하는 것을 막고 좀 더 부드럽게 수정됨)
아다그라드(수정량이 자동으로 조정되지만 수정량이 감소하여 도중에 수정량이 0이 되면 최적화가 더 이상 진행x)
RMSProp(아다그라드의 단점을 개선한 방법)
아담(위의 알고리즘의 장점을 모두 가진 알고리즘)
배치사이즈란?
-가중치와 오차의 수정을 묶어서 진행되는데 이때 이 묶음의 크기를 말하며 학습의 효율성에 영향을 준다.
-모든 훈련 데이터를 1회 학습하는 것이 1에포크 라고 한다.
-훈련데이터가 여러개로 묶인 그룹을 배치라고 한다.
-배치사이즈는 이 그룹에 포함되는 샘플의 수이다.
배치학습?
-배치학습의 배치 사이즈는 전체 훈련 데이터의 개수이다
-1에포크에 모든 훈련 데이터를 가지고 오차의 평균을 구한뒤에 가중치 및 편향을 수정한다.
-안정된 학습이며 속도가 빠르지만 국소 최적해에 빠지기 쉽다.
온라인학습?
-개별 샘플마다 가중치와 편향을 수정한다. 이로 인해서 안전성이 떨어지지만 국소 최적해에 빠지는것을 예방한다.
미니배치학습?
-위의 두개의 학습 방법의 중간정도이며 훈련 데이터를 작은 그룹으로 분할하고 그룹마다 가중치,편향을 수정
회귀문제에서 역전파 구현
import numpy as np
import matplotlib . pyplot as plt
#y=sin(x)함수 학습
#x값은 입력 , y값은 출력 , sin(x)는 정답
input_data = np . arange ( 0 , np . pi * 2 , 0.1 ) #입력값
correct_data = np . sin ( input_data ) #정답값
input_data =( input_data - np . pi )/ np . pi #입력을 -0.1에서 1.0 범위로 수정
n_data = len ( correct_data ) #데이터 수
n_in = 1 #입력층의 뉴런수
n_mid = 3 #은닉층의 뉴런수
n_out = 1 #출력층의 뉴런수
wb_width = 0.01 #가중치와 편향설정을 위한 정규분포의 표준편차
eta = 0.1 #학습률
epoch = 2001 #2001에포크
interval = 200 #경과표시 간격
class OutLayer : #출력츨
def __init__ ( self , n_upper , n ): #초기 설정 (self,앞층의 뉴런수, 이 층의 뉴런수)
#위에서 얻은 뉴런수로 가중치와 편향의 초깃값 설정
self . w = wb_width * np . random . randn ( n_upper , n ) #가중치 행렬 생성
self . b = wb_width * np . random . randn ( n ) #편향 벡터 생성
def forward ( self , x ): #순전파
self . x = x
u = np . dot ( x , self . w )+ self . b #입력값 x외 가중치를 곱하고 편향을 더하여.....
self . y = u #출력값인 y를 계산(항등함수 사용)
def backward ( self , t ): #역전파(self, 이전에 층에서 얻은 정답값)
delta = self . y - t #이전에 얻은 정답을 뺀다
self . grad_w = np . dot ( self . x .T , delta )
self . grad_b = np . sum ( delta , axis = 0 )
self . grad_x = np . dot ( delta , self . w . T )
def update ( self , eta ):
self . w -= eta * self . grad_w
self . b -= eta * self . grad_b
class MiddleLayer : #은닉층
def __init__ ( self , n_upper , n ):
self . w = wb_width * np . random . randn ( n_upper , n )
self . b = wb_width * np . random . randn ( n )
def forward ( self , x ):
self . x = x
u = np . dot ( x , self . w )+ self . b #입력값 x외 가중치를 곱하고 편향을 더하여.....
self . y = 1 /( 1 + np . exp (- u )) #출력값인 y를 계산(시그모이드함수 사용)
def backward ( self , grad_y ):
delta = grad_y *( 1 - self . y )* self . y #시그모이드 함수 미분한다
self . grad_w = np . dot ( self . x .T , delta )
self . grad_b = np . sum ( delta , axis = 0 )
self . grad_x = np . dot ( delta , self . w . T )
def update ( self , eta ): #가중치와 편향 수정
self . w -= eta * self . grad_w
self . b -= eta * self . grad_b
#각 층을 초기화한다.
middle_layer = MiddleLayer ( n_in , n_mid )
out_layer = OutLayer ( n_mid , n_out )
for i in range ( epoch ): #학습
index_random = np . arange ( n_data ) #데이터의 수만큼의 원소 갯수를 가진 index_random을 생성한 뒤에..
np . random . shuffle ( index_random ) #여기에서 순서를 섞어준다
total_error = 0 #결과표시할때 사용
plot_x =[]
plot_y =[]
for idx in index_random : #위에서 셔플로 섞어준 넘파이리스트에서 하나씩 꺼낸다
x = input_data [ idx : idx + 1 ] #입력
t = correct_data [ idx : idx + 1 ] #정답
#순전파
middle_layer . forward ( x . reshape ( 1 , 1 ))
out_layer . forward ( middle_layer . y )
#역전피
out_layer . backward ( t . reshape ( 1 , 1 ))
middle_layer . backward ( out_layer . grad_x )
#가중치와 편향 수정
middle_layer . update ( eta )
out_layer . update ( eta )
if i % interval == 0 :
y = out_layer . y .reshape(- 1 )
total_error += 1.0 / 2.0 * np . sum ( np . square ( y - t ))
plot_x . append ( x )
plot_y . append ( y )
if i % interval == 0 :
plt . plot ( input_data , correct_data , linestyle = "dashed" )
plt . scatter ( plot_x , plot_y , marker = "+" )
plt . show ()
print ( "epoch: " + str ( i )+ "/" + str ( epoch ) , "Error:" + str ( total_error / n_data ))
epoch: 0/2001 Error:0.2859334345101318
epoch: 200/2001 Error:0.01303710291006273
epoch: 400/2001 Error:0.005978601741496623
epoch: 600/2001 Error:0.002343675519545371
epoch: 800/2001 Error:0.0007235721078605079
epoch: 2000/2001 Error:8.914322522327089e-06
분류문제에서 역전파 구현
분류에서는 sin곡선이 상단영역에 위치할지 하단에 위치할지 분류시키는 학습을 한다
정답은 원핫 인코딩이다.
import numpy as np
import matplotlib . pyplot as plt
x = np . arange (- 1.0 , 1.1 , 0.1 )
y = np . arange (- 1.0 , 1.1 , 0.1 )
input_data =[] #입력 벡터
correct_data =[] #정답 벡터
for X in x :
for Y in y :
input_data . append ([ X , Y ])
if Y < np . sin ( np . pi * X ): #sin값이 아래에 존재시에 0,1을 넣는다(원핫 인코딩)
correct_data . append ([ 0 , 1 ])
else : #위에 존재시 1,0 넣는다
correct_data . append ([ 1 , 0 ])
#데이터 수
n_data = len ( correct_data )
input_data = np . array ( input_data )
correct_data = np . array ( correct_data )
n_in = 2
n_mid = 6
n_out = 2
wb_width = 0.01
eta = 0.1
epoch = 101 #에포크는 101번
interval = 10 #구간별 표시 구간은 10으로
class OutLayer : #출력츨
def __init__ ( self , n_upper , n ): #초기 설정 (self,앞층의 뉴런수, 이 층의 뉴런수)
#위에서 얻은 뉴런수로 가중치와 편향의 초깃값 설정
self . w = wb_width * np . random . randn ( n_upper , n ) #가중치 행렬 생성
self . b = wb_width * np . random . randn ( n ) #편향 벡터 생성
def forward ( self , x ): #순전파
self . x = x
u = np . dot ( x , self . w )+ self . b #입력값 x외 가중치를 곱하고 편향을 더하여.....
self . y = np . exp ( u )/ np . sum ( np . exp ( u ), axis = 1 , keepdims = True ) #소프트맥스함수
def backward ( self , t ): #역전파(self, 이전에 층에서 얻은 정답값)
delta = self . y - t #이전에 얻은 정답을 뺀다
self . grad_w = np . dot ( self . x .T , delta )
self . grad_b = np . sum ( delta , axis = 0 )
self . grad_x = np . dot ( delta , self . w . T )
def update ( self , eta ):
self . w -= eta * self . grad_w
self . b -= eta * self . grad_b
class MiddleLayer : #은닉층
def __init__ ( self , n_upper , n ):
self . w = wb_width * np . random . randn ( n_upper , n )
self . b = wb_width * np . random . randn ( n )
def forward ( self , x ):
self . x = x
u = np . dot ( x , self . w )+ self . b #입력값 x외 가중치를 곱하고 편향을 더하여.....
self . y = 1 /( 1 + np . exp (- u )) #출력값인 y를 계산(시그모이드함수 사용)
def backward ( self , grad_y ):
delta = grad_y *( 1 - self . y )* self . y #시그모이드 함수 미분한다
self . grad_w = np . dot ( self . x .T , delta )
self . grad_b = np . sum ( delta , axis = 0 )
self . grad_x = np . dot ( delta , self . w . T )
def update ( self , eta ): #가중치와 편향 수정
self . w -= eta * self . grad_w
self . b -= eta * self . grad_b
#각 층을 초기화한다.
middle_layer = MiddleLayer ( n_in , n_mid )
out_layer = OutLayer ( n_mid , n_out )
sin_data = np . sin ( np . pi * x ) #결과 검증용
for i in range ( epoch ):
index_random = np . arange ( n_data )
np . random . shuffle ( index_random )
total_error = 0
x_1 , y_1 , x_2 , y_2 =[],[],[],[]
for idx in index_random :
X = input_data [ idx ]
t = correct_data [ idx ]
middle_layer . forward ( X .reshape( 1 , 2 ))
out_layer . forward ( middle_layer . y )
out_layer . backward ( t .reshape( 1 , 2 ))
middle_layer . backward ( out_layer . grad_x )
middle_layer . update ( eta )
out_layer . update ( eta )
if i % interval == 0 :
Y = out_layer . y .reshape(- 1 )
total_error += - np . sum ( t * np . log ( y + 1e-7 ))
if Y [ 0 ]> Y [ 1 ]:
x_1 . append ( X [ 0 ])
y_1 . append ( X [ 1 ])
else :
x_2 . append ( X [ 0 ])
y_2 . append ( X [ 1 ])
if i % interval == 0 :
plt . plot ( x , sin_data , linestyle = "dashed" )
plt . scatter ( x_1 , y_1 , marker = "+" )
plt . scatter ( x_2 , y_2 , marker = "x" )
plt . show ()
print ( "epoch: " + str ( i )+ "/" + str ( epoch ) , "Error:" + str ( total_error / n_data ))
Epoch:0/101 Error:0.7226915341273943
Epoch:10/101 Error:0.32361579765015897
Epoch:100/101 Error:0.07152428711763589