import numpy
import scipy.special
import matplotlib.pyplot
%matplotlib inline
#신경망 클래스의 정의
class neutalNetwork:
#신경망 초기화하기
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
#입력, 은닉, 출력 계층의 노드 개수 설정
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
#가중치 행렬 wih와 who -> 정규분포의 중심은 0.0으로 설정, 표준편차는 노드로 들어오는 연결 노드의 개수에 루트를 씌우고 역수를 취함(pow함수)
#배열 내 가중치는 w_i_j로 표기. 노드 i에서 다음 계층의 j로 연결됨을 의미
#w11 w21
#w12 w22 등
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)
pass
#신경망 학습시키기
def train(self, inputs_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))
pass
#신경망에 질의하기
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 = 784 #손글씨 숫자 이미지를 구성하는 픽셀이 28x28의 크기를 가지기 때문
hidden_nodes = 100 #입력 값의 수보다 작은 값을 선택함으로써 신경망이 주요 특징을 찾아낸다, 너무 적은 수의 은닉 계층 노드를 선택한다면 제한적이 될 수도 있다
output_nodes = 10 #0~9까지의 레이블을 구분해야 하므로 출력은 10개면 충분하다.
#학습률은 0.3으로 정의
learning_rate = 0.3
#신경망의 인스턴스를 생성
n = neutalNetwork(input_nodes,hidden_nodes,output_nodes,learning_rate)
#데이터를 불러오고 그 파일을 읽는다.
training_data_file = open("mnist_train_100.txt",'r')
training_data_list = training_data_file.readlines()
training_data_file.close()
#신경망 학습시키기
#학습 데이터 모음 내의 모든 레코드 탐색
for record in training_data_list:
#레코드를 쉼표에 의해 분리
all_values = record.split(',') #split는 구분자로 사용할 기호를 그 매개변수로 가진다. 리스트를 불러와서 쉼표로 구분하여 분리
#입력 값의 범위와 값 조정
inputs = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
#결과 값 생성 (실제 값인 0.99 외에는 모두 0.01)
targets = numpy.zeros(output_nodes) + 0.01
#all_values[0]은 이 레코드에 대한 결과 값
targets[int(all_values[0])] = 0.99
n.train(inputs,targets)
pass