계산 그래프
Q1. 100원인 사과 2개의 구매금액은? 단 소비세 10%을 부과한다
문제풀이 흐름: 계산 그래프를 구성한다 → 그래프에서 계산을 왼쪽에서 오른쪽으로 진행한다(순전파 Forward Propabation)
국소적 계산
계산 그래프는 국소적 계산을 전파해 최종 결과를 얻는다. 국소적은 자시과 직접 관계된 작은 범위를 의미한다. 각 노드는 자신과 관련된 계산만을 담당하며, 노드까지의 중간 결과는 저장한다. 이러한 방식은 복잡한 문제를 단수화하는데 도움이 된다.
역전파 Back Propagation
오른쪽에서 왼쪽으로 전달되는 흐름을 의미한다. 계산 그래프에서 오른쪽으로 왼쪽으로 진행하며 미분값을 구한다
연쇄법칙
합성함수의 미분
z = t**2
t = x+ + y
연쇄법칙과 계산 그래프
각 노드는 이전 노드에서 전달 받은 미분에 해당 노드의 미분을 곱해 전달하는 과정을 통하여 전체 그래프의 미분을 구할 수 있다.
덧셈 노드의 역전파
z = x + y : 덧셈의 미분은 1이므로 역전파에서는 입력값을 그대로 전달한다
곱셈 노드의 역전파
z = xy : 곱셈의 역전파에서는 서로 바꾼 값을 전달한다
class MulLayer :
def __init__(self):
self.x = None
self.y = None
def forward (self, x, y) :
self.x = x
self.y = y
out = x*t
return out
def backward (self, dout) :
dx = dout * self.x
dy = dout * self.y
return dx, dy
클래스 Class
파이썬은 모든 것을 클래스로 정의하는 언어이다. 클래스는 변수, 메소드를 정의하며 프로그램 구조화 모델링을 위한 일종의 틀이다. 데이터 분류에서 사용하는 분류대상을 가리키는 클래스와는 다른 의미이다. 생성된 인스턴스(객체)는 상태를 보관하고 메소드를 실행할 수 있다.
- 과자틀 = 클래스 Class = 유형 / 타입 Type
- 과자 = 객체 Object = 실체 Instnace = 값 Value
단순한 계층 구현하기
덧셈 계층 구현
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
활성화 함수 계층 구현하기
ReLU 계층
역전파에서 양수값은 그대로, 음수값은 0으로 전달한다. mask 인스턴스 변수는 True/False로 구성된 넘파이 배열로, 순전파의 입력인 x의 원소값이 0 이하인 인덱스는 True, 그 외의 0보다 큰 원소는 False로 유지한다.
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
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-self.out) * self.out
return dx
Affine 계층
신경망에서 신호의 전달은 가중치와 신호를 곱하고 편향을 더하는 행렬 연산으로 표현한다. 이때 행렬의 곱을 수행하는 층을 Affine 계층이라 부르고, 미분도 행렬의 미분으로 처리한다.
행렬의 곱 미분
행렬에서 변수 X에 의한 미분은 다음과 같이 표현되며 두 식은 동일한 형상을 갖는다. 동일한 형상으로 복원하기 위해 행렬의 곱을 전치 Transpose하고 이웃하여 수행한다
X = np.array ([10,20])
W = np.array ([[0.1,0.2,0.3],[0.4,0.5,0.6]])
B = np.array ([100,200,300])
print ("X,W,B's shape ", X.shape, W.shape, B.shape)
Y = np.dot (X, W) + B
print ("Y's shape ",Y.shape)
행렬곱의 역전파(미분)
배치용 Affine 계층
N개의 데이터를 묶어서 처리할 수 있는 계층이다. 편향의 역전파 처리시, 형상을 편항의 모양에 맞추기 위해서는 N개 데이터의 미분을 데이터마다 더해서 구한다
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 계층 구현하기
Softmax - with - Loss 계층
출력층에서 함수의 입력값을 정규화하여 출력한다. 학습 단계 출력층인 소프트맥스 계층을 지나면 손실함수를 계산하는 교차 엔트로피 오차 계층이 배치된다. 이를 하나로 묶어 Softmax-with-loss 계층이라는 이름으로 구현하며 네트워크 그래프로 표현할 수 있다. 역전파 도는 값은 소프트맥스 계층의 출력값과 정답레이블의 차이다.
class SoftmaxWithLoss :
def __init__(self):
self.loss = None
self.y = None
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
오차 역전파법 구현하기
- 수치미분으로 구현한 신경망: 느리지만 구현원리가 단순해 검증에 이용한다
- 오차 역전파법(해석적 방법)으로 구현한 신경망: 수행속도가 빠르고 복잡한 망도 구현할 수 있다
두 방식으로 구한 기울기가 근사함을 확인하는 작업을 Gradient Check라고 한다
1. TwoLayerNet 신경망 정의
from common.layers import *
from common.gradient import numerical_gradient
import numpy as np
from collections import OrderedDict
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
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
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) :
# forward
self.loss(x, t)
# backward
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'] = self.layers['Affine1'].dW
grads['b1'] = self.layers['Affine1'].db
grads['W2'] = self.layers['Affine2'].dW
grads['b2'] = self.layers['Affine2'].db
return grads
2. 기울기 검증
from mnist import load_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)
print ('수치미분으로 구한 기울기와 오차 역전파로 구한 기울기 차이 비교')
for key in grad_numerical.keys() :
diff = np.average (np.abs (grad_backprop[key]-grad_numerical[key]))
print (f'{key} : {diff}')
3. 학습 구현
(x_train, t_train), (x_test, t_test ) = load_mnist (normalize = True, one_hot_label = True)
train_loss_list = []
train_acc_list = []
test_acc_list = []
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
network = TwoLayerNet(input_size = 784, hidden_size = 50, output_size = 10)
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(f'train_acc={train_acc:.4f},', f' test_acc={test_acc:.4f}')
'데이터 청년 캠퍼스 > 연관분석, 인공신경망' 카테고리의 다른 글
[인공신경망] Keras 신경망, 수행과정 정보 시각화, 검증 손실, 모델 저장과 적재, 콜백 (0) | 2022.07.20 |
---|---|
[인공신경망] 학습 테크닉: 오버피팅 해결하기, 하이퍼 파라미터 최적화하기 (0) | 2022.07.19 |
[인공신경망] 신경망 학습 - 손실함수, 미니배치, 경사하강법 (0) | 2022.07.18 |
[인공신경망] MNIST 데이터 실습 (0) | 2022.07.18 |
[인공신경망] 퍼셉트론과 인공신경망 (0) | 2022.07.15 |