Implement opset v10 changes for Slice operator (#772)

This commit is contained in:
Hariharan Seshadri 2019-04-10 22:06:05 -07:00 committed by GitHub
parent 53038b33ed
commit 56749a84ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 813 additions and 236 deletions

View file

@ -160,19 +160,19 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDoma
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 5, Reshape);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, Shape);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, Size);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, bool, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, float, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, double, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, MLFloat16, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint8_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint16_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint32_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint64_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int8_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int16_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int32_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int64_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, string, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, bool, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, float, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, double, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, MLFloat16, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint8_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint16_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint32_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint64_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int8_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int16_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int32_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int64_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, string, Slice);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, SpaceToDepth);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 4, DepthToSpace);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 2, Split);
@ -247,6 +247,19 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, QL
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, MatMulInteger);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, ConvInteger);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, QLinearConv);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, bool, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, float, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, double, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, MLFloat16, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint8_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint16_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint32_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint64_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int8_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int16_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int32_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int64_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, string, Slice);
void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 6, Clip)>());
@ -395,21 +408,19 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 5, Reshape)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, Shape)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, Size)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, bool, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, float, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, double, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, MLFloat16, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, uint64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, int64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, string, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, bool, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, float, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, double, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, MLFloat16, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, uint64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, int64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 9, string, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, SpaceToDepth)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 4, DepthToSpace)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 2, Split)>());
@ -484,6 +495,19 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, MatMulInteger)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, ConvInteger)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, QLinearConv)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, bool, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, float, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, double, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, MLFloat16, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, uint64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int8_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int16_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, int64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 10, string, Slice)>());
}
// Forward declarations of ml op kernels

View file

@ -171,12 +171,12 @@ Status MaxUnpool::Compute(OpKernelContext* context) const {
size_t inner_axis = dimension_count - 1;
TensorAxisCounters input_counters(*p_tensor);
SliceIterator<float> input(*p_tensor, input_starts, input_extents);
SliceIterator<float> input(*p_tensor, input_starts, input_extents, {});
while (input_counters) {
Y_data += alignSkip;
{
Y_data = input.CopyInnermostAxis(Y_data);
Y_data = input.CopyInnermostAxisSolitaryInnerStep(Y_data);
int64_t prePad = inferredPads[inner_axis];
int64_t postPad = inferredPads[inner_axis + dimension_count];
Y_data += postPad;

View file

@ -131,7 +131,7 @@ Status Pad<float>::Compute(OpKernelContext* ctx) const {
TensorShape output_shape(output_dims);
TensorShape input_shape(reshaped_input_dims);
SliceIterator<float> input(input_tensor, input_shape, input_starts, input_extents);
SliceIterator<float> input(input_tensor, input_shape, input_starts, input_extents, {});
// output_shape need to keep original.
auto& output_tensor = *ctx->Output(0, output_shape);
@ -155,7 +155,7 @@ Status Pad<float>::Compute(OpKernelContext* ctx) const {
output += alignSkip;
{
float* axisStart = output;
output = input.CopyInnermostAxis(output);
output = input.CopyInnermostAxisSolitaryInnerStep(output);
int64_t prePad = reshaped_pad[inner_axis];
int64_t postPad = reshaped_pad[inner_axis + new_dims_count];
@ -186,7 +186,7 @@ Status Pad<float>::Compute(OpKernelContext* ctx) const {
output += alignSkip;
{
float* axisStart = output;
output = input.CopyInnermostAxis(output);
output = input.CopyInnermostAxisSolitaryInnerStep(output);
int64_t prePad = reshaped_pad[inner_axis];
int64_t postPad = reshaped_pad[inner_axis + new_dims_count];
@ -217,7 +217,7 @@ Status Pad<float>::Compute(OpKernelContext* ctx) const {
output += alignSkip;
{
float* axisStart = output;
output = input.CopyInnermostAxis(output);
output = input.CopyInnermostAxisSolitaryInnerStep(output);
int64_t prePad = reshaped_pad[inner_axis];
int64_t postPad = reshaped_pad[inner_axis + new_dims_count];

View file

@ -3,31 +3,34 @@
#include "core/providers/cpu/tensor/slice.h"
#include "core/providers/cpu/tensor/utils.h"
#include <unordered_map>
#include <limits>
using namespace ::onnxruntime::common;
using namespace std;
namespace onnxruntime {
#define ADD_TYPED_SLICE_OP(data_type) \
ONNX_CPU_OPERATOR_TYPED_KERNEL( \
#define ADD_TYPED_SLICE_V9_OP(data_type) \
ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( \
Slice, \
1, \
1, 9, \
data_type, \
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<data_type>()), \
Slice<data_type, false>);
ADD_TYPED_SLICE_OP(uint8_t);
ADD_TYPED_SLICE_OP(uint16_t);
ADD_TYPED_SLICE_OP(uint32_t);
ADD_TYPED_SLICE_OP(uint64_t);
ADD_TYPED_SLICE_OP(int8_t);
ADD_TYPED_SLICE_OP(int16_t);
ADD_TYPED_SLICE_OP(int32_t);
ADD_TYPED_SLICE_OP(int64_t);
ADD_TYPED_SLICE_OP(float);
ADD_TYPED_SLICE_OP(double);
ADD_TYPED_SLICE_OP(MLFloat16);
ADD_TYPED_SLICE_OP(bool);
ADD_TYPED_SLICE_OP(string);
ADD_TYPED_SLICE_V9_OP(uint8_t);
ADD_TYPED_SLICE_V9_OP(uint16_t);
ADD_TYPED_SLICE_V9_OP(uint32_t);
ADD_TYPED_SLICE_V9_OP(uint64_t);
ADD_TYPED_SLICE_V9_OP(int8_t);
ADD_TYPED_SLICE_V9_OP(int16_t);
ADD_TYPED_SLICE_V9_OP(int32_t);
ADD_TYPED_SLICE_V9_OP(int64_t);
ADD_TYPED_SLICE_V9_OP(float);
ADD_TYPED_SLICE_V9_OP(double);
ADD_TYPED_SLICE_V9_OP(MLFloat16);
ADD_TYPED_SLICE_V9_OP(bool);
ADD_TYPED_SLICE_V9_OP(string);
#ifndef DISABLE_CONTRIB_OPS
namespace contrib {
@ -57,6 +60,31 @@ ADD_TYPED_DYNAMIC_SLICE_OP(string);
} // namespace contrib
#endif
#define ADD_TYPED_SLICE_V10_OP(data_type) \
ONNX_CPU_OPERATOR_TYPED_KERNEL( \
Slice, \
10, \
data_type, \
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<data_type>()) \
.TypeConstraint("Tind", {DataTypeImpl::GetTensorType<int32_t>(), \
DataTypeImpl::GetTensorType<int64_t>()}), \
Slice<data_type, true>);
ADD_TYPED_SLICE_V10_OP(uint8_t);
ADD_TYPED_SLICE_V10_OP(uint16_t);
ADD_TYPED_SLICE_V10_OP(uint32_t);
ADD_TYPED_SLICE_V10_OP(uint64_t);
ADD_TYPED_SLICE_V10_OP(int8_t);
ADD_TYPED_SLICE_V10_OP(int16_t);
ADD_TYPED_SLICE_V10_OP(int32_t);
ADD_TYPED_SLICE_V10_OP(int64_t);
ADD_TYPED_SLICE_V10_OP(float);
ADD_TYPED_SLICE_V10_OP(double);
ADD_TYPED_SLICE_V10_OP(MLFloat16);
ADD_TYPED_SLICE_V10_OP(bool);
ADD_TYPED_SLICE_V10_OP(string);
namespace {
// std::clamp doesn't exist until C++17 so create a local version
template <typename T>
@ -67,6 +95,7 @@ const T& clamp(const T& v, const T& lo, const T& hi) {
}
} // namespace
// Slice V1-9 & DynamicSlice
Status SliceBase::PrepareForCompute(const std::vector<int64_t>& raw_starts,
const std::vector<int64_t>& raw_ends,
const std::vector<int64_t>& raw_axes,
@ -75,46 +104,138 @@ Status SliceBase::PrepareForCompute(const std::vector<int64_t>& raw_starts,
std::vector<int64_t>& output_dims) const {
// Initialize axes to the provided axes attribute or to the default sequence
std::vector<int64_t> axes(raw_axes);
if (axes.size() == 0) {
if (axes.empty()) {
//axes are omitted, they are set to[0, ..., ndim - 1]
axes.resize(starts.size());
std::iota(axes.begin(), axes.end(), 0);
}
// Iterate through the provided axes and override the start/end ranges
std::unordered_set<int64_t> unique_axes;
const auto& dimension_count = input_dimensions.size();
for (size_t axesIndex = 0; axesIndex < axes.size(); axesIndex++) {
auto axis = axes[axesIndex] < 0 ? axes[axesIndex] + static_cast<int64_t>(dimension_count) : axes[axesIndex];
for (size_t axis_index = 0, axes_count = axes.size(); axis_index < axes_count; ++axis_index) {
auto axis = axes[axis_index] < 0 ? axes[axis_index] + static_cast<int64_t>(dimension_count) : axes[axis_index];
if (axis >= static_cast<int64_t>(dimension_count) || axis < 0)
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'axes' has an axis outside of the tensor dimension count");
auto start = raw_starts[axesIndex];
if (unique_axes.find(axis) != unique_axes.end())
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'axes' has duplicates");
unique_axes.insert(axis);
// process start
auto start = raw_starts[axis_index];
if (start < 0)
start += input_dimensions[axis];
starts[axis] = clamp(start, int64_t{0}, input_dimensions[axis]);
auto end = raw_ends[axesIndex];
// process end
auto end = raw_ends[axis_index];
if (end < 0)
end += input_dimensions[axis];
output_dims[axis] = clamp(end, int64_t{0}, input_dimensions[axis]) - starts[axis];
if (output_dims[axis] < 0)
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'starts' and 'ends' values resulted in a negative dimension");
// find output dim value for this axis
auto temp = clamp(end, int64_t{0}, input_dimensions[axis]) - starts[axis];
if (temp < 0)
output_dims[axis] = 0;
else
output_dims[axis] = temp;
}
return Status::OK();
}
// DynamicSlice & Slice V10
Status SliceBase::PrepareForCompute(const std::vector<int64_t>& raw_starts,
const std::vector<int64_t>& raw_ends,
const std::vector<int64_t>& raw_axes,
const std::vector<int64_t>& raw_steps,
const std::vector<int64_t>& input_dimensions,
std::vector<int64_t>& starts,
std::vector<int64_t>& steps,
std::vector<int64_t>& output_dims) const {
// Initialize axes to the provided axes attribute or to the default sequence
std::vector<int64_t> axes(raw_axes);
if (axes.empty()) {
// axes are omitted, they are set to[0, ..., ndim - 1]
axes.resize(starts.size());
std::iota(axes.begin(), axes.end(), 0);
}
// Iterate through the provided axes and override the start/end/steps ranges
std::unordered_set<int64_t> unique_axes;
const auto& dimension_count = input_dimensions.size();
for (size_t axis_index = 0, axes_count = axes.size(); axis_index < axes_count; ++axis_index) {
auto axis = axes[axis_index] < 0 ? axes[axis_index] + static_cast<int64_t>(dimension_count) : axes[axis_index];
if (axis >= static_cast<int64_t>(dimension_count) || axis < 0)
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'axes' has an axis outside of the tensor dimension count");
if (unique_axes.find(axis) != unique_axes.end())
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'axes' has duplicates");
unique_axes.insert(axis);
// process step
auto step = axis_index < raw_steps.size() ? raw_steps[axis_index] : 1;
if (step == 0)
return Status(ONNXRUNTIME, INVALID_ARGUMENT, "'step' value cannot be 0");
steps[axis] = step;
// process start
auto start = raw_starts[axis_index];
if (start < 0)
start += input_dimensions[axis];
if (step < 0)
starts[axis] = clamp(start, int64_t{0}, input_dimensions[axis] - 1);
else
starts[axis] = clamp(start, int64_t{0}, input_dimensions[axis]);
// process end
auto end = raw_ends[axis_index];
// INT_MAX has a special meaning for end according to spec
// equivalent to 'None' in numpy
// it represent slicing to the end of the dimension
if (end == std::numeric_limits<int32_t>::max() ||
end == std::numeric_limits<int64_t>::max()) {
end = step < 0 ? -1 : input_dimensions[axis];
}
else {
if (end < 0)
end += input_dimensions[axis];
if (step < 0)
end = clamp(end, int64_t{-1}, input_dimensions[axis]);
else
end = clamp(end, int64_t{0}, input_dimensions[axis]);
}
// find output dim value for this axis
auto temp = static_cast<int64_t>(ceil(1.0 * (end - starts[axis]) / step));
if (temp < 0)
output_dims[axis] = 0;
else
output_dims[axis] = temp;
}
return Status::OK();
}
// Slice V10 & DynamicSlice
void SliceBase::FillVectorsFromInput(const OpKernelContext* context,
std::vector<int64_t>& input_starts,
std::vector<int64_t>& input_ends,
std::vector<int64_t>& input_axes) const {
std::vector<int64_t>& input_axes,
std::vector<int64_t>& input_steps) const {
auto start_tensor = context->Input<Tensor>(1);
auto ends_tensor = context->Input<Tensor>(2);
auto axes_tensor = context->Input<Tensor>(3);
const Tensor* axes_tensor = nullptr;
if (context->InputCount() >= 4)
axes_tensor = context->Input<Tensor>(3);
// Slice V10 (optional input)
const Tensor* steps_tensor = nullptr;
if (context->InputCount() == 5)
steps_tensor = context->Input<Tensor>(4);
ORT_ENFORCE(nullptr != start_tensor && start_tensor->Shape().NumDimensions() == 1, "Starts must be a 1-D array");
ORT_ENFORCE(nullptr != ends_tensor && ends_tensor->Shape().NumDimensions() == 1, "Ends must be a 1-D array");
ORT_ENFORCE(start_tensor->Shape() == ends_tensor->Shape(), "Starts and ends shape mismatch");
ORT_ENFORCE(nullptr == axes_tensor || start_tensor->Shape() == axes_tensor->Shape(), "Starts and axes shape mismatch");
ORT_ENFORCE(nullptr == steps_tensor || steps_tensor->Shape() == axes_tensor->Shape(), "Steps and axes shape mismatch");
const auto& dtype = start_tensor->DataType();
const auto& size = start_tensor->Shape().Size();
@ -122,12 +243,18 @@ void SliceBase::FillVectorsFromInput(const OpKernelContext* context,
input_ends.resize(size);
if (nullptr != axes_tensor)
input_axes.resize(size);
// Slice V10
if (nullptr != steps_tensor)
input_steps.resize(size);
if (dtype == DataTypeImpl::GetType<int32_t>()) {
std::copy(start_tensor->Data<int32_t>(), start_tensor->Data<int32_t>() + size, input_starts.begin());
std::copy(ends_tensor->Data<int32_t>(), ends_tensor->Data<int32_t>() + size, input_ends.begin());
if (nullptr != axes_tensor)
std::copy(axes_tensor->Data<int32_t>(), axes_tensor->Data<int32_t>() + size, input_axes.begin());
// Slice V10
if (nullptr != steps_tensor)
std::copy(steps_tensor->Data<int32_t>(), steps_tensor->Data<int32_t>() + size, input_steps.begin());
}
else if (dtype == DataTypeImpl::GetType<int64_t>()) {
@ -135,6 +262,9 @@ void SliceBase::FillVectorsFromInput(const OpKernelContext* context,
std::copy(ends_tensor->Data<int64_t>(), ends_tensor->Data<int64_t>() + size, input_ends.begin());
if (nullptr != axes_tensor)
std::copy(axes_tensor->Data<int64_t>(), axes_tensor->Data<int64_t>() + size, input_axes.begin());
// Slice V10
if (nullptr != steps_tensor)
std::copy(steps_tensor->Data<int64_t>(), steps_tensor->Data<int64_t>() + size, input_steps.begin());
}
// should not reach this as no kernel is registered for this condition to be triggered - just an additional safety check
@ -145,15 +275,21 @@ void SliceBase::FillVectorsFromInput(const OpKernelContext* context,
template <typename T>
Status SliceImpl(OpKernelContext* ctx,
const Tensor& input_tensor,
const Tensor& input_tensor,
std::vector<int64_t>& output_dims,
const std::vector<int64_t>& starts) {
const std::vector<int64_t>& starts,
const std::vector<int64_t>& steps) {
TensorShape output_shape(output_dims);
auto& output_tensor = *ctx->Output(0, output_shape);
// output tensor's size is 0, nothing to fill - return
if (output_shape.Size() == 0)
return Status::OK();
auto* output = output_tensor.template MutableData<T>();
const auto* output_end = output + output_tensor.Shape().Size();
SliceIterator<T> input_iterator(input_tensor, starts, output_tensor.Shape().GetDims());
SliceIterator<T> input_iterator(input_tensor, starts, output_dims, steps);
while (output != output_end)
*output++ = *input_iterator++;
@ -166,21 +302,27 @@ Status Slice<T, dynamic>::Compute(OpKernelContext* ctx) const {
ORT_ENFORCE(input_tensor_ptr != nullptr, "Missing input tensor to be processed");
const auto& input_tensor = *input_tensor_ptr;
const auto& input_dimensions = input_tensor.Shape().GetDims();
if (input_dimensions.size() < 1)
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Cannot slice scalars");
// Initialize the starts & ends to the actual tensor shape
std::vector<int64_t> starts(input_dimensions.size(), 0);
std::vector<int64_t> steps(input_dimensions.size(), 1);
std::vector<int64_t> output_dims(input_dimensions);
// Slice V10 & DynamicSlice
if (dynamic) {
std::vector<int64_t> input_starts, input_ends, input_axes;
FillVectorsFromInput(ctx, input_starts, input_ends, input_axes);
ORT_RETURN_IF_ERROR(PrepareForCompute(input_starts, input_ends, input_axes,
input_dimensions, starts, output_dims));
} else {
std::vector<int64_t> input_starts, input_ends, input_axes, input_steps;
FillVectorsFromInput(ctx, input_starts, input_ends, input_axes, input_steps);
ORT_RETURN_IF_ERROR(PrepareForCompute(input_starts, input_ends, input_axes, input_steps,
input_dimensions, starts, steps, output_dims));
}
// Slice V1-9
else {
ORT_RETURN_IF_ERROR(PrepareForCompute(attr_starts_, attr_ends_, attr_axes_,
input_dimensions, starts, output_dims));
}
return SliceImpl<T>(ctx, input_tensor, output_dims, starts);
return SliceImpl<T>(ctx, input_tensor, output_dims, starts, steps);
}
} // namespace onnxruntime

View file

@ -21,6 +21,7 @@ class SliceBase {
}
}
// compute output_dims without steps (Slice V1-9 & DynamicSlice)
Status PrepareForCompute(const std::vector<int64_t>& raw_starts,
const std::vector<int64_t>& raw_ends,
const std::vector<int64_t>& raw_axes,
@ -28,10 +29,22 @@ class SliceBase {
std::vector<int64_t>& starts,
std::vector<int64_t>& output_dims) const;
// compute output_dims with steps (Slice V10)
Status PrepareForCompute(const std::vector<int64_t>& raw_starts,
const std::vector<int64_t>& raw_ends,
const std::vector<int64_t>& raw_axes,
const std::vector<int64_t>& raw_steps,
const std::vector<int64_t>& input_dimensions,
std::vector<int64_t>& starts,
std::vector<int64_t>& steps,
std::vector<int64_t>& output_dims) const;
// Slice V10 & DynamicSlice
void FillVectorsFromInput(const OpKernelContext* context,
std::vector<int64_t>& raw_starts,
std::vector<int64_t>& raw_ends,
std::vector<int64_t>& raw_axes) const;
std::vector<int64_t>& input_starts,
std::vector<int64_t>& input_ends,
std::vector<int64_t>& input_axes,
std::vector<int64_t>& input_steps) const;
std::vector<int64_t> attr_starts_, attr_ends_, attr_axes_;
};

View file

@ -119,47 +119,70 @@ struct ExtentAxisCounters {
gsl::span<const int64_t> extents_; // The extents of each axis
};
// A std::vector that holds the number of entries to skip to go to the next axis start given an extent in each axis
// A std::vector that holds the number of entries to skip to go to the next axis start given an extent
// and optionally steps along each axis:
// This is used by the SliceIterator to iterate over a slice of a tensor
struct SliceSkips : std::vector<int64_t> {
SliceSkips(const TensorShape& input_shape, gsl::span<const int64_t> extents)
: std::vector<int64_t>(input_shape.NumDimensions(), 0) {
SliceSkips(const TensorShape& input_shape, gsl::span<const int64_t> extents, gsl::span<const int64_t> steps)
: std::vector<int64_t>(input_shape.NumDimensions(), 0) {
auto& dims = input_shape.GetDims();
ORT_ENFORCE(static_cast<ptrdiff_t>(dims.size()) == extents.size());
size_t pitch = dims.back();
back() = pitch - extents[size() - 1];
for (size_t i = size() - 1; i-- > 0;) {
ORT_ENFORCE(static_cast<ptrdiff_t>(dims.size()) == extents.size() &&
static_cast<ptrdiff_t>(dims.size()) >= steps.size());
int64_t inner_most_dim = dims.size() - 1;
// assume step == 1 if not present
ptrdiff_t steps_size = steps.size();
int64_t steps_i = 1;
if (inner_most_dim >= 0 && static_cast<ptrdiff_t>(inner_most_dim) < steps_size)
steps_i = steps[inner_most_dim];
size_t pitch = 1;
for (size_t i = size(); i-- > 0;) {
auto prevPitch = pitch;
pitch *= dims[i];
operator[](i) = pitch - prevPitch * extents[i];
// assume step == 1 if not present
int64_t steps_i_minus_1 = 1;
if (i > 0 && static_cast<ptrdiff_t>(i) - 1 < steps_size)
steps_i_minus_1 = steps[i - 1];
// first "revert" back to the old starting position (term with -ve sign)
// and then "step" over the pitch accordingly (term with +ve sign)
operator[](i) = steps_i_minus_1 * pitch - steps_i * extents[i] * prevPitch;
steps_i = steps_i_minus_1;
}
}
};
// This provides easy sequential iteration over a subset of a tensor given a span of starts & extents
// This provides easy sequential iteration over a subset of a tensor given a span of starts, extents & optionally steps
template <typename T>
struct SliceIterator {
SliceIterator(const Tensor& tensor, gsl::span<const int64_t> starts, gsl::span<const int64_t> extents)
: tensor_(tensor), extents_(extents), skips_(tensor_.Shape(), extents), indices_(extents.size(), 0) {
SliceIterator(const Tensor& tensor, gsl::span<const int64_t> starts,
gsl::span<const int64_t> extents, gsl::span<const int64_t> steps)
: tensor_(tensor), extents_(extents), skips_(tensor_.Shape(), extents, steps), indices_(extents.size(), 0) {
auto& dims = tensor_.Shape().GetDims();
Init(dims, starts);
Init(dims, starts, steps);
}
// This construct takes a explicit tensor_shape which might be different from the shape defined in input tensor.
// The explicit tensor_shape usually has inner most axis flattened. For example, given shape[1,4,4,2], if last axis
// does not have padding or slice, then it will be flattened as [1,4,8] for better performance (One inner most copy instead of 4).
SliceIterator(const Tensor& tensor, const TensorShape& tensor_shape, gsl::span<const int64_t> starts, gsl::span<const int64_t> extents)
: tensor_(tensor), extents_(extents), skips_(tensor_shape, extents), indices_(extents.size(), 0) {
// This construct takes a explicit tensor_shape which might be different from the shape defined in input tensor.
// The explicit tensor_shape usually has inner most axis flattened. For example, given shape[1,4,4,2], if last axis
// does not have padding or slice, then it will be flattened as [1,4,8] for better performance (One inner most copy instead of 4).
// Also supports arbitrary positive and negative stepping along individual axes
SliceIterator(const Tensor& tensor, const TensorShape& tensor_shape, gsl::span<const int64_t> starts,
gsl::span<const int64_t> extents, gsl::span<const int64_t> steps)
: tensor_(tensor), extents_(extents), skips_(tensor_shape, extents, steps), indices_(extents.size(), 0) {
auto& dims = tensor_shape.GetDims();
Init(dims, starts);
Init(dims, starts, steps);
}
// Initialize initial skip and inner_extent.
void Init(const std::vector<int64_t>& dims, gsl::span<const int64_t> starts) {
void Init(const std::vector<int64_t>& dims, gsl::span<const int64_t> starts,
gsl::span<const int64_t> steps) {
ORT_ENFORCE(static_cast<ptrdiff_t>(dims.size()) == starts.size() && static_cast<ptrdiff_t>(dims.size()) == extents_.size());
ORT_ENFORCE(static_cast<ptrdiff_t>(dims.size()) == starts.size() &&
static_cast<ptrdiff_t>(dims.size()) == extents_.size() &&
static_cast<ptrdiff_t>(dims.size()) >= steps.size());
size_t pitch = 1;
// Initial skip, so that input_ points to the first element to copy
@ -169,6 +192,8 @@ struct SliceIterator {
}
inner_extent_ = extents_[dims.size() - 1];
inner_step_ = static_cast<ptrdiff_t>(dims.size()) == steps.size()
? steps[dims.size() - 1] : 1;
}
void AdvanceOverInnerExtent() {
@ -181,7 +206,8 @@ struct SliceIterator {
}
const T* operator++(int) {
const T* input = input_++;
const T* input = input_;
input_ += inner_step_;
if (++inner_counter_ == inner_extent_) {
inner_counter_ = 0;
AdvanceOverInnerExtent();
@ -189,7 +215,13 @@ struct SliceIterator {
return input;
}
T* CopyInnermostAxis(T* output) {
// spliting the function that copies the innermost dimension into 2 separate methods,
// as this is most likely being called within a loop
// and we want to avoid the check inside to avoid overhead
// upto the caller to call the relevant one
// Assumes inner_step_ == 1
T* CopyInnermostAxisSolitaryInnerStep(T* output) {
std::copy(input_, input_ + inner_extent_, output);
input_ += inner_extent_;
output += inner_extent_;
@ -197,11 +229,20 @@ struct SliceIterator {
return output;
}
// Assumes generic inner_step_
T* CopyInnermostAxisNonSolitaryInnerStep(T* output) {
for (size_t i = 0; i < inner_extent_; ++i) {
*output++ = *input_;
input_ += inner_step_;
}
return output;
}
private:
const Tensor& tensor_;
const T* input_{tensor_.template Data<T>()};
gsl::span<const int64_t> extents_;
size_t inner_counter_{}, inner_extent_;
size_t inner_counter_{}, inner_extent_, inner_step_;
SliceSkips skips_;
std::vector<int64_t> indices_; // There is no index for innermost axis since it's a special case
};
@ -221,4 +262,4 @@ inline void CopyCpuTensor(const Tensor* src, Tensor* tgt) {
}
}
} // namespace onnxruntime
} // namespace onnxruntime

View file

@ -492,8 +492,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain,
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, float, LSTM);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, double, LSTM);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, MLFloat16, LSTM);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int32_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int64_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, 9, int32_t, Slice);
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, 9, int64_t, Slice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int32_t, DynamicSlice);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int64_t, DynamicSlice);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 9, Compress);
@ -756,8 +756,8 @@ static void RegisterCudaKernels(KernelRegistry& kernel_registry) {
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, float, LSTM)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, double, LSTM)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 7, MLFloat16, LSTM)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, 9, int32_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, 9, int64_t, Slice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int32_t, DynamicSlice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, int64_t, DynamicSlice)>());
kernel_registry.Register(BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 9, Compress)>());

View file

@ -7,10 +7,26 @@
namespace onnxruntime {
namespace cuda {
#define REGISTER_VERSIONED_TYPED_SLICE(TIND) \
ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \
Slice, \
kOnnxDomain, \
1, 9, \
TIND, \
kCudaExecutionProvider, \
KernelDefBuilder().InputMemoryType<OrtMemTypeCPUInput>(1). \
InputMemoryType<OrtMemTypeCPUInput>(2). \
InputMemoryType<OrtMemTypeCPUInput>(3). \
TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()). \
TypeConstraint("Tind", DataTypeImpl::GetTensorType<TIND>()), \
Slice<TIND,false>);
#define REGISTER_TYPED_SLICE(NAME, TIND, DYNAMIC) \
REGISTER_VERSIONED_TYPED_SLICE(int32_t)
REGISTER_VERSIONED_TYPED_SLICE(int64_t)
#define REGISTER_TYPED_DYNAMICSLICE(TIND) \
ONNX_OPERATOR_TYPED_KERNEL_EX( \
NAME, \
DynamicSlice, \
kOnnxDomain, \
1, \
TIND, \
@ -20,12 +36,10 @@ namespace cuda {
InputMemoryType<OrtMemTypeCPUInput>(3). \
TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()). \
TypeConstraint("Tind", DataTypeImpl::GetTensorType<TIND>()), \
Slice<TIND,DYNAMIC>);
Slice<TIND,true>);
REGISTER_TYPED_SLICE(Slice, int32_t, false)
REGISTER_TYPED_SLICE(Slice, int64_t, false)
REGISTER_TYPED_SLICE(DynamicSlice, int32_t, true )
REGISTER_TYPED_SLICE(DynamicSlice, int64_t, true )
REGISTER_TYPED_DYNAMICSLICE(int32_t)
REGISTER_TYPED_DYNAMICSLICE(int64_t)
template<typename Tind, bool dynamic>
Status Slice<Tind, dynamic>::ComputeInternal(OpKernelContext* ctx) const {
@ -36,13 +50,14 @@ Status Slice<Tind, dynamic>::ComputeInternal(OpKernelContext* ctx) const {
// Initialize the starts & ends to the actual tensor shape
const size_t dimension_count = input_dimensions.size();
std::vector<int64_t> starts(dimension_count, 0);
std::vector<int64_t> steps(input_dimensions.size(), 1);
std::vector<int64_t> output_dims(input_dimensions);
if (dynamic) {
std::vector<int64_t> input_starts, input_ends, input_axes;
FillVectorsFromInput(ctx, input_starts, input_ends, input_axes);
std::vector<int64_t> input_starts, input_ends, input_axes, input_steps;
FillVectorsFromInput(ctx, input_starts, input_ends, input_axes, input_steps);
ORT_RETURN_IF_ERROR(PrepareForCompute(input_starts, input_ends, input_axes,
input_dimensions, starts, output_dims));
input_steps, input_dimensions, starts, steps, output_dims));
} else {
ORT_RETURN_IF_ERROR(PrepareForCompute(attr_starts_, attr_ends_, attr_axes_,

View file

@ -7,156 +7,505 @@
namespace onnxruntime {
namespace test {
TEST(SliceTest, Slice1D) {
OpTester test("Slice");
template <typename T>
void RunSliceTest(const std::vector<int64_t>& input_dims,
const std::vector<T>& input_vals,
const std::vector<int64_t>& starts,
const std::vector<int64_t>& ends,
const std::vector<int64_t>& axes,
const std::vector<int64_t>& steps,
const std::vector<int64_t>& output_dims,
const std::vector<T>& output_vals,
bool v10_only = false) {
// V1-9
if (!v10_only)
{
OpTester testv9("Slice", 9);
testv9.AddAttribute("starts", starts);
testv9.AddAttribute("ends", ends);
if (axes.size() != 0)
testv9.AddAttribute("axes", axes);
testv9.AddInput<T>("data", input_dims, input_vals);
testv9.AddOutput<T>("output", output_dims, output_vals);
testv9.Run();
}
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddAttribute("starts", std::vector<int64_t>{2});
test.AddAttribute("ends", std::vector<int64_t>{4});
// V10
OpTester testv10("Slice", 10);
testv10.AddInput<T>("data", input_dims, input_vals);
testv10.AddInput<int64_t>("starts", {static_cast<int64_t>(starts.size())}, starts);
testv10.AddInput<int64_t>("ends", {static_cast<int64_t>(ends.size())}, ends);
if (axes.size() != 0)
testv10.AddInput<int64_t>("axes", {static_cast<int64_t>(axes.size())}, axes);
if (steps.size() != 0)
testv10.AddInput<int64_t>("steps", {static_cast<int64_t>(steps.size())}, steps);
testv10.AddOutput<T>("output", output_dims, output_vals);
testv10.Run();
}
test.AddInput<float>("data", {6}, {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f});
test.AddOutput<float>("output", {2}, {2.0f, 3.0f});
test.Run();
// Slice V1-9 & Slice V10 can both run the following tests
TEST(SliceTest, Slice1D_InvalidStartEndRange) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{3},
{2},
{0},
{},
{0},
{});
}
TEST(SliceTest, Slice1D_ValidStartEndRange_NoOutput) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{2},
{2},
{0},
{},
{0},
{});
}
TEST(SliceTest, Slice1D_Regular) {
RunSliceTest<float>
({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{2},
{4},
{0},
{},
{2},
{2.0f, 3.0f});
}
TEST(SliceTest, Slice1D_Perf) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddAttribute("starts", std::vector<int64_t>{2});
test.AddAttribute("ends", std::vector<int64_t>{502});
std::vector<float> input(1000, 2.0f);
std::vector<float> output(500, 2.0f);
test.AddInput<float>("data", {1000}, input);
test.AddOutput<float>("output", {500}, output);
test.Run();
RunSliceTest<float>({1000},
input,
{2},
{502},
{0},
{},
{500},
output);
}
TEST(SliceTest, Slice2D_OutOfBounds) {
OpTester test("Slice");
TEST(SliceTest, Slice1D_EndOutOfBounds) {
RunSliceTest<float>({6},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f},
{0},
{10},
{},
{},
{6},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f});
}
test.AddAttribute("axes", std::vector<int64_t>{0, 1});
test.AddAttribute("starts", std::vector<int64_t>{0, 1000});
test.AddAttribute("ends", std::vector<int64_t>{10, 1000});
TEST(SliceTest, Slice1D_StartAndEndOutOfBounds) {
RunSliceTest<float>({6},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f},
{1000},
{1001},
{},
{},
{0},
{});
}
test.AddInput<float>("data", {2, 3}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f});
test.AddOutput<float>("output", {2, 0}, {});
test.Run();
TEST(SliceTest, Slice2D_StartAndEndOutOfBounds) {
RunSliceTest<float>({2, 3},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f},
{0, 1000},
{10, 1000},
{0, 1},
{},
{2, 0},
{});
}
TEST(SliceTest, Slice2D_OneAxis) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddAttribute("starts", std::vector<int64_t>{1});
test.AddAttribute("ends", std::vector<int64_t>{3});
test.AddInput<float>("data", {6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f});
test.AddOutput<float>("output", {2, 4},
{10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f});
test.Run();
RunSliceTest<float>({6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f},
{1},
{3},
{0},
{},
{2, 4},
{10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f});
}
TEST(SliceTest, Slice2D_TwoAxes) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{1, 0});
test.AddAttribute("starts", std::vector<int64_t>{2, 3});
test.AddAttribute("ends", std::vector<int64_t>{1000, -1});
test.AddInput<float>("data", {6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f});
test.AddOutput<float>("output", {2, 2},
{32.0f, 33.0f,
42.0f, 43.0f});
test.Run();
RunSliceTest<float>({6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f},
{2, 3},
{1000 ,-1},
{1, 0},
{},
{2, 2},
{32.0f, 33.0f,
42.0f, 43.0f});
}
TEST(SliceTest, Slice2D_TwoAxesEque) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{1, 0});
test.AddAttribute("starts", std::vector<int64_t>{2, 3});
test.AddAttribute("ends", std::vector<int64_t>{1000, 3});
test.AddInput<float>("data", {6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f});
test.AddOutput<float>("output", {0, 2},
{});
test.Run();
RunSliceTest<float>({6, 4},
{00.0f, 01.0f, 02.0f, 03.0f,
10.0f, 11.0f, 12.0f, 13.0f,
20.0f, 21.0f, 22.0f, 23.0f,
30.0f, 31.0f, 32.0f, 33.0f,
40.0f, 41.0f, 42.0f, 43.0f,
50.0f, 51.0f, 52.0f, 53.0f},
{2, 3},
{1000, 3},
{1, 0},
{},
{0, 2},
{});
}
TEST(SliceTest, Slice3D) {
OpTester test("Slice");
RunSliceTest<float>({3, 3, 3},
{111.0f, 112.0f, 113.0f,
121.0f, 122.0f, 123.0f,
131.0f, 132.0f, 133.0f,
test.AddAttribute("starts", std::vector<int64_t>{0, 1, 1});
test.AddAttribute("ends", std::vector<int64_t>{1000, 1000, 1000});
211.0f, 212.0f, 213.0f,
221.0f, 222.0f, 223.0f,
231.0f, 232.0f, 233.0f,
test.AddInput<float>("data", {3, 3, 3},
{111.0f, 112.0f, 113.0f,
121.0f, 122.0f, 123.0f,
131.0f, 132.0f, 133.0f,
311.0f, 312.0f, 313.0f,
321.0f, 322.0f, 323.0f,
331.0f, 332.0f, 333.0f},
{0, 1, 1},
{1000, 1000, 1000},
{},
{},
{3, 2, 2},
{122.0f, 123.0f,
132.0f, 133.0f,
211.0f, 212.0f, 213.0f,
221.0f, 222.0f, 223.0f,
231.0f, 232.0f, 233.0f,
222.0f, 223.0f,
232.0f, 233.0f,
311.0f, 312.0f, 313.0f,
321.0f, 322.0f, 323.0f,
331.0f, 332.0f, 333.0f});
test.AddOutput<float>("output", {3, 2, 2},
{122.0f, 123.0f,
132.0f, 133.0f,
222.0f, 223.0f,
232.0f, 233.0f,
322.0f, 323.0f,
332.0f, 333.0f});
test.Run();
322.0f, 323.0f,
332.0f, 333.0f});
}
TEST(SliceTest, Slice1D_Int) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddAttribute("starts", std::vector<int64_t>{2});
test.AddAttribute("ends", std::vector<int64_t>{4});
test.AddInput<int32_t>("data", {6}, {0L, 1L, 2L, 3L, 4L, 5L});
test.AddOutput<int32_t>("output", {2}, {2L, 3L});
test.Run();
RunSliceTest<int32_t>({6},
{0L, 1L, 2L, 3L, 4L, 5L},
{2},
{4},
{0},
{},
{2},
{2L, 3L});
}
TEST(SliceTest, Slice1D_String) {
OpTester test("Slice");
test.AddAttribute("axes", std::vector<int64_t>{0});
test.AddAttribute("starts", std::vector<int64_t>{2});
test.AddAttribute("ends", std::vector<int64_t>{4});
test.AddInput<std::string>("data", {6}, {"0", "1", "2", "3", "4", "5"});
test.AddOutput<std::string>("output", {2}, {"2", "3"});
test.Run();
RunSliceTest<std::string>({6},
{"0", "1", "2", "3", "4", "5"},
{2},
{4},
{0},
{},
{2},
{"2", "3"});
}
} // namespace Test
// Only Slice V10 can run the following tests
TEST(SliceTest, Slice1D_WithPositiveSteps) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{0},
{6},
{0},
{2},
{3},
{0.0f, 2.0f, 4.0f},
true);
}
// In numpy:
// x = np.array([1, 2, 3, 4])
// y = x[-1:-4:-1]
TEST(SliceTest, Slice1D_WithNegativeSteps_Regular) {
RunSliceTest<float>({4},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{-4},
{0},
{-1},
{3},
{4.0f, 3.0f, 2.0f},
true);
}
TEST(SliceTest, Slice1D_WithNegativeSteps_EndOutOfBounds_1) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{0},
{6},
{0},
{-1},
{0},
{},
true);
}
TEST(SliceTest, Slice1D_WithNegativeSteps_EndOutOfBounds_2) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{0},
{-10},
{0},
{-1},
{1},
{0.0f},
true);
}
TEST(SliceTest, Slice1D_WithNegativeSteps_ValidStartEndRange) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{5},
{0},
{0},
{-1},
{5},
{5.0f, 4.0f, 3.0f, 2.0f, 1.0f},
true);
}
TEST(SliceTest, Slice1D_WithNegativeSteps_StartOutOfBounds) {
RunSliceTest<float>({6},
{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f},
{7},
{0},
{0},
{-3},
{2},
{5.0f, 2.0f},
true);
}
TEST(SliceTest, Slice2D_WithPositiveSteps_1) {
RunSliceTest<float>({2, 4},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f},
{1, 0},
{2, 3},
{0, 1},
{1, 2},
{1, 2},
{5.0f, 7.0f},
true);
}
TEST(SliceTest, Slice2D_WithPositiveSteps_2) {
RunSliceTest<float>({2, 4},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f},
{0, 1},
{-1, 1000},
{}, // default axes
{}, // default steps
{1, 3},
{2.0f, 3.0f, 4.0f},
true);
}
TEST(SliceTest, Slice2D_WithNegativeSteps_1) {
RunSliceTest<float>({2, 4},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f},
{1, 0},
{2, 3},
{0, 1},
{-1, -2},
{0, 0},
{},
true);
}
TEST(SliceTest, Slice2D_WithNegativeSteps_2) {
RunSliceTest<float>({2, 4},
{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f},
{1, 3},
{0, 1},
{0, 1},
{-1, -2},
{1, 1},
{8.0f},
true);
}
TEST(SliceTest, Slice3D_WithPositiveSteps_AllAxes) {
RunSliceTest<int32_t>({3, 3, 3},
{27, 20, 2,
4, 26, 11,
26, 5, 17,
0, 21, 6,
22, 13, 29,
19, 17, 27,
4, 20, 12,
3, 9, 24,
17, 6, 24},
{0, 1, 1},
{1000, 1000, 1000},
{0, 1, 2},
{2, 2, 2},
{2, 1, 1},
{26, 9},
true);
}
TEST(SliceTest, Slice3D_WithPositiveAndNegativeSteps_SubsetOfAxes_1) {
RunSliceTest<int32_t>({3, 3, 3},
{27, 20, 2,
4, 26, 11,
26, 5, 17,
0, 21, 6,
22, 13, 29,
19, 17, 27,
4, 20, 12,
3, 9, 24,
17, 6, 24},
{1, 4},
{1000, 1},
{1, 2},
{3, -2},
{3, 1, 1},
{11, 29, 24},
true);
}
TEST(SliceTest, Slice3D_WithPositiveAndNegativeSteps_SubsetOfAxes_2) {
RunSliceTest<int32_t>({3, 3, 3},
{27, 20, 2,
4, 26, 11,
26, 5, 17,
0, 21, 6,
22, 13, 29,
19, 17, 27,
4, 20, 12,
3, 9, 24,
17, 6, 24},
{1, 4},
{1000, 2},
{1, 2},
{3, -2},
{3, 1, 0},
{},
true);
}
// Slice for Reversing
// With numeric_limit_max, it means slice to the end of a dimension
// (whichever direction we are stepping)
TEST(SliceTest, Slice1D_ReverseAllAxes_1) {
RunSliceTest<float>({4},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{std::numeric_limits<int32_t>::max()},
{0},
{-1},
{4},
{4.0f, 3.0f, 2.0f, 1.0f},
true);
}
// With numeric_limit_min, the end value should be clamped to -1
TEST(SliceTest, Slice1D_ReverseAllAxes_2) {
RunSliceTest<float>({4},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{std::numeric_limits<int32_t>::min()},
{0},
{-1},
{4},
{4.0f, 3.0f, 2.0f, 1.0f},
true);
}
// giving an end value < -{dim_value} should also clamp it to -1
TEST(SliceTest, Slice1D_ReverseAllAxes_3) {
RunSliceTest<float>({4},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{-5},
{0},
{-1},
{4},
{4.0f, 3.0f, 2.0f, 1.0f},
true);
}
TEST(SliceTest, Slice2D_ReverseAllAxes) {
RunSliceTest<float>({2, 2},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1, -1},
{std::numeric_limits<int64_t>::max(), std::numeric_limits<int64_t>::max()},
{0, 1},
{-1, -1},
{2, 2},
{4.0f, 3.0f, 2.0f, 1.0f},
true);
}
TEST(SliceTest, Slice2D_ReverseSubsetOfAxes_1) {
RunSliceTest<float>({2, 2},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{std::numeric_limits<int64_t>::max()},
{1}, // axis = 1 only
{-1},
{2, 2},
{2.0f, 1.0f, 4.0f, 3.0f},
true);
}
TEST(SliceTest, Slice2D_ReverseSubsetOfAxes_2) {
RunSliceTest<float>({2, 2},
{1.0f, 2.0f, 3.0f, 4.0f},
{-1},
{std::numeric_limits<int64_t>::max()}, // end of dimension
{0}, // axis = 0 only
{-1},
{2, 2},
{3.0f, 4.0f, 1.0f, 2.0f},
true);
}
// Slice for implicit copy
TEST(SliceTest, Slice2D_ImplicitCopyBySlicingADimensionFully) {
RunSliceTest<float>({2, 2},
{1.0f, 2.0f, 3.0f, 4.0f},
{0},
{std::numeric_limits<int64_t>::max()}, // end of dimension
{1}, // axis = 1 only
{1},
{2, 2},
{1.0f, 2.0, 3.0f, 4.0f},
true);
}
} // namespace test
} // namespace onnxruntime

View file

@ -83,13 +83,6 @@ backend_test.exclude(r'('
'|^test_vgg19_cpu.*'
'|^test_zfnet512_cpu.*'
'|^test_gru_seq_length_cpu.*'
'|^test_slice_cpu.*'
'|^test_slice_default_axes_cpu.*'
'|^test_slice_default_steps_cpu.*'
'|^test_slice_end_out_of_bounds_cpu.*'
'|^test_slice_neg_cpu.*'
'|^test_slice_neg_steps_cpu.*'
'|^test_slice_start_out_of_bounds_cpu.*'
'|^test_averagepool_2d_ceil_cpu.*'
'|^test_maxpool_2d_ceil_cpu.*'
'|^test_maxpool_2d_dilations_cpu.*'