[머신러닝] #3 신경망 #1 |
"Deep Learning from Scratch” 책을 보고 제가 필요한 내용만 정리한 내용입니다.
자세한 내용은 책을 구매해서 보세요~
-
앞 장에서 배운 퍼셉트론은 좋은 소식과 나쁜 소식이 있다.
좋은 소식은 퍼셉트론으로 복잡한 함수를 표현할 수 있다는 것이고,
나쁜 소식은 가중치 설정은 여전히 사람이 수동으로 한다는 것.
신경망은 이 나쁜 소식을 해결해준다.
가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하는 능력이 신경망의 중요한 성질이다.
3.1. 퍼셉트론에서 신경망으로
3.1.1. 신경망의 예.
-
가장 왼쪽 줄은 입력층,
맨 오른쪽 줄을 출력층,
중간 층을 은닉층이라고 한다.
은닉층의 뉴런은 입력층이나 출력층과 달리 사람 눈에는 보이지 않는다.
이 책에서는 입력층, 은닉층, 출력층을 차례로 0층, 1층, 2층이라고 한다.
-
신경망은 모두 3층으로 구성되지만, 가중치를 갖는 층은 2개뿐이기 때문에 “2층 신경망” 이라고 한다.
문헌에 따라서는 신경망을 구성하는 층수를 기준으로 3층 신경망이라고도 하기도 하니 주의해야 한다.
3.1.2. 퍼셉트론 복습
-
y = h(b + w1x1 + w2x2)
h(x) = 0 if x <= 0
= 1 if x > 0
3.1.3. 활성화 함수의 등장
-
h(x) 라는 함수는 입력 신호의 총합을 출력 신호로 변환하는 함수로 일반적으로 활성화 함수(activation function) 이라고 한다.
활성화 함수는 이름처럼 입력 신호의 총합이 활성화를 일으키는지를 정하는 역할을 한다.
3.2. 활성화 함수
-
활성화 함수는 임계값을 경계로 출력이 바뀌는데, 이런 함수를 계단 함수(step function)이라고 한다.
퍼셉트론에서는 활성화 함수로 계단 함수를 이용한다라고 할 수 있다.
활성화 함수를 계단 함수에서 다른 함수로 변경하는 것이 신경망의 세계로 나아가는 열쇠이다.
3.2.1. 시그모이드 함수
-
시그모이드 함수(sigmoid function)
e 는 자연상수로 2.7182... 값을 갖는다.
-
신경망에서는 활성화 함수로 시그모이드 함수를 이용하여 신호를 변환하고, 그 변환된 신호를 다음 뉴런에 전달한다.
기존에 본 퍼셉트론과 앞으로 볼 신경망의 주된 차이는 이 활성화 함수 뿐이다.
3.2.2. 계단 함수 구현하기
-
def step_function(x):
y = x > 0 # boolean array
return y.astype(np.int) # boolean 이 0 또는 1 로 매핑된 array return, asType 은 자료형 변환
3.2.3. 계단 함수의 그래프
3.2.4. 시그모이드 함수 구현하기
-
def sigmoid(x):
return 1 / ( 1 + np.exp(-x) )
3.2.5. 시그모이드 함수와 계단 함수 비교
-
시그모이드 함수는 부드러운 곡선이며 입력에 따라 출력이 연속적으로 변화한다.
계단 함수는 0을 경계로 출력이 갑자기 바뀌어버린다.
시그모이드 함수의 매끈함이 신경망 학습에서 아주 중요한 역할을 한다.
계단 한수가 0과 1 중 하나의 값만 돌려주는 반면 시그모이드 함수는 실수(0.731.. 0.880... 등)를 돌려준다는 점도 다르다.
이전에 본 퍼셉트론에서는 뉴런 사이에 0 혹은 1이 흘렀다면, 신경망에서는 연속적인 실수가 흐른다.
-
둘의 공통점은 큰 관점에서 같은 모양을 하고 있다.
둘 다 입력이 작을 때의 출력은 0에 가깝고, 입력이 커지면 출력이 1에 가까워진다.
둘 다 입력이 중요하면 큰 값을 출력하고 입력이 중요하지 않으면 작은 값을 출력한다.
입력이 아무리 작거나 커도 출력은 0에서 1사이이다.
3.2.6. 비선형 함수
-
계단 함수와 시그모이드 함수의 공통점은 둘 다 비선형 함수라는 것이다.
시그모이드 함수는 곡선, 계단 함수는 계단처럼 구부러진 직선으로 나타나며, 동시에 비선형 함수로 분류된다.
-
신경망에서는 활성화 함수로 비선형 함수를 사용하고, 선형 함수를 사용해서는 안 된다.
선형 함수를 이용하면 신경망의 층을 깊게 하는 의미가 없어지기 때문이다.
선형의 문제는 층을 아무리 깊게 해도 은닉층이 없는 네트워크로도. 똑같은 기능을 할 수 있다.
예를 들어 선형 함수 h(x) = cx 를 활성화 함수로 사용한 3층 네트워크가 있다고 하자.
y(x) = h(h(h(x))) 는 y(x) = c * c * c * x 처럼 곱셈을 세 번 수행하지만 실은 y(x) = ax 와 똑같다.
즉 은닉층이 없는 네트워크로 표현할 수 있다. 다시 말해 여러 층으로 구성하는 이점을 살릴 수 없다.
3.2.7. ReLU 함수
-
시그모이드 함수는 신경망 분야에서 오래전부터 이용해왔으나, 최근에는 ReLU(Rectified Linear Unit, 렐루) 함수를 주로 이용한다.
ReLU 는 입력이 0 을 넘으면 그 입력을 그대로 출력하고, 0 이하이면 0을 출력하는 함수이다.
h(x) = x if x > 0
= 0 if x <= 0
-
def relu(x):
return np.maximum(0, x)
3.3. 다차원 배열의 계산
3.3.1. 다차원 배열
-
배열의 차원수는 np.ndim() 함수로 확인할 수 있다.
배열의 형상은 인스턴스 변수인 shape 로 알 수 있다. return 값은 튜플이다.
ex)
B = np.array([[1,2], [3,4], [5,6]])
np.ndim(B) # 2
B.shape # (3,2) 이는 3X2 (row X column) 를 이야기함
-
2차원 배열은 특히 행렬(matrix)라고 부른다.
배열의 가로 방향을 행(row), 세로 방향을 열(column)이라고 한다.
3.3.2. 행렬의 내적(행렬 곱)
-
1 2 5 6 19 22
x =
3 4 7 8 43 50
1 * 5 + 2 * 7 = 19
1 * 6 + 2 * 8 = 22
3 * 5 + 4 * 7 = 43
3 * 6 + 4 * 8 = 50
행렬의 내적은 왼쪽 행렬의 행(가로)와 오른쪽 행렬의 열(세로)을 원소별로 곱하고 그 값들을 더해서 계산하며, 그 결과가 새로운 다차원 배열의 원소가 된다.
-
ex)
A = np.array([[1,2], [3,4]])
B = np.array([[5,6], [7,8]])
np.dot(A, B) # 내적은 dot 함수를 사용한다.
np.dot(A,B) 와 np.dot(B,A) 는 다른 값이 될 수 있다.
-
내적을 할 때는 행렬의 형상(shape)에 주의해야 한다.
왼쪽 행렬의 열 수와 오른쪽 행렬의 행 수가 같아야 한다.
2 X 3 행렬과 2 X 2 행렬은 내적을 할 수 없고, 2X2 행렬과 2X3 행렬은 내적을 할 수 있다.
3 X 2 dot 2 X 4 = 3 X 4
내적을 하려면 왼쪽의 뒷녀석과 오른쪽의 앞녀석이 같아야 하고 ( 여기서는 왼쪽의 2와 오른쪽의 2 )
결과 형상은 왼쪽의 앞 녀석, 오른쪽의 뒷 녀석이 된다. ( 여기서는 왼쪽의 3 과 오른쪽의 4. )
-
2차월 행렬과 1차원 배열일 경우도 똑같이 적용된다.
3 X 2 dot 2 = 3
왼쪽의 뒤쪽 녀석과 오른쪽의 값이 같아야 하며 ( 여기서는 왼쪽의 2와 오른쪽 단일 숫자 2 )
결과 형상은 왼쪽의 앞쪽 녀석이 된다. ( 여기서는 3 )
( vector 는 상황에 따라 가로 vector, 세로 vector 모두 가능하다고 본다. )
3.3.3. 신경망의 내적
-
위의 예제는 bias 와 활성화 함수 생략한 가중치만 갖는 케이스인데, 이를 내적으로 표시하면 아래와 같다.
X dot W = Y
2 dot 2 X 3 = 3
X = np.array([1,2])
W = np.array([[1,3,5], [2,4,6]])
Y = np.dot( X, W )
3.4. 3층 신경망 구현하기
3.4.1. 표기법 설명
-
x1 -> Layer1 로 가는 weight 를 보면..
[1] 은 1층 내용이라는 이야기.
1 1 은 to 와 from 이다. (from to 가 아님을 주의!) 즉 0층의 1 에서 1층의 1로 간다는 이야기이다.
3.4.2. 각 층의 신호 전달 구현하기
-
편향을 뜻하는 뉴런은 인덱스가 1개밖에 없으며 to 를 가르킨다. (편향은 하나밖에 없기 때문 from 의 의미가 없다)
-
행렬의 내적을 이용하면 1층의 가중치 부분을 다음처럼 표현할 수 있다. ( 위의 그림과 다르게 책에서는 1층에 3개의 노드가 있다. )
A(1) = XW(1) + B(1) // 여기서 1 은 층을 나타냄
ex)
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])
A1 = np.dot(X, W1) + B1
-
항등 함수는 입력을 그대로 출력하는 함수이다.
-
출력층의 활성화 함수는 풀고자 하는 문제의 성질에 맞게 정한다.
예를 들어 회귀에는 항등 함수를, 클래스 분류에는 시그모이드 함수를, 다중 클래스 분류에는 소프트맥스 함수를 사용하는 것이 일반적이다.
3.4.3. 구현 정리
-
ex)
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’] = …
network[‘b2’] = …
network[‘W3’] = …
network[‘b3’] = …
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 = sigmod(a2)
a3 = np.dot(z2, W3) + b3
y = identity_function(a3)
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
'프로그래밍 놀이터 > 머신러닝, AI, 딥러닝' 카테고리의 다른 글
[머신러닝] #4 신경망 학습 #2 (0) | 2018.07.06 |
---|---|
[머신러닝] #4 신경망 학습 #1 (0) | 2018.07.05 |
[머신러닝] #3 신경망 #2 (0) | 2018.07.04 |
[머신러닝] #2 퍼셉트론 (0) | 2018.07.02 |
[머신러닝] #1 헬로 파이썬 (0) | 2018.07.01 |
댓글