ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何在 Transformers 中为对话模型编写自定义 chat template?

如何在 Transformers 中为对话模型编写自定义 chat template? 如何在 Transformers 中为对话模型编写自定义 chat template【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers当你给一个对话模型写新的对话格式——比如模型官方没有附带 chat template、或者你想调整控制 token 的布局——就需要编写一个自定义 chat template。在 Transformers 中chat template 是存放在 tokenizer 的chat_template属性里的一段 Jinja 模板Jinja 的语法与 Python 很接近。写好模板并赋值给 tokenizer 后每次调用apply_chat_template都会使用它并且save_pretrained时会随 tokenizer 一起保存到磁盘。本文的完整路径是查看现有模板作为参考 → 编写 Jinja 模板 → 赋给 tokenizer → 用apply_chat_template验证渲染结果 → 保存到磁盘。一个关键前提模板必须与模型训练时使用的格式完全一致。同样是 Mistral-7B 基座微调出来的模型Mistral-7B-Instruct 使用[INST]/[/INST]标记用户消息而 Zephyr-7B 使用|user|/|assistant|标记角色控制 token 用错会导致模型表现大幅下降。所以模板中的 token、空白、布局都要逐字对齐模型训练格式不能凭感觉写。第一步查看现有模板作为起点最简单的起点是参考已有模板。对任何 chat 模型执行print(tokenizer.chat_template)就能打印出它正在使用的模板建议从不调用工具、不支持 RAG 的简单模型开始看工具类模型的模板可能非常复杂from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(mistralai/Mistral-7B-Instruct-v0.1) print(tokenizer.chat_template)文档给出的一个基础模板示例长这样它遍历消息列表逐条输出角色、内容和结束 token当add_generation_promptTrue时再追加 assistant 消息的开头标记{%- for message in messages %} {{- | message[role] |\n }} {{- message[content] eos_token }} {%- endfor %} {%- if add_generation_prompt %} {{- |assistant|\n }} {%- endif %}编写模板变量、函数与空白控制模板里固定的常量只有messages变量和add_generation_prompt布尔值但你还可以访问传给apply_chat_template的任意其他关键字参数——最常用的附加变量是toolsJSON schema 格式的工具列表文档建议工具一律用这个命名保持与标准 API 的兼容。另外可以直接按名字访问tokenizer.special_tokens_map里的特殊 token例如{{- bos_token }}、{{- eos_token }}。模板里还有两个可调用的函数写法是{{- function_name(argument) }}raise_exception(msg)抛出TemplateException适合调试或对错误用法发出警告strftime_now(format_str)按指定格式获取当前日期时间等价于 Python 的datetime.now().strftime(format_str)常用于 system 消息里。一个容易踩的坑是空白。Jinja 会原样输出文本块前后的空白而多出来的空白如果不在模型训练数据里会伤害模型性能。解决办法是在 Jinja 行语法里加-如{%- for ... %}和{{- ... }}这样既能用缩进排版又不会把缩进渲染进输出。对比下面两个版本{% for message in messages %} {{ message[role] message[content] }} {% endfor %}上面这段没有用-输出会带入多余空白。推荐写法{%- for message in messages %} {{- message[role] message[content] }} {%- endfor %}跨语言实现兼容性如果你的模板会被非 Python 的 Jinja 实现使用例如用 JavaScript 或 Rust 部署需要做三处替换把 Python 方法换成 Jinja 过滤器string.lower()→string|lowerdict.items()→dict|dictitemsstring.strip()→string|trim把 Python 特有的True、False、None换成true、false、none直接渲染 dict 或 list 时不同实现可能给出不同结果比如字符串引号从单引号变成双引号加上tojson过滤器保持一致。超长模板用独立文件维护工具调用、RAG 等新特性的模板可能超过 100 行。把模板写进独立文件更方便调试——文件里的行号与模板解析或执行错误的行号一一对应# 把当前模板导出到文件 open(template.jinja, w).write(tokenizer.chat_template)编辑完成后再读回 tokenizertokenizer.chat_template open(template.jinja).read()多模态模板的注意点对多模态模型chat_template属性设在processor上而不是 tokenizer 上而且消息的content经常是内容 dict 列表而不是单一字符串模板里需要检查每个内容项的类型并分别处理。一般原则是模板不要直接访问图片或视频数据那是 processor 在模板渲染之后处理的事遇到图片/视频内容时输出一个特殊 token如|image|、|video|由 processor 稍后展开成对应的 token 序列。具体输出哪些 token 取决于模型文档强烈建议先加载一个现成的多模态 processor 观察它的处理方式。示例处理图文混排内容{%- for message in messages %} {%- if loop.index0 0 %} {{- bos_token }} {%- endif %} {{- |start_header_id| message[role] |end_header_id|\n\n }} {%- if message[content] is string %} {{- message[content] }} {%- else %} {%- for content in message[content] %} {%- if content[type] image %} {{- |image| }} {%- elif content[type] text %} {{- content[text] }} {%- endif %} {%- endfor %} {%- endif %} {{- |eot_id| }} {%- endfor %} {%- if add_generation_prompt %} {{- |start_header_id|assistant|end_header_id|\n\n }} {%- endif %}注意并不是所有模型都这样处理——有的模型会把所有图片移到用户消息末尾。模板永远要与模型训练格式一致。第二步把模板赋给 tokenizer 并验证渲染结果模板就绪后赋给chat_template属性再用apply_chat_template测试。输入是role/content键构成的消息 dict 列表先设tokenizeFalse检查渲染出的字符串是否符合预期from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(HuggingFaceH4/zephyr-7b-beta) tokenizer.chat_template 你的模板字符串 messages [ {role: system, content: You are a friendly chatbot who always responds in the style of a pirate}, {role: user, content: How many helicopters can a human eat in one sitting?}, ] print(tokenizer.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue))文档中 Zephyr-7B 的对应示例输出如下文档示例你的模板会渲染出你自己定义的格式|system| You are a friendly chatbot who always responds in the style of a pirate/s |user| How many helicopters can a human eat in one sitting?/s |assistant|确认渲染结果后走完整生成链路验证。add_generation_promptTrue会在末尾追加 assistant 消息开头的 token——模型本质上是继续 token 序列如果不含这个提示它可能继续用户消息而不是回复。tokenizeTrue时可以直接返回张量这是通常更安全的选项import torch from transformers import AutoModelForCausalLM, AutoTokenizer tokenizer AutoTokenizer.from_pretrained(HuggingFaceH4/zephyr-7b-beta) model AutoModelForCausalLM.from_pretrained(HuggingFaceH4/zephyr-7b-beta, device_mapauto, dtypetorch.bfloat16) tokenized_chat tokenizer.apply_chat_template(messages, tokenizeTrue, add_generation_promptTrue, return_tensorspt).to(model.device) print(tokenizer.decode(tokenized_chat[input_ids][0])) outputs model.generate(**tokenized_chat, max_new_tokens128) print(tokenizer.decode(outputs[0]))文档示例中模型以海盗口吻回答了人一次能吃几架直升机文档示例实际生成内容因随机性和版本而异。验证时注意两点如果你先apply_chat_template(tokenizeFalse)得到字符串、之后再手动 tokenize要在 tokenize 时设add_special_tokensFalse否则bos/eos这类特殊 token 会被重复添加伤害性能。tokenizeTrue则不存在这个问题add_generation_prompt只对模板里显式支持它的模型有效——有的模型如 Llama在 assistant 回复前没有特殊 token此时该参数不产生效果。第三步保存到磁盘save_pretrained/push_to_hub默认把模板写成独立的chat_template.jinja文件仓库根目录字符串模板就是一个文件命名模板 dict 则default写入chat_template.jinja其余每个名字写一个additional_chat_templates/name.jinja文件。保存时tokenizer_config.json里的chat_template字段会被移除以避免重复。加载时.jinja文件优先于 config 中内嵌的模板存在多个命名模板时apply_chat_template在传入tools时选用tool_use条目否则选default。两种遗留格式tokenizer_config.json内嵌的chat_template字段、多模态 processor 的chat_template.json只保留用于向后兼容加载文档明确警告不要再往里写模板也没有支持的途径保存成遗留格式。如果仓库里旧格式与新的.jinja文件混用processor 仓库加载时会直接报错。旧仓库可以加载后再存一次完成迁移from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(your-org/your-model) tokenizer.push_to_hub(your-org/your-model)也可以不经过 hub直接编辑 tokenizer 目录下的chat_template.jinja文件——文档指出这通常比操纵模板字符串更容易。限制与后续模板没有万能格式token、空白、布局全部是模型特定的写完后必须逐字核对模型训练格式如果你要为支持工具调用的模型写模板需要同时渲染工具定义tools变量、工具调用assistant 消息的tool_calls键和工具响应tool角色消息模板示例见 Writing a chat template 的 Templates for tools 章节训练场景下用模板预处理数据集时设add_generation_promptFalse因为提示 assistant 回复的额外 token 在训练中没有帮助示例见 Chat templates 的 Model training 章节模板验证通过后用push_to_hub上传到 Hub即使你不是模型 owner为 chat template 缺失或错误的模型补一个模板也是有价值的贡献。【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表