NMS-9 op creation and ref implementation and CPU plugin (#11132)
* operation creation * refrence implementation * code style * soft_nms_supported_by_nms9 * IE core and cpu plugin update * apply review * add transformation test
This commit is contained in:
@@ -1028,6 +1028,177 @@ bool evaluate(const shared_ptr<op::v5::NonMaxSuppression>& op,
|
||||
std::vector<float> selected_scores(info.out_shape_size);
|
||||
int64_t valid_outputs = 0;
|
||||
|
||||
runtime::reference::non_max_suppression5(info.boxes_data.data(),
|
||||
info.boxes_shape,
|
||||
info.scores_data.data(),
|
||||
info.scores_shape,
|
||||
info.max_output_boxes_per_class,
|
||||
info.iou_threshold,
|
||||
info.score_threshold,
|
||||
info.soft_nms_sigma,
|
||||
selected_indices.data(),
|
||||
info.out_shape,
|
||||
selected_scores.data(),
|
||||
info.out_shape,
|
||||
&valid_outputs,
|
||||
info.sort_result_descending);
|
||||
|
||||
auto selected_scores_type = (outputs.size() < 3) ? element::f32 : outputs[1]->get_element_type();
|
||||
|
||||
runtime::reference::nms_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace nms_v9 {
|
||||
using V9BoxEncoding = op::v9::NonMaxSuppression::BoxEncodingType;
|
||||
|
||||
struct InfoForNMS9 {
|
||||
int64_t max_output_boxes_per_class;
|
||||
float iou_threshold;
|
||||
float score_threshold;
|
||||
float soft_nms_sigma;
|
||||
Shape out_shape;
|
||||
Shape boxes_shape;
|
||||
Shape scores_shape;
|
||||
std::vector<float> boxes_data;
|
||||
std::vector<float> scores_data;
|
||||
size_t out_shape_size;
|
||||
bool sort_result_descending;
|
||||
ngraph::element::Type output_type;
|
||||
};
|
||||
|
||||
constexpr size_t boxes_port = 0;
|
||||
constexpr size_t scores_port = 1;
|
||||
|
||||
PartialShape infer_selected_indices_shape(const std::vector<std::shared_ptr<HostTensor>>& inputs,
|
||||
int64_t max_output_boxes_per_class) {
|
||||
const auto boxes_ps = inputs[boxes_port]->get_partial_shape();
|
||||
const auto scores_ps = inputs[scores_port]->get_partial_shape();
|
||||
|
||||
// NonMaxSuppression produces triplets
|
||||
// that have the following format: [batch_index, class_index, box_index]
|
||||
PartialShape result = {Dimension::dynamic(), 3};
|
||||
|
||||
if (boxes_ps.rank().is_static() && scores_ps.rank().is_static()) {
|
||||
const auto num_boxes_boxes = boxes_ps[1];
|
||||
if (num_boxes_boxes.is_static() && scores_ps[0].is_static() && scores_ps[1].is_static()) {
|
||||
const auto num_boxes = num_boxes_boxes.get_length();
|
||||
const auto num_classes = scores_ps[1].get_length();
|
||||
|
||||
result[0] = std::min(num_boxes, max_output_boxes_per_class) * num_classes * scores_ps[0].get_length();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void normalize_corner(float* boxes, const Shape& boxes_shape) {
|
||||
size_t total_num_of_boxes = shape_size(boxes_shape) / 4;
|
||||
for (size_t i = 0; i < total_num_of_boxes; ++i) {
|
||||
float* current_box = boxes + 4 * i;
|
||||
|
||||
float y1 = current_box[0];
|
||||
float x1 = current_box[1];
|
||||
float y2 = current_box[2];
|
||||
float x2 = current_box[3];
|
||||
|
||||
float ymin = std::min(y1, y2);
|
||||
float ymax = std::max(y1, y2);
|
||||
float xmin = std::min(x1, x2);
|
||||
float xmax = std::max(x1, x2);
|
||||
|
||||
current_box[0] = ymin;
|
||||
current_box[1] = xmin;
|
||||
current_box[2] = ymax;
|
||||
current_box[3] = xmax;
|
||||
}
|
||||
}
|
||||
|
||||
void normalize_center(float* boxes, const Shape& boxes_shape) {
|
||||
size_t total_num_of_boxes = shape_size(boxes_shape) / 4;
|
||||
for (size_t i = 0; i < total_num_of_boxes; ++i) {
|
||||
float* current_box = boxes + 4 * i;
|
||||
|
||||
float x_center = current_box[0];
|
||||
float y_center = current_box[1];
|
||||
float width = current_box[2];
|
||||
float height = current_box[3];
|
||||
|
||||
float y1 = y_center - height / 2.0;
|
||||
float x1 = x_center - width / 2.0;
|
||||
float y2 = y_center + height / 2.0;
|
||||
float x2 = x_center + width / 2.0;
|
||||
|
||||
current_box[0] = y1;
|
||||
current_box[1] = x1;
|
||||
current_box[2] = y2;
|
||||
current_box[3] = x2;
|
||||
}
|
||||
}
|
||||
|
||||
void normalize_box_encoding(float* boxes, const Shape& boxes_shape, const V9BoxEncoding box_encoding) {
|
||||
if (box_encoding == V9BoxEncoding::CORNER) {
|
||||
normalize_corner(boxes, boxes_shape);
|
||||
} else {
|
||||
normalize_center(boxes, boxes_shape);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> prepare_boxes_data(const std::shared_ptr<HostTensor>& boxes,
|
||||
const Shape& boxes_shape,
|
||||
const V9BoxEncoding box_encoding) {
|
||||
auto result = get_floats(boxes, boxes_shape);
|
||||
normalize_box_encoding(result.data(), boxes_shape, box_encoding);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<float> prepare_scores_data(const std::shared_ptr<HostTensor>& scores, const Shape& scores_shape) {
|
||||
auto result = get_floats(scores, scores_shape);
|
||||
return result;
|
||||
}
|
||||
|
||||
InfoForNMS9 get_info_for_nms9_eval(const std::shared_ptr<op::v9::NonMaxSuppression>& nms9,
|
||||
const std::vector<std::shared_ptr<HostTensor>>& inputs) {
|
||||
InfoForNMS9 result;
|
||||
|
||||
result.max_output_boxes_per_class = inputs.size() > 2 ? get_integers(inputs[2], Shape({}))[0] : 0;
|
||||
result.iou_threshold = inputs.size() > 3 ? get_floats(inputs[3], Shape({}))[0] : 0.0f;
|
||||
result.score_threshold = inputs.size() > 4 ? get_floats(inputs[4], Shape({}))[0] : 0.0f;
|
||||
result.soft_nms_sigma = inputs.size() > 5 ? get_floats(inputs[5], Shape({}))[0] : 0.0f;
|
||||
|
||||
auto selected_indices_shape = infer_selected_indices_shape(inputs, result.max_output_boxes_per_class);
|
||||
result.out_shape = selected_indices_shape.to_shape();
|
||||
|
||||
result.boxes_shape = inputs[boxes_port]->get_shape();
|
||||
result.scores_shape = inputs[scores_port]->get_shape();
|
||||
|
||||
result.boxes_data = prepare_boxes_data(inputs[boxes_port], result.boxes_shape, nms9->get_box_encoding());
|
||||
result.scores_data = prepare_scores_data(inputs[scores_port], result.scores_shape);
|
||||
|
||||
result.out_shape_size = shape_size(result.out_shape);
|
||||
|
||||
result.sort_result_descending = nms9->get_sort_result_descending();
|
||||
|
||||
result.output_type = nms9->get_output_type();
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace nms_v9
|
||||
|
||||
template <element::Type_t ET>
|
||||
bool evaluate(const shared_ptr<op::v9::NonMaxSuppression>& op,
|
||||
const HostTensorVector& outputs,
|
||||
const HostTensorVector& inputs) {
|
||||
auto info = nms_v9::get_info_for_nms9_eval(op, inputs);
|
||||
|
||||
std::vector<int64_t> selected_indices(info.out_shape_size);
|
||||
std::vector<float> selected_scores(info.out_shape_size);
|
||||
int64_t valid_outputs = 0;
|
||||
|
||||
runtime::reference::non_max_suppression(info.boxes_data.data(),
|
||||
info.boxes_shape,
|
||||
info.scores_data.data(),
|
||||
@@ -1045,12 +1216,12 @@ bool evaluate(const shared_ptr<op::v5::NonMaxSuppression>& op,
|
||||
|
||||
auto selected_scores_type = (outputs.size() < 3) ? element::f32 : outputs[1]->get_element_type();
|
||||
|
||||
runtime::reference::nms5_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
runtime::reference::nms_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1216,12 +1387,12 @@ bool evaluate(const shared_ptr<op::v4::NonMaxSuppression>& op,
|
||||
|
||||
auto selected_scores_type = (inputs.size() < 4) ? element::f32 : inputs[3]->get_element_type();
|
||||
|
||||
runtime::reference::nms5_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
runtime::reference::nms_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1387,12 +1558,12 @@ bool evaluate(const shared_ptr<op::v3::NonMaxSuppression>& op,
|
||||
|
||||
auto selected_scores_type = (inputs.size() < 4) ? element::f32 : inputs[3]->get_element_type();
|
||||
|
||||
runtime::reference::nms5_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
runtime::reference::nms_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1558,12 +1729,12 @@ bool evaluate(const shared_ptr<op::v1::NonMaxSuppression>& op,
|
||||
|
||||
auto selected_scores_type = (inputs.size() < 4) ? element::f32 : inputs[3]->get_element_type();
|
||||
|
||||
runtime::reference::nms5_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
runtime::reference::nms_postprocessing(outputs,
|
||||
info.output_type,
|
||||
selected_indices,
|
||||
selected_scores,
|
||||
valid_outputs,
|
||||
selected_scores_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ NGRAPH_OP(PriorBox, ngraph::op::v8)
|
||||
NGRAPH_OP(PRelu, op::v0)
|
||||
|
||||
NGRAPH_OP(RDFT, op::v9)
|
||||
NGRAPH_OP(NonMaxSuppression, op::v9)
|
||||
NGRAPH_OP(IRDFT, op::v9)
|
||||
|
||||
NGRAPH_OP(ROIAlign, op::v9)
|
||||
|
||||
Reference in New Issue
Block a user