수학/딥러닝 이론

[딥러닝] 합성곱 신경망(CNN) - CNN 구현하기

AI 꿈나무 2020. 10. 5. 21:58
반응형

사이토고키의 <밑바닥부터 시작하는 딥러닝>을 공부하고 정리해보았습니다.

 


 

 

[딥러닝] 합성곱 신경망(CNN) - 풀링 계층 구현하기

사이토고키의 <밑바닥부터 시작하는 딥러닝>을 공부하고 정리해보았습니다. 을 공부하고 정리해보았습니다. 을 공부하고 정리해보았습니다. 을 공부하고 정리해보았습니다. 을 공부하고 정리��

deep-learning-study.tistory.com

 이전 포스팅에서 풀링 계층을 구현해보았습니다.

 합성곱 신경망을 구현하는 방법을 공부해보겠습니다.

 

CNN 구현하기

 합성곱 계층과 풀링 계층을 구현했으니, 이 계층들을 조합하여 손글씨 숫자를 인식하는 CNN을 조립해보겠습니다.

 여기에서는 다음과 같은 CNN을 구현합니다.

 

 "Convolution - ReLU - Pooling - Affine - ReLU - Affine - Softmax'

 

우선 SimpleConvNet 초기화 코드 먼저 구현하겠습니다.

 

class SimpleConvNet:
    def __init__(self, input_dim = (1, 28, 28)
    			conv_param={'filter_num':30, 'filter_size':5,
                			'pad':0, 'stride':1},
                hidden_size=100, output_size=10, weight_init_std=0.01):
        filter_num = conv_param['filter_num']
        filter_size = conv_param['filter_size']
        filter_pad = conv_param['pad']
        filter_stride = conv_param['stride']
        input_ize = input_dim[1]
        conv_output_size = (input_size - filter_size + 2 * filter_pad) \
        					filter_stride + 1
        pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2))

 

 여기에서는 초기화 인수로 주어진 합성곱 계층의 하이퍼파라미터를 딕셔너리에서 꺼냅니다.

 그리고 합성곱 계층의 출력 크기를 계산합니다.

 이어서 다음 코드는 가중치 매개변수를 초기화하는 부분입니다.

 

	self.params = {}
        self.params['W1'] = weight_init_std * \
        					np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
        self.params['b1'] = np.zeros(filter_num)
        self.params['W2'] = weight_init_std * \
        					np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
        self.params['b2'] = np.zeros(filter_num)
        self.params['W3'] = weight_init_std * \
        					np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
        self.params['b3'] = np.zeros(filter_num)

 

 학습에 필요하 매개변수는 1번째 층의 합성곱 계층과 나머지 두 완전연결 계층의 가중치와 편향입니다.

 이 매개변수들은 인스턴스 변수 params 딕셔너리에 저장합니다.

 

 마지막으로 CNN을 구성하는 계층들을 생성합니다.

 

        self.layers = OrderedDict()
        self.layers['Conv1'] = Convolution(self.params['W1'],
        									self.params['b1']
                                            conv_params['stride']
                                            conv_parmas['pad']
        self.layers['Relu1'] = Relu()
        self.layers['pool1'] = Pooling([ppl_h=2, pool_w=2, stride=2)
        self.layers['Affine1'] = Affine(self.params['W2']
        								self.params['b2'])
        self.layers['Relu2'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W3']
        								self.params['b3']
                                        
        self.last_layer = SoftmaxWithLoss()

 

 순서가 있는 딕셔너리인 layers에 계층들을 차례로 추가합니다.

 마지막 SoftmaxWIthLoss 계층만큼은 last_layer라는 별도 변수에 저장합니다.

 이상이 SImpleConvNet의 초기화 입니다.

 

 

 이제 추론을 수행하는 predict 메서드와 손실함수의 값을 구하는 loss 메서드를 구현하겠습니다.

 

    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        return x
        
    def loss(self, x, t):
        y = self.predict(x)
        return self.last_layer.forward(y, t)

 

 이 코드에서 인수 x는 입력 데이터, t는 정답 레이블입니다.

 추론을 수행하는 predict 메서드는 초기화 때 layers에 추가한 계층을 맨 앞에서부터 차례로 forward 메서드를 호출하며 그 결과를 다음 계층에 전달합니다.

 

 손실 함수를 구하는 loss 메서드는 predict 메서드의 결과를 인수로 마지막 층의 forward 메서드를 호출합니다.

 

 즉, 첫 계층부터 마지막 계층까지 foward를 처리합니다.

 

 

 이어서 오차역전파법으로 기울기를 구하는 구현은 다음과 같습니다.

 

    def gradient(self, x, t):
        # 순전파
        self.loss(x, t)
        
        # 역전파
        dout = 1
        dout = self.last_layer.backward(dout)
        
        layers = list(self.layers.values())
        layers.reverse()
        
        for layer in layers:
            dout = layer.backward(dout)
            
        # 결과 저장
        grads = {}
        grads['W1'] = self.layers['Conv1'].dW
        grads['b1'] = self.layers['Conv1'].db
        grads['W2'] = self.layers['Affine1'].dW
        grads['b2'] = self.layers['Affine1'].dW
        grads['W3'] = self.layers['Affine2'].dW
        grads['b3'] = self.layers['Affine2'].dW
        
        return grads

 

 매개변수의 기울기는 오차역전파법으로 구합니다.

 이 과정은 순전파와 역전파를 반복합니다.

 지금까지 각 계층의 순전파와 역전파 기능을 제대로 구현했다면, 여기에서는 단지 그것들을 적절한 순서로 호출만 해주면 됩니다.

 

 마지막으로 grads라는 딕셔너리 변수에 각 가중치 매개변수의 기울기를 저장합니다.

 

 이상이 SimpleConvNet의 구현입니다.

 

 

 지금까지 살펴본 것처럼 합성곱 계층과 풀링 계층은 이미지 인식에 필수적인 모듈입니다.

 이미지라는 공간적인 형상에 담긴 특징을 CNN이 잘 파악하여 손글씨 숫자 인식에서 높은 정확도를 달성할 수 있었습니다.

 

반응형