토크나이제이션 파이프라인

토크나이제이션 파이프라인 (The Tokenization Pipeline)

Tokenizer.encodeTokenizer.encode_batch를 호출하면 입력 텍스트(들)는 다음 파이프라인을 거쳐요:

  • normalization (정규화)
  • pre-tokenization (사전 토큰화)
  • model (모델)
  • post-processing (후처리)

각 단계에서 무슨 일이 일어나는지 자세히 살펴보고, 토큰 ID를 decode하고 싶을 때는 무엇이 일어나는지도 볼게요. 그리고 🤗 Tokenizers 라이브러리가 이 각 단계를 우리의 필요에 맞게 어떻게 커스터마이즈할 수 있게 해 주는지도요. 이미 이 단계들에 익숙하고 코드로 배우고 싶다면 BERT from scratch 예시로 건너뛰어도 돼요.

Tokenizer가 필요한 예시에서는 quicktour에서 훈련한 토크나이저를 사용할 건데, 다음과 같이 불러올 수 있어요.

from tokenizers import Tokenizer
tokenizer = Tokenizer.from_file("data/tokenizer-wiki.json")

정규화 (Normalization)

정규화는 한마디로 원시 문자열에 적용해 덜 무작위적이거나 "더 깨끗하게" 만드는 일련의 연산이에요. 일반적인 연산에는 공백 제거, 악센트 문자 제거, 모든 텍스트 소문자화 등이 있어요. Unicode 정규화에 익숙하다면, 그것도 대부분의 토크나이저에서 적용되는 아주 흔한 정규화 연산입니다.

각 정규화 연산은 🤗 Tokenizers 라이브러리에서 Normalizer로 표현되고, normalizers.Sequence로 여러 개를 결합할 수 있어요. 다음은 NFD Unicode 정규화와 악센트 제거를 적용하는 정규화기 예시입니다.

from tokenizers import normalizers
from tokenizers.normalizers import NFD, StripAccents
normalizer = normalizers.Sequence([NFD(), StripAccents()])

이 정규화기를 어떤 문자열에 적용해서 수동으로 테스트할 수 있어요.

normalizer.normalize_str("Héllò hôw are ü?")
# "Hello how are u?"

Tokenizer를 만들 때 해당 속성을 바꾸기만 하면 정규화기를 커스터마이즈할 수 있어요.

tokenizer.normalizer = normalizer

물론 토크나이저가 정규화를 적용하는 방식을 바꾸면 normalize_str의 출력이 달라지므로, 토크나이저를 사용하기 전에 정규화기가 원하는 동작인지 확인하는 것이 좋아요.

사전 토크나이제이션 (Pre-tokenization)

사전 토크나이제이션은 텍스트를 단어(또는 그에 가까운 것)로 나누는 것이에요. 모델은 실제로 어떤 문자들이 토큰 후보가 될 수 있는지의 경계가 필요하기 때문에, 훈련 중 첫 단계로 텍스트를 "단어"로 분할해 두는 것이 도움이 돼요. 이렇게 분할된 단어들은 나중에 모델이 더 작은 토큰으로 나눌 수 있는 스캐폴드가 됩니다.

🤗 Tokenizers 라이브러리에서 사전 토크나이저는 pre_tokenizers 모듈에서 사용할 수 있어요. 예를 들어, Whitespace 사전 토크나이저는 공백으로 텍스트를 나눠요.

from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()

pre_tokenizer 속성에 할당하는 것만으로 토크나이저의 사전 토크나이저를 바꿀 수 있어요. PreTokenizer는 정규화와 마찬가지로 Sequence로 여러 개를 결합할 수 있습니다.

모델 (Model)

모델은 토크나이제이션 파이프라인의 핵심 알고리즘이에요. BPE, WordPiece, Unigram, WordLevel 등 여러 알고리즘이 있으며, 각각이 단어(또는 사전 토크나이제이션 결과)를 토큰으로 나누는 방식을 결정해요.

from tokenizers import Tokenizer
from tokenizers.models import BPE
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))

Tokenizer를 만들 때 모델을 지정하고, trainer와 훈련 파일들로 모델을 훈련시킬 수 있어요. 훈련이 끝나면 tokenizer.model을 새 모델로 교체하거나, 어휘 파일에서 불러온 모델로 가져올 수도 있습니다.

후처리 (Post-processing)

후처리는 모델이 토큰을 만든 뒤에 입력에 특수 토큰이나 템플릿을 적용하는 단계예요. 대표적인 예가 TemplateProcessing을 사용해 [CLS], [SEP] 같은 특수 토큰을 문장(또는 문장 쌍) 앞뒤에 붙이는 것입니다.

from tokenizers.processors import TemplateProcessing
tokenizer.post_processor = TemplateProcessing(
    single="[CLS] $A [SEP]",
    pair="[CLS] $A [SEP] $B:1 [SEP]:1",
    special_tokens=[
        ("[CLS]", tokenizer.token_to_id("[CLS]")),
        ("[SEP]", tokenizer.token_to_id("[SEP]")),
    ],
)

문장 쌍 템플릿은 "[CLS] $A [SEP] $B [SEP]" 형태여야 해요. 여기서 $A는 첫 번째 문장, $B는 두 번째 문장을 나타내요. :1은 입력의 각 부분에 원하는 type IDs를 나타내며, 기본값은 모든 것에 0입니다 (그래서 $A:0이 없음). 여기서는 두 번째 문장의 토큰과 마지막 "[SEP]" 토큰에 1로 설정합니다.

디코딩 (Decoding)

decode는 토크나이제이션의 역방향 연산이에요. 토큰 ID 리스트를 받아 원래 텍스트로 되돌려 줍니다. Tokenizer.decode 메서드를 사용하며, 속성 decoder로 디코딩 방식을 조정할 수 있어요. 예를 들어 ByteLevel 디코더는 바이트 레벨 토크나이저의 출력을 원래 문자로 복원합니다.

훈련된 토크나이저 사용하기

파이프라인의 각 단계를 이해하고 커스터마이즈했다면, Tokenizer.encode(단일 텍스트)나 Tokenizer.encode_batch(여러 텍스트)로 토크나이저를 사용할 수 있어요. 배치 인코딩은 라이브러리의 속도를 극대화하는 방식입니다.

이 파이프라인에 있는 각 단계를 직접 조합하고 훈련하는 전체 과정을 코드로 보고 싶다면, quicktour에서 토크나이저를 훈련하는 예시를 확인해 보세요.

출처: 공식문서