AI Anytime LLM Fine-Tuning End-to-End Framework
Given any target LLM, dataset, and compute budget, apply a structured methodology to fine-tune an open-source or closed-source large language model using LoRA, QLoRA, and low-code tooling — without memorising training data and with minimised GPU cost.
// TL;DR
The AI Anytime LLM Fine-Tuning End-to-End Framework is a structured methodology for fine-tuning open-source large language models on custom datasets using LoRA, QLoRA, and the low-code Axolotl tool. It guides you through selecting a base model, preparing an instruction-response dataset, choosing between full fine-tuning, LoRA, and QLoRA, provisioning affordable GPU compute (RunPod, Vast.ai), configuring hyperparameters in YAML, and validating for generalisation over memorisation. Use it whenever you need to adapt an LLM to domain-specific data on a limited GPU budget — QLoRA can fine-tune a 7B model for around $5–$20 on a single A100.
// When should you use the LLM fine-tuning framework?
Use this skill whenever a user wants to fine-tune a large language model on a custom or domain-specific dataset and needs to select the right technique (full fine-tuning vs LoRA vs QLoRA), configure hyperparameters, choose compute infrastructure, and run training end-to-end. Also applies when a user is debugging an existing fine-tuning config or trying to reduce GPU memory requirements.
// What do you need before you start fine-tuning an LLM?
- Target LLMrequired
The base model to fine-tune, e.g. Llama 2 7B, Mistral 7B, OpenLlama 3B. Must be a commercially usable model if building a product. - Task-Specific Datasetrequired
Labeled examples relevant to the desired task, typically instruction-response pairs. Minimum recommended size: 10,000 question-answer pairs or ~10 MB file size for a CSV. - Fine-Tuning Techniquerequired
Choice of full fine-tuning, LoRA, or QLoRA. Determined by available GPU memory and dataset complexity. - Compute / GPU Setuprequired
Cloud provider and GPU spec chosen to meet memory requirements (~150–195 GB for 7B models). Options: RunPod, Vast.ai, Lambda Labs, AWS SageMaker, Google Colab. - Hyperparameter Config (YAML)
LoRA rank (r), LoRA alpha, target modules, batch size, gradient accumulation steps, number of epochs, learning rate. Can be auto-populated from an Axolotl YAML template.
// What core principles drive effective LLM fine-tuning?
Pre-Training → Fine-Tuning → LoRA/QLoRA Progression
These are three distinct but related approaches. Pre-training teaches general language knowledge on terabytes of text. Fine-tuning specialises that knowledge on a task-specific dataset. LoRA and QLoRA reduce the memory cost of fine-tuning by injecting trainable rank decomposition matrices rather than updating all weights.
Generalise, Don't Memorise
The fine-tuned model should generalise to unseen data, not memorise the training set too closely. Use regularisation techniques (dropout, weight decay, early stopping) and ensure diversity in your dataset so the model handles varied inputs.
Preservation of Pre-Trained Weights (LoRA Core Principle)
LoRA maintains the frozen state of pre-trained weights, minimising the risk of catastrophic forgetting. The model retains its base language knowledge while adapting to new data through small, portable update matrices.
Rank Determines Capacity vs. Cost
The LoRA rank (r) controls how many rank decomposition matrices are applied to weight matrices. Higher rank = better results but more compute. Start at r=8 (paper recommendation), increase for complex datasets, decrease if hitting memory limits.
Quality Data Over Quantity
Models like Phi (Microsoft) and Orca demonstrate that higher-quality data enables effective fine-tuning at smaller parameter counts (1.5B–3B). Prioritise data quality — diverse, clean, well-structured instruction-response pairs — above raw dataset size.
FT Is Expensive — QLoRA Is the Equaliser
Full fine-tuning of a 175B model with Adam requires 16× A100 (80 GB) GPUs. LoRA reduces trainable parameters by 10,000× and GPU memory by ~3×. QLoRA (quantised LoRA via bits-and-bytes) further reduces this to 2× RTX 3090s for 70B models — making fine-tuning accessible to researchers and startups.
Gradient Accumulation as the Memory Fix
When batch size is constrained by GPU VRAM, gradient accumulation splits a global batch into sequential mini-batches, accumulates their gradients, then performs a single weight update. This simulates a larger effective batch size without the memory cost.
// How do you fine-tune an LLM step by step?
- 1
Define the fine-tuning objective and select the base model
Choose a commercially usable open-source model (Llama 2 7B, Mistral 7B, OpenLlama 3B) for product use cases. Identify whether the task requires instruction-tuning (instruction-response pairs), domain adaptation, or code generation. Confirm the model license permits your use case.
- 2
Prepare and validate the task-specific dataset
Gather labeled examples as instruction-response pairs (JSONL or CSV). Enforce: (a) diversity — multiple scenarios so the model handles varied inputs; (b) minimum size — 10,000 pairs or ~10 MB CSV; (c) quality — follow Phi/Orca principle: fewer high-quality samples beat many low-quality ones. Remove PII and duplicates. Source: Hugging Face Datasets hub for learning; proprietary data for production.
- 3
Select the fine-tuning technique based on compute budget
Full fine-tuning: ~150–195 GB VRAM for 7B models — rarely feasible without enterprise hardware. LoRA: ~3× memory reduction vs full fine-tuning; use when you have multiple A100s. QLoRA (quantised LoRA): load model in 4-bit via bits-and-bytes; enables 7B–70B fine-tuning on consumer GPUs (2× RTX 3090 or 1× A100). Default recommendation for most users: QLoRA.
- 4
Provision GPU compute on a cloud provider
Preferred order: RunPod (recommended — affordable, reliable, secure cloud option) → Vast.ai (cheapest but security concerns on community cloud) → Lambda Labs → AWS SageMaker. For 7B models: 1× A100 80 GB (~$2/hr on RunPod) is sufficient for QLoRA. A 2,000–3,000 row dataset trains in ~$5. Spin up a JupyterLab instance via the provider's dashboard.
- 5
Set up Axolotl as the low-code fine-tuning tool
Clone the Axolotl GitHub repository into the JupyterLab environment. Install dependencies via: pip install packaging, then pip install -e '.[flash-attn,deepspeed]'. Ensure flash-attention >= 2.0 (version 1.x causes errors). Axolotl accepts a single YAML config file as input — this is the control surface for the entire fine-tuning run.
- 6
Configure the YAML file with model, dataset, and LoRA/QLoRA hyperparameters
Navigate to examples/<your-model>/lora.yml or qlora.yml in the Axolotl repo. Set: base_model path or Hugging Face ID; dataset path (local or HF hub); load_in_4bit: true for QLoRA; LoRA hyperparameters (see step 7); num_epochs (start with 1 for testing); micro_batch_size (start with 1); gradient_accumulation_steps (start with 8); learning_rate (~2e-4 typical). Point dataset field to your JSONL/CSV file path or Hugging Face dataset name.
- 7
Set LoRA hyperparameters deliberately
lora_r (LoRA rank): start at 8 (paper default); increase to 16 or 32 for complex datasets; higher rank = better results but more compute. lora_alpha (scaling factor): typically 2× lora_r; lower value preserves more base model knowledge; higher value shifts toward new data. lora_target_modules: at minimum target q_proj (query projection) and v_proj (value projection); optionally add k_proj, o_proj, gate_proj, down_proj, up_proj. If dataset has custom syntax, also target embed_tokens and lm_head. Find exact module names via: [name for name in model.state_dict().keys()].
- 8
Configure QLoRA-specific settings if using quantisation
Set load_in_4bit: true. Set bnb_4bit_quant_type: nf4 (4-bit NormalFloat — optimally handles normally distributed weights). Enable double quantisation (bnb_4bit_use_double_quant: true) to further reduce average memory footprint by quantising the quantisation constants. bits-and-bytes library handles on-the-fly near-lossless quantisation. Expect minor performance degradation — treat as acceptable tradeoff for feasibility.
- 9
Set batch size and gradient accumulation to manage memory
Effective batch size = micro_batch_size × gradient_accumulation_steps × num_GPUs. If GPU OOM errors occur: reduce micro_batch_size to 1, increase gradient_accumulation_steps to 8 or 16 to maintain effective batch size. Understand: one epoch = (dataset_size / batch_size) batches = that many weight updates. Larger batch size → higher GPU memory → use gradient accumulation to compensate.
- 10
Launch fine-tuning and monitor training
Run: accelerate launch -m axolotl.cli.train examples/<model>/qlora.yml. Monitor: train_loss (should decrease), tokens per second, steps per second. Ignore standard warnings. Training a 7B model for 1 epoch on ~2,000–3,000 rows takes approximately 1–2 hours on 1× A100. Checkpoints are saved to the output directory (e.g. qlora-out/). Enable Weights & Biases (wandb) in the YAML for experiment tracking.
- 11
Inspect outputs and validate the fine-tuned adapter
Output directory contains: adapter_model.bin or .safetensors (the LoRA weights), adapter_config.json, optimizer.pt, scheduler.pt. These LoRA adapter weights are portable — they can be merged with the base model or used standalone. Test via the built-in Gradio interface (axolotl.cli.inference) or load the adapter with Hugging Face PEFT library. Run sample prompts similar to — but not identical to — training data to verify generalisation, not memorisation.
- 12
Iterate on hyperparameters based on results
If model memorises training data: increase dataset diversity, add dropout/weight decay, reduce epochs. If model underperforms on new inputs: increase lora_r, increase dataset size/quality, increase epochs. If OOM errors: reduce lora_r, reduce micro_batch_size, enable QLoRA if not already using it. Learning rate too small → slow convergence or local minima. Learning rate too large → unstable training.
// What do real LLM fine-tuning projects look like?
A startup wants to fine-tune a 7B model to act as a domain-specific customer support assistant using 5,000 historical support ticket Q&A pairs, with a budget of ~$20.
Select Mistral 7B (commercially licensed). Format the 5,000 pairs as instruction-response JSONL. Choose QLoRA (load_in_4bit: true, nf4) to fit within 1× A100 budget. Set lora_r=16 (moderate dataset complexity), lora_alpha=32, target q_proj + v_proj + o_proj. Set micro_batch_size=1, gradient_accumulation_steps=8, num_epochs=2. Run on RunPod A100 (~$4/hr × ~2hrs × 2 epochs ≈ ~$16). Validate with held-out tickets not in training set to confirm generalisation.
A researcher wants to instruction-tune an open-source LLM on a high-quality 500-sample dataset following the Phi/Orca quality-over-quantity principle, on a single RTX 3090.
Apply QLoRA with bits-and-bytes 4-bit quantisation — the only technique feasible on a single 24 GB consumer GPU. Use a small model (3B–7B). Set lora_r=8 (paper default — fewer samples don't justify higher rank), lora_alpha=16. Set micro_batch_size=1, gradient_accumulation_steps=16. Prioritise dataset quality: ensure each of the 500 samples is diverse, correct, and covers varied instruction types. Run 3–5 epochs given the small dataset. Evaluate on a 10% validation split held out from the 500 samples.
// What mistakes should you avoid when fine-tuning an LLM?
- Treating fine-tuning as cheap: full fine-tuning of multi-billion parameter models requires hundreds of GBs of VRAM — do not attempt without LoRA or QLoRA unless you have enterprise compute.
- Setting LoRA rank (lora_r) too low for a complex dataset: rank=8 is the paper minimum; complex datasets with rich relational structure need rank=16 or 32.
- Confusing batch size with epoch: batch size is samples processed per update; epoch is one full pass through the entire dataset. These are independent hyperparameters.
- Using flash-attention 1.x instead of 2.x: flash-attention version 1 causes errors in Axolotl — always install flash-attention >= 2.0.
- Ignoring data diversity: training a chat model on a single type of conversation will cause failure on unseen input types — the model cannot generalise what it has not seen.
- Memorisation instead of generalisation: too many epochs on a small dataset causes the model to memorise training examples rather than learn patterns — use early stopping and validation splits.
- Not checking target module names per model: q_proj, v_proj naming conventions differ across model families — always inspect model.state_dict().keys() to confirm exact layer names before setting lora_target_modules.
- Skipping the fundamentals: using low-code tools like Axolotl without understanding pre-training, tokenisation, gradient descent, and LoRA mechanics leads to inability to debug errors or tune performance.
- Choosing Lambda Labs for ease: Lambda Labs has poor support — RunPod is the recommended provider for reliability and affordability.
- Assuming QLoRA has zero performance degradation: quantisation introduces minor performance reduction; treat it as an acceptable tradeoff, but do not assume lossless equivalence to full precision training.
// What are the key LLM fine-tuning terms you should know?
- Pre-Training
- The initial training phase where a model learns general language knowledge (next-word prediction or masked token prediction) on terabytes of text data. Produces a model with general language understanding but no task-specific knowledge.
- Fine-Tuning
- The downstream training phase that specialises a pre-trained model's capabilities on a task-specific, labeled dataset (e.g. instruction-response pairs) by adjusting model weights using gradient-based optimisation. Data size is significantly smaller than pre-training.
- LoRA (Low-Rank Adaptation)
- A training method that reduces memory consumption by injecting pairs of rank decomposition matrices (update matrices) into the model's existing layers, rather than updating all pre-trained weights. Reduces trainable parameters by up to 10,000× and GPU memory by ~3× vs. full fine-tuning.
- QLoRA (Quantised Low-Rank Adaptation)
- LoRA applied to a model loaded in 4-bit quantisation via the bits-and-bytes library. Achieves near-lossless quantisation and enables fine-tuning of 70B models on 2× RTX 3090s instead of 16× A100s.
- LoRA Rank (lora_r)
- Hyperparameter that determines the number of rank decomposition matrices applied to weight matrices. Higher rank = better results but more compute. Paper recommends r=8 as default; complex datasets may require r=16 or r=32.
- LoRA Alpha (lora_alpha)
- Scaling factor that adjusts the contribution of the update matrices during training. Lower value gives more weight to original pre-trained data (preserves base knowledge); higher value shifts the model more toward new training data.
- LoRA Target Modules
- The specific weight matrices selected for LoRA adaptation. Minimum: q_proj (query projection) and v_proj (value projection). Extended targets include k_proj, o_proj, gate_proj, down_proj, up_proj, embed_tokens, lm_head, and norm layers depending on dataset complexity.
- q_proj (Query Projection)
- The projection matrix applied to query vectors in the Transformer attention mechanism. Transforms input hidden states to the desired dimensions for query representation. One of the most important LoRA target modules.
- v_proj (Value Projection)
- The projection matrix applied to value vectors in the Transformer attention mechanism. Transforms input hidden states for effective value representation. Paired with q_proj as the minimum LoRA target.
- lm_head
- The output layer of a language model responsible for generating predictions/scores for the next token. Critical to target in LoRA if the dataset contains custom syntax or specialised output formats.
- embed_tokens
- Parameters in the embedding layer that map input tokens to their vector representations. Important LoRA target when the dataset uses custom vocabulary or syntax.
- nf4 (4-bit NormalFloat)
- A quantisation data type used in QLoRA that optimally handles normally distributed model weights. Enabled via bits-and-bytes library for near-lossless 4-bit quantisation.
- Instruction Tuning (Instruction-Tuned Model)
- A fine-tuning approach where the training dataset consists of instruction-response pairs, teaching the model to follow natural language instructions. The dominant paradigm for chat and assistant models.
- Gradient Accumulation Steps
- A mechanism to simulate large batch sizes without high VRAM: the global batch is split into sequential mini-batches, gradients are accumulated across them, and a single weight update is performed. Effective batch size = micro_batch_size × gradient_accumulation_steps × num_GPUs.
- Causal Language Modeling (CLM)
- The pre-training objective focused on predicting the next word in a sequence given the preceding context. Underpins autoregressive generation models. Distinct from Masked Language Modeling (MLM), which predicts masked tokens.
- Masked Language Modeling (MLM)
- A pre-training objective where certain tokens are intentionally hidden and the model must predict them from surrounding context. Used in encoder-style models; contrasted with Causal Language Modeling.
- Catastrophic Forgetting
- The risk that fine-tuning on new data causes the model to lose its previously learned general language knowledge. LoRA mitigates this by keeping pre-trained weights frozen and only training the injected update matrices.
- Axolotl
- A low-code fine-tuning tool that accepts a single YAML configuration file as input and handles the full fine-tuning pipeline (data loading, tokenisation, LoRA/QLoRA setup, training, checkpointing). The recommended tool in this framework for productivity and efficiency.
- bits-and-bytes (bnb)
- A Python library used by QLoRA to perform on-the-fly 4-bit quantisation of language models, enabling near-lossless model compression and fine-tuning on consumer-grade GPUs.
- Rank Decomposition Matrices (Update Matrices)
- The pairs of low-rank matrices injected by LoRA into existing model layers. These are the only weights trained during LoRA fine-tuning; the original model weights remain frozen.
- Portability of Trained Weights
- A LoRA advantage: the rank decomposition matrices have far fewer parameters than the original model, making them easy to transfer, share, and use across different contexts without carrying the full model.
// FREQUENTLY ASKED QUESTIONS
What is LLM fine-tuning and when do I need it?
LLM fine-tuning specialises a pre-trained model on a task-specific labeled dataset by adjusting weights through gradient-based optimisation. You need it when you want a model to master a domain — customer support, code, medical Q&A — that generic base models handle poorly. Use instruction-response pairs and techniques like LoRA or QLoRA to keep GPU costs low while adapting the model's behaviour.
What is the difference between LoRA and QLoRA?
LoRA injects small trainable rank decomposition matrices into a full-precision model, reducing trainable parameters by up to 10,000× and GPU memory by ~3×. QLoRA does the same but loads the base model in 4-bit quantisation via bits-and-bytes, cutting memory further so you can fine-tune 70B models on 2× RTX 3090s instead of 16× A100s. QLoRA is the recommended default for most users.
How do I fine-tune a 7B model on a budget?
Use QLoRA on a single A100 80GB (~$2/hr on RunPod). Format your data as instruction-response JSONL, clone Axolotl, set load_in_4bit: true with nf4 quantisation, and configure lora_r=8-16. A 2,000-3,000 row dataset trains in 1-2 hours for roughly $5-$20 total. Validate on held-out samples to confirm the model generalises.
How do I choose LoRA rank and alpha?
Start with lora_r=8 (the paper default) and set lora_alpha to roughly 2× the rank (e.g. 16). Increase rank to 16 or 32 for complex datasets with rich relational structure, or decrease it if you hit GPU memory limits. Higher rank means better results but more compute; higher alpha shifts the model toward new data rather than preserving base knowledge.
How does fine-tuning compare to using RAG or prompt engineering?
Fine-tuning changes model weights to internalise a task's style, format, or domain behaviour, while RAG retrieves external facts at inference and prompt engineering steers a frozen model with instructions. Choose fine-tuning for consistent tone, custom syntax, or specialised task behaviour; use RAG for fresh or factual knowledge; use prompting for quick, low-cost adjustments. They are complementary, not mutually exclusive.
When should I use full fine-tuning instead of LoRA or QLoRA?
Only use full fine-tuning when you have enterprise-grade compute — 7B models need ~150-195GB VRAM and a 175B model needs 16× A100 80GB GPUs. For most startups, researchers, and individuals, QLoRA is the better choice because it delivers comparable results at a fraction of the cost while preserving pre-trained weights and avoiding catastrophic forgetting.
What results can I expect from fine-tuning with QLoRA?
Expect a model that follows your domain-specific instructions and output format reliably, with only minor performance degradation from 4-bit quantisation. A well-prepared 5,000-pair dataset can produce a competent domain assistant for under $20. Results depend heavily on data quality and diversity — clean, varied instruction-response pairs matter more than raw volume, per the Phi/Orca principle.
How much GPU memory do I need to fine-tune an LLM?
Full fine-tuning of a 7B model needs ~150-195GB VRAM. LoRA reduces this by roughly 3×, and QLoRA reduces it further so a single A100 80GB or even 2× RTX 3090s (24GB each) can fine-tune 7B-70B models. If you hit out-of-memory errors, reduce micro_batch_size to 1 and raise gradient_accumulation_steps to maintain effective batch size.
What dataset size do I need to fine-tune an LLM?
A minimum of ~10,000 instruction-response pairs or a ~10MB CSV is recommended, but quality beats quantity. Models like Phi and Orca show that 500 high-quality, diverse samples can outperform thousands of noisy ones. Prioritise clean, varied, well-structured pairs, remove PII and duplicates, and always hold out a validation split to check for generalisation.
Why does my fine-tuned model memorise training data instead of generalising?
Memorisation usually means too many epochs on a small dataset or insufficient data diversity. Reduce epochs, add dropout or weight decay, and expand the variety of scenarios in your dataset so the model sees many input types. Use early stopping and a validation split, and test with prompts similar to — but not identical to — your training examples.