从零开始:Qwen3.5-4B 大模型 LoRA 微调实战教程

从零开始:Qwen3.5-4B 大模型 LoRA 微调实战教程
从零开始Qwen3.5-4B 大模型 LoRA 微调实战教程本文手把手带你完成大模型微调全流程模型下载 → 数据准备 → LoRA 微调 → 推理测试。零基础也能看懂目录项目背景环境准备第一步下载基础模型第二步准备训练数据第三步数据预处理Tokenization第四步LoRA 微调训练第五步加载微调模型并推理完整项目文件结构常见问题FAQ1. 项目背景我们要做什么用简历评分数据来微调Qwen3.5-4B大模型让它学会根据工作经历给出专业的评分和建议。什么是大模型微调想象一个场景你有一个很聪明的大学毕业生基础模型他什么都懂一点但遇到专业问题比如给简历打分就不够精准。微调就是给这个毕业生做岗前培训——用专业数据训练他让他成为某个领域的专家。什么是 LoRALoRALow-Rank Adaptation低秩适配是一种高效的微调技术。打个比方全量微调把整本书每个字都重新写一遍消耗巨大LoRA 微调只在不重要的页码上贴便利贴做笔记轻量高效LoRA 的优点是训练速度快显存占用低本文的 4B 模型10GB 左右显存就能跑微调后的增量文件只有几 MB原始模型 8GB硬件要求配置最低要求推荐配置GPU 显存8GB16GB内存16GB32GB硬盘20GB50GB2. 环境准备安装必要的 Python 库pipinstalltorch transformers datasets peft modelscope swanlab各库的作用库名作用torchPyTorch 深度学习框架transformersHuggingFace 模型库加载 Qwen 模型datasets数据处理工具peftLoRA 微调的核心库modelscope国内模型下载魔搭社区swanlab训练过程可视化工具可选3. 第一步下载基础模型对应文件model_download.pyfrommodelscopeimportsnapshot_download model_dirsnapshot_download(Qwen/Qwen3.5-4B,cache_dir./模型微调)print(f模型下载完毕保存位置在{model_dir})代码解读snapshot_download是 ModelScope魔搭社区提供的下载工具Qwen/Qwen3.5-4B是模型名称——Qwen3.5 系列参数量 40 亿4Bcache_dir./模型微调指定下载到哪个文件夹下载完成后模型会保存在./模型微调/Qwen/Qwen3___5-4B/目录下下载了什么Qwen3___5-4B/ ├── config.json # 模型配置多少层、隐藏层大小等 ├── model.safetensors-xxx # 模型权重文件约 8GB ├── tokenizer.json # 分词器 ├── tokenizer_config.json # 分词器配置 ├── chat_template.jinja # 对话模板 ├── vocab.json / merges.txt # 词表文件 └── ...注意.safetensors是一种安全的模型存储格式比旧的.bin格式更快更安全。4. 第二步准备训练数据数据格式我们的训练数据是 JSON 格式每行一条记录放在data/llm_resume_scoring.json中{question:{工作时间:2015.06-2020.12,工作内容:1、负责公司ERP系统的需求分析和功能设计...,职务:IT项目经理,工作单位:上海信息科技有限公司},answer:技术能力8分, 解释候选人成功完成了ERP系统需求分析...}数据解读每条数据包含两部分question问题一份工作经历包含时间、工作内容、职务、工作单位answer答案对该工作经历的评分和详细评价这就是问答对格式——相当于我们给模型看标准答案让它学会如何评分。数据预处理代码对应文件p2.pyimportjsonfromdatasetsimportDatasetfromtransformersimportAutoTokenizer# 1. 加载分词器tokenizerAutoTokenizer.from_pretrained(./模型微调/Qwen/Qwen3___5-4B)# 2. 读取数据data[]withopen(./data/llm_resume_scoring.json,r,encodingUTF-8)asf:forlineinf:lineline.strip()ifline:data.append(json.loads(line))# 3. 转为 Dataset 格式dsDataset.from_list(data)什么是 Tokenization模型不能直接理解中文文字需要把文字转换成数字——这个过程叫Tokenization分词编码。我是程序员 → [1234, 5678, 9012] # 每个数字代表一个 token处理函数详解defprocess_func(example):MAX_LENGTH512SYS给定一个候选人的工作经历信息你需要针对每个职位进行综合评分...messages[{role:system,content:SYS},{role:user,content:json.dumps(example[question],ensure_asciiFalse)},{role:assistant,content:json.dumps(example[answer],ensure_asciiFalse)}]# prompt 部分 system user模型应该看到的输入prompt_idstokenizer.apply_chat_template(messages[:2],tokenizeTrue,add_generation_promptTrue)# full system user assistant完整的对话full_idstokenizer.apply_chat_template(messages,tokenizeTrue,add_generation_promptFalse)# response_ids assistant 的回答部分response_idsfull_ids[len(prompt_ids):]# labelsprompt 部分设为 -100不计算损失只对回答部分计算损失input_idsprompt_idsresponse_ids labels[-100]*len(prompt_ids)response_ids# 截断到最大长度iflen(input_ids)MAX_LENGTH:input_idsinput_ids[:MAX_LENGTH]labelslabels[:MAX_LENGTH]return{input_ids:input_ids,attention_mask:[1]*len(input_ids),labels:labels}关键概念——为什么 prompt 的 label 设为 -100在训练大模型时labels控制模型在哪些位置学习输入部分system user→ labels -100 → 不学习只是上下文 输出部分assistant → labels 真实值 → 学习模型要预测这些就像老师告诉你“前面的话是题目最后那句话才是你要学会写的答案。”5. 第三步数据预处理Tokenization对应文件p2.py与上一步合并# 对所有数据进行 tokenizationtokenized_idds.map(process_func,remove_columnsds.column_names)# 查看处理后第一条数据的实际内容print(tokenizer.decode(tokenized_id[0][input_ids]))执行ds.map(process_func)会让process_func函数对每一条数据都执行一遍把原始文本全部转换成数字 ID。6. 第四步LoRA 微调训练对应文件p3.py这是整个项目最核心的部分。我们来看完整的训练代码6.1 加载基础模型importtorchfromtransformersimportAutoModelForCausalLM,AutoTokenizer modelAutoModelForCausalLM.from_pretrained(./模型微调/Qwen/Qwen3___5-4B,dtypetorch.bfloat16,# 使用 bfloat16 精度节省一半显存device_mapcuda,# 自动分配到 GPU)tokenizerAutoTokenizer.from_pretrained(./模型微调/Qwen/Qwen3___5-4B)知识点bfloat1616 位浮点数格式比 32 位节省一半显存精度损失很小device_mapcuda把模型放到 GPU 上推理速度提升 10-100 倍6.2 配置 LoRAfrompeftimportLoraConfig,TaskType,get_peft_model configLoraConfig(task_typeTaskType.CAUSAL_LM,# 因果语言模型任务target_modules[# 要对哪些层做 LoRAq_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj],inference_modeFalse,# 训练模式r8,# LoRA 秩ranklora_alpha32,# LoRA 缩放系数lora_dropout0.1,# Dropout 防止过拟合)modelget_peft_model(model,config)model.print_trainable_parameters()LoRA 参数详解参数含义建议值rLoRA 的秩越大能力越强但也越慢4~16lora_alpha缩放系数通常是 r 的 2~4 倍16~64lora_dropout随机丢弃比例防止过拟合0.05~0.1target_modules要微调的层Qwen 模型用这 7 个全选LoRA 的工作原理简单版模型中的权重矩阵是 4096×4096 的大矩阵全量微调要更新所有 4096×40961600 万个参数。LoRA 把这个大更新拆成两个小矩阵的乘积比如 4096×8 和 8×4096只需要更新 4096×8×265000 个参数——相当于只更新原来的0.4%6.3 配置训练参数fromtransformersimportTrainingArguments argsTrainingArguments(output_dir./output/Qwen3_5_LoRA,# 训练结果保存位置per_device_train_batch_size4,# 每 GPU 批次大小gradient_accumulation_steps6,# 梯度累积等效 batch_size24gradient_checkpointingTrue,# 节省显存logging_steps10,# 每 10 步打印日志num_train_epochs3,# 训练 3 轮save_steps100,# 每 100 步保存一次learning_rate1e-4,# 学习率bf16True,# bfloat16 加速report_tonone,# 不上报训练日志)训练参数详解参数含义为什么这样设per_device_train_batch_size4每步处理 4 条数据显存有限不能太大gradient_accumulation_steps6累积 6 步再更新等效 batch_size4×624训练更稳定gradient_checkpointingTrue用时间换空间可以节省约 40% 显存num_train_epochs3重复训练 3 遍太少没学会太多会背答案learning_rate1e-4学习率 0.0001LoRA 常用值收敛平稳save_steps100每 100 步存一次可以随时恢复训练6.4 开始训练fromtransformersimportTrainer,DataCollatorForSeq2Seq trainerTrainer(modelmodel,argsargs,train_datasettokenized_id,data_collatorDataCollatorForSeq2Seq(tokenizertokenizer,paddingTrue),)trainer.train()Trainer是 HuggingFace 提供的一键训练器它会自动处理前向传播模型计算预测结果计算损失预测与实际差多少反向传播根据差距调整参数梯度累积和优化6.5 训练完成后训练完成后output/Qwen3_5_LoRA/checkpoint-198/目录下会出现checkpoint-198/ ├── adapter_config.json # LoRA 配置 ├── adapter_model.safetensors # LoRA 增量权重几 MB ├── optimizer.pt # 优化器状态 ├── trainer_state.json # 训练状态 └── ...最关键的只有两个文件adapter_config.json和adapter_model.safetensors加起来通常只有几 MB。7. 第五步加载微调模型并推理对应文件p4.pyfromtransformersimportAutoModelForCausalLM,AutoTokenizerfrompeftimportPeftModelimporttorch# 1. 加载基础模型和分词器model_id./模型微调/Qwen/Qwen3___5-4Blora_path./output/Qwen3_5_LoRA/checkpoint-198tokenizerAutoTokenizer.from_pretrained(model_id)modelAutoModelForCausalLM.from_pretrained(model_id,dtypetorch.bfloat16,device_mapcuda)# 2. 加载 LoRA 增量权重modelPeftModel.from_pretrained(model,model_idlora_path)model.eval()# 3. 构造测试问题messages[{role:system,content:你是一个专业的HR面试官请根据候选人的工作经历给出客观评分和详细建议。},{role:user,content:候选人工作经历工作时间 2015.06-2020.12职务 IT项目经理...}]# 4. 编码输入inputstokenizer.apply_chat_template(messages,add_generation_promptTrue,tokenizeTrue,return_tensorspt,).to(model.device)# 5. 生成回复gen_kwargs{max_new_tokens:1024,do_sample:True,top_p:0.8,temperature:0.7}withtorch.no_grad():outputsmodel.generate(**inputs,**gen_kwargs)# 6. 解码输出outputsoutputs[:,inputs[input_ids].shape[1]:]print(tokenizer.decode(outputs[0],skip_special_tokensTrue))代码解读加载 LoRA 权重modelPeftModel.from_pretrained(model,model_idlora_path)这一行把基础模型 LoRA 增量组装在一起形成微调后的完整模型。生成参数参数含义效果max_new_tokens1024最多生成 1024 个 token约 2000 个汉字do_sampleTrue随机采样不会每次生成一样top_p0.8核采样只从概率前 80% 的词中选平衡创意与准确temperature0.7温度越高越随机0.7 是比较均衡的值8. 完整项目文件结构模型微调/ ├── model_download.py # 下载 Qwen3.5-4B 基础模型 ├── p1.py # 测试基础模型模板输出 ├── p2.py # 数据预处理tokenization ├── p3.py # LoRA 微调训练 ├── p4.py # 加载微调模型并推理 ├── data/ │ └── llm_resume_scoring.json # 训练数据简历评分问答对 ├── output/ │ └── Qwen3_5_LoRA/ │ └── checkpoint-198/ # 微调结果LoRA 增量权重 └── 模型微调/ └── Qwen/Qwen3___5-4B/ # 下载的基础模型执行顺序model_download.py下载模型p2.py数据预处理p3.pyLoRA训练p4.py推理测试先跑model_download.py把 Qwen3.5-4B 下载到本地再跑p2.py把 JSON 数据转换成模型能理解的 token 格式验证数据正确性然后跑p3.py开始 LoRA 微调训练核心步骤耗时最长最后跑p4.py用微调好的模型进行推理测试9. 常见问题FAQQ1为什么选择 Qwen3.5-4B 而不是更大的模型4B40 亿参数是一个很好的入门尺寸单张 16GB 显卡就能训练效果对于简历评分这类任务已经足够训练一个 epoch 大约 10-20 分钟如果你想挑战更大的模型如 7B、14B只需要把模型名称改一下其他代码基本不用动。Q2训练多久合适本文设置num_train_epochs33 轮对于 50 条数据、batch_size24 的情况每轮约 2-3 个 step3 轮总共约 6-9 个 step总耗时约 5-15 分钟取决于显卡如果数据量更大几百上千条可以适当增加 epoch 数但要监控过拟合模型只记住了训练数据遇到新问题不会答。Q3显存不够怎么办几个省显存的技巧按优先级gradient_checkpointingTrue已启用减小per_device_train_batch_size比如改成 1 或 2增大gradient_accumulation_steps来补偿减小MAX_LENGTH比如改成 256使用load_in_4bitTrue4-bit 量化需要bitsandbytes库Q4微调后的模型怎么部署LoRA 的增量权重可以和基础模型合并成一个完整模型merged_modelmodel.merge_and_unload()merged_model.save_pretrained(./merged_model)tokenizer.save_pretrained(./merged_model)合并后就可以像普通模型一样加载使用了。Q5怎么判断微调有没有效果最简单的办法微调前后用同一个问题测试对比回答质量。也可以看训练日志中的loss损失值Loss 持续下降 → 模型在学习Loss 不降了甚至上升 → 可能过拟合了正常训练Loss 从 2-3 降到 1 以下Q6数据格式不对怎么办本文用的是 JSON 格式每行一条你也可以用 CSV、Excel 等格式只要数据预处理时正确解析即可。关键是最终要转换成{question: ..., answer: ...}的结构。总结通过本文你学会了从 ModelScope 下载 Qwen3.5-4B 大模型理解训练数据的格式和预处理方式配置 LoRA 参数并启动训练加载微调后的模型进行推理步骤文件耗时难度下载模型model_download.py5-30 分钟⭐数据预处理p2.py 1 分钟⭐⭐LoRA 训练p3.py10-30 分钟⭐⭐⭐推理测试p4.py 1 分钟⭐⭐核心思想大模型微调 基础模型 专业数据 LoRA 增量训练。就像给一个聪明的大学毕业生做岗前培训让他成为特定领域的专家本文所用模型Qwen3.5-4BLoRA 技术参考HuggingFace PEFT