@mcptoolshop/backpropagate 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,143 +10,155 @@
10
10
  <a href="https://github.com/mcp-tool-shop-org/backpropagate/actions/workflows/ci.yml"><img src="https://github.com/mcp-tool-shop-org/backpropagate/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
11
11
  <a href="https://pypi.org/project/backpropagate/"><img src="https://img.shields.io/pypi/v/backpropagate" alt="PyPI"></a>
12
12
  <a href="https://codecov.io/gh/mcp-tool-shop-org/backpropagate"><img src="https://img.shields.io/codecov/c/github/mcp-tool-shop-org/backpropagate" alt="Coverage"></a>
13
+ <a href="https://scorecard.dev/viewer/?uri=github.com/mcp-tool-shop-org/backpropagate"><img src="https://api.scorecard.dev/projects/github.com/mcp-tool-shop-org/backpropagate/badge" alt="OpenSSF Scorecard"></a>
13
14
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
14
15
  <a href="https://mcp-tool-shop-org.github.io/backpropagate/"><img src="https://img.shields.io/badge/Landing_Page-live-blue" alt="Landing Page"></a>
15
16
  </p>
16
17
 
17
- **Headless LLM fine-tuning in 3 lines. Smart defaults, VRAM-aware batch sizing, multi-run SLAO, and one-click GGUF export for Ollama.**
18
+ # Train an adapter. Ship it to Ollama. Move on.
18
19
 
19
- *SLAO is Single LoRA Continual Learning via Asymmetric Merging the merge-between-runs technique that prevents catastrophic forgetting in extended fine-tuning campaigns ([paper](https://arxiv.org/abs/2512.23017)).*
20
+ Backpropagate is a Python library for fine-tuning large language models on a single GPU. Three lines of code train a 7B model on a 16GB card. One more command exports it to Ollama so you can `ollama run` your finetune. Works first-class on Windows.
20
21
 
21
- *Train LLMs in 3 lines of code. Export to Ollama in one more.*
22
+ ```python
23
+ from backpropagate import Trainer
22
24
 
23
- ## Quick Start
25
+ trainer = Trainer("Qwen/Qwen2.5-7B-Instruct")
26
+ trainer.train("my_data.jsonl", steps=100)
27
+ trainer.export("gguf", quantization="q4_k_m")
28
+ ```
24
29
 
25
30
  ```bash
26
- pip install backpropagate[standard]
31
+ backprop export ./output/lora --format gguf --quantization q4_k_m --ollama --ollama-name my-model
32
+ ollama run my-model
27
33
  ```
28
34
 
29
- ```python
30
- from backpropagate import Trainer
35
+ That's it. There's no YAML config file. There's no `accelerate launch` ceremony. There's no separate "now convert it to GGUF" tutorial. If you have a CUDA GPU and a JSONL file with your training data, you're three lines away from a working finetune.
31
36
 
32
- trainer = Trainer("Qwen/Qwen2.5-7B-Instruct")
33
- trainer.train("examples/quickstart.jsonl", steps=10)
34
- trainer.export("gguf", quantization="q4_k_m") # Ready for Ollama
35
- ```
37
+ ## Install
36
38
 
37
- The repo ships a small `examples/quickstart.jsonl` (5 ShareGPT-format examples) so the snippet above runs end-to-end on a clean install. For your own training, see [Dataset Format](#dataset-format) below.
39
+ ```bash
40
+ # Recommended: isolated Python install (no conflicts with system Python or other projects)
41
+ pipx install backpropagate
42
+
43
+ # Or via uv (faster install, same isolation)
44
+ uv tool install backpropagate
38
45
 
39
- ### No-code path: Web UI
46
+ # Standard pip (if you manage your own virtualenv)
47
+ pip install backpropagate
48
+ ```
40
49
 
41
- Prefer a UI to a Python REPL? Install the same extra and run:
50
+ If you want the optional features, swap the install for one of these:
42
51
 
43
52
  ```bash
44
- pip install backpropagate[standard]
45
- backprop ui --port 7862
53
+ pipx install "backpropagate[standard]" # adds Unsloth (2x faster training) + the web UI
54
+ pipx install "backpropagate[full]" # adds everything: unsloth, ui, monitoring, export, etc.
46
55
  ```
47
56
 
48
- The Reflex (Radix UI) interface lets you point at a JSONL file, pick a model, train, and export no Python required. The UI is local-first; for public-internet exposure see [Web UI](#web-ui) below for the `--share` + `--auth` security contract and supported tunnel options (Cloudflare Tunnel, ngrok).
57
+ Prefer Docker? `docker pull ghcr.io/mcp-tool-shop-org/backpropagate:latest` works too. Images ship for both `linux/amd64` and `linux/arm64`, so Apple Silicon and ARM Linux operators get a native image. A canonical `compose.yaml` for "UI in a container" lives at the repo root — `docker compose up` brings the web UI up on `http://localhost:7860` with a persistent `~/.backpropagate` volume mount.
49
58
 
50
- ## Dataset Format
59
+ ## Where Backpropagate sits in the space
51
60
 
52
- Your JSONL training file should have one example per line. The simplest format is ShareGPT chat:
61
+ There are several good libraries for fine-tuning LLMs. They're each great at different things:
53
62
 
54
- ```jsonl
55
- {"conversations": [{"from": "human", "value": "What is Python?"}, {"from": "gpt", "value": "A programming language."}]}
56
- {"conversations": [{"from": "human", "value": "Explain recursion."}, {"from": "gpt", "value": "A function that calls itself."}]}
57
- ```
63
+ - **[Axolotl](https://github.com/OpenAccess-AI-Collective/axolotl)** — if you like YAML configs and want a community of recipes to copy from
64
+ - **[LLaMA-Factory](https://github.com/hiyouga/LLaMA-Factory)** if you want a web GUI and built-in support for DPO/PPO/RLHF
65
+ - **[Unsloth](https://github.com/unslothai/unsloth)** if you need the fastest possible training and you're on a supported model family
66
+ - **[torchtune](https://github.com/pytorch/torchtune)** — if you want Meta's first-party PyTorch-native recipes you can edit
58
67
 
59
- Alpaca (`instruction`/`output`), OpenAI chat (`messages`), and raw text formats are also supported. See `examples/quickstart.jsonl` for a copyable starting point.
68
+ Backpropagate is the missing option: **a 3-line Python API for solo operators on a single consumer GPU who want to train an adapter and ship it.** No YAML, no GUI, no DPO/PPO, no multi-node. Just the loop everyone actually needs and the export step that gets in the way.
60
69
 
61
- ## Why Backpropagate?
70
+ If you tried one of the libraries above and bounced off the config-file ceremony, or hit a model-family gap, or wanted Windows-first defaults — Backpropagate is for you.
62
71
 
63
- | Problem | Solution |
64
- |---------|----------|
65
- | Fine-tuning is complex | 3 lines: load, train, save |
66
- | Windows is a nightmare | First-class Windows support |
67
- | VRAM management is hard | Auto batch sizing, GPU monitoring |
68
- | Model export is confusing | One-click GGUF + Ollama registration |
69
- | Long runs cause forgetting | Multi-run SLAO training |
72
+ ## What you can fine-tune on a 16GB consumer GPU
70
73
 
71
- ## Key Features
74
+ Here's the practical envelope on a 16GB card (RTX 4080 / 5080 / 4070 Ti Super):
72
75
 
73
- - **Headless by Design**: Built for CI/CD pipelines, automated workflows, and programmatic execution.
74
- - **Smart Defaults**: Automatically configures optimal hyperparameters based on your hardware and dataset.
75
- - **Multi-Run SLAO Training**: Advanced training strategies to prevent catastrophic forgetting during long runs.
76
- - **First-Class Windows Support**: Tested and optimized for Windows environments, avoiding common PyTorch/CUDA pitfalls.
77
- - **Seamless Export**: One-click export to GGUF format and automatic registration with Ollama.
78
- - **Modular Architecture**: Install only the dependencies you need (e.g., `[unsloth]`, `[ui]`, `[export]`).
76
+ | Model | Method | Status |
77
+ |---|---|---|
78
+ | Qwen-3.5-4B / Phi-4-mini-3.8B / SmolLM3-3B | LoRA / QLoRA / DoRA | Comfortable. Full sequence length, room to spare. |
79
+ | Phi-4-mini-3.8B / Qwen-3.5-4B / SmolLM3-3B (≤3B parameter ceiling) | `mode="full"` (full fine-tuning) | v1.4 — pass `--mode=full` on `backprop train` or `Trainer(..., mode="full")`. Gradient checkpointing + paged 8-bit Adam keep the activation memory at sqrt(L). |
80
+ | Qwen-2.5-7B / Llama-3.1-8B / Mistral-7B | QLoRA | Standard. ~7-8 GB. Backpropagate's default presets. |
81
+ | Llama-3 13B | QLoRA + sample packing | Tight but works. Use shorter sequences. |
82
+ | Mixtral 8x7B (47B total parameters) | AQLM 2-bit + LoRA | Planned for v1.5 — see V1_5_BRIEF when posted. |
79
83
 
80
- ## Installation
84
+ AQLM 2-bit quantization (`quant_method="aqlm"` experimental opt-in for Mixtral-8x7B on 16GB) was scoped for v1.4 and is now planned for v1.5. The `aqlm` library is mature; the v1.4 wave-budget prioritized full fine-tuning support for ≤3B models (`mode="full"`) over adding a new quantization backend. See V1_5_BRIEF when posted for the v1.5 implementation plan.
81
85
 
82
- ```bash
83
- pip install backpropagate # Core only (minimal)
84
- pip install backpropagate[unsloth] # + Unsloth 2x faster training
85
- pip install backpropagate[ui] # + Reflex (Radix UI) web interface
86
- pip install backpropagate[standard] # unsloth + ui (recommended)
87
- pip install backpropagate[full] # Everything
88
- ```
86
+ For models 3B and smaller, full fine-tuning (not just LoRA) is feasible on 16GB and now ships in v1.4 as `mode="full"`. Pass `Trainer(..., mode="full")` or `backprop train --mode=full --model phi-4-mini-3.8b` to enable it. A hard gate refuses the mode for models > 3B with `RUNTIME_FULL_FT_MODEL_TOO_LARGE`, naming LoRA + the three sub-3B presets as the recovery options. See [the full fine-tuning handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/full-fine-tuning/) for the configuration math + Biderman 2024 / Thinking Machines 2025 quality comparison. For 7B+ models, full fine-tuning needs a 24GB+ GPU — consider an A100 cloud rental, or stick with LoRA, which recent research shows matches full fine-tuning quality on most post-training tasks anyway (see [the anti-pitch section](#what-backpropagate-is-not-for) for citations).
89
87
 
90
- | Extra | Description | Dependencies |
91
- |-------|-------------|--------------|
92
- | `unsloth` | 2x faster training, 50% less VRAM | unsloth |
93
- | `ui` | Reflex (Radix UI) web interface | reflex>=0.9.2, fastapi>=0.115 |
94
- | `validation` | Pydantic config validation | pydantic, pydantic-settings |
95
- | `export` | GGUF export for Ollama | llama-cpp-python |
96
- | `monitoring` | WandB + system monitoring (auto-wired into trainer in v1.1.0) | wandb, psutil |
97
- | `logging` | Structured logging | structlog |
98
- | `security` | JWT auth + token generation | PyJWT, cryptography |
99
- | `production` | unsloth + ui + validation + logging + security | (bundle) |
88
+ ## What Backpropagate is NOT for
100
89
 
101
- **Requirements:** Python 3.10+ · CUDA GPU (8GB+ VRAM) · PyTorch 2.0+
90
+ If your use case is below, you'll have a better time with a different library — Backpropagate is not the right pick and trying to make it work would cost more than just reaching for the right tool. Reading this section before you start saves the install-and-bounce cycle:
102
91
 
103
- ### Platform prerequisites
92
+ - **Full-parameter fine-tuning of 7B+ models** — Backpropagate uses LoRA / QLoRA, which trains a small adapter rather than updating every weight. For models 7B and larger, full fine-tuning needs 24GB+ of GPU memory and doesn't fit on a 16GB consumer card. For models 3B and smaller, full fine-tuning IS feasible on 16GB and ships in v1.4 as `mode="full"` (pass `Trainer(..., mode="full")` or `--mode=full` on the CLI; a hard gate raises `RUNTIME_FULL_FT_MODEL_TOO_LARGE` for models > 3B and names LoRA + the sub-3B presets as recoveries). The bigger picture: recent research ([Biderman 2024](https://arxiv.org/abs/2405.09673), [Thinking Machines 2025](https://thinkingmachines.ai/blog/lora/)) shows that LoRA at correct configuration matches full fine-tuning quality on most post-training tasks (instruction-following, domain adaptation, persona/style) at 67% of the compute — so for the work most operators actually want, you don't lose anything by sticking with LoRA. `mode="full"` exists for the cases where you've measured a quality gap and decided to spend the extra compute. If you genuinely need full fine-tuning of a 7B+ model, use HuggingFace `transformers.Trainer` directly on a 24GB+ card.
93
+ - **DPO / PPO / GRPO / preference tuning** — Backpropagate does single-stage supervised fine-tuning only. For preference learning, use TRL directly or LLaMA-Factory.
94
+ - **Multi-node training** — single GPU on one machine only. Multi-GPU on one machine works (via `accelerate launch`) but isn't officially supported.
95
+ - **macOS training** — Apple Silicon doesn't have CUDA, so training has to run on a Linux or Windows box with an NVIDIA GPU. You can still run the trained model on a Mac via Ollama.
96
+ - **Anything outside the tested model families** — Qwen 2.5 / 3.5 (7B / 4B), Phi-4-mini-3.8B, SmolLM3-3B, Llama 3.2 (3B / 1B), Mistral 7B. Other models often work but aren't pinned in CI.
104
97
 
105
- Backpropagate handles the runtime quirks (multiprocessing, xformers on RTX 40/50, dataloader workers on Windows). It does **not** handle the install-time platform pain fix those first:
98
+ If you need any of those things, reach for one of the libraries listed above. They're better at them.
106
99
 
107
- - **CUDA toolkit version.** PyTorch is published per-CUDA — picking the wrong wheel silently installs CPU-only torch. Use the picker at <https://pytorch.org/get-started/locally/> for the exact `pip install torch ...` command for your driver. Run `nvidia-smi` to see your driver / CUDA version.
108
- - **Windows.** Visual Studio Build Tools (C++) and CMake are required for the `[export]` extra (`llama-cpp-python` builds from source). `bitsandbytes` wheel is published for Windows natively now (>= 0.43); older guides mentioning `bitsandbytes-windows` are stale.
109
- - **macOS.** GPU training is **not supported** — no CUDA. You can install Backpropagate to run *inference* on an exported GGUF via Ollama, but `trainer.train()` raises `DEP_GPU_NOT_AVAILABLE`. Use a CUDA machine for training.
110
- - **Linux.** Most distros work out of the box. If you're using the PyPI binary release, note that the Linux build uses CPU-only torch (to stay under GitHub's 2 GB release-asset cap); install with the matching CUDA wheel from pytorch.org first.
100
+ ## What Backpropagate gives you
111
101
 
112
- For the long-form install troubleshooting, see [the troubleshooting handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting/).
102
+ Four things, in one install:
113
103
 
114
- ## Configuration
104
+ **1. A real 3-line API that runs without a config file.**
105
+ The snippet at the top of this README runs end-to-end. No `accelerate config`, no YAML, no Hydra overrides. Just `Trainer(model).train(data)` and you have a finetune.
115
106
 
116
- All settings can be overridden with environment variables using the `BACKPROPAGATE_` prefix (e.g., `BACKPROPAGATE_LOG_LEVEL=debug`). A `.env` file in the project root is loaded automatically when the `[validation]` extra is installed.
107
+ **2. Windows that actually works.**
108
+ Most ML libraries treat Windows like an afterthought. Backpropagate is tested first-class on Windows + RTX 5080. The library handles the runtime quirks for you — it knows how to pre-tokenize your data so Windows multiprocessing doesn't crash, it automatically disables xformers on RTX 40/50 cards where it would break, and it picks dataloader settings that don't blow up. You don't have to know any of this. It just runs.
117
109
 
118
- Common knobs (see [the full env-vars reference](https://mcp-tool-shop-org.github.io/backpropagate/handbook/env-vars/) for everything):
110
+ **3. Built for unattended runs.**
111
+ Training takes hours. You don't want to babysit it. Backpropagate is designed to be left running:
119
112
 
120
- | Variable | Default | Notes |
121
- |----------|---------|-------|
122
- | `BACKPROPAGATE_LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
123
- | `BACKPROPAGATE_LOG_JSON` | auto | Force JSON (`true`) or console (`false`) logs |
124
- | `BACKPROPAGATE_LOG_FILE` | unset | Path to mirror logs into |
125
- | `BACKPROPAGATE_DEFER_FEATURE_DETECTION` | unset | Skip optional-dep detection at startup for the fastest CLI cold start |
126
- | `BACKPROPAGATE_SECURITY__REQUIRE_AUTH_FOR_SHARE` | `true` | When `true`, refuses `backprop ui --share` without `--auth` |
127
- | `BACKPROPAGATE_UI__OUTPUT_DIR` | `~/.backpropagate/ui-outputs` | Sandbox base for all UI filesystem writes; denylist-validated |
128
- | `BACKPROPAGATE_MODEL__NAME` | `Qwen/Qwen2.5-7B-Instruct` | Default model |
129
- | `BACKPROPAGATE_TRAINING__LEARNING_RATE` | `2e-4` | Learning rate |
130
- | `BACKPROPAGATE_LORA__R` | `16` | LoRA rank |
113
+ - If you run out of GPU memory, it automatically halves the batch size and retries — up to three times. No hand-tuning.
114
+ - If your GPU gets too hot, it pauses until things cool down and then continues.
115
+ - Every checkpoint is written atomically if your laptop crashes mid-save, the previous good checkpoint is still intact.
116
+ - Every training run gets a unique ID that's stamped onto every log line, every checkpoint, and every Weights & Biases entry. If something goes wrong, one ID lets a maintainer correlate everything.
117
+ - Errors come with stable codes (`RUNTIME_GPU_OOM`, `DEP_OLLAMA_REGISTRATION_FAILED`, etc.) so you can grep your logs and the [troubleshooting guide](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting/) for the fix. CUDA-specific failures have a dedicated [CUDA troubleshooting page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting-cuda/).
131
118
 
132
- Nested keys use double underscore as the delimiter (Pydantic `env_nested_delimiter` convention).
119
+ **4. One command from trained adapter to `ollama run`.**
120
+ Lots of libraries train a model. Few of them get out of your way when you want to actually use it. Backpropagate exports to GGUF (the format Ollama uses) and registers an Ollama model in one command. You go from "training done" to "I can chat with my finetune" in about 30 seconds.
133
121
 
134
- ## Usage
122
+ ## Quick Start
135
123
 
136
- ### Basic Training
124
+ The repo ships a tiny example dataset so the snippet from the top of this README runs on a clean install:
137
125
 
138
- ```python
126
+ ```bash
127
+ pipx install "backpropagate[standard]"
128
+
129
+ python -c "
139
130
  from backpropagate import Trainer
131
+ trainer = Trainer('Qwen/Qwen2.5-7B-Instruct')
132
+ trainer.train('examples/quickstart.jsonl', steps=10)
133
+ trainer.export('gguf', quantization='q4_k_m')
134
+ "
135
+ ```
140
136
 
141
- trainer = Trainer("Qwen/Qwen2.5-7B-Instruct")
142
- trainer.train("my_data.jsonl", steps=100)
143
- trainer.save("./my-model")
144
- trainer.export("gguf", quantization="q4_k_m")
137
+ This trains a Qwen 2.5 7B adapter on 5 short ShareGPT-format conversations, then exports the result to GGUF. For your own data, format your JSONL one example per line:
138
+
139
+ ```jsonl
140
+ {"conversations": [{"from": "human", "value": "What is Python?"}, {"from": "gpt", "value": "A programming language."}]}
141
+ {"conversations": [{"from": "human", "value": "Explain recursion."}, {"from": "gpt", "value": "A function that calls itself."}]}
142
+ ```
143
+
144
+ Alpaca (`instruction` / `output`), OpenAI chat (`messages`), and raw text formats also work — Backpropagate auto-detects the format.
145
+
146
+ For more end-to-end workflows (fine-tune-and-push-to-HF-Hub, resume after OOM, multi-run SLAO across a long campaign, etc.) see the [handbook recipes page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/recipes/).
147
+
148
+ ### Web UI (optional)
149
+
150
+ If you'd rather click than type Python, install the UI extra and launch:
151
+
152
+ ```bash
153
+ pipx install "backpropagate[ui]"
154
+ backprop ui --port 7862
145
155
  ```
146
156
 
147
- `Qwen/Qwen2.5-7B-Instruct` is the canonical default the value `Trainer()` resolves when called with no model argument (see [`config.py`](backpropagate/config.py) `ModelConfig.name`). Older examples pinned the pre-quantized `unsloth/Qwen2.5-7B-Instruct-bnb-4bit`; we switched the default to the official Qwen weights for better reliability ([CHANGELOG v1.1.0](CHANGELOG.md#110---2026-05-21)). Either model works.
157
+ A local web interface opens at `http://localhost:7862` where you can point at a dataset, pick a model, train, and export. The UI is local-only by default. To expose it to other devices, see [Web UI](#web-ui) below for the `--share` + `--auth` security contract.
148
158
 
149
- ### Multi-Run SLAO Training
159
+ ## Multi-run training
160
+
161
+ If you want to fine-tune incrementally across multiple datasets — say you get new training data every week and want to add it without forgetting what you learned before — Backpropagate's `multi_run` mode is for you:
150
162
 
151
163
  ```python
152
164
  from backpropagate import Trainer
@@ -158,196 +170,196 @@ result = trainer.multi_run(
158
170
  num_runs=5,
159
171
  steps_per_run=100,
160
172
  samples_per_run=1000,
161
- merge_mode="slao", # Single LoRA Continual Learning via Asymmetric Merging
162
173
  )
163
174
  ```
164
175
 
165
- SLAO (Single LoRA Continual Learning via Asymmetric Merging) implements the [Merge before Forget](https://arxiv.org/abs/2512.23017) paper: orthogonal A-matrix init via QR decomposition, asymmetric A/B handling, and time-aware `λ(i) = 1/√i` scaling. The CLI flag is `--samples` (the underlying field is `samples_per_run`).
166
-
167
- ### Export to Ollama
168
-
169
- ```python
170
- # Export to GGUF
171
- result = trainer.export("gguf", quantization="q4_k_m")
172
-
173
- # Register with Ollama separately
174
- from backpropagate import register_with_ollama
175
- register_with_ollama(result.path, "my-finetuned-model")
176
- # ollama run my-finetuned-model
177
- ```
176
+ This runs five training passes, merging the adapter between runs in a way that preserves earlier knowledge while incorporating new examples. The technique is based on recent continual-learning research see [References](#references) at the bottom of this README.
178
177
 
179
- ### CLI
178
+ The CLI version:
180
179
 
181
180
  ```bash
182
- backprop train --data my_data.jsonl --model Qwen/Qwen2.5-7B-Instruct --steps 100
183
- backprop multi-run --data my_data.jsonl --runs 5 --steps 100
184
- backprop export ./output/lora --format gguf --quantization q4_k_m --ollama --ollama-name my-model
185
- backprop ui --port 7862
186
- backprop info
187
- backprop list-runs # v1.1.0: query past training runs
188
- backprop show-run <run-id> # v1.1.0: detail view
189
- backprop resume <run-id> # v1.1.0: resume a crashed multi-run
190
- backprop push ./output/lora --repo me/my-model # v1.1.0: push adapter to HF Hub
181
+ backprop multi-run --data my_data.jsonl --runs 5 --steps 100 --samples 1000
191
182
  ```
192
183
 
193
- See the [CLI reference](https://mcp-tool-shop-org.github.io/backpropagate/handbook/cli-reference/) for every subcommand and flag, or run `backprop <subcommand> --help`.
194
-
195
- ### Resume from checkpoint (v1.1.0)
184
+ ## Resume from checkpoint
196
185
 
197
- A 5-run multi-run that crashes at run 4 is now recoverable. Every multi-run session writes its run_id into both `run_history.json` and the on-disk checkpoint manifest, so picking up where you left off is one command:
186
+ A 5-run training that crashes at run 4 is recoverable. Every multi-run session writes its run ID into the on-disk history and checkpoint manifest, so picking up where you left off is one command:
198
187
 
199
188
  ```bash
200
- backprop resume <run-id> # picks up the in-progress session
201
- backprop multi-run --data ... --resume <run-id> # explicit form
202
- backprop train --data ... --resume <run-id> # single-run resume (continues run_id)
189
+ backprop resume <run-id>
190
+ backprop multi-run --data ... --resume <run-id>
191
+ backprop train --data ... --resume <run-id> # single-run resume
203
192
  ```
204
193
 
205
- The default behavior of `backprop multi-run` (no `--resume`) auto-detects an in-progress entry for the same output directory and continues it. Pass `resume_from="off"` (Python API) or omit `--resume` and start in a fresh output dir to force a clean session.
206
-
207
- When a multi-run resumes, the latest checkpoint for that run_id is loaded into the model, the SLAO merger state is restored from `slao/` next to the checkpoint, and the run loop continues from `last_completed_run + 1`. The history entry's `status` flips back to `running` so `backprop list-runs --status running` shows the live session.
194
+ The default behavior of `backprop multi-run` (no `--resume`) auto-detects an in-progress entry in the same output directory and continues it. To force a clean start, point at a fresh output directory.
208
195
 
209
- ### Experiment tracking (v1.1.0)
196
+ ## Training history
210
197
 
211
- `Trainer` auto-detects installed experiment trackers (`wandb`, `tensorboard`, `mlflow`) and wires them into the underlying `transformers.TrainingArguments`. The default `report_to="auto"` picks up whatever's importable:
198
+ Every `backprop train` and `backprop multi-run` invocation records a row in `<output>/run_history.json` model used, dataset, hyperparameters, status, final loss, loss history. You can list and inspect past runs:
212
199
 
213
200
  ```bash
214
- pip install backpropagate[monitoring] # installs wandb + psutil
215
- wandb login # one-time
216
- backprop train --data my_data.jsonl # W&B run gets the same run_id prefix as the on-disk history
201
+ backprop list-runs # last 20 runs
202
+ backprop list-runs --status failed # filter by status
203
+ backprop list-runs --json --limit 100 # machine-readable
204
+ backprop show-run abcd1234 # detail view (partial ID is fine)
217
205
  ```
218
206
 
219
- Override with `Trainer(report_to=["wandb"])`, `Trainer(report_to=["tensorboard"])`, or `Trainer(report_to="none")` to opt out explicitly. For MLflow add `pip install mlflow`; for TensorBoard add `pip install tensorboard`. The W&B run name is `backprop-<run_id_prefix>` so an operator can grep across W&B, our logs, and `run_history.json` by the same identifier.
220
-
221
- ### Training history
207
+ ## Experiment tracking
222
208
 
223
- Every `backprop train` and `backprop multi-run` invocation records a row in `<output>/run_history.json` with the run_id, model, dataset, hyperparameters, status, final loss, loss history, and (for multi-run) the SLAO merge timeline. List recent runs:
209
+ Backpropagate auto-detects installed experiment trackers (Weights & Biases, TensorBoard, MLflow) and wires them in. If `wandb` is installed and you're logged in, every run automatically logs to W&B with a run name that matches the on-disk run ID — so you can grep across W&B, your logs, and `run_history.json` using one identifier.
224
210
 
225
211
  ```bash
226
- backprop list-runs # most recent 20 runs, all statuses
227
- backprop list-runs --status failed # filter
228
- backprop list-runs --json --limit 100 # machine-readable
229
- backprop show-run abcd1234 # detail view (partial run_id ok)
212
+ pip install backpropagate[monitoring] # installs wandb + psutil
213
+ wandb login # one-time setup
214
+ backprop train --data my_data.jsonl
230
215
  ```
231
216
 
232
- Run history survives across processes — the `Runs` tab in the web UI is a separate, in-memory view; the on-disk history is the source of truth for `list-runs` / `show-run` / `resume`.
217
+ Override with `Trainer(report_to=["wandb"])`, `Trainer(report_to=["tensorboard"])`, or `Trainer(report_to="none")` to opt out.
233
218
 
234
- ### Web UI
219
+ ## Web UI
235
220
 
236
- Launch the Reflex interface locally:
221
+ The Reflex web interface is opt-in — install with `pipx install "backpropagate[ui]"` and launch:
237
222
 
238
223
  ```bash
239
224
  backprop ui --port 7862
240
225
  ```
241
226
 
242
- To expose a public-internet URL, you must pair `--share` with `--auth`:
227
+ The UI runs locally on `http://localhost:7862`. To expose it to other devices (other people on your network, a public URL, etc.) you must pair `--share` (or `--host`) with `--auth`:
243
228
 
244
229
  ```bash
245
230
  backprop ui --share --auth alice:hunter2
246
231
  ```
247
232
 
248
- `backprop ui --share` without `--auth` exits with code `1` and the structured error `[RUNTIME_UI_AUTH_NOT_ENFORCED]`. The rationale: `--share` publishes a public URL that anyone on the internet can hit, and without auth that means anyone can drive your training pipeline. There is no opt-out — if you don't want to set credentials, use SSH port-forwarding instead: `ssh -L 7860:localhost:7860 <host>` then open `http://localhost:7860` locally. See [handbook/security.md](site/src/content/docs/handbook/security.md) for the full threat model.
233
+ `backprop ui --share` without `--auth` exits with an error. The reason: `--share` publishes a URL anyone on the internet can reach, and without authentication that means anyone can drive your training pipeline and read your HuggingFace token. There is no opt-out for this — if you don't want to set credentials, use SSH port-forwarding instead:
234
+
235
+ ```bash
236
+ # On the client:
237
+ ssh -L 7860:localhost:7860 <your-training-host>
238
+ # On the server:
239
+ backprop ui # no --share
240
+ # Then open http://localhost:7860 in your local browser
241
+ ```
242
+
243
+ See [handbook/security.md](https://mcp-tool-shop-org.github.io/backpropagate/handbook/security/) for the full threat model.
249
244
 
250
245
  Filesystem writes from the UI are sandboxed to a single directory:
251
246
 
252
247
  - Default: `~/.backpropagate/ui-outputs`
253
- - Override: `BACKPROPAGATE_UI__OUTPUT_DIR=/path/you/own`
254
- - The override is **denylist-validated** — system / credential paths (`/etc`, `/var`, `~/.ssh`, `~/.aws`, `C:\Windows\System32`, etc.) are refused with `[UI_OUTPUT_DIR_FORBIDDEN]`.
248
+ - Override: set `BACKPROPAGATE_UI__OUTPUT_DIR=/path/you/own`
249
+ - The override is denylist-validated — system or credential paths (`/etc`, `~/.ssh`, `~/.aws`, `C:\Windows\System32`, etc.) are refused
255
250
 
256
- ## Windows Support
251
+ ## Platform notes
257
252
 
258
- Backpropagate is designed to work on Windows out of the box:
253
+ **Requirements:** Python 3.10+ · CUDA GPU (8GB+ VRAM) · PyTorch 2.0+
259
254
 
260
- - Pre-tokenization to avoid multiprocessing crashes
261
- - Automatic xformers disable for RTX 40/50 series
262
- - Safe dataloader settings
263
- - Tested on RTX 5080 (16GB VRAM)
255
+ Python 3.10 reaches upstream end-of-life in October 2026, and Backpropagate plans to drop 3.10 in v1.4. For new installs, prefer Python 3.11 or 3.12 — 3.11 is the most-tested floor.
264
256
 
265
- ## Model Presets
257
+ Backpropagate handles the runtime quirks of training on different platforms, but it can't fix install-time problems. The two most common are:
266
258
 
267
- | Preset | VRAM | Speed | Quality |
268
- |--------|------|-------|---------|
269
- | Qwen 2.5 7B | ~12GB | Medium | Best |
270
- | Qwen 2.5 3B | ~8GB | Fast | Good |
271
- | Llama 3.2 3B | ~8GB | Fast | Good |
272
- | Llama 3.2 1B | ~6GB | Fastest | Basic |
273
- | Mistral 7B | ~12GB | Medium | Good |
259
+ - **Wrong CUDA wheel.** PyTorch is published one binary per CUDA version. If you pick the wrong one, you silently get CPU-only PyTorch and training is impossibly slow. Use the wheel picker at <https://pytorch.org/get-started/locally/> for your driver. Run `nvidia-smi` to see your driver / CUDA version.
260
+ - **Windows + GGUF export.** The `[export]` extra builds `llama-cpp-python` from source, which needs Visual Studio Build Tools (C++ component) and CMake.
274
261
 
275
- ## Architecture
262
+ **macOS:** GPU training is not supported (no CUDA). You can run the trained adapter on a Mac via Ollama, but `trainer.train()` raises `DEP_GPU_NOT_AVAILABLE`. Use a CUDA Linux or Windows machine for the training itself.
276
263
 
264
+ See the [troubleshooting handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting/) for the long-form install fix-it guide, and the dedicated [CUDA troubleshooting page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting-cuda/) for driver / VRAM / xformers / bf16-vs-fp16 issues.
265
+
266
+ ## CLI
267
+
268
+ Every Python API has a CLI mirror:
269
+
270
+ ```bash
271
+ backprop train --data my_data.jsonl --model Qwen/Qwen2.5-7B-Instruct --steps 100
272
+ backprop multi-run --data my_data.jsonl --runs 5 --steps 100
273
+ backprop export ./output/lora --format gguf --quantization q4_k_m --ollama --ollama-name my-model
274
+ backprop ui --port 7862
275
+ backprop info # environment + version snapshot
276
+ backprop list-runs # past training runs
277
+ backprop show-run <run-id> # detail view
278
+ backprop resume <run-id> # resume a crashed run
279
+ backprop push ./output/lora --repo me/my-model # push adapter to HuggingFace Hub
280
+ backprop diff-runs <run-a> <run-b> # diff two runs side by side
281
+ backprop replay <run-id> # re-run with same config / dataset
282
+ backprop export-runs --format jsonl # bulk export run history
277
283
  ```
278
- backpropagate/
279
- ├── trainer.py # Core Trainer class
280
- ├── multi_run.py # Multi-run SLAO training
281
- ├── slao.py # SLAO LoRA merging algorithm
282
- ├── datasets.py # Dataset loading, filtering & curriculum
283
- ├── export.py # GGUF/Ollama export
284
- ├── config.py # Pydantic settings + training presets
285
- ├── gpu_safety.py # GPU monitoring & safety
286
- ├── cli.py # CLI entry point (backprop command)
287
- ├── checkpoints.py # Checkpoint management
288
- ├── exceptions.py # Structured error hierarchy
289
- ├── feature_flags.py # Optional feature detection
290
- ├── security.py # Path traversal & torch security
291
- ├── logging_config.py # Structured logging setup
292
- ├── ui_theme.py # Radix theme tokens + CSS (Reflex era)
293
- ├── ui_state.py # rx.State subclasses
294
- ├── ui_app/ # Reflex web interface (Radix UI)
295
- │ ├── app.py # rx.App entry point
296
- │ ├── chrome.py # Header / LeftNav / SideRail / Footer
297
- │ ├── pages/ # Train / Multi-Run / Export / Dataset
298
- │ └── components/ # Bp* primitives (status pill, sparkline, event log…)
299
- └── ui_security.py # Rate limiting, CSRF, file validation (framework-agnostic)
300
- ```
301
284
 
302
- The v1.0 Gradio implementation (`ui_gradio_legacy.py` + `theme_gradio_legacy.py`) was preserved through v1.1.x as reference and removed in v1.2.0.
285
+ Full reference at [the CLI handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/cli-reference/), or `backprop <subcommand> --help`.
286
+
287
+ ## Configuration
288
+
289
+ Every setting can be overridden with an environment variable using the `BACKPROPAGATE_` prefix:
290
+
291
+ | Variable | Default | Notes |
292
+ |---|---|---|
293
+ | `BACKPROPAGATE_LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
294
+ | `BACKPROPAGATE_LOG_JSON` | auto | Force JSON or console logs |
295
+ | `BACKPROPAGATE_MODEL__NAME` | `Qwen/Qwen2.5-7B-Instruct` | Default model |
296
+ | `BACKPROPAGATE_TRAINING__LEARNING_RATE` | `2e-4` | Learning rate |
297
+ | `BACKPROPAGATE_LORA__R` | `256` | LoRA rank (v1.3 default; pass `--lora-preset=fast` for the v1.2.x default of 16) |
298
+ | `BACKPROPAGATE_UI__OUTPUT_DIR` | `~/.backpropagate/ui-outputs` | UI filesystem sandbox |
299
+
300
+ Nested keys use double underscore (`MODEL__NAME`, not `MODEL_NAME`). The full reference is at [the env-vars handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/env-vars/).
301
+
302
+ ## Model presets
303
+
304
+ | Preset | VRAM | License | Notes |
305
+ |---|---|---|---|
306
+ | Qwen-3.5-4B | ~8GB | Apache 2.0 | Recommended default for sub-5B. Best quality at this size. |
307
+ | Phi-4-mini-3.8B | ~8GB | MIT | Strong on reasoning / math / code. Strict license-clean. |
308
+ | SmolLM3-3B | ~6GB | Apache 2.0 | Fully open recipe. Native 64K context. |
309
+ | Qwen 2.5 7B | ~12GB | Apache 2.0 | Existing default. Best quality of the legacy 7B presets. |
310
+ | Qwen 2.5 3B | ~8GB | Qwen-Research | ⚠ research license — see Qwen license terms before commercial use. |
311
+ | Llama 3.2 3B | ~8GB | Llama Community | Solid alternative to Qwen 3B with permissive caveats. |
312
+ | Llama 3.2 1B | ~6GB | Llama Community | For quick experiments on small cards. |
313
+ | Mistral 7B | ~12GB | Apache 2.0 | Comparable to Qwen 7B, different chat template. |
314
+
315
+ Other models often work, but only these eight are pinned in CI. Pass `--lora-preset=quality` (default) for rank-256 / all-linear targets per Biderman 2024 + Thinking Machines 2025, or `--lora-preset=fast` for the legacy rank-16 / q+v target if you need the v1.2.x footprint.
303
316
 
304
317
  ## Troubleshooting
305
318
 
306
- A short index of the most common first-run failures. The full reverse index lives at [the troubleshooting handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting/); every code below is documented at [error codes](https://mcp-tool-shop-org.github.io/backpropagate/handbook/error-codes/).
319
+ A short index of the most common first-run failures. The full reverse index is at [the troubleshooting handbook page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting/). For driver / VRAM / mixed-precision deep-dive see the [CUDA troubleshooting page](https://mcp-tool-shop-org.github.io/backpropagate/handbook/troubleshooting-cuda/).
307
320
 
308
- | Symptom | Code | Fix |
309
- |---------|------|-----|
310
- | GPU runs out of memory mid-training | `RUNTIME_GPU_OOM` | OOM auto-recovery (B-002) halves batch size up to 3 times automatically. To opt out: `Trainer(oom_recovery=False)`. To force smaller: `--batch-size 1`. |
311
- | HF Hub returns 401 / "model not found" | `DEP_MODEL_LOAD_FAILED` | `huggingface-cli login` and re-try. For typos, copy the exact id from <https://huggingface.co/models>. |
312
- | Bad model name typo | `INPUT_VALIDATION_FAILED` or `DEP_MODEL_LOAD_FAILED` | Verify the `org/name` identifier at <https://huggingface.co/models>. |
321
+ | Symptom | Error code | Fix |
322
+ |---|---|---|
323
+ | GPU runs out of memory mid-training | `RUNTIME_GPU_OOM` | Automatic Backpropagate halves the batch size and retries up to 3 times. To opt out: `Trainer(oom_recovery=False)`. To force smaller: `--batch-size 1`. |
324
+ | HuggingFace returns 401 / "model not found" | `DEP_MODEL_LOAD_FAILED` | `huggingface-cli login` and retry. For typos, copy the exact ID from <https://huggingface.co/models>. |
313
325
  | `register_with_ollama` connection refused | `DEP_OLLAMA_REGISTRATION_FAILED` | Start the daemon: `ollama serve`. Install from <https://ollama.com>. Retryable. |
314
- | Disk full during checkpoint save | `STATE_CHECKPOINT_INVALID` | Atomic writes leave a `.partial` directory on crash — safe to delete. Previous good checkpoint is intact. |
315
- | Training paused / aborted on GPU overheat | `RUNTIME_GPU_TEMPERATURE_CRITICAL` | B-003 monitor pauses on NVML temp threshold; resumes automatically as the GPU cools. Improve airflow or lower sustained load. |
316
- | `backprop ui --share` rejected | `INPUT_AUTH_REQUIRED` | Pass `--auth user:password`, or set `BACKPROPAGATE_SECURITY__REQUIRE_AUTH_FOR_SHARE=false` to opt out (loud warning). |
317
- | Multi-run "validation overlap" | `CONFIG_INVALID` (Stage A backend B-001) | Lower `--samples` below the training-pool size, increase dataset, or disable validation. |
326
+ | Disk full during checkpoint save | `STATE_CHECKPOINT_INVALID` | Atomic writes leave a `.partial` directory on crash — safe to delete. The previous good checkpoint is intact. |
327
+ | Training paused on GPU overheat | `RUNTIME_GPU_TEMPERATURE_CRITICAL` | Automatic Backpropagate pauses on the temperature threshold and resumes as the GPU cools. Improve airflow if it keeps happening. |
328
+ | `backprop ui --share` rejected | `INPUT_AUTH_REQUIRED` | Pass `--auth user:password`, or use SSH port-forwarding instead (see [Web UI](#web-ui)). |
318
329
  | GGUF export failed on first try | `RUNTIME_GGUF_EXPORT_FAILED` | `pip install backpropagate[export]`; on Windows you also need Visual C++ Build Tools + CMake. |
319
330
 
320
331
  ## Reporting bugs
321
332
 
322
- When something fails, Backpropagate prints a `run_started run_id=<uuid>` line at startup and binds the same id to checkpoint manifests, SLAO merge history, and structured log lines. Include the `run_id` in any bug report — it lets a maintainer correlate every log line, every checkpoint, and every merge for that exact run.
333
+ When something fails, Backpropagate prints a line at startup like `run_started run_id=<uuid>` and binds the same ID to every log line, every checkpoint, and every Weights & Biases entry. **Include the `run_id` in any bug report** — it lets a maintainer correlate everything for that exact run.
323
334
 
324
335
  A good bug report includes:
325
336
 
326
- 1. **`run_id`** — the uuid printed at startup (also available as `TrainingRun.run_id` and `RunResult.run_id`).
327
- 2. **The error code** — the `[CODE_NAME]: message` line in stderr is what to grep for; see [error codes](https://mcp-tool-shop-org.github.io/backpropagate/handbook/error-codes/) for the catalog.
328
- 3. **The redacted command line.** Stderr in non-verbose mode is automatically redacted (Bearer tokens, `sk-*`, `hf_*`, AWS keys, `password=`/`token=`/`api_key=` pairs are scrubbed) — safe to paste. For the full unredacted traceback, re-run with `--verbose`, but review before posting.
329
- 4. **Python / PyTorch versions, GPU model, OS.** `backprop info` prints all of this in one go.
337
+ 1. **The `run_id`** — the UUID printed at startup. One UUID lets a maintainer correlate every log line, every checkpoint, and every Weights & Biases entry for that exact run.
338
+ 2. **The error code** — the `[CODE_NAME]: message` line in stderr. See [error codes](https://mcp-tool-shop-org.github.io/backpropagate/handbook/error-codes/) for the catalog of stable codes.
339
+ 3. **The redacted traceback.** Stderr is automatically redacted in non-verbose mode (Bearer tokens, `sk-*`, `hf_*`, AWS keys, `password=` / `token=` / `api_key=` pairs are scrubbed) — safe to paste. For the full unredacted traceback, re-run with `BACKPROPAGATE_DEBUG=1` (or `--verbose`); review before posting.
340
+ 4. **The `backprop info` output.** One command prints Python / PyTorch / CUDA / GPU model / VRAM / OS / installed extras everything the maintainer needs to bisect a platform-specific regression.
341
+
342
+ The [bug report template](https://github.com/mcp-tool-shop-org/backpropagate/issues/new?template=bug_report.yml) prompts for each of these explicitly so triage moves fast. Questions, ideas, or "is this expected?" threads belong in [GitHub Discussions](https://github.com/mcp-tool-shop-org/backpropagate/discussions). Security issues should be reported privately via the [GitHub Security Advisory](https://github.com/mcp-tool-shop-org/backpropagate/security/advisories/new) form — see [SECURITY.md](SECURITY.md) for the policy and response timelines.
330
343
 
331
344
  ## Privacy
332
345
 
333
346
  All training happens locally on your GPU. Backpropagate makes no network requests except to download models from HuggingFace (which you initiate). No telemetry, no cloud dependency.
334
347
 
335
- ## Scorecard
348
+ ## References
336
349
 
337
- | Category | Score | Notes |
338
- |----------|-------|-------|
339
- | A. Security | 6/8 | SECURITY.md, trust model, no secrets/telemetry, safe_path(). MCP items skipped |
340
- | B. Error Handling | 5/7 | Structured exception shape (`code`/`message`/`hint`/`cause`/`retryable`) via ERROR_CODES registry; CLI exit codes 0/1/2/3; no raw stack traces without `--verbose`; `run_id` correlation; redacted stderr; `--share`+`--auth` gating. MCP/desktop/vscode skipped. |
341
- | C. Operator Docs | 4/7 | README, CHANGELOG, LICENSE, --help. Logging/MCP/complex skipped |
342
- | D. Shipping Hygiene | 6/9 | verify.sh, version=tag, 5 scanners in CI, dependabot, python_requires, clean build |
343
- | E. Identity | 4/4 | Logo, translations, landing page, metadata |
344
- | **Total** | **25/31** | 14 items skipped with justification · `shipcheck audit` passes 100% · Audit date: 2026-05-21 (B-row re-graded after Stage B + Stage A CLI exit-code work) |
350
+ Backpropagate's defaults and multi-run training mode are built on recent research. If you're interested in the underlying techniques:
345
351
 
346
- Design history and what each line item maps to: see [ROADMAP.md](ROADMAP.md) — all Week 1–4 items are shipped in v1.1.0.
352
+ - **Hu et al. 2021.** *LoRA: Low-Rank Adaptation of Large Language Models.* [arXiv:2106.09685](https://arxiv.org/abs/2106.09685) — the foundational paper introducing LoRA, which is how Backpropagate trains adapters efficiently.
353
+ - **Biderman et al. 2024.** *LoRA Learns Less and Forgets Less.* [arXiv:2405.09673](https://arxiv.org/abs/2405.09673) — empirical evidence that LoRA at rank 256 with all-linear targets matches full fine-tuning quality on most post-training tasks at 67% of the compute. Drives Backpropagate's v1.3 default LoRA configuration.
354
+ - **Thinking Machines 2025.** *LoRA Without Regret.* [thinkingmachines.ai/blog/lora](https://thinkingmachines.ai/blog/lora/) — the practical follow-up identifying the 10× learning-rate-vs-full-FT correction needed at high LoRA rank.
355
+ - **Kirkpatrick et al. 2017.** *Overcoming catastrophic forgetting in neural networks.* [arXiv:1612.00796](https://arxiv.org/abs/1612.00796) — the original characterization of why neural networks "forget" earlier training when you fine-tune on new data (EWC — Elastic Weight Consolidation).
356
+ - **Wang et al. 2023.** *Orthogonal Subspace Learning for Language Model Continual Learning.* [arXiv:2310.14152](https://arxiv.org/abs/2310.14152) — O-LoRA, an earlier approach to using LoRA for continual learning by constraining new adapters to orthogonal subspaces.
357
+ - **Yadav et al. 2023.** *TIES-Merging: Resolving Interference When Merging Models.* [arXiv:2306.01708](https://arxiv.org/abs/2306.01708) — a foundational technique for merging multiple fine-tuned models without interference.
358
+ - **Qiao & Mahdavi 2025.** *Merge before Forget: A Single LoRA Continual Learning via Continual Merging.* [arXiv:2512.23017](https://arxiv.org/abs/2512.23017) — the specific algorithm Backpropagate's multi-run merger implements. A December 2025 preprint; Backpropagate is the paper's first known downstream adopter.
347
359
 
348
360
  ## License
349
361
 
350
- MIT — see [LICENSE](LICENSE) for details.
362
+ MIT — see [LICENSE](LICENSE).
351
363
 
352
364
  ---
353
365