LLMLLM 파인튜닝강의 5개 중 2번째난이도 중급

파인튜닝 데이터 준비 — 수집, 정제, 포맷 변환

발행 읽는 시간 약 1 분

  • LLM
  • 파인튜닝
  • 데이터셋
  • HuggingFace
  • 데이터정제

강의 소개

파인튜닝에 필요한 데이터셋을 수집하고, 품질을 검증하고, 모델이 학습할 수 있는 형식으로 변환하는 방법을 배웁니다. Hugging Face Datasets도 활용합니다.

데이터 품질이 결정적#

"Garbage in, garbage out" — 파인튜닝 결과는 데이터 품질에 달려 있습니다.

Diagram · Mermaid

데이터 수집 방법#

Python
# 1. 기존 데이터에서 추출 (고객 Q&A, 지원 티켓 등)
import pandas as pd

support_tickets = pd.read_csv("support_tickets.csv")

# 해결된 티켓만 사용 (질문-답변 쌍)
resolved = support_tickets[support_tickets["status"] == "resolved"]
qa_pairs = resolved[["question", "answer"]].dropna()

# 2. Hugging Face 공개 데이터셋 활용
from datasets import load_dataset

dataset = load_dataset("databricks/databricks-dolly-15k")
print(dataset["train"][0])
# {'instruction': '...', 'context': '...', 'response': '...', 'category': '...'}

# 3. LLM으로 합성 데이터 생성 (Self-Instruct)
from openai import OpenAI
client = OpenAI()

def generate_qa_pair(topic: str) -> dict:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{
            "role": "user",
            "content": f"{topic}에 관한 전문적인 Q&A 쌍을 JSON으로 생성해줘."
        }],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)

데이터 정제#

Python
import re
from datasets import Dataset

def clean_text(text: str) -> str:
    # 이상한 공백 제거
    text = re.sub(r'\s+', ' ', text).strip()
    # HTML 태그 제거
    text = re.sub(r'<[^>]+>', '', text)
    # URL 제거 (선택적)
    text = re.sub(r'https?://\S+', '[URL]', text)
    return text

def is_quality_sample(sample: dict) -> bool:
    instruction = sample.get("instruction", "")
    output = sample.get("output", "")

    # 최소 길이
    if len(instruction) < 10 or len(output) < 20:
        return False

    # 최대 길이 (토큰 초과 방지)
    if len(instruction) > 2000 or len(output) > 4000:
        return False

    # 유해 콘텐츠 필터 (간단한 예시)
    forbidden = ["욕설", "개인정보"]
    if any(word in output for word in forbidden):
        return False

    return True

# 필터 적용
raw_data = [...]  # 원시 데이터
cleaned = [
    {
        "instruction": clean_text(d["instruction"]),
        "output": clean_text(d["output"]),
    }
    for d in raw_data
    if is_quality_sample(d)
]

print(f"원본: {len(raw_data)}, 정제 후: {len(cleaned)}")

ChatML 포맷 변환#

Python
def to_chat_format(sample: dict) -> dict:
    """지시-응답 데이터를 ChatML 대화 형식으로 변환"""
    messages = []

    if system_prompt := sample.get("system"):
        messages.append({"role": "system", "content": system_prompt})

    user_content = sample["instruction"]
    if context := sample.get("input"):
        user_content = f"컨텍스트:\n{context}\n\n질문: {user_content}"

    messages.append({"role": "user", "content": user_content})
    messages.append({"role": "assistant", "content": sample["output"]})

    return {"messages": messages}

# 전체 데이터셋 변환
chat_data = [to_chat_format(d) for d in cleaned]

# HuggingFace Dataset 객체로 변환
dataset = Dataset.from_list(chat_data)

학습/검증/테스트 분할#

Python
from datasets import DatasetDict

# 8:1:1 분할
splits = dataset.train_test_split(test_size=0.2, seed=42)
train_val = splits["train"]
test = splits["test"]

train_val_splits = train_val.train_test_split(test_size=0.1, seed=42)

final_dataset = DatasetDict({
    "train": train_val_splits["train"],   # 72%
    "validation": train_val_splits["test"], # 8%
    "test": test,                           # 20%
})

print(final_dataset)
# DatasetDict({
#     train: Dataset({features: [...], num_rows: 7200})
#     validation: Dataset({features: [...], num_rows: 800})
#     test: Dataset({features: [...], num_rows: 2000})
# })

데이터 통계 확인#

Python
import matplotlib.pyplot as plt

# 길이 분포 확인
instruction_lengths = [len(d["messages"][1]["content"]) for d in chat_data]
output_lengths = [len(d["messages"][-1]["content"]) for d in chat_data]

print(f"지시 평균 길이: {sum(instruction_lengths)/len(instruction_lengths):.0f}자")
print(f"응답 평균 길이: {sum(output_lengths)/len(output_lengths):.0f}자")
print(f"지시 최대 길이: {max(instruction_lengths)}자")
print(f"응답 최대 길이: {max(output_lengths)}자")

정리#

단계핵심 작업
수집기존 데이터 추출, 공개 데이터셋, LLM 생성
정제중복 제거, 길이 필터, 품질 기준 적용
포맷지시-응답 or 대화(ChatML) 형식
분할train/validation/test (8:1:1)
검증길이 분포, 샘플 확인

다음 편에서는 OpenAI 파인튜닝 — API를 통해 GPT 모델을 직접 파인튜닝하는 방법을 배웁니다.

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.