트랜스포머·PEFT 2일 과정6장 · Qwen 모델 준비와 텍스트 생성9 / 17← 이전목차다음 →MetaContents

6장. Qwen 모델 준비와 텍스트 생성

SFT: 대화하는 법을 배우는 단계

책을 많이 읽었지만 상담은 해 본 적 없는 수습생에게 "환불 규정 알려줘"라고 하면, 답하는 대신 "교환 규정 알려줘, 배송 규정 알려줘"처럼 비슷한 질문을 줄줄이 이어 말할 수 있습니다. 인터넷 글을 이어 쓰는 법만 배웠기 때문입니다. 그래서 모범 답안 카드를 주고 상담 연습을 시킵니다. 이것이 SFT 입니다.

사전학습, 지도 미세조정(SFT), 선호도 정렬의 세 단계와 각 단계의 데이터, 목표, 비용, 그리고 Base 모델, Instruct 모델, 정렬된 모델로 이어지는 강사자료 그림

강사자료 그림은 5장에서 본 LLM 학습 3단계입니다. 1단계 사전학습은 수조 토큰의 글로 다음 토큰을 맞히며 Base 모델을 만들고, 2단계 SFT 는 (지시, 모범 답변) 쌍으로 답변 토큰을 맞히며 Instruct 모델을 만들고, 3단계 선호도 정렬은 (선호 답변, 비선호 답변) 쌍으로 선호 답변의 확률을 높입니다. 그림 아래 줄처럼 2일차 실습은 이미 Instruct 인 Qwen2.5 에 우리 데이터로 2단계 SFT 를 LoRA 로 한 번 더 하는 것입니다.

질문 부분은 입력으로만 쓰고 채점하지 않으며, 답변 부분만 맞혔는지 채점한다는 것을 나란히 놓은 비교 그림

SFT 의 학습 원리는 사전학습과 같은 다음 토큰 맞히기입니다. 다른 점은 답변 부분에서만 손실(벌점)을 계산한다는 것입니다. 질문과 <|im_start|> 같은 머리표는 입력으로만 보고 채점에서 뺍니다. 시험지에 문제는 인쇄되어 있고, 학생이 쓴 답만 채점하는 것과 같습니다.

사전학습과 SFT

구분사전학습SFT
데이터웹, 책, 코드의 글(지시, 모범 답변) 쌍을 대화 양식으로 이은 글
맞히는 것모든 토큰의 다음 토큰답변 토큰의 다음 토큰만
채점에서 빼는 곳없음질문, 템플릿 머리표(labels 를 -100 으로)
결과Base 모델(글 이어 쓰기)Instruct 모델(질문에 답하기)
예Qwen2.5-0.5BQwen2.5-0.5B-Instruct

<|im_start|> 같은 특수 토큰으로 대화 구조를 표시하는 규칙이 Chat Template 입니다. 모델이 SFT 때 본 양식과 쓸 때의 양식을 맞추는 것이 2일차 데이터 구성의 핵심입니다. 7장에서 자세히 봅니다.

짧은 예시

Python
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")

question = [{"role": "user", "content": "환불은 언제까지 신청할 수 있나요?"}]
answer = {"role": "assistant", "content": "수령 후 7일 이내에 마이페이지에서 신청하실 수 있습니다."}

# apply_chat_template = 대본 양식 입히기. tokenize=False 면 글자로 보여 준다
print(tokenizer.apply_chat_template(question + [answer], tokenize=False))
# 결과: <|im_start|>system ... <|im_end|> / <|im_start|>user 환불은 ... / <|im_start|>assistant 수령 후 ...<|im_end|>

# 질문까지(답변 시작 머리표 포함)의 토큰과, 답변까지 넣은 전체 토큰
prompt_ids = tokenizer.apply_chat_template(question, add_generation_prompt=True)
full_ids = tokenizer.apply_chat_template(question + [answer])

# 채점표(labels): 질문 부분은 -100(채점 제외), 답변 부분은 원래 토큰 번호
labels = [-100] * len(prompt_ids) + full_ids[len(prompt_ids):]
print(len(full_ids), labels.count(-100), len(labels) - labels.count(-100))
# 결과: 63 42 21

이 코드가 뜻하는 것

시험지 한 장을 만들어, 문제 칸과 답 칸을 나눈 채점표를 붙인 것입니다. 전체 63칸 가운데 42칸(시스템 안내, 질문, 머리표)은 -100 으로 채점에서 빼고, 답변 21칸(답변 글, <|im_end|>, 줄바꿈)만 채점합니다. Qwen 의 양식은 system 줄을 따로 주지 않아도 "You are Qwen ..." 이라는 기본 안내를 맨 앞에 넣습니다.

줄하는 일쉽게 말하면
apply_chat_template(..., tokenize=False)대본 양식을 글자로 본다시험지 인쇄본 보기
add_generation_prompt=True끝에 <|im_start|>assistant 를 붙인다"답:" 칸까지 인쇄
[-100] * len(prompt_ids)질문 부분을 채점 제외로문제 칸은 채점 안 함
full_ids[len(prompt_ids):]답변 부분의 토큰 번호학생이 쓴 답 칸

실습 2의 chat 함수도 add_generation_prompt=True 로 "답:" 칸까지 인쇄한 시험지를 모델에 줍니다. 학습 때의 양식과 쓸 때의 양식이 같아야 모델이 바로 답을 씁니다.

주의할 점

  • SFT 는 데이터의 말투와 형식을 그대로 따라 합니다. 모범 답변에 틀린 내용이나 나쁜 습관이 있으면 그것도 배웁니다. 데이터 품질이 결과를 정합니다.
  • 실제 학습에서는 7장의 도구(SFTTrainer 의 설정)가 이 -100 채점표를 만들어 줍니다. 손으로 만드는 것은 원리를 보려는 것입니다.
← 이전 절6장 · 디코딩 전략: temperature, top-k, top-p다음 절 →6장 · 선호도 정렬: 더 나은 답을 고르는 법