logo

[text-mining] BERT

BERT: Bi-directional Encoder Representations from Transformers

BERT는 양방향(Bi-directional)으로 정보를 처리하는 트랜스포머 기반의 언어 모형

  • 트랜스포머의 인코더를 이용
  • GPT와 달리 문장 중간의 마스킹된 단어를 예측하도록 학습
  • 다양한 종류의 자연어 처리 과제에 전이 학습을 쉽게 할 수 있도록 설계
 

BERT의 입력

BERT는 문장 분류 및 관계 처리를 위해 다음과 같은 특수 토큰과 임베딩을 사용

  • [CLS] 토큰: 문장 분류(classification)를 위한 특수 토큰으로 문장의 처음에 위치. 양방향 정보 전달 덕분에 [CLS] 토큰의 출력값을 이용해 문장 분류가 가능
  • [SEP] 토큰: 문장 구분(separation)을 위한 토큰으로 각 문장의 끝에 붙음
  • Token Embedding: 토큰 자체의 임베딩
  • Segment Embedding: 자연어 추론 등 두 문장의 관계를 처리할 때, 앞 문장과 뒤 문장을 구분하기 위한 임베딩
  • Position Embedding: 토큰의 위치를 나타내는 임베딩
 

BERT의 사전 학습

BERT는 크게 두 가지 방식으로 사전 학습을 진행

 

1. Masked Language Model (MLM)

입력 토큰 중 15%를 무작위로 선택하여 다음의 비율로 변형한 뒤, 원래 단어를 예측하도록 학습

  • 80%: [MASK] 토큰으로 대체
  • 10%: 무작위로 다른 토큰으로 대체
  • 10%: 원래 단어를 그대로 유지

이러한 방식은 모델이 가려지지 않은 토큰에 대해서도 문맥을 충분히 파악하게 하며, 입력과 출력이 항상 다르거나 같은 상황에 치우치지 않게 함

 

2. Next Sentence Prediction (NSP)

두 문장의 관계를 학습하기 위한 방법

  • 50%는 실제로 이어진 문장, 50%는 무작위로 짝지워진 문장을 입력
  • [CLS] 토큰의 출력값을 통해 두 문장이 실제로 이어진 관계인지 예측
 

BERT의 미세 조정 (Fine-tuning)

BERT는 GPT처럼 새로운 문장을 생성하기보다는, 미세 조정을 통해 다양한 자연어 처리 과제를 수행하는 데 유리

  • 단일 문장 분류: SST-2 (감성 분석), CoLA (문법성 판단)
  • 문장 짝 분류: 문장 유사도 비교, 자연어 추론
  • 토큰 분류: 개체명 인식 (NER)
  • KLUE (Korean Language Understanding Evaluation): 한국어 자연어 이해 평가를 위한 벤치마크 데이터셋 (뉴스 헤드라인 분류, 문장 유사도 비교 등 포함)
 

환경 설정 및 라이브러리 설치

!pip install transformers datasets accelerate evaluate
 

토크나이저 및 모델 로딩

한국어 기반의 klue/bert-base 모델을 사용합니다.

from transformers import AutoTokenizer, AutoModelForSequenceClassification

# 토크나이저 로딩
tokenizer = AutoTokenizer.from_pretrained("klue/bert-base")

# 모델 로딩 (카테고리 7개: IT과학, 경제, 사회, 생활문화, 세계, 스포츠, 정치)
seq_model = AutoModelForSequenceClassification.from_pretrained(
    "klue/bert-base", 
    num_labels=7,
    id2label={
        0: 'IT과학', 1: '경제', 2: '사회', 3: '생활문화', 4: '세계', 5: '스포츠', 6: '정치'
    }
)
seq_model.to('cuda:0')
 

데이터 로딩 및 전처리

datasets 라이브러리를 사용하여 KLUE의 YNAT(연합뉴스 타이틀) 데이터셋을 불러옵니다.

from datasets import load_dataset

ynat_train = load_dataset('klue', 'ynat', split='train')
ynat_val = load_dataset('klue', 'ynat', split='validation')

# 전처리 함수: 제목(title)을 토큰화
def convert_example(example):
    result = tokenizer(example['title'])
    result['label'] = [example['label']]
    return result

ynat_train_dataset = ynat_train.map(convert_example)
ynat_val_dataset = ynat_val.map(convert_example)
 

훈련 설정 및 평가 지표

Trainer 인터페이스를 사용하여 훈련을 진행

from transformers import TrainingArguments, Trainer, DataCollatorWithPadding
import evaluate
import numpy as np

# 하이퍼파라미터 설정
training_args = TrainingArguments(
    output_dir="test_trainer",
    num_train_epochs=1,
    eval_strategy="epoch"
)

# 데이터 수집기 (패딩 처리)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

# 평가 지표 (정확도)
metric = evaluate.load("accuracy")

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

# Trainer 설정
trainer = Trainer(
    model=seq_model,
    args=training_args,
    train_dataset=ynat_train_dataset,
    eval_dataset=ynat_val_dataset,
    data_collator=data_collator,
    compute_metrics=compute_metrics,
)

# 훈련 시작
trainer.train()
 

저장

# 훈련된 모델을 구글 드라이브에 저장
model_path = 'drive/MyDrive/bert-ynat'
seq_model.save_pretrained(model_path)

# 구글 드라이브에서 모델 불러오기
seq_model = AutoModelForSequenceClassification.from_pretrained(model_path)
 

파이프라인 만들기

# 파이프라인으로 테스트
from transformers import pipeline
text_cls = pipeline('text-classification', model=seq_model, tokenizer=tokenizer, device='cuda:0')
text_cls('2회 연속 은메달 우상혁 "아쉽지만 파리올림픽 있어."')
Previous
GPT 미세 조정