[CPU] PriorBox & PriorBoxClustered dynamism enabling (#8597)

This commit is contained in:
Edward Shogulin authored and GitHub committed 2021-12-30 17:43:16 +03:00
1 parent 8ba94cfb8f
commit ec5198094a
13 files changed
+1073 -10

No files matched your search

+3 -1
View File
@@ -185,7 +185,9 @@ const InferenceEngine::details::caseless_unordered_map<std::string, Type> type_t
{ "MatrixNms", MatrixNms},
{ "MulticlassNms", MulticlassNms},
{ "Reference", Reference},
{ "Subgraph", Subgraph}
{ "Subgraph", Subgraph},
{ "PriorBox", PriorBox},
{ "PriorBoxClustered", PriorBoxClustered},
};
Type TypeFromName(const std::string& type) {
+3 -1
View File
@@ -101,7 +101,9 @@ enum Type {
NonMaxSuppression,
MatrixNms,
MulticlassNms,
Subgraph
Subgraph,
PriorBox,
PriorBoxClustered,
};
enum Algorithm {
@@ -83,6 +83,8 @@
#include "nodes/mkldnn_non_zero.h"
#include "nodes/mkldnn_color_convert_node.h"
#include "nodes/subgraph.h"
#include "nodes/mkldnn_priorbox_node.h"
#include "nodes/mkldnn_priorbox_clustered_node.h"
#define MKLDNN_NODE(__prim, __type) \
registerNodeIfRequired(MKLDNNPlugin, __prim, __type, MKLDNNNodeImpl<__prim>)
@@ -174,4 +176,6 @@ MKLDNNPlugin::MKLDNNNode::NodesFactory::NodesFactory()
MKLDNN_NODE(MKLDNNNonZeroNode, NonZero);
MKLDNN_NODE(MKLDNNSnippetNode, Subgraph);
MKLDNN_NODE(MKLDNNColorConvertNode, ColorConvert);
MKLDNN_NODE(MKLDNNPriorBoxNode, PriorBox);
MKLDNN_NODE(MKLDNNPriorBoxClusteredNode, PriorBoxClustered);
}
@@ -0,0 +1,170 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "mkldnn_priorbox_clustered_node.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include <vector>
#include <ie_parallel.hpp>
#include <mkldnn_types.h>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset1.hpp>
using namespace MKLDNNPlugin;
using namespace InferenceEngine;
bool MKLDNNPriorBoxClusteredNode::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
try {
const auto priorBox = std::dynamic_pointer_cast<const ngraph::opset1::PriorBoxClustered>(op);
if (!priorBox) {
errorMessage = "Only opset1 PriorBoxClustered operation is supported";
return false;
}
} catch (...) {
return false;
}
return true;
}
MKLDNNPriorBoxClusteredNode::MKLDNNPriorBoxClusteredNode(
const std::shared_ptr<ngraph::Node>& op,
const mkldnn::engine& eng,
MKLDNNWeightsSharing::Ptr &cache) : MKLDNNNode(op, eng, cache) {
std::string errorMessage;
if (!isSupportedOperation(op, errorMessage)) {
IE_THROW(NotImplemented) << errorMessage;
}
const auto priorBox = std::dynamic_pointer_cast<const ngraph::opset1::PriorBoxClustered>(op);
const ngraph::opset1::PriorBoxClustered::Attributes& attrs = priorBox->get_attrs();
widths = attrs.widths;
heights = attrs.heights;
clip = attrs.clip;
variances = attrs.variances;
step = attrs.step;
step_heights = attrs.step_heights;
step_widths = attrs.step_widths;
offset = attrs.offset;
number_of_priors = widths.size();
if (variances.empty()) {
variances.push_back(0.1f);
}
}
bool MKLDNNPriorBoxClusteredNode::needShapeInfer() const {
auto& memory = getChildEdgeAt(0)->getMemoryPtr();
if (memory->GetShape().isDynamic()) {
return true;
}
const auto& outputShape = memory->GetShape().getStaticDims();
const int* in_data = reinterpret_cast<int*>(memory->GetPtr());
const int h = in_data[0];
const int w = in_data[1];
const auto output = static_cast<size_t>(4 * h * w * number_of_priors);
return outputShape[1] != output;
}
std::vector<VectorDims> MKLDNNPriorBoxClusteredNode::shapeInfer() const {
const int* in_data = reinterpret_cast<int*>(getParentEdgeAt(0)->getMemoryPtr()->GetPtr());
const int H = in_data[0];
const int W = in_data[1];
const auto output = static_cast<size_t>(4 * H * W * number_of_priors);
return {{2, output}};
}
bool MKLDNNPriorBoxClusteredNode::needPrepareParams() const {
return false;
}
void MKLDNNPriorBoxClusteredNode::initSupportedPrimitiveDescriptors() {
if (!supportedPrimitiveDescriptors.empty())
return;
addSupportedPrimDesc(
{{LayoutType::ncsp, Precision::I32}, {LayoutType::ncsp, Precision::I32}},
{{LayoutType::ncsp, Precision::FP32}},
impl_desc_type::ref_any);
}
void MKLDNNPriorBoxClusteredNode::createPrimitive() {
if (inputShapesDefined()) {
if (needPrepareParams())
prepareParams();
updateLastInputDims();
}
}
void MKLDNNPriorBoxClusteredNode::execute(mkldnn::stream strm) {
const int* in_data = reinterpret_cast<int*>(getParentEdgeAt(0)->getMemoryPtr()->GetPtr());
const int layer_height = in_data[0];
const int layer_width = in_data[1];
const int* in_image = reinterpret_cast<int*>(getParentEdgeAt(1)->getMemoryPtr()->GetPtr());
int img_height = in_image[0];
int img_width = in_image[1];
float step_w = step_widths == 0 ? step : step_widths;
float step_h = step_heights == 0 ? step : step_heights;
if (step_w == 0 && step_h == 0) {
step_w = static_cast<float>(img_width) / layer_width;
step_h = static_cast<float>(img_height) / layer_height;
}
float* dst_data = reinterpret_cast<float*>(getChildEdgeAt(0)->getMemoryPtr()->GetPtr());
const auto& out_shape = getChildEdgeAt(0)->getMemory().GetShape().getStaticDims();
size_t var_size = variances.size();
parallel_for2d(layer_height, layer_width, [&](int64_t h, int64_t w) {
float center_x = (w + offset) * step_w;
float center_y = (h + offset) * step_h;
for (size_t s = 0; s < number_of_priors; ++s) {
float box_width = widths[s];
float box_height = heights[s];
float xmin = (center_x - box_width / 2.0f) / img_width;
float ymin = (center_y - box_height / 2.0f) / img_height;
float xmax = (center_x + box_width / 2.0f) / img_width;
float ymax = (center_y + box_height / 2.0f) / img_height;
if (clip) {
xmin = (std::min)((std::max)(xmin, 0.0f), 1.0f);
ymin = (std::min)((std::max)(ymin, 0.0f), 1.0f);
xmax = (std::min)((std::max)(xmax, 0.0f), 1.0f);
ymax = (std::min)((std::max)(ymax, 0.0f), 1.0f);
}
const uint64_t idx = h * layer_width * number_of_priors * 4 + w * number_of_priors * 4 + s * 4;
dst_data[idx + 0] = xmin;
dst_data[idx + 1] = ymin;
dst_data[idx + 2] = xmax;
dst_data[idx + 3] = ymax;
// At this point we have either:
// 1. A single variance value (to be repeated 4 times for each prior)
// 2. 4 variance values
if (var_size == 1) {
for (size_t j = 0; j < 4; j++)
dst_data[idx + j + out_shape[1]] = variances[0];
} else {
for (size_t j = 0; j < var_size; j++)
dst_data[idx + j + out_shape[1]] = variances[j];
}
}
});
}
bool MKLDNNPriorBoxClusteredNode::created() const {
return getType() == PriorBoxClustered;
}
REG_MKLDNN_PRIM_FOR(MKLDNNPriorBoxClusteredNode, PriorBoxClustered)
@@ -0,0 +1,46 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <vector>
#include <ie_common.h>
#include <mkldnn_node.h>
namespace MKLDNNPlugin {
class MKLDNNPriorBoxClusteredNode : public MKLDNNNode {
public:
MKLDNNPriorBoxClusteredNode(const std::shared_ptr<ngraph::Node>& op, const mkldnn::engine& eng, MKLDNNWeightsSharing::Ptr &cache);
void getSupportedDescriptors() override {};
void initSupportedPrimitiveDescriptors() override;
void createPrimitive() override;
void execute(mkldnn::stream strm) override;
bool created() const override;
bool needShapeInfer() const override;
std::vector<VectorDims> shapeInfer() const override;
bool needPrepareParams() const override;
void executeDynamicImpl(mkldnn::stream strm) override { execute(strm); }
static bool isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept;
private:
std::vector<float> widths;
std::vector<float> heights;
std::vector<float> variances;
bool clip;
float step;
float step_heights;
float step_widths;
float offset;
int number_of_priors;
};
} // namespace MKLDNNPlugin
@@ -0,0 +1,324 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "mkldnn_priorbox_node.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include <vector>
#include <ie_parallel.hpp>
#include <mkldnn_types.h>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset1.hpp>
using namespace MKLDNNPlugin;
using namespace InferenceEngine;
#define THROW_ERROR IE_THROW() << "PriorBox layer with name '" << getName() << "': "
namespace {
float clip_great(float x, float threshold) {
return x < threshold ? x : threshold;
}
float clip_less(float x, float threshold) {
return x > threshold ? x : threshold;
}
}
bool MKLDNNPriorBoxNode::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
try {
const auto priorBox = std::dynamic_pointer_cast<const ngraph::opset1::PriorBox>(op);
if (!priorBox) {
errorMessage = "Only opset1 PriorBox operation is supported";
return false;
}
} catch (...) {
return false;
}
return true;
}
MKLDNNPriorBoxNode::MKLDNNPriorBoxNode(
const std::shared_ptr<ngraph::Node>& op,
const mkldnn::engine& eng,
MKLDNNWeightsSharing::Ptr &cache) : MKLDNNNode(op, eng, cache) {
std::string errorMessage;
if (!isSupportedOperation(op, errorMessage)) {
IE_THROW(NotImplemented) << errorMessage;
}
const auto priorBox = std::dynamic_pointer_cast<const ngraph::opset1::PriorBox>(op);
const ngraph::opset1::PriorBox::Attributes& attrs = priorBox->get_attrs();
offset = attrs.offset;
step = attrs.step;
min_size = attrs.min_size;
max_size = attrs.max_size;
flip = attrs.flip;
clip = attrs.clip;
scale_all_sizes = attrs.scale_all_sizes;
fixed_size = attrs.fixed_size;
fixed_ratio = attrs.fixed_ratio;
density = attrs.density;
bool exist;
aspect_ratio.push_back(1.0f);
for (float aspect_ratio_item : attrs.aspect_ratio) {
exist = false;
if (std::fabs(aspect_ratio_item) < std::numeric_limits<float>::epsilon()) {
THROW_ERROR << "Aspect_ratio param can't be equal to zero";
}
for (float _aspect_ratio : aspect_ratio) {
if (fabs(aspect_ratio_item - _aspect_ratio) < 1e-6) {
exist = true;
break;
}
}
if (exist) {
continue;
}
aspect_ratio.push_back(aspect_ratio_item);
if (flip) {
aspect_ratio.push_back(1.0f / aspect_ratio_item);
}
}
number_of_priors = ngraph::opset1::PriorBox::number_of_priors(attrs);
if (attrs.variance.size() == 1 || attrs.variance.size() == 4) {
for (float i : attrs.variance) {
if (i < 0) {
THROW_ERROR << "Variance must be > 0.";
}
variance.push_back(i);
}
} else if (attrs.variance.empty()) {
variance.push_back(0.1f);
} else {
THROW_ERROR << "Wrong number of variance values. Not less than 1 and more than 4 variance values.";
}
}
bool MKLDNNPriorBoxNode::needShapeInfer() const {
auto& memory = getChildEdgeAt(0)->getMemoryPtr();
if (memory->GetShape().isDynamic()) {
return true;
}
const auto& outputShape = memory->GetShape().getStaticDims();
const int* in_data = reinterpret_cast<int*>(memory->GetPtr());
const int h = in_data[0];
const int w = in_data[1];
const auto output = static_cast<size_t>(4 * h * w * number_of_priors);
return outputShape[1] != output;
}
std::vector<VectorDims> MKLDNNPriorBoxNode::shapeInfer() const {
const int* in_data = reinterpret_cast<int*>(getParentEdgeAt(0)->getMemoryPtr()->GetPtr());
const int H = in_data[0];
const int W = in_data[1];
const auto output = static_cast<size_t>(4 * H * W * number_of_priors);
return {{2, output}};
}
bool MKLDNNPriorBoxNode::needPrepareParams() const {
return false;
}
void MKLDNNPriorBoxNode::initSupportedPrimitiveDescriptors() {
if (!supportedPrimitiveDescriptors.empty())
return;
addSupportedPrimDesc(
{{LayoutType::ncsp, Precision::I32}, {LayoutType::ncsp, Precision::I32}},
{{LayoutType::ncsp, Precision::FP32}},
impl_desc_type::ref_any);
}
void MKLDNNPriorBoxNode::createPrimitive() {
if (inputShapesDefined()) {
if (needPrepareParams())
prepareParams();
updateLastInputDims();
}
}
void MKLDNNPriorBoxNode::execute(mkldnn::stream strm) {
const int* in_data = reinterpret_cast<int*>(getParentEdgeAt(0)->getMemoryPtr()->GetPtr());
const int H = in_data[0];
const int W = in_data[1];
const int* in_image = reinterpret_cast<int*>(getParentEdgeAt(1)->getMemoryPtr()->GetPtr());
const int IH = in_image[0];
const int IW = in_image[1];
const int OH = 4 * H * W * number_of_priors;
const int OW = 1;
float* dst_data = reinterpret_cast<float*>(getChildEdgeAt(0)->getMemoryPtr()->GetPtr());
float step_ = step;
auto min_size_ = min_size;
if (!scale_all_sizes) {
// mxnet-like PriorBox
if (step_ == -1)
step_ = 1.f * IH / H;
else
step_ *= IH;
for (auto& size : min_size_)
size *= IH;
}
int64_t idx = 0;
float center_x, center_y, box_width, box_height, step_x, step_y;
float IWI = 1.0f / static_cast<float>(IW);
float IHI = 1.0f / static_cast<float>(IH);
if (step_ == 0) {
step_x = static_cast<float>(IW) / W;
step_y = static_cast<float>(IH) / H;
} else {
step_x = step_;
step_y = step_;
}
auto calculate_data =
[&dst_data, &IWI, &IHI, &idx](float center_x, float center_y, float box_width, float box_height, bool clip) {
if (clip) {
// order: xmin, ymin, xmax, ymax
dst_data[idx++] = clip_less((center_x - box_width) * IWI, 0);
dst_data[idx++] = clip_less((center_y - box_height) * IHI, 0);
dst_data[idx++] = clip_great((center_x + box_width) * IWI, 1);
dst_data[idx++] = clip_great((center_y + box_height) * IHI, 1);
} else {
dst_data[idx++] = (center_x - box_width) * IWI;
dst_data[idx++] = (center_y - box_height) * IHI;
dst_data[idx++] = (center_x + box_width) * IWI;
dst_data[idx++] = (center_y + box_height) * IHI;
}
};
for (int64_t h = 0; h < H; ++h) {
for (int64_t w = 0; w < W; ++w) {
if (step_ == 0) {
center_x = (w + 0.5f) * step_x;
center_y = (h + 0.5f) * step_y;
} else {
center_x = (offset + w) * step_;
center_y = (offset + h) * step_;
}
for (size_t s = 0; s < fixed_size.size(); ++s) {
auto fixed_size_ = static_cast<size_t>(fixed_size[s]);
box_width = box_height = fixed_size_ * 0.5f;
if (!fixed_ratio.empty()) {
for (float ar : fixed_ratio) {
auto density_ = static_cast<int64_t>(density[s]);
auto shift = static_cast<int64_t>(fixed_size[s] / density_);
ar = std::sqrt(ar);
float box_width_ratio = fixed_size[s] * 0.5f * ar;
float box_height_ratio = fixed_size[s] * 0.5f / ar;
for (int64_t r = 0; r < density_; ++r) {
for (int64_t c = 0; c < density_; ++c) {
float center_x_temp = center_x - fixed_size_ / 2 + shift / 2.f + c * shift;
float center_y_temp = center_y - fixed_size_ / 2 + shift / 2.f + r * shift;
calculate_data(center_x_temp, center_y_temp, box_width_ratio, box_height_ratio, true);
}
}
}
} else {
if (!density.empty()) {
auto density_ = static_cast<int64_t>(density[s]);
auto shift = static_cast<int64_t>(fixed_size[s] / density_);
for (int64_t r = 0; r < density_; ++r) {
for (int64_t c = 0; c < density_; ++c) {
float center_x_temp = center_x - fixed_size_ / 2 + shift / 2.f + c * shift;
float center_y_temp = center_y - fixed_size_ / 2 + shift / 2.f + r * shift;
calculate_data(center_x_temp, center_y_temp, box_width, box_height, true);
}
}
}
// Rest of priors
for (float ar : aspect_ratio) {
if (fabs(ar - 1.) < 1e-6) {
continue;
}
auto density_ = static_cast<int64_t>(density[s]);
auto shift = static_cast<int64_t>(fixed_size[s] / density_);
ar = std::sqrt(ar);
float box_width_ratio = fixed_size[s] * 0.5f * ar;
float box_height_ratio = fixed_size[s] * 0.5f / ar;
for (int64_t r = 0; r < density_; ++r) {
for (int64_t c = 0; c < density_; ++c) {
float center_x_temp = center_x - fixed_size_ / 2 + shift / 2.f + c * shift;
float center_y_temp = center_y - fixed_size_ / 2 + shift / 2.f + r * shift;
calculate_data(center_x_temp, center_y_temp, box_width_ratio, box_height_ratio, true);
}
}
}
}
}
for (size_t ms_idx = 0; ms_idx < min_size_.size(); ms_idx++) {
box_width = min_size_[ms_idx] * 0.5f;
box_height = min_size_[ms_idx] * 0.5f;
calculate_data(center_x, center_y, box_width, box_height, false);
if (max_size.size() > ms_idx) {
box_width = box_height = std::sqrt(min_size_[ms_idx] * max_size[ms_idx]) * 0.5f;
calculate_data(center_x, center_y, box_width, box_height, false);
}
if (scale_all_sizes || (!scale_all_sizes && (ms_idx == min_size_.size() - 1))) {
size_t s_idx = scale_all_sizes ? ms_idx : 0;
for (float ar : aspect_ratio) {
if (std::fabs(ar - 1.0f) < 1e-6) {
continue;
}
ar = std::sqrt(ar);
box_width = min_size_[s_idx] * 0.5f * ar;
box_height = min_size_[s_idx] * 0.5f / ar;
calculate_data(center_x, center_y, box_width, box_height, false);
}
}
}
}
}
if (clip) {
parallel_for((H * W * number_of_priors * 4), [&](size_t i) {
dst_data[i] = (std::min)((std::max)(dst_data[i], 0.0f), 1.0f);
});
}
uint64_t channel_size = OH * OW;
if (variance.size() == 1) {
parallel_for(channel_size, [&](size_t i) {
dst_data[i + channel_size] = variance[0];
});
} else {
parallel_for(H * W * number_of_priors, [&](size_t i) {
for (size_t j = 0; j < 4; ++j) {
dst_data[i * 4 + j + channel_size] = variance[j];
}
});
}
}
bool MKLDNNPriorBoxNode::created() const {
return getType() == PriorBox;
}
REG_MKLDNN_PRIM_FOR(MKLDNNPriorBoxNode, PriorBox)
@@ -0,0 +1,52 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <vector>
#include <ie_common.h>
#include <mkldnn_node.h>
namespace MKLDNNPlugin {
class MKLDNNPriorBoxNode : public MKLDNNNode {
public:
MKLDNNPriorBoxNode(const std::shared_ptr<ngraph::Node>& op, const mkldnn::engine& eng, MKLDNNWeightsSharing::Ptr &cache);
void getSupportedDescriptors() override {};
void initSupportedPrimitiveDescriptors() override;
void createPrimitive() override;
void execute(mkldnn::stream strm) override;
bool created() const override;
bool needShapeInfer() const override;
std::vector<VectorDims> shapeInfer() const override;
bool needPrepareParams() const override;
void executeDynamicImpl(mkldnn::stream strm) override { execute(strm); }
static bool isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept;
private:
float offset;
float step;
std::vector<float> min_size;
std::vector<float> max_size;
bool flip;
bool clip;
bool scale_all_sizes;
std::vector<float> fixed_size;
std::vector<float> fixed_ratio;
std::vector<float> density;
std::vector<float> aspect_ratio;
std::vector<float> variance;
int number_of_priors;
};
} // namespace MKLDNNPlugin