From 440978920c6932b80f5e358b8972e68d084ad761 Mon Sep 17 00:00:00 2001 From: ingyukoh Date: Wed, 11 Feb 2026 15:35:09 +0900 Subject: [PATCH 1/2] Fix CoreML reshape to support dynamic shapes CoreML MIL supports -1 in shape dimensions and can infer at runtime. Change GetStaticShape to GetShape to allow dynamic input shapes, and only apply ReshapeHelper when the shape is fully static. Fixes #26328 --- .../coreml/builders/impl/reshape_op_builder.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc index e3781ed7d388b..fac7ba15c8fa5 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc @@ -40,15 +40,19 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); std::vector input_shape; - ORT_RETURN_IF_NOT(GetStaticShape(*input_defs[0], input_shape, logger), "Cannot get shape of data"); + ORT_RETURN_IF_NOT(GetShape(*input_defs[0], input_shape, logger), "Cannot get shape of data"); const auto& data_name = input_defs[0]->Name(); const auto& new_shape_name = input_defs[1]->Name(); Initializer unpacked_tensor(model_builder.GetGraphViewer().GetGraph(), *model_builder.GetConstantInitializer(new_shape_name)); TensorShapeVector new_shape = ToShapeVector(unpacked_tensor.DataAsSpan()); - // ReshapeHelper applies the ONNX rules to create the concrete output shape - ReshapeHelper helper(TensorShape(input_shape), new_shape); + // ReshapeHelper applies the ONNX rules to create the concrete output shape. + // Only use it if the input shape is static (no dynamic dimensions). + // CoreML MIL supports -1 in the shape and can infer at runtime. + if (IsStaticShape(input_shape)) { + ReshapeHelper helper(TensorShape(input_shape), new_shape); + } if (model_builder.CreateMLProgram()) { using namespace CoreML::Specification::MILSpec; @@ -96,7 +100,7 @@ bool ReshapeOpBuilder::IsOpSupportedImpl(const Node& node, } std::vector input_shape; - if (!GetStaticShape(*input_defs[0], input_shape, logger)) + if (!GetShape(*input_defs[0], input_shape, logger)) return false; if (input_shape.empty()) { From 221f693a7e154ed95488eb12face7157fbb58be2 Mon Sep 17 00:00:00 2001 From: ingyukoh Date: Mon, 16 Feb 2026 16:04:11 +0900 Subject: [PATCH 2/2] Add test for CoreML reshape with dynamic input shapes Add a test model (Reshape with dynamic M dimension, shape [-1, 2048]) and a corresponding test case in dynamic_input_test.cc to verify the CoreML EP handles reshape operations with dynamic input shapes. --- .../providers/coreml/dynamic_input_test.cc | 35 ++++++++++++++++++ .../reshape_with_dynamic_input_shape.onnx | Bin 0 -> 144 bytes .../reshape_with_dynamic_input_shape.py | 33 +++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 onnxruntime/test/testdata/reshape_with_dynamic_input_shape.onnx create mode 100644 onnxruntime/test/testdata/reshape_with_dynamic_input_shape.py diff --git a/onnxruntime/test/providers/coreml/dynamic_input_test.cc b/onnxruntime/test/providers/coreml/dynamic_input_test.cc index 6e8c7a2f09821..b1ae5d0cdce8e 100644 --- a/onnxruntime/test/providers/coreml/dynamic_input_test.cc +++ b/onnxruntime/test/providers/coreml/dynamic_input_test.cc @@ -84,6 +84,41 @@ TEST(CoreMLExecutionProviderDynamicInputShapeTest, MobileNetExcerpt) { } } +TEST(CoreMLExecutionProviderDynamicInputShapeTest, Reshape) { + constexpr auto model_path = ORT_TSTR("testdata/reshape_with_dynamic_input_shape.onnx"); + + auto test = [&](const size_t M) { + SCOPED_TRACE(MakeString("M=", M)); + std::unordered_map options; + auto coreml_ep = CoreMLProviderFactoryCreator::Create(options)->CreateProvider(); + + const auto ep_verification_params = EPVerificationParams{ + ExpectedEPNodeAssignment::All, + 1e-4f, + }; + +#if defined(__APPLE__) + RandomValueGenerator gen{1234}; + // Input is [M, 512], reshape to [-1, 2048] so M must be a multiple of 4. + const auto X_shape = std::vector{static_cast(M * 4), 512}; + const auto X_data = gen.Uniform(X_shape, 0.0f, 1.0f); + + OrtValue X = CreateInputOrtValueOnCPU(X_shape, X_data); + + RunAndVerifyOutputsWithEP(model_path, CurrentTestName(), + std::move(coreml_ep), + {{"X", X}}, + ep_verification_params); +#else + TestModelLoad(model_path, std::move(coreml_ep), ep_verification_params.ep_node_assignment); +#endif + }; + + for (size_t i = 1; i <= 3; ++i) { + test(i); + } +} + TEST(CoreMLExecutionProviderDynamicInputShapeTest, EmptyInputFails) { constexpr auto model_path = ORT_TSTR("testdata/matmul_with_dynamic_input_shape.onnx"); diff --git a/onnxruntime/test/testdata/reshape_with_dynamic_input_shape.onnx b/onnxruntime/test/testdata/reshape_with_dynamic_input_shape.onnx new file mode 100644 index 0000000000000000000000000000000000000000..59695d5b53275a769f5b254ebee3c5375cddc0ca GIT binary patch literal 144 zcmdi