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

172 lines
5.5 KiB
Python

"""
Adapted from https://gist.github.com/xenova/a452a6474428de0182b17605a98631ee
Generator of mlc-chat-config.json and tokenizer configuration.
"""
# isort: off
import json
import os
from typing import Dict, List, Optional # noqa: UP035
def bpe(
mergeable_ranks: Dict[bytes, int], # noqa: UP006
token: bytes,
max_rank: Optional[int] = None,
) -> List[bytes]: # noqa: UP006
"""Adapted from https://github.com/openai/tiktoken/issues/60#issuecomment-1499977960"""
parts = [bytes([b]) for b in token]
while True:
min_idx = None
min_rank = None
for i, pair in enumerate(zip(parts[:-1], parts[1:])):
rank = mergeable_ranks.get(pair[0] + pair[1])
if rank is not None and (min_rank is None or rank < min_rank):
min_idx = i
min_rank = rank
if min_rank is None or (max_rank is not None and min_rank >= max_rank):
break
assert min_idx is not None
parts = [*parts[:min_idx], parts[min_idx] + parts[min_idx + 1], *parts[min_idx + 2 :]]
return parts
def generate_vocab_and_merges(encoder, mergeable_ranks):
"""Generate vocab and merges in huggingface tokenizers format"""
from transformers.models.gpt2.tokenization_gpt2 import (
bytes_to_unicode,
)
byte_encoder = bytes_to_unicode()
def token_bytes_to_string(b):
"""Convert a token from bytes to a string"""
return "".join([byte_encoder[ord(char)] for char in b.decode("latin-1")])
merges = []
vocab = {}
for token, rank in mergeable_ranks.items():
vocab[token_bytes_to_string(token)] = rank
if len(token) == 1:
continue
merged = tuple(bpe(mergeable_ranks, token, max_rank=rank))
assert len(merged) == 2
merges.append(" ".join(map(token_bytes_to_string, merged)))
# Also add special tokens
vocab.update(encoder._special_tokens)
return vocab, merges
def convert_tiktoken(model_path, output_dir, context_window_size=None):
"""Convert tiktoken tokenizers to huggingface tokenizers style"""
try:
from transformers import AutoTokenizer
except ImportError:
raise ImportError(
'Converting tiktoken tokenizer requires the "transformers" package.'
'Please install the "transformers" package to convert toktoken tokenizer'
)
tiktoken_tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
encoder = tiktoken_tokenizer.tokenizer
vocab, merges = generate_vocab_and_merges(encoder, tiktoken_tokenizer.get_vocab())
added_tokens = [
{
"id": id,
"content": content,
"single_word": False,
"lstrip": False,
"rstrip": False,
"normalized": False,
"special": True,
}
for content, id in encoder._special_tokens.items()
]
tokenizer_template = {
"version": "1.0",
"truncation": None,
"padding": None,
"added_tokens": added_tokens,
"normalizer": None,
"pre_tokenizer": {
"type": "ByteLevel",
"add_prefix_space": False,
"trim_offsets": True,
"use_regex": True,
},
"post_processor": {
"type": "ByteLevel",
"add_prefix_space": True,
"trim_offsets": False,
"use_regex": True,
},
"decoder": {
"type": "ByteLevel",
"add_prefix_space": True,
"trim_offsets": True,
"use_regex": True,
},
"model": {
"type": "BPE",
"dropout": None,
"unk_token": None,
"continuing_subword_prefix": "",
"end_of_word_suffix": "",
"fuse_unk": False,
"byte_fallback": False,
"vocab": vocab,
"merges": merges,
},
}
tokenizer_config_template = {
"add_prefix_space": False,
"bos_token": "<|endoftext|>",
"clean_up_tokenization_spaces": True,
"eos_token": "<|endoftext|>",
"unk_token": "<|endoftext|>",
}
tokenizer_name = type(tiktoken_tokenizer).__name__
tokenizer_config_template["tokenizer_class"] = tokenizer_name
if context_window_size:
tokenizer_config_template["model_max_length"] = context_window_size
tokenizer_config_template = dict(sorted(tokenizer_config_template.items(), key=lambda x: x[0]))
os.makedirs(output_dir, exist_ok=True)
# Save to files
with open(os.path.join(output_dir, "vocab.json"), "w", encoding="utf-8") as fp:
json.dump(vocab, fp, indent=2, ensure_ascii=False)
with open(os.path.join(output_dir, "tokenizer.json"), "w", encoding="utf-8") as fp:
json.dump(tokenizer_template, fp, indent=2, ensure_ascii=False)
with open(os.path.join(output_dir, "tokenizer_config.json"), "w", encoding="utf-8") as fp:
json.dump(tokenizer_config_template, fp, indent=2, ensure_ascii=False)
with open(os.path.join(output_dir, "special_tokens_map.json"), "w", encoding="utf-8") as fp:
json.dump(
{
"bos_token": "<|endoftext|>",
"eos_token": "<|endoftext|>",
"unk_token": "<|endoftext|>",
},
fp,
indent=2,
ensure_ascii=False,
)
with open(os.path.join(output_dir, "merges.txt"), "w", encoding="utf-8") as fp:
fp.write("#version: 0.2\n")
fp.write("\n".join(merges))