SFT 다음에 DPO가 필요한 이유
TL;DR
- SFT(지도 미세조정) 는 입출력 형식·스키마·톤을 모델에 각인시키는 단계다.
- DPO(Direct Preference Optimization) 는 정답/오답 쌍(chosen/rejected)으로 모델의 선호를 정렬한다. SFT만으로 안 되는 “더 나은 응답 고르기”를 다룬다.
- 고성능 출시를 목표로 할 때, 형식 검증은 SFT로 잡고, 품질 판단은 DPO로 밀어붙이는 순서가 덜 후회된다.
- 데이터가 레거시 코퍼스에서 나오면 “옛날 기준”까지learn 될 수 있어서, chosen/rejected 설계에 주의가 필요하다.
들어가며
도메인 API에 LLM을 붙이다 보면 결국 이 순서로 질문이 돌아온다.
- 프롬프트(few-shot)로 버티는가?
- 안 되면 SFT를 돌릴 것인가?
- SFT까지 했는데도 “뭔가 좀 아쉽다” — 이때 다음 단계로 DPO가 나온다.
SFT가 필요할 때 글에서 “형식은 few-shot, 반복되는 정답 선택은 SFT”라고 썼다. 이번에 말할 건 그다음이다. SFT로 형식은 맞췄는데, 응답이 “틀리진 않지만 더 나은 표현·덜 지루한 설명·함정이 적은 답안”을 안정적으로 못 낼 때가 있다. 그때 chosen/rejected 데이터로 선호를 학습시키는 선택지, 즉 DPO를 고민하게 된다.
1. SFT가 하는 일 — 다시 정리
SFT는 (입력 → 정답) 쌍으로 모델을 추가로 학습시키는 것이다. LoRA/Q-LoRA처럼 base는 두고 adapter만 뽑는 방식이 실무에서 흔하다.
앞서 LoRA vs Q-LoRA 글에서 썼듯, 양자화 여부에 따라 adapter도 달라진다. 구조는 비슷해도 학습 경로가 다르면 결과도 다르다.
SFT가 잘 풀리는 구간은 대략 이렇다.
- 출력 포맷 고정 (JSON 스키마, 키 이름, 설명 금지)
- 도메인 톤·역할 정렬
- 반복되는 슬롯 채우기 (같은 유형에 같은 정답이 필요한 경우)
즉 SFT는 “무얼 출력해야 하는가”를 가르치는 데 강하다. 반대로 “여러 정답 후보 중 어느 쪽이 더 나은가”는 SFT alone로 잡기 까다롭다. 정답 1개만 넣는 데이터로는 선호 순서를 학습하기 어렵기 때문이다.
2. 왜 DPO 이야기가 나오는가
DPO의 핵심 아이디어는 간단하다.
- chosen(정답으로 삼고 싶은 응답)과 rejected(피하고 싶은 응답) 쌍을 준다
- chosen이 rejected보다 높은 점수를 받도록 모델을 조정한다
- 중간에 별도 보상 모델(reward model)을 굳이 세우지 않고, 선호 데이터를 직접 학습에 넣는 방식이 DPO의 등장으로 많이 정리됐다
여기서 중요한 건 “틀림/맞음”이 아니라 “더 좋음/덜 좋음”이라는 점이다. SFT가 “정답 복제”에 가깝다면, DPO는 “선호 순서”를 배운다. 그래서 같은 질문에도 더 자연스럽고 덜 장황한 응답, 함정이 적은 표현, 사용자 의도를 덜 벗어나는 답을 만드는 방향으로 쓰일 수 있다.
물론 마법처럼 만능이 되는 건 아니다. chosen/rejected 데이터 설계가 엉망이면 모델도 그 영향을 그대로 받는다.
3. 실제 파이프라인에서 어디에 끼는가
일반적인 흐름:
- few-shot / 프롬프트 — 형식·스키마·톤을 빠르게 고정
- SFT — 반복되는 입출력 쌍을 데이터로 굳힘 (LoRA/Q-LoRA 등)
- DPO — chosen/rejected로 “더 나은 응답” 쪽으로 정렬
- 평가/루프 — 로그를 보고 실패 패턴이 남으면 데이터·라벨부터 고침
여기서 순서를 건너뛰면 보통 후회가 남는다.
- 프롬프트 좀 길어졌다고 바로 DPO로 도망가면, 데이터 없이 학습부터 하는 셈
- SFT도 안 붙였는데 DPO부터 생각하면, 형식조차 흔들리는 상태에서 선호만 얘기하게 됨
- 반대로 SFT로 형식 잡혔다고 “끝”이라 생각하면, 출력 품질·선호 개선이 남았는데 놓침
한 줄로 말하면: SFT는 “무엇을” 맞추게 하고, DPO는 “어느 쪽이 더 나은지”를 밀어붙인다. 둘은 경쟁이라기보다 단계·보완에 가깝다.
4. 데이터 포맷과 함정
DPO를 얘기할 때 실제 운영에서 걸리는 건 대개 데이터다.
- chosen이 정말 chosen인가? — 검수 기준이 모호하면 모델이 배우는 “선호”도 흐릿해진다
- rejected가 너무 약한가? — 학습에 쓸 rejected가 정답과 거의 차이 없으면 신호가 약하다
- 레거시 코퍼스 오염 — 예전 기준에 맞춘 데이터를 그대로 쓰면 “옛날 습관”까지learn 될 수 있다
- 평가 없이 좋아졌다고 착각 — 체감만으로 정렬을 판단하면, 지표·엣지에서 다시 샌다
그래서 DPO를 넣기 전에, chosen/rejected가 실제로 어떤 기준으로 갈렸는지부터 적는 게 좋다. “더 짧고 정확해서”, “함정 표현이 없어서”, “사용자 질문 의도를 덜 비틀어서” 같은 이유가 데이터 셀마다 붙어 있어야 나중에 루프 돌릴 때 덜 헤맨다.
5. 흔한 착각
- SFT 하면 DPO는 필요 없다 — 형식·슬롯은 잡히지만, “더 나은 응답” 선택은 남았다.
- DPO 하면 프롬프트/RAG가 필요 없다 — 아니다. DPO는 품질을 다듬는 쪽이고, 최신·대량 지식은 여전히 검색/갱신이 필요한 구간이다.
- 데이터만 있으면 자동으로 좋아진다 — chosen/rejected의 기준과 오염 여부가 결과를 크게 바꾼다.
- 한 번 돌리고 끝 — 로그가 쌓이면 선호 데이터도 갱신되는 게 자연스럽다. 고정보다는 루프가 맞다.
6. 실무에서 언제 꺼내볼까
바로 꺼내도 되는 경우:
- 형식·스키마는 SFT/프롬프트로 충분히 잡혔다
- chosen/rejected를 만들 검수 기준이 서 있다
- “틀리진 않지만 더 나은 답”을 원하는 구간이 명확하고, 그 차이를 데이터로 남길 수 있다
- 평가셋이 있어서 “좋아졌는지”를 말 할 수 있다
아직 시기상조인 경우:
- 형식 자체가 아직 흔들린다 (먼저 SFT/프롬프트)
- chosen/rejected 라벨이 없다 (먼저 데이터·검수 체계)
- 실패 원인이 검색·인덱스·파서 쪽인데 모델만 보고 있다
- 평가 없이 “느낌상 좋아졌네”만 가능한 상황
마무리
SFT 다음에 DPO를 생각하는 건, “정답”은 맞췄는데 “더 나은 응답”을 안정적으로 뽑고 싶을 때다.
- 형식은 SFT로 굳히고
- chosen/rejected로 선호를 정렬하고
- 레거시 코퍼스·검수 기준·평가셋을 같이 챙기고
- 로그가 쌓이면 데이터도 같이 갱신한다
이 순서는 “학습부터 던지고 보자”가 아니라, “형식을 잡고, 선호 데이터를 쌓고, 그중 더 나은 쪽으로 밀어준다”에 가깝다. DPO가 만능은 아니지만, 형식 위에 품질을 올리는 루프에서 꽤 자주 등장하는 도구다.
Comments