LLaMA-Factory学习笔记(1)——采用LORA对大模型进行SFT并采用vLLM部署的全流程

该博客是我根据自己学习过程中的思考与总结来写作的,由于初次学习,可能会有错误或者不足的地方,望批评与指正。

1. 安装

1.1 LLaMA-Factory安装

安装可以参考官方 readme (https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md)

懒得跳转网页的也可以直接复制下面的内容:

git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .

1.2 下载LLM

huggingface或者镜像源(https://hf-mirror.com/)下载想要微调的模型。

PS:可以不用下载到本地,不过因为我们服务器不允许挂梯子,而且担心网络不稳定,所以我都是下载到本地的。

2. 准备训练数据

这应该是用LLaMA-Factory微调整个大模型中为数不多的需要写代码的部分。数据集的说明请参考:https://github.com/hiyouga/LLaMA-Factory/blob/main/data/README_zh.md。

由于我们是采用SFT的方式来构建数据集,所以简单点可以直接看https://github.com/hiyouga/LLaMA-Factory/blob/main/data/alpaca_zh_demo.json 这个json文件的格式,将数据集构建为上述json格式即可,即:

[{"instruction": "人类指令(必填)","input": "人类输入(选填)","output": "模型回答(必填)","system": "系统提示词(选填)","history": [["第一轮指令(选填)", "第一轮回答(选填)"],["第二轮指令(选填)", "第二轮回答(选填)"]]}
]

数据为一个列表,列表中每个元素为一个字典。如果是单轮对话则无需 history

当数据集构建完成后,可以放在data/路径下,也可以放在其他位置。

3. 配置dataset_info.json文件

将数据集构建完成后,需要在data/目录下找到dataset_info.json文件,并在这个文件中配置数据集的信息(个人觉得这一步类似于django中的注册url)。

假设构建的数据集名字为input_data.json,那么在dataset_info.json需要加如下的字典:

'数据集名称': {"file_name": "input_data.json","columns": {"prompt": "instruction","query": "input","response": "output"}},

这里数据集名称可以自行定义,只需要在后续写yaml文件时把这个名称写进去就行。这里的file_name要与数据集的名称相同,如果文件放在了data/路径下,只需要数据集名称就行,而如果文件没有放在该路径下,则需要在这里指定路径。

4. 微调模型

微调模型可以选用启动网页服务来进行微调,执行以下命令启动网页服务:

llamafactory-cli webui

当然我更喜欢用配置文件的方式来微调模型。新建一个 yaml 文件,假设名为train_qwen_lora_sft.yaml,可以在该文件中定义具体的训练设置。当然很多朋友不知道有哪些参数需要设置,可以查看github中的demo进行配置(https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/train_lora/llama3_lora_sft.yaml),具体而言:

### model
model_name_or_path: Qwen2-1.5B-Instruct### method
stage: sft
do_train: true
finetuning_type: lora
lora_target: all### dataset
dataset: input_data
template: qwen
cutoff_len: 1024
max_samples: 1000
overwrite_cache: true
preprocessing_num_workers: 16### output
output_dir: saves/llama3-8b/lora/sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000### eval
val_size: 0.1
per_device_eval_batch_size: 1
eval_strategy: steps
eval_steps: 500

这里要注意的有几个参数:

  • model_name_or_path: 这个是需要微调的模型,如果下载到了本地,则指定本地路径;如果没有下载到本地,就在huggingface上找路径。
  • dataset:这个是数据集的名称,即在第三步中配置的数据集名称。这里支持多个数据集进行微调,如果要设置多个数据集,那么用逗号隔开,即数据集名称1,数据集名称2
  • template: 用的什么模型就用什么模板,比如用的通义千问就设置qwen。template的名字可以参考https://zhuanlan.zhihu.com/p/689333581。
  • output_dir:这里是输出的文件路径,需要注意的是,由于采用的是LORA进行微调,所以这里输出的文件是LORA的参数,在实际部署的时候最好将LORA参数和原模型参数进行合并。具体合并的方式下一步会讲。
  • num_samples:如果想用数据集中所有数据进行训练,这个值可以设置的很大,比如999999,否则这个值如果小于数据集大小的话只会选择部分数据进行训练。
  • learning_rate:不只是learning_rate,所有的数字都可能会面临一个问题,即如果采用科学计数法(如1e-6),会报错,详见:https://blog.csdn.net/qq_35357274/article/details/143615453,解决方式就是用1.0e-6或者0.000001
  • eval:如果不需要验证这一坨其实可以不需要的。

微调的时候有可能显卡被人占用了,需要指定在哪几张卡上进行微调,所以用如下的命令进行微调:

CUDA_VISIBLE_DEVICES=0 llamafactory-cli train yaml路径

微调完成后,在output_dir路径下会有个文件夹,即LORA的参数文件,接着需要合并文件。

5. 合并文件

合并文件的yaml文件(注意不是训练的yaml文件,需要新建一个,我最开始以为两个是一个文件)可以参考https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/merge_lora/qwen2vl_lora_sft.yaml,具体而言:

### Note: DO NOT use quantized model or quantization_bit when merging lora adapters### model
model_name_or_path: Qwen/Qwen2-VL-7B-Instruct
adapter_name_or_path: saves/qwen2_vl-7b/lora/sft
template: qwen2_vl
finetuning_type: lora### export
export_dir: models/qwen2_vl_lora_sft
export_size: 2
export_device: cpu
export_legacy_format: false
  • model_name_or_path:如上面一样是原始模型的路径。
  • adapter_name_or_path:LORA的参数位置,即第四步中output_dir的路径。
  • export_dir:合并后的文件路径。
  • export_size:单个文件的最大大小(GB)。

运行命令:

llamafactory-cli export yaml路径

6. 部署

我这里选用的vLLM作为部署框架,有两种部署方式。如果是自己做实验的话可以离线部署,如果是上线的话建议用在线部署。

6.1 离线部署

离线部署即自己写个类或者方法,调用微调后的模型,代码如下:

import os
import torch
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
from vllm import LLM, SamplingParamsclass Detect:def __init__(self, model_path, temperature=0.8, top_p=0.95):""":param model_path: str:param temperature: float取值范围: [0, +∞]- 当 temperature 设为 0 时,模型总是选择具有最高概率的单词,这会导致生成的结果非常确定性,缺乏随机变化。- 当 temperature 接近 1 时,模型的选择更加随机,这可以增加生成文本的多样性。- 高于 1 的值可能会导致生成的文本更加随机,有时可能失去连贯性- 注: 如果生成的内容太多就调低这个值:param top_p: float取值范围: (0, 1]- top_p 参数表示从候选词汇中选取累积概率总和达到或超过 p 的词汇集合,然后从中随机选取下一个词汇。这种方式可以减少 temperature 为高值时可能出现的无意义输出。- 当 top_p 设置为接近 1 的值时,几乎所有的候选词汇都会被考虑,这类似于 temperature 接近 1 的情况。- 当 top_p 设置为较低值时,只有最有可能出现的几个词汇会被选中,这样可以减少输出的不确定性。- 注: 如果生成的内容太多就调低这个值"""if not isinstance(temperature, (int, float)) or not isinstance(top_p, (int, float)):raise ValueError('变量 "temperature" 和 "top_p" 必须为整型或浮点数')if temperature < 0:raise ValueError('变量 "temperature" 的取值范围为[0, +∞]')if top_p <= 0 or top_p > 1:raise ValueError('变量 "top_p" 的取值范围为(0, 1]')self.template = 'hi'self.llm = LLM(model=model_path, dtype=torch.bfloat16)self.tokenizer = self.llm.get_tokenizer()self.sampling_params = SamplingParams(temperature=temperature, top_p=top_p)def detect(self, input_texts):prompts = []for input_text in input_texts:prompt = [{'role': 'system', 'content': self.template},{'role': 'user', 'content': input_text + '\n输出:'}]prompts.append(prompt)prompts = self.tokenizer.apply_chat_template(prompts, add_generation_prompt=True, tokenize=False)outputs = self.llm.generate(prompts, self.sampling_params)return [output.outputs[0].text for output in outputs]

这里model_path即微调后的模型路径。还需注意的是,如果服务器足够垃圾,有可能self.llm = LLM(model=model_path, dtype=torch.bfloat16)会报错,因为老的服务器有可能不支持bfloat16,改为float16就行。

离线的代码如果部署到线上,在多线程调用的情况下,很有可能会触发cuda显存不够的错误,所以部署项目的时候通常采用在线部署的方式。

6.2 在线部署

与离线部署不同,采用在线部署首先需要启动服务。

CUDA_VISIBLE_DEVICES=2 python3 -m vllm.entrypoints.openai.api_server --model model_path --served-model-name qwen --trust-remote-code --host 0.0.0.0 --port 8080 --dtype bfloat16

这里model_path是微调后的模型路径;host是主机,默认为localhost,如果项目是在容器内的话,这里需要自行设置IP地址;port是端口号,默认为8000。

当启动服务后,会有这么一个提示信息:
提示信息
这个IP地址即服务的地址,就可以采用访问http的形式来调用模型。

有的人会使用curl http的形式来调用接口,我选用的是采用python脚本实现,具体代码如下:

from openai import OpenAIdef detect(input_texts, template, port='http://localhost:8000/v1', temperature=0.8, top_p=0.95):""":param input_texts: list输入文本:param template: str提示模板:param port: str端口号:param temperature: float取值范围: [0, +∞]- 当 temperature 设为 0 时,模型总是选择具有最高概率的单词,这会导致生成的结果非常确定性,缺乏随机变化。- 当 temperature 接近 1 时,模型的选择更加随机,这可以增加生成文本的多样性。- 高于 1 的值可能会导致生成的文本更加随机,有时可能失去连贯性- 注: 如果生成的内容太多就调低这个值:param top_p: float取值范围: (0, 1]- top_p 参数表示从候选词汇中选取累积概率总和达到或超过 p 的词汇集合,然后从中随机选取下一个词汇。这种方式可以减少 temperature 为高值时可能出现的无意义输出。- 当 top_p 设置为接近 1 的值时,几乎所有的候选词汇都会被考虑,这类似于 temperature 接近 1 的情况。- 当 top_p 设置为较低值时,只有最有可能出现的几个词汇会被选中,这样可以减少输出的不确定性。- 注: 如果生成的内容太多就调低这个值:return:"""if not isinstance(temperature, (int, float)) or not isinstance(top_p, (int, float)):raise ValueError('变量 "temperature" 和 "top_p" 必须为整型或浮点数')if temperature < 0:raise ValueError('变量 "temperature" 的取值范围为[0, +∞]')if top_p <= 0 or top_p > 1:raise ValueError('变量 "top_p" 的取值范围为(0, 1]')openai_api_key = "EMPTY"openai_api_base = portclient = OpenAI(api_key=openai_api_key,base_url=openai_api_base,)outputs = []for input_text in input_texts:chat_response = client.chat.completions.create(model="qwen",messages=[{"role": "system", "content": template},{"role": "user", "content": input_text},],temperature=temperature,top_p=top_p,)outputs.append(chat_response.choices[0].message.content)return outputs

这个代码里面port即上面控制台信息中返回的IP地址,传入即可。

7. 参考

[1] https://github.com/hiyouga/LLaMA-Factory/tree/main
[2] llama-factory SFT系列教程 (二),大模型在自定义数据集 lora 训练与部署
[3] VLLM 把模型部署成 openai API server 形式
[4] https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct
[5] https://github.com/echonoshy/cgft-llm/blob/master/llama-factory/README.md

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

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

相关文章

Linux -- 进程初印象

目录 预备知识 切入点 PCB 看见进程 pid getpid 函数 预备知识 Linux -- 冯诺依曼体系结构&#xff08;硬件&#xff09;-CSDN博客https://blog.csdn.net/2301_76973016/article/details/143598784?spm1001.2014.3001.5501 Linux -- 操作系统&#xff08;软件&#xf…

342--358作业整理(错误 + 重点)

目录 1. 在需要运行的类中 定义 main 方法 2. this 。访问逻辑&#xff1a;先访问本类中&#xff0c;再访问父类中可以访问的成员&#xff08;不包括和本类中重名的成员&#xff09; 3. super 。访问逻辑&#xff1a;super&#xff08;父类对象&#xff09;直接访问父类及以…

Jekins篇(搭建/安装/配置)

目录 一、环境准备 1. Jenkins安装和持续集成环境配置 2. 服务器列表 3. 安装环境 Jekins 环境 4. JDK 环境 5. Maven环境 6. Git环境 方法一&#xff1a;yum安装 二、JenKins 安装 1. JenKins 访问 2. jenkins 初始化配置 三、Jenkins 配置 1. 镜像配置 四、Mave…

【Linux】冯诺依曼体系结构

目录 一、冯诺依曼体系结构二、冯诺依曼体系结构的基本组成三、关于冯诺依曼体系结构的一些问题结尾 一、冯诺依曼体系结构 冯诺依曼体系结构&#xff0c;也称为普林斯顿结构&#xff0c;是现代计算机设计的基础框架。这一体系结构由数学家冯诺依曼在20世纪40年代提出&#xf…

M1M2 MAC安装windows11 虚拟机的全过程

M1/M2 MAC安装windows11 虚拟机的全过程 这两天折腾了一下windows11 arm架构的虚拟机&#xff0c;将途中遇到的坑总结一下。 1、虚拟机软件&#xff1a;vmware fusion 13.6 或者 parallel 19 &#xff1f; 结论是&#xff1a;用parellel 19。 这两个软件都安装过&#xff0…

NAT、代理服务与内网穿透技术全解析

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 NAT 技术背景NAT IP 转换过程NAPTNAT 技术的缺陷 代理服务器正向代理工作原理功能特点应用场景 反向代理基本原理应用场景 NAT 和代理…

优选算法 - 1 ( 双指针 移动窗口 8000 字详解 )

一&#xff1a;双指针 1.1 移动零 题目链接&#xff1a;283.移动零 class Solution {public void moveZeroes(int[] nums) {for(int cur 0, dest -1 ; cur < nums.length ; cur){if(nums[cur] 0){}else{dest; // dest 先向后移动⼀位int tmp nums[cur];nums[cur] num…

qt配合映美精取图开发

最近开发一个项目&#xff0c;用映美精相机配合halcon做取图开发&#xff0c;由于网上资料小特意写个记录。到映美精官网下载驱动&#xff0c;映美精官网&#xff0c;下载映美精的工具开发包SDK 映美精的SDK下载SDK后找到classlib文件夹 里面就是SDK新建一个qt程序&#xff0c…

华为云计算HCIE-Cloud Computing V3.0试验考试北京考场经验分享

北京试验考场 北京考场位置 1.试验考场地址 北京市海淀区北清路156号中关村环保科技示范园区M地块Q21楼 考试场选择北京&#xff0c;就是上面这个地址&#xff0c;在预约考试的时候会显示地址&#xff0c;另外在临近考试的时候也会给你发邮件&#xff0c;邮件内会提示你考试…

LeetCode 509.斐波那契数

动态规划思想 五步骤&#xff1a; 1.确定dp[i]含义 2.递推公式 3.初始化 4.遍历顺序 5.打印dp数组 利用状态压缩&#xff0c;简化空间复杂度。在原代码中&#xff0c;dp 数组保存了所有状态&#xff0c;但实际上斐波那契数列的计算只需要前两个状态。因此&#xff0c;我们…

反向代理开发

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…

RabbitMQ — 异步调用

RabbitMQ 是一个开源的消息代理中间件&#xff0c;它使用高级消息队列协议&#xff08;AMQP, Advanced Message Queuing Protocol&#xff09;来实现不同系统之间的消息传递。它以 Erlang 语言编写&#xff0c;具有高可靠性、灵活性和易于扩展的特点&#xff0c;被广泛应用于异…

2025 年使用 Python 和 Go 解决 Cloudflare 问题

作为一名从事网络自动化和爬取工作的开发者&#xff0c;我亲眼目睹了日益复杂的安全性措施带来的挑战。其中一项挑战是 Cloudflare 的 Turnstile CAPTCHA 系统&#xff0c;目前该系统已在全球 2600 多万个网站上使用。这种先进的解决方案重新定义了我们对机器人检测的处理方式&…

大数据的实时处理:工具和最佳实践

在当今的数字世界中&#xff0c;数据以前所未有的速度从无数来源生成&#xff0c;包括社交媒体、物联网设备、电子商务平台等。随着组织认识到这些数据的潜在价值&#xff0c;他们越来越多地转向实时处理&#xff0c;以获得即时、可操作的见解。但是&#xff0c;实时处理大数据…

104、Python并发编程:基于事件Event实现多线程间的同步

引言 继续介绍关于多线程同步的实现方式&#xff0c;本文将介绍基于Event的线程同步方式。 本文的主要内容有&#xff1a; 1、什么是Event 2、Event的使用场景 3、Event的代码实例 4、Event与Condition的比较 什么是Event 在Python的多线程编程中&#xff0c;Event是一个…

第2章2.3立项【硬件产品立项的核心内容】

硬件产品立项的核心内容 2.3 硬件产品立项的核心内容2.3.1 第一步&#xff1a;市场趋势判断2.3.2 第二步&#xff1a;竞争对手分析1.竞争对手识别2.根据竞争对手分析制定策略 2.3.3 第三步&#xff1a;客户分析2.3.4 第四步&#xff1a;产品定义2.3.5 第五步&#xff1a;开发执…

ReactPress数据库表结构设计全面分析

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎Star。 ReactPress是一个基于React框架开发的开源发布平台和内容管理系统&#xff08;CMS&#xff09;。它不仅支持用户在支持React和MySQL数据库的服务器上搭建自己的博客和网站&#…

ANDROIDWORLD: A Dynamic BenchmarkingEnvironment for Autonomous Agents论文学习

这个任务是基于androidenv的。这个环境之前学过&#xff0c;是一个用来进行强化学习的线上环境。而这篇文章的工作就是要给一些任务加上中间的奖励信号。这种训练环境的优点就是动态&#xff0c;与静态的数据集&#xff08;比如说我自己的工作&#xff09;不同&#xff0c;因此…

华为ENSP--ISIS路由协议

项目背景 为了确保资源共享、办公自动化和节省人力成本&#xff0c;公司E申请两条专线将深圳总部和广州、北京两家分公司网络连接起来。公司原来运行OSFP路由协议&#xff0c;现打算迁移到IS-IS路由协议&#xff0c;张同学正在该公司实习&#xff0c;为了提高实际工作的准确性和…

python-26-Python ORM系列之pymysql实现对数据库的增删改查及新建表

python-26-Python ORM系列之pymysql实现对数据库的增删改查及新建表 一.简介 在Python基础系列ORM部分我们为大家介绍了如何搭建MySQL数据和MySQL一些访问配置&#xff0c;同时细节的同学应该已经了解到了ORM的2个库pymysql和sqlalchemy&#xff1b; PyMySQL — MySQL 数据库…