diff --git a/onnxruntime/core/framework/tensorprotoutils.cc b/onnxruntime/core/framework/tensorprotoutils.cc index c737239d0c..73c0b00dec 100644 --- a/onnxruntime/core/framework/tensorprotoutils.cc +++ b/onnxruntime/core/framework/tensorprotoutils.cc @@ -1008,6 +1008,8 @@ ONNX_NAMESPACE::TensorProto TensorToTensorProto(const Tensor& tensor, const std: common::Status ConstantNodeProtoToTensorProto(const ONNX_NAMESPACE::NodeProto& node, const Path& model_path, ONNX_NAMESPACE::TensorProto& tensor, const std::string& tensor_name) { + ORT_RETURN_IF_NOT(node.attribute_size() > 0, "Constant node: ", node.name(), " has no data attributes"); + const AttributeProto& constant_attribute = node.attribute(0); switch (constant_attribute.type()) { diff --git a/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc b/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc index 120cac7e48..0de7dccd2a 100644 --- a/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc +++ b/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc @@ -595,10 +595,14 @@ FastReduceKind OptimizeShapeForFastReduce(gsl::span input_shape, TensorShapeVector& fast_axes, bool keep_dims, bool noop_with_empty_axes) { if (input_shape.empty()) { - fast_shape.assign(input_shape.begin(), input_shape.end()); - fast_output_shape = fast_shape; - fast_axes.assign(reduced_axes.begin(), reduced_axes.end()); - return FastReduceKind::kNone; + fast_shape.clear(); + fast_output_shape.clear(); + // XXX: Should we enforce the absence of the axes in the scalar input case? + // The operator spec refers to Numpy which returns error because axes can not possibly contain any valid + // value in scalar case, but pytorch simply ignores it. + // ORT_ENFORCE(reduced_axes.empty(), "With scalar input shape, axis can not contain valid values"); + fast_axes.clear(); + return FastReduceKind::kEmpty; } InlinedHashSet axes; diff --git a/onnxruntime/core/providers/cpu/tensor/transpose.h b/onnxruntime/core/providers/cpu/tensor/transpose.h index c88c318dda..133b35ac80 100644 --- a/onnxruntime/core/providers/cpu/tensor/transpose.h +++ b/onnxruntime/core/providers/cpu/tensor/transpose.h @@ -62,20 +62,24 @@ class TransposeBase { Status ComputeOutputShape(const Tensor& X, TensorShapeVector& output_dims, InlinedVector& default_perm, const InlinedVector*& p_perm) const { - size_t rank = X.Shape().NumDimensions(); + const size_t rank = X.Shape().NumDimensions(); const auto& input_dims = X.Shape().GetDims(); - // Determine permutation to use: - // If no permutation was specified in the attributes, the default is [rank-1, ..., 0] - default_perm.resize(rank); - if (perm_specified_) p_perm = &perm_; else { + // Determine permutation to use: + // If no permutation was specified in the attributes, the default is [rank-1, ..., 0] + default_perm.resize(rank); for (size_t i = 0; i < rank; ++i) default_perm[i] = rank - i - 1; p_perm = &default_perm; } + if (p_perm->size() != rank) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "perm size: ", p_perm->size(), " does not match input rank: ", std::to_string(rank)); + } + // Determine shape of output output_dims.resize(rank); for (size_t i = 0; i < rank; i++) { diff --git a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc index b44ba75486..1dfaf9b10e 100644 --- a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc +++ b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc @@ -3215,6 +3215,24 @@ TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithZero1) { ASSERT_EQ(fast_axes, expected_fast_axes); } +TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithScalarInputAxesPresent) { + FastReduceKind fast_kind; + TensorShapeVector fast_shape, fast_output_shape, fast_axes; + TensorShapeVector expected_fast_shape, expected_fast_output_shape, expected_fast_axes; + + // R - keep_dims=1 - noop=false + fast_kind = OptimizeShapeForFastReduce( + EmptySpan(), AsSpan({1, 2, 3}), + fast_shape, fast_output_shape, fast_axes, true); + expected_fast_shape = {}; + expected_fast_axes = {}; + expected_fast_output_shape = {}; + ASSERT_EQ(fast_kind, FastReduceKind::kEmpty); + ASSERT_EQ(fast_output_shape, expected_fast_output_shape); + ASSERT_EQ(fast_shape, expected_fast_shape); + ASSERT_EQ(fast_axes, expected_fast_axes); +} + TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithZero1b) { FastReduceKind fast_kind; TensorShapeVector fast_shape, fast_output_shape, fast_axes; diff --git a/onnxruntime/test/providers/cpu/tensor/transpose_test.cc b/onnxruntime/test/providers/cpu/tensor/transpose_test.cc index fd3b363ee6..1ae46f072b 100644 --- a/onnxruntime/test/providers/cpu/tensor/transpose_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/transpose_test.cc @@ -24,6 +24,22 @@ TEST(TransposeOpTest, IsTransposeReshapeTest) { ASSERT_FALSE(IsTransposeReshape(perm, input_dims)); } +// Negative test, making sure it fails +TEST(TransposeOpTest, PermRankDoesNotMatchTensorRank) { + const std::vector input_vals(1 * 2 * 3 * 4, 0.f); + const std::vector perm{0, 2, 1}; + + OpTester test("Transpose"); + test.AddAttribute("perm", perm); + test.AddInput("X", {1, 2, 3, 4}, input_vals); + // Output is not very relevant + test.AddOutput("Y", {1, 3, 2, 4}, input_vals); + // This failure comes from shape inference, because in this case it knows the input dims. + // But in the real world, the model can supply different input dims at runtime. + test.Run(OpTester::ExpectResult::kExpectFailure, + "Node:node1 Output:Y [ShapeInferenceError] Mismatch between number of source and target dimensions. Source=3 Target=4"); +} + // Some of the tests can't run on TensorrtExecutionProvider because of errors. // Those tests will fallback to other EPs.