增加對tokenizer.chat_template的支援

#22
by p208p2002 - opened

簡短

設置 tokenizer.chat_template 來使用tokenizer.apply_chat_template, model.generatepipeline(text-gen) 等transformer提供之功能,減少不一致性可能。

model_id_or_path = "THUDM/chatglm3-6b"
tokenizer = AutoTokenizer.from_pretrained(model_id_or_path,trust_remote_code=True)
tokenizer.chat_template = "{% for message in messages %}{% if loop.first %}[gMASK]sop<|{{ message['role'] }}|> \n {{ message['content'] }}{% else %}<|{{ message['role'] }}|> \n {{ message['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>{% endif %}"

此PR目的

新版本的 transformer tokenizer 已經支援 chat_template 屬性 (https://huggingface.co/blog/zh/chat-templates),其目的在更好的讓使用者遵守聊天模型需要的對話格式。

一些第三方部屬框架也開始採用這個設定(如OpenLLM),但是對於沒有設置tokenizer.chat_template的分詞器會自動fallback採用tokenizer.default_chat_template導致格式不正確:

目前沒有設置 chat_template

chatglm_tokenizer.chat_template
# None

預設的 chat_template (ChatML格式)

chatglm_tokenizer.default_chat_template
# {% for message in messages %}{{'<|im_start|>' + message['role'] + '
# ' + message['content'] + '<|im_end|>' + '
# '}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant
# ' }}{% endif %}

chat_template fot chatglm

這個PR提供 jinja template 讓新的 tokenzier.chat_template feature 能夠 work:

{% for message in messages %}{% if loop.first %}[gMASK]sop<|{{ message['role'] }}|> \n {{ message['content'] }}{% else %}<|{{ message['role'] }}|> \n {{ message['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>{% endif %}

使用 chat_template

現在可以直接使用 model.generate,具體效果如下:

from transformers import AutoTokenizer,AutoModelForCausalLM

model_id_or_path = "THUDM/chatglm3-6b"
tokenizer = AutoTokenizer.from_pretrained(model_id_or_path,trust_remote_code=True)
tokenizer.chat_template = "{% for message in messages %}{% if loop.first %}[gMASK]sop<|{{ message['role'] }}|> \n {{ message['content'] }}{% else %}<|{{ message['role'] }}|> \n {{ message['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>{% endif %}"
model = AutoModelForCausalLM.from_pretrained(model_id_or_path,device_map="auto",trust_remote_code=True)
inputs = tokenizer.apply_chat_template([
    {"role":"system","content":"你是一位樂於助人、尊重他人且誠實的助理。請始終以最有幫助的方式回答問題。如果你對某個問題不知道答案,請不要提供虛假信息。"},
    {"role":"user","content":"如何減緩地球暖化?"}
],add_generation_prompt=True,tokenize=True,return_tensors="pt")

out = model.generate(inputs,max_new_tokens=256)
print(tokenizer.decode(out[0]))
[gMASK]sop<|system|> 
 你是一位樂於助人、尊重他人且誠實的助理。請始終以最有幫助的方式回答問題。如果你對某個問題不知道答案,請不要提供虛假信息。<|user|> 
 如何減緩地球暖化?<|assistant|> 
 減緩地球暖化有許多方法,以下是一些主要的措施:

1. 減少二氧化碳排放:這包括減少工業和交通碳排放,以及提高能源效率。
2. 採用可再生能源:如太陽能、風能和水能等。
3. 保護森林:森林可以吸收二氧化碳,如果森林被砍伐或被燒毀,會增加二氧化碳的排放。
4. 減少溫室氣體排放:這包括減少農業和工業溫室氣體排放,以及提高能源效率。
5. 改變飲食習慣:減少肉類和乳製品 consumption,因為它們產生的大氣碳排}>

格式正確性驗證

已經透過difflabtokenizer.build_chat_input比較確輸出一致性

#from difflib import ndiff
# 如果樣板結果與官方版本不同,比較差異
if not jinja_template_result == official_result:
    str1 = jinja_template_result
    str2 = official_result
    diff = ndiff(str1.splitlines(), str2.splitlines())
    for line in diff:
        print(line)
p208p2002 changed pull request title from Update tokenizer_config.json to 增加對tokenizer.chat_template的支援
zRzRzRzRzRzRzR changed pull request status to merged

Sign up or log in to comment