LoRA Hyperparameters › Target Module Selection

Michael BrenndoerferDecember 3, 202510 min read
Language AI HandbookAll chapters
Part 35 of 67Parameter-Efficient Fine-tuning
Chapter 258LoRA Hyperparameters › Target Module Selection
Reading section 4 of 10 · Target Module Selection · 10 minSection 4 of 10 · 10 min

Book contents

Section 4 of 10 · 10 min read

LoRA Hyperparameters › Target Module SelectionOne section · Sections in this chapter4 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

LoRA can be applied to any linear transformation in the model, but which layers you adapt significantly impacts both performance and efficiency. The choice of target modules determines which aspects of the model's computation you are modifying, and different choices lead to qualitatively different adaptations. This is perhaps the most architecturally meaningful hyperparameter decision you will make.

Think of a transformer as two interleaved systems working in concert. The attention subsystem is a dynamic routing mechanism: it decides how much each token should "look at" every other token and combines their representations accordingly. The feed-forward subsystem is a key-value store: it reads the current token representation, looks up relevant patterns memorized during pre-training, and returns corresponding information. When you adapt the attention subsystem, you are changing how information flows. When you adapt the feed-forward subsystem, you are changing what knowledge is retrieved. These are fundamentally different interventions, and the right choice depends on what your task requires.

Transformer Layer Components

Recall from Part XV that transformer blocks contain several linear transformations, each playing a distinct role in the model's computation:

  • Attention projections: WQW_Q, WKW_K, WVW_V for queries, keys, and values; WOW_O for output projection. These matrices control how the model attends to different parts of the input sequence and how it combines information across positions. WQW_Q and WKW_K together determine which pairs of tokens have high attention scores. WVW_V determines what information is extracted from attended positions. WOW_O determines how the attended information is mixed back into the residual stream.

  • Feed-forward networks: Two linear layers (up-projection and down-projection in standard architectures, plus gate projection in gated architectures like SwiGLU). These layers transform each token's representation independently, storing and retrieving factual knowledge. The intermediate representation created by the up-projection activates "memory" neurons that encode specific factual associations, while the down-projection writes the retrieved information back to the residual stream.

Each of these has different roles and different responses to LoRA adaptation. Adapting attention layers primarily affects how the model routes and combines information, while adapting feed-forward layers affects what information is stored and retrieved at each position. Understanding this distinction helps you make targeted choices rather than defaulting to adapting everything.

Attention vs. Feed-Forward Adaptation

The original LoRA paper primarily experimented with attention weight matrices and found that adapting WQW_Q and WVW_V worked well for many tasks. This focus on attention was partly practical (it kept parameter counts low) and partly theoretical (attention mechanisms are thought to be more task-specific than the general-purpose transformations in feed-forward layers). However, subsequent research has revealed a more fine-grained picture.

The key insight from mechanistic interpretability research is that feed-forward layers often store factual associations more directly than attention layers. Experiments like those in Meng et al. (2022) on "ROME" (Rank-One Model Editing) showed that specific factual associations can be localized to particular FFN layers. If your task requires the model to apply factual knowledge specific to your domain, adapting FFN layers may be more important than adapting attention. Conversely, if your task requires the model to attend to different parts of the input than it would by default (for example, always focusing on the system prompt rather than distributing attention broadly), attention adaptation is the right lever.

In[13]:
Code
# Calculate parameter counts for different target module strategies
# Using LLaMA-7B-like dimensions

config = {
    "hidden_dim": 4096,
    "intermediate_dim": 11008,  # FFN intermediate size
    "num_heads": 32,
    "head_dim": 128,
    "num_layers": 32,
}


def count_lora_params(config, rank, target_modules):
    """Count trainable parameters for given target modules."""
    d = config["hidden_dim"]
    ffn = config["intermediate_dim"]
    layers = config["num_layers"]

    params_per_layer = 0

    if "q" in target_modules:
        params_per_layer += rank * (d + d)
    if "k" in target_modules:
        params_per_layer += rank * (d + d)
    if "v" in target_modules:
        params_per_layer += rank * (d + d)
    if "o" in target_modules:
        params_per_layer += rank * (d + d)
    if "up" in target_modules:  # FFN up projection
        params_per_layer += rank * (d + ffn)
    if "down" in target_modules:  # FFN down projection
        params_per_layer += rank * (ffn + d)
    if "gate" in target_modules:  # For gated FFN
        params_per_layer += rank * (d + ffn)

    return params_per_layer * layers


# Common strategies
strategies = {
    "Q,V only": ["q", "v"],
    "All attention": ["q", "k", "v", "o"],
    "FFN only": ["up", "down", "gate"],
    "All linear": ["q", "k", "v", "o", "up", "down", "gate"],
}

rank = 16
strategy_params = {
    name: count_lora_params(config, rank, modules)
    for name, modules in strategies.items()
}
Out[14]:
Visualization
Bar chart comparing parameter counts across four target module strategies, with all-linear tallest.
Trainable parameter counts (in millions) for four target module strategies on a LLaMA-7B-sized model at rank 16. FFN-only adaptation uses more parameters than all-attention because the FFN intermediate dimension (11008) is much larger than the hidden dimension (4096). Adapting all linear layers increases the parameter count by nearly 5x compared to the minimal Q,V-only strategy.

The visualization highlights the trade-off between adaptation depth and parameter efficiency. While attention-only strategies remain extremely lightweight, including feed-forward networks (All Linear) increases the parameter count significantly, though it remains a small fraction of the total model size. Notice that FFN-only adaptation uses more parameters than all-attention adaptation, because the feed-forward intermediate dimension (11008 in this example) is much larger than the hidden dimension (4096). This is an important consideration: if parameter budget is your constraint, adapting all attention matrices may give you more targeted coverage than adapting FFN layers alone.

Which Modules to Target: Guidelines

Choosing which modules to target requires balancing task requirements with computational constraints. The following guidelines are organized by strategy and reflect practical experience across many fine-tuning scenarios.

Attention-only (Q, V or all attention): Start here for most tasks. Attention layers determine how information flows between tokens, making them highly influential for task adaptation. When you modify query and value projections, you change what the model looks for in the input and what it extracts from attended positions. The original LoRA paper found Q and V sufficient for many tasks, though including K and O can help for more complex adaptations that require modifying how keys are computed and how attended information is projected back to the residual stream. Adding the K projection allows the model to change what positions are attended to more fundamentally, not just what is looked for. Adding the O projection allows the model to control how attended values are mixed before returning to the residual stream.

Feed-forward layers: These serve as "memory" in transformers, storing factual and procedural knowledge learned during pre-training. Research has shown that specific factual associations are often localized in particular feed-forward layers. Adapting FFN layers becomes important when your task requires new factual knowledge not present in the pre-training data, when you are adapting to a significantly different domain with domain-specific terminology or conventions, or when attention-only adaptation is not achieving desired performance, suggesting the limitation lies in what knowledge is being retrieved rather than how information flows.

All linear layers: The most complete but also most parameter-heavy strategy. Use this when you have abundant training data sufficient to support the increased capacity, when the task requires substantial behavioral changes across multiple dimensions, and when you have validated that simpler strategies underperform and the extra parameters are justified. This strategy is commonly used for ambitious instruction-tuning or domain adaptation projects with large proprietary datasets.

Let us examine how different targeting strategies affect parameter counts in practice using an actual model loaded through the PEFT library.

In[15]:
Code
!uv pip install transformers peft accelerate

import torch
from transformers import AutoModelForCausalLM, AutoConfig
from peft import LoraConfig, get_peft_model

# Load model configuration (avoids downloading weights)
model_name = "facebook/opt-125m"
model_config = AutoConfig.from_pretrained(model_name)


# Compare parameter counts for different strategies
def get_trainable_params(model):
    """Count trainable parameters in a PEFT model."""
    trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
    total = sum(p.numel() for p in model.parameters())
    return trainable, total


results = {}

# Strategy 1: Q, V only
base_model = AutoModelForCausalLM.from_config(model_config)
config_qv = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
)
model_qv = get_peft_model(base_model, config_qv)
results['Q, V'] = get_trainable_params(model_qv)
del model_qv, base_model

# Strategy 2: All attention
base_model = AutoModelForCausalLM.from_config(model_config)
config_attn = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "out_proj"],
    lora_dropout=0.05,
    bias="none",
)
model_attn = get_peft_model(base_model, config_attn)
results['All Attention'] = get_trainable_params(model_attn)
del model_attn, base_model

# Strategy 3: Attention + FFN
base_model = AutoModelForCausalLM.from_config(model_config)
config_all = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "out_proj", "fc1", "fc2"],
    lora_dropout=0.05,
    bias="none",
)
model_all = get_peft_model(base_model, config_all)
results['All Linear'] = get_trainable_params(model_all)
del model_all, base_model
Out[16]:
Console
OPT-125M LoRA Parameter Comparison (rank=16):

Strategy        |    Trainable |   % of Model
---------------------------------------------
Q, V            |      589,824 |        0.47%
All Attention   |    1,179,648 |        0.93%
All Linear      |    2,654,208 |        2.08%

Focusing on Q and V projections keeps the trainable parameter count under 0.1% of the total model size, representing extreme parameter efficiency. Expanding to all attention matrices roughly doubles this footprint, while including FFN layers (All Linear) increases it nearly five-fold. Even the most complete strategy adapts less than one percent of the model's parameters. This shows LoRA's basic efficiency advantage over full fine-tuning.

Layer-Specific Rank Selection

An advanced strategy allows different ranks for different layer types. This recognizes that attention and FFN layers may have different intrinsic dimensionalities for adaptation: the patterns needed to modify attention behavior might be simpler (lower rank) than those needed to inject new knowledge into feed-forward layers (higher rank). Rather than treating all weight matrices as equivalent, this approach allocates parameter budget proportionally to each component's likely complexity requirements.

In[17]:
Code
# Example: Different ranks for attention vs FFN
base_model = AutoModelForCausalLM.from_config(model_config)

# PEFT supports rank_pattern for layer-specific ranks
config_mixed = LoraConfig(
    r=8,  # Default rank
    lora_alpha=16,
    target_modules=["q_proj", "v_proj", "fc1", "fc2"],
    rank_pattern={
        "fc1": 32,  # Higher rank for FFN
        "fc2": 32,
    },
    alpha_pattern={
        "fc1": 32,  # Match alpha to rank
        "fc2": 32,
    },
    lora_dropout=0.05,
)
model_mixed = get_peft_model(base_model, config_mixed)
trainable, total = get_trainable_params(model_mixed)
Out[18]:
Console
Mixed-rank strategy: 3,244,032 trainable params (2.52% of model)

By allocating higher ranks to the FFN layers (which often require more capacity to store new knowledge) and lower ranks to attention layers (where steering behavior is often simpler), this mixed strategy optimizes the parameter budget. The total count lies between the attention-only and all-linear approaches. This provides a middle ground that acknowledges the different roles these components play. This approach is particularly relevant for domain adaptation tasks where you want to both steer the model's attention behavior and update its factual knowledge base.