Skip to content

Remove PyTorch from the cutedsl dependency extra - #455

Draft
Anerudhan wants to merge 2 commits into
NVIDIA:developfrom
Anerudhan:remove/torch_dependency
Draft

Remove PyTorch from the cutedsl dependency extra#455
Anerudhan wants to merge 2 commits into
NVIDIA:developfrom
Anerudhan:remove/torch_dependency

Conversation

@Anerudhan

@Anerudhan Anerudhan commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Removes torch and torch-c-dlpack-ext from [project.optional-dependencies].cutedsl, and makes every module under python/cudnn importable without PyTorch. Missing PyTorch is reported only when a PyTorch-dependent entry point is actually invoked.

Implements torch-dependency-removal.md (included in this branch, with review comment C23 applied: the torch import is attempted on first probe, not at helper initialization).

Framework dependency boundary

  • New cudnn/_deps/torch_dep.py is the sole runtime import torch. The import is attempted lazily on the first is_available() / require() call and cached (module or failure, never retried), so importing the helper -- and therefore import cudnn -- stays PyTorch-free.
  • New public cudnn.TorchNotAvailableError (subclasses ImportError) with the canonical message. The lazy optional-symbol loader re-raises it unwrapped rather than burying it in the generic optional-dependency hint.

Import safety

  • 72 modules converted off module-level import torch onto torch_dep.require(), using postponed annotations plus if TYPE_CHECKING: import torch.
  • 84 PyTorch-valued parameter defaults became None, resolved immediately after require(), with the fixed effective default stated in the docstring (e.g. `None` means `torch.float32`) and annotations widened to Optional[...]. Effective values are unchanged.
  • 23 module-scope PyTorch constants became lazily-resolved accessors.
  • wrapper.Graph remains deliberately PyTorch-only (it allocates Torch outputs/workspace and manages the default Torch stream), but now fails fast with TorchNotAvailableError instead of a bare RuntimeError.
  • datatypes.is_cutlass_available() no longer requires PyTorch -- a real bug fix: CUTLASS-native cutlass.Numeric types now keep working when CUTLASS is installed and Torch is not.

Custom operators (facade + guarded implementation)

ops/causal_conv1d.py, experimental/ops/sdpa.py and experimental/ops/moe_grouped_matmul.py are now import-safe facades that resolve their public callables on first attribute access, preserving the original function objects and therefore their signatures. The former bodies moved to _causal_conv1d_torch.py / _sdpa_torch.py / _moe_grouped_matmul_torch.py, each wrapped in one top-level if torch_dep.is_available(): block. Module caching means the schemas, fake implementations, compiler hooks and autograd formulas still register exactly once when PyTorch is present, with unchanged operator names. These modules deliberately keep real (non-postponed) annotations, which torch.library.custom_op needs for schema inference.

The two package __init__ files bind from the implementation modules rather than the same-named facade submodules -- importing cudnn.ops.causal_conv1d sets it as an attribute of the parent package and would otherwise shadow the function of the same name.

Packaging

The extra no longer installs PyTorch. Documented install order: (1) the PyTorch build matching your CUDA environment, (2) nvidia-cudnn-frontend[cutedsl], (3) optionally torch-c-dlpack-ext to restore its AOT Torch->DLPack fast path. Omitting (3) affects conversion startup/performance, not numerical behavior.

Test plan

Passing in this branch:

  • test/python/tools/audit_no_runtime_torch_import.py -- PASSES across all 226 modules. Rejects runtime torch imports (plain / aliased / from / submodule / literal-dynamic), PyTorch-valued defaults, and unguarded module-scope PyTorch access outside the dependency helper. Type-checking-only imports and the single guarded block in the three implementation modules are permitted.
  • python -m compileall python/cudnn -- clean.
  • test/python/tools/smoke_no_torch_import.py (new) -- blocks torch with a MetaPathFinder raising ModuleNotFoundError for exactly torch/torch.*, imports every submodule, and asserts representative entry points raise TorchNotAvailableError.

Executed with PyTorch genuinely absent (and the unbuilt pybind module stubbed, since this branch was authored without a build):

  • import cudnn succeeds and torch is not in sys.modules afterwards
  • 212 submodules import cleanly; none hard-require torch
  • is_torch_available() is False; cudnn.TorchNotAvailableError is exported and subclasses ImportError
  • cudnn.Graph(), cudnn.ops.{causal_conv1d,b2b_causal_conv1d}, and both experimental ops each raise TorchNotAvailableError with the canonical message
  • 5 modules fail for an unrelated pre-existing reason (they need a newer CUTLASS than 4.5.2 -- cannot import name 'CollectorOp'), which reproduces without the torch blocker

Still to run in a proper environment: the clean-venv wheel acceptance check (assert neither distribution appears in pip list), an enable_tvm_ffi=True conversion path with PyTorch but without torch-c-dlpack-ext, and the existing PyTorch-installed test suites.

Remaining before merge

  • Docs-inventory sweep for the install instructions listed in the plan (docs/fe-oss-apis/*, benchmark/dsa/README.md, etc.). python/cudnn/__init__.py's optional-dependency hint and pyproject.toml are already updated.
  • File the tracked follow-up issue "Add permanent no-Torch import CI coverage" and link it here; the two tools above are intended to become that coverage.

🤖 Generated with Claude Code

Drops `torch` and `torch-c-dlpack-ext` from `[project.optional-dependencies].cutedsl`
and makes `python/cudnn` importable without PyTorch. Missing PyTorch is now
reported only when a PyTorch-dependent entry point is invoked.

Framework dependency boundary:
- New `cudnn/_deps/torch_dep.py` is the sole runtime `import torch`. The import
  is attempted lazily on the first `is_available()`/`require()` call and cached
  (module or failure, never retried), so importing the helper -- and therefore
  `import cudnn` -- stays PyTorch-free.
- New public `cudnn.TorchNotAvailableError` (subclasses `ImportError`) carries a
  canonical message; the lazy optional-symbol loader re-raises it unwrapped.

Import safety:
- 72 modules converted off module-level `import torch` onto `torch_dep.require()`
  with postponed annotations plus `if TYPE_CHECKING: import torch`.
- 84 PyTorch-valued parameter defaults became `None`, resolved after `require()`,
  with the fixed effective default stated in the docstring; annotations widened
  to `Optional[...]`. Effective values are unchanged.
- 23 module-scope PyTorch constants became lazily-resolved accessors.
- `wrapper.Graph` stays deliberately PyTorch-only but now fails fast with
  `TorchNotAvailableError` instead of a bare `RuntimeError`.
- `datatypes.is_cutlass_available()` no longer requires PyTorch, so CUTLASS-native
  `cutlass.Numeric` types keep working when CUTLASS is present and Torch is not.

Validation:
- New `test/python/tools/audit_no_runtime_torch_import.py` rejects runtime torch
  imports (plain/aliased/from/submodule/dynamic), PyTorch-valued defaults, and
  unguarded module-scope PyTorch access outside the dependency helper.
- `python -m compileall python/cudnn` is clean.

Known remaining work (tracked in the PR description): the three custom-op modules
(`ops/causal_conv1d.py`, `experimental/ops/{sdpa,moe_grouped_matmul}.py`) still
import torch at module scope. They are lazily loaded, so `import cudnn` is
unaffected, but they need the facade/guarded-implementation split before the
audit passes clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2279dc3f-00d4-4f93-981e-067c015b77d1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Completes the import-safety sweep: `python/cudnn` now has no runtime PyTorch
import outside `cudnn/_deps/torch_dep.py`, and the audit passes clean.

- `ops/causal_conv1d.py`, `experimental/ops/sdpa.py` and
  `experimental/ops/moe_grouped_matmul.py` become import-safe facades that
  resolve their public callables on first attribute access via module
  `__getattr__`, preserving the original function objects and therefore their
  signatures.
- The former module bodies move to `_causal_conv1d_torch.py`, `_sdpa_torch.py`
  and `_moe_grouped_matmul_torch.py`, each wrapped in a single top-level
  `if torch_dep.is_available():` block that binds torch through
  `torch_dep.require()`. Because Python caches modules, the operator schemas,
  fake implementations, compiler hooks and autograd formulas inside still
  register exactly once when PyTorch is present, with unchanged operator names.
  These modules keep real (non-postponed) annotations, which
  `torch.library.custom_op` needs for schema inference.
- `ops/__init__.py` and `experimental/ops/__init__.py` resolve names lazily and
  deliberately bind from the implementation modules, not the same-named facade
  submodules: importing e.g. `cudnn.ops.causal_conv1d` sets it as an attribute
  of the parent package and would otherwise shadow the function of the same
  name.

Adds `test/python/tools/smoke_no_torch_import.py`, which blocks torch with a
MetaPathFinder raising ModuleNotFoundError for exactly `torch`/`torch.*`, then
imports every submodule and asserts the representative entry points raise
`TorchNotAvailableError`.

Verified with torch absent and the pybind module stubbed: `import cudnn` does not
import torch, 212 submodules import cleanly, none hard-require torch, and
`cudnn.Graph`, the causal-conv1d names and both experimental ops all raise
`TorchNotAvailableError` with the canonical message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant