<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Michał Chromiak's blog - Optimization</title><link href="https://mchromiak.github.io/" rel="alternate"/><link href="/feeds/optimization.atom.xml" rel="self"/><id>https://mchromiak.github.io/</id><updated>2023-05-26T09:33:00+02:00</updated><subtitle>Be a fool to become a Polymath.</subtitle><entry><title>QLoRA: How to fine-tune large language models with less memory</title><link href="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/" rel="alternate"/><published>2023-05-26T09:33:00+02:00</published><updated>2023-05-26T09:33:00+02:00</updated><author><name>Michał Chromiak</name></author><id>tag:mchromiak.github.io,2023-05-26:/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/</id><summary type="html">&lt;p&gt;QLoRA makes large language models cheaper to fine-tune by storing the base model in 4 bits and training small, higher-precision adapters. This guide explains LoRA, NormalFloat, double quantization, and paged optimizers, then puts the Guanaco chatbot results in context.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Adapting a language model to a new task usually costs much more GPU memory than simply running it. Training needs room for the model, intermediate calculations, and the information used to update its weights. For a model with billions of parameters, those extra costs can put fine-tuning out of reach even when inference fits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;QLoRA combines two ways to save memory: compress the pretrained model and train a small set of additional weights.&lt;/strong&gt; In their 2023 paper, Tim Dettmers and colleagues use this approach to fine-tune a 65-billion-parameter LLaMA model on a single 48 GB GPU. They also introduce Guanaco, a family of chatbots trained with QLoRA. &lt;a href="https://arxiv.org/html/2305.14314v1#S1"&gt;Paper, introduction&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The method is easiest to understand in two steps: first decide which weights need to change, then reduce the memory used by the weights that stay fixed.&lt;/p&gt;
&lt;h2 id="why-fine-tuning-needs-so-much-memory"&gt;Why fine-tuning needs so much memory&lt;a class="headerlink" href="#why-fine-tuning-needs-so-much-memory" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A pretrained model's &lt;strong&gt;weights&lt;/strong&gt;, also called parameters, are the numbers it learned during its original training. &lt;strong&gt;Fine-tuning&lt;/strong&gt; adapts those numbers, or adds trainable ones, using examples of the behavior we want. For instruction tuning, an example might pair a question with a useful answer.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;full fine-tuning&lt;/strong&gt;, all the model's weights can change. Training also stores &lt;strong&gt;gradients&lt;/strong&gt;, which indicate how to adjust trainable weights, and &lt;strong&gt;optimizer state&lt;/strong&gt;, the running statistics an optimizer uses to choose those adjustments. &lt;strong&gt;Activations&lt;/strong&gt;, the intermediate results produced as inputs pass through the network, require memory too.&lt;/p&gt;
&lt;p&gt;The paper estimates that conventional 16-bit fine-tuning of LLaMA 65B requires more than 780 GB of GPU memory. That is a training-memory estimate, not just the size of the model's weights. QLoRA reduces several parts of this memory budget together. &lt;a href="https://arxiv.org/html/2305.14314v1#S2"&gt;Paper, sections 1 and 2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="lora-learn-a-small-update-instead-of-rewriting-the-model"&gt;LoRA: Learn a small update instead of rewriting the model&lt;a class="headerlink" href="#lora-learn-a-small-update-instead-of-rewriting-the-model" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;LoRA&lt;/strong&gt;, short for &lt;em&gt;Low-Rank Adaptation&lt;/em&gt;, keeps the pretrained weights &lt;strong&gt;frozen&lt;/strong&gt;: training does not update them. It adds small trainable components called &lt;strong&gt;adapters&lt;/strong&gt; alongside selected layers. Each layer combines its original computation with an adjustment learned by its adapter.&lt;/p&gt;
&lt;p&gt;For example, when adapting a model to answer customer-support questions, the base model continues to supply its learned language capabilities. Training adjusts the adapters using the new examples. The resulting behavior depends on both parts, even though only the adapters change.&lt;/p&gt;
&lt;p&gt;An adapter represents an update using two smaller matrices, or grids of numbers, instead of one full-size matrix. Their narrow intermediate dimension is the &lt;strong&gt;adapter rank&lt;/strong&gt;. This restriction greatly reduces the number of trainable parameters and the gradients and optimizer state associated with them. Ordinary LoRA still needs to keep the large base model in memory; QLoRA addresses that remaining cost.&lt;/p&gt;
&lt;p&gt;For a fuller explanation of rank, adapter training, and merging updates for inference, see &lt;a href="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/"&gt;LoRA: Fine-tuning a model by learning a small update&lt;/a&gt;.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;The algebra: How two small matrices change a layer&lt;/summary&gt;
&lt;p&gt;The QLoRA paper writes the LoRA computation as follows in equation (3):&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
\mathbf{Y} = \mathbf{X}\mathbf{W} + s\mathbf{X}\mathbf{L}_1\mathbf{L}_2.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Here, &lt;span class="math"&gt;\(\mathbf{X}\)&lt;/span&gt; is the layer's input and &lt;span class="math"&gt;\(\mathbf{Y}\)&lt;/span&gt; its output. The frozen matrix &lt;span class="math"&gt;\(\mathbf{W}\)&lt;/span&gt; has shape &lt;span class="math"&gt;\(h \times o\)&lt;/span&gt;, where &lt;span class="math"&gt;\(h\)&lt;/span&gt; and &lt;span class="math"&gt;\(o\)&lt;/span&gt; are the input and output widths. The trainable matrices &lt;span class="math"&gt;\(\mathbf{L}_1\)&lt;/span&gt; and &lt;span class="math"&gt;\(\mathbf{L}_2\)&lt;/span&gt; have shapes &lt;span class="math"&gt;\(h \times r\)&lt;/span&gt; and &lt;span class="math"&gt;\(r \times o\)&lt;/span&gt;. Their product has the same shape as &lt;span class="math"&gt;\(\mathbf{W}\)&lt;/span&gt;, but rank at most &lt;span class="math"&gt;\(r\)&lt;/span&gt;. The scalar &lt;span class="math"&gt;\(s\)&lt;/span&gt; controls the size of the adapter's contribution.&lt;/p&gt;
&lt;p&gt;For an illustrative layer with input and output widths of 4,096 and rank 8, the two adapter matrices contain 65,536 parameters in total. A full 4,096-by-4,096 weight matrix contains 16,777,216. The adapter therefore uses 256 times fewer trainable parameters for this layer. This is a count of parameters, not a prediction of the total GPU-memory saving.&lt;/p&gt;
&lt;p&gt;In QLoRA, the base matrix is stored in quantized form and reconstructed approximately for computation. The adapters remain higher precision. The paper's equations (5) and (6) give the full expression, including the reconstruction of quantization scales. &lt;a href="https://arxiv.org/html/2305.14314v1#S3"&gt;Paper, sections 2 and 3&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;&lt;img alt="Diagram comparing full fine-tuning, LoRA, and QLoRA: full fine-tuning updates the base model; LoRA trains adapters; QLoRA also compresses the base model and pages optimizer state to CPU memory." src="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/img/QLoRA.png"&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 1. The paper's comparison of the three methods. Blue arrows show parameter updates, green arrows show gradient flow, and pink arrows show movement of optimizer state between GPU and CPU memory. In LoRA and QLoRA, gradients pass through the base model's computation to train the adapters, while the base weights stay fixed. Source: Dettmers et al., &lt;a href="https://arxiv.org/html/2305.14314v1#S1.F1"&gt;figure 1&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-qlora-adds"&gt;What QLoRA adds&lt;a class="headerlink" href="#what-qlora-adds" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QLoRA builds on LoRA with three memory-saving components. Each addresses a different cost: storing the weights, storing the information needed to reconstruct those weights, and handling temporary peaks during training.&lt;/p&gt;
&lt;h3 id="1-normalfloat-store-the-base-weights-in-4-bits"&gt;1. NormalFloat: Store the base weights in 4 bits&lt;a class="headerlink" href="#1-normalfloat-store-the-base-weights-in-4-bits" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Quantization&lt;/strong&gt; replaces high-precision numbers with a smaller set of representable values. Four bits provide 16 possible codes. Each stored weight selects one of those codes, which maps to an approximate numerical value.&lt;/p&gt;
&lt;p&gt;QLoRA introduces &lt;strong&gt;4-bit NormalFloat (NF4)&lt;/strong&gt;, whose representable values are arranged for a zero-centered normal distribution: a bell-shaped distribution with most values near zero. It places more of its limited precision in that crowded region, where many pretrained weights lie, rather than spacing all values evenly.&lt;/p&gt;
&lt;p&gt;The weights are divided into small blocks, each with its own scaling factor. This lets the same set of NF4 values represent blocks with different numerical ranges. The paper finds that NF4 performs better than the other 4-bit formats it tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Four-bit storage does not mean four-bit arithmetic throughout training.&lt;/strong&gt; When the model uses a group of quantized weights, it dequantizes them into a computation format, usually 16-bit BFloat16 (BF16), before matrix multiplication. Dequantization reconstructs an approximation; it does not recover the exact original weights. The adapters learn while operating alongside that approximation. &lt;a href="https://arxiv.org/html/2305.14314v1#S3"&gt;Paper, sections 3 and 4&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="2-double-quantization-compress-the-scales-too"&gt;2. Double quantization: Compress the scales too&lt;a class="headerlink" href="#2-double-quantization-compress-the-scales-too" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The scaling factors also occupy memory. If every block of 64 weights has a 32-bit scale, that scale adds half a bit per weight. Across billions of weights, this overhead is substantial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Double quantization&lt;/strong&gt; quantizes these scaling factors as well. The paper uses 8-bit values for the first set of scales, with higher-precision scales shared across larger groups. This reduces the scale overhead from 0.5 to approximately 0.127 bits per weight, saving about 0.37 bits per parameter, or roughly 3 GB for a 65B model.&lt;/p&gt;
&lt;p&gt;The second quantization therefore targets the scales, not a second round of four-bit compression applied directly to the model weights. &lt;a href="https://arxiv.org/html/2305.14314v1#S3"&gt;Paper, section 3&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="3-paged-optimizers-make-room-for-temporary-memory-peaks"&gt;3. Paged optimizers: Make room for temporary memory peaks&lt;a class="headerlink" href="#3-paged-optimizers-make-room-for-temporary-memory-peaks" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A training run can fit in memory most of the time and still fail on a batch containing long sequences. The extra intermediate calculations create a temporary peak.&lt;/p&gt;
&lt;p&gt;QLoRA's &lt;strong&gt;paged optimizers&lt;/strong&gt; use NVIDIA unified memory to move optimizer state between GPU memory and CPU RAM as needed. When GPU memory is under pressure, some of that state can reside in CPU RAM; it returns when the optimizer needs it. This helps accommodate peaks without reserving enough GPU memory for all optimizer state at all times.&lt;/p&gt;
&lt;p&gt;Paging works alongside &lt;strong&gt;gradient checkpointing&lt;/strong&gt;, which saves activation memory by recomputing some intermediate results during the backward pass. Neither technique removes the need to budget for sequence length and batch size. &lt;a href="https://arxiv.org/html/2305.14314v1#S3"&gt;Paper, sections 3 and 4&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="one-training-step-from-input-to-update"&gt;One training step, from input to update&lt;a class="headerlink" href="#one-training-step-from-input-to-update" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Putting the pieces together, a QLoRA training step works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Run the examples through the model.&lt;/strong&gt; Quantized base weights are dequantized as needed for computation, and the adapters contribute their learned adjustments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure the prediction error.&lt;/strong&gt; The model predicts tokens, the chunks of text it processes. A loss measures how well those predictions match the training targets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backpropagate through the computation.&lt;/strong&gt; Gradients pass through the frozen model's operations to determine how the adapter weights should change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update the adapters.&lt;/strong&gt; The base weights stay fixed. Paged optimizer state can move between CPU and GPU memory when needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This explains how a frozen model can participate in training: its computations influence the adapter gradients, even though training never updates its own weights.&lt;/p&gt;
&lt;h2 id="what-the-experiments-establish"&gt;What the experiments establish&lt;a class="headerlink" href="#what-the-experiments-establish" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The authors compare QLoRA with both full 16-bit fine-tuning and 16-bit LoRA. On the evaluated tasks, QLoRA broadly matches these baselines while using much less memory. The comparison depends on scale: the largest LLaMA experiments, from 7B to 65B, compare against &lt;strong&gt;16-bit LoRA&lt;/strong&gt;, not full fine-tuning of every weight at every size.&lt;/p&gt;
&lt;p&gt;Those LLaMA experiments use &lt;strong&gt;MMLU&lt;/strong&gt;, a multiple-choice benchmark spanning 57 subjects. Table 4 reports mean accuracy of 53.1% for NF4 with double quantization and 53.0% for the 16-bit adapter baseline, averaged across the tested model sizes and tuning datasets. Individual settings vary, but the overall result is close.&lt;/p&gt;
&lt;p&gt;Adapter placement matters too. The paper finds that applying LoRA across all linear layers in the transformer blocks is important for matching full fine-tuning in its LLaMA 7B experiment. Adding adapters only to the query and value projections in attention does not achieve the same result. &lt;a href="https://arxiv.org/html/2305.14314v1#S4"&gt;Paper, section 4&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="guanaco-and-the-single-gpu-results"&gt;Guanaco and the single-GPU results&lt;a class="headerlink" href="#guanaco-and-the-single-gpu-results" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;QLoRA is the training method; Guanaco is a family of models trained with it.&lt;/strong&gt; The authors build Guanaco by instruction-tuning LLaMA on OpenAssistant's OASST1 conversation data. They use supervised learning, without a reinforcement-learning stage.&lt;/p&gt;
&lt;p&gt;The original release reports two particularly useful hardware reference points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Guanaco 33B:&lt;/strong&gt; fine-tuning on a single 24 GB GPU, with a reported run taking less than 12 hours.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guanaco 65B:&lt;/strong&gt; fine-tuning on a single 48 GB GPU, with a reported run taking about 24 hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are results for the authors' training recipe, not fixed runtimes for arbitrary datasets and sequence lengths. They show how the memory reductions make much larger models accessible on a single GPU. &lt;a href="https://arxiv.org/html/2305.14314v1#S1"&gt;Paper, introduction and section 4&lt;/a&gt;; &lt;a href="https://github.com/artidoro/qlora"&gt;authors' implementation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="what-993-of-chatgpt-means"&gt;What "99.3% of ChatGPT" means&lt;a class="headerlink" href="#what-993-of-chatgpt-means" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The widely repeated figure comes from Guanaco 65B's score relative to the 2023 ChatGPT baseline in the paper's &lt;strong&gt;Vicuna benchmark evaluation&lt;/strong&gt;. GPT-4 scored responses to 80 prompts; the authors expressed Guanaco's score as a percentage of ChatGPT's and averaged over both response orders to reduce ordering bias. The resulting 99.3% is a relative score under that evaluation, not a measurement of 99.3% of ChatGPT's overall capabilities.&lt;/p&gt;
&lt;p&gt;The paper also compares human and model-based judgments and examines failures that aggregate scores miss. Its broader lesson is that the evaluation should match the intended use: strong performance on a multiple-choice knowledge benchmark need not imply equally strong conversational answers. Training-data suitability matters as well as size. &lt;a href="https://arxiv.org/html/2305.14314v1#S5"&gt;Paper, sections 5 and 6&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-closer-look-design-choices-and-memory-costs"&gt;A closer look: Design choices and memory costs&lt;a class="headerlink" href="#a-closer-look-design-choices-and-memory-costs" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following comparisons show where the gains come from. The first tests adapter placement; the second tests number formats; the worked example separates weight storage from the rest of the training budget.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;Why does adapter placement matter?&lt;/summary&gt;
&lt;p&gt;The paper compares several ways to fine-tune LLaMA 7B on Alpaca. &lt;strong&gt;Attention layers&lt;/strong&gt; combine information from different positions in the text. &lt;strong&gt;Feed-forward layers&lt;/strong&gt;, abbreviated FFN, transform the representation at each position. Adapters can be added to either group or both.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/img/qlora-adapter-placement.svg"&gt;&lt;img alt="Paper figure 2: QLoRA with adapters across all linear transformer-block layers achieves higher ROUGE-L than feed-forward-only or attention-only placement, and is comparable to the tuned 16-bit baseline." src="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/img/qlora-adapter-placement.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 2. Adapter-placement comparison from Dettmers et al., &lt;a href="https://arxiv.org/html/2305.14314v1#S4.F2"&gt;figure 2&lt;/a&gt;. The original figure is linked at full size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to read it.&lt;/strong&gt; Each dot is a run with a different random seed. The vertical axis is ROUGE-L, a measure of overlap between generated and reference answers based on their longest common subsequence. Higher is better on this metric. Blue dots use four-bit base weights; orange dots show the 16-bit full-fine-tuning baselines.&lt;/p&gt;
&lt;p&gt;QLoRA-All places adapters across all linear layers in the transformer blocks. It scores above the FFN-only and attention-only variants and is comparable to the authors' tuned full-fine-tuning baseline, labeled "Alpaca (ours)." The lower Stanford-Alpaca results also show why tuning the baseline matters: outperforming a weak training setup would be less convincing.&lt;/p&gt;
&lt;p&gt;The useful distinction is &lt;strong&gt;where the model can learn an adjustment&lt;/strong&gt;, not just how few parameters it updates. This experiment supports broad adapter coverage in this setup; ROUGE-L alone does not establish general chatbot quality. &lt;a href="https://arxiv.org/html/2305.14314v1#S4"&gt;Paper, section 4&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;What do NF4 and double quantization each contribute?&lt;/summary&gt;
&lt;p&gt;The paper also isolates the effect of the number format by evaluating quantized LLaMA models. Here, &lt;strong&gt;zero-shot&lt;/strong&gt; means the evaluation supplies no worked examples in the prompt. This comparison tests the quantized models, rather than Guanaco's instruction-tuned conversational behavior.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/img/qlora-quantization-comparison.svg"&gt;&lt;img alt="Paper figure 3: NormalFloat gives higher mean zero-shot accuracy than regular four-bit floating point; adding double quantization moves results toward lower total model bits with similar accuracy." src="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/img/qlora-quantization-comparison.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 3. Quantization comparison from Dettmers et al., &lt;a href="https://arxiv.org/html/2305.14314v1#S4.F3"&gt;figure 3&lt;/a&gt;. The original figure is linked at full size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to read it.&lt;/strong&gt; The horizontal axis is total model bits on a logarithmic scale; farther left means less storage. The vertical axis is mean accuracy across five benchmarks: WinoGrande, HellaSwag, PIQA, ARC-Easy, and ARC-Challenge. Higher means better performance on that collection of tasks.&lt;/p&gt;
&lt;p&gt;The orange NormalFloat curve sits above the blue ordinary-float curve. Both use four-bit weight codes, but choosing the representable values differently changes the error introduced by quantization. The green NormalFloat-plus-DQ curve stays close to the orange curve while shifting left: compressing the scales saves storage with little change in accuracy here.&lt;/p&gt;
&lt;p&gt;The two components therefore do different jobs. &lt;strong&gt;NF4 improves the representation of the weights; double quantization reduces the overhead of their scales.&lt;/strong&gt; These results explain the choice of quantization scheme. The fine-tuning comparisons in table 4 address the separate question of how well the models perform after adapter training. &lt;a href="https://arxiv.org/html/2305.14314v1#S4"&gt;Paper, section 4&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;A worked memory budget for 65 billion weights&lt;/summary&gt;
&lt;p&gt;Start with an idealized model containing exactly 65 billion weights. A byte contains eight bits, so storing every weight in 16 bits requires 130 GB. Four bits per weight reduces that to 32.5 GB. These calculations use decimal gigabytes and count only the stored weight values.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What is stored&lt;/th&gt;
&lt;th&gt;Approximate size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weight values at 16 bits each&lt;/td&gt;
&lt;td&gt;130 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weight values at 4 bits each&lt;/td&gt;
&lt;td&gt;32.5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Four-bit values plus the paper's double-quantized scale overhead&lt;/td&gt;
&lt;td&gt;33.5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last row adds approximately 0.127 bits per weight for scales, using the paper's block sizes: 64 weights per first-level block and 256 scales per second-level block. That contributes about 1 GB across 65 billion weights. Without double quantization, the 0.5-bit scale overhead would contribute about 4.1 GB instead. This is where the roughly 3 GB saving comes from. &lt;a href="https://arxiv.org/html/2305.14314v1#S3"&gt;Paper, section 3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The 33.5 GB estimate is not the total training requirement.&lt;/strong&gt; A real run also needs adapters, their gradients and optimizer state, activations, temporary computation buffers, and any parameters kept at higher precision. Sequence length and batch size affect several of these costs. Gradient checkpointing reduces saved activations through recomputation; paging lets some optimizer state reside in CPU RAM when GPU memory is tight.&lt;/p&gt;
&lt;p&gt;This calculation explains how the frozen weights can fit within the paper's 48 GB training setup while leaving some room for the rest. It is an illustrative storage budget, not a reproduction of the authors' measured peak memory. Their &lt;a href="https://arxiv.org/html/2305.14314v1#A7"&gt;appendix G&lt;/a&gt; examines the memory footprint in more detail.&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;Figures 2 and 3 are reproduced unmodified from the original paper by Dettmers et al., distributed under &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;CC BY 4.0&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-takeaway"&gt;The takeaway&lt;a class="headerlink" href="#the-takeaway" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;QLoRA makes fine-tuning more accessible by separating the large body of pretrained weights from the much smaller set of weights that must change. LoRA reduces the trainable part; NF4 and double quantization compress the frozen part; paged optimizers help handle temporary memory pressure.&lt;/p&gt;
&lt;p&gt;The result is a practical route to adapting larger models within a limited GPU-memory budget. The paper's strongest message is the combination: carefully chosen quantization and well-placed adapters can preserve strong task performance without the memory cost of updating the whole model.&lt;/p&gt;
&lt;h2 id="related-reading"&gt;Related reading&lt;a class="headerlink" href="#related-reading" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a different approach to training efficiency, see &lt;a href="https://mchromiak.github.io/articles/2023/Jun/17/Self-Supervised-Learning-from-Images-with-a-Joint-Embedding-Predictive-Architecture/"&gt;I-JEPA: Learning from images by predicting missing features&lt;/a&gt;. I-JEPA learns visual representations from unlabeled images; QLoRA adapts pretrained language models. The articles address different stages of learning, rather than two versions of the same method.&lt;/p&gt;
&lt;p&gt;For an architectural example built around dense matrix operations, see &lt;a href="https://mchromiak.github.io/articles/2021/May/05/MLP-Mixer/"&gt;MLP-Mixer: How image patches communicate without attention&lt;/a&gt;. MLP-Mixer is a vision backbone, whereas QLoRA is a memory-efficient way to adapt a pretrained language model; the connection is computational perspective, not task or method.&lt;/p&gt;
&lt;h2 id="original-sources"&gt;Original sources&lt;a class="headerlink" href="#original-sources" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tim Dettmers, Artidoro Pagnoni, Ari Holtzman, and Luke Zettlemoyer. &lt;a href="https://arxiv.org/abs/2305.14314"&gt;QLoRA: Efficient Finetuning of Quantized LLMs&lt;/a&gt;, 2023. This explanation follows the &lt;a href="https://arxiv.org/html/2305.14314v1"&gt;original May 2023 version&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/artidoro/qlora"&gt;QLoRA code and Guanaco model information&lt;/a&gt;, maintained by the authors.&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Optimization"/><category term="Adapters"/><category term="Low-Rank"/><category term="LoRA"/><category term="QLoRA"/></entry><entry><title>CoLT5: Reading long documents with selective computation</title><link href="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/" rel="alternate"/><published>2023-03-30T14:33:00+02:00</published><updated>2023-03-30T14:33:00+02:00</updated><author><name>Michał Chromiak</name></author><id>tag:mchromiak.github.io,2023-03-30:/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/</id><summary type="html">&lt;p&gt;CoLT5 processes every input token with lightweight layers and gives selected tokens additional, higher-capacity computation. This guide explains its learned routing, light and heavy branches, faster decoding, and experiments with inputs up to 64k tokens.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Suppose a model must answer a question about a lengthy report. It needs enough context to find the relevant evidence, but not every passage deserves the same amount of processing. Repeated headings, background material, and the sentence containing the answer all consume space in the input; their usefulness to the task can be very different.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CoLT5 gives every token a lightweight path through the encoder, then spends extra computation on selected tokens.&lt;/strong&gt; It learns which tokens to select separately at each layer and for each kind of operation. The aim is to improve the balance between answer quality and processing time, rather than simply making the model smaller.&lt;/p&gt;
&lt;p&gt;Joshua Ainslie and colleagues introduced CoLT5, short for &lt;em&gt;Conditional LongT5&lt;/em&gt;, in March 2023. It builds on LongT5 with conditional computation in the encoder, multi-query cross-attention for faster decoding, and a UL2-style pretraining objective. Their experiments cover long-document question answering, summarization, and inference over contracts, with a separate study extending input length to 64k tokens. &lt;a href="https://arxiv.org/abs/2303.09752v1"&gt;Original paper&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-efficient-attention-is-only-part-of-the-problem"&gt;Why efficient attention is only part of the problem&lt;a class="headerlink" href="#why-efficient-attention-is-only-part-of-the-problem" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;token&lt;/strong&gt; is a chunk of text processed by the model. A token's &lt;strong&gt;representation&lt;/strong&gt; is the vector of numbers the network uses to describe it at a particular layer. In an encoder-decoder model such as T5, the &lt;strong&gt;encoder&lt;/strong&gt; builds representations of the input, and the &lt;strong&gt;decoder&lt;/strong&gt; uses them to generate an answer or summary.&lt;/p&gt;
&lt;p&gt;Two operations do much of the encoder's work. &lt;strong&gt;Attention&lt;/strong&gt; lets token representations draw information from other positions. A &lt;strong&gt;feed-forward network&lt;/strong&gt;, also called an MLP, transforms each position's representation independently. Attention also needs learned projections that turn representations into queries, keys, and values.&lt;/p&gt;
&lt;p&gt;Ordinary full attention compares every position with every other position, so the number of comparisons grows quadratically with input length. LongT5 reduces that cost using local attention and, in its transient-global variant, summaries of token blocks. But the feed-forward networks and attention projections still process every token. Once attention becomes cheaper, these operations can dominate the computational budget.&lt;/p&gt;
&lt;p&gt;CoLT5 therefore asks a second question: &lt;strong&gt;can the expensive feed-forward and projection work also be concentrated on fewer tokens?&lt;/strong&gt; &lt;a href="https://arxiv.org/html/2303.09752v1#S2"&gt;Paper, section 2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="one-light-path-for-everyone-extra-work-for-selected-tokens"&gt;One light path for everyone, extra work for selected tokens&lt;a class="headerlink" href="#one-light-path-for-everyone-extra-work-for-selected-tokens" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each CoLT5 encoder layer has light and heavy branches for both attention and feed-forward processing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Light branches process every token.&lt;/strong&gt; They maintain a representation for the full input using local attention and a narrower feed-forward network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heavy branches process selected tokens.&lt;/strong&gt; They add a wider feed-forward transformation or attention across selected positions from throughout the input.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routers choose the tokens.&lt;/strong&gt; The choices depend on the current input representations and can change from one layer to the next.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/colt5-architecture.png"&gt;&lt;img alt="CoLT5 encoder-layer diagram: all tokens pass through light attention and a light MLP, while routers send selected query, key/value, and MLP tokens through the corresponding heavy branches." src="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/colt5-architecture.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 1. The CoLT5 encoder layer, reproduced from the paper's &lt;a href="https://arxiv.org/html/2303.09752v1#S1.F1"&gt;figure 1&lt;/a&gt;. The symbols &lt;span class="math"&gt;\(q\)&lt;/span&gt;, &lt;span class="math"&gt;\(v\)&lt;/span&gt;, and &lt;span class="math"&gt;\(m\)&lt;/span&gt; count routed attention queries, key/value tokens, and feed-forward tokens. The diagram reads from bottom to top.&lt;/p&gt;
&lt;p&gt;Think of reading a report once for context and revisiting selected passages more carefully. The analogy has a limit: CoLT5 does not permanently discard the other passages or perform a single document-level selection. All tokens keep their light-path representations, and selection is repeated throughout the encoder.&lt;/p&gt;
&lt;h3 id="routing-what-does-important-mean"&gt;Routing: What does "important" mean?&lt;a class="headerlink" href="#routing-what-does-important-mean" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A router gives each token a score by comparing its current representation with a learned vector. It selects the highest-scoring positions within a chosen budget. Training teaches the router which selections help the overall task; it does not receive human labels declaring particular words important.&lt;/p&gt;
&lt;p&gt;Each layer has &lt;strong&gt;three independent routers&lt;/strong&gt;: one for heavy feed-forward processing, one for heavy attention queries, and one for heavy attention keys and values. A token can therefore be useful for one operation without being selected for another.&lt;/p&gt;
&lt;p&gt;This distinction matters when answering a question. Some positions may need information from elsewhere in the document; other positions may contain the evidence those positions need. CoLT5 can select these two groups separately. In the paper's TriviaQA analysis, question tokens and tokens matching the answer were more likely to receive heavy processing than other tokens, though routing is not a human-readable explanation of the model's reasoning. &lt;a href="https://arxiv.org/html/2303.09752v1#S3.SS1"&gt;Paper, sections 3.1 and 4.6&lt;/a&gt;.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;The routing scores and feed-forward update&lt;/summary&gt;
&lt;p&gt;The paper denotes token &lt;span class="math"&gt;\(i\)&lt;/span&gt;'s representation by &lt;span class="math"&gt;\(X_i\)&lt;/span&gt; and a learned routing vector by &lt;span class="math"&gt;\(u\)&lt;/span&gt;. Its routing score is:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
s_i = X_i \cdot u.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;The dot product produces one score per token. A generalized softmax normalizes these scores so that their sum equals the target routing budget. The resulting normalized score is written &lt;span class="math"&gt;\(\tilde{s}_i\)&lt;/span&gt;. The router selects the top-scoring tokens, and the score weights their heavy-branch contribution. This weighting supplies a training signal for the routing vector; a hard selection alone would not do that.&lt;/p&gt;
&lt;p&gt;Using the paper's notation, the feed-forward update is:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
\begin{aligned}
X_i ={}&amp;amp; X_i + \mathrm{FFd}_{\mathrm{Light}}(X_i) \\
&amp;amp;+ \tilde{s}_i \cdot \mathrm{FFd}_{\mathrm{Heavy}}(X_i).
\end{aligned}
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;This is an in-place update: the right-hand side uses the token's incoming representation. The first term preserves that representation, the second adds light processing, and the third adds the weighted heavy result. In this update, &lt;span class="math"&gt;\(\tilde{s}_i\)&lt;/span&gt; is set to zero for non-routed tokens. The implementation computes the heavy branch only for selected positions, rather than computing it everywhere and multiplying unwanted outputs by zero.&lt;/p&gt;
&lt;p&gt;The paper uses an entropy-regularized optimization procedure from Qian et al. to normalize scores. Appendix C specifies 50 iterations and &lt;span class="math"&gt;\(\epsilon=1.0\)&lt;/span&gt;, and permits the top &lt;span class="math"&gt;\(9k/8\)&lt;/span&gt; tokens to have nonzero weight during training to improve the learning signal. This is a training detail beyond the simpler top-&lt;span class="math"&gt;\(k\)&lt;/span&gt; explanation above. &lt;a href="https://arxiv.org/html/2303.09752v1#S3.SS1"&gt;Paper, section 3.1&lt;/a&gt; and &lt;a href="https://arxiv.org/html/2303.09752v1#A3"&gt;appendix C&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;h3 id="feed-forward-branches-wider-is-not-deeper"&gt;Feed-forward branches: Wider is not deeper&lt;a class="headerlink" href="#feed-forward-branches-wider-is-not-deeper" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The light feed-forward branch uses half the standard T5 hidden width, while the heavy branch uses roughly four times that width. The heavy branch is more capable per selected token, but only a small fraction of the input uses it.&lt;/p&gt;
&lt;p&gt;The branches do &lt;strong&gt;not&lt;/strong&gt; achieve this by using different numbers of encoder layers. Corresponding CoLT5 and LongT5 models have the same layer count and model width. CoLT5 has more total parameters because it includes the additional heavy branch, yet accesses those parameters sparsely.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;Model dimensions and a worked compute example&lt;/summary&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/CoLT5_branch_dims.png"&gt;&lt;img alt="Original hyperparameter table comparing LongT5 and CoLT5 Base, Large, and XL: corresponding models have equal layer counts and model dimensions, while CoLT5 splits feed-forward width and attention heads between light and heavy branches." src="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/CoLT5_branch_dims.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 2. Model configurations from the paper's &lt;a href="https://arxiv.org/html/2303.09752v1#S5.T7"&gt;table 7&lt;/a&gt;. The original image is linked at full size. Parameter count measures stored capacity, not how much computation is performed on each token.&lt;/p&gt;
&lt;p&gt;For example, the Large models both have 24 layers and a model dimension of 1,024. LongT5-L uses feed-forward hidden width 2,816; CoLT5-L uses 1,408 in the light branch and 11,264 in the heavy branch.&lt;/p&gt;
&lt;p&gt;For its simplified FLOP accounting, the paper writes the feed-forward cost as:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
\mathrm{FLOPs}_{\mathrm{FFd}} = 8nr_Ld^2 + 8mr_Hd^2.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Here, &lt;span class="math"&gt;\(n\)&lt;/span&gt; is input length, &lt;span class="math"&gt;\(m\)&lt;/span&gt; is the number of routed feed-forward tokens, &lt;span class="math"&gt;\(d\)&lt;/span&gt; is model dimension, and &lt;span class="math"&gt;\(r_L\)&lt;/span&gt; and &lt;span class="math"&gt;\(r_H\)&lt;/span&gt; are the light and heavy hidden-width ratios. Substituting the main experiment's ratios, &lt;span class="math"&gt;\(r_L=1/2\)&lt;/span&gt;, &lt;span class="math"&gt;\(r_H=4\)&lt;/span&gt;, and &lt;span class="math"&gt;\(m=n/16\)&lt;/span&gt;, gives:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
\mathrm{FLOPs}_{\mathrm{FFd}} = 4nd^2 + 2nd^2 = 6nd^2.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;That is 75% of the standard &lt;span class="math"&gt;\(8nd^2\)&lt;/span&gt; feed-forward cost in this accounting. The heavy network is wider, but it runs on sufficiently few tokens to reduce the combined work. This is a component-level FLOP estimate, not a prediction of a 25% reduction in total running time. The paper counts each multiply-add as one FLOP. &lt;a href="https://arxiv.org/html/2303.09752v1#S3.SS1"&gt;Paper, sections 2 and 3.1&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;h3 id="attention-branches-separate-who-asks-from-who-supplies-information"&gt;Attention branches: Separate who asks from who supplies information&lt;a class="headerlink" href="#attention-branches-separate-who-asks-from-who-supplies-information" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An attention &lt;strong&gt;query&lt;/strong&gt; represents a position seeking information. &lt;strong&gt;Keys&lt;/strong&gt; are used to score possible matches, and &lt;strong&gt;values&lt;/strong&gt; supply the information combined into the output.&lt;/p&gt;
&lt;p&gt;The light attention branch gives every token access to a local window. The heavy branch lets selected queries attend to a separately selected set of keys and values from across the input. Here, "global" means that the selected positions can be far apart; it does not mean that every token attends to every other token.&lt;/p&gt;
&lt;p&gt;In the main 16k-input setup, the routing budgets are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1,024 tokens for the heavy feed-forward branch;&lt;/li&gt;
&lt;li&gt;1,024 query tokens for heavy attention; and&lt;/li&gt;
&lt;li&gt;2,048 key/value tokens for heavy attention.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The query and feed-forward budgets have the same size, but their routers need not choose the same positions. The key/value budget is twice as large, allowing a smaller group of queries to gather evidence from a larger group of source positions. The heavy attention results are added to the selected queries' light-path updates. &lt;a href="https://arxiv.org/html/2303.09752v1#S3.SS1"&gt;Paper, section 3.1&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="two-other-changes-complete-the-recipe"&gt;Two other changes complete the recipe&lt;a class="headerlink" href="#two-other-changes-complete-the-recipe" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="multi-query-cross-attention-speeds-up-the-decoder"&gt;Multi-query cross-attention speeds up the decoder&lt;a class="headerlink" href="#multi-query-cross-attention-speeds-up-the-decoder" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Making the encoder cheaper does not automatically make answer generation fast. The decoder repeatedly reads the encoded document as it generates output tokens, and moving the keys and values through memory can become a bottleneck for long inputs.&lt;/p&gt;
&lt;p&gt;CoLT5 uses &lt;strong&gt;multi-query attention (MQA)&lt;/strong&gt; in the decoder's cross-attention layers. Query heads remain separate, but share keys and values. This reduces the amount of key/value data that must be repeatedly read. MQA addresses decoder memory bandwidth, while conditional computation addresses encoder work; they solve different parts of the runtime problem. &lt;a href="https://arxiv.org/html/2303.09752v1#S3.SS2"&gt;Paper, section 3.2&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/1911.02150"&gt;original MQA paper&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="ul2-supports-learning-from-examples-in-the-input"&gt;UL2 supports learning from examples in the input&lt;a class="headerlink" href="#ul2-supports-learning-from-examples-in-the-input" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;CoLT5 replaces LongT5's PEGASUS pretraining objective with a variant of &lt;strong&gt;UL2&lt;/strong&gt;, a mixture of text-reconstruction tasks. Its recipe combines prefix language modeling, which predicts a continuation, with span corruption, which reconstructs removed spans of different lengths.&lt;/p&gt;
&lt;p&gt;This supports &lt;strong&gt;in-context learning&lt;/strong&gt;: the model receives examples of the desired task in its input, then responds to a new example without updating its weights. A longer input can accommodate more demonstrations as well as the document to be processed.&lt;/p&gt;
&lt;p&gt;The paper tests this on Natural Questions and TriviaQA. For the 16k-context experiment, it first continues pretraining a CoLT5-Large model at that length for another 100,000 steps. The authors found that in-context learning did not reliably extend beyond the length used in training. Thus, the demonstration is not simply a 4k-trained model being handed a much longer prompt. &lt;a href="https://arxiv.org/html/2303.09752v1#S4.SS4"&gt;Paper, sections 3.3 and 4.4&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2205.05131"&gt;UL2 paper&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-the-experiments-show"&gt;What the experiments show&lt;a class="headerlink" href="#what-the-experiments-show" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="quality-and-speed-at-roughly-16k-input-length"&gt;Quality and speed at roughly 16k input length&lt;a class="headerlink" href="#quality-and-speed-at-roughly-16k-input-length" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The main comparison uses 16,384 input tokens, except ContractNLI, which uses 8,192. It covers nine datasets: TriviaQA and arXiv, plus the seven tasks in SCROLLS. Those tasks span document question answering, summarization, and identifying whether a contract supports a given statement.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/colt5_longt5.png"&gt;&lt;img alt="Two plots comparing average task performance with inference and fine-tuning time: CoLT5 Large matches the LongT5 Large average with less time per sample, and CoLT5 XL improves the average while also running faster." src="https://mchromiak.github.io/articles/2023/Mar/30/COLT5_Faster_Long-Range-Transformers-with-Conditional-Computation/img/colt5_longt5.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 3. The paper's &lt;a href="https://arxiv.org/html/2303.09752v1#S1.F2"&gt;figure 2&lt;/a&gt;, showing the main quality-speed comparison, not the separate 64k experiment. Higher and farther left is better. Batched timings are normalized per sample per TPUv4 chip; they are not single-request latency measurements. The LongT5 inference comparison includes MQA for a conservative baseline.&lt;/p&gt;
&lt;p&gt;At Large size, both models have an average score of 45.3 across the reported tasks. CoLT5-XL reaches 47.4 versus 46.6 for LongT5-XL. CoLT5-Base is faster but has a lower average score, 42.4 versus 43.1. The improvement is therefore a better overall quality-speed trade-off, not a win on every task at every model size.&lt;/p&gt;
&lt;p&gt;The paper reports 35-75% training speedups and 50-100% inference speedups for Large and XL in this comparison, beyond MQA's contribution. Its CoLT5-XL result was state of the art on the SCROLLS leaderboard at the time. The average combines different task metrics: answer F1, exact match, and ROUGE-based summarization scores. It is not a single accuracy percentage. &lt;a href="https://arxiv.org/html/2303.09752v1#S4.SS2"&gt;Paper, table 3 and section 4.2&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="the-64k-result-more-context-without-more-routed-tokens"&gt;The 64k result: More context without more routed tokens&lt;a class="headerlink" href="#the-64k-result-more-context-without-more-routed-tokens" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The long-input scaling study uses &lt;strong&gt;NarrativeQA&lt;/strong&gt;, where answering questions can require information from lengthy stories. The authors compare LongT5-Large and CoLT5-Large at increasing input lengths. CoLT5 achieves a better quality-speed trade-off and continues to gain answer F1 when its input grows from 32k to 64k.&lt;/p&gt;
&lt;p&gt;For that last increase, the heavy routing budget stays fixed: 2,048 feed-forward tokens and queries, with 4,096 key/value tokens. The model sees twice as much input without doubling the number of heavy-branch tokens. Their fraction of the input therefore falls.&lt;/p&gt;
&lt;p&gt;This supports the intuition that a longer document may contain proportionally fewer positions that need expensive processing. It does &lt;strong&gt;not&lt;/strong&gt; show that the absolute number of useful tokens must decrease, or that the total model runs in sublinear time. &lt;a href="https://arxiv.org/html/2303.09752v1#S4.SS3"&gt;Paper, section 4.3&lt;/a&gt;.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;Does conditional attention remove quadratic scaling?&lt;/summary&gt;
&lt;p&gt;Heavy attention compares &lt;span class="math"&gt;\(q\)&lt;/span&gt; selected queries with &lt;span class="math"&gt;\(v\)&lt;/span&gt; selected key/value positions, so its comparison work depends on &lt;span class="math"&gt;\(qv\)&lt;/span&gt;. With the main fixed fractions, &lt;span class="math"&gt;\(q=n/16\)&lt;/span&gt; and &lt;span class="math"&gt;\(v=n/8\)&lt;/span&gt;, their product is &lt;span class="math"&gt;\(n^2/128\)&lt;/span&gt;. This is a calculation of query-key pairs, not the paper's complete attention FLOP formula: projections, heads, and local attention also contribute.&lt;/p&gt;
&lt;p&gt;The smaller fraction greatly reduces the quadratic term's coefficient, but does not eliminate it. With a fixed heavy routing budget, that part stops growing with input length. The light branches still process every token, and the routers still need to score the input. The 32k-to-64k result demonstrates useful scaling of a selected-token budget, not constant-time or sublinear processing of the entire document.&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="what-the-ablations-teach-us"&gt;What the ablations teach us&lt;a class="headerlink" href="#what-the-ablations-teach-us" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The authors also change individual parts of the recipe to test their contribution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learned routing matters.&lt;/strong&gt; Selecting evenly spaced positions instead lowers the average score in the Base ablation from 42.5 to 40.5.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The routing budget trades speed for quality.&lt;/strong&gt; Raising the feed-forward/query budget from 512 to 1,024 helps; further increases show diminishing returns in the tested setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not every query needs every key/value.&lt;/strong&gt; Letting selected queries attend to the entire input gives little average quality improvement at greater cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQA is a deliberate trade-off.&lt;/strong&gt; Ordinary multi-head cross-attention gives a slightly higher average score in the ablation, but much slower inference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UL2 is not the source of every fine-tuning gain.&lt;/strong&gt; PEGASUS is slightly stronger on the fine-tuned task average in this ablation; UL2 is retained for its in-context-learning capability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These results are useful when interpreting the architecture: routing, context length, decoder bandwidth, and the training objective affect different aspects of performance. &lt;a href="https://arxiv.org/html/2303.09752v1#S4.SS5"&gt;Paper, section 4.5&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="where-the-approach-is-useful"&gt;Where the approach is useful&lt;a class="headerlink" href="#where-the-approach-is-useful" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CoLT5 is aimed at encoder-decoder tasks with long inputs: finding evidence in documents, summarizing reports or meetings, and answering questions about extended narratives. It is especially relevant when only part of the input needs costly global interactions, but retaining local representations of the rest remains useful.&lt;/p&gt;
&lt;p&gt;The experiments suggest three practical questions for evaluating such a design: does extra context improve the task, how much quality is lost when the heavy-token budget shrinks, and is the runtime bottleneck in the encoder or decoder? Parameter count alone cannot answer them. CoLT5's heavy branches increase stored capacity, while conditional execution reduces the work applied to each example.&lt;/p&gt;
&lt;h2 id="sources-and-implementation-notes"&gt;Sources and implementation notes&lt;a class="headerlink" href="#sources-and-implementation-notes" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This explanation follows the &lt;a href="https://arxiv.org/abs/2303.09752v1"&gt;March 2023 CoLT5 paper&lt;/a&gt;. The authors describe an implementation using JAX, Flax, Flaxformer, and T5X. That implementation description should not be confused with a downloadable pretrained CoLT5 checkpoint.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/lucidrains/CoLT5-attention"&gt;Phil Wang's CoLT5-attention&lt;/a&gt; implements conditionally routed components in PyTorch. It is not an official release of the paper's complete trained models, and its README identifies implementation choices that differ from, or interpret gaps in, the paper.&lt;/p&gt;
&lt;p&gt;For the routing background, the original CoLT5 paper cites &lt;a href="https://arxiv.org/abs/2211.01267"&gt;Qian et al., Multi-Vector Retrieval as Sparse Alignment&lt;/a&gt;. The community implementation also points to &lt;a href="https://arxiv.org/abs/2304.04947"&gt;Conditional Adapters (CoDA)&lt;/a&gt; and &lt;a href="https://arxiv.org/abs/1502.04759"&gt;Wright's coordinate-descent review&lt;/a&gt;. CoDA's arXiv submission came after CoLT5's original March release, so it is better treated here as related reading than as the original paper's stated source.&lt;/p&gt;
&lt;p&gt;Other foundations are &lt;a href="https://arxiv.org/abs/2112.07916"&gt;LongT5&lt;/a&gt;, &lt;a href="https://github.com/google-research/text-to-text-transfer-transformer/blob/main/released_checkpoints.md#t511"&gt;T5.1.1&lt;/a&gt;, &lt;a href="https://arxiv.org/abs/1911.02150"&gt;multi-query attention&lt;/a&gt;, and &lt;a href="https://arxiv.org/abs/2205.05131"&gt;UL2&lt;/a&gt;. The figures reproduced from the CoLT5 paper are attributed to Ainslie et al.; the original preprint is distributed under &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;CC BY 4.0&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-takeaway"&gt;The takeaway&lt;a class="headerlink" href="#the-takeaway" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CoLT5 keeps a lightweight representation of the whole input while concentrating additional capacity on learned selections of tokens. Its separate routers distinguish positions that need information from positions that can supply it. Together with faster cross-attention and a suitable pretraining objective, this lets the model make better use of long documents within a given computation budget.&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Optimization"/><category term="T5"/><category term="LongT5"/><category term="Conditional Computation"/><category term="CoLT5"/><category term="Transformer"/></entry><entry><title>LoRA: Fine-tuning a model by learning a small update</title><link href="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/" rel="alternate"/><published>2023-03-18T13:01:00+01:00</published><updated>2023-03-18T13:01:00+01:00</updated><author><name>Michał Chromiak</name></author><id>tag:mchromiak.github.io,2023-03-18:/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/</id><summary type="html">&lt;p&gt;LoRA adapts a pretrained model by training small, low-rank updates while keeping its original weights fixed. This guide explains the two-matrix construction, the memory and storage savings, the conditions for merging adapters, and the connection to QLoRA.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Suppose you want a language model to turn questions into database queries. It already knows a great deal about language, but it needs examples of the task and the kind of answer you expect. Fine-tuning can teach that behavior. The expensive part is allowing billions of existing weights to change and storing everything needed to update them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LoRA keeps the pretrained weights fixed and learns a small adjustment alongside them.&lt;/strong&gt; Instead of training a full-size update for each chosen weight matrix, it represents that update with two much smaller matrices. The model still uses all its pretrained weights; only the additional matrices are trained.&lt;/p&gt;
&lt;p&gt;Edward J. Hu and colleagues introduced &lt;em&gt;Low-Rank Adaptation&lt;/em&gt; in June 2021, and the paper appeared at ICLR 2022. Its central question is practical: how much of full fine-tuning's performance can we retain while learning and storing far fewer task-specific parameters? &lt;a href="https://arxiv.org/abs/2106.09685"&gt;Original paper&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-train-an-update-instead-of-the-whole-model"&gt;Why train an update instead of the whole model?&lt;a class="headerlink" href="#why-train-an-update-instead-of-the-whole-model" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A model's &lt;strong&gt;parameters&lt;/strong&gt;, often called weights, are the numbers it learns during training. &lt;strong&gt;Full fine-tuning&lt;/strong&gt; starts from a pretrained model and updates all of those parameters on a new dataset. It is not training from scratch, but it still requires gradients and optimizer state for the weights being updated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gradients&lt;/strong&gt; indicate how the training loss changes with each parameter. An optimizer such as Adam also keeps running statistics to help choose the updates. These extra tensors can take much more memory than the final model checkpoint alone. Intermediate results, called &lt;strong&gt;activations&lt;/strong&gt;, add another substantial cost.&lt;/p&gt;
&lt;p&gt;There is also a storage problem. If each task gets a complete fine-tuned copy of a large model, every new task adds another large checkpoint. LoRA separates what can be shared, the pretrained model, from what changes between tasks, the learned update.&lt;/p&gt;
&lt;p&gt;This makes LoRA a &lt;strong&gt;parameter-efficient fine-tuning (PEFT)&lt;/strong&gt; method. Parameter-efficient means that relatively few parameters are trained; it does not mean the large base model disappears from memory.&lt;/p&gt;
&lt;h2 id="two-paths-through-a-layer"&gt;Two paths through a layer&lt;a class="headerlink" href="#two-paths-through-a-layer" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A dense layer multiplies an input vector by a matrix of learned weights. LoRA adds a second path alongside that operation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The original matrix processes the input using its frozen weights.&lt;/li&gt;
&lt;li&gt;A small trainable matrix, called &lt;span class="math"&gt;\(A\)&lt;/span&gt;, maps the same input into a narrow intermediate space.&lt;/li&gt;
&lt;li&gt;Another trainable matrix, &lt;span class="math"&gt;\(B\)&lt;/span&gt;, maps that intermediate result back to the layer's output width.&lt;/li&gt;
&lt;li&gt;The layer adds the original result and the learned adjustment.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/img/LoRA.png"&gt;&lt;img alt="LoRA's two parallel paths: the input x passes through frozen pretrained weights W and through trainable matrices A and B; the two outputs are added to produce h. A starts randomly initialized and B starts at zero." src="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/img/LoRA.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 1. The LoRA construction from Hu et al., &lt;a href="https://arxiv.org/html/2106.09685v2#S1.F1"&gt;figure 1&lt;/a&gt;. Read from bottom to top. The narrow width &lt;span class="math"&gt;\(r\)&lt;/span&gt; is the adapter rank. The figure uses a square weight matrix; the same idea works for rectangular matrices.&lt;/p&gt;
&lt;p&gt;The small matrices are often called a &lt;strong&gt;LoRA adapter&lt;/strong&gt;. They learn together with the task's training objective. LoRA does not first compute a full fine-tuned model and then compress the difference: the small matrices are the parameters it trains from the start.&lt;/p&gt;
&lt;h3 id="what-does-low-rank-mean"&gt;What does "low rank" mean?&lt;a class="headerlink" href="#what-does-low-rank-mean" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The rank of a matrix measures how many independent directions it can express. In LoRA, the narrow intermediate width limits the number of directions available to the &lt;strong&gt;update&lt;/strong&gt;. If that width is 8, the update matrix has rank at most 8, even when the original layer has thousands of inputs and outputs.&lt;/p&gt;
&lt;p&gt;Crucially, &lt;strong&gt;the pretrained matrix is not forced to have low rank&lt;/strong&gt;. It remains intact. The assumption is that adapting an already capable model to a particular task may need a much simpler change than learning the model in the first place.&lt;/p&gt;
&lt;p&gt;The authors draw motivation from work on the low &lt;em&gt;intrinsic dimensionality&lt;/em&gt; of fine-tuning: some tasks can be learned by optimizing within a much smaller parameter space. LoRA turns that motivation into a specific constraint on individual weight updates. It is an empirical hypothesis about adaptation, not a proof that every useful update must be low-rank. &lt;a href="https://arxiv.org/html/2106.09685v2#S4.SS1"&gt;Paper, section 4.1&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2012.13255"&gt;Aghajanyan et al.&lt;/a&gt;.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;The algebra, with the paper's notation&lt;/summary&gt;
&lt;p&gt;Let the frozen weight matrix be &lt;span class="math"&gt;\(W_0 \in \mathbb{R}^{d \times k}\)&lt;/span&gt;. It maps an input &lt;span class="math"&gt;\(x\)&lt;/span&gt; with &lt;span class="math"&gt;\(k\)&lt;/span&gt; components to an output &lt;span class="math"&gt;\(h\)&lt;/span&gt; with &lt;span class="math"&gt;\(d\)&lt;/span&gt; components. LoRA represents the update as:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
\Delta W = BA,
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;where &lt;span class="math"&gt;\(A \in \mathbb{R}^{r \times k}\)&lt;/span&gt; and &lt;span class="math"&gt;\(B \in \mathbb{R}^{d \times r}\)&lt;/span&gt;, with &lt;span class="math"&gt;\(r \ll \min(d,k)\)&lt;/span&gt;. The product &lt;span class="math"&gt;\(BA\)&lt;/span&gt; has the same dimensions as &lt;span class="math"&gt;\(W_0\)&lt;/span&gt;, but rank at most &lt;span class="math"&gt;\(r\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Equation (3) of the paper writes the modified forward pass as:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
h = W_0x + \Delta Wx = W_0x + BAx.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Immediately afterward, the paper specifies that the update contribution is scaled by &lt;span class="math"&gt;\(\alpha/r\)&lt;/span&gt;. Writing that scaling explicitly gives:&lt;/p&gt;
&lt;p&gt;
&lt;div class="math"&gt;$$
h = W_0x + \frac{\alpha}{r}BAx.
$$&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Here, &lt;span class="math"&gt;\(\alpha\)&lt;/span&gt; controls the strength of the update relative to its rank. The paper holds &lt;span class="math"&gt;\(\alpha\)&lt;/span&gt; fixed when varying &lt;span class="math"&gt;\(r\)&lt;/span&gt; in this construction. Rank and scaling are related settings, but changing rank changes the space of possible updates, not just their size.&lt;/p&gt;
&lt;p&gt;The paper initializes &lt;span class="math"&gt;\(A\)&lt;/span&gt; with random Gaussian values and &lt;span class="math"&gt;\(B\)&lt;/span&gt; with zeros. Consequently, &lt;span class="math"&gt;\(BA=0\)&lt;/span&gt; initially: the adapter starts by adding nothing to the original layer. Training then learns a nonzero adjustment. &lt;a href="https://arxiv.org/html/2106.09685v2#S4.SS1"&gt;Paper, section 4.1&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="how-much-smaller-is-the-trainable-part"&gt;How much smaller is the trainable part?&lt;a class="headerlink" href="#how-much-smaller-is-the-trainable-part" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a layer with &lt;span class="math"&gt;\(k\)&lt;/span&gt; inputs and &lt;span class="math"&gt;\(d\)&lt;/span&gt; outputs, full fine-tuning updates &lt;span class="math"&gt;\(dk\)&lt;/span&gt; matrix entries. LoRA trains &lt;span class="math"&gt;\(rk+dr=r(k+d)\)&lt;/span&gt; entries instead, excluding biases or any separately trained task head.&lt;/p&gt;
&lt;p&gt;Consider a 4,096-by-4,096 matrix and rank 8:&lt;/p&gt;
&lt;div class="table-responsive"&gt;
&lt;table class="table table-striped"&gt;
&lt;thead&gt;&lt;tr&gt;&lt;th scope="col"&gt;Trainable component&lt;/th&gt;&lt;th scope="col"&gt;Parameter count&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Full weight matrix&lt;/td&gt;&lt;td&gt;16,777,216&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LoRA matrix A, shape 8 by 4,096&lt;/td&gt;&lt;td&gt;32,768&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LoRA matrix B, shape 4,096 by 8&lt;/td&gt;&lt;td&gt;32,768&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Both LoRA matrices&lt;/td&gt;&lt;td&gt;65,536&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;That is &lt;strong&gt;256 times fewer trainable parameters for this matrix&lt;/strong&gt;. The frozen 16.8 million weights are still present, and the model still computes with them. Total training memory also includes activations and temporary buffers, so it will not fall by the same factor.&lt;/p&gt;
&lt;h3 id="a-training-step-with-frozen-weights"&gt;A training step with frozen weights&lt;a class="headerlink" href="#a-training-step-with-frozen-weights" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For our question-to-SQL example, training proceeds as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run a question through the model. Each adapted layer adds its LoRA adjustment to the original computation.&lt;/li&gt;
&lt;li&gt;Compare the predicted output with the target SQL query and calculate a loss.&lt;/li&gt;
&lt;li&gt;Backpropagate through the computation to determine how the adapter matrices should change.&lt;/li&gt;
&lt;li&gt;Update the adapter parameters, leaving the pretrained weights fixed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Frozen weights still participate in backpropagation.&lt;/strong&gt; Their operations help determine the gradients needed by adapters earlier in the network. LoRA saves the work and storage associated with updating the frozen weights; it does not eliminate the backward pass through the model.&lt;/p&gt;
&lt;h2 id="where-should-the-adapters-go"&gt;Where should the adapters go?&lt;a class="headerlink" href="#where-should-the-adapters-go" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Transformer attention uses projections called queries, keys, values, and an output projection. Queries and keys determine which positions attend to one another; values provide the information that attention combines.&lt;/p&gt;
&lt;p&gt;The original LoRA study concentrates on attention weights, usually the &lt;strong&gt;query and value projections&lt;/strong&gt;, while leaving the feed-forward networks frozen. LoRA itself is not restricted to those locations. The choice determines where the model can learn adjustments, and it matters alongside rank.&lt;/p&gt;
&lt;p&gt;In the paper's GPT-3 experiment with an approximately 18-million-parameter budget, adapting both query and value matrices at rank 4 works better on WikiSQL than spending the same budget on query matrices alone at rank 8. This illustrates why distributing capacity across useful locations can matter more than increasing the rank at one location. &lt;a href="https://arxiv.org/html/2106.09685v2#S7.SS1"&gt;Paper, sections 4.2 and 7.1&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="is-a-larger-rank-always-better"&gt;Is a larger rank always better?&lt;a class="headerlink" href="#is-a-larger-rank-always-better" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No. A larger rank allows a more expressive update and increases the number of trainable parameters, but does not guarantee better validation performance. On the paper's GPT-3 WikiSQL and MultiNLI experiments, query-and-value adapters already work well at very low ranks, including rank 1.&lt;/p&gt;
&lt;p&gt;That result is specific to those models and tasks. The authors explicitly caution that small ranks need not suffice for every dataset. Rank, placement, learning rate, and the training data should be evaluated together. A low-rank constraint can limit fitting capacity, but it does not by itself guarantee less overfitting. &lt;a href="https://arxiv.org/html/2106.09685v2#S7.SS2"&gt;Paper, section 7.2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-the-papers-results-establish"&gt;What the paper's results establish&lt;a class="headerlink" href="#what-the-papers-results-establish" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The experiments cover language understanding and generation using RoBERTa, DeBERTa, GPT-2, and GPT-3. They show that LoRA can match or exceed full fine-tuning on a range of tested tasks while training far fewer parameters. They do not establish that LoRA is always the best method for every adaptation problem.&lt;/p&gt;
&lt;p&gt;The GPT-3 175B results make the scale of the savings concrete:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Training memory:&lt;/strong&gt; the paper reports a reduction from 1.2 TB to 350 GB in its setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task-specific storage:&lt;/strong&gt; with rank-4 query-and-value adapters, the stored update is about 35 MB instead of a roughly 350 GB full-model checkpoint. The base model is still required.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training speed:&lt;/strong&gt; the reported throughput rises from 32.5 to 43.1 tokens per second per V100 GPU, using the same number of model-parallel weight shards. That corresponds to about 25% less time for the same token workload, not a universal runtime guarantee.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The approximately 10,000-fold reduction, or about 0.01% of the full parameter count, refers to the rank-4 storage example. It is not a fixed fraction for every LoRA configuration. &lt;a href="https://arxiv.org/html/2106.09685v2#S4.SS2"&gt;Paper, section 4.2&lt;/a&gt;.&lt;/p&gt;
&lt;details class="dinov2-background"&gt;
&lt;summary&gt;A closer look at the GPT-3 task scores&lt;/summary&gt;
&lt;p&gt;The following selection comes from the paper's table 4:&lt;/p&gt;
&lt;div class="table-responsive"&gt;
&lt;table class="table table-striped"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope="col"&gt;Method&lt;/th&gt;
&lt;th scope="col"&gt;Trainable parameters&lt;/th&gt;
&lt;th scope="col"&gt;WikiSQL accuracy&lt;/th&gt;
&lt;th scope="col"&gt;MNLI-m accuracy&lt;/th&gt;
&lt;th scope="col"&gt;SAMSum ROUGE-L&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full fine-tuning&lt;/td&gt;
&lt;td&gt;175,255.8 million&lt;/td&gt;
&lt;td&gt;73.8%&lt;/td&gt;
&lt;td&gt;89.5%&lt;/td&gt;
&lt;td&gt;44.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoRA&lt;/td&gt;
&lt;td&gt;4.7 million&lt;/td&gt;
&lt;td&gt;73.4%&lt;/td&gt;
&lt;td&gt;91.7%&lt;/td&gt;
&lt;td&gt;45.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoRA&lt;/td&gt;
&lt;td&gt;37.7 million&lt;/td&gt;
&lt;td&gt;74.0%&lt;/td&gt;
&lt;td&gt;91.6%&lt;/td&gt;
&lt;td&gt;45.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;WikiSQL reports logical-form validation accuracy for question-to-SQL prediction, rather than execution accuracy. MNLI-m measures whether one sentence entails, contradicts, or is neutral with respect to another, on the matched validation set. SAMSum evaluates dialogue summaries; ROUGE-L measures overlap with reference summaries using the longest common subsequence.&lt;/p&gt;
&lt;p&gt;These are different metrics, not interchangeable measurements of general intelligence. The smaller LoRA configuration is slightly below full fine-tuning on WikiSQL, within the paper's stated typical fluctuation of about 0.5 percentage points, while exceeding it on the other two reported metrics. The point is competitive task performance with much less trainable state, not a claim of a win in every table cell. &lt;a href="https://arxiv.org/html/2106.09685v2#S5.T4"&gt;Paper, table 4&lt;/a&gt;.&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id="serving-models-and-switching-tasks"&gt;Serving models and switching tasks&lt;a class="headerlink" href="#serving-models-and-switching-tasks" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During training, LoRA has two computational paths. At deployment, their weights can be &lt;strong&gt;merged&lt;/strong&gt;: add the learned update to the pretrained matrix once, then use the resulting matrix as an ordinary dense layer.&lt;/p&gt;
&lt;p&gt;With the paper's scaling made explicit, the merged matrix is:&lt;/p&gt;
&lt;div class="math"&gt;$$
W_{\mathrm{merged}} = W_0 + \frac{\alpha}{r}BA.
$$&lt;/div&gt;
&lt;p&gt;This is the basis of the paper's &lt;strong&gt;no additional inference latency&lt;/strong&gt; claim. After merging, there is no separate adapter computation at that layer. Keeping adapters separate can make task switching convenient, but retains the extra operations.&lt;/p&gt;
&lt;p&gt;Different tasks can share one base model and store separate small adapters. To switch a merged model between tasks, the paper describes subtracting the first update and adding the second. In practice, keeping the original base checkpoint also provides a clean starting point for each merge. Once weights are merged for one task, serving different adapters together in a batch requires additional handling; the original paper identifies this as a limitation. &lt;a href="https://arxiv.org/html/2106.09685v2#S4.SS1"&gt;Paper, sections 4.1 and 4.2&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="does-freezing-prevent-catastrophic-forgetting"&gt;Does freezing prevent catastrophic forgetting?&lt;a class="headerlink" href="#does-freezing-prevent-catastrophic-forgetting" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Freezing preserves the original parameter values, so disabling the adapters recovers the base model's computation when no other parameters have been changed. That is useful when maintaining several task-specific versions.&lt;/p&gt;
&lt;p&gt;It does not guarantee that the &lt;strong&gt;adapted model&lt;/strong&gt; retains every original capability. Its outputs depend on the adapters as well as the base weights, and the learned adjustment can harm performance on other tasks. Retention therefore needs evaluation alongside the new task's score. The original paper does not establish a general guarantee against catastrophic forgetting.&lt;/p&gt;
&lt;h2 id="how-lora-fits-among-peft-methods"&gt;How LoRA fits among PEFT methods&lt;a class="headerlink" href="#how-lora-fits-among-peft-methods" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The taxonomy below places LoRA in a broader family of approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Additive methods&lt;/strong&gt; introduce trainable components, such as nonlinear adapter modules or learned soft prompts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selective methods&lt;/strong&gt; update a subset of existing parameters, such as biases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reparameterization-based methods&lt;/strong&gt;, including LoRA, express a trainable change through a more economical parameterization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/img/PEFT_taxonomy.png"&gt;&lt;img alt="PEFT taxonomy showing overlapping additive, selective, and reparameterization-based methods; LoRA appears in the reparameterization group, while adapters and soft prompts occupy additive subgroups." src="https://mchromiak.github.io/articles/2023/Mar/18/LoRA-Low-Rank-Adaptation-of-Large-Language-Models/img/PEFT_taxonomy.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="center"&gt;Figure 2. Taxonomy reproduced from the 2023 survey &lt;a href="https://arxiv.org/abs/2303.15647v1"&gt;Scaling Down to Scale Up&lt;/a&gt;. The overlapping regions represent methods that combine ideas. This is a survey figure, not a figure from the original LoRA paper.&lt;/p&gt;
&lt;p&gt;The word &lt;em&gt;adapter&lt;/em&gt; can cause confusion here. A LoRA adapter is a pair of matrices representing a weight update. The classic bottleneck adapters compared in the original paper insert additional layers with a nonlinearity. LoRA's linear update can be merged into the original matrix; those nonlinear modules generally cannot be absorbed in the same way.&lt;/p&gt;
&lt;h2 id="from-lora-to-qlora"&gt;From LoRA to QLoRA&lt;a class="headerlink" href="#from-lora-to-qlora" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LoRA reduces the part of the model that must be trained. It leaves another large expense: storing the frozen base weights. &lt;strong&gt;QLoRA addresses that expense by storing the base model in four-bit form while training higher-precision LoRA adapters.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The distinction is simple: LoRA is a method for learning a compact update; QLoRA combines that method with quantization and additional memory-saving techniques. QLoRA is not merely LoRA with a smaller rank, and its placement experiments extend beyond the original LoRA paper's attention-focused study.&lt;/p&gt;
&lt;p&gt;Continue with &lt;a href="https://mchromiak.github.io/articles/2023/May/26/QLoRA-Efficient-Finetuning-of-Quantized-LLMs/"&gt;QLoRA: How to fine-tune large language models with less memory&lt;/a&gt; for NormalFloat, double quantization, paged optimizers, and the single-GPU results.&lt;/p&gt;
&lt;h2 id="the-takeaway"&gt;The takeaway&lt;a class="headerlink" href="#the-takeaway" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LoRA does not make a large pretrained model small. It makes the &lt;strong&gt;task-specific change&lt;/strong&gt; small. Two trainable matrices can provide a useful adjustment while the original model remains shared and fixed. The practical gains are fewer gradients and optimizer states, smaller task checkpoints, and ordinary inference computation when the update is merged.&lt;/p&gt;
&lt;p&gt;Its success depends on whether the chosen rank and adapter locations give the model enough freedom to learn the task. That is the trade-off to test: task quality against the memory, storage, and training cost of the update.&lt;/p&gt;
&lt;h2 id="sources-and-implementation"&gt;Sources and implementation&lt;a class="headerlink" href="#sources-and-implementation" title="Permanent link"&gt;🔗&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Hu et al., &lt;a href="https://arxiv.org/abs/2106.09685"&gt;LoRA: Low-Rank Adaptation of Large Language Models&lt;/a&gt;, first submitted in 2021 and published at ICLR 2022. This article follows &lt;a href="https://arxiv.org/html/2106.09685v2"&gt;arXiv version 2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Microsoft's official &lt;a href="https://github.com/microsoft/LoRA"&gt;LoRA repository and loralib&lt;/a&gt;, including examples for adding LoRA layers, saving adapter weights, and merging for inference. Its default setup trains only LoRA parameters; training biases is an explicit option.&lt;/li&gt;
&lt;li&gt;Aghajanyan et al., &lt;a href="https://arxiv.org/abs/2012.13255"&gt;Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning&lt;/a&gt;, the motivation cited by the LoRA authors.&lt;/li&gt;
&lt;li&gt;Lialin et al., &lt;a href="https://arxiv.org/abs/2303.15647v1"&gt;Scaling Down to Scale Up: A Guide to Parameter-Efficient Fine-Tuning&lt;/a&gt;, the source of the broader PEFT taxonomy.&lt;/li&gt;
&lt;/ul&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Optimization"/><category term="PEFT"/><category term="Adapter"/><category term="low-rank"/><category term="LLM"/></entry></feed>