transformers 사용 - NLP, Pytorch

Hugging Face에서 제공하는 transformers를 이용하면, 모델의 구조를 전부 설계할 필요 없이 편리하게 사전 학습된 모델을 사용할 수 있다. 

* 아래에 작성한 코드는 Jupyter(Colab) 환경에서 실행한다는 전제로 작성하였다. 

참고자료: https://huggingface.co/docs/transformers/index

 

🤗 Transformers

Reinforcement learning models

huggingface.co

 

설치

!pip install transformers

Pipeline

pipeline은 해결하고자 하는 문제(task)에 맞는 사전학습 모델을 제공한다. task의 분류는 pipeline에서 확인할 수 있다. 

예를 들어, NER(개체명 인식 문제)을 통해 이름과 고유명사를 찾는 방식은 아래와 같다.

from transformers import pipeline

# NER 모델 다운로드
ner = pipeline(task="ner")

# NER 태그 생성
sentences = ["James lives in England", "I like Disney"]
results = ner(sentences)

# 결과 확인
for result in results:
    print(result)
    
"""
[{'entity': 'I-PER', 'score': 0.9993838, 'index': 1, 'word': 'James', 'start': 0, 'end': 5}, {'entity': 'I-LOC', 'score': 0.99970454, 'index': 4, 'word': 'England', 'start': 15, 'end': 22}]
[{'entity': 'I-ORG', 'score': 0.9083705, 'index': 3, 'word': 'Disney', 'start': 7, 'end': 13}]
"""

Tokenizer, Model

  • AutoTokenizer는 사전 학습된 tokenizer를 제공한다. 
  • AutoModel은 사전 학습된 모델을 제공한다.

from_pretrained에 원하는 사전학습 모델을 입력해주면 자동으로 모델을 가져와준다. [문서] 참고.

from transformers import AutoTokenizer, AutoModel

# Tokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# Model
model = AutoModel.from_pretrained('bert-base-cased')

 

모델 클래스를 명시적으로 불러오는 방법도 있다. 제공하는 모델: [문서 > API > MODELS > TEXT MODELS]

from transformers import BertTokenizer, BertModel

model = BertModel.from_pretrained('bert-base-cased')
tokenizer = BertTokenizer.from_pretrained('bert-base-cased')

 

기본 모델 외에 다양한 사전 학습 모델들이 있다. 모델을 불러오는 방법은 각 모델의 설명을 확인해야 한다. 

예: 

from transformers import PreTrainedTokenizerFast

tokenizer = PreTrainedTokenizerFast.from_pretrained("skt/kogpt2-base-v2")
tokenizer.tokenize("SKT에서 공개한 한국어 GPT-2입니다.")

Tokenize

위에서 보았던 Tokenizer를 활용해 문장의 토큰화를 수행한다. 토큰화를 수행하는 방식은 tokenizer마다 다르다. 

  • padding: 문장의 길이가 다를 때, 짧은 문장에 padding 값을 더해 길이를 맞춘다. 
  • truncation: 문장의 길이가 길 때, 모델이 받을 수 있는 길이로 자른다. 
  • return_tensors: "pt"일 때, 반환값을 torch의 tensor로 받는다.
  • 다른 파라미터: [문서]
from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
sentences = [...]

encoded = tokenizer(
    sentences, 
    padding=True, 
    truncation=True, 
    return_tensors="pt"
)

Fine-Tuning

fine-tuning은 사전 학습된 모델에 추가로 데이터를 학습시켜 모델을 원하는 방향으로 변형하는 것이다. 

(아래 내용은 자세한 설명보다 전체적인 학습 과정을 보여주는데 집중하였다.)

!pip install datasets
from datasets import Dataset
from transformers import AutoTokenizer

# tokenize 불러오기
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

def tokenize(data):
    # 토근화 수행
    return tokenizer(data["text"], padding="max_length", truncation=True)


# df_train = pd.read_csv(...)

# DataFrame에서 Dataset 객체로 변환
train_set = Dataset.from_pandas(df_train.reset_index(drop=True))

# 위에서 수행한 `tokenize` 함수를 데이터에 적용
train_set = train_set.map(tokenize, batched=True, batch_size=len(train_set))

# DataFrame에서 torch 데이터로 변경
train_set.set_format("torch", columns=[...])

데이터를 불러온 후 tokenize한 데이터이다. 위 코드는 datasets.Dataset 패키지를 활용해 데이터를 처리한 예시이다. (pandas)Dataframe으로된 데이터를 불러와 인덱스를 제거하고 토큰화를 수행한다. 

 

from transformers import AutoModelForSequenceClassification, TrainingArguments

# 모델 불러오기
model = AutoModelForSequenceClassification.from_pretrained(
    "bert-base-cased", 
    num_labels=5
)
# 학습에 필요한 파라미터 전달
TRAIN_ARGS = TrainingArguments(
    num_train_epochs=5,
    per_device_train_batch_size=8,  
    per_device_eval_batch_size=8,
    learning_rate=2e-5,
    warmup_steps=500,
    weight_decay=0.01,
    save_strategy="no"
)

device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device)

사전 학습된 bert-base 모델을 불러오고, transformers에서 제공하는 TrainingArguments에 파라미터를 설정해 준다. 

 

from sklearn.metrics import accuracy_score, f1_score

def compute_metrics(pred):
    labels = pred.label_ids
    preds = pred.predictions.argmax(-1)
    f1 = f1_score(labels, preds, average="macro")
    acc = accuracy_score(labels, preds)
    return {
        "f1": f1,
        "accuracy": acc
    }
# 학습할 모델과 데이터 등을 전달
trainer = Trainer(
    model=model,
    args=TRAIN_ARGS,
    compute_metrics=compute_metrics,
    train_dataset=train_set,
    eval_dataset=eval_set
)

compute_metrics 함수는 모델을 평가하기 위해 전달되는 함수이며, Trainer 객체를 이용하면 쉽게 학습과 평가를 진행할 수 있다. 만약 변경하고 싶은 내용이 있다면 위에서 봤던 TrainingArguments에서 변경해주면 된다.

 

trainer.train()  # 학습
model_eval = trainer.evaluate()  # 평가

print("Accuracy: {:.5f}".format(model_eval["eval_accuracy"]))
print("F1-macro: {:.5f}".format(model_eval["eval_f1"]))

학습과 평가는 매우 간단하다. train을 통해 학습을 진행하고, evaluate를 통해 평가한다. compute_metrics 함수의 반환값 key에 eval_ 을 붙여 평가값을 가져올 수 있다. (i.e. 'f1' → 'eval_f1')


Pytorch

위 예시는 transformers에서 제공하는 객체를 활용해 학습하는 방식이다. pytorch에서 학습하는 것과 동일하게 학습하고 싶다면, torch의 방식 그대로 적용해 학습하는 것도 가능하다. torch를 활용하면 더 정교한 학습이 가능하다는 장점이 있지만, 사용하고자 하는 모델의 데이터가 어떻게 토큰화되고, 어떤 값을 입력과 출력으로 가지는지 이해할 필요가 있다. 그리고 당연히 torch에 대한 지식도 필요하다. 반면 transformers는 모델에 대한 자세한 이해 없이도 간편하게 학습시킬 수 있다는 장점이 있다. 하지만 정교한 학습을 위해서는  transformers의 API에 대해 학습해야 하며, API에 의존할 수 밖에 없다는 단점이 있다. 따라서, 상황에 맞춰 필요한 방식을 선택하는 것이 좋아보인다. 

Pytorch를 활용한 예시는 아래 Github 링크를 통해 확인할 수 있다. 

예시

"# Model" 부분부터 확인하면 빠르게 학습 과정만 확인할 수 있다.