Skip to main content

torch-preflight

CI Python License Tests

Docs | Rules | VRAM estimation | CLI

A static analyzer for PyTorch that understands autograd โ€” it catches VRAM leaks and silent convergence bugs at commit time, and tells you whether your training run will OOM before you launch it.

$ torch-preflight check train.py

train.py
  7:19  error   TG001 (CRITICAL_OOM)
  `losses.append(...)` stores a tensor that is still attached to the autograd graph;
  every iteration's graph is retained in VRAM.
    7 โ”‚     losses.append(loss)
      โ”‚                   ^^^^
  help: Use `.item()` to keep just the scalar value, or `.detach()` to keep the tensor
        without its graph.
  fix:  add .detach() (run with --fix)

Found 1 error in 1 file(s).

One line, one wasted GPU hour. Caught in milliseconds, before it runs.

  • ๐Ÿ” Six rules for bugs ruff and flake8 cannot see โ€” retained autograd graphs, missing zero_grad(), evaluation without no_grad(), starved dataloaders, doubled softmax
  • ๐Ÿงฎ Pre-flight VRAM estimation โ€” projects peak memory from your script and says which change would make it fit
  • ๐Ÿ› ๏ธ Autofixes via concrete syntax tree rewrites, so formatting and comments survive untouched
  • ๐Ÿ“Š Measured, not guessed โ€” every constant calibrated against real hardware, 5.0% mean error versus measured peaks
  • ๐Ÿคซ Quiet on real code โ€” 5 findings across PyTorch's own 2,239 files, all deliberate
  • โšก No GPU and no PyTorch required โ€” pure static analysis over LibCST; a CI job asserts torch is never imported
  • ๐Ÿ Python 3.9โ€“3.13, pyproject.toml config, pre-commit hook, GitHub Action, SARIF output

ruff and flake8 understand Python. They don't understand autograd graphs, gradient accumulation, or what num_workers=0 does to eight GPUs waiting on one CPU. torch-preflight is built for the bugs that only cost money once you're paying for a GPU.

Table of contents

Getting started

pip install torch-preflight
torch-preflight check ./src/                        # lint a tree
torch-preflight check ./src/ --fix                  # apply the safe fixes
torch-preflight estimate train.py --gpu a100-80gb   # will this run fit?
torch-preflight explain TG003                       # why a rule exists, and what it costs

The base install has no heavy dependencies. torch-preflight[hub] adds Hugging Face architecture lookup; torch-preflight[vram] adds exact meta-device profiling.

The line that costs you a GPU hour

losses = []
for batch, targets in loader:
    optimizer.zero_grad()
    loss = criterion(model(batch), targets)
    loss.backward()
    optimizer.step()
    losses.append(loss)          # โ† keeps every step's graph alive in VRAM

You have written this. Everyone has. loss still carries its computational graph, so appending it retains every intermediate activation from that step โ€” and the next, and the next. Memory climbs linearly until CUDA gives up, hours in.

Why this is hard: losses.append(x) is only a bug when x carries a graph. torch-preflight runs a dataflow pass to find out, tracing values across assignments, arithmetic, tensor methods and function scopes, and refusing to propagate through .detach(), .item() or argmax. So losses.append(loss.item()) stays silent, and so does anything inside torch.no_grad(). A linter that pattern-matched on .append( would be unusable.

See all six rules โ†’

Will this fit on the GPU I'm about to rent?

$ torch-preflight estimate finetune.py --gpu a100-80gb

Model      llama-2-7b  (arch-snapshot)   6.74 B params
Config     amp ยท AdamW ยท batch 4 ยท seq 2048

  weights            25.10 GiB      autocast cache     12.55 GiB
  gradients          25.10 GiB      activations        66.44 GiB
  optimizer state    50.21 GiB      fragmentation      18.84 GiB
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  projected peak    198.37 GiB   (178.53 GiB โ€“ 218.21 GiB)

Target     NVIDIA A100 80GB (78.0 GiB usable)   โ†’   254% of capacity   โœ— OOM

What would make it fit:
  โœ—  โˆ’ 66.30 GiB  โ†’  132.07 GiB   gradient checkpointing
  โœ—  โˆ’ 41.61 GiB  โ†’  156.76 GiB   8-bit AdamW (bitsandbytes)
  โœ—  โˆ’112.02 GiB  โ†’   86.35 GiB   all of the above + flash attention
                                  + halve micro-batch โ€” still does not fit

A single 80GB A100 is the wrong tool for a full 7B fine-tune at sequence 2048. Better to learn that now than after the instance is running.

Model, batch size, sequence length, precision and sharding are read out of your script โ€” nothing is imported or executed. 41 architectures ship built in, 23 GPUs and 34 cloud instances are known by name (--gpu p4de.24xlarge works), and anything else is measured exactly on PyTorch's meta device without allocating a byte.

Every other estimator stops at the number. The list of what to change is the part you actually wanted.

See VRAM estimation โ†’

Why you can trust the numbers

Memory estimators are easy to write and easy to be quietly wrong about. So:

Constants are measured Activation coefficients from saved_tensors_hooks on the meta device; allocator behaviour and CUDA context from a real GPU. Measurement showed the published Megatron constants are a midpoint of two regimes โ€” models with dropout retain 3ร— the attention tensors โ€” so Llama-class models are charged the cheaper rate they actually pay.
Projections are checked 5.0% mean absolute error against measured peaks for GPT-2, BERT and DistilBERT on a T4. Harness and fixtures in tests/calibration/, so you can re-run them.
It refuses to guess An unrecognised model reports UNKNOWN and widens the interval rather than inventing a parameter count. Verdicts are bands with an error range, never a fabricated "95% risk" score.
It stays quiet 5 findings across PyTorch's own 2,239 files, every one deliberate. That pass found four bugs in the rules, now regression-tested.

294 tests. PyTorch's entire source tree lints in ~50 seconds.

Integrations

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/highwaterlabs/torch-preflight
    rev: v0.1.0
    hooks:
      - id: torch-preflight
# .github/workflows/lint.yml
- uses: highwaterlabs/torch-preflight@v0
  with:
    paths: src/
    format: github      # inline PR annotations

SARIF output feeds GitHub code scanning; JSON feeds everything else. Set target_gpu in pyproject.toml and CI fails on a projected OOM before the job is ever submitted.

See CI integration โ†’

Documentation

Rules All six rules, and the false positives deliberately suppressed
VRAM estimation Custom architectures, CI gating, VRAMGuard, accuracy
CLI reference Commands, flags, exit codes, autofixes
Configuration pyproject.toml and inline suppression
CI integration GitHub Action, pre-commit, SARIF
Architecture How the analysis pipeline works
Development Tests, adding a rule, roadmap

Design notes live in design/, including the RFC behind the estimator and the spike the cost model rests on.

What stays free

MIT licensed. These are commitments, not just current state:

  • Every rule that has ever shipped free stays free.
  • The estimator, the remediation solver and VRAMGuard stay complete โ€” not a demo tier.
  • The rule API stays open, so anyone can write and ship their own rules.
  • The calibration method and data stay public and reproducible. Numbers are only worth trusting if you can check them.

A hosted service may come later for things that genuinely need a server or a team. Nothing above is part of that.

Contributing

Issues and pull requests are welcome. Adding a rule is one file plus a @register decorator โ€” see development for the walkthrough and the test conventions.

License

MIT โ€” see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

torch_preflight-0.1.0.tar.gz (140.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

torch_preflight-0.1.0-py3-none-any.whl (97.1 kB view details)

Uploaded Python 3

File details

Details for the file torch_preflight-0.1.0.tar.gz.

File metadata

  • Download URL: torch_preflight-0.1.0.tar.gz
  • Upload date:
  • Size: 140.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for torch_preflight-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3b07d54fa964b147c073ff6091af5c213799f24d2274c70cf430fba4a757177a
MD5 0c51f8e10895f68be79f7a038b7f0207
BLAKE2b-256 292e59e4e6d8c3efc3cc3013eee9ebf839cca111ae2be0abdf8c1bdb22b4e6d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for torch_preflight-0.1.0.tar.gz:

Publisher: release.yml on highwaterlabs/torch-preflight

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file torch_preflight-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: torch_preflight-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 97.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for torch_preflight-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c232c9b14d0d33cfe37cbe84381659638f12c245dd842303206c0bf1c0301a9e
MD5 642e75a1b95618ea50d6e423f6c70cd1
BLAKE2b-256 0afbec1f06081deea20dbff15355fa6eaa646695bc6be720abcfba843b413d1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for torch_preflight-0.1.0-py3-none-any.whl:

Publisher: release.yml on highwaterlabs/torch-preflight

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page