도서 : 신경망 첫걸음(한빛미디어)

지음 : 타리크라시드(송교석 옮김)


 

  •  기본적인 숫자들을 그래프의 그림형태로 나타내 보겠습니다. MNIST 손글씨 데이터는 책 안의 내용에서 찾을 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy
import matplotlib.pyplot
%matplotlib inline
 
#데이터를 불러오고 그 파일을 읽는다.
data_file = open("mnist_train_100.txt",'r')
data_list = data_file.readlines()
data_file.close()
 
all_values = data_list[0].split(','#split는 구분자로 사용할 기호를 그 매개변수로 가진다. 리스트를 불러와서 쉼표로 구분하여 분리
#asfarray는 문자열을 실수로 변환한 다음에 그 숫자로 구성된 배열을 생성한다.
#reshape((28,28))함수는 784개의 어레이 숫자들을 28 x 28 형태의 정방 행렬로 만들어 준다
image_array = numpy.asfarray(all_values[1:]).reshape((28,28)) #리스트의 원소중 가장 첫 번째 원소는 이 원소들이 무엇을 표현하는 것인지를 알려주는 것이기 때문에 빼준다.
matplotlib.pyplot.imshow(image_array, cmap='Greys', interpolation='None'#imshow를 이용해 어레이를 시각화
cs
  • 결과

  • MNIST 학습 데이터 준비하기     

  • 현재 학습 데이터들의 값은 0~255의 값이므로 이를 255로 나눈 후 0.99를 곱하고 0.01을 더해 0.01 ~ 1.0의 범위로 만들겠습니다.

1
2
scaled_input = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
print(scaled_input)
cs

  • 우리가 신경망에 바라는 바는 이미지를 분류해 정확한 레이블을 할당하는 것입니다. 레이블은 0~9까지 10개 숫자 중 하나입니다. 다시 말해 10개의 노드로 구성된 출력 계층이 필요하고, 각 노드는 가능한 결과 값, 즉 각 레이블에 해당할 것입니다.

  • 우리는 0.01~ 0.99사이의 값을 결과로 가지고자 합니다. 각 원소들의 첫 번째 값을 targets의 인덱스로 두고 그 값을 0.99로 정해주면 그 원소에 해당하는 노드의 값을 0.99로 설정해 준 것이 됩니다. 

  • 이를 바탕으로 우리는 0~9까지의 숫자를 구분지어 줄 수 있으며 이전에 만든 인공신경망을 사용해 이를 학습시킬 수 있게 됩니다.

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
#신경망의 인스턴스를 생성
= 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
cs
  • 이 소스를 실행시켰다면 신경망이 학습되었을 것입니다.
  • 이제 테스트를 해보도록 하겠습니다. 학습시킨 100개의 데이터가 아닌 10개의 데이터에서 값을 찾아 신경망에 넣고 정확한 결과가 나오는지 확인합니다.
  • 먼저 데이터를 확인해 보겠습니다.
1
2
3
4
5
6
7
8
9
test_data_file = open("mnist_test_10.txt",'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
 
all_values = test_data_list[0].split(',')
print(all_values[0])
 
image_array = numpy.asfarray(all_values[1:]).reshape((28,28))
matplotlib.pyplot.imshow(image_array, cmap='Greys', interpolation='None')
cs
  • 결과는

  • 그리고 우리가 학습시킨 인공 신경망에 질의를 하면?
1
n.query((numpy.asfarray(all_values[1:])/255.0*0.99)+0.01)
cs

  • 레이블 7에 해당하는 결과 값이 가장 크다는 것을 알 수 있습니다. 학습데이터와는 전혀다른 손글씨를 구분한 것입니다. 
  • 이번에는 10개의 테스트 데이터를 인공 신경망이 잘 구분하는지 확인해 보겠습니다.
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
#신경망 테스트
 
#신경망의 성능의 지표가 되는 성적표를 아무 값도 가지지 않도록 초기화
scorecard = []
 
#테스트 데이터 모음 내의 모든 레코드 탐색
for record in test_data_list:
    #레코드를 쉼표에 의해 분리
    all_values = record.split(',')
    #정답은 첫 번째 값
    correct_label = int(all_values[0])
    print(correct_label,"correct label")
    #입력 값의 범위와 값 조정
    inputs = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
    #신경망에 질의
    outputs = n.query(inputs)
    #가장 높은 값의 인덱스는 레이블의 인덱스와 일치
    label = numpy.argmax(outputs)
    print(label, "network's answer")
    #정답 또는 오답을 리스트에 추가
    if(label == correct_label):
        #정답인 경우 성적표에 1을 더함
        scorecard.append(1)
    else:
        #정답이 아닌 경우 성적표에 0을 더함
        scorecard.append(0)
        pass
    pass
 
print(scorecard)
cs

  • 일치하는 값은 10개 중 6개 입니다. 즉, 100개의 데이터로 학습시킨 인공 신경망은 60%의 정확도밖에 보이지 않는다는 말 입니다.
  •  전체 데이터를 이용해 학습 및 테스트하기
    • 이제부터는 좀 더 큰 학습 데이터와 테스트 데이터를 이용해 정확도를 확인해 보도록 하겠습니다.
    • 책의 내용에 있는 깃허브에서 각각의 파일을 다운로드 한 후 폴더에 넣어줍니다.
    • 그 후 파일명만 바꿔주면 됩니다.
1
2
3
#스코어 평균
scorecard_array = numpy.asarray(scorecard)
print("performance = ", scorecard_array.sum()/scorecard_array.size)
cs

  • 약 95%의 정확도를 가질 수 있게 되었습니다. 

도서 : 신경망 첫걸음(한빛미디어)

지음 : 타리크라시드(송교석 옮김)


  • 입력 값
    • 시그모이드 함수에서 입력 값이 크면 활성화 함수는 평범한 형태를 띠는 것을 볼 수 있습니다.
    • 기울기를 이용해 가중치를 업데이트하므로 평평한 활성화 함수는 문제가 있습니다.
    • 가중치의 변화는 활성화 함수의 기울기에 좌우됩니다. 이는 작은 기울기는 학습 능력이 제한된다는 것을 의미합니다. 이를 일컬어 신경망에 포화(saturation)가 발생했다고 합니다. 포화가 일어나지 않게 하기 위해 우리는 입력 값을 작게 유지해야만합니다.
    • 이 수식은 입력 신호(Oj)에도 영향을 받습니다. 따라서 우리는 가중치를 너무 작게 만들 수 없습니다. 컴퓨터는 매우 작거나 매우 큰 수를 처리할 때 정확도를 잃을 수 있으므로 매우 작은 수도 문제가 될 수 있는 것입니다.
    • 0.0~1.0 사이에 입력 값이 놓이도록 그 크기를 조정하는 것입니다. 때로는 입력 값에 0.01같은 작은 오프셋 값을 더해서 입력 값이 0이 되는 것을 방지하기도 합니다. 입력 값이 0이면 Oj = 0으로 설정되므로 가중치 업데이트 수식에 의한 학습 능력이 죽어버리기 때문입니다.

  • 결과 값
    • 신경망의 결과 값은 마지막 계층의 노드들로부터 출력되는 신호입니다.
    • 우리가 사용하는 시그모이드 함수는 0과 1에 한 없이 가까워지기는 하지만 일치하지는 않는 함수입니다. 만약 도달할 수 없는 값으로 목표 값을 설정한다면, 신경망을 학습하면 할수록 활성화 함수에 의해 만들어질 수 없는 더 큰 결과 값을 만들기 위해 점점 더 큰 가중치를 시도하게 될 것입니다. 그 결과, 결국 신경망을 포화시키게 됩니다.
    • 그러므로 목표 값을 도달 불가능한 값으로 설정하지 않도록 해야하며, 활성화 함수가 출력할 수 있는 값으로 재조정해야 합니다.
  • 임의의 값으로 가중치 초기화
    • 가중치 역시 입력 값, 출력 값과 마찬가지로 초기화 시 큰 값을 피해야 합니다.
    • 큰 값을 가지는 가중치는 신호를 크게 만들어 활성화 함수에 전달하게 되며 이는 우리가 계속 언급하고 있는 포화를 일으켜 가중치를 학습하는 능력을 떨어뜨리게 되기 때문입니다.
    • 가중치의 초기화는 -1.0 ~ 1.0 사이의 임의의 값으로 하는 것이 좋은 선택일 것입니다.
    • 수학자들이 도달한 결론은 노드로 오는 연결 노드의 개수에 루트를 씌운 다음 역수를 취해 얻은 값을 범위로 해서 가중치의 값을 초기화 하면 된다는 것이었습니다. -> ex)노드가 4개의 연결 노드를 가진다면 가중치의 초기값은 ±1/2 가 됩니다.
    • 가중치가 지나치게 큰 값으로 초기화하면 활성화 함수를 편향된 방향으로 편향시키게 될 것이며, 지나치게 큰 가중치는 그 활성화 함수를 포화시킬 것입니다.
    • 노드로 들어오는 연결 노드가 많을수록 더 많은 신호들이 합쳐지게 됩니다. 그러므로 많은 연결 노드를 가지면 가중치의 범위를 줄여야 한다는 것이 경험적으로 옳을 것입니다.
    • 어떤 경우라도 가중치의 초기 값을 같은 상수로 설정하면 안 됩니다. 신경망에 있는 모든 노드들이 같은 신호 값을 받아서 각 출력 노드의 출력 값 역시 동일하게 출력되기 때문입니다. 또한 오차를 역전파함으로써 가중치를 업데이트하는 과정에서 오차는 모두 같은 값으로 나뉘어 전파될 것입니다. 이를 대칭(symmetry)이라고 표현합니다.
    • 가중치가 0이 된다면 입력신호를 죽여버리기 때문에 더욱 좋지 않습니다. 입력 신호에 의해 좌우되는 가중치 업데이트 함수는 모두 0이 되어버립니다. 

도서 : 신경망 첫걸음(한빛미디어)

지음 : 타리크라시드(송교석 옮김)


 

  • 이번에는 결과 값의 오차에 따른 가중치 업데이트 방식을 알아보고자 합니다.
  • 모든 연결된 노드에 대해 오차를 균일하게 나누어 분배하는 방식

모든 가중치에 동일한 오차를 부여하는 방식입니다.

 

  • 오차를 나누어 분배하지만 차별을 두는 방식 : 더 큰 가중치를 가지는 연결에 더 큰 오차를 분배

가중치의 크기에 따라 오차를 부여하는 방식입니다. 각각의 연결이 오차에 영향을 주는 정도에 비례해서 전달합니다.

  • 우리는 가중치를 두 가지 방법으로 활용한다는 것을 알게 되었습니다. 하나는 앞에서 살펴본 것 같이 하나의 계층에서 다음 계층으로 전파하는 데에 가중치를 이용하는 것, 그리고 두 번째는 오차를 하나의 계층에서 직전 계층으로 전파하는 데에도 이용한다는 것(역전파 - backpropagation)입니다.

  • 만약 출력 계층이 2개의 노드를 가진다면? 두 번째 노드에 대해서도 동일한 작업을 하게 됩니다.

  • 2개의 출력 노드를 가지는 그림입니다. 2개의 출력 노드 모두 오차를 가질 수 있습니다. 특히 우리가 아직 네트워크를 학습시키지 않은 경우에는 거의 무조건 오차를 가지고 있습니다.
  • e1의 경우 학습 데이터 t1에 의해 제공된 실제 값과 우리가 계산한 출력 값 o1 사이의 차이를 의미합니다. 다시 말해 e1 = t1 - o1입니다. 이렇게 보면 가중치 w(1,1)과 w(2,1)에 의해 e1이 영향을 받게 되었으므로 e1은 두 가중치에 업데이트에 영향을 주게 됩니다. 따라서 앞서 배운바와 같이 w(1,1)은 w(1,1)/{w(1,1) + w(2,1)}이라는 식이 업데이트를 하는데 사용되고 w(2,1)은 w(2,1)/{w(1,1) + w(2,1)}이라는 식이 사용됩니다.
  • 결론적으로 여러 개의 출력 노드가 있는 경우에도 그저 각각의 출력 노드를 개별적으로 처리하면 될 뿐, 복잡해질 것이 전혀 없다는 사실을 알게 되었습니다.

  • 그렇다면 멀리 떨어져 잇는 계층과 관련된 가중치, 즉 여러 개의 계층이 있는 경우는 어떻게 해야 할까요?
  • 3개 계층(입력, 은닉, 출력)이 존재하는 경우입니다. 먼저 오른쪽 끝의 최종 출력 계층부터 보겠습니다. 출력 계층의 오차를 이용해 출력 계층과 연결된 노드들의 가중치를 업데이트 합니다. 여기서 출력 계층의 오차를 e_output, 은닉 계층과 출력 계층사이의 가중치를 w_ho라고 표현하겠습니다.

  • w_ho의 경우는 앞서 배운 것 처럼 e_output을 이용하여 업데이트가 가능합니다. 그렇게 업데이트를 한 후 e_hidden을 이용하여 입력 계층과 은닉 계층사이의 가중치 w_ih를 업데이트 하면 될 것 같습니다. 그러나 e_hidden은 어떤 오차 값을 사용하는 것일까요?

 

 

 

  • 중간에 위치하는 은닉 계층은 사실 명백한 오차를 가지고 있지 않습니다. 직전 계층의 입력 값에 가중치를 적용한 후, 활성화 함수를 적용한 값이 은닉 계층의 출력 값입니다. 따라서 은닉 계층에는 목표로 하는 출력 값이 없는 것입니다. 오직 최종 출력 계층의 노드만이 학습 데이터로부터 얻은 실제 값, 즉 목표로 하는 출력 값을 가지고 있습니다.

  • 은닉 계층의 노드로부터 오는 2개의 연결 노드 각각에 대해 어떤 오차가 존재합니다. 우리는 이러한 2개의 연결 노드의 오차를 재조합(recombine)함으로써 은닉 계층의 노드의 에러로 사용할 수 있습니다.

  • 공식은 다음과 같습니다. e_hidden(1) = 연결 노드 w11, w12로 나뉘어 전달되는 오차의 합 = {e_output(1) * w(1,1)}/{w(1,1) + w(2,1)} + {e_output(2) * w(1,2)}/{w(1,2) + w(2,2)}

 

  • e1이 0.8, e2가 0.5이고 w(1,1)이 2.0, w(2,1)이 3.0, w(1,2)가 1.0, w(2,2)가 4.0이므로 은닉 계층의 1번째 노드에는 0.8*2.0/(2.0+3.0) = 0.32와 0.5*1.0/(1.0+4.0) = 0.1의 합이 e_hidden(1)의 값이 됩니다. 즉 0.42입니다.

 

  • 이 그림은 한 단계 더 나아가 은닉 계층의 e값을 이용하여 입력 계층의 e값을 구하는 것을 보여줍니다.


  • 행렬곱을 이용한 오차의 역전파

  • 앞서 본 예제는 엄청나게 간단한 구조의 계층들이었습니다. 물론 실제 역전파는 매우 복잡합니다. 그렇다면 우리는 역전파에도 행렬곱을 이용하여 복잡한 계산을 좀 더 간단하게 나타내야 할 것입니다.

  • 이렇게 행렬곱으로 표현하는 방식을 벡터화한다(vectorize)고 합니다.

  • 앞서 본 예제의 식들을 간단한 행렬곱으로 나타내보겠습니다.

  • 조금 복잡해 보이는 식이 되었지만 여기서 우리는 분수가 있는 행렬의 분모 부분은 일종의 정규화 인자(nomalizing factor)라고 할 수 있습니다. 만약 이 정규화 인자를 무시한다고 해도 우리는 되돌아오는 오차의 일정 비율 정도를 잃을 뿐입니다. 따라서 간단하게 e1*w(1,1)로 표현해도 되는 것 입니다. 이를 적용하면 행렬곱은 훨씬 보기 좋아집니다.

  • 우리가 지난 글에서 배웠던 w_hidden_output행렬의 전치(transpose)행렬로 보입니다. 이제 다음과 같이 오차의 역전파를 행렬로 간결하게 표현할 수 있게 되었습니다. -> error_hidden = W^T(hidden) * error_output

도서 : 신경망 첫걸음(한빛미디어)

지음 : 타리크라시드(송교석 옮김)


  •  신경망 내의 신호를 따라가보기 위해 간단한 2개의 계층에 각각 2개의 노드가 있는 신경망을 만들어보겠습니다.
    • 가중치는 임의로 W(1,1) = 0.9, W(1,2) = 0.2, W(2,1) = 0.3, W(2,2) = 0.8로 정했습니다.
    • 입력값은 1.0과 0.5, 이렇게 두고 각각의 노드로 입력되는 값들을 계산해 보면 다음과 같습니다.
    • 이를 마지막으로 시그모이드 활성화 함수에 입력 값으로 적용하면 y = 1 / (1 + 0.3499) = 1 / 1.3499 = 0.7408과 y = 1 / (1 + 0.5488) = 1 / 1.5488 = 0.6457이라는 출력 값을 얻게 됩니다.
    • 지금은 2개의 계층 뿐이지만 엄청나게 많은 노드들과 계층들을 계산하기 위해서는 하나하나 계산하기 힘들 것입니다.
    • 따라서 행렬을 이용하여 좀 더 쉽게 계산하는 방법을 알아보겠습니다.

  • 솔직히 행렬곱은 유용합니다
    • 행렬(matrix)이란 사실상 숫자로 구성된 사각형의 격자에 지나지 않습니다. 행렬은 위의 복잡한 계산을 매우 간단한 형태로 압축해서 표현할 수 있도록 도와줍니다.
    • 대부분의 컴퓨터 프로그래밍 언어는 행렬 작업을 잘 처리하므로 이런 복잡한 업무를 행렬 기반으로 잘 만들어서 컴퓨터에게 넘기기만 하면 컴퓨터가 알아서 매우 빠르고 효율적으로 처리할 수 있게 됩니다.
    • 점곱(dot product) 또는 내적(inner product) : 첫 번째 행렬의 열의 수와 두 번째 행렬의 행의 수가 같아서 서로 다른 크기의 행렬임에도 행렬곱이 가능
    • 2개 계층의 노드 간 가중치로 구성되어 있는 행렬과 입력 계층의 신호로 구성되어 있는 행렬의 행렬곱을 표현해보면 다음과 같습니다.
    • 결과 행렬에서 나타내는 바는 input값들이 가중치에 의해 조정되어 더해진 결과입니다. 이 결과값들은 시그모이드 활성화 함수에 입력 값 x로 전달됩니다. 이를 간단한 공식으로 나타내면 X(시그모이드 함수로 넘겨질 x값의 행렬) = W(가중치의 행렬) * I(입력 값들의 행렬) -> 일반적으로 행렬을 표현할 때는 다른 하나의 숫자를 담고있는 변수보다 진하게 표시한다
    • 따라서 계층 2의 최종 결과물은 O(신경망의 마지막 계층의 모든 결과 값을 포함하는 행렬) = sigmoid(X) 와 같이 표현할 수 있습니다.

  • 3계층 신경망에 행렬곱 적용하기
    • 계층이 3개인 신경망을 통해 신호를 전달해보겠습니다. 계층 1은 입력 계층(input layer)이라고 부르며 마지막 계층 3은 출력 계층(out layer)이라고 부릅니다. 중간에 위치하는 계층 2는 은닉 계층(hidden layer)이라고 합니다.

    • 입력 값은 3개가 존재하며 각각 0.9, 0.1, 0.8입니다. 각 가중치들은 다음과 같이 행렬로 표현했습니다. 입력 계층과 은닉 계층의 행렬, 은닉 계층과 출력 계층 간의 가중치의 행렬이 각각 만들어졌습니다.

    • 먼저 입력 값들을 첫 번째 순서인 입력 계층 -> 은닉 계층의 행렬과 곱합니다. 그렇게 나온 결과 값을 sigmoid함수에 넣어서 완전한 결과 값을 도출합니다.

    • 그 후 다시 은닉 계층 -> 출력 계층의 행렬과 곱합니다. 그렇게 나온 결과 값을 다시 sigmoid함수에 넣어서 최종적인 출력 값을 구합니다.

    • 다음 단계는 지금 얻은 결과 값을 학습 데이터의 실제 값과 비교해 오차를 구하는 것이 될 것입니다.

+ Recent posts