# `fitcheck` — Specification > **PRD + Technical Design + Definition of Done — One Document** > > Version: 0.3.1 beta · Author: Anas · Date: September 2026 --- ## Section 1: Problem & Users ### The Pain Point Every ML practitioner who fine-tunes LLMs has hit the same wall: 1. Pick a model, set training config (batch size, LoRA rank, sequence length, precision). 2. Launch training. Wait 2–5 minutes for the model to load. 3. **`CUDA OutOfMemoryError`.** 4. Guess a smaller config. Relaunch. Wait again. Repeat. This trial-and-error loop wastes 10–30 minutes per attempt and provides **zero insight** into *why* it doesn't fit or *how close* you are. The information needed to answer "will it fit?" exists — it's pure math from the model's `config.json` — but nobody has packaged it into a tool that gives a precise, component-level breakdown with actionable advice. ### Target Users | Persona | What they need | How they use `fitcheck` | |:---|:---|:---| | **Solo GPU owner** (RTX 3090/4090) | Know if a QLoRA job fits before launching | `fitcheck --gpu 4090 --lora-r 64 ...` | | **Cloud ML engineer** (A100/H100) | Pick the cheapest instance that fits | `fitcheck --gpu a100-40 ...` vs `--gpu a100-80` | | **ML student / beginner** | Understand *where* GPU memory goes during training | Interactive REPL → `explain` command | | **Framework developer** (Axolotl, Unsloth) | Pre-validate user configs before launching jobs | JSON output mode for CI/CD integration | | **Inference deployer** (Ollama, vLLM) | Know if a model fits for serving | `fitcheck infer --gpu 4090` — **v0.2**, see §2 | ### Why Existing Tools Don't Solve This | Tool | Gap | |:---|:---| | `accelerate estimate-memory` | No LoRA/QLoRA. No activations, optimizer, gradients. Weights only. | | HF Model Memory Calculator | Inference only. No training components. | | LLM-Calc | Napkin math. No component breakdown. No LoRA. | | vram.asmirnov.xyz | No GQA-aware formulas. No CLI. Limited architectures. | **`fitcheck` fills every gap simultaneously:** component-level breakdown, LoRA/QLoRA-native, GQA-aware, architecture-specific (reads `config.json`), actionable advice, CLI-first, and two interaction modes (one-liner + interactive REPL). --- ## Section 2: Feature Scope ### MVP (v0.1 — Days 1–5) | Feature | Priority | Notes | |:---|:---:|:---| | CLI with `click`: `fitcheck [flags]` | P0 | Power-user one-liner mode | | Interactive REPL: `fitcheck` (no args) | P0 | Commands: `model`, `gpu`, `memory`, `infer`, `explain`, `optimize`, `compare`, `help`, `exit` | | Fetch HuggingFace `config.json` via `huggingface_hub` | P0 | No weight download — config only | | Compute all 6 memory components | P0 | Weights, LoRA, optimizer, gradients, activations, overhead | | GPU database (hard-coded) | P0 | 22 entries — consumer, older/cloud, workstation, datacenter. Roster in §3.4 | | Rich terminal output | P0 | Colored table, pass/fail verdict, headroom %, max batch suggestion | | Precision support: FP32, FP16, BF16, INT8, INT4 | P0 | | | Optimizer support: AdamW, SGD, Adam8bit | P0 | | | LoRA + QLoRA support | P0 | GQA-aware LoRA param counting | | Read `intermediate_size` from config | P0 | Never assume `4h` | | `--json` output for CI/CD | P0 | Machine-readable `MemoryReport` | | `--explain` + savings hints | P0 | The "where did my VRAM go" teaching path | | `pip install fitcheck-llm` | P0 | PyPI published on day 5 | | Unit tests with `pytest` | P0 | ≥80% coverage on `memory/` modules | | GitHub Actions CI | P0 | Three jobs: `lint` (`ruff check .` + `mypy --strict fitcheck/` — see §3.10), `test` (pytest on 3.10/3.11/3.12, coverage badge) and `floor` (lowest declared dependency versions on 3.10 — see §3.9) | ### Stretch — v0.2+ (Post-MVP) | Feature | Phase | Notes | |:---|:---:|:---| | `fitcheck infer ` — inference mode | 1.5 | KV cache math, concurrent request estimation — **done, v0.2** (§3.1 Component 7, §3.5 Mode C) | | `fitcheck advise` — config advisor | 2 | Sweep of (batch_size, lora_r, seq_len) → per-axis prices, per-axis ceilings, and the frontier at the edge of what fits — **done, v0.3** (§3.5 Mode D for the CLI, §3.5 Mode B for the session command, `docs/ADVISOR.md` for the derivation). Dominance is over **two** objectives (maximise tokens/step, maximise rank) with `total_mib ≤ usable` as the *constraint*, not a third objective: MiB is a monotone function of the other two, so minimising it filters nothing (measured 60 of 60 fitting points surviving on a 150-point Llama-3.1-8B grid) | | Calibration mode | 3 | 1 real forward pass → correction factor | | HuggingFace Gradio Space | 3 | Web UI for non-CLI users — live at https://huggingface.co/spaces/mlanvvs/fitcheck | | Cost estimator (RunPod/Lambda pricing) | 3 | | | ZeRO / FSDP sharding | 4 | Multi-GPU memory modeling | | Axolotl/Unsloth YAML integration | 4 | Read their config, output estimate | --- ## Section 3: Technical Design ### 3.1 — The 6 Memory Components and Their Formulas All training estimates use the master equation: $$\boxed{\text{Peak VRAM} = W_{base} + W_{lora} + S_{optim} + G_{grad} + A_{act} + C_{overhead}}$$ Each component below uses the same order: what it counts, formula, why, and limits. All results are converted to MiB at the boundary. --- #### Component 1: Base Model Weights ($W_{base}$) **What it counts.** The resident base-model weights and quantization scales. A quantized base has a packed slice and an unquantized slice. The latter includes `embed_tokens`, `lm_head`, and layernorms. **Formula.** Unquantized base: $$W_{base} = P \times \text{bytes\_per\_param}$$ Quantized base: $$W_{base} = P_q \times \left(\text{bytes\_per\_param} + \frac{4}{B_q}\right) + P_{skip} \times 4$$ Quantization-scale overhead: $$Q_{overhead} = P_q \times \frac{4}{B_q}\text{ bytes}$$ Double quantization: $$\text{Overhead}^{DQ} = \frac{8\text{ bits}}{64} + \frac{32\text{ bits}}{64 \times 256} = 0.125 + 0.00195 \approx \mathbf{0.127}\text{ bits/param} \approx \mathbf{0.0159}\text{ bytes/param}$$ The factor relative to single quantization is $\mathbf{0.254}$. Double quantization removes about three quarters of scale overhead. Parameter count: $$P = V h + L \left[P_{attn} + 3h \cdot d_{ff} + 2h\right] + h + V h \cdot \mathbb{1}[\text{untied}]$$ Attention parameter count: $$P_{attn} = 2h \cdot n_h \cdot d_k + 2h \cdot n_{kv} \cdot d_k$$ | Attention type | Condition | $P_{attn}$ | | :--- | :--- | ---: | | MHA | $n_{kv}=n_h$ | $4h^2$ | | GQA | $1