신경망(neural network)에서 backpropagation을 이용해서 학습 하는것은 input을 이용해서 output을 예측하려는 것이다.
3개열의 input을 이용해서 output을 예측하는 것을 이용해 보자.
2 Layer Neural Network:
code 설명 :
3개열의 input을 이용해서 output을 예측하는 것을 이용해 보자.
2 Layer Neural Network:
import numpy as np def sigmo(x, deriv=False): if(deriv == True): return x*(1-x) return 1/(1+np.exp(-x)) X = np.array([[0,0,1],
[1,1,1],
[1,0,1],
[0,1,1]]) y = np.array([[0,1,1,0]]).T np.random.seed(1)
syn0 = np.random.random_sample((3,1))for itr in xrange(10000): l0 = X l1 = sigmo(np.dot(l0, syn0)) l1_error = y - l1 l1_delta = l1_error * sigmo(l1,True) syn0 += np.dot(l0.T,l1_delta) print "Output after training :"
print l1
Output after training :
[[ 0.00966449]
[ 0.99211957]
[ 0.99358898]
[ 0.00786506]]
위의 결과 "Output after training"을 보면, 뭔가 작동하여 결과가 나왔다. 아래의 설명을 보기 전에 직관적으로 코드가 어떻게 구성되어 있는지, 사이사이의 값들은 어떻게 변하는지 직접 실행해 보길 바란다.
예를 들어,
print y
print syn0
print l1
print l1_error
등의 값을 확인해 보기 바란다. xrange(1), xrange(10) 등의 값으로 반복 횟수를 줄여서도 확인해 보기 바란다.
code 설명 :
def sigmo(x, deriv=False):
--> sigmoid 함수를 정의한다. Sigmoid 함수는 0과 1사이의 값이다. 이 값은 확률값을 구하는데 사용된다. (누적확률분포(여기서는 Sigmoid 함수)와 uniform 분표(여기서는 y 값(0~1사이)을 이용하면 확률 분포를 컴퓨터를 이용하여 구현할 수 있다. )
if(deriv == True):
return x*(1-x)
--> sigmoid 를 미분하면 나오는 값 (deviv == True 일때)
--> sigmoid 를 미분하면 나오는 값 (deviv == True 일때)
return 1/(1+np.exp(-x))
--> sigmoid 함수 값
--> sigmoid 함수 값
X = np.array([[0,0,1],
[1,1,1],
[1,0,1],
[0,1,1]])
[1,1,1],
[1,0,1],
[0,1,1]])
--> 3개의 input nodes가 있는, 4개의 training 샘플을 초기화, 행렬의 형태로 보면, 4 X 3 행렬
y = np.array([[0,1,1,0]]).T
--> output. numpy의 transpose(행렬 변환)를 이용하여, 1 X 4 행렬(벡터)를 4 X 1 행렬(벡터)로 변환 시킴.
input과 output을 연결시켜줄 스냅시스는 3 X 4 행렬이어야 하는 것을 알 수 있다.
np.random.seed(1)
--> Rnadom number 생성을 위한 seed를 1로 고정 시킴. seed값을 변경하지 않으면, 항상 동일한 Random number가 성생됨. (컴퓨터의 Random number는 일정한 수식에 의해서 생성된다. 이 수식에 입력되는 초기 값을 seed라고 한다. 즉 seed 값이 같으면, 동일한 Random number가 생성되는 것이다.)
syn0 = np.random.random_sample((3,1))
--> random 함수는 [0.0, 1.0)의 범위에서 생성되는 uniform 분포이다. 그 값을 3 X 1 형태의 array 에 넣어 준다. 이것은 weight matrix이다. 우리의 간단한 예제는 3개의 input과 1개의 output이 있다. 또한 4X3(input)행렬과 4X1(output)행렬의 연결시켜 주기 위해서는 3X1(syn0)이 필요한 것이다. 우리는 이것을 시냅스0라고 부를 것이다.
이 간단한 예제에서 neural network은 syn0이다. l0(layer0), l1(layer1)은 input과 output값이고, syn0만 hidden layer로써, 모든 learning이 저장된다. (참고, backpropagation)
l1 = sigmo(np.dot(l0, syn0))
--> for 반복문 안에서, 먼저 l0와 syn0 를 행렬 dot 연산을 한다. 위에서 살펴본 것처럼, l0 = X이므로, np.dot(l0, syn0)의 결과는 (4X3) X (3X1) 형태의 형렬 연상이다. 결과는 4X1 형태의 행렬이 된다. 즉 4X1형태의 연산 결과가 sigmo 함수로 전달되고, 그 결과가 l1에 저장된다. sigmo함수 선언에서 deriv==False로 줘놨기 때문에 기본적으로 False값이 전달된다.
l1_error = y - l1
--> y(4X1)와 l1(4X1)을 동일한 형식을 갖고 있으므로, 행렬의 뺄셈을 할 수 있다. 그 차이값(y와 l1의 차이)을 l1_error로 저장하였고, 그 값다 4X1 행렬 형태이다. learning(예측)결과와 output(실제) 값을 비교하여 error값을 계산한다.
l1_delta = l1_error * sigmo(l1,True)
syn0 += np.dot(l0.T,l1_delta)
--> 아래 결과를 보면, for 반복문이 진행되면서, l1, l1_error, sigmo(l1, True), l1_delta 값이 어떻게 변해 가는지 확인할 수 있다.
--> output. numpy의 transpose(행렬 변환)를 이용하여, 1 X 4 행렬(벡터)를 4 X 1 행렬(벡터)로 변환 시킴.
input과 output을 연결시켜줄 스냅시스는 3 X 4 행렬이어야 하는 것을 알 수 있다.
np.random.seed(1)
--> Rnadom number 생성을 위한 seed를 1로 고정 시킴. seed값을 변경하지 않으면, 항상 동일한 Random number가 성생됨. (컴퓨터의 Random number는 일정한 수식에 의해서 생성된다. 이 수식에 입력되는 초기 값을 seed라고 한다. 즉 seed 값이 같으면, 동일한 Random number가 생성되는 것이다.)
syn0 = np.random.random_sample((3,1))
--> random 함수는 [0.0, 1.0)의 범위에서 생성되는 uniform 분포이다. 그 값을 3 X 1 형태의 array 에 넣어 준다. 이것은 weight matrix이다. 우리의 간단한 예제는 3개의 input과 1개의 output이 있다. 또한 4X3(input)행렬과 4X1(output)행렬의 연결시켜 주기 위해서는 3X1(syn0)이 필요한 것이다. 우리는 이것을 시냅스0라고 부를 것이다.
이 간단한 예제에서 neural network은 syn0이다. l0(layer0), l1(layer1)은 input과 output값이고, syn0만 hidden layer로써, 모든 learning이 저장된다. (참고, backpropagation)
l1 = sigmo(np.dot(l0, syn0))
--> for 반복문 안에서, 먼저 l0와 syn0 를 행렬 dot 연산을 한다. 위에서 살펴본 것처럼, l0 = X이므로, np.dot(l0, syn0)의 결과는 (4X3) X (3X1) 형태의 형렬 연상이다. 결과는 4X1 형태의 행렬이 된다. 즉 4X1형태의 연산 결과가 sigmo 함수로 전달되고, 그 결과가 l1에 저장된다. sigmo함수 선언에서 deriv==False로 줘놨기 때문에 기본적으로 False값이 전달된다.
l1_error = y - l1
--> y(4X1)와 l1(4X1)을 동일한 형식을 갖고 있으므로, 행렬의 뺄셈을 할 수 있다. 그 차이값(y와 l1의 차이)을 l1_error로 저장하였고, 그 값다 4X1 행렬 형태이다. learning(예측)결과와 output(실제) 값을 비교하여 error값을 계산한다.
l1_delta = l1_error * sigmo(l1,True)
syn0 += np.dot(l0.T,l1_delta)
--> 아래 결과를 보면, for 반복문이 진행되면서, l1, l1_error, sigmo(l1, True), l1_delta 값이 어떻게 변해 가는지 확인할 수 있다.
0 -l1 : 예측값 (for문의 0번째 iteration)
[[ 0.50002859]
[ 0.75721315]
[ 0.60279781]
[ 0.67270365]]
l1_error : (y - l1)의 결과, 실제값과 예측값의 차이
[[-0.50002859]
[ 0.24278685]
[ 0.39720219]
[-0.67270365]]
sigmo(l1,True) : 위의 l1에서의 sigmoid 함수의 기울기
[[ 0.25 ]
[ 0.1838414 ]
[ 0.23943261]
[ 0.22017345]]
l1_delta : l1_error에 sigmo(l1,True) 를 곱한 값
[[-0.12500715]
[ 0.04463427]
[ 0.09510316]
[-0.14811148]]
syn0 :
[[ 0.55675944]
[ 0.61684728]
[-0.13326682]]
1 -l1 : (for문의 1번째 iteration)
[[ 0.46673252]
[ 0.73891558]
[ 0.6043187 ]
[ 0.61859299]]
l1_error
[[-0.46673252]
[ 0.26108442]
[ 0.3956813 ]
[-0.61859299]]
sigmo(l1,True) :
[[ 0.24889327]
[ 0.19291934]
[ 0.23911761]
[ 0.2359357 ]]
l1_delta
[[-0.11616658]
[ 0.05036823]
[ 0.09461437]
[-0.14594817]]
syn0
[[ 0.70174204]
[ 0.52126735]
[-0.25039898]]
2 -l1
[[ 0.4377253 ]
[ 0.7256395 ]
[ 0.61095851]
[ 0.56730608]]
l1_error
[[-0.4377253 ]
[ 0.2743605 ]
[ 0.38904149]
[-0.56730608]]
sigmo(l1,True) :
[[ 0.24612186]
[ 0.19908682]
[ 0.23768821]
[ 0.24546989]]
l1_delta
[[-0.10773377]
[ 0.05462156]
[ 0.09247057]
[-0.13925656]]
syn0
[[ 0.84883417]
[ 0.43663234]
[-0.35029717]]
3 -l1
[[ 0.41331036]
[ 0.71812285]
[ 0.62211546]
[ 0.5215704 ]]
l1_error
[[-0.41331036]
[ 0.28187715]
[ 0.37788454]
[-0.5215704 ]]
sigmo(l1,True) :
[[ 0.24248491]
[ 0.20242242]
[ 0.23508781]
[ 0.24953472]]
l1_delta
[[-0.10022152]
[ 0.05705825]
[ 0.08883605]
[-0.13014992]]
syn0
[[ 0.99472848]
[ 0.36354068]
[-0.43477431]]
[[ 0.50002859]
[ 0.75721315]
[ 0.60279781]
[ 0.67270365]]
l1_error : (y - l1)의 결과, 실제값과 예측값의 차이
[[-0.50002859]
[ 0.24278685]
[ 0.39720219]
[-0.67270365]]
sigmo(l1,True) : 위의 l1에서의 sigmoid 함수의 기울기
[[ 0.25 ]
[ 0.1838414 ]
[ 0.23943261]
[ 0.22017345]]
l1_delta : l1_error에 sigmo(l1,True) 를 곱한 값
[[-0.12500715]
[ 0.04463427]
[ 0.09510316]
[-0.14811148]]
syn0 :
[[ 0.55675944]
[ 0.61684728]
[-0.13326682]]
1 -l1 : (for문의 1번째 iteration)
[[ 0.46673252]
[ 0.73891558]
[ 0.6043187 ]
[ 0.61859299]]
l1_error
[[-0.46673252]
[ 0.26108442]
[ 0.3956813 ]
[-0.61859299]]
sigmo(l1,True) :
[[ 0.24889327]
[ 0.19291934]
[ 0.23911761]
[ 0.2359357 ]]
l1_delta
[[-0.11616658]
[ 0.05036823]
[ 0.09461437]
[-0.14594817]]
syn0
[[ 0.70174204]
[ 0.52126735]
[-0.25039898]]
2 -l1
[[ 0.4377253 ]
[ 0.7256395 ]
[ 0.61095851]
[ 0.56730608]]
l1_error
[[-0.4377253 ]
[ 0.2743605 ]
[ 0.38904149]
[-0.56730608]]
sigmo(l1,True) :
[[ 0.24612186]
[ 0.19908682]
[ 0.23768821]
[ 0.24546989]]
l1_delta
[[-0.10773377]
[ 0.05462156]
[ 0.09247057]
[-0.13925656]]
syn0
[[ 0.84883417]
[ 0.43663234]
[-0.35029717]]
3 -l1
[[ 0.41331036]
[ 0.71812285]
[ 0.62211546]
[ 0.5215704 ]]
l1_error
[[-0.41331036]
[ 0.28187715]
[ 0.37788454]
[-0.5215704 ]]
sigmo(l1,True) :
[[ 0.24248491]
[ 0.20242242]
[ 0.23508781]
[ 0.24953472]]
l1_delta
[[-0.10022152]
[ 0.05705825]
[ 0.08883605]
[-0.13014992]]
syn0
[[ 0.99472848]
[ 0.36354068]
[-0.43477431]]
작성중,
참고 : https://iamtrask.github.io/2015/07/12/basic-python-network/
참고 : https://iamtrask.github.io/2015/07/12/basic-python-network/
댓글 없음:
댓글 쓰기