12장. 멀티모달 RAG 와 데이터셋 자동 생성
데이터셋 나누기와 기록
수능 문제를 미리 본 학생의 점수는 실력이 아닙니다. 학습 데이터에 시험 문제가 섞이면 점수가 부풀려집니다. 데이터셋은 시험용을 따로 두고, 어디서 어떻게 만들었는지 기록을 남깁니다.
왼쪽은 시험 문제를 생성 데이터에서 떼어 내지 않고 사람이 따로 쓰는 것입니다. 가운데는 학습 데이터에 시험 문제와 같은 질문이 없는지 확인하는 것입니다. 오른쪽은 생성 모델, 지시, 거르기 기준, 남은 수를 데이터셋 카드로 남기는 것입니다. 여기서 미리 본 수능 문제가 데이터 누출입니다.
기록할 것
| 칸 | 예 | 왜 |
|---|---|---|
| 원래 문서 | care_guide.md, 절 12개 | 문서가 바뀌면 다시 만든다 |
| 생성 모델과 설정 | qwen2.5:3b, 온도 0.3, 씨앗 42, 7 | 같은 데이터를 다시 만들 수 있게 |
| 거르기 기준과 남은 수 | 기준마다 걸린 수 | 데이터가 어디서 줄었는지 |
| 시험 묶음 | 사람이 쓴 질문 12개 | 점수가 무엇을 잰 것인지 |
| 라이선스, 개인정보 | 사내 문서, 개인정보 없음 | 학습해도 되는 자료인지 |
누출 확인하기
train_q = ["선물 포장은 얼마예요?", "교환은 며칠 안에 해요?"]
test_q = ["선물 포장 비용은 얼마인가요?", "교환은 며칠 안에 해요?"]
norm = lambda s: s.replace(" ", "").rstrip("?")
leak = [q for q in test_q if norm(q) in {norm(t) for t in train_q}] # 띄어쓰기만 다른 같은 질문도 잡는다
print("겹친 시험 질문:", leak)코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
lambda s: ... | lambda(람다)는 이름 없는 짧은 함수를 만드는 말이다. 여기서는 질문을 견주기 좋게 다듬는 함수다 |
.replace(" ", "") | 띄어쓰기를 모두 지운다 |
.rstrip("?") | right strip 의 줄임이다. 오른쪽 끝의 물음표를 뗀다 |
{norm(t) for t in train_q} | 다듬은 학습 질문의 집합(set)이다. 같은 것은 하나만 남고, 들어 있는지 빨리 찾는다 |
q for q in test_q if ... in ... | 시험 질문 가운데 학습 질문 집합에 들어 있는 것만 고른다 |
이 코드가 뜻하는 것
도서관이 새 책을 들일 때는 이미 서가에 있는 책인지 목록과 대조합니다. 제목의 띄어쓰기나 물음표 같은 작은 차이는 무시하고 견줍니다. 여기서 서가 목록이 학습 질문 집합, 새로 들어온 책이 시험 질문, 작은 차이를 무시하는 일이 norm 입니다. 다만 사서는 같은 내용의 다른 제목도 알아보지만, 이 코드는 다듬은 글자가 똑같아야만 잡습니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
train_q = [...] | 학습 데이터의 질문 | 서가에 있는 책 |
test_q = [...] | 시험 질문 | 새로 들어온 책 |
norm = lambda s: ... | 띄어쓰기와 끝 물음표를 지운다 | 제목의 작은 차이 무시 |
leak = [...] | 학습 질문과 같은 시험 질문을 모은다 | 이미 있는 책 골라내기 |
실행하면 겹친 시험 질문: ['교환은 며칠 안에 해요?'] 가 나옵니다. "선물 포장 비용은 얼마인가요?"는 묻는 사실이 학습 질문과 같지만 글자가 달라 잡히지 않습니다. 아래 주의할 점의 둘째 줄처럼, 이런 질문은 누출이 아니라 미세조정이 잘 됐는지 재는 문제입니다.
주의할 점
- 글자가 같은 질문만 찾으면 말만 바꾼 질문은 놓칩니다. 임베딩 유사도가 아주 높은 쌍도 함께 봅니다.
- 시험 질문이 학습 질문과 말만 다르고 묻는 사실이 같은 것은 누출이 아닙니다. 미세조정이 "외운 사실을 다른 말로 물어도 답하는가"를 재는 것이기 때문입니다.