순전파 (Feedforward)
Input에서 Output으로 가중치를 업데이트하면서 활성화 함수를 통해서 결과값을 가져오는 것을 순전파(foward)라고 한다.
역전파 (Backpropagation)
역전파 알고리즘은 input과 output 값을 알고 있는 상태에서 신경망을 학습 시키는 방법이다.
역전파 방법은 결과 값을 통해서 다시 역으로 input 방향으로 오차를 다시 보내며 가중치를 재업데이트 하는 것이다.
결과에 영향을 많이 미친 노드(뉴런)에 더 많은 오차를 돌려준다.
계산 그래프 (computational graph)
- 계산 그래프(computational graph)는 계산 과정을 그래프로 나타낸 것
- 그래프는 복수의 노드 node 와 에지 edge 로 표현된다.
문제
현빈 군은 슈퍼에서 사과를 2개, 귤을 3개 샀습니다. 사과는 1개에 100원, 귤은 1개 150원입니다. 소비세가 10%일 때 지불 금액을 구하라.
계산 그래프를 이용한 문제 풀이는 다음 흐름으로 진행된다.
- 계산 그래프를 구성한다.
- 그래프에서 계산을 왼쪽에서 오른쪽으로 진행한다.
여기서 계산을 왼쪽에서 오른쪽으로 진행하는 단계를 순전파 forward propagation 이라고 한다.
오르쪽에서 왼쪽으로의 전파도 있다. 역전파이다. 역전파는 이후 미분을 계산할 때 중요한 역할을 한다.
✔︎ 국소적 계산
국소적이란, 자신과 직접 관계된 작은 범위라는 뜻이다.
국소적 계산은 결국, 전체에서 어떤 일이 벌어지든 상관없이 자신과 관계된 정보만으로 결과를 출력할 수 있다는 것이다.
계산 그래프는 국소적 계산에 집중한다.
전체 계산이 아무리 복잡하더라도 각 단계에서 하는 일은 해당 노드의 국소적 계산이다.
국소적인 계산은 단순하지만, 그 결과를 전달함으로써 전체를 구성하는 복잡한 계산을 할 수 있다.
✔ 계산 그래프를 사용하는 이유?
- 국소적 계산을 통해 각 노드의 계산에 집중하여 문제를 단순화할 수 있다.
- 역전파를 통해 '미분'을 효율적으로 계산할 수 있다. ⭐
연쇄 법칙 - Chain Rule
✔ 계산 그래프의 역전파
역전파 계산 예제로 y = f(x) 의 역전파를 계산해보자.
역전파 계산 순서는 신호 E에 노드(f)의 국소적 미분 $\frac{\partial y }{\partial x}$ 을 곱한 후 엣지(edge)를 통해 다음 노드로 전달하는 것이다. 여기서 국소적 미분은 순전파 때의 $y = f(x)$에 대한 미분을 구하는 것이고, 이것은 $x$ 에 대한 $$y의 미분 을 ($\frac{\partial y }{\partial x}$) 구한다는 의미이다.
✔ 연쇄법칙이란?
- 합성함수의 미분은 합성 함수를 구성하는 각 함수의 미분의 곱으로 나타낼 수 있다.
역전파
✔ 덧셈 노드의 역전파
- 덧셈 노드의 역전파는 입력값을 그대로 흘려보낸다. 이를 보고 gradient distributor라고 하기도 한다.
✔ 곱셈 노드의 역전파
곱셈 노드의 역전파는 입력값의 위치를 서로 바꾼 다음 곱해서 흘려보낸다. 이를 보고 gradient switcher라고 부르기도 한다.
단순한 계층 구현하기
✔ 곱셈 계층
forward()는 순전파, backward()는 역전파이다.
class MulLayer:
def __init__(self):
self.x = None
self.y = None
def forward(self, x, y):
self.x = x
self.y = y
out = x * y
return out
def backward(self, dout):
dx = dout * self.y # x와 y를 바꾼다.
dy = dout * self.x
return dx, dy
apple = 100
apple_num = 2
tax = 1.1
mul_apple_layer = MulLayer()
mul_tax_layer = MulLayer()
# forward
apple_price = mul_apple_layer.forward(apple, apple_num)
price = mul_tax_layer.forward(apple_price, tax)
print(price)
✔ 덧셈 계층
class AddLayer:
def __init__(self):
pass
def forward(self, x, y):
out = x + y
return out
def backward(self, dout):
dx = dout * 1
dy = dout * 1
return dx, dy
apple = 100
apple_num = 2
orange = 150
orange_num = 3
tax = 1.1
# layer
mul_apple_layer = MulLayer()
mul_orange_layer = MulLayer()
add_apple_orange_layer = AddLayer()
mul_tax_layer = MulLayer()
# forward
apple_price = mul_apple_layer.forward(apple, apple_num) # (1)
orange_price = mul_orange_layer.forward(orange, orange_num) # (2)
all_price = add_apple_orange_layer.forward(apple_price, orange_price) # (3)
price = mul_tax_layer.forward(all_price, tax) # (4)
# backward
dprice = 1
dall_price, dtax = mul_tax_layer.backward(dprice) # (4)
dapple_price, dorange_price = add_apple_orange_layer.backward(dall_price) # (3)
dorange, dorange_num = mul_orange_layer.backward(dorange_price) # (2)
dapple, dapple_num = mul_apple_layer.backward(dapple_price) # (1)
print("price:", int(price))
print("dApple:", dapple)
print("dApple_num:", int(dapple_num))
print("dOrange:", dorange)
print("dOrange_num:", int(dorange_num))
print("dTax:", dtax)
활성화 함수 계층 구현하기
✔ ReLU 계층
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
Relu 계층은 mask 라는 인스턴스 변수를 가진다.
mask 는 True/False 로 구성된 넘파일 배열로, 순전파의 입력인 x 원소 값이 0이하인 인덱스는 True, 그 외 0보다 큰 원소는 False 로 유지한다.
✔ Sigmoid 계층
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = 1 / (1 + np.exp(-x))
self.out = out
return out
def backward(self, dout):
dx = dout * (1.0 - self.out) * self.out
return dx
Affine/Softmax 계층 구현하기
✔ Affine 계층
✔ 배치용 Affine 계층
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.dW = None
self.db = None
def forward(self, x):
self.x = x
out = np.dot(x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
return dx
✔ Softmax-with-Loss 계층
딥러닝을 학습할 때는 Softmax 계층이 필요
소프트맥스(softmax) 계층을 구현할때, 손실함수인 교차 엔트로피 오차(cross entropy error)도 포함하여 아래의 그림과 같이 Softmax-with-Loss 계층을 구현한다.
import os, sys
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from common.functions import softmax, cross_entropy_error
class SoftmaxWithLoss:
def __init__(self):
self.loss = None # 손실
self.y = None # softmax의 출력
self.t = None # 정답 레이블(one-hot)
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.shape[0]
dx = (self.y - self.t) / batch_size
return dx
'DL(Deep-Learning) > 개념' 카테고리의 다른 글
활성화 함수 activation function (0) | 2022.01.29 |
---|---|
[실습] numpy로 만드는 단층 신경망 - 회귀 문제 (0) | 2022.01.29 |
[DL] 신경망 Neural Network (0) | 2022.01.28 |
[DL] 퍼셉트론(Perceptron) (0) | 2022.01.28 |
인공지능이란? (0) | 2022.01.28 |