반응형


" You are going be fine! "


이전 포스팅에서 만든 신경망을 "더 좋은 신경망으로 만드는 방법"에 대해 알아보도록 하겠습니다.




오차 역전파란?


신경망 학습 처리에서 오차를 최소화하는 함수의 경사를


효율적으로 계산하기 위한 방법입니다.



< 비용함수(cost function)의 경사(기울기)를 계산하는 방법>



1. 수치미분


: 구현하기 쉽고 정확성이 높으나, 매우 느리다.



2. 오차 역전파


: 출력층으로부터 차례대로 역방향으로 각 층에 있는 노드의 오차를 계산하여,

그 오차로 함수의 경사를 계산합니다.


즉, 전파된 오차를 이용하여 가중치를 조정하는 것이 '오차역전파' 입니다.



< 계산 그래프 >


계산 그래프란, 순전파와 역전파에 계산 과정을 그래프로 나타내는 방법입니다.



왜 계산 그래프로 문제를 해결할까요?


1. 전체가 아무리 복잡해도 각 노드에서 단순한 계산에 집중하여

문제를 단순화 할 수 있습니다. ( 국소적 계산 )



2. 역전파를 통해서 미분을 효율적으로 계산할 수 있습니다.




< 합성함수 미분 구하기 >



우선 기본적인 미분 공식은 다음과 같습니다.



원리: 접선은 할선의 극한입니다.



하지만 위와 같은 진정한 미분은 h 가 0이 될 경우, 컴퓨터로 구현하기 어렵기 때문에


근사한 접선인 할선을 구하는 "수치미분"을 사용해야합니다.


따라서 수치미분에는 약간의 오차가 포함됩니다.



[ 파이썬으로 수치미분 구현하기 ]

def numerical_diff(f,x): h = 1e-4 # 0.0001 # 컴퓨터로 극한 값을 구하기 어려우므로 도함수를 구현한다. # return (f(x+h) - f(x-h)) / ((x+h) - (x-h)) return (f(x+h) - f(x-h)) / 2*h



< 편미분 >


변수가 2개 이상인 함수를 미분할 때 미분 대상 변수 외에 나머지 변수를

상수처럼 고정시켜 미분하는 것을 편미분이라고 합니다.



[ 파이썬으로 편미분 구현하기 ]


def numerical_gradient(f,x): h = 1e-4 grad = np.zeros_like(x) for idx in range(x.size): tmp_val = x[idx] # f(x+h) 계산 x[idx] = tmp_val + h fxh1 = f(x) # f(x-h) 계산 x[idx] = tmp_val - h fxh2 = f(x) grad[idx] = (fxh1 - fxh2) / 2*h x[idx] = tmp_val # 값 복원 return grad



< 신경망 학습을 시키기 위한 방법 >



(W: Weight, 기울기: 오차함수 미분한 값)




< 합성함수 미분 >



추가설명:

f(x) = ax + b


f(x)를 X로 보고 미분하고 (ax + b)를 속 미분하여 더한다.


혹시 증명을 알고 싶으신 분들은 구글에..ㅎㅎ



< 연쇄법칙 >


합성 함수의 미분은 합성 함수를 구성하는 각 함수의 미분의 곱으로 나타낼 수 있습니다.


이것이 연쇄 법칙의 원리 입니다.




< 역전파 >


신경망의 역전파에서의 중요한 성질은

출력과 정답 레이블의 차이인 오차가 앞 계층에 전해지는 것입니다.


1. Affine / Relu 계층


Affine 계층이란,


신경망의 순전파 때 수행하는 행렬의 내적은 기하학에서는 어파인 변환이라고 합니다.


그래서 어파인 변환을 수행하는 처리를 'Affine 계층'이라는 이름으로 구현하도록 하겠습니다.



2. Softmax-with-Loss 계층


마지막으로 출력층에서 사용하는 함수로


신경망의 학습의 목적인 신경망의 출력(Softmax의 출력)이

정답 레이블과 가까워지도록 가중치 매개변수의 값을 조정하는 역할을 합니다.




< MNIST 신경망 구현하기 >


드디어 역전파를 Python으로 구현해보도록 하겠습니다.



[ 2층 신경망 구현하기 ]


import numpy as np from common.layers import * from common.gradient import numerical_gradient # 수치미분 함수 from collections import OrderedDict class TwoLayerNet: def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01): # 가중치 초기화 self.params = {} self.params['W1'] = weight_init_std * \ np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = weight_init_std * \ np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size) # 계층생성 self.layers = OrderedDict() # 순전파 순서의 반대로 역전파가 된다. self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1']) self.layers['Relu1'] = Relu() self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2']) self.lastLayer = SoftmaxWithLoss() # 예측 수행 def predict(self, x): for layer in self.layers.values(): x = layer.forward(x) return x # x: 입력데이터, t: 레이블 def loss(self, x, t): y = self.predict(x) return self.lastLayer.forward(y,t) def accuracy(self, x, t): y = self.predict(x) y = np.argmax(y, axis=1) if t.ndim != 1: t= np.argmax(t, axis=1) accuracy = np.sum(y == t) / float(x.shape[0]) return accuracy # x: 입력데이터, t: 레이블 def numerical_gradient(self, x, t): loss_W = lambda W: self.loss(x,t) grads = {} grads['W1'] = numerical_gradient(loss_W, self.params['W1']) grads['b1'] = numerical_gradient(loss_W, self.params['b1']) grads['W2'] = numerical_gradient(loss_W, self.params['W2']) grads['b2'] = numerical_gradient(loss_W, self.params['b2']) return grads # 오차 역전파 def gradient(self, x, t): # 순전파 self.loss(x,t) # 역전파 dout = 1 dout = self.lastLayer.backward(dout) layers = list(self.layers.values()) layers.reverse() for layer in layers: dout = layer.backward(dout) # 결과 저장 grads = {} grads['W1'] = self.layers['Affine1'].dW grads['b1'] = self.layers['Affine1'].db grads['W2'] = self.layers['Affine2'].dW grads['b2'] = self.layers['Affine2'].db return grads


※ 참고


수치미분과 오차역전파법의 결과를 비교하면 오차역전파법의 구현에 잘못이 없는지 확인할 수 있습니다.



[ MNIST 데이터 학습 구현하기 ]


import numpy as np from dataset.mnist import load_mnist # 데이터 읽기 (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) iters_num = 10000 train_size = x_train.shape[0] batch_size = 100 learning_rate = 0.1 train_loss_list = [] train_acc_list = [] test_acc_list = [] iter_per_epoch = max(train_size / batch_size, 1) for i in range(iters_num): batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] # 오차역전파법으로 기울기를 구한다. grad = network.gradient(x_batch, t_batch) # 갱신 for key in ('W1', 'b1','W2','b2'): network.params[key] -= learning_rate * grad[key] loss = network.loss(x_batch, t_batch) train_loss_list.append(loss) if i % iter_per_epoch == 0: train_acc = network.accuracy(x_train, t_train) test_acc = network.accuracy(x_test, t_test) train_acc_list.append(train_acc) test_acc_list.append(test_acc) print(train_acc, test_acc)


※ 추가


문제. 위의 2차 신경망으로 3차 신경망을 구하고 정확도를 확인하시오



코드 출처: Deep Learning from Scratch

데이터: 한빛 미디어 깃 허브 저장소




오늘은 여기까지!


다음 포스팅은 학습 관련 기술들에 대해 더 자세히 알아보도록 합시다!!

반응형
반응형



안녕하세요~ 오늘은 드디어! 신경망에 대해 살짝 맛보도록 하겠습니다!



우선, 퍼셉트론과 신경망의 차이부터 알아봅시다!


퍼셉트론을 모른다면 "퍼셉트론(Perceptron)이란?" 을 참고하세요!



1. 퍼셉트론은 원하는 결과를 출력하도록 사람이 직접 가중치를 정해줘야 합니다!


AND, OR, NAND 게이트를 만들때 가중치를 채워 넣는 문제를 냈습니다!


어떻게 찾으셨나요? 저는 직접 숫자를 대입해보며 찾았답니다!


 혹시 더 쉽게 찾는 방법을 아시나요? 아신다면 댓글로 공유해주세요!



2. 신경망은 가중치 매개변수의 적절한 값을 기계가 데이터로부터 학습해서 자동으로 알아냅니다!





" 신경망 학습하기 "




이전 포스팅에서 신경망에 들어가는 함수


계단함수, 시그모이드 함수, 렐루 함수에 대해 알아보았습니다!



좀더 자세히 말하자면 위의 3가지 함수는


은닉층에 들어가는 함수 중 3가지를 의미합니다.




그렇다면 마지막 출력층에 들어가는 함수는 어떻게 될까요?


출력층 함수란,


그동안 흘러온 확률의 숫자를 취합해 결론을 내는 함수입니다.



신경망으로 구현하고자 하는 문제에 따라 사용하는 출력층 함수가 다릅니다.



1. 회귀(Regression)의 경우, 항등함수를 사용합니다.


항등함수란, 어떤 변수도 자기 자신을 함수값으로 하는 함수입니다.


[파이썬코드]

def identity(x): return x

간단하죠?




2. 분류(Classfication) 의 경우, 두 가지로 나뉘는데요.


2-1) 시그모이드(Sigmoid) 함수 : 2클래스 분류에서 사용합니다. ( ex, 개 vs 고양이 분류)


2-2) 소프트맥스(Softmax) 함수 : 다중 클래스 분류 (ex, 정상 폐사진 vs 폐결절, 폐혈증... 등 분류)



시그모이드는 은닉층의 활성화 함수에서 알아봤으니,



새로운 함수인, 소프트맥스 함수에 대해 더 자세히 알아보겠습니다.


소프트 맥스(Softmax) 함수란?


0과 1사이의 숫자를 출력하는 함수로, 출력하는 값은 확률입니다.


[파이썬 코드]


def softmax(a): C = np.max(a) exp_a = np.exp(a-C) sum_a = np.sum(exp_a) return exp_a / sum_a


[소프트 맥스 함수식]


e%203.10.png



소프트 맥스 함수식과 위의 파이썬 코드가 조금 다르죠?


그 이유는, overflow때문입니다!



우선, 소프트 맥스 함수는 지수함수를 사용하는데 이 지수함수라는 것은 아주 쉽게 아주 큰 값을 내뱉습니다.



예를 들어


exp == e (무리수: 자연상수)


e ^10 > 20000: 자연상수의 10승은 20000보다 크고


e ^1000 == inf : 자연상수의 1000승은 무한대(inf)를 나타냅니다.



따라서 표현할 수 없는 큰 값을 해결하기위해 아래와 같은 식으로 변형을 해서 사용합니다.




지수함수와 로그함수를 잘 모르겠다면 "여기"를 참고하세요!






" 이제, 아래의 신경망을 직접 구현해보도록 하겠습니다!"





import numpy as np # 신경망 함수 def sigmoid(x): return 1 / (1 + np.exp(-x)) def identity(x): return x def init_network(): network = {} network['W1'] = np.array([[1,3,5],[2, 4, 6]]) # weight 은 관습적으로 W라고 합니다. network['W2'] = np.array([[1,2],[3,4],[5,6]]) network['W3'] = np.array([[1,2],[3,4]]) return network

# 신경망 구현 def forward(network, x): W1, W2, W3 = network['W1'], network['W2'], network['W3'] y = np.dot(x, W1) y_hat = sigmoid(y) k = np.dot(y_hat, W2) k_hat = sigmoid(k) j = np.dot(k_hat, W3) j_hat = identity(j) # identity 대신 softmax함수를 사용할 수 있습니다. return j_hat network = init_network() x = np.array([1,2]) # 입력 y = forward(network, x) # 출력 print(y)





오늘은 여기까지!


신경망 학습 방법은 다음 포스팅에서 더 자세히 다루겠습니다!


좋은 하루 보내세요! 

반응형
반응형



안녕하세요~


오늘은 XOR(다층 퍼셉트론)신경망 활성화 함수(activation function) 에 대해 알아보겠습니다.



우선, 이전 포스팅 퍼셉트론에 이어


XOR에 대해 먼저 알아보도록 하겠습니다.


[ XOR 진리표 ]


XOR 게이트는 단층 퍼셉트론으로 구현이 되지 않습니다.


따라서, 다층 퍼셉트론으로 구현해야합니다.



" 단층 퍼셉트론 vs 다층 퍼셉트론 "


"단층 퍼셉트론"이란,

AND, OR, NAND 게이트와 같이


입력층에 가중치를 곱해 바로 출력되는 퍼셉트론입니다.


아래와 같이 표현할 수 있습니다. 




"다층 퍼셉트론"이란,

퍼셉트론을 층으로 쌓은 것으로,


입력층과 출력층 사이 은닉층이 존재하는 것입니다.




위와 같은 다층 퍼셉트론으로 XOR 게이트를 구현할 수 있습니다.



XOR 게이트는 아래와 같이 AND, OR, NAND를 조합해서 만들 수 있습니다.






※ 참고: 각각의 게이트는 아래와 같은 의미 갖고 있습니다.




이제 XOR 진리표를 완성해볼까요?




문제1. XOR 게이트를 파이썬으로 구현해보세요








활성화 함수란?


입력신호의 총합을 출력신호로 변환하는 함수를 일반적으로 활성화 함수라고 합니다.

활성화 함수는 입력신호의 총합이 활성화를 일으키는지 정하는 역할을 합니다.


출처: Deep Learning from Scratch



" 활성화 함수의 종류 3가지 "


1. 계단함수(Step Function) : 0 또는 1 의 값을 출력하는 함수


2. 시그모이드 함수(Sigmoid Function) : 0 ~ 1 사이의 실수를 출력하는 함수


3. ReLu(Rectified Linear Units) : 입력이 0이 넘으면 그 입력값을 그대로 출력하고 0 이하이면 0을 출력하는 함수




이제 각각의 특징을 알았으니, 파이썬으로 구현해보도록 하겠습니다.




1. 계단함수 (Step Function)


" 퍼셉트론에서는 활성화 함수로 계단함수를 이용한다. "



" numpy로 계단함수 구현하기 "

import numpy as np


def step_function(x_data): # return [0 if x<=0 else 1 for x in x_data ]

# np.array.astype(np.int): bool type을 정수로 변환하기 return (x_data > 0).astype(np.int)


문제2. 위에서 만든 계단함수를 이용해서, 아래와 같이 그래프를 그리시오







2. 시그모이드 함수 (Sigmoid Function)



※ 계단함수와 시그모이드 함수의 공통점 & 차이점


[공통점]


둘다 0과 1 사이의 데이터만 출력한다

비선형 함수이다.


[차이점]


계단함수는 숫자 1 과 0만 출력하는데 시그모이드 함수는 0과 1사이의 실수를 출력한다.



[시그모이드 함수식]

sigmoid



" 통계학에서 성공할 확률이 실패할 확률보다 얼마나 큰지를 나타내는 오즈비율이라는 값이 있다. "



오즈비율(Odds ratio) = 성공 / 실패 = P / (1 - P)



성공할 확률 P를 0에서 1사이의 값으로 나타내면,

실패할 확률은 (1 - P)이다.


위에 그래프에서 확인할 수 있듯이,

P(성공할 확률)가 1에 가까워지면 오즈 비율 값이 급격히 커지는 현상이 발생한다.



그러한 현상을 방지하기 위해, 로그를 취한 Logit이라는 함수를 만든다.



로그를 사용하는 이유: 큰 숫자를 작은 숫자로 표현하기 위해





Logit Function = log(P/(1-P)) = wx + b



이 로짓 함수를 뉴런의 출력값에 따라 확률 P를 구하기 쉽도록 지수 함수 형태로 바꾸면,


위에서 확인한 시그모이드 함수가 됩니다.



" numpy로 Sigmoid 함수 구현하기"


import numpy as np def sigmoid(x): return 1 / (1 + np.exp(-x))


문제3. 위에서 만든 시그모이드 함수를 이용해서, 아래와 같이 그래프를 그리시오





3. ReLu 함수( RectifiedLinearUnits Function)


" 최근에는 활성화 함수로 ReLU(렐루)함수를 주로 이용합니다 "


이유는 이후 포스팅에 설명하겠습니다.



"numpy로 ReLU 함수 구현하기"

import numpy as np

def relu(x):
# if x <= 0: # return 0 # return x

# maximum 은 두 입력 중 큰 값을 선택해 반환하는 함수이다.
return np.maximum(0,x)


문제4. 위에서 만든 렐루(ReLU)함수를 이용해서, 아래와 같이 그래프를 그리시오







오늘은 여기까지!!


다음 주에는 신경망으로 돌아올게요!!

반응형
반응형

안녕하세요!



오늘은


신경망에서 오차 역전파에서 사용되는


지수함수와 로그함수에 대해 알아보겠습니다.





고등학교 수학시간때 들었지만


저는 기억이 가물가물... 열심히 하지 않았나봐요..



그래서 딥러닝을 위해 다시 공부해보도록 하겠습니다!




우선,


지수란?


2 x

 

이러한 거듭제곱의 형태를 말합니다.



그렇다면,


지수함수란?


y = 2 x


위와 같이 y= 을 붙여서 짝을 지어주는 것을 말합니다.


이것을 밑이 2인 지수함수라고 합니다.



이러한 지수함수는 밑이 1보다 큰 경우와


밑이 0보다 크고 1보다 작은 경우로 나눌 수 있습니다.



그래프로 비교해 볼까요?




(1 < 밑)  y =  x  함수의 그래프





(0 < 밑 < 1) y =  (1/2) x 함수의 그래프




따라서


 y =  x 그래프와 y = (1/2) x 그래프는 Y축 대칭입니다.


 y =  x 는 증가함수 그래프의 형태를


y = (1/2) x 는 감소함수 그래프의 형태를 띄게됩니다.


(위의 그래프는 구글에서 직접 그려보실 수 있습니다.)




로그 함수란?


y = loga x (a > 0, a != 1, x > 0)


이것을 a를 밑으로 하는 로그함수라고 말합니다.


여기서 x는 진수입니다.


로그함수는 지수함수의 역함수입니다.



이러한 로그함수도 밑이 1보다 큰 경우와


밑이 0보다 크고 1보다 작은 경우로 나눌 수 있습니다.




그래프로 확인해 볼까요?



(1 < 밑) 일 때, 아래의 그래프 형태를 띕니다.




(0 < 밑 < 1) 일 때, 아래의 그래프 형태를 띕니다.





따라서 


y = logx  그래프와  y =  a x 그래프는 Y = X축 대칭입니다.


y = x 라는 것은 x 대신 y, y 대신 x 의 값을 갖는 다는 것입니다.





오늘은 여기까지!


이 원리를 이용하는 신경망 오차 역전파 방법은 파이썬에서 활용해보도록 해보겠습니다.

반응형

+ Recent posts