ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [cs231n] 7강 신경망 훈련하기 (3/4, 더 멋진 최적화 (fancier optimization 3))
    AI 2021. 3. 23. 17:11

    진짜 빠르고 더럽고 쉬운 것은 이 모델 앙상블 (model ensembles)을 시도하는 겁니다. 이건 때때로 머신러닝의 많은 다양한 영역에서 동작합니다. 아이디어는 꽤 단순합니다. 하나의 모델만 가지기 보다는, 10개의 다른 모델을 임의의 다른 초기 재시작으로 독립적으로 훈련시킬 겁니다. 테스트시에는 데이타를 10개의 모델 모두에서 실행시키고 이 10개의 모델의 예측값을 평균냅니다. 이 여러 개의 모델을 같이 더하는 것은 과적합 (overfitting)을 약간 줄여주고 성능을 약간 개선합니다. 일반적으로 2% 정도죠. 이건 보통 극적인 개선은 아니지만, 일관적인 개선입니다. 이미지넷 (ImageNet)이나 다른 경연에서, 최대 성능을 얻기 위해 모델 앙상블을 사용하는 것은 매우 흔한 일이라는 것을 알게 될 것입니다.

    이것에 대해서 약간 창조적으로 할 수도 있는데요. 별도의 모델을 독립적으로 훈련시키기 보다는, 훈련 과정에서 모델의 여러 개의 스냅샷 (snapshot)을 가지고 있다가 그걸 앙상블로 사용할 수 있습니다. 그다음 테스트시에, 이 여러 스냅샷의 예측을 여전히 평균내야 할 필요는 있죠. 그러나 학습 과정에서 스냅샷을 수집할 수 있습니다.

    이번주에 ICLR에서 매우 좋은 논문이 발표되었는데요. 이 아이디어의 멋진 버전이죠. 여기서는 미친 학습률 일정 (schedule)을 사용해서 학습률이 매우 느렸다가, 매우 빨랐다가, 다시 매우느렸다가, 매우 빨라집니다. 이 미친 학습률 일정으로 훈련과정에 걸쳐, 모델은 이 목표 지형에서 여러 영역으로 수렴할 수 있을 겁니다. 그것 모두는 꽤 좋죠. 이 여러 스냅샷에 대해 앙상블을 하면, 성능을 꽤 좋게 개선할 수 있습니다. 모델을 한번만 훈련시킨다고 해도요.

    가끔씩 할 수 있는 작은 트릭 (trick)은 훈련 동안, 파라미터 벡터 자체의 지수적 감소 평균을 유지해서 훈련동안 망의 부드러운 앙상블을 같는 것입니다. 실제 체크포인트 (checkpoint)보다는 파라미터 벡터의 이런 부드럽게 감소하는 평균을 사용하는 거죠. 이건 폴리악 에버리징 (Polyak averaging)이라고 불리는데, 때때로 도움이 됩니다. 그건 여러분이 가끔씩 더할 수 있는 이 작은 트릭들의 하나이지만, 실제에선 아주 자주 쓰이진 않을 겁니다.

    또다른 궁금한 점은 어떻게 단일 모델 (single model)의 성능을 개선할 수 있느냐는 겁니다. 앙상블이 있을 때는, 테스트시에 10개 모델을 실행해야 할 겁니다. 그건 좋지 않죠. 우리는 단일 모델들의 성능을 개선할 수 있는 전략을 정말 원합니다. 그것이 정규화 (regularization) 아이디어죠. 모델에 어떤 것을 더해서 훈련 데이타에 너무 잘 맞도록 하지 못하게 하는 겁니다. 보지 않은 데이타에서 더 잘 동작하도록 하려구요.

    우리는 정규화에 대한 몇 개 방법을 이미 봤고, 거기서는 손실에 어떤 명시적인 추가 항을 더했죠. 하나의 항은 모델에게 데이타에 맞추라고 얘기하는 거고, 다른 항은 정규화항이죠. 몇 강의 전에 얘기했는데, 신경망 문맥에서는 이 L2 정규화는 별로 많이 의미가 있지는 않습니다. 때때로 신경망을 위해서는 우리는 다른 것들을 사용하죠.

    신경망을 위해 슈퍼 슈퍼 흔히 사용되는 정규화 전략은 드랍아웃 (dropout)입니다. 드랍아웃은 슈퍼 간단하죠. 망 (network)을 통해 순방향 전파 (forward pass)를 할 때, 각 계층에서, 임의로 몇몇 뉴런들을 0으로 설정합니다. 순방향 전달을 할 때마다, 다른 임의의 뉴런 집합을 0으로 설정합니다. 이것은 한번에 한 계층씩 전진하죠. 하나의 계층을 거치고, 계층의 값을 계산하고, 임의로 그들 중 일부를 0으로 설정하고, 망을 통과하며 계속 올라갑니다. 왼쪽의 완전 연결 (fully connected) 망을 보고, 같은 망의 드랍아웃 버전을 오른쪽에서 보세요. 드랍아웃을 하고 나면, 같은 망의 더 작은 버전처럼 보입니다. 뉴런의 어떤 하위 집합만을 사용하는 거죠. 우리가 사용하는 이 하위 집합은 각 이터레이션 (iteration) 마다,각 순방향 전파마다 달라집니다.

    드랍아웃은 실제에서 슈퍼 간단합니다. 단지 코드 2줄만 추가하면 되죠. 드랍아웃 호출마다 한줄입니다. 여기서 보듯이 이 추가적인 코드 줄을 추가하는 것으로 몇몇을 임의로 0으로 설정할 수 있습니다. 구현하기 정말 쉽죠.

    근데 왜 이게 좋은 아이디어일까요? 우리는 훈련시에 여러 값들을 0으로 설정함으로써 이 망을 심각하게 망치고 있죠. 이게 도대체 어떻게 말이 되죠? 약간 논리적이지 않은 설명은 드랍아웃이 피쳐 (feature)의 상호적응 (co-adaptation)을 제한한다는 겁니다. 만약 우리가 고양이를 분류하는 것을 생각해 보면, 어떤 세상에서는, 망이 귀가 있다는 것을 하나의 뉴런 (neuron)이 학습하고, 꼬리가 있다는 것에 대해 한 뉴런이, 입력이 털이 있다는 것을 한 뉴런이 학습할지도 모르겠습니다. 그다음 이것들을 모두 합쳐서 고양이인지 아닌지를 결정하는 거죠. 만약 드랍아웃이 있다면, 고양이다움에 대한 최종 결정을 내리는 데 있어서, 이 망은 이 피쳐들의 어떤 것에 과도하게 의존할 수 없습니다. 그 대신, 고양이다움의 아이디어를 많은 다양한 피쳐에 분산해야하는 거죠. 이것이 어느정도 과적합을 제한합니다.

    약간 최근에 나온 드랍아웃에 대한 다른 해석은 단일 모델 내에서 모델 앙상블 (model ensembles)을 하고 있다는 겁니다. 왼쪽 그림을 보면, 망에 드랍아웃을 적용한 다음, 뉴런의 하위 집합 (subset)을 이용하여, 이 하위 망을 계산하는 거죠. 이제 모든 여러 잠재적인 드랍아웃 마스크 (mask)가 여러 잠재적인 하위 망에 이르게 합니다. 이제 드랍아웃은 여러 모든 망의 전체 앙상블을 학습하는 거고 동시에 모두 파라미터들을 공유합니다. 그런데, 잠재적인 드랍아웃 마스크의 숫자가 뉴런의 숫자에서 지수적으로 증가하기 때문에, 이 모든 것들은 절대 샘플링 할 수 없을 겁니다. 이건 모두 동시에 훈련되는 정말 거대하고 거대한 망의 앙상블입니다.

    테스트시에는 무슨일이 벌어지나요? 일단 드랍아웃으로 가면, 우리는 신경망의 연산을 근본적으로 변경한 겁니다. 일전에 우리는 신경망이 있었고, f는 가중치 w와 입력 x의 함수고, 출력 y를 만들어내죠. 그러나 우리 망은 이제 추가적인 입력 z를 받죠. z는 어떤 드랍아웃 매스크입니다. z는 랜덤이죠. 테스트시에 임의성을 갖는 것은 나쁩니다. 여러분이 페이스북에서 일하고 있고 사람들이 올리는 이미지를 분류한다고 생각해 보죠. 오늘 여러분의 이미지는 고양이로 분류되고 내일은 아닌거죠. 그건 정말 이상하고 나쁠 겁니다. 망이 이미 훈련되었다면 여러분은 어쩌면 테스트시에 이 확률성 (stochasticity)를 없애고 싶을 겁니다. 그다음 우리는 이 임의성을 평균내어 버립니다. 여러분이 그걸 없애 버리면, 어떤 적분으로 이 임의성을 낮추는 (marginalize) 것을 생각할 수 있습니다. 하지만, 실제에선, 이 적분은 전혀 추적할 수 없습니다. 우리는 이것을 어떻게 평가해야 하는 지 알 수 없고, 나쁜 모양에 빠지는 거죠. 생각해 볼 수 있는 건 이 적분을 샘플링을 통해 근사하는 것입니다. z의 여러 개의 샘플을 꺼내서 테스트시에 평균내는 거죠. 그러나 이것도 여전히 약간의 임의성을 가져올 거고 약간 나쁠겁니다.

    고맙게도, 드랍아웃의 경우에는, 지역적으로 (locally) 적은 비용으로 이 적분을 근사할 수 있습니다. 단일 뉴런을 생각해 보면, 출력은 a이고, 입력은 x와 y이며 2개의 가중치, w1, w2가 있습니다.

    테스트시에는 우리의 값은 w1 x 더하기 w2 y죠.

    훈련 동안에는, 1/2 확률로 뉴런을 드랍하는 드랍아웃을 사용했습니다. 훈련 동안의 기대값 (expected value)에 대해서는 , 이 작은 경우에 대해서 분석적으로 계산할 수 있습니다. 4개의 가능한 드랍아웃 마스크가 있고, 우리는 이 4개의 마스크에 대해서 값을 평균낼 겁니다. 보다시피, 훈련중의 기대값은 1/2 (w1 x + w2 y)죠. 여기 연결이 끊어진 것이 있는데, 테스트시의 (w1 x + w2 y)의 평균값과 훈련시의 평균값의 차이는 단지 1/2 만큼이죠.

    우리가 할 수 있는 비용이 적은 방식은 테스트시에 확률성을 갖지 않는 것이죠. 그 대신 우린 이 출력을 드랍아웃 확률로 그냥 곱하는 겁니다. 이제 기대값은 똑같죠. 이건 일종의 이 복잡한 적분에 대한 지역적이고 비용이 낮은 근사죠. 사람들이 실제에서 드랍아웃 할 때 정말 많이 하는 겁니다.

    드랍아웃에서, 우리는 이 예측 함수 (prediction function)가 있고 우리는 그냥 우리의 계층 출력을 드랍아웃 확률로 곱합니다.

    드랍아웃을 요약하면 순방향 전달에서는 정말 간단하죠. 그냥 구현할 때 2줄의 코드를 넣어서 어떤 노드들을 임의로 0으로 만드는 거죠. 테스트시에는 예측 함수에 확률로 곱하는 하나의 작은 연산을 넣는 겁니다. 드랍아웃은 슈퍼 간단하고, 신경망을 정규화하는데 때때로 잘 동작하는 편입니다.

    그런데, 가끔씩 볼 수 있는 흔한 트릭 (trick)은 역 (inverted) 드랍아웃인데요. 아마도 테스트시에 여러분은 효율성을 더 신경쓸겁니다. 그래서 테스트시에 저 추가적인 p로 곱하는 것을 없애고 싶을 텐데요. 그럼 테스트시에 전체 가중치 행렬을 사용하고, 그러나 훈련시에는, 대신 p로 나누는 겁니다. 왜냐면 훈련은 아마도 GPU에서 일어나고 있기 때문이죠. 훈련시에 추가적인 곱하기를 하는 건 별로 신경 안 쓰겠지만, 테스트 시에는, 이것이 가능한한 효율적이 되길 바라겠죠.

    댓글

Designed by Tistory.