目录
1. prompt-tuning background
2. Prompt Tuning 模型介绍
2.1 2021 prefix-tuning
2.2 2021 P-tuning v1
2.3 2021 Parameter-efficient prompt tuning (PET)
2.4 2022 P-tuning v2
2.5 2019 Adapter
2.6 2021 LoRA (Low-Rank Adaptation)
2.7 2024 DoRA (Weight-Decoupled Low-Rank Adaptation)
3. LoRA Implementation
3.1 LoRA 复现 01: MiniLoRA
3.1.1 core codes:torch.nn.utils.parametrize.register_parameterization 参数化应用函数
3.2 LoRA 复现 02: LoRA from Scratch on MNIST
3.2.1 core codes: Lightning 深度学习框架
3.3 LoRA 复现 03: Torch tutorial with torchtune
3.3.1 core codes: torchtune package 介绍
3.4 LoRA 复现 04: peft implementation
3.4.1 core codes: AutoModelForSeq2SeqLM 介绍
3.4.2 code codes: peft package 介绍
3.5 *LoRA 05: Explanation
Reference:
1. prompt-tuning background
problem: 之前的fune-tuning/model-tuning是对大模型进行下游任务re-training,即对whole模型参数进行微调!但由于LLM参数量太大,fine-tuning需要大量的数据、算力去更新学习参数,不够实用!
solution:prompt-tuning (p-tuning),是一种通过提示词(prompt tokens)优化生成式预训练模型(e.g. GPT)的技术,旨在通过调整prompts而不是整个模型参数来提高模型在特定任务上的表现,达到节省计算开销和资源消耗、保持甚至提升model performance的目的。
按照时间顺序,prompt-tuning演进过程分别是:prefix-tuning、p-tuning v1、parameter-efficient prompt tuning、p-tuning v2。
2. Prompt Tuning 模型介绍
2.1 2021 prefix-tuning
prefix-tuning, paper: Optimizing Continuous Prompts for Generation, 就是在input tokens前面加上几个与任务相关task-specific的tokens,并用单独训练生成embeddings。
Note:tokens不拼接!原有的input tokens依旧用transformer生成embeddings,并且保持transformer参数不变。The prefix tokens' embeddings , hi are drawn from a trainable matrix MLP~. Then remaining tokens' embeddings are computed by the Transformer.
- 优点:实现简单、高效训练、任务一致性。
- 缺点:适用性有限,prefix-tuning在一些特定任务中效果不如p-tuning,e.g. 上下文限制,由于prefix embeddings始终位于序列前端,可能无法充分利用输入序列的上下文信息。
2.2 2021 P-tuning v1
p-tuning v1, paper: GPT Understands, Too. 它通过在输入层提示模板固定位置插入可训练的提示词向量trainable prompt tokens embeddings,来提升模型性能。
problem: Previous prompts方法是离散discrete向量空间,主要是从词库V中选词vi作为提示词prompt来出入提示模板的第i个位置,并用prompt generator来生成提示词向量prompt embeddings。这种固定的提示词叫作hard prompt,只能用来微调整个模型的参数 pre-trained model parameters。
solution: p-tuning v1是连续continuous向量空间,主要是通过prompt encoder生成trainable parameterized prompt embeddings来代替词库词vi插入输入层,这种generated trainable prompts称为soft prompt。
- 初始化 initialize prompts: <T1> <T2> The movie was fantastic <T3> <T4>. -> 训练优化 -> 推理 inference,这时不BP。
- 优点:少量参数、提高性能、通用性强。
- 缺点:训练复杂;依赖提示词位置。
2.3 2021 Parameter-efficient prompt tuning (PET)
Parameter-efficient prompt tuning, paper: The power of scale for parameter-efficient prompt tuning, 可以在输入序列的任意位置插入trianable prompt embeddings。
2.4 2022 P-tuning v2
p-tuning v2, paper: Prompt tuning can be comparable to fine-tuning universally across scale and tasks, 多层提示prompt,在每一层加上prefix prompt embeddings。
problem: 在模型参数量小于10B的训练中,prompt training效果要低于fine-tuning。
solution:p-tuning v2在每一层都加上了layer prefix prompt embeddings,不同任务可以共享相同的网络参数,支持多任务学习。
- 优点:可以更好地捕捉和利用上下文信息,进一步提高模型性能、更好泛化、灵活性强。
- 缺点:实现复杂;计算开销增加。
2.5 2019 Adapter
paper: Parameter-Efficient transfer learning for NLP.
2.6 2021 LoRA (Low-Rank Adaptation)
paper: Low-Rank Adaptation of Large Language Models.
LoRA保持pre-trained model参数冻结,只在原始矩阵中添加一个参数,其参数比原始矩阵少。
problem: 如果我们构造一个与Worig具有相同维度nxm的新矩阵来对模型进行微调,模型performance没有提升!还会将参数加倍!
solution:所以设计鬼才提出了低秩概念r,通过基于低秩r的低维矩阵乘法来构造, r << n和r << m,B和A相乘会产生一个与具有相同维度的矩阵,但由更少的参数构成。因为我们希望训练开始时增量为零,让微调像原始模型一样开始。因此,B通常被初始化为零矩阵,而A被初始化为随机值(即正态分布)。
For example,input dim=1024,那origin W参数量=1024*1024100万,而低秩参数量=1024*4+4*1024 8k。
优点:
- 效率高,使用更少的参数。
- 提高泛化性能 《-- 通过限制模型复杂性,防止过拟合。
- 可以无缝集成到现有的神经网络中。
2.7 2024 DoRA (Weight-Decoupled Low-Rank Adaptation)
核心:每个权重矩阵W通过多个低秩矩阵Ai和Bi的乘积进行近似,可以表示为:。
3. LoRA Implementation
LoRA实现公式:
my github link: GitHub - yuyongsheng1990/LLM_Prompts
3.1 LoRA 复现 01: MiniLoRA
简单、通俗、易懂、powerful
reference:minLoRA/demo.ipynb at main · cccntu/minLoRA · GitHub
3.1.1 core codes:torch.nn.utils.parametrize.register_parameterization 参数化应用函数
from functools import partial # 用于固定某些函数的参数,从而创建一个新的函数。这个新函数会记住被固定的参数,并在调用时使用这些固定参数。
'''
simple example: torch.nn.utils.parametrize.register_parametrization
output: 原始参数(weight或bias)会被替换为一个通过指定参数模块生成的参数。
Linear(
(weight): ParametrizationList(
(0): MyParametrization()
)
(bias): Parameter containing: [torch.FloatTensor of size 5]
)
'''
# -----------------single lora parameters---------------
linear = nn.Linear(5, 5)
print(linear)
class LowRankParametrization(nn.Module):
def __init__(self, original_weight, rank=4):
super().__init__()
self.rank = rank
self.U = nn.Parameter(torch.randn(original_weight.size(0), rank))
self.V = nn.Parameter(torch.randn(rank, original_weight.size(1)))
def forward(self, x):
return self.U @ self.V
# 注册低秩参数化
'''
torch.nn.utils.parametrize.register_parametrization函数用于在模型的参数上注册新的参数化方法。
这个功能允许你在现有参数layer.weight上应用一些变换LoRAParametrization,特别适用于LoRA
'''
parametrize.register_parametrization(linear, 'weight', LowRankParametrization(linear.weight))
# ----------------multiple lora parameters-------------------
# 可以顺序应用多个参数化方法,继续加就行 <--对应DoRA
# 定义第二个参数化方法
class MultiplyByTwoParametrization(nn.Module):
def __init__(self, original_weight, rank=4):
super().__init__()
self.rank = rank
self.U = nn.Parameter(torch.randn(original_weight.size(0), rank))
self.V = nn.Parameter(torch.randn(rank, original_weight.size(1)))
def forward(self, x):
return self.U @ self.V
parametrize.register_parametrization(linear, 'weight', MultiplyByTwoParametrization(linear.weight, rank=3))
# 打印线性层,查看参数化后的结果
print(linear)
'''
output:
Linear(in_features=5, out_features=5, bias=True) # 原始linear层
-------------------------------------------------
ParametrizedLinear( # 替换后的参数化线性层para linear
in_features=5, out_features=5, bias=True # 这表示layer原始参数original weight
(parametrizations): ModuleDict( # parametrizations表示应用参数化方法,新模型参数会存储在ModuleDict中,ModuleDict是一个module容器,它像一个dict一样工作。
(weight): ParametrizationList( # 这表示weight原始参数现在被替换/应用了ParametrizationList中一个或多个参数化方法.
(0): LowRankParametrization() # (0)表示ParametrizationList的第一个参数化方法。
# (1): MultiplyByTwoParametrization() # 顺序应用:当ParametrizationList存储多个参数化方法时,所有方法会按顺序应用到weight参数上。
)
)
)
'''
3.2 LoRA 复现 02: LoRA from Scratch on MNIST
reference: lora_from_scratch/lora_on_mnist.ipynb at main · sunildkumar/lora_from_scratch · GitHub
3.2.1 core codes: Lightning 深度学习框架
import lightning as L # lightning是一个高层次的深度学习框架,建立在pytorch之上,用于简化和加速模型的开发和训练过程。
from lightning.pytorch.loggers import CSVLogger # 用于将训练日志记录到csv文件中,便于之后的分析和可视化。
from lightning.pytorch.callbacks import LearningRateFinder # 通过在training过程中调整学习率lr来找到最优的学习率,以提升模型性能
from lightning.pytorch.callbacks.early_stopping import EarlyStopping # 用于在validation loss不再改善时提前停止,防止模型过拟合。
from pytorch_lightning import Callback # 用于实现自定义的回调函数,在training过程中的特定时间点执行特定的操作,比如记录日志、保存model、调整lr。
3.3 LoRA 复现 03: Torch tutorial with torchtune
reference: Finetuning Llama2 with LoRA — TorchTune documentation
3.3.1 core codes: torchtune package 介绍
from torchtune.models.llama2 import llama2_7b, lora_llama2_7b # torchtune是一个torch库,用于轻松创作、微调和试验LLM。
'''
torchtune, https://pytorch.org/torchtune/stable/index.html
- Llama3 in torchtune
- Finetuning with LoRA in torchtune
- Understanding QLoRA in TorchTune
- End-to-End Workflow with torchtune
'''
3.4 LoRA 复现 04: peft implementation
reference: LoRA-Implementation/prepare_data.py at main · hahuyhoang411/LoRA-Implementation · GitHub
3.4.1 core codes: AutoModelForSeq2SeqLM 介绍
'''
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
# 指定模型名称或路径
model_name = "t5-small"
# 加载预训练模型和分词器
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 输入文本
input_text = "Translate English to French: How are you?"
# 编码文本--成模型可接受的输入格式
inputs = tokenizer(input_text, return_tensors="pt")
# 生成输出
outputs = model.generate(**inputs)
# 解码输出文本
output_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"Input: {input_text}")
print(f"Output: {output_text}")
'''
3.4.2 code codes: peft package 介绍
'''
peft (Parameter-Efficient Fine-Tuning) package introduction:
Fine-tuning large pretrained models is often prohibitively costly due to their scale.
PEFT methods enable efficient adaptation of large pretrained models to various downstream applications by only fine-tuning a
small number of (extra) model parameters instead of all the model's parameters.
This significantly decreases the computational and storage costs.
Recent state-of-the-art PEFT techniques achieve performance comparable to fully fine-tuned models.
PEFT is integrated with Transformers for easy model training and inference,
peft简化了LLM-finetuning 模型配置和加载功能,特别是使用LoRA等技术。
- LoraConfig,用于配置LoRA参数。
- TaskType,用于定义任务类型, e.g. task_type = TaskType.TEXT_GENERATION
- get_peft_config,用于获取peft配置
- get_peft_model,用于获取pretrained peft模型。
'''
'''
----------------peft翻译模型---------------------
# 翻译模型bigscience/mt0-large: English -> French
'''
# prepare a model for training with a PEFT method such as LoRA by wrapping the base model and PEFT configuration with get_peft_model.
# For the bigscience/mt0-large model, you are only training 0.19% of the parameters!
from transformers import AutoModelForSeq2SeqLM # 用于加载和处理pre-trained seq2seq模型,用于处理nlp任务
from peft import get_peft_config, get_peft_model, LoraConfig, TaskType
# 加载预训练模型和分词器
model_name = 'bigscience/mt0-large'
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 定义lora配置
lora_config = LoraConfig(
task_type = TaskType.SEQ_2_SEQ_LM,
inference_mode=False,
r=8,
lora_alpha=32,
lora_dropout=0.1
)
# 获取peft model
peft_model = get_peft_model(model, peft_config)
print(peft_model.print_trainable_parameters()) # 输出peft mode可训练参数
# 准备输入数据
input_text = "Translate English to French: How are you?"
inputs = tokenizer(input_text, return_tensors="pt")
# 使用 PEFT 模型生成输出
outputs = peft_model.generate(**inputs)
output_text = tokenizer.decode(outputs[0], skip_special_tokens=True) # 解码
print(outputs)
print(output_text)
'''
------------peft因果推理模型----------------------
因果推理模型 ybelkada/opt-350m-lora; gpt2
'''
from peft import AutoPeftModelForCausalLM # 用于加载和配置因果语言模型Causal LM,并进行高效微调参数
from transformers import AutoTokenizer
import torch
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = AutoPeftModelForCausalLM.from_pretrained('ybelkada/opt-350m-lora').to(device)
tokenizer = AutoTokenizer.from_pretrained('facebook/opt-350m')
model.eval()
inputs = tokenizer('Preheat the oven to 350 degrees and place the cookie dough', return_tensors='pt')
outputs = model.generate(input_ids=inputs['input_ids'].to(device), max_new_tokens=50) # 生成输出
outputs_text = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0] # tokenizer解码输出文本
print(outputs)
print(outputs_text)
3.5 *LoRA 05: Explanation
***选看:太难、太复杂,不做实现喽
reference: 使用Pytorch从零开始构建LoRA_torch lora 使用 nn-CSDN博客
3.5 *LoRA 06: huanhuan chat
***选看:太难、太复杂,不做实现喽
reference: https://github.com/datawhalechina/self-llm/blob/master/GLM-4/05-GLM-4-9B-chat%20Lora%20%E5%BE%AE%E8%B0%83.ipynb
Reference:
[1] He J, Zhou C, Ma X, Berg-Kirkpatrick T, Neubig G. Towards a unified view of parameter-efficient transfer learning. arXiv preprint arXiv:2110.04366. 2021 Oct 8.
[2] https://mltalks.medium.com/%E8%AF%A6%E8%A7%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83%E6%96%B9%E6%B3%95prompt-tuning-%E5%86%85%E9%99%84%E5%AE%9E%E7%8E%B0%E4%BB%A3%E7%A0%81-7e4276927729