cs231n 과제2 Q3- Dropout

이준학·2024년 7월 17일

cs231n 과제

목록 보기
8/15

  Q3는 dropout을 구현해보는 과제이다. 이미 구현해놓은 fc_net 파일에 dropout이 적용되도록 하는 거라, 그렇게 헷갈릴 것은 없다. 그러나 언제나와 같이 나는 헷갈렸다. 그것도 아주 오래. 별거 아닌걸로 일주일을 붙잡고 있었고, 심지어 참고로 읽어본 논문도 강의에서 추천한 것과 다른 걸 읽어서 꽤 고생했다. 그래도 끝까지 남의 코드를 그대로 가져오지 않은 점은 잘한 것 같다. 딴소리는 이만하고 과제 내용을 살펴보자.

1. fc_net.py 최종

  이번 과제까지 해서 fc_net.py 파일은 더 이상 건드리지 않아도 되는 것 같다. 때문에 지금까지 내가 나름 정리해서 구현한 코드를 공유한다. 과제에서 채우라고 하는 부분들만 정리하겠다.

####### Initialization ########
        tmp_dim=input_dim
        for i in range(self.num_layers):
          if i==self.num_layers-1:
            self.params['W'+str(i+1)]=np.random.randn(tmp_dim,num_classes)*weight_scale
            self.params['b'+str(i+1)]=np.zeros(num_classes)

          else:
            if normalization=='batchnorm':
              self.params['W'+str(i+1)]=np.random.randn(tmp_dim,hidden_dims[i])*weight_scale
              self.params['b'+str(i+1)]=np.zeros(hidden_dims[i])
              self.params['gamma'+str(i+1)]=np.ones(hidden_dims[i])
              self.params['beta'+str(i+1)]=np.zeros(hidden_dims[i])
              tmp_dim=hidden_dims[i]

            elif normalization=='layernorm':
              self.params['W'+str(i+1)]=np.random.randn(tmp_dim,hidden_dims[i])*weight_scale
              self.params['b'+str(i+1)]=np.zeros(hidden_dims[i])
              self.params['gamma'+str(i+1)]=np.ones(hidden_dims[i])
              self.params['beta'+str(i+1)]=np.zeros(hidden_dims[i])
              tmp_dim=hidden_dims[i]

            else:
              self.params['W'+str(i+1)]=np.random.randn(tmp_dim,hidden_dims[i])*weight_scale
              self.params['b'+str(i+1)]=np.zeros(hidden_dims[i])
              tmp_dim=hidden_dims[i]

####### Forward pass ########
        cache={}
        do_cache={}
        out=X
        for i in range(self.num_layers):
          W=self.params['W'+str(i+1)]
          b=self.params['b'+str(i+1)]

          if i == self.num_layers-1:
            out, cache[i] = affine_forward(out,W,b)

          else:  
            if self.normalization == 'batchnorm':
              gamma=self.params['gamma'+str(i+1)]
              beta=self.params['beta'+str(i+1)]
              bn=self.bn_params[i]
              out,cache[i]=affine_batchnorm_forward(out,W,b,gamma,beta,bn)

            elif self.normalization=="layernorm":
              gamma=self.params['gamma'+str(i+1)]
              beta=self.params['beta'+str(i+1)]
              bn=self.bn_params[i]
              out,cache[i]=affine_layernorm_forward(out,W,b,gamma,beta,bn)

            else:
              out, cache[i] = affine_relu_forward(out,W,b)
            
            if self.use_dropout:
              out, do_cache[i] = dropout_forward(out, self.dropout_param)
         
        scores=out

####### Backward pass #######
        weight_sum_squared=0
        for i in range(self.num_layers):
          weight_sum_squared+=np.sum(np.square(self.params['W'+str(i+1)]))

        loss,dx=softmax_loss(scores,y)
        loss+=self.reg*0.5*weight_sum_squared

        for i in reversed(range(self.num_layers)):
          if i == self.num_layers-1:
            dx, dW, db = affine_backward(dx,cache[i])# last layer doesn't need relu.
            grads['W'+str(i+1)] = dW+self.reg*self.params['W'+str(i+1)]
            grads['b'+str(i+1)] = db
            
          else:
            if self.use_dropout:
              dx = dropout_backward(dx, do_cache[i])

            if self.normalization == 'batchnorm':
              dx, dW, db, dgamma, dbeta = affine_batchnorm_backward(dx,cache[i])
              grads['W'+str(i+1)] = dW+self.reg*self.params['W'+str(i+1)]
              grads['b'+str(i+1)] = db
              grads['gamma'+str(i+1)] = dgamma
              grads['beta'+str(i+1)] = dbeta

            elif self.normalization=="layernorm":
              dx, dW, db, dgamma, dbeta=affine_layernorm_backward(dx,cache[i])
              grads['W'+str(i+1)]=dW+self.reg*self.params['W'+str(i+1)]
              grads['b'+str(i+1)]=db
              grads['gamma'+str(i+1)]=dgamma
              grads['beta'+str(i+1)]=dbeta

            else:
              dx, dW, db = affine_relu_backward(dx,cache[i])
              grads['W'+str(i+1)] = dW+self.reg*self.params['W'+str(i+1)]
              grads['b'+str(i+1)] = db

  내가 이 부분에서 실수한 것은 backward pass의 for ~ reversed 문에서 last layer일 때의 코드이다. 처음에는 affine_relu_backward를 썼었다. 그러나 원래 last layer에는 affine만 적용해야 하기 때문에 affine_backward로 바꿔야 했다. 실제로 relu까지 같이 쓴다면 모델의 training accuracy와 validation accuracy가 0.2까지 올라갔다 하락하는 추세를 보였다.
그 밖에 dropout을 구현하는 부분은 너무 간단해서 어려울 것은 딱히 없었다. dropout 논문을 읽고 리뷰를 해볼 필요는 있을 것 같다.

내 풀이 링크:

https://github.com/danlee0113/cs231n

profile
AI/ Computer Vision

0개의 댓글