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

以下个人没整理太全

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

使用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, pipelinemessages = [{'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.mzph.cn/pingmian/76563.shtml

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

相关文章

Linux网络编程——详解网络层IP协议、网段划分、路由

目录 一、前言 二、IP协议的认识 1、什么是IP协议&#xff1f; 2、IP协议报头 三、网段划分 1、初步认识IP与路由 2、IP地址 I、DHCP动态主机配置协议 3、IP地址的划分 I、CIDR设计 II、子网数目的计算 III、子网掩码的确定 四、特殊的IP地址 五、IP地址的数量限…

ansible+docker+docker-compose快速部署4节点高可用minio集群

目录 github项目地址 示例服务器列表 安装前 修改变量文件group_vars/all.yml 修改ansible主机清单 修改setup.sh安装脚本 用法演示 安装后验证 github项目地址 https://github.com/sulibao/ansible_minio_cluster.git 示例服务器列表 安装前 修改变量文件group_var…

MySql主从相关概念

想象一下&#xff0c;你的业务飞速增长&#xff0c;用户请求如潮水般涌来&#xff0c;突然数据库主库宕机&#xff0c;数据丢失&#xff0c;服务瘫痪——这简直是开发者的噩梦&#xff01;MySQL主从复制就像一张安全网&#xff0c;通过主库写、从库读的协作模式&#xff0c;不仅…

机械臂只有位置信息是否可以进行手眼标定?

平常我在做手眼标定时&#xff0c;一般都是通过OpenCV的cv::calibrateHandEye函数进行求解&#xff0c;需要输入多组不同的机械臂位姿。今天遇到了一款舵机机器人&#xff0c;只能获取位置&#xff0c;得不到姿态信息&#xff0c;想着那就把姿态都设为0&#xff0c;结果求不出来…

华为数字芯片机考2025合集2已校正

单选 1. 题目内容 关于亚稳态的描述错误的是&#xff08; &#xff09;。 1. 解题步骤 1.1 理解亚稳态&#xff08;Metastability&#xff09;的核心特性 亚稳态是指触发器无法在指定时间内稳定输出有效逻辑电平&#xff08;0或1&#xff09;的状态&#xff0c;其关键特点…

T-Box车载系统介绍及其应用

定义 T-Box汽车系统&#xff0c;全称为Telematics - BOX&#xff0c;也常简称为车载T - BOX&#xff0c;是汽车智能系统及车联网系统中的核心组成部分&#xff0c;是安装在车辆上的一种高科技远程信息处理器。 工作原理 T-Box的核心功能主要通过MPU和MCU实现。MPU负责应用程序功…

[redis进阶一]redis的持久化(1)RDB篇章

目录 一 认识持久化 (1)先看总结图 (2)什么是持久化? (3)redis是怎么进行持久化的呢 (4)简单分析一下RDB持久化和AOF持久化的不同 二 RDB持久化 (1)RDB的触发机制 (2)RDB的bgsave执行流程 (3)RDB文件的处理 (4)RDB的优缺点 (5)RDB效果演示板书 三 温习Linux文件…

uniapp日常总结--uniapp页面跳转方式

uniapp日常总结--uniapp页面跳转方式_uniapp 跳转-CSDN博客

《汽车电器与电子技术》实验报告

SRS系统结构原理与故障检测诊断 车辆上为什么要配安全气囊&#xff1f;——解析汽车被动安全的关键防线 一、安全气囊的核心作用&#xff1a;应对高速碰撞的“救命缓冲垫” 车辆在高速碰撞时&#xff08;如正面碰撞、侧面碰撞&#xff09;&#xff0c;人体会因惯性以极高速度…

ffmpeg编解码器相关函数

文章目录 &#x1f3af; 你需要理解的核心结构体&#xff1a;&#x1f4e6; 常用函数及使用顺序&#xff08;以解码为例&#xff09;1️⃣ avcodec_find_decoder() / avcodec_find_encoder()2️⃣ avcodec_alloc_context3()3️⃣ avcodec_parameters_to_context()4️⃣ avcodec…

尚硅谷2019版Java网络编程笔记

第14章 网络编程 网络编程概述 什么是网络编程&#xff1f; 网络编程是通过网络协议实现计算机之间的数据交换。Java提供了强大的网络编程支持&#xff0c;隐藏了底层细节&#xff0c;开发者可以轻松实现网络通信。 网络编程的核心问题 如何定位网络上的主机&#xff1a;通…

解决【远程主机可能不符合 glibc 和 libstdc++ Vs code 服务器的先决条件】

可能是因为vscode不支持远程操作系统的版本&#xff0c;要么升级操作系统要么回退vscode版本 vscode回退1.97版本下载地址&#xff1a; 1.97版本VSCODE

forms+windows添加激活水印

formswindows添加激活水印 多语言水印文本&#xff0c;根据系统语言自动切换。水印显示在每个屏幕的右下角&#xff0c;位置动态调整。半透明灰色文字&#xff0c;微软雅黑字体。窗口无边框、置顶、透明背景&#xff0c;不干扰用户操作。支持多显示器。高DPI适配。 效果图&am…

LeetCode --- 444 周赛

题目列表 3507. 移除最小数对使数组有序 I 3508. 设计路由器 3509. 最大化交错和为 K 的子序列乘积 3510. 移除最小数对使数组有序 II 一、移除最小数对使数组有序 I & II 由于数组是给定的&#xff0c;所以本题的操作步骤是固定的&#xff0c;我们只要能快速模拟操作的过…

限流、降级、熔断、隔离?

在微服务架构中&#xff0c;服务限流、降级、熔断和隔离是保障系统高可用性的核心手段&#xff0c;但它们解决的问题和应用场景不同。以下是它们的区别、解决方案和实际案例的详细说明&#xff1a; 一、服务限流&#xff08;Rate Limiting&#xff09; 定义&#xff1a;通过限…

Day22 -php开发01--留言板+知识点(超全局变量 文件包含 数据库操作 第三方插件)

环境要求&#xff1a;php7.0.9 小皮 navicat phpstorm24.1 知识点&#xff1a;会写&#xff08;留言板 留言板后台&#xff09; 超全局变量 三方插件的使用 文件包含 1、开启小皮并利用navicat新建一个数据库 注意&#xff1a;本地的服务mysql关闭后 才可打开小皮。属…

制造一只电子喵 (qwen2.5:0.5b 微调 LoRA 使用 llama-factory)

AI (神经网络模型) 可以认为是计算机的一种新的 “编程” 方式. 为了充分利用计算机, 只学习传统的编程 (编程语言/代码) 是不够的, 我们还要掌握 AI. 本文以 qwen2.5 和 llama-factory 举栗, 介绍语言模型 (LLM) 的微调 (LoRA SFT). 为了方便上手, 此处选择使用小模型 (qwen2…

LeetCode 解题思路 37(Hot 100)

解题思路&#xff1a; 初始化&#xff1a; 初始化最大举行 max 和栈 stack。左右补零&#xff1a; 考虑柱子递增的边界情况&#xff0c; 初始化填充柱状图 newHeights。遍历处理&#xff1a; 对于每一根遍历到的柱子 newHeights[i]&#xff0c;若柱子高度小于栈口索引&#xf…

HTML — 过渡与动画

HTML过渡与动画是提升网页交互体验的核心技术&#xff0c;主要通过CSS实现动态效果。 过渡 CSS过渡&#xff08;Transition&#xff09;介绍 适用于元素属性变化时的平滑渐变效果&#xff0c;如悬停变色、尺寸调整。通过定义transition-property&#xff08;过渡属性&#xf…

跨站请求是什么?

介绍 跨站请求&#xff08;Cross-Site Request&#xff09;通常是指浏览器在访问一个网站时&#xff0c;向另一个域名的网站发送请求的行为。这个概念在 Web 安全中非常重要&#xff0c;尤其是在涉及到“跨站请求伪造&#xff08;CSRF&#xff09;”和“跨域资源共享&#xff…