当前位置: 首页 > news >正文

从微调到部署一条龙:LLaMA + LoRA + vLLM

完整训练代码 vLLM 生产级部署方案32G 消费级显卡全流程跑通想拥有自己的专属 AI 模型却被动辄数百 GB 的显存需求劝退今天这篇教程带你用LoRA 微调vLLM 推理部署在32G 消费级显卡上完成从训练到上线的全流程。文章包含完整代码、逐行详细解释以及生产级部署方案收藏这一篇就够了。整体流程概览加载数据集 → 数据预处理 → 加载基座模型 → 配置LoRA → 训练 → 保存 → 清理显存 → 合并模型 → vLLM部署上线我们一步步来。一、环境准备pip install transformers datasets peft accelerate torch vllm核心依赖说明transformersHugging Face 模型框架训练主力datasets数据处理工具peft参数高效微调库LoRA 就在这里accelerate分布式训练与显存优化torchPyTorch 深度学习框架vllm高性能推理引擎部署用二、加载数据集from datasets import load_datasetimport transformersds load_dataset(json, data_filesalpaca_gpt4_data_zh.json)ds ds[train]print(ds[:3])print(transformers.__version__)详细解释load_dataset(json, data_filesalpaca_gpt4_data_zh.json)从 JSON 文件加载中文指令微调数据集。每条数据包含三个字段字段含义示例instruction指令“请解释什么是光合作用”input输入可选提供任务的上下文或具体输入output期望输出“光合作用是植物利用光能…”ds[train]取训练集。print(ds[:3])打印前 3 条数据快速验证格式。print(transformers.__version__)记录版本号方便日后复现。三、数据预处理核心步骤3.1 加载分词器from transformers import AutoTokenizertokenizer AutoTokenizer.from_pretrained(/home/will/models/llama)tokenizer.pad_token tokenizer.eos_tokenAutoTokenizer.from_pretrained(...)加载与 LLaMA 模型配套的分词器把文本转成模型能理解的 token IDstokenizer.pad_token tokenizer.eos_tokenLLaMA 原始分词器没有定义 pad_token借用 eos_token结束标记来补齐 batch 内的短序列3.2 构造训练样本def process_func(example): MAX_LENGTH 512 instruction tokenizer( \n.join([Human: example[instruction], example[input]]).strip() \n\nAssistant: , add_special_tokensFalse ) response tokenizer( example[output] tokenizer.eos_token, add_special_tokensFalse ) input_ids instruction[input_ids] response[input_ids] attention_mask instruction[attention_mask] response[attention_mask] labels [-100] * len(instruction[input_ids]) response[input_ids] 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 }这段代码是整篇文章最需要理解的部分 对话格式构造把数据拼接成如下格式Human: 请解释什么是光合作用Assistant: 光合作用是植物利用光能...eosHuman:代表用户提问Assistant:代表模型回答。这种格式让模型学会问答对话模式。 add_special_tokensFalse默认分词器会在文本开头自动加bos。设为 False 是因为我们要手动控制 token 拼接顺序——先 instruction 后 response由自己决定特殊标记的位置。 labels 的设置指令微调的精髓labels [-100] * len(instruction[input_ids]) response[input_ids]-100是 CrossEntropyLoss 的ignore_index标记为 -100 的位置不计算损失、不参与训练只有Assistant:之后的回复部分才参与训练为什么因为我们要训练的是模型 “如何回答”而不是训练它 “如何重复问题”。完整 input_ids: [Human: ... \n\nAssistant: ...回复内容...] |←────── 忽略不训练 ──────→|←── 训练这部分 ──→|对应 labels: [-100, -100, ..., -100, 回复的token_ids...] MAX_LENGTH 512限制每条样本最大 512 个 token。超长截断目的是控制显存——序列越长显存消耗越大。32G 显卡处理 512 长度比较安全。3.3 执行预处理tokenized_ds ds.map(process_func, remove_columnsds.column_names)print(tokenized_ds)print(tokenizer.decode(tokenized_ds[0][input_ids]))print(tokenizer.decode(list(filter(lambda x: x ! -100, tokenized_ds[0][labels]))))ds.map(...)对每条样本应用处理函数remove_columns...删除原始列只保留input_ids、attention_mask、labels下面三行验证处理结果打印数据结构、还原 input_ids 为文本、过滤 -100 后还原 labels确保格式正确四、加载基座模型import torchfrom transformers import AutoModelForCausalLMmodel AutoModelForCausalLM.from_pretrained( /home/will/models/llama, low_cpu_mem_usageTrue, torch_dtypetorch.float16, device_mapauto, use_cacheFalse)参数详解参数值为什么这么设low_cpu_mem_usageTrue减少 CPU 内存占用避免加载大模型时 OOMtorch_dtypefloat16半精度显存比 float32 减半32G 显卡必备device_mapauto自动将模型层分配到可用 GPUuse_cacheFalse训练时不需要推理 KV cache关掉省显存 8bit 量化选项代码注释中提供# model AutoModelForCausalLM.from_pretrained(# /home/will/models/llama,# load_in_8bitTrue,# device_mapauto,# use_cacheFalse# )如果模型较大如 13B建议开启 8bit 量化需安装bitsandbytes。五、配置 LoRA 微调from peft import LoraConfig, TaskType, get_peft_modelconfig LoraConfig(task_typeTaskType.CAUSAL_LM)model get_peft_model(model, config)model.print_trainable_parameters()LoRA 原理一句话不改动原始权重在每层旁边加一个小型旁路适配器只训练这个小适配器。就像改造大楼不需要重建只需要在每层加个小阳台——阳台很小成本自然低。LoraConfig 默认参数参数默认值含义r8秩rank决定适配器大小。越大表达能力越强lora_alpha8缩放系数控制 LoRA 权重影响力lora_dropout0Dropout 比率防过拟合target_modulesNone自动检测所有线性层q_proj, v_proj 等生产环境建议显式指定config LoraConfig( task_typeTaskType.CAUSAL_LM, r16, lora_alpha32, # 通常是 r 的 2 倍 lora_dropout0.05, target_modules[q_proj, v_proj],)get_peft_model 做了什么原始模型权重被冻结不参与训练不需要梯度只有 LoRA 适配器的参数可训练可训练参数通常只有原模型的0.1% ~ 1%执行print_trainable_parameters()你会看到类似trainable params: 4,194,304 || all params: 7,000,000,000 || trainable%: 0.0599%7B 的模型只训练约 400 万参数六、配置训练参数from transformers import TrainingArguments, Trainer, DataCollatorForSeq2Seqargs TrainingArguments( output_dir./chatbot, per_device_train_batch_size1, per_device_eval_batch_size1, gradient_accumulation_steps8, logging_steps10, num_train_epochs1, gradient_checkpointingTrue, optimadamw_torch, save_steps500, save_total_limit2, fp16True, bf16False, dataloader_num_workers0, remove_unused_columnsFalse,)参数逐行详解参数值含义output_dir./chatbot模型和检查点保存目录per_device_train_batch_size1每张 GPU 每次处理 1 条32G 显卡安全值gradient_accumulation_steps8梯度累积。等效 batch_size 1 × 8 8。每 8 步才更新一次权重logging_steps10每 10 步打印训练日志num_train_epochs1指令微调 1-3 轮即可多了容易过拟合gradient_checkpointingTrue梯度检查点。用时间换显存省约 60% 激活显存optimadamw_torchAdamW 优化器save_steps500每 500 步保存检查点save_total_limit2最多保留 2 个检查点超了自动删最旧的fp16True混合精度训练bf16False不启用 bf16需 Ampere 架构 RTX 30/40 系列dataloader_num_workers0主进程加载避免多进程问题remove_unused_columnsFalse保留所有数据列关于有效 Batch Size有效 batch_size per_device_batch_size × gradient_accumulation_steps × GPU数量 1 × 8 × 1 8虽然每次只处理 1 条数据但通过梯度累积等效于 batch_size8 的训练效果。七、开始训练trainer Trainer( modelmodel, argsargs, train_datasettokenized_ds.select(range(6000)), data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue))import gcgc.collect()torch.cuda.empty_cache()trainer.train()关键点tokenized_ds.select(range(6000))取前 6000 条样本。大数据集可先取一部分跑通流程DataCollatorForSeq2Seqbatch 内序列对齐自动 paddinggc.collect()torch.cuda.empty_cache()训练前清理显存碎片trainer.train()一行启动自动处理前向传播、反向传播、梯度累积、学习率调度、日志记录、检查点保存训练日志示例{loss: 1.2345, learning_rate: 5e-5, epoch: 0.5}{loss: 1.1234, learning_rate: 4.8e-5, epoch: 0.6}loss 逐渐下降模型在认真学习八、保存模型trainer.save_model()tokenizer.save_pretrained(./chatbot)这里保存的只是 LoRA 适配器的权重通常只有几十 MB不是完整模型。好处同一基础模型可以训练多个不同任务的适配器灵活切换。九、清理显存为合并做准备del modeldel trainertorch.cuda.empty_cache()gc.collect()删除训练对象释放显存。下一步的模型合并需要额外空间不清理会 OOM。十、合并模型base_model AutoModelForCausalLM.from_pretrained( /home/will/models/llama, torch_dtypetorch.float16, device_mapcpu, low_cpu_mem_usageTrue)from peft import PeftModelmodel PeftModel.from_pretrained(base_model, ./chatbot)merged_model model.merge_and_unload()merged_output_dir ./chatbot_mergedmerged_model.save_pretrained(merged_output_dir)tokenizer.save_pretrained(merged_output_dir)print(fMerged model saved to {merged_output_dir})print(Training and merge completed!)为什么要合并LoRA 训练后权重是 “分离” 的——基础模型一套适配器一套。合并把 LoRA 权重加回基础模型对应层得到完整的独立模型。为什么加载到 CPUdevice_mapcpu合并不需要 GPU 加速把 GPU 腾出来避免显存不足32G 显卡同时加载基础模型 做合并操作压力太大合并后的目录结构./chatbot_merged/├── config.json # 模型配置├── pytorch_model.bin # 完整模型权重├── tokenizer.json # 分词器文件├── tokenizer_config.json└── ...十一、vLLM 部署上线模型训练合并完成后就可以部署了。这里我们使用vLLM——目前最快的开源大模型推理引擎。启动命令python -m vllm.entrypoints.openai.api_server \ --model /code/chatbot_merged \ --served-model-name llama \ --max-model-len 8192 \ --host 0.0.0.0 \ --port 6006 \ --dtype bfloat16 \ --gpu-memory-utilization 0.8 \ --trust-request-chat-template \ --enable-auto-tool-choice \ --tool-call-parser hermes参数逐行详解参数值含义--model/code/chatbot_merged指向合并后的模型目录--served-model-namellamaAPI 中显示的模型名称--max-model-len8192最大上下文长度 8K。模型能处理的最长 token 数--host0.0.0.0监听所有网络接口允许远程访问--port6006服务端口--dtypebfloat16使用 bf16 精度推理。比 fp16 数值稳定性更好不会溢出前提是你的显卡支持 bf16RTX 30/40 系列都支持--gpu-memory-utilization0.8限制 GPU 显存使用率为 80%。留 20% 给系统和其他进程避免把显卡吃满导致崩溃--trust-request-chat-template—信任模型自带的对话模板自动处理 Human/Assistant 格式--enable-auto-tool-choice—启用自动工具选择让模型能够自主决定何时调用外部工具--tool-call-parserhermes使用 Hermes 格式解析工具调用。如果你的模型支持 Function CallingvLLM 会自动识别并执行为什么用 vLLM相比直接用 transformers 推理vLLM 有巨大优势特性transformersvLLM推理速度基准快 2-10 倍显存效率一般PagedAttention 技术显存利用率极高并发处理差支持高并发自带批处理API 兼容性需要自己写兼容 OpenAI API 格式最关键的一点vLLM 的 API 完全兼容 OpenAI 格式。这意味着所有用 OpenAI SDK 的代码只需要改一行就能切换到自己的模型# 只需要改 base_url其他代码不用动from openai import OpenAIclient OpenAI( base_urlhttp://localhost:6006/v1, api_keynot-needed # 本地部署不需要 key)response client.chat.completions.create( modelllama, messages[ {role: user, content: 请介绍一下中国的首都} ])print(response.choices[0].message.content)验证服务是否正常启动后访问http://你的IP:6006/v1/models如果返回模型信息说明服务正常。也可以用 curl 测试curl http://localhost:6006/v1/chat/completions \ -H Content-Type: application/json \ -d { model: llama, messages: [ {role: user, content: 你好请自我介绍一下} ] }关于 dtype 的补充说明训练时用的是fp16部署用的是bf16。这是可以的模型权重在合并后保存在磁盘上加载时 vLLM 会自动转换bf16比fp16数值范围更大推理时更稳定不容易出现 NaN前提条件你的显卡需要支持 bf16RTX 3090/4090 等 Ampere/Ada 架构都支持如果你的显卡不支持 bf16如 RTX 2080Ti改成--dtype float16即可。十二、32G 显卡优化总结训练阶段技巧效果float16半精度显存减半gradient_checkpointing省约 60% 激活显存batch_size1gradient_accumulation8小 batch 模拟大 batchMAX_LENGTH512控制序列长度训练后delempty_cache及时释放显存模型合并放在 CPU避免 GPU OOM推理阶段技巧效果--gpu-memory-utilization 0.8限制显存使用留出余量--dtype bfloat16更稳定的半精度推理--max-model-len 8192支持长上下文训练时 512 也没关系推理时可以更长vLLM PagedAttention显存利用率远高于原生推理十三、常见问题Q1: 训练很慢怎么办先用少量数据1000 条跑通流程降低MAX_LENGTH到 256确认模型确实跑在 GPU 上Q2: loss 不下降添加learning_rate2e-4到 TrainingArguments用tokenizer.decode检查数据格式尝试num_train_epochs3Q3: 合并时 OOM确保训练后已del model并清理显存device_mapcpu必须设Q4: vLLM 启动报错 Out of Memory降低--gpu-memory-utilization到 0.7 或 0.6减小--max-model-len确认没有其他进程占用 GPUnvidia-smi查看Q5: 训练用 fp16部署用 bf16 会不会有问题不会。合并后的模型权重加载时 vLLM 会自动转换精度bf16 比 fp16 数值范围更大推理更稳定十四、总结回顾整个流程加载数据集→ JSON 格式指令数据数据预处理→ 构造对话格式labels 只对回复部分计算损失加载基座模型→ 半精度 自动设备分配配置 LoRA→ 只训练 0.1% 参数训练→ Trainer 一行启动保存 合并→ 得到完整模型vLLM 部署→ OpenAI 兼容 API一行切换从训练到部署32G 消费级显卡全部搞定。关键在于每一步的显存优化策略。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
http://www.zskr.cn/news/1383815.html

相关文章:

  • 低成本四足机器人定位新思路:给Go1狗腿装上MPU9250 IMU,实测漂移降低80%
  • 每天25分钟的淘宝任务,如何用智能脚本一键搞定?
  • 俄罗斯诚实标识 DataMatrix 码采集的技术实现与合规优化
  • 15个靶场如何构建渗透测试能力成长路径
  • 全球无障碍宣传日:iOS 26 辅助功能大升级,这些实用小功能你用过吗?
  • Vue2-Verify:解决前端验证码安全性与用户体验平衡问题的技术方案实现
  • 3分钟快速安装BetterNCM插件管理器,让你的网易云音乐功能翻倍
  • 实现自己的IOC容器——Winter(三)Spring原生ApplicationContext机制梳理
  • 微生物组学数据分析终极指南:用microeco快速完成专业分析
  • 基于SMD与贝壳的微型音频装置:从电路设计到嵌入式开发的完整实践
  • 基于状态变量滤波器的有源分频器设计:低成本高保真音频系统核心
  • ATtiny13A驱动LED沙漏计时器:从电路设计到软件实现的完整指南
  • 中国股票市场限价单成交概率与微观结构高频分析【附模型】
  • 钻机车机电液一体化系统性能优化关键技术【附程序】
  • 别再猜了!彻底搞懂Unity中Texture的sRGB选项:勾与不勾,对Alpha混合结果影响有多大?
  • 什么情况下会核销贷款
  • Ofd2Pdf:彻底解决OFD文档格式兼容性难题的专业工具
  • 当AI学会告白:骁龙在520,把科技写成人的温柔
  • 简单学习 --> SSE
  • CANN生产环境最佳实践——从实验室到量产的避坑指南(完整版)
  • 深入Linux内核:软件如何“冒充”硬件?揭秘fixed-link背后的虚拟MDIO总线设计
  • 告别书签混乱:3个步骤让你的浏览器收藏夹重获新生
  • Ubuntu 22.04 LTS下,腾达U9 USB网卡驱动安装保姆级教程(解决内核6.5+编译问题)
  • Java NIO.2 异步调度中枢:AsynchronousChannelGroup 源码深度剖析与线程池契约
  • Unity Timeline信号(Signal)系统实战:告别硬编码,实现灵活的事件驱动交互
  • 别再刷高并发概念了,这 5 个“复杂级”全栈垂直平台带你死磕底层业务
  • 如何快速突破原神60帧限制:面向PC玩家的完整帧率解锁指南
  • VideoDownloadHelper终极指南:三步掌握全网视频下载的完整教程
  • 网盘限速终结者:LinkSwift直链下载助手终极指南
  • 2026年杭州电商公司实力大比拼:哪家更值得信赖?