Diagnostic autopsy for PyTorch training runs
Project description
🩻 torchmortem
Diagnostic autopsy for PyTorch training runs.
torchmortem hooks into your PyTorch training loop and produces a diagnostic
report (an "autopsy", if you will) telling you why your training might be broken
and how to fix it.
If you need full-fledged experiment tracking, hyperparameter sweeps, or collaborative dashboards, this is probably not the right tool. Instead, go look at platforms like Weights & Biases or TensorBoard.
Installation
Install into a virtual environment with uv:
uv venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"
Or install from PyPI (once published):
pip install torchmortem
Requires Python >=3.10 and PyTorch >=2.0.
Quick Start
from torchmortem import Autopsy
with Autopsy(model, optimizer=optimizer) as autopsy:
for epoch in range(num_epochs):
for batch in dataloader:
loss = model(batch)
loss.backward()
optimizer.step()
autopsy.step(loss=loss.item())
autopsy.report("autopsy_report.html")
How it works
torchmortem is built using a plugin architecture for maximum extensibility.
- Collectors (implementing
Collectorincollectors/base.py) attach PyTorch hooks to a model and record raw signals during training. - Detectors (implementing
Detectorindetectors/base.py) analyze the collected signals and return findings. - The interpreter (
DefaultInterpreterininterpreters/default.py, override-able via the protocol ininterpreters/base.py) synthesizes the findings from all detectors by applying the rules defined ininterpreters/rules. - The interpreter produces human-readable reports using renderers (defined in
renderers/).
Built-in feature set
Individual detectors:
- Vanishing / exploding gradients -- inter-layer gradient ratio analysis
- Dead units -- persistently inactive neurons (dead ReLU problem)
- Activation saturation -- sigmoid/tanh layers stuck in flat regions
- Unhealthy update ratios -- ||update||/||weight|| deviating from ~1e-3
- Loss dynamics -- catapult phase, edge-of-stability, plateaus, divergence
- Rank collapse -- representation dimensionality shrinking over training
- Weight norm pathologies -- explosion, stagnation, inter-layer imbalance
- Gradient noise -- SNR and batch size efficiency
Cross-signal insights (correlation rules):
- Gradient starvation -- vanishing gradients + dead units
- Instability feedback loop -- exploding gradients + weight explosion
- Representation bottleneck -- rank collapse + loss stagnation
- Curvature traps -- edge-of-stability + plateau
Report features:
- Executive summary -- 3-5 sentence assessment with the top recommendation
- Per-layer health scores -- 0-1 score for each layer, visualized as a heatmap
- Interactive charts -- loss curve, gradient norms, weight norms, update ratios, dead unit fractions, effective rank
- Cross-signal insights -- root-cause explanations synthesized from multiple detectors
- Findings -- each with severity, explanation, affected layers, remediation, and references
- JSON output -- for CI pipelines and programmatic analysis
Sampling Configuration
Control the overhead/detail tradeoff:
# Presets
Autopsy(model, sampling="thorough") # max detail
Autopsy(model, sampling="balanced") # default
Autopsy(model, sampling="fast") # minimal overhead
# Granular control
from torchmortem import SamplingConfig
Autopsy(model, sampling=SamplingConfig(
default_interval=1,
expensive_interval=50,
overrides={"curvature": 20},
))
Examples
See the examples/ directory:
basic_mlp.py-- Deep MLP with sigmoid activations (vanishing gradients, dead units)healthy_resnet.py-- Well-configured residual networktransformer_debug.py-- Transformer with high LR and no clippingcnn_overfit.py-- Small CNN that overfits on a toy image datasetlstm_vanishing.py-- Vanilla LSTM with extreme sequence length
Contributing
Contributions are welcome! The plugin architecture aims to make it relatively easy for contributors to add new features. Please refer to CONTRIBUTING.md for guidelines.
Custom detector example
Here is a complete example of a custom detector that flags any layer whose gradient norm exceeds a configurable threshold:
import numpy as np
from torchmortem.registry import register_detector
from torchmortem.types import CollectorState, Finding, RunMetadata, Severity
@register_detector
class LargeGradientDetector:
"""Flags layers where the gradient norm exceeds a fixed threshold."""
name: str = "large_gradient"
required_collectors: list[str] = ["gradient"]
def __init__(self, threshold: float = 100.0) -> None:
self._threshold = threshold
def analyze(
self,
collector_states: dict[str, CollectorState],
metadata: RunMetadata,
) -> list[Finding]:
grad_state = collector_states["gradient"]
norms = grad_state.series.get("grad_norm")
if norms is None or len(grad_state.steps) == 0:
return []
findings: list[Finding] = []
for idx, layer in enumerate(grad_state.layers):
layer_norms = norms[:, idx]
max_norm = float(np.max(layer_norms))
if max_norm > self._threshold:
findings.append(Finding(
detector=self.name,
severity=Severity.WARNING,
category="gradient_flow",
title=f"Large gradient in {layer}",
summary=f"Gradient norm in {layer} reached {max_norm:.1f}, exceeding the {self._threshold:.1f} threshold.",
detail=f"The maximum gradient L2 norm observed in {layer} was {max_norm:.1f}. Large gradients can destabilize training and cause weight explosion.",
affected_layers=[layer],
step_range=(int(grad_state.steps[0]), int(grad_state.steps[-1])),
remediation=[
"Add gradient clipping (torch.nn.utils.clip_grad_norm_).",
"Reduce the learning rate.",
],
))
return findings
The detector will be picked up automatically once the module containing it
is imported before the Autopsy context manager is entered.
License
torchmortem is provided under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file torchmortem-0.1.0.tar.gz.
File metadata
- Download URL: torchmortem-0.1.0.tar.gz
- Upload date:
- Size: 111.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3297b9c8fec5360a304cb4831ee41a81743ef204bf76aedbb9587bdec770082e
|
|
| MD5 |
dc07fb2a183352e1385000f0a6088a0d
|
|
| BLAKE2b-256 |
8594a5ce80f4c6c72c5d76ecb794594fe83a690237ab989ca56d5d218eeeeba9
|
Provenance
The following attestation bundles were made for torchmortem-0.1.0.tar.gz:
Publisher:
publish.yml on sebseager/torchmortem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
torchmortem-0.1.0.tar.gz -
Subject digest:
3297b9c8fec5360a304cb4831ee41a81743ef204bf76aedbb9587bdec770082e - Sigstore transparency entry: 1084695472
- Sigstore integration time:
-
Permalink:
sebseager/torchmortem@353fefb37cc43488baa6bdb081702e4a59c9eb1e -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sebseager
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@353fefb37cc43488baa6bdb081702e4a59c9eb1e -
Trigger Event:
release
-
Statement type:
File details
Details for the file torchmortem-0.1.0-py3-none-any.whl.
File metadata
- Download URL: torchmortem-0.1.0-py3-none-any.whl
- Upload date:
- Size: 61.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d8376d3efb37383b0844ea34a9e8c528081ae06b1b8b0d402f7a9284dff6442
|
|
| MD5 |
4b47fd79a85a12cadba2cc26bf42fdad
|
|
| BLAKE2b-256 |
f0d3acdb560169b9d0a5604a7ae735d20d547e5fce468934805dde4918643c7f
|
Provenance
The following attestation bundles were made for torchmortem-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on sebseager/torchmortem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
torchmortem-0.1.0-py3-none-any.whl -
Subject digest:
3d8376d3efb37383b0844ea34a9e8c528081ae06b1b8b0d402f7a9284dff6442 - Sigstore transparency entry: 1084695553
- Sigstore integration time:
-
Permalink:
sebseager/torchmortem@353fefb37cc43488baa6bdb081702e4a59c9eb1e -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/sebseager
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@353fefb37cc43488baa6bdb081702e4a59c9eb1e -
Trigger Event:
release
-
Statement type: