LoRA linear layer

ImplementEasy15 min13 checks

lorafine-tuninglinear-algebra

Problem

LoRA fine-tunes a large model without a change to its weights. It keeps the weight W of a linear layer frozen and adds a small trainable path through two low rank matrices A and B. After training, you can merge the path into W, so inference costs the same as the base model.

Task

Write three functions.

  1. lora_forward(x, W, b, A, B, alpha) returns the output of the layer with the adapter.
  2. merge_lora(W, A, B, alpha) returns the merged weight.
  3. count_trainable(in_features, out_features, rank) returns the number of trainable values in A and B.

The rank r is the number of rows of A. The output of the layer is

y = x W^T + b + \frac{\alpha}{r} \, x A^T B^T.

The merged weight is W' = W + \frac{\alpha}{r} B A. With the merged weight, x W'^T + b equals the output of lora_forward.

Only A and B train. W and b are frozen and do not count.

Input and output

NameTypeShapeMeaning
xfloat array(N, in_features)one input row for each of the N examples
Wfloat array(out_features, in_features)the frozen weight
bfloat array(out_features,)the frozen bias
Afloat array(r, in_features)the down projection of the adapter
Bfloat array(out_features, r)the up projection of the adapter
alphafloatscalarthe LoRA scale numerator
in_features, out_features, rankintscalarthe layer sizes and the rank
  • lora_forward returns a float array of shape (N, out_features).
  • merge_lora returns a new float array of shape (out_features, in_features).
  • count_trainable returns a Python int.

Constraints

  • 1 <= N <= 64, 1 <= in_features, out_features <= 4096 and 1 <= r <= 64.
  • The rank can be larger than in_features or out_features.
  • alpha > 0.
  • Do not change the input arrays.
  • Use numpy only.

Examples

pythonx = np.array([[1.0, 2.0, 0.0], [0.0, -1.0, 1.0]])
W = np.array([[0.5, -0.5, 1.0], [1.0, 0.0, 0.0]])
b = np.array([0.1, -0.2])
A = np.array([[1.0, 0.0, 1.0], [0.0, 1.0, 0.0]])
B = np.array([[1.0, 0.5], [-1.0, 0.0]])
lora_forward(x, W, b, A, B, 4.0)
text[[ 3.6 -1.2]
 [ 2.6 -2.2]]

With B = np.zeros((2, 2)), the same call returns the base output [[-0.4, 0.8], [1.6, -0.2]].

pythonmerge_lora(W, A, B, 4.0)
text[[ 2.5  0.5  3. ]
 [-1.   0.  -2. ]]
pythoncount_trainable(4096, 4096, 8)
text65536

Hints

4 hints

    Solution and notes

    Locked

    Pass every check with Submit to open the reference solution and the notes.

    Run it on your computer

    Clone the repository, install numpy and run the same checks in a terminal:

    python3 scripts/practice/run.py lora-forward my_answer.py
    python3 scripts/practice/run.py lora-forward my_answer.py --examples

    Start my_answer.py from starter.py.

    Your code

    Python loads on the first run

    Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.

    Keyboard shortcuts
    Ctrl Enter
    Run the examples
    Ctrl Shift Enter
    Submit
    Tab / Shift Tab
    Indent or outdent the lines
    Esc then Tab
    Move the focus out of the editor
    Alt H
    Show the next hint

    On a Mac, use Cmd in place of Ctrl.

    Select Run to check the examples, or Submit to run every check.