Skip to content

Commit

Permalink
[GPU] Add check of multiple axis broadcasting in is_valid_fusion() wh…
Browse files Browse the repository at this point in the history
…en dynamic shape (openvinotoolkit#28252)

### Details:
- Add check of multiple axis broadcasting in is_valid_fusion() when
dynamic shape
- Current ocl fused_op jit constant doesn't support multiple axis
boradcase.

![image](https://github.com/user-attachments/assets/5064faef-252c-416e-a7ba-71151d35db1e)


### Tickets:
 - 159939
  • Loading branch information
wilson-seok authored Jan 6, 2025
1 parent 74041ec commit 3bd87f0
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/plugins/intel_gpu/src/graph/primitive_inst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2658,6 +2658,18 @@ bool primitive_inst::is_valid_fusion() const {
if (fd.is_type<eltwise>())
can_broadcast = ov::PartialShape::broadcast_merge_into(merged_shape, outer_dep_pshape, fd.typed_desc<eltwise>()->broadcast_spec);

// Check if broadcast happens more than single axis.
// Current gemm_tiled_opt kernel FUSED_OP_LOAD macro cannot support broadcast on dynamic dimension.
if (_node->is_type<gemm>() && can_broadcast == true && merged_shape.rank().get_length() == outer_dep_pshape.rank().get_length()) {
uint8_t broadcast_more_than_single_axis = 0;
for (int64_t i = 0; i < merged_shape.rank().get_length(); i++) {
if (merged_shape.get_shape().at(i) != outer_dep_pshape.get_shape().at(i))
broadcast_more_than_single_axis++;
}
if (broadcast_more_than_single_axis > 1)
can_broadcast = false;
}

#ifdef ENABLE_ONEDNN_FOR_GPU
// WA for OneDNN binary add fusions: we need to broadcast batch dimension to avoid situation with
// batch dimension mismatch in OneDNN tensor descriptors as follow:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "common_test_utils/ov_tensor_utils.hpp"
#include "common_test_utils/file_utils.hpp"
#include "shared_test_classes/base/ov_subgraph.hpp"

#include "openvino/op/parameter.hpp"
#include "openvino/op/matmul.hpp"
#include "openvino/op/multiply.hpp"

namespace {

using ov::test::InputShape;

using DynamicUnfusionsParams = std::tuple<std::vector<InputShape>, // input shapes
ov::element::Type>; // input precision

class DynamicUnfusions : public testing::WithParamInterface<DynamicUnfusionsParams>,
virtual public ov::test::SubgraphBaseTest {
public:
static std::string getTestCaseName(testing::TestParamInfo<DynamicUnfusionsParams> obj) {
std::vector<InputShape> input_shapes;
ov::element::Type input_precision;

std::tie(input_shapes, input_precision) = obj.param;

std::ostringstream result;
result << "IS=(";
for (const auto& shape : input_shapes) {
result << ov::test::utils::partialShape2str({shape.first}) << "_";
}
result << ")_TS=";
for (const auto& shape : input_shapes) {
result << "(";
if (!shape.second.empty()) {
auto itr = shape.second.begin();
do {
result << ov::test::utils::vec2str(*itr);
} while (++itr != shape.second.end() && result << "_");
}
result << ")_";
}
result << "input_precision=" << input_precision;
return result.str();
}

protected:
std::shared_ptr<ov::Model> init_subgraph(std::vector<ov::PartialShape>& input_shapes,
const ov::element::Type input_precision) {
auto input0 = std::make_shared<ov::op::v0::Parameter>(input_precision, input_shapes[0]);
auto input1 = std::make_shared<ov::op::v0::Parameter>(input_precision, input_shapes[1]);
auto input2 = std::make_shared<ov::op::v0::Parameter>(input_precision, input_shapes[2]);

auto matmul = std::make_shared<ov::op::v0::MatMul>(input0, input1);
auto mul = std::make_shared<ov::op::v1::Multiply>(matmul, input2);

matmul->set_friendly_name("MatMul");
mul->set_friendly_name("Multiply");

return std::make_shared<ov::Model>(ov::NodeVector{mul}, ov::ParameterVector{input0, input1, input2}, "DynamicUnfusions");
}

void SetUp() override {
targetDevice = ov::test::utils::DEVICE_GPU;

std::vector<InputShape> input_shapes;
ov::element::Type input_precision;

std::tie(input_shapes, input_precision) = GetParam();

init_input_shapes(input_shapes);

inType = outType = input_precision;
function = init_subgraph(inputDynamicShapes, input_precision);
}
};

TEST_P(DynamicUnfusions, Inference) {
run();
}

const std::vector<ov::element::Type> input_precisions = {ov::element::f32};

const std::vector<std::vector<InputShape>> input_shapes_dyn = {
{{{1024, -1}, {{1024, 1024}}}, {{-1, 1024}, {{1024, 1024}}}, {{1, -1}, {{1, 1}}}},
};

INSTANTIATE_TEST_SUITE_P(DynamicUnfusions_basic,
DynamicUnfusions,
::testing::Combine(::testing::ValuesIn(input_shapes_dyn),
::testing::ValuesIn(input_precisions)),
DynamicUnfusions::getTestCaseName);
} // namespace

0 comments on commit 3bd87f0

Please sign in to comment.