[인공지능] AI - CS231n 6강 Training Neural Networks, Part 1


cs231n 6강 youtube 강의 링크
cs231n 공개 강의자료
cs231n 과제 링크


CS231n 6강 - Training Neural Networks, Part 1

Keywords

  • Activation functions(Sigmoid, tanh, ReLU, Leaky ReLU, Maxout, ELU)
  • zero-centered / saturation
  • Data Preprocessing
  • Xavier initialization
  • Batch Normalization
  • Sanity check
  • Weight initialization
  • Regularization
  • Hyperparameter Optimization

이제 우리는 이미지를 공간 정보를 포함하여 학습할 수 있게 되었고, 이 학습을 어떻게 시키는 가를 배울 차례이다. 그렇기에 이번엔 그와 관련된 활성화 함수와 데이터 전처리에 대해 배울 것이다. 또한, 가중치 W를 효율적으로 초기화하는 방법과 Batch Normalization에 대해 배울 것이다.

1. Activation Functions

Activation function이란 input값을 다음 노드로 보낼 때 어떻게 처리해서 보낼 지를 결정해준다. 이러한 활성화 함수는 주로 비선형성을 띈 함수들이다. 그 이유는 선형함수를 사용하게 되면 여러 층을 깊게 하는 의미가 줄어들기 때문이다. 선형성이 확보된 함수들이었다면 n 개의 층을 1 개의 층으로 줄일 수 있기 때문이다.

  1. Sigmoid
    sigmoid
    • 출력값을 0에서 1 사이로 고정하는 함수이다.

하지만, 이 함수에는 3 가지 문제점이 있다.

첫째로, 기울기 소실 문제(gradient vanishing)이다.
위의 그림에서 x가 -10, 0, 10일때 어떻게 될까? -10이나 10일때는 기울기가 0에 가까워진다. 0일 때는 그나마 기울기가 제일 크다. Sigmoid를 미분하면 sigmoid(x)(1-sigmoid(x))를 얻을 수 있는데 여기에 0을 대입하면 해봐야 제일 큰 값이 0.25라는 것을 알 수 있다. (sigmoid(0) = 0.5) 즉, Backpropagation을 반복할수록 0에 가까운 수가 곱해지기 때문에 0에 수렴하게 된다.

둘째로, zero-centered가 아니다. output 값이 양수, 음수 모두 가능하는 지를 말하는데zero centered라고 왜 이름을 지었을까요.. , 이는 곧 파라미터들의 gradient가 서로 다른 부호를 가질 수 없다는 뜻이다.

왜 서로 다른 부호를 가질 수 없을까? chain rule을 생각하면 간단하다. Sigmoid 함수는 항상 양수의 출력값을 가지는데 이때 W의 gradient 값은 어떨까? dl/df * df/dwi인데 df/dwi는 x가 될 것이고 x는 항상 양수이다. 그렇기 때문에 부호는 dl/df에 의해 결정되는데 이 부호는 결국 앞선 gradient를 가져오는 것이기 때문에 부호는 항상 모두 음수이거나 모두 양수가 된다.

서로 다른 부호를 가질 수 없다면 어떤 문제가 발생할까? 특정 벡터 공간으로 gradient가 갱신되지 않기 때문에 update가 매우 느리다. 아래 그림을 보면 알겠지만 제1사분면, 제3사분면 성분으로만 업데이트가 가능해서 지그재그로 업데이트된다. 그렇기 때문에 zero-mean data가 필요한 것이다.
zig zag path

마지막으로, exp연산은 +,-와 달리 비싼 연산이라는 점이다.

위 세 가지 이유로 sigmoid는 잘 사용되지 않는다.

  1. tanh
    tanh
    • 출력값을 -1에서 1 사이로 고정하는 함수이다.
    • zero-centered하다.
    • 여전히 기울기 소실 문제가 발생한다.

그래프의 양 끝 부분을 보면 기울기가 0에 수렴하는 것을 알 수 있어 여전히 기울기 소실 문제가 발생한다는 것을 알 수 있다.

  1. ReLU(Rectified Linear Unit)
    ReLU
    • 출력이 양수인 부분에서는 더 이상 기울기 소실 문제가 없다.
    • 연산에 있어 효율적이다.
    • sigmoid나 tanh에 비해 훨씬 빨리 수렴한다. 약 6배나 빨리..
    • zero-centered하지 않다.

여전히 음수인 부분에서 기울기 소실 문제가 발생한다. 예를 들어 x가 0이하인 부분에서의 기울기그래프 상으로 0에서 기울기가 정의되진 않지만 0이라 하자는 소실되는데 이를 dead ReLU라고 한다.

dead ReLU가 발생하는 경우는 크게 2 가지인데, W의 초기화가 잘못되는 경우와 learning rate가 너무 클 때이다. 1) W의 초기화가 잘못되면 W가 train data와 멀리 떨어져서 ReLU가 활성화되지 않을 것이므로 gradient가 업데이트 되지 않을 것이다. 즉, Backpropagation이 일어나지 않을 것이다. 2) learning rate가 너무 크다면 train data에서 걸쳐 있던 적절한 ReLU도 멀리 떨어져서 dead ReLU가 될 것이다.

그래서 dead ReLU를 회피하고자 0.01과 같은 bias값을 더해서 W를 초기화하려고 했지만 딱히 효과가 있진 않았다. 쓰는 사람 있고 안쓰는 사람 있다네요.. 또, 일부만 dead ReLU에 빠져도 학습이 잘 되지 않을 것 같지만 실제론 그렇지 않다고 한다.

  1. Leaky ReLU
    Leaky ReLU
    • ReLU와 달리 기울기 소실 문제가 발생하지 않는다.
    • 연산에 있어 효율적이다.
    • sigmoid나 tanh에 비해 훨씬 빨리 수렴한다.
    • dead ReLU가 없어진다.

Leaky ReLU는 ReLU를 살짝 보완한 것이다.
cf) Parametric Rectifier(PReLU) => f(x) = max(ax, x)로, a값을 Backpropagation을 통해 학습, 결정하기 때문에 leaky ReLU보다 유연하다.

Q1. Leaky ReLU과 ReLU와 달리 죽지 않는 이유는?
Data cloud

위의 그림을 보고 이해하면 이해하기 쉽다. ReLU는 음의 영역에서 기울기 소실 문제가 있기 때문에 일정 부분에 있어 업데이트가 이루어지지 않는다. 즉, 빨간선의 화살표 반대 방향의 데이터들은 전부 0이되어 업데이트가 되지 않아 죽었다고 하는 것이다. 반면, Leaky ReLU는 전체 범위에서 기울기 소실 문제가 없기 때문에 죽지 않는다. 화살표 반대 방향으로도 값이 있기 때문에 죽지 않는다.

  1. Exponential Linear Units (ELU)
    ELU
    • zero-centered하다.
    • 0에서의 미분 불가점을 미분 가능하게 했다.
    • 음의 영역에서 기울기 소실 문제가 있지만 Leaky ReLU에 비해 noise에 약간의 강인함을 주었다.
    • exp연산이 있어 연산의 cost가 비싸다.
  2. Maxout => max(w1Tx+b1, w2Tx+b2)
    • 위와 같이 생긴 식의 최대값을 구하므로 linear regime이며 기울기 소실 문제도 없고 죽지도 않는다.
    • ReLU와 Leaky ReLU를 일반화한 식으로 연산량이 두 배가 되어 잘 사용하지 않는다.

위의 6 가지 활성함수를 배웠으나 보통은 ReLU, Leaky ReLU를 사용하면 된다. 다만 step size인 learning rate를 잘 설정해야하며 때때로 tanh, Maxout, ELU 등을 사용해볼 수 있다.


2. Data Preprocessing

학습할 때 데이터를 날 것 그대로 사용하는 경우는 드물다. 여러 이유로 약간의 가공을 거쳐서 사용하곤 한다. 일반적으론, data를 zero-centering하고 normalize하는 식으로 전처리를 해준다.

Zero-centering을 하는 이유는 앞서 왜 zero-centered가 중요한 가와 동일하다. 그렇다면 Normalize를 하는 이유는? 특정 범위 안에 값을 모아두고 싶어서인데, 학습도 더 빠르게 할 수 있고 local optimum에 빠질 가능성을 낮춰주는 장점이 있기 때문이다.

하지만 이미지 처리에 있어서 data normalize를 하지 않는다. 왜일까?
이미 모든 픽셀 값은 0~255사이의 값을 갖기 때문이다. 이미 값이 모여있으니 normalize를 해줄 필요가 없는 것이다.

또 다른 방식으로 PCA와 Whitening이 있다. 하지만 normalize와 마찬가지로 이미지에서 잘 사용되지 않는다고 한다. 왜일까? 아무래도 이미지를 저차원으로 바꿔서 학습하려는 게 아니라 이미지 데이터 자체를 Conv layer에서 필터를 통해 공간적으로 해석하려고 하기 때문이 아닐까 싶다.


3. Weight Initialization

우리가 W를 학습하기 위해 loss function, gradient descent 등 수많은 개념을 배워왔다. 그렇다면 W의 값은 어떤 값으로 초기화해야할까? 이제 W의 초기화에 대해 알아볼 차례이다.

Q1. 만약 가중치 W가 0으로 초기화되었다면 어떻게 될까?

모든 노드(뉴런)들은 같은 일을 하게 되어 의미가 없을 것이다. 모든 파라미터가 동일한 값으로 update되며 이는 곧 모든 alyer에 노드가 1개인 신경망을 훈련시키는 것과 같다.

처음 시도할만한 접근으론 그냥 가우스 분포(평균: 0, 표준편차: 0.01)를 따르는 임의의 작은 값으로 초기화하고 작은 상수를 곱해주는 것이다. 작은 상수를 곱해주는 이유는 좀 더 작은 값을 만들기 위함인데, 그래야 그나마 기울기를 소실, 폭등할(tanh / ReLU) 여지를 줄일 수 있기 때문이다. 하지만 이 방법은 작은 네트워크에는 통하지만 깊은 네트워크에는 통하지 않는다.

WI Example
각 층에 500개의 뉴런을 가지며 10개의 층으로 이루어진 네트워크를 예시로 들어보자. 활성화 함수로 tanh 함수를 사용했다.

WI graph
각 layer에서 나온 값들의 분포가 처음에는 가우스 분포를 따르지만 점점 0에 수렴한다. 이는 tanh를 사용했기 때문이다. 이렇게 되면 update가 잘 되지 않는다.

WI graph
이번엔 1 대신 0.01을 넣었더니 출력값이 전부 1과 -1이 된다. tanh에서 1과 -1값에 해당하는 것들은 기울기가 전부 0이기 때문에 update가 되지 않는다. 그럼 뭐 어쩌라고!!! 그렇기 때문에 W의 초기화를 어떻게 하느냐가 아주 중요한 것이다. 너무 작으면 collapse되고 너무 크면 explode하기 때문이다.

이제 정답을 알려줄 시간이다. 2010년에 Xavier initialization이라는 것이 나타났다. 앞선 두 방식은 W에 고정값으로 1이나 0.01을 곱해주었다면 이번엔 그 대신 가우시안 분포에서 랜덤으로 뽑은 값을 입력의 수로 스케일링해준다. 이게 무슨말이냐면 결국, 입력의 수가 작으면 그 수로 나누게되니 큰 값을 얻게 되고 반대로 크면 작은 값을 얻게 된다는 것이다. 이를 통해 적절한 W를 얻게 된다.

그러나 이게 매번 정답은 아니다. 활성화함수가 ReLU라면 dead ReLU가 발생하여 잘 동작하지 않기 때문이다. ReLU의 출력값 중 절반이 0이 되기 때문에 출력값의 분산도 절반이 되고 그에 따라 W가 매우 작아져서 0에 수렴하기 때문이다. 이를 근거로 나누어주는 수를 입력의 수/2로 바꾸어 주었더니 나아졌다. 아래 그래프를 보면 마지막 layer에도 출력값이 잘 살아있는 것을 확인할 수 있다. WI graph

4. Batch Normalization

활성화 함수, learning rate, small number initialization 등으로 위에서는 열심히 Weight을 잘 초기화하려고 하는데 이 짓을 안해도 되는 방법이 있다. 바로 Batch Normalization이다. 이는 기본적으로 학습 시 기울기 소실 문제가 일어나지 않도록 한다. 어떻게 가능하게 할까?

바로 각 활성화 함수 layer에 들어가는 input 자체에 손대는 것이다. 현재 batch에서의 평균과 분산을 이용하여 각 층마다 가우스 분포(평균: 0, 표준편차: 1)를 따르게끔 바꿔주는 것이다. 이는 또한 미분 가능한 함수이므로 Backpropagation에도 문제가 없다. 어떻게 평균과 분산을 이용하느냐고?

BN

  1. 먼저 평균과 분산을 구한다.
  2. N*D의 input이 들어오면 이를 normalize한다. 평균값을 빼서 평균을 0으로 만들고, 분산으로 값을 나눠서 분산을 1로 만들어준다.
  3. FC나 Conv layer 다음과 비선형 함수(활성화 함수) 이전에 삽입한다.

과연 이러한 unit gaussian이 적합한지에 대해 따져보아야 하는데 이 또한 학습에 의해 결정 가능하다.

BN gamma beta
Normalize 이후에 감마나 베타 값 같은 하이퍼파라미터를 조정하여 batch normalization을 할지 안할지 결정한다. 감마는 normalizing scale을 조절하고 베타는 shift를 조절해주는 파라미터이다.

BN formula
결과적으로, Batch normalization은 mini-batch마다 평균과 분산을 구하고 normalize를 거친 다음 scale이나 shift를 얼마나 할 지를 결정하여 값을 정하게 된다. 이를 통해, learning rate의 범위를 키울 수 있고 초기화에 있어 강인해지고 Regularization같이 작동한다. 평균과 분산으로 normalize해주기 때문


5. Babysitting the Learning Process

  1. 데이터를 전처리한다. 주로 zero centering.
  2. 아키텍쳐를 고른다. (Hidden layer를 어떻게 구성할 지)
  3. loss값이 잘 나오는 지 확인한다. (Sanity check) sanity check이 뭐였더라..?
  4. 학습시켜본다. (일부의 데이터만을 사용해서 Train accuracy 확인)
  5. 적절한 Regularization과 learning rate로 loss 값 최소화

6. Hyperparameter Optimization

  1. Cross-validation strategy
    Finer search
    넓은 범위에서 좁은 범위로 줄여나가며 적절한 값을 찾아간다. 로그값을 취해주어 값의 범위를 줄여준다. 이제 최적화를 해주어야 한다. 53%까지 값이 올라가지만 best가 아닐 수 있다. 그 이유는 놓친 부분이 있을 수 있기 때문이다.
    Finer search
    위와 같이 빨간 선이 learning rate의 범위인데 현재 범위에서 도출된 좋은 결과값들이 상대적으로 경계에 치우쳐져있는 것을 확인할 수 있다. 그렇기 때문에 청록색 선으로 범위를 확장해주는 것이 좋다. 즉, 좋은 값들을 범위의 중간이 되게 끔 옮겨주는 것이다.

  2. Random search / Grid search
    Random search vs Grid search
    grid search는 적절한 값을 놓칠 수 있기 때문에 random search가 더 좋다. 그렇기에 보통 random search를 사용한다. 위 그림을 보면 왜 그런지 알 수 있다.

하이퍼파라미터의 예시) 네트워크 아키텍쳐, learning rate, decay schedule, update type, Regularization 등

learning rate를 어떻게 고르느냐에 따라 loss는 천차만별이다. 다음 그래프를 보자.
loss Visualization
적절한 값만이 효율적으로 loss를 낮출 수 있다.

Bad init wrt loss
어느 시점까지는 loss가 낮춰지지 않다가 확 낮춰지는 모양을 볼 수 있는데 이는 잘못 초기화했다는 반증이다. 적절한 값을 찾지 못해서 학습이 되지 않다가 갑자기 어느 지점에서 학습이 되어버린 것이기 때문이다.

Visualize the accuracy
만약, train set의 정확도와 validation set의 정확도가 큰 차이를 보인다면 overfitting하고 있단 뜻이며, 차이가 없다면 모델의 capacity를 늘릴 수 있는 여유가 있으므로 늘리면 된다.

Update scale
업데이트의 크기에 대해 어떻게 감 잡을 수 있을까? 파라미터의 norm을 구해 W의 규모를 구하고 업데이트의 사이즈 또한 norm으로 구해주어 비율을 계산하면 알 수 있다. 대략 0.001 정도이면 바람직한 업데이트의 크기라고 볼 수 있다. 디버깅용으로 사용하면 좋을 듯 싶다.