mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
Update Squeeze, Unsqueeze, Split and ReduceSum kernel for Opset13 (#5691)
* Split change * ReduceSum and Split change * Other op changes, Grad builder, tests, registering required opset 13 ops * Rebase fixes * Fix tests, add some more * Review changes, rebase * Fix windows build * Disable new tests for TesnorRT EP * Disable unsupported for OpenVINO Co-authored-by: Aishwarya <aibhanda@OrtTrainingDev4.af05slrtruoetgaxwwjv5nsq5e.px.internal.cloudapp.net>
This commit is contained in:
parent
830f567be8
commit
6d8e81cb08
21 changed files with 729 additions and 266 deletions
|
|
@ -326,10 +326,10 @@ class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOn
|
|||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, float, ReduceProd);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, int32_t, ReduceProd);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, int64_t, ReduceProd);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, float, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, double, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int32_t, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int64_t, ReduceSum);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, float, ReduceSum);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, double, ReduceSum);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, int32_t, ReduceSum);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, int64_t, ReduceSum);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, float, ReduceSumSquare);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, double, ReduceSumSquare);
|
||||
class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, int32_t, ReduceSumSquare);
|
||||
|
|
@ -346,9 +346,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Co
|
|||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Concat);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Gather);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Slice);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Split);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Squeeze);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Unsqueeze);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Split);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Squeeze);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Unsqueeze);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Det);
|
||||
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, ScatterElements);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, NonMaxSuppression);
|
||||
|
|
@ -529,6 +529,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Po
|
|||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, DepthToSpace);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, SpaceToDepth);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Slice);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Split);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Unsqueeze);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Squeeze);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Transpose);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Tile);
|
||||
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Gather);
|
||||
|
|
@ -571,6 +574,10 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain,
|
|||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, ReduceSumSquare);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, ReduceSumSquare);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, ReduceSumSquare);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int64_t, ReduceSum);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Resize);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, Resize);
|
||||
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, uint8_t, Resize);
|
||||
|
|
@ -1048,9 +1055,9 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
|
|||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Concat)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Gather)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Slice)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Split)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Squeeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Unsqueeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Split)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Squeeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, Unsqueeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Det)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, ScatterElements)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11,
|
||||
|
|
@ -1155,14 +1162,14 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
|
|||
int32_t, ReduceProd)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
int64_t, ReduceProd)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, float,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int32_t,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, double,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, int64_t,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
float, ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
int32_t, ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
double, ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
int64_t, ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
float, ReduceSumSquare)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12,
|
||||
|
|
@ -1378,6 +1385,9 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
|
|||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Log)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Pow)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Slice)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Split)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Unsqueeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Squeeze)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Transpose)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Tile)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Gather)>,
|
||||
|
|
@ -1455,6 +1465,14 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
|
|||
ReduceSumSquare)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double,
|
||||
ReduceSumSquare)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int64_t,
|
||||
ReduceSum)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13,
|
||||
float, Resize)>,
|
||||
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13,
|
||||
|
|
@ -1656,4 +1674,4 @@ std::shared_ptr<KernelRegistry> CPUExecutionProvider::GetKernelRegistry() const
|
|||
std::unique_ptr<IDataTransfer> CPUExecutionProvider::GetDataTransfer() const {
|
||||
return onnxruntime::make_unique<CPUDataTransfer>();
|
||||
}
|
||||
} // namespace onnxruntime
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -166,11 +166,14 @@ REGISTER_UNARY_ELEMENTWISE_KERNEL(ReduceProd, 13);
|
|||
REGISTER_UNARY_ELEMENTWISE_KERNEL_INT64_ONLY(ReduceProd, 13);
|
||||
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL(ReduceSum, 1, 10);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL(ReduceSum, 11);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL_INT64_ONLY(ReduceSum, 1, 10);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL_INT64_ONLY(ReduceSum, 11);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL_DOUBLE_ONLY(ReduceSum, 1, 10);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL_DOUBLE_ONLY(ReduceSum, 11);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL(ReduceSum, 11, 12);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL_INT64_ONLY(ReduceSum, 11, 12);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL_DOUBLE_ONLY(ReduceSum, 11, 12);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL(ReduceSum, 13);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL_INT64_ONLY(ReduceSum, 13);
|
||||
REGISTER_UNARY_ELEMENTWISE_KERNEL_DOUBLE_ONLY(ReduceSum, 13);
|
||||
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL(ReduceSumSquare, 1, 10);
|
||||
REGISTER_UNARY_ELEMENTWISE_VERSIONED_KERNEL_DOUBLE_ONLY(ReduceSumSquare, 1, 10);
|
||||
|
|
@ -560,7 +563,7 @@ Status ReduceProd<T>::Compute(OpKernelContext* ctx) const {
|
|||
template <typename T>
|
||||
Status ReduceSum<T>::Compute(OpKernelContext* ctx) const {
|
||||
ResultsNoTransposePrepareForReduce last_results;
|
||||
CommonReduce<T, ReduceAggregatorSum<T>>(ctx, axes_, keepdims_, last_results);
|
||||
CommonReduce<T, ReduceAggregatorSum<T>>(ctx, axes_, keepdims_, last_results, noop_with_empty_axes_);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
|||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllTensorTypes()),
|
||||
Concat);
|
||||
|
||||
// Opset 13 .
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
Concat,
|
||||
13,
|
||||
|
|
|
|||
|
|
@ -17,5 +17,4 @@ ONNX_CPU_OPERATOR_KERNEL(
|
|||
13,
|
||||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()).TypeConstraint("T1", DataTypeImpl::GetTensorType<int64_t>()),
|
||||
Shape);
|
||||
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -23,9 +23,22 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
|||
Split);
|
||||
|
||||
// Opset 11 starts to support Neg Axis.
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
||||
Split,
|
||||
11,
|
||||
12,
|
||||
KernelDefBuilder().TypeConstraint("T",
|
||||
std::vector<MLDataType>{
|
||||
DataTypeImpl::GetTensorType<float>(),
|
||||
DataTypeImpl::GetTensorType<int32_t>(),
|
||||
DataTypeImpl::GetTensorType<int64_t>(),
|
||||
DataTypeImpl::GetTensorType<std::string>()}),
|
||||
Split);
|
||||
|
||||
// Opset 13 starts to supports 'split' as optional input.
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
Split,
|
||||
13,
|
||||
KernelDefBuilder().TypeConstraint("T",
|
||||
std::vector<MLDataType>{
|
||||
DataTypeImpl::GetTensorType<float>(),
|
||||
|
|
@ -48,7 +61,7 @@ Status SplitBase::PrepareForCompute(const TensorShape& input_shape, int num_outp
|
|||
? 1 // we multiply by this value so must be 1 not 0
|
||||
: gsl::narrow<int>(input_shape.SizeFromDimension(axis + 1));
|
||||
|
||||
if (split_sizes_.empty()) {
|
||||
if (split_sizes.empty()) {
|
||||
// equal split based on number of outputs
|
||||
if (split_dim_size % static_cast<size_t>(num_outputs) != 0) {
|
||||
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Input cannot be split evenly on selected axis. Input shape=", input_shape,
|
||||
|
|
@ -58,17 +71,18 @@ Status SplitBase::PrepareForCompute(const TensorShape& input_shape, int num_outp
|
|||
// populate split_sizes with the same size for each output
|
||||
split_sizes = std::vector<int64_t>(static_cast<size_t>(num_outputs), split_dim_size / num_outputs);
|
||||
} else {
|
||||
if (split_sizes_.size() != static_cast<size_t>(num_outputs) || split_size_sum_ != split_dim_size)
|
||||
int64_t split_size_sum = split_size_sum_;
|
||||
if (split_size_sum == -1){
|
||||
split_size_sum = std::accumulate(split_sizes.cbegin(), split_sizes.cend(), 0LL);
|
||||
}
|
||||
if (split_sizes.size() != static_cast<size_t>(num_outputs) || split_size_sum != split_dim_size)
|
||||
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL,
|
||||
"Cannot split using values in 'split' attribute. Axis=", axis_,
|
||||
" Input shape=", input_shape,
|
||||
" NumOutputs=", num_outputs,
|
||||
" Num entries in 'split' (must equal number of outputs) was ", split_sizes_.size(),
|
||||
" Sum of sizes in 'split' (must equal size of selected axis) was ", split_size_sum_);
|
||||
|
||||
split_sizes = split_sizes_;
|
||||
" Num entries in 'split' (must equal number of outputs) was ", split_sizes.size(),
|
||||
" Sum of sizes in 'split' (must equal size of selected axis) was ", split_size_sum);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +126,18 @@ Status Split::ComputeImpl(OpKernelContext& context, const Tensor& input) const {
|
|||
int after_dims_excluding_split = 0;
|
||||
std::vector<int64_t> split_sizes;
|
||||
|
||||
size_t num_inputs = context.InputCount();
|
||||
if (num_inputs == 2) {
|
||||
//override the attribute value with the input value for split_split
|
||||
const Tensor* split_tensor = context.Input<Tensor>(1);
|
||||
ORT_ENFORCE(split_tensor->Shape().NumDimensions() == 1, "An split tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(split_tensor->Shape()[0]);
|
||||
const auto* data = split_tensor->template Data<int64_t>();
|
||||
split_sizes.assign(data, data + nDims);
|
||||
}
|
||||
else{
|
||||
split_sizes.assign(split_sizes_.begin(), split_sizes_.end());
|
||||
}
|
||||
ORT_RETURN_IF_ERROR(PrepareForCompute(input_shape,
|
||||
num_outputs,
|
||||
axis,
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@ class SplitBase {
|
|||
SplitBase(const OpKernelInfo& info) {
|
||||
axis_ = info.GetAttrOrDefault<int64_t>("axis", 0);
|
||||
|
||||
// optional
|
||||
if (info.GetAttrs("split", split_sizes_).IsOK()) {
|
||||
split_size_sum_ = std::accumulate(split_sizes_.cbegin(), split_sizes_.cend(), 0LL);
|
||||
ORT_ENFORCE(std::all_of(split_sizes_.cbegin(), split_sizes_.cend(), [](int64_t value) { return value >= 0; }),
|
||||
"Invalid value in 'split' attribute. All values must be > 0");
|
||||
size_t numInputs = info.GetInputCount();
|
||||
if(numInputs == 1){
|
||||
// optional
|
||||
if (info.GetAttrs("split", split_sizes_).IsOK()) {
|
||||
split_size_sum_ = std::accumulate(split_sizes_.cbegin(), split_sizes_.cend(), 0LL);
|
||||
ORT_ENFORCE(std::all_of(split_sizes_.cbegin(), split_sizes_.cend(), [](int64_t value) { return value >= 0; }),
|
||||
"Invalid value in 'split' attribute. All values must be > 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +35,7 @@ class SplitBase {
|
|||
|
||||
int64_t axis_;
|
||||
std::vector<int64_t> split_sizes_;
|
||||
int64_t split_size_sum_ = 0;
|
||||
int64_t split_size_sum_ = -1;
|
||||
};
|
||||
|
||||
class Split final : public OpKernel, public SplitBase {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,19 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
|||
Squeeze);
|
||||
|
||||
// Opset 11 starts to support Neg Axis.
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
||||
Squeeze,
|
||||
11,
|
||||
12,
|
||||
KernelDefBuilder()
|
||||
.TypeConstraint("T", DataTypeImpl::AllTensorTypes())
|
||||
.Alias(0, 0),
|
||||
Squeeze);
|
||||
|
||||
// axes is input instead of attribute
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
Squeeze,
|
||||
13,
|
||||
KernelDefBuilder()
|
||||
.TypeConstraint("T", DataTypeImpl::AllTensorTypes())
|
||||
.Alias(0, 0),
|
||||
|
|
|
|||
|
|
@ -14,27 +14,30 @@ class SqueezeBase {
|
|||
protected:
|
||||
explicit SqueezeBase(const OpKernelInfo& info) {
|
||||
std::vector<int64_t> axes;
|
||||
// Parse attribute 'axes'
|
||||
Status status = info.GetAttrs<int64_t>("axes", axes);
|
||||
size_t numInputs = info.GetInputCount();
|
||||
if (numInputs == 1) {
|
||||
// Parse attribute 'axes'
|
||||
Status status = info.GetAttrs<int64_t>("axes", axes);
|
||||
|
||||
// Handle out of order and repeating dims when 'axes' exists.
|
||||
if (status.IsOK()) {
|
||||
std::sort(axes.begin(), axes.end());
|
||||
axes.erase(std::unique(axes.begin(), axes.end()), axes.end());
|
||||
axes_ = axes;
|
||||
// Handle out of order and repeating dims when 'axes' exists.
|
||||
if (status.IsOK()) {
|
||||
std::sort(axes.begin(), axes.end());
|
||||
axes.erase(std::unique(axes.begin(), axes.end()), axes.end());
|
||||
axes_ = axes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<int64_t> ComputeOutputShape(
|
||||
const TensorShape& input_shape,
|
||||
const TensorShape& axes) {
|
||||
const std::vector<int64_t>& axes) {
|
||||
size_t j = 0;
|
||||
std::vector<int64_t> output_shape;
|
||||
auto num_dimensions = input_shape.NumDimensions();
|
||||
|
||||
// Handle negtive axis, then resort and uniq.
|
||||
std::vector<int64_t> axes_corrected(axes.NumDimensions());
|
||||
for (size_t i = 0; i < axes.NumDimensions(); i++) {
|
||||
std::vector<int64_t> axes_corrected(axes.size());
|
||||
for (size_t i = 0; i < axes.size(); i++) {
|
||||
axes_corrected[i] = HandleNegativeAxis(axes[i], num_dimensions);
|
||||
}
|
||||
std::sort(axes_corrected.begin(), axes_corrected.end());
|
||||
|
|
@ -53,7 +56,7 @@ class SqueezeBase {
|
|||
return output_shape;
|
||||
}
|
||||
|
||||
TensorShape axes_;
|
||||
std::vector<int64_t> axes_;
|
||||
};
|
||||
|
||||
class Squeeze final : public OpKernel, public SqueezeBase {
|
||||
|
|
@ -63,7 +66,22 @@ class Squeeze final : public OpKernel, public SqueezeBase {
|
|||
Status Compute(OpKernelContext* context) const override {
|
||||
const auto* X = context->Input<Tensor>(0);
|
||||
const TensorShape& X_shape = X->Shape();
|
||||
std::vector<int64_t> output_shape = ComputeOutputShape(X_shape.GetDims(), axes_);
|
||||
|
||||
std::vector<int64_t> axes;
|
||||
size_t num_inputs = context->InputCount();
|
||||
if (num_inputs == 2) { //axes is an input
|
||||
const Tensor* axes_tensor = context->Input<Tensor>(1);
|
||||
ORT_ENFORCE(axes_tensor != nullptr, "Axes input is null");
|
||||
ORT_ENFORCE(axes_tensor->Shape().NumDimensions() == 1,
|
||||
"An axes tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(axes_tensor->Shape()[0]);
|
||||
const auto* data = axes_tensor->template Data<int64_t>();
|
||||
axes.assign(data, data + nDims);
|
||||
} else {
|
||||
axes.assign(axes_.begin(), axes_.end());
|
||||
}
|
||||
|
||||
std::vector<int64_t> output_shape = ComputeOutputShape(X_shape, axes);
|
||||
|
||||
Tensor* Y = context->Output(0, TensorShape(output_shape));
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,19 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
|||
.TypeConstraint("T", DataTypeImpl::AllTensorTypes()),
|
||||
Unsqueeze);
|
||||
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
ONNX_CPU_OPERATOR_VERSIONED_KERNEL(
|
||||
Unsqueeze,
|
||||
11,
|
||||
12,
|
||||
KernelDefBuilder()
|
||||
.Alias(0, 0)
|
||||
.TypeConstraint("T", DataTypeImpl::AllTensorTypes()),
|
||||
Unsqueeze);
|
||||
|
||||
// axes is input instead of attribute
|
||||
ONNX_CPU_OPERATOR_KERNEL(
|
||||
Unsqueeze,
|
||||
13,
|
||||
KernelDefBuilder()
|
||||
.Alias(0, 0)
|
||||
.TypeConstraint("T", DataTypeImpl::AllTensorTypes()),
|
||||
|
|
@ -31,12 +41,26 @@ Status UnsqueezeBase::PrepareCompute(OpKernelContext* ctx, Prepare& p) const {
|
|||
ORT_ENFORCE(X != nullptr);
|
||||
auto& input_tensor = *X;
|
||||
|
||||
// New dimension count is the current dimensions + the number of entries in axes_
|
||||
// Initialize output_dims to 0 in each axis initially
|
||||
std::vector<int64_t> output_dims(axes_.size() + input_tensor.Shape().NumDimensions(), 0);
|
||||
std::vector<int64_t> axes;
|
||||
size_t num_inputs = ctx->InputCount();
|
||||
if (num_inputs == 2) { //axes is an input
|
||||
const Tensor* axes_tensor = ctx->Input<Tensor>(1);
|
||||
ORT_ENFORCE(axes_tensor != nullptr, "Axes input is null");
|
||||
ORT_ENFORCE(axes_tensor->Shape().NumDimensions() == 1,
|
||||
"An axes tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(axes_tensor->Shape()[0]);
|
||||
const auto* data = axes_tensor->template Data<int64_t>();
|
||||
axes.assign(data, data + nDims);
|
||||
} else {
|
||||
axes.assign(axes_.begin(), axes_.end());
|
||||
}
|
||||
|
||||
// Set all axes_ indices to 1 in output_dims and check for duplicates
|
||||
for (int64_t axis : axes_) {
|
||||
// New dimension count is the current dimensions + the number of entries in axes
|
||||
// Initialize output_dims to 0 in each axis initially
|
||||
std::vector<int64_t> output_dims(axes.size() + input_tensor.Shape().NumDimensions(), 0);
|
||||
|
||||
// Set all axes indices to 1 in output_dims and check for duplicates
|
||||
for (int64_t axis : axes) {
|
||||
// Valid axis range is [0, output_rank - 1]
|
||||
axis = HandleNegativeAxis(axis, output_dims.size());
|
||||
if (axis < 0 || axis >= static_cast<int64_t>(output_dims.size()))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ namespace onnxruntime {
|
|||
class UnsqueezeBase {
|
||||
protected:
|
||||
UnsqueezeBase(const OpKernelInfo& info) {
|
||||
ORT_ENFORCE(info.GetAttrs("axes", axes_).IsOK(), "Missing/Invalid 'axes' attribute value");
|
||||
size_t numInputs = info.GetInputCount();
|
||||
if (numInputs == 1) { //axes must be a valid attribute
|
||||
ORT_ENFORCE(info.GetAttrs("axes", axes_).IsOK(), "Missing/Invalid 'axes' attribute value");
|
||||
}
|
||||
}
|
||||
|
||||
struct Prepare {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,35 @@ namespace cuda {
|
|||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
|
||||
name<T>);
|
||||
|
||||
// Register with the latest version 13
|
||||
#define REGISTER_KERNEL_TYPED_13(name, T) \
|
||||
ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \
|
||||
name, \
|
||||
kOnnxDomain, \
|
||||
1, 10, \
|
||||
T, \
|
||||
kCudaExecutionProvider, \
|
||||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
|
||||
name<T>); \
|
||||
ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \
|
||||
name, \
|
||||
kOnnxDomain, \
|
||||
11, 12, \
|
||||
T, \
|
||||
kCudaExecutionProvider, \
|
||||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
|
||||
name<T>); \
|
||||
ONNX_OPERATOR_TYPED_KERNEL_EX( \
|
||||
name, \
|
||||
kOnnxDomain, \
|
||||
13, \
|
||||
T, \
|
||||
kCudaExecutionProvider, \
|
||||
KernelDefBuilder() \
|
||||
.InputMemoryType<OrtMemTypeCPUInput>(1) \
|
||||
.TypeConstraint("T", DataTypeImpl::GetTensorType<T>()), \
|
||||
name<T>);
|
||||
|
||||
// TODO ReduceKernel::ReduceKernelShared() is still used by some other training classes though it's not used here - this should be refactored.
|
||||
template <bool allow_multi_axes>
|
||||
template <typename T, typename OutT, cudnnReduceTensorIndices_t ReduceTensorIndices>
|
||||
|
|
@ -618,11 +647,32 @@ template <bool allow_multi_axes>
|
|||
template <typename T, cudnnReduceTensorIndices_t ReduceTensorIndices>
|
||||
Status ReduceKernel<allow_multi_axes>::ComputeImpl(OpKernelContext* ctx, cudnnReduceTensorOp_t cudnn_reduce_op) const {
|
||||
const Tensor* X = ctx->Input<Tensor>(0);
|
||||
std::vector<int64_t> axes;
|
||||
|
||||
size_t num_inputs = ctx->InputCount();
|
||||
if (num_inputs == 2) {
|
||||
//override the attribute value with the input value for reduction_axes
|
||||
const Tensor* axes_tensor = ctx->Input<Tensor>(1);
|
||||
ORT_ENFORCE(axes_tensor != nullptr, "Axes input is null");
|
||||
ORT_ENFORCE(axes_tensor->Shape().NumDimensions() == 1, "An axes tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(axes_tensor->Shape()[0]);
|
||||
const auto* data = axes_tensor->template Data<int64_t>();
|
||||
axes.assign(data, data + nDims);
|
||||
} else {
|
||||
axes.assign(axes_.begin(), axes_.end());
|
||||
}
|
||||
|
||||
// empty axes and no-op
|
||||
if (axes.empty() && noop_with_empty_axes_) {
|
||||
auto* Y = ctx->Output(0, X->Shape());
|
||||
CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(Y->template MutableData<T>(), X->template Data<T>(), X->SizeInBytes(), cudaMemcpyDeviceToDevice));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
PrepareReduceMetadata prepare_reduce_metadata;
|
||||
ORT_RETURN_IF_ERROR(PrepareForReduce(X,
|
||||
keepdims_,
|
||||
axes_,
|
||||
axes,
|
||||
prepare_reduce_metadata));
|
||||
Tensor* Y = ctx->Output(0, prepare_reduce_metadata.squeezed_output_dims);
|
||||
bool fast_reduction = fast_reduction_;
|
||||
|
|
@ -642,12 +692,33 @@ Status ReduceKernel<true>::ComputeImpl<int32_t, CUDNN_REDUCE_TENSOR_NO_INDICES>(
|
|||
typedef typename ToCudaType<int32_t>::MappedType CudaT;
|
||||
|
||||
const Tensor* X = ctx->Input<Tensor>(0);
|
||||
std::vector<int64_t> axes;
|
||||
|
||||
size_t num_inputs = ctx->InputCount();
|
||||
if (num_inputs == 2) {
|
||||
//override the attribute value with the input value for reduction_axes
|
||||
const Tensor* axes_tensor = ctx->Input<Tensor>(1);
|
||||
ORT_ENFORCE(axes_tensor != nullptr, "Axes input is null");
|
||||
ORT_ENFORCE(axes_tensor->Shape().NumDimensions() == 1, "An axes tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(axes_tensor->Shape()[0]);
|
||||
const auto* data = axes_tensor->template Data<int64_t>();
|
||||
axes.assign(data, data + nDims);
|
||||
} else {
|
||||
axes.assign(axes_.begin(), axes_.end());
|
||||
}
|
||||
|
||||
// empty axes and no-op
|
||||
if (axes.empty() && noop_with_empty_axes_) {
|
||||
auto* Y = ctx->Output(0, X->Shape());
|
||||
CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(Y->template MutableData<int32_t>(), X->template Data<int32_t>(), X->SizeInBytes(), cudaMemcpyDeviceToDevice));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
PrepareReduceMetadata prepare_reduce_metadata;
|
||||
|
||||
ORT_RETURN_IF_ERROR(PrepareForReduce(X,
|
||||
keepdims_,
|
||||
axes_,
|
||||
axes,
|
||||
prepare_reduce_metadata));
|
||||
|
||||
Tensor* Y = ctx->Output(0, prepare_reduce_metadata.squeezed_output_dims);
|
||||
|
|
@ -952,7 +1023,12 @@ REGISTER_KERNEL_TYPED_12(ReduceMin, int8_t)
|
|||
REGISTER_KERNEL_TYPED_12(ReduceMin, uint8_t)
|
||||
|
||||
REGISTER_KERNEL_HFD(ReduceProd)
|
||||
REGISTER_KERNEL_HFD(ReduceSum)
|
||||
|
||||
REGISTER_KERNEL_TYPED_13(ReduceSum, MLFloat16)
|
||||
REGISTER_KERNEL_TYPED_13(ReduceSum, float)
|
||||
REGISTER_KERNEL_TYPED_13(ReduceSum, double)
|
||||
REGISTER_KERNEL_TYPED_13(ReduceSum, int32_t)
|
||||
|
||||
REGISTER_KERNEL_HFD(ReduceLogSum)
|
||||
REGISTER_KERNEL_HFD(ReduceSumSquare)
|
||||
REGISTER_KERNEL_HFD(ReduceLogSumExp)
|
||||
|
|
@ -965,7 +1041,6 @@ REGISTER_KERNEL_INT32(ReduceL2)
|
|||
REGISTER_KERNEL_INT32(ReduceMean)
|
||||
|
||||
REGISTER_KERNEL_INT32(ReduceProd)
|
||||
REGISTER_KERNEL_INT32(ReduceSum)
|
||||
|
||||
} // namespace cuda
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -23,11 +23,14 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(Split,
|
|||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
Split);
|
||||
|
||||
// explicitly supports 'split' as optional input
|
||||
ONNX_OPERATOR_KERNEL_EX(Split,
|
||||
kOnnxDomain,
|
||||
13,
|
||||
kCudaExecutionProvider,
|
||||
KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
KernelDefBuilder()
|
||||
.InputMemoryType<OrtMemTypeCPUInput>(1)
|
||||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
Split);
|
||||
|
||||
Status Split::ComputeInternal(OpKernelContext* ctx) const {
|
||||
|
|
@ -39,7 +42,18 @@ Status Split::ComputeInternal(OpKernelContext* ctx) const {
|
|||
int before_dims = 0;
|
||||
int block_size_including_axis_dim = 0;
|
||||
int block_size_inside_axis_dim = 0;
|
||||
std::vector<int64_t> split_sizes;
|
||||
std::vector<int64_t> split_sizes(num_outputs);
|
||||
|
||||
size_t num_inputs = ctx->InputCount();
|
||||
if (num_inputs == 2) {
|
||||
const Tensor* split_tensor = ctx->Input<Tensor>(1);
|
||||
ORT_ENFORCE(split_tensor->Shape().NumDimensions() == 1, "An split tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(split_tensor->Shape()[0]);
|
||||
const int64_t* data = split_tensor->template Data<int64_t>();
|
||||
split_sizes.assign(data, data + nDims);
|
||||
} else {
|
||||
split_sizes.assign(split_sizes_.begin(), split_sizes_.end());
|
||||
}
|
||||
|
||||
ORT_RETURN_IF_ERROR(PrepareForCompute(input_shape,
|
||||
num_outputs,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(
|
|||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
Squeeze);
|
||||
|
||||
// axes is input instead of attribute
|
||||
ONNX_OPERATOR_KERNEL_EX(
|
||||
Squeeze,
|
||||
kOnnxDomain,
|
||||
|
|
@ -34,13 +35,29 @@ ONNX_OPERATOR_KERNEL_EX(
|
|||
kCudaExecutionProvider,
|
||||
KernelDefBuilder()
|
||||
.Alias(0, 0)
|
||||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes())
|
||||
.InputMemoryType<OrtMemTypeCPUInput>(1),
|
||||
Squeeze);
|
||||
|
||||
Status Squeeze::ComputeInternal(OpKernelContext* ctx) const {
|
||||
const Tensor* X = ctx->Input<Tensor>(0);
|
||||
const TensorShape& X_shape = X->Shape();
|
||||
std::vector<int64_t> output_shape = ComputeOutputShape(X_shape, axes_);
|
||||
|
||||
std::vector<int64_t> axes;
|
||||
size_t num_inputs = ctx->InputCount();
|
||||
if (num_inputs == 2) { //axes is an input
|
||||
const Tensor* axes_tensor = ctx->Input<Tensor>(1);
|
||||
ORT_ENFORCE(axes_tensor != nullptr, "Axes input is null");
|
||||
ORT_ENFORCE(axes_tensor->Shape().NumDimensions() == 1,
|
||||
"An axes tensor must be a vector tensor.");
|
||||
auto nDims = static_cast<size_t>(axes_tensor->Shape()[0]);
|
||||
const auto* data = axes_tensor->template Data<int64_t>();
|
||||
axes.assign(data, data + nDims);
|
||||
} else {
|
||||
axes.assign(axes_.begin(), axes_.end());
|
||||
}
|
||||
|
||||
std::vector<int64_t> output_shape = ComputeOutputShape(X_shape, axes);
|
||||
|
||||
Tensor* Y = ctx->Output(0, TensorShape(output_shape));
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(
|
|||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
Unsqueeze);
|
||||
|
||||
// support bfloat16
|
||||
// axes is input instead of attribute, support bfloat16
|
||||
ONNX_OPERATOR_KERNEL_EX(
|
||||
Unsqueeze,
|
||||
kOnnxDomain,
|
||||
|
|
@ -35,8 +35,9 @@ ONNX_OPERATOR_KERNEL_EX(
|
|||
kCudaExecutionProvider,
|
||||
KernelDefBuilder()
|
||||
.Alias(0, 0)
|
||||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()),
|
||||
Unsqueeze);
|
||||
.TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes())
|
||||
.InputMemoryType<OrtMemTypeCPUInput>(1),
|
||||
Unsqueeze);
|
||||
|
||||
Status Unsqueeze::ComputeInternal(OpKernelContext* ctx) const {
|
||||
Prepare p;
|
||||
|
|
|
|||
|
|
@ -1330,6 +1330,61 @@ TEST(ReductionOpTest, ReduceSum_keepdims) {
|
|||
test.Run();
|
||||
}
|
||||
|
||||
TEST(ReductionOpTest, ReduceSum_int32_axes_input) {
|
||||
OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain);
|
||||
test.AddAttribute("keepdims", (int64_t)1);
|
||||
test.AddInput<int32_t>("data", {3, 2, 2},
|
||||
{1, 2,
|
||||
3, 4,
|
||||
|
||||
5, 6,
|
||||
7, 8,
|
||||
|
||||
9, 10,
|
||||
11, 12});
|
||||
test.AddInput<int64_t>("axes", {2}, std::vector<int64_t>{0, 2}, true);
|
||||
test.AddOutput<int32_t>("reduced", {1, 2, 1}, {33, 45});
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(ReductionOpTest, ReduceSum_do_not_keepdims_axes_input_initializer) {
|
||||
OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain);
|
||||
test.AddAttribute("keepdims", (int64_t)0);
|
||||
test.AddInput<float>("data", {1, 2, 2},
|
||||
{1.0f, 2.0f,
|
||||
3.0f, 4.0f});
|
||||
test.AddInput<int64_t>("axes", {1}, std::vector<int64_t>{1}, true);
|
||||
test.AddOutput<float>("reduced", {1, 2}, {4.0f, 6.0f});
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(ReductionOpTest, ReduceSum_do_not_keepdims_axes_input_not_initializer) {
|
||||
OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain);
|
||||
test.AddAttribute("keepdims", (int64_t)0);
|
||||
test.AddInput<float>("data", {1, 2, 2},
|
||||
{1.0f, 2.0f,
|
||||
3.0f, 4.0f});
|
||||
test.AddInput<int64_t>("axes", {1}, std::vector<int64_t>{1}, false);
|
||||
test.AddOutput<float>("reduced", {1, 2}, {4.0f, 6.0f});
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(ReductionOpTest, ReduceSum_noop_axes_input_initializer) {
|
||||
OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain);
|
||||
test.AddAttribute("keepdims", (int64_t)0);
|
||||
test.AddAttribute("noop_with_empty_axes", (int64_t)1);
|
||||
test.AddInput<float>("data", {1, 2, 2},
|
||||
{1.0f, 2.0f,
|
||||
3.0f, 4.0f});
|
||||
test.AddInput<int64_t>("axes", {0}, {}, true);
|
||||
test.AddOutput<float>("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f});
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
#if !(defined USE_TENSORRT) && !(defined USE_TVM)
|
||||
TEST(ReductionOpTest, ReduceSum0DTensor) {
|
||||
OpTester test("ReduceSum");
|
||||
|
|
|
|||
|
|
@ -17,15 +17,19 @@ using ExpectResult = OpTester::ExpectResult;
|
|||
template <typename T>
|
||||
void RunTest(int64_t axis, const std::vector<int64_t> split_sizes, const ShapeAndData<T>& input,
|
||||
const std::vector<ShapeAndData<T>>& outputs, bool is_tensorrt_supported = true,
|
||||
bool expect_failure = false, const std::string& err_msg = {}) {
|
||||
OpTester test("Split");
|
||||
bool expect_failure = false, bool split_as_input = false,
|
||||
bool is_initializer = true, const std::string& err_msg = {}) {
|
||||
int opset_version = split_as_input ? 13 : 7;
|
||||
OpTester test("Split", opset_version, onnxruntime::kOnnxDomain);
|
||||
|
||||
test.AddAttribute("axis", axis);
|
||||
|
||||
if (!split_sizes.empty())
|
||||
test.AddAttribute("split", split_sizes);
|
||||
|
||||
test.AddInput<T>("input", input.first, input.second);
|
||||
if (!split_sizes.empty()){
|
||||
if (split_as_input)
|
||||
test.AddInput<int64_t>("split", {static_cast<int64_t>(split_sizes.size())}, split_sizes, is_initializer);
|
||||
else
|
||||
test.AddAttribute("split", split_sizes);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (auto& output : outputs) {
|
||||
|
|
@ -414,7 +418,7 @@ TEST(SplitOperatorTest, InvalidAxis) {
|
|||
|
||||
outputs.push_back({{1}, {0.f}});
|
||||
|
||||
RunTest<float>(axis, {}, input, outputs, true, true, "Invalid value of attribute 'axis'");
|
||||
RunTest<float>(axis, {}, input, outputs, true, true, false, true, "Invalid value of attribute 'axis'");
|
||||
}
|
||||
|
||||
// sum of values in splits is too small
|
||||
|
|
@ -434,7 +438,7 @@ TEST(SplitOperatorTest, SplitAttributeSumTooSmall) {
|
|||
outputs.push_back({{1, 2}, {1.f, 2.f}});
|
||||
outputs.push_back({{2, 2}, {3.f, 4.f, 5.f, 6.f}});
|
||||
|
||||
RunTest<float>(axis, splits, input, outputs, false, true, "Cannot split using values in 'split' attribute"); //TensorRT parser: Assertion failed: axis != BATCH_DIM
|
||||
RunTest<float>(axis, splits, input, outputs, false, true, false,true, "Cannot split using values in 'split' attribute"); //TensorRT parser: Assertion failed: axis != BATCH_DIM
|
||||
}
|
||||
|
||||
TEST(SplitOperatorTest, InvalidValueInSplitAttribute) {
|
||||
|
|
@ -452,7 +456,55 @@ TEST(SplitOperatorTest, InvalidValueInSplitAttribute) {
|
|||
outputs.push_back({{1, 2}, {1.f, 2.f}});
|
||||
outputs.push_back({{3, 2}, {3.f, 4.f, 5.f, 6.f, 7.f, 8.f}});
|
||||
|
||||
RunTest<float>(axis, splits, input, outputs, false, true, "in 'split' attribute"); //TensorRT parser: Assertion failed: axis != BATCH_DIM
|
||||
RunTest<float>(axis, splits, input, outputs, false, true, false,true, "in 'split' attribute"); //TensorRT parser: Assertion failed: axis != BATCH_DIM
|
||||
}
|
||||
|
||||
// split as input
|
||||
TEST(SplitOperatorTest, Axis0UnequalSplitInputFloat) {
|
||||
const int64_t axis = 0;
|
||||
std::vector<ShapeAndFloatData> outputs;
|
||||
|
||||
// input shape and data
|
||||
ShapeAndFloatData input = {{4, 2}, // shape
|
||||
{1.f, 2.f,
|
||||
3.f, 4.f,
|
||||
5.f, 6.f,
|
||||
7.f, 8.f}};
|
||||
|
||||
std::vector<int64_t> splits{1, 3};
|
||||
|
||||
outputs.push_back({{1, 2}, {1.f, 2.f}});
|
||||
|
||||
outputs.push_back({{3, 2},
|
||||
{3.f, 4.f,
|
||||
5.f, 6.f,
|
||||
7.f, 8.f}});
|
||||
|
||||
RunTest<float>(axis, splits, input, outputs, false, false, true);
|
||||
}
|
||||
|
||||
// split as input
|
||||
TEST(SplitOperatorTest, Axis0UnequalSplitInputFloat_not_initializer) {
|
||||
const int64_t axis = 0;
|
||||
std::vector<ShapeAndFloatData> outputs;
|
||||
|
||||
// input shape and data
|
||||
ShapeAndFloatData input = {{4, 2}, // shape
|
||||
{1.f, 2.f,
|
||||
3.f, 4.f,
|
||||
5.f, 6.f,
|
||||
7.f, 8.f}};
|
||||
|
||||
std::vector<int64_t> splits{1, 3};
|
||||
|
||||
outputs.push_back({{1, 2}, {1.f, 2.f}});
|
||||
|
||||
outputs.push_back({{3, 2},
|
||||
{3.f, 4.f,
|
||||
5.f, 6.f,
|
||||
7.f, 8.f}});
|
||||
|
||||
RunTest<float>(axis, splits, input, outputs, false, false, true, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -108,5 +108,40 @@ TEST(SqueezeOpTest, SqueezeNegAxis_2) {
|
|||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(SqueezeOpTest, Squeeze_2_axes_input) {
|
||||
OpTester test("Squeeze", 13);
|
||||
test.AddInput<float>("data", {1, 4, 1, 1, 2},
|
||||
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
|
||||
test.AddInput<int64_t>("axes", {3}, std::vector<int64_t>{0, 2, 3});
|
||||
test.AddOutput<float>("squeezed", {4, 2},
|
||||
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
|
||||
// Incorrect precision for OpenVINO EP. Will be re-enabled after it's fixed
|
||||
// TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(SqueezeOpTest, Squeeze_Empty_Axes_opset13) {
|
||||
OpTester test("Squeeze", 13);
|
||||
test.AddInput<float>("data", {1, 1, 4, 1}, std::vector<float>(4, 1.0f));
|
||||
test.AddOutput<float>("squeezed", {4}, std::vector<float>(4, 1.0f));
|
||||
// TensorRT doesn't seem to support missing 'axes'
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(SqueezeOpTest, SqueezeNegAxis_axes_input) {
|
||||
OpTester test("Squeeze", 13);
|
||||
test.AddInput<float>("data", {1, 4, 1, 1, 2},
|
||||
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
|
||||
|
||||
test.AddInput<int64_t>("axes",{3} ,std::vector<int64_t>{0, -3, -2});
|
||||
test.AddOutput<float>("squeezed", {4, 2},
|
||||
std::vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f});
|
||||
|
||||
// nGraph does not support neg axis.
|
||||
// OpenVINO EP Incorrect precision. Will be re-enabled after its fixed
|
||||
// TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kOpenVINOExecutionProvider, kTensorrtExecutionProvider});
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -46,42 +46,88 @@ TEST(TensorOpTest, Unsqueeze_3) {
|
|||
}
|
||||
|
||||
TEST(TensorOpTest, Unsqueeze_Duplicate) {
|
||||
// This test is valid for opset 12.
|
||||
// setting opset to -1 makes the test infra pick the latest available opset, so ort will pull the
|
||||
// schema for that opset and do verification against it. Since opset 13 is enabled this test
|
||||
//will fail schema validation.
|
||||
OpTester test("Unsqueeze", 12);
|
||||
{
|
||||
OpTester test("Unsqueeze", 12); // opset 1-12 has axes attribute
|
||||
|
||||
test.AddAttribute("axes", std::vector<int64_t>{2, 1, 0, 2});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] 'axes' attribute must not contain any duplicates",
|
||||
{kTensorrtExecutionProvider}); //TensorRT failed
|
||||
test.AddAttribute("axes", std::vector<int64_t>{2, 1, 0, 2});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] 'axes' attribute must not contain any duplicates",
|
||||
{kTensorrtExecutionProvider}); //TensorRT failed
|
||||
}
|
||||
{
|
||||
OpTester test("Unsqueeze", -1); // use latest opset with axis input
|
||||
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddInput<int64_t>("axes", {4}, std::vector<int64_t>{2, 1, 0, 2}, true); //set as initializer to enable shape inference
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] 'axes' attribute must not contain any duplicates",
|
||||
{kTensorrtExecutionProvider}); //TensorRT failed
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TensorOpTest, Unsqueeze_OutOfRange) {
|
||||
// This test is valid for opset 12.
|
||||
// setting opset to -1 makes the test infra pick the latest available opset, so ort will pull the
|
||||
// schema for that opset and do verification against it. Since opset 13 is enabled this test
|
||||
// will fail schema validation.
|
||||
OpTester test("Unsqueeze", 12);
|
||||
|
||||
test.AddAttribute("axes", std::vector<int64_t>{4});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddOutput<float>("output", {2, 1, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] values in 'axes' are beyond the bounds of the computed output shape");
|
||||
{
|
||||
OpTester test("Unsqueeze", 12); // opset 1-12 has axes attribute
|
||||
test.AddAttribute("axes", std::vector<int64_t>{4});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddOutput<float>("output", {2, 1, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] values in 'axes' are beyond the bounds of the computed output shape");
|
||||
}
|
||||
{
|
||||
OpTester test("Unsqueeze", -1); // use latest opset with axis input
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddInput<int64_t>("axes", {1}, std::vector<int64_t>{4}, true); //set as initializer to enable shape inference
|
||||
test.AddOutput<float>("output", {2, 1, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
// nGraph and TensorRT does not support negative axis.
|
||||
test.Run(OpTester::ExpectResult::kExpectFailure,
|
||||
"[ShapeInferenceError] values in 'axes' are beyond the bounds of the computed output shape",
|
||||
{kTensorrtExecutionProvider}); //TensorRT expects 'axes' attribute
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TensorOpTest, UnsqueezeNegAxis_3) {
|
||||
OpTester test("Unsqueeze", 12); // use latest opset for shape inference errors
|
||||
{
|
||||
OpTester test("Unsqueeze", 12); // opset 1-12 has axes attribute
|
||||
test.AddAttribute("axes", std::vector<int64_t>{-4, 1, -6});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
// nGraph and TensorRT does not support negative axis.
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kTensorrtExecutionProvider});
|
||||
}
|
||||
{
|
||||
OpTester test("Unsqueeze", 13); // use latest opset with axis input
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddInput<int64_t>("axes", {3}, std::vector<int64_t>{-4, 1, -6});
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
// nGraph and TensorRT does not support negative axis.
|
||||
// TODO: TensorRT, OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider,
|
||||
kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TensorOpTest, Unsqueeze_1_int32_axes_input) {
|
||||
OpTester test("Unsqueeze", 13);
|
||||
|
||||
test.AddInput<int32_t>("input", {2, 3, 4}, std::vector<int32_t>(2 * 3 * 4, 1));
|
||||
test.AddInput<int64_t>("axes", {1}, std::vector<int64_t>{1});
|
||||
test.AddOutput<int32_t>("output", {2, 1, 3, 4}, std::vector<int32_t>(2 * 3 * 4, 1));
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(TensorOpTest, Unsqueeze_3_axes_input) {
|
||||
OpTester test("Unsqueeze", 13);
|
||||
|
||||
test.AddAttribute("axes", std::vector<int64_t>{-4, 1, -6});
|
||||
test.AddInput<float>("input", {2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
test.AddInput<int64_t>("axes", {3}, std::vector<int64_t>{2, 1, 0});
|
||||
test.AddOutput<float>("output", {1, 1, 1, 2, 3, 4}, std::vector<float>(2 * 3 * 4, 1.0f));
|
||||
// nGraph and TensorRT does not support negative axis.
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kTensorrtExecutionProvider});
|
||||
// TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider});
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
|
|
|||
|
|
@ -792,11 +792,19 @@ IMPLEMENT_GRADIENT_BUILDER(GetLogSoftmaxGradient) {
|
|||
}
|
||||
|
||||
IMPLEMENT_GRADIENT_BUILDER(GetUnsqueezeGradient) {
|
||||
return std::vector<NodeDef>{
|
||||
NodeDef("Squeeze",
|
||||
{GO(0)},
|
||||
{GI(0)},
|
||||
SrcNodeAttributes())};
|
||||
if (SrcNodeOpsetVersion() < 13) {
|
||||
return std::vector<NodeDef>{
|
||||
NodeDef("Squeeze",
|
||||
{GO(0)},
|
||||
{GI(0)},
|
||||
SrcNodeAttributes())};
|
||||
} else { // mandatory input 'axes' since opset 13
|
||||
return std::vector<NodeDef>{
|
||||
NodeDef(OpDef{"Squeeze", kOnnxDomain, 13},
|
||||
{GO(0), I(1)},
|
||||
{GI(0)},
|
||||
SrcNodeAttributes())};
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_GRADIENT_BUILDER(GetGatherGradient) {
|
||||
|
|
@ -830,26 +838,34 @@ IMPLEMENT_GRADIENT_BUILDER(GetReluGradient) {
|
|||
|
||||
IMPLEMENT_GRADIENT_BUILDER(GetSqueezeGradient) {
|
||||
std::vector<NodeDef> result;
|
||||
auto attributes = SrcNodeAttributes();
|
||||
std::vector<int64_t> axes_values;
|
||||
if (attributes.find("axes") != attributes.end()) {
|
||||
axes_values = RetrieveValues<int64_t>(attributes.at("axes"));
|
||||
size_t numInputs = GetSrcNodeInputSize();
|
||||
if (SrcNodeOpsetVersion() < 13) { //axes attribute
|
||||
auto attributes = SrcNodeAttributes();
|
||||
std::vector<int64_t> axes_values;
|
||||
if (attributes.find("axes") != attributes.end()) {
|
||||
axes_values = RetrieveValues<int64_t>(attributes.at("axes"));
|
||||
result.push_back(
|
||||
NodeDef("Unsqueeze",
|
||||
{GO(0)},
|
||||
{GI(0)},
|
||||
{MakeAttribute("axes", axes_values)}));
|
||||
}
|
||||
} else if(numInputs == 2){ //optional input 'axes' is provided
|
||||
result.push_back(
|
||||
NodeDef("Unsqueeze",
|
||||
{GO(0)},
|
||||
{GI(0)},
|
||||
{MakeAttribute("axes", axes_values)}));
|
||||
// if axes attribute not provided for squeeze
|
||||
} else {
|
||||
result.push_back(
|
||||
NodeDef("Shape",
|
||||
{I(0)},
|
||||
{IA("I0_shape")}));
|
||||
result.push_back(
|
||||
NodeDef("Reshape",
|
||||
{GO(0), IA("I0_shape")},
|
||||
NodeDef(OpDef{"Unsqueeze", kOnnxDomain, 13},
|
||||
{GO(0), I(1)},
|
||||
{GI(0)}));
|
||||
} else { // if axes attribute/input not provided for squeeze
|
||||
result.push_back(
|
||||
NodeDef("Shape",
|
||||
{I(0)},
|
||||
{IA("I0_shape")}));
|
||||
result.push_back(
|
||||
NodeDef("Reshape",
|
||||
{GO(0), IA("I0_shape")},
|
||||
{GI(0)}));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1119,10 +1135,20 @@ IMPLEMENT_GRADIENT_BUILDER(GetReduceSumGradient) {
|
|||
}
|
||||
|
||||
ArgDef grad = GO(0);
|
||||
if (!keepdims && attributes.find("axes") != attributes.end()) {
|
||||
std::vector<int64_t> axes_values = RetrieveValues<int64_t>(attributes.at("axes"));
|
||||
grad = IA("Unqueezed_Grad");
|
||||
result.push_back(NodeDef("Unsqueeze", {GO(0)}, {grad}, {MakeAttribute("axes", axes_values)}));
|
||||
if (!keepdims) {
|
||||
size_t numInputs = GetSrcNodeInputSize();
|
||||
if (SrcNodeOpsetVersion() < 13) { //axes is attribute
|
||||
if (attributes.find("axes") != attributes.end()) {
|
||||
std::vector<int64_t> axes_values = RetrieveValues<int64_t>(attributes.at("axes"));
|
||||
|
||||
grad = IA("Unqueezed_Grad");
|
||||
result.push_back(NodeDef("Unsqueeze", {GO(0)}, {grad}, {MakeAttribute("axes", axes_values)}));
|
||||
|
||||
}
|
||||
} else if (numInputs == 2) { //optional input 'axes' is available as input I(1)
|
||||
grad = IA("Unqueezed_Grad");
|
||||
result.push_back(NodeDef(OpDef{"Unsqueeze", kOnnxDomain, 13}, {GO(0), I(1)}, {grad}));
|
||||
} //axes is not available, the GO(0) is a scalar which can be expanded to required shape
|
||||
}
|
||||
|
||||
result.push_back(NodeDef("Shape", {I(0)}, {IA("Shaped_X")}));
|
||||
|
|
|
|||
|
|
@ -181,6 +181,10 @@ class GradientBuilderBase {
|
|||
return node_->OpType();
|
||||
}
|
||||
|
||||
int SrcNodeOpsetVersion() const {
|
||||
return node_->Op()->since_version();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static NodeDef ConstantVectorNode(const std::vector<T>& values, const std::string& arg_name) {
|
||||
auto t_proto = ONNX_NAMESPACE::ToTensor<T>(values);
|
||||
|
|
|
|||
|
|
@ -38,63 +38,78 @@ static bool IsErrorWithinTolerance(float error, float tolerance) {
|
|||
#define EXPECT_IS_TINY(max_error) \
|
||||
EXPECT_IS_TINIER_THAN(max_error, 1.5e-2f)
|
||||
|
||||
static void RunReductionTests(const OpDef& op_def) {
|
||||
TestDataVector test_data(
|
||||
// Input X
|
||||
{
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
{{4, 3, 2}},
|
||||
},
|
||||
// Input Y
|
||||
{
|
||||
{{1, 1, 1}},
|
||||
{{}},
|
||||
{{1, 3, 1}},
|
||||
{{2}},
|
||||
{{4, 1, 2}},
|
||||
{{4, 3}},
|
||||
{{4, 1, 2}},
|
||||
{{4}}},
|
||||
// Attributes
|
||||
{
|
||||
// default
|
||||
{},
|
||||
// axes = [0, 1, 2], keepdims = 0
|
||||
{MakeAttribute("axes", std::vector<int64_t>{0, 1, 2}),
|
||||
MakeAttribute("keepdims", int64_t(0))},
|
||||
// axes = [0, 2], keepdims = 1
|
||||
{MakeAttribute("axes", std::vector<int64_t>{0, 2})},
|
||||
// axes = [0, 1], keepdims = 0
|
||||
{MakeAttribute("axes", std::vector<int64_t>{0, 1}),
|
||||
MakeAttribute("keepdims", int64_t(0))},
|
||||
// axes = [1], keepdims = 1
|
||||
{MakeAttribute("axes", std::vector<int64_t>{1}),
|
||||
MakeAttribute("keepdims", int64_t(1))},
|
||||
// axes = [2], keepdims = 0
|
||||
{MakeAttribute("axes", std::vector<int64_t>{2}),
|
||||
MakeAttribute("keepdims", int64_t(0))},
|
||||
// axes = [-2], keepdims = 1
|
||||
{MakeAttribute("axes", std::vector<int64_t>{-2}),
|
||||
MakeAttribute("keepdims", int64_t(1))},
|
||||
// axes = [-2, -1], keepdims = 0
|
||||
{MakeAttribute("axes", std::vector<int64_t>{-2, -1}),
|
||||
MakeAttribute("keepdims", int64_t(0))}});
|
||||
static void RunReductionTests(const OpDef& op_def,
|
||||
bool axes_as_input = false,
|
||||
bool check_not_have_shape_inferencing = false) {
|
||||
std::vector<std::vector<int64_t>>
|
||||
x_shapes = {
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
{4, 3, 2},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> y_shapes = {
|
||||
{1, 1, 1},
|
||||
{},
|
||||
{1, 3, 1},
|
||||
{2},
|
||||
{4, 1, 2},
|
||||
{4, 3},
|
||||
{4, 1, 2},
|
||||
{4},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> axes_vec = {
|
||||
{}, //default case
|
||||
{0, 1, 2},
|
||||
{0, 2},
|
||||
{0, 1},
|
||||
{1},
|
||||
{2},
|
||||
{-2},
|
||||
{-2, -1},
|
||||
};
|
||||
std::vector<int64_t> keepdims_ip = {
|
||||
-1, //default case
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
};
|
||||
|
||||
GradientChecker<float, float, float> gradient_checker;
|
||||
|
||||
float max_error;
|
||||
|
||||
for (size_t i = 0; i < std::get<0>(test_data).size(); i++) {
|
||||
for (size_t i = 0; i < x_shapes.size(); i++) {
|
||||
max_error = 0;
|
||||
gradient_checker.ComputeGradientError(op_def, std::get<0>(test_data)[i],
|
||||
std::get<1>(test_data)[i], &max_error,
|
||||
std::get<2>(test_data)[i]);
|
||||
TensorShape x_shape = x_shapes[i];
|
||||
TensorShape y_shape = y_shapes[i];
|
||||
std::vector<int64_t> axes = axes_vec[i];
|
||||
std::vector<std::vector<float>> x_datas;
|
||||
RandomValueGenerator random{};
|
||||
x_datas.push_back(random.Gaussian<float>(x_shapes[i], 0.f, 5.f));
|
||||
std::vector<TensorInfo> input = {x_shape};
|
||||
std::vector<ONNX_NAMESPACE::AttributeProto> attributes = {};
|
||||
if (keepdims_ip[i] != -1) attributes.push_back(MakeAttribute("keepdims", keepdims_ip[i]));
|
||||
if (axes_as_input) {
|
||||
std::vector<float> axes_float;
|
||||
std::transform(begin(axes), end(axes), std::back_inserter(axes_float), [](int64_t i) { return static_cast<float>(i); });
|
||||
TensorInfo axes_info({static_cast<int64_t>(axes.size())}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>());
|
||||
input.push_back(axes_info);
|
||||
x_datas.push_back(axes_float);
|
||||
} else {
|
||||
if (axes.size() > 0)
|
||||
attributes.push_back(MakeAttribute("axes", axes));
|
||||
}
|
||||
|
||||
gradient_checker.ComputeGradientError(op_def, input, {y_shape}, &max_error, x_datas,
|
||||
attributes, true, check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
}
|
||||
|
|
@ -399,7 +414,7 @@ TEST(GradientCheckerTest, NegGrad) {
|
|||
}
|
||||
|
||||
TEST(GradientCheckerTest, LogGrad) {
|
||||
TensorShape shape({2,5,6});
|
||||
TensorShape shape({2, 5, 6});
|
||||
|
||||
std::function<float(float)> transformer = [](float x) { return std::fabs(x) + 1e-1f; };
|
||||
TensorInfo x_info{shape, true, &transformer};
|
||||
|
|
@ -548,9 +563,14 @@ TEST(GradientCheckerTest, ReduceMeanGrad) {
|
|||
|
||||
TEST(GradientCheckerTest, ReduceSumGrad) {
|
||||
// Attribute axes supports negative values from opset 11.
|
||||
OpDef op_def{"ReduceSum", kOnnxDomain, 11};
|
||||
OpDef op_def_11{"ReduceSum", kOnnxDomain, 11};
|
||||
|
||||
RunReductionTests(op_def);
|
||||
RunReductionTests(op_def_11, false, true);
|
||||
|
||||
// axes is input from opset 13.
|
||||
OpDef op_def_13{"ReduceSum", kOnnxDomain, 13};
|
||||
|
||||
RunReductionTests(op_def_13, true, true);
|
||||
}
|
||||
|
||||
TEST(GradientCheckerTest, ReduceLogSumExpGrad) {
|
||||
|
|
@ -590,6 +610,12 @@ TEST(GradientCheckerTest, SplitGrad) {
|
|||
gradient_checker.ComputeGradientError(op_def, {shape}, {{3, 5}, {3, 5}, {3, 5}}, &max_error,
|
||||
{MakeAttribute("axis", int64_t(0))});
|
||||
EXPECT_IS_TINY(max_error);
|
||||
|
||||
//opset13 test
|
||||
OpDef op_def_13{"Split", kOnnxDomain, 13};
|
||||
gradient_checker.ComputeGradientError(op_def_13, {shape}, {{3, 5}, {3, 5}, {3, 5}}, &max_error,
|
||||
{MakeAttribute("axis", int64_t(0))});
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -752,9 +778,9 @@ TEST(GradientCheckerTest, ConvGrad) {
|
|||
}
|
||||
|
||||
static void TestConcatOpGrad(const std::string& op_type,
|
||||
const std::string& domain = kOnnxDomain,
|
||||
int opset_version = 9,
|
||||
bool check_not_have_shape_inferencing = false) {
|
||||
const std::string& domain = kOnnxDomain,
|
||||
int opset_version = 9,
|
||||
bool check_not_have_shape_inferencing = false) {
|
||||
float max_error;
|
||||
GradientChecker<float, float, float> gradient_checker;
|
||||
const bool extra_input = op_type == "ConcatTraining";
|
||||
|
|
@ -767,9 +793,9 @@ static void TestConcatOpGrad(const std::string& op_type,
|
|||
std::vector<TensorInfo> output = {y_shape};
|
||||
if (extra_input) output.push_back(TensorInfo({3}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>()));
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape, x_shape, x_shape},
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(0))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(0))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
||||
|
|
@ -781,7 +807,7 @@ static void TestConcatOpGrad(const std::string& op_type,
|
|||
if (extra_input) output.push_back(TensorInfo({3}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>()));
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape, x_shape, x_shape},
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(1))}, true,
|
||||
{MakeAttribute("axis", int64_t(1))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
|
@ -794,7 +820,7 @@ static void TestConcatOpGrad(const std::string& op_type,
|
|||
if (extra_input) output.push_back(TensorInfo({3}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>()));
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape, x_shape, x_shape},
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(2))}, true,
|
||||
{MakeAttribute("axis", int64_t(2))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
|
@ -808,7 +834,7 @@ static void TestConcatOpGrad(const std::string& op_type,
|
|||
if (extra_input) output.push_back(TensorInfo({2}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>()));
|
||||
gradient_checker.ComputeGradientError(op_def, {x1_shape, x2_shape},
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(1))}, true,
|
||||
{MakeAttribute("axis", int64_t(1))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
|
@ -822,7 +848,7 @@ static void TestConcatOpGrad(const std::string& op_type,
|
|||
if (extra_input) output.push_back(TensorInfo({2}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>()));
|
||||
gradient_checker.ComputeGradientError(op_def, {x1_shape, x2_shape},
|
||||
output, &max_error,
|
||||
{MakeAttribute("axis", int64_t(-1))}, true,
|
||||
{MakeAttribute("axis", int64_t(-1))}, true,
|
||||
check_not_have_shape_inferencing);
|
||||
EXPECT_IS_TINY(max_error);
|
||||
}
|
||||
|
|
@ -985,90 +1011,97 @@ TEST(GradientCheckerTest, TransposeGrad) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(GradientCheckerTest, UnsqueezeGrad) {
|
||||
static void RunSqueezeUnsqueezeTests(const OpDef& op_def,
|
||||
std::vector<std::vector<int64_t>> x_shapes,
|
||||
std::vector<std::vector<int64_t>> y_shapes,
|
||||
std::vector<std::vector<int64_t>> axes_ip,
|
||||
bool axes_input = false) {
|
||||
float max_error;
|
||||
GradientChecker<float, float, float> gradient_checker;
|
||||
OpDef op_def{"Unsqueeze"};
|
||||
float error_tolerance = 1e-3f;
|
||||
|
||||
{
|
||||
TensorShape x_shape({2, 3});
|
||||
TensorShape y_shape({1, 2, 3, 1});
|
||||
std::vector<int64_t> axes{0, 3};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
for (size_t i = 0; i < x_shapes.size(); i++) {
|
||||
TensorShape x_shape = x_shapes[i];
|
||||
TensorShape y_shape = y_shapes[i];
|
||||
std::vector<int64_t> axes = axes_ip[i];
|
||||
std::vector<std::vector<float>> x_datas;
|
||||
RandomValueGenerator random{};
|
||||
x_datas.push_back(random.Gaussian<float>(x_shapes[i], 0.f, 5.f));
|
||||
std::vector<TensorInfo> input = {x_shape};
|
||||
std::vector<ONNX_NAMESPACE::AttributeProto> attributes = {};
|
||||
if (axes_input) {
|
||||
std::vector<float> axes_float;
|
||||
std::transform(begin(axes), end(axes), std::back_inserter(axes_float), [](int64_t i) { return static_cast<float>(i); });
|
||||
TensorInfo axes_info({static_cast<int64_t>(axes.size())}, false, nullptr, DataTypeImpl::GetTensorType<int64_t>());
|
||||
input.push_back(axes_info);
|
||||
x_datas.push_back(axes_float);
|
||||
} else {
|
||||
attributes.push_back(MakeAttribute("axes", axes));
|
||||
}
|
||||
|
||||
{
|
||||
TensorShape x_shape({2, 3});
|
||||
TensorShape y_shape({1, 1, 2, 3});
|
||||
std::vector<int64_t> axes{0, 1};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
|
||||
{
|
||||
TensorShape x_shape({2, 3});
|
||||
TensorShape y_shape({1, 2, 1, 3, 1});
|
||||
std::vector<int64_t> axes{0, 2, 4};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
gradient_checker.ComputeGradientError(op_def, input, {y_shape}, &max_error, x_datas, attributes);
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GradientCheckerTest, SqueezeGrad) {
|
||||
float max_error;
|
||||
GradientChecker<float, float, float> gradient_checker;
|
||||
OpDef op_def{"Squeeze"};
|
||||
float error_tolerance = 1e-3f;
|
||||
|
||||
{
|
||||
TensorShape x_shape({1, 2, 3, 1});
|
||||
TensorShape y_shape({2, 3});
|
||||
std::vector<int64_t> axes{0, 3};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
|
||||
{
|
||||
TensorShape x_shape({1, 1, 2, 3, 4});
|
||||
TensorShape y_shape({2, 3, 4});
|
||||
std::vector<int64_t> axes{0, 1};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
|
||||
{
|
||||
TensorShape x_shape({1, 2, 1, 3, 1});
|
||||
TensorShape y_shape({2, 3});
|
||||
std::vector<int64_t> axes{0, 2, 4};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
|
||||
{
|
||||
TensorShape x_shape({1, 2, 1, 3, 1});
|
||||
TensorShape y_shape({1, 2, 3, 1});
|
||||
std::vector<int64_t> axes{2};
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error,
|
||||
{MakeAttribute("axes", axes)});
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
|
||||
/* TODO: enable test with no axis when squeeze kernel is fixed (separate bug filed)
|
||||
{
|
||||
TensorShape x_shape({1, 2, 1, 3, 1});
|
||||
TensorShape y_shape({2, 3});
|
||||
gradient_checker.ComputeGradientError(op_def, {x_shape}, {y_shape}, &max_error);
|
||||
EXPECT_IS_TINIER_THAN(max_error, error_tolerance);
|
||||
}
|
||||
*/
|
||||
std::vector<std::vector<int64_t>> x_shapes = {
|
||||
{1, 2, 3, 1},
|
||||
{1, 1, 2, 3, 4},
|
||||
{1, 2, 1, 3, 1},
|
||||
{1, 2, 1, 3, 1},
|
||||
// {1, 2, 1, 3, 1},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> y_shapes = {
|
||||
{2, 3},
|
||||
{2, 3, 4},
|
||||
{2, 3},
|
||||
{1, 2, 3, 1},
|
||||
// {2, 3},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> axes_ip = {
|
||||
{0, 3},
|
||||
{0, 1},
|
||||
{0, 2, 4},
|
||||
{2},
|
||||
// {}
|
||||
};
|
||||
|
||||
OpDef op_def{"Squeeze"};
|
||||
RunSqueezeUnsqueezeTests(op_def, x_shapes, y_shapes, axes_ip);
|
||||
|
||||
//axes as input from opset 13
|
||||
OpDef op_def_2{"Squeeze", kOnnxDomain, 13};
|
||||
RunSqueezeUnsqueezeTests(op_def_2, x_shapes, y_shapes, axes_ip, true);
|
||||
}
|
||||
|
||||
TEST(GradientCheckerTest, UnsqueezeGrad) {
|
||||
std::vector<std::vector<int64_t>> x_shapes = {
|
||||
{2, 3},
|
||||
{2, 3},
|
||||
{2, 3},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> y_shapes = {
|
||||
{1, 2, 3, 1},
|
||||
{1, 1, 2, 3},
|
||||
{1, 2, 1, 3, 1},
|
||||
};
|
||||
std::vector<std::vector<int64_t>> axes_ip = {
|
||||
{0, 3},
|
||||
{0, 1},
|
||||
{0, 2, 4},
|
||||
};
|
||||
|
||||
OpDef op_def{"Unsqueeze"};
|
||||
RunSqueezeUnsqueezeTests(op_def, x_shapes, y_shapes, axes_ip);
|
||||
|
||||
//axes as input from opset 13
|
||||
OpDef op_def_2{"Unsqueeze", kOnnxDomain, 13};
|
||||
RunSqueezeUnsqueezeTests(op_def_2, x_shapes, y_shapes, axes_ip, true);
|
||||
}
|
||||
|
||||
// TODO: Reshape missing
|
||||
|
|
@ -1234,7 +1267,7 @@ void GradientCheckerSoftmaxGradHelper(bool is_log_softmax) {
|
|||
float max_error;
|
||||
GradientChecker<float, float, float> gradient_checker;
|
||||
|
||||
const std::string op = is_log_softmax? "LogSoftmax" : "Softmax";
|
||||
const std::string op = is_log_softmax ? "LogSoftmax" : "Softmax";
|
||||
OpDef op_def{op};
|
||||
|
||||
// default_axis
|
||||
|
|
|
|||
Loading…
Reference in a new issue