⊢ AI 모델 활용

사전 학습과 파인 튜닝

최 수빈 2025. 3. 25. 00:43

 

사전 학습 (Pre-training)

 

대규모 일반 텍스트 데이터로 언어의 패턴과 구조를 학습하는 과정

 

방대한 데이터셋 사용 (예: 위키백과, 북 코퍼스)

특정 작업(X) 일반적인 언어 이해(O)

 

예:

BERT 사전 학습

MLM(Masked Lanuage Modeling): 일부 단어를 가리고 예측

NSP (Next Sentence Prediction): 문장 간 자연스러운 연결 예측

 

 

파인 튜닝 (Fine-tuning)

 

사전 학습된 모델을 특정 작업(예: 감정 분석)에 맞게 추가 학습

 

특정 태스크에 맞춘 미세 조정

적은 데이터로도 효과적

사전 학습된 가중치를 기반으로 빠른 수렴 가능

 

 

 

IMDb 영화 리뷰 감정 분석

*IMDb(Internet Movie Database)

영화 리뷰를 바탕으로 만든 이진 감정 분석용 데이터셋

  • 샘플 수: 총 50,000개 (Train 25,000개 + Test 25,000개)
  • 라벨: 긍정(1), 부정(0)
  • 형식: 영화 리뷰 텍스트(text) + 감정 라벨(label)
  • 라벨 분포: 긍정 50%, 부정 50%
  • 언어: 영어
  • 토큰화 상태: 전처리되지 않음(Raw text)

 

라이브러리 설치 및 임포트

pip install transformers datasets torch accelerate -U
from transformers import AutoTokenizer, AutoForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
import torch
import numpy as np
from sklearn.metrics import accuracy_score

AutoTokenizer 어떤 모델이 주어지든 알아서 맞은 tokenizer를 불러옴

AutoForSequenceClassification Hugging Face에서 자동으로 적절한 모델 클래스를 불러와주는 스마트 클래스

 

 

데이터 로드

dataset = load_dataset("imdb")

 

 

토크나이저 설정 및 토큰화

# 토크나이저 설정
model_checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)

# 전처리 함수 정의
def tokenize_function(examples):
    return tokenizer(examples['text'], padding="max_length", truncation=True)
    
# 토큰화 적용
tokenized_datasets = dataset.map(tokenize_function, batched=True)

 

 

BERT 모델 로드 및 학습 준비

model = AutoForSequenceClassification.from_pretrained(model_checkpoint, num_labels=2)

training_args = TrainingArguments(
    output_dir='./results', # 학습된 모델과 체크포인트 저장 경로
    evaluation_strategy='epoch', # 평가를 언제 할지: 'epoch'마다 평가 진행
    save_strategy='epoch', # 체크포인트 저장 시점: 'epoch'마다 저장
    num_train_epochs=3, # 총 학습 epoch 수 (3번 데이터셋 전체 반복)
    per_device_train_batch_size=8, # GPU 하나당 학습 배치 사이즈
    per_device_eval_batch_size=8, # GPU 하나당 평가 배치 사이즈
    weight_decay=0.01, # L2 정규화 계수 (과적합 방지용)
    load_best_model_at_end=True, # 평가 지표 기준으로 가장 좋은 모델을 마지막에 로드함
    logging_dir='./logs', # 로그 저장 경로 (TensorBoard 등에서 사용 가능)
    logging_steps=100, # 100 step 마다 로그 출력 (loss 등 출력됨)
    save_steps=10000, # 10,000 step마다 저장 (epoch 기준 저장과 별개) 
    save_total_limit=2, # 체크포인트 최대 2개만 유지 (이전 건 삭제됨)
)

 

 

Trainer 구성 및 모델 학습

#Trainer 준비
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["test"],
)

# 학습 시작
trainer.train()

"""
 [9375/9375 2:35:05, Epoch 3/3]
Epoch	Training Loss	Validation Loss
1	0.269100	0.332941
2	0.192500	0.251271
3	0.066700	0.327422
TrainOutput(global_step=9375, training_loss=0.20054683151245117, metrics={'train_runtime': 9307.7521, 'train_samples_per_second': 8.058, 'train_steps_per_second': 1.007, 'total_flos': 1.9733329152e+16, 'train_loss': 0.20054683151245117, 'epoch': 3.0})
"""

 

 

모델 성능 평가 (정확도)

def compute_metrics(p):
    preds = np.argmax(p.predictions, axis=1)
    labels = p.label_ids
    acc = accuracy_score(labels, preds)
    return {'accuracy': acc}

trainer.compute_metrics = compute_metrics

eval_result = trainer.evaluate()
print(f"Accuracy: {eval_result['eval_accuracy']:.4f}")

 

 

  사전 학습 (Pre-training) 파인 튜닝(Fine-tuning)
목적 일반 언어 이해 능력 학습 특정 작업(예: 감정 분석)에 맞춤 조정
데이터 대규모 범용 텍스트 도메인 특화 소량 데이터 가능
학습 방식 MLM, NSP 등 언어 모델링 과제  분류, 요약, 질의응답 등 태스크 기반
Hugging Face 대부분의 모델이 이 과정을 거쳐 제공됨 사용자가 직접 수행해야 함

 

Fine-tuning으로 사전 학습 기반의 다양한 NLP 태스크(번역, 질의응답, 요약 등)로 확장할 수 있음

 

import torch.nn.functional as F

checkpoint_path = "./results"

tokenizer = AutoTokenizer.from_pretrained(checkpoint_path)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint_path)
model.eval()

def predict_sentiment(text):
  # 토크나이즈
  inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True)
  
  # 모델에 입력
  with torch.no_grad():
    outputs = model(**inputs)
    logits = outputs.logits
    probs = F.softmax(logits, dim=1)
    pred_class = torch.argmax(probs, dim=1).item()

  # 결과 리턴
  label_map = {0: "부정", 1: "긍정"}
  return label_map[pred_class], probs.squeeze().tolist()
  
  while True:
  user_input = input("\n문장 입력 (종료하려면 'exit' 입력): ")
  if user_input.lower() == "exit":
    break
  sentiment, probs = predict_sentiment(user_input)
  print(f"감정: {sentiment}, 확률: {probs}")
  
"""
문장 입력 (종료하려면 'exit' 입력): 모르겠음
감정: 부정, 확률: [0.6484286189079285, 0.3515714406967163]

문장 입력 (종료하려면 'exit' 입력): 부정아닌데?
감정: 부정, 확률: [0.9052274823188782, 0.09477252513170242]

문장 입력 (종료하려면 'exit' 입력): 아니라고
감정: 긍정, 확률: [0.33711591362953186, 0.6628841757774353]

문장 입력 (종료하려면 'exit' 입력): 재밌었다.
감정: 긍정, 확률: [0.4452223479747772, 0.5547776222229004]

문장 입력 (종료하려면 'exit' 입력): good
감정: 긍정, 확률: [0.002968259621411562, 0.9970316886901855]

문장 입력 (종료하려면 'exit' 입력): not bad
감정: 부정, 확률: [0.9740968942642212, 0.025903116911649704]

문장 입력 (종료하려면 'exit' 입력): not good
감정: 부정, 확률: [0.9976633787155151, 0.002336661797016859]

문장 입력 (종료하려면 'exit' 입력): 음.. 
감정: 부정, 확률: [0.9087718725204468, 0.09122808277606964]

문장 입력 (종료하려면 'exit' 입력): 킹왕짱
감정: 부정, 확률: [0.6484286189079285, 0.3515714406967163]

문장 입력 (종료하려면 'exit' 입력): 잼따
감정: 부정, 확률: [0.6484286189079285, 0.3515714406967163]

문장 입력 (종료하려면 'exit' 입력): exit
"""

 

별로다.