Fine-Tuning 27B–32B LLMs on a Single 24GB GPU: Unsloth and 4-Bit QLoRA Production Guide
AK
Alex Kim Threat intelligence editor · Updated Aug 15, 2026, 8:25 AM EDT
Learn how to fine-tune 27B–32B LLMs like Qwen 2.5 on a single 24GB GPU using Unsloth and 4-bit QLoRA with full code, memory optimization, and serving guides.
Fine-tuning 27B to 32B open-weight large language models on a single 24GB GPU is now achievable in production using Unsloth and 4-bit Quantized Low-Rank Adaptation (QLoRA). While 8B models fit easily on consumer hardware, they frequently struggle with nuanced domain reasoning in legal analysis, financial extraction, and cybersecurity threat classification. Conversely, 70B parameter models require expensive multi-GPU distributed clusters. Architectures in the 27B–32B tier—such as Google's Gemma 2 27B and Alibaba's Qwen 2.5 32B—occupy the sweet spot for enterprise reasoning density. Standard 16-bit fine-tuning of these models demands upwards of 120GB of VRAM, but custom Triton kernels, manual backpropagation rewrites, and 4-bit NormalFloat (NF4) quantization compress the entire training pipeline into 20.8GB of VRAM.
This guide provides an end-to-end implementation blueprint using Qwen/Qwen2.5-32B-Instruct as the reference architecture, covering dataset tokenization, response-only loss masking, hyperparameter tuning, and export paths for vLLM and Ollama.
A
C
E
Hardware Profile and Memory Allocation
Fitting a 32B parameter model into a 24GB envelope requires strict VRAM budget management. Base parameters quantized in 4-bit NF4 consume approximately 14.8GB including quantization constants. Confining gradient updates to low-rank adapter matrices ($r=16$) keeps optimizer memory under 1GB, while activation checkpointing bounds memory spikes during forward passes.
Component
Minimum Specification
Recommended Production Setup
Operational Notes
GPU
1× 24GB VRAM (RTX 3090 / A10G / L4)
1× 24GB NVIDIA RTX 4090 or A100
Compute capability ≥ 8.0 required for native FlashAttention-2 and bfloat16.
System RAM
32 GB DDR4/DDR5
64 GB DDR5
Staging memory during weight conversion and GGUF quantization exports.
Storage
100 GB NVMe SSD
250 GB NVMe SSD
Base model checkpoints (~15GB 4-bit, ~65GB 16-bit) and merged artifacts.
CUDA Driver
CUDA 12.1+ (Driver ≥ 535.xx)
CUDA 12.4+ (Driver ≥ 550.xx)
PyTorch and Triton builds must align with installed host drivers.
OS
Ubuntu 22.04 LTS / WSL2
Ubuntu 22.04 LTS (Dockerized)
Native Linux provides 15% faster I/O during checkpoint persistence.
Dataset Structuring and ChatML Alignment
Domain adaptation requires strict adherence to the tokenizer's chat template. Qwen architectures utilize ChatML syntax with explicit <|im_start|> and <|im_end|> delimiters.
[
{
"messages": [
{
"role": "system",
"content": "You are an enterprise cybersecurity analyst specializing in CVE classification and MITRE ATT&CK mapping."
},
{
"role": "user",
"content": "Analyze the following vulnerability: CVE-2024-3094. Provide the affected component, attack vector, and mitigation."
},
{
"role": "assistant",
"content": "### Vulnerability Analysis: CVE-2024-3094\n- **Component:** XZ Utils (liblzma), versions 5.6.0 and 5.6.1.\n- **Vector:** Malicious backdoor injected via M4 macros during tarball compilation.\n- **MITRE ATT&CK:** T1195.002 (Supply Chain Compromise).\n- **Mitigation:** Downgrade to XZ Utils 5.4.x stable releases immediately."
}
]
}
]
To prevent catastrophic forgetting and maintain conversational flow, training must compute gradients strictly over assistant completions. Unsloth provides prompt-loss masking that maps all system and user prompt tokens to the standard ignore index (-100).
from unsloth.chat_templates import get_chat_template
tokenizer = get_chat_template(
tokenizer,
chat_template="qwen-2.5",
mapping={"role": "role", "content": "content", "user": "user", "assistant": "assistant"},
)
dataset = dataset.map(
lambda x: {"text": [tokenizer.apply_chat_template(c, tokenize=False, add_generation_prompt=False) for c in x["messages"] batch_format_here]},
batched=True,
)
Step-by-Step QLoRA Implementation Blueprint
The training pipeline initializes Qwen/Qwen2.5-32B-Instruct in 4-bit precision, attaches trainable LoRA matrices across all seven core linear projections, and runs supervised fine-tuning via Hugging Face's SFTTrainer.
Adapting attention and feed-forward projection layers simultaneously allows the network to learn domain vocabularies and syntax without destabilizing baseline knowledge.
Hyperparameter
Target Setting
Technical Justification
LoRA Rank ($r$)
16 or 32
Ranks under 8 under-fit complex domain syntax; ranks above 64 increase activation memory without measurable gain.
LoRA Alpha ($\alpha$)
32 or 64
Maintains a stable $2\times$ scaling ratio relative to rank ($r$), stabilizing initial parameter update steps.
Target Projections
All 7 Linear Layers
Targets attention (q, k, v, o) and MLP blocks (gate, up, down) for deep domain alignment.
Learning Rate
1e-4 to 2e-4
Cosine decay schedule. Rates exceeding 5e-4 risk gradient destabilization on 4-bit base weights.
Warmup Ratio
0.05 to 0.10
5–10% warmup dampens early gradient variance across randomly initialized adapter weights.
Optimizer
paged_adamw_8bit
Dynamically pages inactive optimizer memory states to host RAM during gradient accumulation bursts.
Context Window Limits and Diagnostics
Running a 32B model inside 24GB VRAM imposes strict context window trade-offs. While 8B models can process sequences exceeding 32,000 tokens on a single GPU, 27B–32B models are practically constrained to sequence lengths between 2,048 and 4,096 tokens due to activation tensor scaling.
Out of Memory (OOM) Errors: Lower max_seq_length to 2048, verify use_gradient_checkpointing="unsloth", keep per_device_train_batch_size=1, and increase gradient_accumulation_steps to achieve target effective batch sizes.
Loss Collapsing Below 0.35: Signals dataset leakage or repetitive template boilerplate. Confirm train_on_responses_only is active so static system instructions are excluded from backpropagation.
Loss Spikes to NaN: Caused by numerical underflow in mixed-precision FP16 on modern architectures. Enforce bf16=True on Ampere/Ada/Hopper GPUs and reduce learning rate to 1e-4.
Healthy Loss Convergence: Training loss should start around 2.5–3.2 and steadily plateau between 0.75 and 1.10 over 3 epochs on a 2,000–5,000 sample domain dataset.
Adapter Merging and Production Serving
Trained LoRA adapters can be merged directly into full precision weights for enterprise API clusters running vLLM, or converted to GGUF format for local deployment in Ollama.
flowchart TD
A["Trained LoRA Adapters
(outputs_qwen_32b_lora)"] --> B{"Deployment Target"}
B -->|"High-Throughput API Cluster"| C["Merge to Full 16-Bit Weights
model.save_pretrained_merged()"]
C --> D["Serve via vLLM Engine
(PagedAttention & Continuous Batching)"]
B -->|"Local & Air-Gapped Serving"| E["Direct GGUF Quantization
model.save_pretrained_gguf()"]
E --> F["Serve via Ollama / llama.cpp
(Local Modelfile Runtime)"]
High-Throughput Serving with vLLM
Merge adapter weights into standard 16-bit floating-point weights:
By pairing 4-bit base parameter quantization with memory-optimized Triton kernels, engineering teams can fine-tune high-reasoning 27B–32B parameter models on accessible 24GB GPUs without operating multi-node compute clusters.