[Huggingface 🤗 Transformers Tutorial] 3. Preprocess

nkw011·2022년 8월 25일
1

※ 이 글의 원문은 이 곳에서 확인할 수 있습니다.
※ 모든 글의 내용을 포함하지 않으며 새롭게 구성한 내용도 포함되어 있습니다.

tokenizer를 이용해서 주어진 text를 model이 요구하는 형식에 맞게 전처리하는 과정을 간단하게 익혀봅니다.

!pip install transformers

먼저 전처리할 문장 3개를 정의힙나다.

texts = ['이순신은 조선 중기의 무신이었다.', '본관은 덕수, 자는 여해, 시호는 충무였으며, 한성 출신이었다.', '옥포해전은 이순신의 첫 승전을 알리게 된 해전이다.']

Tokenize

tokenization에 필요한 tokenizer를 불러옵니다. 여기서는 'bert-base-multilingual-cased'를 사용합니다.

MODEL_NAME = 'bert-base-multilingual-cased'
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)

tokenizer를 이용해 tokenization하는 방법은 3가지가 있었습니다.

  1. tokenizer를 call하는 방식
  2. tokenize() 메소드
  3. encode() 메소드

2,3번 방식은 tokenization을 하지만 model이 요구하는 입력 형태로 반환하지 않습니다. 단순히 tokenization과 encoding만 해줄 뿐입니다.

1번 방식을 이용해 model이 요구하는 모든 입력 요소를 반환하겠습니다.

encoded_input = tokenizer(texts[0])

print(encoded_input)
{'input_ids': [101, 9638, 119064, 25387, 10892, 59906, 9694, 46874, 9294, 25387, 58926, 119, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

한 문장이 아니라 여러 문장들을 동시에 tokenization하기 위해서는 입력으로 문장 리스트를 넣어주면 됩니다.

encoded_inputs = tokenizer(texts)

for key in encoded_inputs.keys():
    print(f"{key}(길이: {len(encoded_inputs[key])}): {encoded_inputs[key]}")
input_ids(길이: 3): [[101, 9638, 119064, 25387, 10892, 59906, 9694, 46874, 9294, 25387, 58926, 119, 102], [101, 9358, 101958, 9075, 15891, 113, 3789, 4867, 114, 117, 9651, 11018, 9565, 14523, 113, 4886, 7247, 114, 117, 9485, 100543, 9770, 32537, 113, 3803, 4794, 114, 9573, 24098, 117, 9954, 17138, 9768, 25387, 58926, 119, 102], [101, 9581, 55530, 14523, 16617, 10892, 9638, 119064, 87143, 9750, 9484, 54918, 9524, 12692, 14153, 9099, 9960, 16617, 11925, 119, 102]]
token_type_ids(길이: 3): [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
attention_mask(길이: 3): [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

text는 총 3개 였습니다. input_ids, token_type_ids, atttention_mask 모두 3개가 만들어진 것을 확인할 수 있습니다.

Pad

모델의 입력으로 사용하기 위해서는 batch로 들어오는 모든 sequence의 길이가 동일해야합니다. padding token을 추가하여 sequence의 길이를 동일하게 맞출 수 있습니다.

# pad token id
print(tokenizer.vocab['[PAD]'])
0
encoded_inputs = tokenizer(texts, padding=True)

for key in encoded_inputs.keys():
    print(key,":")
    for data in encoded_inputs[key]:
        print(data)
input_ids :
[101, 9638, 119064, 25387, 10892, 59906, 9694, 46874, 9294, 25387, 58926, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[101, 9358, 101958, 9075, 15891, 113, 3789, 4867, 114, 117, 9651, 11018, 9565, 14523, 113, 4886, 7247, 114, 117, 9485, 100543, 9770, 32537, 113, 3803, 4794, 114, 9573, 24098, 117, 9954, 17138, 9768, 25387, 58926, 119, 102]
[101, 9581, 55530, 14523, 16617, 10892, 9638, 119064, 87143, 9750, 9484, 54918, 9524, 12692, 14153, 9099, 9960, 16617, 11925, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
token_type_ids :
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
attention_mask :
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0]

가장 길이가 긴 2번째 문장을 기준으로 1, 3번째 문장에 padding token이 추가된 것을 확인할 수 있습니다.

Truncation

model이 입력으로 받을 수 있는 sequence의 길이는 정해져있습니다. 너무 긴 길이는 다루지 못할 수 있습니다.

truncation=True parameter를 이용하여 maximum length보다 길 경우 초과한 만큼 길이를 잘라냅니다.

보통 max_length parameter도 같이 사용하기도 합니다. max_length를 이용하여 maximum length를 통제할 수 있습니다.

print(tokenizer(texts, padding=True, truncation=True))
{'input_ids': [[101, 9638, 119064, 25387, 10892, 59906, 9694, 46874, 9294, 25387, 58926, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 9358, 101958, 9075, 15891, 113, 3789, 4867, 114, 117, 9651, 11018, 9565, 14523, 113, 4886, 7247, 114, 117, 9485, 100543, 9770, 32537, 113, 3803, 4794, 114, 9573, 24098, 117, 9954, 17138, 9768, 25387, 58926, 119, 102], [101, 9581, 55530, 14523, 16617, 10892, 9638, 119064, 87143, 9750, 9484, 54918, 9524, 12692, 14153, 9099, 9960, 16617, 11925, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0]]}

주어진 text는 BERT가 다룰 수 있는 maximum length보다 length가 작기 때문에 truncation이 되지 않은 것을 확인할 수 있습니다.

encoded_inputs = tokenizer(texts, max_length=12)

for key in encoded_inputs.keys():
    print(key,":")
    for data in encoded_inputs[key]:
        print(data)
input_ids :
[101, 9638, 119064, 25387, 10892, 59906, 9694, 46874, 9294, 25387, 58926, 102]
[101, 9358, 101958, 9075, 15891, 113, 3789, 4867, 114, 117, 9651, 102]
[101, 9581, 55530, 14523, 16617, 10892, 9638, 119064, 87143, 9750, 9484, 102]
token_type_ids :
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
attention_mask :
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

max_length를 이용하면 maximum length를 조절할 수 있음을 확인할 수 있습니다.

Build tensors

return_tensors parameter를 이용하여 원하는 형태의 tensor로 반환할 수 있습니다.

  • return_tensors='pt': PyTorch
  • return_tensors='tf': TensorFlow
encoded_inputs = tokenizer(texts, padding=True, truncation=True, max_length=15, return_tensors='pt')

print(encoded_inputs)
{'input_ids': tensor([[   101,   9638, 119064,  25387,  10892,  59906,   9694,  46874,   9294,
          25387,  58926,    119,    102,      0,      0],
        [   101,   9358, 101958,   9075,  15891,    113,   3789,   4867,    114,
            117,   9651,  11018,   9565,  14523,    102],
        [   101,   9581,  55530,  14523,  16617,  10892,   9638, 119064,  87143,
           9750,   9484,  54918,   9524,  12692,    102]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
profile
Deep Dive into Development (GitHub Blog: https://nkw011.github.io/)

0개의 댓글