목차
메타 설명
Hugging Face Trainer를 이용해 사전 학습 Transformer 모델을 내 데이터로 Fine-tuning하는 방법을 알아봅니다. TrainingArguments, Tokenizer, Data Collator, 평가 지표, Checkpoint, Early Stopping, 혼합 정밀도, 학습 재개, 모델 저장, Pipeline 추론, Hugging Face Hub 업로드까지 감정 분석 프로젝트로 실습합니다.
지난 시간에는 Hugging Face Datasets를 이용해 AI 학습 데이터를 준비했습니다.
원본 영화 리뷰
→ 빈 데이터 제거
→ 텍스트 정제
→ Tokenizer 적용
→ input_ids 생성
→ attention_mask 생성
→ Train·Validation·Test 분리
→ PyTorch Batch 준비이제 데이터는 훈련장 입구까지 도착했습니다.
사전 학습 모델도 준비되어 있습니다.
데이터:
“정리 끝났습니다.”
Tokenizer:
“숫자 변환도 완료했습니다.”
사전 학습 모델:
“기본 교육은 이미 받았습니다.”
개발자:
“그럼 이제 우리 업무를 배워봅시다.”이번 시간에는 `Trainer`를 이용해 사전 학습된 DistilBERT 모델을 영화 리뷰 감정 분석 모델로 Fine-tuning하겠습니다.
Hugging Face의 `Trainer`는 Transformer 모델을 위한 학습과 평가 루프를 제공하며, 학습 설정, 배치 구성, 역전파, 평가, 로그, Checkpoint 저장 같은 반복 작업을 대신 관리합니다. 현재 Trainer는 특히 Transformers의 PyTorch 모델과 함께 사용하도록 최적화되어 있습니다.
오늘의 핵심 흐름은 다음과 같습니다.
사전 학습 DistilBERT
+ 긍정·부정 영화 리뷰 데이터
+ Hugging Face Trainer
= 우리 데이터에 맞춘 감정 분석 모델AI 훈련소의 교관을 호출해 보겠습니다. 🏋️🤖
1. Fine-tuning이란?
Fine-tuning은 대규모 데이터로 미리 학습된 모델을 특정 업무 데이터로 추가 학습하는 과정입니다.
예를 들어 DistilBERT는 대규모 텍스트를 통해 언어의 기본적인 패턴을 이미 학습했습니다.
사전 학습 모델이 아는 것
단어의 사용 방식
문장 안의 단어 관계
문맥에 따른 표현 변화
일반적인 언어 패턴하지만 우리가 원하는 업무는 아직 모를 수 있습니다.
이 영화 리뷰가 긍정인가?
이 고객 문의가 환불 요청인가?
이 이메일이 스팸인가?
이 보안 로그가 위험한가?Fine-tuning은 사전 학습 모델에 특정 업무를 추가로 가르치는 과정입니다.
기본 교육을 마친 모델
→ 업무 데이터 제공
→ 작은 Learning Rate로 추가 학습
→ 특정 업무에 적응Hugging Face 공식 Fine-tuning 가이드도 사전 학습 모델을 특정 작업의 데이터셋으로 계속 학습하는 과정을 Fine-tuning으로 설명하며, 처음부터 모델을 학습하는 것보다 훨씬 적은 데이터와 연산 자원으로 시작할 수 있다고 안내합니다.
2. 처음부터 학습하는 것과 차이
처음부터 학습
무작위로 초기화된 모델
→ 대규모 학습 데이터 필요
→ 많은 GPU 필요
→ 긴 학습 시간
→ 언어 기본 원리부터 학습Fine-tuning
사전 학습된 모델
→ 특정 업무 데이터 사용
→ 비교적 짧은 추가 학습
→ 업무에 맞는 모델 완성비유하면 다음과 같습니다.
처음부터 학습:
글자 읽기부터 교육
→ 문장 읽기
→ 감정 개념 교육
→ 영화 리뷰 분류
Fine-tuning:
언어를 이미 아는 직원 채용
→ 영화 리뷰 분류 기준만 교육경력직 AI를 우리 회사에 온보딩하는 셈입니다.
3. Feature Extraction과 Fine-tuning
사전 학습 모델을 활용하는 방법은 크게 두 가지로 나눌 수 있습니다.
Feature Extraction
사전 학습 모델의 파라미터를 고정합니다.
Transformer 본체:
학습하지 않음
분류기:
새로 학습코드에서는 모델 파라미터의 기울기 계산을 끌 수 있습니다.
for parameter in model.base_model.parameters():
parameter.requires_grad = False장점:
학습 속도가 빠름
GPU 메모리 사용량 감소
작은 데이터에서 과적합 감소 가능단점:
모델 본체가 업무 데이터에 적응하지 않음
복잡한 업무에서 성능 제한 가능Fine-tuning
사전 학습 모델의 전체 또는 일부 파라미터를 업데이트합니다.
Transformer 본체:
추가 학습
분류 Head:
추가 학습이번 편에서는 전체 모델의 파라미터를 업데이트하는 Full Fine-tuning을 사용합니다.
4. Trainer란?
`Trainer`는 Hugging Face Transformers가 제공하는 고수준 학습 API입니다.
일반적인 PyTorch 학습 코드에서는 다음 작업을 직접 구현해야 합니다.
DataLoader 생성
Batch 반복
Tensor를 GPU로 이동
Optimizer 초기화
Forward Pass
Loss 계산
Backward Pass
Gradient 초기화
Optimizer 업데이트
Learning Rate Scheduler 실행
평가 반복
Checkpoint 저장Trainer에서는 핵심 객체를 전달한 뒤 학습을 시작할 수 있습니다.
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=validation_dataset,
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics
)
trainer.train()현재 공식 텍스트 분류 가이드도 모델, `TrainingArguments`, 데이터셋, Processing Class, Data Collator, 평가 함수를 Trainer에 전달한 뒤 `train()`을 호출하는 흐름을 사용합니다.
5. Trainer가 자동으로 처리하는 작업
Trainer는 다음 작업을 관리합니다.
학습 Batch 생성
Optimizer 구성
Learning Rate Scheduler 구성
Loss 기반 역전파
Gradient Clipping
Gradient Accumulation
혼합 정밀도 학습
학습 로그 기록
Validation 평가
Checkpoint 저장
최적 모델 선택
중단된 학습 재개
분산 학습 환경 연결
Hub 업로드개발자는 주로 다음 항목을 설계합니다.
어떤 모델을 사용할 것인가?
어떤 데이터를 사용할 것인가?
어떤 평가 지표를 사용할 것인가?
Learning Rate는 얼마인가?
Batch Size는 얼마인가?
몇 Epoch 학습할 것인가?
언제 평가하고 저장할 것인가?Trainer가 운동을 대신하는 것은 아닙니다.
운동 계획표를 관리하고 기록을 남기는 AI 트레이너에 가깝습니다.
6. Trainer를 사용하기 좋은 경우
Trainer는 다음 상황에서 특히 편리합니다.
Transformers 모델 Fine-tuning
텍스트 분류
개체명 인식
질문 답변
이미지 분류
음성 분류
요약·번역 모델 학습
Checkpoint와 평가 자동화Trainer는 Transformers 모델의 출력 규칙에 맞춰 설계되어 있습니다.
사용자 정의 모델을 Trainer에 연결하려면 일반적으로 다음 조건을 만족해야 합니다.
ModelOutput 또는 Tuple 반환
labels가 전달되면 Loss 계산
Tuple 반환 시 첫 번째 값이 Loss이 요구사항은 공식 Trainer 문서에도 명시되어 있습니다.
일반적인 PyTorch 모델을 자유롭게 제어해야 한다면 순수 PyTorch 학습 루프나 Hugging Face Accelerate가 더 자연스러울 수 있습니다.
7. 현재 버전과 API 주의사항
2026년 8월 2일 기준 PyPI의 최신 Transformers 안정 버전은 5.14.1이며, 2026년 7월 16일 공개되었습니다. 현재 Transformers는 Python 3.10 이상과 PyTorch 2.4 이상을 지원 대상으로 안내합니다.
이 글은 다음과 같은 현재 API 이름을 사용합니다.
eval_strategy="epoch"오래된 예제에서는 다음 이름을 발견할 수 있습니다.
evaluation_strategy="epoch"현재 공식 문서와 텍스트 분류 예제는 `eval_strategy`를 사용합니다.
Trainer에 Tokenizer를 전달할 때도 현재 공식 예제는 다음과 같이 작성합니다.
processing_class=tokenizer오래된 글에서는 다음 코드를 자주 볼 수 있습니다.
tokenizer=tokenizer현재 Trainer API는 Tokenizer, Image Processor, Feature Extractor 같은 처리 객체를 `processing_class`로 받으며, 저장할 때 모델과 함께 보관할 수 있습니다.
AI 라이브러리의 API는 빠르게 변합니다.
인터넷 예제 작성일:
2022년
현재 설치 버전:
2026년
개발자:
“둘이 왜 대화가 안 되죠?”버전과 공식 문서를 함께 확인해야 합니다.
8. 개발 환경 설치
가상환경 만들기
Windows
python -m venv venv
venv\Scripts\activatemacOS·Linux
python3 -m venv venv
source venv/bin/activate패키지 설치
python -m pip install --upgrade pip
python -m pip install \
"transformers[torch]" \
datasets \
accelerate \
scikit-learn \
tensorboardWindows 명령 프롬프트에서는 한 줄로 입력합니다.
python -m pip install "transformers[torch]" datasets accelerate scikit-learn tensorboard현재 Transformers는 Python 3.10 이상을 요구하며, Datasets 5.0.1은 2026년 7월 28일 공개된 안정 버전입니다.
설치 확인
import datasets
import torch
import transformers
print(
f"Transformers: {transformers.__version__}"
)
print(
f"Datasets: {datasets.__version__}"
)
print(
f"PyTorch: {torch.__version__}"
)
print(
f"CUDA: {torch.cuda.is_available()}"
)9. 프로젝트 구조
trainer_finetuning/
├─ train.py
├─ requirements.txt
├─ outputs/
│ └─ checkpoints/
└─ models/
└─ sentiment-distilbert/`requirements.txt`:
transformers[torch]
datasets
accelerate
scikit-learn
tensorboard운영 프로젝트에서는 실제 검증한 버전을 고정합니다.
transformers==5.14.1
datasets==5.0.1PyTorch는 CPU와 CUDA 환경에 따라 설치 방식이 달라질 수 있으므로 실행 장치에 맞는 버전을 선택해야 합니다.
10. 전체 Fine-tuning 과정
이번 프로젝트의 전체 흐름입니다.
1. 영화 리뷰 데이터셋 로딩
2. Label 정보 확인
3. Tokenizer 로딩
4. 전체 데이터 토큰화
5. Dynamic Padding 구성
6. 분류 모델 로딩
7. 평가 함수 작성
8. TrainingArguments 설정
9. Trainer 생성
10. train() 실행
11. Validation 평가
12. Test 최종 평가
13. 모델 저장
14. Pipeline 추론11. 데이터셋 불러오기
from datasets import load_dataset
DATASET_ID = (
"cornell-movie-review-data/"
"rotten_tomatoes"
)
dataset = load_dataset(
DATASET_ID
)
print(dataset)구조는 다음과 비슷합니다.
DatasetDict({
train: Dataset(...)
validation: Dataset(...)
test: Dataset(...)
})각 데이터는 다음 열을 가집니다.
text
→ 영화 리뷰 문장
label
→ 긍정·부정 숫자 라벨12. Train·Validation·Test 역할
세 데이터는 목적이 다릅니다.
Train
모델의 파라미터를 학습합니다.
모델이 실제로 공부하는 문제집Validation
학습 중 성능을 확인하고 설정을 선택합니다.
중간 모의고사Test
모든 학습과 설정 선택이 끝난 뒤 최종 성능을 확인합니다.
최종 시험Test 데이터를 반복해서 보며 Learning Rate나 Epoch를 조정하면 Test 데이터도 사실상 학습 과정에 참여하게 됩니다.
Test 결과 확인
→ 설정 변경
→ 다시 Test 확인
→ 설정 변경
결과:
Test가 Validation처럼 사용됨최종 평가 데이터는 마지막까지 봉인해 두는 것이 좋습니다.
13. Tokenizer 준비
이번에는 DistilBERT 기본 체크포인트를 사용합니다.
DistilBERT는 지식 증류를 이용해 더 큰 Transformer 모델의 성능을 유지하면서 모델을 작고 빠르게 만들기 위해 개발된 구조입니다.
from transformers import AutoTokenizer
MODEL_ID = (
"distilbert/"
"distilbert-base-uncased"
)
tokenizer = (
AutoTokenizer
.from_pretrained(
MODEL_ID
)
)DistilBERT 기본 모델은 감정 분석 업무를 아직 학습하지 않은 상태입니다.
영어 문맥:
기본적으로 이해
긍정·부정 분류:
아직 추가 학습 필요14. 데이터 토큰화
def tokenize_batch(
batch
):
return tokenizer(
batch["text"],
truncation=True,
max_length=256
)전체 Split에 적용합니다.
tokenized_dataset = dataset.map(
tokenize_batch,
batched=True,
desc="영화 리뷰 토큰화 중"
)새로운 열이 추가됩니다.
text
label
input_ids
attention_mask`batched=True`를 사용하면 여러 문장을 한 번에 Tokenizer로 처리할 수 있습니다.
15. Dynamic Padding
문장마다 토큰 길이가 다릅니다.
리뷰 A:
17 Token
리뷰 B:
84 Token
리뷰 C:
231 TokenTensor Batch로 묶으려면 길이를 맞춰야 합니다.
모든 데이터를 최대 길이 256으로 미리 Padding할 수도 있습니다.
tokenizer(
text,
padding="max_length",
max_length=256
)하지만 짧은 문장에도 많은 Padding이 붙습니다.
실제 토큰:
17개
Padding:
239개Dynamic Padding은 현재 Batch에서 가장 긴 문장까지만 Padding합니다.
from transformers import (
DataCollatorWithPadding
)
data_collator = (
DataCollatorWithPadding(
tokenizer=tokenizer,
return_tensors="pt"
)
)공식 텍스트 분류 가이드도 전체 데이터셋을 고정 길이로 Padding하는 대신 각 Batch의 최대 길이에 맞추는 Dynamic Padding이 더 효율적이라고 안내합니다.
16. 라벨 정보 구성
데이터셋의 라벨 이름을 가져옵니다.
label_feature = (
dataset["train"]
.features["label"]
)
label_names = (
label_feature.names
)
print(label_names)라벨 매핑을 만듭니다.
id2label = {
label_id: label_name.upper()
for label_id, label_name
in enumerate(label_names)
}
label2id = {
label_name.upper(): label_id
for label_id, label_name
in enumerate(label_names)
}결과 예:
id2label:
0 → NEG
1 → POS이 매핑을 모델 설정에 저장하면 추론 결과가 `LABEL_0` 대신 의미 있는 이름으로 출력됩니다.
17. 분류 모델 불러오기
from transformers import (
AutoModelForSequenceClassification
)
model = (
AutoModelForSequenceClassification
.from_pretrained(
MODEL_ID,
num_labels=len(
label_names
),
id2label=id2label,
label2id=label2id
)
)`AutoModelForSequenceClassification`은 기본 Transformer 모델 위에 문장 분류용 Head를 추가합니다.
입력 문장
→ DistilBERT 본체
→ 문장 표현
→ 분류 Head
→ NEG·POS Logits18. 새 분류 Head 경고 이해하기
모델을 불러올 때 다음과 비슷한 경고가 나타날 수 있습니다.
Some weights of
DistilBertForSequenceClassification
were not initialized from the model checkpoint
and are newly initialized이 경고는 기본 DistilBERT 체크포인트에 현재 프로젝트의 긍정·부정 분류 Head가 없어서 새로 생성되었다는 의미입니다.
DistilBERT 본체:
사전 학습 가중치 로딩
분류 Head:
새로 초기화따라서 다음 안내도 함께 나타날 수 있습니다.
You should probably TRAIN this model
on a downstream task바로 지금 하려는 작업입니다.
오류가 아니라 새 직원의 업무용 사원증을 발급했다는 안내에 가깝습니다.
19. TrainingArguments란?
`TrainingArguments`는 학습에 필요한 설정을 모아 관리하는 객체입니다.
Trainer 공식 문서에는 학습 기간, 최적화, 평가, Checkpoint, 로그, 혼합 정밀도, 분산 학습 등 다양한 설정이 제공됩니다.
기본 예:
from transformers import (
TrainingArguments
)
training_args = TrainingArguments(
output_dir="outputs/checkpoints",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
num_train_epochs=3,
weight_decay=0.01,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True
)각 옵션을 하나씩 살펴보겠습니다.
20. Output Directory
output_dir="outputs/checkpoints"학습 중 생성되는 Checkpoint와 설정 파일이 저장되는 위치입니다.
outputs/checkpoints/
├─ checkpoint-100/
├─ checkpoint-200/
└─ checkpoint-300/최종 모델 폴더와 학습 중 Checkpoint 폴더는 분리하는 것이 좋습니다.
outputs/checkpoints
→ 학습 중 상태
models/sentiment-distilbert
→ 최종 배포 모델21. Learning Rate
learning_rate=2e-5Learning Rate는 한 번의 업데이트에서 모델 가중치를 얼마나 크게 변경할지 결정합니다.
너무 큼
→ 기존 지식을 크게 훼손
→ Loss 불안정
→ 학습 실패 가능
너무 작음
→ 학습 속도 느림
→ 충분히 적응하지 못할 수 있음Fine-tuning에서는 사전 학습된 가중치를 조심스럽게 수정해야 하므로 작은 Learning Rate를 자주 사용합니다.
2e-5
= 0.00002Learning Rate는 모델, 데이터 크기, Batch Size에 따라 실험으로 결정해야 합니다.
22. Batch Size
per_device_train_batch_size=16한 장치에서 한 번에 처리할 학습 Sample 수입니다.
GPU 1개:
16개
GPU 2개:
각각 16개
→ 한 Step에서 총 32개평가 Batch는 Gradient를 저장하지 않으므로 학습 Batch보다 크게 설정할 수 있습니다.
per_device_eval_batch_size=32Batch Size를 늘리면 처리량이 증가할 수 있지만 GPU 메모리도 더 많이 사용합니다.
23. Gradient Accumulation
GPU 메모리가 부족해 Batch Size를 키울 수 없다면 Gradient Accumulation을 사용할 수 있습니다.
per_device_train_batch_size=4
gradient_accumulation_steps=4한 장치 기준 유효 Batch Size:
4 × 4 = 16공식 Trainer 문서의 유효 Batch Size 계산은 다음과 같습니다.
유효 Batch Size
= 장치당 Batch Size
× 장치 수
× Gradient Accumulation StepsGradient Accumulation은 추가 메모리 없이 더 큰 Batch를 흉내 내지만 업데이트까지 여러 번의 Forward·Backward Pass가 필요합니다.
예:
Batch 1:
Gradient 누적
Batch 2:
Gradient 누적
Batch 3:
Gradient 누적
Batch 4:
Gradient 누적
→ Optimizer Update24. Epoch와 Step
Epoch
전체 Train 데이터를 한 번 모두 학습한 상태입니다.
num_train_epochs=3전체 데이터를 세 번 반복합니다.
Step
일반적으로 Optimizer가 한 번 업데이트된 횟수를 의미합니다.
Train 데이터:
8,000개
유효 Batch Size:
16
1 Epoch:
약 500 Step`max_steps`를 양수로 지정하면 Epoch 대신 최대 Step 수가 우선됩니다.
max_steps=1000Streaming Dataset처럼 전체 길이를 알 수 없는 데이터에서는 최대 Step을 명시해야 할 수 있습니다.
25. Weight Decay
weight_decay=0.01Weight Decay는 모델 가중치가 지나치게 커지는 것을 억제하는 정규화 방법입니다.
모델:
학습 데이터 정답을 완벽하게 외우려 함
Weight Decay:
“너무 과하게 외우지는 마세요.”과적합을 줄이는 데 도움을 줄 수 있지만 지나치게 크면 학습을 방해할 수 있습니다.
26. Warmup과 Scheduler
학습 시작부터 최대 Learning Rate를 적용하면 초기 가중치가 불안정하게 바뀔 수 있습니다.
Warmup은 Learning Rate를 작은 값에서 서서히 올립니다.
warmup_ratio=0.1전체 학습 Step의 10%를 Warmup 구간으로 사용합니다.
학습 초반:
Learning Rate 천천히 증가
Warmup 종료:
설정한 Learning Rate 부근
이후:
Scheduler에 따라 감소Scheduler:
lr_scheduler_type="linear"Linear Scheduler는 Warmup 이후 Learning Rate를 점차 낮춥니다.
학습 시작:
천천히 가속
학습 중반:
정상 속도
학습 후반:
서서히 감속AI 모델도 출발하자마자 액셀을 바닥까지 밟으면 훈련장 벽과 친해질 수 있습니다.
27. 평가·저장 전략
Epoch마다 평가
eval_strategy="epoch"Epoch마다 Checkpoint 저장
save_strategy="epoch"현재 `eval_strategy`가 지원하는 대표 값은 다음과 같습니다.
no
→ 학습 중 평가하지 않음
steps
→ 일정 Step마다 평가
epoch
→ Epoch 종료마다 평가`save_strategy`에는 `no`, `steps`, `epoch`, `best` 등이 제공됩니다.
Step 기준
eval_strategy="steps"
eval_steps=100
save_strategy="steps"
save_steps=100`load_best_model_at_end=True`를 사용할 때는 평가와 저장 전략을 호환되도록 설정해야 합니다. Step 방식을 사용하면 `save_steps`가 `eval_steps`의 배수여야 합니다.
28. 로그 설정
logging_strategy="steps"
logging_steps=25
logging_first_step=True다음 정보가 출력될 수 있습니다.
Step
Training Loss
Validation Loss
Learning Rate
Epoch
평가 지표외부 추적 도구를 연결하지 않을 때는 다음과 같이 설정할 수 있습니다.
report_to="none"Trainer는 TensorBoard, Weights & Biases, MLflow 같은 실험 추적 도구와 연결할 수 있으며, `logging_strategy`, `logging_steps`, `report_to`로 로그 방식을 제어합니다.
29. 혼합 정밀도 FP16·BF16
기본적으로 모델 연산은 주로 FP32 형식을 사용합니다.
혼합 정밀도는 일부 연산에 더 작은 자료형을 사용해 속도와 메모리 사용량을 개선할 수 있습니다.
BF16 지원 확인
import torch
use_bf16 = (
torch.cuda.is_available()
and torch.cuda.is_bf16_supported()
)FP16 사용 여부
use_fp16 = (
torch.cuda.is_available()
and not use_bf16
)TrainingArguments:
bf16=use_bf16,
fp16=use_fp16현재 Trainer 문서는 지원 하드웨어에서는 FP16보다 수치적으로 안정적인 BF16을 우선 검토하도록 안내합니다.
CUDA 없음:
둘 다 False
BF16 지원 GPU:
BF16 True
BF16 미지원 CUDA GPU:
FP16 TrueCPU와 Apple MPS 환경에서는 위 설정을 그대로 사용하지 않고 환경별 지원 상태를 확인해야 합니다.
30. Gradient Checkpointing
gradient_checkpointing=True일반 학습에서는 Forward Pass의 중간 Activation을 저장한 뒤 Backward Pass에서 사용합니다.
Gradient Checkpointing은 일부 Activation을 저장하지 않고 Backward Pass에서 다시 계산합니다.
기본 방식:
메모리 사용 증가
→ 계산 재사용
→ 빠름
Gradient Checkpointing:
메모리 사용 감소
→ 일부 계산 반복
→ 느려짐공식 Trainer 문서도 Gradient Checkpointing을 연산량과 속도를 희생해 메모리를 줄이는 기능으로 설명합니다.
작은 DistilBERT 모델에는 꼭 필요하지 않지만 더 큰 모델에서 유용할 수 있습니다.
31. 평가 지표 만들기
Trainer는 기본적으로 평가 Loss를 계산합니다.
하지만 분류 모델은 다음 지표도 필요합니다.
Accuracy
Precision
Recall
F1 Score`compute_metrics` 함수를 작성합니다.
import numpy as np
from sklearn.metrics import (
accuracy_score,
precision_recall_fscore_support
)
from transformers import EvalPrediction
def compute_metrics(
eval_prediction: EvalPrediction
) -> dict[str, float]:
logits = (
eval_prediction.predictions
)
labels = (
eval_prediction.label_ids
)
if isinstance(
logits,
tuple
):
logits = logits[0]
predictions = np.argmax(
logits,
axis=-1
)
accuracy = accuracy_score(
labels,
predictions
)
(
precision,
recall,
f1,
_
) = precision_recall_fscore_support(
labels,
predictions,
average="binary",
zero_division=0
)
return {
"accuracy": float(
accuracy
),
"precision": float(
precision
),
"recall": float(
recall
),
"f1": float(
f1
)
}Trainer는 평가가 끝난 뒤 모델의 예측값과 정답 Label을 `compute_metrics`에 전달합니다. 공식 텍스트 분류 가이드도 예측 Logits에서 가장 큰 클래스 인덱스를 선택한 뒤 평가 지표를 계산하는 방식을 사용합니다.
32. Accuracy·Precision·Recall·F1
Accuracy
전체 데이터 중 맞춘 비율입니다.
정답 90개
전체 100개
Accuracy:
90%Precision
모델이 Positive라고 예측한 것 중 실제 Positive 비율입니다.
모델이 긍정이라고 예측:
50개
실제 긍정:
40개
Precision:
80%Recall
실제 Positive 데이터 중 모델이 찾아낸 비율입니다.
실제 긍정:
50개
찾은 긍정:
40개
Recall:
80%F1 Score
Precision과 Recall의 조화평균입니다.
Precision만 높고 Recall이 낮거나
Recall만 높고 Precision이 낮은 상황을
균형 있게 평가클래스가 불균형하면 Accuracy만으로 모델을 평가하기 어렵습니다.
정상:
99%
위험:
1%
모든 데이터를 정상으로 예측
Accuracy:
99%
위험 탐지:
0%숫자 하나만 보면 우수한 모델처럼 보이지만 정작 중요한 일을 전혀 하지 못할 수 있습니다.
33. Trainer 생성
from transformers import (
EarlyStoppingCallback,
Trainer
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=(
tokenized_dataset["train"]
),
eval_dataset=(
tokenized_dataset["validation"]
),
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
callbacks=[
EarlyStoppingCallback(
early_stopping_patience=2,
early_stopping_threshold=0.001
)
]
)구성 요소:
model
→ 학습할 모델
args
→ 학습 설정
train_dataset
→ 실제 학습 데이터
eval_dataset
→ 학습 중 평가 데이터
processing_class
→ Tokenizer
data_collator
→ Dynamic Padding
compute_metrics
→ 평가 지표
callbacks
→ Early Stopping 등 추가 동작34. Fine-tuning 시작
train_result = trainer.train()학습 중 다음 작업이 반복됩니다.
Batch 가져오기
→ Forward Pass
→ Loss 계산
→ Backward Pass
→ Gradient 업데이트
→ Scheduler 업데이트
→ 로그 기록
→ Validation 평가
→ Checkpoint 저장학습 결과에는 실행 시간과 Loss 등의 정보가 포함됩니다.
print(
train_result.metrics
)Trainer의 `train()`은 학습이 끝나면 `TrainOutput`을 반환합니다.
35. 학습 결과 확인
trainer.log_metrics(
"train",
train_result.metrics
)
trainer.save_metrics(
"train",
train_result.metrics
)
trainer.save_state()저장되는 파일 예:
outputs/checkpoints/
├─ train_results.json
├─ trainer_state.json
├─ training_args.bin
└─ checkpoint-...학습 로그 예
Epoch 1
Training Loss:
0.42
Validation Loss:
0.31
Accuracy:
0.87
F1:
0.86Epoch 2
Training Loss:
0.21
Validation Loss:
0.27
Accuracy:
0.89
F1:
0.89Training Loss와 Validation 성능을 함께 봐야 합니다.
36. 모델 평가
Validation 데이터 평가:
validation_metrics = (
trainer.evaluate()
)
print(
validation_metrics
)결과 예:
{
"eval_loss": ...,
"eval_accuracy": ...,
"eval_precision": ...,
"eval_recall": ...,
"eval_f1": ...,
"eval_runtime": ...
}저장:
trainer.log_metrics(
"validation",
validation_metrics
)
trainer.save_metrics(
"validation",
validation_metrics
)37. Test 데이터 최종 평가
모든 설정 선택이 끝난 뒤 Test 데이터에서 최종 평가합니다.
test_metrics = trainer.evaluate(
eval_dataset=(
tokenized_dataset["test"]
),
metric_key_prefix="test"
)
print(
test_metrics
)결과:
test_loss
test_accuracy
test_precision
test_recall
test_f1저장:
trainer.log_metrics(
"test",
test_metrics
)
trainer.save_metrics(
"test",
test_metrics
)38. Confusion Matrix 확인
어떤 클래스를 주로 틀리는지 확인하려면 `predict()`를 사용합니다.
prediction_output = trainer.predict(
tokenized_dataset["test"]
)예측값:
test_predictions = np.argmax(
prediction_output.predictions,
axis=-1
)정답:
test_labels = (
prediction_output.label_ids
)Confusion Matrix:
from sklearn.metrics import (
confusion_matrix
)
matrix = confusion_matrix(
test_labels,
test_predictions
)
print(matrix)2개 클래스일 때 구조:
[
[실제 NEG를 NEG로 예측, 실제 NEG를 POS로 예측],
[실제 POS를 NEG로 예측, 실제 POS를 POS로 예측]
]예:
[
[492, 41],
[52, 481]
]이 결과는 다음을 의미합니다.
부정을 긍정으로 잘못 예측:
41개
긍정을 부정으로 잘못 예측:
52개Accuracy 하나로는 보이지 않던 오류 방향을 확인할 수 있습니다.
39. 최적 모델 자동 선택
load_best_model_at_end=True
metric_for_best_model="f1"
greater_is_better=True학습이 끝나면 가장 마지막 모델이 아니라 Validation F1이 가장 높은 Checkpoint를 불러옵니다.
현재 Trainer 문서에 따르면 `metric_for_best_model`은 평가 함수가 반환하는 지표 이름을 사용하며, `eval_` 접두사는 생략할 수 있습니다. 지표 이름이 `loss`로 끝나지 않으면 `greater_is_better`의 기본 방향은 높은 값으로 설정됩니다.
최적 Checkpoint 확인:
print(
trainer.state.best_model_checkpoint
)
print(
trainer.state.best_metric
)40. Early Stopping
Epoch를 많이 지정하더라도 Validation 성능이 개선되지 않으면 학습을 일찍 중단할 수 있습니다.
EarlyStoppingCallback(
early_stopping_patience=2,
early_stopping_threshold=0.001
)의미:
Validation 평가 결과가
0.001 이상 개선되지 않는 상태가
2회 연속 발생
→ 학습 중단Early Stopping Callback은 `metric_for_best_model`과 함께 동작하며, `load_best_model_at_end`를 통해 최적 지표를 추적합니다.
모델:
“아직 10 Epoch 남았습니다.”
Validation F1:
“두 번 연속 나아지지 않았습니다.”
Early Stopping:
“오늘 훈련은 여기까지입니다.”무조건 오래 훈련하는 것이 좋은 것은 아닙니다.
41. Checkpoint 구조
Checkpoint에는 모델 가중치만 저장되는 것이 아닙니다.
checkpoint-500/
├─ model.safetensors
├─ config.json
├─ optimizer.pt
├─ scheduler.pt
├─ trainer_state.json
├─ rng_state.pth
└─ training_args.bin주요 파일:
model.safetensors
→ 모델 가중치
optimizer.pt
→ Optimizer 상태
scheduler.pt
→ Learning Rate Scheduler 상태
trainer_state.json
→ Step, Epoch, 최고 지표, 로그
rng_state.pth
→ 난수 상태Optimizer와 Scheduler 상태가 있어야 정확한 지점에서 학습을 이어가기 쉽습니다.
42. 중단된 학습 재개
가장 최근 Checkpoint에서 재개:
trainer.train(
resume_from_checkpoint=True
)특정 Checkpoint:
trainer.train(
resume_from_checkpoint=(
"outputs/checkpoints/"
"checkpoint-500"
)
)Trainer는 Checkpoint에서 모델, Optimizer, Scheduler 상태를 복원해 학습을 이어갈 수 있습니다. `True`를 전달하면 `output_dir`에서 가장 최근 Checkpoint를 찾습니다.
정전 전:
Epoch 2
Step 500
정전 후:
Checkpoint 500 로딩
→ Step 501부터 계속`save_only_model=True`로 모델 가중치만 저장했다면 Optimizer와 Scheduler 상태가 없기 때문에 완전한 학습 재개가 불가능할 수 있습니다.
43. 모델과 Tokenizer 저장
최종 저장 폴더:
from pathlib import Path
FINAL_MODEL_DIR = Path(
"models/"
"sentiment-distilbert"
)모델 저장:
trainer.save_model(
str(
FINAL_MODEL_DIR
)
)Tokenizer 저장:
tokenizer.save_pretrained(
FINAL_MODEL_DIR
)저장 결과:
models/sentiment-distilbert/
├─ config.json
├─ model.safetensors
├─ tokenizer.json
├─ tokenizer_config.json
├─ special_tokens_map.json
└─ vocab.txt이 폴더만 있으면 학습 코드 없이 추론 모델을 다시 불러올 수 있습니다.
44. Pipeline으로 추론
import torch
from transformers import pipeline
def select_pipeline_device():
if torch.cuda.is_available():
return 0
if torch.backends.mps.is_available():
return "mps"
return -1
classifier = pipeline(
task="text-classification",
model=str(
FINAL_MODEL_DIR
),
tokenizer=str(
FINAL_MODEL_DIR
),
device=select_pipeline_device()
)추론:
result = classifier(
"This movie was exciting "
"from beginning to end."
)
print(result)결과 예:
[
{
"label": "POS",
"score": 0.98
}
]부정 문장:
result = classifier(
"The story was boring "
"and painfully predictable."
)45. 여러 문장 일괄 추론
reviews = [
(
"The acting was excellent "
"and the story was moving."
),
(
"I almost fell asleep "
"during the entire movie."
),
(
"The visual effects were good, "
"but the plot was confusing."
)
]
results = classifier(
reviews,
batch_size=3,
truncation=True
)
for review, result in zip(
reviews,
results
):
print(
f"리뷰: {review}"
)
print(
f"예측: {result['label']}"
)
print(
f"확률: {result['score']:.2%}"
)
print(
"-" * 50
)마지막 문장처럼 긍정과 부정이 섞인 리뷰는 모델이 판단하기 어려울 수 있습니다.
시각 효과:
긍정
줄거리:
부정
최종 라벨:
어느 쪽?이런 오류를 모아 데이터와 모델을 개선해야 합니다.
46. Hugging Face Hub 업로드
로그인:
hf auth loginTrainingArguments에 Hub 설정을 추가할 수 있습니다.
push_to_hub=True,
hub_model_id=(
"사용자명/"
"sentiment-distilbert"
),
hub_private_repo=True,
hub_strategy="end"학습 후 업로드:
trainer.push_to_hub(
commit_message=(
"Fine-tune DistilBERT "
"for movie sentiment"
)
)Trainer는 모델과 Processing Class를 Hub에 업로드할 수 있으며, 학습 설정과 결과를 포함한 Model Card 초안도 생성할 수 있습니다.
공개 업로드 전 확인:
학습 데이터 재배포 권한
모델 라이선스
개인정보 포함 여부
모델의 제한사항
평가 지표
실패 사례
예상 사용 목적모델이 올라간 뒤에 라이선스를 고민하면 AI보다 사람이 더 빠르게 위험해집니다.
47. TensorBoard 로그 확인
TrainingArguments에 로그 폴더를 지정합니다.
logging_dir=(
"outputs/tensorboard"
)로그 대상:
report_to=[
"tensorboard"
]학습 후 실행:
tensorboard \
--logdir outputs/tensorboardWindows에서는 한 줄로 실행합니다.
tensorboard --logdir outputs/tensorboard브라우저 주소:
http://localhost:6006확인할 수 있는 정보:
Training Loss
Validation Loss
Learning Rate
평가 지표
학습 Step48. GPU 메모리 부족 해결
대표 오류:
CUDA out of memoryBatch Size 줄이기
per_device_train_batch_size=4Gradient Accumulation
gradient_accumulation_steps=4최대 토큰 길이 줄이기
max_length=128혼합 정밀도 사용
fp16=True또는 지원 GPU:
bf16=TrueGradient Checkpointing
gradient_checkpointing=True작은 모델 사용
BERT Base
→ DistilBERT
→ TinyBERT 계열평가 메모리 줄이기
eval_accumulation_steps=8Trainer의 평가는 여러 Batch의 Logits를 GPU에서 모을 수 있으므로 대규모 평가 데이터에서는 메모리 부족이 발생할 수 있습니다. `eval_accumulation_steps`를 사용하면 일정 Batch마다 예측 결과를 CPU로 옮길 수 있습니다.
49. 과적합과 과소적합
과소적합
Training Loss:
높음
Validation Loss:
높음
Train 성능:
낮음
Validation 성능:
낮음가능한 원인:
학습 시간 부족
Learning Rate가 너무 작음
모델 표현력 부족
데이터 전처리 오류과적합
Training Loss:
계속 감소
Validation Loss:
다시 증가
Train 성능:
매우 높음
Validation 성능:
정체 또는 감소가능한 대응:
Early Stopping
Weight Decay
Epoch 감소
데이터 추가
데이터 증강
작은 모델 사용
Dropout 조정이상적인 흐름
Training Loss:
감소
Validation Loss:
함께 감소
Validation F1:
증가 후 안정모델이 공부를 잘하는 것과 문제집 답을 외우는 것은 다릅니다.
50. 데이터 누수 방지
데이터 누수는 모델이 학습 과정에서 평가 정답에 해당하는 정보를 미리 보는 문제입니다.
중복 리뷰
Train:
“This movie was fantastic.”
Test:
“This movie was fantastic.”모델이 일반화한 것이 아니라 문장을 외웠을 수 있습니다.
같은 원본에서 파생된 데이터
Train:
원본 문서 일부
Test:
같은 문서의 다른 일부Test 기반 설정 선택
Test F1 확인
→ Epoch 변경
→ Test F1 다시 확인시간 데이터 혼합
미래 데이터를 학습에 넣어 과거를 예측하면 실제 운영 상황과 다릅니다.
데이터 Split은 단순히 무작위 비율만 나누는 것이 아니라 실제 서비스 구조를 반영해야 합니다.
51. 재현 가능한 학습
난수 Seed를 설정합니다.
seed=2026,
data_seed=2026직접 설정할 수도 있습니다.
from transformers import set_seed
set_seed(
2026
)Seed는 다음 요소에 영향을 줍니다.
데이터 순서
Dropout
분류 Head 초기화
일부 GPU 연산
Batch Sampling동일한 Seed를 사용해도 하드웨어, 라이브러리 버전, 병렬 처리 방식에 따라 완전히 같은 결과가 나오지 않을 수 있습니다.
따라서 다음 정보를 함께 기록합니다.
Python 버전
PyTorch 버전
Transformers 버전
Datasets 버전
모델 ID와 Revision
데이터셋 ID와 Revision
학습 설정
Random Seed
GPU 종류52. 실전 프로젝트 전체 코드
다음 내용을 `train.py`로 저장합니다.
from pathlib import Path
import json
import numpy as np
import torch
from datasets import load_dataset
from sklearn.metrics import (
accuracy_score,
confusion_matrix,
precision_recall_fscore_support
)
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
DataCollatorWithPadding,
EarlyStoppingCallback,
EvalPrediction,
Trainer,
TrainingArguments,
pipeline,
set_seed
)
DATASET_ID = (
"cornell-movie-review-data/"
"rotten_tomatoes"
)
MODEL_ID = (
"distilbert/"
"distilbert-base-uncased"
)
CHECKPOINT_DIR = Path(
"outputs/checkpoints"
)
TENSORBOARD_DIR = Path(
"outputs/tensorboard"
)
FINAL_MODEL_DIR = Path(
"models/"
"sentiment-distilbert"
)
SEED = 2026
def select_precision() -> tuple[
bool,
bool
]:
"""
현재 CUDA 장치에 맞춰
BF16 또는 FP16 사용 여부를 반환합니다.
"""
if not torch.cuda.is_available():
return (
False,
False
)
use_bf16 = (
torch.cuda.is_bf16_supported()
)
use_fp16 = not use_bf16
return (
use_bf16,
use_fp16
)
def select_pipeline_device():
"""Pipeline 추론 장치를 선택합니다."""
if torch.cuda.is_available():
return 0
if torch.backends.mps.is_available():
return "mps"
return -1
def compute_metrics(
eval_prediction: EvalPrediction
) -> dict[str, float]:
"""분류 평가 지표를 계산합니다."""
logits = (
eval_prediction.predictions
)
labels = (
eval_prediction.label_ids
)
if isinstance(
logits,
tuple
):
logits = logits[0]
predictions = np.argmax(
logits,
axis=-1
)
accuracy = accuracy_score(
labels,
predictions
)
(
precision,
recall,
f1,
_
) = precision_recall_fscore_support(
labels,
predictions,
average="binary",
zero_division=0
)
return {
"accuracy": float(
accuracy
),
"precision": float(
precision
),
"recall": float(
recall
),
"f1": float(
f1
)
}
def main() -> None:
set_seed(
SEED
)
CHECKPOINT_DIR.mkdir(
parents=True,
exist_ok=True
)
TENSORBOARD_DIR.mkdir(
parents=True,
exist_ok=True
)
FINAL_MODEL_DIR.mkdir(
parents=True,
exist_ok=True
)
print(
"[1/10] 데이터셋 로딩"
)
dataset = load_dataset(
DATASET_ID
)
print(dataset)
label_feature = (
dataset["train"]
.features["label"]
)
label_names = (
label_feature.names
)
id2label = {
label_id: label_name.upper()
for label_id, label_name
in enumerate(label_names)
}
label2id = {
label_name.upper(): label_id
for label_id, label_name
in enumerate(label_names)
}
print(
f"라벨: {id2label}"
)
print(
"[2/10] Tokenizer 로딩"
)
tokenizer = (
AutoTokenizer
.from_pretrained(
MODEL_ID
)
)
def tokenize_batch(
batch
):
return tokenizer(
batch["text"],
truncation=True,
max_length=256
)
print(
"[3/10] 데이터 토큰화"
)
tokenized_dataset = (
dataset.map(
tokenize_batch,
batched=True,
desc="영화 리뷰 토큰화 중"
)
)
data_collator = (
DataCollatorWithPadding(
tokenizer=tokenizer,
return_tensors="pt"
)
)
print(
"[4/10] 분류 모델 로딩"
)
model = (
AutoModelForSequenceClassification
.from_pretrained(
MODEL_ID,
num_labels=len(
label_names
),
id2label=id2label,
label2id=label2id
)
)
use_bf16, use_fp16 = (
select_precision()
)
print(
f"CUDA: "
f"{torch.cuda.is_available()}"
)
print(
f"BF16: {use_bf16}"
)
print(
f"FP16: {use_fp16}"
)
print(
"[5/10] 학습 설정 생성"
)
training_args = (
TrainingArguments(
output_dir=str(
CHECKPOINT_DIR
),
learning_rate=2e-5,
lr_scheduler_type="linear",
warmup_ratio=0.1,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
gradient_accumulation_steps=1,
num_train_epochs=5,
weight_decay=0.01,
eval_strategy="epoch",
save_strategy="epoch",
logging_strategy="steps",
logging_steps=25,
logging_first_step=True,
logging_dir=str(
TENSORBOARD_DIR
),
load_best_model_at_end=True,
metric_for_best_model="f1",
greater_is_better=True,
save_total_limit=2,
bf16=use_bf16,
fp16=use_fp16,
report_to="none",
seed=SEED,
data_seed=SEED,
run_name=(
"rotten-tomatoes-"
"distilbert"
)
)
)
print(
"[6/10] Trainer 생성"
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=(
tokenized_dataset[
"train"
]
),
eval_dataset=(
tokenized_dataset[
"validation"
]
),
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
callbacks=[
EarlyStoppingCallback(
early_stopping_patience=2,
early_stopping_threshold=0.001
)
]
)
print(
"[7/10] Fine-tuning 시작"
)
train_result = (
trainer.train()
)
trainer.log_metrics(
"train",
train_result.metrics
)
trainer.save_metrics(
"train",
train_result.metrics
)
trainer.save_state()
print(
"[8/10] Test 데이터 평가"
)
test_output = trainer.predict(
tokenized_dataset[
"test"
]
)
test_metrics = (
test_output.metrics
)
trainer.log_metrics(
"test",
test_metrics
)
trainer.save_metrics(
"test",
test_metrics
)
test_predictions = np.argmax(
test_output.predictions,
axis=-1
)
test_labels = (
test_output.label_ids
)
matrix = confusion_matrix(
test_labels,
test_predictions
)
print(
"Confusion Matrix:"
)
print(matrix)
matrix_path = (
CHECKPOINT_DIR
/ "confusion_matrix.json"
)
matrix_path.write_text(
json.dumps(
matrix.tolist(),
ensure_ascii=False,
indent=2
),
encoding="utf-8"
)
print(
"[9/10] 최종 모델 저장"
)
trainer.save_model(
str(
FINAL_MODEL_DIR
)
)
tokenizer.save_pretrained(
FINAL_MODEL_DIR
)
print(
f"최적 Checkpoint: "
f"{trainer.state.best_model_checkpoint}"
)
print(
f"최적 지표: "
f"{trainer.state.best_metric}"
)
print(
"[10/10] 저장 모델 추론"
)
classifier = pipeline(
task="text-classification",
model=str(
FINAL_MODEL_DIR
),
tokenizer=str(
FINAL_MODEL_DIR
),
device=(
select_pipeline_device()
)
)
sample_reviews = [
(
"The acting was wonderful "
"and the story was deeply moving."
),
(
"The movie was boring, "
"predictable, and far too long."
),
(
"The visuals were impressive, "
"but the plot was difficult "
"to follow."
)
]
results = classifier(
sample_reviews,
batch_size=3,
truncation=True
)
print(
"\n[추론 결과]"
)
for review, result in zip(
sample_reviews,
results
):
print(
f"리뷰: {review}"
)
print(
f"예측: {result['label']}"
)
print(
f"확률: "
f"{result['score']:.2%}"
)
print(
"-" * 60
)
if __name__ == "__main__":
main()53. 실행 방법
1단계: 폴더 만들기
mkdir trainer_finetuning
cd trainer_finetuning2단계: 가상환경
Windows
python -m venv venv
venv\Scripts\activatemacOS·Linux
python3 -m venv venv
source venv/bin/activate3단계: 패키지 설치
python -m pip install \
"transformers[torch]" \
datasets \
accelerate \
scikit-learn \
tensorboard4단계: 실행
python train.pyCPU 환경에서도 실행할 수 있지만 GPU보다 학습 시간이 크게 늘어날 수 있습니다.
처음 실행할 때는 데이터셋과 모델을 다운로드합니다.
54. 출력 결과 해석
학습 로그 예:
{
"loss": 0.521,
"learning_rate": 0.000017,
"epoch": 0.5
}의미:
loss
→ 현재 학습 오차
learning_rate
→ 현재 Scheduler가 적용한 학습률
epoch
→ 전체 데이터 학습 진행 위치평가 로그:
{
"eval_loss": 0.302,
"eval_accuracy": 0.882,
"eval_precision": 0.891,
"eval_recall": 0.869,
"eval_f1": 0.880
}해석:
Accuracy:
전체 중 약 88.2% 정답
Precision:
긍정 예측 중 약 89.1% 정답
Recall:
실제 긍정 중 약 86.9% 탐지
F1:
Precision과 Recall 균형 약 88.0%프로젝트에서 중요한 지표가 무엇인지는 업무에 따라 달라집니다.
스팸 차단:
정상 메일 오탐이 중요할 수 있음
질병 선별:
놓치는 환자를 줄이는 Recall이 중요할 수 있음
상품 추천:
순위와 클릭 기반 지표가 필요할 수 있음55. Trainer의 한계
Trainer는 편리하지만 모든 학습 작업에 최적은 아닙니다.
세밀한 학습 흐름 제어
Batch마다 서로 다른 Optimizer 사용
복잡한 다중 Loss 계산
특수한 Gradient 업데이트
여러 모델 교대 학습이런 작업은 사용자 정의 Trainer나 순수 PyTorch 학습 루프가 더 적합할 수 있습니다.
대규모 LLM Fine-tuning
수십억 개 파라미터의 생성형 모델을 Full Fine-tuning하면 막대한 GPU 메모리가 필요합니다.
작은 분류 모델:
Trainer Full Fine-tuning 가능
대형 LLM:
LoRA·QLoRA·PEFT 검토자동 성능 보장
Trainer가 코드를 줄여 주지만 좋은 성능을 자동으로 보장하지는 않습니다.
잘못된 데이터
잘못된 라벨
부적합한 모델
평가 지표 오류
데이터 누수이 문제들은 Trainer도 해결할 수 없습니다.
56. 자주 발생하는 오류
오류 1. accelerate가 필요함
Using the Trainer with PyTorch
requires accelerate설치:
python -m pip install --upgrade accelerate오류 2. eval_strategy를 인식하지 못함
unexpected keyword argument
'eval_strategy'설치된 Transformers 버전을 확인합니다.
python -m pip show transformers오래된 버전 예제와 현재 버전 API를 혼합하지 않았는지 확인합니다.
오류 3. evaluation_strategy를 인식하지 못함
현재 버전 공식 문서는 `eval_strategy`를 사용합니다.
eval_strategy="epoch"오류 4. tokenizer 인수 경고
오래된 코드:
Trainer(
tokenizer=tokenizer
)현재 방식:
Trainer(
processing_class=tokenizer
)오류 5. 모델 입력에 labels가 없음
데이터셋의 라벨 열 이름을 확인합니다.
print(
tokenized_dataset[
"train"
].column_names
)일반적인 분류 모델은 `label` 또는 `labels`를 사용할 수 있습니다.
필요하면 변경합니다.
tokenized_dataset = (
tokenized_dataset
.rename_column(
"label",
"labels"
)
)오류 6. Tensor 길이가 맞지 않음
stack expects each tensor
to be equal sizeDynamic Padding을 사용합니다.
data_collator = (
DataCollatorWithPadding(
tokenizer=tokenizer
)
)오류 7. CUDA 메모리 부족
CUDA out of memory우선순위:
Batch Size 줄이기
Gradient Accumulation 증가
max_length 줄이기
FP16·BF16 사용
Gradient Checkpointing 사용오류 8. FP16을 CPU에서 사용함
FP16 mixed precision
can only be used on CUDACUDA 조건을 확인합니다.
fp16=torch.cuda.is_available()오류 9. load_best_model_at_end 설정 오류
save strategy must match
evaluation strategy수정:
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=TrueStep 방식:
eval_strategy="steps",
eval_steps=100,
save_strategy="steps",
save_steps=100오류 10. metric_for_best_model을 찾지 못함
metric_for_best_model:
f1
compute_metrics 반환:
{
"accuracy": ...
}`f1`을 반환해야 합니다.
return {
"accuracy": accuracy,
"f1": f1
}오류 11. Early Stopping이 작동하지 않음
확인:
eval_strategy 설정
load_best_model_at_end=True
metric_for_best_model 설정
평가 지표 이름 일치
평가와 저장 시점 일치오류 12. Checkpoint에서 재개할 수 없음
Checkpoint에 다음 파일이 존재하는지 확인합니다.
optimizer.pt
scheduler.pt
trainer_state.json모델 가중치만 저장했다면 Optimizer 상태를 복원할 수 없습니다.
오류 13. 모델이 LABEL_0을 출력함
모델 생성 시 라벨 매핑을 지정합니다.
model = (
AutoModelForSequenceClassification
.from_pretrained(
MODEL_ID,
id2label=id2label,
label2id=label2id
)
)오류 14. Training Loss는 감소하지만 평가 성능은 하락함
과적합 가능성이 있습니다.
대응:
Epoch 감소
Early Stopping
Weight Decay 증가 검토
데이터 추가
중복 데이터 제거오류 15. W&B 로그인을 요구함
Weights & Biases가 설치되어 자동 연결되었을 수 있습니다.
외부 추적을 사용하지 않는다면:
report_to="none"오류 16. Tokenizer 병렬 처리 경고
멀티프로세싱 이후 Tokenizer가 생성되면 병렬 처리 경고가 나타날 수 있습니다.
환경에 따라 다음 설정을 사용할 수 있습니다.
Windows PowerShell
$env:TOKENIZERS_PARALLELISM="false"macOS·Linux
export TOKENIZERS_PARALLELISM=false성능 문제의 원인을 확인한 뒤 적용합니다.
오류 17. DataLoader Worker 오류
Windows에서 `dataloader_num_workers`를 크게 설정하면 프로세스 관련 오류가 발생할 수 있습니다.
먼저 기본값으로 테스트합니다.
dataloader_num_workers=0정상 작동 후 조금씩 늘립니다.
오류 18. 학습 결과가 실행할 때마다 크게 달라짐
확인:
seed
data_seed
데이터 Split
모델 Revision
라이브러리 버전
GPU 연산의 결정성57. 연습 문제
문제 1
영화 리뷰 데이터셋의 라벨 이름을 출력하세요.
문제 2
DistilBERT Tokenizer를 이용해 최대 길이 128로 데이터를 토큰화하세요.
문제 3
DataCollatorWithPadding을 이용해 Dynamic Padding을 구성하세요.
문제 4
분류 모델의 `id2label`과 `label2id`를 설정하세요.
문제 5
다음 조건의 TrainingArguments를 작성하세요.
Learning Rate:
3e-5
Train Batch:
8
Eval Batch:
16
Epoch:
3
Evaluation:
Epoch마다
Checkpoint:
Epoch마다문제 6
Gradient Accumulation을 이용해 다음 유효 Batch Size를 만드세요.
장치당 Batch:
4
장치:
1개
목표 유효 Batch:
32정답:
gradient_accumulation_steps:
8문제 7
Accuracy와 F1을 반환하는 `compute_metrics`를 작성하세요.
문제 8
Validation F1이 가장 높은 모델을 자동으로 불러오도록 설정하세요.
문제 9
Validation F1이 세 번 연속 개선되지 않으면 학습을 중단하세요.
문제 10
Checkpoint를 최대 3개만 유지하세요.
문제 11
가장 최근 Checkpoint에서 학습을 재개하세요.
문제 12
Test 데이터에서 Confusion Matrix를 출력하세요.
문제 13
최종 모델과 Tokenizer를 로컬 폴더에 저장하세요.
문제 14
저장된 모델을 Pipeline으로 불러와 세 문장을 일괄 추론하세요.
문제 15
TensorBoard에 학습 Loss와 평가 결과를 기록하세요.
문제 16
CUDA GPU가 BF16을 지원하면 BF16, 그렇지 않으면 FP16을 사용하도록 설정하세요.
문제 17
GPU 메모리가 부족한 상황을 가정해 다음 설정을 적용하세요.
Train Batch:
2
Gradient Accumulation:
8
max_length:
128
Gradient Checkpointing:
활성화문제 18
Trainer Fine-tuning 프로젝트에 다음 기능을 추가하세요.
모델 Revision 고정
데이터셋 Revision 고정
학습 설정 JSON 저장
Confusion Matrix 이미지 저장
오분류 리뷰 CSV 저장
Hugging Face Hub 비공개 업로드58. 핵심 요약
모델과 Tokenizer
tokenizer = (
AutoTokenizer
.from_pretrained(
MODEL_ID
)
)
model = (
AutoModelForSequenceClassification
.from_pretrained(
MODEL_ID,
num_labels=2
)
)Tokenizer 적용
tokenized_dataset = dataset.map(
tokenize_batch,
batched=True
)Dynamic Padding
data_collator = (
DataCollatorWithPadding(
tokenizer=tokenizer
)
)TrainingArguments
training_args = TrainingArguments(
output_dir="outputs",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
num_train_epochs=3,
weight_decay=0.01,
warmup_ratio=0.1,
eval_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1",
greater_is_better=True
)Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=(
tokenized_dataset["train"]
),
eval_dataset=(
tokenized_dataset[
"validation"
]
),
processing_class=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics
)학습
trainer.train()평가
metrics = trainer.evaluate()Test 예측
predictions = trainer.predict(
tokenized_dataset["test"]
)학습 재개
trainer.train(
resume_from_checkpoint=True
)저장
trainer.save_model(
"saved_model"
)
tokenizer.save_pretrained(
"saved_model"
)Pipeline 추론
classifier = pipeline(
"text-classification",
model="saved_model",
tokenizer="saved_model"
)Hub 업로드
trainer.push_to_hub()59. 마무리
이번 시간에는 Hugging Face Trainer를 이용해 사전 학습된 DistilBERT 모델을 영화 리뷰 감정 분석 모델로 Fine-tuning했습니다.
전체 흐름을 다시 정리하겠습니다.
Datasets로 데이터 준비
→ Tokenizer 적용
→ Dynamic Padding 구성
→ 분류 모델 로딩
→ TrainingArguments 작성
→ Trainer 생성
→ train() 실행
→ Validation 평가
→ 최적 Checkpoint 선택
→ Test 최종 평가
→ 모델 저장
→ Pipeline 추론Trainer의 핵심 역할은 반복적인 학습 코드를 관리하는 것입니다.
Optimizer
Scheduler
Backward Pass
평가
로그
Checkpoint
학습 재개하지만 Trainer가 대신 결정할 수 없는 것도 많습니다.
좋은 데이터인가?
라벨 기준이 정확한가?
어떤 지표가 중요한가?
Test 데이터가 오염되지 않았는가?
모델의 오류가 허용 가능한가?
실제 업무 데이터에서도 성능이 유지되는가?Trainer는 유능한 훈련 교관입니다.
그러나 잘못된 교재를 주면 틀린 내용을 아주 성실하게 가르칠 수 있습니다.
개발자:
“학습이 완료되었습니다.”
Trainer:
“Validation F1은 92%입니다.”
개발자:
“실제 고객 문의에서는요?”
Trainer:
“그 데이터는 아직 본 적이 없습니다.”학습 지표가 높다는 사실과 실제 서비스가 성공한다는 사실은 같지 않습니다.
최종 모델은 실제 운영 환경과 유사한 데이터에서 검증해야 합니다.
훈련 데이터 성능
Validation 성능
Test 성능
실제 운영 성능네 숫자가 서로 비슷할 때 모델은 비로소 훈련장을 나와 실전에 투입될 준비를 갖춥니다.
이번 편까지 진행하면서 AI 학습 파이프라인의 중요한 조각이 연결되었습니다.
Hugging Face Hub
→ 사전 학습 모델 발견
Transformers
→ 모델 로딩
Datasets
→ 학습 데이터 준비
Trainer
→ Fine-tuning
Pipeline
→ 추론
Gradio
→ 웹 데모이제 Python 코드 몇 줄로 사전 학습 모델을 가져오는 단계를 넘어, 우리 데이터와 업무 기준을 반영한 전용 모델을 만들 수 있게 되었습니다. 🤗🚀
다음 편 예고
[Python 완전정복 시리즈 #38] PEFT와 LoRA 완벽 이해하기 | 거대한 AI 모델의 일부만 학습해 비용과 메모리를 줄이는 방법
다음 시간에는 대형 Transformer 모델의 모든 파라미터를 학습하지 않고 작은 Adapter만 학습하는 PEFT와 LoRA를 알아봅니다.
LoRA의 원리, Rank와 Alpha, Target Module, Trainable Parameter 확인, QLoRA 개념, Adapter 저장과 병합, Trainer 연결, GPU 메모리 절감, Hugging Face Hub 업로드까지 실습합니다.
#Python #파이썬 #Python강좌 #파이썬기초 #HuggingFace #허깅페이스 #Transformers #Trainer #TrainingArguments #FineTuning #파인튜닝 #DistilBERT #감정분석 #머신러닝 #딥러닝 #인공지능 #AI모델학습 #Tokenizer #DataCollator #DynamicPadding #EarlyStopping #Checkpoint #GradientAccumulation #FP16 #BF16 #PyTorch #HuggingFaceHub #모델배포 #코딩공부 #프로그래밍
