본문 바로가기

책/밑바닥부터 시작하는 딥러닝

4장 신경망 학습 (2)

학습 알고리즘 구현하기

1단계 - 미니배치

훈련 데이터 중 일부를 무작위로 가져온다. 이렇게 선별한 데이터를 미니배치라 하며, 그 미니배치의 손실 함수 값을 줄이는 것이 목표이다.

 

2단계 - 기울기 산출

손실함수에 대한 각 가중치 매개변수의 기울기를 구한다. 

 

3단계 - 매개변수 갱신

가중치 매개변수를 learning rate 만큼 기울기 방향으로 갱신한다.

 

4단계 - 반복

1~3단계를 반복한다.

 

2층 신경망 클래스 구현하기

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 가중치 초기화
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

생성자는 매개변수를 초기화한다. 가중치는 표준편차가 weight_ini_std 인 정규분포가 되도록 랜덤 샘플링한다.

 

    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']

        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = sigmoid(a2)

        return y

forward 부분

 

    def loss(self, x, t):
        y = self.predict(x)

        return cross_entropy_error(y, t)
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)

        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

손실함수는 cross_entropy_error 사용

 

    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads

가중치 매개변수 갱신을 위한 수치미분 부분이다. numerical_gradient는 loss_W라는 손실함수에 대한 각 파라미터의 수치미분을 계산하고 각각의 grads라는 딕셔너리 변수에 저장한다. 

 

이 클래스를 가지고 학습을 진행하면 속도가 매우 느린데, numerical_gradient가 중심 차분으로 기울기를 구하기 때문이다. 매 iteration 마다 이러한 계산을 하면 느릴 수 밖에 없다. 왜냐하면 수치미분보다는 해석학으로 미분값을 구하는 것이 더 빠르기 때문이다.

 

예를 들어 $y = x^2$이 있고 우리는 해석적으로 y의 도함수가 $2x$임을 알고 있다. 하지만 수치미분은 이를 중심 차분으로 구하기 때문에 계산량이 많아져 느릴 수 밖에 없다. 이 부분은 다음 장에서 개선한다.

 

학습 구현

이 클래스를 가지고 학습을 진행하는 것은 시간이 오래 걸리고 비효율적이라 gradient를 어떻게 갱신하는지만 알아보겠다.

for i in range(iters_num):
    # 미니배치 만들기
    batch_mask = np.random.choice(num_train, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
	
    # gradient 계산하기
    grad = network.numerical_gradient(x_batch, t_batch)
	
    # 계산된 gradient로 매개변수 갱신하기
    for key in grad.keys():
        network.params[key] -= learning_rate * grad[key]

매 iteration마다 미니배치를 만들고 미니배치에 대한 gradient를 구한 뒤 네트워크의 파라미터를 갱신한다.

' > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글

5장 오차역전파법 (2)  (0) 2023.09.19
5장 오차역전파법 (1)  (0) 2023.09.19
4장 신경망 학습 (1)  (0) 2023.09.13
3장 신경망  (0) 2023.09.13
2장 퍼셉트론  (0) 2023.09.13