Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions docs/operations/CausalConv1d.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Supports forward and backward passes with `torch.autograd` and `torch.compile`.

## Support

- **Architectures**: Blackwell (SM100+)
- **Data types**: FP32, FP16, BF16
- **Architectures**: Turing (SM75) and newer, subject to available dynamic shared memory
- **Data types**: FP64, FP32, FP16, BF16
- **Activations**: `identity`, `silu`

## Python API
Expand Down Expand Up @@ -54,7 +54,7 @@ In most cases you should use `cudnn.ops.causal_conv1d` instead, which handles au

| Tensor | Device | Data Type | Shape |
|--------|--------|-----------|-------|
| x | GPU | FP32, FP16, or BF16 | $(B, D, L)$ |
| x | GPU | FP64, FP32, FP16, or BF16 | $(B, D, L)$ |
| weight | GPU | same as x | $(D, K)$ |
| bias | GPU | same as x | $(D,)$ |

Expand All @@ -78,6 +78,10 @@ In most cases you should use `cudnn.ops.causal_conv1d` instead, which handles au
| dweight | GPU | same as x | $(D, K)$ |
| dbias | GPU | same as x | $(D,)$ |

The backend accumulation buffers for `dweight` and `dbias` are FP32 for
FP16, BF16, and FP32 inputs, and FP64 for FP64 inputs. The Python autograd
results are returned in the corresponding input tensor dtype.

## Example

```python
Expand Down
71 changes: 71 additions & 0 deletions docs/operations/FFTCausalConv1d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# FFT Causal Conv1d

The cuDNN Frontend Python API exposes FFT-based depthwise causal convolution
through:

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

This API requires cuDNN 9.26.0 or newer. It supports FP16, BF16, FP32, and FP64
CUDA tensors, `torch.autograd`, and `torch.compile`.

## Operation

For `x` shaped `(batch, dim, seq_len)` and `weight` shaped
`(dim, kernel_size)`, the operation computes:

```text
y[b, c, t] = sum(x[b, c, t - j] * weight[c, j], j=0..kernel_size-1)
```

Here, `x[b, c, t - j]` is zero when `t - j` is outside the input sequence.
This is FIR-order weight storage:
`weight[0]` multiplies the current sample. It is reversed relative to
`cudnn.ops.causal_conv1d`, whose first stored weight multiplies the oldest
sample in the causal window.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Path Selection

The convenience wrapper follows cuhyena's Python API:

- It rounds `kernel_size` up to a power of two, with a minimum of 128.
- It selects the medium FFT path when the filter fits that path's dtype and
device limit.
- It right-pads the input to a multiple of the medium filter length.
- Otherwise it right-pads input and filter to one common power-of-two length
and selects the long FFT path.
- It trims the output and autograd gradients back to the caller's shapes.

The medium path supports FP64 filters through 4096. Other dtypes support
filters through 8192 before SM90 and through 16384 on SM90 or newer.

The raw long backend path requires power-of-two `seq_len == kernel_size` in
`[4096, 16777216]`. FP64 supports lengths through 8388608; length 16777216 for
other dtypes requires SM90 or newer.

## Long FFT Buffers

Long FFT forward queries and allocates two opaque byte buffers:

- Workspace is temporary scratch for the current forward or backward call.
- Reserve space stores transformed signal and filter state from forward and is
retained by the autograd context for the matching backward call.

Applications calling the C APIs directly must preserve this same reserve-space
lifetime. See
`samples/cpp/causal_conv1d/fft_causal_conv1d.cpp` for medium and long C API
examples.

## Example

```python
import cudnn
import torch

x = torch.randn(2, 16, 4096, device="cuda", requires_grad=True)
weight = torch.randn(16, 256, device="cuda", requires_grad=True)

y = cudnn.ops.fft_causal_conv1d(x, weight)
y.sum().backward()
```
153 changes: 153 additions & 0 deletions include/cudnn_frontend_shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,159 @@ b2b_causal_conv1d_backward(cudaStream_t stream,
}
#endif

#if CUDNN_VERSION >= 92600
inline cudnnStatus_t
fft_causal_conv1d_forward(cudaStream_t stream,
const void *x,
const void *weight,
void *y,
int batch,
int dim,
int seq_len,
int kernel_size,
cudnnDataType_t data_type) {
auto effective_cudnn_ver = std::min(detail::get_compiled_version(), detail::get_backend_version());
if (effective_cudnn_ver < 92600) {
return CUDNN_STATUS_NOT_SUPPORTED;
}
NV_FE_CALL_TO_BACKEND(fft_causal_conv1d_forward,
cudnnFFTCausalConv1dForward,
stream,
x,
weight,
y,
batch,
dim,
seq_len,
kernel_size,
data_type);
}

inline cudnnStatus_t
fft_causal_conv1d_backward(cudaStream_t stream,
const void *x,
const void *weight,
const void *dy,
void *dx,
void *dweight,
int batch,
int dim,
int seq_len,
int kernel_size,
cudnnDataType_t data_type) {
auto effective_cudnn_ver = std::min(detail::get_compiled_version(), detail::get_backend_version());
if (effective_cudnn_ver < 92600) {
return CUDNN_STATUS_NOT_SUPPORTED;
}
NV_FE_CALL_TO_BACKEND(fft_causal_conv1d_backward,
cudnnFFTCausalConv1dBackward,
stream,
x,
weight,
dy,
dx,
dweight,
batch,
dim,
seq_len,
kernel_size,
data_type);
}

inline cudnnStatus_t
long_fft_causal_conv1d_get_buffer_sizes(int batch,
int dim,
int seq_len,
int kernel_size,
cudnnDataType_t data_type,
size_t *workspace_size_in_bytes,
size_t *reserve_space_size_in_bytes) {
auto effective_cudnn_ver = std::min(detail::get_compiled_version(), detail::get_backend_version());
if (effective_cudnn_ver < 92600) {
return CUDNN_STATUS_NOT_SUPPORTED;
}
NV_FE_CALL_TO_BACKEND(long_fft_causal_conv1d_get_buffer_sizes,
cudnnLongFFTCausalConv1dGetBufferSizes,
batch,
dim,
seq_len,
kernel_size,
data_type,
workspace_size_in_bytes,
reserve_space_size_in_bytes);
}

inline cudnnStatus_t
long_fft_causal_conv1d_forward(cudaStream_t stream,
const void *x,
const void *weight,
void *y,
int batch,
int dim,
int seq_len,
int kernel_size,
cudnnDataType_t data_type,
void *workspace,
size_t workspace_size_in_bytes,
void *reserve_space,
size_t reserve_space_size_in_bytes) {
auto effective_cudnn_ver = std::min(detail::get_compiled_version(), detail::get_backend_version());
if (effective_cudnn_ver < 92600) {
return CUDNN_STATUS_NOT_SUPPORTED;
}
NV_FE_CALL_TO_BACKEND(long_fft_causal_conv1d_forward,
cudnnLongFFTCausalConv1dForward,
stream,
x,
weight,
y,
batch,
dim,
seq_len,
kernel_size,
data_type,
workspace,
workspace_size_in_bytes,
reserve_space,
reserve_space_size_in_bytes);
}

inline cudnnStatus_t
long_fft_causal_conv1d_backward(cudaStream_t stream,
const void *dy,
void *dx,
void *dweight,
int batch,
int dim,
int seq_len,
int kernel_size,
cudnnDataType_t data_type,
void *workspace,
size_t workspace_size_in_bytes,
void *reserve_space,
size_t reserve_space_size_in_bytes) {
auto effective_cudnn_ver = std::min(detail::get_compiled_version(), detail::get_backend_version());
if (effective_cudnn_ver < 92600) {
return CUDNN_STATUS_NOT_SUPPORTED;
}
NV_FE_CALL_TO_BACKEND(long_fft_causal_conv1d_backward,
cudnnLongFFTCausalConv1dBackward,
stream,
dy,
dx,
dweight,
batch,
dim,
seq_len,
kernel_size,
data_type,
workspace,
workspace_size_in_bytes,
reserve_space,
reserve_space_size_in_bytes);
}
#endif

inline std::string
convert_version_to_str(size_t const version) {
// The multiplier for major version pre-v9 and post-v9 are different.
Expand Down
1 change: 1 addition & 0 deletions llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Published documentation: https://docs.nvidia.com/deeplearning/cudnn/latest/devel
- [Block Scaling (MXFP8/NVFP4 quantization)](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/BlockScaling.md)
- [RoPE](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/RoPE.md)
- [Causal Conv1d](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/CausalConv1d.md)
- [FFT Causal Conv1d](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/FFTCausalConv1d.md)
- [Concatenate](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/Concatenate.md), [Reshape](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/Reshape.md), [Slice](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/Slice.md), [Transpose](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/Transpose.md), [Resampling](https://github.com/NVIDIA/cudnn-frontend/blob/main/docs/operations/Resampling.md)

## Open-source (frontend-only) kernel APIs
Expand Down
5 changes: 5 additions & 0 deletions python/cudnn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ def is_windows():
"causal_conv1d_nwh_backward",
"b2b_causal_conv1d_forward",
"b2b_causal_conv1d_backward",
"fft_causal_conv1d_forward",
"fft_causal_conv1d_backward",
"long_fft_causal_conv1d_get_buffer_sizes",
"long_fft_causal_conv1d_forward",
"long_fft_causal_conv1d_backward",
]:
if hasattr(_pybind_module, _optional_symbol):
globals()[_optional_symbol] = getattr(_pybind_module, _optional_symbol)
Expand Down
1 change: 1 addition & 0 deletions python/cudnn/ops/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .causal_conv1d import causal_conv1d, causal_conv1d_nwh, b2b_causal_conv1d
from .fft_causal_conv1d import fft_causal_conv1d
Loading