9장. 모델 평가와 활용, QLoRA
2일차 정리
요리 수업의 마지막 시간에는 그날 만든 요리를 한 상에 차려 놓고 돌아봅니다. 재료 손질(데이터), 레시피 양식(Chat Template), 불 조절(LoRA 설정), 시식(평가)까지 각 단계가 결과에 어떻게 이어졌는지 봅니다. 2일차의 네 장(6~9차시)을 한 줄로 놓아 봅니다.
그림은 6장의 모델 준비에서 시작해 7장의 SFT 데이터, 8장의 LoRA 학습, 9장의 평가와 활용으로 이어집니다. 각 상자 아래 숫자는 이 PC 에서 실제로 나온 값입니다.
2일차 핵심
| 주제 | 핵심 포인트 |
|---|---|
| 모델 준비 | Qwen 불러오기, 가중치 메모리 = 파라미터 수 × 바이트 수(BF16 942MB) |
| SFT 데이터 | (요청, 모범 답변) 쌍. 대화 형식 변환 → train 263 / valid 32 / test 32 |
| Chat Template | messages 를 모델별 문자열 꼴로 바꾼다. 학습과 추론에 같은 템플릿 |
| labels | 질문 구간은 -100 으로 가리고 답변과 종료 토큰만 학습 |
| PEFT | 기반 모델은 동결하고 일부 파라미터만 학습해 메모리와 저장 공간을 줄인다 |
| LoRA | 변화량을 작은 행렬 A, B 로 학습. B=0 으로 시작, 병합 가능(1.75% 학습) |
| QLoRA | 4비트 기반 모델 + LoRA. 큰 모델을 GPU 한 장으로 학습 |
| SFTTrainer | 템플릿 적용, 토큰화, 답변 마스킹, 학습 반복을 한 번에 처리 |
| 평가 | 손실(정량) + 답변 직접 읽기(정성) + 부작용 점검 |
| 활용 | 어댑터 교체 운영 또는 병합 배포, RAG 와 조합 |
무엇이 무엇을 정하나
| 요소 | 정하는 것 |
|---|---|
| 데이터 품질 | 결과를 정한다 |
| Chat Template + labels 마스킹 | 모델이 "무엇을" 배우는지 정한다 |
| LoRA 설정(r, target_modules, 학습률, epoch) | "얼마나" 배우는지 정한다 |
| 평가(정량 + 부작용) | 서비스에 써도 되는지 판단한다 |
짧은 예시
import pandas as pd
# 2일차에 이 PC 에서 실제로 나온 숫자를 한 표로 모은다(6~9차시 실행 출력)
day2 = pd.DataFrame([
("6차시", "Qwen 파라미터 수", "494,032,768"),
("6차시", "BF16 가중치 메모리", "942 MB"),
("7차시", "train / valid / test", "263 / 32 / 32"),
("8차시", "LoRA 학습 파라미터", "8,798,208 (1.75%)"),
("8차시", "어댑터 파일", "33.6 MB"),
("9차시", "test loss 학습 전 → 후", "4.044 → 3.19"),
("9차시", "4bit (NF4) 메모리", "430 MB"),
], columns=["장", "항목", "값"])
print(day2.to_string(index=False))
# 결과: 7행 3열의 표. 장, 항목, 값 차례
print(day2.groupby("장").size().to_dict())
# 결과: {'6차시': 2, '7차시': 1, '8차시': 2, '9차시': 2}이 코드가 뜻하는 것
한 상에 차린 요리마다 이름표를 붙인 것과 같습니다. 숫자 하나하나가 어느 장에서 나왔는지 표로 모아 두면, 다시 볼 때 어디를 펼칠지 바로 압니다. 여기서 한 상이 day2, 이름표가 "장" 열입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
pd.DataFrame([...], columns=[...]) | 튜플 목록으로 표를 만든다 | 요리마다 이름표 |
to_string(index=False) | 번호 열 없이 표를 찍는다 | 깔끔하게 차리기 |
groupby("장").size() | 장마다 몇 줄인지 센다 | 장별 요리 수 |
표의 숫자는 모두 이 교안의 실습 출력에 실린 값입니다. 다른 GPU 에서 다시 학습하면 8, 9장의 손실 같은 값은 조금 달라집니다.
주의할 점
- 2일차의 생성 결과는 대부분
do_sample=False로 만들어 다시 실행해도 같습니다. 샘플링(do_sample=True)을 쓰는 셀과 학습 결과는 실행할 때마다, GPU 마다 조금씩 달라집니다. - 0.5B 모델은 연습용으로 고른 작은 모델입니다. 답의 내용이 엉뚱해도 이 과정에서는 "말투와 형식이 바뀌는가"에 집중합니다. 실제 서비스에는 더 큰 모델과 더 많은 데이터가 필요합니다.