Neural Net Basic (1)
인공신경망 기초 (1)
Last updated
인공신경망 기초 (1)
Last updated
from random import seed
from random import random
import numpy as np
# 네트워크 초기 설정
def initialize_network(n_inputs, n_hidden, n_outputs):
network = list()
hidden_layer = [{'weights':[random() for i in range(n_inputs + 1)]} for i in range(n_hidden)] # 개수는 같게 설정
network.append(hidden_layer)
output_layer = [{'weights':[random() for i in range(n_hidden + 1)]} for i in range(n_outputs)] # 개수는 같게 설정
network.append(output_layer)
return network
seed(1)
network = initialize_network(2, 1, 2)
# (2+1(bias))개의 input node, 1개의 hidden layer, 2개의 ouput node
# w 값은 임의로 설정한다
for layer in network:
print(layer)
# initialize_network function
# 첫번째(input node)가 들어가서 두번째(hidden layer)가 나오고
# 두번째(hidden layer)가 들어가서 세번째(output node)가 나온다
# 결과값은 차례대로
# 1) hidden layer: input node의 [w0, w1, w2], (2 input weights + bias)
# 2) output node: hidden layer의 [w00, w01], [w10, w11] (1 weight + bias)[{'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614]}]
[{'weights': [0.2550690257394217, 0.49543508709194095]}, {'weights': [0.4494910647887381, 0.651592972722763]}]def activate(weights, inputs):
activation = weights[-1] # weights 벡터의 마지막 값이 bias: 그래서 [-1] 넣는 것. bias는 곱하지 않고 넣어야 하기 때문에 그냥 넣는다
for i in range(len(weights)-1):
activation += inputs[i] * weights[i] # 순전파 진행 : 곱해서 activation list에 추가한다는 뜻
return activation # bias + activation 한 것 = list
def sigmoid(activation):
return 1 / (1 + np.exp(-activation)) # 시그모이드 구현
def forward_propagate(network, row):
inputs = row
for layer in network: # network = U1, U2 전체를 말하는 것, 그 중 layer는 U1, U2 각각을 말하는 것
new_inputs = []
for neuron in layer: # layer의 하나의 열이 neuron
activation = activate(neuron['weights'], inputs) # neuron['weight'] = 하나의 열에서 가중치 각각 말하는 것
neuron['output'] = sigmoid(activation) # 활성함수에 activation 값을 넣어서 출력시킨다
new_inputs.append(neuron['output']) # new_input은 다음 히든층에 들어갈 값
inputs = new_inputs
return inputsnetwork # 똑같다: forward propagation은 weight에 전혀 영향을 주지 않는다[[{'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614]}],
[{'weights': [0.2550690257394217, 0.49543508709194095]},
{'weights': [0.4494910647887381, 0.651592972722763]}]]row = [1, 0, None] # None = bias 의미
output = forward_propagate(network, row)
print(output)[0.6629970129852887, 0.7253160725279748]def sigmoid_derivative(output):
return output * (1 - output) # 시그모이드 미분
def backward_propagate_error(network, expected): # expected = 예측값: NN 통과해서 나온 값, ouput = 실제값: target 변수의 값
for i in reversed(range(len(network))): # network 층 거꾸로 간다
layer = network[i] # 마지막 층부터 고려한다
errors = []
if i != len(network)-1: # 출력단인 경우
for j in range(len(layer)):
error = 0.0
for neuron in network[i + 1]:
error += (neuron['weights'][j] * neuron['delta'])
errors.append(error)
else: # 출력단이 아닌 경우
for j in range(len(layer)):
neuron = layer[j]
errors.append(expected[j] - neuron['output'])
# hidden layer의 error = (가중치 * 에러) * 활성함수 미분(예측값)
# backpropagation에서 hidden -> input 으로 갈 때, (U1으로 미분 과정에서)
# 오류 역전파의 유도 과정에서 결론적으로 다 미분하면 가중치만 남게 되므로
# 가중치를 곱해 주면서 에러를 업데이트 한다
for j in range(len(layer)):
neuron = layer[j]
neuron['delta'] = errors[j] * sigmoid_derivative(neuron['output'])
# output node의 error = (실제값 - 예측값) * 활성함수 미분(예측값)
# output -> hidden으로 갈 때, (U2로 미분 과정에서)
# 결론적으로 Zj만 남게 되므로
# 업데이트 된 에러와 활성함수 미분값을 곱해 delta에 저장한다expected = [0, 1] # label
backward_propagate_error(network, expected)
for layer in network:
print(layer)[{'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614], 'output': 0.7105668883115941, 'delta': -0.002711797799238243}]
[{'weights': [0.2550690257394217, 0.49543508709194095], 'output': 0.6629970129852887, 'delta': -0.14813473120687762}, {'weights': [0.4494910647887381, 0.651592972722763], 'output': 0.7253160725279748, 'delta': 0.05472601157879688}]def weights_update(network, row, l_rate): # 한 단계 가중치 업데이트
for i in range(len(network)):
inputs = row[:-1]
if i != 0:
inputs = [neuron['output'] for neuron in network[i - 1]]
for neuron in network[i]:
for j in range(len(inputs)):
neuron['weights'][j] += l_rate * neuron['delta'] * inputs[j] # 가중치 갱신 : w
neuron['weights'][-1] += l_rate * neuron['delta'] # 퍼셉트론 학습 규칙: bias - Yk의 유무의 따라서 달라지기 때문
def train_network(network, train, l_rate, n_epoch, n_outputs): # 전체 학습 과정 - 무수히 가중치 업데이트 과정을 반복
for epoch in range(n_epoch):
sum_error = 0
for row in train: # train data set의 하나하나의 row
outputs = forward_propagate(network, row) # 순전파: 예상값
expected = [0 for i in range(n_outputs)] # label
expected[row[-1]] = 1 # 0 / 1 classification - 값이 있으면 1, 없으면 0으로 채워준다
sum_error += sum([(expected[i] - outputs[i])**2 for i in range(len(expected))]) # 예측값의 오차 합: euclidean distance
backward_propagate_error(network, expected)
weights_update(network, row, l_rate)
if epoch%100==0:
print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error))seed(1)
dataset = [[2.7810836,2.550537003,0],
[1.465489372,2.362125076,0],
[3.396561688,4.400293529,0],
[1.38807019,1.850220317,0],
[3.06407232,3.005305973,0],
[7.627531214,2.759262235,1],
[5.332441248,2.088626775,1],
[6.922596716,1.77106367,1],
[8.675418651,-0.242068655,1],
[7.673756466,3.508563011,1]]n_inputs = len(dataset[0])-1 # 입력 노드의 개수는 training data의 독립변수 개수 (X1, X2)
n_outputs = len(set([dataset[i][-1] for i in range(len(dataset))])) # output의 target 개수 = 여기에서는 2 (0, 1)
network = initialize_network(n_inputs, 2, n_outputs)
train_network(network, dataset, 0.02, 5001, n_outputs) # 자유롭게 설정하고 최적을 찾아보세요.>epoch=0, lrate=0.020, error=6.697
>epoch=100, lrate=0.020, error=4.299
>epoch=200, lrate=0.020, error=3.007
>epoch=300, lrate=0.020, error=2.037
>epoch=400, lrate=0.020, error=1.415
>epoch=500, lrate=0.020, error=1.020
>epoch=600, lrate=0.020, error=0.754
>epoch=700, lrate=0.020, error=0.570
>epoch=800, lrate=0.020, error=0.444
>epoch=900, lrate=0.020, error=0.356
>epoch=1000, lrate=0.020, error=0.293
>epoch=1100, lrate=0.020, error=0.247
>epoch=1200, lrate=0.020, error=0.212
>epoch=1300, lrate=0.020, error=0.185
>epoch=1400, lrate=0.020, error=0.163
>epoch=1500, lrate=0.020, error=0.146
>epoch=1600, lrate=0.020, error=0.131
>epoch=1700, lrate=0.020, error=0.119
>epoch=1800, lrate=0.020, error=0.109
>epoch=1900, lrate=0.020, error=0.101
>epoch=2000, lrate=0.020, error=0.093
>epoch=2100, lrate=0.020, error=0.087
>epoch=2200, lrate=0.020, error=0.081
>epoch=2300, lrate=0.020, error=0.076
>epoch=2400, lrate=0.020, error=0.072
>epoch=2500, lrate=0.020, error=0.068
>epoch=2600, lrate=0.020, error=0.064
>epoch=2700, lrate=0.020, error=0.061
>epoch=2800, lrate=0.020, error=0.058
>epoch=2900, lrate=0.020, error=0.055
>epoch=3000, lrate=0.020, error=0.053
>epoch=3100, lrate=0.020, error=0.050
>epoch=3200, lrate=0.020, error=0.048
>epoch=3300, lrate=0.020, error=0.046
>epoch=3400, lrate=0.020, error=0.045
>epoch=3500, lrate=0.020, error=0.043
>epoch=3600, lrate=0.020, error=0.041
>epoch=3700, lrate=0.020, error=0.040
>epoch=3800, lrate=0.020, error=0.039
>epoch=3900, lrate=0.020, error=0.037
>epoch=4000, lrate=0.020, error=0.036
>epoch=4100, lrate=0.020, error=0.035
>epoch=4200, lrate=0.020, error=0.034
>epoch=4300, lrate=0.020, error=0.033
>epoch=4400, lrate=0.020, error=0.032
>epoch=4500, lrate=0.020, error=0.031
>epoch=4600, lrate=0.020, error=0.030
>epoch=4700, lrate=0.020, error=0.030
>epoch=4800, lrate=0.020, error=0.029
>epoch=4900, lrate=0.020, error=0.028
>epoch=5000, lrate=0.020, error=0.027# 업데이트 된 가중치
for layer in network:
print(layer)[{'weights': [-1.9544732139957548, 2.704321541499767, 1.427507893789529], 'output': 0.016593738310259763, 'delta': -0.000252180328244517}, {'weights': [1.134364357068215, -1.6866805418327002, -0.3324719515881516], 'output': 0.9208338348540293, 'delta': 0.0005597952940571184}]
[{'weights': [4.903406947389829, -2.108155861429033, -1.2721372756183076], 'output': 0.04180758754504879, 'delta': -0.0016747999653304656}, {'weights': [-4.566502112347264, 2.615993561526247, 0.8280139001392679], 'output': 0.9593429092162126, 'delta': 0.0015857928993322072}]# 학습한 네트워크로 예측값을 뽑아보자.
def predict(network, row):
outputs = forward_propagate(network, row)
return outputs.index(max(outputs))
# 데이터셋 별로 예측하는 것 = 0 / 1 라벨에 속할 '확률'값
# 이 중에 더 큰 것이 최종적으로 예측한 값
# output의 max의 index를 구하면 된다# 네트워크가 잘 학습되었는지 확인해보자.
for row in dataset:
prediction = predict(network, row) # 앞서 최적(학습)시킨 네트워크로 잘 학습되었는지 평가
print('실제값=%d, 예측값=%d' % (row[-1], prediction))실제값=0, 예측값=0
실제값=0, 예측값=0
실제값=0, 예측값=0
실제값=0, 예측값=0
실제값=0, 예측값=0
실제값=1, 예측값=1
실제값=1, 예측값=1
실제값=1, 예측값=1
실제값=1, 예측값=1
실제값=1, 예측값=1