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

Lora原理介绍并用Macbook air超快实现本地微调小模型

note:我认为“干中学”是AI时代最高效的掌握技能的方式,本篇文章将基于一个简单的微调示例,解释微调的相关概念以及相关工具的使用。本次实践完全参照下面这篇文章,感谢大佬让我这个大模型小白能快速试验微调
https://juejin.cn/post/7426343844595335168

微调基础概念

什么是微调?

微调是基于一个已经训练好的神经网络模型,通过对其参数进行细微调整,使其更好地适应特定的任务或数据。通过在新的小规模数据集上继续训练模型的部分或全部层,模型能够在保留原有知识的基础上,针对新任务进行优化,从而提升在特定领域的表现。

微调的划分

以下内容参考自大模型为什么需要微调?有哪些微调方式?#大模型 #微调_哔哩哔哩_bilibili

1. 按照微调参数规模划分

  • FPFT(Full Parameter Fine-Tuning)全参数微调:用预沉练模型作为初始化权重,在特定数据集上继续训练,全部参数都更新的方法

  • PEFT(Parameter Efficient Fine-Tuning)参数高效微调:用更少的计算资源完成模型参数的更新,包括只更新一部分参数,或者通过对参数进行某种结构化约束,例如稀疏化或低秩近似来降低微调的模型参数量

    • 我们熟知的就有 Adapter、Lora、Qlora、P-turning等

2. 按照训练流程划分

按照大模型训练阶段进行微调,或者根据大模型微调的目标来区分,从提示微调 Prompt Tuning、
有监督微调SFT、RLHF 人类反馈强化学习的方式来划分。
​​​​​​​​在这里插入图片描述
其中ICL (In-Context learning)上下文学习:区别于普通微调 Fine-Tuning,不对LLMs执行任何
的微调,直接将模型的输入输出拼接起来作为一个 prompt。这也是当前 AI 应用很常见的一种方法。

3. 按照训练的方式划分

  • 预训练Pre-Training:LLMs 预训练过程是无监督的(或者叫自监督的更合适),但微调过程往往是有监督的。当进行有监督微调时,模型权重会根据与真实标签的差异进行调整。

  • Supervised fine-tuningSFT:有监督微调使用有标签的数据(Label Data )来调整已经预训练的LLMS,使其更适应某一特定场景任务。

    • 而我们熟悉的 Instruction Turning 其实是 SFT 的一种特殊形式。指令微调旨在增强模型理解并执行不同指令的能力。通过指令-输出对的训练,使模型能够更好地遵循人类指令,提高其在多个任务上的泛化能力。下面是其数据形式。
[{"instruction": "用简单的语言解释量子力学。","input": "",//可省略"output": "量子力学是研究微小粒子行为的科学..."},{"instruction": "将以下句子翻译成法语。","input": "你好,今天天气不错。","output": "Bonjour, il fait beau aujourd'hui."}
]

LoRA原理

由于下面的案例主要是基于 Lora 实现的,下面我将简单介绍一下 Lora 的基本原理

背景

在大模型(如 GPT、BERT 等)应用中,微调面临以下主要挑战:

  • 计算资源消耗大:大模型参数量巨大,微调时需要大量的计算资源和存储空间。
  • 模型性能风险:直接微调全部参数,可能会破坏预训练模型原有的泛化能力和性能。
  • 存储与部署压力:每个微调版本都需存储一份完整模型,导致存储和多场景部署成本极高。
  • 推理延迟增加:部分微调方法会显著增加推理时的计算量,影响模型的实时响应能力。

​LoRA 的提出正是为了解决上述问题。

它通过引入低秩矩阵的方式,仅对模型中的部分参数进行高效、低成本的微调,极大减少了计算和存储开销,同时保持了模型的原始性能和推理效率。这使得大模型的微调和多场景部署变得更加高效和灵活。

预备知识——低秩矩阵分解

ps:下面内容来源于B站课程-唐国梁Tommy

低秩矩阵分解是一种将高维矩阵近似为两个低维矩阵乘积的技术,常用于数据降维、压缩、推荐系统等领域。

步骤1:理解目标
我们有一个高维矩阵 Δ W \Delta W ΔW ,希望将其近似为两个低维矩阵 A A A B B B的乘积,即 Δ W ≈ B A \Delta W \approx BA ΔWBA

步骤2:设定矩阵维度
假设 Δ W \Delta W ΔW是一个 d × d d \times d d×d的矩阵。我们选择一个较小的整数 r r r,使得 r ≪ d r \ll d rd 。矩阵 A A A 的维度将是 d × r d \times r d×r ,矩阵 B B B 的维度将是 r × d r \times d r×d

步骤3:矩阵初始化

  • 初始化矩阵 A A A B B B 。可以使用随机初始化、正态分布初始化等方法。例如:
    • A ∼ N ( 0 , σ 2 ) A \sim \mathcal{N}(0, \sigma^2) AN(0,σ2) ,表示矩阵 A A A 的每个元素都是从均值为0、方差为 σ 2 \sigma^2 σ2 的正态分布中随机抽取的。
    • B B B 初始化为零矩阵,即 B = 0 B = 0 B=0

步骤4:矩阵乘积

  • 通过矩阵乘积 B A BA BA ,可以得到一个近似的 d × d d \times d d×d 矩阵:
    W ′ = B A W' = BA W=BA
    其中 W ′ ≈ Δ W W' \approx \Delta W WΔW

步骤5:优化和训练

  • 在训练过程中,通过优化算法(如梯度下降),不断调整矩阵 A A A B B B 的值,使得 W ′ W' W 更加接近于 Δ W \Delta W ΔW
  • 损失函数通常是衡量 Δ W \Delta W ΔW W ′ W' W 之间差距的一个函数,例如均方误差:
    L = ∥ Δ W − B A ∥ F 2 L = \| \Delta W - BA \|_F^2 L=∥ΔWBAF2

步骤6:更新规则

  • 通过优化算法计算损失函数关于 A A A B B B 的梯度,并更新 A A A B B B 的值。例如,使用梯度下降法更新规则如下:

    A ← A − η ∂ L ∂ A A \leftarrow A - \eta \frac{\partial L}{\partial A} AAηAL

    B ← B − η ∂ L ∂ B B \leftarrow B - \eta \frac{\partial L}{\partial B} BBηBL

    其中 η \eta η 是学习率。

LoRA详解

LoRA原理

所以LoRA假设模型参数更新矩阵(ΔW)具有低秩特性,即可以用两个更小的矩阵(A和B)的乘积来近似:

Δ W ≈ B A \Delta W \approx BA ΔWBA

其中,A是维度为 d × r d \times r d×r的降维矩阵,B是维度为 r × d r \times d r×d 的升维矩阵,r(秩)远小于原始维度d(例如r=8)。这使得可训练参数量从 d 2 d^2 d2减少到 2 r d 2rd 2rd,显著降低计算需求

在整个过程中,原始模型权重(W)在微调过程中完全冻结,仅训练低秩矩阵A和B。
输出叠加:模型的实际输出为原始权重与低秩调整项的结合:
h = W x + α ⋅ ( B ⋅ A x ) h = Wx + α · (B·Ax) h=Wx+α(BAx)

其中,α为缩放因子,用于控制低秩调整对输出的影响幅度
在这里插入图片描述
其中A 是一个随机初始化的矩阵,服从正态分布;B 初始化为零矩阵。
为什么要用这种初始化方式?
(1)如果B和A全部初始化为零矩阵,缺点是很容易导致梯度消失;(2)如果B和A全部正态分布初始化,那么在模型训练开始时,就会容易得到一个过大的偏移值 Δ W \Delta W ΔW,从而引起太多噪声,导致难以收敛

选择哪些权重矩阵进行适配?

在这里插入图片描述

与其他微调方法对比

(1)与全量微调(Full Finetuning)的差异

  • 全量微调:反向传播需计算所有参数的梯度(包括 WV),计算图和显存占用与模型规模成
    正比。
  • LORA:仅计算低秩矩阵的梯度,但需保留完整的计算图路径(因 W 冻结但参与前向传播),因此反向传播的计算复杂度略高于仅训练部分参数的方法(如Adapter)。

(2) 与参数高效微调(PEFT)方法的对比

  • Adapter:插入小型网络模块,反向传播需计算模块内所有参数的梯度,但模块参数量通常大于LORA。
  • Prefix-Tuning:仅优化前缀嵌入的梯度,不涉及权重矩阵的分解,但任务泛化性较差14。

举个简单例子

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Macbook 简单微调实践

本次实践用的是MLX,MLX是由苹果的机器学习研究团队推出的用于机器学习的阵列框架,该开源框架专为 Apple Silicon 芯片而设计优化。该库允许在新的 Apple Silicon(M 系列)芯片上对 LLM 进行微调。此外,MLX 还支持使用 LoRA 、QLoRA等方法对 LLM 进行微调。

下载模型

下载一个小模型, 我的电脑是 M3 air 24G内存, 微调1.5B的小模型够了, 就选Qwen/Qwen2.5-1.5B

#安装依赖
uv pip install -U huggingface_hub
#设置环境变量
export HF_ENDPOINT=https://hf-mirror.com 
#下载模型,保存至qwen2.5-0.5B目录
huggingface-cli download --max-workers 4 --resume-download Qwen/Qwen2.5-1.5B --local-dir Qwen2.5-1.5B

逐行代码解释

  1. 使用 uv 工具升级(或安装)huggingface_hub 这个 Python 库。
  2. 设置环境变量 HF_ENDPOINT,指定 Hugging Face 镜像站点为 https://hf-mirror.com。 这样做可以加速模型下载,尤其是在中国大陆访问 Hugging Face 官方站点较慢时。 该环境变量会被 huggingface_hub 及
    huggingface-cli 工具自动识别和使用。
  3. 使用 huggingface-cli 工具下载 Hugging Face 上的 Qwen2.5-1.5B 模型到本地目录。 huggingface-cli download:调用 huggingface 的命令行工具进行模型下载。
    –max-workers 4:设置最多使用 4 个线程并发下载,加快速度。
    –resume-download:如果下载中断,可以断点续传,避免重复下载已完成的部分。 Qwen/Qwen2.5-1.5B:指定要下载的模型仓库名称(组织/模型名)。
    –local-dir Qwen2.5-1.5B:将模型文件保存到本地的 Qwen2.5-1.5B 目录下。

安装依赖与mlx

pip install mlx-lm  
pip install transformers  
pip install torch  
pip install numpy  
git clone --depth 1 https://github.com/ml-explore/mlx-examples

可以看到 mlx_example下面的目录结构
在这里插入图片描述

准备数据集

MLX支持三种格式的数据集

  1. Completion

{ “prompt”: “What is the capital of France?”, “completion”: “Paris.” }

  1. chat

{ “messages”: [
{
“role”: “system”,
“content”: “You are a helpful assistant.”
},
{
“role”: “user”,
“content”: “Hello.”
},
{
“role”: “assistant”,
“content”: “How can I assistant you today.”
} ] }

  1. text

{ “text”: “This is an example for the model.” }

在 lora 下面自带一个数据集 就是最后一种 text 格式,看起来是实现text2sql 任务
在这里插入图片描述
我们可以按照第一种Completion方式准确数据
新建 test_data 数据集,输入相应文本
在这里插入图片描述
准备数据集

vi test_data/train.jsonl  {"prompt": "PolarDB是什么<|endoftext|>", "completion": "阿里云开源宇宙无敌数据库<|endoftext|>"}  
{"prompt": "Oracle数据库会被什么打败<|endoftext|>", "completion": "国产数据库<|endoftext|>"}  
{"prompt": "为什么电动汽车比较费油<|endoftext|>", "completion": "因为电很贵<|endoftext|>"}  
{"prompt": "哪吒的师傅是谁<|endoftext|>", "completion": "孙悟空的师傅的舅舅<|endoftext|>"}  
{"prompt": "月亮哪天最圆<|endoftext|>", "completion": "星期八<|endoftext|>"}  vi test_data/valid.jsonl  {"prompt": "PolarDB是什么<|endoftext|>", "completion": "阿里云开源宇宙无敌数据库<|endoftext|>"}  
{"prompt": "Oracle数据库会被什么打败<|endoftext|>", "completion": "国产数据库<|endoftext|>"}  
{"prompt": "为什么电动汽车比较费油<|endoftext|>", "completion": "因为电很贵<|endoftext|>"}  vi test_data/test.jsonl  {"prompt": "哪吒的师傅是谁<|endoftext|>", "completion": "孙悟空的师傅的舅舅<|endoftext|>"}  
{"prompt": "月亮哪天最圆<|endoftext|>", "completion": "星期八<|endoftext|>"}  

微调模型

 mlx_lm.lora --model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B --train --data ./test_data --learning-rate 1.0e-4 --val-batches -1 --batch-size 2

代码解释
–mlx_lm.lora
这是一个命令行工具(或 Python 脚本),用于对大模型进行 LoRA(低秩适配)微调。
–model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B
指定要微调的基础模型的路径,这里是本地的 Qwen2.5-1.5B 模型目录。
–train
表示执行训练(微调)操作。
–data ./test_data
指定训练数据所在的目录,这里是当前目录下的 test_data 文件夹。里面应包含用于微调的数据集。
–learning-rate 1.0e-4
设置训练时的学习率为 0.0001。学习率决定了模型参数每次更新的步长,是训练中非常重要的超参数。
–val-batches -1
指定验证集的 batch 数量为 -1,通常表示“使用全部验证数据”进行评估。
–batch-size 2
设置每个训练 batch 的样本数为 2。batch size 越大,显存/内存消耗越多,但训练更稳定。

效果测试

mlx_lm.generate --model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "PolarDB是什么?"
@bogon lora % mlx_lm.generate --model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "PolarDB是什么?"
==========
阿里云开源宇宙无敌数据库
==========
Prompt: 24 tokens, 182.174 tokens-per-sec
Generation: 7 tokens, 32.178 tokens-per-sec
Peak memory: 3.134 GB

可以发现效果还不错
最后可以把微调后的参数和模型融合, 生成本地微调后的模型

mlx_lm.fuse --model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B --adapter-path adapters --save-path ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B-test

最后还可以使用融合后的模型测试

@anonymous ml_study_test % mlx_lm.generate --model ~/Documents/PythonProject/ml_study_test/Qwen2.5-1.5B-test --prompt "哪吒的师傅是谁?"
==========
孙悟空的师傅的舅舅
==========
Prompt: 25 tokens, 208.395 tokens-per-sec
Generation: 6 tokens, 33.323 tokens-per-sec
Peak memory: 3.126 GB

自此基于 mlx 的简单微调就成功了 但是肯定在这个过程中还是会对其中各个步骤的细节有疑惑,比如说lora微调代码原理、adapters是干什么的等等 这些问题就在之后的文章里解释吧~

http://www.xdnf.cn/news/4185.html

相关文章:

  • AI日报 · 2025年5月05日|雅诗兰黛与微软合作成立 AI 创新实验室,加速美妆产品研发与营销
  • 【言语理解】片段阅读之下文推断(6)
  • 设计模式每日硬核训练 Day 18:备忘录模式(Memento Pattern)完整讲解与实战应用
  • 全球化电商平台AWS云架构设计
  • 矩阵置零(中等)
  • 设计模式-基础概念学习总结(继承、多态、虚方法、方法重写)
  • 深入理解块级格式化上下文(BFC)
  • 文本三剑客
  • 字符串匹配 之 拓展 KMP算法(Z算法)
  • 数据集-目标检测系列- 印度人脸 检测数据集 indian face >> DataBall
  • 深度解析:从 GPT-4o“谄媚”到 Deepseek“物理腔”,透视大模型行为模式的底层逻辑与挑战
  • Unity:AddTorque()(增加旋转力矩)
  • uniapp 云开发全集 云数据库
  • JavaScript 笔记 --- part7 --- JS进阶 (part2)
  • 【信息系统项目管理师-论文真题】2008上半年论文详解(包括解题思路和写作要点)
  • Python生活手册-NumPy数组创建:从快递分拣到智能家居的数据容器
  • 互联网大厂Java求职面试:AI大模型与云原生架构设计深度解析
  • 【学习心得】Xtuner模型qlora微调时错误记录
  • 【嘉立创EDA】FPCB(Flexible-PCB)柔性软板设计如何增加补强层
  • 反常积分(广义积分)
  • Redis总结(六)redis持久化
  • C++ 适配器模式详解
  • Java中使用Lock简化同步机制
  • 安装SDL和FFmpeg
  • 强化学习ppo算法在大语言模型上跑通
  • [ 设计模式 ] | 单例模式
  • Android学习总结之GetX库篇(场景运用)
  • 智能合约在去中心化金融(DeFi)中的核心地位与挑战
  • 机器学习中常见搜索算法
  • 代码随想录算法训练营第三十二天