[허깅페이스] Transformers 사용해보기
트랜스포머 모델을 훈련시키고, 배포하는 것은 쉽지 않습니다. 허깅페이스에서 제공하는 Transformers 라이브러리는 이러한 문제를 해결하기 위해 만들어졌으며, 실제 많은 연구와 모델 구현에 활용되고 있습니다.
해당 라이브러리를 이해하기 위해 내부 동작 과정을 자세히 알아봅시다.
1. 파이프라인 내부 동작 과정
1) Tokenizer를 이용한 전처리
다른 모델과 마찬가지로 Transformer 모델도 원시 텍스트를 바로 처리할 수 없기 때문에 파이프라인의 첫번째 단계는 텍스트를 모델이 이해할 수 있는 숫자로 변환하는 것 입니다. 이 과정을 위해 토크나이저를 사용합니다.
전처리에 사용하는 클래스는 "AutoTokenizer" 클래스이며, "AutoTokenizer"의 from_pretrained() 메서드를 사용합니다. 체크포인트 이름을 사용하여 모델의 토크나이저와 연관된 데이터를 자동으로 가져와서 저장합니다.
from transformers import AutoTokenizer
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
토크나이저는 아래와 같이 여러 개의 문장 리스트를 전달 받아, 텐서 형태로 데이터를 반환받을 수 있고, 텐서 유형까지 지정할 수 있습니다. 얻고자 하는 tensor 타입을 지정하여 return_tensors 전달인자를 사용합니다.
raw_inputs = [
"I've been waiting for a HuggingFace course my whole life.",
"I hate this so much!",
]
inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt")
print(inputs)
출력은 아래와 같습니다.
"input_ids"와 "attention_mask" 2개의 키를 갖는 딕셔너리 입니다. input_ids는 각 문장 내 토큰의 고유 식별자인 정수로 이루어진 2개의 행을 가지고 있습니다. 즉 컴퓨터는 텍스트를 직접 이해하지 못하므로 텍스트를 작은 단위로 쪼개고, 각 토큰을 고유 숫자로 변환하였습니다.
{
'input_ids': tensor([
[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102],
[ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0]
]),
'attention_mask': tensor([
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
])
}
2) 모델 처리
전처리 과정에서 숫자로 변환된 데이터가 모델에 입력되는 처리 과정 입니다. 모델은 각 입력에 대해 의미를 담은 숫자 벡터(hidden states)를 생성하며, 특정 작업을 위한 모델 헤드가 이 벡터를 최종 결과물로 변환합니다.
from transformers import AutoModelForSequenceClassification
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
3) 후처리
아래 모델은 문장을 긍정 또는 부정으로 분류할 수 있게 하는 시퀸스 분류 헤드를 가진 " AutoModelForSequenceClassification" 모델을 사용합니다. 출력 형태를 보면 차원이 훨씬 적은 것을 알 수 있습니다.
이전에 봤던 고차원 벡터를 입력으로 받아 2개의 값으로 이루어진 벡터를 출력합니다.
from transformers import AutoModelForSequenceClassification
checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
print(outputs.logits.shape)
# torch.Size([2, 2])
모델의 출력 값이 그 자체로 의미있는 것은 아닙니다. 이 값들은 확률이 아니라 모델의 마지막 층에 의해 출력된 정규화 되지 않은 점수인 logits입니다. 확률로 변환되기 위해 logits은 Softmax층을 거쳐야 합니다.
print(outputs.logits)
# tensor([[-1.5607, 1.6123],
# [ 4.1692, -3.3464]], grad_fn=<AddmmBackward>)
모델은 첫번째 문장에 대해 [0.0402, 0.9598]로 예측했고, 두번째 모델에 대해 [0.9995, 0.0005]로 예측했습니다. 이 값들은 확실하게 확률값이었습니다. 즉 모델의 예측 결과는 다음과 같습니다.
- 첫 번째 문장: NEGATIVE: 0.0402, POSITIVE: 0.9598
- 두 번째 문장: NEGATIVE: 0.9995, POSITIVE: 0.0005
import torch
predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
print(predictions)
# tensor([[4.0195e-02, 9.5980e-01],
# [9.9946e-01, 5.4418e-04]], grad_fn=<SoftmaxBackward>)
model.config.id2label
# {0: 'NEGATIVE', 1: 'POSITIVE'}
이렇듯 Transformers는 복잡한 텍스트 처리 과정을 간편하게 수행할 수 있도록 도와주는 도구 입니다. 내부적으로는 여러 단계를 거치지만, 사용자는 몇 줄의 코드만으로 AI 기능을 활용할 수 있게 됩니다.