[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회 연속 은메달 우상혁 "아쉽지만 파리올림픽 있어."')