llamafactory使用8张昇腾910b算力卡lora微调训练qwen2-72b大模型

说明

我需要在昇腾服务器上对Qwen2-72B大模型进行lora微调,改变其自我认知。
我的环境下是8张910B1卡。显存约512GB。

准备:安装llamafactory

请参考官方方法安装llamafactory:https://github.com/hiyouga/LLaMA-Factory

特别强调下,deepspeed一定要按照文档中要求的版本安装,太新或者太旧,多卡训练都有问题。

准备数据集和训练配置

我准备的工作目录如下:

./
├── data
│   ├── dataset_info.json
│   └── self_cognition.json
├── deepspeed
│   └── ds_z3_config.json
├── models
├── start_train.sh
└── train_config.yaml

其中data目录下self_cognition.json是我准备的数据集,他是alpaca格式的,dataset_info.json是数据集的入口配置文件,一会训练要指定它。

dataset_info.json内容如下:

{
"train_data_name": {
    "file_name": "self_cognition.json"
  }
 }

我在这里只写了一个数据集,其实可以配置很多的。

deepspeed目录下的ds_z3_config.json是deepspeed的配置文件,使用多卡训练必须要有这个文件。
这个文件在LLaMA-Factory代码工程下examples/deepspeed下有参考文件,我直接复制了一个过来。
其内容如下:

{
  "train_batch_size": "auto",
  "train_micro_batch_size_per_gpu": "auto",
  "gradient_accumulation_steps": "auto",
  "gradient_clipping": "auto",
  "zero_allow_untested_optimizer": true,
  "fp16": {
    "enabled": "auto",
    "loss_scale": 0,
    "loss_scale_window": 1000,
    "initial_scale_power": 16,
    "hysteresis": 2,
    "min_loss_scale": 1
  },
  "bf16": {
    "enabled": "auto"
  },
  "zero_optimization": {
    "stage": 3,
    "overlap_comm": true,
    "contiguous_gradients": true,
    "sub_group_size": 1e9,
    "reduce_bucket_size": "auto",
    "stage3_prefetch_bucket_size": "auto",
    "stage3_param_persistence_threshold": "auto",
    "stage3_max_live_parameters": 1e9,
    "stage3_max_reuse_distance": 1e9,
    "stage3_gather_16bit_weights_on_model_save": true
  }
}

models目录是空的,用来存放训练生成的模型。

train_config.yaml是训练配置文件,起内容如下:

### model
model_name_or_path: /data/xxx/mindformer_share/Qwen2-72B-Instruct/

### method
stage: sft
do_train: true
finetuning_type: lora
lora_target: all

### ddp
ddp_timeout: 180000000
deepspeed: ./deepspeed/ds_z3_config.json

### dataset
dataset: train_data_name
template: qwen
cutoff_len: 1024
max_samples: 200
overwrite_cache: true
preprocessing_num_workers: 16

### output
output_dir: ./models/
logging_steps: 10
save_steps: 50
plot_loss: true
overwrite_output_dir: true
  #report_to: tensorboard
  #logging_dir: /data/xxx/mindformer_share/llamaFactory/tensorboard/

### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 2
learning_rate: 1.0e-4
num_train_epochs: 40.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
fp16: true

### eval
val_size: 0.1
per_device_eval_batch_size: 1
eval_strategy: steps
eval_steps: 500

其中model_name_or_path用爱指定基础模型的路径,output_dir用来指定训练生成模型的输出路径。num_train_epochs是训练的轮数,max_samples是最大样本的数量,可根据实际情况修改这个值。save_steps是多少步保存一次中间checkpoint。

重点要说下deepspeed配置,如果不指定deepspeed配置文件,则默认使用数据并行,一旦模型无法在单张卡上加载就会出错。而配置了deepspeed之后,则模型会被切分到各张卡上,大模型可以平均分布在多张卡上。

我的训练启动脚本是start_train.sh,其内容如下:

#!/bin/sh

source /usr/local/Ascend/ascend-toolkit/set_env.sh

set -x
#export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

llamafactory-cli train ./train_config.yaml

执行训练

在命令行执行start_train.sh脚本

sh start_train.sh

训练完成后./models目录下文件如下:

./models/
├── adapter_config.json
├── adapter_model.safetensors
├── added_tokens.json
├── all_results.json
├── checkpoint-100
├── checkpoint-150
├── checkpoint-200
├── checkpoint-50
├── eval_results.json
├── merges.txt
├── README.md
├── runs
├── special_tokens_map.json
├── tokenizer_config.json
├── tokenizer.json
├── trainer_log.jsonl
├── trainer_state.json
├── training_args.bin
├── training_loss.png
├── train_results.json
└── vocab.json

我的模型训练了40轮,每50步保存一次模型。通过查看trainer_log.jsonl,发现checkpoint-150之后loss就已经很稳定了,我决定就使用checkpoint-150这个中间结果做后面的操作。

{"current_steps": 10, "total_steps": 200, "loss": 4.1278, "lr": 4e-05, "epoch": 2.0, "percentage": 5.0, "elapsed_time": "0:03:03", "remaining_time": "0:58:11"}
{"current_steps": 20, "total_steps": 200, "loss": 2.4438, "lr": 9e-05, "epoch": 4.0, "percentage": 10.0, "elapsed_time": "0:05:48", "remaining_time": "0:52:20"}
{"current_steps": 30, "total_steps": 200, "loss": 1.0016, "lr": 9.951340343707852e-05, "epoch": 6.0, "percentage": 15.0, "elapsed_time": "0:08:35", "remaining_time": "0:48:39"}
{"current_steps": 40, "total_steps": 200, "loss": 0.4434, "lr": 9.755282581475769e-05, "epoch": 8.0, "percentage": 20.0, "elapsed_time": "0:11:18", "remaining_time": "0:45:13"}
{"current_steps": 50, "total_steps": 200, "loss": 0.0837, "lr": 9.414737964294636e-05, "epoch": 10.0, "percentage": 25.0, "elapsed_time": "0:13:59", "remaining_time": "0:41:58"}
{"current_steps": 60, "total_steps": 200, "loss": 0.0096, "lr": 8.940053768033609e-05, "epoch": 12.0, "percentage": 30.0, "elapsed_time": "0:17:36", "remaining_time": "0:41:06"}
{"current_steps": 70, "total_steps": 200, "loss": 0.0059, "lr": 8.345653031794292e-05, "epoch": 14.0, "percentage": 35.0, "elapsed_time": "0:20:22", "remaining_time": "0:37:50"}
{"current_steps": 80, "total_steps": 200, "loss": 0.0019, "lr": 7.649596321166024e-05, "epoch": 16.0, "percentage": 40.0, "elapsed_time": "0:23:07", "remaining_time": "0:34:41"}
{"current_steps": 90, "total_steps": 200, "loss": 0.0026, "lr": 6.873032967079561e-05, "epoch": 18.0, "percentage": 45.0, "elapsed_time": "0:25:51", "remaining_time": "0:31:36"}
{"current_steps": 100, "total_steps": 200, "loss": 0.0011, "lr": 6.0395584540887963e-05, "epoch": 20.0, "percentage": 50.0, "elapsed_time": "0:28:36", "remaining_time": "0:28:36"}
{"current_steps": 110, "total_steps": 200, "loss": 0.0007, "lr": 5.174497483512506e-05, "epoch": 22.0, "percentage": 55.0, "elapsed_time": "0:32:03", "remaining_time": "0:26:13"}
{"current_steps": 120, "total_steps": 200, "loss": 0.001, "lr": 4.3041344951996746e-05, "epoch": 24.0, "percentage": 60.0, "elapsed_time": "0:34:44", "remaining_time": "0:23:09"}
{"current_steps": 130, "total_steps": 200, "loss": 0.0009, "lr": 3.4549150281252636e-05, "epoch": 26.0, "percentage": 65.0, "elapsed_time": "0:37:25", "remaining_time": "0:20:08"}
{"current_steps": 140, "total_steps": 200, "loss": 0.0008, "lr": 2.6526421860705473e-05, "epoch": 28.0, "percentage": 70.0, "elapsed_time": "0:40:08", "remaining_time": "0:17:12"}
{"current_steps": 150, "total_steps": 200, "loss": 0.0009, "lr": 1.9216926233717085e-05, "epoch": 30.0, "percentage": 75.0, "elapsed_time": "0:42:48", "remaining_time": "0:14:16"}
{"current_steps": 160, "total_steps": 200, "loss": 0.0009, "lr": 1.2842758726130283e-05, "epoch": 32.0, "percentage": 80.0, "elapsed_time": "0:46:37", "remaining_time": "0:11:39"}
{"current_steps": 170, "total_steps": 200, "loss": 0.0007, "lr": 7.597595192178702e-06, "epoch": 34.0, "percentage": 85.0, "elapsed_time": "0:49:21", "remaining_time": "0:08:42"}
{"current_steps": 180, "total_steps": 200, "loss": 0.0007, "lr": 3.6408072716606346e-06, "epoch": 36.0, "percentage": 90.0, "elapsed_time": "0:52:05", "remaining_time": "0:05:47"}
{"current_steps": 190, "total_steps": 200, "loss": 0.0007, "lr": 1.0926199633097157e-06, "epoch": 38.0, "percentage": 95.0, "elapsed_time": "0:54:53", "remaining_time": "0:02:53"}
{"current_steps": 200, "total_steps": 200, "loss": 0.0007, "lr": 3.04586490452119e-08, "epoch": 40.0, "percentage": 100.0, "elapsed_time": "0:57:36", "remaining_time": "0:00:00"}
{"current_steps": 200, "total_steps": 200, "epoch": 40.0, "percentage": 100.0, "elapsed_time": "0:58:26", "remaining_time": "0:00:00"}

合并lora模型到基础模型

merge方法1:llamafactory-cli export

llamafactory的命令行工具自带了lora合并功能,参考源码工程目录examples/merge_lora/下的配置文件编写一个合并的配置文件即可。

首先编写一个合并用的配置文件qwen_merge_lora_config.yaml:

### Note: DO NOT use quantized model or quantization_bit when merging lora adapters

### model
model_name_or_path: /data/xxx/mindformer_share/Qwen2-72B-Instruct/
adapter_name_or_path: /data/xxx/mindformer_share/llamaFactory/models/checkpoint-150/
template: qwen
finetuning_type: lora

### export
export_dir: /data/xxx/mindformer_share/llamaFactory/export_merge_lora/
export_size: 2
export_device: cpu  # 也可以写npu
export_legacy_format: false

上面文件中,model_name_or_path是基础模型路径,adapter_name_or_path是lora训练输出路径,export_dir是合并后输出的模型路径。template时模型的架构,跟lora训练配置里一致即可。

然后在命令行窗口执行:

llamafactory-cli export qwen_merge_lora_config.yaml

执行完毕,在export_dir定义路径下就是合并后的完整模型。

merge方法2:

也可以使用python,通过调用peft来合并lora模型。

import torch
import torch_npu
from torch_npu.npu import amp
from torch_npu.contrib import transfer_to_npu
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation.utils import GenerationConfig
from peft import PeftModel


model_path="/data/xxx/mindformer_share/Qwen2-72B-Instruct/"
lora_path="/data/xxx/mindformer_share/llamaFactory/models/checkpoint-150/"
merge_path="./export_python_merge"


print(f"Loading the Base model from {model_path}")
tokenizer = AutoTokenizer.from_pretrained(model_path,
    revision="v2.0",
    use_fast=False,
    trust_remote_code=True)
base_model = AutoModelForCausalLM.from_pretrained(model_path,
    revision="v2.0",
    device_map="auto",
    torch_dtype=torch.float16,
    trust_remote_code=True)
    #trust_remote_code=True).eval().half().npu()

print(f"Loading the LoRA from {lora_path}")
lora_model = PeftModel.from_pretrained(
        base_model,
        lora_path,
        torch_dtype=torch.float16,
    )


print("Applying the LoRA")
model = lora_model.merge_and_unload()

print(f"Saving the target model to {merge_path}")
model.save_pretrained(merge_path)
print(f"Saving the tokenizer to {merge_path}")
tokenizer.save_pretrained(merge_path)

上述代码中model_path是基础模型路径,lora_path是lora模型目录,merge_path是合并模型输出路径。

2种合并方法的比较

其中方法1中,export_device设置为cpu时,内存至少占140G(大约时模型尺寸大小),cpu会占用到100个核,NPU资源几乎不占。

方法1中export_device设置为npu时整体效果和方法2差不多。

2种方法合并模型的时间都约15分钟。

测试合并后的模型

合并后的模型就和huggingface上下载的模型使用同样的方法测试。这是我测试qwen2-72b合并后的模型的代码。

from transformers import AutoModelForCausalLM, AutoTokenizer
device = "npu" # the device to load the model onto

#model_path="/data/yuanll/mindformer_share/Qwen2-72B-Instruct/"
#model_path="./export_merge_lora"
model_path="./export_python_merge"

model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype="auto",
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_path)

#{"role": "system", "content": "You are a helpful assistant."},
prompt = "告诉我你的身份和创造者"
messages = [
    {"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(device)

generated_ids = model.generate(
    model_inputs.input_ids,
    max_new_tokens=512
)
generated_ids = [
    output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]

response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(f"response:{response}")

参考资料

在昇腾开发环境合并baichuan2-13B模型的lora文件

Qwen/Qwen2-72B-Instruct

LLaMA-Factory 实战(一):采用 LoRA 方式对QWen2 做指令微调

LLaMA-Factory 8卡4090 deepspeed zero3 微调Qwen14B-chat

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openssl s_server源码剥离

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…

前端小案例——网页井字棋

前言:我们在学习完了HTML、CSS和JavaScript之后,就会想着使用这三个东西去做一些小案例,不过又没有什么好的案例让我们去练手,本篇文章就提供里一个案例——网页井字棋。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可…

Leetcode 983. 最低票价 动态规划

原题链接&#xff1a;Leetcode 983. 最低票价 class Solution { public:int mincostTickets(vector<int>& days, vector<int>& costs) {int n days.size();int last days[n - 1];int dp[last 1];map<int, int> mp;for (auto x : days)mp[x] 1;dp…

Java中的 锁现象演示和原理解释 多线程操作资源类 八种案例 同步方法 静态方法 对象锁 类锁

目录 面试题 案例 1 标准访问有 ab 两个线程 案例 2 其中一个同步方法暂停 3 秒 案例 3 新增普通方法 案例 4 创建两个对象 案例 5 两个静态同步方法 一个对象 案例 6 两个静态同步方法 两个对象 案例 7 一个静态同步方法 一个普通同步方法 一个对象 案例 8 一个静态同…

HTML应用指南:利用GET请求获取全国特斯拉充电桩位置

随着电动汽车的普及&#xff0c;充电基础设施的建设变得至关重要。作为电动汽车领域的先驱&#xff0c;特斯拉不仅在车辆技术创新上持续领先&#xff0c;还积极构建广泛的充电网络&#xff0c;以支持其不断增长的用户群体。为了提升用户体验和服务质量&#xff0c;开发人员和数…

cuda + cudnn安装

1.安装CUDA Toolkit 在设备管理器&#xff08;此电脑–右键–属性&#xff09;的显示适配器中可以查看自己的显卡型号&#xff0c;去下载对应的CUDA Toolkit 。或者输入以下命令查看Driver Version &#xff0c;cuda Version&#xff1a;12.2代表12.2版本以下兼容可以进行安装 …

【k8s面试题2025】1、练气期

主要通过呼吸吐纳等方法&#xff0c;将外界的天地灵气吸入体内&#xff0c;初步改造身体&#xff0c;使身体素质远超常人。 文章目录 docker 和虚拟机的不同Kubernetes 和 docker 的关系Kube-proxy IPVS 和 iptables 的异同蓝绿发布Kubernetes中常见的数据持久化方式关于 Docke…

vue | 插值表达式

Vue 是一个用于 构建用户界面 的 渐进式 框架 1. 构建用户界面&#xff1a;基于 数据 动态 渲染 页面 2. 渐进式&#xff1a;循序渐进的学习 3. 框架&#xff1a;一套完整的项目解决方案&#xff0c;提升开发效率↑ (理解记忆规则) 插值表达式&#xff1a; 插值表达式是一种 Vu…

【蜂巢——方向,数学】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; int dx[6] {-1, -1, 0, 1, 1, 0}; int dy[6] {0, 1, 1, 0, -1, -1}; void cal(int d, int p, int q, int& x, int& y) {x p * dx[d];y p * dy[d];d (d 2) % 6;x q * dx[d];…

C语言进阶习题【1】指针和数组(1)——一维数组

1. 数组名的意义&#xff1a; sizeof(数组名)&#xff0c;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小。&数组名&#xff0c;这里的数组名表示整个数组&#xff0c;取出的是整个数组的地址。除此之外所有的数组名都表示首元素的地址。&#xff08;一维数…

禁用输入法的方案

车间运行的SF系统&#xff0c;扫描产品条码。WB输入法等工具流氓软件&#xff0c;文本框获得焦点之后&#xff0c;自动打开输入状态&#xff0c;美其名日&#xff0c;智能化。输入法open状态下&#xff0c;扫描条码是乱码的&#xff0c;或是不全&#xff0c;缺字符。分析是输入…

Linux提权-02 sudo提权

文章目录 1. sudo 提权原理1.1 原理1.2 sudo文件配置 2. 提权利用方式2.1 sudo权限分配不当2.2 sudo脚本篡改2.3 sudo脚本参数利用2.4 sudo绕过路径执行2.5 sudo LD_PRELOAD环境变量2.6 sudo caching2.7 sudo令牌进程注入 3. 参考 1. sudo 提权原理 1.1 原理 sudo是一个用于在…

3. 后端验证前端Token

书接上回&#xff0c;后端将token返回给前端&#xff0c;前端存入cookie&#xff0c;每次前端给后端发送请求&#xff0c;后端是如何验证的。 若依是用过滤器来实现对请求的验证&#xff0c;过滤器的简单理解是每次发送请求的时候先发送给过滤器执行逻辑判断以及处理&#xff0…

【转】厚植根基,同启新程!一文回顾 2024 OpenHarmony 社区年度工作会议精彩瞬间

在数字化浪潮奔腾不息的今天&#xff0c;开源技术已成为推动科技创新与产业发展的强大引擎。2025年1月10日-11日&#xff0c;OpenAtom OpenHarmony&#xff08;开放原子开源鸿蒙&#xff0c;以下简称“OpenHarmony”或“开源鸿蒙”&#xff09;社区2024年度工作会议于深圳盛大启…

数据结构(Java版)第九期:LinkedList与链表(四)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 目录 一、LinkedList的模拟实现 1.1. 头插法 1.2. 尾插法 1.3. 插入中间节点 1.4. 删除某个节点 1.5. 删除所有为key的元素 二、LinkedList的使用 2.1. 什么是LinkedList 2.2. LinkedList的使⽤ 三、…

第22篇 基于ARM A9处理器用汇编语言实现中断<四>

Q&#xff1a;怎样编写ARM A9处理器汇编语言代码配置使用按键和定时器中断&#xff1f; A&#xff1a;本次实验同样为中断模式和监督模式都设置ARM A9堆栈指针&#xff0c;并使能中断&#xff0c;此外在主程序中调用子程序CONFIG_HPS_TIMER和CONFIG_KEYS分别对HPS Timer 0&…

Python学习(十三)什么是模块、模块的引入、自定义模块、常见的内置模块(math、random、os、sys、uuid、时间模块、加密模块)

目录 一、什么是模块&#xff1f;1.1 定义1.2 分类1.3 五种模块引入的方法1&#xff09;import 模块名&#xff08;全部引入&#xff09;2&#xff09;from 模块名 import 功能名&#xff08;部分引入&#xff09;3&#xff09;from 模块名 import *&#xff08;引入公共功能&a…

宝塔php7.4安装报错,无法安装,php8以上可以安装,以下的不行,gd库什么的都正常

宝塔的依赖问题导致的问题&#xff0c;最后手动挂载后才解决。。。废了三天三夜终于搞好了。。。。无语&#xff5e; 建议&#xff1a;不要一直升级宝塔版本&#xff0c;升级前备份或者开服务商的实例镜像&#xff0c;方便恢复&#xff0c;不然&#xff0c;可就GG了&#xff5…

C语言:-三子棋游戏代码:分支-循环-数组-函数集合

思路分析&#xff1a; 1、写菜单 2、菜单之后进入游戏的操作 3、写函数 实现游戏 3.1、初始化棋盘函数&#xff0c;使数组元素都为空格 3.2、打印棋盘 棋盘的大概样子 3.3、玩家出棋 3.3.1、限制玩家要下的坐标位置 3.3.2、判断玩家要下的位置是否由棋子 3.4、电脑出棋 3.4.1、…

flutter的web页面

有几个服务器 有几个后台 直接通过web端进去虽然说很方便&#xff0c;但… 于是把web页面镶嵌到应用里面去&#xff0c; 这样就换了个方式打开web页面了 比如这里有有个列表 这里是写死了&#xff0c;活的列表可以通过io去获取 import package:flutter/material.dart; imp…