[CPU] Fix for the convolution node dummy shapes generation (#14521)

This commit is contained in:
Maksim Kutakov 2022-12-12 20:08:15 +01:00 committed by GitHub
parent 7e1b9353d5
commit ad0ef56665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 32 deletions

View File

@ -157,5 +157,18 @@ Shape MemoryDescUtils::makeDummyShape(const Shape &shape, Dim dummyVal) {
return Shape(dummyDims);
}
Shape MemoryDescUtils::makeDummyShape(const Shape &shape, const VectorDims& dummyVals) {
if (shape.getRank() != dummyVals.size()) {
IE_THROW() << "makeDummyShape(): dummyVals vector size and shape ranks mismatch";
}
const auto& minDims = shape.getMinDims();
const auto& maxDims = shape.getMaxDims();
const auto& dims = shape.getDims();
VectorDims dummyDims(dims.size());
for (size_t i = 0; i < dims.size(); ++i) {
dummyDims[i] = dims[i] == Shape::UNDEFINED_DIM ? std::min(maxDims[i], std::max(minDims[i], dummyVals[i])) : dims[i];
}
return Shape(dummyDims);
}
} // namespace intel_cpu
} // namespace ov

View File

@ -93,12 +93,20 @@ public:
/**
* @brief Makes a static dummy shape where all undefined values are replaced with the smallest value between the parameter and the upper bound dim
* @param shape a shape from which the new static shape is generated
* @param shape a Shape object from which the new static shape is generated
* @param dummyVal Dim value to replace undefined dimensions
* @return a new Shape with dummy values instead of undefined dims
*/
static Shape makeDummyShape(const Shape& shape, Dim dummyVal = DEFAULT_DUMMY_VAL);
/**
* @brief Makes a static dummy shape where all undefined values are replaced with the smallest value between the parameter and the upper bound dim
* @param shape a Shape object from which the new static shape is generated
* @param dummyVals vector of values to replace undefined dimensions
* @return a new Shape with dummy values instead of undefined dims
*/
static Shape makeDummyShape(const Shape& shape, const VectorDims& dummyVals);
/**
* @brief Converts dim to string, undefined dim represented as ?
* @param dim Dim to be converted

View File

@ -826,8 +826,7 @@ void Convolution::createDescriptor(const std::vector<MemoryDescPtr>& inputDesc,
if (inputDesc[0]->isDefined()) {
inpDesc = inputDesc[0];
} else {
auto dummyInDims = MemoryDescUtils::makeDummyShape(inputDesc[0]->getShape()).getStaticDims();
dummyInDims[1] = IC;
auto dummyInDims = makeInputDummyShape(inputDesc[0]->getShape());
inpDesc = inputDesc[0]->cloneWithNewDims(dummyInDims);
}
DnnlMemoryDescPtr definedInpMemDesc = MemoryDescUtils::convertToDnnlMemoryDesc(inpDesc);
@ -917,7 +916,8 @@ void Convolution::addLegacyZeroPoints(dnnl::primitive_attr& attr) {
void Convolution::SetPostOpsAndZeroPoints(std::vector<dnnl::primitive_attr> &attrs) {
// attr[0] - Legacy post ops + Legacy zero points.
attrs.resize(1);
setPostOps(attrs[0], MemoryDescUtils::makeDummyShape(getOutputShapeAtPort(0)).getStaticDims(), true);
auto outputShape = outputStaticShape();
setPostOps(attrs[0], outputShape, true);
addLegacyZeroPoints(attrs[0]);
//dw-conv would be fused into conv only on AVX2 platform. no need attr[1]. Avoid extra useless attribute.
if (attrs[0].get_post_ops().get()->find(dnnl::impl::primitive_kind::convolution) != -1) {
@ -939,9 +939,9 @@ void Convolution::SetPostOpsAndZeroPoints(std::vector<dnnl::primitive_attr> &att
//WR to ONEDNN limitation. attr[1] - legacy post ops + stock zero point.
//@todo:Unify to use binary postops+stock zero point when limitation is fixed.
//For now, have to adapt to JIT_AMX kernel for performance.
setPostOps(attrs[1], MemoryDescUtils::makeDummyShape(getOutputShapeAtPort(0)).getStaticDims(), true);
setPostOps(attrs[1], outputShape, true);
else
setPostOps(attrs[1], MemoryDescUtils::makeDummyShape(getOutputShapeAtPort(0)).getStaticDims(), false);
setPostOps(attrs[1], outputShape, false);
addZeroPoints(attrs[1]);
}
@ -1613,7 +1613,7 @@ void Convolution::initTryBrgconvFlag() {
// should remove after binary postops performance issue resolved
// heuristics: if it's avx512 ISA model && it doesn't have binary post ops or per channel zero point.
dnnl::primitive_attr attr;
setPostOps(attr, MemoryDescUtils::makeDummyShape(getOutputShapeAtPort(0)).getStaticDims(), false);
setPostOps(attr, outputStaticShape(), false);
const auto& ops = attr.get_post_ops();
if (ops.get()->find(dnnl::impl::primitive_kind::binary) != -1) {
shouldTryBrgconv = false;
@ -1641,6 +1641,39 @@ void Convolution::initializeInputZeroPoints(const uint8_t* inputZpData, const si
inputZeroPoints.push_back(static_cast<int32_t>(inputZpData[0]));
}
VectorDims Convolution::makeInputDummyShape(const Shape& inpShape) const {
// There are a bunch of heuristics mostly aimed to guess the most appropriate oneDNN implementation, to reduce the
// amount of the implementation mismatch and the internal reordering as a consequence.
constexpr Dim dummyInputDim = 64;
const size_t spatialRank = stride.size();
const size_t filterStartIndx = weightDims.size() - spatialRank;
VectorDims dummyInputShapeVals(inpShape.getRank(), dummyInputDim);
dummyInputShapeVals[1] = IC; //channels
for (size_t i = 0; i < spatialRank; i++) {
if (weightDims[filterStartIndx + i] > dummyInputShapeVals[2 + i]) {
constexpr Dim dummyOutputDim = 16;
dummyInputShapeVals[2 + i] = (dummyOutputDim - 1) * stride[i] -
(paddingL[i] + paddingR[i]) +
weightDims[filterStartIndx + i] +
(weightDims[filterStartIndx + i]- 1) * (dilation[i]);
}
}
return MemoryDescUtils::makeDummyShape(inpShape, dummyInputShapeVals).getStaticDims();
}
VectorDims Convolution::outputStaticShape() const {
auto& outputShape = getOutputShapeAtPort(0);
if (outputShape.isDynamic()) {
auto inpDummyShape = makeInputDummyShape(getInputShapeAtPort(0));
auto outputDims = shapeInferGeneric({ Shape(inpDummyShape), Shape(weightDims) });
return Shape(outputDims.front()).getStaticDims();
}
return outputShape.getStaticDims();
}
} // namespace node
} // namespace intel_cpu
} // namespace ov

View File

@ -112,7 +112,8 @@ private:
void updatePadding();
MemoryDescPtr getSumMemDesc(dnnl::primitive_desc_iterator &primitive_desc_it);
MemoryPtr getOutputMemory() const;
VectorDims makeInputDummyShape(const Shape& inpShape) const;
VectorDims outputStaticShape() const;
void appendLegacyZeroPointsArgs();
void appendZeroPointsArgs();
void initTryBrgconvFlag();

View File

@ -214,31 +214,33 @@ TEST_P(ConvolutionLayerCPUTest, CompareWithRefs) {
}
}
// Skip tests for brgconv convolution where kernel size = 1x1
if (priority[0] == "brgconv_avx512" || priority[0] == "brgconv_avx512_amx") {
bool is_1x1 = true;
for (const auto &i : kernel) {
if (i != 1) {
is_1x1 = false;
break;
}
if (!priority.empty()) {
// Skip tests for brgconv convolution where kernel size = 1x1
if (priority[0] == "brgconv_avx512" || priority[0] == "brgconv_avx512_amx") {
bool is_1x1 = true;
for (const auto &i : kernel) {
if (i != 1) {
is_1x1 = false;
break;
}
}
if (is_1x1) {
GTEST_SKIP() << "Disabled test due to the brgconv does not support 1x1 convolution kernel." << std::endl;
}
}
if (is_1x1) {
GTEST_SKIP() << "Disabled test due to the brgconv does not support 1x1 convolution kernel." << std::endl;
}
}
// Skip tests for brgconv_amx convolution where dilation is not 1
if (priority[0].find("amx") != std::string::npos) {
bool dilation_is_1x1 = true;
for (const auto &i : dilation) {
if (i != 1) {
dilation_is_1x1 = false;
break;
}
}
if (!dilation_is_1x1) {
GTEST_SKIP() << "Disabled test due to the brgconv amx does not support non 1 dilation convolution kernel." << std::endl;
// Skip tests for brgconv_amx convolution where dilation is not 1
if (priority[0].find("amx") != std::string::npos) {
bool dilation_is_1x1 = true;
for (const auto &i : dilation) {
if (i != 1) {
dilation_is_1x1 = false;
break;
}
}
if (!dilation_is_1x1) {
GTEST_SKIP() << "Disabled test due to the brgconv amx does not support non 1 dilation convolution kernel." << std::endl;
}
}
}
@ -1683,4 +1685,53 @@ INSTANTIATE_TEST_SUITE_P(smoke_Conv_winograd, ConvolutionLayerCPUTest,
} // namespace winograd
/* ============= Large Filter Test ============= */
namespace {
const size_t outChannels = 80;
const SizeVector kernel = { 251 };
const SizeVector stride = { 10 };
const std::vector<ptrdiff_t> padBegins = { 0 };
const std::vector<ptrdiff_t> padEnds = { 0 };
const SizeVector dilations = { 1 };
const auto convParams_1D = ::testing::Combine(
::testing::Values(kernel),
::testing::Values(stride),
::testing::Values(padBegins),
::testing::Values(padEnds),
::testing::Values(dilations),
::testing::Values(outChannels),
::testing::Values(ngraph::op::PadType::EXPLICIT)
);
std::vector<InputShape> inShapes = {
{{}, {{ 1, 1, 600 }}},
{
//dynamic shape
{ -1, 1, -1 },
{ //target static shapes
{ 1, 1, 600 },
{ 10, 1, 700 },
{ 1, 1, 600 }
}
}
};
INSTANTIATE_TEST_SUITE_P(smoke_Conv_Large_Filter, ConvolutionLayerCPUTest,
::testing::Combine(
::testing::Combine(
convParams_1D,
::testing::Values(ElementType::f32),
::testing::Values(ElementType::f32),
::testing::Values(ElementType::undefined),
::testing::ValuesIn(inShapes),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
::testing::Values(CPUSpecificParams{{}, {}, {}, CPUTestsBase::any_type}),
::testing::Values(emptyFusingSpec),
::testing::Values(cpuEmptyPluginConfig)),
ConvolutionLayerCPUTest::getTestCaseName);
} // namespace
} // namespace CPULayerTestsDefinitions

View File

@ -222,7 +222,7 @@ void CPUTestsBase::CheckPluginRelatedResultsImpl(const std::shared_ptr<const ov:
}
bool CPUTestsBase::primTypeCheck(std::string primType) const {
return selectedType == CPUTestsBase::any_type || selectedType == primType;
return selectedType.find(CPUTestsBase::any_type) != std::string::npos || selectedType == primType;
}
std::string CPUTestsBase::getTestCaseName(CPUSpecificParams params) {