텍스트 분류는 입력 텍스트에 미리 정의된 **레이블(Label)**을 부여하는 태스크입니다. 스팸 필터링, 감성 분석, 주제 분류, 의도 인식 등 가장 널리 사용되는 NLP 태스크 중 하나입니다. 이 문서에서는 한국어 감성 분석 데이터셋을 사용하여 BERT 모델을 Fine-tuning하는 전체 과정을 실습합니다.
# 결측치 제거dataset = dataset.filter(lambda x: x["document"] is not None)print(f"훈련 데이터: {len(dataset['train']):,}건")print(f"테스트 데이터: {len(dataset['test']):,}건")
2
토크나이저 적용
한국어 BERT 모델의 토크나이저를 사용하여 텍스트를 토큰화합니다.
Copy
from transformers import AutoTokenizermodel_name = "klue/bert-base"tokenizer = AutoTokenizer.from_pretrained(model_name)# 토크나이징 예시sample = "이 영화 정말 재미있었어요!"tokens = tokenizer(sample, return_tensors="pt")print(tokenizer.convert_ids_to_tokens(tokens["input_ids"][0]))# ['[CLS]', '이', '영화', '정말', '재미있', '##었', '##어요', '!', '[SEP]']
전체 데이터셋에 토크나이저를 일괄 적용합니다.
Copy
def tokenize_function(examples): """데이터셋 토크나이징 함수""" return tokenizer( examples["document"], padding="max_length", truncation=True, max_length=128, # 리뷰 텍스트는 대부분 128 토큰 이내 )# 배치 단위 토크나이징 (num_proc으로 병렬 처리)tokenized_dataset = dataset.map( tokenize_function, batched=True, num_proc=4, remove_columns=["id", "document"], # 불필요한 컬럼 제거)# 모델이 기대하는 형식으로 포맷 설정tokenized_dataset.set_format("torch")print(tokenized_dataset["train"].column_names)# ['label', 'input_ids', 'token_type_ids', 'attention_mask']
3
모델 준비 및 학습 설정
사전학습된 BERT에 분류 헤드(Classification Head)를 추가한 모델을 로딩합니다.
Copy
from transformers import AutoModelForSequenceClassificationmodel = AutoModelForSequenceClassification.from_pretrained( model_name, num_labels=2, # 이진 분류)# BERT 본체 위에 Linear(768, 2) 분류 헤드가 추가됩니다
Trainer에 전달할 학습 인자를 설정합니다.
Copy
from transformers import TrainingArgumentstraining_args = TrainingArguments( output_dir="./results", eval_strategy="epoch", # 매 에포크마다 평가 save_strategy="epoch", learning_rate=2e-5, # BERT Fine-tuning 권장 lr per_device_train_batch_size=32, per_device_eval_batch_size=64, num_train_epochs=3, weight_decay=0.01, load_best_model_at_end=True, # 최고 성능 모델 자동 복원 metric_for_best_model="f1", logging_steps=500, fp16=True, # Mixed Precision 학습)
from transformers import Trainertrainer = Trainer( model=model, args=training_args, train_dataset=tokenized_dataset["train"], eval_dataset=tokenized_dataset["test"], compute_metrics=compute_metrics,)# 학습 시작trainer.train()
학습이 완료되면 자동으로 최고 성능 모델이 복원됩니다.
5
모델 평가 및 추론
테스트 데이터셋에서 최종 성능을 확인합니다.
Copy
# 테스트셋 평가results = trainer.evaluate()print(f"Accuracy: {results['eval_accuracy']:.4f}")print(f"F1-Score: {results['eval_f1']:.4f}")# klue/bert-base 기준 약 Accuracy 0.90, F1 0.90 수준
학습된 모델로 새로운 텍스트를 추론합니다.
Copy
from transformers import pipeline# 추론 파이프라인 생성classifier = pipeline( "text-classification", model=trainer.model, tokenizer=tokenizer, device=0, # GPU 사용)# 새로운 리뷰 예측texts = [ "연기도 좋고 스토리도 탄탄해서 몰입감이 대단했습니다", "시간 아까운 영화. 다시는 안 봄", "그저 그런 영화였어요. 나쁘지도 좋지도 않은",]predictions = classifier(texts)for text, pred in zip(texts, predictions): label = "긍정" if pred["label"] == "LABEL_1" else "부정" print(f"[{label} ({pred['score']:.2f})] {text}")
클래스 불균형 주의: 데이터셋의 클래스 비율이 불균형할 경우 Accuracy만으로는 모델 성능을 정확히 판단할 수 없습니다. 예를 들어 긍정 95%, 부정 5%인 데이터셋에서 모든 것을 긍정으로 예측해도 Accuracy는 95%입니다. F1-Score를 주요 지표로 사용하세요.
KLUE-TC(Topic Classification)는 7개 주제(정치, 경제, 사회, 생활, 세계, IT/과학, 스포츠)로 분류하는 다중 클래스 데이터셋입니다.
Copy
# KLUE-TC 데이터셋 로딩klue_tc = load_dataset("klue", "ynat")# num_labels만 변경하면 동일한 파이프라인 사용 가능model = AutoModelForSequenceClassification.from_pretrained( "klue/bert-base", num_labels=7, # 7개 클래스)
다중 클래스에서는 macro 또는 weighted 평균 F1-Score를 사용합니다.
Copy
f1_metric = evaluate.load("f1")def compute_metrics_multiclass(eval_pred): logits, labels = eval_pred predictions = np.argmax(logits, axis=-1) return { "f1_macro": f1_metric.compute( predictions=predictions, references=labels, average="macro", # 클래스별 F1의 단순 평균 )["f1"], "f1_weighted": f1_metric.compute( predictions=predictions, references=labels, average="weighted", # 클래스 비율 가중 평균 )["f1"], }
CUDA Out of Memory 오류가 발생합니다
per_device_train_batch_size를 줄이세요 (32 → 16 → 8). GPU 메모리에 따라 적절한 배치 크기가 다릅니다. fp16=True 설정으로 메모리 사용량을 약 절반으로 줄일 수 있습니다. gradient_accumulation_steps를 함께 늘려 실효 배치 크기를 유지하세요.
학습 loss가 줄어들지 않습니다
Learning rate가 너무 높거나 낮을 수 있습니다. BERT Fine-tuning에는 2e-5 ~ 5e-5 범위가 권장됩니다. 데이터 전처리 과정에서 label 컬럼이 올바르게 매핑되었는지 확인하세요.
검증 성능이 에포크마다 악화됩니다
과적합(Overfitting)의 징후입니다. weight_decay를 늘리거나, num_train_epochs를 줄이세요. load_best_model_at_end=True가 설정되어 있다면 최고 성능 모델이 자동으로 복원됩니다.
한국어 텍스트가 [UNK] 토큰으로 많이 변환됩니다
모델의 토크나이저가 한국어를 충분히 커버하지 못하는 경우입니다. bert-base-multilingual-cased 대신 klue/bert-base나 monologg/kobert 같은 한국어 특화 모델을 사용하세요.