에코프로.AI

[Hugging Face - 5] Tokenizers 본문

AI Tutorial

[Hugging Face - 5] Tokenizers

AI_HitchHiker 2025. 1. 1. 12:57

https://www.youtube.com/watch?v=VFp38yj8h3A


Tokenizers 는 NLP 파이프라인의 핵심 구성 요소 중 하나입니다. Tokenizers 는 텍스트를 모델에서 처리할 수 있는 데이터로 변환하는 한 가지 용도로 사용됩니다. 모델은 숫자만 처리할 수 있으므로 Tokenizers 는 텍스트 입력을 숫자 데이터로 변환해야 합니다. 이 섹션에서는 토큰화 파이프라인에서 정확히 어떤 일이 일어나는지 살펴보겠습니다.

https://www.youtube.com/watch?v=nhJxYji1aho

 

NLP 작업에서 일반적으로 처리되는 데이터는 원시 텍스트입니다. 다음은 이러한 텍스트의 예입니다:

Jim Henson was a puppeteer

 

하지만 모델은 숫자만 처리할 수 있으므로 원시 텍스트를 숫자로 변환하는 방법을 찾아야 합니다. 이것이 바로 토큰화 도구가 하는 일이며, 이를 수행하는 방법에는 여러 가지가 있습니다. 목표는 가장 의미 있는 표현, 즉 모델에 가장 적합한 표현을 찾는 것이며, 가능하면 가장 작은 표현을 찾는 것입니다.

 

토큰화 알고리즘의 몇 가지 예를 살펴보고 토큰화에 대해 궁금해하실 수 있는 몇 가지 질문에 답해 보겠습니다.

 


Word-based

가장 먼저 떠오르는 토큰화 도구 유형은 단어 기반입니다. 일반적으로 몇 가지 규칙만으로 설정하고 사용하기가 매우 쉬우며, 종종 괜찮은 결과를 산출합니다. 예를 들어, 아래 이미지의 목표는 원시 텍스트를 단어로 분할하고 각 단어에 대한 숫자 표현을 찾는 것입니다:

 

https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/word_based_tokenization.svg

 

텍스트를 분할하는 방법에는 여러 가지가 있습니다. 예를 들어 공백을 사용하여 파이썬의 split() 함수를 적용하여 텍스트를 단어로 토큰화할 수 있습니다:

 

tokenized_text = "Jim Henson was a puppeteer".split()
print(tokenized_text)
['Jim', 'Henson', 'was', 'a', 'puppeteer']

vscode실행화면

 

구두점에 대한 추가 규칙이 있는 단어 토큰화기의 변형도 있습니다. 이러한 종류의 토큰화기를 사용하면 어휘가 말뭉치에 있는 독립 토큰의 총 수로 정의되는 꽤 큰 '어휘집'을 만들 수 있습니다.

 

각 단어에는 0부터 시작하여 어휘의 크기에 따라 올라가는 ID가 할당됩니다. 모델은 이러한 ID를 사용하여 각 단어를 식별합니다.

 

단어 기반 토큰 생성기로 한 언어를 완전히 커버하려면 해당 언어의 각 단어에 대한 식별자가 필요하며, 이는 엄청난 양의 토큰을 생성하게 됩니다. 예를 들어, 영어에는 500,000개가 넘는 단어가 있으므로 각 단어에서 입력 ID로 맵을 구축하려면 그만큼 많은 ID를 추적해야 합니다. 게다가 'dog'와 같은 단어는 'dogs'와 같은 단어와 다르게 표현되므로 모델에서는 처음에는 'dog'와 'dogs'가 비슷하다는 것을 알 방법이 없어 두 단어가 서로 관련이 없는 것으로 식별하게 됩니다. 'run'와 'running'와 같은 다른 유사한 단어도 마찬가지로 처음에는 모델이 유사하다고 인식하지 못합니다.

https://www.youtube.com/watch?v=nhJxYji1aho

 

마지막으로, 어휘집에 없는 단어를 표현하기 위한 사용자 지정 토큰이 필요합니다. 이를 "알 수 없는( unknown )" 토큰이라고 하며, 흔히 "[UNK]" 또는 "<unk>"로 표시됩니다. 토큰 생성기가 이러한 토큰을 많이 생성하는 것은 일반적으로 나쁜 신호이며, 이는 토큰 생성기가 단어의 적절한 표현을 검색할 수 없고 그 과정에서 정보를 잃고 있기 때문입니다. 어휘를 만들 때 목표는 토큰화 도구가 가능한 한 적은 단어를 미지의 토큰으로 토큰화하는 방식으로 어휘를 만드는 것입니다.

 

알 수 없는 토큰의 양을 줄이는 한 가지 방법은 문자 기반 토큰라이저를 사용하여 한 단계 더 깊이 들어가는 것입니다.


Character-based

문자 기반 토큰화기는 텍스트를 단어가 아닌 문자로 분할합니다. 여기에는 두 가지 주요 이점이 있습니다:

  • 어휘가 훨씬 작습니다.
  • 모든 단어를 문자로 만들 수 있기 때문에 어휘를 벗어난(알 수 없는) 토큰이 훨씬 적습니다.

하지만 여기에서도 공백과 구두점에 관한 몇 가지 질문이 생깁니다:

https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/character_based_tokenization.svg

 

이 접근 방식도 완벽하지는 않습니다. 단어가 아닌 문자를 기반으로 표현하기 때문에 직관적으로 각 문자가 그 자체로는 큰 의미가 없는 반면, 단어는 의미가 있다고 주장할 수 있습니다. 그러나 이는 언어에 따라 다르며, 예를 들어 중국어에서는 각 문자가 라틴어의 문자보다 더 많은 정보를 전달합니다.

 

고려해야 할 또 다른 사항은 모델에서 처리해야 할 토큰의 양이 매우 많다는 점입니다. 단어 기반 토큰라이저를 사용하면 단어가 하나의 토큰에 불과하지만, 문자로 변환하면 10개 이상의 토큰으로 쉽게 바뀔 수 있습니다.

https://www.youtube.com/watch?v=ssLq_EK2jLE

 

두 가지 장점을 모두 누리기 위해 두 가지 접근 방식을 결합한 세 번째 기술인 서브워드 토큰화를 사용할 수 있습니다.


Subword tokenization

Subword tokenization 알고리즘은 자주 사용되는 단어를 더 작은 하위 단어로 나누지 않고, 드물게 사용되는 단어를 의미 있는 하위 단어로 분해해야 한다는 원칙에 의존합니다.

※ 대부분의 Transformer 모델은 Subword tokenzation 을 사용합니다.

 

예를 들어, "annoyingly"는 희귀한 단어로 간주될 수 있으며 "annoying"과 "ly"로 분해될 수 있습니다. 이 둘은 독립적인 하위 단어로 더 자주 나타날 가능성이 있지만 동시에 "annoyingly"의 의미는 "annoying"과 "ly"의 복합적 의미로 유지됩니다.

https://www.youtube.com/watch?v=zHvTiHr506c

 

다음은 하위 단어 토큰화 알고리즘이 " Let’s do tokenization! "라는 시퀀스를 토큰화하는 방법을 보여주는 예입니다.

https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter2/bpe_subword.svg

 

이러한 하위 단어는 결국 많은 의미적 의미를 제공합니다. 예를 들어, 위의 예에서 "tokenization"은 "token"과 "ization"으로 나뉘었습니다. 이 두 토큰은 의미적 의미를 가지면서도 공간 효율적입니다(긴 단어를 나타내는 데 토큰이 두 개만 필요함). 이를 통해 적은 어휘로 비교적 좋은 적용 범위를 확보할 수 있으며, 알려지지 않은 토큰은 거의 없습니다.

https://www.youtube.com/watch?v=zHvTiHr506c

 

이러한 접근 방식은 터키어와 같은 교착어에서 특히 유용합니다. 교착어에서는 하위 단어를 연결하여 (거의) 임의로 긴 복잡한 단어를 형성할 수 있습니다.


그리고 더 많은 것들!

당연히 더 많은 기술이 있습니다. 몇 가지 예를 들어보겠습니다:

https://www.youtube.com/watch?v=zHvTiHr506c

  • Byte-level BPE, as used in GPT-2
  • WordPiece, as used in BERT
  • SentencePiece or Unigram, as used in several multilingual models

이제 토큰라이저의 작동 방식에 대한 충분한 지식을 갖추었으므로 API를 시작할 수 있습니다.

Loading and saving

토큰라이저를 로드하고 저장하는 것은 모델을 사용하는 것만큼이나 간단합니다. 사실, 이는 동일한 두 가지 메서드인 from_pretrained() 및 save_pretrained()를 기반으로 합니다. 이 메서드는 토큰화 도구에서 사용하는 알고리즘(모델의 아키텍처와 유사)과 어휘(모델의 가중치와 유사)를 로드하거나 저장합니다.

 

BERT와 동일한 체크포인트로 훈련된 BERT 토큰라이저를 로드하는 것은 모델을 로드하는 것과 동일한 방식으로 이루어지지만, BertTokenizer 클래스를 사용한다는 점이 다릅니다:

from transformers import BertTokenizer

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

 

AutoModel과 마찬가지로 AutoTokenizer 클래스는 체크포인트 이름에 따라 라이브러리에서 적절한 토큰화 클래스를 가져와 모든 체크포인트에 직접 사용할 수 있습니다:

from transformers import AutoTokenizer

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

 

이제 이전 섹션에 표시된 대로 토큰라이저를 사용할 수 있습니다:

tokenizer("Using a Transformer network is simple")
{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],
 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

vscode 실행화면

 

토큰라이저를 저장하는 것은 모델을 저장하는 것과 동일합니다:

tokenizer.save_pretrained("E:\hf")

vscode 실행화면

 

"added_tokens.json" 파일은 생성이 안되어있다. 추가확인 사항

 


Encoding

텍스트를 숫자로 변환하는 것을 인코딩이라고 합니다. 인코딩은 토큰화 후 입력 ID로 변환하는 2단계 프로세스로 이루어집니다.

 

지금까지 살펴본 것처럼 첫 번째 단계는 텍스트를 단어(또는 단어의 일부, 구두점 기호 등)로 분할하는 것이며, 이를 보통 토큰이라고 합니다. 이 프로세스를 제어할 수 있는 여러 규칙이 있으므로 모델 이름을 사용하여 토큰화기를 인스턴스화하여 모델을 사전 학습할 때 사용한 것과 동일한 규칙을 사용하도록 해야 합니다.

 

두 번째 단계는 토큰을 숫자로 변환하여 텐서를 구축하고 이를 모델에 공급하는 것입니다. 이를 위해 토큰화 도구에는 어휘가 있으며, 이 어휘는 from_pretrained() 메서드로 인스턴스화할 때 다운로드하는 부분입니다. 다시 말하지만, 모델을 사전 학습할 때 사용한 어휘와 동일한 어휘를 사용해야 합니다.

 

두 단계를 더 잘 이해하기 위해 별도로 살펴보겠습니다. 토큰화 파이프라인의 일부를 개별적으로 수행하는 몇 가지 방법을 사용하여 해당 단계의 중간 결과를 보여드리지만, 실제로는 입력에 대해 토큰화 도구를 직접 호출해야 합니다

 

Tokenization

https://www.youtube.com/watch?v=Yffk5aydLzg

 

토큰화 프로세스는 토큰화 도구의 tokenize() 메서드에 의해 수행됩니다.

위에 저장한 Tokenizer를 불러와서 사용합니다.

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("E:\hf")

sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)

print(tokens)

 

이 메서드의 출력은 문자열 또는 토큰 목록입니다:

['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']

vscode 실행화면

 

이 토큰화기는 하위 단어 토큰화기로, 해당 어휘로 표현할 수 있는 토큰을 얻을 때까지 단어를 분할합니다. Transformer의 경우 Transform과 ##er라는 두 개의 토큰으로 나뉩니다.

 

From tokens to input IDs (토큰을 입력 ID로 변환)

입력 ID로의 변환은 convert_tokens_to_ids() 토큰화 메서드가 처리합니다:

ids = tokenizer.convert_tokens_to_ids(tokens)

print(ids)
[7993, 170, 11303, 1200, 2443, 1110, 3014]

vscode 실행화면

이러한 출력은 적절한 프레임워크 텐서로 변환된 후 이 장의 앞부분에서 살펴본 것처럼 모델의 입력으로 사용할 수 있습니다.

 

Decoding

디코딩은 반대 방향으로 진행됩니다. 어휘 인덱스에서 문자열을 얻고자 합니다. 이 작업은 다음과 같이 decode() 메서드를 사용하여 수행할 수 있습니다:

decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)
'Using a Transformer network is simple'

vscode 실행화면

 

디코딩 방법은 인덱스를 토큰으로 다시 변환할 뿐만 아니라 같은 단어의 일부였던 토큰을 함께 그룹화하여 읽을 수 있는 문장을 생성합니다. 이 동작은 새로운 텍스트를 예측하는 모델을 사용할 때(프롬프트에서 생성된 텍스트나 번역 또는 요약과 같은 순서대로 이어지는 문제) 매우 유용합니다.

 

이제 토큰화, ID로의 변환, ID를 다시 문자열로 변환하는 등 토큰화 도구가 처리할 수 있는 원자적인 연산을 이해하셨을 것입니다. 하지만 이는 빙산의 일각에 불과합니다. 다음 섹션에서는 이러한 한계에 대한 접근 방식을 살펴보고 이를 극복하는 방법을 살펴보겠습니다.

 

[참고사이트] https://huggingface.co/learn/nlp-course/chapter2/4?fw=pt

 

 

끝~