티스토리 뷰
신경망
퍼셉트론과 신경망
활성하 함수
위 그림은 말로 옯기면 입력신호와 가중치를 곱한뒤 총합을 활성화 함수인 시그모이드 함수를 통과시켜 출력하는 것을 의미합니다.
계단 함수
1234567 import numpy as np def step_function(x): y=x>0 return y.astype(np.int) print(step_function(np.array([1.0,2.0]))) cs
1 2 3 4 5 6 7 | import numpy as np def step_function(x): y=x>0 return y.astype(np.int) print(step_function(np.array([1.0,2.0]))) | cs |
활성화 함수를 구현하는 코드는 4와 5 총 2줄입니다.
스크립트가 아닌 인터프리터에서 위 코드를 쳐보면 부등호 연산 시 bool타입으로 변환되는 것을 볼 수 있습니다. 그리고 이걸 asytpe(np.int)로 변환하면 true와 false가 아닌 1과 0으로 구분할 수 있게 됩니다.
이제 그래프를 그려서 어떤 형태로 나오는지도 알아보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 | import numpy as np import matplotlib.pylab as plt def step_function(x): return np.array(x>0, dtype=np.int) x=np.arange(-5.0,5.0,0.1) y=step_function(x) plt.plot(x,y) plt.ylim(-0.1,1.2) #y측 범위 지정 plt.show() | cs |
시그모이드 함수
시그모이드 함수는 계단 함수처럼 0이었다가 갑자기 1이 되지 않고, 0부터 1까지의 변화가 부드럽게 바뀝니다.
시그모이드 함수를 구현해 보겠습니다.
1 2 3 4 5 6 | import numpy as np def sigmoid(x): return 1/(1+np.exp(-x)) print(sigmoid(np.array([-1.0,1.0,2.0]))) | cs |
*np.array()부분이 되는 이유는 numpy의 브로드캐스트 때문입니다. 브로드캐스트는 넘파이 배열과 스칼라값의 연산을 넘파이 배열의 원소 각각과 스칼라 값의 연산으로 바꿔 수행하는 것을 말합니다.
시그모이드를 그래프로 출력해보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 | import numpy as np import matplotlib.pyplot as plt def sigmoid(x): return 1/(1+np.exp(-x)) x=np.arange(-5.0,5.0,0.1) y=sigmoid(x) plt.plot(x,y) plt.ylim(-0.1,1.1) plt.show() | cs |
위 코드를 실행해보면 0부터 1까지 부드럽게 연결 되는 것을 볼 수 있습니다.
시그모이드 함수와 계단 함수의 차이
비선형 함수
ReLU 함수
식은 이렇게 나타내면 됩니다.
그럼 구현을 해보겠습니다.
1 2 3 4 | import numpy as np def relu(x): return np.maximum(0,x) | cs |
다차원 배열
1 2 3 4 5 6 7 8 9 10 | >>> import numpy as np >>> a=np.array([1,2,3,4]) >>> print(a) [1 2 3 4] >>> np.ndim(a) 1 >>> a.shape (4,) >>> a.shape[0] 4 | cs |
1 2 3 4 5 6 7 8 9 | >>> b=np.array([[1,2],[3,4],[5,6]]) >>> print(b) [[1 2] [3 4] [5 6]] >>> np.ndim(b) 2 >>> b.shape (3, 2) | cs |
행렬의 내적(행렬 곱)
위 그림에서처럼 행렬 내적은 왼쪽 행렬의 행(가로)과 오른쪽 행렬의 열(세로)을 원소별로 곱하고 그 값들을 더해서 계산합니다. 그리고 그 계산 결과가 새로운 다차원 배열의 원소가 됩니다.
코드로 구현해 보겠습니다.
1 2 3 4 5 6 7 8 9 | >>> import numpy as np >>> a=np.array([[1,2],[[3,4]]) >>> a=np.array([[1,2],[3,4]]) >>> a.shape (2, 2) >>> b=np.array([[5,6],[7,8]]) >>> np.dot(a,b) array([[19, 22], [43, 50]]) | cs |
이 코드에서 a와 b는 2*2 행렬이며, 이들 두 행렬의 내적은 넘파이 함수 np.dot()으로 계산하는데, np.dot()은 넘파이 배열 2개를 인수로 받아 그 내적을 반환합니다.
행렬곱을 할 때 주의해야 할 점은 행렬의 형상에 주의해야 합니다. 이 말은 행렬 a의 1번째 차원의 원소 수(열 수)와 행렬 b의 0번째 ㅏ원의 원소 수(행 수)가 같아야 합니다. 예를 들어 보면 3x2와 2x4를 행렬곱하면 3x4가 되고, 3x2와 2를 내적하면 3이 됩니다.
행렬이 매우 중요한 이유는 다층 신경망을 빠르고 간결하게 구현하는데 핵심이 되기 때문입니다.
3층 신경망 구현
각 층의 신호 전달 구현
위 그림에서 입력층을 1층, 은닉층을 2층, 출력층을 3층이라 하겠습니다.
색칠한 노드를 식으로 나타내 보겠습니다.
a1=w11*x1+w12*x2+b1
지금은 가중치와 입력값이 적어서 손으로 써줄 수 있지만 이보다 더 많은 경우에는 너무 귀찮을 수 있습니다. 그래서 이 식을 행렬의 내적을 이용하여 식을 간소화 할 수 있습니다.
A=XW+B
그리고 이 식을 활성화 함수에 넣어 출력하는 내용입니다.
위 내용을 코드로 구현해 보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import numpy as np X=np.array([1.0,0.5]) W1=np.array(([0.1,0.3,0.5],[0.2,0.4,0.6])) B1=np.array([0.1,0.2,0.3]) def sigmoid(x): return 1/(1+np.exp(-x)) print(W1.shape) #(2,3) print(X.shape) #(2,) print(B1.shape) #(3,) A1=np.dot(X,W1)+B1 Z1=sigmoid(A1) print(A1) print(Z1) | cs |
나머지 은닉층들도 같은 원리입니다. 여기서 2층에서 출력층으로 신호 전달할 활성화 함수가 다릅니다. 이 경우에는 출력층의 활성화 함수는 풀고자 하는 문제의 성질에 맞게 정합니다. 예를 들어 회귀에는 항등 함수를, 2클래스 분류에는 시그모이드 함수를, 다중 클래스 분류에는 소프트맥스 함수를 사용하는 것이 일반적입니다. 자세한 설명은 아래에 있는 출력층 설계에서 설명하겠습니다.
구현 정리
위에서 구현했던 코드를 정리해 보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import numpy as np def sigmoid(x): return 1/(1+np.exp(-x)) def identity_function(x): return x def init_network(): network={} network['W1']=np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]]) network['b1']=np.array([0.1,0.2,0.3]) network['W2']=np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]]) network['b2']=np.array([0.1,0.2]) network['W3']=np.array([[0.1,0.3],[0.2,0.4]]) network['b3']=np.array([0.1,0.2]) return network def forward(network,x): W1,W2,W3=network['W1'],network['W2'],network['W3'] b1,b2,b3=network['b1'],network['b2'],network['b3'] a1=np.dot(x,W1)+b1 z1=sigmoid(a1) a2=np.dot(z1,W2)+b2 z2=sigmoid(a2) a3=np.dot(z2,W3)+b3 y=identity_function(a3) return y net=init_network() x=np.array([0.1,0.5]) y=forward(net,x) print(y) | cs |