[CS 231n] Two layer net 과제(Assignment)

포스팅을 시작하기에 앞서 수준 높은 강의와 강의 자료를 무료로 배포해주신 Stanford University CS231n 교수진께 감사의 말씀을 드립니다. 
온라인 강의: https://www.youtube.com/watch?v=vT1JzLTH4G4&list=PLC1qU-LWwrF64f4QKQT-Vg5Wr4qEE1Zxk 
강의 자료: https://cs231n.github.io


* 블로그 작성자 github 주소: https://github.com/withAnewWorld/JamesHanamura

Fully connected layer 구조

input -> hidden layers(activation function cf) relu, sigmoid 등) -> loss function(svm, softmax 등)

Assignment 구조

작성되어 있는 부분(파란색), 과제로 주어진 부분(빨간색)

    - 데이터 불러오기

    - 상대 오차 함수

    - layers
        - affine_forward & backward
        - relu_forward & backward
        - svm_loss
        - softmax_loss

    - Debugging strategy(gradient check, relative error) 

      cf) layer_utils(max(0, wx+b) forward & backward) - 자동화

    - fc_net
        - w1, b1, w2, b2 초기화
        - forward
            - fully connected two layer
            - loss function
        - backward(gradient)

    - Debugging strategy(gradient check, relative error, visualize) 

    - API
        - train 
        - SGD(Stochastic Gradient Descent)

     - Test image 예측


Affine forward & backward

forward

    1. inputs
        x: shape = (N, d_1, d_2, ... , d_k)
        w: shape = (D, M)
        b: shape = (M, )
    2. return
        out: wx+b
        cache: (x, w, b)
    3. 목적
        wx+b를 계산하여 out 변수에 저장하고 x, w, b를 cache에 저장.
    4. algorithm
        1) x.dot(w)를 계산하기 위해 x의 shape을 적절히 바꿔준다. 
            이 때, cache에 원래 데이터 x를 반환해야 하므로 x의 shape을 바꾸어 저장하지 말도록 한다. 
        2) out = x.dot(w) +b, cache= (x, w, b)





backward

$db = {\partial(Wx+b) \over \partial(Wx+b)}*{\partial(Wx+b) \over \partial(b) }={\partial(Wx+b) \over \partial(Wx+b)}*1$

$dWx=d(Wx+b)$

$dW = {\partial(Wx+b) \over \partial(Wx+b)}*{\partial(Wx+b) \over \partial(W)}={\partial(Wx+b) \over \partial(Wx+b)}*x$

$dx= {\partial(Wx+b) \over \partial(Wx+b)}*{\partial(Wx+b) \over \partial(x)}={\partial(Wx+b) \over \partial(Wx+b)}*W$ 
위의 수식을 차원에 맞게 곱하면 dx, dw, db를 얻을 수 있다. 


먼저,  dW의 차원: (D,M)이므로 dW= dx.T.dot(d(Wx+b)) (dx.T: D*N), d(Wx+b): N*M)
dx의 차원: (N, D)이므로 dx= d(Wx+b).dot.(W.T) (d(Wx+b): N*M, W.T: M*D)
db의 차원: (M,)이므로 db= d(Wx+b).T.dot(np.ones(N)) (d(Wx+b).T: M*N, np.ones(N): N)

주의 해야할 점은 x의 원래 차원이 (N, d_1, d_2, ..., d_k)이므로 이에 맞게 다시 차원을 변경해야 한다.


relu_foward & backward

    forward






   backward

${\partial max(0,x) \over \partial x} = 1 ( x>0)$이므로 $x<0$일 때는 $dx=0$, $x>0$일 때는 $dout$을 반환하면 된다. ($\because dx=dout*1, x>0$)





svm_loss

    loss

    $loss_{i} = max(0, s_{j}-s_{yi}+\Delta)$ 이므로
    1) $s_{j}-s_{yi} (s_{yi}= x[range(x.shape[0]), y]$
    2) $+\Delta$
    3) $s_{yi}=0$
    4) $max(0, s_{j}-s_{yi}+\Delta)$
    5) $sum(loss_i)/n$

    gradient

${\partial (SVM) \over \partial x} = {\partial (s_{j}-s_{yi}+\Delta) \over \partial x} \ (when \ s_{j}-s_{yi}+\Delta>0) \\ \therefore \ {\partial (SVM) \over \partial x}= {\partial (SVM) \over \partial x_{j}}, {\partial (SVM) \over \partial x_{yi}} \\ \ {\partial (SVM) \over \partial x_{j}} =+1,  \ {\partial (SVM)\over \partial x_{yi}}=-1$



soft max_loss

    $soft max= -log(\frac{e^f_{y}}{\sum e^{f_{j} }})$

    loss

    1) soft max의 경우 score가 지수로 올라가기 때문에 over flow를 막기 위해 행의 최대 값을 빼줘야 합니다. 과제에서는 w가 적게 초기화되기 때문에 over flow가 생기지 않지만 평상시에 습관을 잘 들여놔서 코드를 작성하는 것을 추천합니다.
    $x -=np.max(x, axis=1, keepdims=True)$

    2) $exp(x)$

    3) $loss_i = -log(e^{x_{j}}/\sum e^{x_{i}} )$

    4) $sum(loss_i)/n$

    gradient

    ${\partial(softmax) \over \partial(x)} = {\partial \over \partial x}*(-f_{yi} + log({\sum e^{f_{j}}}))$

    ${\partial(softmax) \over \partial x_{yi} } = -1+ {e^{ f_{yi} } \over \sum e^{ f_{j} } },  {\partial(softmax) \over \partial x_{i}}={ e^{ f_{i} } \over \sum e^{ f_{j} } }$

    $dx = dx/n$


layer_utils


    fully connected layer에서 자주 쓰이는 연산인 max(0, wx+b)의 forward와 backward를 자동으로 계산해 주는 함수입니다.
    * affine_relu_forward
    \[{a= wx+b}\]

    \[fc_cache = (x, w, b)\]

    \[out = max(0, wx+b)\]

    \[relu_cache = wx+b\]
 
    *affine_relu_backward
    \[da={d(max(0, wx+b)) \over d(wx+b)}\]

    \[dx= {da \over dx}\]

    \[dw= {da \over dw} , db = {da \over db}\]

fc_net

    1) init
        W1, b1, W2, b2를 초기화 하여 dict형식인 self.params에 저장해야 합니다. 이 때, W1, W2는 np.random.normal 함수를 이용하여 std=weight_scale인 정규분포에서 추출하여야 하고 b1, b2는 0으로 초기화해야 합니다.


    2) loss
        - fully connected layer
            1) w1x+b1
            2) max(0, w1x+b1)
            3) w2max(0, w1x+b1)+b2
         - loss function(soft max)
           
    3) gradient(backpropagation)

SGD(Stochastic Gradient Descent)


Cross validation

    learning rate, epoch, hidden size, regularization의 hyper parameters을 이용하여 two_layer_net의 가장 좋은 성능을 뽑아내는 파트입니다. 강의에서 learning rate가 가장 우선적으로 생각해야 할 변수라고 설명했으므로 learning rate를 먼저 초기화 해줍니다. 
random.uniform 함수를 통해 $10^{(-5, -1)}$을 난수 생성하여 가장 좋은 성능을 가질 것으로 기대되는 learning rate를 추출합니다. 이 때 num_epoch의 개수를 5정도로 줄여 빠르게 확인할 수 있습니다.

그 다음으로 이전 과제들에서 cross validation을 하듯 반복문을 통해 가장 좋은 two layer network를 저장하시면 됩니다.


이 블로그의 인기 게시물

[CS231n] Features 과제(Assignment)

[minGPT]play_image 설명

[CS231n] lecture 4. backpropagation 강의 요약