[딥러닝] 신경망 구현 코드

2020. 3. 26. 09:42노트/Python : 프로그래밍

신경망 구현  

  1. 초기화 ( 입력, 은닉, 출력 노드의 수 )
  2. 학습 (가중치 업데이트)
  3. 질의 (입력 -> 연산 -> 출력 노드에 전달)

 

트레이닝, 테스트 데이터 

mnist_test_10.csv
0.02MB
mnist_train_100.csv
0.17MB

 

 

라이브러리 호출 

import scipy
from scipy import integrate # scipy.special 속성 오류해결 
import numpy as np

 

신경망 클래스 생성 

class neuralNetwork:
    #신경망 초기화 기능 
    def __init__(self,input_nodes, hidden_nodes, output_nodes, learning_rate): #첫번째 인수는 무조건 self
        self.inodes=input_nodes
        self.hnodes=hidden_nodes
        self.onodes=output_nodes
        self.lr=learning_rate
 #가중치는 행렬로 표현 
 #입력/은닉 가중치 행렬 형식: 
 #(은닉노드 * 입력노드)
        self.wih=np.random.normal(0.0,pow(self.hnodes,-0.5),(self.hnodes,self.inodes))
 #은닉/출력 가중치 행렬 형식: 
 #(출력노드 * 은닉노드)
        self.who=np.random.normal(0.0,pow(self.onodes,-0.5),(self.onodes,self.hnodes))
 #활성화 함수 초기화 
        self.activation_function=lambda x:scipy.special.expit(x) #sigmoid 함수
        pass
    #신경망 학습 기능 (2단계)
    #1단계(forward propagation): 입력 데이터에 대해 계산을 하는 단계 (query와 비슷)
    #2단계(backward propagation): 예측값과 실제값의 차이계산->에러에 대해서 가중치 업데이트
    def train(self, inputs_list, targets_list):
#입력리스트를 2차원 행렬로 변환 
        inputs=np.array(inputs_list, ndmin=2).T
        targets=np.array(targets_list, ndmin=2).T
#은닉계층으로 들어오는 신호를 계산
        hidden_inputs=np.dot(self.wih,inputs)
#은닉계층에서 나가는 신호 계산
        hidden_outputs=self.activation_function(hidden_inputs)
#출력계층으로 들어오는 신호를 계산
        final_inputs=np.dot(self.who,hidden_outputs)
        final_outputs=self.activation_function(final_inputs) # sigmoid
#오차= 실제값 - 예측값 
        output_errors=targets-final_outputs

#은닉 계층 노드에 대한 역전파된 오차 
#은닉 계층에서 오차는 가중치에 의해 나뉜 출력 계층의 오차들을 재조합하여 계산 
        hidden_errors=np.dot(self.who.T, output_errors)
#은닉 계층과 출력 계층 간의 가중치 업데이트 (who)
        self.who+=self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs) ) , 
                         np.transpose(hidden_outputs))
        self.wih+=self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs) ) , 
                         np.transpose(inputs))    
        pass
    #신경망 질의 기능
    def query(self, inputs_list):
#입력리스트를 2차원 행렬로 변환 
        inputs=np.array(inputs_list, ndmin=2).T
#은닉계층으로 들어오는 신호를 계산
        hidden_inputs=np.dot(self.wih,inputs)
#은닉계층에서 나가는 신호 계산
        hidden_outputs=self.activation_function(hidden_inputs)
#출력계층으로 들어오는 신호를 계산
        final_inputs=np.dot(self.who,hidden_outputs)
        final_outputs=self.activation_function(final_inputs)
        return final_outputs
        

 

* 함수 내 지역변수를 전역변수로 지정

input_nodes, hidden_nodes, output_nodes 는 지역변수라서 train 이나 query 함수에서 사용이 불가함. 
그래서 self.inodes, self.hnodes .... 로 값을 전달하여 class 내에서 해당 변수값을 사용할 수 있도록 지정.

 

 

Training 

#입력, 은닉, 출력 노드의 수 
input_nodes=784 
hidden_nodes=100
output_nodes=10 #(0~9)

#학습률 0.3 
learning_rate=0.3

#신경망 객체생성
n=neuralNetwork(input_nodes,hidden_nodes,output_nodes,learning_rate)

#mnist 트레이닝 데이터 불러오기
training_data_file=open("mnist_train_100.csv","r")
training_data_list=training_data_file.readlines() #한 줄씩 읽어라 
training_data_file.close()

epochs=100
for e in range(epochs):
    for record in training_data_list:
        all_values=record.split(",")
        inputs=(np.asfarray(all_values[1:])/255*0.99)+0.01 #0.01~1.0 으로 rescaling 
        #결과값 생성 
        targets=np.zeros(output_nodes)+0.01
        targets[int(all_values[0])]=0.99 # 정답이 들어가있음
        n.train(inputs,targets)   

 

Test 

test_data_file=open("mnist_test_10.csv","r")
test_data_list=test_data_file.readlines()
test_data_file.close()

test_data_list[0]
all_values=test_data_list[0].split(",")
all_values[0] # 첫번째 테스트 데이터 정답 : 7 

image_array=np.asfarray(all_values[1:]).reshape((28,28))
plt.imshow(image_array, cmap="Greys")

outputs=n.query(np.asfarray(all_values[1:])/255*0.99+0.01)
label=np.argmax(outputs)
print(label, ": my network's answer")

scorecard=[]

for record in test_data_list:
    all_values=record.split(",")
    #정답
    correct_label=int(all_values[0])
    print(correct_label, ":correct_label")
    
    outputs=n.query(np.asfarray(all_values[1:])/255*0.99+0.01)
    label=np.argmax(outputs)
    print(label, ": my network's answer")
    if (label==correct_label):
        scorecard.append(1)
    else:
        scorecard.append(0)

scorecard_array=np.asarray(scorecard)
print(scorecard_array.sum()/scorecard_array.size)