【一起来学AI大模型】微调技术:LoRA(Low-Rank Adaptation) 的实战应用

 LoRA(Low-Rank Adaptation) 的实战应用,使用 Hugging Face 的 peft (Parameter-Efficient Fine-Tuning) 库对大型语言模型进行高效微调。LoRA 因其显著降低资源消耗(显存和计算)同时保持接近全量微调性能的特点,成为当前最热门的微调技术之一。

核心思想回顾:

LoRA 的核心假设是:模型在适应新任务时,权重的改变具有低秩特性。它不直接微调原始的大型权重矩阵 W (维度 d x k),而是学习两个更小的低秩矩阵 A (维度 d x r) 和 B (维度 r x k),其中 r << min(d, k)(秩 r 通常很小,如 8, 16, 32)。微调时,原始权重 W 被冻结(不更新),只更新 A 和 B。前向传播变为:

h = Wx + BAx = (W + BA)x
  • Wx:冻结的原始模型计算。

  • BAx:LoRA 适配器引入的低秩更新计算。

LoRA 的优势:

  1. 大幅降低显存占用: 只存储和更新 A 和 B (r * (d + k) 个参数) 的梯度/优化器状态,而非全量 W (d * k 个参数) 的。显存节省可达 90% 以上(尤其对于 Attention 的 Q/K/V/O 矩阵)。

  2. 减少计算开销: 额外计算 BAx 相对于原始 Wx 很小。

  3. 模块化与轻量级: 训练后,可以将 BA 加到原始 W 中部署,也可以保持分离。保存的 LoRA 权重通常只有 几十 MB

  4. 减少过拟合风险: 更少的可训练参数本身就是一种正则化。

  5. 易于任务切换: 同一个基础模型上可以训练多个不同的 LoRA 适配器,运行时根据需要动态加载。

  6. 与量化结合(QLoRA): 可与 4-bit 量化(如 bitsandbytes)结合,实现 在消费级 GPU(如 24GB)上微调 10B+ 模型

实战流程(使用 Hugging Face Transformers + peft + bitsandbytes (可选 QLoRA)):

环境准备:

pip install torch transformers accelerate  # 基础环境
pip install peft                          # PEFT 核心库
pip install bitsandbytes                  # 用于 4-bit 量化 (QLoRA)
pip install datasets                      # 加载和处理数据集
pip install trl                           # (可选) Hugging Face 的强化学习库,包含一些训练工具
pip install wandb                         # (可选) 实验跟踪

1. 导入必要的库

import torch
from transformers import (AutoModelForCausalLM,      # 用于因果LM (如 GPT, LLaMA)AutoTokenizer,             # 分词器TrainingArguments,         # 训练参数配置Trainer,                   # 训练器BitsAndBytesConfig,        # 4-bit 量化配置 (QLoRA)
)
from peft import (LoraConfig,                # LoRA 参数配置get_peft_model,            # 将基础模型转换为 PEFT 模型prepare_model_for_kbit_training,  # (QLoRA) 准备模型进行 k-bit 训练
)
from datasets import load_dataset  # 加载数据集
import wandb  # 可选,用于监控

2. 加载基础模型和分词器

  • 选择模型: 选择一个开源预训练模型(如 meta-llama/Llama-2-7b-hfbigscience/bloom-7b1gpt2-xltiiuae/falcon-7b)。确保你有访问权限(如 LLaMA 2 需要申请)。

  • 加载模型:

    • 全精度/半精度 (FP16/BF16):

      model_name = "meta-llama/Llama-2-7b-hf"
      tokenizer = AutoTokenizer.from_pretrained(model_name)
      tokenizer.pad_token = tokenizer.eos_token  # 为兼容性设置 pad_token
      model = AutoModelForCausalLM.from_pretrained(model_name,torch_dtype=torch.bfloat16,  # 或 torch.float16device_map="auto",           # 多 GPU 自动分配trust_remote_code=True,      # 如果模型需要
      )

    • QLoRA (4-bit 量化): 使用 BitsAndBytesConfig 显著降低显存需求。

      bnb_config = BitsAndBytesConfig(load_in_4bit=True,              # 加载 4-bit 量化模型bnb_4bit_quant_type="nf4",      # 量化类型 (推荐 nf4)bnb_4bit_compute_dtype=torch.bfloat16,  # 计算时使用 bfloat16bnb_4bit_use_double_quant=True, # 嵌套量化,进一步节省显存
      )
      model = AutoModelForCausalLM.from_pretrained(model_name,quantization_config=bnb_config,  # 应用量化配置device_map="auto",trust_remote_code=True,
      )
      model = prepare_model_for_kbit_training(model)  # 关键!准备模型进行 k-bit 训练
      tokenizer = AutoTokenizer.from_pretrained(model_name)
      tokenizer.pad_token = tokenizer.eos_token

3. 配置 LoRA (核心步骤)

使用 LoraConfig 定义 LoRA 的参数:

peft_config = LoraConfig(r=8,                     # LoRA 秩 (关键超参数)。值越小越省资源,但能力可能越弱。常用 8, 16, 32, 64。lora_alpha=32,           # LoRA 缩放因子 (关键超参数)。通常设置为 `r` 的 2-4 倍。控制新学到的知识对原始知识的相对重要性。target_modules=["q_proj", "v_proj"],  # 应用 LoRA 的目标模块名称列表 (极其重要!)# 常见目标模块 (取决于模型架构):#   LLaMA/GPT-like: ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "down_proj", "up_proj"]#   BLOOM: ["query_key_value", "dense", "dense_h_to_4h", "dense_4h_to_h"]#   通常只选 `query` (`q_proj`) 和 `value` (`v_proj`) 效果就不错且省资源。lora_dropout=0.05,       # LoRA 层的 Dropout 概率,防止过拟合。bias="none",             # 是否训练偏置。'none' (不训练), 'all' (训练所有), 'lora_only' (只训练LoRA相关的偏置)。task_type="CAUSAL_LM",   # 任务类型。对于文本生成是 "CAUSAL_LM"。也可以是 "SEQ_CLS", "TOKEN_CLS" 等。
)
  • target_modules 查找技巧:

    • 查看模型的 model.print_trainable_parameters() 输出(在下一步之后),确认目标模块是否被正确找到和替换。

    • 查看模型架构文档 (model.config.architectures) 或直接打印 model 的结构。

    • 常用库如 peft 的 get_peft_model 函数有时会打印可用的模块名。

4. 创建 PEFT 模型

将基础模型包装成支持 LoRA 的 PEFT 模型:

model = get_peft_model(model, peft_config)

5. (可选,但推荐) 打印可训练参数

检查 LoRA 是否成功应用且冻结了大部分参数:

model.print_trainable_parameters()
# 期望输出类似:
# trainable params: 4,194,304 || all params: 6,738,415,616 || trainable%: 0.062205960660696904

6. 准备数据集

  • 加载数据集: 使用 datasets 库加载你的任务数据集(如指令跟随、对话、特定领域文本)。

  • 格式化和分词: 将数据集格式化为模型期望的输入格式(通常是包含 text 字段)。使用 tokenizer 进行分词和填充。

  • 关键 - 模板化: 对于指令微调,使用清晰模板包装输入输出(例如 "### Instruction:\n{instruction}\n\n### Response:\n{response}" + EOS token)。

  • 示例:

def tokenize_function(examples):# 使用模板构造完整文本texts = [f"### Instruction:\n{inst}\n\n### Response:\n{resp}{tokenizer.eos_token}"for inst, resp in zip(examples['instruction'], examples['response'])]# 分词,注意 truncation 和 paddingresult = tokenizer(texts, max_length=512, truncation=True, padding="max_length")# 创建 labels 字段 (用于计算损失)。通常将 input_ids 复制给 labels,但将 padding 和 instruction 部分的 token 设置为 -100 (被忽略)。result["labels"] = result["input_ids"].copy()return result# 加载数据集 (示例)
dataset = load_dataset("your_dataset_name_or_path")
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# 划分 train/eval
train_dataset = tokenized_datasets["train"]
eval_dataset = tokenized_datasets["validation"]  # 如果有的话

7. 配置训练参数 (TrainingArguments)

training_args = TrainingArguments(output_dir="./lora-finetuned-model",  # 输出目录 (保存模型、日志等)per_device_train_batch_size=4,        # 每个 GPU/TPU 核心的训练批次大小 (根据显存调整,QLoRA 下可增大)per_device_eval_batch_size=4,         # 评估批次大小gradient_accumulation_steps=4,        # 梯度累积步数 (模拟更大的批次大小)learning_rate=2e-5,                   # 学习率 (LoRA 通常比全量微调大,1e-5 到 5e-5 常见)num_train_epochs=3,                   # 训练轮数weight_decay=0.01,                    # 权重衰减optim="paged_adamw_8bit",             # 优化器 (推荐用于稳定性,尤其 QLoRA)# optim="adamw_torch",                # 常规优化器 (非 QLoRA)lr_scheduler_type="cosine",           # 学习率调度器 (cosine, linear等)warmup_ratio=0.03,                    # 预热比例 (总步数的比例)logging_dir="./logs",                 # 日志目录logging_steps=10,                     # 每多少步记录一次日志save_steps=500,                       # 每多少步保存一次检查点evaluation_strategy="steps" if eval_dataset is not None else "no",  # 评估策略eval_steps=200 if eval_dataset is not None else None,  # 评估步数report_to="wandb",                    # 报告工具 (可选: "wandb", "tensorboard")fp16=True,                            # 半精度训练 (FP16) - 如果 GPU 支持# bf16=True,                          # 或者 BF16 (如果 Ampere+ GPU 支持)tf32=True,                            # 在 Ampere+ GPU 上启用 TF32 数学gradient_checkpointing=True,          # 梯度检查点 (用计算时间换显存)
)

关键参数说明:

  • gradient_accumulation_steps:将多个小批次的梯度累积起来再更新参数,模拟大 batch size。

  • gradient_checkpointing:显著减少训练显存(约 60-70%),但会增加约 20% 的训练时间。强烈推荐开启

  • fp16/bf16:半精度训练,节省显存加速训练。

  • optim="paged_adamw_8bit"bitsandbytes 提供的 8-bit AdamW 优化器,在 QLoRA 训练中非常稳定且节省显存

8. 创建 Trainer 并开始训练

trainer = Trainer(model=model,args=training_args,train_dataset=train_dataset,eval_dataset=eval_dataset,  # 如果没有验证集,设为 Nonetokenizer=tokenizer,# 可选:定义 data_collator (如 DataCollatorForLanguageModeling),但通常默认足够
)# 开始训练!
trainer.train()# 保存最终模型 (只保存 LoRA 权重)
trainer.model.save_pretrained(training_args.output_dir)
# 也可以保存完整模型 (基础模型 + LoRA 权重合并)
# merged_model = model.merge_and_unload()
# merged_model.save_pretrained("merged_lora_model")

9. (训练后) 加载和使用 LoRA 模型

  • 仅加载 LoRA 适配器 (运行时动态加载):

from peft import PeftModelbase_model = AutoModelForCausalLM.from_pretrained("base_model_name", ...)  # 加载基础模型
peft_model = PeftModel.from_pretrained(base_model, "./lora-finetuned-model")  # 加载 LoRA 权重# 使用 peft_model 进行推理
inputs = tokenizer("### Instruction:\nWhat is AI?\n\n### Response:\n", return_tensors="pt")
outputs = peft_model.generate(**inputs, max_new_tokens=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
  • 加载合并后的完整模型: 如果你之前运行了 merge_and_unload() 并保存了完整模型,可以直接像普通模型一样加载使用:

    merged_model = AutoModelForCausalLM.from_pretrained("merged_lora_model", ...)
    # ... 进行推理 ...

LoRA 实战关键技巧与注意事项:

  1. target_modules 选择: 这是影响效果最重要的配置之一。对于 decoder-only (GPT/LLaMA) 模型,通常优先选择 q_proj 和 v_proj。添加 o_projdown_projup_projgate_proj 可能提升效果但会增加可训练参数。encoder-decoder 模型 (如 T5) 需要分别指定 encoder 和 decoder 的模块。实验是找到最佳组合的关键!

  2. 秩 r 和 Alpha lora_alpha

    • r:值越大,LoRA 表达能力越强,越接近全量微调,但参数和计算开销也越大。常用范围 8-64。任务越复杂/数据量越大,r 可能需要越大。

    • alpha:控制 LoRA 更新的幅度相对于原始预训练权重的比例。经验法则:alpha = 2 * r 或 alpha = r 是比较好的起点。实际效果 scale = alpha / r 更重要。scale 太大可能导致不稳定,太小可能导致学习不足。

  3. 数据集质量与模板: 对于指令微调,清晰、一致的提示模板 (### Instruction:### Response:EOS token) 至关重要。数据质量直接影响最终模型效果。

  4. 学习率: LoRA 通常可以使用比全量微调更大的学习率(如 1e-5 到 5e-5 vs 1e-6 到 5e-6)。尝试在 1e-52e-55e-5 之间调整。

  5. 批次大小与梯度累积: 在有限显存下,使用较小的 per_device_train_batch_size 配合较大的 gradient_accumulation_steps 来模拟大 batch size(如 16, 32),通常有助于稳定训练和提升最终性能。

  6. 开启梯度检查点: gradient_checkpointing=True 是 在消费级 GPU 上训练大模型(即使使用 LoRA/QLoRA)的关键

  7. QLoRA (bitsandbytes): 对于在 24GB 或更小显存的 GPU 上训练 7B/13B 模型,QLoRA 几乎是必备的。确保正确使用 BitsAndBytesConfig 和 prepare_model_for_kbit_training

  8. 评估与早停: 使用验证集监控损失和任务特定指标(如困惑度、BLEU、ROUGE 或人工评估)。设置 evaluation_strategy 和 eval_steps,考虑在验证指标不再提升时早停 (EarlyStoppingCallback,需额外实现)。

  9. 实验跟踪: 使用 wandb 或 tensorboard 记录超参数、训练损失、评估指标,方便分析和复现结果。

  10. 资源监控: 训练时使用 nvidia-smi 或 gpustat 监控 GPU 显存占用和利用率。

总结:

使用 Hugging Face peft 库实现 LoRA 微调是一个高效且相对直接的过程。核心步骤包括:加载(量化)模型 -> 配置 LoraConfig (重点是 ralphatarget_modules) -> 创建 PEFT 模型 -> 准备数据集(注意模板)-> 配置 TrainingArguments (开启梯度检查点和梯度累积) -> 使用 Trainer 训练 -> 保存和加载 LoRA 权重。通过合理选择 target_modules、调整 r/alpha、利用 QLoRA 和梯度检查点,你可以在资源有限的设备上高效地微调大型语言模型,使其适应你的特定任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88784.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88784.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RedisJSON 内存占用剖析与调优

一、基础内存模型指针包装 所有 JSON 值&#xff08;标量、对象、数组、字符串等&#xff09;至少占用 8 字节&#xff0c;用于存储一个带类型标记的指针。标量与空容器 null、true、false、小整数&#xff08;静态缓存&#xff09;、空字符串、空数组、空对象 均不分配额外内存…

【LeetCode 热题 100】23. 合并 K 个升序链表——(解法一)逐一合并

Problem: 23. 合并 K 个升序链表 题目&#xff1a;给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 文章目录整体思路完整代码时空复杂度时间复杂度&#xff1a;O(K * N)空间复杂度&#xff1a;O(1…

垃圾收集器-Serial Old

第一章 引言1.1 JVM 中垃圾收集的简要概述JVM&#xff08;Java Virtual Machine&#xff09;作为 Java 程序的运行时环境&#xff0c;负责将字节码加载至内存并执行&#xff0c;同时也承担着内存管理的重任。垃圾收集&#xff08;Garbage Collection&#xff0c;简称 GC&#x…

Docker(02) Docker-Compose、Dockerfile镜像构建、Portainer

Docker-Compose 1、Docker Desktop 在Windows上安装Docker服务&#xff0c;可以使用Docker Desktop这个应用程序。 下载并安装这样的一个安装包 安装好后&#xff1a;执行命令 docker --version 从Docker Hub提取hello-world映像并运行一个容器&#xff1a; docker run h…

大数据时代UI前端的用户体验设计新思维:以数据为驱动的情感化设计

hello宝子们...我们是艾斯视觉擅长ui设计和前端数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;从 “经验设计” 到 “数据共情” 的体验革命传统 UI 设计常陷入 “设计师主观经…

TypeScript 学习手册

1.TypeScript 概念 TypeScript&#xff08;简称 TS&#xff0c;静态类型&#xff09;是微软公司开发的一种基于 JavaScript &#xff08;简称 JS&#xff0c;动态类型&#xff09;语言的编程语言。TypeScript 可以看成是 JavaScript 的超集&#xff08;superset&#xff09;&a…

掌握现代CSS:变量、变形函数与动态计算

CSS近年来发展迅速&#xff0c;引入了许多强大的功能&#xff0c;如变量、高级变形函数和动态计算能力。本文将深入探讨如何在CSS中设置并使用变量&#xff0c;以及如何有效利用translate3d、translateY和translateX等变形方法。我们还将解析var()和calc()函数的关键作用。一、…

贝尔量子实验设想漏洞

1 0 1 0 1 1 0 1 0 1 1 1 0 0 1 0 带墨镜如果先上下交换再左右交换&#xff0c;很可能不一样的概率是2%&#xff0c;但是因为交换诞生了一个与之前序列相同的所以不一样概率变成1%&#xff0c;我们在测的时候不能这么测啊&#xff0c;你得看序列完…

在 Android 库模块(AAR)中,BuildConfig 默认不会自动生成 VERSION_CODE 和 VERSION_NAME 字段

为什么AAR库模块的 BuildConfig 没有 versionCode 和 versionName&#xff1f; aar库模块的 BuildConfig 默认不包含版本信息 应用模块&#xff08;com.android.application&#xff09;会自动生成 versionCode 和 versionName 到 BuildConfig。但库模块&#xff08;com.androi…

强化学习 (11)随机近似

计算均值的新方法有两种方法。第一种方法很直接&#xff0c;即收集所有样本后计算平均值&#xff1b;但这种方法的缺点是&#xff0c;若样本是在一段时间内逐个收集的&#xff0c;我们必须等到所有样本都收集完毕。第二种方法可避免此缺点&#xff0c;因为它以增量迭代的方式计…

PHP `implode` 深度解析:从基础到高阶实战指南

文章目录一、基础语法与底层原理执行过程解析&#xff1a;二、性能关键&#xff1a;避免隐含陷阱1. 类型转换黑盒2. 大数组内存优化3. 关联数组处理三、高阶应用场景1. SQL语句安全构建2. CSV文件生成3. 模板引擎实现四、多维数组处理方案1. 递归降维2. JSON转换桥接五、性能对…

开发语言中关于面向对象和面向过程的笔记

开发语言中关于面向对象和面向过程的笔记市面主流语言分类面向过程面向对象市面主流语言分类 面向过程编程&#xff08;Procedural Programming&#xff09;&#xff1a;C语言&#xff1b;面向对象编程语言&#xff08;Object-Oriented Programming, OOP&#xff09; &#xf…

AI产品经理面试宝典第3天:技术分层、边界与市场全景系列面试题

面试指导 面试官:请从技术实现效果的角度,解释AI技术分层。 你的回答: AI技术分为三层。 第一层是认知层:通过图像处理、语音识别、自然语言理解等技术,让机器感知环境。比如摄像头识别行人动作,麦克风捕捉用户指令。 第二层是预测层:基于行为数据预判下一步需求。例如…

Intel英特尔ICH7R/ICH8R/ICH9R/ICH10R系列下载地址--intel_msm_8961002 下载 Version 8.9.6.1002

Intel英特尔ICH7R/ICH8R/ICH9R/ICH10R系列下载地址intel_msm_8961002 下载 Version 8.9.6.1002https://xiazai.zol.com.cn/detail/66/653449.shtml通过网盘分享的文件&#xff1a;intel_msm_8961002.zip 链接: https://pan.baidu.com/s/13N9ZLXWkaWaEHQ5P90Jt0g?pwd3790 提取码…

AI(学习笔记第五课) 使用langchain进行AI开发 load documents(web)

文章目录AI(学习笔记第五课) 使用langchain进行AI开发 load documents(web)学习内容&#xff1a;1.load documents&#xff08;web&#xff09;1.1 学习url1.2 提前安装python的package1.2 使用WebBaseLoader进行webpage的load1.3 使用BeautifulSoup4进行webpage的部分截取1.4 …

使用macvlan实现容器的跨主机通信

使用环境&#xff1a; 两台运行docker的服务器 A机器网段&#xff1a;192.168.86.61 B机器网段&#xff1a;192.168.86.62 运行的容器需装有ping指令&#xff0c; 实验参数解释&#xff1a; -d macvlan 指定创建网络驱动类型 --subnet 指定子网范围 -gateway 指定网关地址 -o p…

深度学习_全连接神经网络

1.什么是神经网络神经网络中信息只向一个方向移动&#xff0c;即从输入节点向前移动&#xff0c;通过隐藏节点&#xff0c;再向输出节点移 动&#xff0c;网络中没有循环或者环。其中的基本构件是&#xff1a; 输入层&#xff1a;即输入x的那一层 输出层&#xff1a;即输出y的那…

OpenLayers使用

初学ol&#xff0c;实现了高德地图不同图层的切换、交互性地图飞行以及加载本地JSON数据。说一下不同图层切换的想法&#xff1a;1.对于标准地图和卫星地图&#xff1a;二者最初便挂载到map上&#xff0c;两个图层是叠加显示的&#xff1b;当点击按钮时&#xff0c;其实是使用 …

day4--上传图片、视频

1. 分布式文件系统 1.1 什么是分布式文件系统 文件系统是负责管理和存储文件的系统软件&#xff0c;操作系统通过文件系统提供的接口去存取文件&#xff0c;用户通过操作系统访问磁盘上的文件。 下图指示了文件系统所处的位置&#xff1a; 常见的文件系统&#xff1a;FAT16/FA…

极矢量与轴矢量

物理量分为标量和矢量&#xff0c;矢量又分为极矢量和轴矢量。 矢量是既有大小又有方向并按平行四边形法则相加的量。矢量有极矢量和轴矢量两种&#xff0c;其间的区别是在镜像反射变换下遵循不同的变换规律,许多物理量都是矢量,同样,其中也有极矢量和轴矢量的区分,在力学中,例…