ML 모델 개발을 하기 위해선 먼저 적절한 ML 알고리즘을 선정해야함
이번 장에서는 ML 알고리즘을 선택하기 위한 팁들과 디버깅, 실험 추적, 버전 관리 등 모델 개발의 다양한 측면에 대해 기술함
모델 개발은 반복 프로세스이므로 반복이 끝날 때마다 모델 성능 비교 필요
모델 배포 전 다양한 테스트를 통해 프로덕션 환경에서 좋은 결과를 내는 모델을 선정해야함
ML 모델 선정은 기본적으로 ML에 대한 백그라운드가 많이 필요한 영역
책의 저자인 칩 후옌은 깃허브를 통해 ‘Basic ML Review’ 제공함
개인적인 생각으로 ML에 대한 기본 개념은 자주 잊어버리기 때문에 이런 페이지들을 늘 찾아보는 습관이 중요
6.1 모델 개발과 훈련
ML모델 개발과 훈련에는 모델 평가 방법, 앙상블 생성, 실험 추적, 버전 관리, 분산 훈련 등 고려해야할 여러 가지 사항들이 있음
6.1.1 머신러닝 모델 평가
모델 개발에 시간과 연산 능력에 제한이 없다면 가용한 모든 해결책을 적용한 후 최적을 선택하는 것이 합리적
그러나 현실엔 언제나 여러 가지 제약이 있으므로 모델 선택에는 전략적 접근이 중요
알고리즘 선택이라고 하면 보통 고전 알고리즘(ML 계열)과 딥러닝을 떠올리기 쉬움 (나 역시도)
물론 기존 ML알고리즘을 딥러닝이 많이 대체하는 중이지만 여전히 ML알고리즘도 많이 쓰이고 있음
(개인적으로 회사에서 했던 프로젝트 모두 GBM 계열 알고리즘만 사용했다)
또한 딥러닝과 고전 알고리즘이 함께 쓰이는 경우도 많음
딥러닝으로 피처를 추출하고 알고리즘에 적용되거나 알고리즘으로 추출된 피처를 딥러닝에 적용하기도 함
어떤 문제에 대한 모델을 선택할 때는 가용 모델 전체가 아니라 문제에 일반적으로 적합한 모델에 집중해야함
분류 문제라면 분류 문제에 적합한 모델, 회귀 문제라면 회귀 문제에 적합한 모델부터 고려해야 한다는 소리
또한 같은 분류 문제라도 텍스트 분류와 Table데이터는 특성이 다르므로 여기에 적합한 모델도 고려해야함
그리고 알고리즘 유형에 따라 연산량과 필요한 레이블 개수(데이터 개수)도 많은 차이를 보임
그러므로 주어진 문제에 대한 모델을 선정하기 위해선 일반적인 ML작업유형과 이를 해결하기 위한 접근법에 대한 지식이 필요
책의 저자인 칩 후옌은 본인의 다양한 실무 경험을 통해 모델 선택 시 활용할 수 있는 6가지 팁을 제시함
1. 최첨단만 추종하는 함정에 빠지지 않기
많은 사람들이 흔히 하는 착각 중에 하나가 바로 ‘최첨단 = 최적의 솔루션’ 이라는 것
기존 알고리즘들을 개선했다고 주장하는 수많은 최신 알고리즘들이 문제를 더 쉽게 풀어줄거라고 착각함
(이 부분을 읽으면서 매우 뜨끔했다)
하지만 최신 알고리즘들은 보통 ‘학문적’맥락에서 가장 좋은 성능을 보이는 알고리즘
보통의 SOTA는 연구에서 사용되는 정적인 데이터셋에서 기존 모델보다 성능이 좋다는 뜻 (게다가 요즘은 매우 한정적인 가정에서만 SOTA인 경우도 많음)
가장 좋은 모델이라는 의미가 결코 구현 측면에서 더 빠르거나 비용이 낮다는 의미가 아닐뿐더러 내가 가진 데이터에서 성능이 더 좋다는 뜻이 아님
그리고 비즈니스 관점에서 오래되고 자주 쓰인 알고리즘은 그만큼 커뮤니티가 활발하다는 뜻
문제가 생겨도 사례를 찾아보기 쉽고 유명한 문제들은 이미 해결책까지 제시되어 있는 경우가 많음
ML을 처음 도입하는 기업이라도 적어도 모델링에 대한 위험부담은 낮출 수 있음
2. 가장 단순한 모델부터 시작하기
파이썬의 선(Zen of Python)에는 ‘단순함이 복잡한 것보다 낫다’라는 원칙이 존재
이는 ML에도 적용 가능
단순함은 3가지 측면에서 유용
- 단순한 모델은 배포하기 쉬움. 모델을 빨리 배포할수록 예측 파이프라인과 훈련 파이프라인이 일치하는지 빨리 확인 가능
- 단순한 것부터 시작해 복잡한 것을 단계별로 추가하는 편이 모델을 이해하고 디버깅하기 쉬움
- 가장 단순한 모델은 보다 복잡한 모델의 비교 대상으로 베이스라인 역할을 수행
가장 단순한 모델이 노력이 최소한으로 드는 모델은 아님
Pre-train된 BERT모형은 복잡하지만 작업을 시작하기 용이하고 문제를 해결하기 위한 커뮤니티도 성숙
그러나 BERT를 개선하는 노고는 상당히 많이 듦
단순한 모델로 시작하면 모델을 손쉽게 개선하기 쉬우나 초기에 모델을 구성하는 것은 상대적으로 귀찮고 어려움
상용적으로 쓰이는 모델들이 Pre-train된 형태로 많이 제공되면서 일정 부분 트레이드오프가 존재
3. 모델을 선택할 때 사람의 편향을 주의하기
사람마다 선호하는 알고리즘이 다르기 때문에 같은 작업에 대한 최적 알고리즘을 다르게 생각하는 경우가 많음
특히 ML 알고리즘은 다양한 피처와 하이퍼파라미터를 조합하므로 특정 알고리즘에 관심이 많다면 그 알고리즘에 대한 실험에 더욱 많은 노력이 들어갈 가능성이 높음
서로 다른 아키텍처를 비교할 때는 비교 가능한 설정 아래에서 비교하는 것이 중요
서로 같은 실험 횟수 등을 맞춰 놓고 비교해야 공정한 비교가 가능
모델 성능은 상황에 따라 다른 의미를 가지므로 특정 모델이 다른 모델보다 낫다고 단언하기 어려운 문제
4. 현재 성과와 미래 성과를 비교 평가하기
현재 최적인 모델이 미래에도 최적은 아닐 수 있음
예를 들어, 데이터가 많지 않을 땐 트리 기반 모델이 좋지만 데이터가 쌓일수록 신경망 기반 모델 성능이 훨씬 좋아질 수 있음
Andrew Ng은 학습 알고리즘의 편향이 크면 학습 데이터를 더 많이 확보해도 큰 도움이 되지 않고, 학습 알고리즘의 분산이 높다면 데이터를 더 확보하면 도움이 된다고 함
학습 곡선을 통해 데이터가 늘어남에 따라 모델 성능이 어떻게 변할지 가늠 가능
학습 곡선은 사용하는 훈련 샘플 개수에 따른 모델 성능 플롯
훈련 데이터 증가에 따른 정확한 성능 향상은 알 수없지만 대략적인 파악은 가능

프로덕션 환경은 모델이 예측만 수행하는 환경이 아니고 데이터도 쌓이는 환경
따라서 가까운 미래에 개선 가능한 잠재력과 개선 작업의 난이도를 고려해 모델 선택 필요
5. 트레이드오프를 평가하기
ML 모델에는 수많은 트레이드오프가 존재하고 이를 고려해야함
대표적인 트레이트오프로 type 1 error와 type2 error에 대한 트레이드오프
비즈니스 관점에서 어떤 성능이 더 중요한지 이해하고 결정해야함
예를 들어 지문 잠금 해제 같은 모델은 위음성보다 위양성이 훨씬 위험하므로 위양성이 적은 모델 선호
코로나19 진단 모델 등은 위음성이 더 중요하므로 위음성이 낮은 모델 선호
즉, 각각의 상황에 따라 더 중요한 지표가 달라짐을 명확히 이해해야함
또한 연산량과 정확도 간의 트레이드오프도 존재
보통 복잡한 모델이 더 좋은 성능을 보이곤 하지만 연산량도 비례해서 증가함
연산량이 증가하면 추론 레이턴시가 늘어날 가능성이 높고 더 좋은 성능의 머신이 필요
복잡한 모델은 모델 해석 가능성 역시 떨어짐
6. 모델의 가정을 이해하기
우리가 사용하는 모델은 현실을 그대로 반영하는 것이 아니라 가정을 통해 어느 정도 근사만 가능
따라서 모델에는 저마다의 가정이 포함되어 있음
모델이 무엇을 가정하며 데이터가 그 가정을 실제로 충족하는지 이해한다면 유스케이스에 가장 적합한 모델이 무엇인지 평가 가능
흔히 사용하는 가정들
예측 가정(Prediction assumption)
입력 X에서 출력 Y를 예측하는 것이 목표인 모델은 X를 기반으로 Y를 예측할 수 있다고 가정
IID(Independent and Identically Distributed)
각각의 데이터가 독립적이고 분포가 동일하다고 가정
이는 모든 데이터가 동일한 결합 분포에서 독립적으로 추출됐다는 의미
Smoothness
유사한 입력값은 유사한 출력값으로 변환된다는 가정
모든 알고리즘은 입력을 출력으로 변환하는 함수 집합을 가정하는데 이 함수 집합에 대한 가정
X에 가까운 입력은 Y에 가까운 출력값을 생성함
계산 가능성(Tractability)
X가 입력이고 Z가 X의 잠재 표현일 때 생성 모델은 확률 를 계산할 수 있다고 가정
경계(Boundaries)
선형 분류기의 결정 경계는 선형이라고 가정
선형으로 분류 가능하다고 가정 (그래서 비선형 데이터에는 안 맞음)
조건부 독립(Conditional indepedence)
나이브 베이즈 등 분류기는 정해진 클래스에 대해 속성값들이 상호 독립이라고 가정
정규 분포(Normally distributed)
많은 통계적 방법론들이 하는 가정으로 데이터가 정규 분포를 따른다고 가정
6.1.2 앙상블
문제를 처음 고민하는 단계에선 단일 모델로 많이 시작하지만 성능 향상을 위해서 앙상블을 적용하는 경우가 많음
앙상블 내의 각 모델을 기본 학습기(base learner)라고 함
캐글 대회에서 우승한 많은 솔루션들이 앙상블을 사용 중
앙상블은 배포가 복잡하고 유지관리가 어려워 프로덕션에서 자주 쓰이진 않지만 광고 클릭 예측과 같이 성능이 조금만 향상돼도 금전적 이득이 큰 경우 자주 사용되기도 함 (역시 비용 대비 편익이 가장 중요하다..)

앙상블을 사용하면 단일 모델을 사용했을 때보다 정확도가 증가함
단일 모델의 정확도가 70%라면 모델 3개를 앙상블했을 때의 정확도는 0.343 + 0.441 = 0.784 로 증가 (모델 결과에 대한 다수결 투표)
이 계산은 모델 간 상관관계가 없을 때만 유효
모든 분류기가 서로 1의 상관계수를 갖는다면 (모두 같은 예측을 한다면) 아무런 의미가 없음
앙상블은 기본 학습기 간의 상관관계가 낮을수록 유리
일반적으로 앙상블을 구성할 때는 트랜스포머, 순환 신경망, GBM 등 서로 유형이 상당히 다른 모델을 결합
앙상블을 구성하는 방법은 배깅, 부스팅, 스태킹 등이 있음
여러 연구들을 통해 앙상블은 성능 향상 외에도 불균형 데이터셋 문제 완화에도 크게 도움이 된다고 밝혀짐
배깅
배깅은 Bootstrap Aggregating의 줄임말로 알고리즘의 훈련 안정성과 정확도를 모두 개선하도록 설계됨
분산을 줄이고 과적합을 방지하는데 효과적

전체 데이터셋으로 하나의 분류기를 훈련하는 대신 복원 추출을 통해 여러 데이터셋 생성(부츠트랩 생성)
복원 추출이므로 각 부츠트랩은 서로 독립적으로 생성됨
최종 예측값은 모든 모델의 다수결 투표로 결정 (회귀 모델에서는 모든 모델의 예측값 평균)
배깅은 일반적으로 불안정성이 높은 기법의 성능을 개선
신경망, 분류 및 회귀 트리, 선형 회귀 등에 사용하면 효과가 좋음
K-최근접 이웃과 같은 안정적인 기법에서는 성능이 저하될 수 있음
랜덤 포레스트는 배깅의 일종
배깅에 피처의 무작위성을 더해 구성한 트리 모음
각 트리는 무작위로 정한 피처 집합에서 사용할 피처를 선택하게 됨
부스팅
부스팅은 약한 학습기를 강한 학습기로 바꾸는 반복 학습 앙상블 알고리즘
앙상블을 구성하는 각 학습기는 동일한 샘플 집합으로 학습하지만 반복마다 각 샘플에 다른 가중치 부여
나중에 더해지는 학습기는 이전의 학습기들이 잘못 분류한 데이터에 더욱 집중하게 됨

부스팅의 각 단계
- 원래 데이터셋으로 첫 번째 분류기 학습
- 샘플마다 첫 번째 분류기에서 얼마나 잘 분류되는지에 따라 가중치 부여. 예를 들어 잘못 분류된 샘플에는 더 높은 가중치 부여 등
- 가중치가 부여된 데이터셋으로 두 번째 분류기 학습 앙상블은 첫 번째와 두 번째 분류기로 구성
- 샘플마다 앙상블에서 얼마나 잘 분류되는지에 따라 가중치 재부여
- 가중치가 부여된 데이터셋으로 세 번째 분류기 학습. 앙상블에 세 번째 분류기 추가
- 위 과정을 필요한만큼 반복
- 최종적으로 기존 분류기의 가중치 조합으로 강한 분류기를 구성. 분류기의 훈련 오차가 적을수록 가중치 높음
부스팅 알고리즘 예시로는 GBM 계열 알고리즘이 있음
다른 부스팅 방법과 마찬가지로 단계적으로 모델을 구축하고 임의의 미분 가능한 손실 함수를 최적화하면서 모델을 일반화하는 알고리즘
XGBoost, LightGBM 등이 대표적인 GBM 계열 알고리즘
스태킹
스태킹은 훈련 데이터로 기본 학습기를 학습하고 출력을 결합해 최종 예측을 수행하는 메타 학습기를 만듦
여기서 메타 학습기는 단순한 휴리스틱(평균 등)일 수도 있음

6.1.3 실험 추적과 버전 관리
모델 개발 프로세스에선 다양한 아키텍처와 모델에 대한 실험이 필수적
따라서 실험 및 관련 아티팩트를 재현하는데 필요한 정의를 모두 추적하는 것이 중요
아티팩트는 실험 중에 생성되는 파일을 말함
아티팩트의 예로는 손실 곡선, 로그, 학습 중간 결과 파일, 최종 모델 등이 있음
실험 추적은 실험 진행 상황과 결과를 추적하는 과정
버전 관리는 나중에 재현하거나 다른 실험과 비교할 목적으로 실험의 모든 세부 정보를 기록하는 프로세스
최근 ML실험관리 툴들은 두 가지 기능이 통합된 형태로 제공됨 (MLflow, WandB 등)
실험 추적
ML 모델을 학습 시 학습 프로세스를 살펴보는 일은 중요한 문제
손실이 감소하지 않거나(발산), 과대 적합과 과소 적합, 가중치값이 널뛰는 문제, 뉴런이 죽는 문제, 메모리 부족 등 다양한 문제가 학습 과정에서 발생할 수 있음
이런 문제를 감지하고 학습이 올바르게 되고 있는지 평가하려면 학습 중에 발생하는 일을 계속 추적해야함
훈련 과정에서 실험에 대해 고민해야할 추적 지표들은 아래와 같음
- 손실 곡선
- 모델 성능 지표
- 샘플, 예측값, 로그 등
- 모델 훈련 속도
- 시스템 성능 지표
- 매개변수와 하이퍼파라미터
이론 상 추적 가능한 모든 지표를 추적하는 것도 가능하지만 너무 많은 정보가 포함됨
정보가 많을수록 추적 자체가 부담이 되기도 하고 정작 중요한 정보를 놓치기도 함
실험 추적을 통해 다수의 실험을 비교 가능
구성 요소가 변하면 모델 성능에 어떤 영향을 미치는지 관찰해 그 요소의 역할을 이해할 수 있음
간단한 실험 추적 방법으로는 실험에 필요한 모든 코드의 복사본과 출력을 타임스탬프와 함께 기록하는 것
최근에는 MLflow와 같은 서드 파티 실험 추적 도구를 사용하면 매우 편리
(기회가 되면 MLflow나 WandB 사용법을 한번 정리해야겠다)
버전 관리
ML 모델도 기본적으로 코드를 기반으로 이루어지기 때문에 Git과 같은 버전 관리 도구는 필수
하이퍼파라미터나 설정값이 조금만 바뀌어도 결과가 크게 달라지기 때문에 버전 관리는 중요한 문제
또 중요한 사항은 데이터 버전 관리
데이터 버전 관리의 중요성은 모두가 알지만 실제로 실천하는 건 어려운 문제
(데이터의 조그만 수정이 어떤 나비 효과를 불러오는지 알게되면 저절로 버전을 관리하고 싶게 된다!)
하지만 데이터 버전 관리는 생각보다 까다로운 문제
코드에 비해 데이터는 용량이 훨씬 크기 때문에 코드처럼 모든 버전의 복사본을 유지하기 어려움
또 어느 시점부터 변경되었다고 정의하기가 까다로움 (diff 정의가 어려움)
DVC같은 데이터 버전 관리 도구는 전체 디렉터리의 체크섬이 변경되고 파일이 제거되거나 추가되었을 때만 diff를 등록함
그리고 일반적인 코드 버전 관리와 다르게 병합 충돌을 해결할 방법이 없음 (개발자 1이 데이터 X를 사용해 모델을 만들고, 개발자 2가 데이터 Y를 사용했을 때 둘의 병합 버전 Z를 만드는 건 Z를 사용한 모델이 없기 때문에 아무런 의미가 없음)
마지막으로 규정으로 인해 데이터 버전 관리가 더욱 어려움
사용자가 민감 정보에 대한 삭제를 요구하면 해당 버전으로 데이터 복구가 불가능함
꼼꼼한 실험 추적과 버전 관리는 재현성에 도움이 되지만 재현성을 완전히 보장하지는 않음
프레임워크와 하드웨어의 차이에서 기인하는 변화로도 결과값이 달라질 수 있기 때문
ML 모델 디버깅
디버깅은 소프트웨어 개발의 본질적인 요소로 ML모델도 반드시 디버깅이 포함되어야 함
하지만 ML모델 디버깅은 아래 이유로 좀 더 고통스러운 과정일 수 있음
- ML모델은 명시적인 중단이나 출력없이 조용히 실패할 수 있음
모든 과정이 올바르게 이루어지고 예측값이 나와도 예측값이 잘못 되었을 수 있음 이런 오류는 바로 알아차리기가 매우 힘들어서 그대로 배포될 수도 있음
- 버그를 찾았어도 수정하는 과정이 매우 복잡하고 느릴 수 있음
모델에서 오류를 찾고 수정하고 나면 모델을 다시 학습시키는데 몇 시간 혹은 며칠이 걸릴 수도 있음
- ML모델 디버깅 자체가 기능 간 복잡도로 인해 매우 까다로움
ML모델에는 데이터, 레이블, 피처, 알고리즘, 코드, 인프라 등 다양한 구성 요소가 있으며 구성 요소마다 관리 주체가 다른 경우가 많음
오류의 원인이 다양한 구성 요소의 복합적인 문제로 발생할 수 있어 누가 관장해야 하고 어디서 손을 대야하는지 결정하기가 매우 어려운 경우가 많음
ML모델 실패 원인
이론상의 제약 조건
각 모델은 데이터와 피처에 대한 고유한 가정이 존재하지만 실제 데이터와 피처가 가정에 부합하지 않는 경우
예를 들어 선형 모델에 비선형 데이터를 적용하는 경우
잘못된 모델 구현
모델 구현 상 버그가 있는 경우 (Pytorch 사용 중 모델 검증 과정에서 gradient 추적을 안끄는 경우 등)
모델에 구성 요소가 많을수록 문제가 생길 가능성이 높고 어디서 문제가 생겼는지 추적이 어려움
최근에는 미리 준비되고 검증된 모델을 사용하는 경우가 많아 많이 완화되는 추세
잘못된 하이퍼파라미터 선택
같은 모델이어도 하이퍼파라미터에 의해 천차만별인 결과를 보이는 경우가 많음
데이터 문제
데이터 수집과 전처리 단의 문제로 모델 성능 저하
잘못된 피처 선택
모델 학습에 너무 많은 피처를 사용하면 모델이 과적합될 우려가 있음
반대로 너무 적은 피처를 사용하면 예측력이 떨어지는 문제 발생
ML모델 디버깅 기법 - 자세한 내용은 안드레이 카르파티의 블로그 참조
단순하게 시작하고 점진적으로 구성 요소를 추가하기
가장 단순한 모델에서 시작해 구성 요소를 추가하면서 성능 변화 관찰
BERT 모델을 예로 들면 처음에는 MLM 손실만 적용해보고 NSP 손실 추가 등
단일 배치에 과적합시키기
모델을 단순하게 구현해 소량의 데이터로 훈련 데이터에 과적합시킨 뒤 같은 데이터로 평가해보기
같은 데이터에서 도달가능한 최소 손실을 달성하는지 확인
예를 들어 10개의 이미지가 100% 정확도를 보이는지 확인하는 과정
데이터 수가 작은데도 과적합이 안된다면 구현에 문제가 있을 수 있음
무작위 시드값을 고정하기
ML모델은 무작위성을 포함하는 요소가 너무 많기 때문에 가급적 모든 무작위성을 고정하는 것이 좋음
무작위성을 고정하지 않으면 성능 변화가 모델 변화 때문인지 무작위 시드값인지 알기 어려움
6.1.4 분산 훈련
모델이 점점 커지고 자원을 대량으로 사용함에 따라 대규모 훈련에 대한 고려가 중요해짐
최근에는 머신의 메모리 크기보다 큰 데이터를 사용하는 경우도 많음
데이터가 메모리 크기보다 크다면 데이터 전처리, 셔플링, 분할 처리 등을 아웃 오브 코어 형태나 병렬로 처리
데이터 샘플 하나가 크다면 배치 크기가 줄어들어 경사 하강법 기반 최적화 작업이 불안정해지는 문제도 발생
데이터 샘플 하나가 메모리보다 큰 경우도 종종 있음
이런 경우 메모리 풋프린트나 그래디언트 체크포인팅 기법 등을 활용해야함
그래디언트 체크포인팅이란 중간 계층의 그래디언트를 메모리에 저장하는 대신 이를 계산하는데 필요한 연산 그래프만 저장한 후 필요한 시점에 연산 그래프로 다시 계산하는 기법
그래디언트 체크포인팅을 사용해 샘플 크기가 작더라도 더 큰 배치 크기를 쓸 수도 있음
데이터 병렬 처리
데이터 병렬화는 여러 머신에 데이터를 분할하고 각 머신에서 모델을 훈련한 뒤 그래디언트를 합산하는 방법
최신 ML프레임워크에서 지원하는 병렬화 기법 중 가장 보편적인 기법이고 실제로도 많이 쓰이는 방법
데이터 병렬 처리에서 가장 까다로운 문제는 서로 다른 머신에서 계산한 그래디언트를 어떻게 정확하고 효과적으로 합산할 것인가에 대한 문제
모든 모델이 실행 완료 후 합산하는 동기식 확률적 경사하강법(SGD; Synchronous Stochastic Gradient Descent)를 사용한다면 작업 속도가 느린 머신 하나가 전체 속도를 늦추는 문제 발생
이런 낙오자 문제(straggler problem)는 병렬 분산 처리에서 늘 발생하는 문제
모델이 각 머신의 그래디언트를 사용해 개별적으로 가중치를 업데이트하는 비동기식 SGD를 사용하면 한 머신의 그래디언트가 다른 머신의 그래디언트를 입수하기 전에 가중치가 바뀌는 현상이 발생
따라서 최신이 아닌 그래디언트를 적용하는 문제가 발생하는데 이를 그래디언트 부패(Gradient staleness)라 함

이론상 비동기식 SGD도 수렴하긴 하지만 동기식 SGD보다 더 많은 반복이 필요함
하지만 가중치 수가 많을 땐 그래디언트 업데이트가 희소하게 이루어지는 경향이 있으므로 실제 서로 다른 두 머신이 같은 가중치를 수정할 가능성은 낮음
그래디언트 업데이트가 희소하다면 그래디언트 부패 문제가 발생할 확률이 줄어들고 두 경우 모두 유사하게 수렴
데이터 병렬화의 또 다른 문제로 배치 크기가 매우 커진다는 문제 발생
머신 한 대가 1000개짜리 배치를 처리한다면 머신 100대는 100만 개짜리 배치를 처리 가능
단순히 반복마다 더 많이 학습하도록 학습률을 높일 수 있지만 이는 수렴이 불안정해지는 상황을 야기하기도 함
배치는 크면 클수록 좋지만 너무 크면 이득이 줄어드는 지점이 존재
마지막으로 모델 설정은 동일하게 가져가면서 주 작업자가 다른 작업자보다 더 많은 자원을 사용하는 문제 발생
모든 머신을 균일하게 사용하기 위해 각 머신 간의 워크로드 균형을 맞춰줘야 함
효과적이진 않지만 가장 쉬운 방법은 주 작업자의 배치 크기를 줄이고 다른 작업자의 배치 크기를 늘리는 것
모델 병렬 처리
데이터 병렬 처리는 머신마다 모델을 복제해와서 모든 계산을 수행하는 방식
모델 병렬 처리는 모델의 각기 다른 구성 요소를 서로 다른 머신에서 훈련하는 방식
예를 들어 머신 1은 처음 두 레이어에 대한 계산을 처리하고 머신 2가 다음 두 레이어 처리
혹은 특정 머신이 정방향 패스를 처리하고 다른 머신이 역방향 패스를 처리하는 방식 등
아래 그림에서 볼 수 있듯 병렬 처리라고는 하지만 모든 머신이 병렬로 동작하는 것은 아님
특정 머신은 이전 머신의 작업이 끝날 때까지 대기해야하는 경우도 존재

파이프라인 병렬 처리(pipeline parallelism)은 모델 병렬 처리의 병렬성을 좀 더 높이기 위해 고안된 기법
핵심 아이디어는 각 머신의 계산을 여러 부분으로 잘게 나누는 것
머신 1이 계산의 첫 번째 부분을 완료하면 그 결과를 머신 2에 전달하고 머신 1은 두 번째 부분 처리
이 때 머신 2는 첫 번째 부분 계산을 마무리하게 됨
아래 그림처럼 각 머신은 신경망의 특정 구성 요소에 대해 순방향 패스와 역방향 패스를 모두 처리하게 됨

모델 병렬 처리와 데이터 병렬 처리는 상호 배타적인 개념이 아님
하드웨어 활용도를 높이기 위해 둘을 동시에 사용하고자 하지만 엔지니어링에 상당한 시간과 노력이 듦
분산 훈련 도구(DeepSpeed, FSDP) 등의 발전으로 엔지니어링 부담은 크게 줄었다고 함
6.1.5 AutoML
우수한 ML연구원이란 스스로 설계할 줄 아는 지능적인 AI알고리즘을 설계해 모두를 실직시키는 사람 😱
AutoML이 추구하는 방향
- 현재: 솔루션 = ML전문지식 + 데이터 + 연산능력
- 미래: 솔루션 = 데이터 + 100배의 연산 능력
100명의 연구원이 이리저리 움직이다 결국 최적이 아닌 것을 고르기보다 압도적인 연산 능력으로 최적의 모델을 찾아내겠다는 것
(분명히 매우 편리한 기술이지만 밥그릇 걱정이 계속 되는 건 왜일까..)
소프트 오토ML : 하이퍼파라미터 조정
오토ML은 실제 문제를 풀기 위해 ML알고리즘 탐색 프로세스를 자동화하는 것
가장 단순하지만 프로덕션 환경에서 인기있는 형태는 하이퍼파라미터 조정 프로세스를 자동화하는 단계
머신러닝 알고리즘도 하이퍼파라미터가 많지만 딥러닝은 정말 너무 많은 하이퍼파라미터가 있으므로 최적 조합을 찾는 것을 자동화하겠다는 것
하이퍼파라미터의 중요성은 이미 너무 많은 사람이 알고 있음
동일한 모델과 데이터셋에서 하이퍼파라미터 집합만 바껴도 전혀 다른 성능을 보일 수 있음
2018년 논문에서는 구식 모델이라도 하이퍼파라미터 조정만 잘 되면 최첨단 모델보다 성능이 좋다는 것을 보임
그럼에도 선호되는 방법은 수동으로 조정하는 직관적인 방법
가장 인기있는 방법은 대학원생들이 모델이 작동할 때까지 하이퍼파라미터를 만지작거리는 석박사 하강법(GSD; Graduate Student Descent 미국식 유머에 빵 터지긴 처음이었다)
최근에는 하이퍼파라미터 조정 단계를 표준 파이프라인에 포함하는 경우도 많음
F/W에 하이퍼파라미터 조정을 위한 유틸리티가 내장되거나 타사 유틸리티를 포함
사이킷런의 auto-sklearn, 텐서플로의 Keras Tuner 등이 있음
하이퍼파라미터 조정 기법으로는 무작위 탐색, 격자 탐색, 베이즈 최적화 등이 주로 사용됨
모델 성능은 여러 개의 하이퍼파라미터보다 특정 하이퍼파라미터 변경에 더 민감하므로 민감한 하이퍼파라미터는 더 신중하게 조정해야 함
하드 오토ML: 아키텍처 탐색과 학습된 옵티마이저
하드 오토ML은 모델의 서로 다른 구성 요소 혹은 모델 전체를 하이퍼파라미터로 간주하여 자동으로 탐색하는 기법
예를 들어 Conv layer 크기나 skip layer 유무 등을 자동으로 탐색
이런 연구 분야를 신경망 아키텍처 탐색(Neural Architecture Search; NAS)이라고 함
NAS에는 세 가지 구성 요소가 존재
탐색 공간
가능한 모델 아키텍처의 범위를 정의 선택 가능한 구성 단위와 이를 결합하는 방법에 대한 제약 조건을 정의
성능 추정 전략
각 아키텍처 후보별로 학습을 끝까지 하지 않고도 성능을 평가할 방법이 존재해야함
대상 모델이 많을 경우 모든 모델을 끝까지 학습한다는 것은 비용이 매우 많이 드는 일
탐색 전략
탐색 공간을 탐험하는 방법 가장 쉬운 방법은 무작위 탐색이지만 너무 많은 비용이 드는 방법 일반적으로 강화 학습이나 유전 알고리즘을 응용해서 사용함
ML알고리즘에서 가장 중요한 요소는 옵티마이저
이론 상으로 NAS 구성 단위에 옵티마이저를 포함시켜 가장 잘 작동하는 것을 탐색하면 되지만 옵티마이저는 하이퍼파라미터 설정에 민감하고 아키텍처별로 하이퍼파라미터가 상이하므로 실제 적용은 어려움
해결책으로 업데이트 규칙을 정하는 함수를 신경망으로 대체하는 방법이 있음
옵티마이저 자체를 신경망으로 구성해 학습된 옵티마이저를 만들어 내는 것
학습된 옵티마이저 역시 신경망이므로 학습이 필요함
나머지 신경망과 동일한 데이터셋에서 학습할 수 있지만 이러면 작업마다 옵티마이저를 새로 학습해야함
또 다른 접근으로 기존 작업 집합으로 옵티마이저를 한번 더 학습시켜서 새로운 작업마다 사용하는 것
학습은 기존 작업의 합산 손실을 손실함수로 수작업으로 만든 옵티마이저를 학습 규칙으로 사용함
이 접근법은 학습된 옵티마이저를 자체 개선하는 식으로 더 좋은 옵티마이저를 훈련하는데 사용할 수 있다는 장점
자세한 내용은 논문 참조
아키텍처 탐색이나 메타 러닝 학습 규칙과 같은 선행 훈련(up-front learning)은 매우 비싼 비용이 듦
이런 작업을 실제로 수행할 수 있는 회사는 구글이나 MS와 같은 빅테크밖에 없음
하지만 프로덕션 환경 ML에 관심이 있다면 진행상황에 관심을 가져야할 두 가지 이유가 존재
- 이런 연구의 결과로 나온 아키텍처와 학습된 옵티마이저는 ML알고리즘이 다양한 실제 작업에서 즉각 동작할 수 있도록 하며 학습과 추론에 대한 비용을 줄여줌 (역시 남의 꺼 가져다 쓰는 능력이 제일 중요하다)
- 오토ML은 기존 아키텍처와 옵티마이저만으로는 불가능했던 다양한 실제 작업을 해결할 수 있음
ML 모델 개발의 네 가지 단계
ML 도입 시 실행 전략은 아래 채택 단계에 따라 달라짐 단계별 솔루션은 다음 단계의 솔루션을 평가하기 위한 베이스라인으로 사용 가능
1단계: 머신러닝 도입 전
ML이 아닌 솔루션을 먼저 적용해보기
예를 들어 가장 단순한 휴리스틱으로 이미 원하는 목표를 이룰 수 있는지 확인해볼 것
실제로 많은 문제는 휴리스틱만으로도 충분한 경우가 많음
2단계: 가장 단순한 머신러닝 모델 사용하기
첫 번째 모델은 가장 단순한 알고리즘으로 시작하기
문제 유형과 데이터의 유용성을 검증할 수 있도록 작업에 대한 가시성 확보가 가능해야함
또한 구현과 배포가 쉬워 전체 파이프라인과 프레임워크를 빠르게 구축하고 테스트해보면서 보완 가능
3단계: 단순한 모델 최적화 하기
2단계 작업으로 F/W와 파이프라인이 구축되었다면 모델 최적화에 집중할 수 있음
다양한 목적 함수, 하이퍼파라미터 탐색, 피처 엔지니어링 등이 해당
4단계: 복잡한 모델 사용하기
단순한 모델이 한계에 도달해 모델 개선을 통한 성능 향상이 필요할 때
재학습 요구 사항을 지원하는 인프라 구축을 위해 프로덕션 환경에서 모델 성능이 얼마나 빠르게 감소하는지 실험해봐도 좋음
6.2 모델 오프라인 평가
현실에서 가장 답변하기 어려운 질문은 “이 모델이 정말 좋은 모델인가요? 어떻게 알 수 있나요?” 라는 질문
알고리즘 성능 뿐만 아니라 적용될 환경을 고려해야 하는 질문이기 때문
여러 번 나온 내용이지만 비즈니스 환경에서 어떤 알고리즘이 더 나은지 평가하는 건 매우 어려운 일
적절한 평가 방법과 지표를 설정하지 못하면 확실하게 일하기는 매우 어려워짐
특히 비즈니스와 적합한 평가 방법을 찾지 못하면 관리자를 설득하기 까다롭기 때문에 비즈니스와 연관된 평가 지표를 만들어 내는 것이 중요
이상적인 평가 방법은 개발과 프로덕션 환경 간에 동일해야하지만 현실적으론 어려움
개발 환경에서는 그라운드 트루스가 존재하지만 프로덕션 환경에는 없는 경우가 많음
추천과 같은 특정 작업에서는 프로덕션 환경에서 그라운드 트루스를 확인할 수 있지만 편향이 많음
프로덕션 환경의 모델은 끊임없는 모니터링이 중요
모델 오프라인 평가는 모델을 배포하기 전 성능을 평가하는 방법
평가를 위한 베이스라인을 설정하고 어떤 지표로 모델을 평가할 것인지에 대한 일반적인 방법들을 다룸
6.2.1 베이스라인
평가 지표는 그 자체로는 큰 의미가 없음
정확도가 0.9라 해도 데이터가 원래 10% 양성만 있다면 음성으로만 판정해도 도달 가능한 수치
모델을 평가할 때는 평가 기준을 정확히 알아야함
정확한 베이스라인은 유스케이스별로 다르지만 일반적으로 유용한 베이스라인들
무작위 베이스라인
무작위로 예측했을 때의 기대 성능
예측은 균등 분포나 데이터의 레이블 분포 등 특정 분포에 따라 무작위로 생성됨
단순 휴리스틱
가장 쉽게 접근할 수 있는 방법으로 선택했을 때의 성능
0 규칙 베이스라인
단순 휴리스틱의 특수한 경우로 가장 흔한 클래스로 예측
보통 이 경우보다 성능이 좋아야함 (복잡도를 희생하는 대신)
인간에 의한 베이스라인
사람과 비교했을 때의 성능
일반적으로 사람이 하는 일을 자동화하는 경우가 많음
기존 솔루션
현재 사용중인 솔루션 대비 성능 (ML모델이 아닌)
ML모델이 반드시 성능이 더 좋아야 유용한 것은 아님
성능은 다소 떨어지더라도 확장성과 사용성이 좋고 저렴하면 유용
모델을 평가할 때 ‘좋은 시스템’과 ‘유용한 시스템’을 구별하는 것이 중요
좋은 시스템이 반드시 유용한 것은 아니고 나쁜 시스템이 반드시 유용하지 않은 것도 아님
자율 주행 자동차는 이전 자율 주행 자동차보다 개선되었다면 좋은 것이지만 사람보다 성능이 안나온다면 여전히 유용하지는 않음
실제 예측 성능은 그렇게 좋지 않더라도 사람보다 반응이 훨씬 빠르다면 유용할 수도 있음
6.2.2 평가 방법
학문적 맥락에서는 성능 지표만을 보지만 프로덕션 환경에서는 강건성, 공정성 등 여러가지 지표 고려
모델의 이런 특성을 측정하는데 유용한 평가 방법들
교란 테스트
프로덕션 환경은 개발 환경보다 데이터에 잡음이 훨씬 많이 들어올 가능성이 높음
교란 테스트는 데이터에 잡음이 포함되었을 때 모델이 얼마나 잘 작동하는지 보는 테스트
모델에 일부 잡음이 포함된 데이터를 사용해 성능을 평가
모델이 잡음에 민감할수록 유지 관리가 어렵고 적대적 공격에 취약해짐
불변성 테스트
입력에 특정 변경을 적용했을 때 출력이 변하면 안됨
예를 들어 인종 정보만 변경했을 때 출력이 변하는 경우 등
불변성 테스트는 모델에 편향이 존재하는지 확인하기 위한 테스트
가장 좋은 방법은 모델이 민감 정보를 제외하는 것
방향 예상 테스트
입력에 특정 변경을 적용했을 때 출력이 예측 가능한 방향으로 변하는지 확인하는 테스트
집값 예측인 경우 크기가 커졌을 때 예측값이 증가하는지에 대한 확인
출력이 예상과 다르다면 학습이 잘못됐을 가능성이 높음
모델 보정
모델 보정은 미묘하지만 중요한 개념
특히 보정은 ML실무에서 간과되는 경우가 많지만 모든 예측 시스템에서 매우 중요한 속성
예를 들어 모델이 1팀이 2팀을 이길 확률이 70%라고 예측했는데 1000회 대결 중 1팀이 60%만 이긴다면 이 모델은 보정되지 않은 모델
잘 보정된 모델은 1팀이 60% 확률로 이긴다고 예측해야함
예를 들어, 사용자가 다음에 볼 가능성이 가장 높은 영화를 추천하는 시스템을 개발한다고 가정
특정 사용자는 로맨스를 80%, 코미디 20%로 시청함
이 사용자가 볼 가능성이 가장 높은 영화를 추천한다면 모든 항목을 로맨스로만 구성해야함
추천 항목에 실제 시청 습관이 드러나게 하려면 8:2로 보정을 해야함
보정된 정도를 간단히 측정하려면 모델이 확률 X를 출력한 횟수와 예측이 맞은 빈도 Y를 플롯
모델이 완벽하게 보정됐다면 그래프 상 모든 포인트가 일치해야함
사이킷런에서는 sklearn.calibration.calibration_curve를 통해 보정 곡선을 그릴 수 있음

일반적인 모델 보정 방법은 플랫 스케일링이며 사이킷런에 구현되어 있음 (sklearn.calibration)
그 외 책에서 추천하는 제프 플라이스가 구현한 오픈 소스가 있음
모델 보정에 대한 추가적인 설명은 이 블로그를 통해 알아볼 수 있음
신뢰도 측정
신뢰도 측정은 개별 예측의 유용성에 대한 임곗값을 생각해보는 방식
간단하게 말해 사용자에게 어디까지 보여줄 것인가를 결정하는 것
신뢰도 측정은 개별 샘플에 대한 지표로 다른 지표들이 시스템 전체 성능을 측정하는 것과는 다름
슬라이스 기반 평가
슬라이싱은 데이터를 하위 집합으로 분리하고 각 하위 집합마다 모델의 개별 성능을 확인하는 것
대부분 전체 데이터에 대한 지표는 확인하지만 슬라이스 기반 지표는 확인하지 않는데 이는 두 가지 문제를 야기
- 모델이 서로 다른 데이터 슬라이스에서 동일하게 수행돼야할 때 다르게 수행됨
데이터에 다수 집단과 소수 집단이 있을 때 소수 집단에서는 예측이 부정확할 수 있음
소수 집단에 대해 모델 성능을 개선한다면 모델 전반을 개선하는 결과로 이어짐
- 모델이 서로 다른 데이터 슬라이스에서 다르게 수행돼야할 때도 동일하게 수행됨
데이터에서 일부 하위 집단이 더 중요한 경우 모델은 여기에 초점을 맞춰야함
하지만 전체 성능에 초점을 맞추면 중요한 특성이 무시당할 수 있음
슬라이스 기반 평가가 중요한 이유는 심슨의 역설(Simpson’s paradox) 때문
어떤 추세가 여러 데이터 집단에 나타나지만 집단을 결합하면 사라지거나 반전되는 현상
모든 데이터를 함께 놓고 보면 모델 2가 1보다 더 잘 동작하지만 개별 집단에서는 모델 1이 더 성능이 좋은 현상
심슨의 역설은 생각보다 흔한 문제로 집계를 하면 실제 상황을 은폐하고 모순되게 할 수 있다는 시사점을 가짐
슬라이스 기반 평가를 통해 전체 및 중요 데이터에서 모델 성능을 개선하고 잠재적인 편향을 감지 가능
또한 모델과 상관없는 문제를 밝혀낼 수도 있고 모델이 동작하는 방식을 세분화해서 이해할 수 있게됨
슬라이스 평가를 하기 위해선 중요한 슬라이스가 무엇인지 알아야함
슬라이싱은 경험과 데이터 탐색의 영역으로 아래와 같은 주요 접근법이 존재함
휴리스틱 기반
데이터에 대한 작업과 도메인 지식 활용
오류 분석
잘못 분류된 데이터를 수작업으로 분류하고 거기서 패턴을 탐색하는 방법
슬라이스 파인더
Slice Finder: Automated Data Slicing for Model Validation 나 Subgroup Discovery Algorithms: A Survey and Empirical Evaluation 등 슬라이스 탐색 프로세스를 체계화하는 연구 수행 중
일반적으로 빔 검색, 클러스터링, 의사 결정과 같은 알고리즘으로 슬라이스 후보를 생성한 후 걸러내는 방식
중요한 슬라이스를 찾았다면 평가를 위해 슬라이스별 레이블된 데이터가 충분한지 확인 필요
평가 품질은 평가 데이터의 품질에 의해 좌우됨

Uploaded by N2T
'MLOps' 카테고리의 다른 글
머신러닝 시스템 설계 - Chapter 7. 모델 배포와 예측 서비스 (2) | 2023.12.10 |
---|---|
머신러닝 시스템 설계 - Chapter 5. 피처 엔지니어링 (2) | 2023.10.10 |
머신러닝 시스템 설계 - Chapter 4. 훈련 데이터 (2) | 2023.10.06 |
머신러닝 시스템 설계 - Chapter 3. 데이터 엔지니어링 기초 (3) | 2023.08.15 |
머신러닝 시스템 설계 - Chapter 2. 머신러닝 시스템 설계 소개 (0) | 2023.08.06 |