Prefix Tuning

wen IT资讯 21

本文目录导读:

Prefix Tuning

  1. The Core Idea
  2. How it Works (Conceptual)
  3. Why Use Prefix Tuning? (Pros)
  4. Cons and Limitations
  5. Comparison with Similar Methods
  6. Reparameterization (The "Trick" for Stability)
  7. Practical Example (Conceptual Code)
  8. Summary

Prefix Tuning is a parameter-efficient fine-tuning technique for large language models (LLMs). Instead of modifying the weights of the pre-trained model (which is expensive), it prepends a set of learnable, continuous vectors (a "prefix") to the input of each Transformer layer.

Here is a breakdown of how it works, why it is used, and how it differs from similar methods.

The Core Idea

In standard fine-tuning, you take the pre-trained weights $W$ and update them to $W'$ for a specific task. This requires storing a full copy of the model for each task.

Prefix Tuning keeps the original model weights frozen.

  • It introduces a small, new set of parameters: the "prefix."
  • These prefixes act like a "virtual task embedding" or "context" that steers the model toward a specific behavior.
  • Only the parameters of the prefix are updated during training.

How it Works (Conceptual)

A Transformer decoder layer typically has two main components:

  1. Self-Attention (where tokens attend to previous tokens)
  2. Cross-Attention (usually in encoder-decoder models) or Feed-Forward Network (FFN)

Prefix Tuning modifies the keys and values of the attention mechanism.

The Mechanics:

  1. Standard Attention: In a standard layer, you have an input sequence $X = [x_1, x_2, ..., x_n]$. This is projected into Queries ($Q$), Keys ($K$), and Values ($V$).
  2. Prefix Insertion: For a prefix of length $L$, you create two matrices: $P_K \in \mathbb{R}^{L \times d_k}$ (key prefix) and $P_V \in \mathbb{R}^{L \times d_v}$ (value prefix).
  3. Concatenation: These learnable vectors are prepended to the original $K$ and $V$ matrices. The attention mechanism then operates on the concatenated sequence:
    • New $K' = [P_K; K]$
    • New $V' = [P_V; V]$
  4. Training: The model computes the loss (e.g., cross-entropy for language modeling). Gradients flow back to update only the prefix matrices $P_K$ and $P_V$ (and optionally an MLP that reparameterizes them for stability). The pre-trained model weights remain untouched.

Note: The queries ($Q$) are not modified. This means the original input tokens attend to the prefix tokens, allowing the prefix to influence the representation of every subsequent token.

Why Use Prefix Tuning? (Pros)

  • Massive Memory/Storage Savings: Instead of saving a full 7B parameter model for each task (e.g., sentiment analysis, summarization, translation), you only save a small prefix (e.g., a few hundred thousand parameters). This enables "one model, many tasks."
  • Parameter Efficiency: You only train a tiny fraction of the total parameters (often < 0.1%).
  • Prevents Catastrophic Forgetting: Because the original weights are frozen, the model retains its general knowledge from pre-training. The prefix only adapts its behavior.
  • Composable: You can theoretically swap prefixes for different tasks without loading new model weights.
  • Works well for NLG: It is particularly effective for generative tasks.

Cons and Limitations

  • Inference Speed: Because the prefix is prepended to the sequence, the effective sequence length increases. This leads to slightly higher latency and memory consumption during inference (since attention is $O(n^2)$).
  • Not as "Strong" as Full Fine-Tuning: For very specialized tasks or out-of-distribution data, full fine-tuning or LoRA might achieve slightly higher accuracy (though the gap is often small).
  • Architecture Specific: Prefix Tuning works best with autoregressive models (GPT) and encoder-decoder models (T5). It is less intuitive for pure encoder models (BERT).

Comparison with Similar Methods

Feature Prefix Tuning LoRA (Low-Rank Adaptation) Adapter Layers
What is added? Learnable "virtual tokens" prepended to $K$ and $V$ Low-rank matrices injected into the weight matrices ($W_q$, $W_v$) Small bottleneck feed-forward layers inserted between existing layers
Where is it added? Input to attention layers (concatenation) Parallel to the weight matrices (addition) Series between layers (insertion)
Inference Overhead Higher (increased sequence length) Negligible (matrices are merged into weights) Slightly higher (extra computation path)
Popularity Pioneering, used in early LLM adapters Most popular (standard for LLMs like Llama, Stable Diffusion) Common in NLP (e.g., BERT)

Key Difference from LoRA:

  • LoRA learns a delta ($\Delta W$) on the weight matrices. At inference, you can merge LoRA weights into the original model ($W' = W + \Delta W$) with zero overhead.
  • Prefix Tuning cannot be merged because it manipulates the sequence of tokens. It always adds computational cost.

Reparameterization (The "Trick" for Stability)

In the original paper (Li & Liang, 2021), the authors found that directly optimizing the prefix vectors ($P_K, P_V$) led to unstable training. Their solution was reparameterization:

  • Instead of learning $P_K$ and $P_V$ directly, they learned a smaller matrix (a "prompt encoder," often an MLP or LSTM) that generated the prefix.
  • $P_K = MLP(P'_K)$
  • During training, only the MLP parameters are updated. During inference, the MLP is used once to create the prefix, and then discarded.

This made the optimization much more stable.

Practical Example (Conceptual Code)

Here is a simplified pseudo-code illustration using PyTorch and a Hugging Face Transformers model:

import torch
import torch.nn as nn
from transformers import GPT2LMHeadModel
class PrefixTuningGPT(nn.Module):
    def __init__(self, base_model_name='gpt2', prefix_length=10, hidden_dim=768):
        super().__init__()
        self.gpt = GPT2LMHeadModel.from_pretrained(base_model_name)
        # Freeze the base model
        for param in self.gpt.parameters():
            param.requires_grad = False
        self.prefix_length = prefix_length
        self.n_layers = self.gpt.config.n_layer
        self.n_head = self.gpt.config.n_head
        self.n_embd = self.gpt.config.n_embd
        # Reparameterization MLP
        self.mlp = nn.Sequential(
            nn.Linear(hidden_dim, 2 * self.n_layers * self.n_head * self.n_embd // self.n_head),
            nn.Tanh(),
            nn.Linear(2 * self.n_layers * self.n_head * self.n_embd // self.n_head, 2 * self.n_layers * ...)
        )
        # Learnable prompt embedding
        self.prompt_embedding = nn.Parameter(torch.randn(prefix_length, hidden_dim))
    def forward(self, input_ids, attention_mask):
        batch_size = input_ids.shape[0]
        # Generate prefix for all layers
        prefix_output = self.mlp(self.prompt_embedding)  # [L, 2 * n_layers * n_head * d_k]
        # Reshape into (n_layers, 2, batch, n_head, L, d_k)
        # ... (complex reshaping to match GPT2 attention K/V structure)
        # Pass through GPT model with the prefix argument
        # Forward hook or custom layer replaces the K,V with concatenated K_prefix, V_prefix
        outputs = self.gpt(input_ids=input_ids, 
                          past_key_values=prefix_kv, 
                          attention_mask=attention_mask)
        return outputs.loss
# Training loop
model = PrefixTuningGPT()
optimizer = torch.optim.Adam(model.mlp.parameters(), lr=5e-5)
for batch in dataloader:
    loss = model(**batch)
    loss.backward()
    optimizer.step()

Summary

Prefix Tuning is a smart method to adapt large language models without retraining them. It works by learning a short sequence of "fake tokens" that are prepended to every layer's attention mechanism, steering the model's behavior. While it is slightly slower at inference than LoRA, it was a groundbreaking technique that proved you don't need to update the core weights to get strong task-specific performance.

抱歉,评论功能暂时关闭!