GitHub - brody-0125/dart_sentencepiece_tokenizer: A lightweight, pure Dart implementation of SentencePiece tokenizer. Supports BPE (Gemma) and Unigram (Llama) algorithms.
Service

GitHub - brody-0125/dart_sentencepiece_tokenizer: A lightweight, pure Dart implementation of SentencePiece tokenizer. Supports BPE (Gemma) and Unigram (Llama) algorithms.

brody-0125
2026.02.08
·GitHub·by 권준호
#BPE#Dart#SentencePiece#Tokenizer#Unigram

핵심 포인트

  • 1`dart_sentencepiece_tokenizer`는 SentencePiece 알고리즘(BPE, Unigram)을 순수 Dart로 구현하여 경량화 및 메모리 효율성을 극대화한 토크나이저 라이브러리입니다.
  • 2이 라이브러리는 인코딩/디코딩, 배치 처리, 스트리밍 등 LLM 토크나이징에 필요한 포괄적인 API와 HuggingFace 호환성을 제공하며, 최적화된 BPE 병합으로 높은 성능을 자랑합니다.
  • 3웹, 서버, Flutter 등 다양한 Dart 환경에서 활용 가능하며, ONNX Runtime 통합 및 초당 50만 토큰 이상의 처리량을 통해 LLM 애플리케이션 개발을 효과적으로 지원합니다.

dart_sentencepiece_tokenizer는 SentencePiece 토크나이저의 경량의 순수 Dart 구현체입니다. 이는 Dart 기반의 애플리케이션(Flutter, 서버, CLI, 웹)에서 어떠한 외부 의존성 없이 작동하도록 설계되었습니다.

핵심 기능 및 방법론:

  1. 지원 알고리즘:
    • BPE (Byte Pair Encoding): Gemma 모델에서 사용되는 알고리즘을 지원합니다. 병합(merge) 연산을 O(1) 시간 복잡도로 수행하기 위해 연결 리스트(linked list)와 병합 캐싱(merge caching)을 활용하는 최적화된 방식을 구현하여 성능을 향상시켰습니다.
    • Unigram: Llama 모델에서 사용되는 알고리즘을 지원합니다.
  1. 메모리 효율성: Int32ListUint8List와 같은 Dart의 Typed Arrays를 적극적으로 사용하여 메모리 사용량을 50-70% 절감했습니다. 특히, 토큰 ID(ids)는 Int32List(토큰당 4바이트), 토큰 타입 ID(typeIds), 어텐션 마스크(attentionMask), 스페셜 토큰 마스크(specialTokensMask)는 Uint8List(토큰당 1바이트)로 저장됩니다.
  1. 포괄적인 API:
    • 인코딩 (Encoding):
      • 단일 텍스트 인코딩: encode(text)Encoding 객체를 반환하며, 여기에는 토큰 문자열(tokens), 토큰 ID(ids), 어텐션 마스크(attentionMask), 토큰 타입 ID(typeIds), 문자 오프셋(offsets), 단어 인덱스(wordIds), 시퀀스 인덱스(sequenceIds) 등이 포함됩니다.
      • 쌍 인코딩: encodePair(textA, textB)를 통해 질의응답(QA)이나 문장 유사도 태스크를 위한 텍스트 쌍을 인코딩할 수 있으며, 이때 typeIdssequenceIds가 생성됩니다.
      • 배치 인코딩: encodeBatch(texts)는 순차적으로, encodeBatchParallel(texts)는 Dart Isolate를 활용하여 병렬로 배치 인코딩을 수행하여 대규모 데이터 처리 효율성을 높였습니다.
      • 최대 입력 길이는 500,000자로 제한하여 메모리 부족(OOM) 오류를 방지합니다.
    • 디코딩 (Decoding): decode(ids, skipSpecialTokens)를 통해 토큰 ID를 원래 텍스트로 복원하며, 스페셜 토큰 제외 여부를 선택할 수 있습니다. decodeBatch(idsBatch)로 배치 디코딩도 지원합니다.
    • 패딩 (Padding): enablePadding() 메서드를 통해 길이, 방향(SpPaddingDirection.right) 등을 설정하여 자동 패딩을 활성화하거나, withPadding()withPaddingToMultipleOf()를 통해 수동으로 패딩을 적용할 수 있습니다.
    • 자르기 (Truncation): enableTruncation() 메서드로 최대 길이(maxLength), 방향(SpTruncationDirection.right)을 설정하여 자동 자르기를 활성화하거나, withTruncation()을 통해 수동으로 자를 수 있습니다. 텍스트 쌍 자르기에는 longestFirst, onlyFirst, onlySecond, doNotTruncate와 같은 다양한 전략(TruncationStrategy)을 제공합니다.
    • 오프셋 매핑 (Offset Mapping): charToToken(), tokenToChars(), wordToTokens(), tokenToWord(), tokenToSequence() 등 다양한 유틸리티 메서드를 통해 문자 위치, 토큰 인덱스, 단어 인덱스, 시퀀스 인덱스 간의 매핑 정보를 제공합니다.
    • 어휘 접근 (Vocabulary Access): 어휘 크기(vocabSize), 특수 토큰 ID(unkId, bosId, eosId, padId) 접근, 토큰과 ID 간 변환(convertTokensToIds, convertIdsToTokens), 어휘 포함 여부 확인(vocab.contains()), Hugging Face 호환 어휘 맵(getVocab()) 제공 등 폭넓은 어휘 관련 기능을 제공합니다.
  1. Hugging Face 호환성:
    • tokenize(text)tokenizeBatch(texts) 메서드는 Hugging Face의 토크나이저 API와 호환되는 List<String>List<String> 형태의 토큰 문자열을 반환합니다.
    • JSON 직렬화 및 역직렬화(toJson(), saveToJson(), TokenizerJsonLoader.fromJson())를 통해 Hugging Face tokenizer.json 형식과 호환됩니다.
    • 벤치마크 스크립트를 통해 Hugging Face sentencepiece 라이브러리와의 호환성을 검증합니다.
  1. 동적 토큰 추가: addTokens() 메서드로 새로운 토큰을 어휘에 추가하거나, addSpecialTokens()를 통해 [PAD], [MASK], [CLS], [SEP] 등과 같은 특수 토큰을 동적으로 추가할 수 있습니다.
  1. 스트리밍 API (v1.3.0+): Hugging Face의 TextStreamer와 호환되는 실시간 LLM(Large Language Model) 출력 디코딩 기능을 제공합니다. createTextStreamer()를 통해 스트리머를 생성하고, put(tokenId)으로 토큰을 전달하면 onFinalizedText 콜백을 통해 텍스트 청크를 받을 수 있습니다. decodeStream() 또는 decodeWithCallback()을 통해 스트림 기반 디코딩도 지원합니다. 프롬프트 토큰 건너뛰기(skipPrompt) 기능도 포함되어 있습니다.
  1. 설정 유연성: SentencePieceConfig를 통해 addBosTokenaddEosToken 추가 여부를 세밀하게 제어할 수 있어 Gemma (BOS, EOS 모두 추가) 및 Llama (BOS만 추가) 모델과 같은 다양한 시나리오에 맞춰 구성할 수 있습니다.

성능 특성:

  • 처리량 (Throughput): 초당 약 50만 개 이상의 토큰 처리.
  • 모델 로딩 시간: 32K 어휘 기준 약 50ms.
  • 메모리 (어휘): 약 3MB.
  • 검색 복잡도 (Lookup complexity): 토큰당 O(k)O(k) (여기서 kk는 토큰의 길이).
  • BPE 병합 (Merge): 병합 연산당 O(1)O(1).

이 구현체는 Dart 생태계 내에서 효율적이고 유연한 SentencePiece 토크나이징 기능을 제공하며, 특히 LLM 관련 애플리케이션 개발에 유용합니다.