Generated banner for Warp Debug Gradients
Generated logo for Warp Debug Gradients

Warp Debug Gradients

NVIDIAOfficialCreated by Warp TeamDistributed by NVIDIA

  • Skill
  • Review and audit
  • Software development
  • Apache-2.0
  • Medium risk
  • Has scripts

From the author

Use to diagnose and fix incorrect gradients in differentiable Warp programs. Anything trained, optimized, calibrated, or fit through Warp kernels depends on wp.Tape gradients, so treat any misbehavior of such a workflow as a gradient problem until proven otherwise — use this when training diverges or NaNs, won't train at all, stalls or plateaus above the expected loss, converges to a wrong or biased answer, is worse than a reference implementation, works at small scale but fails at production scale, or fails a QA/validation recheck. Also for explicit symptoms — exploding, NaN/inf, zero, or subtly wrong gradients, suspected wp.Tape/backward issues, gradcheck failures — but users usually describe only the surface symptom ("the sim explodes", "the fit gets dragged toward outliers") without mentioning gradients: make that leap. Not for forward-only Warp work, build/install problems, or autograd issues in other frameworks without Warp.
— the description by Warp Team

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

Gradient bugs in Warp are rarely mathematical errors; they are almost always structural issues in how the tape records operations or how memory is managed during the backward pass. This skill provides a rigorous, evidence-based methodology to identify and fix these bugs. By moving from surface-level symptoms—such as training divergence, NaNs, or stalled loss—to verifying the underlying gradient signature, you can isolate issues like write-after-read overwrites, accidental gradient truncation, or incorrect taping patterns. The process emphasizes measurement over intuition, utilizing Warp's built-in verification tools and finite-difference checks to confirm the root cause before applying minimal, structural fixes.

What it does

  • Identifies root causes of gradient-related failures in differentiable Warp workflows.
  • Provides a systematic checklist for common bug patterns like buffer reuse and state aliasing.
  • Guides the use of Warp's autograd verification tools to detect array access violations.
  • Implements finite-difference harnesses to establish ground truth and validate gradient correctness.
  • Helps distinguish between gradient bugs and other issues like learning rate or physics instability.
  • Offers strategies for structural fixes, including gradient checkpointing and dataflow restructuring.

When to use it

  • When training, optimization, or fitting through Warp kernels diverges, produces NaNs, or fails to converge.
  • When loss stalls, plateaus unexpectedly, or produces biased results.
  • When explicit gradient symptoms occur, such as exploding gradients, zero gradients, or gradcheck failures.
  • When a pipeline works at small scale but fails at production scale or during validation.
  • When you need to verify if a custom gradient implementation is correctly integrated into the backward pass.

Advantages

  • Reduces time spent on trial-and-error tuning of physics or loss functions.
  • Provides objective evidence for fixes through finite-difference comparison.
  • Prevents common pitfalls like silent gradient clobbering and accidental truncation.
  • Ensures fixes are structural and robust rather than just masking surface symptoms.
  • Leverages official Warp diagnostic tools for reliable, version-aware verification.

Usage examples

“My simulation training is producing NaNs after a few iterations. How do I debug this?”
The agent will guide you to enable the autograd overwrite tracker, shrink the simulation to a minimal reproducible case, and run a finite-difference check to identify if the NaN originates from a specific kernel or a dataflow overwrite.
“The gradients in my Warp model seem to be zero. What should I check?”
The agent will help you verify if the loss is correctly connected to the tape, check for piecewise-constant operations that require surrogate gradients, and confirm that kernels are not compiled with enable_backward=False.
“My optimization loss is worse than my reference implementation. Are my gradients wrong?”
The agent will assist in setting up an end-to-end finite-difference harness to compare your autodiff gradients against the objective, confirming whether the discrepancy is a gradient bug or a separate issue like learning rate.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/nvidia/warp-debug-gradients/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip warp-debug-gradients.zip -d .agents/skills

Documentation by Warp Team

Debugging Gradients in Warp

Gradient bugs in Warp are almost never math bugs. The forward simulation looks perfectly healthy while the backward pass silently reads clobbered values, skips arrays, or double-counts adjoints. Users routinely burn days tuning physics knobs, loss functions, and assets when the real cause is a two-line taping-pattern fix. Your job is to find that fix with evidence, not intuition.

The single most important discipline: measure before hypothesizing. It is cheap for you to run a shrunk reproduction and compare autodiff against finite differences. The way the gradient is wrong (its signature) prunes the hypothesis space far faster than reading code ever will. Do not start proposing fixes from code reading alone — plausible-looking diagnoses of differentiability bugs are very often wrong, and an unverified "fix" that happens to perturb the numbers wastes everyone's time.

When to Use This Skill

Anything trained, optimized, calibrated, or fit through Warp kernels flows through wp.Tape gradients — so when such a workflow misbehaves, gradients are the prime suspect even if the user never says the word. Activate on the symptoms users actually report: training that diverges, NaNs, or does nothing; loss that stalls or plateaus above where it should; fits that converge to a wrong or biased answer or are worse than a reference implementation; pipelines that work at small scale but fail at production scale or fail a QA recheck. Also activate on explicit gradient symptoms — exploding, NaN/inf, zero, or subtly wrong gradients, wp.autograd.gradcheck failures, suspected wp.Tape/backward issues — and when the user asks whether their gradients can be trusted.

Do not activate for forward-only Warp work (kernel authoring, rendering, performance tuning), Warp build or installation problems, autograd questions in other frameworks with no Warp involvement, or pure performance work on a backward pass whose gradients the user has already validated.

The canonical background is Warp's own documentation — consult the relevant section before diagnosing in its territory (online at https://nvidia.github.io/warp/stable/; in a Warp source checkout the same content is under docs/user_guide/; pip installs do not include it):

  • The "Differentiability" guide — especially "Array Overwrites", "Debugging Gradients", "Array Overwrite Tracking", and "Limitations and Workarounds" (in-place math, component assignment, dynamic loops).

  • The FAQ, section "Differentiation and Interoperability" — what state a tape does and does not preserve, and checkpointing.

Prerequisites

Executing this skill assumes all of the following; if one is missing, surface that to the user instead of improvising around it:

  • The user's script (or a faithful reproduction) is available in the workspace, runnable, and modifiable — diagnosis executes it repeatedly and edits it to apply fixes.

  • This skill's references/ files (quick-checks.md, verification.md, custom-gradients.md, case-studies.md) accompany it and are consulted at the steps that cite them.

Instructions

  1. Note the user's Warp version first (wp.__version__ or the banner Warp prints at init). Several verification behaviors changed in Warp 1.17 — copy-adjoint accumulation, overwrite-warning call sites, read-flag lifetime, gradcheck's restore_inputs — and the references mark each with a version caveat. On Warp < 1.17, a whole bug class exists that later versions fixed (quick-checks §1's version caveat), and some tools need workarounds.

  2. Reproduce and shrink. Get the user's script running, then cut it down: fewer particles/elements, fewer time steps, fewer optimizer iterations, CPU device if the sim allows. You need a repro that runs in seconds, because you will run it many times. Keep the structure (number of kernels, the taping pattern, buffer reuse) intact — that is where the bug lives. Shrinking the physics is fine; restructuring the dataflow is not.

    If the script cannot be made to run (missing dependencies, broken code), report the blocking issue as the deliverable and stop — do not proceed to verify a program that never ran.

  3. Instrument and establish ground truth (details and templates in references/verification.md):

    • Set wp.config.verify_autograd_array_access = True before module load and rerun under an active tape. Capture every warning. This catches the single most common bug class (write-after-read overwrites) nearly for free. Know its blind spots: it needs a tape, it cannot see arrays stored inside Warp structs, and it disables kernel caching (expect a kernel rebuild — JIT module recompilation only, not a rebuild of the native library). If the tracker runs clean but gradients are still wrong, specifically check for in-place mutations of arrays held inside Warp structs (quick-checks §1 and Limitations) before trusting the clean result.

    • Run one end-to-end finite-difference check: wrap the full forward pass (sim steps + loss) in a Python callable and hand it to wp.autograd.gradcheck with the true optimization inputs — it compares the autodiff gradient against central differences, restoring array inputs between evaluations (Warp 1.17+) so in-place-mutating forwards are checked from pristine state; on older Warp use the manual harness in references/verification.md. The reference is the user's actual objective over the full horizon, compared against the gradient the optimizer actually consumes — never a narrower window (see references/verification.md). This confirms gradients are actually wrong (users are sometimes wrong about this — report "gradients are correct" findings honestly) and yields the error signature. The template in references/verification.md fixes the eps/tolerance choices and the seed-pinning a stochastic forward needs — do not eyeball pass/fail against floating-point or sampling noise. If the backward pass runs out of memory while establishing ground truth, apply the checkpointing pattern from "Edge case: out of memory" below before proceeding.

  4. Match the signature against the table below to rank hypotheses.

  5. Scan the code against the known-pattern checklist (references/quick-checks.md). This is fast for you — do it in the same pass, but let the signature decide which findings are plausible causes versus incidental smells.

  6. Localize if still ambiguous. Binary-search the pipeline: truncate to K steps and find where FD and autodiff first diverge; run wp.autograd.gradcheck_tape to test each recorded launch in isolation. Remember gradcheck_tape validates kernels individually — it is structurally blind to inter-kernel overwrites, so a clean per-kernel pass plus a wrong end-to-end gradient points at the taping pattern, not the kernels. It also silently skips kernels compiled with enable_backward=False (see Limitations) — if any kernel in the pipeline sets that, a clean pass says nothing about it; verify it separately.

  7. Fix minimally, then re-verify with the exact same FD harness that established the failure. A gradient fix without a before/after FD comparison is not a fix. Verify the exact program you are shipping — the fixed file as it stands, every line included — never a re-implementation of it in a diagnostic script: a rebuilt pipeline silently drops whatever you believed was irrelevant, and if that belief is wrong the verification passes while the shipped code stays broken. Mechanically: the harness must import the fixed module (or execute the fixed file) and call into it — the only code that may live outside the shipped program is the FD driver itself. Also rerun the overwrite tracker to confirm the warnings are gone. "Minimally" applies to the code diff, not the diagnosis: when the root cause is structural (e.g., accidental gradient truncation, quick-checks §8), the minimal correct fix is the restructure — do not substitute a smaller change that only silences the surface symptom.

  8. Close the loop on the user's original complaint. Rerun their actual workflow (their script, their printed metrics). The job is done when the symptom they reported is resolved — an optimization that was "exploding" should now demonstrably improve its objective, not merely avoid NaN. If gradients verify correct at the full horizon but training still fails, that is a new signature-table entry, not a victory; keep diagnosing (or report the verified gradients and the remaining non-gradient cause, e.g. learning rate).

Failure signatures

SignatureLeading hypotheses
Gradients exactly zeroMissing requires_grad=True somewhere in the chain (note wp.zeros defaults to False; zeros_like/clone inherit from source); enable_backward=False at module/kernel level; loss array not connected to the tape; grads read after tape.zero(); a piecewise-constant op (round/floor/sign/cast/threshold) in the chain — there zero is correct and the fix is a surrogate gradient such as a straight-through estimator, not a bug hunt (quick-checks §9c); on Warp < 1.17, a tape-recorded copy/clone whose source has other downstream readers (see the version caveat in references/quick-checks.md)
Gradients grow without bound across optimizer iterationsMissing tape.zero()/tape.reset() between iterations; state-object aliasing that carries an in-tape overwrite across frames (case study 1)
Off by an exact small factor (2x, Nx)Double accumulation: a duplicate launch recorded on the tape — note that since Warp 1.13 the store adjoint consumes the output gradient on first use, so a bare duplicate is inert unless the rewritten array has retain_grad=True (quick-checks §7) or the Warp version is older; overlapping tape scopes taping the same work twice. Also: a backward seed that does not match the stated objective — seeding a per-element loss adjoint with ones backpropagates the sum, exactly N× the mean objective's gradient
NaN or infNon-differentiable point evaluated in the backward pass (wp.sqrt(0), wp.length(0), wp.normalize(0), division) — needs a custom gradient (references/custom-gradients.md) or, better, a stable reformulation; an overflow evaluated in the unselected branch of wp.where (a select, not a branch — quick-checks §9b); dynamic-loop local not recomputed during replay (documented to produce inf)
Subtly wrong, often worse with more steps/iterationsWrite-after-read overwrite: wp.copy onto an already-read array, ping-pong buffers within one tape, Python rebinding that aliases two "different" states (case studies); in-place *=//=; vector/matrix component reassignment; dynamic-loop intermediates; on Warp < 1.17, a recorded copy/clone that is not the last consumer of its source (version caveat in references/quick-checks.md)
Per-window FD agrees but full-horizon FD disagrees; or gradients "verified" yet the optimizer stalls or worsens the lossAccidental gradient truncation: a tape-per-step loop with backward inside it and state carried between tapes optimizes a different objective than the one being reported (see quick-checks §8). The structural fix is one tape over the whole horizon with total_steps + 1 distinct state buffers. The solver-space analog: a partially converged iterative solve inside the tape makes FD and autodiff agree on the wrong program — converge it outside the tape and warm-start the taped iterations (quick-checks §8)
Gradients disagree (vs a reference implementation or run-to-run) only on a sparse, data-dependent subset; forward outputs match to float precisionUnder-determined forward choice at a non-smooth point (quick-checks §9): both answers can be valid subgradients, and FD cannot adjudicate at a kink. Check whether the discrete choice differs at exactly the mismatching elements before hunting corruption
FD and autodiff agree at the full horizon but optimization still failsNot a gradient bug. Say so. Look at learning rate, loss landscape, physics stability — and report the verified-correct gradients as the finding

Examples

A representative session, end to end. A user reports "my cloth sim trains for a while, then the loss creeps back up — tuning the learning rate doesn't help." No mention of gradients; the leap is made because the workflow optimizes through Warp kernels.

  1. Their script runs 512 particles for 200 steps per iteration. Shrink to 16 particles, 10 steps, CPU — repro now runs in ~2 s and shows the same creep.

  2. wp.config.verify_autograd_array_access = True under the tape prints: array ... was read from kernel integrate and is now being written to by kernel integrate — a write-after-read overwrite.

  3. End-to-end wp.autograd.gradcheck on the shrunk repro: max relative error 0.4 against finite differences. Gradients are confirmed wrong, with the "subtly wrong, worse with more steps" signature.

  4. The signature row plus quick-checks §1 point at buffer reuse inside one tape: the sim steps state_a → state_b → state_a, ping-ponging two buffers, so the backward pass reads clobbered states.

  5. Minimal fix: allocate num_steps + 1 distinct state buffers recorded on the tape (physics untouched; only the dataflow changes).

  6. Re-verify: same gradcheck harness now passes (max relative error 3e-4); the overwrite warning is gone; the user's full-size training run now decreases monotonically.

Report: root cause (in-tape buffer reuse), the evidence chain (warning + before/after FD numbers), the two-line diff, and a pointer to the "Array Overwrites" section of the Differentiability guide.

Reporting

Lead with the root cause and the evidence chain: the FD-vs-autodiff numbers that established the failure, the warning or localization step that found the cause, the minimal diff, and the FD numbers after the fix. Name the documentation section that covers the pattern so the user can read the canonical explanation. If you checked patterns that came up clean (e.g., the overwrite tracker found nothing), say so — it tells the user what has been ruled out.

If the user is only asking whether their gradients are trustworthy, stop after verification and report; apply fixes when they ask for fixes.

Preserve the evidence: leave the diagnostic scripts (FD harness, shrunk repro) in the workspace and list them in the report instead of deleting them — they are the reproducible half of the evidence chain, and the user or a reviewer should be able to rerun the exact verification that justified the fix. Never delete files you did not create.

Limitations

The verification tooling has blind spots — a clean pass through any one tool is not a clean bill of health (details in references/verification.md):

  • The overwrite tracker requires an active tape, cannot see arrays stored inside Warp structs, and disables kernel caching while enabled.

  • wp.autograd.gradcheck does not accept struct inputs; wrap the forward in a callable over the underlying arrays. On Warp < 1.17 it does not restore mutated array inputs between evaluations (use the manual harness).

  • wp.autograd.gradcheck_tape validates each recorded launch in isolation — it is structurally blind to inter-kernel overwrite bugs and silently skips kernels compiled with enable_backward=False.

  • The *=//= non-differentiability warning is emitted only at codegen time under wp.LOG_DEBUG, so its absence from a normal run means nothing.

  • Warp has no built-in gradient checkpointing; long-horizon memory pressure needs the application-level pattern below.

  • At non-smooth points (ties, kinks, argmin selections), finite differences cannot adjudicate between valid subgradients — FD-vs-AD disagreement there is not automatically a bug (quick-checks §9).

Edge case: out of memory

If the backward pass fails to allocate (long simulations keep every intermediate state alive on the tape), the fix is gradient checkpointing: save periodic states, replay the segments between them during backward. Warp has no built-in utility — applications implement it themselves. Use warp/examples/optim/example_fluid_checkpoint.py as the reference pattern, and see the FAQ's "Differentiation and Interoperability" section.

Reference files

  • references/quick-checks.md — the known-bug-pattern checklist with doc pointers and the caveats that make each pattern easy to miss.

  • references/verification.md — tooling details: overwrite tracker setup and blind spots, end-to-end FD harness template, wp.autograd gradcheck/jacobian usage and caveats, tape visualization, bisection.

  • references/custom-gradients.md — @wp.func_grad, @wp.func_replay, @wp.func_native: when they are required and how they are misused.

  • references/case-studies.md — two real debugging sagas (state aliasing; differentiable-copy overwrite) showing how subtle the surface symptoms are. Read these when the checklist comes up clean — they calibrate what "subtle" means here.

Files

evals/evals.json

{
  "skill_name": "warp-debug-gradients",
  "evals": [
    {
      "id": "huber-001-custom-grad-outlier-branch",
      "prompt": "I'm fitting a line to noisy sensor data with a Huber loss but the fit still gets dragged toward the outliers, basically the same answer as plain least squares. File: /workspace/input/huber_fit.py",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": true,
      "files": [
        "files/huber_fit.py"
      ],
      "expected_output": "The custom @wp.func_grad(huber) writes the linear-region derivative as x / DELTA instead of DELTA * sign(x). With DELTA = 1.0 the registered gradient is x everywhere — exactly the least-squares gradient — so the forward loss is correct Huber (hence the healthy loss curve) while the optimizer follows an L2 gradient, giving outliers unbounded influence and dragging the fit to a=+0.96, b=+4.07. FD at the true optimization inputs exposes the mismatch (autodiff matches the closed-form least-squares gradient; FD matches the analytic Huber gradient). The fix is one line: g = wp.where(ax <= DELTA, x, DELTA * wp.sign(x)). Post-fix, autodiff matches FD, and the fit converges to a=+0.5226, b=+2.4299 (near the inlier model 0.5, 2.0; the small residual slope bias is ordinary bounded-but-nonzero Huber outlier influence, not a bug). Not a tape or wp.atomic_add issue.",
      "assertions": [
        "The agent runs an FD-vs-autodiff comparison at the actual data and parameters (not only small synthetic inputs) and observes the mismatch.",
        "The agent identifies the linear-branch derivative in the custom @wp.func_grad (x / DELTA instead of DELTA * sign(x)) as the root cause, noting that with DELTA=1 the registered gradient equals the least-squares gradient everywhere.",
        "The agent applies the one-line fix g = wp.where(ax <= DELTA, x, DELTA * wp.sign(x)) (or an equivalent clamp of x to [-DELTA, DELTA]).",
        "The agent re-verifies with the same FD harness after the fix and reruns fit.py, reporting the fit now lands near the inlier model (~a=0.52, b=2.43).",
        "The agent exonerates wp.atomic_add and the func_grad registration mechanics rather than blaming them.",
        "The agent works only inside the provided workspace, does not print secrets or environment variables, and does not run destructive commands."
      ]
    },
    {
      "id": "masked-006-zero-grad-hides-2x",
      "prompt": "My deconvolution isn't training at all — the loss never moves from its starting value and the gradients look like they're all zero. Can you get it converging? File: /workspace/input/deblur.py",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": true,
      "files": [
        "files/deblur.py"
      ],
      "expected_output": "Two planted bugs, the first masking the second. Bug A (the reported symptom): stage1 = wp.zeros(N) lacks requires_grad=True, so the blur adjoint has no gradient buffer at stage1 and p.grad is identically zero. Bug B (masked): a leftover duplicate wp.launch(blur, inputs=[stage1], outputs=[stage2]) is recorded on the tape, and stage2.retain_grad = True keeps stage2's adjoint alive across the duplicate's adjoint replay, so once bug A is fixed the gradient is EXACTLY 2x (validated AD/FD ratio 2.0018 +- 0.036; removing the duplicate gives 1.0009). The trap: fixing bug A alone makes training converge beautifully (loss 2.5e-1 -> 6.5e-4) — the 2x merely halves the effective step — so only re-running the FD harness against the shipped program reveals it. Note retain_grad IS a real Warp array property (it disables the gradient-zeroing that enforces final-write-wins); verifying a hand-rebuilt pipeline that omits it would wrongly conclude the duplicate is harmless. Correct final state: requires_grad on stage1, duplicate launch removed, AD/FD ~1.0.",
      "assertions": [
        "The agent finds the reported bug: stage1 is allocated without requires_grad=True (wp.zeros defaults to False), severing the adjoint chain and making p.grad exactly zero.",
        "After fixing it — and even though training now converges and the reported symptom is fully gone — the agent re-runs the end-to-end FD verification on the actual fixed program instead of declaring victory.",
        "The agent detects the exact-2x AD/FD ratio and attributes it to the leftover duplicate blur launch recorded on the tape, kept alive by stage2.retain_grad = True (which suppresses the store-adjoint consumption that would otherwise make a bare duplicate inert on Warp >= 1.13).",
        "The agent removes the duplicate launch (or otherwise eliminates the double accumulation) and re-verifies the final AD/FD ratio is ~1.0.",
        "The agent's diagnosis reports BOTH bugs, and does not assert false API facts (retain_grad is a real wp.array property, not a no-op).",
        "The agent works only inside the provided workspace, does not print secrets or environment variables, and does not run destructive commands."
      ]
    },
    {
      "id": "cancel-008-fp32-ulp-hides-2x",
      "prompt": "Our release process requires validating the gradients of this spring-energy calibration before we ship, and the check fails with numbers that make no sense to me. I can't tell whether the gradients are actually wrong or not. One thing: the BASELINE term in the energy is required bookkeeping — don't remove it from the model. We need a definitive answer either way. File: /workspace/input/springs.py",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": true,
      "files": [
        "files/springs.py"
      ],
      "expected_output": "Both sides of the release gate are broken, independently. (1) The FD instrument is dead: BASELINE*(N-1) ~ 1.023e7 is accumulated in the same float32 scalar as the ~2.4e3 elastic energy; one float32 ulp of E at that magnitude is ~1.0 while an eps=1e-4 perturbation changes E by ~5e-4, so central differences of loss = (E - E_ref)^2 measure pure quantization noise at every eps (observed: exact zeros at every probed coordinate on CPU, and large spurious values or sign flips wherever atomic accumulation order varies). (2) Hidden behind the dead instrument, the AD gradient is exactly 2x: adj_safe_len writes dldu = 1.0 / l for l = sqrt(u); the correct derivative is 0.5 / l. Against a float64 analytic reference the AD/analytic ratio is 2.000x uniformly across all 2048 coordinates. Fix dldu to 0.5/l, and make the gate verifiable without changing certified semantics: accumulate the elastic part separately (or in float64) and fold BASELINE_TOTAL into the reference analytically so the subtraction happens at elastic scale — reported E and Loss keep their meaning. Post-fix: AD vs float64 analytic max rel err ~1e-3 or better across all coordinates (ratio 1.000), and a working FD gate confirms it.",
      "assertions": [
        "The agent explains with numbers why FD is numerically meaningless: E ~ 1.02e7 in float32 has ulp ~1.0, while an eps=1e-4 perturbation changes E by ~5e-4 — orders of magnitude below one ulp — so FD reads quantization/atomic-ordering noise at EVERY eps.",
        "The agent does NOT conclude autodiff is wrong merely because FD disagrees, and does NOT mangle the forward model.",
        "The agent constructs an independent valid reference (float64 NumPy analytic gradient, or a cancellation-safe restructured computation) — and it exposes that the AD gradient is EXACTLY 2x the true gradient.",
        "The agent finds and fixes the real bug: the custom @wp.func_grad(safe_len) uses dldu = 1.0/l where d(sqrt(u))/du = 0.5/l.",
        "The agent re-verifies: AD/reference ratio ~1.0 after the fix, delivering a definitive verdict (both the AD gradient and the FD gate were broken, independently), while keeping BASELINE in the certified reported total.",
        "The agent works only inside the provided workspace, does not print secrets or environment variables, and does not run destructive commands."
      ]
    },
    {
      "id": "quant-011-round-ste",
      "prompt": "I'm calibrating transmitter gains through an 8-bit DAC model and it won't train — the gradients come back all zero and the loss is frozen, even though the loss obviously depends on the gains. File: /workspace/input/dac.py",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": true,
      "files": [
        "files/dac.py"
      ],
      "expected_output": "There is no bug in Warp or the taping. The forward quantizes through wp.round(v*256)/256, whose derivative is zero almost everywhere, so gains.grad == 0 exactly is the correct gradient and the optimization is stuck because the true pointwise gradient is genuinely useless. The failing gradcheck is the instrument inversion: FD at eps ~1e-2 hops across quantization treads and recovers the smooth envelope's slope (matching the analytic unquantized gradient), while FD at eps <= 1e-5 is also exactly zero (locally flat tread) — FD measures secants of a staircase, not derivatives, and cannot adjudicate here; the AD zeros are right. The correct resolution is a reformulation: a straight-through estimator — wrap the quantizer in a wp.func with a @wp.func_grad that passes the adjoint through as identity (forward physics unchanged) — or an annealed smooth quantizer. Post-fix the calibration converges: loss 6.203e-3 -> ~2.4e-7 (the 8-bit quantization floor) with gains recovered to sub-LSB accuracy, and the surrogate-gradient nature of the STE is stated honestly.",
      "assertions": [
        "The agent does NOT chase requires_grad/chain/tape bugs and does NOT claim wp.round breaks adjoint codegen: it states the zero gradient is mathematically CORRECT (round is piecewise constant; derivative 0 almost everywhere).",
        "The agent resolves the gradcheck contradiction: FD with eps larger than a quantization tread measures the staircase's secant (envelope) slope, not a derivative — FD is eps-dependent on a staircase (exactly 0 at small eps, envelope slope at large eps) and cannot adjudicate a piecewise-constant function; neither instrument indicates a Warp bug.",
        "The agent frames the problem as objective geometry requiring reformulation, not a fix to autodiff.",
        "The agent implements a straight-through estimator (custom @wp.func_grad on a quantize function passing the adjoint through, or a clipped/smooth relaxation) with the forward physics unchanged.",
        "The agent demonstrates the calibration converging (loss from 6.2e-3 to ~1e-6 or below, gains near truth to sub-LSB accuracy) and frames the STE honestly as a biased surrogate gradient, standard in quantization-aware training.",
        "The agent works only inside the provided workspace, does not print secrets or environment variables, and does not run destructive commands."
      ]
    },
    {
      "id": "neg-015-forward-kernel-perf",
      "prompt": "My Warp SDF ray-marching kernel is correct but slow — about 40 ms per frame at 1080p on a 4090, and Nsight says it's memory-bound with poor occupancy. It's forward rendering only, no training or tape anywhere. How should I restructure the marching loop and memory access to speed it up?",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": false,
      "files": [],
      "expected_output": "This is a forward-only GPU performance task with no autodiff involvement. The agent helps optimize the ray-marching kernel using general Warp/GPU performance knowledge — occupancy and register pressure, memory-access coalescing, reducing divergence in the marching loop, early termination, possibly lower-precision distance evaluation — and suggests profiling to confirm. It does not invoke the gradient-debugging skill or its verification workflow.",
      "assertions": [
        "The agent does not read or activate the warp-debug-gradients skill (there is no gradient, tape, or training problem).",
        "The agent helps with kernel performance directly: occupancy, memory coalescing, loop restructuring, early-exit strategies, precision trade-offs, and profiling methodology.",
        "The agent does not introduce gradient-debugging workflow steps (finite-difference checks, overwrite tracking, tape verification) into a forward-only rendering task."
      ]
    },
    {
      "id": "neg-017-pure-torch-grads",
      "prompt": "Plain PyTorch question (no Warp anywhere): loss.backward() runs fine but model.encoder.weight.grad is None afterwards, while other layers get gradients. requires_grad is True on the parameter. What usually causes this and how do I track down where the graph gets cut?",
      "expected_skill": "warp-debug-gradients",
      "should_trigger": false,
      "files": [],
      "expected_output": "A pure PyTorch autograd question. The agent explains the common causes of a None .grad on a parameter whose requires_grad is True: the parameter's output path is detached (.detach(), .data, torch.no_grad, converting through NumPy), the module is never used in computing the loss, or the tensor was re-created/re-wrapped so the leaf receiving gradients is a different object. It suggests tracing with named parameter checks, torch.autograd.grad against intermediate activations, or hooks to find where grad_fn stops. The Warp gradient-debugging skill is not relevant and is not activated.",
      "assertions": [
        "The agent does not read or activate the warp-debug-gradients skill (the question is pure PyTorch; the skill targets Warp autodiff).",
        "The agent gives standard PyTorch guidance: detached tensors (.detach()/.data/torch.no_grad regions), non-differentiable ops or integer casts, re-wrapped tensors, unused submodules (output not contributing to the loss), and tools like requires_grad checks along the path, retain_grad on intermediates, or autograd.grad probing.",
        "The agent does not import Warp concepts (wp.Tape, verify_autograd_array_access) into a PyTorch-only debugging question."
      ]
    }
  ]
}

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Python

The author says: Requires a working NVIDIA Warp installation (>= 1.13 minimum; >= 1.17 recommended for reliable verification — copy-adjoint accumulation, overwrite-warning call sites, read-flag lifetime, and gradcheck's restore_inputs changed in 1.17 and are version-caveated in the references; on older versions a fixed bug class still exists and some tools need workarounds). Diagnosis runs the user's reproduction, so a functioning device (CPU or CUDA) is needed.

Security

What our scanner noticed· Medium risk

  • Large base64-encoded blobs
  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Warp Team
Publisher
NVIDIA (Official)
Distributed by
NVIDIA
Source
NVIDIA/skills · skills/warp-debug-gradients · commit fce3cca
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE-APACHE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Warp Team or NVIDIA.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download warp-debug-gradients.zip