
CharacterGLM-6B LoRA 微调实战基于 transformers 与 peft 打造个性化对话模型【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm导读本文基于开源项目《开源大模型食用指南》中 models/CharacterGLM 目录下的教程完整演示如何基于 transformers 与 peft 框架对清华大学 CoAI 实验室与聆心智能联合发布的 CharacterGLM-6B 对话模型进行 LoRA 微调。文章以甄嬛对话风格个性化角色为例从环境配置、指令集构建、数据格式化、LoRA 参数配置到模型训练、推理与重新加载全流程展开并结合仓库内的完整脚本与 Notebook 源码进行底层原理级剖析。读完本文你将掌握一套可直接复制运行的 LLM 指令微调流水线并能将任何开源 Chat 模型适配为具备特定人设的对话助手。一、任务背景为什么选择 LoRA 微调 CharacterGLM-6BCharacterGLM-6B 是由聆心智能和清华大学 CoAI 实验室联合发布的新一代对话预训练模型仓库中 models/CharacterGLM 目录完整收录了它的 Transformer 部署、FastAPI 部署、WebDemo 部署与 LoRA 微调全流程。模型权重约 12 GB可通过 ModelScope 的snapshot_download下载到本地参考 01-CharacterGLM-6B Transformer部署调用.md 与 03-CharacterGLM-6B-chat.md。对于 6B 量级的对话模型直接全参数微调成本极高。LoRALow-Rank Adaptation通过在冻结的原始权重旁插入低秩可训练矩阵将可训练参数量压缩到极低水平。在本仓库的实际运行记录中插入 LoRA 后模型可训练参数为1,949,696 个而全部参数为6,245,533,696 个可训练比例仅约0.0312%——这正是 LoRA 能以极小显存开销完成大模型领域微调的关键原因。本文微调不涉及分布式框架运行环境以 AutoDL 等提供 24G 显存显卡如 3090的 Linux 平台为基准。二、环境配置与依赖安装在完成基础环境配置Python 虚拟环境、CUDA 环境、模型已下载到本地的前提下还需要安装以下指定版本的第三方库pip install transformers4.37.2 pip install peft0.4.0.dev0 pip install datasets2.10.1 pip install accelerate0.21.0几点说明transformers提供AutoTokenizer、AutoModelForCausalLM、TrainingArguments、Trainer等核心组件peft提供LoraConfig、get_peft_model、PeftModel等 LoRA 实现组件datasets用于把微调数据集包装为Dataset对象并执行批量格式化映射accelerate为Trainer训练提供底层设备与显存管理支持。微调数据集放置于仓库根目录的 dataset/huanhuan.json该数据集共包含3729 条甄嬛风格的对话样本Notebook 运行记录显示num_rows: 3729结构为instruction/input/output三字段。仓库同时提供了 jsonl 与 JSON 两种格式见 dataset 目录。三、指令集构建让模型学会扮演甄嬛LLM 微调通常指指令微调Instruction Tuning。指令微调使用的数据形如{ instruction: 回答用户以下问题直接给出结果。, input: 中国第一个诺贝尔奖得主是谁, output: 莫言 }三个字段的含义instruction用户指令告知模型需要完成的任务input完成指令所必需的输入内容output模型应该给出的标准输出。核心训练目标是让模型具备理解并遵循用户指令的能力因此在构建指令集时必须针对目标任务设计专用数据。本教程的目标是构建一个能模拟甄嬛对话风格的个性化 LLM指令形式如下{ instruction: , input: 你是谁, output: 家父是大理寺少卿甄远道。 }从仓库 dataset/huanhuan.json 中可以直观看到这类语料的真实形态例如{ instruction: 娘娘。, input: , output: 你放心本宫到任何时候都不会自轻自贱委屈了这孩子。 }完整语料集与配套可训练脚本可在仓库的 examples/Chat-嬛嬛 项目中查看其训练脚本 train.py 展示了同一套人设扮演微调思路的完整落地。四、QA 与 Instruction 两种数据格式的区别和联系QAQuestion Answer是一问一答形式用户提问模型直接回答。而 Instruction 格式源自 Prompt Engineering把一次提问拆成两个部分——Instruction 描述任务Input 描述待处理对象。以请解释 INFJ 和 ENTP 两种 MBTI 性格之间的区别为例问答QA格式把完整问题直接作为输入——指令(instruction) 输入(input)INFJ和ENTP这两种MBTI性格之间的区别是什么指令Instruction格式把任务描述与处理对象分离——指令(Instruction)请解释下面两种MBTI性格的区别 输入(input)INFJ和ENTPQA 数据适合训练模型回答具体问题Instruction 数据则把任务意图显式剥离让模型学会泛化到同类任务。两种格式在数据层面可以互相转换实际微调中通常混合使用或统一为一种模板。五、数据格式化将文本编码为 input_ids 与 labelsLoRA 训练的数据必须先经过格式化与编码将输入文本编码为input_ids将输出文本编码为labels编码结果均为多维向量。核心预处理函数process_func如下完整版见 04-CharacterGLM-6B-Lora微调.pydef process_func(example): MAX_LENGTH 512 input_ids, labels [], [] prompt tokenizer.encode(用户:\n现在你要扮演皇帝身边的女人--甄嬛。, add_special_tokensFalse) instruction_ tokenizer.encode(\n.join([example[instruction], example[input]]).strip(), add_special_tokensFalse, max_length512) instruction tokenizer.encode(prompt instruction_) response tokenizer.encode(CharacterGLM-6B:\n: example[output], add_special_tokensFalse) input_ids instruction response [tokenizer.eos_token_id] labels [tokenizer.pad_token_id] * len(instruction) response [tokenizer.eos_token_id] pad_len MAX_LENGTH - len(input_ids) input_ids [tokenizer.pad_token_id] * pad_len labels [tokenizer.pad_token_id] * pad_len labels [(l if l ! tokenizer.pad_token_id else -100) for l in labels] return { input_ids: input_ids, labels: labels }逐段拆解这段逻辑拼接人设前缀将用户:\n 现在你要扮演皇帝身边的女人--甄嬛。编码为prompt这是注入模型的人设系统提示词编码指令与输入把instruction和input用换行拼接并strip()去空白后编码编码输出将CharacterGLM-6B:\n: output编码为response其中CharacterGLM-6B:是模型的回复标识符告诉模型该你说台词了拼接完整序列input_ids instruction response [eos_token_id]在序列末尾追加结束符构造 labels 对齐labels的前len(instruction)位用pad_token_id占位表示这些位置的输出不参与损失计算即只让模型学习回答部分response部分保留原文末尾追加eos_token_id长度对齐用pad_token_id把input_ids与labels都补齐到MAX_LENGTH 512关键一步将 labels 中的pad_token_id全部替换为-100这是因为 transformers 的损失函数在计算交叉熵时会自动忽略 label 为 -100 的位置从而确保模型只对回答部分求梯度。最终每条数据是一个包含input_ids和labels两个键的字典。Notebook04-CharacterGLM-6B-Lora微调.ipynb中验证了解码结果input_ids解码后为[gMASK] sop 用户:\n现在你要扮演皇帝身边的女人--甄嬛。 … CharacterGLM-6B:\n:你们俩话太多了…而过滤掉-100后的labels解码后恰好只剩CharacterGLM-6B:\n:你们俩话太多了…这一回答片段证明掩码逻辑正确生效。六、加载 tokenizer 与半精度模型模型以半精度torch.half即 fp16形式加载以节省显存若显卡较新也可改用torch.bfloat16。由于 CharacterGLM-6B 依赖仓库自带的自定义代码加载时必须指定trust_remote_codeTruetokenizer AutoTokenizer.from_pretrained(/root/autodl-tmp/THUCoAI/CharacterGLM-6B, use_fastFalse, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained(/root/autodl-tmp/THUCoAI/CharacterGLM-6B, trust_remote_codeTrue, torch_dtypetorch.half, device_mapauto)关于 CharacterGLM-6B 的 tokenizerNotebook 中的运行记录揭示了几个关键细节词表大小为64794padding_sideleft左侧填充适配对话生成场景truncation_siderighteos_token为/spad_token为unk额外注册了两个特殊 token[gMASK]id 64790与sopid 64792这正是 GLM 系列 Chat 模型对话模板的标志。tokenizer.get_command([gMASK])返回(64790, )。此外CharacterGLM 官方的对话模板为[Round {i}]\n\n用户{query}\n\nCharacterGLM-6B{response}\n\n见 Notebook 中的build_prompt函数这也是推理阶段拼装提示词时应遵循的格式。七、定义 LoraConfig 与 LoRA 缩放原理LoraConfig可配置的参数非常丰富核心参数如下参数含义task_type模型任务类型对话模型使用TaskType.CAUSAL_LMtarget_modules需要插入 LoRA 的层名主要是 attention 部分不同模型层名不同可传数组、字符串或正则表达式rLoRA 的秩rank决定低秩矩阵的宽度lora_alphaLoRA 的缩放系数lora_dropoutLoRA 层的 dropout 概率用于缓解过拟合modules_to_save除拆成 LoRA 的模块外其它需要完整训练的模块名本教程使用的配置config LoraConfig( task_typeTaskType.CAUSAL_LM, target_modules[query_key_value], inference_modeFalse, r8, lora_alpha32, lora_dropout0.1 )要点解读target_modules的选择CharacterGLM-6B 沿用了 ChatGLM 系列的注意力结构其 QKV 融合在一个名为query_key_value的层中因此这里指向该层。Notebook 中特别提到target_modules也可传正则表达式例如..1.query_key_value可匹配以h.1结尾的query_key_value层实现按层号精细控制modules_to_save指定除 LoRA 化之外的、仍需完整训练非低秩分解的模块例如需要整体适配的自定义输出层缩放比例LoRA 的缩放方式为lora_alpha / r本例中32 / 8 4即缩放 4 倍。需要强调这个缩放并不改变 LoRA 的参数量本质是把参数值做广播乘法、进行线性缩放从而稳定训练过程。在 .py 脚本中配置创建后通过model get_peft_model(model, config)将 LoRA 结构注入冻结的基座模型。Notebook 中打印出的完整LoraConfig对象还展示了fan_in_fan_outFalse、biasnone、init_lora_weightsTrue等默认值说明 peft 默认不训练偏置、并采用随机初始化 LoRA 权重。八、自定义 TrainingArguments 参数TrainingArguments是Trainer训练循环的配置中心其源码对每个参数都有详细说明。常用参数如下output_dir模型与 checkpoint 的输出路径per_device_train_batch_size单卡 batch sizegradient_accumulation_steps梯度累积步数。显存较小时可调小 batch size、调大累积步数等效扩大 batchlogging_steps每多少步输出一次训练日志num_train_epochs训练轮数gradient_checkpointing梯度检查点。一旦开启模型必须执行model.enable_input_require_grads()否则反向传播会因输入缺少梯度而报错save_steps每多少步保存一次 checkpointlearning_rate学习率。同时还需要配置与序列标注/生成任务配套的DataCollatorForSeq2Seq保证 batch 内序列长度对齐且 labels 的填充位为-100data_collator DataCollatorForSeq2Seq( tokenizer, modelmodel, label_pad_token_id-100, pad_to_multiple_ofNone, paddingFalse ) args TrainingArguments( output_dir./output/CharacterGLM, per_device_train_batch_size4, gradient_accumulation_steps2, logging_steps10, num_train_epochs3, gradient_checkpointingTrue, save_steps100, learning_rate1e-4, )仓库中的实际可运行脚本 04-CharacterGLM-6B-Lora微调.py 采用了更适合单卡 24G 显存的参数组合per_device_train_batch_size1、gradient_accumulation_steps8、logging_steps20、num_train_epochs1效果上等效于 batch size 8。Notebook 中的训练记录显示单 epoch 共 466 个训练步训练 loss 从第 20 步的5.751稳步下降至第 460 步的2.238左右最终平均训练损失约2.62验证了参数配置的合理性。九、使用 Trainer 启动训练将模型、训练参数与格式化后的数据集一并交给Trainer即可开始训练trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatordata_collator, ) trainer.train()其中tokenized_id即ds.map(process_func, remove_columnsds.column_names)的输出。在 .py 脚本中数据集的加载与映射流程为df pd.read_json(../../dataset/huanhuan.json) ds Dataset.from_pandas(df) tokenized_ds ds.map(process_func, remove_columnsds.column_names)即先用 pandas 读取 JSON转为 Hugging FaceDataset再对每条样本执行process_func并移除原始列最终得到仅含input_ids与labels的训练集。训练完成后checkpoint 会按save_steps间隔写入output_dir。十、微调后模型推理训练完成、LoRA 权重已在内存中与模型结合可直接进行推理验证model model.cuda() ipt tokenizer(用户{}\n{}.format(现在你要扮演皇帝身边的女人--甄嬛。你是谁, ).strip() characterGLM-6B:\n, return_tensorspt).to(model.device) tokenizer.decode(model.generate(**ipt, max_length128, do_sampleTrue)[0], skip_special_tokensTrue)注意提示词需要同时包含人设引导与问题现在你要扮演皇帝身边的女人--甄嬛。你是谁并以characterGLM-6B:\n结尾把话语权交给模型。Notebook 的真实推理结果为[gMASK] sop 用户现在你要扮演皇帝身边的女人--甄嬛。你是谁characterGLM-6B:\n我是甄嬛是陛下的嫔妃。模型已经能以甄嬛的口吻作答说明微调成功。十一、重新加载微调后的模型PeftModel通过 PEFT 微调产出的模型只保存了 LoRA 增量参数随时可以用如下方式重新加载并推理加载原始 base model 与 tokenizer用PeftModel.from_pretrained把原始模型与 PEFT 微调参数合并。from peft import PeftModel model AutoModelForCausalLM.from_pretrained( /root/autodl-tmp/THUCoAI/CharacterGLM-6B, trust_remote_codeTrue, low_cpu_mem_usageTrue ) tokenizer AutoTokenizer.from_pretrained( /root/autodl-tmp/THUCoAI/CharacterGLM-6B, use_fastFalse, trust_remote_codeTrue ) p_model PeftModel.from_pretrained(model, model_id./output/CharacterGLM/checkpoint-1000/) ipt tokenizer(用户{}\n{}.format(现在你要扮演皇帝身边的女人--甄嬛。你是谁, ).strip() characterGLM-6B:\n, return_tensorspt).to(model.device) tokenizer.decode(p_model.generate(**ipt, max_length128, do_sampleTrue)[0], skip_special_tokensTrue)几个实践要点model_id指向训练时保存的 checkpoint 目录如./output/CharacterGLM/checkpoint-1000/目录内包含adapter_config.json与adapter_model.bin若希望把 LoRA 增量真正合回原权重、生成完整模型可使用p_model.merge_and_unload()从源码结构看由于 LoRA 只增加了约 195 万可训练参数checkpoint 体积远小于原始 12 GB 权重便于分发与部署。十二、完整实战路径回顾与注意事项从零到一的完整链路租用 24G 显存机器如 AutoDL 3090镜像选择 PyTorch 2.0.0 / Python 3.8 / CUDA 11.8用 ModelScopesnapshot_download(THUCoAI/CharacterGLM-6B, cache_dir/root/autodl-tmp)下载约 12 GB 模型权重下载约需 10~15 分钟按第二节安装transformers、peft、datasets、accelerate指定版本准备instruction/input/output三字段指令集参考 dataset/huanhuan.json定义process_func完成编码与 labels 掩码半精度加载模型 → 配置LoraConfig→get_peft_model注入 LoRA → 配置TrainingArguments与DataCollatorForSeq2Seq→Trainer.train()推理验证 → 用PeftModel.from_pretrained重新加载 checkpoint 复用。核心注意事项显存需求不使用分布式框架时微调 CharacterGLM-6B 至少需要21G 及以上显存显存紧张时优先调小per_device_train_batch_size并增大gradient_accumulation_steps必须修改路径运行前需将脚本中的模型路径/root/autodl-tmp/THUCoAI/CharacterGLM-6B与数据集路径../../dataset/huanhuan.json改为自己的实际路径trust_remote_codeTrue不可省略CharacterGLM-6B 依赖远程自定义模型代码自定义模型加载时该参数必须为 True开启gradient_checkpointing必须配套model.enable_input_require_grads()否则反向传播会失败labels 中 -100 的约定所有填充位必须映射为 -100训练损失才会只针对回答部分计算对话模板一致性训练时使用的用户:\n...CharacterGLM-6B:\n拼接格式与推理时的提示词格式必须保持一致模型才能正确理解轮到自己发言。以上完整代码可直接参考仓库中的 04-CharacterGLM-6B-Lora微调.py可独立运行的脚本版与 04-CharacterGLM-6B-Lora微调.ipynb带真实运行输出的 Notebook 版。掌握这套流程后你可以用同样的方法为任意开源对话模型注入任意人设、领域知识与任务能力。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考