내 노트북으로 270M 모델 파인튜닝하기 (Full Fine-Tuning, 처음부터)
요약
Gemma 270M 모델을 사용하여 노트북 환경에서 Full Fine-tuning을 수행하는 과정을 다룹니다. Banking77 데이터셋을 활용해 분류 헤드 대신 텍스트 생성 방식을 채택하여 인스트럭션 튜닝과 동일한 구조를 구축하는 방법을 설명합니다.
핵심 포인트
- Gemma 270M 모델을 활용해 Apple Silicon 노트북에서 Full Fine-tuning 실습
- 분류 헤드 대신 텍스트 생성 방식을 사용하여 LoRA/QLoRA와의 일관성 유지
- 손실 계산 시 프롬프트 토큰을 마스킹하여 레이블 학습 효율 극대화
- 전체 파인튜닝 시 높은 학습률은 기존 지식을 파괴할 위험이 있음
시리즈 — 파인튜닝 (Fine-Tuning), 가장 작은 모델부터 가장 큰 모델까지 (동일한 작업, 세 가지 기술, 가장 작은 모델부터 가장 큰 모델까지):
- Full Fine-Tuning (270M) ← 현재 위치
- LoRA (1.5B)
- QLoRA (7B)
- 작은 모델이 잘 작동했다면, 왜 더 큰 모델로 가야 할까요?
저는 단순히 튜토리얼을 따라 하며 고개를 끄덕이는 것이 아니라, 파인튜닝 (Fine-tuning)을 실제로 _이해_하고 싶었습니다. 그래서 스스로 제약을 걸었습니다: 동일한 작업, 세 가지 기술, 가장 작은 모델부터 가장 큰 모델까지. Full Fine-tuning, 그 다음 LoRA, 그 다음 QLoRA 순서로 진행합니다. 작업은 고정하고 유일한 변수는 방법론뿐입니다.
이 첫 번째 포스트는 가장 강력하고 가장 비용이 많이 드는 옵션인 Full Fine-tuning에 관한 것입니다: 모델의 모든 가중치(weight)를 업데이트합니다.
작업 (The task)
Banking77: 약 13,000개의 실제 은행 고객 지원 메시지, card_arrival, lost_or_stolen_card, exchange_rate와 같은 77개의 의도(intents)가 포함되어 있습니다. 모델은 메시지를 읽고 그 의도를 명명합니다.
모델: 의도적으로 아주 작게
저는 **Gemma 3, 270M 파라미터 (parameters)**를 선택했습니다. 노트북(Apple Silicon / MPS)에서 전체 파인튜닝 (Full fine-tuning)을 수행하기에 충분히 작습니다. 이는 의도적인 선택입니다. Full fine-tuning은 모든 파라미터에 대한 그래디언트 (gradients)와 옵티마이저 상태 (optimizer state)를 저장하므로, 메모리 사용량이 모델 크기의 약 4배에 달합니다. 저는 이를 글로 읽는 것이 아니라 직접 느껴보고 싶었습니다.
한 가지 설계 결정: 분류하지 말고 레이블을 생성하라
뻔한 접근 방식은 모델에 77개의 클래스를 가진 분류 헤드 (classification head)를 부착하는 것입니다. 저는 그렇게 하지 않았습니다. 대신 모델이 **의도를 텍스트로 생성(generate)**하도록 했습니다. 말 그대로 card_arrival를 출력하게 만든 것입니다. 왜일까요? 이것이 인스트럭션 튜닝 (instruction-tuning)과 동일한 형태이기 때문에, 이후의 LoRA/QLoRA 프로젝트들이 이 프로젝트를 자연스럽게 이어받을 수 있기 때문입니다.
핵심적인 세부 사항은 손실 (loss)을 마스킹 (masking)하여 모델이 프롬프트 (prompt)가 아닌 _레이블 (label) 토큰에 대해서만 평가받도록 하는 것입니다:
# "프롬프트 + 레이블"을 구축하되, 프롬프트 토큰을 -100으로 설정하여 손실 계산에서 제외합니다.
prompt_ids = tokenizer(prompt, add_special_tokens=False)["input_ids"]
target_ids = tokenizer(" " + label_name + tokenizer.eos_token,
...
만약 그 마스킹 (masking) 과정을 건너뛴다면, 모델은 정답을 배우는 대신 프롬프트 (prompt)를 재현하는 데 용량을 소모하게 됩니다.
나를 놀라게 한 점: 전체 파인튜닝 (Full FT)은 취약하다
사전 학습된 (pretrained) 모든 가중치 (weights)를 업데이트하기 때문에, 너무 높은 학습률 (learning rate)은 모델이 기존에 가진 지식을 파괴합니다. 저는 5e-5를 사용했고 깔끔하게 학습되었습니다. 2e-4로 높였더니 불안정해졌습니다. 그 외의 학습 설정 (training config)은 평범합니다. 그리고 바로 그 점이 핵심입니다:
TrainingArguments(
num_train_epochs=3,
per_device_train_batch_size=16,
...
(이후 프로젝트들은 베이스 (base)를 동결 (freeze) 시키는데, 바로 그 점 때문에 훨씬 더 높은 학습률을 견딜 수 있는 것입니다. 파괴할 취약한 사전 학습 지식이 없기 때문입니다.)
결과
일반적인 의도 (intents)에 대해 약 96%의 정확도를 보였습니다. 거의 완벽한 대각선 형태의 혼동 행렬 (confusion matrix)을 나타냅니다. 노트북에서 전체 파인튜닝 (fully fine-tuned)된 270M 모델이 작업을 완벽히 수행해냈습니다.
한 가지 지속적인 실수: **card_arrival**를 **card_delivery_estimate**와 혼동했습니다. 이 점을 유념해 두세요. 이 실수는 이 시리즈의 모든 프로젝트에서 나타나며, 그 이유는 4부의 핵심 결론 (punchline)입니다.
다음 단계
2부에서는 5배 더 큰 모델을 가져와 모델의 1% 미만만을 학습시키고도 동일한 정확도를 얻는 과정을 다룹니다. 그것이 바로 LoRA입니다.
📓 Kaggle에서 실행 가능한 전체 노트북: https://www.kaggle.com/code/sumannath88/01-full-finetune-gemma270m
PyTorch + Hugging Face Transformers로 제작되었습니다. 질문이나 수정 사항은 댓글로 환영합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기