Algorithm explanation
September 1, 2026 · View on GitHub
Basic Idea

Linear Layer
We fine-tune to get
LoRA-type methods focus on how we decompose
( and are respectively and in the above figure)
From LoRA to LoCon
LoRA for linear layers
--
LoRA for convolution
Consider im2col of matmul first:

and then write down this conventional LoRA for conv layer
In this method, we can get that with
--
LoRA for convolution with Tucker decomposition
Triggered by use_tucker=True
As mentioned above, the weight shape for convolution layer is , and we just unfold it to for decomposition.
But actually there is a method to decompose any shape of tensor more efficiently called Tucker decomposition.
Using Tucker decomposition in Covolution will give something like (with representing n-mode product):
Or write this thing as multiple conv layer:
Conv(in, dim, (1, 1))
↓
Conv(dim, dim, (kw, kh), stride, padding)
↓
conv(dim, out, (1, 1))
For hadamard product implementation, just use 2 different and multiply them together.
LoHa
Image from FedPara
Consider . We have . We then use conventional method on and , which means it can use 2x dim to get square rank.
Rank != Information capacity, but they may be related
Based on the experiment result from the paper, it seems like although is just an upper bound, almost everytime it will produce with .
Why custom backward
With , when you need to compute the backpropogation, you will need and to compute , and and to compute .
With pytorch's autograd, this kind of operation will cache both and for computing the backward, which means it will cache 2x size of weight for backward.
To avoid this terrible situation, LyCORIS implements a custom backward which will reconstruct and when actually needed, this method saved tons of memory.
LoKr
Kronercker Product
If is an matrix and is a matrix, then the Kronecker roduct of two matrices is an matrix.
In meaning of matrix, becomes weight and becomes weight scale of
About rank
And we can decompose using LoRA with rank .
then
We get , , and
=>
Put it simply, rank is mutiplicative under Kronecker product.
Number of parameters
We decompose matrix, , with ,
(# of parameters) =
When factor is set to -1, we roughly have and
then, (# of parameters) =
We can reduce the number of parameters to the order of square root of matrix width/height if we further decompose
As a sequence of linear layers
Sparse Bias
Todo...
T-LoRA
Motivation
Standard LoRA uses random initialization for its low-rank matrices. This means different rank components can learn correlated features, leading to interference. T-LoRA addresses this through SVD-based orthogonal initialization, ensuring each rank component captures independent information.
Additionally, diffusion models have different requirements at different noise levels:
- High noise (early denoising): Need structure-level adaptation
- Low noise (late denoising): Need detail-level adaptation
T-LoRA enables timestep-dependent rank masking to dynamically control how many ranks are active during training.
Mathematical Formulation
For a weight matrix , we compute its SVD:
We then initialize T-LoRA components from the top-k (or bottom-k, or middle-k) singular vectors:
(down projection, orthogonal rows)
(up projection, orthogonal columns)
(learnable singular values)
The weight delta is computed as:
The subtraction of the base state ensures that at initialization (when P, Q, equal their base values), the delta is zero regardless of the mask.
Timestep-Dependent Rank Masking
The mask is computed based on the current denoising timestep:
r = int(((max_timestep - timestep) / max_timestep) ** alpha * (max_rank - min_rank)) + min_rank
mask = [1, 1, ..., 1, 0, 0, ..., 0] # First r entries are 1
This creates a progression:
- At t=1000 (pure noise): only min_rank ranks active
- At t=500 (mid-denoising): roughly half ranks active
- At t=0 (final detail): all ranks active
Orthogonality Regularization
T-LoRA can optionally include an orthogonality regularization loss:
This encourages P and Q to remain orthogonal throughout training, preserving the independence of rank components.
sig_type Options
- principal: Use top-k singular vectors (largest singular values). Best for preserving the model's main learned features.
- last: Use bottom-k singular vectors (smallest singular values). Perturbs the "unused" subspace of the original weights.
- middle: Use middle-k singular vectors. Balances between principal and unused subspaces.
Usage with Training Frameworks
Training frameworks must set the timestep mask before each forward pass:
from lycoris.modules.tlora import set_timestep_mask, compute_timestep_mask
# In training loop:
mask = compute_timestep_mask(
timestep=current_timestep,
max_timestep=1000,
max_rank=lora_dim,
min_rank=1,
alpha=1.0,
)
set_timestep_mask(mask)
output = model(noisy_latents, timestep, ...)
As a sequence of operations
Input → Q (orthogonal projection) → scale by λ*mask → P (orthogonal projection) → Output
With residual subtraction from base state to ensure zero contribution at initialization.