최근 NLP에선 BERT계열 모델을 활용한 Trnasfer-Learning이 굉장히 🔥hot🔥하다. 사실 Transfer-Learning이 유명해지게된 것은 Computer Vision 분야인데 BERT가 나오면서 NLP 분야에서도 Transfer-Learning이 hot해지기 시작하였다. NLP에 관심이 많은 사람들이라면 다 아는 이야기이니 전이학습, Transfer-Learning에 대한 이야기는 이정도로 하고 전이학습에서 주로 사용되는 용어인 PLM, Fine-tuning 등에 대해 간략히 설명해보겠다.
PLM(Pretrained Language Model)
많은 양의 텍스트 데이터를 활용하여 일반적인 수준의 언어 이해(language understanding)가 가능하도록 단어 시퀀스에 확률을 부여하는 모델인 LM(Language Model)을 사전에 학습시킨 모델을 의미한다.
Fine-tuning
사전에 학습시킨 언어 모델 PLM을 text_classification, QA(Question Answering), NER(Name Entity Recognintion) 과 같은 downstream task를 수행함으로써 PLM의 파라미터들을 재업데이트하는 과정을 fine-tuning이라고 말할 수 있다.
Inference
infernece란 fine-tuning처럼 학습을 마친 모델에 실제 데이터(test-data)를 input으로 적용하는 행위로 말할 수 있다.
자, 이제 간단하게 fine-tuning을 위한 기본적인 개념을 설명해보았고 이번 포스트에서 기술하려는 fine-tuning 프로젝트의 스펙(?)에 대해 간략하게 설명해보겠다.
- PyTorch에 대한 High-level 인터페이스를 제공하는 오픈소스 Python 라이브러리.
- 코드의 추상화를 통해, 정돈된 코드 스타일을 갖추게 된다는게 pytorch lightning의 장점이다.
- trainer 클래스가 매력적.
import transformers
import torch
import numpy as np
import pandas as pd
import random
import os
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_recall_fscore_support, accuracy_score
from datasets import load_dataset, load_metric
from transformers import Trainer,TrainingArguments,AutoTokenizer,AutoModelForSequenceClassification,DataCollatorForTokenClassification,EarlyStoppingCallback
from datasets import Dataset
import time
model_checkpoint = "klue/roberta-large"
batch_size = 32
wd = 0.01
lr = 2e-5
epochs = 3
task = "binary_classification"
label_list = [0,1]
num_labels = 2
def seed_everything(seed:42):
random.seed(seed)
np.random.seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed) # type: ignore
torch.backends.cudnn.deterministic = True # type: ignore
torch.backends.cudnn.benchmark = True # type: ignore
# fix seed
seed_everything(42)
- 대부분의 머신러닝 모델은 class간의 데이터의 비율이 비슷하다는 가정에서 성립된다.
- binary classification에서 class 0에 90%의 샘플이 있고, class 1에 10%의 샘플이 있을 때, loss 값에는 class 0가 90%, class 1이 10% 기여를 하는 셈이고 모든 예측을 0으로 한다고해도 90%의 정확도를 갖는 예측을 할 수 있게된다.
- 즉, 학습을 수행하는 loss 값에 각각 데이터 샘플 별로 기여를 하기 때문에, 샘플 수가 많은 majority class만을 잘 예측하도록 학습된다.
train_data, val_data = train_test_split(data, random_state=42,test_size=.2)
df_train = pd.DataFrame({"title":train_data["title"],'label':train_data["label"]})
dataset_train = Dataset.from_pandas(df_train)
df_val = pd.DataFrame({"title": val_data["title"],'label':val_data["label"]})
dataset_val = Dataset.from_pandas(df_val)
try:
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=num_labels)
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
except:
time.sleep(5)
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=num_labels)
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
import transformers
assert isinstance(tokenizer, transformers.PreTrainedTokenizerFast)
def tokenize_function(examples):
return tokenizer(examples["title"], padding="max_length", max_length = 50,truncation=True)
tokenized_train_datasets = dataset_train.map(tokenize_function, batched=True)
tokenized_val_datasets = dataset_val.map(tokenize_function, batched=True)
model_name = model_checkpoint.split("/")[-1]
args = TrainingArguments(
f"test-{task}",
evaluation_strategy = "epoch",
save_strategy = "epoch",
learning_rate= lr,#2e-5
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
num_train_epochs=epochs,
seed = 42,
weight_decay=wd,load_best_model_at_end=True,)
def compute_metrics(pred):
labels = pred.label_ids
preds = pred.predictions.argmax(-1)
precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='macro')
acc = accuracy_score(labels, preds)
return {
'accuracy': acc,
'f1': f1,
'precision': precision,
'recall': recall
}
trainer = Trainer(
model,
args,
train_dataset=tokenized_train_datasets,
eval_dataset=tokenized_val_datasets,
tokenizer=tokenizer,
compute_metrics=compute_metrics,
callbacks=[EarlyStoppingCallback(early_stopping_patience=3)],
)
trainer.train()
trainer.evaluate()
from transformers import pipeline
pipe = pipeline(task = "text-classification",
model = model,
tokenizer = tokenizer,
device = 0)
from sklearn.metrics import classification_report
print(classification_report(list(test_data["실적"]), list(test_data['filter'])))
해당 프로젝트는 필자가 이전 회사에서 진행하였던 NLP 프로젝트 중 하나였다.
binary classification 이외에도 QA,NER, Document Clustering 등 다양한 NLP 프로젝트들을 수행하였고 계속하여 관련 프로젝트에 대한 포스트를 올리도록 하겠다.
혹시 개념에서의 오류나 코드상에서의 오류 ,미숙함, 오타, 이것은 궤변이다, 등등 다양한 의견을 받고 있으니 언제든지 부족한 필자의 발전을 위해 남겨주면 감사하겠다 매우매우....!!!!!!!!
(https://medium.com/data-folks-indonesia/modeling-using-hugging-face-transformers-f956bccf7ccd)
(https://baeseongsu.github.io/posts/pytorch-lightning-introduction/)
(https://github.com/klue-benchmark/klue?utm_medium=social&utm_source=medium&utm_campaign=everyone%20ai&utm_content=klue)
(https://hyeonchan523.github.io/ds/class-imbalance/)
(http://blog.hwahae.co.kr/all/tech/tech-tech/5876/)
코드 구현하는데 큰 도움이 됐어요 감사합니다!