추론 vs 파인튜닝 — 남의 모델 쓰기와 내 모델 만들기의 차이
pipeline()은 배달 시켜먹기, 파인튜닝은 레시피 받아서 내 입맛에 간 조절하기
흔한 오해: 파인튜닝 = 학습된 모델을 사용하는 것?
아니다. 그건 추론이다.
추론(inference): 남이 만든 모델을 가져다 "사용"
파인튜닝(fine-tuning): 남이 만든 모델을 베이스로 내 데이터로 "재훈련" → 내 모델이 됨
| 추론 | 파인튜닝 | |
|---|---|---|
| 비유 | 배달 시켜먹기 | 레시피 받아서 내 입맛에 간 조절 |
| 코딩 비유 | npm install해서 그냥 쓰기 | fork해서 내 코드 추가 후 빌드 |
| 모델 | 남의 모델 | 내 모델 (남의 모델 기반) |
| 데이터 | 필요 없음 | 필요함 (학습 재료) |
| GPU | 없어도 됨 | 있으면 좋음 |
| 시간 | 즉시 | 수 분~수 시간 |
추론: 이전에 했던 것
from transformers import pipeline
# 남이 만든 모델을 그대로 가져다 사용
classifier = pipeline("sentiment-analysis")
print(classifier("I love this product!"))
# → [{'label': 'POSITIVE', 'score': 0.9998}]
이건 HuggingFace에 올라와 있는 이미 완성된 모델을 다운로드해서 쓴 것이다. 내가 훈련한 게 아니다.
파인튜닝: 내 모델을 만드는 것
파인튜닝을 하려면 3가지가 필요하다:
- 베이스 모델 — 이미 잘 훈련된 모델 (DistilBERT 등)
- 데이터셋 — "이 문장은 긍정, 이 문장은 부정" 같은 학습 재료
- 훈련 코드 — HuggingFace Trainer가 거의 다 해줌
데이터셋은 어디서 오나?
HuggingFace Hub에 모델만 있는 게 아니다. 데이터셋도 있다.
huggingface.co/models → 학습된 모델 100만+
huggingface.co/datasets → 학습용 데이터 20만+ ← 여기
from datasets import load_dataset
# HuggingFace에서 IMDB 영화 리뷰 데이터셋 자동 다운로드
dataset = load_dataset("imdb")
print(dataset)
# DatasetDict({
# train: Dataset({features: ['text', 'label'], num_rows: 25000})
# test: Dataset({features: ['text', 'label'], num_rows: 25000})
# })
print(dataset["train"][0])
# {'text': 'I rented this movie and...', 'label': 1} ← 1=긍정, 0=부정
IMDB 데이터셋의 구조는 이렇다:
문장(text) 라벨(label)
"This movie was absolutely fantastic!" 1 (positive)
"Terrible acting, worst film ever" 0 (negative)
"The plot was boring and predictable" 0 (negative)
"A masterpiece of modern cinema" 1 (positive)
... (25,000개)
이건 테스트 데이터가 아니라 훈련용 학습 재료다. 모델에게 "이런 문장은 긍정, 이런 문장은 부정"이라고 가르치는 데 쓴다.
파인튜닝이 "파인(fine)"인 이유
처음부터 훈련하는 게 아니라, 이미 잘 훈련된 모델을 살짝만 조정하는 거라서 fine(미세한) tuning(조정)이다.
처음부터 훈련 (pre-training):
백지 상태 → 인터넷 전체 텍스트로 수개월 훈련 → 기본 모델
(GPU 수천 개, 수억 원, OpenAI/Google/Meta급)
파인튜닝 (fine-tuning):
기본 모델 → 내 데이터 수천 개로 수 시간 훈련 → 내 모델
(노트북 GPU 1개면 됨)
DistilBERT는 이미 영어 문법, 단어 의미, 문맥을 이해하고 있다. 거기에 "이런 문장은 긍정, 이런 문장은 부정"만 추가로 가르치면 된다. 영어를 처음부터 가르칠 필요가 없다.
감정 분석 파인튜닝 전체 코드
진짜 이게 전부다:
from datasets import load_dataset
from transformers import (AutoTokenizer, AutoModelForSequenceClassification,
Trainer, TrainingArguments)
# 1. 데이터 로드 (HuggingFace에서 자동 다운로드)
dataset = load_dataset("imdb")
# 2. 토크나이저 (텍스트 → 숫자 변환)
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
dataset = dataset.map(
lambda x: tokenizer(x["text"], truncation=True, padding="max_length", max_length=512),
batched=True
)
# 3. 베이스 모델 + 분류 헤드 (긍정/부정 2개 클래스)
model = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased", num_labels=2
)
# 4. 훈련 (이게 파인튜닝)
trainer = Trainer(
model=model,
train_dataset=dataset["train"].select(range(1000)), # 1000개만 (빠른 테스트)
eval_dataset=dataset["test"].select(range(200)),
args=TrainingArguments(
output_dir="./my-sentiment-model",
num_train_epochs=3,
per_device_train_batch_size=8
)
)
trainer.train() # ← 여기서 내 모델이 만들어진다
trainer.save_model() # ./my-sentiment-model/ 에 저장
# 5. 내 모델로 추론
my_pipe = pipeline("sentiment-analysis", model="./my-sentiment-model")
print(my_pipe("This movie was absolutely fantastic!"))
# → [{'label': 'LABEL_1', 'score': 0.9876}] (1=positive)
각 단계에서 무슨 일이 일어나나
load_dataset("imdb")
→ HuggingFace Hub에서 25,000개 영화 리뷰 + 라벨 다운로드
tokenizer("This movie was fantastic!")
→ [101, 2023, 3185, 2001, 10392, 999, 102] (룩업 테이블)
AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2)
→ 이미 영어를 이해하는 DistilBERT를 가져옴
→ 맨 위에 "2개 클래스 분류 레이어"를 새로 붙임
→ 이 새 레이어만 훈련하면 됨 (나머지는 이미 학습됨)
trainer.train()
→ 1000개 리뷰를 보여주면서 "이건 긍정, 이건 부정" 학습
→ 3 에폭 (같은 데이터를 3번 반복)
→ 수 분이면 끝남
pipeline("sentiment-analysis", model="./my-sentiment-model")
→ 내가 훈련한 모델을 로드해서 추론
왜 감정 분석이 파인튜닝 입문에 가장 적합한가
| 요소 | 감정 분석 | 텍스트 생성 | 번역 |
|---|---|---|---|
| 데이터 형태 | 문장 + 라벨 (2열 CSV) | 대규모 코퍼스 | 병렬 코퍼스 |
| 출력 | 숫자 1개 (긍정/부정) | 문장 N개 (가변 길이) | 문장 1개 (다른 언어) |
| 평가 | 정확도 (맞았나 틀렸나) | BLEU/ROUGE (복잡) | BLEU (복잡) |
| 모델 수정 | 마지막 레이어만 교체 | 전체 모델 조정 | 인코더-디코더 전체 |
| 훈련 시간 | 수 분 | 수 시간~수 일 | 수 시간~수 일 |
| 데이터 구하기 | 쉬움 (IMDB, NSMC) | 어려움 | 매우 어려움 |
감정 분석은 모든 면에서 가장 단순하다.
다음 단계: 내 데이터로 파인튜닝
IMDB로 연습한 후에는 내 데이터를 쓸 수 있다:
# 내 CSV 파일로 파인튜닝
# my_reviews.csv:
# text,label
# "배송이 빨라서 좋았어요",1
# "품질이 별로예요",0
# ...
from datasets import load_dataset
dataset = load_dataset("csv", data_files="my_reviews.csv")
한국어를 하고 싶으면:
# NSMC (네이버 영화 리뷰 20만 개)
dataset = load_dataset("nsmc")
# 베이스 모델도 한국어용으로
model = AutoModelForSequenceClassification.from_pretrained(
"klue/bert-base", num_labels=2 # 한국어 BERT
)
HuggingFace Hub의 전체 그림
huggingface.co/
├── models (100만+) ← 학습된 모델 (추론용 / 파인튜닝 베이스)
├── datasets (20만+) ← 학습 데이터 (파인튜닝용 재료)
└── spaces (50만+) ← 데모 앱 (Gradio/Streamlit)
세 가지가 전부 Hub에 있다:
models = npm 패키지
datasets = npm 패키지가 의존하는 테스트 데이터/학습 데이터
spaces = npm 패키지의 라이브 데모
# 모델 다운로드
pipeline("sentiment-analysis", model="distilbert/distilbert-base-uncased-finetuned-sst-2-english")
# 데이터셋 다운로드 (같은 인터페이스!)
load_dataset("imdb")
load_dataset("nsmc")
load_dataset("squad")
load_dataset("csv", data_files="my_data.csv") # 내 파일도 가능
파인튜닝에 대한 흔한 오해 3가지
파인튜닝을 처음 접하면 거의 100% 이런 오해를 한다. 정리해둔다.
오해 1: 파인튜닝 = 학습된 모델을 "사용"하는 것?
아니다. 그건 추론(inference)이다.
추론: pipeline("sentiment-analysis") → 남의 완성 모델을 그냥 사용
파인튜닝: trainer.train() → 남의 모델을 내 데이터로 재훈련 → 내 모델
오해 2: IMDB 데이터를 기존 모델에 "합치는" 것?
아니다. 합치는 게 아니라 기존 모델의 가중치를 조정하는 것이다.
❌ 기존 모델 + IMDB 데이터 = 새 모델 (합치기가 아님)
✅ 기존 모델의 66M개 숫자를 IMDB로 살짝 조정 = 새 모델 (조정)
DistilBERT는 66M개의 숫자(가중치)로 이루어져 있다. 파인튜닝은 이 숫자들을 IMDB 데이터를 보면서 하나씩 미세하게 바꾸는 과정이다. 뭔가를 더하거나 합치는 게 아니다.
비유하면 — 대학 졸업생(DistilBERT)한테 업무 매뉴얼(IMDB)로 OJT를 시키는 것이다. 대학에서 배운 지식에 매뉴얼을 "합치는" 게 아니라, 이미 있는 지식 위에서 새로운 기술을 익히는 것이다.
오해 3: 원래 훈련 데이터(Wikipedia 등)에 내 데이터를 "추가"하는 것?
아니다. 원래 훈련 데이터는 전혀 건드리지 않는다.
Pre-training (이미 끝남, 우리와 무관):
백지 + Wikipedia/인터넷 전체 → 수개월 → DistilBERT
(이 데이터는 더 이상 사용 안 함)
Fine-tuning (우리가 함):
DistilBERT(완성품) + IMDB(새 데이터만) → 수 시간 → 내 모델
(Wikipedia는 이 과정에 등장하지 않음)
원래 데이터(Wikipedia)는 이미 모델의 가중치(66M개 숫자) 안에 "녹아있다". 파인튜닝은 그 가중치를 새 데이터로 미세 조정할 뿐이다.
AI에서 "더하기/합치기"는 기본적으로 없다
❌ 모델A + 모델B = 모델C (안 됨)
❌ 데이터A + 데이터B → 모델에 주입 (이런 개념이 아님)
✅ 모델의 숫자 66M개를 조금씩 조정 (이게 거의 전부)
AI의 핵심 동작은 "숫자를 조정한다" 하나로 귀결된다. 합치기보다는 깎기/다듬기에 가깝다.
예외적으로 "더하기" 비슷한 기법이 있긴 하다:
| 기법 | 뭘 하나 | 합치기? |
|---|---|---|
| 파인튜닝 | 기존 가중치를 조정 | ❌ 조정 |
| LoRA | 작은 어댑터를 모델에 끼움 | △ 끼우는 느낌 |
| RAG | 외부 문서를 검색해서 프롬프트에 첨부 | △ 참고하는 느낌 |
| 모델 머징 | 두 모델의 가중치를 평균냄 | ✅ 진짜 합치기 (실험적) |
LoRA가 그나마 "더하기"에 가깝다 — 베이스 모델(66M, 고정)에 작은 어댑터(1M, 새로 훈련)를 붙여서 쓴다. 근데 이것도 결국 가중치 조정의 효율적인 방법일 뿐이다.
한 줄 요약
파인튜닝 = 이미 완성된 모델의 가중치(숫자)를 내 데이터로 살짝 조정하는 것. 합치기도 아니고, 더하기도 아니고, 데이터를 모델에 주입하는 것도 아니다. 그냥 숫자를 조금 바꾸는 것이다.
핵심 개념
추론 = 남의 모델 사용: pipeline(\"sentiment-analysis\")로 바로 결과
파인튜닝 = 내 모델 만들기: 베이스 모델 + 내 데이터 → 재훈련 → 내 모델
Hub에 데이터셋도 있다: load_dataset(\"imdb\")로 25,000개 영화 리뷰 다운로드
Trainer.train()이 파인튜닝의 핵심 — 이 한 줄에서 내 모델이 만들어진다
pipeline(model=\"./my-model\")로 내가 만든 모델을 추론에 사용