LLM 엔지니어링12장 · 멀티모달 RAG 와 데이터셋 자동 생성11 / 22← 이전목차다음 →MetaContents

12장. 멀티모달 RAG 와 데이터셋 자동 생성

생성 데이터 거르기

문제집을 인쇄하기 전에는 검수를 합니다. 문제와 답이 교과서와 맞는지, 같은 문제가 두 번 나오지 않는지, 글자가 깨지지 않았는지 봅니다. 생성한 질문-답도 학습에 넣기 전에 같은 검수를 거칩니다.

JSON 꼴, 답의 근거, 중복, 깨진 글자의 네 가지 거르기 기준을 견준 카드

네 카드는 이 장의 거르기 기준입니다. 꼴은 질문과 답이 비어 있지 않은지, 근거는 답의 숫자와 낱말이 원래 절에 있는지, 중복은 뜻이 거의 같은 질문이 이미 있는지, 글자는 한자나 러시아 문자처럼 섞이면 안 되는 글자가 있는지 봅니다. 여기서 교과서와 맞는지 보기가 근거 확인입니다.

기준과 거르는 법

기준걸리는 예거르는 법
꼴답이 비었다, 질문이 너무 짧다길이와 빈칸을 본다
근거답의 "3,000원"이 원래 글에 없다답의 숫자가 모두 원래 글에 있고, 낱말이 절반 넘게 겹치는지
중복"언제까지 교환해요?"와 "교환 기한이 언제예요?"질문 임베딩의 코사인 유사도가 0.92 이상이면 하나만
글자"팔ается가요", "꽃鉢"한자, 가나, 키릴 문자가 있으면 뺀다

근거 확인하기

Python
import re

source = "방수 덮개는 2,000원에 따로 팝니다."

def grounded(answer, source):
    """답의 숫자가 모두 원래 글에 있고, 답의 두 글자 묶음이 절반 넘게 원래 글에 있으면 True"""
    nums = re.findall(r"\d[\d,]*", answer)
    if any(n.replace(",", "") not in source.replace(",", "") for n in nums):
        return False
    a = answer.replace(" ", "")
    pairs = [a[i:i + 2] for i in range(len(a) - 1)]
    return sum(p in source.replace(" ", "") for p in pairs) / max(len(pairs), 1) > 0.5

print(grounded("방수 덮개는 2,000원입니다.", source), grounded("방수 덮개는 3,000원입니다.", source))

코드에 나오는 함수

코드쉬운 뜻
re.findall(r"\d[\d,]*", answer)\d 는 digit(숫자)이다. 숫자로 시작해 숫자나 쉼표가 이어지는 덩어리를 모두 찾는다
n.replace(",", "")쉼표를 지워 "2,000"과 "2000"을 같게 본다
any(...)하나라도 참이면 True 다. 원래 글에 없는 숫자가 하나라도 있으면 바로 False 를 돌려준다
a[i:i + 2]i 번째부터 두 글자를 잘라 낸다. 두 글자 묶음(bigram)이라고 한다
sum(p in ... for p in pairs)원래 글에 있는 묶음을 1, 없는 묶음을 0 으로 세어 더한다
max(len(pairs), 1)묶음이 하나도 없을 때 0 으로 나누지 않게 한다
> 0.5묶음의 절반을 넘게 원래 글에 있어야 통과한다

이 코드가 뜻하는 것

장을 보고 영수증을 확인할 때는 먼저 찍힌 값이 진열대 가격표와 같은지 보고, 그다음 품목 이름이 맞는지 훑어봅니다. 여기서 영수증이 생성한 답, 가격표가 원래 글, 값 확인이 숫자 검사, 품목 이름 훑기가 두 글자 묶음의 겹침 검사입니다. 다만 영수증은 하나라도 틀리면 다시 계산하지만, 이 함수의 글자 검사는 절반만 넘게 겹치면 통과시킵니다.

줄하는 일쉽게 말하면
nums = re.findall(...)답에 든 숫자를 모두 뽑는다영수증의 값들
if any(...): return False원래 글에 없는 숫자가 있으면 바로 탈락가격표에 없는 값이 찍혔다
a = answer.replace(" ", "")답의 띄어쓰기를 지운다품목 이름의 빈칸 무시
pairs = [...]답을 두 글자 묶음으로 자른다품목 이름을 조각내 본다
return sum(...) / ... > 0.5원래 글에 있는 묶음의 비율이 절반을 넘는지이름이 대체로 맞나

실행하면 True False 가 나옵니다. 첫 답은 숫자 2,000 이 원래 글에 있어 통과하고, 둘째 답은 3,000 이 원래 글에 없어 글자를 볼 것도 없이 탈락합니다.

작게 줄여서 눈으로 보기

설명을 위해 지어낸 글로 숫자 찾기와 두 글자 묶음이 어떻게 나오는지 봅니다.

Python
import re

a = "덮개는3,000원"
print(re.findall(r"\d[\d,]*", "덮개는 3,000원, 우산은 12,500원"))
print([a[i:i + 2] for i in range(len(a) - 1)])
출력
['3,000', '12,500']
['덮개', '개는', '는3', '3,', ',0', '00', '00', '0원']
결과읽는 법
['3,000', '12,500']쉼표가 든 큰 숫자도 한 덩어리로 찾는다. 숫자 뒤의 "원"은 숫자도 쉼표도 아니라서 덩어리가 거기서 끝난다
묶음 8개띄어쓰기를 지운 9 글자를 한 칸씩 밀며 두 글자씩 잘랐다. 글자가 n 개면 묶음은 n-1 개다
'00' 두 번같은 묶음이 여러 번 나오면 여러 번 센다

주의할 점

  • 거르기는 틀린 데이터를 줄일 뿐 없애지는 못합니다. 걸러 낸 뒤에도 표본을 사람이 읽어 봅니다.
  • 거르면 데이터가 줄고, 어떤 사실은 통째로 빠질 수 있습니다. 걸러 낸 뒤 "시험에 나올 사실이 데이터에 남아 있는지"를 세어 봅니다(실습 6).
← 이전 절12장 · 미세조정 데이터셋 자동 생성다음 절 →12장 · 데이터셋 나누기와 기록