Finetune LLM with QLoRA

Finetune OVerview

Introduction

Large Language Models (LLMs) have become an integral part of our daily lives, powering everything from chatbots to code generation tools. However, these models are typically trained for general purposes, and in many cases, we may need them to specialize in a particular domain or use case. This is where LLM fine-tuning comes into play, allowing us to adapt these powerful models to our specific needs. The challenge, however, is that fine-tuning such massive models requires substantial computational resources—far beyond what is available for free. To address this, researchers have developed techniques like LoRA (Low-Rank Adaptation) and its optimized variant, QLoRA (Quantized LoRA), which significantly reduce the resource requirements for fine-tuning while maintaining model performance. In this blog, we’ll explore how QLoRA enables efficient fine-tuning of LLMs on limited hardware.

LoRA and QLoRA

NN Architecture

LoRA :

It works by adding a smaller number of new weights to the model, which are then trained, rather than retraining the entire model or adding new layers for new tasks. It keeps the original model unchanged and adds small, changeable parts to each layer of the model. This significantly reduces the trainable parameters of the model and reduces the GPU memory requirement for the training process.

Low Rank Matrices: Low Rank Matrices are very important with respect to LoRA working. A matrix is of lower rank if its rank is less than the maximum possible given its size. For example, in a 3x3 matrix, if the rank is less than 3, it's a lower rank matrix. Lower rank matrix helps in compressing the data while preserving as much information as possible.

Large models have a lot of parameters. For example, GPT-3 has 175 billion parameters. These parameters are just numbers stored in matrices. Storing them requires a lot of storage. Full fine-tuning means all the parameters will be trained, and this will require an extraordinary amount of compute resources that can easily cost in the millions of dollars for a model size like GPT. Unlike traditional fine-tuning that requires adjusting the entire model, LoRA focuses on modifying a smaller subset of parameters (lower-rank matrices), thereby reducing computational and memory overhead.

Reducing the matrix to low rank:

In transformer models, the weight matrix \( W \) in a linear layer transforms input features \( x \): \( y = Wx \)

where:

During fine-tuning, updating \( W \) requires \( d \times k \) trainable parameters, which is costly.

LoRA Optimization

Instead of updating \( W \) directly, LoRA introduces two small trainable matrices \( A \) and \( B \) of rank \( r \): \(\Delta W = BA \)

where:

Since \( \Delta W \) is the product of two low-rank matrices, it captures model updates with far fewer parameters.

Parameter Reduction with LoRA

Instead of \( d \times k \) parameters in full fine-tuning, LoRA requires: \(r(d + k)\)

For example, if:

QLoRA:

QLoRA represents a more memory-efficient iteration of LoRA. QLoRA takes LoRA a step further by also quantizing the weights of the LoRA adapters (smaller matrices) to lower precision (e.g., 4-bit instead of 8-bit).

Core Idea:
  1. Storing model weights in 4-bit precision
  2. Converting them to 16-bit only when needed for computations
  3. Using special techniques to maintain accuracy despite the compression
Qlora
Main Techniques
  1. NormalFloat(NF4) Quantization: 4-bit NormalFloat Quantization is a method designed to efficiently quantize the weights of neural networks into a 4-bit format. NormalFloat data type is designed to optimally quantize data, particularly for use in neural networks and based on a method called “Quantile Quantization” which ensures that each bin (or category) in the quantization process has an equal number of values from the input data.

  2. Double Quantization: Double quantization is the process of quantizing the quantization constant to reduce the memory down further to save these constant.

  3. Paged Quantization: When training large models with billions of parameters GPU’s running out of memory is common problem. Paged optimizers are used to address these memory spikes that occur during model training. NVIDIA unified memory facilitates automatic page-to-page transfers between the CPU and GPU, similar to regular memory paging between CPU RAM and the disk. When the GPU runs out of memory, these optimizer states are moved to the CPU RAM and are transferred back into GPU memory when needed.

Implementation

Much of the below code is just important steps and configurations for the training. For entire code see here

References and useful resources:

  1. QLoRA Paper
  2. QLoRA: Fine-Tuning Large Language Models (LLM’s)
  3. Mastering Low-Rank Adaptation (LoRA): Enhancing Large Language Models for Efficient Adaptation
  4. Making LLMs even more accessible with bitsandbytes, 4-bit quantization and QLoRA