Prefix-tuning

核心概念:
        前缀序列:一个可训练的序列,插入到输入序列的前面,用于引导模型生成特定任务的输出。
        参数冻结:在微调过程中,预训练模型的参数保持不变,只训练前缀序列的参数。
        任务特定:前缀序列可以根据不同的任务进行训练,使得模型能够适应多种任务。
工作原理:

        1.前缀序列的插入:
                在输入序列之前插入一个可训练的前缀序列。这个前缀序列可以看作是任务特定的提示,用于引导模型生成特定任务的输出。前缀序列的长度通常较短,例如几十个token。
        2.模型结构:
                假设我们有一个预训练的语言模型 M,输入序列为 x,前缀序列为 p。
                在微调过程中,模型的输入变为 [p,x],即前缀序列和输入序列的拼接。
                模型的输出仍然是基于整个输入序列 [p,x] 生成的。
        3.训练过程:
                只有前缀序列的参数在微调过程中被更新,预训练模型的参数保持不变。
                通过反向传播,优化前缀序列的参数,使其能够引导模型生成特定任务的输出。

实现细节:
  1. 定义前缀序列

    • 前缀序列通常是一个随机初始化的张量,形状为 [1,prefixlength,hiddensize],其中 prefix_length 是前缀序列的长度,hidden_size 是模型的隐藏层大小。
    • 前缀序列可以插入到模型的每个Transformer层之前,或者只插入到第一个Transformer层之前。

      2.插入前缀序列:

import torch
import torch.nn as nn
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# 加载预训练的GPT-2模型和分词器
model = GPT2LMHeadModel.from_pretrained("gpt2")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")

# 定义前缀序列的长度和隐藏层大小
prefix_length = 10
hidden_size = model.config.hidden_size

# 初始化前缀序列
prefix = nn.Parameter(torch.randn(1, prefix_length, hidden_size))

def add_prefix(input_ids):
    prefix_ids = prefix.repeat(input_ids.size(0), 1, 1)
    input_embeddings = model.transformer.wte(input_ids)
    prefixed_input = torch.cat([prefix_ids, input_embeddings], dim=1)
    return prefixed_input

# 输入示例
input_text = "Translate English to French: Hello"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids

# 插入前缀序列
prefixed_input = add_prefix(input_ids)

# 通过模型
outputs = model(inputs_embeds=prefixed_input)
logits = outputs.logits

      3.训练:

from transformers import Trainer, TrainingArguments

# 定义训练参数
training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=8,
    per_device_eval_batch_size=16,
    warmup_steps=500,
    weight_decay=0.01,
    logging_dir="./logs",
)

# 定义训练数据集
train_dataset = ...  # 你的训练数据集
eval_dataset = ...   # 你的验证数据集

# 定义训练器
class PrefixTuningTrainer(Trainer):
    def compute_loss(self, model, inputs, return_outputs=False):
        prefixed_input = add_prefix(inputs["input_ids"])
        outputs = model(inputs_embeds=prefixed_input, labels=inputs["labels"])
        loss = outputs.loss
        return (loss, outputs) if return_outputs else loss

# 创建训练器
trainer = PrefixTuningTrainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
)

# 开始训练
trainer.train()

优势
        参数效率:相比于全模型微调,Prefix Tuning 只需要训练前缀序列的参数,大大减少了计算资源的消耗。
        任务适应性:前缀序列可以根据不同的任务进行训练,使得模型能够适应多种任务。
        灵活性:可以轻松地将新的任务添加到现有的前缀集合中,而不需要重新训练整个模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值