np-lora: null space projection for subject-style lora fusion

Nov 5, 2026 | ml, lora, wip

Status: work in progress. These are my reading notes on the paper, written while working through the math. Expect gaps and rough edges.

We write a LoRA matrix, \({}\Delta \mathbf{W}{}\) as: \(\Delta \mathbf{W}=\mathbf{BA}\) where \({}\mathbf{A}{}\) is the up-projection matrix and \({}\mathbf{B}{}\) is the down-projection matrix.

The LoRA matrix can be SVD decomposed as: \(\Delta \mathbf{W} = \mathbf{U\Sigma V^\top}\)

The vectors in \(\mathbf{V}\) identify at most \(r\) input directions that the update can detect.

\(\Delta W \in ℝ^{(m × n)}\), rank \((\Delta W) = r\)

\(U \in \mathbb{R}^{m \times r}, \Sigma \in \mathbb{R}^{r \times r}, V \in \mathbb{R}^{n \times r},\) \(\Sigma\) has \(r\) singular values.

rank(\(U\)) = rank(\(V\)) = rank(\(\Sigma\)) = r

\(V^T x\)

The vectors in \(U\) identify at most \(r\) output directions that the update can produce.

This means that once we have calculated the signed lengths of the projections of \(x\) along the right singular vectors \(v_i\), we multiply \(V^Tx\) with \(U\) which contains the left singular vectors. They are the normalized eigen basis of \(AA^T\).

Rank-one LoRA example

For a rank-one update:

\[\Delta W = \sigma_1 u_1v_1^\top\]

Let:

\[v_1 = \left[1, 0\right]^\top, \qquad u_1 = \left[0, 1\right]^\top, \qquad \sigma_1 = 3\]

For input:

\[x = \left[2, 5\right]^\top\]

The component of \(x\) along \(v_1\) is:

\[v_1^\top x = 2\]

The LoRA update output is:

\[\Delta W x = 3 \cdot 2 \cdot \left[0, 1\right]^\top = \left[0, 6\right]^\top\]

Thus, the update adds \(6\) to the second coordinate of the base layer output. It adds nothing to the first coordinate.

If:

\[W_0x = \left[10, -1\right]^\top\]

then the adapted output is:

\[(W_0 + \Delta W)x = \left[10, -1\right]^\top + \left[0, 6\right]^\top = \left[10, 5\right]^\top\]

The vector \(v_1\) detects the first input coordinate. The vector \(u_1\) specifies the output direction that LoRA changes.

Questions

Content LoRA and style LoRA

content LoRA: dog

style LoRA: van gogh style

Both LoRAs can respond to similar hidden-state directions, such as texture or shape information. Their output changes can then conflict when direct merging adds both updates. \(\mathbf{P = V_k V_k} ^\top,\) where \(\mathbf{P} \in \mathbb{R}^{m \times m}\) and \(\mathbf{V_k} \in \mathbb{R}^{m \times k}\) is formed by selecting \(k\) vectors from the right singular matrix \(\mathbf{V}\) that have non-zero singular values in. \(\mathbf{P}\) takes an \(m\)-dimensional vector \(\mathbf{x}\) and finds \(k\)-coordinates which are projections along the singular directions in \({}\mathbf{V}{k}{}\), while doing so it reduces \(\mathbf{x}\) to \(k\)-dimensions. \({}\mathbf{V}{k}{}\) then brings it back to \(m\)-dimensional space and expresses the \(k\)-coordinates in terms of the standard basis. \({}\mathbf{V}{k}\mathbf{V}{k}^\top\mathbf{x}{}\) is a vector in the \(k\)-dimensional subspace in \({}\mathbb{R}^n{}\).

What does \(\mathbf{P}\) do?

\(\mathbf{P}\) transforms a given vector \(\mathbf{x}\) into another vector in the \(k\)-dimensional subspace in \(\mathbb{R}^n\), keeping only the components along \(\mathbf{V}{k}\). If \(V{k}\) correspond to the style directions in the LoRA \(\Delta \mathbf{W}_{S}\) then \(\mathbf{P}\) will keep only these input directions in \(\mathbf{x}\). \(\mathbf{I} - \mathbf{P}\) keeps the other input components.

\(\mathbf{P}\) can also be formed as: \(\mathbf{P}=\mathbf{Q}\mathbf{Q}^\top\) where \(\mathbf{Q}\) is formed as the QR-decomposition of the transpose of the up-projection matrix, \(\mathbf{A}^\top=\mathbf{QR}\). \(\mathbf{Q}\) and \(\mathbf{V}\) span the same subspace. This works when \(k=r\) but if we choose \(k<r\) then we have to use a method like SVD decomposition.

When both the style and content LoRA are applied: \(\Delta \mathbf{W}_{m} = \Delta \mathbf{W}_{s}+\Delta \mathbf{W}_{c}\)

\({}\Delta \mathbf{W}{s}{}\) and \({}\Delta \mathbf{W}{c}{}\) both update singular directions. Some of the directions are common to both the LoRA matrices and this causes a collision. The solution proposed by the authors of NP-LoRA is to “remove” the colliding singular vectors from one of the LoRA matrices and then merge the style and content LoRAs.

The content LoRA can be split into these two parts: \(\Delta \mathbf{W}_{c} = \Delta \mathbf{W}_{c}\mathbf{P}+\Delta \mathbf{W}_{c}(\mathbf{I}-\mathbf{P})\) The first terms acts on \({}\mathbf{P}\mathbf{x}{}\), the component of \({}\mathbf{x}{}\) in the style subspace. The second terms acts on \({}(\mathbf{I} - \mathbf{P})\mathbf{x}{}\), the component outside that subspace. In case of direct merging, the content LoRA can affect the subspace where the style LoRA acts. \(\Delta \mathbf{W}_{m}\mathbf{P} = \Delta \mathbf{W}_{s}+\Delta \mathbf{W}_{c}\mathbf{P}\) NP-LoRA use hard projection to avoid this issue: \(\Delta \mathbf{W}_{m} = \Delta \mathbf{W}_{s}+\Delta \mathbf{W}_{c}(\mathbf{I}-\mathbf{P})\) This way the update directions of content LoRA don’t collide with those of the style LoRA. \(\Delta \mathbf{W}_{m}\mathbf{P} = \Delta \mathbf{W}_{s}\) Instead of hard projection where the directions of the content LoRA along the style LoRA are eliminated, a soft projection approach would be as follow:

Let \({}\mathbf{X}{}\) be the changed content update.

\(\min_{\mathbf{X}} ||\mathbf{X} - \Delta \mathbf{W}_{c}||_{F}^2 + ||\mathbf{X}\mathbf{P}||_{F}^2\) The first term ensures that the content update \({}\mathbf{X}{}\) stays close to the original content update, \({}\Delta \mathbf{W}_{c}{}\) while the second term penalizes the part of \({}\mathbf{X}{}\) that acts on the style subspace.

The closed form solution is \({}\mathbf{X}=\Delta \mathbf{W}_{c}(\mathbf{I} + \mu \mathbf{P})^{-1}{}\). A more intuitive form is: \(\mathbf{X} = \Delta \mathbf{W}_{c}(\mathbf{I}-\mathbf{P}) + \frac{1}{1+\mu}\Delta \mathbf{W}_{c}\mathbf{P}.\)

The content update that doesn’t affect the style subspace remains the same while the part along that subspace is attenuated by a factor of \({}\frac{1}{1+\mu}{}\). When \(\mu=0\), direct merging happens while when \(\mu=\infty\), hard projection happens.

Projection without forming dense matrices

\({}\Delta \mathbf{W}{m}=\Delta \mathbf{W}{s} + \Delta \mathbf{W}_{c}(\mathbf{I}-\mathbf{P}){}\)

It can also be written as:

\({}\Delta \mathbf{W}{m}=\mathbf{B}{s}\mathbf{A}{s} + \mathbf{B}{c}\mathbf{A}_{c}(\mathbf{I-P}){}\)

We focus on the second part:

\({}\mathbf{B}{c}\mathbf{A}{c}(\mathbf{I-P}) = \mathbf{B}{c}\mathbf{A}{c}(\mathbf{I-QQ^\top})=\mathbf{B}{c}(\mathbf{\mathbf{A}{c}-\mathbf{A}_{c}QQ^\top}){}\)

We define \({}\mathbf{A}_{c}^\prime{}\) and introduce the \({}\mu{}\) parameter there: \(\mathbf{A}_{c}^\prime = \mathbf{\mathbf{A}_{c}-\frac{\mu}{1+\mu}\mathbf{A}_{c}QQ^\top}\)

The new equation becomes: \({}\Delta \mathbf{W}_{m}=\mathbf{B}_{s}\mathbf{A}_{s} + \mathbf{B}_{c}\mathbf{A}_{c}^\prime{}\) We can express this equation as a larger LoRA factor pair.

$$ \mathbf{B}{m} = \begin{bmatrix} \mathbf{B}{s} & \mathbf{B}{c} \end{bmatrix}

\mathbf{A}
{m} = \begin{bmatrix} \mathbf{A}{s}
\mathbf{A}^\prime
{c} \end{bmatrix} \ \

\Delta \mathbf{W}{m} = \mathbf{B}{m}\mathbf{A}_{m} $$ The rank of the style LoRA and the content LoRA are at most \(r_s\) and \(r_c\) resp. Therefore, as per the sub-additivity property, the rank of the merged LoRA is at most \(r_s + r_c\).

Evaluations

The style and content LoRAs are merged using different methods like NP-LoRA, K-LoRA, direct merging, etc. Each of the outputs of the merged LoRA are compared against the content and style images. This comparison is done using visual feature similarity methods like DINO and CLIP. The arithmetic mean and harmonic mean of the four comparisons are reported.

The harmonic mean is emphasized because it is penalized more than arithmetic mean if one of its input values is small.

\(S_{harmonic} = \frac{n}{\frac{1}{x_{1}} + \frac{1}{x_{2}} + \cdots \frac{1}{x_{n}}}\) where \({}n{}\) is the number of values and \({}x_{i}{}\) is the \(i\)-th value.

TODO: qualitative evaluation write-up still pending.

~ end of post ~