[DL] CS231n Lecture 6: Training Neural Networks, Part I
카테고리: DL
1. Activation function
데이터 입력이 들어오면 weight와 곱해지고 활성함수(Activation function), 즉 비선형 연산을 진행한다.
sigmoid function
입력을 받아 그 값이 [0,1] 사이의 값이 되도록 한다.
문제점
-
Saturated neurons “kill” the gradients
X = -10일 때의 gradient는 0에 가까워 죽는다(의미가 없어진다). 마찬가지로 X = 10일 때도 gradient는 0에 가까워진다.
-
Sigmoid outputs are not zero-centered
backpropagation을 통해 계산을 할 때 upstream gradient x local gradient로 계산을 한다고 했는데 이 경우 local gradient \(\frac{df(activation)}{dW}\) 는 그냥 X가 된다. 그러므로 항상 upstream gradient 부호를 따라간다.
input X가 항상 양수(혹은 음수)일 경우를 생각해보면, 파라미터를 업데이트 할 때마다 다 같이 증가하거나 다 같이 감소한다. 이것의 문제는 이런 식의 gradient 업데이트는 매우 비효율적이라는 것이다.
X가 양수 음수 모두를 가지고 있으면 전부 같은 방향으로 움직이는 일은 발생하지 않는다.
-
exp() is a bit compute expensive
이 경우는 그렇게 큰 문제는 아니다. 실제로 내적 연산이 더 비싸기 때문
tanh(x)
sigmoid함수와 유사하지만 범위가 [-1,1]이다. 이를 통해 두번째 문제였던 zero-centered 문제가 해결된다. 하지만 여전히 gradient가 죽는 문제가 발생한다.
ReLU
양수의 영역에서 gradient가 죽지 않는다. (절반)
exp연산이 없고, max연산을 사용하기 때문에 sigmoid tanh보다 약 6배정도 빠르다. 하지만 ReLU의 문제점은 여전히 zero-centered output이 아니다. 그리고 음수의 영역에서는 gradient가 죽는다. 그래서 dead ReLU라는 문제를 겪을 수 있다.
dead ReLU에서는 activate가 절대 일어나지 않아 update가 안되고 active ReLU에서는 일정 부분 activate 될 수 있다.
더 흔한 경우는 Learning rate(학습률)이 지나치게 높은 경우이다. 처음에는 적절한 ReLU로 시작한다 해도 update를 지나치게 크게 해버려 W가 날뛴다면 ReLU가 데이터의 manifold를 벗어나게 된다. 그래서 처음에는 학습이 잘되다가 갑자기 죽어버리는 경우가 생기는 것이다.
Leaky ReLU
음수의 영역에서도 gradient를 갖고, 계산도 빠르다
Parametric Rectifier (PReLU)
역전파를 통해 학습되는 파라미터 \(\alpha\)를 사용한다.
Exponential Linear Units (ELU)
ReLU의 여러 장점을 가져가지만 Leaky ReLU에서 해결했던 gradient가 죽는 문제를 일으킨다 하지만 이러한 deactivation이 Leaky ReLU보다 noise에 robust하게 하다고 주장한다.
exp 연산을 해야한다는 점에서 연산량이 많아진다.
Maxout
내적연산을 진행하지 않기 때문에 선형 활성함수이다. gradient가 죽는일도(0이 됨) 없지만, 파라미터의 수가 2배가 됐다는 문제가 있다.
2. Data Preprocessing
zero-centered를 하는 이유는 앞서 살펴본 대로 입력이 전부 양수이거나 음수이면 gradient update가 한 방향으로만 진행될 수 있기 때문이다.
nomalized를 하는 이유는 모든 차원이 동일한 범위안에 있게 해줘서 전부 동등한 기여를 하게 된다.
보통 이미지의 경우 zero-centering까지만 진행을 한다. 왜냐하면 이미지는 이미 각 차원 간에 스케일이 어느정도 맞춰져있기 때문이다. 따라서 스케일이 엄청 다양한 여러 ML문제와는 달리 이미지의 경우 normalization을 엄청 잘해야할 필요는 없다.
ML에서 PCA나 whitening 같은 더 복잡한 전처리 과정이 있긴 하지만 이미지에서는 zero-mean정도만 진행하고 normalization 그 밖의 방법은 잘 안쓴다. 일반적으로 이미지를 다룰때는 굳이 입력을 더 낮은 차원으로 projection 시키지도 않는다.
CNN에서는 원본 이미지 자체의 spatial 정보를 이용해서 이미지의 spatial structure를 얻으려 한다.
normalization을 하면 좋은 이유는 손실함수가 작은 가충치 변화에도 엄청 민감하기 때문이다. 원점으로부터 멀수록 작은 움직임에도 크게 변할 수 있기 때문이라고 이해했다. 그렇기 때문에 normalization을 하고 나면 최적화가 더 쉽고 학습이 쉽다.
3. Weight Initialization
만약 가중치(Weight)가 모두 0으로 초기화(Initialization)된다면 모든 뉴런들은 같은 연산을 하고, 출력도 같고 결국 gradient도 같은 값을 갖을 것이다. 결국 가중치는 같은 값으로 업데이트 된다.
이를 해결하기 위한 첫번째 방법은 작은 임의의숫자를 사용하는 것이다.
Small Random numbers
작은 값으로 설정을 하게되면 앞의 문제였던 gradient가 같은 값을 갖는 문제는 해결될 수 있다. 하지만 W가 너무 작은 값을 갖게 되면 gradient를 구하는 backpropagation에서 문제가 발생한다.
backp의 계산은 local gradient X upstream gradient로 계산한다. 활성화 함수에 들어가는 값인 WX + b가 너무 작아진다. 그러면서 upstream gradient가 0이되는 vanish 문제가 발생한다.
Big Random numbers
그렇다면 0.01 대신 1.00을 사용하면 어떻게 될까? (tanh)
tanh의 문제는 일정 범위를 벗어나는 값들이 saturated 되는 것이었다. 즉, gradient가 0이 되면서 가중치 업데이트가 일어나지 않을 것이다.
Xavier initialization
xavier initialization은 입출력의 분산을 맞춰주는 것이다. 입력의 수가 작으면 더 작은 값으로 나눠서 더 큰값을 얻는다. 작은 입력의 수가 가중치와 곱해지기 때문에, 가중치가 더 커야만 출력의 분산만큼 큰 값을 얻을 수 있다.
하지만 이것의 문제점은 ReLU에서는 잘 동작을 안한다는 것이다. ReLU는 출력의 절반을 죽인다(음수 영역)
결국 출력의 분산을 반토막 내는것이다.
He intialization
ReLU는 음수를 0으로 보내기 때문에 분산이 절반으로 감소하는 문제가 있다. 이를 해결하기 위해 입력을 2로 나눠 사용한다.
4. Batch Normalization
Layer의 출력이 unit gaussian 이길 바란다. Batch normalization은 그렇다면 강제로 그렇게 만드는 것이다.
어떤 Layer로부터 나온 Batch 단위 만큼의 activations이 있다고 했을 때, 이 값들이 Unit gaussian이기를 원한다. 이것은 현재 Batch에서 계산한 평균과 분산을 통한 normalization으로 만들 수 있다.
가중치를 잘 초기화 시키는 것 대신에 학습 할 때 마다 각 레이어에 이런 일을 해줘서 레이어가 Unit gaussian이 되도록 한다.
평균과 분산을 상수로 가지고 있으면 미분 가능한 함수 이기 때문에 Backprop이 가능하다
D차원인 N개의 학습 데이터가 있다. 각 차원별로 평균과 분산을 계산해 Normalize한다.
이것을 FC나 Convolution Layer 후 그리고 nonlinearity 전에 넣어준다. BC는 입력의 스케일을 살짝만 조정하는 것이기 때문에 FC와 Conv 어디든 적용할 수 있다.
Conv에서 차이점이 있다면 Normalize를 차원마다 적용하는 것이 아니라 같은 Activation map에 있는 요소들은 같이 normalize 해준다.
위 수식을 활용해 Normalize된 data를 다시 복구할 수 있다. 이렇게 되면 유연성을 갖을 수 있다. normalize하는 것이 좋을 때도 있지만 항상 그런 것은 아닐 수 있다. 이러한 유연성을 통해 조금씩 scaling하거나 shifting할 수 있는 여지를 줄 수 있다.
5. Babysitting the Learning Process
Step 1: NN을 학습할 때 가장 먼저 해야하는 것은 역시 데이터 전처리이다.
Step 2 : 그다음 아키텍쳐를 선택을 한다.
앞선 강의에서 배웠던 것 처럼 가중치가 작은 값일 때 Loss가 대강 어떻게 분포해야하는지 알고 있다.
softmax classifier의 Loss는 negative log likelihood가 되어야 한다. 예를 들어 10개의 class가 있다면 Loss는 \(-\log(1/10)\)일 것이다. 이 값은 대략 2.3정도 이다.
Loss를 확인했을 때 값이 맞게 나오면 Loss가 제대로 동작하고 있는 것이다.(sanity check)
Step 3
처음시작할 때 좋은 방법은 데이터의 일부만 우선 학습시켜 보는 것이다. 데이터가 적으면 당연히 overfit가 생기고 Loss가 줄어들 것이다. 이때 regularization을 사용하지 않고 Loss가 내려가는지를 본다.
Step 4
sanity check가 끝났다면 전체 데이터 셋을 사용하고, regularization을 약간만 주면서 적절한 Learning rate를 찾는다.
Learing rate를 몇가지 정해 실험을 해본다.
Learning rate가 지나치게 작으면 gradient 업데이트가 충분히 일어나지 않게 되고 Cost가 안 변한다.
Learning rate가 지나치게 크면 Cost가 NaN으로 되면서 발산될 수 있다.
보통 learning rate는 [1e-3 … 1e-5] 값을 사용한다.
6. Hyperparameter Optimization
하이퍼파라미터를 최적화시키고 그중 가장 좋은 것을 선택하는 방법중 하나는 Cross-validation이다.
Cross-validation은 Training set로 학습하고 Validate set로 평가한다.
Step 1 : 몇번의 epoch만 거치면서 어느 정도에서 잘 동작할지 파악한다.
Step 2 : 조금더 fine하게 좁은 범위를 설정해 학습을 길게 시켜보면서 최적의 값을 찾는다. 만약 Cost가 갑자기 3배정도 커지커나 하면 뭔가 잘못되고 있는 것이므로 종료한다.
learning rate를 설정할 때는 기본적으로 gradient와 곱해지는 것이기 때문에 lr의 선택 범위를 log 스케일을 선택하는 것이 좋다.
accuracy가 높게 나오는 것들을 보면 lr가 e-04부근에 몰려있다. 이것은 좋지 않을 수 있는게 한 곳에 몰려있으면 최적의 값을 찾기 어렵다. 실제 최적 lr이 e-05 혹은 e-06에 있을 수도 있기 때문에 최적의 값이 내가 선택한 범위 중간에 나오도록 범위를 설정하는 것이 중요하다.
최적의 하이퍼파라미터를 찾는 방법으로 Grid Search라는 것도 있다. 이것은 일정 간격으로 하이퍼파라미터를 조정하는 것인데 이것보다는 random search가 더 효과가 좋다.
Loss 그래프를 통해 learning rate를 파악할 수 있다.
만약 Loss가 너무 평평하면 lr이 낮은 것이고, 발산하면 lr이 높은 것이다. 가파르게 내려가다가 정체가 생긴다면 이것 또한 lr이 높은 것이다.
위의 파란 그래프처럼 비교적 급격하게 감소하면서도 꾸준히 감소를 한다면 이것은 적절한 lr이라고 판단할 수 있다.
위 그래프와 같이 초반에 정체되어있다가 갑자기 가파르게 내려가는 경우는 초기화의 문제일 수 있다.
gradient의 backpropb가 초기에는 잘 안되다가 학습을 진행하면서 회복되는 경우이다.
만약 train_accuracy와 validation accuary가 큰 차이를 보인다면 overfit 된 것일 수 있다. 따라서 regularization을 높여야 할 수도 있다.
gap이 없다면 overfit하지 않은 것이고 capacity를 높일 수 있는 여유가 있다는 뜻이다.
가중치의 크기 대비 가중치 업데이트의 비율을 지켜볼 필요가 있다.
우선 파라미터의 norm을 구해서 가중치의 규모와 업데이트 size를 구한다. 보통은 이 ratio가 0.0001정도를 원하지만 정확한 것은 아니라 그냥 어느정도 비율인지를 파악해 살펴보면 된다.
댓글남기기