무료하게 시간을 보내다 정신을 차리니 일요일 저녁이다. 1편에 이어 2편을 바로 적어야 할 것 같은 압박감에 급하게 적는다. 이 글은 모델 복잡도를 다루는 방법들을 종합/정리하는 차원에서 적기 때문에 개념적으로 설명한다. 개별 알고리즘의 상세 내용은 다른 레퍼런스를 참조하기 바란다.
작년에 팀에 새로 합류한 친구들과 약 스무 개의 모델 복잡도를 다루는 방법을 나열한 적이 있다. 모든 방법을 다 수긍한 것은 아니지만 일반적으로 활용하는 방법들은 대부분 정리된 듯하다. 당시에 논의했던 리스트는 지금 없어서 지금 당장 생각나는 방법들만 몇 개의 카테고리로 나눠서 적는다. 1편에서 적었듯이 모델 복잡도는 모델의 변수가 많고 차수가 높아서 복잡해지는 경우도 있고, 사용되는 데이터의 차원이 너무 크거나 데이터가 부족하거나 너무 많아서 적절한 모델을 제대로 구축하지 못한 경우도 있고, 때론 지나치게 학습 데이터에 과적합하게 학습된 경우 등 다양한 원인에서 발생한다고 했다. 그렇기에 이들 각각의 원인을 제거하면 모델 복잡도는 해결된다. 그래서 크게 데이터 관점에서, 모델 또는 알고리즘 관점에서, 그리고 (학습) 테크닉 관점에서 모델 복잡도를 제어할 수 있다고 본다. 아래 나열한 것은 절대적인 기준이 아니다. 하나의 방법을 한 카테고리에 넣어놨지만 관점을 조금만 달리하면 다른 카테고리에 놓을 수도 있다.
모델/알고리즘
-
우선 모델 자체가 복잡해서 복잡도가 증가하기 때문에 간단한 모델을 사용하면 된다. 가능하다면 우선은 선형 모델을 사용한다. 선형 모델의 성능이 나쁘지 않다면 굳이 더 복잡하고 차수가 높은 비선형 모델을 사용할 이유가 없다. 시작은 간단한 모델로 해서 애초에 복잡해질 가능성을 원천적으로 차단하는 게 맞다. 하지만 간단한 모델은 주어진 데이터를 제대로 설명하지 못할 가능성이 높다.
-
말장난 같지만 더 적합한 모델을 사용하는 것도 복잡도를 미연에 방지하는 방법이다. 어떤 문제나 데이터든 그걸 설명하는 가장 적합한 모델이 분명 존재한다. 그걸 찾아가는 것이 복잡도를 제어하는 방법이다. 데이터 문제 해결에 가장 적합한 모델이 딥러닝이라면 딥러닝이 아무리 복잡하더라도 사용해야 한다. 무조건 간단한 모델을 사용하는 것이 복잡도를 해결하는 방법은 아니다.
-
단일 모델로 데이터 문제를 해결할 수 있으면 가장 좋지만, 역설적이게도 다양하고 많은 모델을 앙상블 (Ensemble)하는 것도 복잡도를 해결하는 방법이다. 좀 더 정확하게 말하면 과적합 (over-fit)된 모델을 해결하는 방법이다. 랜덤 포레스트 Random Forest는 Decision Tree보다 훨씬 복잡하지만, 개별 Decision Tree가 특정 상황에 과적합되는 걸 막아준다. 보통 Bagging은 overfitting을 해결해주고, boosting은 under-fitting을 해결한다.
-
모델 복잡도를 제어하는 가장 흔한 방법은 모델의 복잡도에 페널티를 주는 방법이다. Regularization이라 부르는 방식으로, 모델의 weight의 절댓값 (1-norm)이나 제곱 (2-norm)의 합을 원래 모델에 추가하는 방식이다. 흔히 L1/L2 Regularizer라 부른다. 인터뷰에서 L1/L2의 장단점을 물어보면 답변을 제대로 못하는 지원자를 종종 본다. 아주 간단히 요약하면 L1은 피쳐 셀렉션이 가능하고, L2는 미분가능하다.
데이터
-
정답 데이터만 사용해서 학습한다. 과적합이 발생하는 이유는 결국 불필요한 또는 노이즈 데이터가 학습 및 테스트 데이터에 포함돼있기 때문이다. 애초에 잘 선별해서 잘 정제된 정답 (Y를 뜻하지 않음) 데이터만 사용한다면 쓰레기 결과를 염려할 필요가 없다. 때론 가비지를 만들어내는 모델이 있기도 하다. 데이터를 정제할 때는 편향 bias 되는 걸 조심해야 한다. Denoising도 크게 보면 정답 추리기로 볼 수 있다.
-
데이터를 정제하는 것은 새로운 모델을 구축하는 것만큼/보다 어려울 수 있다. 그래서 역으로 더 많은 데이터를 사용함으로써 복잡도를 줄인다. 데이터가 많아질수록 문제 공간을 더 많이 커버할 수 있고 소수의 노이즈로부터 좀 더 로부스트해진다. 일종의 물타기인 셈이다. 또 실제 환경에서 데이터가 많으면 굳이 모델을 구축할 필요가 없을 수도 있다. 빅데이터 환경에선 때론 단순 카운팅이 예측 모델보다 더 낫다. 그런데 데이터가 많아지면 노이즈도 많아지겠지만, 큰 수의 법칙처럼 원래 데이터의 분포에 수렴할 가능성이 높다.
-
더 많은 데이터를 수급할 수 없다면 기존 데이터를 변형해서 정답을 부풀리는 방식도 가능하다. 대표적으로 이미지 데이터는 좌우상하 반전, 여러 각도로 회전, 일부 영역만 크롭, 또는 상하/좌우로 늘리기 또는 distortion 등의 연산을 통해서 하나의 정답을 여러 개로 만들 수 있다. 고양이 사진은 좌우 반전을 시켜도 여전히 고양이다.
-
비슷한 방법으로 정답에 노이즈를 추가하는 가능하다. 드라마에선 점 하나 찍으면 다른 사람이 되지만 데이터에선 극히 일부를 조금 변형하더라도 속성이 크게 변하진 않는다. 물론 너무 많이 변형하면 원래 속성을 잃어버릴 테니 적당선은 필요하다. 이미지 객체 인식 문제에서 원본 이미지에 노이즈를 조금 추가하면 완전히 엉뚱한 걸로 인식하는 오류가 있었는데, 애초에 이런 노이즈를 포함한 것도 정답으로 제공해서 학습시키면 그런 오류를 다소 해결할 수 있을 거다.
-
변수가 너무 많아서 복잡도가 증가했다면 변수를 줄이면 된다. 무턱대로 죽일 수는 없기에 feature selection 방식이 필요하다. 모델의 설명/정확도는 유지하면서 중요한 변수로만 모델을 구축하면 복잡도가 감소한다. 역으로 현재 가진 데이터에 중요한 변수가 포함되어있지 않다면 새로운 데이터와 합쳐서 새로운 (중요) 변수를 추가하는 것도 방법도 가능하다. 피쳐 셀렉션이 가능하다면 일반적인 차원 축소 Dimension Reduction (이전 글 참조)도 모델 복잡도를 줄이는 좋은 방법이다. 보통 차원 축소를 통해서 중복 또는 노이즈 데이터를 줄일 수 있다.
테크닉 (휴리스틱?)
-
과적합 문제를 해결하는 가장 쉬운 방법으로 Early Stop이 있다. 학습 데이터를 다시 학습용 데이터와 검증용 데이터로 분리하고, 학습용 데이터로만 모델을 학습을 진행하면서 검증용 데이터로 계속 검증해서 검증 오류가 증가하는 지점을 찾아내서 학습을 중단하는 방식이다. (임의로 선택된) 검증 데이터가 unseen/테스트 데이터와 속성이 비슷하다면 검증에서 중단 지점이 테스트에서 error가 증가하는 지점이 될 가능성이 높다. 그래서 흔히 학습 데이터와 테스트 데이터로만 나뉘는 줄 아는데, 실제는 학습 데이터, 검증 데이터, 그리고 테스트 데이터로 나눠서 모델을 학습한다.
-
Stochastic 방법을 통해서 모델을 계속 흔드는 것도 복잡도를 제어하는 방법이다. 딥러닝에서는 DropOut으로 알려졌는데, 학습에서 임의의 모델 파라미터를 임의로 비활성화해서 그 파라미터 없이 나머지 파라미터들로만 예측해도 전체를 사용한 것과 같은 효과를 내도록 한다. 어떻게 보면 ‘데이터’에서 노이즈를 추가하는 것과 비슷할 수도 있다 (어떤 데이터의 특정 변수를 0 —> 1 또는 1 —> 0으로 변경하는 것도 노이즈 추가로 볼 수 있다). 불완전한 모델이 완전한 모델과 거의 같게 작동한다면 실제 환경에서 돌발 상황에 더 능동적으로 대처할 수 있다.
-
딥러닝에서 많이 사용되는 BatchNormalization도 한 가지 방법이다. 이는 중간 결과물을 정규분포로 변환하는 과정을 추가한 것이다. 그래서/그런데 어떻게 보면 데이터를 변환하는 것이므로 위의 데이터 카테고리에 놓아도 될 듯하다.
-
데이터 feed 순서를 임의로 shuffle 하거나 mini-batch로 만드는 것도 방법이 될 수 있다. 모델이 새로운 데이터로 계속 학습한다고는 하지만 먼저 투입된 데이터에 모델 구조와 가중치가 편향될 수밖에 없다. 백조는 흰색이다라고 어릴 때부터 배웠다면 호주에 있는 black swan을 봤을 때 백조로 인식하지 못할 거다. 새로운 사실을 알려주는 많은 데이터가 들어오기 전에는 기존 데이터로 학습된 구조/가중치가 쉽게 바뀔 수 없다. 그렇기 때문에 각 이터레이션에서 데이터 피딩 순서를 계속 바꿔줌으로써 특정 데이터에만 편향되지 않도록 한다.
-
학습 과정에서 글로벌 옵티멈에 이르지 못하고 로컬 옵티멈에 빠지는 것도 모델이 복잡해지고 (더 엄밀히, 엉뚱해지고) 테스트 에러가 크지는 원인이라 본다. 그렇다며 글로벌 옵티멈으로 수렴하는데 도움이 되는 다양한 스토케스틱 방법이나 랜덤 초기화도 도움이 된다. 임의의 여러 지점을 초기값으로 해서 최적화를 반복해서 글로벌 옵티멈을 찾는다.
이외에도 다양한 방법이 존재한다. 원인 또는 관점이 여럿이듯이 해결하는 방법도 여럿이다.