Versions as of 2026-08-06: unsloth 2026.8.5, axolotl 0.18.0, llamafactory 0.9.5, trl 1.9.2. It is not a four-way race, because torchtune was wound down in 2025 and its last release, 0.6.1, shipped 2025-04-07, sixteen months before this post. The 3.2 / 3.4 / 4.7 / 5.8 hour table copied into every comparison traces to a single undated GPU-rental vendor blog with no repo, no seed, no commit and only an Axolotl 0.8.x pin, roughly ten minor releases behind current. Unsloth publishes real primary-source gains on its own docs: gpt-oss-20b BF16 on B200 at 8,192 context runs 712.33 ms per step against 5,226.86 ms for Transformers v5, at 47.43 GB against 73.80 GB, and holds 55.13 GB at 16,384 where Transformers v5 goes out of memory. The same page shows the opposite trend on Qwen3-30B-A3B, where the speedup shrinks from 1.7x at 1K context to 1.1x at 16K, so the advantage is a property of the checkpoint, not of context length. Unsloth documents DDP and FSDP but no tensor, context or expert parallelism, while Axolotl exposes tensor_parallel_size, context_parallel_size and expert_parallel_size and TRL exposes parallelism_config_cp_size and parallelism_config_sp_size with hard Accelerate 1.11.0 and 1.12.0 floors. LLaMA-Factory is the fastest UI-driven path and carries four published advisories, two of them remote code execution, with 0.9.4 as the minimum safe version. Pick on parallelism ceiling and checkpoint coverage, not on a wall-clock number nobody can reproduce.
Four numbers get copied into nearly every comparison of these tools: 3.2 hours, 3.4 hours, 4.7 hours and 5.8 hours, for Unsloth, LLaMA-Factory, TorchTune and Axolotl on Llama-3.1 8B QLoRA on a single A100 40 GB. If you are searching unsloth vs axolotl vs llama-factory, that table is the first thing you will find and the last thing you should trust. It traces back to one undated blog post published by a GPU-rental vendor, on that vendor's own rental hardware, with no repository, no commit hash, no seed, no dataset name, no tokenizer and no version pins beyond "Axolotl v0.8.x" and "PyTorch 2.5". Axolotl 0.8.x is roughly ten minor releases behind the current 0.18.0.
The table is also wrong about the field itself, in a way that would embarrass anyone who acted on it. So here is the actual decision, built from primary sources: package metadata, repository state, the frameworks' own published benchmarks, their config references, and their issue trackers.
The maintenance check nobody ran: TorchTune is not the fourth option
TorchTune appears in that speed table, in the roundups that copy it, and in a surprising number of 2026 shortlists. It should not appear in any of them.
The torchtune README carries a banner reading, verbatim, "Torchtune is no longer actively maintained: torchtune development wound down in 2025". Issue 2883 in the repository, titled "The future of torchtune" and opened 2025-07-15, states "We are stopping active development on torchtune, effective immediately" and "No new features will be added to the library", with critical bug fixes and security patches promised only through 2025. The last release on PyPI is 0.6.1, published 2025-04-07, which is sixteen months old as of this post. The project also moved repositories along the way, so older links redirect and give the impression of activity.
Recommending it to a regulated client in 2026 means recommending an unmaintained training dependency for a model that will end up in a system of record. The choice is Unsloth, Axolotl or LLaMA-Factory, plus TRL as the library the other three build on or around.
Release cadence is the sleeper column. TRL shipped 1.5.1, 1.6.0, 1.7.0, 1.7.1, 1.8.0, 1.9.0, 1.9.1 and 1.9.2 between 2026-05-27 and 2026-07-28. LLaMA-Factory shipped 0.9.4 on 2025-12-31 and 0.9.5 on 2026-05-30, roughly two releases a year. Neither cadence is wrong, but they imply very different pinning strategies: TRL needs a lockfile and a weekly look at the changelog, LLaMA-Factory needs a security watch on the advisory feed.
| Unsloth | Axolotl | LLaMA-Factory | TRL | torchtune | |
|---|---|---|---|---|---|
| PyPI package | unsloth | axolotl | llamafactory | trl | torchtune |
| Latest version | 2026.8.5 | 0.18.0 | 0.9.5 | 1.9.2 | 0.6.1 |
| Released | 2026-08-06 | 2026-07-17 | 2026-05-30 | 2026-07-28 | 2025-04-07 |
| requires_python | <3.15,>=3.9 | >=3.10 | >=3.11.0 | >=3.10 | >=3.9 |
| Stars | 69,631 | 12,318 | 73,845 | 19,015 | 5,793 |
| Open issues | 1,032 | 277 | n/a | 250 | n/a |
| Last push | 2026-08-06 | 2026-08-05 | 2026-08-06 | 2026-08-06 | bots only |
| Maintenance | Active | Active | Active | Active | Wound down 2025-07-15 |
| Releases, last 90 days | multiple per week | 2 | 0 | 8 | 0 |
Unsloth vs Axolotl vs LLaMA-Factory vs TRL: what actually diverges
Feature lists no longer separate these tools. All of them do LoRA, QLoRA and full fine-tuning; LLaMA-Factory's README lists pre-training, SFT, reward modeling, PPO, DPO, KTO, ORPO and SimPO, and TRL covers SFT, DPO and GRPO first-party. Reading a feature matrix in 2026 tells you almost nothing.
Four things diverge, and every one of them can invalidate a plan after you have booked GPU time:
The speed numbers that are real, and the trend that reverses
Unsloth publishes per-step timings and peak VRAM on its own documentation, with hardware, model, context length and baseline stated. That is vendor-published and should be read as such, but it is measured, specific and falsifiable, which puts it in a different category from the four-number table above.
gpt-oss-20b BF16 on a B200, Unsloth against Transformers v5:
The obvious conclusion is that the advantage grows with context. That conclusion is wrong, and the counter-example is on the same page. Qwen3-30B-A3B on the same B200 at LoRA rank 8:
Same vendor, same page, same GPU, opposite direction. The speedup is a property of how well the kernels cover that specific architecture, not a property of context length. Anyone quoting one curve as the general behavior of the library has not read the second table.
Two more numbers deserve their caveats. Unsloth's MoE headline is "~12x faster Mixture of Experts (MoE) LLM training with >35% less VRAM", but no published table on that page reaches 12x; the highest measured entry is the 7.3x above. And the famous "30x faster" figure comes from the December 2023 launch post, where it describes two Tesla T4s under DDP going from 164 hours to 5 hours on a public dataset, using the closed Max tier. The open-source library was described on that same page as 2x faster with 50 percent less memory, and today's README says up to 2x faster with 70 percent less VRAM.
One useful independent signal: the Transformers v5 memory regression that makes the right-hand columns look so bad is not only an Unsloth talking point. Axolotl issue 3374, opened 2026-01-27, is titled "Transformers-v5 causes OOM on QLoRA config previously working on 4.57.6 (GLM-4.5-Air on 2x RTX Pro 6000)". Two projects with no shared interest observed the same thing.
| Context | Unsloth ms/step | TF v5 ms/step | Unsloth peak VRAM | TF v5 peak VRAM | Speedup | VRAM saving |
|---|---|---|---|---|---|---|
| 1,024 | 275.35 | 376.99 | 40.91 GB | 43.88 GB | 1.4x | 6.76% |
| 2,048 | 292.88 | 696.57 | 41.83 GB | 44.93 GB | 2.4x | 6.89% |
| 4,096 | 370.30 | 1,785.89 | 43.68 GB | 49.86 GB | 4.8x | 12.39% |
| 8,192 | 712.33 | 5,226.86 | 47.43 GB | 73.80 GB | 7.3x | 35.73% |
| 16,384 | 1,775.80 | OOM | 55.13 GB | OOM | n/a | n/a |
| Context | Unsloth ms/step | TF v5 ms/step | Unsloth VRAM | TF v5 VRAM | Speedup |
|---|---|---|---|---|---|
| 1,024 | 366.3 | 628.3 | 80.88 GB | 104.80 GB | 1.7x |
| 2,048 | 467.0 | 745.3 | 80.88 GB | 104.81 GB | 1.6x |
| 4,096 | 711.6 | 975.5 | 80.89 GB | 104.80 GB | 1.4x |
| 8,192 | 1,376.6 | 1,633.5 | 80.90 GB | 104.81 GB | 1.2x |
| 16,384 | 3,182.2 | 3,407.9 | 85.53 GB | 116.61 GB | 1.1x |
VRAM decides your hardware order before speed does
For on-premise buyers this is the table that actually spends money, because it sets how many cards you order and which ones. Our RTX PRO 6000 against H100 against L40S comparison covers the card-level economics; this is the training-side demand that feeds into it.
Both projects call these minimums, and both are quoting short sequences. Context is what actually eats the card. Unsloth's own benchmark on Llama 3.1 8B QLoRA at rank 32, batch size 2 and gradient accumulation 4 shows maximum trainable context of 2,972 tokens on 8 GB where the Hugging Face plus Flash Attention 2 baseline goes out of memory, 21,848 against 932 on 12 GB, 40,724 against 2,551 on 16 GB, 78,475 against 5,789 on 24 GB and 342,733 against 28,454 on 80 GB.
MoE models sit outside these tables and need their own figures. Unsloth lists gpt-oss-20b at 14 GB for QLoRA on the model page and reports a 12.8 GB measured peak on the MoE kernel page, gpt-oss-120b at 65 GB QLoRA and 210 GB BF16 LoRA, and Qwen3-30B-A3B at 63 GB for 16-bit LoRA. The 12.8 and the 14 are not the same claim, so do not average them into one number for a capacity plan.
If you are still deciding whether to fine-tune at all rather than which tool to use, start with prompt engineering against fine-tuning and how much data a fine-tune actually needs. The framework question only becomes real once those two are settled.
| Model size | Unsloth QLoRA 4-bit | Unsloth LoRA 16-bit | LLaMA-Factory QLoRA 4-bit | LLaMA-Factory LoRA 16-bit | LLaMA-Factory full bf16 |
|---|---|---|---|---|---|
| 7B | 5 GB | 19 GB | 6 GB | 16 GB | 120 GB |
| 8B | 6 GB | 22 GB | n/a | n/a | n/a |
| 14B | 8.5 GB | 33 GB | 12 GB | 32 GB | 240 GB |
| 30B | n/a | n/a | 24 GB | 64 GB | 600 GB |
| 32B | 26 GB | 76 GB | n/a | n/a | n/a |
| 70B | 41 GB | 164 GB | 48 GB | 160 GB | 1,200 GB |
| 405B | 237 GB | 950 GB | n/a | n/a | n/a |
Parallelism is the ceiling, and it is where the choice is made
Here is the correction that matters more than any wall-clock figure. "Unsloth is single-GPU only" is repeated everywhere, including in competing projects' comparison material. It is stale. Unsloth's multi-GPU documentation covers DDP and FSDP through Accelerate, DeepSpeed via Accelerate, accelerate launch train.py, torchrun --nproc_per_node N_GPUS train.py, and device_map = "balanced" for models that will not fit on one card.
The sharper and more useful statement is this: Unsloth does data parallelism only. Tensor, context and expert parallelism are not documented at all, and the multi-GPU path has open correctness bugs, including issue 3915 from 2026-01-21 ("Multi GPU (DDP) is not working in any setting"), issue 6831 from 2026-07-02 reporting silent multi-GPU corruption with a layer-40 reproduction, and issue 4142 from 2026-03-02 reporting multi-node broken specifically in the one-GPU-per-node configuration. The docs themselves note the process is complex and requires manual setup.
Two caveats keep this table honest. Axolotl's parallelism guide publishes FSDP plus TP, HSDP plus TP and FSDP plus TP plus CP as supported, but the config reference help string for tensor_parallel_size reads "Only supported with DeepSpeed AutoTP", which is materially narrower than PyTorch-native tensor parallelism composed with FSDP2. Architect against the config reference, not the guide. And expert_parallel_size appears in that guide but was not found in the config reference, so treat it as guide-documented and reference-unconfirmed until you see it accepted by your install.
# axolotl 0.18.0, MoE QLoRA with expert quantisation base_model: zai-org/GLM-4.7-Flash load_in_4bit: true adapter: qlora quantize_moe_experts: true # requires lora/qlora with load_in_4bit or load_in_8bit sequence_len: 32768 sample_packing: true flash_attention: true micro_batch_size: 1 fsdp_version: 2 fsdp_config: fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP fsdp_activation_checkpointing: true fsdp_reshard_after_forward: true dp_shard_size: 4 dp_replicate_size: 1 tensor_parallel_size: 1 # DeepSpeed AutoTP only context_parallel_size: 2 # divisor of GPU count # sequence_parallel_degree: 4 # DEPRECATED, use context_parallel_size
That deprecated key is a live foot-gun. The most-cited Axolotl long-context benchmark, published 2025-04-04, uses sequence_parallel_degree throughout, and its YAML has been copied into 2026 posts unchanged. The benchmark's scaling shape is still worth knowing, on Llama 3.1 8B on H100:
Sequence parallelism buys context, not throughput. At degree 8 you are paying eight GPUs for 15.2 percent per-GPU efficiency. That is a rational trade when the alternative is not training at all, and an irrational one when a shorter context would have worked.
TRL splits the same problem across two backends with hard version floors, and picking the wrong one wastes a day:
from trl import SFTConfig
training_args = SFTConfig(
pad_to_multiple_of=4, # cp_size * 2
max_length=16384, # global length, TRL splits it
packing=True,
use_liger_kernel=True,
gradient_checkpointing=False, # cannot co-exist with fsdp_activation_checkpointing
per_device_train_batch_size=1,
)TRL's own documentation states that with 8 GPUs, context lengths over 300k tokens become feasible, and the page carries a banner marking the section as under construction. Plan for the API to move.
| Capability | Unsloth | Axolotl 0.18.0 | TRL 1.9.2 | LLaMA-Factory 0.9.5 |
|---|---|---|---|---|
| DDP | Yes (torchrun) | Yes | Yes | Yes |
| FSDP / FSDP2 | Yes (via Accelerate) | fsdp_version: 2, dp_shard_size | Yes (fsdp_version: 2) | Yes |
| HSDP | Not documented | dp_replicate_size plus dp_shard_size | parallelism_config_dp_replicate_size | Not documented |
| Tensor parallel | Not documented | tensor_parallel_size (DeepSpeed AutoTP only) | parallelism_config_tp_size | via DeepSpeed |
| Context parallel | Not documented | context_parallel_size | parallelism_config_cp_size | Not documented |
| Sequence parallel (Ulysses) | Not documented | via DeepSpeed | parallelism_config_sp_size | Not documented |
| Expert parallel | Not documented | expert_parallel_size (needs DeepEP) | Not documented | Not documented |
| Composable matrix published | No | Yes | Yes | No |
| Model-splitting fallback | device_map = "balanced" | n/a | n/a | n/a |
| SP degree | QLoRA max context | QLoRA tok/s | Context scaling | Per-GPU efficiency |
|---|---|---|---|---|
| 1 | 17,408 | 9,104.38 | 1.00x | 100.0% |
| 2 | 34,816 | 15,806.46 | 2.00x | 86.8% |
| 4 | 66,560 | 12,313.60 | 3.82x | 33.8% |
| 8 | 129,024 | 11,096.06 | 7.41x | 15.2% |
| Ring Attention (FSDP2) | ALST / Ulysses (DeepSpeed) | |
|---|---|---|
| Backend | PyTorch FSDP2 | DeepSpeed ZeRO |
| Attention implementation | SDPA only, no Flash Attention | FA2 or SDPA |
| Minimum Accelerate | 1.11.0 | 1.12.0 |
| Minimum DeepSpeed | n/a | 0.18.1 |
| Sequence divisibility | cp_size * 2 | sp_size |
| Hard constraint | none on head count | num_heads >= sp_size |
The coverage cliff: check your checkpoint before you book the GPU
Unsloth's speed comes from architecture-specific kernels, and coverage is not an architecture check at runtime. It is a lookup table keyed by exact Hugging Face repository id. unsloth/models/mapper.py defines INT_TO_FLOAT_MAPPER, FLOAT_TO_INT_MAPPER, MAP_TO_UNSLOTH_16bit, FLOAT_TO_FP8_BLOCK_MAPPER and FLOAT_TO_FP8_ROW_MAPPER, with roughly 250 or more entries in the core dict, each one a literal string like unsloth/mistral-7b-bnb-4bit.
If your checkpoint is not in that table, you do not get a degraded version of the advantage. You get the generic path, and the entire reason you chose the library evaporates.
python - <<'PY'
import unsloth.models.mapper as m
tables = {k: getattr(m, k) for k in dir(m)
if k.isupper() and isinstance(getattr(m, k), dict)}
print("mapper tables:", {k: len(v) for k, v in tables.items()})
CKPT = "meta-llama/Llama-3.1-8B-Instruct" # your exact repo id
hits = {name: (CKPT in tbl or CKPT in tbl.values()) for name, tbl in tables.items()}
print(CKPT, "->", hits)
if not any(hits.values()):
print("NOT MAPPED: expect the generic path, none of the published speedup.")
PYThe failure modes when coverage is missing are loud, at least. Verbatim from the issue tracker: "unsloth/gemma-4-E4B-it is not supported in your current Unsloth version!" (issue 4942, 2026-04-10), "unsloth/Qwen3.5-0.8B is not supported yet in transformers==4.57.6" (issue 4146, 2026-03-03), and "NYI: Currently non power of 2 embedding dimension are not supported" (issue 4036, 2026-02-11). Run the load once on a cheap instance before you reserve a week of cluster time. The same discipline applies to a base model you may not keep, which is the argument in large model against fine-tuned small model.
Reproducibility, and the security tail on the UI-driven path
For a regulated deployment the run has to leave behind an artifact an auditor can read: base model and revision, dataset version, hyperparameters, seed, framework version, and the exact hardware. Axolotl wins this on structure alone, because the whole run is one YAML file you commit next to the code. TRL's Python configs are reviewable but easier to drift, and a notebook-driven Unsloth workflow is the hardest of the four to reconstruct six months later, which is a process problem rather than a library defect.
LLaMA-Factory earns its 73,845 stars on ergonomics: llamafactory-cli webui gives a non-specialist a working LoRA run in an afternoon, and use_unsloth: true puts Unsloth kernels underneath it. Note that both use_unsloth and use_unsloth_gc default to False in src/llamafactory/hparams/model_args.py, so the acceleration is opt-in and applies to LoRA training only. Anyone reporting LLaMA-Factory timings without publishing the config has not told you whether the kernels were on.
The tail on that convenience is a web UI that has repeatedly been reachable from the network:
Nothing below 0.9.4 belongs anywhere near regulated data, and the training UI should never be exposed beyond localhost or a bastion. No published advisories were found for unsloth, axolotl or trl at the time of writing, which is not the same as there being none.
pip install "unsloth==2026.8.5" "unsloth_zoo==2026.8.4" pip install "axolotl==0.18.0" # Python >=3.10 pip install "llamafactory>=0.9.4" # Python >=3.11, never pin below 0.9.4 pip install "trl==1.9.2" # Python >=3.10 # torchtune is not a live option: last release 0.6.1, 2025-04-07
Across the on-premise stacks we audit at Particula Tech, the recurring gap is not framework choice at all. It is that six months after a fine-tune ships, nobody can produce the dataset revision it was trained on. Pick the tool that makes that record fall out of the build, and treat the environment itself as part of the record: the same air-gapped discipline described in our offline vLLM deployment guide applies to training hosts, and the wider build-versus-buy tradeoff is in cloud against on-premise AI security and cost.
| CVE | CVSS | Affected | Fixed in | Root cause |
|---|---|---|---|---|
| CVE-2024-52803 | 8.6 High | <=0.9.0 | 0.9.1 | Popen(shell=True) with unsanitized output_dir |
| CVE-2025-46567 | 6.1 Moderate | <=0.9.2 | 0.9.3 | CWE-502 unsafe torch.load() in a conversion script |
| CVE-2025-53002 | 8.3 High | <=0.9.3 | 0.9.4 | vhead_file loaded without weights_only=True |
| CVE-2025-61784 | 7.6 High | <=0.9.3 | 0.9.4 | SSRF and LFI in _process_request on /v1/chat/completions |
What to do
Concretely: use Unsloth on one GPU after you have grepped mapper.py for your checkpoint, and use Axolotl the moment you need a second node or a parallelism axis beyond data. Use TRL when you are writing the loss function yourself. Use LLaMA-Factory when a non-specialist team needs results this week, pinned at 0.9.4 or later, with the UI bound to localhost. Do not use torchtune. And do not quote the 3.2 hours against 5.8 hours table in a hardware proposal, because the first person who asks for the config will find out there isn't one.
The framework is the smallest decision in this stack anyway. Where the model runs afterward, and what evidence you kept about how it was built, are the ones that survive an audit. That larger picture is laid out in our LLM models pillar guide.
| Binding constraint | Pick | Reason | What will bite you |
|---|---|---|---|
| One GPU, speed-bound, mainstream checkpoint | Unsloth | 7.3x and 35.7% less VRAM at 8K on B200 | Coverage is a lookup table in mapper.py |
| One GPU, 24 GB or less, long context | Unsloth | 78,475 tokens at 24 GB against 5,789 on HF plus FA2 | Same coverage cliff |
| 2 to 8 GPUs, long context, needs TP/CP/EP | Axolotl | Publishes the supported matrix and the refused combinations | 15.2% per-GPU efficiency at SP degree 8 |
| Multi-node | Axolotl or TRL | Both document it; Unsloth does not | Unsloth issue 4142 open since 2026-03-02 |
| Custom loss, deepest Hugging Face integration | TRL | 8 releases in about 9 weeks, first-party PEFT and Accelerate | CP path is SDPA only, no Flash Attention |
| Audit-first, regulated client | Axolotl | The whole run is one version-controlled YAML | TP is DeepSpeed AutoTP only |
| Fastest UI-driven path | LLaMA-Factory | Web UI plus use_unsloth: true | Four advisories, two RCE; floor is 0.9.4 |
| MoE checkpoints | Unsloth single-node, Axolotl multi-node | Unsloth MoE kernels, Axolotl quantize_moe_experts | Speedup narrows to 1.1x on Qwen3-30B-A3B at 16K |
FAQ
Quick answers to the questions this post tends to raise.




