萱仔大模型学习记录3.2-BERT算法微调理论和实践Adapter_Tuning、Prefix_Tuning等
3.Adapter Tuning 原版论文:https://arxiv.org/pdf/1902\.00751\.pdf
原版代码:GitHub - google-research/adapter-bert
Adapter Tuning 是一种在预训练模型的基础上进行高效微调的方法。通过插入adapter modules,只需增加少量可训练参数,就能使模型在新任务上取得优异的性能。(我个人感觉这个在使用上和lora有点类似,lora是引入了两个矩阵,在外面训练微调,较低成本实现训练任务。这个是加入一个适配器的模块。 Adapter Modules 是插入到现有预训练模型中的小型网络层。由少量可训练参数组成,通常包括一个下采样层、一个ReLU之类的非线性激活层,以及一个上采样层。(这一点又和计算机视觉中有一点点像,上采样和下采样各有作用,然后加上激活函数的非线性函数,加入到神经网络中可以让网格拟合非线性映射。 Adapter Modules 插入位置通常在Transformer层之间。)
在适配器微调过程中,预训练模型的参数保持不变。只训练适配器模块的参数,从而实现参数高效的迁移学习。相比于传统的微调,适配器微调只需增加很少的新参数,但能够取得接近或甚至超越全量微调的效果。适配器模块可以独立于任务进行训练,适应多任务学习的需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 import torch from transformers import BertModel, BertTokenizer, BertForSequenceClassification, AdapterConfig # 加载预训练BERT模型和Tokenizer model_name = "bert-base-uncased" tokenizer = BertTokenizer.from_pretrained(model_name) model = BertForSequenceClassification.from_pretrained(model_name) # 冻结BERT主体模型的所有参数 for param in model.bert.parameters(): param.requires_grad = False # 添加适配器模块配置 adapter_config = AdapterConfig( hidden_size=64, # 适配器模块的隐藏层大小 adapter_non_linearity="relu", # 非线性激活函数 reduction_factor=16 # 下采样比例 ) # 为分类任务添加适配器 model.add_adapter("text_classification_adapter", config=adapter_config) model.train_adapter("text_classification_adapter") # 示例输入 inputs = tokenizer("This is a test sentence.", return_tensors="pt") # 模型预测前向传播 outputs = model(**inputs) # 打印模型输出 print(outputs.logits) # 准备训练数据(以GLUE任务中的MRPC数据集为例) from datasets import load_dataset dataset = load_dataset("glue", "mrpc") train_dataset = dataset['train'] validation_dataset = dataset['validation'] # 数据处理函数 def preprocess_function(examples): return tokenizer(examples['sentence1'], examples['sentence2'], truncation=True, padding=True) # 预处理数据 train_dataset = train_dataset.map(preprocess_function, batched=True) validation_dataset = validation_dataset.map(preprocess_function, batched=True) # 数据加载器 from torch.utils.data import DataLoader train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True) validation_loader = DataLoader(validation_dataset, batch_size=16) # 定义优化器和损失函数 from transformers import AdamW optimizer = AdamW(model.parameters(), lr=5e-5) loss_fn = torch.nn.CrossEntropyLoss() # 训练适配器 model.train() for epoch in range(3): # 训练3个epoch for batch in train_loader: inputs = {k: v.to(model.device) for k, v in batch.items() if k in tokenizer.model_input_names} labels = batch['label'].to(model.device) optimizer.zero_grad() outputs = model(**inputs) loss = loss_fn(outputs.logits, labels) loss.backward() optimizer.step() print(f"Epoch {epoch + 1}: Loss {loss.item()}") # 验证模型 model.eval() correct_predictions = 0 total_predictions = 0 with torch.no_grad(): for batch in validation_loader: inputs = {k: v.to(model.device) for k, v in batch.items() if k in tokenizer.model_input_names} labels = batch['label'].to(model.device) outputs = model(**inputs) predictions = torch.argmax(outputs.logits, dim=-1) correct_predictions += (predictions == labels).sum().item() total_predictions += labels.size(0) accuracy = correct_predictions / total_predictions print(f"Validation Accuracy: {accuracy}") # 保存适配器 model.save_adapter("text_classification_adapter", "output_adapter_directory")
4.Prefix Tuning输入增加可训练的上下文前缀 原版论文: https://arxiv.org/pdf/2101.00190.pdf
原版代码:
Fine-tuning是利用大型预训练语言模型来执行下游任务的默认方式。然而,微调会修改所有语言模型的参数,因此需要为每个任务存储一份完整的副本。本文提出了一种轻量级的微调替代方法——前缀调优prefix-tuning,专用于自然语言生成任务。前缀调优保持语言模型参数不变,仅优化一个小的任务特定的连续向量(称为前缀)。前缀调优受提示(prompting)的启发,允许后续的token关注这个前缀,仿佛它们是“虚拟token”。这篇论文将前缀调优应用于GPT-2进行表格到文本生成,以及BART进行摘要生成。结果表明,通过仅学习0.1%的参数,前缀调优在完整数据集环境中获得了与全量微调相当的性能,在低数据环境中表现优于微调,并且在训练时未见过主题的例子上具有更好的外推能力。
Prefix Tuning 是一种在预训练语言模型(如 BERT 或 GPT-2)基础上进行高效微调的方法。与传统的微调方式不同,Prefix Tuning 只调整少量的前缀参数,而不修改原始模型的参数,从而在多个任务之间实现高效迁移。
前缀参数(Prefix Parameters)
:
* 前缀参数是在每层 Transformer 网络的输入前增加的一组可训练参数。
* 这些参数在模型进行任务特定的微调时可以独立更新,而无需调整原始模型的参数。
冻结预训练模型
:
* 在 Prefix Tuning 过程中,预训练模型的参数保持不变。
* 只训练前缀参数,从而实现高效的参数更新和迁移学习。
高效微调
:
* 相比于传统的微调,Prefix Tuning 只需调整少量的前缀参数,但能够取得接近或甚至超越全量微调的效果。
* 前缀参数可以独立于任务进行训练,适应多任务学习的需求。
总结
传统微调的局限性 :
修改所有语言模型参数,需要为每个任务存储一个完整的模型副本。
前缀调优的优势 :
保持语言模型参数不变,仅优化前缀参数。
通过仅学习0.1%的参数,前缀调优在全数据集设置中获得了可比的性能,在低数据设置中表现优于微调,并在训练中未见的主题上表现更好。
应用场景 :
前缀调优适用于自然语言生成任务,如表格到文本生成和摘要生成。
所有P-tuning都是基于优化连续的prefix或者prompt的思想。调整软提示优于先前对离散提示优化的工作。Prompt-tuning的工作表明全量微调和P*-tuning之间的性能差距随着模型的大小增大而消失。
5.Prompt Tuning输入增加可训练的嵌入向量提示