Add `ChatGLMTokenizerFast` and `ChatGLMTokenizerConverter`

#12
by chielo - opened

Add ChatGLMTokenizerFast and ChatGLMTokenizerConverter

#7 is also merged.

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
chielo changed pull request status to open

这个可以合并吗?

Knowledge Engineering Group (KEG) & Data Mining at Tsinghua University org

暂时还没有进行尝试,接下来将会进行尝试

这块进展怎样了?能否提供tokenizer.json给candle用?

这块进展怎样了?能否提供tokenizer.json给candle用?

当前的这个 commit 是依靠 ChatGLMTokenizerFast 的 Python 代码来完成 chatglm 的 tokenizer 的特定逻辑,所以生成的 tokenizer.json 暂时并不能独立地用于 tokenization。

近期我会根据主分支里新的代码调整一下,确保通过 tokenizers 加载 tokenizer.json 文件也能有相同的 tokenization 的结果。

修改了一下 converter 和相关的逻辑,已经可以直接加载 tokenizer.json

@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.pytokenizer_config.jsontokenizer.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。

Cannot merge
This branch has merge conflicts in the following files:
  • tokenizer_config.json

Sign up or log in to comment