본문 바로가기
ML & DL/CS231n (Stanford Univ.)

[CS231n] Lecture 7 | Training Neural Networks II

by 남르미누 2020. 11. 28.

< Fancier optimization >

 

지난 강의를 돌이켜보면

Neural network에서 가장 중요한 것은

바로 최적화 문제였다.

 

vanilla gradient descent를 하게되면 위 식처럼 weight를 초기화 해준다.

여기서 batch단위로 끊어서 한게 SGD이다.

 

미니 배치 안에서 데이터 loss를 계산하고,

그리고 gradient의 반대 방향을 이용해서

파라미터 벡터를 업데이트 시켜준다.

 

그런데 SGD의 문제점이 있다.

 

 

손실함수의 모양에 따라 영향을 많이 받는다.

 

위 그림처럼 타원 모양을 갖게 되면 저 빨간색 점에서 스마일표시까지 어떻게 찾아가게 될까?

위의 경우 loss가 수직 방향의 가중치 변화에 훨씬 더 민감하게 반응하여서

빨간색 선처럼 gradient의 방향이 매우 크게 튀면서 지그재그 형태로 지점을 찾아가게 된다.

가로 방향의 가중치는 느리게 변하는 반면에 수직 방향의 가중치가 빠르게 변화하기 때문이다.

이러면 매우 느려진다는 단점이 있다.

 

불균형한 방향이 존재한다면 SGD는 잘 동작하지 않을 것이다.

(파라키터의 수가 많으면 이런 불균형의 발생비율이 상당히 높다.)

 

 

Local minima & saddle point 문제도 있다.

 

Local minima는 기울기가 0이 되어버리니까 찾은줄 알고 중간에 멈춰버리는 것이다.

Saddle point도 순간적으로 기울기가 0에 가까운 지점이 있기 때문에 멈춰버릴 수도 있는 것이다.

 

보통 고차원에서는 saddle point가 더 일반적으로 발생한다.

 

 

미니배치를 가지고 업데이트 하는데, 이는 매번 정확한 gradient를 얻을 수가 없다는 것을 의미한다.

대신에 gradient의 부정확한 추정값만을 구할뿐이다.

 

즉, 개선점이 필요하다.

어떻게? 기울기가 0인 지점이 나와도 멈추지 않는 힘이 필요하다.

 

 

이 문제를 해결하는 방법이 바로 SGD에 momentum term을 추가하는 것이다.

 

쉽게 이야기해서 가속도를 주는 것이다.

즉, 기울기가 0인 지점이 나와도 가속도로 인해 게속 갈 수 있게 하는 것이다.

 

위의 식에서 vx가 velocity라고 보면 된다.

rho는 마찰계수라고 생각하면 된다.

즉, 너무 빠르게 가지 않도록 일종의 마찰을 주는 것이다.

(rho는 보통 0.9~0.99를 준다고 한다.)

 

이를 통해 gradient vector 방향 그대로 가는 것이 아니라,

velocity vector의 방향으로 나아가게 된다.

 

 

위의 파란색 선과 같이 부드럽게 이동하는 것을 확인할 수 있다.

 

공이 굴러가는 것과 같이 속도로 생각하면 gradient가 0이어도 충분히 움직일 수 있다.

그 덕분에 local minima와 saddle point를 극복할 수 있게 되고 계속해서 내려갈 수 있게 된다.

 

모멘텀을 추가함으로써 속도가 생기면 노이즈가 평균화되어 버리는 것이다.

 

 

현재 gradient 방향이 붉은색, 속도 vector는 초록색을 의미한다.

actual step은 이 둘의 가중평균으로 구할 수 있다.

 

Nesterov Momentum이라는 것도 있다.

이는 계산하는 순서를 조금 바꾼 것이다.

 

기존의 SGD 모멘텀은 현재지점에서 gradient를 계산한 뒤에 velocity와 섞어준다.

Nesterov 모멘텀은 먼저 velocity 방향으로 움직이고 그 지점에서 gradient를 계산한다.

그리고 다시 원점으로 돌아가서 둘을 합치는 것이다.

velocity의 초기값은 0으로 둔다.

 

Nesterov 모멘텀은 convex 최적화에서는 성능이 뛰어나지만

NN과 같은 non convex에서는 그러지 못한다.

(convex function이 optimal한 값을 찾기 쉽기 때문)

 

 

기존의 모멘텀과는 저 파란색 부분이 다르다.

파란색 부분이 뜻하는 것은 미리 velocity 방향을 예측해서 gradient를 구해준다는 의미이다.

 

위처럼 수식적인 부분에서는 필자 또한 이해하지 못한 부분이 많아 넘어가도록 하겠다.

 

이 그림을 보면 nesterov가 잘 동작한 것으로 나오는데

실제로는 거의 이렇지 않다고 한다.

 

 

AdaGrad(아다그라드)라는 방법도 있다.

 

위 방법은 각각의 매개변수에 맞춤으로 갱신을 해주는 알고리즘이다.

훈련도중 계산되는 gradient를 활용하는 방법이다.

여기서 A는 adaptive인데 적응적으로(?) 학습률을 조정하는 것이다.

 

velocity term 대신에 grad squared term을 사용한다.

학습 도중에 계산되는 gradient에 제곱을 해서 계속 더해준다.

업데이트 할 때는 update term을 앞서 계산한 gradient 제곱근 항으로 나눠준다.

 

그러다보니까 분모값이 커지기 때문에 step을 진행할수록 값이 작아지게 된다.

그만큼 처음에 올바른 지점으로 접근할 때 속도가 빨랐다가 점차 속도가 느려진다는 것이다.

즉, 업데이트 속도가 느려지는 것이다.

 

convex할 때는 minimum에 서서히 속도를 줄여서 수렴하면 좋다.

하지만 non convex할 때는 saddle point에 걸려서 멈출 수도 있어서 문제가 된다.

즉, 업데이트가 되지 않는 것이다.

(NN을 학습시킬 때는 AdaGrad를 잘 사용하지 않는다고 한다.)

 

하여 이러한 문제점의 해결책으로 RMSProp이 나오게 된다.

 

RMSProp은 AdaGrad의 gradient 제곱항을 그대로 사용한다.

하지만 이 값들을 누적만 시키는게 아니라 파란색 상자와 같이 decay_rate를 곱해준다.

 

보통 decay_rate는 보통 0.9 또는 0.99를 사용한다.

그리고 현재 gradient 제곱은 (1-decay_rate)를 곱해주고 더해준다.

 

이는 adagrad와 매우 비슷하기에 step의 속도를 가속/감속하는 것이 가능하다.

이를 통해 속도가 줄어드는 문제를 해결하였다.

 

위 방법들을 비교하는 그림이다.

RMSProp이 우리가 원하는 이상적인 방향으로 가는 것을 확인할 수 있다.

 

여기까지 우리는 모멘텀을 봤다. 가속도를 이용한다.

AdaGrad도 봤다. 이에 대한 대안으로 RMSProp을 사용한다.

 

이 둘은 일종의 모멘텀 계열과 Ada 계열로 나뉜다.

 

이 두 개를 합친 것이 나오는데 그게 바로 Adam(아담)이다.

 

아담은 first moment와 second moment를 이용해서 이전의 정보를 유지시킨다.

 

빨간색 상자(first)는 gradient의 가중합이다.

파란색 상자(second)는 AdaGrad나 RMSProp 처럼 gradients의 제곱을 이용하는 방법이다.

마치 모멘텀과 RMSProp을 합친 것과 같이 보인다.

 

근데 초기 step에서 문제가 발생한다고 한다.

 

식을 보면 first_moment와 second_moment가 0이다. 근데 second_moment를 1회 update하고 났을 때 beta2는 decay_rate이니까 0.9 또는 0.99로 1에 가까운 수이다. 그렇기 때문에 1회 update 이후에 second moment는 여전히 0에 가깝다. 이후 update step에서 second_moment로 나누게 되는데 나눠주는 값이 작다보니까 분자가 커져서 값이 튈 수도 있다고 한다. 값이 크면 step이 커져서 이상한 곳으로 튀어버릴 수도 있다.

 

 

그래서 이를 해결하기 위해 보정항을 추가한다.

(1e-7는 나누는 값이 0이 되는 것을 방지한다.)

 

first / second moment를 update하고 현재 step에 맞는 적절한 bias를 넣어줘서 값이 튀지 않게 방지하는 것이다.

 

그림에서 보는 것과 같이 Adam이 효과가 좋고 실제로도 많이 사용한다고 한다.

 

 

위에서 본 방법 모두 learning rate를 갖고있다.

learning rate의 하이퍼 파라미터 값을 찾는 것은 쉽지않다.

 

learning rate를 설정할 때, 다양한 방법이 있다.

Decay learning rate 같은 경우 처음에 learning rate를 높게 설정하고 학습이 진행될수록 점점 낮추는 것이다.

 

 

위의 내용은 ResNet 논문에서 나온 내용이다.

step decay learning rate 전략을 이용해서 loss를 나타낸 것이다.

평평해지다가 내려가는 구간은 learning rate를 낮추는 구간이다.

learning rate decay는 adam보다는 momentum에서 자주 사용한다고 한다.

보통 학습초기에는 learning rate decay가 없다고 생각하고 learning rate를 잘 선택하는 것이 중요하다고 한다.

decay없이 하다가 필요한 구간이 어디인지 고려해보는 것이 좋다고 한다.

 

 

지금까지 배운 것은 모두 1차 미분을 활용한 최적화이다.

 

 

2차 근사의 정보를 추가적으로 활용하는 방법이 있다.

이를 이용하면 minima에 더 잘 근접할 수 있다.

이를 Newton Step이라고 한다.

 

2차 미분값들로 구성된 행렬인 Hessian matrix를 계산한다.

이 hessian matrix의 역행렬을 이용하게 되면

실제 손실함수의 2차 근사를 이용해 minima로 곧장 이동할 수 있을 것이다.

 

 

기존과는 다르게 learning rate가 존재하지 않는다.

하지만 2차 근사도 완벽하지 않기 때문에 결국엔 필요하다.

하지만 NN에서는 사용 불가하다.

 

Hessian matrix는 NxN matrix이다.

(N : network의 파라미터 수)

 

그래서 실제로는 hessian을 근사시켜서 사용하는 방법을 택한다. (L-BFGS)

 

 

정리하자면,

 

Adam이 가장 좋은 선택이고, full batch이라면 L-BFGS도 좋은 선택이 될 수도 있다.

 

위 모든 것은 training error를 줄이고, 손실함수를 최소화 시키기 위한 방법이었다.

 

 

우리는 loss를 줄이면서 동시에 train과 val의 격차를 좁혀야한다.

 

이게 넓어지면 넓어질수록 오버피팅이 된다는 것이기 때문이다.

 

우리는 이처럼 loss를 줄여서 손실함수를 최소화 시키기 위해서 optimization 알고리즘을 사용해 과정을 거쳤다.

 

최적화를 끝마친 상황에서 한 번도 보지 못한 데이터에서의 성능을 올리기 위해서는 어떻게 해야할까?

 

 

가장 빠르고 쉬운 방법은 앙상블이다.

다수개의 모델을 만들고 이들의 평균을 이용하는 방법이다.

(나중에 90% 이상대로 가면 1~2% 올리는게 쉽지 않은데 이럴때 보통 앙상블을 많이 사용한다고 한다.)

 

 

다른 방법으로 모델을 독립적으로 학습시키는게 아니라 학습 도중 중간 모델들을 저장(snapshot)하고 앙상블로 사용할 수 있다고 한다. 그리고 test때에는 여러 snapshots에서 나온 예측값들을 평균을 내서 사용한다.

 

여기서 스냅샷은 구간을 정해놓은 지점이다. 훈련을 하는데 10개의 체크포인트를 두어서 10번째마다 새로 하겠다라는 식의 구간이라고 생각하면 된다. 이게 앙상블을 사용하면 모델을 여러 개 만들기 때문에 그만큼 시간 소모가 든다. 그 방법 대신에 한 모델 안에서 10개의 구간을 두고 마치 앙상블처럼 하겠다는 것이다.

 

위의 슬라이드에서 빨간색을 보면 train loss가 낮아졌다가 갑자기 올라가고 그러는데

이게 어느 지점에서 learning rate를 엄청 낮췄다가 높였다가를 반복하여

손실함수가 다양한 지역에 수렴할 수 있도록 하는 것이다.

 

이러한 앙상블 기법으로 모델을 한번만 train 시켜도 좋은 성능을 얻을 수 있다고 한다.


< Regularization >

 

그렇다면 앙상블은 모델을 여러개 만들기 때문에 별로 효율적이지 않다고 하는데

앙상블을 사용하지 않고 모델 성능을 향상시킬 수 있는 방법은 무엇이 있을까?

 

바로 regularization을 사용하는 것이다.

 

단일 모델의 성능을 올리는 것이 우리가 원하는 것이다.

모델에 어떤 것을 추가하여 training data에 fit하는 것을 막아준다.

 

 

앞에서 L1과 L2에 대해서 배웠지만 뉴런 네트워크에서 실제로는 잘 사용하지 않는다고 한다.

 

 

그래서 사용하는 Regularization이 바로 dropout이다.

 

forward pass 과정에서 일부 뉴런을 0으로 만드는 것이다.

오로지 뉴런의 일부만 사용하고 있다.

 

forward pass 반복마다 그 모양은 계속 바뀐다.

현재의 activatons의 일부를 0으로 만들어 다음 레이어의 일부가 0과 곱해지게 하는 것이다.

 

 

특징은 feature들 간의 "상호작용"을 방지하는 것이다.

이후에 모델이 고양이라고 예측할 때 다양한 features를 골고루 이용할 수 있도록 한다.

따라서 dropout이 오버피팅을 어느정도 막아준다.

단일 모델로 앙상블 효과를 가질 수 있다.

dropout은 아주 거대한 앙상블 모델을 동시에 학습시키는 것과 같다.

즉, forward pass마다 dropout을 랜덤하게 하니까

forward pass마다 마치 다른 모델을 만드는 것처럼 효과가 나오게 될 수 있다.

 

 

z는 random이다. Test time에 임의의 값을 부여하는 것은 좋지 않다.

 

 

dropout = 0.5로 학습시킨다고 생각해보자.

 

4가지 경우의 수가 존재하고, 그 값들을 4개의 마스크에 대해 평균화 시켜준다.

 

이 부분에서 train/test 간 기대값이 서로 상이하다.

test가 train의 절반밖에 되지 않는다.

 

이를 해결하기 위해 dropout probability를 네트워크의 출력에 곱한다.

그럼 이제 기댓값이 같아졌다.

 

일부 노드를 무작위로 0으로 만들어주고, test time에서는 그저 값 하나만 곱해주면 된다. (probability)

 

 

Test time에는 기존의 연산을 가져가고 train time에서 p를 나눠준다.

Test time에서 가능한 효율적으로 작동하기 바라기 때문이다.

 

dropout을 사용하게 되면 전체 학습시간은 늘어나지만 모델이 수렴한 후에는 더 좋은 일반화 능력을 얻을 수 있다.

 

정리하자면,

 

(1) train time에는 네트워크에 무작위성을 추가해 training data에 너무 fit하지 않게 한다.

(2) test time에는 randomness를 평균화 시켜서 generalization 효과를 주는 것이다.

 

BN도 비슷한 역할을 할 수 있다.

그래서 BN을 할 때 dropout을 사용하지 않는다.

regularization이 충분히 되기 때문이다.

 

 

train time에 이미지를 무작위로 변환시켜 볼 수 있다.

레이블을 그대로 놔둔채로 진행한다.

이미지 반전을 시킨다.

 

 

잘라내고 반전시켜서 학습을 한다.

이미지의 밝기를 낮추기도 한다. (color jittering)

 

train time에 입력 데이터에 임의의 변환(Data augmentation)을 시켜주게 되면

일종의 regularization 효과를 얻을 수 있다.

 

train time에는 stochasticity가 추가되고 test time에는 marginalize out 되기 때문이다.

 

 

Dropout과 유사하게 dropconnect라는 방법이 있는데,

이는 activation이 아닌 weight matrix를 임의적으로 0으로 만들어주는 방법이다.

 

 

Fractional Max Pooling은 pooling이 될 지역을 임의로 설정하여 샘플링하는 것이다.

 

 

Stochastic Depth

 

Train time에서 일부 레이어를 제외하고 학습을 하고, test time에는 전체 네트워크를 다 사용한다.

 

대개는 BN만으로도 충분하지만 오버피팅이 발생한다 싶으면 dropout을 추가하기도 한다.

 


< Transfer Learning >

 

원하는 양보다 더 적은 데이터만을 가지고 있을 때 사용하는 방법이다.

 

오버피팅이 일어날 수 있는 상황 중 하나가 충분한 데이터가 없을 때이다.

 

Transfer learning은 "CNN은 엄청 많은 데이터가 필요함"이라는 미신을 깨부순다.

 

 

가장 마지막 FC layer는 최종 feature와 class score간의 연결인데 이를 초기화시킨다.

 

그리고 차원을(ex. 클래스 수만큼으로) 줄이고, 마지막 레이어만 가지고 우리 데이터를 학습시킨다.

 

데이터가 조금 많다고 생각되면 전체를 fine tuning 해볼 수도 있다.

 

 

데이터셋이 크지 않은 경우라면 task와 유사한 데이터셋으로 학습된 pretrained model을 다운로드 받는다.

그리고 모델의 일부를 초기화시키고, 데이터로 모델을 fine tune하는 것이다.

 

 

오늘은 여기까지 :)


(참고자료)

 

leechamin.tistory.com/search/cs231n

 

참신러닝(Fresh - Learning)

이차민의 iOS/ML/DL 공부 블로그 Computer Vision과 iOS개발에 대한 전반적인 공부를 합니다. "Be The First Penguin"

leechamin.tistory.com

lsjsj92.tistory.com/

 

꿈 많은 사람의 이야기

안녕하세요. 이수진이라고 합니다. 이 블로그는 AI(인공지능), Data Science(데이터 사이언스), Machine Learning, Deep Learning 등의 IT를 주제로 운영하고 있는 블로그입니다.

lsjsj92.tistory.com

taeyoung96.github.io/categories/CS231n/

 

CS231n Summary

한 발자국씩 앞으로 나아가자

taeyoung96.github.io

 

댓글