Skip to content

Add FFT causal conv1d frontend bindings - #437

Open
yeliu-oss wants to merge 3 commits into
NVIDIA:developfrom
yeliu-oss:yeliu/fft-causal-conv1d
Open

Add FFT causal conv1d frontend bindings#437
yeliu-oss wants to merge 3 commits into
NVIDIA:developfrom
yeliu-oss:yeliu/fft-causal-conv1d

Conversation

@yeliu-oss

@yeliu-oss yeliu-oss commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Before submitting

  • I agree to license this contribution under the terms of LICENSE.txt.
  • I ran pre-commit run and committed any formatting changes.

Affected area

  • Python API or bindings

Summary

  • Add dynamically loaded pybind shims for medium and long FFT causal conv1d backend APIs, including the long-path workspace/reserve-space size query.
  • Add cudnn.ops.fft_causal_conv1d(x, weight), following cuhyena's medium/long selection, padding, trimming, dtype support, and autograd behavior.
  • Preserve long-forward reserve space for the matching backward call.
  • Add C++ medium/long API samples, executed forward/backward notebooks, operation documentation, and focused Python tests.

Why

cuDNN 9.26 adds backend FFT causal conv1d kernels for filters beyond the efficient range of the existing direct causal conv1d kernels. This change makes those APIs usable from cuDNN Frontend while retaining the upstream cuhyena Python signature and selection policy.

Related issues

Depends on the FFT causal conv1d backend APIs targeted for cuDNN 9.26.

API and compatibility impact

Adds the public Python API:

y = cudnn.ops.fft_causal_conv1d(x, weight)

It also exposes the low-level long-path buffer query:

workspace_size, reserve_size = cudnn.long_fft_causal_conv1d_get_buffer_sizes(
    batch, dim, seq_len, kernel_size, data_type
)
  • Requires cuDNN 9.26.0 or newer at compile time and runtime.
  • Supports FP16, BF16, FP32, and FP64 CUDA tensors.
  • Supports PyTorch autograd, torch.compile, and warmed-up CUDA Graph capture.
  • Medium FFT right-pads the filter to a compatible power of two and the input to a filter-length multiple. Long FFT pads both to one common power-of-two length. Outputs and gradients are trimmed to the caller's original shapes.
  • The medium path does not require opaque workspace or reserve-space buffers.
  • For long FFT, forward queries the backend sizes and allocates temporary workspace plus reserve space. Autograd retains the reserve space containing transformed input/filter state. Backward re-queries the sizes, allocates fresh temporary workspace, and consumes the retained reserve space.
  • Uses cuhyena's FIR weight convention, where weight[0] multiplies the current sample. This is reversed relative to the existing direct causal conv1d wrapper.
  • Builds against older cuDNN headers remain supported because all new bindings and samples are compile-time guarded; older runtimes return CUDNN_STATUS_NOT_SUPPORTED.

Testing

  • pre-commit run --files <all changed files>: passed (clang-format, black, black-jupyter).
  • Python bindings configured and built against the local cuDNN 9.26 debug backend: passed.
  • python -m pytest -v -m 'L1 or L2' test/python/test_fft_causal_conv1d.py: 7 passed.
  • cmake --build /tmp/cudnn-frontend-fft-cpp-build -j16 --target samples: passed.
  • samples '[fft_causal_conv1d]': 2 passed (medium forward/backward and long forward/backward).
  • Executed and persisted outputs in 66_fft_causal_conv1d_forward.ipynb and 67_fft_causal_conv1d_backward.ipynb: passed for padded medium and genuine long paths.
  • Manually verified compiled autograd and warmed-up CUDA Graph capture/replay for both medium and long paths.

Summary by CodeRabbit

  • New Features
    • Added FFT-based causal 1D convolution (fft_causal_conv1d) with medium/long-kernel forward and backward support.
    • Extended existing causal 1D convolution variants to support FP64, with improved dtype handling for gradient computation.
    • Supports autograd and torch.compile.
  • Documentation
    • Added full operation reference and examples for fft_causal_conv1d.
    • Updated causal conv1d docs to reflect FP64 support and accumulation behavior.
  • Tests
    • Added correctness, buffer/long-path validation, and compilation tests for fft_causal_conv1d.
    • Added broader causal conv1d test coverage across dtypes/layouts, including compiled autograd.

@yeliu-oss
yeliu-oss requested a review from Anerudhan July 24, 2026 20:54
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b9b0876a-9ecd-4bfc-93a8-ef0611d8e02e

📥 Commits

Reviewing files that changed from the base of the PR and between 4b7f0a4 and 62a7c78.

📒 Files selected for processing (4)
  • docs/operations/CausalConv1d.md
  • docs/operations/FFTCausalConv1d.md
  • test/python/test_causal_conv1d.py
  • test/python/test_fft_causal_conv1d.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/operations/CausalConv1d.md
  • test/python/test_fft_causal_conv1d.py
  • docs/operations/FFTCausalConv1d.md
  • test/python/test_causal_conv1d.py

📝 Walkthrough

Walkthrough

Adds cudnn.ops.fft_causal_conv1d with medium and long FFT paths, cuDNN 9.26.0+ bindings, autograd and torch.compile support, validation, samples, and documentation. Existing causal convolution variants also gain FP64 support and dtype-dependent gradient accumulation.

Changes

FFT Causal Conv1d

Layer / File(s) Summary
Backend bindings and exports
include/cudnn_frontend_shim.h, python/pycudnn.cpp, python/cudnn/__init__.py, python/cudnn/ops/__init__.py
Adds version-gated backend shims, pybind functions, optional symbol imports, and the package-level operation export.
Python FFT operation
python/cudnn/ops/fft_causal_conv1d.py
Implements validation, medium and long FFT custom CUDA operations, reserve-space handling, autograd wiring, path selection, padding, and output trimming.
Validation and usage coverage
samples/cpp/..., samples/python/66_fft_causal_conv1d_forward.ipynb, samples/python/67_fft_causal_conv1d_backward.ipynb, test/python/test_fft_causal_conv1d.py
Adds C++ tests, forward and backward notebooks, numerical comparisons, dtype coverage, compilation coverage, and buffer-size validation.
API documentation
docs/operations/FFTCausalConv1d.md, llms.txt
Documents the operation contract, constraints, buffer lifetimes, usage example, and reference index entry.

Causal Conv1d FP64 support

Layer / File(s) Summary
FP64 dtype and gradient accumulation
python/cudnn/ops/causal_conv1d.py, docs/operations/CausalConv1d.md, test/python/test_causal_conv1d.py
Adds FP64 mappings and documentation, selects dtype-dependent gradient accumulation, and validates standard, NWH, and B2B variants with forward, backward, and compiled-autograd tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant fft_causal_conv1d
  participant CustomCUDAOp
  participant cuDNNBackend
  Caller->>fft_causal_conv1d: Provide x and weight
  fft_causal_conv1d->>CustomCUDAOp: Select medium or long path
  CustomCUDAOp->>cuDNNBackend: Run FFT causal convolution
  cuDNNBackend-->>CustomCUDAOp: Return output and reserve state
  CustomCUDAOp-->>Caller: Return trimmed output
Loading

Suggested labels: mod-frontend

Suggested reviewers: anerudhan

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding FFT causal conv1d frontend bindings.
Description check ✅ Passed The description matches the template and covers area, summary, why, compatibility, and testing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/operations/FFTCausalConv1d.md`:
- Around line 15-25: Correct the operation equation in the FFTCausalConv1d
documentation to include batch and channel indices, indexing weights as
weight[c, j] for tensor shape (dim, kernel_size). State the elementwise contract
for y[b, c, t] and explicitly define x[b, c, t - j] as zero when the index is
out of range.

In `@python/cudnn/ops/fft_causal_conv1d.py`:
- Around line 305-310: Update _long_autograd_bwd to accept both gradient
arguments produced by _long_fwd_primitive, including the gradient for
reserve_space, while continuing to use the output gradient for the backward
primitive. Preserve the existing returned gradients for x and weight.

In `@samples/cpp/causal_conv1d/fft_causal_conv1d.cpp`:
- Around line 75-97: Add numerical verification after execution in the sample’s
forward and backward paths, covering y_tensor, dx_tensor, and dweight_tensor
against a causal-convolution reference with dtype-appropriate tolerances. Keep
the existing CUDNN_CHECK calls and synchronization, and apply the same
execute-then-verify sequence to the code around the additional indicated
section.

In `@test/python/test_fft_causal_conv1d.py`:
- Around line 11-13: Update _require_fft_causal_conv1d to also verify that
cudnn.long_fft_causal_conv1d_get_buffer_sizes exists, and skip when either
required FFT symbol is unavailable while retaining the existing backend-version
check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 63d73f12-c0d5-4b9f-ae72-a27e92cb6362

📥 Commits

Reviewing files that changed from the base of the PR and between d2d0d02 and 6923b14.

📒 Files selected for processing (12)
  • docs/operations/FFTCausalConv1d.md
  • include/cudnn_frontend_shim.h
  • llms.txt
  • python/cudnn/__init__.py
  • python/cudnn/ops/__init__.py
  • python/cudnn/ops/fft_causal_conv1d.py
  • python/pycudnn.cpp
  • samples/cpp/CMakeLists.txt
  • samples/cpp/causal_conv1d/fft_causal_conv1d.cpp
  • samples/python/66_fft_causal_conv1d_forward.ipynb
  • samples/python/67_fft_causal_conv1d_backward.ipynb
  • test/python/test_fft_causal_conv1d.py

Comment thread docs/operations/FFTCausalConv1d.md
Comment on lines +305 to +310
@torch.compiler.allow_in_graph
def _long_autograd_bwd(ctx, grad_out):
x, weight, reserve_space = ctx.saved_tensors
grad_y = grad_out[0]
grad_x, grad_weight = torch.ops.cudnn.long_fft_causal_conv1d_bwd_primitive(grad_y, x, weight, reserve_space)
return grad_x, grad_weight

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant sections and nearby tests/helpers.
sed -n '220,330p' python/cudnn/ops/fft_causal_conv1d.py
printf '\n--- tests ---\n'
sed -n '1,260p' test/python/test_fft_causal_conv1d.py

Repository: NVIDIA/cudnn-frontend

Length of output: 8202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the exact autograd registration signature semantics from installed PyTorch docs if available,
# and probe the long-path backward call shape with a small standalone Python snippet.
python3 - <<'PY'
import inspect
import torch

print("torch version:", torch.__version__)
print("register_autograd:", inspect.signature(torch.library.register_autograd))
print("autograd.Function.backward docs available:", hasattr(torch.autograd.Function, 'backward'))
PY

Repository: NVIDIA/cudnn-frontend

Length of output: 277


🌐 Web query:

PyTorch torch.library.register_autograd backward signature number of gradients matches number of outputs official docs

💡 Result:

Yes, the official PyTorch documentation explicitly states that the number of gradients passed to the backward function matches the number of outputs of the operator [1][2][3]. When registering a backward formula using torch.library.register_autograd, the backward function accepts the signature (ctx, *grads) [1][2][3]. In this signature, the grads parameter represents one or more gradients, and the number of these gradients corresponds exactly to the number of outputs produced by the operator [1][2][3]. The semantics of this backward_fn are consistent with those of torch.autograd.Function.backward() [1][2][3].

Citations:


_long_autograd_bwd must accept the second output grad.

_long_fwd_primitive returns y and reserve_space, so the registered backward receives two grad args. The current (ctx, grad_out) signature will fail on the long FFT path.

🐛 Proposed fix
 `@torch.compiler.allow_in_graph`
-def _long_autograd_bwd(ctx, grad_out):
+def _long_autograd_bwd(ctx, grad_y, _grad_reserve_space):
     x, weight, reserve_space = ctx.saved_tensors
-    grad_y = grad_out[0]
     grad_x, grad_weight = torch.ops.cudnn.long_fft_causal_conv1d_bwd_primitive(grad_y, x, weight, reserve_space)
     return grad_x, grad_weight
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@torch.compiler.allow_in_graph
def _long_autograd_bwd(ctx, grad_out):
x, weight, reserve_space = ctx.saved_tensors
grad_y = grad_out[0]
grad_x, grad_weight = torch.ops.cudnn.long_fft_causal_conv1d_bwd_primitive(grad_y, x, weight, reserve_space)
return grad_x, grad_weight
`@torch.compiler.allow_in_graph`
def _long_autograd_bwd(ctx, grad_y, _grad_reserve_space):
x, weight, reserve_space = ctx.saved_tensors
grad_x, grad_weight = torch.ops.cudnn.long_fft_causal_conv1d_bwd_primitive(grad_y, x, weight, reserve_space)
return grad_x, grad_weight
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cudnn/ops/fft_causal_conv1d.py` around lines 305 - 310, Update
_long_autograd_bwd to accept both gradient arguments produced by
_long_fwd_primitive, including the gradient for reserve_space, while continuing
to use the output gradient for the backward primitive. Preserve the existing
returned gradients for x and weight.

Comment on lines +75 to +97
CUDNN_CHECK(cudnnFFTCausalConv1dForward(stream,
x_tensor.devPtr,
weight_tensor.devPtr,
y_tensor.devPtr,
batch,
dim,
seq_len,
kernel_size,
CUDNN_DATA_HALF));

CUDNN_CHECK(cudnnFFTCausalConv1dBackward(stream,
x_tensor.devPtr,
weight_tensor.devPtr,
dy_tensor.devPtr,
dx_tensor.devPtr,
dweight_tensor.devPtr,
batch,
dim,
seq_len,
kernel_size,
CUDNN_DATA_HALF));

CUDA_CHECK(cudaDeviceSynchronize());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Verify numerical results for both paths.

CUDNN_CHECK and synchronization only prove the calls completed. Compare y_tensor, dx_tensor, and dweight_tensor against a causal-convolution reference with dtype-appropriate tolerances; otherwise layout, weight-order, and gradient regressions pass this sample silently.

As per coding guidelines, “C++ samples should follow the sequence: … execute, then verify results.”

Also applies to: 130-160

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@samples/cpp/causal_conv1d/fft_causal_conv1d.cpp` around lines 75 - 97, Add
numerical verification after execution in the sample’s forward and backward
paths, covering y_tensor, dx_tensor, and dweight_tensor against a
causal-convolution reference with dtype-appropriate tolerances. Keep the
existing CUDNN_CHECK calls and synchronization, and apply the same
execute-then-verify sequence to the code around the additional indicated
section.

Source: Coding guidelines

Comment thread test/python/test_fft_causal_conv1d.py
@Anerudhan

Copy link
Copy Markdown
Collaborator
  • How long are the added tests?
  • Can we mark them L0, so they are run nightly ?

@Anerudhan

Copy link
Copy Markdown
Collaborator

@yeliu-oss for ^^^

@Anerudhan Anerudhan added mod-backend cuDNN backend API, graph execution, descriptors, engines, or backend integration. orig-nv-eng Reported or requested by NVIDIA engineering. cat-enhancements labels Jul 28, 2026
@Anerudhan Anerudhan added this to the Frontend 1.27.0 milestone Jul 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/python/test_causal_conv1d.py`:
- Around line 30-33: Update _require_variant to query
torch.cuda.get_device_capability() and skip the causal-conv1d cases when the
device is below SM100, in addition to the existing cuDNN version and symbol
checks. Keep the current version requirement and skip message behavior intact
for other unsupported configurations.
- Around line 9-13: Update the torch.float64 entry in _TOLERANCES to use the
tighter FP64 tolerance established by related causal-conv tests, while leaving
the float32, float16, and bfloat16 tolerances unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b9b13106-e4fa-4481-8277-69bf7465dc28

📥 Commits

Reviewing files that changed from the base of the PR and between 6923b14 and 4b7f0a4.

📒 Files selected for processing (4)
  • docs/operations/CausalConv1d.md
  • python/cudnn/ops/causal_conv1d.py
  • test/python/test_causal_conv1d.py
  • test/python/test_fft_causal_conv1d.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/python/test_fft_causal_conv1d.py

Comment thread test/python/test_causal_conv1d.py
Comment on lines +30 to +33
def _require_variant(required_symbols, dtype, minimum_version):
required_version = max(minimum_version, 92600 if dtype == torch.float64 else 0)
if cudnn.backend_version() < required_version or any(not hasattr(cudnn, name) for name in required_symbols):
pytest.skip(f"SE causal conv1d case requires cuDNN {required_version // 10000}.{required_version // 100 % 100}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files test/python/test_causal_conv1d.py test/AGENTS.md
printf '\n--- outline ---\n'
ast-grep outline test/python/test_causal_conv1d.py --view expanded

printf '\n--- file excerpt ---\n'
cat -n test/python/test_causal_conv1d.py | sed -n '1,220p'

printf '\n--- capability search ---\n'
rg -n "get_device_capability|SM100|sm100|cudnn.backend_version|_require_variant|causal_conv1d" test/python -S

Repository: NVIDIA/cudnn-frontend

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- causal conv1d references ---\n'
rg -n "causal_conv1d|b2b_causal_conv1d|fft_causal_conv1d" -S . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

printf '\n--- Blackwell/SM100 helper patterns in nearby tests ---\n'
sed -n '1,120p' test/python/test_sm100_prefill_oss_engine.py
printf '\n---\n'
sed -n '1,120p' test/python/test_sm100_rms_norm_silu_graph_api.py
printf '\n---\n'
sed -n '1,220p' test/python/test_cudnn_sdpa_op.py

Repository: NVIDIA/cudnn-frontend

Length of output: 48222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- python/cudnn/ops/causal_conv1d.py excerpt ---\n'
cat -n python/cudnn/ops/causal_conv1d.py | sed -n '1,260p'

printf '\n--- docs/operations/CausalConv1d.md excerpt ---\n'
cat -n docs/operations/CausalConv1d.md | sed -n '1,220p'

printf '\n--- test/python/test_fft_causal_conv1d.py excerpt ---\n'
cat -n test/python/test_fft_causal_conv1d.py | sed -n '1,180p'

Repository: NVIDIA/cudnn-frontend

Length of output: 20391


Gate causal-conv1d tests on SM100+. _require_variant() only checks backend version and symbol presence; these cases are documented as Blackwell-only, so add a torch.cuda.get_device_capability() guard before running them to avoid hitting unsupported kernels on older GPUs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/python/test_causal_conv1d.py` around lines 30 - 33, Update
_require_variant to query torch.cuda.get_device_capability() and skip the
causal-conv1d cases when the device is below SM100, in addition to the existing
cuDNN version and symbol checks. Keep the current version requirement and skip
message behavior intact for other unsupported configurations.

Source: Coding guidelines

@yeliu-oss

Copy link
Copy Markdown
Collaborator Author
  • How long are the added tests?
  • Can we mark them L0, so they are run nightly ?

FFT causal conv1d python tests took ~1.5 mins, the non-fft causal conv1d python tests took ~3.5 mins. I marked them L0 in the latest commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cat-enhancements mod-backend cuDNN backend API, graph execution, descriptors, engines, or backend integration. orig-nv-eng Reported or requested by NVIDIA engineering.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants