[CS 231n] Two layer net 과제(Assignment)
포스팅을 시작하기에 앞서 수준 높은 강의와 강의 자료를 무료로 배포해주신 Stanford University CS231n 교수진께 감사의 말씀을 드립니다.
forward
온라인 강의: 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)
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를 저장하시면 됩니다.