Part4-27. 쉽게 배우는 역전파 학습법 - 08. (STEP 3) 수치 미분을 이용한 심층 신경망 학습 - 1,2
유틸리티함수
사용의 편의성을 위해 미리 정의해둠
epsilon = 0.0001
def _t(x):
return np.transpose(x)
def _m(A, B):
return np.matmul(A, B)
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def mean_squared_error(h, y):
return 1 / 2 * np.mean(np.square(h - y))

뉴런구현
class Neuron:
def __init__(self, W, b, a):
# Model Parameter
self.W = W
self.b = b
self.a = a
# Gradients
self.dW = np.zeros_like(self.W) # 0행렬 생성
self.db = np.zeros_like(self.b)
def __call__(self, x):
return self.a(_m(_t(self.W), x) + self.b) # activation((W^T)x + b) #W의 형태가 프랜스포즈 하기 전상대기 때문에
싱층신경망 구현
class DNN:
def __init__(self, hidden_depth, num_neuron, num_input, num_output, activation=sigmoid):
def init_var(i, o):
return np.random.normal(0.0, 0.01, (i, o)), np.zeros((o,)) #인풋아웃풋 채녈의 개수 W,b 정의
self.sequence = list()
# First hidden layer
W, b = init_var(num_input, num_neuron)
self.sequence.append(Neuron(W, b, activation))
# Hidden layers
for _ in range(hidden_depth - 1): #여러개 만들어야하므로 for문구현
W, b = init_var(num_neuron, num_neuron) #입력과 출력의 개수가 동일
self.sequence.append(Neuron(W, b, activation))
# Output layer
W, b = init_var(num_neuron, num_output)
self.sequence.append(Neuron(W, b, activation)) #마지막 activation을 변경해도 가능. 지금은 그냥 그대로 구현
def __call__(self, x):
for layer in self.sequence:
x = layer(x) #입력출력을 반복
return x
def calc_gradient(self, x, y, loss_func):
def get_new_sequence(layer_index, new_neuron): #특정레이어 뉴런 교체(특정 b, W를 변경했을때를 평가)
new_sequence = list()
for i, layer in enumerate(self.sequence):
if i == layer_index:
new_sequence.append(new_neuron)
else:
new_sequence.append(layer)
return new_sequence
#새로운 sequence를 평가하는 함수 작성
def eval_sequence(x, sequence):
for layer in sequence:
x = layer(x)
return x
#기준이되는 현재상태의 loss
loss = loss_func(self(x), y)
#비효율적인 루프
#각 레이어를 순회하고 weight, bias를 순환하여 모든 스칼라값을 변화시켜주고
#각각 loss function를 eval
for layer_id, layer in enumerate(self.sequence): # iterate layer
for w_i, w in enumerate(layer.W): # iterate W (row)
for w_j, ww in enumerate(w): # iterate W (col)
W = np.copy(layer.W)
W[w_i][w_j] = ww + epsilon #입실론만큼 변형
new_neuron = Neuron(W, layer.b, layer.a)
new_seq = get_new_sequence(layer_id, new_neuron)
h = eval_sequence(x, new_seq)
num_grad = (loss_func(h, y) - loss) / epsilon # (f(x+eps) - f(x)) / epsilon의 형태
layer.dW[w_i][w_j] = num_grad #해당위치의 gradient저장
for b_i, bb in enumerate(layer.b): # iterate b
b = np.copy(layer.b)
b[b_i] = bb + epsilon
new_neuron = Neuron(layer.W, b, layer.a)
new_seq = get_new_sequence(layer_id, new_neuron)
h = eval_sequence(x, new_seq)
num_grad = (loss_func(h, y) - loss) / epsilon # (f(x+eps) - f(x)) / epsilon
layer.db[b_i] = num_grad
return loss #로스를 리턴해야 학습하는과정에서 loss확인가능
직접 구현하기 때문에 발생한 비효율적 루프
경사하강 학습법
다른 방법들을 적용가능 Adam Adagrad 등 사용가능
def gradient_descent(network, x, y, loss_obj, alpha=0.01):
loss = network.calc_gradient(x, y, loss_obj) #로스를 미리받아놓음
for layer in network.sequence:
layer.W += -alpha * layer.dW
layer.b += -alpha * layer.db
return loss
동작테스트
새로운 데이터를 입력해서도 학습가능
x = np.random.normal(0.0, 1.0, (10,))
y = np.random.normal(0.0, 1.0, (2,))
dnn = DNN(hidden_depth=5, num_neuron=32, num_input=10, num_output=2, activation=sigmoid)
t = time.time()
for epoch in range(100):
loss = gradient_descent(dnn, x, y, mean_squared_error, 0.01)
print('Epoch {}: Test loss {}'.format(epoch, loss))
print('{} seconds elapsed.'.format(time.time() - t))

역전파 학습으로 속도 비교
'책&강의 학습 > 올인원 패키지 :딥러닝&인공지능' 카테고리의 다른 글
| [패스트캠퍼스 수강 후기] 인공지능강의 100% 환급 챌린지 35회차 미션 (0) | 2020.08.02 |
|---|---|
| [패스트캠퍼스 수강 후기] 인공지능강의 100% 환급 챌린지 34회차 미션 (0) | 2020.08.01 |
| [패스트캠퍼스 수강 후기] 인공지능강의 100% 환급 챌린지 32회차 미션 (0) | 2020.07.30 |
| [패스트캠퍼스 수강 후기] 인공지능강의 100% 환급 챌린지 31회차 미션 (0) | 2020.07.29 |
| [패스트캠퍼스 수강 후기] 인공지능강의 100% 환급 챌린지 30회차 미션 (0) | 2020.07.28 |
댓글