分布式训练qwen3-32b

训练框架-LLaMA-Factor

安装 - LLaMA Factory

docker部署镜像,以便后续传入内网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory

docker build -f ./docker/docker-cuda/Dockerfile \
--build-arg PIP_INDEX=https://pypi.org/simple \
--build-arg EXTRAS=metrics \
-t llamafactory:latest .

docker run -dit --ipc=host --gpus=all \
-p 7860:7860 \
-p 8001:8000 \ # 主机 8001 → 容器 8000,主机8000端口被占用了
--name llamafactory \
-v /aisys/:/aisys/ \
docker.1ms.run/hiyouga/llamafactory

docker run -dit --ipc=host --gpus=all -p 7860:7860 -p 8001:8000 -v /aisys/:/aisys/ --name llamafactory docker.1ms.run/hiyouga/llamafactory

docker exec -it llamafactory bash
1
2
3
4
5
docker pull docker.1ms.run/hiyouga/llamafactory                                    

docker save docker.1ms.run/hiyouga/llamafactory:latest -o llamafactory-image.tar

docker load -i llamafactory-image.tar

LLaMA Board 可视化微调(由 Gradio 驱动)

1
llamafactory-cli webui
  • Web UI 访问:http://localhost:7860
  • API 服务访问:http://localhost:8001

数据集-easy-dataset

docker部署镜像,以便后续传入内网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
git clone https://github.com/ConardLi/easy-dataset.git
cd easy-dataset

docker build -t easy-dataset .

docker load -i easy-dataset.tar

docker run -d \
-p 1717:1717 \
-v /aisys/repo_dev/xizhang/lora_database:/app/local-db \
-v /aisys/repo_dev/xizhang/lora_databse_prisma:/app/prisma \
--name easy-dataset \
easy-dataset


docker exec -it easy-dataset sh

docker stop easy-dataset
docker rm easy-dataset

#实时跟踪
docker logs -f easy-dataset

注意: 请将 {YOUR_LOCAL_DB_PATH}{LOCAL_PRISMA_PATH} 替换为你希望存储本地数据库的实际路径,建议直接使用当前代码仓库目录下的 local-dbprisma 文件夹,这样可以和 NPM 启动时的数据库路径保持一致。

注意: 如果需要挂载数据库文件(PRISMA),需要提前执行 npm run db:push 初始化数据库文件。

使用开源项目制作数据集

打开浏览器,访问 http://localhost:1717

上传内网

使用scp

1
scp -r "F:\project python\实习\微调\universal-llm_latest.tar" root@10.117.128.50:/aisys/repo_dev/xizhang/images

SCP 全称是 Secure Copy Protocol(安全复制协议),是一种用于在计算机之间安全地复制文件的网络协议。

它基于 SSH(Secure Shell)协议工作,因此所有传输的数据都是加密的,可以防止被窃听或篡改,非常适合在不安全的网络(如互联网)中使用。

模型部署与调用

制作模型运行镜像

qwen3部署版本要求如下

使用 Python 3.10 或以上版本, PyTorch 2.6 或以上版本

transformers>=4.51.0 版本

使用 sglang>=0.4.6.post1vllm>=0.8.5 来创建一个与 OpenAI 兼容的 API 端点

镜像信息

类别 组件 版本 / 来源 说明
OS Ubuntu 22.04 LTS (Jammy) 上游镜像继承
Python CPython 3.11 镜像自带
PyTorch PyTorch 2.6.0+cu126 官方 wheel,CUDA 12.6
CUDA Runtime 12.6.3 与宿主机 535 驱动兼容
cuDNN cuDNN 9 包含在镜像
核心库 transformers ≥4.51.0 官方最新
tokenizers ≥0.21 transformers 依赖
accelerate ≥1.0.0 训练 / 推理加速
sentencepiece ≥0.2.0 Qwen3 分词器必需
protobuf ≥5.28.0 序列化 / 模型加载
tiktoken ≥0.8.0 OpenAI 格式分词
推理框架 vLLM ≥0.8.5 支持 tensor-parallel、PagedAttention
SGLang ≥0.4.6.post1 支持 outline 解码、MoE 优化
可选加速 flash-attn ≥2.7 长上下文 / 大 batch 推理
权重下载 modelscope 最新 国内镜像加速
工具链 git / git-lfs 最新 拉取 HuggingFace 权重
curl / jq / vim 最新 调试 & 健康检查

基础镜像pytorch/pytorch:2.6.0-cuda12.6-cudnn9-develPyTorch 官方在 Docker Hub 上提供的“全家桶”开发镜像,发布日期 2025-01-29,镜像大小约 13 GB,定位是 “开箱即用”的 GPU 训练 / 推理 / 调试环境

dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# ---------- 1. 基础镜像 ----------
FROM pytorch/pytorch:2.6.0-cuda12.6-cudnn9-devel

# ---------- 2. 国内镜像源 ----------
RUN sed -i 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list && \
sed -i 's|http://security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list && \
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn

# ---------- 3. 系统依赖 ----------
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
git git-lfs build-essential ninja-build curl wget vim jq && \
rm -rf /var/lib/apt/lists/*

# ---------- 4. Python 依赖 ----------
RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
pip install --no-cache-dir \
"torch==2.6.0+cu126" \
"transformers>=4.51.0" \
"tokenizers>=0.21" \
"accelerate>=1.0.0" \
"sentencepiece>=0.2.0" \
"protobuf>=5.28.0" \
"tiktoken>=0.8.0" \
"vllm>=0.8.5" \
"sglang[all]>=0.4.6.post1" \
"modelscope" \
"fastapi" "uvicorn[standard]" "pydantic"

# ---------- 5. 可选性能加速 ----------
RUN pip install --no-cache-dir "flash-attn>=2.7" --no-build-isolation || true

# ---------- 6. 国内 HuggingFace 镜像 ----------
ENV HF_ENDPOINT=https://hf-mirror.com

# ---------- 7. 工作目录 ----------
WORKDIR /app
EXPOSE 4000 4001 4002

# ---------- 8. 默认命令 ----------
CMD ["/bin/bash"]

运行容器

1
2
3
4
5
6
7
8
9
10
docker run -it \
--name llm-service \
--gpus all \
-p 4000:4000 \
-p 4001:4001 \
-p 4002:4002 \
-v /aisys/repo_dev/xizhang/models:/app/models \
-v /aisys/repo_dev/xizhang/models/cache:/app/models/.cache \
--shm-size=8g \
universal-llm:latest bash

vllm部署qwen3

1
2
3
4
5
6
7
8
vllm serve /app/models/qwen3-32b-lora-new \
--port 4001 \
--tensor-parallel-size 4 \
--max-model-len 1024 \
--reasoning-parser qwen3 \
--gpu-memory-utilization 0.8 \
--max-num-seqs 8 \
--host 0.0.0.0
参数 含义 推荐/注意
--port 8000 服务监听端口 -p 8000:8000 保持一致;如需多实例,可改 8001/8002 …
--tensor-parallel-size 4 把模型权重切成 4 份,跨 4 张 GPU 并行计算 必须 ≤ 实际 GPU 数量;Qwen3-32B 在 4×L20 上显存刚好够,不可再大
--max-model-len 1024 单次推理最大 token 数(含 prompt + 生成) 若场景需要 4k/8k/32k,可调到 4096/8192;显存占用 ∝ 长度²
--reasoning-parser qwen3 vLLM ≥0.8.5 新增开关,解析 Qwen3 的 <think>…</think> 标签,把推理过程单独返回 仅在 Qwen3 系列模型有效,其他模型请去掉
--gpu-memory-utilization 0.8 显存使用上限 80 %;剩余 20 % 留给 CUDA kernel、KV cache 膨胀 若出现 OOM,可降到 0.7;若想多并发,可尝试 0.85(风险 OOM)
--max-num-seqs 8 同一时刻最多并发处理的 请求条数 --max-model-len 和显存同时决定;若长度 ↑,此值需 ↓
--host 0.0.0.0 监听所有网卡,使容器外可访问 生产环境可改为内网 IP 或 127.0.0.1 提高安全性

测试

1
2
3
4
5
6
7
8
9
10
curl http://localhost:4001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "/app/models/qwen3-32b-lora-new",
"messages": [
{"role": "user", "content": "请用中文介绍一下你自己"}
],
"temperature": 0.7,
"max_tokens": 512
}'

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os
from openai import OpenAI

# 指向本地 vLLM
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="dummy" # vLLM 不做鉴权,随便填
)

resp = client.chat.completions.create(
model="qwen3-32b", # 必须和 vLLM 启动路径或 --served-model-name 保持一致
messages=[
{"role": "user", "content": "9.9 和 9.11 哪个大?"}
],
max_tokens=512,
temperature=0.7,
stream=False # True 可开流式
)

print(resp.choices[0].message.content)

快速入门 - Qwen — Quickstart - Qwen

通义千问3-32B · 模型库

微调数据集

alpaca和sharegpt的区别

▶ Alpaca 典型字段

1
2
3
4
5
6
7
{
"instruction": "把下面句子翻译成英文",
"input": "今天天气真好",
"output": "The weather is nice today.",
"system": "你是一个翻译助手", // 可选
"history": [] // 可选,放前几轮
}
  • 一条数据 = 一次独立任务
  • 字段固定:instruction / input / output 三板斧

▶ ShareGPT 典型字段

1
2
3
4
5
6
7
8
9
10
{
"conversations": [
{"from": "human", "value": "我今天心情不好"},
{"from": "gpt", "value": "怎么啦?想聊聊吗"},
{"from": "human", "value": "论文又被拒了"},
{"from": "gpt", "value": "理解你的挫败感…"}
],
"system": "你是贴心聊天机器人", // 可选
"tools": [...] // 可选,放函数描述
}
  • 一条数据 = 一段完整的多轮对话
  • 角色交替:human / gpt / function / observation
维度 Alpaca ShareGPT
来源 斯坦福 Alpaca 项目,为了低成本做指令微调 ShareGPT 网站爬取的真实 ChatGPT 对话
目标 让模型学会“看到指令+输入→给出答案” 让模型学会“像 ChatGPT 一样多轮对话”

详解

1
2
3
4
5
6
{
"instruction": "电阻率测定法的环境温湿度控制对检测结果的可信度有何影响?",
"input": "- \"检测依据:DL/T 421-2009 电力用油体积电阻率测定法\"\n- \"检测地点及环境条件:油品检测室 温度:16℃ 湿度:57%RH\"\n- \"电阻率(\"",
"output": "<think>### \n首先,理解问题的核心:电阻率测定法中,环境温湿度控制如何影响检测结果的可信度,这涉及到测量过程的准确性和可靠性。\n\n然后,分析关键信息:检测依据是DL/T 421-2009标准,它规定了电阻率测定的方法;环境条件被记录为温度16℃和湿度57%RH;检测结果显示电阻率为1.04×10^10 Ω·cm,符合DL/T 571-2014标准的要求(≥6×10^9 Ω·cm)。\n\n接着,推理温湿度控制的影响:环境温湿度是测量过程中的关键变量,控制这些条件确保",
"system": "作为电力能源报告解读专家,我在生成答案时,将严格遵循以下格式:\n根据“信息来源”,“信息来源”是原文中可直接支撑结论的句子、数据或图表编号给出“结论与推理”——用上述逐条复现的信息为唯一依据,推导出最终答案。"
}

instruction为问题;input为上下文;output包含思维链与答案;system为系统提示词

微调参数设置

DeepSpeed stage(DeepSpeed 阶段)

deepSpeed 的 ZeRO 分布式优化阶段,用于在多 GPU 上高效训练大模型。

Stage 功能 说明
Stage 0 不做任何优化 基础分布式训练(DDP),显存占用高
Stage 1 梯度分片(Gradient Sharding) 将梯度切分到不同 GPU,减少显存
Stage 2 参数 + 梯度分片 进一步降低显存,但需通信同步
Stage 3 参数 + 梯度 + 优化器状态分片 最强显存优化,支持超大模型

使用 DeepSpeed offload(使用 offload)

部分或全部模型参数、优化器状态卸载到 CPU 内存,进一步释放 GPU 显存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
llamafactory-cli train \
--stage sft \
--do_train True \
--model_name_or_path /aisys/repo_dev/xizhang/models/qwen3-32b-lora-new \
--preprocessing_num_workers 16 \
--finetuning_type lora \
--template qwen3 \
--flash_attn auto \
--dataset_dir /aisys/repo_dev/xizhang/lora_database/P9er76jCWCFW \
--dataset [Easy Dataset] [P9er76jCWCFW] Alpaca \
--cutoff_len 4096 \
--learning_rate 5e-05 \
--num_train_epochs 3.0 \
--max_samples 100000 \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 1 \
--lr_scheduler_type cosine \
--max_grad_norm 1.0 \
--logging_steps 5 \
--save_steps 200 \
--warmup_steps 0 \
--packing False \
--enable_thinking True \
--report_to none \
--output_dir saves/Qwen3-32B-Thinking/lora/train_2025-08-28-03-04-52 \
--bf16 True \
--plot_loss True \
--trust_remote_code True \
--ddp_timeout 180000000 \
--include_num_input_tokens_seen True \
--optim adamw_torch \
--lora_rank 8 \
--lora_alpha 16 \
--lora_dropout 0 \
--lora_target all \
--val_size 0.15 \
--eval_strategy steps \
--eval_steps 200 \
--per_device_eval_batch_size 2 \
--deepspeed cache/ds_z3_config.json

训练结果

image-20250827091214108

评估

不知道为什么使用llamafactory的评估会爆显存,我怀疑是因为那个webui评估可能不支持多卡,就进行一下人工评估吧

输入

image-20250828144300339

微调模型

image-20250828145106050

初始模型

image-20250828145750115

在内网计算节点访问SwanLab Cloud

在内网计算节点访问SwanLab Cloud | SwanLab官方文档

如何计算训练步数

1. 训练集样本量

公式 训练集样本量 = 总数据量 × (1 − 验证集比例)

示例 总数据 2876 条,验证集占 15% 2876 × (1 − 0.15) = 2876 × 0.85 = 2446 条

2. 每次参数更新处理的样本数(effective batch size)

公式 每次更新样本数 = 单设备批次大小 × GPU 数 × 梯度累积步数

示例

  • per_device_train_batch_size = 1
  • GPU 数 = 2
  • gradient_accumulation_steps = 8

1 × 2 × 8 = 16 条

通俗理解: GPU 一次只能看 1 条 → 2 卡并行就是 2 条 → 累积 8 次才更新一次参数,所以一次更新真正看了 16 条数据。

3. 每轮(epoch)的训练步数

公式 每轮步数 = ⌊ 训练集样本量 ÷ 每次更新样本数 ⌋ (⌊ ⌋ 表示向下取整)

示例 2446 ÷ 16 = 152.875 → 152 步

4. 总训练步数

公式 总步数 = 每轮步数 × 训练轮数 (epochs)

示例 152 × 3 = 456 步

如何计算一个模型占用的显存

基础模型的权重

  • 定义:预训练模型的参数矩阵,即选择的预训练模型所占用显存的大小。
  • 计算公式显存占用 = 模型参数数量 × 单个参数的字节数

常见模型精度下的单个参数显存占用:

表格

复制

精度类型 二进制位数 字节数
FP32 32位 4字节
FP16 16位 2字节
BF16 16位 2字节(指数位同FP32)
INT8 8位 1字节
INT4 4位 0.5字节
INT2 2位 0.25字节

例如

  • 模型选择:Qwen2.5-7B-Instruct
  • 参数规模:70亿(7B)
  • 计算精度:BF16(2字节/参数)
  • 预估显存占用70亿 × 2字节 = 140亿字节 = 14GB

框架开销(Framework Overhead)

  • 定义:LLaMAFactory 底层使用的深度学习框架(如 PyTorch)本身的显存占用。
  • 包含内容
    • 张量缓存
    • 线程资源
    • 内核调度开销
    • 自动微分图结构等
  • 计算方法:难以精确计算
  • 估算方法:通常占用不大,默认估算为 1 GB

LoRA 适配器(LoRA Adapters)

  • 定义:在 LoRA 微调中,不直接修改原始模型的庞大权重,而是插入轻量级的“LoRA适配器模块”来学习微调所需的变化。

  • 计算方法

    显存占用=LoRA层数×秩(Rank)×(输入维度+输出维度)×2B

  • 估算方法

    • 与 LoRA 的秩(Rank)大小相关
    • 一般占用不大,常规配置下通常不超过 0.5 GB,保守估计为 0.5 GB

激活值(Activations)

  • 定义:前向传播过程中各层的输出张量(如隐藏层状态、注意力矩阵等),即模型“处理数据时产生的所有中间结果”。

  • 计算方法

    显存占用=批量大小×序列长度×隐藏层维度×模型层数×单个元素字节数

  • 估算方法

    • 单次处理的 Token 量每增加 1K,显存约增加 2.5 GB
    • 与单 GPU 的批量大小和数据集的截断长度(序列长度)正相关
    • 在固定其他配置(基础模型权重、框架开销、LoRA适配器)后,剩余显存即为激活值占用

加速方式

加速方式 全称 / 来源 核心原理与特点 适用场景与注意事项
auto 自动选择 由框架(如 transformers、LLaMA-Factory、DeepSpeed 等)根据当前硬件、驱动、CUDA 版本自动挑选最快的可用算子或路径。 优点:零配置、开箱即用;缺点:不一定能启用最新、最快的内核。 初次实验、不想手动调参时首选。
flashattn2 FlashAttention-2 通过 IO-Aware 的算法和 GPU Tensor Core 优化,将标准 Multi-Head Attention 的显存访问次数大幅降低,从而显著加快训练/推理速度(通常 2-4×),并减少显存占用。 需要 A100、H100、RTX 30/40 系列等 Ampere/Lovelace 架构;依赖 CUDA≥11.8、PyTorch≥2.0 且需安装 flash-attn wheel。 训练/微调 LLM 时首选;序列越长收益越大。若编译失败可退回 xformers 或原生实现。
unsloth Unsloth 开源库 针对 Llama、Mistral、Qwen 等架构,使用动态量化、手工 fused-kernel 和梯度检查点优化,使 LoRA 微调在消费级 GPU 上也能跑更大 batch/更长序列。官方宣称速度提升 2-5×,显存节省 50-70%。 安装简单:pip install unsloth(会自动替换部分 PyTorch 层)。 单卡 4090/3090 上 LoRA 微调 7B-13B 模型效果最佳;目前仅支持有限模型。
liger_kernel Liger-Kernel(微软开源) 以 Triton 编写的高性能 fused-kernel 合集(SwiGLU、RMSNorm、CrossEntropy、RoPE 等),在保持数值精度的同时减少 kernel launch 和显存写回,训练吞吐量可提升 10-20%。 纯 Python/Triton 实现,无需额外 CUDA 编译。 对训练框架侵入性小,可与 FlashAttention 并存;适合想“无痛”提速 10-20% 的场景。

参考资料

LLaMA Factory