Add `ChatGLMTokenizerFast` and `ChatGLMTokenizerConverter`
Add ChatGLMTokenizerFast
and ChatGLMTokenizerConverter
Showcase
import transformers, tokenizers
transformers.__version__, tokenizers.__version__
# Out: ('4.37.2', '0.15.1')
from transformers import AutoTokenizer
fast_tokenizer = AutoTokenizer.from_pretrained(
"./", trust_remote_code=True, use_fast=True
)
slow_tokenizer = AutoTokenizer.from_pretrained(
"./", trust_remote_code=True, use_fast=False
)
# NOTE: ChatGLMTokenizerFast does not support saving slow tokenizer.
# Saving it at the same directory may break the original tokenizer.
# Please keep a backup beforehand.
fast_tokenizer.save_pretrained("/tmp/chatglm3-tokenizer")
fast_tokenizer_saved = AutoTokenizer.from_pretrained(
"/tmp/chatglm3-tokenizer", trust_remote_code=True, use_fast=True
)
content = "是哪个星球的呢?"
history = [
{
"role": "user",
"content": "这是什么语言?“aburaka dabura ”",
"metadata": {"username": "Chielo"},
},
{"role": "assistant", "content": "这是来自外星的语言。"},
]
new_prompt = fast_tokenizer.build_chat_prompt(content, history=history)
new_prompt
# Out: "<|user|><!dummy-prefix!>{'username': 'Chielo'}\n<!dummy-prefix!>这是什么语言?“aburaka dabura ”<|assistant|><!dummy-prefix!>\n<!dummy-prefix!>这是来自外星的语言。<|user|><!dummy-prefix!>\n<!dummy-prefix!>是哪个星球的呢?<|assistant|>"
old_inputs = slow_tokenizer.build_chat_input(content, history=history)
new_inputs = fast_tokenizer.build_chat_input(content, history=history)
new_inputs_saved = fast_tokenizer_saved.build_chat_input(content, history=history)
old_input_ids = old_inputs["input_ids"][0].tolist()
old_decoded_text = slow_tokenizer.decode(old_input_ids)
# The fast tokenizer behaves as the same as the original one
assert new_inputs["input_ids"][0].tolist() == old_input_ids
assert new_inputs_saved["input_ids"][0].tolist() == old_input_ids
assert fast_tokenizer.encode(new_prompt) == old_input_ids
assert fast_tokenizer_saved.encode(new_prompt) == old_input_ids
assert fast_tokenizer.decode(old_input_ids) == old_decoded_text
assert fast_tokenizer_saved.decode(old_input_ids) == old_decoded_text
# The saved `tokenizer.json` can also be used by Rust `tokenizers`
rust_tokenizer = tokenizers.Tokenizer.from_file("/tmp/chatglm3-tokenizer/tokenizer.json")
assert rust_tokenizer.encode(new_prompt).ids == old_input_ids
assert rust_tokenizer.decode(old_input_ids, skip_special_tokens=False) == old_decoded_text
这个可以合并吗?
暂时还没有进行尝试,接下来将会进行尝试
这块进展怎样了?能否提供tokenizer.json给candle用?
这块进展怎样了?能否提供tokenizer.json给candle用?
当前的这个 commit 是依靠 ChatGLMTokenizerFast
的 Python 代码来完成 chatglm 的 tokenizer 的特定逻辑,所以生成的 tokenizer.json
暂时并不能独立地用于 tokenization。
近期我会根据主分支里新的代码调整一下,确保通过 tokenizers
加载 tokenizer.json
文件也能有相同的 tokenization 的结果。
@GuoqingBao Hi,该 Pull request 的代码已经更新,接口有变动。
新的 fast tokenizer 导出的 tokenizer.json
可以提供给 Rust 的 tokenizers
库使用。
新的流程可以参考上面更新后的 Showcase。
@GuoqingBao Hi,该 Pull request 的代码已经更新,接口有变动。
新的 fast tokenizer 导出的
tokenizer.json
可以提供给 Rust 的tokenizers
库使用。新的流程可以参考上面更新后的 Showcase。
多谢,能否直接生成一个tokenizer. json文件放到这个repo的file目录里?这样Candle和其他库就可以跑ChatGLM了。目前candle跑通ChatGLM就差这个文件了。
@GuoqingBao Hi,该 Pull request 的代码已经更新,接口有变动。
新的 fast tokenizer 导出的
tokenizer.json
可以提供给 Rust 的tokenizers
库使用。新的流程可以参考上面更新后的 Showcase。
多谢,能否直接生成一个tokenizer. json文件放到这个repo的file目录里?这样Candle和其他库就可以跑ChatGLM了。目前candle跑通ChatGLM就差这个文件了。
这个不太行,因为 chatglm 的 slow tokenizer 有比较多的定制的逻辑,保存的 fast tokenizer 并不能和 slow tokenizer 共存。主要是受到保存后新增的 special_tokens_map.json
等文件的影响。
假定当前的 pr 中的 tokenizer 在路径 ./chatglm3-tokenizer/
中(至少包括 tokenization_chatglm.py
、tokenizer_config.json
和 tokenizer.model
完整的文件),可参考如下代码导出文件 ./chatglm3-fast-tokenizer/tokenizer.json
:
from transformers import AutoTokenizer
fast_tokenizer = AutoTokenizer.from_pretrained(
"./chatglm3-tokenizer/", trust_remote_code=True, use_fast=True
)
fast_tokenizer.save_pretrained("./chatglm3-fast-tokenizer/")
另外,请注意到 fast tokenizer 需要特定的 prompt 格式。该格式可以参考 fast tokenizer 中 build_chat_prompt
等部分的逻辑,比如 showcase 中的 new_prompt
就是通过该接口生成的 prompt。