[CPU][GPU] Mismatch tensor and port types: i64 vs i32 (#23859)
HETERO plugin ('HETERO:GPU,CPU') raises an error [GPU] Mismatch tensor
and port types: i64 vs i32
### Details:
- *Do not convert Result element type after Extension if required;*
- *Eliminate converts after the second call of the ConvertPrecisoin
pass;*
- *Support string input in the `benchmark_app`*.
### Tickets:
- *136752*
This commit is contained in:
parent
a3ababde4d
commit
77f69957b1
|
|
@ -584,6 +584,24 @@ ov::Tensor get_random_tensor(const std::pair<std::string, benchmark_app::InputIn
|
|||
return create_tensor_random<int16_t, int16_t>(inputInfo.second);
|
||||
} else if (type == ov::element::boolean) {
|
||||
return create_tensor_random<uint8_t, uint32_t>(inputInfo.second, 0, 1);
|
||||
} else if (type == ov::element::string) {
|
||||
const auto& in_info = inputInfo.second;
|
||||
const auto tensor_size = ov::shape_size(in_info.dataShape);
|
||||
auto tensor = ov::Tensor(in_info.type, in_info.dataShape);
|
||||
auto data = tensor.data<std::string>();
|
||||
|
||||
std::mt19937 str_len_gen(0);
|
||||
uniformDistribution<uint32_t> len_distribution(20, 50);
|
||||
std::mt19937 char_val_gen(0);
|
||||
uniformDistribution<uint32_t> char_distribution(0, 127);
|
||||
for (size_t i = 0; i < tensor_size; i++) {
|
||||
data[i].resize(len_distribution(str_len_gen));
|
||||
for (size_t j = 0lu; j < data[i].size(); j++) {
|
||||
data[i][j] = static_cast<char>(char_distribution(char_val_gen));
|
||||
}
|
||||
}
|
||||
|
||||
return tensor;
|
||||
} else {
|
||||
OPENVINO_THROW("Input type is not supported for " + inputInfo.first);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// Copyright (C) 2023 Intel Corporation
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "insert_convert_after_extension.hpp"
|
||||
|
||||
#include <openvino/op/convert.hpp>
|
||||
#include "openvino/op/convert.hpp"
|
||||
#include "cpu_types.h"
|
||||
#include "itt.hpp"
|
||||
#include <transformations/utils/utils.hpp>
|
||||
#include "transformations/utils/utils.hpp"
|
||||
|
||||
ov::pass::InsertConvertAfterExtension::InsertConvertAfterExtension() {
|
||||
ov::pass::InsertConvertAfterExtension::InsertConvertAfterExtension(bool convert_output_precision) {
|
||||
MATCHER_SCOPE(InsertConvertAfterExtension);
|
||||
|
||||
auto i64_extension = [](const ov::Output<ov::Node>& output) -> bool {
|
||||
|
|
@ -29,6 +29,10 @@ ov::pass::InsertConvertAfterExtension::InsertConvertAfterExtension() {
|
|||
auto convert = std::make_shared<op::v0::Convert>(output, ov::element::i32);
|
||||
|
||||
for (const auto& targetInput : targetInputs) {
|
||||
// Keep the original output element type if required.
|
||||
if (!convert_output_precision && is_type<op::v0::Result>(targetInput.get_node())) {
|
||||
continue;
|
||||
}
|
||||
targetInput.replace_source_output(convert);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (C) 2023 Intel Corporation
|
||||
// Copyright (C) 2018-2024 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openvino/pass/graph_rewrite.hpp>
|
||||
#include "openvino/pass/graph_rewrite.hpp"
|
||||
|
||||
namespace ov {
|
||||
namespace pass {
|
||||
|
|
@ -15,7 +15,7 @@ namespace pass {
|
|||
class InsertConvertAfterExtension: public ov::pass::MatcherPass {
|
||||
public:
|
||||
OPENVINO_RTTI("InsertConvertAfterExtension", "0");
|
||||
InsertConvertAfterExtension();
|
||||
InsertConvertAfterExtension(bool convert_output_precision = true);
|
||||
};
|
||||
|
||||
} // namespace pass
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ inline void ConvertToCPUSpecificOpset(std::shared_ptr<ov::Model> &nGraphFunc, in
|
|||
false,
|
||||
false);
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::Validate);
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::EliminateConvert); // Need to clean up after the ConvertPrecision.
|
||||
|
||||
manager.run_passes(nGraphFunc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,9 +405,12 @@ void Transformations::PreLpt(const std::vector<ov::element::Type>& defaultPrecis
|
|||
// Common ConvertPrecision pass handles only a limited set of opevino operations to match the list of precisions supported by the plugin.
|
||||
// However, if the extension operation produces an output precision that is not natively supported, this may lead to inconsistency during
|
||||
// element type propagation. This transformation is called before the ConvertPrecision pass to align the actual precisions with the list of supported ones.
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::InsertConvertAfterExtension);
|
||||
constexpr bool convert_input_output_precision = false;
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::InsertConvertAfterExtension, convert_input_output_precision);
|
||||
// Do not insert pass::Validate between pass::InsertConvertAfterExtension and pass::ConvertPrecision.
|
||||
// This may result in the loss of the original Element type of the Output .
|
||||
// element type convert is disabled.
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::ConvertPrecision, precisions, type_to_fuse, false, false);
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::ConvertPrecision, precisions, type_to_fuse, false, convert_input_output_precision);
|
||||
|
||||
CPU_REGISTER_PASS_COMMON(manager, ov::pass::EliminateConvert);
|
||||
CPU_REGISTER_PASS_COMMON(manager, SwapConvertTranspose);
|
||||
|
|
|
|||
|
|
@ -2,46 +2,71 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <common_test_utils/ov_tensor_utils.hpp>
|
||||
#include <openvino/op/op.hpp>
|
||||
#include <shared_test_classes/base/ov_subgraph.hpp>
|
||||
#include "common_test_utils/ov_tensor_utils.hpp"
|
||||
#include "openvino/op/op.hpp"
|
||||
#include "shared_test_classes/base/ov_subgraph.hpp"
|
||||
#include "utils/cpu_test_utils.hpp"
|
||||
|
||||
// --------------------- ---------------------
|
||||
// | PARAMETER | | PARAMETER |
|
||||
// --------------------- ---------------------
|
||||
// | | | |
|
||||
// ------------- ---------- ------------- ----------
|
||||
// | EXT_I64 | | CPU_OP | | EXT_I64 | | CPU_OP |
|
||||
// ------------- ---------- -------\ ------------- ----------
|
||||
// |i64 |i32 | \ |i64 |i32 |
|
||||
// -------- --------- ------------- / -------------- --------- -------------
|
||||
// | CPU_OP | | RES_I32 | | EXT_I64 | -------/ | CVT I64->I32 | | RES_I32 | | EXT_I64 |
|
||||
// -------- --------- ------------- -------------- --------- -------------
|
||||
// |i64 |i64 |i32 |i32 |i64 |i32
|
||||
// --------- --------- --------- -------- --------- ---------
|
||||
// | RES_I64 | | RES_I64 | | RES_I32 | | CPU_OP | | RES_I64 | | RES_I32 |
|
||||
// --------- --------- --------- -------- --------- ---------
|
||||
// |i32
|
||||
// --------------
|
||||
// | CVT I32->I64 |
|
||||
// --------------
|
||||
// |i64
|
||||
// ---------
|
||||
// | RES_I64 |
|
||||
// ---------
|
||||
|
||||
using namespace ov::test;
|
||||
using namespace CPUTestUtils;
|
||||
|
||||
namespace ov {
|
||||
namespace test {
|
||||
using CustomOpI64CPUTestParams = std::tuple<ElementType, InputShape>;
|
||||
using CustomOpI64CPUTestParams = std::tuple<
|
||||
ElementType, // Input element type
|
||||
InputShape // Input shape
|
||||
>;
|
||||
|
||||
class CustomOpI64 : public ov::op::Op {
|
||||
public:
|
||||
OPENVINO_OP("CustomOpI64");
|
||||
|
||||
CustomOpI64() = default;
|
||||
CustomOpI64(const ov::OutputVector& args) : Op(args) {
|
||||
|
||||
CustomOpI64(const Output<Node>& arg) : Op({arg}) {
|
||||
constructor_validate_and_infer_types();
|
||||
}
|
||||
|
||||
void validate_and_infer_types() override {
|
||||
const auto& inputs_count = input_values().size();
|
||||
OPENVINO_ASSERT(inputs_count == 1,
|
||||
"Input count must be 1, Got: ",
|
||||
inputs_count);
|
||||
OPENVINO_ASSERT(get_input_element_type(0) == ov::element::Type_t::i32,
|
||||
"The input must be i32.");
|
||||
OPENVINO_ASSERT(inputs_count == 1, "Input count must be 1, Got: ", inputs_count);
|
||||
OPENVINO_ASSERT(get_input_element_type(0) == element::i32, "The input must be i32.");
|
||||
set_output_size(2);
|
||||
|
||||
auto inShape = get_input_partial_shape(0);
|
||||
auto in_shape = get_input_partial_shape(0);
|
||||
|
||||
set_output_type(0, ov::element::Type_t::i64, inShape);
|
||||
set_output_type(1, ov::element::Type_t::i32, inShape);
|
||||
set_output_type(0, element::i64, in_shape);
|
||||
set_output_type(1, element::i32, in_shape);
|
||||
}
|
||||
|
||||
std::shared_ptr<ov::Node> clone_with_new_inputs(const ov::OutputVector& new_args) const override {
|
||||
OPENVINO_ASSERT(new_args.size() == 1, "Incorrect number of new arguments");
|
||||
|
||||
return std::make_shared<CustomOpI64>(new_args);
|
||||
return std::make_shared<CustomOpI64>(new_args[0]);
|
||||
}
|
||||
|
||||
bool visit_attributes(ov::AttributeVisitor& visitor) override {
|
||||
|
|
@ -81,42 +106,44 @@ class CustomOpConvertI64CPUTest : public testing::WithParamInterface<CustomOpI64
|
|||
public CPUTestsBase {
|
||||
public:
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<CustomOpI64CPUTestParams>& obj) {
|
||||
ElementType inType;
|
||||
InputShape inputShape;
|
||||
std::tie(inType, inputShape) = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << "IS=" << inputShape << "_";
|
||||
result << "Prc=" << inType;
|
||||
|
||||
result << "InElType=" << std::get<0>(obj.param) << "_";
|
||||
result << "IS=" << std::get<1>(obj.param);
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
targetDevice = ov::test::utils::DEVICE_CPU;
|
||||
targetDevice = test::utils::DEVICE_CPU;
|
||||
|
||||
ElementType inType;
|
||||
InputShape inputShape;
|
||||
std::tie(inType, inputShape) = this->GetParam();
|
||||
const auto& params = this->GetParam();
|
||||
const auto& in_el_type = std::get<0>(params);
|
||||
const auto& in_shape = std::get<1>(params);
|
||||
|
||||
init_input_shapes({inputShape});
|
||||
ov::ParameterVector inputParams;
|
||||
ov::OutputVector paramsOuts;
|
||||
for (auto&& shape : inputDynamicShapes) {
|
||||
auto param = std::make_shared<ov::op::v0::Parameter>(inType, shape);
|
||||
inputParams.push_back(param);
|
||||
paramsOuts.push_back(param);
|
||||
}
|
||||
auto customOp = std::make_shared<CustomOpI64>(paramsOuts);
|
||||
init_input_shapes({in_shape});
|
||||
auto param = std::make_shared<op::v0::Parameter>(in_el_type, inputDynamicShapes[0]);
|
||||
|
||||
ov::ResultVector results{std::make_shared<ov::op::v0::Result>(customOp)};
|
||||
function = std::make_shared<ov::Model>(results, inputParams, "customOpTest");
|
||||
auto custom_op_0 = std::make_shared<CustomOpI64>(param);
|
||||
auto i32_op_0 = std::make_shared<op::v1::LogicalNot>(custom_op_0->output(0));
|
||||
auto i32_op_1 = std::make_shared<op::v1::LogicalNot>(param);
|
||||
auto custom_op_1 = std::make_shared<CustomOpI64>(i32_op_1);
|
||||
|
||||
OutputVector results{
|
||||
i32_op_0->output(0),
|
||||
custom_op_0->output(1),
|
||||
custom_op_1->output(0),
|
||||
custom_op_1->output(1)
|
||||
};
|
||||
|
||||
function = std::make_shared<ov::Model>(results, ParameterVector{param}, "customOpI64Test");
|
||||
}
|
||||
|
||||
void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override {
|
||||
inputs.clear();
|
||||
const auto& funcInputs = function->inputs();
|
||||
for (size_t i = 0; i < funcInputs.size(); ++i) {
|
||||
for (size_t i = 0lu; i < funcInputs.size(); ++i) {
|
||||
const auto& funcInput = funcInputs[i];
|
||||
auto tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
|
||||
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
|
||||
|
|
@ -138,8 +165,41 @@ protected:
|
|||
|
||||
TEST_P(CustomOpConvertI64CPUTest, CompareWithRefs) {
|
||||
run();
|
||||
// TODO: Graph could not be dumped with int64 for now. Swith on this in scope of int64 enabling.
|
||||
// CPUTestUtils::CheckNumberOfNodesWithType(compiledModel, "Convert", 1);
|
||||
|
||||
size_t cvt_i64_i32_num = 0lu;
|
||||
size_t cvt_i32_i64_num = 0lu;
|
||||
size_t res_i64_num = 0lu;
|
||||
size_t res_i32_num = 0lu;
|
||||
|
||||
for (const auto& node : compiledModel.get_runtime_model()->get_ops()) {
|
||||
auto rt_info = node->get_rt_info();
|
||||
auto it = rt_info.find(exec_model_info::LAYER_TYPE);
|
||||
ASSERT_NE(rt_info.end(), it);
|
||||
|
||||
if (it->second.as<std::string>() == "Convert") {
|
||||
if (node->get_output_element_type(0) == element::i64) {
|
||||
cvt_i32_i64_num++;
|
||||
} else if (node->get_output_element_type(0) == element::i32) {
|
||||
cvt_i64_i32_num++;
|
||||
} else {
|
||||
FAIL() << "Unexpected convertion type: " << node->get_output_element_type(0);
|
||||
}
|
||||
}
|
||||
if (it->second.as<std::string>() == "Output") {
|
||||
if (node->get_output_element_type(0) == element::i64) {
|
||||
res_i64_num++;
|
||||
} else if (node->get_output_element_type(0) == element::i32) {
|
||||
res_i32_num++;
|
||||
} else {
|
||||
FAIL() << "Unexpected Result type: " << node->get_output_element_type(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(cvt_i32_i64_num, 1lu) << "Unexpected number of the Convert i32->i64 nodes.";
|
||||
ASSERT_EQ(cvt_i64_i32_num, 1lu) << "Unexpected number of the Convert i64->i32 nodes.";
|
||||
ASSERT_EQ(res_i64_num, 2lu) << "Unexpected number of the Result nodes with type i64.";
|
||||
ASSERT_EQ(res_i32_num, 2lu) << "Unexpected number of the Result nodes with type i32.";
|
||||
}
|
||||
|
||||
const InputShape inputShapes = {
|
||||
|
|
@ -148,8 +208,9 @@ const InputShape inputShapes = {
|
|||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_CustomOp,
|
||||
CustomOpConvertI64CPUTest,
|
||||
::testing::Combine(::testing::Values(ElementType::i32), ::testing::Values(inputShapes)),
|
||||
::testing::Combine(
|
||||
::testing::Values(ElementType::i32),
|
||||
::testing::Values(inputShapes)),
|
||||
CustomOpConvertI64CPUTest::getTestCaseName);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ov
|
||||
|
|
|
|||
Loading…
Reference in New Issue