Deep learning/모델 구현

18. CNN(5) - CNN 구현하기

jwjwvison 2021. 4. 25. 11:26

이 포스팅은 밑바닥부터 시작하는 딥러닝을 공부하고 정리한것 입니다.


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_size=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(pool_output_size,hidden_size)
        self.params['b2']=np.zeros(hidden_size)
        self.params['W3']=weight_init_std * np.random.randn(hidden_size,output_size)
        self.params['b3']=np.zeros(output_size)

 학습에 필요한 매개변수는 1번째 층의 합성곱 계층과 나머지 두 완전연결 계층의 가중치와 편향이다. 이 매개변수들은 인스턴스 변수 params 딕셔너리에 저장한다. 1번째 층의 합성곱 계층의 가중치를 W1, 편향을 b1, 2번째 층의 완결연결 계층의 가중치와 평향을 W2,b2, 마지막 3번째 층의 완전연결 계층의 가중치와 편향을 W3와 b3라는 키로 각각 저장한다.

 

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

        self.layers=OrderDict()
        self.layers['Conv1']=Convolution(self.params['W1'],
                                        self.params['b1'],
                                        conv_param['stride'],
                                        conv_param['pad'])
        self.layers['Relu1']=Relu()
        self.layers['Pool1']=Pooling(pool_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()

 마지막 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)

 

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

        def gradient(self,x,t):
            #순전파
            self.loss(x,t)
            
            #역전파
            dout=1
            dout=self.last_layer.backward(dout)
            
            layers=list(self.layers.values())
            layers.revrse()
            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'].db
            grads['W3']=self.layers['Affine2'].dw
            grads['b3']=self.layers['Affine2'].db
            
            return grads

 매개변수의 기울기는 오차역전파법으로 구한다. 이 과정은 순전파와 역전파를 반복한다. 지금까지 각 계층의 순전파와 역전파 기능을 제대로 구현했다면, 여기에서는 단지 그것들을 적절한 순서로 호출해주면 된다. 마지막으로 grads라는 딕셔너리 변수에 각 가중치 매개변수의 기울기를 저장한다. 이상이 SimpleConvNet의 구현이다.