Weight-Decomposed Low-Rank Adaptation (DoRA)
Weight-Decomposed Low-Rank Adaptation (DoRA) is a Parameter-Efficient Fine-Tuning (PEFT) technique introduced to bridge the performance gap between Standard Low-Rank Adaptation (LoRA) and full fine-tuning.
By decomposing pre-trained weights into magnitude and directional components and updating only the direction using low-rank matrices, DoRA achieves performance that matches or sometimes surpasses full fine-tuning while maintaining LoRA’s inference efficiency.
The Core Concept: Weight Decomposition
A weight matrix $W_0 \in \mathbb{R}^{d \times k}$ can be decomposed into a magnitude vector $m \in \mathbb{R}^{1 \times k}$ and a directional matrix $V \in \mathbb{R}^{d \times k}$:
$$W = m \cdot \frac{V}{|V|_c}$$
Where $|\cdot|_c$ denotes the vector $L_2$ norm of each column.
In full fine-tuning, both $m$ and $V$ are updated freely. In standard LoRA, the weight matrix is updated as:
$$W = W_0 + \Delta W = W_0 + B A$$
Where $B \in \mathbb{R}^{d \times r}$ and $A \in \mathbb{R}^{r \times k}$ are low-rank matrices. However, LoRA updates magnitude and direction together in a coupled manner, which differs fundamentally from the learning dynamics of full fine-tuning.
DoRA solves this by applying LoRA updates only to the directional component while keeping the magnitude component parameterized separately.
How DoRA Works
DoRA initializes its magnitude vector $m$ from the pre-trained weights $W_0$:
$$m = |W_0|_c$$
The directional matrix is initialized as $V = W_0$. During fine-tuning, the directional matrix $V$ is updated using a standard low-rank LoRA adapter $\Delta V = B A$:
$$W = m \cdot \frac{W_0 + B A}{|W_0 + B A|_c}$$
Here:
- $m$ (magnitude) is a learnable vector of size $1 \times k$.
- $B$ and $A$ are learnable low-rank matrices (initialized such that $BA = 0$).
- $W_0$ remains frozen.
By splitting the updates into magnitude and direction, DoRA allows the optimizer to adjust magnitude adjustments and direction adjustments independently. Empirical studies show that full fine-tuning tends to make updates that are highly decoupled (large changes in direction with minimal changes in magnitude, or vice versa). DoRA replicates this decoupling behavior, whereas standard LoRA shows a strong positive correlation between magnitude and direction updates.
Key Advantages of DoRA
- Closer to Full Fine-Tuning: DoRA matches full fine-tuning performance on complex tasks (e.g., math reasoning, instruction following) where standard LoRA often falls short.
- No Extra Inference Latency: Just like LoRA, the adapters ($B$ and $A$) and the magnitude vector ($m$) can be folded back (merged) into the base weight matrix $W_0$ before deployment.
- Robustness to Rank Size: DoRA performs exceptionally well even at lower ranks ($r = 4$ or $r = 8$), reducing the memory overhead of training.
Implementing DoRA with PEFT
Hugging Face’s peft library supports DoRA natively. You simply need to set use_dora=True in the LoraConfig.
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer
# 1. Load base model and tokenizer
model_id = "meta-llama/Llama-3-8B"
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_id)
# 2. Define LoRA Config with DoRA enabled
peft_config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
use_dora=True, # <-- Activates DoRA instead of standard LoRA
)
# 3. Wrap model with PEFT
dora_model = get_peft_model(model, peft_config)
# Print trainable parameters to verify efficiency
dora_model.print_trainable_parameters()
Tuning Tips for DoRA
- Learning Rate: DoRA can benefit from slightly higher learning rates compared to standard LoRA, as the magnitude parameters learn quickly and stabilize training.
- Target Modules: Just like LoRA, targeting all linear layers (Q, K, V, O, gate, up, down projections) yields the best performance.
- Rank Selection: If you have memory constraints, try reducing the rank $r$ to $4$ or $8$ first before sacrificing target modules, as DoRA maintains performance better than LoRA at lower ranks.