혜온의 이것저것

[Chapter 1 신경망 복습] 2 신경망의 추론 본문

Deep Learning/밑바닥부터 시작하는 딥러닝2

[Chapter 1 신경망 복습] 2 신경망의 추론

혜온 :) 2022. 1. 24. 11:38

1.2.1 신경망 추론 전체 그림

신경망은 간단히 말하면 함수와도 같다. 무엇인가를 입력하면 무엇인가를 출력한다는 점에서.

2차원 데이터를 입력하면 3차원 데이터를 출력하는 예이다.

입력층(input layer)에는 뉴런2개, 출력층(output layer)에는 뉴련 3개가 있고, 은닉층(hidden layer)에는 적당한 수의 뉴런을 배치한다.

각 뉴런을 잇는 화살표에는 가중치(weight)가 존재하며, 그 가중치와 뉴런의 값을 각각 곱해서 합한 값이 다음 뉴런의 입력으로 쓰이게 된다.

이때 각 층에서 이전의 뉴런의 값에 영향을 받지 않는 정수인 편향값(bias)도 함게 더해진다.

신경망은 인접하는 층의 모든 뉴런과 연결되어 있다는 뜻에서 완전연결계층(fully connected layer)이라고 한다.

 

위 그림을 식으로 나타내면 아래와 같다.

$$ h_1 = x_1w_(11) + x_2w_(21) +b_1 $$

이 계산이 뉴런의 수만큼 반복되면서 hidden layer에 속한 모든 뉴런의 값을 구할 수 있다. 이를 행렬의 곱을 이용해 표현 가능하다.

$$ \mathbf{h=xW+b} $$

이 기호는 각각 모두 행렬이다. 행렬의 곱에서는 대응하는 차원의 원수 수가 일치해야 한다

 

fully connected layer에 의한 변환은 선형변환이다. 여기에 비선형 효과를 부여하는 것이 활성화함수이다. 비선형 활성화 함수를 이용함으로써 신경망의 표현력을 높일 수 있다. 대표적인 예로는 0과 1 사이의 실수를 출력하는 시그모이드 함수(sigmoid function)가 있다.

$$ \sigma(x)=\frac{1}{1+exp(-x)} $$

 

이 활성화 함수를 이용하여 활성화(activation)를 하여 또 다른 완전연결계층에 통과시켜 변환한다.

이를 코드로 표현하면 아래와 같다.

import numpy as np

def sigmoid(x):
	return 1/(1+np.exp(-x))
    
x=np.random.randn(10,2)
W1=np.random.randn(2,4)
b1=np.random.randn(4)
W2=np.random.randon(4,3)
b2=np.random.randon(3)

h=np.matmul(x,W1)+b1
a=sigmoid(h)
s=np.matmul(a,W2)+b2

2차원 데이터 10개가 3차원 데이터 10개로 변환되었다. 각 차원의 값을 이용하여 클래스 분류가 가능하다. 이 경우, 출력된 3차원 벡터의 각 차원은 각 클래스에 대응하는 점수(score)가 된다.

(나중에 나오지만, 점수를 softmax function에 입력하면 확률을 얻을 수 있다.)

 

 

1.2.2 계층으로 클래스화 및 순전파 구현

신경망에서 하는 처리를 layer로 구현해보자. 완전연결계층에 의한 변환은 Affine 계층으로, 시그모이드 함수에 의한 변환은 Sigmoid 계층으로 구현한다.

(신경망 추론 과정에서 하는 처리는 신경망의 순전파(forward propagation)에 해당한다.)

 

이 책에서의 구현 규칙은 다음과 같다.

- 모든 계층은 forward()와 backward() 메서드를 가진다.

- 모든 계층은 인스턴스 변수인 params와 grads를 가진다.

params는 가중치와 평향 같은 매개변수를 담는 리스트이고, grads는 params에 저장된 각 매개변수에 대응하여, 해당 매개변수의 기울기를 보관하는 리스트이다.

 

이번 절에서는 순전파만 구현할 것이다.

먼저 Sigmoid계층이다.

import numpy as np

class Sigmoid:
	def __init__(self):
    	self.params=[]
        
    def forward(self,x):
    	return 1/(1+np.exp(-x))

Sigmoid 계층에는 학습하는 매개변수가 따로 없으므로 params는 빈 리스트로 초기화한다.

 

다음은 Affine 계층이다.

class Affine:
	def __init__(self):
    	self.params=[W,b]
    
    def forward(self,x):
    	W,b=self.params
        out=np.matmul(x,W)+b
        return out

가중치와 편향이 Affine계층이 매개변수이며 params변수에 저장된다.

 

위에서 구현한 계층을 사용해 신경망의 추론 처리를 구현해보자.

입력 x가 Affine계층, Sigmoid계층, Affine계층을 차례로 거쳐 점수인 s를 출력하게 된다.

class TwoLayerNet:
	def __init__(self, input_size, hidden_size, output_size):
    	I, H, O=input_size, hidden_size, output_size
        
        # 가중치와 편향 초기화
        W1=np.random.randn(I,H)
        b1=np.random.randn(H)
        W2=np.random.randn(H,O)
        b2=np.random.randon(O)
        
        # 계층 생성
        self.layers=[Affine(W1,b1), Sigmoid(), Affine(W2,b2)]
        
        # 모든 가중치를 리스트에 모은다.
        self.params=[]
        for layer in self.layer:
        	slef.params+=layer.params
            
    def predict(self,x):
    	for layer in self.layers:
        	x=layer.forward(x)
        return x

이 클래스의 초기화 메서드(__init__)는 먼저 가중치를 초기화하고 3개의 계층을 생성한다. 마지막으로는 학습해야 할 가중치 매개변수들을 params 리스트에 저장한다. 모든 계층은 자신의 학습 매개변수들을 params에 보관하고 있으므로, 이 변수들을 더해주기만 하면 된다.

 

TwoLayerNet클래스를 이용해 신경망의 추론을 수행해보자.

x=np.random.randn(10,2)
model=TwoLayerNet(2,4,3)
s=model.predict(x)

이처럼 계층을 클래스로 만들어두면 신경망을 쉽게 구현할 수 있다. 또한 학습해야 할 모든 매개변수가 model.params라는 하나의 리스트에 모여 있으므로, 이어서 설명할 신경망 학습이 한결 수월해진다.

Comments