DataCollator & Tokenizer

SeongGyun Hong·2024년 10월 2일

NLP

목록 보기
4/5

1. DataCollator와 Tokenizer... 차이가 뭘까?

NLP Task들을 하다보면 자연스레 Huggingface 라이브러리를 많이 사용하게되고, 그 중에서 특히 많이 다루게 되는 것이 DataCollator다.
그런데 대체 왜 우리는 Tokenizer만 사용하면 되지 DataCollator까지 사용해줄까?
아니,,, Padding 기능도 애당초 Tokenizer에 있지 않나?! 굳이 왜? DataCollator까지?

2. 우선 각각을 알아보자...

2.1 Tokenizer의 역할과 기능

  1. 텍스트 분할 (Tokenization)
    입력된 텍스트를 더 작은 단위인 토큰으로 나눈다.
    예시:
    "Hello, how are you?" → ["Hello", ",", "how", "are", "you", "?"]

  2. 숫자 변환 (Encoding)
    토큰을 모델이 이해할 수 있는 숫자(token_id)로 변환한다.
    예시:
    ["Hello", "world"] → [101, 7592, 2088, 102]

  3. 특수 토큰 추가
    [CLS], [SEP] 등 모델에 필요한 특수 토큰을 추가한다.

  4. 패딩 (Padding)
    입력 시퀀스의 길이를 동일하게 맞추기 위해 패딩 토큰을 추가해준다.

  5. Attention Mask 생성
    패딩된 부분을 모델이 무시하도록 하는 마스크를 생성

  6. 디코딩 (Decoding)
    token_id를 다시 텍스트로 변환한다.


예시

from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-cased")

# 토큰화
text = "Hello, how are you?"
tokens = tokenizer.tokenize(text)
print("Tokens:", tokens)

# 인코딩
input_ids = tokenizer.encode(text, add_special_tokens=True)
print("Input IDs:", input_ids)

# 디코딩
decoded_text = tokenizer.decode(input_ids)
print("Decoded text:", decoded_text)

# 여러 문장 처리
sentences = ["Hello, how are you?", "I'm fine, thank you!"]
encoded = tokenizer(sentences, padding=True, truncation=True, return_tensors="pt")
print("Encoded batch:", encoded)

2.2 DataCollator의 역할과 기능

  1. 동적 배치 생성 (그룹화에 초점)
    다양한 길이의 입력 시퀀스를 효율적으로 하나의 배치로 결합해준다.
    입력 데이터의 길이가 서로 다를 때, 배치 내에서 가장 긴 시퀀스의 길이에 맞춰 다른 시퀀스를 패딩한다.
    동적 패딩과 비슷한 기능이지만, 동적 배치 생성의 목적은 계산 처리의 효율성을 높이기 위해 여러 입력을 하나의 배치로 그룹화 하는데 있다고, 동적 패딩은 배치 내 다양한 길이의 시퀀스를 max_length하나로 통일하는 것이 아니라, 각 배치마다 다른 가장 긴 시퀀스의 길이에 맞춰 효율적인 패딩을 가능하게 하고, 이를 통해 메모리 사용과 계산 효율성을 개선해준다.
  1. 동적 패딩 (효율적인 처리에 초점)
    각 배치 내에서 가장 긴 시퀀스에 맞춰 다른 시퀀스들을 패딩한다.

  2. 레이블 처리
    레이블도 적절히 패딩하며, 손실 계산 시 무시할 부분을 특수 값(보통 -100)으로 마스킹한다.

    예시 : [1,2,3] -> [1,2,3, -100, -100]

  3. 모델 특정 입력 준비
    예를 들어, seq2seq 모델을 위한 디코더 입력을 자동으로 생성한다.

    예시 :
    디코더 입력 생성: 타겟 시퀀스를 한 칸씩 오른쪽으로 시프트하고, 시작 토큰을 추가합니다.

    입력: ["Hello", "World"]
    디코더 입력: [<start>, "Hello", "World"]
    레이블: ["Hello", "World", <end>]

  4. 텐서 변환
    입력 데이터를 PyTorch 텐서로 변환한다.


예시

from transformers import DataCollatorForSeq2Seq, T5Tokenizer, T5ForConditionalGeneration

# 모델과 토크나이저 초기화
model = T5ForConditionalGeneration.from_pretrained("t5-small")
tokenizer = T5Tokenizer.from_pretrained("t5-small")

# DataCollator 초기화
data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)

# 입력 데이터 (이미 토큰화되었다고 가정)
batch = [
    {
        "input_ids": [1, 2, 3, 4],
        "attention_mask": [1, 1, 1, 1],
        "labels": [5, 6, 7]
    },
    {
        "input_ids": [1, 2, 3],
        "attention_mask": [1, 1, 1],
        "labels": [5, 6, 7, 8]
    },
    {
        "input_ids": [1, 2, 3, 4, 5],
        "attention_mask": [1, 1, 1, 1, 1],
        "labels": [5, 6]
    }
]

# DataCollator 적용
collated_batch = data_collator(batch)

print("Collated batch:")
for key, value in collated_batch.items():
    print(f"{key}:")
    print(value)
    print()

>>> 출력
Collated batch:
input_ids: # 입력 시퀀스가 가장 긴 시퀀스 5에 맞춰 패딩됨.
tensor([[1, 2, 3, 4, 0],
        [1, 2, 3, 0, 0],
        [1, 2, 3, 4, 5]])

attention_mask: # 실제 토큰은 1, 패딩된 부분은 0 표시
tensor([[1, 1, 1, 1, 0],
        [1, 1, 1, 0, 0],
        [1, 1, 1, 1, 1]])

labels: # 가장 긴 레이블 시퀀스인 4에 맞춰 패딩됨. 패딩된 부분은 -100으로 설정되어 손실 계산시 무시됨.
tensor([[ 5,  6,  7, -100],
        [ 5,  6,  7,    8],
        [ 5,  6, -100, -100]])

decoder_input_ids: # 디코더 입력 자동생성 (시작 부분에 0(시작토큰) 추가
tensor([[0, 5, 6, 7],
        [0, 5, 6, 7],
        [0, 5, 6, 0]])

2.3 라벨에서 패딩된 부분을 -100으로 설정하는 의미

-100은 PyTorch와 같은 딥러닝 프레임 워크에서 손실함수 계산시 자동으로 무시되며, 그레디언트 계산에서도 제외된다.
즉, Cross Entropy loss와 같은 손실 함수에서 -100으로 표시된 위치의 예측은 손실 계산에 포함되지 않는다.


3. Tokenizer와 DataCollator의 관계

Tokenizer와 DataCollator는 상호 보완적인 역할을 한다.
Tokenizer는 텍스트를 모델이 이해할 수 있는 형태로 변환한다면,
DataCollator는 이러한 변환된 데이터를 효율적인 배치 형태로 만들어 모델 훈련을 최적화한다.

Tokenizer의 경우 데이터셋 준비 단계에서 활용되며, 원시 텍스트가 입력되어 token_id, attention mask 등의 출력으로 나오고
DataCollator의 경우 모델 훈련 루프 내에서 사용되며, 토큰화된 샘플들의 리스트가 입력되어 Tensor 형태의 배치로 출력된다.

Tokenizer에서 별도로 패딩을 하지 않더라도, DataCollator에서 패딩을 넣을 수 있다.

예시

data_collator = DataCollatorForSeq2Seq(
    tokenizer,
    model=model,
    padding=True,
    max_length=512
)
profile
헤매는 만큼 자기 땅이다.

0개의 댓글