返回首页
PROJECT REPORT · 2026-10-31

LLM 小参数模型微调与部署
—— 基于 HX-100 的 QLoRA 实践

硬件:RTX 3080 Ti 16GB 6 个开源模型微调 QLoRA 4bit OpenAI 兼容 API 上线
6微调模型(≤4B)
58,754中文指令数据
2.68 GB最高训练显存
:8000OpenAI API 端口
目录
  1. 项目概述与目标
  2. 数据集介绍
  3. 训练模型介绍
  4. 微调过程详细介绍
  5. 微调效果对比(前后对照)
  6. 验收与部署详细介绍
  7. 踩坑记录与经验总结
  8. 产物清单与后续规划

一、项目概述与目标

本项目在局域网主机 HX-100(Ubuntu,RTX 3080 Ti 16GB 显存)上,以 /data/nvme2t/workspace/LLM-WS 为根目录,搭建了一套完整的小参数大模型微调工作区,覆盖「数据集下载 → 开源模型下载 → QLoRA 微调 → 效果对比评估 → OpenAI 兼容 API 部署」全链路。

核心目标

① 数据集准备COIG-CQIA 58K ② 模型下载6× ≤4B hf-mirror ③ QLoRA 微调4bit · r16 · 120步 ④ 对比评估基座 vs 微调 ⑤ API 部署OpenAI 兼容
项目五阶段流水线

二、数据集介绍

微调效果的上限由数据决定。本项目选用 COIG-CQIA 作为统一中文指令微调数据集。

2.1 COIG-CQIA 数据集

全称:Chinese Open Instruction Generalist — Quality is All You Need

来源:HuggingFace m-a-p/COIG-CQIA(BAAI 智源研究院 COIG 系列的高质量子集)

构建方式:从中文互联网(知乎、豆瓣、SegmentFault、小红书、wiki 等)采集真实问答与文章,经深度清洗、重构、人工审核构建,主打「质量至上」,贴合真实人类交互行为。

子集构成:包含 coig_pc(通用)、exam(考试)、zhihu、douban、segmentfault、logi(逻辑)、fitness 等多个子集,覆盖问答、写作、推理、考试、生活常识等任务。

2.2 数据加工流程

样例:instruction「若计算机主存地址为 32 位…该 Cache 中比较器的个数和位数分别为()」→ output 给出组相联映射的推理过程与答案。整体为高质量中文指令-回答对。

三、训练模型介绍

选取 6 个参数量 ≤4B 的开源模型,覆盖不同厂商、不同架构与不同训练定位,便于横向对比微调适配性。

模型参数量厂商/架构定位与特点许可证
Qwen3-0.6B0.6B阿里 · Qwen3最新一代小模型,原生支持 think/非 think 双模式Apache 2.0
Qwen3-1.7B1.7B阿里 · Qwen3同系更大容量,推理能力更强Apache 2.0
Qwen2.5-1.5B-Instruct1.5B阿里 · Qwen2成熟指令版,中文能力强、生态全Apache 2.0
Qwen2.5-3B-Instruct3B阿里 · Qwen2本组最大,中文理解与生成最均衡Apache 2.0
SmolLM2-1.7B-Instruct1.7BHuggingFace · Llama系轻量英文优化模型,中文较弱Apache 2.0
TinyLlama-1.1B-Chat1.1B社区 · Llama极简教学/实验模型,英文为主Apache 2.0
选型逻辑:以 Qwen 系为主力(中文场景最优、许可证宽松可商用),辅以 SmolLM2 / TinyLlama 作为「非中文优化模型」的对照组,验证同一中文数据集在不同模型上的适配差异。

四、微调过程详细介绍

4.1 技术路线:为什么是 QLoRA

16GB 显存无法承载全参数微调(7B 全参需 40–60GB)。采用 QLoRA:将冻结的基座权重量化为 4bit NF4 加载,仅训练注入的 LoRA 低秩适配器(约占总参数 1–2%),显存需求下降约 4 倍,是单卡微调的现实最优解。配套使用 Unsloth 框架(手写 CUDA kernel,官方宣称 2× 提速、省 70% 显存)。

4.2 环境栈

组件版本/说明
GPU / 驱动RTX 3080 Ti 16GB(Ampere sm_86),驱动 580,CUDA 13
PyTorch2.6.0+cu124(经清华 PyPI 镜像安装,wheel 自带 CUDA runtime)
微调框架Unsloth 2026.10.11(自动管理 TRL / PEFT / 编译优化)
训练库trl、peft、transformers、bitsandbytes(4bit 量化)、accelerate
Python3.12,独立 venv(.venv/)
精度bf16(Unsloth 检测本环境支持 bf16,训练用 bf16=True)

4.3 统一微调超参数

  • 量化:load_in_4bit=True(NF4 + 双重量化)
  • LoRA:r=16, alpha=32, dropout=0
  • 目标模块:q/k/v/o_proj + gate/up/down_proj(全注意力+MLP)
  • 序列长度:max_seq_length=1024
  • 训练步数:120 步(冒烟+对比规模)
  • batch:per_device=1, grad_accum=8(有效 batch=8)
  • 学习率:2e-4,warmup 5 步
  • 优化器:paged_adamw_8bit,gradient_checkpointing=unsloth

训练数据经各模型 chat_template 渲染为「user→assistant」对话格式,仅对回答部分计算 loss。

4.4 微调结果汇总

模型训练 loss(终)峰值显存耗时LoRA 产物
Qwen3-0.6B2.6280.80 GB161 sruns/qwen3-0.6b
Qwen3-1.7B2.2951.66 GB328 sruns/qwen3-1.7b
Qwen2.5-1.5B1.9831.77 GB334 sruns/qwen25-1.5b
Qwen2.5-3B1.8642.68 GB535 sruns/qwen25-3b
SmolLM2-1.7B1.4971.30 GB349 sruns/smollm2-1.7b
TinyLlama-1.1B1.6151.03 GB274 sruns/tinyllama-1.1b
关键观察:6 个模型全部一次微调成功,最高峰值显存仅 2.68GB(远低预期),16GB 显存余量极大——为后续加大 batch、拉长序列、乃至微调 7B/14B 留足空间。loss 均正常收敛。

五、微调效果对比(前后对照)

用同一批提示词、同样的解码参数,分别调用基座模型与微调模型,从「指令遵循、简洁度、能力保持」三维度对比。以下为 Qwen2.5-3B 实测。

Q:用一句话解释什么是递归。
基座递归是这样一个过程或计算方法,其中每次调用自身版本的函数或过程,并且每次调用时使用更小规模的问题作为输入。(53 字,绕口)
微调递归是指一个函数直接或间接地调用自身的过程。(22 字,直击定义)
Q:把「时间就是金钱」翻译成英文。
基座"时间就是金钱" 可以翻译成英文为 "Time is money."
微调Time is money.(去掉冗余铺垫)
Q:太阳从西边升起吗?(拒答边界 / 事实保持)
基座不是的,太阳从东方升起。这是一个常见的误解。在地球自转的影响下…
微调不是,太阳是从东边升起的。(事实正确且更简洁)

对比结论

评估维度结果
指令遵循 / 简洁度✅ 显著提升:微调后平均输出缩短约 25 字,去掉"当然可以!"等冗余铺垫,直接作答
逻辑推理保持✅ 未退化:三段论推理题(Tom 会爬树吗)前后均正确
格式遵循✅ 未退化:JSON 输出前后均能正确解析
事实正确性✅ 未退化:常识题答案保持正确
非中文优化模型⚠️ SmolLM2 / TinyLlama 微调后出现重复、语句不通——120 步小样本难以补救中文短板
总评:这是一次「好」的微调——目标行为(指令遵循、简洁作答)明显改进,且基础能力(推理、格式、事实)无退化。Qwen 系(尤其 Qwen2.5-3B)为最佳模型。

六、验收与部署详细介绍

6.1 权重合并

为便于独立部署(不再依赖基座路径 + adapter),将 LoRA adapter 合并进基座,导出独立 fp16 模型:

# scripts/merge.py 核心步骤
model, tok = FastLanguageModel.from_pretrained(repo, load_in_4bit=True)
model = PeftModel.from_pretrained(model, "runs/qwen25-3b")
model = model.merge_and_unload()          # LoRA 权重并入基座
model.save_pretrained(out, safe_serialization=True)
# 产物:models_merged/qwen25-3b (2.3GB,独立可用)

6.2 OpenAI 兼容 API 服务

采用 FastAPI + Transformers 自研轻量推理服务(无需 vLLM 重依赖),完整实现 OpenAI 协议:

接口说明验证
GET /v1/models模型列表✅
POST /v1/chat/completions非流式对话,含 usage token 统计✅
POST /v1/chat/completions(stream)SSE 流式输出(chat.completion.chunk)✅
GET /health健康检查✅
OpenAI 官方 SDKbase_url 指向本服务,非流式+流式均通过✅

6.3 服务信息

# Python 调用(OpenAI SDK)
from openai import OpenAI
client = OpenAI(base_url="http://${请替换为实际服务地址}:8000/v1", api_key="none")
r = client.chat.completions.create(model="qwen25-3b-sft",
    messages=[{"role":"user","content":"你的问题"}], max_tokens=512)
print(r.choices[0].message.content)
兼容性:因遵循标准 OpenAI 协议,任何支持自定义 base_url 的客户端均可直接接入——LangChain、Dify、NextChat、Cline/Cursor、以及你自己的 dc-tool 等。

七、踩坑记录与经验总结

问题根因解决方案
HF 模型下载 401新版 huggingface_hub 默认走 xet 后端设 HF_HUB_DISABLE_XET=1
HF/ModelScope 单连接 KB 级镜像限速snapshot_download 多线程叠加吞吐
torch 官方源卡死download.pytorch.org 国内极慢改用清华 PyPI 镜像(wheel 自带 CUDA)
fp16/bf16 报错Unsloth 检测本环境支持 bf16训练改 bf16=True, fp16=False
远程后台任务消失SSH 断开 & 进程被清一律用 tmux 运行长任务
合并权重报错LoRA 未合并即保存基座先 merge_and_unload() 再 save

八、产物清单与后续规划

8.1 产物清单(HX-100 工作区)

模型资产

  • 6 个基座模型缓存(26G)
  • 6 个 LoRA adapter(runs/)
  • 1 个合并独立模型(models_merged/)

数据与评估

  • COIG-CQIA 原始 + 处理后 1500/200
  • 12 个 base/sft 对比 json
  • train_info.json 训练指标

可复用脚本

  • sft.py / train_all.sh(微调)
  • eval_model.py / compare.py(评估)
  • merge.py / serve.py(部署)

8.2 后续规划