Fine-tune Qwen 3 on a custom dataset
Qwen 3 is one of the strongest open-weight models for reasoning and multilingual tasks. This guide shows how to fine-tune Qwen 3 8B on your own dataset with Soup CLI.
1. Install
pip install "soup-cli[train,fast]"Since v0.71.0 the base
soup-clipackage is a light, PyTorch-free CLI.[train]adds the training stack;[fast]adds Unsloth on top. Installing[fast]alone cannot train.
2. Dataset (ShareGPT format)
Qwen 3 handles multi-turn conversations well. Use the ShareGPT format:
[
{
"conversations": [
{"from": "user", "value": "Explain gradient descent in one paragraph."},
{"from": "assistant", "value": "Gradient descent is..."}
]
}
]That one row only shows the shape of the file. Soup holds out 10% of the rows for validation by default (data.val_split), so a one-row file leaves nothing to train on (soup train --dry-run on it exits 1 with No training rows). Use your real dataset.
3. Config
base: Qwen/Qwen3-8B
task: sft
backend: unsloth # root-level, NOT under training
data:
train: conversations.json
format: sharegpt
max_length: 4096 # sequence length lives under data
training:
epochs: 2
lr: 1.5e-4 # the key is lr, not learning_rate
batch_size: 4
gradient_accumulation_steps: 4
lora:
r: 32 # LoRA turns on when r > 0; there is no enabled flag
alpha: 64
target_modules: [q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj]
output: ./runs/qwen3Why target all projections? Qwen 3 benefits from training LoRA on both attention and MLP projections for instruction-following tasks.
Before you train
Save the config as qwen3.yaml and run soup doctor --config qwen3.yaml first. Since v0.76.0 many more settings are refused when the config loads, each naming the field and what to change, so a config that loaded on v0.75 can stop loading. soup doctor --config prints the error and exits 2 without loading a model (it stops at the first cross-field refusal, so fix that setting and run it again until it prints no error); a setting that nothing reads yet, or a deprecated value, prints a warning and the config still loads. See Config refusals.
4. Train
soup train --config qwen3.yaml5. Serve with vLLM
pip install "soup-cli[serve-fast]"
soup serve --model ./runs/qwen3 --backend vllm --port 8000Pass the adapter directory itself as --model: Soup reads the base model from its adapter_config.json and serves base plus LoRA. --adapters name=path (several adapters on one server) is for --backend transformers only and exits 1 with --backend vllm.
The model is now available at http://localhost:8000/v1/chat/completions with OpenAI-compatible API.
Tips
- Qwen 3 has a vocabulary of about 151k tokens, so the output logits are large. If a run runs out of memory, lower
data.max_lengthortraining.batch_sizebefore anything else. training.neftune_alpha: 5adds noise to the embeddings during training (NEFTune). Whether it helps depends on your data; compare against a run without it.training.packing: truepacks several short examples into one sequence for efficient training on short data. Upstream reports that on TRL 0.29.1 a packed SFT run lost the assistant-onlylabelsand trained every input token except the first, prompt and system tokens included; since v0.76.0 packing keeps the assistant-only loss mask (#1236). If you packed with assistant-only masking on, check which TRL you had.
Related
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.