GN⁺: Tokenizer에 주의를 기울여야 합니다
(cybernetist.com)- e-commerce 데이터를 다루는 AI 앱 개발을 돕는 과정에서 Retrieval-augmented generation(RAG)이 일부 쿼리에서는 잘 동작하지만 다른 쿼리에서는 그렇지 않았다는 문제를 발견함
- 이러한 문제 해결 시 입력 데이터(인덱싱된 원본 텍스트, 검색에 사용되는 사용자 쿼리)를 살펴보는 것이 중요함
- 특히 chunking과 토크나이제이션 측면에서 최적화가 필요해 보였음
[Tokenization]
- 토크나이제이션은 텍스트를 토크나이저에 의해 더 작은 조각인 토큰으로 분해하는 과정
- 이 토큰들은 토크나이저 어휘 내에서 토큰을 고유하게 식별하는 정수 값인 토큰 ID에 매핑됨
- 토크나이저 어휘는 토크나이저 학습에 사용되는 모든 가능한 토큰의 집합
- 텍스트의 토큰이 LLM의 토크나이저 어휘에 없는 경우 문제가 발생할 수 있음
- 대부분의 LLM은 30k~300k 크기의 큰 어휘를 가지고 있음
- 대부분의 널리 사용되는 LLM은 subword 토크나이저에 의존함(BPE, Wordpiece 등)
- 토크나이저 종류
- word: 공백 문자와 구두점 등을 기준으로 분할
- character: 개별 문자(때로는 구두점까지)로 분할
- subword: 토큰을 의미 없어 보이는 하위 단어로 분할
- 대부분의 LLM은 subword 토크나이저를 사용
- BPE(Byte-Pair Encoder): OpenAI의 tiktoken 라이브러리
- Wordpiece: Cohere, MiniLM-L6-v2 등
MiniLM-L6-v2와 tiktoken 비교
- MiniLM-L6-v2 모델의 토크나이저 어휘 크기는 30522로 tiktoken(200019) 보다 훨씬 작음
- "tokenizer tokenizes text into tokens" 문장을 토크나이징하면
- MiniLM-L6-v2: [CLS] token ##izer token ##izes text into token ##s [SEP]
- tiktoken: token, izer, token, izes, text, into, tokens
- OpenAI의 tiktoken 라이브러리는 BPE 토크나이저를 구현하며 ChatGPT LLM 모델에서 사용됨
- MiniLM-L6-v2 어휘에는 독일어 글자, 일본어 글자도 포함되어 있음
이모지, 오타, 도메인 특화 단어 토크나이징
- MiniLM-L6-v2는 이모지를 [UNK] 토큰으로 토크나이징함
- tiktoken은 일부 유니코드 문자 토큰으로 학습되었지만 RAG에는 여전히 문제가 될 수 있음
- "Gucci Savoy Leathertrimmed Printed Coatedcanvas Suitcase"와 같은 도메인 특화 제품명도 제대로 토크나이징되지 않음
- 오타가 있는 문장("I hve received wrong pckage")의 경우
- MiniLM-L6-v2: i, h, ##ve, received, wrong, pc, ##ka, ##ge
- tiktoken: I, h, ve, received, wrong, p, ck, age
[Embeddings]
- 토크나이저 자체로는 별로 쓸모가 없음. 주로 개별 토큰의 빈도를 기반으로 복잡한 수치 분석을 하기 위해 개발됨
- 텍스트의 맥락적 의미를 보존하기 위해서는 토큰 간의 관계를 캡처할 수 있는 방법이 필요함
- 임베딩은 토큰을 나타내는 벡터로, 텍스트의 단어 간 의미와 관계를 잘 포착함
- 임베딩은 변환기 학습의 부산물이며, 토큰화된 텍스트 더미에서 실제로 학습됨
- 텍스트 생성을 요청할 때 LLM에 입력으로 주어지는 것이 바로 임베딩임
- LLM은 인코더와 디코더라는 두 가지 주요 구성 요소로 이루어짐
- 인코더와 디코더 모두 임베딩을 입력으로 받음
- 인코더의 출력 또한 임베딩이며, 이는 디코더의 교차 어텐션 헤드로 전달되어 디코더 출력의 토큰 생성(예측)에 중요한 역할을 함
- RAG 파이프라인에서 텍스트는 먼저 토큰화되고, 임베딩된 다음, 변환기에 입력됨
- 토큰 ID는 토크나이저 어휘의 인덱스 역할을 하며, 임베딩 행렬에서 임베딩을 가져오는 데에도 사용됨
- 가져온 임베딩은 텐서로 조립되어 변환기 입력으로 주어짐
- 인코더 흐름: 텍스트 토큰화 -> 각 토큰의 임베딩 가져오기 -> 임베딩 텐서 조립 -> 변환기 입력에 넣기 -> 인코딩 -> 인코더 출력을 디코더 교차 어텐션에 전달 -> 디코더 출력 생성
임베딩 예시
- "You can break it 😞"와 "You can not break it 😊"는 감정이 반대임에도 MiniLM-L6-v2에서는 임베딩 거리가 매우 가까움
- OpenAI는 토큰 어휘가 이모지를 잘 처리하므로 더 나은 성능을 보임
- 오타의 경우에도 OpenAI가 더 잘 처리함
- 하지만 OpenAI에서도 문장 끝에 공백을 추가하면 임베딩 간 거리가 예상 외로 벌어짐
- 날짜 형식을 다룰 때도 개발자들이 어려움을 겪음. 상대적 시간 표현("어제 배송되었습니다")은 특히 더 큰 문제가 될 수 있음
- 통화 표기 방식(£40, $50, 40£, 50¢ 등)의 차이도 이상한 문제를 일으킬 수 있음
- Gucci 가방 사례처럼 도메인 특화 데이터의 경우 일반적으로 파인튜닝으로 해결하지만, 항상 데이터와 평가 지표를 꼭 확인해야 함
결론
- 이 글은 토크나이저가 RAG 앱에 어떤 영향을 미칠 수 있는지, 그리고 왜 토크나이저에 주의를 기울여야 하는지에 대해 더 잘 이해할 수 있게 해줌
- 에이전트 애플리케이션에서는 garbage-in garbage-out이 항상 기대한 만큼의 성과를 내지는 않을 것임
- 입력 텍스트를 약간만 정리하는 것도 큰 도움이 될 수 있음
- 날짜 형식을 일관되게 표준화
- 가능한 한 후행 공백 제거(임베딩에 미치는 영향을 확인함)
- 서로 다른 통화의 가격 등 다른 숫자 데이터에도 동일하게 적용
- 언젠가는 토크나이저에 대해 전혀 생각하지 않아도 되기를 바람. 완전히 버릴 수 있기를
- 그렇게 되면 오타, 임의의 공백 문자, 단어 perplexity 기반 적대적 공격 등을 다룰 필요가 없어질 것임. 슬픔의 한 부류가 하루아침에 사라질 수 있음
- 그때까지는 책임감 있게 토큰화 하기를
GN⁺의 의견
- 이 글은 토크나이저와 임베딩이 RAG 기반 AI 앱의 성능에 어떤 영향을 미칠 수 있는지 잘 보여주고 있음. 특히 이모지, 오타, 도메인 특화 용어 등을 다룰 때 주의해야 할 점을 실제 사례와 함께 설명하고 있어 개발자들에게 많은 도움이 될 것으로 보임
- 다만 이 글에서 소개된 MiniLM-L6-v2와 OpenAI의 tiktoken은 모두 영어에 최적화된 모델이므로, 한국어와 같은 다른 언어를 다룰 때는 추가적인 고려사항이 있을 수 있음. 한국어의 경우 형태소 분석기를 활용한 토크나이징이 많이 사용되는데, 이에 따른 장단점과 한계에 대해서도 살펴볼 필요가 있어 보임
- 또한 이 글은 RAG 파이프라인에서의 토크나이저와 임베딩의 역할에 집중하고 있지만, 실제 프로덕션 환경에서는 데이터 전처리, 하이퍼파라미터 튜닝, 모델 경량화 등 고려해야 할 사항이 훨씬 더 많음. 따라서 이 글의 내용은 하나의 출발점으로 삼되, 실제 개발 과정에서는 다양한 실험과 평가를 통해 최적의 방법을 찾아가는 것이 중요할 것으로 보임
- 한편으로 GPT-4와 같은 거대 언어 모델의 등장으로 토크나이저의 중요성이 감소하고 있다는 의견도 있음. 이들 모델은 토큰 수준이 아닌 문장 또는 단락 수준에서 동작하므로, 개별 토큰의 품질이 성능에 미치는 영향이 상대적으로 작아질 수 있기 때문. 다만 아직 이에 대한 연구가 충분치 않아 단정 짓기는 어려워 보임
- 마지막으로 이 글에서 언급된 바와 같이, 입력 데이터를 미리 정제하고 표준화하는 것만으로도 모델 성능을 크게 개선할 수 있음. 실제 서비스를 개발할 때는 사용자 입력의 다양성과 노이즈를 고려하여, 강건한 데이터 전처리 파이프라인을 구축하는 것이 매우 중요할 것으로 보임. 아울러 데이터 라벨링과 주석 작업에도 충분한 리소스를 투입하여 고품질의 학습 데이터를 확보하는 것이 필요해 보임
Hacker News 의견
-
토크나이저는 LLM의 "섹시한" 부분으로 간주되지 않지만, 기회로 보는 사람도 있음. xVal 같은 논문은 토크나이제이션의 전문화 전략을 제시함. 철자와 문자 작업은 토크나이제이션 혁신으로 이익을 볼 수 있는 또 다른 문제임
- LLM은 단어의 문자 수를 세거나 문자 생략을 수행하는 데 약함. 예를 들어, GPT-4o는 문자의 인스턴스를 세기 위해 작은 파이썬 프로그램을 작성하고 실행함. 토크나이제이션은 프롬프트의 문자에 대한 지식을 효과적으로 지우고 이러한 작업의 성능에 직접적으로 부정적인 영향을 미침
-
데이터를 이해해야 의미 있는 작업을 수행할 수 있음. 많은 사람들이 자동화된 데이터 처리 도구를 사용하는 주된 이유는 데이터를 직접 보고 싶지 않기 때문임. 컴퓨터가 데이터를 보고 추가 정보 수집 요청을 할 수 있기를 바람
-
블로그 게시물에서 오타에 대한 부분을 특히 감사하게 생각함. 프로젝트에서 RAG와 유사한 애플리케이션을 돕고 있으며, 사용자 쿼리의 작은 오타나 형식 차이가 임베딩 거리 계산에 미치는 영향을 걱정하고 있음
- 훈련 데이터에 의도적인 오타/대체/대문자화를 추가하여 "wrk"와 "work"가 아마도 동의어임을 학습하도록 해야 하는지 고민 중임
-
Elasticsearch를 사용하여 1-2문장 입력과 문단 이상의 문서 간 유사성을 고급 텍스트 쿼리로 처리하는 앱에서 일한 경험이 있음. 토크나이제이션 전략이 특정 쿼리에 얼마나 영향을 미칠 수 있는지 흥미로웠음
- 예를 들어, "W-4" 또는 "W4" 같은 경우, 표준 토크나이제이션은 "-" 또는 문자/숫자 경계에서 나눌 수 있음. 이 입력은 인덱스에서 완전히 식별할 수 없게 됨
-
기사에서 각 문제에 대한 해결책이 논의된 부분이 부족하다고 느낌. 철자 검사를 토크나이징 전에 실행하거나 잘못된 철자 단어와 잠재적 수정 단어를 나란히 토크나이징하는 방법을 제안함
- 브랜드 이름 문제는 해결 방법을 알 수 없음. 이 문제는 덜 일반적인 언어 또는 복합어를 많이 사용하는 언어에서 더 심각할 수 있음
-
많은 개발자가 전통적인(결정론적) 공간에서 개발하는 데 익숙하지만, 통계적 공간에서 문제를 생각하는 방식을 변경하지 못함. LLM 앱은 궁극적으로 통계적 공간임
- 개발자로서 이 문제를 사용자에게 설명하는 데 어려움을 겪고 있음
-
RAG를 구현하는 대부분의 사람들이 토크나이제이션에 대해 생각하지 않고 임베딩에 대해 생각함
- 데이터 코퍼스를 청크로 나누고 각 청크에 대한 임베딩을 계산함. 쿼리를 생성하고 각 쿼리에 대한 임베딩을 계산함. 쿼리에 대한 거리로 코퍼스 청크를 순위 매김. 반환 값을 구성함
- 이 기사는 시스템 성능에 큰 영향을 미칠 수 있는 숨겨진, 상대적으로 평범한 작업의 중요성을 강조함
-
블로그 게시물의 일부 숫자를 재현할 수 없음. 예를 들어, SentenceTransformer를 사용한 코드에서 두 문장의 코사인 유사도를 계산한 결과가 예상과 다름
-
여러 RAG 구현에서 대상 문서가 들어오는 쿼리에 대한 좋은 검색 키가 될 것이라고 가정하는 문제를 봄. 최근 프로젝트에서 검색 키를 반환 값(청크된 문서)과 분리하고 LM을 사용하여 적절한 키를 생성하여 임베딩함으로써 검색 관련성이 크게 향상됨
-
많은 대형 LLM 어휘가 상당히 크다고 하지만, 영어만 해도 100만 개 이상의 단어가 있음. 30k-300k 토큰은 작아 보임