chore: import upstream snapshot with attribution
Docker Image CI / build-ubuntu2004 (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:36:55 +08:00
commit c8a779b1bb
1887 changed files with 3245738 additions and 0 deletions
@@ -0,0 +1,30 @@
#
# SPDX-FileCopyrightText: Copyright (c) 1993-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
add_plugin_source(
atomics.cuh
reducer.cuh
scatterElementsCommon.h
scatterElementsPlugin.cpp
scatterElementsPlugin.h
scatterElementsPluginKernel.cu
scatterElementsPluginKernel.h
scatterElementsPluginLegacy.cpp
scatterElementsPluginLegacy.h
TensorInfo.cuh
)
+61
View File
@@ -0,0 +1,61 @@
# scatterElements
**Table Of Contents**
- [Description](#description)
* [Structure](#structure)
- [Parameters](#parameters)
- [Additional resources](#additional-resources)
- [License](#license)
- [Changelog](#changelog)
- [Known issues](#known-issues)
## Description
The scatterElements plugin implements the scatter operation described in (https://github.com/rusty1s/pytorch_scatter), in compliance with the [ONNX specification for ScatterElements](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ScatterElements)
Note: ScatterElements with reduce="none" is implemented in TRT core, not this plugin.
### Structure
This plugin has the 2 versions. The latest is plugin creator class `ScatterElementsPluginV3Creator` and the plugin class `ScatterElementsPluginV3` which extends `IPluginV3`. (name: `ScatterElements`, version: 2)
The legacy plugin that will be deprecated, is plugin creator class `ScatterElementsPluginV2Creator` and the plugin class `ScatterElementsPluginV2`, which extends `IPluginV2DynamicExt` (name: `ScatterElements`, version: 1).
The `ScatterElements` plugin consumes the following inputs:
1. `data` - T: Tensor of rank r >= 1.
2. `indices` - Tind: Tensor of int64 indices, of r >= 1 (same rank as input). All index values are expected to be within bounds [-s, s-1] along axis of size s. It is an error if any of the index values are out of bounds.
3. `updates` - T: Tensor of rank r >=1 (same rank and shape as indices)
The `ScatterElements` plugin produces the following output:
1. `output` - T: Tensor, same shape as `data`.
## Parameters
The `ScatterElements` plugin has the following parameters:
| Type | Parameter | Description
|------------------|---------------------------------|--------------------------------------------------------
|`int` |`axis` | Which axis to scatter on. Default is 0. Negative value means counting dimensions from the back. Accepted range is [-r, r-1] where r = rank(data).
|`char` |`reduction` | Type of reduction to apply: add, mul, max, min. add: reduction using the addition operation. mul: reduction using the multiplication operation.max: reduction using the maximum operation.min: reduction using the minimum operation.
The following resources provide a deeper understanding of the `scatterElements` plugin:
- [pytorch_scatter: original implementation and docs](https://github.com/rusty1s/pytorch_scatter)
- [ONNX specification for ScatterElements](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ScatterElements)
## License
For terms and conditions for use, reproduction, and distribution, see the [TensorRT Software License Agreement](https://docs.nvidia.com/deeplearning/sdk/tensorrt-sla/index.html)
documentation.
## Changelog
- July 2024: Version 2 of the plugin migrated to `IPluginV3` interface design. The legacy plugin (version 1) using `IPluginV2DynamicExt` interface is deprecated.
- Oct 2023: This is the first release of this `README.md` file.
## Known issues
- Types T=BFLOAT16 and T=INT8 are currently not supported.
- ONNX spec allows Tind=int32 : only INT64 is supported by this plugin
@@ -0,0 +1,153 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
---
name: ScatterElements
interface: "IPluginV3"
versions:
"2":
inputs:
- data
- indices
- updates
supported_input_types:
- combination1:
data: float32
indices: int64
updates: float32
- combination2:
data: int32
indices: int64
updates: int32
- combination3:
data: int64
indices: int64
updates: int64
- combination4:
data: float16
indices: int64
updates: float16
- combination5:
data: bfloat16
indices: int64
updates: bfloat16
configs:
config1:
input_types:
data: float32
indices: int64
updates: float32
attribute_options:
axis:
- -1
- 0
- 1
reduction:
- "add"
- "mul"
- "min"
- "max"
config2:
input_types:
data: float16
indices: int64
updates: float16
attribute_options:
axis:
- -1
- 0
- 1
reduction:
- "add"
- "mul"
- "min"
- "max"
config3:
input_types:
data: int32
indices: int64
updates: int32
attribute_options:
axis:
- -1
- 0
- 1
reduction:
- "add"
- "mul"
- "min"
- "max"
config4:
input_types:
data: int64
indices: int64
updates: int64
attribute_options:
axis:
- -1
- 0
- 1
reduction:
- "add"
- "mul"
- "min"
- "max"
config5:
input_types:
data: bfloat16
indices: int64
updates: bfloat16
attribute_options:
axis:
- -1
- 0
- 1
reduction:
- "add"
- "mul"
- "min"
- "max"
outputs:
- output
attributes:
- axis
- reduction
attribute_types:
axis: int32
reduction: char
attribute_length:
axis: 1
reduction: -1
attribute_options:
axis:
min: "=ninf"
max: "=pinf"
reduction:
- "add"
- "mul"
- "min"
- "max"
attributes_required:
- reduction
golden_io_path: "plugin/ScatterElementsPlugin_PluginGoldenIO.json"
abs_tol: 1e-2
rel_tol: 1e-2
bf16_rtol: 5e-2
bf16_atol: 5e-2
fp16_rtol: 5e-2
fp16_atol: 5e-2
...
+151
View File
@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************************
* Modified from pytorch_scatter
* Copyright (c) 2020 Matthias Fey <matthias.fey@tu-dortmund.de>
* See https://github.com/rusty1s/pytorch_scatter/blob/master/LICENSE for details
* ************************************************************************
*/
#ifndef TRT_SCATTER_ELEMENTS_TENSOR_INFO_H
#define TRT_SCATTER_ELEMENTS_TENSOR_INFO_H
#include "common/plugin.h"
namespace nvinfer1
{
namespace plugin
{
namespace detail
{
static constexpr int32_t kMAX_TENSORINFO_DIMS = 25;
// CUDA kernel argument that defines tensor layout
template <typename TScalar, typename TIndex>
struct TensorInfo
{
TensorInfo();
TensorInfo(const TScalar* p, int32_t dim, TIndex sz[kMAX_TENSORINFO_DIMS], TIndex st[kMAX_TENSORINFO_DIMS]);
// Contiguous tensors of more than one dimension are collapsed down
// to one tensor
__host__ __device__ inline bool isContiguous() const
{
return (dims == 1 && strides[0] == 1);
}
const TScalar* data;
TIndex sizes[kMAX_TENSORINFO_DIMS];
TIndex strides[kMAX_TENSORINFO_DIMS];
int32_t dims;
};
// Creates TensorInfo object from PluginTensorDesc and data address
template <typename TScalar, typename TIndex>
TensorInfo<TScalar, TIndex> getTensorInfo(const void* d, PluginTensorDesc const& t)
{
TIndex sz[kMAX_TENSORINFO_DIMS];
TIndex st[kMAX_TENSORINFO_DIMS];
int32_t dims = t.dims.nbDims;
for (int32_t i = 0; i < dims; ++i)
{
sz[i] = t.dims.d[i];
}
for (int32_t i = dims; i < kMAX_TENSORINFO_DIMS; ++i)
{
sz[i] = static_cast<TIndex>(0);
}
// calculate strides
st[dims - 1] = 1;
for (int32_t i = dims - 2; i >= 0; --i)
{
st[i] = st[i + 1] * sz[i + 1];
}
return TensorInfo<TScalar, TIndex>(reinterpret_cast<const TScalar*>(d), dims, sz, st);
}
template <typename TScalar, typename TIndex>
TensorInfo<TScalar, TIndex>::TensorInfo()
{
data = nullptr;
dims = 0;
}
template <typename TScalar, typename TIndex>
TensorInfo<TScalar, TIndex>::TensorInfo(
const TScalar* p, int32_t dim, TIndex sz[kMAX_TENSORINFO_DIMS], TIndex st[kMAX_TENSORINFO_DIMS])
{
data = p;
dims = dim;
for (int32_t i = 0; i < dim; ++i)
{
sizes[i] = sz[i];
strides[i] = st[i];
}
}
// Translate a linear index for the apply to a T* offset;
// specialized on `Dims` to reduce nvcc compilation time
template <typename TScalar, typename TIndex, int tDims>
struct IndexToOffset
{
static __host__ __device__ TIndex get(TIndex linearId, const TensorInfo<TScalar, TIndex>& info)
{
TIndex offset = 0;
// Uses static dims
for (int32_t i = tDims - 1; i > 0; --i)
{
TIndex curDimIndex = linearId % info.sizes[i];
TIndex curDimOffset = curDimIndex * info.strides[i];
offset += curDimOffset;
linearId /= info.sizes[i];
}
return offset + linearId * info.strides[0];
}
};
// Uses dynamic (runtime) instead of static (compiletime) dims
template <typename TScalar, typename TIndex>
struct IndexToOffset<TScalar, TIndex, -1>
{
static inline __host__ __device__ TIndex get(TIndex linearId, const TensorInfo<TScalar, TIndex>& info)
{
TIndex offset = 0;
for (int32_t i = info.dims - 1; i > 0; --i)
{
TIndex curDimIndex = linearId % info.sizes[i];
TIndex curDimOffset = curDimIndex * info.strides[i];
offset += curDimOffset;
linearId /= info.sizes[i];
}
return offset + linearId * info.strides[0];
}
};
} // namespace detail
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SCATTER_ELEMENTS_TENSOR_INFO_H
+218
View File
@@ -0,0 +1,218 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************************
* Modified from pytorch_scatter
* Copyright (c) 2020 Matthias Fey <matthias.fey@tu-dortmund.de>
* See https://github.com/rusty1s/pytorch_scatter/blob/master/LICENSE for details
* ************************************************************************
*/
#ifndef TRT_SCATTER_ELEMENTS_ATOMICS_H
#define TRT_SCATTER_ELEMENTS_ATOMICS_H
#include <cstdint>
#include <cuda_fp16.h>
#include <cuda_bf16.h>
#include <utility>
#define ATOMIC(NAME) \
template <typename TScalar, size_t tSize> \
struct Atomic##NAME##IntegerImpl; \
\
template <typename TScalar> \
struct Atomic##NAME##IntegerImpl<TScalar, 4> \
{ \
inline __device__ void operator()(TScalar* address, TScalar val) \
{ \
std::uint32_t* addressAsUI = reinterpret_cast<std::uint32_t*>(address); \
std::uint32_t old = *addressAsUI; \
std::uint32_t assumed; \
\
do \
{ \
assumed = old; \
old = atomicCAS(addressAsUI, assumed, OP(val, static_cast<TScalar>(old))); \
} while (assumed != old); \
} \
}; \
\
template <typename TScalar> \
struct Atomic##NAME##IntegerImpl<TScalar, 8> \
{ \
inline __device__ void operator()(TScalar* address, TScalar val) \
{ \
unsigned long long* addressAsULL = reinterpret_cast<unsigned long long*>(address); \
unsigned long long old = *addressAsULL; \
unsigned long long assumed; \
\
do \
{ \
assumed = old; \
old = atomicCAS(addressAsULL, assumed, OP(val, static_cast<TScalar>(old))); \
} while (assumed != old); \
} \
}; \
\
template <typename TScalar, size_t tSize> \
struct Atomic##NAME##DecimalImpl; \
\
template <typename TScalar> \
struct Atomic##NAME##DecimalImpl<TScalar, 4> \
{ \
inline __device__ void operator()(TScalar* address, TScalar val) \
{ \
std::int32_t* addressAsI = reinterpret_cast<std::int32_t*>(address); \
std::int32_t old = *addressAsI; \
std::int32_t assumed; \
\
do \
{ \
assumed = old; \
old = atomicCAS(addressAsI, assumed, __float_as_int(OP(val, __int_as_float(assumed)))); \
} while (assumed != old); \
} \
}; \
template <typename TScalar> \
struct Atomic##NAME##DecimalImpl<TScalar, 2> \
{ \
inline __device__ void operator()(TScalar* address, TScalar val) \
{ \
uint32_t* addressAsUI = reinterpret_cast<std::uint32_t*>((char*) address - ((std::size_t) address & 2)); \
std::uint32_t old = *addressAsUI; \
std::uint32_t assumed; \
\
do \
{ \
assumed = old; \
std::uint16_t hsum_old; \
hsum_old = reinterpret_cast<size_t>(address) & 2 ? (old >> 16) : (old & 0xffff); \
auto hsum = OP(*reinterpret_cast<TScalar*>(&hsum_old), val); \
old = (size_t) address & 2 ? (old & 0xffff) | ((*reinterpret_cast<std::uint16_t*>(&hsum)) << 16) \
: (old & 0xffff0000) | *reinterpret_cast<std::uint16_t*>(&hsum); \
old = atomicCAS(addressAsUI, assumed, old); \
} while (assumed != old); \
} \
};
#define OP(X, Y) ((Y) + (X))
ATOMIC(Add)
#undef OP
static inline __device__ void atomAdd(float* address, float val)
{
atomicAdd(address, val);
}
static inline __device__ void atomAdd(__half* address, __half val)
{
#if defined(USE_ROCM) || (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 700 || CUDA_VERSION < 10000))
AtomicAddDecimalImpl<__half, sizeof(__half)>()(address, val);
#else
atomicAdd(address, val);
#endif
}
static inline __device__ void atomAdd(__nv_bfloat16* address, __nv_bfloat16 val)
{
#if (defined(__CUDACC__) && (!defined(__CUDA_ARCH__) || (__CUDA_ARCH__ >= 800))) || defined(_NVHPC_CUDA)
atomicAdd(address, val);
#else
AtomicAddDecimalImpl<__nv_bfloat16, sizeof(__nv_bfloat16)>()(address, val);
#endif
}
static inline __device__ void atomAdd(std::int32_t* address, std::int32_t val)
{
atomicAdd(address, val);
}
static inline __device__ void atomAdd(std::int64_t* address, std::int64_t val)
{
AtomicAddIntegerImpl<std::int64_t, sizeof(std::int64_t)>()(address, val);
}
#define OP(X, Y) ((Y) * (X))
ATOMIC(Mul)
#undef OP
static inline __device__ void atomMul(std::int32_t* address, std::int32_t val)
{
AtomicMulIntegerImpl<std::int32_t, sizeof(std::int32_t)>()(address, val);
}
static inline __device__ void atomMul(std::int64_t* address, std::int64_t val)
{
AtomicMulIntegerImpl<std::int64_t, sizeof(std::int64_t)>()(address, val);
}
static inline __device__ void atomMul(float* address, float val)
{
AtomicMulDecimalImpl<float, sizeof(float)>()(address, val);
}
static inline __device__ void atomMul(__half* address, __half val)
{
AtomicMulDecimalImpl<__half, sizeof(__half)>()(address, val);
}
static inline __device__ void atomMul(__nv_bfloat16* address, __nv_bfloat16 val)
{
AtomicMulDecimalImpl<__nv_bfloat16, sizeof(__nv_bfloat16)>()(address, val);
}
#define OP(X, Y) ((X) < (Y)) ? (Y) : (X)
ATOMIC(Max)
#undef OP
static inline __device__ void atomMax(std::int32_t* address, std::int32_t val)
{
atomicMax(address, val);
}
static inline __device__ void atomMax(float* address, float val)
{
AtomicMaxDecimalImpl<float, sizeof(float)>()(address, val);
}
static inline __device__ void atomMax(std::int64_t* address, std::int64_t val)
{
AtomicMaxIntegerImpl<std::int64_t, sizeof(std::int64_t)>()(address, val);
}
static inline __device__ void atomMax(__half* address, __half val)
{
AtomicMaxDecimalImpl<__half, sizeof(__half)>()(address, val);
}
static inline __device__ void atomMax(__nv_bfloat16* address, __nv_bfloat16 val)
{
AtomicMaxDecimalImpl<__nv_bfloat16, sizeof(__nv_bfloat16)>()(address, val);
}
#define OP(X, Y) ((X) > (Y)) ? (Y) : (X)
ATOMIC(Min)
#undef OP
static inline __device__ void atomMin(std::int32_t* address, std::int32_t val)
{
atomicMin(address, val);
}
static inline __device__ void atomMin(std::int64_t* address, std::int64_t val)
{
AtomicMinIntegerImpl<std::int64_t, sizeof(std::int64_t)>()(address, val);
}
static inline __device__ void atomMin(float* address, float val)
{
AtomicMinDecimalImpl<float, sizeof(float)>()(address, val);
}
static inline __device__ void atomMin(__half* address, __half val)
{
AtomicMinDecimalImpl<__half, sizeof(__half)>()(address, val);
}
static inline __device__ void atomMin(__nv_bfloat16* address, __nv_bfloat16 val)
{
AtomicMinDecimalImpl<__nv_bfloat16, sizeof(__nv_bfloat16)>()(address, val);
}
#endif
+174
View File
@@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************************
* Modified from pytorch_scatter
* Copyright (c) 2020 Matthias Fey <matthias.fey@tu-dortmund.de>
* See https://github.com/rusty1s/pytorch_scatter/blob/master/LICENSE for details
* ************************************************************************
*/
#ifndef TRT_SCATTER_ELEMENTS_REDUCER_H
#define TRT_SCATTER_ELEMENTS_REDUCER_H
#include <limits>
#include "atomics.cuh"
#include "scatterElementsPluginKernel.h"
namespace nvinfer1
{
namespace plugin
{
#define AT_DISPATCH_REDUCTION_TYPES(reduce, ...) \
[&] { \
switch (reduce) \
{ \
case ReductionType::kSUM: \
{ \
static constexpr ReductionType REDUCE = ReductionType::kSUM; \
return __VA_ARGS__(); \
} \
case ReductionType::kMEAN: \
{ \
static constexpr ReductionType REDUCE = ReductionType::kMEAN; \
return __VA_ARGS__(); \
} \
case ReductionType::kMUL: \
{ \
static constexpr ReductionType REDUCE = ReductionType::kMUL; \
return __VA_ARGS__(); \
} \
case ReductionType::kMIN: \
{ \
static constexpr ReductionType REDUCE = ReductionType::kMIN; \
return __VA_ARGS__(); \
} \
case ReductionType::kMAX: \
{ \
static constexpr ReductionType REDUCE = ReductionType::kMAX; \
return __VA_ARGS__(); \
} \
} \
}()
template <typename TScalar, ReductionType tReduce>
struct Reducer
{
static inline __host__ __device__ TScalar init()
{
if (tReduce == ReductionType::kMUL)
{
return TScalar(1);
}
else if (tReduce == ReductionType::kMIN)
{
return std::numeric_limits<TScalar>::max();
}
else if (tReduce == ReductionType::kMAX)
{
return std::numeric_limits<TScalar>::lowest();
}
else
{
return TScalar(0);
}
}
static inline __host__ __device__ void update(TScalar* val, TScalar newVal)
{
if (tReduce == ReductionType::kSUM || tReduce == ReductionType::kMEAN)
{
*val = *val + newVal;
}
else if (tReduce == ReductionType::kMUL)
{
*val = *val * newVal;
}
else if ((tReduce == ReductionType::kMIN && newVal < *val) || (tReduce == ReductionType::kMAX && newVal > *val))
{
*val = newVal;
}
}
static inline __host__ __device__ void update(TScalar* val, TScalar newVal, int64_t* arg, int64_t newArg)
{
if (tReduce == ReductionType::kSUM || tReduce == ReductionType::kMEAN)
{
*val = *val + newVal;
}
else if (tReduce == ReductionType::kMUL)
{
*val = *val * newVal;
}
else if ((tReduce == ReductionType::kMIN && newVal < *val) || (tReduce == ReductionType::kMAX && newVal > *val))
{
*val = newVal;
*arg = newArg;
}
}
static inline __host__ __device__ void write(
TScalar* address, TScalar val, int64_t* argAddress, int64_t arg, int count)
{
if (tReduce == ReductionType::kSUM || tReduce == ReductionType::kMUL)
{
*address = val;
}
else if (tReduce == ReductionType::kMEAN)
{
*address = val / (TScalar) (count > 0 ? count : 1);
}
else if (tReduce == ReductionType::kMIN || tReduce == ReductionType::kMAX)
{
if (count > 0)
{
*address = val;
*argAddress = arg;
}
else
{
*address = (TScalar) 0;
}
}
}
static inline __device__ void atomic_write(TScalar* address, TScalar val)
{
if (tReduce == ReductionType::kSUM || tReduce == ReductionType::kMEAN)
{
atomAdd(address, val);
}
else if (tReduce == ReductionType::kMUL)
{
atomMul(address, val);
}
else if (tReduce == ReductionType::kMIN)
{
atomMin(address, val);
}
else if (tReduce == ReductionType::kMAX)
{
atomMax(address, val);
}
}
};
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SCATTER_ELEMENTS_REDUCER_H
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SCATTER_ELEMENTS_COMMON_H
#define SCATTER_ELEMENTS_COMMON_H
#include <map>
#include <memory>
#include <stdint.h>
#include <string>
#include <vector>
#include "common/plugin.h"
enum class ReductionType : int32_t
{
kSUM,
kMUL,
kMEAN,
kMIN,
kMAX
};
extern std::unordered_map<std::string, ReductionType> const kREDUCE_STR_TO_ENUM;
extern std::unordered_map<ReductionType, std::string> const kREDUCE_ENUM_TO_STR;
#endif // SCATTER_ELEMENTS_COMMON_H
@@ -0,0 +1,364 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <string_view>
#include "common/serialize.hpp"
#include "scatterElementsPlugin.h"
#include "scatterElementsPluginKernel.h"
namespace nvinfer1::plugin
{
std::unordered_map<std::string, ReductionType> const kREDUCE_STR_TO_ENUM{
{"add", ReductionType::kSUM},
{"mean", ReductionType::kMEAN},
{"mul", ReductionType::kMUL},
{"min", ReductionType::kMIN},
{"max", ReductionType::kMAX},
};
std::unordered_map<ReductionType, std::string> const kREDUCE_ENUM_TO_STR{
{ReductionType::kSUM, "add"},
{ReductionType::kMEAN, "mean"},
{ReductionType::kMUL, "mul"},
{ReductionType::kMIN, "min"},
{ReductionType::kMAX, "max"},
};
namespace
{
constexpr char const* kSCATTER_PLUGIN_VERSION{"2"};
constexpr char const* kSCATTER_PLUGIN_NAME{"ScatterElements"};
} // namespace
ScatterElementsPluginV3::ScatterElementsPluginV3(ReductionType reduction, int32_t dim)
: mReduction(reduction)
, mAxis(dim)
{
}
ScatterElementsPluginV3::ScatterElementsPluginV3(std::string const& reduction, int32_t dim)
: mReduction(kREDUCE_STR_TO_ENUM.at(reduction))
, mAxis(dim)
{
}
int32_t ScatterElementsPluginV3::getNbOutputs() const noexcept
{
return 1;
}
IPluginCapability* ScatterElementsPluginV3::getCapabilityInterface(PluginCapabilityType type) noexcept
{
try
{
if (type == PluginCapabilityType::kBUILD)
{
return static_cast<IPluginV3OneBuild*>(this);
}
if (type == PluginCapabilityType::kRUNTIME)
{
return static_cast<IPluginV3OneRuntime*>(this);
}
PLUGIN_ASSERT(type == PluginCapabilityType::kCORE);
return static_cast<IPluginV3OneCore*>(this);
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
char const* ScatterElementsPluginV3::getPluginVersion() const noexcept
{
return kSCATTER_PLUGIN_VERSION;
}
int32_t ScatterElementsPluginV3::getOutputShapes(DimsExprs const* inputs, int32_t nbInputs,
DimsExprs const* shapeInputs, int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs,
IExprBuilder& exprBuilder) noexcept
{
try
{
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(inputs != nullptr);
PLUGIN_ASSERT(nbOutputs == 1);
outputs[kOUTPUT_TENSOR_IDX] = inputs[kDATA_TENSOR_IDX];
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t ScatterElementsPluginV3::enqueue(PluginTensorDesc const* inputDesc, PluginTensorDesc const* outputDesc,
void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc[kINDICES_TENSOR_IDX].type == DataType::kINT64);
runScatterElementsKernel(outputs[kOUTPUT_TENSOR_IDX], inputs[kDATA_TENSOR_IDX], inputs[kUPDATES_TENSOR_IDX],
inputs[kINDICES_TENSOR_IDX], outputDesc[kOUTPUT_TENSOR_IDX], inputDesc[kDATA_TENSOR_IDX],
inputDesc[kUPDATES_TENSOR_IDX], inputDesc[kINDICES_TENSOR_IDX], mAxis, mReduction, stream);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return -1;
}
int32_t ScatterElementsPluginV3::onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc const* out, int32_t nbOutputs) noexcept
{
PLUGIN_ASSERT(in != nullptr);
PLUGIN_ASSERT(out != nullptr);
PLUGIN_ASSERT(nbOutputs == 1);
PLUGIN_ASSERT(nbInputs == 3);
auto rank = in[0].dims.nbDims;
// rank of input should be >=1
PLUGIN_ASSERT(rank >= 1);
// rank of indices should be same as rank of data
PLUGIN_ASSERT(in[1].dims.nbDims == rank);
// rank and shape of updates should be same as indices
PLUGIN_ASSERT(in[2].dims.nbDims == rank);
PLUGIN_VALIDATE(std::equal(in[2].dims.d, in[2].dims.d + rank, in[1].dims.d));
return pluginStatus_t::STATUS_SUCCESS;
}
PluginFieldCollection const* ScatterElementsPluginV3::getFieldsToSerialize() noexcept
{
mDataToSerialize.clear();
// "reduction" field is serialized as string
mDataToSerialize.emplace_back("reduction", kREDUCE_ENUM_TO_STR.at(mReduction).c_str(), PluginFieldType::kCHAR,
kREDUCE_ENUM_TO_STR.at(mReduction).size());
mDataToSerialize.emplace_back("axis", &mAxis, PluginFieldType::kINT32, 1);
mFCToSerialize.nbFields = mDataToSerialize.size();
mFCToSerialize.fields = mDataToSerialize.data();
return &mFCToSerialize;
}
bool ScatterElementsPluginV3::supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(inOut && pos < (nbInputs + nbOutputs));
if (inOut[pos].desc.format != PluginFormat::kLINEAR)
{
return false;
}
auto currentType = inOut[pos].desc.type;
auto firstType = inOut[kDATA_TENSOR_IDX].desc.type;
// Only INT64 is supported for indices
return pos == kINDICES_TENSOR_IDX ? (currentType == DataType::kINT64)
: (currentType == firstType)
&& (currentType == DataType::kFLOAT || currentType == DataType::kHALF
|| (hasBfloat16AtomicAdd() && currentType == DataType::kBF16) || currentType == DataType::kINT32
|| currentType == DataType::kINT64);
}
catch (std::exception const& e)
{
caughtError(e);
return false;
}
}
ScatterElementsPluginV3* ScatterElementsPluginV3::clone() noexcept
{
try
{
auto plugin = std::make_unique<ScatterElementsPluginV3>(mReduction, mAxis);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
catch (std::exception const& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV3* ScatterElementsPluginV3::attachToContext(IPluginResourceContext* context) noexcept
{
ScatterElementsPluginV3* obj = clone();
return obj;
}
int32_t ScatterElementsPluginV3::configurePlugin(
DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(nbInputs == 3);
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
int32_t ScatterElementsPluginV3::getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_ASSERT(inputTypes != nullptr);
PLUGIN_ASSERT(nbInputs == 3);
PLUGIN_ASSERT(nbOutputs == 1);
outputTypes[kOUTPUT_TENSOR_IDX] = inputTypes[kDATA_TENSOR_IDX];
return pluginStatus_t::STATUS_SUCCESS;
}
catch (std::exception const& e)
{
caughtError(e);
}
return pluginStatus_t::STATUS_FAILURE;
}
size_t ScatterElementsPluginV3::getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
void ScatterElementsPluginV3::setPluginNamespace(char const* libNamespace) noexcept
{
try
{
PLUGIN_ASSERT(libNamespace != nullptr);
mNamespace = libNamespace;
}
catch (std::exception const& e)
{
caughtError(e);
}
}
char const* ScatterElementsPluginV3::getPluginName() const noexcept
{
return kSCATTER_PLUGIN_NAME;
}
char const* ScatterElementsPluginV3::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
//
// ScatterElementsPluginV3Creator
//
ScatterElementsPluginV3Creator::ScatterElementsPluginV3Creator()
{
static std::mutex sMutex;
std::lock_guard<std::mutex> guard(sMutex);
gPluginAttributes.clear();
gPluginAttributes.emplace_back(PluginField("reduction"));
gPluginAttributes.emplace_back(PluginField("axis"));
gFC.nbFields = gPluginAttributes.size();
gFC.fields = gPluginAttributes.data();
}
char const* ScatterElementsPluginV3Creator::getPluginName() const noexcept
{
return kSCATTER_PLUGIN_NAME;
}
char const* ScatterElementsPluginV3Creator::getPluginVersion() const noexcept
{
return kSCATTER_PLUGIN_VERSION;
}
PluginFieldCollection const* ScatterElementsPluginV3Creator::getFieldNames() noexcept
{
return &gFC;
}
char const* ScatterElementsPluginV3Creator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
void ScatterElementsPluginV3Creator::setPluginNamespace(char const* libNamespace) noexcept
{
PLUGIN_VALIDATE(libNamespace != nullptr);
mNamespace = libNamespace;
}
IPluginV3* ScatterElementsPluginV3Creator::createPlugin(
char const* name, PluginFieldCollection const* fc, TensorRTPhase phase) noexcept
{
std::string reductionArg;
int32_t axisArg = 0;
try
{
PLUGIN_VALIDATE(fc != nullptr);
auto fields = fc->fields;
std::set<std::string> requiredFields{"reduction"};
plugin::validateRequiredAttributesExist(requiredFields, fc);
using namespace std::string_view_literals;
for (int32_t i = 0; i < fc->nbFields; ++i)
{
PLUGIN_VALIDATE(fields[i].name != nullptr);
PLUGIN_VALIDATE(fields[i].data != nullptr);
if (fields[i].name == "axis"sv)
{
auto data = static_cast<int32_t const*>(fields[i].data);
axisArg = *data;
}
else if (fields[i].name == "reduction"sv)
{
auto data = static_cast<char const*>(fields[i].data);
reductionArg = fields[i].length != -1 ? std::string(data, fields[i].length) : std::string(data);
}
}
PLUGIN_VALIDATE(kREDUCE_STR_TO_ENUM.find(reductionArg) != kREDUCE_STR_TO_ENUM.end(),
(reductionArg + ": invalid value for 'reduction' plugin argument").c_str());
auto plugin = std::make_unique<ScatterElementsPluginV3>(reductionArg, axisArg);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
catch (std::exception& e)
{
caughtError(e);
}
return nullptr;
}
} // namespace nvinfer1::plugin
@@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TRT_SCATTER_ELEMENTS_PLUGIN_H
#define TRT_SCATTER_ELEMENTS_PLUGIN_H
#include "NvInfer.h"
#include "NvInferPlugin.h"
#include "common/plugin.h"
#include "scatterElementsCommon.h"
namespace nvinfer1
{
namespace plugin
{
class ScatterElementsPluginV3 : public IPluginV3,
public IPluginV3OneCore,
public IPluginV3OneBuild,
public IPluginV3OneRuntime
{
public:
// ctor and dtor
ScatterElementsPluginV3() = delete;
ScatterElementsPluginV3(ScatterElementsPluginV3 const&) = delete;
ScatterElementsPluginV3(std::string const&, int32_t);
ScatterElementsPluginV3(ReductionType, int32_t);
~ScatterElementsPluginV3() override = default;
// IPluginV3 Methods
IPluginCapability* getCapabilityInterface(PluginCapabilityType type) noexcept override;
ScatterElementsPluginV3* clone() noexcept override;
// end IPluginV3 Methods
// IPluginV3Core Methods
char const* getPluginVersion() const noexcept override;
char const* getPluginName() const noexcept override;
char const* getPluginNamespace() const noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept;
// end IPluginV3Core Methods
// IPluginV3Build Methods
int32_t getNbOutputs() const noexcept override;
bool supportsFormatCombination(
int32_t pos, DynamicPluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept override;
int32_t getOutputShapes(DimsExprs const* inputs, int32_t nbInputs, DimsExprs const* shapeInputs,
int32_t nbShapeInputs, DimsExprs* outputs, int32_t nbOutputs, IExprBuilder& exprBuilder) noexcept override;
int32_t configurePlugin(DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(DynamicPluginTensorDesc const* inputs, int32_t nbInputs,
DynamicPluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept override;
int32_t getOutputDataTypes(
DataType* outputTypes, int32_t nbOutputs, DataType const* inputTypes, int32_t nbInputs) const noexcept override;
// end IPluginV3Build Methods
// IPluginV3Runtime Methods
int32_t enqueue(nvinfer1::PluginTensorDesc const* inputDesc, nvinfer1::PluginTensorDesc const* outputDesc,
void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept override;
int32_t onShapeChange(
PluginTensorDesc const* in, int32_t nbInputs, PluginTensorDesc const* out, int32_t nbOutputs) noexcept override;
IPluginV3* attachToContext(IPluginResourceContext* context) noexcept override;
PluginFieldCollection const* getFieldsToSerialize() noexcept override;
// end IPluginV3Runtime Methods
private:
ReductionType mReduction;
int32_t mAxis;
std::vector<nvinfer1::PluginField> mDataToSerialize;
nvinfer1::PluginFieldCollection mFCToSerialize;
std::string mNamespace;
// input metadata
static constexpr int32_t kINDICES_TENSOR_IDX = 1;
static constexpr int32_t kUPDATES_TENSOR_IDX = 2;
static constexpr int32_t kDATA_TENSOR_IDX = 0;
// output metadata
static constexpr int32_t kOUTPUT_TENSOR_IDX = 0;
};
class ScatterElementsPluginV3Creator : public nvinfer1::IPluginCreatorV3One
{
public:
// ctor and dtor
ScatterElementsPluginV3Creator();
~ScatterElementsPluginV3Creator() override = default;
// get plugin metadata
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
char const* getPluginNamespace() const noexcept override;
// setter
void setPluginNamespace(char const* libNamespace) noexcept;
// create plugin
IPluginV3* createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc, TensorRTPhase phase) noexcept override;
private:
nvinfer1::PluginFieldCollection gFC;
std::vector<PluginField> gPluginAttributes;
std::string mNamespace;
};
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SCATTER_ELEMENTS_PLUGIN_H
@@ -0,0 +1,161 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************************
* Modified from pytorch_scatter
* Copyright (c) 2020 Matthias Fey <matthias.fey@tu-dortmund.de>
* See https://github.com/rusty1s/pytorch_scatter/blob/master/LICENSE for details
* ************************************************************************
*/
#include "TensorInfo.cuh"
#include "common/dimsHelpers.h"
#include "reducer.cuh"
#include "scatterElementsPluginKernel.h"
#include <thrust/device_vector.h>
namespace nvinfer1
{
namespace plugin
{
#define THREADS 256
#define BLOCKS(N) (N + THREADS - 1) / THREADS
using detail::TensorInfo;
using detail::getTensorInfo;
using nvinfer1::pluginInternal::volume;
template <typename TScalar, ReductionType tReduce>
__global__ void scatterElements_kernel(const TScalar* updatesData, const TensorInfo<int64_t, int32_t> indexInfo,
TScalar* outData, int32_t nE, int32_t nK, int32_t nN, int32_t nbElements)
{
int32_t thread_idx = blockIdx.x * blockDim.x + threadIdx.x;
int32_t b = thread_idx / (nE * nK);
int32_t k = thread_idx % nK;
if (thread_idx < nbElements)
{
int32_t offset = detail::IndexToOffset<int64_t, int32_t, -1>::get(thread_idx, indexInfo);
int64_t idx = indexInfo.data[offset];
Reducer<TScalar, tReduce>::atomic_write(outData + b * nN * nK + idx * nK + k, updatesData[thread_idx]);
}
}
bool hasBfloat16AtomicAdd()
{
int deviceId;
cudaGetDevice(&deviceId);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, deviceId);
return deviceProp.major >= 8;
}
inline uint32_t getElementSize(nvinfer1::DataType t)
{
switch (t)
{
case nvinfer1::DataType::kINT64: return 8;
case nvinfer1::DataType::kINT32:
case nvinfer1::DataType::kFLOAT: return 4;
case nvinfer1::DataType::kBF16:
case nvinfer1::DataType::kHALF: return 2;
case nvinfer1::DataType::kBOOL:
case nvinfer1::DataType::kUINT8:
case nvinfer1::DataType::kINT8:
case nvinfer1::DataType::kFP8: return 1;
case nvinfer1::DataType::kINT4:
case nvinfer1::DataType::kFP4:
case nvinfer1::DataType::kE8M0:
PLUGIN_FAIL("Unsupported data type");
}
return 0;
}
template <typename TScalar>
void dispatchScatterElementsKernel(void* outDataPtr, void const* dataDataPtr, void const* updatesDataPtr,
void const* indicesDataPtr, PluginTensorDesc const& outDesc, PluginTensorDesc const& dataDesc,
PluginTensorDesc const& updatesDesc, PluginTensorDesc const& indicesDesc, int64_t axis, ReductionType reduction,
cudaStream_t stream)
{
auto updatesNumEl = volume(updatesDesc.dims);
auto nB = 1;
for (auto i = 0; i < axis; i++)
{
nB *= updatesDesc.dims.d[i];
}
auto nE = updatesDesc.dims.d[axis];
auto nK = updatesNumEl / (nB * nE);
auto nN = outDesc.dims.d[axis];
auto indexInfo = getTensorInfo<int64_t, int32_t>(indicesDataPtr, indicesDesc);
auto updatesData = (TScalar*) updatesDataPtr;
auto outData = (TScalar*) outDataPtr;
AT_DISPATCH_REDUCTION_TYPES(reduction, [&] {
scatterElements_kernel<TScalar, REDUCE>
<<<BLOCKS(updatesNumEl), THREADS, 0, stream>>>(updatesData, indexInfo, outData, nE, nK, nN, updatesNumEl);
});
}
#define DISPATCH_RUN_KERNEL(TYPE) \
dispatchScatterElementsKernel<TYPE>(outDataPtr, dataDataPtr, updatesDataPtr, indicesDataPtr, outDesc, dataDesc, \
updatesDesc, indicesDesc, axis, reduction, stream)
void runScatterElementsKernel(void* outDataPtr, void const* dataDataPtr, void const* updatesDataPtr,
void const* indicesDataPtr, PluginTensorDesc const& outDesc, PluginTensorDesc const& dataDesc,
PluginTensorDesc const& updatesDesc, PluginTensorDesc const& indicesDesc, int64_t axis, ReductionType reduction,
cudaStream_t stream)
{
auto updatesNumEl = volume(updatesDesc.dims);
auto outNumEl = volume(outDesc.dims);
// copy dataDataPtr data to outDataPtr area first
cudaMemcpyAsync(outDataPtr, dataDataPtr, getElementSize(outDesc.type) * outNumEl, cudaMemcpyDeviceToDevice, stream);
if (updatesNumEl == 0)
{
return;
}
switch (outDesc.type)
{
case nvinfer1::DataType::kFLOAT: DISPATCH_RUN_KERNEL(float); break;
case nvinfer1::DataType::kHALF: DISPATCH_RUN_KERNEL(__half); break;
case nvinfer1::DataType::kINT32: DISPATCH_RUN_KERNEL(int32_t); break;
case nvinfer1::DataType::kINT64: DISPATCH_RUN_KERNEL(int64_t); break;
case nvinfer1::DataType::kBF16: DISPATCH_RUN_KERNEL(__nv_bfloat16); break;
case nvinfer1::DataType::kBOOL:
case nvinfer1::DataType::kUINT8:
case nvinfer1::DataType::kINT8:
case nvinfer1::DataType::kINT4:
case nvinfer1::DataType::kFP8:
case nvinfer1::DataType::kFP4:
case nvinfer1::DataType::kE8M0:
std::ostringstream stream;
stream << "Unsupported data type:" << (int)outDesc.type << std::endl;
PLUGIN_FAIL(stream.str().c_str());
break;
}
}
} // namespace plugin
} // namespace nvinfer1
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************************
* Modified from pytorch_scatter
* Copyright (c) 2020 Matthias Fey <matthias.fey@tu-dortmund.de>
* See https://github.com/rusty1s/pytorch_scatter/blob/master/LICENSE for details
* ************************************************************************
*/
#ifndef TRT_SCATTER_ELEMENTS_KERNEL_PLUGIN_H
#define TRT_SCATTER_ELEMENTS_KERNEL_PLUGIN_H
#include "common/plugin.h"
#include "scatterElementsCommon.h"
namespace nvinfer1
{
namespace plugin
{
bool hasBfloat16AtomicAdd();
void runScatterElementsKernel(void* outDataPtr, void const* dataDataPtr, void const* updatesDataPtr,
void const* indicesDataPtr, PluginTensorDesc const& outDesc, PluginTensorDesc const& dataDesc,
PluginTensorDesc const& updatesDesc, PluginTensorDesc const& indicesDesc, int64_t axis, ReductionType reduction,
cudaStream_t stream);
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SCATTER_ELEMENTS_KERNEL_PLUGIN_H
@@ -0,0 +1,312 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <string_view>
#include "common/serialize.hpp"
#include "scatterElementsPluginKernel.h"
#include "scatterElementsPluginLegacy.h"
namespace nvinfer1::plugin
{
std::unordered_map<std::string, ReductionType> const kREDUCE_STR_TO_ENUM{
{"add", ReductionType::kSUM},
{"mean", ReductionType::kMEAN},
{"mul", ReductionType::kMUL},
{"min", ReductionType::kMIN},
{"max", ReductionType::kMAX},
};
namespace
{
constexpr char const* kSCATTER_ELEMENTS_NAME{"ScatterElements"};
constexpr char const* kSCATTER_ELEMENTS_VERSION{"1"};
} // namespace
ScatterElementsPluginV2::ScatterElementsPluginV2(ReductionType reduction, int32_t dim)
: mReduction(reduction)
, mAxis(dim)
{
}
ScatterElementsPluginV2::ScatterElementsPluginV2(std::string const& reduction, int32_t dim)
: mReduction(kREDUCE_STR_TO_ENUM.at(reduction))
, mAxis(dim)
{
}
ScatterElementsPluginV2::ScatterElementsPluginV2(void const* serialData, size_t serialLength)
{
deserialize_value(&serialData, &serialLength, &mReduction);
deserialize_value(&serialData, &serialLength, &mAxis);
}
int32_t ScatterElementsPluginV2::getNbOutputs() const noexcept
{
return 1;
}
int32_t ScatterElementsPluginV2::initialize() noexcept
{
return 0;
}
char const* ScatterElementsPluginV2::getPluginType() const noexcept
{
return kSCATTER_ELEMENTS_NAME;
}
char const* ScatterElementsPluginV2::getPluginVersion() const noexcept
{
return kSCATTER_ELEMENTS_VERSION;
}
DimsExprs ScatterElementsPluginV2::getOutputDimensions(
int32_t index, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept
{
try
{
PLUGIN_VALIDATE(nbInputs == 3);
PLUGIN_VALIDATE(inputs);
PLUGIN_VALIDATE(index <= kOUTPUT_TENSOR_IDX);
// both outputs are of the same size
DimsExprs out(inputs[kDATA_TENSOR_IDX]);
return out;
}
catch (std::exception const& e)
{
caughtError(e);
}
return DimsExprs();
}
int32_t ScatterElementsPluginV2::enqueue(PluginTensorDesc const* inputDesc, PluginTensorDesc const* outputDesc,
void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept
{
try
{
PLUGIN_VALIDATE(inputDesc[kINDICES_TENSOR_IDX].type == DataType::kINT64);
runScatterElementsKernel(outputs[kOUTPUT_TENSOR_IDX], inputs[kDATA_TENSOR_IDX], inputs[kUPDATES_TENSOR_IDX],
inputs[kINDICES_TENSOR_IDX], outputDesc[kOUTPUT_TENSOR_IDX], inputDesc[kDATA_TENSOR_IDX],
inputDesc[kUPDATES_TENSOR_IDX], inputDesc[kINDICES_TENSOR_IDX], mAxis, mReduction, stream);
return 0;
}
catch (std::exception const& e)
{
caughtError(e);
return -1;
}
}
size_t ScatterElementsPluginV2::getSerializationSize() const noexcept
{
auto ret = serialized_size(mReduction) + serialized_size(mAxis);
return ret;
}
void ScatterElementsPluginV2::serialize(void* buffer) const noexcept
{
serialize_value(&buffer, mReduction);
serialize_value(&buffer, mAxis);
}
bool ScatterElementsPluginV2::supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(inOut && pos < (nbInputs + nbOutputs));
if (inOut[pos].format != PluginFormat::kLINEAR)
{
return false;
}
auto mytype = inOut[pos].type;
auto firsttype = inOut[kDATA_TENSOR_IDX].type;
// Only INT64 is supported for indices
return pos == kINDICES_TENSOR_IDX ? (mytype == DataType::kINT64)
: (mytype == firsttype)
&& (mytype == DataType::kFLOAT || mytype == DataType::kHALF
|| (hasBfloat16AtomicAdd() && mytype == DataType::kBF16) || mytype == DataType::kINT32
|| mytype == DataType::kINT64);
}
catch (std::exception const& e)
{
caughtError(e);
return false;
}
}
void ScatterElementsPluginV2::terminate() noexcept {}
void ScatterElementsPluginV2::destroy() noexcept
{
// This gets called when the network containing plugin is destroyed
delete this;
}
IPluginV2DynamicExt* ScatterElementsPluginV2::clone() const noexcept
{
auto plugin = std::make_unique<ScatterElementsPluginV2>(mReduction, mAxis);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
void ScatterElementsPluginV2::configurePlugin(
DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out, int32_t nbOutputs) noexcept
{
try
{
PLUGIN_VALIDATE(nbInputs == 3);
}
catch (std::exception const& e)
{
caughtError(e);
}
}
DataType ScatterElementsPluginV2::getOutputDataType(
int32_t index, DataType const* inputTypes, int32_t nbInputs) const noexcept
{
try
{
PLUGIN_VALIDATE(inputTypes && nbInputs == 3 && index == kOUTPUT_TENSOR_IDX);
}
catch (std::exception const& e)
{
caughtError(e);
}
return inputTypes[kDATA_TENSOR_IDX];
}
size_t ScatterElementsPluginV2::getWorkspaceSize(
PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept
{
return 0;
}
void ScatterElementsPluginV2::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
char const* ScatterElementsPluginV2::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
//
// ScatterElementsPluginV2Creator
//
ScatterElementsPluginV2Creator::ScatterElementsPluginV2Creator()
{
gPluginAttributes.clear();
gPluginAttributes.emplace_back(PluginField("reduction"));
gPluginAttributes.emplace_back(PluginField("axis"));
gFC.nbFields = gPluginAttributes.size();
gFC.fields = gPluginAttributes.data();
}
char const* ScatterElementsPluginV2Creator::getPluginName() const noexcept
{
return kSCATTER_ELEMENTS_NAME;
}
char const* ScatterElementsPluginV2Creator::getPluginVersion() const noexcept
{
return kSCATTER_ELEMENTS_VERSION;
}
PluginFieldCollection const* ScatterElementsPluginV2Creator::getFieldNames() noexcept
{
return &gFC;
}
char const* ScatterElementsPluginV2Creator::getPluginNamespace() const noexcept
{
return mNamespace.c_str();
}
void ScatterElementsPluginV2Creator::setPluginNamespace(char const* libNamespace) noexcept
{
mNamespace = libNamespace;
}
IPluginV2DynamicExt* ScatterElementsPluginV2Creator::createPlugin(
char const* name, PluginFieldCollection const* fc) noexcept
{
std::string reductionArg;
int32_t axisArg = 0;
try
{
PLUGIN_VALIDATE(fc != nullptr);
auto fields = fc->fields;
std::set<std::string> requiredFields{"reduction"};
plugin::validateRequiredAttributesExist(requiredFields, fc);
using namespace std::string_view_literals;
for (int32_t i = 0; i < fc->nbFields; ++i)
{
PLUGIN_VALIDATE(fields[i].name != nullptr);
PLUGIN_VALIDATE(fields[i].data != nullptr);
if (fields[i].name == "axis"sv)
{
auto data = static_cast<int32_t const*>(fields[i].data);
axisArg = *data;
}
else if (fields[i].name == "reduction"sv)
{
auto data = static_cast<char const*>(fields[i].data);
reductionArg = std::string(data);
}
}
PLUGIN_VALIDATE(kREDUCE_STR_TO_ENUM.find(reductionArg) != kREDUCE_STR_TO_ENUM.end(),
(reductionArg + ": invalid value for 'reduction' plugin argument").c_str());
auto plugin = std::make_unique<ScatterElementsPluginV2>(reductionArg, axisArg);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
catch (std::exception& e)
{
caughtError(e);
}
return nullptr;
}
IPluginV2DynamicExt* ScatterElementsPluginV2Creator::deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept
{
auto plugin = std::make_unique<ScatterElementsPluginV2>(serialData, serialLength);
plugin->setPluginNamespace(mNamespace.c_str());
return plugin.release();
}
} // namespace nvinfer1::plugin
@@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1993-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TRT_SCATTER_ELEMENTS_PLUGIN_LEGACY_H
#define TRT_SCATTER_ELEMENTS_PLUGIN_LEGACY_H
#include "common/plugin.h"
#include "scatterElementsCommon.h"
namespace nvinfer1
{
namespace plugin
{
class ScatterElementsPluginV2 final : public nvinfer1::IPluginV2DynamicExt
{
public:
ScatterElementsPluginV2() = delete;
ScatterElementsPluginV2(ScatterElementsPluginV2 const&) = delete;
ScatterElementsPluginV2(std::string const&, int32_t);
ScatterElementsPluginV2(ReductionType, int32_t);
ScatterElementsPluginV2(void const* serialData, size_t serialLength);
~ScatterElementsPluginV2() override = default;
// IPluginV2 methods
char const* getPluginType() const noexcept override;
char const* getPluginVersion() const noexcept override;
int32_t getNbOutputs() const noexcept override;
int32_t initialize() noexcept override;
void terminate() noexcept override;
size_t getSerializationSize() const noexcept override;
void serialize(void* buffer) const noexcept override;
void destroy() noexcept override;
void setPluginNamespace(char const* libNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
void setClipParam(bool clip) noexcept;
void setScoreBits(int32_t scoreBits) noexcept;
void setCaffeSemantics(bool caffeSemantics) noexcept;
// IPluginV2Ext methods
nvinfer1::DataType getOutputDataType(
int32_t index, nvinfer1::DataType const* inputTypes, int32_t nbInputs) const noexcept override;
// IPluginV2DynamicExt methods
IPluginV2DynamicExt* clone() const noexcept override;
DimsExprs getOutputDimensions(
int32_t outputIndex, DimsExprs const* inputs, int32_t nbInputs, IExprBuilder& exprBuilder) noexcept override;
bool supportsFormatCombination(
int32_t pos, PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept override;
void configurePlugin(DynamicPluginTensorDesc const* in, int32_t nbInputs, DynamicPluginTensorDesc const* out,
int32_t nbOutputs) noexcept override;
size_t getWorkspaceSize(PluginTensorDesc const* inputs, int32_t nbInputs, PluginTensorDesc const* outputs,
int32_t nbOutputs) const noexcept override;
int32_t enqueue(PluginTensorDesc const* inputDesc, PluginTensorDesc const* outputDesc, void const* const* inputs,
void* const* outputs, void* workspace, cudaStream_t stream) noexcept override;
private:
ReductionType mReduction;
int32_t mAxis;
std::string mNamespace;
static constexpr int32_t kINDICES_TENSOR_IDX = 1;
static constexpr int32_t kUPDATES_TENSOR_IDX = 2;
static constexpr int32_t kDATA_TENSOR_IDX = 0;
// outputs
static constexpr int32_t kOUTPUT_TENSOR_IDX = 0;
};
class ScatterElementsPluginV2Creator : public nvinfer1::IPluginCreator
{
public:
ScatterElementsPluginV2Creator();
~ScatterElementsPluginV2Creator() override = default;
char const* getPluginName() const noexcept override;
char const* getPluginVersion() const noexcept override;
nvinfer1::PluginFieldCollection const* getFieldNames() noexcept override;
nvinfer1::IPluginV2DynamicExt* createPlugin(
char const* name, nvinfer1::PluginFieldCollection const* fc) noexcept override;
nvinfer1::IPluginV2DynamicExt* deserializePlugin(
char const* name, void const* serialData, size_t serialLength) noexcept override;
void setPluginNamespace(char const* pluginNamespace) noexcept override;
char const* getPluginNamespace() const noexcept override;
private:
nvinfer1::PluginFieldCollection gFC;
std::vector<nvinfer1::PluginField> gPluginAttributes;
std::string mNamespace;
};
} // namespace plugin
} // namespace nvinfer1
#endif // TRT_SCATTER_ELEMENTS_PLUGIN_LEGACY_H