Files
wehub-resource-sync 770d92cb1f
Lint / lint (push) Has been cancelled
Build Docs / Deploy Docs (push) Has been cancelled
Windows CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:23:58 +08:00

128 lines
4.0 KiB
Python

"""The tokenizer and related tools in MLC LLM.
This tokenizer essentially wraps and binds the HuggingFace tokenizer
library and sentencepiece.
Reference: https://github.com/mlc-ai/tokenizers-cpp
"""
import json
from dataclasses import asdict, dataclass
from typing import List, Literal # noqa: UP035
import tvm_ffi
from tvm.runtime import Object
from . import _ffi_api
@dataclass
class TokenizerInfo:
"""Useful information of the tokenizer during generation.
Attributes
----------
token_postproc_method : Literal["byte_fallback", "byte_level"]
The method to post-process the tokens to their original strings.
Possible values (each refers to a kind of tokenizer):
- "byte_fallback": The same as the byte-fallback BPE tokenizer, including LLaMA-2,
Mixtral-7b, etc. E.g. "▁of" -> " of", "<0x1B>" -> "\x1b".
This method:
1) Transform tokens like <0x1B> to hex char byte 1B. (so-called byte-fallback)
2) Replace \\u2581 "▁" with space.
- "byte_level": The same as the byte-level BPE tokenizer, including LLaMA-3, GPT-2,
Phi-2, etc. E.g. "Ġin" -> " in", "ě" -> "\x1b"
This method inverses the bytes-to-unicode transformation in the encoding process in
https://github.com/huggingface/transformers/blob/87be06ca77166e6a6215eee5a990ab9f07238a18/src/transformers/models/gpt2/tokenization_gpt2.py#L38-L59
prepend_space_in_encode : bool
Whether to prepend a space during encoding.
strip_space_in_decode : bool
Whether to strip the first space during decoding.
"""
token_postproc_method: Literal["byte_fallback", "byte_level"] = "byte_fallback"
prepend_space_in_encode: bool = False
strip_space_in_decode: bool = False
def asjson(self) -> str:
"""Return the config in string of JSON format."""
return json.dumps(asdict(self))
@staticmethod
def from_json(json_str: str) -> "TokenizerInfo":
"""Construct a config from JSON string."""
return TokenizerInfo(**json.loads(json_str))
@tvm_ffi.register_object("mlc.Tokenizer")
class Tokenizer(Object):
"""The tokenizer class in MLC LLM."""
def __init__(self, tokenizer_path: str) -> None:
"""Create the tokenizer from tokenizer directory path."""
self.__init_handle_by_constructor__(
_ffi_api.Tokenizer,
tokenizer_path,
)
def encode(self, text: str) -> List[int]: # noqa: UP006
"""Encode text into ids.
Parameters
----------
text : str
The text string to encode.
Returns
-------
token_ids : List[int]
The list of encoded token ids.
"""
return list(_ffi_api.TokenizerEncode(self, text))
def encode_batch(self, texts: List[str]) -> List[List[int]]: # noqa: UP006
"""Encode a batch of texts into ids.
Parameters
----------
texts : List[str]
The list of text strings to encode.
Returns
-------
token_ids : List[List[int]]
The list of list of encoded token ids.
"""
return list(_ffi_api.TokenizerEncodeBatch(self, texts))
def decode(self, token_ids: List[int]) -> str: # noqa: UP006
"""Decode token ids into text.
Parameters
----------
token_ids : List[int]
The token ids to decode to string.
Returns
-------
text : str
The decoded text string.
"""
return _ffi_api.TokenizerDecode(self, tvm_ffi.Shape(token_ids))
@staticmethod
def detect_tokenizer_info(tokenizer_path: str) -> TokenizerInfo:
"""Detect the tokenizer info from the given path of the tokenizer.
Parameters
----------
tokenizer_path : str
The tokenizer directory path.
Returns
-------
tokenizer_info : str
The detected tokenizer info in JSON string.
"""
return TokenizerInfo.from_json(_ffi_api.DetectTokenizerInfo(tokenizer_path))