news 2026/9/19 7:31:34

基于 Self-LLM 的 DeepSeek-7B-Chat 4bits 量化 QLoRA 微调实战:6G 显存训练 7B 模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Self-LLM 的 DeepSeek-7B-Chat 4bits 量化 QLoRA 微调实战:6G 显存训练 7B 模型

基于 Self-LLM 的 DeepSeek-7B-Chat 4bits 量化 QLoRA 微调实战:6G 显存训练 7B 模型

【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/datawhalechina/self-llm

本篇技术指南围绕 models/DeepSeek/05-DeepSeek-7B-chat 4bits量化 Qlora 微调.md 展开,讲解如何在 Linux 环境下基于 transformers、peft、bitsandbytes 框架,对 DeepSeek-7B-Chat 模型执行 4bits 量化的 QLoRA 高效微调,并用 6G 显存级别的消费级显卡训练一个完整的 7B 参数模型。读完本文,你将掌握 4bit 量化模型加载、QLoRA 配置、低显存训练参数调优以及微调后的模型推理验证这一整套实战技能。

概述:为什么选择 4bits 量化 QLoRA

传统全量微调 7B 级模型对显存的要求极高,普通消费级显卡难以承受。LoRA(Low-Rank Adaptation)通过冻结原模型权重、只训练注入的低秩矩阵,大幅降低了可训练参数量与显存开销;而 QLoRA 更进一步,将基础模型以 4bits 量化精度加载进显存,使得「6G 显存训练 7B 模型」成为可能。

本教程使用的方案要点如下:

  • 基于transformerspeftbitsandbytes三个核心框架完成全流程;
  • 以 4bits(NF4 量化格式)加载 DeepSeek-7B-Chat 基础模型,加载完成后用nvidia-smi查看显存占用约5.7G
  • 只对注入的 LoRA 低秩矩阵做反向传播与参数更新,原模型权重保持冻结;
  • 优化器采用 QLoRA 配套的paged_adamw_32bit分页加载方案,进一步压低显存峰值。

配套的可运行实现见 05-DeepSeek-7B-chat 4bits量化 Qlora 微调.ipynb,可与本文对照学习。若需对比不加量化的普通 LoRA 微调流程,可参考同目录下的 04-DeepSeek-7B-chat Lora 微调.md。

环境配置:安装量化微调依赖

在完成基础环境配置(Python、CUDA 驱动、PyTorch)与本地模型部署之后,还需要安装一组经过本教程验证的第三方库,版本组合如下:

pip install transformers==4.35.2 pip install peft==0.4.0 pip install datasets==2.10.1 pip install accelerate==0.20.3 pip install tiktoken pip install transformers_stream_generator pip install bitsandbytes==0.41.1

其中,bitsandbytes是 QLoRA 的量化基石,负责在 GPU 上执行 4bits 线性层量化与反量化计算;peft提供LoraConfigget_peft_model等低秩适配 API;accelerate支撑device_map="auto"的自动设备分配;datasets用于将 JSON 指令集转换为 Dataset 对象。

本教程使用的微调数据集为仓库根目录下的 dataset/huanhuan.json,该数据集由约 3700 条甄嬛风格对话样本组成(notebook 中处理结果显示num_rows: 3729),是后续指令微调的原料。若安装依赖时网络受限,可先参考 General-Setting/01-pip、conda换源.md 配置国内镜像源。

指令集构建:让模型学会「扮演甄嬛」

LLM 的微调通常指指令微调(Instruction Tuning),即使用形如下方的三元组数据:

{ "instrution":"回答以下用户问题,仅输出答案。", "input":"1+1等于几?", "output":"2" }

字段语义如下:

  • instruction:用户指令,告知模型需要完成的任务;
  • input:用户输入,是完成指令所必需的输入内容;
  • output:模型应当给出的标准输出。

核心训练目标是让模型具备理解并遵循用户指令的能力,因此指令集必须针对目标任务专门构建。本教程以「模拟甄嬛对话风格」的个性化 LLM 为目标,构造的指令样本形如:

{ "instruction": "现在你要扮演皇帝身边的女人--甄嬛", "input":"你是谁?", "output":"家父是大理寺少卿甄远道。" }

全部构造好的指令数据存放在 dataset/huanhuan.json 中。从实际样本看(dataset/huanhuan.json),多数样本的input字段为空字符串,instruction直接承载完整语境,output为甄嬛口吻的回答,例如:

{ "instruction": "皇上驾到!", "input": "", "output": "皇上万福金安。" }

仓库中 examples/Chat-嬛嬛 目录同样围绕该对话风格数据集展开,可看到同一数据集在不同模型上的复用方式。

数据格式化:将指令集编码为模型可读的序列

LoRA 训练数据需要先经过格式化、编码再送入模型。熟悉 PyTorch 训练流程的同学知道,通常需要把输入文本编码为input_ids,把输出文本编码为labels,编码结果都是多维向量。为此定义一个预处理函数process_func,对每个样本编码输入、输出文本并返回编码后的字典:

def process_func(example): MAX_LENGTH = 384 # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性 input_ids, attention_mask, labels = [], [], [] instruction = tokenizer(f"User: {example['instruction']+example['input']}\n\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens response = tokenizer(f"Assistant: {example['output']}<|end▁of▁sentence|>", add_special_tokens=False) input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id] attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1 labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id] if len(input_ids) > MAX_LENGTH: # 做一个截断 input_ids = input_ids[:MAX_LENGTH] attention_mask = attention_mask[:MAX_LENGTH] labels = labels[:MAX_LENGTH] return { "input_ids": input_ids, "attention_mask": attention_mask, "labels": labels }

该格式化逻辑参考了 DeepSeek 官方仓库 README 中给出的对话模板:

User: {messages[0]['content']} Assistant: {messages[1]['content']}<|end▁of▁sentence|>User: {messages[2]['content']} Assistant:

几个关键细节:

  • 输入侧拼接为User: ...前缀,输出侧拼接为Assistant: ...前缀并以 DeepSeek 的结束符<|end▁of▁sentence|>收尾,保持与官方对话格式一致;
  • add_special_tokens=False表示不在开头额外添加 special token;
  • labels中,输入部分(User:段)全部置为-100(PyTorch 交叉熵损失会忽略该值),只有Assistant:输出段参与损失计算;
  • 序列末尾补充pad_token_id,并将对应attention_mask位置补1,保证长度对齐;
  • MAX_LENGTH = 384用于截断超长样本,因为 DeepSeek 使用的 Llama 系分词器会把一个中文字切分为多个 token,需要放宽最大长度以保留数据完整性。

在 notebook 中,加载数据集并应用该函数的过程为:

from datasets import Dataset import pandas as pd df = pd.read_json('../../data/huanhuan.json') ds = Dataset.from_pandas(df) tokenized_id = ds.map(process_func, remove_columns=ds.column_names)

处理完成后tokenized_id的特征列为['input_ids', 'attention_mask', 'labels'],共 3729 行。用tokenizer.decode可以验证格式化结果,例如解码某样本得到:

'User: 小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——\n\nAssistant: 嘘——都说许愿说破是不灵的。<|end▁of▁sentence|><|end▁of▁sentence|>'

过滤掉-100后单独解码labels,则能还原出仅含 Assistant 回复的训练目标:

'Assistant: 你们俩话太多了,我该和温太医要一剂药,好好治治你们。<|end▁of▁sentence|><|end▁of▁sentence|>'

加载 Tokenizer 与 4bit 量化模型

模型以 4bits 精度加载,可大幅压缩显存占用。如果你的显卡较新,也可以改用torch.bfloat16作为计算精度。对于 DeepSeek 这类自定义代码模型,加载时必须指定trust_remote_code=True

tokenizer = AutoTokenizer.from_pretrained('./deepseek-ai/deepseek-llm-7b-chat/', use_fast=False, trust_remote_code=True) tokenizer.padding_side = 'right' # padding在右边 model = AutoModelForCausalLM.from_pretrained( '/root/model/deepseek-ai/deepseek-llm-7b-chat/', trust_remote_code=True, torch_dtype=torch.half, device_map="auto", low_cpu_mem_usage=True, # 是否使用低CPU内存 load_in_4bit=True, # 是否在4位精度下加载模型。如果设置为True,则在4位精度下加载模型。 bnb_4bit_compute_dtype=torch.half, # 4位精度计算的数据类型。这里设置为torch.half,表示使用半精度浮点数。 bnb_4bit_quant_type="nf4", # 4位精度量化的类型。这里设置为"nf4",表示使用nf4量化类型。 bnb_4bit_use_double_quant=True # 是否使用双精度量化。如果设置为True,则使用双精度量化。 ) model.generation_config = GenerationConfig.from_pretrained('/root/model/deepseek-ai/deepseek-llm-7b-chat/') model.generation_config.pad_token_id = model.generation_config.eos_token_id

4bit 加载相关参数的作用如下:

参数取值作用
load_in_4bitTrue以 4bits 精度加载模型,是 QLoRA 的核心开关
bnb_4bit_compute_dtypetorch.half4bits 权重参与计算时反量化到的计算精度,通常设为半精度
bnb_4bit_quant_typenf44bits 量化格式,nf4(Normal Float 4)是 bitsandbytes 针对正态分布权重设计的 4bit 量化格式,精度优于传统的 int4
bnb_4bit_use_double_quantTrue双重量化,即对量化缩放因子再做一次量化,进一步压缩显存占用
device_map"auto"由 accelerate 自动将各层分配到可用设备
low_cpu_mem_usageTrue降低加载过程中的 CPU 内存峰值

加载完成后,可以在终端用nvidia-smi确认显存占用,本教程实践观察约5.7G左右。从 notebook 输出的模型结构也可以印证量化确实生效:模型各线性层均显示为Linear4bit,例如:

(self_attn): LlamaAttention( (q_proj): Linear4bit(in_features=4096, out_features=4096, bias=False) (k_proj): Linear4bit(in_features=4096, out_features=4096, bias=False) (v_proj): Linear4bit(in_features=4096, out_features=4096, bias=False) (o_proj): Linear4bit(in_features=4096, out_features=4096, bias=False) ) (mlp): LlamaMLP( (gate_proj): Linear4bit(in_features=4096, out_features=11008, bias=False) (up_proj): Linear4bit(in_features=4096, out_features=11008, bias=False) (down_proj): Linear4bit(in_features=11008, out_features=4096, bias=False) ... )

可见 DeepSeek-7B-Chat 的注意力四投影(q/k/v/o)与 MLP 三个投影(gate/up/down)全部被替换为Linear4bit,这正是显存被压到 6G 量级的直接原因。

定义 LoraConfig:注入低秩适配器

LoraConfig是 peft 中配置低秩适配的核心类,可设置参数较多,但核心参数并不多:

  • task_type:模型任务类型,因果语言模型填TaskType.CAUSAL_LM
  • target_modules:需要注入 LoRA 的层名,主要是 attention 部分,不同模型层名不同,可传数组、字符串或正则表达式;
  • r:LoRA 的秩(rank);
  • lora_alpha:LoRA 的缩放系数;
  • lora_dropout:LoRA 层 dropout 比例。

需要特别澄清的是,LoRA 的实际缩放比例是lora_alpha / r,而不是r本身。下面配置中lora_alpha=32r=8,缩放即为 4 倍。

config = LoraConfig( task_type=TaskType.CAUSAL_LM, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], inference_mode=False, # 训练模式 r=8, # Lora 秩 lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理 lora_dropout=0.1# Dropout 比例 )

需要说明的是,配套 notebook 中target_modules实际使用的是["q_proj", "k_proj", "v_proj", "o_proj"],即只对 attention 四个投影注入 LoRA;而本教程正文给出的是同时覆盖 MLP 三个投影(gate_projup_projdown_proj)的扩展版本。从训练成本角度推断,覆盖 MLP 层会增加可训练参数量与计算开销,但对模型表达能力可能有一定增益,读者可根据显存余量自行取舍。对应地,notebook 中 4 模块配置下调用get_peft_model后的可训练参数统计为:

trainable params: 7,864,320 || all params: 3,882,602,496 || trainable%: 0.20255279823525874

即在约 38.8 亿参数(含 4bit 量化基座)的模型中,仅约 786 万参数参与训练,训练比例仅约0.20%,这正是 LoRA 高效微调的直接量化证据。

在正式训练前还需注意:若开启梯度检查点(gradient_checkpointing=True),必须执行model.enable_input_require_grads()

model = get_peft_model(model, config) model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法 model.print_trainable_parameters()

自定义 TrainingArguments:为低显存场景调参

TrainingArguments的源码对每个参数都有说明,这里介绍几个训练中最常用的:

  • output_dir:模型输出目录;
  • per_device_train_batch_size:单卡 batch size;
  • gradient_accumulation_steps:梯度累加步数,显存较小时可调小 batch size、增大梯度累加;
  • logging_steps:每隔多少步输出一次日志;
  • num_train_epochs:训练轮数(epoch);
  • save_steps:每隔多少步保存一次 checkpoint;
  • learning_rate:学习率;
  • gradient_checkpointing:梯度检查点,开启后以计算换显存,可显著降低激活值占用,但必须配合model.enable_input_require_grads()使用;
  • optim="paged_adamw_32bit":使用 QLoRA 的分页优化器,当显存不足时将优化器状态换出到 CPU 内存,从而避免 OOM。
args = TrainingArguments( output_dir="./output/DeepSeek", per_device_train_batch_size=8, gradient_accumulation_steps=2, logging_steps=10, num_train_epochs=3, save_steps=100, learning_rate=1e-4, save_on_each_node=True, gradient_checkpointing=True, optim="paged_adamw_32bit" # 优化器类型 )

显存适配说明:上方正文配置(batch_size=8、梯度累加 2)适合显存较充裕的场景;而 notebook 中为了演示低显存训练,实际采用了per_device_train_batch_size=1gradient_accumulation_steps=1的更保守组合,配合 4bit 量化与梯度检查点,即可在约 6G 显存条件下完成 7B 模型的训练。两种配置的其余超参数保持一致,读者可根据自身显卡显存灵活调整。

使用 Trainer 训练

数据、模型与训练参数就绪后,使用 transformers 的Trainer启动训练,并用DataCollatorForSeq2Seq对批次内序列做动态 padding:

trainer = Trainer( model=model, args=args, train_dataset=tokenized_id, data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True), ) trainer.train()

几点补充说明:

  • DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True)会在每个 batch 内部按最长序列动态补齐pad_token_id,相比固定长度 padding 更省显存;
  • 由于TrainingArguments中设置了save_steps自动保存策略,训练结束后并不需要手动保存模型,checkpoint 会自动写入output_dir
  • 整个训练集为 3729 条样本,3 个 epoch 下迭代步数有限,适合在消费级显卡上一次跑通全流程。

模型推理与效果验证

训练完成后,用经典方式做一次推理验证,输入一句甄嬛风格的台词观察模型回复:

text = "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——" inputs = tokenizer(f"User: {text}\n\n", return_tensors="pt") outputs = model.generate(**inputs.to(model.device), max_new_tokens=100) result = tokenizer.decode(outputs[0], skip_special_tokens=True) print(result)

本教程的推理结果如下,可见即使是 4bits 量化的微调模型,对话风格还原效果依然不错:

User: 小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的—— Assistant: 姐姐,你别说了,我自有打算。

推理时需注意保持与训练一致的对话模板前缀(User: ...),并设置max_new_tokens控制生成长度;skip_special_tokens=True用于在解码时剔除<|end▁of▁sentence|>等特殊 token。

小结

本文完整复现了基于 models/DeepSeek/05-DeepSeek-7B-chat 4bits量化 Qlora 微调.md 的 DeepSeek-7B-Chat QLoRA 微调全流程:从bitsandbytes等依赖安装、甄嬛指令集构建与格式化,到 4bits NF4 量化模型加载、LoraConfig注入低秩适配器、TrainingArguments低显存调参,再到Trainer训练与推理验证。

核心要点回顾:

  • 4bits 量化(load_in_4bit+bnb_4bit_quant_type="nf4"+ 双重量化)将 7B 模型的显存占用压到约 5.7G,使消费级显卡训练成为可能;
  • LoRA 只训练约 0.20% 的参数,配合paged_adamw_32bit分页优化器与梯度检查点,进一步控制显存峰值;
  • 数据格式必须与 DeepSeek 官方User:/Assistant:对话模板保持一致,labels中仅 Assistant 段参与损失计算;
  • 配套完整实现可直接参考 05-DeepSeek-7B-chat 4bits量化 Qlora 微调.ipynb,数据与更多示例见 dataset/huanhuan.json 与 examples/Chat-嬛嬛。

【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/datawhalechina/self-llm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 7:30:48

imx6 Yocto环境搭建实战:从主机准备到SD卡镜像生成

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 7:30:17

OpenClaw 模型返回 401?TaoToken 这样改 openclaw.json 的 baseUrl

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 7:29:33

WPF开发进阶:资源、样式与触发器深度解析

1. WPF UI开发核心三要素概述在桌面应用开发领域&#xff0c;WPF&#xff08;Windows Presentation Foundation&#xff09;始终保持着强大的生命力。作为.NET生态中最成熟的UI框架之一&#xff0c;其独特的资源系统与样式机制让界面开发效率产生质的飞跃。我经历过多个WPF大型…

作者头像 李华
网站建设 2026/9/19 7:27:05

FO开发环境搭建:VS2019版本锁定与Model创建避坑指南

1. 这不是“装个VS就能跑”的事&#xff1a;F&O开发者的第一个真实门槛Dynamics 365 Finance and Operations&#xff08;简称F&O&#xff09;的开发&#xff0c;从来就不是点开Visual Studio、新建一个项目、按F5就能跑通的轻量级体验。它是一套高度集成、强依赖、版本…

作者头像 李华
网站建设 2026/9/19 7:26:56

工控协议深度扫描:从Modbus TCP到S7comm的指纹识别实战

简介&#xff1a;一套聚焦工业互联网安全测试的PPT课件&#xff0c;系统讲解工控协议基础与扫描插件应用&#xff0c;面向工业控制系统安全测试人员、网络安全学习者及工业网络运维工程师。内容涵盖EPA现场总线标准、Ethernet/IP报文类型、Modbus TCP通信体系结构等关键协议&am…

作者头像 李华
网站建设 2026/9/19 7:26:19

移动端开发工具选型与跨平台技术实践指南

1. 移动端开发工具全景概览在智能手机普及率达到78%的今天&#xff0c;移动应用开发已成为技术领域的热门方向。作为一名经历过从原生开发到跨平台技术演进的老兵&#xff0c;我见证了开发工具从单一平台走向多元融合的完整历程。目前主流的移动端开发工具大致可分为三类&#…

作者头像 李华