235B 모델을 4개 GPU로 학습시킨 팀이 결국 그 모델을 쓰지 않은 이유
문서에서 엔티티를 찾아 정해진 라벨을 붙이는 분류 작업을 하던 버텍스커버가, 상용 API 파인튜닝 모델을 자체 하드웨어에서 돌리는 오픈 모델로 대체할 수 있는지 실험한 결과를 공개했다. 대상은 Qwen3-235B-A22B-Thinking, 장비는 H100 80GB 네 장과 시스템 RAM 960GB였다. 숫자만 보면 성공이다. 3,600여 개 예시로 한 에폭을 학습해 측정한 모든 고객사에서 정확도가 올랐고 평균 F1은 7.6포인트 상승했다. 토큰당 비용은 기존 API 모델의 약 3분의 1이었다. 그런데 이 모델은 서비스에 들어가지 않았다.
학습 한 번에 걸린 시간은 26시간이다. 고객사마다 문서 형식이 달라 정확도는 테넌트별 F1로 따로 측정했고, 결과적으로 기존에 비용을 내고 쓰던 파인튜닝 API 모델보다 정확도와 토큰당 비용 양쪽에서 앞섰다. 문제는 그 결론에 도달하기까지의 과정이었다.
출발점은 비용이었다. 정확도 자체는 만족스러웠지만 월 청구서가 계속 커졌고, 통제 가능한 하드웨어에서 직접 학습해 같은 수준을 낼 수 있는지 확인하고 싶었다는 것이 이 실험의 동기다. 모델을 고른 기준도 크기가 아니라 성능이었다. 여러 오픈 모델을 같은 작업으로 먼저 비교했고 그중 Qwen3-235B-A22B-Thinking이 가장 높은 점수를 냈다.
이 모델은 MoE 구조라 전체 235B 파라미터 가운데 토큰 하나에 실제로 쓰이는 것은 약 22B뿐이다. 레이어마다 128개의 작은 전문가 네트워크를 두고 토큰을 몇 개에만 라우팅하는 방식으로 추론 비용을 낮춘다. 대신 적재가 까다롭다. 16비트 원본은 470GB, 4비트로 압축하면 약 120GB다. GPU 메모리 320GB에 120GB라면 넉넉해 보이지만, 압축과 분산을 서로 다른 라이브러리가 맡으면서 순서가 어긋난다. 압축 라이브러리는 가중치 행렬을 통째로 봐야 하고, 분산 라이브러리는 최대한 일찍 잘라 각 프로세스가 전체 모델을 들지 않게 하려 한다. 그 사이에서 470GB를 어디에 얼마나 올려둘 수 있느냐가 실행 가능 여부를 갈랐다.
다섯 가지 구성 중 네 개는 학습 스텝을 한 번도 밟지 못했다. Axolotl은 한 프로세스가 RAM에 모델을 올리고 나머지가 기다리는 설정에서 적재까지는 됐지만 GPU로 옮기는 단계에서 죽었고, 그 설정을 끄면 각 프로세스가 120GB를 80GB짜리 GPU에 직접 올리다 실패했다. Unsloth는 적재를 통과한 뒤 Triton 커널에서 CPU 텐서가 GPU 자리에 들어가는 오류로 멈췄다(이슈 #4137, 이후 수정). Answer.AI가 공개한 FSDP+QLoRA 구현은 Llama·Mistral 기준으로 2024년 6월에 마지막 갱신된 탓에, Transformers 4.48에서 제거된 클래스를 import하면서 Qwen3-MoE 지원(4.51부터)과 버전이 어긋나 시작조차 못 했다.
가장 오래 붙잡았던 것은 LlamaFactory에 FSDP를 붙인 구성이다. 30분이 넘도록 학습 스텝이 하나도 끝나지 않았고 시스템 RAM이 계속 차오르다 프로세스가 강제 종료됐다. 원인은 하위 라이브러리인 Transformers가 4비트 양자화 경로에서는 메모리 절약 설정을 경고도 오류도 없이 꺼버린 것이었다. 결과적으로 네 프로세스가 470GB 모델을 각자 RAM에 올려 약 1.9TB를 요구했고, 960GB에서는 버틸 수 없었다. 해당 가드는 지금도 modeling_utils.py에 남아 있고, 관련 LlamaFactory 이슈 #4785는 2024년 7월부터 열려 있다.
실제로 돌아간 조합은 LlamaFactory에 DeepSpeed ZeRO-3와 CPU offload를 켠 것이었다. 모델을 GPU에 상주시키는 것을 포기한 대신, 학습 대상인 어댑터 가중치와 옵티마이저 상태만 네 프로세스에 샤딩했다. 동결된 4비트 베이스는 압축 라이브러리가 행렬을 통째로 필요로 하기 때문에 샤딩되지 않았고, 프로세스마다 120GB 사본을 RAM에 들고 있다가 필요할 때 레이어 단위로 GPU에 복사한 뒤 버리는 방식이었다. 960GB RAM이 있었기에 성립한 구성이다. 대가는 속도였다. 가중치가 매 스텝 RAM과 GPU 사이를 오갔고, GPU에 상주시키는 구성이라면 몇 배는 빨랐을 학습이 26시간으로 늘어났다. 한 번만 돌리면 되는 실험이라 이 지연은 감수했다.
체크포인트 저장도 우회가 필요했다. 학습 파라미터가 네 프로세스에 흩어져 있어 정상 방식으로는 하나의 프로세스에 모아야 하는데 남은 RAM이 부족했다. 프로세스별 조각을 따로 저장한 뒤 DeepSpeed의 zero_to_fp32.py에 --exclude_frozen_parameters를 붙여 어댑터 가중치만 다시 조립했다. 어댑터는 작아서 이 재구성은 몇 분이면 끝난다.
배포하지 않은 이유는 학습과 별개였다. 235B 규모의 thinking 모델을 충분히 빠르게, 그리고 방금 확보한 비용 절감을 유지할 만큼 싸게 서빙하는 일이 파인튜닝보다 큰 프로젝트로 번졌다. 그 작업을 진행하는 사이 문제는 다른 방향에서 풀렸다. 파인튜닝 없이도 분류 워크로드 상당 부분을 처리하는 오픈소스 모델들이 새로 나왔다.
실무적으로 남는 것은 두 가지다. 첫째, 이 규모의 MoE를 QLoRA로 학습할 때 병목은 GPU 성능이 아니라 라이브러리 조합의 호환성이다. 압축과 샤딩, FSDP와 양자화가 서로를 인식하지 못하면 메모리 산수가 맞아도 실행이 안 된다. 둘째, 설정이 조용히 무시되는 동작이 디버깅 비용을 키운다. 이 사례는 특정 고객 문서 분류 작업 하나에 대한 결과이고, 26시간이라는 시간은 학습을 한 번만 돌린다는 전제 위에서 허용된 값이다. 며칠에서 몇 주를 투자해 어렵게 만든 구성이 다음 모델 릴리스 한 번으로 불필요해질 수 있다는 점도 함께 기록해 둘 만하다.