[BUG fix] Reshape node: WA in-place failure case by mem-copy (#10828)

* Handle in-place failure cases in reshape node

* Disable inplace when non-const reshape connected to constant

* Add comment to reshape_inplace test

* move copy WA into execute() to cover more general in-place failure cases
This commit is contained in:
Tingqian Li 2022-07-05 12:46:27 +08:00 committed by GitHub
parent a571539107
commit 3f9c6b2f3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 4 deletions

View File

@ -111,6 +111,12 @@ void Reshape::initSupportedPrimitiveDescriptors() {
if (inPrec != outPrec)
inPrec = outPrec;
bool canBeInPlace = true;
// CVS-81059 : disable inPlace in following case since it won't be satisfied by framework
if (!isConstant() && getParentEdgeAt(0)->getParent()->isConstant())
canBeInPlace = false;
NodeConfig config;
config.dynBatchSupport = true;
config.inConfs.resize(getParentEdges().size());
@ -121,7 +127,7 @@ void Reshape::initSupportedPrimitiveDescriptors() {
config.inConfs[i].setMemDesc(creatorsMap.at(LayoutType::ncsp)->createSharedDesc((i > 0 ? secondInPrc : inPrec), getInputShapeAtPort(i)));
}
config.outConfs.resize(1);
config.outConfs[0].inPlace(0);
config.outConfs[0].inPlace(canBeInPlace ? 0 : -1);
config.outConfs[0].constant(false);
config.outConfs[0].setMemDesc(creatorsMap.at(LayoutType::ncsp)->createSharedDesc(outPrec, getOutputShapeAtPort(0)));
supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown);
@ -131,6 +137,24 @@ void Reshape::executeDynamicImpl(dnnl::stream strm) {
execute(strm);
}
void Reshape::execute(dnnl::stream strm) {
auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr();
auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
auto srcPtr = static_cast<uint8_t*>(srcMemPtr->GetPtr());
auto dstPtr = static_cast<uint8_t*>(dstMemPtr->GetPtr());
if (dstPtr != srcPtr) {
cpu_memcpy(dstPtr, srcPtr, dstMemPtr->GetSize());
}
}
bool Reshape::isExecutable() const {
bool inPlaceEnabled =
getSelectedPrimitiveDescriptor() && getSelectedPrimitiveDescriptor()->getConfig().outConfs[0].inPlace() >= 0;
return !inPlaceEnabled;
}
bool Reshape::created() const {
return getType() == Type::Reshape;
}

View File

@ -22,14 +22,13 @@ public:
void getSupportedDescriptors() override;
void initSupportedPrimitiveDescriptors() override;
bool created() const override;
bool isExecutable() const override {
return false;
}
bool isExecutable() const override;
bool needShapeInfer() const override;
std::vector<VectorDims> shapeInfer() const override;
bool needPrepareParams() const override { return false; }
void executeDynamicImpl(dnnl::stream strm) override;
void execute(dnnl::stream strm) override;
static bool isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept;

View File

@ -0,0 +1,90 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <common_test_utils/ov_tensor_utils.hpp>
#include "ngraph/runtime/aligned_buffer.hpp"
#include "ngraph_functions/builders.hpp"
#include "ngraph_functions/utils/ngraph_helpers.hpp"
#include "shared_test_classes/base/layer_test_utils.hpp"
#include "shared_test_classes/base/ov_subgraph.hpp"
using namespace InferenceEngine;
using namespace ov::test;
namespace SubgraphTestsDefinitions {
// Subgraph:
/*
* params[0] params[1]
* | |
* constant shapeOf /
* \ | /
* broadcast /
* \ /
* \ /
* reshape
* |
* result
*
* This test is designed for correctness of reshape's in-place implementation.
*
* Due to non-const target shape parameter (params[1]), reshape node
* is non-constant node even though the input tensor is constant node.
*
* some logic protecting constant data from being corrupted by
* the in-place consumer may breaks the in-place assumption, and reshape
* should be able to handle this case correctly.
*/
class InPlaceReshapeFromConstantCheck : public SubgraphBaseTest {
protected:
void SetUp() override {
const auto rtPrc = ov::element::f32;
const ov::Shape inpShape = {21660, 4};
const ov::Shape secShape = {4};
ngraph::ParameterVector params(2);
targetStaticShapes = {{inpShape, secShape}};
targetDevice = CommonTestUtils::DEVICE_CPU;
params[0] = ngraph::builder::makeParams(rtPrc, {inpShape})[0];
params[1] = ngraph::builder::makeParams(ov::element::i32, {secShape})[0];
auto shape = std::make_shared<ov::opset8::ShapeOf>(params[0]);
auto c = ngraph::builder::makeConstant<float>(rtPrc, {}, {1.0f});
auto broadcast = std::make_shared<ov::opset8::Broadcast>(c, shape);
auto reshape = std::make_shared<ov::opset8::Reshape>(broadcast, params[1], false);
ov::ResultVector results{std::make_shared<ngraph::opset1::Result>(reshape->output(0))};
function = std::make_shared<ngraph::Function>(results, params, "reshape_check");
}
void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override {
inputs.clear();
const auto& funcInputs = function->inputs();
for (int i = 0; i < funcInputs.size(); ++i) {
const auto& funcInput = funcInputs[i];
ov::runtime::Tensor tensor;
if (i == 1) {
tensor = ov::runtime::Tensor{ov::element::i32, targetInputStaticShapes[i]};
auto inputData = tensor.data<ov::element_type_traits<ov::element::i32>::value_type>();
const std::vector<unsigned> data = {38, 38, 15, 4};
for (size_t j = 0lu; j < data.size(); ++j) {
inputData[j] = data[j];
}
} else {
if (funcInput.get_element_type().is_real()) {
tensor = utils::create_and_fill_tensor(funcInput.get_element_type(),
targetInputStaticShapes[i],
10,
0,
1000);
} else {
tensor = utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i]);
}
}
inputs.insert({funcInput.get_node_shared_ptr(), tensor});
}
}
};
TEST_F(InPlaceReshapeFromConstantCheck, smoke_CPU_InPlaceReshapeFromConstantCheck) {
SKIP_IF_CURRENT_TEST_IS_DISABLED()
run();
}
} // namespace SubgraphTestsDefinitions