Skip to main content

sdcguard

Catch GPUs that compute wrong answers, inside your own PyTorch training and vLLM serving.

A GPU can return wrong numbers without crashing. Sometimes the hardware is at fault, sometimes a library, and from the outside the two look the same. ByteDance found 18 such incidents over 3.5 x 10^7 GPU-hours, and 15 of them were silent (AEGIS, OSDI '26). The usual health checks run a test on an idle GPU. sdcguard checks the math of your actual job while it runs, with the kernels, precisions and settings you really use.

A real bug the usual tools missed

NVIDIA lists cuBLAS known issue 6862950 in the CUDA 13.4 Update 2 release notes: on Hopper GPUs, a process running under MPS with less than 100% of the SMs can get wrong FP16, BF16 and FP8 matmul results. On October 20 we ran a head-to-head on an H200, with the rules written before the run:

MPS share sdcguard check DCGM diagnostic gpu-burn
100% PASS pass pass
40% FAIL pass pass
75% FAIL pass pass
14% FAIL pass pass

DCGM and gpu-burn didn't malfunction. Their own test matmuls came out right at every share, so the bug never reached them. A test of the GPU isn't a test of your job. Rules, predictions and raw logs: METHOD.md, results/h2h.

Install

pip install "sdcguard[all]"

Python 3.10+, PyTorch 2.5+, an NVIDIA GPU. The demo and self-test also run on a CPU.

Check a GPU

sdcguard check            # every GPU on this machine, about 5 minutes
sdcguard check --share    # same, plus a link to add your result to the public board

It trains and serves a small model with checks on, runs matmuls in every precision the GPU supports (BF16, FP16, TF32, FP32, FP64, INT8, FP8) checked in float64, pattern-tests most of the memory, measures speed, and runs a fixed model three times to see that the output stays bit-identical. The precisions matter: in ByteDance's study, four GPUs with bad matmuls all got BF16 and FP16 right (SDCs in the Wild, OSDI '26).

Each GPU gets PASS, FAIL, SUSPECT (output that should repeat didn't) or INCOMPLETE (part of the check couldn't run or couldn't judge its results). A FAIL saves the inputs and the wrong output, so sdcguard replay can recompute them on another GPU. PASS means these checks found nothing, not that the GPU is flawless. Shared results go on the board.

An example sdcguard check result card

In training

from sdcguard import SDCGuard

guard = SDCGuard(every=20).protect(model)    # checks nn.Linear layers: forward, dX and dW
for step, (x, y) in enumerate(loader):
    with guard.on_step(step):                # only every 20th step is checked
        loss = model(x, y); loss.backward()
    optimizer.step(); optimizer.zero_grad()
    if guard.log.events:                     # stop and look at the evidence
        print(guard.log.events[0].to_json()); break

Checking every 20th step cost 1.7% on GPT-2 small and 1.3% on a 0.9B model (H100). With exact_reductions=False the gradients are bit-identical to a run without sdcguard.

In serving

SDCGUARD=1 SDCGUARD_SHARE=0.125 vllm serve Qwen/Qwen2.5-7B-Instruct

This checks one linear layer in eight. With Qwen2.5-7B on an H100 (vLLM 0.31, compiled mode) it cost about 4% of throughput, every compared answer was word for word the same, and a weight bit flipped in a checked layer was caught and named. Checking every layer costs about 23% for now (details).

Any other PyTorch model:

from sdcguard.serve import ServeGuard

guard = ServeGuard().attach(model, share=0.125)   # bf16 or fp16 model on its GPU
...                                                # serve as usual, eager or torch.compile
for event in guard.poll():                         # doesn't stall the GPU
    print(event.to_json())

guard.coverage_report() shows which layers actually ran their check and how many times.

Across a fleet

sdcguard screen --minutes 10                         # screen every GPU on the node
sdcguard replay screen_out/GPU-.../evidence_0.pt     # recompute a failure on another GPU
sdcguard report node*/sdcguard_check --out fleet_report

There's also sdcguard nhc, a node health check for Kubernetes and Slurm (deploy/), signed per-GPU certificates (sdcguard keygen, sdcguard check --key, sdcguard verify), and alerts to Slack, Discord or Prometheus. An alert is where an investigation starts. It doesn't prove the board is bad.

How it works

For C = A @ B, the sum of each block of 128 output columns has to equal A times the matching column sums of B. Both sides are cheap to compute, so a wrong value in C shows up as a mismatch. This is algorithm-based fault tolerance (Huang and Abraham, 1984). Each block also gets a randomly signed sum, so most errors can't cancel out. Normal bf16 rounding makes the two sides differ a little, so sdcguard estimates each block's rounding noise and alarms only past 6 times that. On NVIDIA GPUs the checks run as Triton kernels.

What it catches, and what it misses

It catches:

  • wrong results in the matmuls it checks, during real training and serving, on one GPU, with no replicas or replay
  • errors that repeat exactly every time, because each result is checked against the math, not an earlier run
  • in a fault-injection study on GPT-2, 99% of faults that moved a 128-column block by 10% or more, and 70% of those between 1% and 10% (harm study)
  • a mantissa bit flip injected into real L4 tensor-core instructions with NVBit: the loss looked normal, and sdcguard flagged 30 of 30 steps (results)

It misses:

  • small errors: nothing under about 1% of a block. ByteDance found that checksums of bf16 outputs located none of their incidents and fp32 accumulators found them (AEGIS, section 8). sdcguard's fp32 check (precise mode) is still experimental.
  • anything outside the checked matmuls: attention internals, normalization, MoE experts, the optimizer, communication
  • correct math on wrong inputs, like the wrong weights or a broken quantization
  • steps and layers that sampling skips

No naturally defective GPU has been caught yet. The evidence so far is injected faults and a real library bug. On clean GPUs it raised no false alarm in 24.6 million checks of GPT-2 training on an H100 or in 1.68 million checks across 10 cloud GPUs.

Compared with what you may already run

Tool What it does What it can't see
DCGM diagnostic, gpu-burn Run the same test matmul many times on an idle GPU and compare the results with each other An error that repeats exactly; BF16 and FP8; your job's own kernels and settings
Megatron Core rerun state machine Reruns a step when a check rejects it; built in: NaN or Inf in the loss or gradient norms, opt-in spikes Wrong results that leave the loss and gradients looking normal; jobs outside Megatron
TorchTitan's replayer, SCOUT Bitwise replay of a step, or exact comparison across 3 or more replicas An error every replica shares, like a library bug; serving

Sources for each row are in WHY.md.

Coverage

  • Tested: PyTorch training in bf16 and fp16 (DDP on 4 H100s, FSDP2 on CPU), Hugging Face and vLLM serving, sdcguard check on B200, H200, H100, A100, L40S, L4 and T4.
  • Not checked: fp32, TF32 and quantized matmuls in training and serving (check tests them one matmul at a time), convolutions, fused MoE experts, vLLM's LM head, the inside of fused attention.
  • Not tested yet: Megatron tensor and pipeline parallel, DeepSpeed, multi-node, AMD.

No GPU? Try the demo

python -m sdcguard.demo       # simulated corruption during training, clearly labeled as a demo
python -m sdcguard.selftest   # checks that sdcguard works on this machine

Or run it in Colab. The same kind of simulation on 4 H100s:

Training loss of the same run on 4 H100s with and without sdcguard. GPU 2 starts returning wrong results at step 205. sdcguard flags it at step 210 and the run finishes all 1,000 steps on GPUs 0, 1 and 3. Without sdcguard the loss looks normal until it turns NaN at step 215, and restarting crashes again.

Logs and raw numbers: results/demo_4gpu.

More

  • docs/METHOD.md: how every number was measured, with pass/fail criteria written before the GPU runs
  • docs/EVIDENCE.md: what others published and what sdcguard measured, kept apart, negative results included
  • docs/WHY.md: what already exists and what it misses
  • results/: raw output of the GPU runs
  • To reproduce: pip install -e ".[experiments,dev]" && pytest -q, then the Modal scripts in scripts/

Status

Alpha (0.3.0), MIT license. Built by Hari Krishna Kancharla. Bug reports and results from your own GPUs are very welcome, most of all from a GPU you think is bad.

Metadata

Release files for sdcguard 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sdcguard 0.3.0
File Size Uploaded Provenance
sdcguard-0.3.0.tar.gz 260.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sdcguard 0.3.0
File Interpreter ABI Platform
sdcguard-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 437.0 kB

Release files / sdcguard-0.3.0.tar.gz

Download URL sdcguard-0.3.0.tar.gz
Size 260.7 kB
Tags Source
SHA-256 checksum
How to use checksums
41816a4b4c8173a959637d647c42b4261972d58e3045fba0083b3b33e7beaaba
BLAKE2b-256 checksum
How to use checksums
74035b0540b5aff82e64c808ab22f378684b7d155e7a2e9fc8db8a54fcc4ead5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / sdcguard-0.3.0-py3-none-any.whl

Download URL sdcguard-0.3.0-py3-none-any.whl
Size 176.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
307d1c27c28a1c91118543c75b4ee549ac7dac3b1b8da9fdc9a66df69d9017bd
BLAKE2b-256 checksum
How to use checksums
a6fd40a8c613519346a5ac7d3a6ba25ecb4775542da15c6e55a08b7581194930
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for sdcguard 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sdcguard-0.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page