일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 우하하!!!
- UiPathStudio
- 우하하!!!!
- javascript
- 딥러닝기초
- 밑바닥부터시작하는딥러닝
- Doit!자바스크립트+제이쿼리입문
- KTAIVLESchool
- 파이팅!!!!
- AivleSchool
- 사전설명회
- 커피는역시
- AIVLE
- C언어프로젝트
- 신경망
- c언어
- 딥러닝
- NeuralNetwork
- 자바스크립트기초문법
- Doit!자바스크립트+제어쿼리입문
- coding
- deeplearning
- Programming
- 에이블스쿨
- KT에이블스쿨
- 에이블스쿨5기
- KTAIVLESchool5기
- 자바스크립트
- C
- KT
- Today
- Total
삶은 계란
딥러닝 기초 부수기 - 오차역전파법(backpropagation) 본문
딥러닝 기초 부수기 - 오차역전파법(backpropagation)
본 게시글은 한빛미디어 출판사의 '밑바닥부터 시작하는 딥러닝(저자: 사이토 고키)' 도서 내용을 바탕으로 작성하였습니다.
1. 서론
수치 미분은 계산 시간이 오래 걸린다는 단점이 있다. 이러한 단점을 개선한 것이 오차역전파법(backpropagation)이다. 이번 게시글은 이 오차역전파법에 대해 정리한 내용을 담고 있다.
2. 계산 그래프
계산 그래프(computational graph)는 계산 과정을 나타낸 그래프이다. 노드(node)와 에지(edge, 노드 사이 직선)로 표현된다. 예시를 들어 계산 그래프를 표현해보겠다. 1개에 1000원인 물건을 3개 구매했다고 하자. 소비세는 10% 부과된다. 이때의 지불 금액을 구하는 과정을 계산 그래프로 나타내면
위와 같이 표현할 수 있다. 다른 예시를 들어보도록 하자. 1개에 1000원인 물건 A를 3개, 1개에 2000원인 물건 B를 2개 구매했다고 하자. 소비세는 10% 부과된다. 이때의 지불 금액을 구하는 과정을 계산 그래프로 나타내면
위와 같이 표현할 수 있다. 이러한 계산 그래프는 국소적 계산을 전파하면서 최종 결과를 얻는다. 해당 노드와 직접 관련된 계산만 수행할 뿐 전체와는 상관이 없다는 의미이다. 또한 계산을 왼쪽에서 오른쪽으로 진행한다는 것을 알 수 있다. 이러한 방향으로 계산을 전파하는 것을 순전파(forward propagation)라 한다. 계산을 오른쪽에서 왼쪽으로 진행하는 전파는 역전파(backward propagation)라 한다. 역전파를 통해 미분을 효율적으로 계산할 수 있기 때문에 계산 그래프를 사용한다.
3. 연쇄 법칙
역전파는 국소적 미분을 순전파의 반대 방향으로 전달한다. 전달하는 원리는 연쇄 법칙(chain rule)에 따른 것이며, 연쇄 법칙은 합성함수 미분에 대한 성질이다.
아래와 같은 합성함수가 있다고 하자. 연쇄 법칙에 따라 미분을 할 수 있다.
최종 미분식은 두 미분(2t와 1)을 곱해 계산한다. 아래 그림은 위 연쇄 법칙 계산을 계산 그래프로 나타낸 것이다.
4. 역전파
(1) 덧셈 노드 역전파
덧셈 노드의 역전파는 미분 값을 그대로 흘려보낸다. z = x+y 식에서 x에 대한 미분이든 y에 대한 미분이든 둘 다 계산하면 값은 1이 나온다. 결과적으로 덧셈 노드의 역전파는 상류에서 전해진 미분 값에 1을 곱하기만 할 뿐이다.
(2) 곱셈 노드 역전파
곱셈 노드의 역전파는 상류에서 전해진 미분 값에 순전파 때의 입력 값들을 서로 바꾼 값을 곱해서 흘려보낸다. z = xy 식에서 x에 대한 미분 값은 y이고 y에 대한 미분 값은 x이다. 결과적으로 미분 값에 서로 바꾼 값을 곱하는 형태가 된다.
5. 단순한 계층 구현
위에서 예시로 든 물건 구입의 계산 그래프를 파이썬으로 구현한 코드이다.
(1) 곱셈 계층
# 곱셈 계층
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
(2) 덧셈 계층
# 덧셈 계층
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
(3) 계산 그래프 구현
# 물건 구매 계산 그래프 구현
thing = 1000
thing_num = 3
tax = 1.1
mul_thing_layer = MulLayer()
mul_tax_layer = MulLayer()
# 순전파
thing_price = mul_thing_layer.forward(thing, thing_num)
price = mul_tax_layer.forward(thing_price, tax)
# 역전파
dprice = 1
dthing_price, dtax = mul_tax_layer.backward(dprice)
dthing, dthing_num = mul_thing_layer.backward(dthing_price)
print("price:", int(price))
print("dThing:", dthing)
print("dThing_num:", int(dthing_num))
print("dTax:", dtax)
6. 활성화 함수 계층 구현
계산 그래프를 신경망에 적용할 수 있다. 우선 활성화 함수 ReLU, Sigmoid 계층을 구현한 코드이다.
(1) ReLU 계층
# ReLU 계층
class Relu:
def __init__(self):
self.mask = None # mask 배열의 원소가 True인 곳에는 상류에서 전파된 dout을 0으로 설정
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
(2) Sigmoid 계층
# Sigmoid 계층
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = sigmoid(x)
self.out = out
return out
def backward(self, dout):
dx = dout * (1.0 - self.out) * self.out
return dx
7. Affine, Softmax 계층 구현
(1) Affine 계층
신경망의 순전파 때 수행하는 행렬의 곱(입력 값과 가중치와의 곱)을 기하학에서 어파인 변환(affine transformation)이라 한다. 어파인 변환을 수행하는 계층이 Affine 계층이다.
(2) 배치용 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
(3) Softmax-with-Loss 계층
신경망 학습 시 출력층에서 사용하는 활성화 함수인 소프트맥스 함수에 손실 함수인 교차 엔트로피 오차를 포함하여 Softmax-with-Loss 계층으로 구현할 수 있다.
신경망의 역전파에서는 출력 값과 정답 레이블의 오차가 앞 계층에 전해진다.
# Softmax-with-Loss 계층
class SoftmaxWithLoss:
def __init__(self):
self.loss = None # 손실
self.y = None # softmax의 출력
self.t = None # 정답 레이블(원-핫 벡터)
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.t.shape[0]
dx = (self.y - self.t) / batch_size
return dx
8. 오차역전파법 구현
지금까지의 계층을 조합하여 신경망을 구현할 수 있다. 오차역전파법은 기울기를 산출할 때 수치 미분 대신 사용한다.
(1) 오차역전파법 적용 신경망
# 오차역전파법 적용 신경망
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'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
(2) 오차역전파법으로 구한 기울기 검증
수치 미분으로 구한 기울기와 오차역전파법으로 구한 기울기가 일치하는지 확인하면서 오차역전파법을 검증할 수 있다.
# 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)
x_batch = x_train[:3]
t_batch = t_train[:3]
grad_numerical = network.numerical_gradient(x_batch, t_batch) # 수치 미분
grad_backprop = network.gradient(x_batch, t_batch) # 오차역전파법
# 각 가중치 차의 절댓값을 구하고, 그 절댓값들의 평균 내기
for key in grad_numerical.keys():
diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )
print(key + ":" + str(diff))
수치 미분과 오차역전파법으로 구한 기울기의 오차가 매우 작음을 알 수 있다.
(3) 오차역전파법을 사용한 학습 구현
지금까지와 다른 점은 기울기를 오차역전파법으로 구한다는 것뿐이다.
# 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)
훈련 데이터와 시험 데이터의 정확도가 그리 차이 나지 않는 것을 알 수 있다.
'딥러닝' 카테고리의 다른 글
딥러닝 기초 부수기 - 합성곱 신경망(CNN) (0) | 2022.03.19 |
---|---|
딥러닝 기초 부수기 - 학습 관련 기술들 (0) | 2022.03.14 |
딥러닝 기초 부수기 - 신경망 학습 (0) | 2022.03.02 |
딥러닝 기초 부수기 - 신경망(neural network) (4) | 2022.02.07 |
딥러닝 기초 부수기 - 퍼셉트론(perceptron) (4) | 2022.02.03 |