【大模型微调】如何解决llamaFactory微调效果与vllm部署效果不一致如何解决

news2025/4/15 19:53:02

以下个人没整理太全

一、生成式语言模型的对话模板介绍

使用Qwen/Qwen1.5-0.5B-Chat训练
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
对话模板不一样。回答的内容就会不一样。
我们可以看到例如qwen模型的tokenizer_config.json文件,就可以看到对话模板,一般同系列的模型,模板基本都一致。可以通过更改chat_template(对话模板)内容,来实现自己想要的对话模板。
在这里插入图片描述
如果我们使用open-webui来做前端显示,你会发现open-webui有自己的对话模板,他和我自己训练的qwen系列的大模型对话模板不一样,这就导致了,你用ollama跑qwen时回答的内容,和用open-webui做前端页面渲染回答的内容是不一致的。很奇葩,真的很奇葩。同时你会发现大模型微调框架、推理框架,以及像前端页面转发的open-webui他们的框架对话模板可能也是一样的。这就导致了,你明明在LLamaFactory微调框架的模板回答是自己想要的东西,但是在推理框架,比如vllm上就会不一样。头大吧。
在这里插入图片描述
对话的内容也会受一下参数控制,一般后两个参数都是统一的,唯一变化的就是最大生成长度。

在这里插入图片描述

这个问题可复现
比如我们在LLamaFactory,跑的是我自己训练过后的qwen模型。
在这里插入图片描述
使用vllm跑的自己训练过后的qwen模型
在这里插入图片描述

需要安装vllm(必须是Linux环境),不然前后台都会报错。
在这里插入图片描述

pip install vllm>=0.4.3,<=0.7.3 -i https://pypi.tuna.tsinghua.edu.cn/simple

在这里插入图片描述
你会发现效果一致了。如果效果不一致,说明你的模型需要继续训练。

2.Lora微调后单独部署大模型输出结果不一致

在这里插入图片描述
使用vllm serve启动自己训练的模型

vllm serve 你的模型

然后就可以通过后端代码调用对话了。
在这里插入图片描述
你会发现其实会有明显的差距,说明模型训练还未收敛,你需要继续训练,让大模型继续学习。
在这里插入图片描述

3.如何导出LLama Factory的对话模板
同时我们可以看一下LLamaFactory源码下的qwen对话模板
在这里插入图片描述
源码搜索就可以找到了
在这里插入图片描述
你会发现LLamaFactory整合了同一系列的对话模板。
LLamaFactory找到这个jinja模板
在这里插入图片描述
我们可以看到他是一个私有化的方法,外部没法调用,但是可以调用
在这里插入图片描述
fix_jinja_template生成jinja模板。那么就需要我们自己写代码了。可以用ai工具生成。

# mytest.py
import sys
import os

# 将项目根目录添加到 Python 路径
# root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# sys.path.append(root_dir)

from llamafactory.data.template import TEMPLATES
from transformers import AutoTokenizer

# 1. 初始化分词器(任意支持的分词器均可)
tokenizer = AutoTokenizer.from_pretrained(r"D:\Program Files\python\PycharmProjects\AiStudyProject\demo07\models\Qwen\Qwen2___5-1___5B-Instruct-merge")

# 2. 获取模板对象
template_name = "qwen"  # 替换为你需要查看的模板名称
template = TEMPLATES[template_name]

# 3. 修复分词器的 Jinja 模板
template.fix_jinja_template(tokenizer)

# 4. 直接输出模板的 Jinja 格式
print("=" * 40)
print(f"Template [{template_name}] 的 Jinja 格式:")
print("=" * 40)
print(tokenizer.chat_template)

就可以得到jinja得到qwen的path-to-chat-template.jinja模板,就可以给vllm用了。

{%- if tools %}
    {{- '<|im_start|>system\n' }}
    {%- if messages[0]['role'] == 'system' %}
        {{- messages[0]['content'] }}
    {%- else %}
        {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}
    {%- endif %}
    {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
    {%- for tool in tools %}
        {{- "\n" }}
        {{- tool | tojson }}
    {%- endfor %}
    {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
{%- else %}
    {%- if messages[0]['role'] == 'system' %}
        {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}
    {%- else %}
        {{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }}
    {%- endif %}
{%- endif %}
{%- for message in messages %}
    {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}
        {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
    {%- elif message.role == "assistant" %}
        {{- '<|im_start|>' + message.role }}
        {%- if message.content %}
            {{- '\n' + message.content }}
        {%- endif %}
        {%- for tool_call in message.tool_calls %}
            {%- if tool_call.function is defined %}
                {%- set tool_call = tool_call.function %}
            {%- endif %}
            {{- '\n<tool_call>\n{"name": "' }}
            {{- tool_call.name }}
            {{- '", "arguments": ' }}
            {{- tool_call.arguments | tojson }}
            {{- '}\n</tool_call>' }}
        {%- endfor %}
        {{- '<|im_end|>\n' }}
    {%- elif message.role == "tool" %}
        {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}
            {{- '<|im_start|>user' }}
        {%- endif %}
        {{- '\n<tool_response>\n' }}
        {{- message.content }}
        {{- '\n</tool_response>' }}
        {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
            {{- '<|im_end|>\n' }}
        {%- endif %}
    {%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|im_start|>assistant\n' }}
{%- endif %}

那么接下来启动

 vllm serve 模型名称 --chat-template ./path-to-chat-template.jinja

最方便的方法是可以直接替换LLamaFactory里的tokenizer_config.json里的chat_template模板里的内容
在这里插入图片描述

四、vllm推理模型时自定义对话模板

一、vLLM聊天模板

  1. 作用:为了使语言模型支持聊天协议,vLLM要求模型在其tokenizer配置中包含聊天模板。

  2. 聊天模板定义:聊天模板是一个Jinja2模板,用于指定角色、消息和其他特定于聊天的token如何在输入中编码。
    可以在 NousResearch/Meta-Llama-3-8B-Instruct 的示例聊天模板可以在这里找到。

  3. 使用场景

    • 有些模型即使经过指令/聊天微调,也不提供聊天模板。对于这些模型,可以在--chat-template参数中使用聊天模板的文件路径或字符串形式的模板手动指定其聊天模板。
    • 如果没有聊天模板,服务器将无法处理聊天,并且所有聊天请求都会出错。
  4. 使用方法

    vllm serve <model> --chat-template ./path-to-chat-template.jinja
    
  5. 模板来源:vLLM社区为流行的模型提供了一组聊天模板,可以在examples目录下找到它们。

二、LMDeploy自定义对话模板

  1. 添加对话模板形式

    • 利用现有对话模板:直接配置一个json文件使用。
    • 自定义Python对话模板类:注册成功后直接使用,优点是自定义程度高,可控性强。
  2. json文件配置示例

{
  "model_name": "your awesome chat template name",
  "system": "<|im_start|>system\n",
  "meta_instruction": "You are a robot developed by LMDeploy.",
  "eosys": "<|im_end|>\n",
  "user": "<|im_start|>user\n",
  "eoh": "<|im_end|>\n",
  "assistant": "<|im_start|>assistant\n",
  "eoa": "<|im_end|>",
  "separator": "\n",
  "capability": "chat",
  "stop_words": ["<|im_end|>"]
}
  • model_name为必填项,可以是LMDeploy内置对话模板名,也可以是新名字。
  • 其他字段可选填。当model_name是内置对话模板名时,json文件中各非null字段会覆盖原有对话模板的对应属性。
  • model_name是新名字时,它会把BaseChatTemplate直接注册成新的对话模板。
  1. 模板拼接形式
{system}{meta_instruction}{eosys}{user}{user_content}{eoh}{assistant}{assistant_content}{eoa}{separator}{user}...
  1. 使用方法

    • 使用CLI工具时,可以通过--chat-template传入自定义对话模板。
      lmdeploy serve api_server internlm/internlm2_5-7b-chat --chat-template ${JSON_FILE}
      
    • 通过接口函数传入。
      from lmdeploy import ChatTemplateConfig, serve
      serve('internlm/internlm2_5-7b-chat', chat_template_config=ChatTemplateConfig.from_json('${JSON_FILE}'))
      
  2. 自定义Python对话模板类示例

from lmdeploy.model import MODELS, BaseChatTemplate

@MODELS.register_module(name='customized_model')
class CustomizedModel(BaseChatTemplate):
    """A customized chat template."""
    def __init__(self,
                 system='<|im_start|>system\n',
                 meta_instruction='You are a robot developed by LMDeploy.', 
                 user='<|im_start|>user\n',
                 assistant='<|im_start|>assistant\n',
                 eosys='<|im_end|>\n',
                 eoh='<|im_end|>\n',
                 eoa='<|im_end|>',
                 separator='\n',
                 stop_words=['<|im_end|>', '<|action_end|>']):
        super().__init__(system=system,
                         meta_instruction=meta_instruction,
                         eosys=eosys,
                         user=user,
                         eoh=eoh,
                         assistant=assistant,
                         eoa=eoa,
                         separator=separator,
                         stop_words=stop_words)

from lmdeploy import ChatTemplateConfig, pipeline

messages = [{'role': 'user', 'content': 'who are you?'}]
pipe = pipeline('internlm/internlm2_5-7b-chat', chat_template_config=ChatTemplateConfig('customized_model'))
for response in pipe.stream_infer(messages):
    print(response.text, end='')

LLamaFactory找到这个jinja模板,然后使用代码导出模板,然后给vllm做模板。
在这里插入图片描述
我们可以看到他是一个私有化的方法,外部没法调用,但是可以调用
在这里插入图片描述
fix_jinja_template生成jinja模板。那么就需要我们自己写代码了。可以用ai工具生成。

# mytest.py
import sys
import os

# 将项目根目录添加到 Python 路径
# root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# sys.path.append(root_dir)

from llamafactory.data.template import TEMPLATES
from transformers import AutoTokenizer

# 1. 初始化分词器(任意支持的分词器均可)
tokenizer = AutoTokenizer.from_pretrained(r"D:\Program Files\python\PycharmProjects\AiStudyProject\demo07\models\Qwen\Qwen2___5-1___5B-Instruct-merge")

# 2. 获取模板对象
template_name = "qwen"  # 替换为你需要查看的模板名称
template = TEMPLATES[template_name]

# 3. 修复分词器的 Jinja 模板
template.fix_jinja_template(tokenizer)

# 4. 直接输出模板的 Jinja 格式
print("=" * 40)
print(f"Template [{template_name}] 的 Jinja 格式:")
print("=" * 40)
print(tokenizer.chat_template)

就可以得到jinja得到qwen的path-to-chat-template.jinja模板,就可以给vllm用了。

{%- if tools %}
    {{- '<|im_start|>system\n' }}
    {%- if messages[0]['role'] == 'system' %}
        {{- messages[0]['content'] }}
    {%- else %}
        {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}
    {%- endif %}
    {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
    {%- for tool in tools %}
        {{- "\n" }}
        {{- tool | tojson }}
    {%- endfor %}
    {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
{%- else %}
    {%- if messages[0]['role'] == 'system' %}
        {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}
    {%- else %}
        {{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }}
    {%- endif %}
{%- endif %}
{%- for message in messages %}
    {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}
        {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
    {%- elif message.role == "assistant" %}
        {{- '<|im_start|>' + message.role }}
        {%- if message.content %}
            {{- '\n' + message.content }}
        {%- endif %}
        {%- for tool_call in message.tool_calls %}
            {%- if tool_call.function is defined %}
                {%- set tool_call = tool_call.function %}
            {%- endif %}
            {{- '\n<tool_call>\n{"name": "' }}
            {{- tool_call.name }}
            {{- '", "arguments": ' }}
            {{- tool_call.arguments | tojson }}
            {{- '}\n</tool_call>' }}
        {%- endfor %}
        {{- '<|im_end|>\n' }}
    {%- elif message.role == "tool" %}
        {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}
            {{- '<|im_start|>user' }}
        {%- endif %}
        {{- '\n<tool_response>\n' }}
        {{- message.content }}
        {{- '\n</tool_response>' }}
        {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
            {{- '<|im_end|>\n' }}
        {%- endif %}
    {%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|im_start|>assistant\n' }}
{%- endif %}

那么接下来启动,把模板丢给vllm

 vllm serve 模型名称 --chat-template ./path-to-chat-template.jinja

注意:如果你使用修改后的模板启动,然后用open-webui做前端页面转发,修改后的模板不生效。这是因为open-webui每次都会覆盖原模型的模板,使用自己的模板,适合自己用。
启动open-webui
在这里插入图片描述

source activate openwebui
export HF_ENDPOINT=https://hf-mirror.com
export ENABLE_OLLAMA_API=False   #关闭调用ollama的api,使用vllm的
export OPENAI_API_BASE_URL=http://localhost:8000/v1 #vllm端口
open-webui sever

端口映射
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334501.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2025最新】windows本地部署LightRAG,完成neo4j知识图谱保存

之前在服务器部署neo4j失败&#xff0c;无奈只能在本地部署&#xff0c;导致后期所有使用的知识图谱数据都存在本地&#xff0c;这里为了节省时间&#xff0c;先在本地安装LigthRAG完成整个实验流程&#xff0c;后续在学习各种服务器部署和端口调用。从基础和简单的部分先做起来…

14、nRF52xx蓝牙学习(串口 UART 和 UARTE 外设应用)

一、UART 功能描述 串口 UART 也称为通用异步收发器。是各种处理器中常用了通信接口&#xff0c;在 nRF52 芯片中&#xff0c; UART 具有以下特点&#xff1a; ● 全双工操作 ● 自动流控 ● 奇偶校验产生第 9 位数据 串口 UART 的数据发送与接收流程 : ◆硬件配置…

DeepSeek轻松入门教程——从入门到精通

大家好&#xff0c;我是吾鳴。 今天吾鳴要给大家分享一份DeepSeek小白轻松入门指导手册——《DeepSeek 15天指导手册&#xff0c;从入门到精通》。指导手册分为基础入门对话篇、效率飞跃篇、场景实战篇、高手进化篇等&#xff0c;按照指导手册操作&#xff0c;DeepSeek从入门到…

Vue2 老项目升级 Vue3 深度解析教程

Vue2 老项目升级 Vue3 深度解析教程 摘要 Vue3 带来了诸多改进和新特性&#xff0c;如性能提升、组合式 API、更好的 TypeScript 支持等&#xff0c;将 Vue2 老项目升级到 Vue3 可以让项目获得这些优势。本文将深入解析升级过程&#xff0c;涵盖升级前的准备工作、具体升级步骤…

WXJ196微机小电流接地选线装置使用简单方便无需维护

WXJ196微机小电流接地选线装置&#xff0c;能在系统发生单相接地时&#xff0c;准确、迅速地选出接地线路母 线。使用简单方便&#xff0c;无需维护&#xff0c;可根据用户需要将相关信息通过通信接口传给上级监控系统&#xff0c; 适用于无人值守变电站。 2 功能及特点 全新的…

Java第四节:idea在debug模式夏改变变量的值

作者往期文章 Java第一节&#xff1a;debug如何调试程序&#xff08;附带源代码&#xff09;-CSDN博客 Java第二节&#xff1a;debug如何调试栈帧链&#xff08;附带源代码&#xff09;-CSDN博客 Java第三节&#xff1a;新手如何用idea创建java项目-CSDN博客 步骤一 在需要修改…

门极驱动器DRV8353M设计(二)

目录 13.3.4.4 MOSFET VDS 感测 (SPI Only) 13.3.5 Gate Driver保护回路 13.3.5.1 VM 电源和 VDRAIN 欠压锁定 (UVLO) 13.3.5.2 VCP 电荷泵和 VGLS 稳压器欠压锁定 (GDUV) 13.3.5.3 MOSFET VDS过流保护 (VDS_OCP) 13.3.5.3.1 VDS Latched Shutdown (OCP_MODE 00b) 13.…

学点概率论,打破认识误区

概率论是统计分析和机器学习的核心。掌握概率论对于理解和开发稳健的模型至关重要&#xff0c;因为数据科学家需要掌握概率论。本博客将带您了解概率论中的关键概念&#xff0c;从集合论的基础知识到高级贝叶斯推理&#xff0c;并提供详细的解释和实际示例。 目录 简介 基本集合…

NVIDIA AI Aerial

NVIDIA AI Aerial 适用于无线研发的 NVIDIA AI Aerial 基础模组Aerial CUDA 加速 RANAerial Omniverse 数字孪生Aerial AI 无线电框架 用例构建商业 5G 网络加速 5G生成式 AI 和 5G 数据中心 加速 6G 研究基于云的工具 优势100% 软件定义通过部署在数字孪生中进行测试6G 标准化…

OpenCV 关键点定位

一、Opencv关键点定位介绍 关键点定位在计算机视觉领域占据着核心地位&#xff0c;它能够精准识别图像里物体的关键特征点。OpenCV 作为功能强大的计算机视觉库&#xff0c;提供了多种实用的关键点定位方法。本文将详细阐述关键点定位的基本原理&#xff0c;深入探讨 OpenCV 中…

arm_math.h、arm_const_structs.h 和 arm_common_tables.h

在 ​​FOC&#xff08;Field-Oriented Control&#xff0c;磁场定向控制&#xff09;​​ 中&#xff0c;arm_math.h、arm_const_structs.h 和 arm_common_tables.h 是 CMSIS-DSP 库的核心组件&#xff0c;用于实现高效的数学运算、预定义结构和查表操作。以下是它们在 FOC 控…

buuctf sql注入类练习

BUU SQL COURSE 1 1 实例无法访问 / Instance cant be reached at that time | BUUCTF但是这个地方很迷惑就是这个 一个 # 我们不抓包就不知道这个是sql注入类的判断是 get 类型的sql注入直接使用sqlmap我们放入到1.txt中 目的是 优先检测 ?id1>python3 sqlmap.py -r 1.t…

具身导航中的视觉语言注意力蒸馏!Vi-LAD:实现动态环境中的社会意识机器人导航

作者&#xff1a;Mohamed Elnoor 1 ^{1} 1, Kasun Weerakoon 1 ^{1} 1, Gershom Seneviratne 1 ^{1} 1, Jing Liang 2 ^{2} 2, Vignesh Rajagopal 3 ^{3} 3, and Dinesh Manocha 1 , 2 ^{1,2} 1,2单位&#xff1a; 1 ^{1} 1马里兰大学帕克分校电气与计算机工程系&#xff0c; 2…

全局前置守卫与购物车页面鉴权

在很多应用里&#xff0c;并非所有页面都能随意访问。例如购物车页面&#xff0c;用户需先登录才能查看。这时可以利用全局前置守卫来实现这一鉴权功能。 全局前置守卫的书写位置在 router/index.js 文件中&#xff0c;在创建 router 对象之后&#xff0c;暴露 router 对象之前…

layui 弹窗-调整窗口的缩放拖拽几次就看不到标题、被遮挡了怎么解决

拖拽几次&#xff0c;调整窗口的缩放&#xff0c;就出现了弹出的页面&#xff0c;右上角叉号调不出来了&#xff0c;窗口关不掉 废话不多说直入主题: 在使用layer.alert layer.confirm layer.msg 等等弹窗时&#xff0c;发现看不到弹窗&#xff0c;然后通过控制台检查代码发现…

网络空间安全(57)K8s安全加固

一、升级K8s版本和组件 原因&#xff1a;K8s新版本通常会引入一系列安全功能&#xff0c;提供关键的安全补丁&#xff0c;能够补救已知的安全风险&#xff0c;减少攻击面。 操作&#xff1a;将K8s部署更新到最新稳定版本&#xff0c;并使用到达stable状态的API。 二、启用RBAC&…

2025蓝桥杯C++A组省赛 题解

昨天打完蓝桥杯本来想写个 p y t h o n python python A A A 组的题解&#xff0c;结果被队友截胡了。今天上课把 C A CA CA 组的题看了&#xff0c;感觉挺简单的&#xff0c;所以来水一篇题解。 这场 B B B 是一个爆搜&#xff0c; C C C 利用取余的性质比较好写&#…

论文学习:《通过基于元学习的图变换探索冷启动场景下的药物-靶标相互作用预测》

原文标题&#xff1a;Exploring drug-target interaction prediction on cold-start scenarios via meta-learning-based graph transformer 原文链接&#xff1a;https://www.sciencedirect.com/science/article/pii/S1046202324002470 药物-靶点相互作用&#xff08;DTI&…

十八、TCP多线程、多进程并发服务器

1、TCP多线程并发服务器 服务端&#xff1a; #include<stdio.h> #include <arpa/inet.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <pthread.h>…

AIGC-文生图与图生图

在之前的文章中&#xff0c;我们知道了如何通过Web UI和Confy UI两种SD工具来进行图片生成&#xff0c;今天进一步地讲解其中的参数用处及如何调节。 文生图 参数详解 所谓文生图&#xff0c;就是通过文字描述我们想要图片包含的内容。初学的话&#xff0c;还是以Web UI为例…