Model을 훈련하려면 dataset를 모델에 맞는 입력 형식(Tensor)으로 전처리 해야합니다. 우리의 데이터가 텍스트, 이미지, 오디오이던 간에, 모든 데이터는 Tensor batch
형태로 변환되어야 합니다.
HuggingFace의 Transformers는 데이터를 전처리하기 위한 클래스 및 함수를 제공합니다. NLP에서는, 데이터 전처리를 위해 Tokenizer
를 사용해서 텍스트를 Token sequence(tokens)
로 변환하고, tokens
들을 모델의 input이 되는 숫자
와 Tensor
로 변환합니다.
만약 우리가 pretrained 모델을 사용한다면, pretrained된 토크나이저를 사용해야합니다. 이렇게 하면 텍스트가 사전 학습 코퍼스와 동일한 방식으로 분할되고, 사전 학습 중에 동일한 해당 토큰-인덱스(일반적으로 vocab)를 사용합니다.
pretrained 토크나이저는 AutoTokenizer.from_pretrained()
메소드를 통해 로드할 수 있습니다. 이는 모델의 pretrained vocab를 다운로드합니다.
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("roberta-base")
그리고 우리의 테스트 텍스트를 토크나이저에 통과시켜봅시다. tokenizer(text)
메소드를 통해 통과시킬 수 있습니다.
encoded_input = tokenizer("This is the study of natural language processing")
encoded_input
#output
{'input_ids': [0, 713, 16, 5, 892, 9, 1632, 2777, 5774, 2],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
토크나이저는 최대 3개의 dictionary 아이템들을 리턴합니다.
input_ids
: 토큰화된 input에서 각 토큰에 상응하는 index들의 값attention_mask
: 토큰화된 input에서 해당 토큰에 attention할것인지 아닐것인지 나타내는 값token_type_ids
: 위의 예시에서는 없지만, 둘 이상의 시퀀스가 있는 경우 토큰이 속한 시퀀스를 식별합니다.input_ids
를 디코딩해서 input을 다시 확인해봅시다. tokenizer.decode(input_ids)
메소드를 통해 디코딩할 수 있습니다.
tokenizer.decode(encoded_input["input_ids"])
#output
'<s>This is the study of natural language processing</s>'
스페셜 토큰이란 Transformer 모델에서 사용되는 특수 토큰
입니다. 주로 tokenizer는 자동으로 스페셜 토크들을 추가해줍니다.
위의 예시에서보면 우리의 토크나이저는 스페셜 토큰 s
를 문장 앞뒤로 추가한 것을 볼 수 있습니다. 이들은 토크나이저를 통해, 토큰들을 인코딩할 때 추가되는 특별한 토큰입니다. RoBERTa 토크나이저는 오직 <s>(BOS token)
와 </s>(SEP token)
만 가지고 있습니다.
스페셜 토큰은 여러가지 종류가 있습니다.
bos_token
: 문장의 시작부분을 나타내는 토큰입니다. eos_token
: 문장의 끝을 나타내는 토큰입니다.sep_token
: 문장과 문장의 구분을 나타내는 토큰입니다. 주로 두 문장을 하나로 결합할 때 사용됩니다. cls_token
: 주로 classification 문제에서 사용되는 토큰으로, 문장의 시작에 추가되며, 이를 통해 모델은 입력문장에 대한 분류를 수행할 수 있습니다. mask_token
: 언어 모델 학습과 같은 곳에서 사용됩니다. 모델이 문장에서 어떤 부분을 예측하도록 만들기 위해 랜덤하게 선택된 토큰들을 가려주는데 사용됩니다.Padding
은 주로 시퀀스의 길이를 맞추기 위해 사용됩니다. 모든 시퀀스를 동일한 길이로 만들기 위해 짧은 시퀀스에 패딩을 추가할 때 사용됩니다.
만약 모델이 100개의 토큰을 필요로 한다면 80개의 토큰이 있는 시퀀스에 나머지 20개를 채우기 위해 pad_token이 사용됩니다. padding=True
설정을 통해 패딩을 설정할 수 있습니다.
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True)
print(encoded_input)
#output
{'input_ids': [[0, 1708, 99, 59, 200, 7080, 116, 2, 1, 1, 1, 1, 1],
[0, 6766, 75, 206, 37, 2215, 59, 200, 7080, 6, 30533, 4, 2],
[0, 2264, 59, 19353, 29, 918, 116, 2, 1, 1, 1, 1, 1]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[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]]}
첫문장과 마지막 문장의 input_ids를 보면 나머지 부분이 1로 채워진 것을 볼 수 있습니다.
반대의 케이스로 만약 시퀀스의 길이가 너무 길면 어떨까요? 모든 시퀀스를 동일한 길이로 맞추기 위해 긴 시퀀스를 잘라냅니다. truncation=True
설정을 통해 잘라낼 수 있습니다.
batch_sentences = [
"But what about second breakfast?",
"Don't think he knows about second breakfast, Pip.",
"What about elevensies?",
]
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True)
print(encoded_input)
#output
{'input_ids': [[0, 1708, 99, 59, 200, 7080, 116, 2, 1, 1, 1, 1, 1],
[0, 6766, 75, 206, 37, 2215, 59, 200, 7080, 6, 30533, 4, 2],
[0, 2264, 59, 19353, 29, 918, 116, 2, 1, 1, 1, 1, 1]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[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]]}
마지막 작업은 input을 텐서로 변환해주어야 합니다. return_tensors=
설정을 통해 설정 할 수 있습니다.
encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt")
print(encoded_input)
#output
{'input_ids': tensor([[0, 1708, 99, 59, 200, 7080, 116, 2, 1, 1, 1, 1, 1],
[0, 6766, 75, 206, 37, 2215, 59, 200, 7080, 6, 30533, 4, 2],
[0, 2264, 59, 19353, 29, 918, 116, 2, 1, 1, 1, 1, 1]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[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]])}