Enterprise DNA

Omni by Enterprise DNA

Enterprise DNA Resources

Step-by-step how-tos. Practical AI operating-system thinking for owners, operators, and teams doing real work.

220k+

Data professionals

Omni

AI agents and apps

Audit

Map the manual work

Guide Intermediate General

LoRA Fine TuningTutorial: GPU Free Setup Guide

A practical LoRA fine tuning tutorial that runs on free GPU tiers like Colab and Kaggle, with real code, real settings, and an honest look at the trade-offs.

Sam McKay |
LoRA Fine TuningTutorial: GPU Free Setup Guide

What LoRA actually is

LoRA stands for Low-Rank Adaptation. It is a parameter-efficient fine-tuning method introduced in 2021 by Hu and colleagues as a way to adapt large pretrained models without retraining every weight. The core idea is simple and worth understanding because everything else flows from it.

A standard transformer has weight matrices, mostly in the attention and feed-forward layers, with dimensions like 4096 by 4096. That is roughly 16 million parameters per matrix. Full fine-tuning updates all of them, which means storing gradients, optimizer states, and a copy of the model for every training step. On a 7 billion parameter model, that adds up to many tens of gigabytes of VRAM just to update, before you even count the model weights themselves.

LoRA freezes the original weights entirely. It then injects two small trainable matrices alongside each target weight. If the original weight W is d by k, LoRA adds a pair of matrices A and B, where A is d by r and B is r by k, and r is a small rank like 8 or 16. The product A times B is d by k, the same shape as W, so it can be added in. During training, only A and B get gradient updates. The number of trainable parameters drops by orders of magnitude, often to less than one percent of the full model.

At inference time you have two options. You can keep the LoRA adapters separate and load them on top of the base model when you need them, which is great for swapping skills in and out. Or you can merge the adapter weights back into the base model and save a single set of weights, with no runtime overhead at all.

QLoRA is the variant most people actually use on free GPUs. It combines LoRA with 4-bit quantization of the frozen base model, so the base weights take roughly a quarter of the memory they would otherwise need. Dettmers and coauthors introduced this in 2023, and it is what makes 7B and 13B models trainable on a 16GB consumer card or a free Colab T4.

The marketing version of LoRA talks about “training huge models on a laptop.” The honest version is that LoRA is a genuinely clever mathematical trick that lets you adapt a frozen model cheaply. The savings are real. They are not magic, and the quality ceiling is lower than full fine-tuning for tasks that need deep behavior change.

Setup and authentication

The fastest path to a working LoRA setup on free infrastructure is Google Colab, Kaggle Notebooks, or Lightning AI Studios. All three give you a Jupyter environment with a free GPU and zero local setup.

For Colab, open a new notebook, then in the menu choose Runtime, then Change runtime type, then set Hardware accelerator to T4 GPU. The free tier gives you a T4 with 15GB of VRAM, with idle disconnects after a short window. For longer runs, Kaggle’s free tier gives you 30 hours per week of GPU access with a T4 or P100 and longer session stability.

You will need a Hugging Face account to pull the base model and push your trained adapter. Create an account at huggingface.co if you do not have one. Then go to Settings, then Access Tokens, then create a new token with write scope. Copy the token into your notebook with the userdata helper in Colab.

Install the libraries. The current versions of the relevant packages are what you should grab, and pinning them avoids the usual breakage from upstream API drift.

In a Colab cell, run pip install -q transformers peft trl datasets bitsandbytes accelerate. The bitsandbytes package is what provides the 4-bit quantization kernels that QLoRA depends on. The trl package wraps Hugging Face Trainer with supervised fine-tuning helpers that handle the chat template and padding for you.

For a private or gated model, accept the license on the model’s Hugging Face page first, then authenticate. In a notebook cell write from huggingface_hub import login, then login with your token. The CLI alternative is huggingface-cli login, which prompts you in a terminal.

If you want to push your finished adapter to the Hub, you will also need to call trainer.push_to_hub with your repository name. The token you stored earlier gives that write access.

First working example

Below is a complete, runnable fine-tuning of a small open model on a free Colab T4. The model is small enough that you can also scale this to a 7B model on the same hardware if you are willing to use 4-bit quantization.

The dataset is a small instruction-following set in Alpaca format, which has an instruction, an optional input, and an expected output. You can swap in your own JSON Lines file in the same shape.

Load the model and tokenizer. We use AutoModelForCausalLM and BitsAndBytesConfig to load in 4-bit. The bnb_4bit_quant_type field set to nf4 is the recommended setting from the QLoRA paper. The compute dtype of bfloat16 works on T4, though bfloat16 support on T4 is partial. Float16 is a safer fallback if you see NaNs.

Wrap the base model with PeftModel and get_peft_model. The LoraConfig takes a target_modules list. For most decoder-only models this is the attention projection names. You can inspect them by printing the model and looking for Linear layers inside the attention blocks. Common targets are q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj.

Then create an SFTTrainer from trl. Pass the LoRA-wrapped model, the training arguments, the dataset, and a formatting function that turns each example into a single string. The SFTConfig in the current version of TRL handles packing and the chat template internally if you pass a tokenizer with a chat template.

A minimal training arguments block looks like this. Per-device train batch size of 2, gradient accumulation steps of 4, learning rate of 2e-4, num_train_epochs of 3, warmup ratio of 0.03, logging steps of 10, save strategy of steps, save steps of 100, and a bf16 or fp16 flag matching your hardware.

Call trainer.train. On a T4 with a 1B parameter model and a few thousand examples, this finishes in well under an hour. On a 7B model with 4-bit quantization, expect longer, in the range of one to three hours for a similar dataset.

After training, save the adapter with model.save_pretrained. To use it for inference, load the base model in the same way, then call PeftModel.from_pretrained with the adapter path. For production, call model.merge_and_unload and save the merged model, which removes the adapter overhead and gives you a single set of weights you can serve with vLLM, TGI, or llama.cpp.

Key settings that matter

Rank is the single most important knob. It is the r in the low-rank decomposition. Typical values are 4, 8, 16, 32, and 64. Lower rank means fewer trainable parameters, less memory, and faster training, but less expressive capacity. Higher rank lets the adapter represent more complex adaptations but starts to eat the memory savings. For most style and tone adaptations, 8 or 16 is plenty. For behavior shifts, you may want 32 or 64.

Alpha controls the scaling of the LoRA update. The effective update is alpha divided by rank times the product A times B. The common rule of thumb is to set alpha equal to 2 times rank, so the effective scale is 2. Setting alpha equal to rank gives a scale of 1, which is more conservative.

Target modules decide where in the model the adapters get injected. Attention-only targets (q_proj and v_proj) are the original recommendation from the LoRA paper and work well for many tasks. Adding the MLP projections (gate_proj, up_proj, down_proj) typically gives a quality bump at the cost of more trainable parameters and memory. For most decoder-only models in the current landscape, the all-linear convention is a solid default.

Learning rate for LoRA is much higher than full fine-tuning. Full fine-tuning of a 7B model usually uses a learning rate in the 1e-5 to 5e-5 range. LoRA training commonly uses 1e-4 to 3e-4. Going higher than that without a warmup usually destabilizes training.

Quantization dtype for QLoRA is the next decision. NF4 with double quantization is the default and a sensible starting point. FP4 is faster but slightly less accurate in practice. If you have a GPU with good bfloat16 support, you can also use 8-bit quantization for the base model, which costs more memory but trains more stably.

Sequence length matters more than most beginners expect. Long contexts multiply memory use in attention. On a T4 with a 7B model in 4-bit, a sequence length of 1024 is the practical ceiling for batch size 1. You can trade batch size for sequence length with gradient accumulation, but you cannot escape the attention memory cost.

Number of epochs and dataset size are where the quality ceiling actually lives, not the LoRA settings themselves. A rank-8 adapter trained for many epochs on a well-curated thousand-example set will usually outperform a rank-64 adapter trained for one epoch on noisy data.

Where it shines

LoRA is at its best when you need to teach a strong base model a narrow, well-defined skill. Examples that work well include teaching a model to respond in a specific format, to follow a particular writing style, to use domain terminology correctly, or to output structured data in a schema of your choice.

It is also excellent for tool use and function calling, where you are essentially teaching the model a new output grammar. The adapter is small, often tens of megabytes, so you can keep a library of them, one per tool or per customer, and swap them in and out at runtime.

Multilingual adaptation is another good fit. A base model that already knows a language can be nudged into cleaner, more idiomatic output in that language with a relatively small LoRA on a few thousand examples.

Personalization is the use case that gets the most attention. You can fine-tune a small adapter per user or per account, and because the base model is shared, you only pay the storage cost for the small adapter files. This is the architecture behind a lot of the “your own AI” services in the current landscape.

LoRA also shines in research and experimentation. Because each training run is cheap, you can iterate on prompts, data mixes, and hyperparameters far more aggressively than you can with full fine-tuning. The feedback loop is short, which matters more than people expect.

Where it fails

LoRA cannot teach a model genuinely new factual knowledge at the scale most people imagine. The base model’s weights are frozen, and the adapter is too small to store more than a sliver of new information. If you try to fine-tune a model to “know” your entire 500-page internal knowledge base, you will get a model that hallucinates confidently in the shape of your documents.

Tasks that require large behavior changes are also a poor fit. If the base model refuses a class of requests and you want it to comply, LoRA will fight the base weights and usually lose. The adapter capacity is not enough to override a strong prior baked into the model.

Long-context reasoning is limited by the base model’s context length, not by LoRA. People sometimes blame LoRA for context failures when the underlying issue is the model running out of attention budget.

Inference quality at the high end still trails full fine-tuning, especially for tasks like complex math, multi-step reasoning, and code generation. The gap is smaller than it used to be, and a well-tuned QLoRA adapter is often within a few percent of full fine-tuning on standard benchmarks, but the ceiling is real.

Free GPU tiers have their own failure modes. Colab will time out and disconnect you if your session sits idle or runs too long. Kaggle resets your weekly quota. Lightning AI free credits expire. For any production work, plan for a paid tier or a self-hosted box, because the free tiers are training environments, not reliable serving environments.

Merging adapters is not free of trade-offs. Once you merge a LoRA into the base model, you cannot easily unmerge it, and you cannot selectively disable it. For multi-adapter pipelines, keep adapters separate and load them at inference.

Practical workflow pattern

A realistic workflow looks like this. Start with a strong base model, usually one of the open 7B to 13B parameter chat models in the current landscape. Pick the smallest model that can plausibly do the task, because smaller models are faster to iterate on and easier to serve.

Curate a small, high-quality dataset. A few hundred to a few thousand examples is usually enough for a narrow skill. Quality matters more than quantity, and you should be ruthless about removing noise, duplicates, and examples that conflict with what you actually want.

Run a baseline evaluation before you train anything. Pick a small held-out set of inputs, generate outputs from the base model, and score them. This is your floor, and it tells you whether LoRA is moving the needle at all.

Train with conservative defaults. Rank 16, alpha 32, attention plus MLP targets, learning rate 2e-4, three epochs, sequence length 1024. Save checkpoints frequently so you can compare runs.

Evaluate after training on the same held-out set, plus a small set of edge cases and adversarial inputs. Look for regressions as well as improvements, because LoRA can make the model better at one thing and worse at something it used to do well.

If the adapter is good, decide between merging and keeping it separate. Merge if you are shipping a single-purpose model and want maximum inference speed. Keep separate if you want to swap adapters, A/B test, or roll back easily.

Store your training data, your LoRA config, your evaluation prompts, and your notes in version control. LoRA runs are cheap, but reproducibility is not free, and you will want to rerun this in three months.

For the “GPU free” angle specifically, treat the free tier as your development environment. Use it to iterate on data, prompts, and configurations. When you have a configuration that works, promote it to a paid Colab Pro, a Lambda, a RunPod, or a CoreWeave for the long training run and any production serving.

For a deeper walkthrough of tools like this and how they fit together, the free Working With Claude field guide covers the ecosystem end to end. Get the guide.