DeepSeek-Coder-V2-Lite-Instruct LoRA 微调实战:基于 transformers 与 peft 打造甄嬛风格对话模型

📅 发布时间:2026/9/11 21:32:10
DeepSeek-Coder-V2-Lite-Instruct LoRA 微调实战:基于 transformers 与 peft 打造甄嬛风格对话模型
DeepSeek-Coder-V2-Lite-Instruct LoRA 微调实战基于 transformers 与 peft 打造甄嬛风格对话模型【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm本文基于《开源大模型食用指南》仓库self-llm中的 DeepSeek-Coder-V2-Lite-Instruct LoRA 微调教程系统讲解如何利用transformers、peft、datasets等框架对 DeepSeek-Coder-V2-Lite-Instruct 进行 LoRA 高效微调并以甄嬛对话语料为例完整走通「指令集构建 → 数据格式化 → 半精度/全精度加载 → LoRA 配置 → Trainer 训练 → 加载 LoRA 权重推理」的端到端流程。读者读完本文后将掌握 MoE 架构代码模型的 LoRA 微调全链路实操能力能够迁移到其他开源模型的个性化对话微调场景。一、准备工作硬件要求与基础环境1.1 硬件与软件环境微调 DeepSeek-Coder-V2-Lite-Instruct 这类 15B 级 MoE 模型对显存要求较高教程作者实测需要4×309024GB显卡。本文基础环境如下---------------- ubuntu 22.04 python 3.12 cuda 12.1 pytorch 2.3.0 ----------------本文默认学习者已安装好以上 Pytorch(cuda) 环境如未安装请自行安装。1.2 依赖安装pip换源加速下载并安装依赖包为保证与教程以及配套 notebook行为一致所有关键库均锁定版本python -m pip install --upgrade pip # 更换 pypi 源加速库的安装 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install modelscope1.16.1 pip install transformers4.43.2 pip install accelerate0.32.1 pip install peft0.11.1 pip install datasets2.20.0注意flash-attn 安装会比较慢大概需要十几分钟请耐心等待。仓库为该模型在 AutoDL 平台准备了开箱即用的环境镜像遇到环境配置困难的学习者可以直接基于该镜像创建实例跳过依赖安装环节。在正式开始前可以先浏览同目录下的 notebook 版本它与本文内容一一对应每一步都保留了真实运行输出适合逐格运行加深理解。二、模型下载使用 modelscope 拉取权重使用modelscope中的snapshot_download函数下载模型。第一个参数为模型名称参数cache_dir为自定义的模型下载路径参数revision为模型仓库分支版本master代表主分支也是一般模型上传的默认分支。先切换到autodl-tmp目录cd /root/autodl-tmp然后新建名为model_download.py的 Python 文件输入以下内容并保存# model_download.py import torch from modelscope import snapshot_download, AutoModel, AutoTokenizer model_dir snapshot_download(deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct, cache_dir/root/autodl-tmp, revisionmaster)在终端中执行python model_download.py注意该模型权重文件较大需要耐心等待一段时间直到模型下载完成同时记得把cache_dir修改为自己的模型下载路径。关于模型下载的通用机制如魔搭下载、HF 下载等可进一步参考仓库中的 通用模型下载说明。三、指令集构建理解 instruction / input / output 三要素LLM 的微调一般指指令微调过程。所谓指令微调是指我们使用的微调数据形如{ instruction: 回答以下用户问题仅输出答案。, input: 11等于几?, output: 2 }其中instruction用户指令告知模型其需要完成的任务input用户输入是完成用户指令所必须的输入内容output模型应该给出的输出。核心训练目标是让模型具备理解并遵循用户指令的能力。因此在指令集构建时应针对目标任务针对性构建任务指令集。例如本节采用甄嬛对话风格项目作为示例目标是构建一个能够模拟甄嬛对话风格的个性化 LLM因此构造的指令形如{ instruction: 你是谁, input: , output: 家父是大理寺少卿甄远道。 }本教程所使用的全部指令数据集位于仓库根目录下 dataset/huanhuan.json。此外仓库还提供了多种形态的同一份数据dataset/huanhuan.jsonl每行一条 JSON 的 JSONL 格式共 3729 条与 notebook 训练时num_rows: 3729完全对应dataset/huanhuan-100.json抽取 100 条的小样本版本适合先跑通流程、快速验证数据管道与训练链路是否正确。该数据集的构建与使用源自仓库中的 Chat-嬛嬛 示例项目其中 train.py 还提供了可直接运行的训练脚本供参考。四、数据格式化对齐 DeepSeek-Coder-V2 的对话模板LoRA 训练的数据需要经过格式化、编码之后再输入给模型。熟悉 PyTorch 训练流程的同学会知道我们一般需要将输入文本编码为input_ids将输出文本编码为labels编码后的结果都是多维向量。首先定义一个预处理函数process_func对每一个样本编码其输入、输出文本并返回编码后的字典def process_func(example): MAX_LENGTH 384 input_ids, attention_mask, labels [], [], [] instruction tokenizer((fbegin▁of▁sentence假设你是皇帝身边的女人--甄嬛。\n fUser: {example[instruction]example[input]}\nAssistant: ).strip(), add_special_tokensFalse) response tokenizer(f{example[output]}end▁of▁sentence, add_special_tokensFalse) 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-Coder-V2-Lite-Instruct 采用的 Prompt Template 格式如下begin▁of▁sentence{system_message} User: {user_message_1} Assistant: {assistant_message_1}end▁of▁sentenceUser: {user_message_2} Assistant:注意User:、Assistant:前缀与句子边界符begin▁of▁sentence、end▁of▁sentence都是模板的固定组成部分训练数据的拼接必须严格对齐该格式否则模型在推理时将无法正确理解输入结构。labels 掩码指令instruction部分的 token 对应 label 全部置为-100这样在计算损失时这些位置会被忽略模型只学习「Assistant 回答部分」的生成回答部分则直接使用response[input_ids]作为标签。截断设置MAX_LENGTH 384超出部分直接切片截断防止超长样本撑爆显存。padding 对齐序列尾部补tokenizer.pad_token_idattention mask 对应补1因为 eos token 也是要关注的。在 notebook 中数据先通过pandas读取 JSON 并转为datasets.Dataset再执行mapfrom datasets import Dataset import pandas as pd df pd.read_json(huanhuan.json) ds Dataset.from_pandas(df) tokenized_id ds.map(process_func, remove_columnsds.column_names) tokenized_id运行后得到Dataset({features: [input_ids, attention_mask, labels], num_rows: 3729})说明 3729 条甄嬛语料全部完成格式化。解码第一个样本可以看到拼接效果begin▁of▁sentence假设你是皇帝身边的女人--甄嬛。 User: 小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的—— Assistant:嘘——都说许愿说破是不灵的。end▁of▁sentenceend▁of▁sentence输出中出现两个end▁of▁sentence是因为该模型 tokenizer 的pad_token_id与eos_token_id均为100001notebook 中验证输出(100001, 100001)且tokenizer.eos_token为end▁of▁sentencepadding token 与 eos token 指向同一个 id属于该模型实现上的正常现象。五、加载 tokenizer 与模型指定 32 位精度与 trust_remote_codeDeepSeek-Coder-V2-Lite-Instruct 属于使用自定义代码实现的模型加载时必须指定trust_remote_codeTrue同时原文档强调该模型需要以32 位精度torch.float32形式加载model_path /root/autodl-tmp/deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct tokenizer AutoTokenizer.from_pretrained(model_path, use_fastFalse, trust_remote_codeTrue) tokenizer.padding_side right model AutoModelForCausalLM.from_pretrained(model_path, trust_remote_codeTrue, torch_dtypetorch.float32, device_mapauto)要点说明use_fastFalse使用慢速 tokenizer原生实现避免与自定义特殊 token 处理不一致tokenizer.padding_side right右侧 padding与自回归语言模型的训练范式匹配device_mapauto由 accelerate 自动将模型分配到所有可用 GPU这正是 4×3090 多卡场景下的标准用法。从 notebook 打印的模型结构可以看到节选关键部分这是一个基于 DeepSeek-V2 架构的代码大模型DeepseekV2ForCausalLM( (model): DeepseekV2Model( (embed_tokens): Embedding(102400, 2048) (layers): ModuleList( (0): DeepseekV2DecoderLayer( # 第 0 层为 Dense 注意力 (self_attn): DeepseekV2Attention( (q_proj): Linear(in_features2048, out_features3072, biasFalse) (kv_a_proj_with_mqa): Linear(in_features2048, out_features576, biasFalse) (kv_a_layernorm): DeepseekV2RMSNorm() (kv_b_proj): Linear(in_features512, out_features4096, biasFalse) (o_proj): Linear(in_features2048, out_features2048, biasFalse) (rotary_emb): DeepseekV2YarnRotaryEmbedding() ) ... ) (1-26): 26 x DeepseekV2DecoderLayer( # 第 1~26 层为 MoE (mlp): DeepseekV2MoE( (experts): ModuleList((0-63): 64 x DeepseekV2MLP(...)) # 64 个专家 (gate): MoEGate() (shared_experts): DeepseekV2MLP(...) # 共享专家 ) ... ) ) ) )从模块命名与维度可以推断出该模型的两大架构特点MLAMulti-head Latent Attention低秩注意力注意力模块中的kv_a_proj_with_mqa2048→576先将 KV 压缩到低维潜在空间kv_b_proj512→4096再投影回多头维度实现「压缩存储、推理时升维」大幅降低 KV Cache 开销这一点与 DeepSeek-V2 系列公开的技术路线一致。MoE 混合专家除第 0 层使用 Dense MLP 外第 1~26 层均为 DeepseekV2MoE每个 MoE 层内置 64 个专家专家内 FFN 维度 2048→1408 1 组共享专家2048→2816由MoEGate路由选择激活。词表 102400、隐藏层 2048 等维度信息也清晰可查。理解这些结构信息直接关系到下一节target_modules的选择LoRA 需要挂载的正是这些注意力与 MLP 投影层。六、定义 LoraConfigtarget_modules 与缩放比例LoraConfig中可以设置很多参数但主要的参数不多简单说明如下参数含义本教程取值task_type模型类型TaskType.CAUSAL_LM因果语言模型target_modules需要训练的模型层名字主要是 attention 与 MLP 的投影层可传数组、字符串或正则表达式[q_proj, kv_a_proj_with_mqa, kv_b_proj, o_proj, gate_proj, up_proj, down_proj]rLoRA 的秩决定低秩矩阵的宽度8lora_alphaLoRA 的缩放系数 alpha32lora_dropoutDropout 比例用于抑制过拟合0.1config LoraConfig( task_typeTaskType.CAUSAL_LM, target_modules[q_proj, kv_a_proj_with_mqa, kv_b_proj, o_proj, gate_proj, up_proj, down_proj], # 考虑到显存限制只微调部分层即可完成演示 inference_modeFalse, # 训练模式 r8, # Lora 秩 lora_alpha32, # Lora alaph具体作用参见 Lora 原理 lora_dropout0.1# Dropout 比例 )需要特别澄清一个常见误区LoRA 的缩放不是r秩而是lora_alpha / r。在本配置中缩放系数为32 / 8 4倍即低秩分支B×A的输出在注入原权重前会放大 4 倍用于控制微调强度与训练稳定性。target_modules中 7 个模块与第五节模型结构一一对应注意力侧q_projQ 投影、kv_a_proj_with_mqaMLA 压缩投影、kv_b_projMLA 解压投影、o_proj输出投影MLP 侧gate_proj、up_proj、down_proj。由于 MoE 层的专家内部同样由这三个投影组成LoRA 挂载后会在所有 64 个专家及共享专家上生效。peft 支持直接传模块名数组会自动在每一层同名模块上插入适配器。使用get_peft_model包装后可以打印可训练参数统计from peft import LoraConfig, TaskType, get_peft_model model get_peft_model(model, config) model.print_trainable_parameters()输出trainable params: 144,918,528 || all params: 15,851,402,752 || trainable%: 0.9142即模型总参数量约 158.5 亿而 LoRA 实际只训练约 1.45 亿参数可训练比例仅 0.9142%——这正是「高效微调」的直观体现绝大部分权重被冻结仅训练极少量低秩适配器即可完成领域迁移。七、自定义 TrainingArguments 与 Trainer 训练TrainingArguments的源码详细介绍了每个参数的作用这里说明几个常用的关键参数参数含义本教程取值output_dir模型的输出路径./output/deepseek_coder_v2per_device_train_batch_size单卡 batch size1gradient_accumulation_steps梯度累加步数显存较小时可调小 batch_size、调大梯度累加8logging_steps多少步输出一次 log10num_train_epochs训练轮数epoch2save_steps多少步保存一次 checkpoint100learning_rate学习率1e-5save_on_each_node多节点场景下每个节点都保存Truegradient_checkpointing梯度检查点用计算换显存开启后必须执行model.enable_input_require_grads()Trueargs TrainingArguments( output_dir./output/deepseek_coder_v2, per_device_train_batch_size1, gradient_accumulation_steps8, logging_steps10, num_train_epochs2, save_steps100, learning_rate1e-5, save_on_each_nodeTrue, gradient_checkpointingTrue, )梯度检查点与enable_input_require_grads开启gradient_checkpointing后模型需要在前向传播中保存中间激活用于反向计算此时必须调用model.enable_input_require_grads()为输入张量开启梯度需求否则反向传播会因缺少输入梯度而报错。这正是 notebook 中在加载模型后立即执行model.enable_input_require_grads()的原因。同时训练日志中会出现提示use_cacheTrue与梯度检查点不兼容Trainer 会自动将其置为False这是正常行为。训练逻辑本身非常简洁直接交给Trainer完成trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue), ) trainer.train()其中DataCollatorForSeq2Seq负责在 batch 内按最长序列动态 padding 并对齐 labels。从 notebook 的训练进度条可以看到总训练步数932 步3729 条样本 ÷ 8 梯度累加 ≈ 466 步/epoch × 2 epoch每 10 步输出一次 loss训练初期 loss 从9.1272逐步下降到8.5629整体呈稳定下降趋势说明模型正在学习甄嬛语料的分布。由于模型参数量大完成全部教程代码训练需要10 小时左右4×3090 实测。如果只是学习使用方法看到 loss 下降即可提前停止训练不必跑完全部 epoch。八、加载 LoRA 权重推理训练完成后使用PeftModel.from_pretrained将 LoRA 适配器挂载回基础模型即可推理from transformers import AutoModelForCausalLM, AutoTokenizer import torch from peft import PeftModel model_path /root/autodl-tmp/deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct lora_path ./output/deepseek_coder_v2 # 加载tokenizer tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) # 加载模型推理阶段可使用 bf16 精度以节省显存 model AutoModelForCausalLM.from_pretrained(model_path, device_mapauto, torch_dtypetorch.bfloat16, trust_remote_codeTrue).eval() # 加载lora权重 model PeftModel.from_pretrained(model, model_idlora_path) messages[ {role: system, content: 假设你是皇帝身边的女人--甄嬛。}, {role: user, content: 你好} ] inputs tokenizer.apply_chat_template(messages, add_generation_promptTrue, return_tensorspt).to(model.device) outputs model.generate(inputs, max_new_tokens512, do_sampleFalse, top_k50, top_p0.95, num_return_sequences1, eos_token_idtokenizer.eos_token_id) print(tokenizer.decode(outputs[0][len(inputs[0]):], skip_special_tokensTrue))几个实操要点精度选择训练阶段按原文档要求以float32加载推理阶段改用bfloat16在保证数值稳定的同时显著降低显存占用notebook 中 10 个 checkpoint shard 加载即为此场景。chat 模板推理时用apply_chat_template自动将messages渲染成模型训练时一致的 Prompt 格式并传入add_generation_promptTrue在末尾追加Assistant:从而触发续写。生成参数max_new_tokens512限制最大生成长度do_sampleFalse采用贪心解码top_k50、top_p0.95作为采样约束eos_token_id明确指定结束符避免越界生成。原文档中的role: sysrem属于笔误本文已修正为规范的system。notebook 中的实际推理输出为我是甄嬛家父是大理寺少卿甄远道。模型已经学会了以甄嬛的身份与口吻回答用户问题说明 LoRA 微调成功地将「甄嬛人设」注入了 DeepSeek-Coder-V2-Lite-Instruct 中。九、常见问题与调参建议显存不足怎么办优先调小per_device_train_batch_size并等比调大gradient_accumulation_steps保证总 batch 不变其次开启gradient_checkpointing并记得调用model.enable_input_require_grads()若仍不足可考虑target_modules只保留q_proj、o_proj等注意力层减少挂载的适配器数量。为什么必须trust_remote_codeTrueDeepSeek-Coder-V2 的模型结构MLA、MoE、自定义 tokenizer由远端代码仓库提供不信任远端代码则无法加载其自定义实现加载与训练阶段都必须开启。训练 loss 不下降怎么办先确认数据格式化是否正确——用tokenizer.decode(tokenized_id[0][input_ids])检查拼接结果是否包含完整的User:/Assistant:模板再确认labels中-100掩码是否只覆盖了指令部分可用tokenizer.decode(list(filter(lambda x: x ! -100, labels)))验证解码结果恰好是回答文本。如何迁移到自己的数据集只需把process_func中的instruction/input/output字段替换为你自己数据集的字段名并按目标人设修改 system prompt 文案即可训练与推理代码无需任何改动。训练时间太长学习使用阶段看到 loss 稳定下降即可CtrlC提前终止或使用 100 条小样本的 dataset/huanhuan-100.json 先验证整条流水线再切换到完整语料正式训练。结语本文完整复现了 DeepSeek-Coder-V2-Lite-Instruct 的 LoRA 微调全流程从环境搭建、模型下载、指令集构建、数据格式化到 LoraConfig / TrainingArguments 配置、Trainer 训练与 PeftModel 推理。结合 notebook 的逐格运行输出你可以零成本验证每一步的正确性。掌握这套流程后无论是复刻甄嬛对话风格还是构建其他垂直领域代码、医疗、法律等的个性化助手都可以在同一套框架下快速落地。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考