Skip to content

[CUDA] Add cuDNN-free ArgMax/ArgMin/ReduceSum and fix LogSoftmax on plugin EP#29620

Open
tianleiwu wants to merge 8 commits into
mainfrom
tlwu/20260708/optional_cudnn_ops
Open

[CUDA] Add cuDNN-free ArgMax/ArgMin/ReduceSum and fix LogSoftmax on plugin EP#29620
tianleiwu wants to merge 8 commits into
mainfrom
tlwu/20260708/optional_cudnn_ops

Conversation

@tianleiwu

Copy link
Copy Markdown
Contributor

Summary

Phase 2 of the CUDA plugin execution provider "no-cuDNN" work. It lets single last-axis ArgMax/ArgMin run through a small custom CUDA kernel instead of cuDNN, fixes LogSoftmax classification in the plugin adapter, and adds a non-throwing cuDNN handle accessor so reduction kernels can fall back gracefully when cuDNN is disabled.

Key Changes

Area Change
reduction_functions.cu / .h New arg_min_max_last_axis<TIn, IsArgMax> kernel (instantiated for half, float, double) that computes ArgMax/ArgMin indices over the last dimension of a row-major matrix without cuDNN.
reduction_ops.cc In ReduceComputeCore, route a single last-axis ArgMax/ArgMin (CUDNN_REDUCE_TENSOR_FLATTENED_INDICES) to the custom kernel when shapes fit int; otherwise fall through to the existing cuDNN path. ReduceKernel::ComputeImpl now uses TryGetCudnnHandle.
cuda_kernel.h (native) / cuda_kernel_adapter.h (plugin) Add TryGetCudnnHandle, which returns the cuDNN handle when available and nullptr otherwise (instead of throwing at handle acquisition).
softmax.h Detect LogSoftmax from node.OpType() instead of info.GetKernelDef().OpName(), so the plugin EP adapter classifies it correctly.
test_cuda_plugin_ep.py Add LogSoftmax and ArgMin tests; drop the @requires_cudnn gate from ArgMax, ReduceMean, ReduceSum; reduce over the last axis to exercise the cuDNN-free paths.
docs/cuda_plugin_ep/QUICK_START.md Drop ArgMax and reductions from the list of ops that still require cuDNN.

Correctness Notes

  • select_last_index == 1 is already rejected on the CUDA EP, so the kernel keeping the first matching index (strict > / <) is spec-correct for the supported case.
  • The custom path guards n > 0, returns early for m == 0, computes the row offset in int64_t, and only engages when m and n fit in int (gsl::narrow_cast); larger tensors fall back to cuDNN.

Testing

  • python -m pytest onnxruntime/test/python/transformers/test_cuda_plugin_ep.py -k "log_softmax or argmax or argmin or reduce_mean or reduce_sum"
  • Plugin no-cuDNN validation: bash .env/cuda_130_plugin_no_cudnn.sh --build --test_plugin
  • onnxruntime_provider_test --gtest_filter='*Reduce*:*ArgM*'

Phase 2 of the CUDA plugin EP no-cuDNN work.

- Add a custom arg_min_max_last_axis CUDA kernel and route single last-axis
  ArgMax/ArgMin through it in ReduceComputeCore, so these ops no longer require
  a cuDNN handle. select_last_index==1 is already rejected on CUDA, so keeping
  the first matching index is correct.
- Add TryGetCudnnHandle (native and plugin adapter) that returns the cuDNN
  handle when available and nullptr otherwise, and use it in the reduction
  kernel so unsupported cuDNN paths degrade instead of throwing during handle
  acquisition.
- Detect LogSoftmax from node.OpType() instead of the KernelDef op name so the
  plugin EP adapter classifies it correctly.
- Enable and extend plugin EP tests: LogSoftmax and ArgMin coverage, drop the
  requires_cudnn gate from ArgMax/ReduceMean/ReduceSum, and reduce over the last
  axis to exercise the cuDNN-free paths.

Copilot AI 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.

Pull request overview

This PR is phase 2 of the CUDA Plugin EP “no-cuDNN” effort: it adds a cuDNN-free last-axis ArgMax/ArgMin path, fixes LogSoftmax detection for the plugin adapter, and introduces a non-throwing cuDNN handle accessor so kernels can run/fall back when cuDNN is disabled.

Changes:

  • Added a custom CUDA kernel (arg_min_max_last_axis) for last-axis ArgMax/ArgMin indices (half/float/double) and routed eligible cases to it.
  • Switched reduction kernels to use TryGetCudnnHandle (nullable) instead of throwing at handle acquisition, and fixed LogSoftmax classification using node.OpType().
  • Expanded CUDA plugin EP Python tests (LogSoftmax, ArgMin) and adjusted reduction tests to exercise last-axis non-cuDNN paths; updated plugin quick-start docs accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
onnxruntime/test/python/transformers/test_cuda_plugin_ep.py Adds LogSoftmax/ArgMin tests and updates ArgMax/Reduce* tests to run without cuDNN and exercise last-axis paths.
onnxruntime/core/providers/cuda/reduction/reduction_ops.cc Routes last-axis ArgMax/ArgMin to the new kernel and switches reduction execution to use TryGetCudnnHandle.
onnxruntime/core/providers/cuda/reduction/reduction_functions.h Declares the new last-axis ArgMin/ArgMax helper.
onnxruntime/core/providers/cuda/reduction/reduction_functions.cu Implements and instantiates the cuDNN-free last-axis ArgMin/ArgMax kernel.
onnxruntime/core/providers/cuda/plugin/cuda_kernel_adapter.h Adds TryGetCudnnHandle for the plugin adapter.
onnxruntime/core/providers/cuda/math/softmax.h Fixes LogSoftmax detection using node.OpType() for correct plugin classification.
onnxruntime/core/providers/cuda/cuda_kernel.h Adds TryGetCudnnHandle (nullable) to native CUDA kernels.
docs/cuda_plugin_ep/QUICK_START.md Updates the list of ops requiring cuDNN for plugin no-cuDNN validation.

Comment thread onnxruntime/core/providers/cuda/plugin/cuda_kernel_adapter.h
Comment thread onnxruntime/core/providers/cuda/reduction/reduction_functions.cu
tianleiwu added 2 commits July 8, 2026 18:27
Expand the Linux no-cuDNN CUDA EP smoke test from a single Add to also run LogSoftmax, ReduceMean, ReduceSum, ArgMax and ArgMin over the last axis with enable_cudnn=0, verifying the phase-2 cuDNN-free op paths execute on the regular CUDA EP. The Windows plugin no-cuDNN CI already exercises these ops via test_cuda_plugin_ep.py.
…in_max helper

- TryGetCudnnHandle now treats a cudnnSetStream failure as "no handle" and returns nullptr (via non-throwing CUDNN_CALL) instead of throwing through CUDNN_CALL_THROW, so callers can fall back to a cuDNN-free path.
- arg_min_max_last_axis guards n <= 0 in addition to m == 0, keeping the helper safe against out-of-bounds reads if reused without the caller's n > 0 check.

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread onnxruntime/core/providers/cuda/plugin/cuda_kernel_adapter.h
@tianleiwu tianleiwu marked this pull request as ready for review July 8, 2026 22:06
@tianleiwu tianleiwu changed the title [CUDA] Add cuDNN-free ArgMax/ArgMin and fix LogSoftmax on plugin EP [CUDA] Add cuDNN-free ArgMax/ArgMin/ReduceSum and fix LogSoftmax on plugin EP Jul 9, 2026
tianleiwu added 3 commits July 9, 2026 21:44
The manylinux build image sets USER onnxruntimedev (uid 1001), so the
disposable smoke-test container ran as non-root. The new cuDNN-removal
step deletes system libcudnn*.so under /usr/lib64 and rebuilds the
dynamic linker cache with ldconfig, both of which require root, causing
'ldconfig: Can't create temporary cache file /etc/ld.so.cache~:
Permission denied' and aborting under set -e. Run this throwaway
container with --user root so the removal and ldconfig succeed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants