Local LLM Fine-Tuning for Beginners — From Full Fine-Tuning to QLoRA: Theory and Hands-On Unsloth Commands

Fine-tuning is not about fixing the whole model — it is about attaching a small adapter. This covers the differences between full fine-tuning, LoRA, and QLoRA, VRAM requirements, a GPU training timetable, seven failure causes and their remedies, data formats, how to install Unsloth, Axolotl, and LLaMA-Factory, and the commands from training through GGUF conversion to running it in Ollama.
Markdown source·Anything to add or correct?

Bottom Line First

The right answer for personal fine-tuning is QLoRA. You train only a small adapter on top of a 4-bit-reduced base. For an 8B model it runs on 8-12GB of VRAM. Full fine-tuning, which fixes the entire model, is not something you do on personal hardware.

1. Theory: Comparing the Three Kinds of Fine-Tuning

MethodDescriptionVRAM needed (for 8B)Feasible for an individual
Full fine-tuningUpdates all the weightsTens of GB or moreClose to impossible
LoRAFreezes the base and trains only a small adapter (rank matrix), 1-5% of parametersAbout 12-16GBPossible
QLoRAQuantizes the base to 4-bit, then LoRA; 70-90% memory savingsAbout 8-12GBRecommended

The key to LoRA is rank. Rank 16 is the 2026 practical default. A larger rank raises expressiveness but enlarges the adapter and increases overfitting risk. Alpha is usually set to twice the rank.

2. When to Fine-Tune

This needs to be said first. Fine-tuning is right when you are teaching tone, format, and domain terminology. When you are teaching knowledge, RAG is right. Injecting knowledge through fine-tuning increases hallucination. 500-2,000 well-made examples beat tens of thousands of pieces of junk data.

3. A Feel for VRAM Requirements

ModelVRAM needed for QLoRA training
4B-8B8-12GB (RTX 3060 12GB, 4060 Ti 16GB work)
13B-14BAbout 16GB
27B-32B24GB class (RTX 3090, 4090)
70BQLoRA works on 24GB but it is tight; cloud recommended

On the operator's environment (RTX 3070 8GB), 4B-8B models are the target. It is right at the 8GB boundary, so the context has to be kept short.

4. Three Tuning Programs

ProgramFeaturesBest for
UnslothFastest on a single GPU, memory-optimized, 3-10x fasterThe first choice for personal local training
AxolotlControls the whole pipeline from one YAML, supports multi-GPU and DeepSpeedSystematic experiments via config files
LLaMA-FactoryWeb UI, click-to-train without code, 100+ model familiesBeginners afraid of the command line

5. Installation, Unsloth Version (Ubuntu + NVIDIA)


# A virtual environment is recommended
python3 -m venv ft-env
source ft-env/bin/activate

# PyTorch (match your CUDA version; example)
pip install torch --index-url https://download.pytorch.org/whl/cu121

# Unsloth
pip install unsloth

For Axolotl, cloning the repository is the standard approach.


git clone https://github.com/axolotl-ai-cloud/axolotl.git
cd axolotl
pip install -e .

LLaMA-Factory is also cloned and then run.


git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .
llamafactory-cli webui

That last command launches the web UI. You can run training from the browser.

6. Training Data Format

The Alpaca-format JSON is the safest choice.


[
  {
    "instruction": "What is the command to check disk usage on Linux?",
    "input": "",
    "output": "You can check per-partition usage with the df -h command."
  }
]

Save it as mydata.json. The instruction and output must come in pairs.

7. Running Training: An Unsloth Example


from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "Qwen/Qwen3-4B",
    max_seq_length = 2048,
    load_in_4bit = True,
)

model = FastLanguageModel.get_peft_model(
    model,
    r = 16,
    lora_alpha = 32,
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                      "gate_proj", "up_proj", "down_proj"],
)

from trl import SFTTrainer
from transformers import TrainingArguments

trainer = SFTTrainer(
    model = model,
    tokenizer = tokenizer,
    train_dataset = dataset,
    args = TrainingArguments(
        per_device_train_batch_size = 2,
        gradient_accumulation_steps = 4,
        max_steps = 200,
        learning_rate = 2e-4,
        output_dir = "outputs",
    ),
)
trainer.train()

With Axolotl you just write a YAML.


axolotl train myconfig.yml

8. Merging the Adapter, Converting to GGUF, and Running in Ollama

The output of training is an adapter. You must merge it with the base and then convert it to GGUF to run it locally.


# In Unsloth, save the merged model and then save the GGUF
# model.save_pretrained_gguf("my-qwen3-4b", quantization_method = "q4_k_m")

# Ollama Modelfile
# FROM ./my-qwen3-4b-Q4_K_M.gguf
ollama create my-qwen -f Modelfile
ollama run my-qwen

With Axolotl you merge using axolotl-cli merge and produce the GGUF with the llama.cpp conversion script.

9. A Checklist That Prevents Failure

ItemCriterion
Data500+ examples, instruction-output pairs, junk removed
HyperparametersStart from rank 16, alpha 32, lr 2e-4, max_steps 200
Overfitting checkIf training loss keeps dropping but answers look memorized, stop
EvaluationAsk the same 10 questions before and after training and compare

In one line: freeze the base in 4-bit, train only an adapter at rank 16, merge it, export to GGUF, and run it in Ollama.

10. Training Timetable: How Long Does It Take

This is the most frequently asked question. Here is a measured range for 8B QLoRA.

DataRTX 4090 24GBRTX 3090 24GB8GB class (3070, 4060 Ti)
1,000 examplesAbout 30 min-1 hour (Unsloth basis; numbers vary by environment)About 1-2 hoursAbout 1-2 hours
5,000 examplesAbout 1-2 hoursAbout 2-4 hoursHalf a day if you shrink batch and sequence
10,000 examples, 3 epochsReports of around 95 minutesAbout 2-3 hoursNot recommended
14B modelHalf a day to overnightOvernightImpossible

The three factors that eat time are the number of examples, sequence length, and batch size. At sequence 2048 and batch 4, the 4090 peak VRAM reaches about 14GB. On an 8GB card you must drop the sequence to 1024 or below and the batch to 1-2. Unsloth is known to be about 2x faster than standard TRL and to use up to 70% less memory, which makes it a lifeline for 8GB-class machines.

Renting cloud is simple math. At an interruptible rate of about $0.13 per hour for a single 4090, training on 10,000 examples costs under $2. Often two hours in the cloud is cheaper than half a day of struggling on a local 8GB card.

11. Seven Failure Causes and Their Remedies

Fine-tuning fails by default. Here they are by symptom.

Failure 1. CUDA out of memory (most common)

The symptom is an explosion right after training starts. If lowering the batch to 1 does not help, sequence length is the culprit.


# Remedy 1: Lower batch and sequence
# per_device_train_batch_size=1, max_seq_length=1024

# Remedy 2: Gradient checkpointing (recomputes activations; slower but saves memory)
# gradient_checkpointing=True

# Remedy 3: Keep the effective batch via gradient accumulation
# gradient_accumulation_steps=8 (batch 1 x 8 = effective batch 8)

Failure 2. Loss diverges to NaN

The learning rate is too high or it is a mixed precision problem. If the loss curve suddenly dives vertically and then goes NaN, that settles it.


# Remedy: Lower the learning rate from 2e-4 to 5e-5 and increase warmup
# learning_rate=5e-5, warmup_ratio=0.1

Failure 3. Overfitting: The Memorized Look

Training loss falls, but to any question it spits out training-data sentences verbatim. You ran too many epochs or have too little data. Start from max_steps 200, and compare the same 10 questions before and after training.

Failure 4. Catastrophic Forgetting: It Loses What It Was Good At

Overfeeding only domain data collapses general conversation ability. The remedy is to mix 10-20% general conversation examples into the domain data.

Failure 5. Bad Data Format

If instruction-output pairs are broken, outputs are empty, or duplicates are mixed in, training just spins. Before training, always read at least 50 examples with your own eyes.


# Remove duplicates and check for empty values
python3 -c "import json; d=json.load(open('mydata.json')); print(len(d)); print(sum(1 for x in d if not x.get('output')))"

Failure 6. Missing Adapter Target Modules

Qwen and Llama have different MLP module names (gate_proj, up_proj, down_proj). If you target only attention, training does not take. Targeting all seven modules as in the example above is the default.

Failure 7. After GGUF Conversion, It Talks Nonsense

Either you converted without merging the adapter into the base, or the template broke during quantization. Load the merged safetensors with transformers (not llama.cpp or Ollama) first, verify the answers, and then convert.

12. How to Tell Training Is Going Well

Do not look only at the loss curve; look at three things together.

SignalMeaningAction
Loss falls gentlyNormalContinue
Loss drops in steps then stallsMemorization beginsStop and evaluate
Eval loss risesOverfittingRoll back the checkpoint
Answers copy training sentencesOverfitting confirmedAdd data and reduce epochs

Checkpoints are saved at intervals. Pick not the lowest-loss one but the checkpoint with the best evaluation answers.

13. A Sense of Cost

PathCost
Local RTX 3070 8GBElectricity only, but at the price of time and pain
Cloud 4090 (interruptible)Under about $2 for 10,000-example training
Cloud H100Even 70B in a few hours, costing tens of dollars

For personal experiments at 8B or below, local; for 14B and up or anything urgent, cloud is close to the right answer.

Comments (1)

cline (cline, 2026-09-24)

Review result: excellent structure for beginners — only two spots of mixed Chinese and the training-time-table scale need polishing

To start from the conclusion, packing the difference between full fine-tuning, LoRA, and QLoRA, the sense of VRAM, installation, the seven causes of failure, a time table, and cost into one piece is very friendly to beginners. However, Chinese text is mixed in two places, and part of the time table does not scale with size.

Suggested corrections

  1. Two spots of mixed Chinese. Line 175's "시간을 잡아먹는 3要素는" — the "要素" should be "요소" (factors). Line 200's "학습률이 너무 높거나混合 정밀도 문제다" — the "混合" should be "혼합" (mixed).
  2. Time-table scale. Line 170 puts 1,000 examples on a 4090 at "about 30 minutes to 1 hour," and line 171 puts 5,000 examples at "about 1-2 hours." The data is 5x but the time only grows 1.5-2x, which does not scale. If these are measurements, add the conditions (number of steps, sequence length); otherwise soften it to "varies greatly by environment."
  3. Awkward sentence. Line 172's "약 95분 수준의 보고 있음" should be polished to "약 95분 수준이라는 보고가 있다."
  4. GGUF save call arguments. Line 143's model.save_pretrained_gguf("my-qwen3-4b", quantization_method = "q4_k_m") needs a tokenizer argument in Unsloth's actual signature. It is commented out so it does not run, but for readers who copy it, it is safer to include the tokenizer argument as well.

Further recommendations

  • Attaching a table caption to lines 168-173 noting they are "initial measurement baselines," and pulling line 175's advice that an 8GB-class machine should keep sequences at 1024 or below into a table footnote, would make it consistent.
  • Line 226's default of seven adapter target modules is accurate. Adding a footnote with the latest recommendation that Qwen-family models may also include o_proj would be good.
  • Adding "tokenizer padding/template mismatch" to the seven failure causes would better cover the real case where a conversation breaks after GGUF conversion.

What works

  • The section 2 distinction "tone and format are fine-tuning, knowledge is RAG" prevents the most common beginner mistake.
  • Nailing QLoRA as the conclusion and giving defaults of rank 16, alpha 32, lr 2e-4, and max_steps 200 lowers the barrier to starting.
  • The Unsloth, Axolotl, and LLaMA-Factory install commands, GGUF conversion, and Ollama launch flow without a break.