基于imdb的LoRA微调分类模型 Xlnet[简单例子,小白可上手]
温馨提示:这篇文章已超过370天没有更新,请注意相关的内容是否还可用!
LORA微调简单例子
- 什么是LORA微调?
- 为什么我会接触LoRA?
- 1. 安装库
- 2.开始LoRA微调
- Train with LoRA
- inference
- 说明下target_modules这个参数(可选)
- 谈一下LoRA的当下的应用
什么是LORA微调?
LoRA 全称为 low-rank adaptation, 低秩自适应微调方法。
paper:LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS
大概思路:借鉴知乎 https://www.zhihu.com/tardis/zm/art/623543497?source_id=1005 的这个图说明一下:
- LoRA微调什么? 预训练模型是 左边, Lora微调得到的模型是 右边。
LoRA相当于训练一个新的额外的参数,来学习原参数的知识。
- LoRA优点:相比于全量微调(full finetune)方法的优点是 LoRA通常只需要更新不到1%的参数就能达到与全量微调相当的效果。
full finetune:更新所有的预训练网络参数。
例如在下面的例子中,peftmodel 显示lora微调训练的参数量是原来的0.62倍,十分小。
model.print_trainable_parameters()
为什么我会接触LoRA?
最近在2张40G的GPU上,想要实现基于imdb数据集微调Xlnet-large模型,发现直接load pre-trained model 全量微调压根跑不起来,内存直接爆炸。
- 内存/存储空间不够
因此,想通过一些高效低参的微调的方法来实现,如LoRA, bitfit(只微调网络中的bias 参数,比lora效果差得多)。
接下来直接上代码介绍怎么基于LoRA微调xlnet-base-cased吧。很简单的过程,但是你要能连接Huggingface,不能连接的话就把数据和模型下到本地吧。
依赖库 提供方 手册 transformer Huggingface https://huggingface.co/docs/transformers/pipeline_tutorial datasets Huggingface https://huggingface.co/docs/datasets/load_hub evaluate Huggingface https://huggingface.co/docs/evaluate/transformers_integrations peft Huggingface https://huggingface.co/docs/peft/quicktour 建议在conda 虚拟环境里跑哈 使用的环境如下:
Framework versions PEFT 0.9.0 Transformers 4.38.2 Pytorch 2.2.1 Datasets 2.18.0 Tokenizers 0.15.2 python 3.10
1. 安装库
执行以下代码安装相关的库函数,需要翻墙,能够连接上Huggingface :
pip install transformers datasets evaluate peft
2.开始LoRA微调
下载xlnet-base-cased模型-- 用peft封装模型- - 训练参数 — 训练模型 – 上传模型到hub
Train with LoRA
def train_lora(): # 如果需要将模型推送到hub上的话,需要登录一下hub login(token='hf_XXX') ##hf_XXX 替换成你自己的hub账号的token peft_config = LoraConfig(task_type=TaskType.SEQ_CLS, target_modules=['layer_1','layer_2'], inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1) #下载xlnet-base-cased模型 model_base = 'xlnet-base-cased' device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = AutoModelForSequenceClassification.from_pretrained(model_base, num_labels=2) print(model) #用peft封装模型 model = get_peft_model(model,peft_config) model.print_trainable_parameters() model = model.to(device) tokenizer = AutoTokenizer.from_pretrained(model_base,max_length=350) def preocess_tokenize(exam): return tokenizer(exam['text'],truncation=True,padding=True) #下载数据集 imdb = load_dataset('imdb') tokenized_imdb = imdb.map(preocess_tokenize,batched=True) #设置评估指标 accuracy = evaluate.load("accuracy") def compute_metrics(eval_pred): predictions, labels = eval_pred predictions = np.argmax(predictions, axis=1) return accuracy.compute(predictions=predictions, references=labels) #设置训练参数 bts = 1 accumulated_step = 2 training_args = TrainingArguments( output_dir=f"imdb_{model_base.replace('-','_')}", learning_rate=2e-5, per_device_train_batch_size=bts, per_device_eval_batch_size=bts, num_train_epochs=1, weight_decay=0.01, evaluation_strategy="epoch", save_strategy="epoch", load_best_model_at_end=True, push_to_hub=True, gradient_accumulation_steps=accumulated_step, ) #配置训练器 trainer = Trainer( model=model, args=training_args, train_dataset=tokenized_imdb["train"], eval_dataset=tokenized_imdb["test"], tokenizer=tokenizer, compute_metrics=compute_metrics, ) #训练并上传 print(f'Start to Train {model_base}') trainer.train() print('Success!') trainer.push_to_hub() print('Success to push the model to huggingface') if __name__ =='__main__': train_lora()inference
以下是我训练号一个peftmodel = Siki-77/imdb_xlnet_base_cased,使用它去判断其他样本的过程如下
from peft import PeftModel, PeftConfig from transformers import AutoModelForSequenceClassification config = PeftConfig.from_pretrained("Siki-77/imdb_xlnet_base_cased") model = AutoModelForSequenceClassification.from_pretrained("xlnet-base-cased") model = PeftModel.from_pretrained(model, "Siki-77/imdb_xlnet_base_cased") tokenizer = AutoTokenizer.from_pretrained(model_base,max_length=350) inputs = tokenizer("Preheat the oven to 350 degrees and place the cookie dough", return_tensors="pt") with torch.no_grad(): logits = model(**inputs).logits label = logits.argmax().item() # 这里是2分类,因此 label=0 或1以上例子结束,代码完全跑的通,很简单的代码流程。
说明下target_modules这个参数(可选)
这一小节回答以下问题:
- 任意的模型进行LoRA微调的话,需要怎么设置target modules 这个参数呢??
- 省流回答:target module 只能选择以下几类层的名称
-torch.nn.Linear, torch.nn.Embedding, torch.nn.Conv2d, transformers.pytorch_utils.Conv1D
本节主要补充一下 peft_config两个关键参数说明:
peft_config = LoraConfig( task_type=TaskType.SEQ_CLS, target_modules=['layer_1','layer_2'], inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1)- task_type表示要微调的模型类型,TaskType.SEQ_CLS表示文本分类模型,
- target_modules 表示用更少参数代替的层(只允许 linear
- 其他参数默认
如,我用的pre-trained model = xlnet-base-cased,它的模型结构如上图所示,一般lora压缩的是堆叠好几层的模块的 linear/conv层,这里只有名为“layer-1”“layer-2”的线性层,因此
target_modules=['layer_1','layer_2'],
如果我设置了unsupport layer的名称为 target modules,将会报错,如下
peft_config = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, target_modules=["layer_norm"],## "layer_norm" is non-linear layer task_type=TaskType.SEQ_CLS, # this is necessary )报错信息如下
Currently, only the following modules are supported: torch.nn.Linear, torch.nn.Embedding, torch.nn.Conv2d, transformers.pytorch_utils.Conv1D
谈一下LoRA的当下的应用
随着GPT-3.5以来,越来越多大模型发布,甚至开源。如果要在本地微调这些大模型的话,基本全量微调是希望渺茫的(除非你的GPU内存真的超足),这种情况下,LoRA简直是天选之子,微调的首选方式。
真的十分有效,当然LoRA也不一定能解决存储不足的问题。
还有一个流行的“微调” promt,不微调参数,而是直接引导模型为我所用,很玄也很难定义怎么prompt才能“为我所用”。
相比于prompt微调,个人感觉LoRA还是可控性比较高的微调。
- 内存/存储空间不够
- LoRA微调什么? 预训练模型是 左边, Lora微调得到的模型是 右边。

![基于imdb的LoRA微调分类模型 Xlnet[简单例子,小白可上手]](https://img-blog.csdnimg.cn/direct/f31a81ded2644ab6b9fe591187a9f672.png)
![基于imdb的LoRA微调分类模型 Xlnet[简单例子,小白可上手]](https://img-blog.csdnimg.cn/direct/9a8dbd345aab46e7a11231e55bb62e6c.png)
![基于imdb的LoRA微调分类模型 Xlnet[简单例子,小白可上手]](https://img-blog.csdnimg.cn/direct/f2e2f256390f4fe6ba8a8f740923da75.png)