brunch

6. 문자단위보다 더 세밀한 서브워드분할

1장 AI는 데이터를 어떻게 이해할까: 특징량화의 원리

by AI개발자
gaebalai.com (44).png

"알 수 없는 토큰(unknown token)"이 원리적으로 발생하지 않도록 하기 위해, 문자단위가 아니라 바이트(byte)단위로 BPE를 수행하는 방법이 존재합니다.

이전에도 설명했듯이, BPE의 원래 압축 및 복원 알고리즘은 바이트 단위였지만, 머신러닝(기계학습)에서 활용될 때는 보통 문자 단위로 바뀌어 쓰였습니다. 이번에는 다시 바이트 단위 접근으로 돌아가는 셈입니다. 이 방식을 도입한 논문 중 하나가 바로 다음입니다.


Language models are unsupervised multitask learners (2019/02/14)


원 논문에서도 다음과 같이 명시되어 있습니다.

“Despite its name, reference BPE implementations often operate on Unicode code points and not byte sequences.”
(이름은 BPE지만, 실제로는 바이트 시퀀스가 아니라 Unicode 코드 포인트 단위로 작동하는 구현이 많다.)

즉, 당시의 머신러닝용 BPE는 문자단위로 적용되는게 주류였습니다. 이 논문에서는 바이트 단위 BPE를 사용함으로써, 언어에 의존하지 않으면서 미지토큰이 발생하지 않는 토크나이저를 구축했습니다.


이미 BPE 자체의 원리를 이해했으므로, 여기서 알아야 할 것은 Unicode 문자열을 UTF-8로 인코딩한 바이트열을 다루는 방법입니다. UTF-8의 최소단위는 1바이트(8비트)이므로, 처음의 어휘(vocabulary)는 다음과 같이 시작합니다.

1바이트(0~255) = 256개 토큰 → 프로그램에서는 보통 16진수(hex)로 처리합니다.

그 다음, BPE병합(merge) 프로세스를 통해 지정한 수(논문에서는 50,000개)의 토큰을 추가합니다. 마지막에는 특수토큰 <endoftext>를 추가하여 마무리합니다.

이 토크나이저는 토큰화 과정에서 언제든지 바이트 단위까지 폴백(fallback)되므로, 원리적으로 "알 수 없는 토큰(unknown token)"이 발생하지 않습니다.


이 단순한 접근법이 효과적으로 작동하도록, 원 논문에서는 Unicode 카테고리 정보를 이용해 서로 다른 문자 카테고리를 섞어 병합하지 않도록 설계했습니다. 예를 들어 Unicode에는 Other Punctuation이라는 카테고리가 있는데, 그 안에는 !, ., ?와 같은 문장부호가 포함됩니다. 이런 문자들을 다른 카테고리(예: 알파벳, 숫자 등)와 같은 서브워드로 병합하지 않게 제한함으로써,

dog!, dog. , dog?와 같은 토큰이 각각 등록되는 것을 방지하고,

공통된 서브워드인 dog만을 어휘에 포함시키는 것이 가능합니다.

이 방식은 한정된 어휘크기 내에서 중복된 의미의 토큰이 생기는 걸 막는 효율적인 설계입니다. 단, 공백(space)에 대해서는 예외적으로 병합을 허용합니다. 이는 "압축효율을 높이기 위해서"라는 논문에서 설명합니다. 공백을 문자처럼 다룬다는 점에서 이전에 다룬 SentencePiece의 접근과 유사합니다. 예를 들어, SentencePiece처럼 am과 ␣am은 서로 다른 토큰으로 등록됩니다.


연습문제15: "공백을 예외적으로 병합하도록 허용하면 압축효율이 높아진다"는 말은 무슨 뜻인지 설명해 봅시다.

(힌트: 자연어 텍스트에서 공백이 등장하는 빈도와 연관이 있습니다)



원 논문에서도 다음과 같이 강조합니다.

“Our model operates on a byte level and does not require lossy pre-processing or tokenization.”
(우리 모델은 바이트 단위로 작동하며, 정보 손실이 일어나는 전처리나 토크나이징이 필요 없다.)

즉, SentencePiece와 마찬가지로 이 모델도 가역 토크나이저(reversible tokenizer)입니다. 그리고 언어에 관계없이 사용할 수 있는 진정한 의미의 언어 비의존형 토크나이저라고 할 수 있습니다.


생성형 AI 시대의 주류는 언어별 특수 처리를 최대한 배제하고, 가역적 토크나이저를 대규모 텍스트 데이터로 학습시켜 범용적으로 활용하는 방식입니다. 다만, 현실적으로 학습에 쓰이는 텍스트 데이터는 영어 비중이 매우 높기 때문에, 데이터가 적은 언어는 출현 빈도를 충분히 확보하지 못해 토큰이 과도하게 잘게 분할되는 경향이 있습니다. 이는 바이트 단위 접근법이 언어 의존성은 낮추지만, 데이터 불균형 문제에는 여전히 취약하는 점을 보여줍니다.


이런 바이트 단위 BPE 토크나이저의 대표적인 오픈소스 구현으로 tiktoken이 있습니다. 여기서는 세부구현을 깊게 다루진 않지만, tiktoken은 Rust언어로 작성되어 매우 빠르게 동작하며,관심있는 독자는 직접 코드를 살펴보면 좋습니다. 또한, 웹브라우저에서 바로 토큰화를 실험해 볼 수 있는 웹앱도 공개되어 있어, 직접 토큰화 결과를 확인하는데 유용합니다.


연습문제16: tiktoken이 바이트 단위 BPE를 수행하고 있다는 사실을 체감할 수 있도록, https://tiktokenizer.vercel.app/에서 직접 예시 문장을 토큰화 결과를 관찰하고 그 중 대표적인 예시를 제시해 봅시다.


원래 바이트단위였던 BPE가 문자단위 서브워드 분할 알고리즘으로 발전했다가, 다시금 바이트 단위 알고리즘으로 회귀한 것은 시대의 흐름과 기술적 요구가 어떻게 순환하는지를 보여주는 흥미로운 변화입니다.



©2024-2025 MDRULES.dev, Hand-crafted & made with Jaewoo Kim.


AI 에이전트 개발, 컨텍스트 엔지니어링 교육 컨설팅, 바이브코딩 강의 문의: https://bit.ly/4kjk5OB


keyword
이전 04화5. SentencePiece