본문 바로가기
논문으로 현업 씹어먹기

딥러닝을 대하는 우리의 자세 - (A Recipe for Training Neural Networks / Andrej Karpathy)

by Yoo Sung Hyun 2021. 4. 22.
728x90

오늘 정말 너무너무 공감되서 가슴이 뜨거워질 정도였던 블로그 글을 읽게 되었다.

 

무려 만 32살에 Tesla AI Team 팀장을 맡게된 Andrej Karpathy의 기술 블로그를 보던중 과거의 글 중에 이런 글이 있었다.

karpathy.github.io/2019/04/25/recipe/

 

A Recipe for Training Neural Networks

Some few weeks ago I posted a tweet on “the most common neural net mistakes”, listing a few common gotchas related to training neural nets. The tweet got quite a bit more engagement than I anticipated (including a webinar :)). Clearly, a lot of people

karpathy.github.io

참고로 Andrej Karpathy는 딱딱한 통계와 논문 범벅인 딥러닝 생태계에서, 트위터등을 통해 깊게 뒷통수를 후려치듯 할만한 이야기들을 쉽고, 마치 동료 개발자인것처럼 공감해주며 소통하는 어떻게 보면 대단한 사람이라고 생각한다.

 

twitter.com/karpathy

 

Andrej Karpathy(@karpathy) 님 | 트위터

@karpathy 님 언뮤트하기 @karpathy 님 뮤트하기 팔로우 @karpathy 님 팔로우하기 팔로잉 @karpathy 님 팔로우 중 언팔로우 @karpathy 님 언팔로우하기 차단됨 @karpathy 님이 차단됨 차단 해제 @karpathy님 차단 해

twitter.com

AutoPilot에 관련될 수 있는 논문은 물론이고, 그냥 자기가 일하다가 있었던 mistake happening들까지 공유하는데, 이게 또 내가 겪는 실수들과 비슷한 경우도 있어서, 멀지만 가깝게 느껴지는 친구다...ㅋㅋㅋㅋ

 

A Recipe for Training Neural Networks-Andrej Karpathy.pdf
4.66MB

사이트에 들어간 것을 조금 의역하고, 내 의견을 곁다리로 좀 더 추가해서 써놓은건 해당 pdf를 봐도 되겠다. (내 글씨를 해석할 수 있으면...?ㅋㅋㅋ)

 

저기서 정리한걸 조금 축약하면서, 내가 느낀점도 곁들여 볼까하니, 시간이 많고 현업에 삶이 지친 AI 엔지니어들은 핑거푸드 먹는다고 생각하고 가볍게 봐주면 고맙겠다.

(생각해보면, 시간이 많은데 현업에 삶이 지친 사람이 있을리가 없겠구나. 미안하다...)

 

(참고로 내가 느끼는 점이나 내가 말하고 싶은건 '-- --' block으로 표현하겠다. 나머지는 그대로 블로그 내용을 번역, 의역한 내용이다.)

 

서론

서론은 이렇다, 카페시가 웨비나를 하는데, 꽤나 격렬했단다. 왜 인고하니, 누구는 CNN의 기초를 이야기하는가하면, 누군가는 CNN의 최신기술을 이야기하고 있더라는거다. (기술의 이해와 접근방식, 기대수치 등 온도차가 너무 컸다는 이야기인것 같다.)

 

카페시가 생각해보니까, 또 이거 트위터나 블로그에 살만 붙혀서 이런저런 이론적인 얘기나 리스트업 하느니, 좀 더 깊이있게 톡까놓고 얘기해보자는 것이다.

 

1) Neural net training is a leaky abstraction (뉴럴넷은 구멍난 추상화이다.)

(Neural net은 표현을 쉽게 하기 위해 딥러닝이라 칭하겠다.)

(leaky abstraction은 정확히는 '새는 추상화' 이지만, 나는 구멍난 추상화라고 의역하겠다.)

 

Leaky Abstraction

이걸 또 안걸고 넘어갈 수 없겠다. 내가 왜 구멍난 추상화라고 표현했을까?

rapapa.net/?p=3266

 

개발에서의 Leaky Abstraction – Rapapa Dev Story

지금으로부터 15년전, 강산이 한번 변하고, 다시 한참 변하고 있을 때 쯔음에 Joel은 그의 블로그에 Leaky Abstraction이라는 주제로 글을 썼다.  (참조: Link) 이것이 많은 개발자들에게 회자되면서 비

rapapa.net

Leaky Abstraction은 좀 꼰대같은 표현을 빌리자면,

요즘것들 다 쉽게만 wrapping된 편한 클래스만 사용하고, 근본을 모른다 이말이다. 그렇기 때문에, 특정 상황에서 Leak이 발생할 수 있다는 것을 명심하자는 것이다.

 

딥러닝에 비유를 대보자면, 역전파가 대단한 문제가 생겨, 전혀 다른 수학함수로 변경해야된다. 우리는 가슴에 손을 얹고 그 일련의 과정을 전부 Custom 할 수 있겠는가? (이래서 딥러닝이 구멍난 추상화라고 하는 것이다. 카페시의 말을 좀 인용했다..ㅋㅋ)

 

요즘 클라우드, ML Studio라던가, AWS SageMaker를 쓰면서 느끼는점은, TensorFlow를 베타때부터 접하고, 그 시절에 주구장창 Scikit-Learn을 돌리던 내 스스로가 바보가 된 것 같은 느낌을 받을때가 있다. 좀 더 늦게 시작했으면, 더 편하게 일할 수 있었을텐데...하는 편협한 생각이 들때가 있었다. (선배님들 죄송합니다.)

 

하지만 요즘은 또 그런 생각을 안하는게, 신입이들이랑 똑같이 써보면서 느끼는점은, 가끔 신입이들은 AutoML 돌려보다가 구글찾다가 쉽게 포기하는 경향이 있을때가 많은데, 나는 근본적 문제를 파악하면 그냥 Local에서 바로 Custom해서 써버리는 편이다. (구멍을 막아버리는 것이지.)

 

뭐 쨋든 거두절미하고,

 

카페시도 비슷하게 생각하는가보다,

파이썬 소스는 대부분 친숙하고, 우리가 생각하듯 소스를 짜면 아주 짧고 멋지게 돌아가지만, 사실 그 안에는 여러가지 번거로운 작업들을 개발자들이 잘도 숨겨놓은 것 뿐이다.

불행히도, 딥러닝은 어림도없다. Imagenet에서 쪼~끔만 벗어나면, They are not "off-the-shelf" technology (선반위에 판매되는 기성품과같은 기술이 아니다.)

카페시의 포스트 "Yes you should understand backprop(응~ 역전파 이해해야되~)"를 보면 알 수 있듯이, 역전파가 구멍난 추상화라고 볼 수 있다고 한다. (Yes you should understand backprop은 내가 매우 빠른 시일내에 번역해서 정리하겠다.)

딥러닝에서 그냥 제공되는 메소드나 방식들이 마법처럼 모든 문제를 해결해주진 않는다.

공식으로 꼭 만들어보는 것만이 정답은 아니지만, 이해는 하고있어야 모델이 나빠지지 않을 수 있다.

 

2) Neural net training fails silently (딥러닝은 조용하게 나빠진다.)

-- 이 부분 역시 내가 매우 공감했던 부분. 1)번과 더불어서 내가 항상 느끼면서 한국인 현업 이해시키기 가장 힘든 부분. --

-- (외국계에서 외국인들도 그런가? 혹시 경험하고 계신분 있으면 귀띔좀...ㅠㅠ) --

 

-- 파이썬이랑, 딥러닝 프레임워크는 나는 솔직히 전혀 다른 언어라고 표현하고싶다. --

-- 기획과 가설의 차이이며, --

-- 개발과 실험의 차이이고, (1번에 해당하는 내용) --

-- 오류와 오차의 차이이다. (2번에 해당하는 내용) --

 

카페시가 말하길,

소스코드는 에러가 명확하다.

딥러닝은 'Syntactically'(구문적으로) 완벽해도, 'Logical'(논리적으로) 에러가 발생하고, 이를 미연에 발견하기가 힘들다.

딥러닝에서의 오류가 아닌 실수들이 무시되면, 동작은 잘되지만, 운좋아야 에러가 떨어지고, 대부분은 잘못 학습된다.

 

딥러닝에서, "fast and furious"(영화 이름을 비유하는 것 같다. 분노의 질주. 우다다다 빠르게만 개발하는 형태를 비꼰게 아닐까?) 방식의 접근은 고-통만 야기시긴다. 뭐 지금이야 딥러닝이 잘되기위해 고통이야 당연하긴한데, 항상 방어적이고, 편집증 수준으로 인내하고, 세밀하게 하나하나 관심을 가지는 것이 기본 덕목이라고 보겠다.

-- 이 역시 공감되는게, 딥러닝은 오류가 아닌 오차라서, 조밀조밀 하나하나 신경쓰지 않고 그냥 돌렸다가는, 전혀 어긋난 결과를 얻을때가 태반이기 때문이다. (귀찮다고 한번 넘어가면 꼭 그 부분이 문제됨 귀신같음...ㅋㅋㅋㅋ;;) --

 

The Recipe (방법. 나는 자세라고 표현하고싶다.)

이제 카페시가 딥러닝을 옳바르게 대하는, 자신만의 설명 가능한 방법들을 제시한다고 한다.

-- 어떻게 딥러닝을 대해야, 더 잘 이해하고, 더 쉽게 학습시켜서 원하는 output을 얻을 수 있으며, 더 지식수준을 쌓아 진보된 내가 될 수 있는지에 대한 방법들을 설명해주는 것 같다. --

-- 여기서 대충 결말까지 던져주는데, (역시 논문쓰는놈이라 두괄식인가...) --

초장에 검증되지도 않은거 복잡하게 짜지만 말고, 매번 학습간에 하나하나 test set을 이용하여 확인하여 관계를 추측하고, 평가해나가라.

 

1. Become one with the data (데이터와 하나가 되어라.)

딥러닝 수정보다는 데이터 패턴검증이 더 중요하다.

데이터를 검증하고 패턴을 찾는과정이 모델 아키텍쳐를 결정하는 요소로 작용될 것이다.

 

모델은 데이터의 컴파일이며, 모델을 보고 데이터의 문제를 이해할 수도 있다. 이상한 예측값을 통해 우리는 역으로 데이터의 어떤부분이 잘못되었는지도 알아낼 수 있다.

 

데이터를 시각화하는 것은 이상치나 전처리에서 생길수 있는 버그들을 발견하는데 도움이 될 수 있다.

 

-- 이건 너무 당연한 얘기인 것 같다. 모델을 데이터의 컴파일이라고 표현하는 부분에서 좀 멋지다고 생각되었음. --

 

2. Set up the end-to-end training/evaluation skeleton+get dumb baselines (train/eval 과정의 뼈대를 한큐에 정의하고, 우매한 기준선을 잡아라.)

바로 복잡한 모델을 적용한다고해서, 문제가 잘 해결될 것 같은가? 어림도없지! 그 과정은 고-통의 연속이다. 간단한 모델부터 해나가면서, 실험의 단계를 점점 짤라내고, 실험군에서의 정답에 대한 믿음을 찾아나가야한다.

-- 너무 복잡한것 부터 적용해서 문제를 해결하기 어렵게 만들기보단, 쉬운것부터 조금씩 옳게 되고있음을 확인하면서 한스텝씩 나아가라는 의미로 해석된다. --

 

  • fix random seed. 균일한 실험의 출력물을 비교하기 위해서는 random seed를 사용하는 것 보다는, 고정된 seed를 활용하는 것을 추천한다.
  • simplify. 데이터를 증분할 생각같은 것도 하지말고, 최대한 단순한 수준에서 모델을 돌려라. 데이터 증분같은거는 나중가서 해봐도 충분하며, 쓸데없는 버그만 더 날 수 있다.
  • add significant digits to your eval. 로스가 낮아짐에만 의존하지 마라. 결국 중요한건 모델이 얼마나 잘 맞추느냐하는 정확도이다.
  • verify loss @init. 시작손실이 동일하게 모델을 검증할 수 있는지 확인해야한다.  -- 카페시는 최대한 동일한 시점에서 최소한의 변경사항만을 줘가며 변경 전, 후 모델을 테스트해나가는 일련의 단계, 단계별 과정을 중요하게 생각하는 것 같다. 그래서 최대한 랜덤화 될 수 있는 요소들은 억제하고, 모델의 최소한만 변경해나가며 모델을 검증하고 학습시켜나가는데 포커스를 맞춘 것으로 보인다. --
  • init well. bias 초기값 설정을 하면 학습 속도 증진에 효과가 있을 수 있다. -- 필자는 bias는 거의 무시하는 값이었는데, 좀 더 이해를 높혀 나중에는 초기값 설정에도 신중하게 임해야겠다... --
  • human baseline. 사람이 인지 가능한 척도도 써라(accuarcy 같은.). 예측값과 실제값을 같이놓고 확인하는 것도 중요하다. -- 의외로 loss로만 모델을 검증하는 사람이 많나싶다...;; 이건 당연한 소리 아닌가? --
  • input-indepent baseline. 기준에 독립적인 인풋값을 사용해라. 0같은걸 입력하는 방식으로, 모델이 특징학습을 잘 하고있는지 확인해라(?) -- 이 부분은 번역해도 이해가 잘 되지 않는다. 맞게 이해한지 잘 모르겠다. --
  • overfit one batch. 오히려 과적합시켜서 loss가 0에 수렴하는 것을 보고, 모델의 구성이 적절한지 검증해볼 수 있다. -- 이거 아주 기발한거같다. 생각해보면 모델자체가 잘못되면, 과적합도 잘 안되는게 일반적이겠지 ㄷㄷ --
  • verify decreasing training loss. data를 늘려가면서 loss가 떨어지는 것을 확인해라. -- 이쯤 읽으니, 한번에 너무 많은 데이터를 다 넣고 검증하려고 하기보단, 조금씩 단계별로 늘려가라는 의미로 해석된다. --
  • visualize just before the net. 소스에서 어느 시점에서는 꼭 데이터를 확인하고 모델정보를 확인해라. -- 그냥 막무가내로 돌리는 사람이 많나보다. 기본적인 내용같은데... --
  • visualize prediction dynamics. 예측을 항시 확인하면서 모델이 고통받고있진 않은지 확인해라. -- 사람도 중간고사 보기전에 모의고사 보듯이 확인하며 굴리는데, 우리 모델을 너무 막굴리진 말자. 나도 매번 스텝별로 어떻게 학습되는지 prediction값을 출력하면서, 기울기 클리핑을 한다던지 decay를 한다던지 각종 방법을 적용하기도 하고, 이거 확인하는거 별거 아닌거같은데 되게 유용하다. --
  • use backprop to chart dependencies. loss를 계산하기 쉽게 custom하고 역전파를 디버깅해보라. 가끔 결과가 비슷하다고 메소드를 다르게 쓰던지 해서, 학습 전파가 잘 안되는 경우도 있는데, 이런경우를 타파할 수 있다. -- 이부분은 역전파를 심도있게 이해한 자만이 가능할 것 같으며, 할 수만 있다면 매우 유용하겠다. 필자는 아직 시도해본적은 없는 영역. --
  • generalize a special case. 한땀한땀 감당 가능한 수준으로 소스를 작성하고, 나중가서 검증하고, 모델링해라. 카페시도, for문으로 만들어서 확인해보고, 벡터화 시킨다. -- 본인이 디버깅 가능한 수준으로 모델을 적절히 설계해서 테스트 해가면서 고도화 시키라는 얘기로 해석된다. --

3. Overfit (오버피트)

평가하고 재단할 준비는 끝났고, 이제 좋은 모델을 얻기위한 반복의 시간이다.

 

카페시가 생각한 좋은 접근법을 2가지 소개하자면,

1. 최대한 training loss로 오버피팅 시킨다

2. 정규화 하면서 valid에 집중한다

어짜피 오류율이 엄청 낮지 않으면, 언제든 오류는 재현될 수 있다.

-- 1번의 과정으로 모델 아키텍쳐를 정립하고, 2번의 과정으로 valid에 치중하면서 현실문제에 부딪칠 모델에 대한 안정성을 확보하라는 이야기로 해석된다. 아마 오류가 재현될 수 있다는 부분은, 이런 작업을 통해 오류에 대한 안정성을 최대한 확보하는게 중요하다는 이야기로 해석된다. --

 

  • picking the model. Don't be a hero. (영웅이 되려 하지마라.) 논문의 것을 이용하는게 더 이득일 수 있고, 그걸 깨트릴 기회는 언제든지 있다. -- 구체적으로 설명하면, 본인이 직접 생각한 아주 무거운 아키텍쳐를 고집하는 사람들이 많고, 일을 하다보면 그 매력에 매료될때도 많은데, 그것에 대해 저항하는 자세가 필요하며, 검증된 모델을 먼저 사용하라는 이야기이다. (나는 논문부터 찾아보고, 고도화 하긴하지만, 그 매료되는 부분은 정말 내 얘기같아서 공감되더라.)
  • adam is safe. Adam은 하이퍼 파라미터에 좀 더 관대하며 대부분 Adam이 낫고, RNN에서는 더욱 그렇다. 엥간하면 논문을 따르되, Adam이 통상 괜찮다. -- 카페시도 인정하는 Adam은 대체.... --
  • complexify only one at a time. 추가해봐야할게 여러개라면, 한개씩 복잡성을 늘려가며, 성능이 실제로 향상되는지 확인해라.
  • do not trust learning rate decay defaults. 소스 퍼다쓴다고 그 소스의 hyper parameter를 맹신하지 마라. 너의 dataset에 맞게 사용하는 것이 중요하다. 특히 decay는 빠르게 0이 되어 학습 진행이 안될 수도 있다. 카페시는 무조건 초반엔 off해놓고 사용한다. -- 이부분은 나도 decay 대충 선언해놓고 쓰다가. 퇴근하고 다음날 기대되는 마음으로 확인해봤는데 기울기 조정 안되서 하루 날려먹은적있다 젠장...ㅋㅋㅋ;; --

4. Regularize (정규화)

실제로 valid 부분을 신경쓸때가 되었다.

 

  • get more data. 데이터가 깡패다! 적은 데이터로 엔지니어링 즙 짜느니, 그 시간에 데이터 모으는게 낫다. 데이터 모으는게 모델 개선 누워서 떡먹는 방법이며, 또 다른 방법이라면 앙상블이 있는데, 이건 감당 가능하겠냐? 쓸거면 5개 이하로 앙상블하는게 좋더라.
  • data augment. 가짜 데이터를 추가해서라도 데이터를 늘려라.
  • creative augmentation. 절반정도의 가짜 데이터로도 잘 안된다면, 각종 방법으로 창의적으로 데이터를 확장해보라. -- 원문에는 확장 기법들이 몇가지 소개된다. 자세한건 원문참조 --
  • pretrain. 데이터가 많아도, 가능하다면 pre-trained 모델을 사용하라. -- 이건 BERT에서 봤던거 같은데, 범용적인 pre-trained모델에다가 본인들의 domain을 추가로 학습시켜서 pre-trained모델을 사용하면 더 좋은 Acc가 나온다는 말이 논문에 있었다. --
  • stick with supervised learning. vision에서는 현재는 비지도학습이 지도학습을 이긴 사례가 없다. BERT와 그 친구들은 논외인데, 텍스트 한정임... -- 앤드류 응도 BERT하고 GPT말고는 다 Data가 중요하다고 하는데, 저 둘은 진짜 개쩔긴 한가보다...;; --
  • smaller input dimensionality. 이상한 특성은 overfit 가능성만 높힌다. 세부정보가 필요없다면 이미지(데이터)를 축소시키는 것도 방법이다.
  • smaller model size. 모델을 도메인 지식 제한으로 작게 해보자. ImageNet도 결국엔 pooling 부분에서 모델이 단순화 되었다. -- BERT도 Al-BERT 나온거보면, 도메인에 대한 기술적 지식을 녹여서 차라리 모델을 단순화 시킬 수 있다면 하는게 더 효율적인거 같기도. --
  • decrease the batch size. 전체로 정규화하는 것보다 작은 배치로 작은 범위에서 정규화하는것이 더 효과적이다. -- 정규화가 매번 국소 데이터에대해 민감하게 정규화되기 때문에, 좀 더 뭉개지는 부분이 적어지기 때문일까..? 이 부분도 절반만 이해됨. --
  • drop. dropout 사용해라. 다만 배치정규화랑 같이 쓰는건 효과가 없을 수 있으니 잘 고려해서 사용해라. -- 이거 내가 실제로 겪어봤다. 나는 개인적으로 batch norm만 썼을때가 더 잘됐는거 같음. 구글에 그런 아티클도 많고. --
  • weight decay. weight decay 패널티를 올려가면서 학습해라. -- 이거 갠적으로 학습속도도 빨라지고, 가끔 학습도 더 잘된다. 근데 중요한건 대충 찍어놓고 안보고 있으면 학습 귀신같이 안됨 ㅋㅋㅋㅋ. --
  • early stopping. valid loss 캐치해서 early stopping 쓰는거로 오버피팅 막을 수 있다. -- 이거는 매우 레퍼런스도 많고, 진짜로 맞는 얘기며, 나는 이제는 학습시간 줄일라고 답답해서라도 쓴다. --
  • try a larger model. early stopping이 적용된 모델은 종종 큰 모델이 나을때도 많다. 과적합은 근데 항상 조심할 것!

마지막으로, 첫번째 layer의 weight를 출력해보는 것으로, 모델의 학습 경과를 확인해본다. 첫번째 layer output이 뭔가 노이즈 같다면, 뭔가 학습이 잘못되고 있다는 것이다. 이런 것들을 통해서 activation function이 제대로 어떻게 영향을 미치는지도 확인해볼 수 있고. -- 이거는 vision 한정 아닐까? 내가 LSTM도 이렇게 검증해봤는데, 학습이 되고있구나, 안되고 있구나만 좀 잘 파악되고, '어떻게' 잘못되고 있구나는 좀 파악하기 힘들었다. units들의 순서로 예측정도만 해볼뿐... --

 

5. Tune (조율)

이제 낮은 valid loss를 찾아나가는 "반복"의 과정이다.

  • random over grid search. -- grid search보다 random search가 나을 수도 있다. a가 중요하고, b는 영향이 별로 없다면, 고정된 지점에서 반복해서 확인하는 것 보다는, a만 샘플링해서 확인하는게 나을 수 있다. -- pipeline + grid search 개인적으로 많이 쓰는 편인데, random search는 안써봐서 나중에 한번 경험해봐야겠다. --
  • hyper-parameter optimization. 베이지안 하이퍼 파라미터 최적화 툴이 잘되있으니 한번 써보자. 카페시 친구들은 효과 좋단다. 근데 카페시 생각에는, 그냥 인턴들 굴리는게 더 나은거 같다. 물론 농담이다 :) -- 대단히 한국형 꼰대스러운 농담이라고 생각한다. 무서운사람... --

6. Squeeze out the juice (즙짜기. 거의 뭐 마른오징어 물짜기 수준)

마른오징어에서 물짜는 법.

  • ensembles. 앙상블은 보장된 정확도 +2% 룰이다. 다만 본인이 감당 가능한 선에서만. 물론 흑마술처럼 표현한 힌튼교수님 논문을 참고해봐도 좋다. -- 힌튼 교수님 논문은 본문 내의 링크 참조 --
  • leave it training. vailid loss만 보고 쉽게 포기하지마라. 적당히 valid loss가 평평해진다고 그만하는 사람들 많은데, 카페시는 겨울방학 실수로 그냥 보내고왔는데 그게 SOTA였던 적이 있었다. -- 내 사수가 항상 하는 얘기. 모델은 스테이크처럼 다 구워졌다고 생각했을때 좀 더 구워봐야 마이야르가 지대로 나온다. --

Conclusion (결론)

이로써, 준비는 다 끝났다!

모두 논문읽고, 시도하고, SOTA를 얻어보자!

-- 이놈 새끼 그 속에 느껴지는 고통과 탈모는 쏙 빼놨네.;; --

 

--- 끝!

 

 

솔직히 이거 진짜 회사다니면서, Data Science랑 SI 개발이랑 구분 못하는애들 출력해서 면전에 꽂아주고싶다. ^^

공감되면 하트 눌러주시길!

728x90

댓글