신경망 학습시키기
신경망 학습의 두 가지 단계
- 주어진 학습 데이터에 대해 결과 값을 계산해내는 단계.
- 계산한 결과 값을 실제의 값과 비교하고 이 차이를 이용해 가중치를 업데이트 하는 단계
tarin() 함수 코드
입력 계층으로부터의 신호를 최종 출력 계층까지 전파하는 과정은 query() 함수와 동일 하므로 내용은 거의 동일하다.
다만 아래 함수 매개변수를 보면 targets_list 가 추가로 존재한다. 이 매개변수 없이는 신경망을 제대로 학습시킬 수 없다.
1 | def train(self, input_list, targets_list): | cs |
앞에서 inputs_list를 numpy 배열로 변환했던 것과 동일한 방법으로 targets_list를 변환해줍니다.
1 | targets = numpy.array(targets_list, ndmin=2).T | cs |
이제 계산 값과 실제 값 간의 오차에 기반해 신경망의 동작에서 핵심이 되는 가중치를 업데이트할 준비가 거의 되었습니다.
단계별로 나누어 보면
우선 오차를 계산해야 합니다. 오차는 학습 데이터에 의해 제공되는 실제 값과 우리가 계산한 결과 값 간의 차이로 정의됩니다.
결국 오차는 ( 실제 값 행렬 - 계산 값 행렬 ) 이라는 연산의 결과 값이 됩니다. 이 연산은 원소 간 연산입니다. 파이썬으로 구현하면 다음과 같습니다.
1 2 | # 출력계층의 오차는 (실제 값 - 계산 값) output_errors = targets - final_outputs | cs |
그 다음 은닉 계층의 노드들에 대해 역전파된 오차도 구할 수 있습니다.
1 2 | # 은닉 계층의 오차는 가중치에 의해 나뉜 출력 계층의 오차들을 재조합해 계산 hidden_errors = numpy.dot(self.who.T, output_errors) | cs |
그러면 각각의 계층에서 가중치를 업데이트하기 위해 필요한 모든 것을 갖추게 되었습니다. 은닉 계층과 최종 계층 간의 가중치는 output_errors를 이용하면 되고, 입력 계층과 은닉 계층 간의 가중치는 방금 구한 hidden_errors를 이용하면 되는 것입니다. 입력 계층과 은닉 계층 사이의 가중치에 대한 코드도 유사합니다. 계층의 이름 정도만 변경해주면 되겠습니다.
1 2 | # 은닉 계층과 출력 계층 간의 가중치 업데이트 self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs)) | cs |
1 2 | # 입력 계층과 은닉 계층간의 가중치 업데이트 self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs)) | cs |
이렇게 간단하게(?) 구현이 가능합니다. 인공 신경망 예제는 아래 책에서 참고해서 적습니다. 내용은 완벽하게 적지는 않았습니다.
책 제목 : 신경망 첫걸음
지은이 : 타리크 라시드
옮긴이 : 송교석
이상으로 인공 신경망 구현을 마쳤습니다. 소스 코드는 아래에 올려두고, 다음에는 MNIST 손글씨 데이터 인식을 할 예정입니다.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | import scipy.special import numpy # 신경망 클래스의 정의 class neuralNetwork: # 신경망 초기화 (입력노드 , 은닉노드 , 출력 노드 , 학습률) def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): # 입력, 은닉, 출력 계층의 노드 개수 설정 self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes # 가중치 행렬 wih 와 who # self.wih = (numpy.random.rand(self.hnodes, self.inodes)-0.5) # self.who = (numpy.random.rand(self.onodes, self.hnodes)-0.5) # 더 정교한 가중치 self.wih = numpy.random.normal(0.0 , pow(self.hnodes, -0.5),(self.hnodes, self.inodes)) self.who = numpy.random.normal(0.0 , pow(self.onodes, -0.5),(self.onodes, self.hnodes)) # 학습률 self.lr = learningrate # 활성화 함수로는 시그모이드 함수를 이용 self.activation_function = lambda x: scipy.special.expit(x) # 신경망 학습 def train(self, input_list, targets_list): # 입력 리스트를 2차원 행렬로 변환 inputs = numpy.array(inputs_list, ndmin=2).T targets = numpy.array(targets_list, ndmin=2).T # 은닉 계층으로 들어오는 신호를 계산 hidden_inputs = numpy.dot(self.wih, inputs) # 은닉 계층으로 나가는 신호를 계산 hidden_outputs = self.activation_function(hidden_inputs) # 최종 출력 계층으로 들어오는 신호를 계산 final_inputs = numpy.dot(self.who, hidden_outputs) # 최종 출력 계층으로 나가는 신호를 계산 final_outputs = self.activation_function(final_inputs) # 출력계층의 오차는 (실제 값 - 계산 값) output_errors = targets - final_outputs # 은닉 계층의 오차는 가중치에 의해 나뉜 출력 계층의 오차들을 재조합해 계산 hidden_errors = numpy.dot(self.who.T, output_errors) # 은닉 계층과 출력 계층 간의 가중치 업데이트 self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs)) # 입력 계층과 은닉 계층간의 가중치 업데이트 self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs)) # 신경망에 질의 def query(self, inputs_list): # 입력 리스트를 2차원 행렬로 변환 inputs = numpy.array(inputs_list, ndmin=2).T # 은닉 계층으로 들어오는 신호를 계산 hidden_inputs = numpy.dot(self.wih, inputs) # 은닉 계층으로 나가는 신호를 계산 hidden_outputs = self.activation_function(hidden_inputs) # 최종 출력 계층으로 들어오는 신호를 계산 final_inputs = numpy.dot(self.who, hidden_outputs) # 최종 출력 계층에서 나가는 신호를 계산 final_outputs = self.activation_function(final_inputs) return final_outputs # 입력, 은닉, 출력 노드의 수 input_nodes = 3 hidden_nodes = 3 output_nodes = 3 # 학습률 0.3 learning_rate = 0.3 # 인스턴스 생성 n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate) | cs |
'기타 > 기타 잡다한 것들' 카테고리의 다른 글
[머신러닝] 프레임워크 scikit-learn을 사용하여 XOR 연산 해보기 (0) | 2018.09.29 |
---|---|
머신러닝 기본 정리 및 개요 (0) | 2018.09.29 |
[신경망] 파이썬으로 인공 신경망 만들기 4 (0) | 2018.09.28 |
[신경망] 파이썬으로 인공 신경망 만들기 3 (0) | 2018.09.28 |
[신경망] 파이썬으로 인공 신경망 만들기 2 (0) | 2018.09.27 |