Merge remote-tracking branch 'upstream/master' into debian-packages
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <ngraph/function.hpp>
|
||||
#include <ngraph/opsets/opset1.hpp>
|
||||
#include <ngraph/opsets/opset8.hpp>
|
||||
#include <ngraph/pass/manager.hpp>
|
||||
#include <transformations/op_conversions/convert_maxpool_upgrade.hpp>
|
||||
#include <transformations/init_node_info.hpp>
|
||||
|
||||
#include "common_test_utils/ngraph_test_utils.hpp"
|
||||
|
||||
using namespace testing;
|
||||
|
||||
TEST_F(TransformationTestsF, ConvertMaxPool1ToMaxPool8) {
|
||||
{
|
||||
auto data = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::Shape{1, 2, 3});
|
||||
ngraph::Strides strides{1};
|
||||
ngraph::Shape pads_begin{0}, pads_end{0}, kernel{1};
|
||||
auto maxpool_1 = std::make_shared<ngraph::opset1::MaxPool>(data, strides, pads_begin, pads_end,
|
||||
kernel);
|
||||
|
||||
function = std::make_shared<ngraph::Function>(ngraph::OutputVector{maxpool_1->output(0)},
|
||||
ngraph::ParameterVector{data});
|
||||
|
||||
manager.register_pass<ngraph::pass::ConvertMaxPool1ToMaxPool8>();
|
||||
}
|
||||
|
||||
{
|
||||
auto data = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::Shape{1, 2, 3});
|
||||
ngraph::Strides strides{1}, dilations{1};
|
||||
ngraph::Shape pads_begin{0}, pads_end{0}, kernel{1};
|
||||
auto maxpool_8 = std::make_shared<ngraph::opset8::MaxPool>(data, strides, dilations, pads_begin, pads_end,
|
||||
kernel);
|
||||
|
||||
function_ref = std::make_shared<ngraph::Function>(ngraph::OutputVector{maxpool_8->output(0)},
|
||||
ngraph::ParameterVector{data});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TransformationTestsF, negative_ConvertMaxPool1ToMaxPool8_dynamic_rank) {
|
||||
{
|
||||
auto data = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::PartialShape::dynamic());
|
||||
ngraph::Strides strides{1};
|
||||
ngraph::Shape pads_begin{0}, pads_end{0}, kernel{1};
|
||||
auto maxpool_1 = std::make_shared<ngraph::opset1::MaxPool>(data, strides, pads_begin, pads_end,
|
||||
kernel);
|
||||
|
||||
function = std::make_shared<ngraph::Function>(ngraph::OutputVector{maxpool_1->output(0)},
|
||||
ngraph::ParameterVector{data});
|
||||
|
||||
manager.register_pass<ngraph::pass::ConvertMaxPool1ToMaxPool8>();
|
||||
}
|
||||
|
||||
{
|
||||
auto data = std::make_shared<ngraph::opset1::Parameter>(ngraph::element::f32, ngraph::PartialShape::dynamic());
|
||||
ngraph::Strides strides{1};
|
||||
ngraph::Shape pads_begin{0}, pads_end{0}, kernel{1};
|
||||
auto maxpool_1 = std::make_shared<ngraph::opset1::MaxPool>(data, strides, pads_begin, pads_end,
|
||||
kernel);
|
||||
|
||||
function_ref = std::make_shared<ngraph::Function>(ngraph::OutputVector{maxpool_1->output(0)},
|
||||
ngraph::ParameterVector{data});
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,4 @@
|
||||
|
||||
ie_add_sample(NAME hello_reshape_ssd
|
||||
SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
|
||||
HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/reshape_ssd_extension.hpp"
|
||||
DEPENDENCIES format_reader ie_samples_utils)
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
# Hello Reshape SSD C++ Sample {#openvino_inference_engine_samples_hello_reshape_ssd_README}
|
||||
|
||||
This sample demonstrates how to execute an inference of object detection networks like SSD-VGG using Synchronous Inference Request API, [input reshape feature](../../../docs/IE_DG/ShapeInference.md) and implementation of [custom extension library for CPU device](../../../docs/IE_DG/Extensibility_DG/CPU_Kernel.md) (CustomReLU kernel).
|
||||
This sample demonstrates how to execute an inference of object detection networks like SSD-VGG using Synchronous Inference Request API, [input reshape feature](../../../docs/IE_DG/ShapeInference.md).
|
||||
|
||||
Hello Reshape SSD C++ sample application demonstrates how to use the following Inference Engine C++ API in applications:
|
||||
|
||||
| Feature | API | Description |
|
||||
|:--- |:--- |:---
|
||||
| Network Operations | `InferenceEngine::CNNNetwork::getBatchSize`, `InferenceEngine::CNNNetwork::getFunction` | Managing of network, operate with its batch size.
|
||||
|Input Reshape|`InferenceEngine::CNNNetwork::getInputShapes`, `InferenceEngine::CNNNetwork::reshape`| Resize network to match image sizes and given batch
|
||||
|nGraph Functions|`ngraph::Function::get_ops`, `ngraph::Node::get_friendly_name`, `ngraph::Node::get_type_info`| Go thru network nGraph
|
||||
|Custom Extension Kernels|`InferenceEngine::Core::AddExtension`| Load extension library
|
||||
|CustomReLU kernel| `InferenceEngine::ILayerExecImpl`| Implementation of custom extension library
|
||||
|Network Operations| `ov::runtime::Core::read_model`, `ov::runtime::Core::compile_model` | Managing of network.
|
||||
|Input Reshape|`ov::Function::reshape`| Resize network to match image sizes and given batch
|
||||
|nGraph Functions|`ov::Function::get_ops`, `ov::Node::get_type_info`| Go thru network nGraph
|
||||
|
||||
Basic Inference Engine API is covered by [Hello Classification C++ sample](../hello_classification/README.md).
|
||||
|
||||
@@ -80,13 +78,28 @@ of the detected objects along with the respective confidence values and the coor
|
||||
rectangles to the standard output stream.
|
||||
|
||||
```
|
||||
Resizing network to the image size = [960x1699] with batch = 1
|
||||
Resulting input shape = [1,3,960,1699]
|
||||
Resulting output shape = [1,1,200,7]
|
||||
[0,1] element, prob = 0.722292, bbox = (852.382,187.756)-(983.352,520.733), batch id = 0
|
||||
The resulting image was saved in the file: hello_reshape_ssd_output.jpg
|
||||
|
||||
This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool
|
||||
[ INFO ] Loading model files: C:\temp\models\public\ssd_mobilenet_v1_fpn_coco\FP16\ssd_mobilenet_v1_fpn_coco.xml
|
||||
[ INFO ] model name: ssd_mobilenet_v1_fpn_coco
|
||||
[ INFO ] inputs
|
||||
[ INFO ] input name: image_tensor
|
||||
[ INFO ] input type: f32
|
||||
[ INFO ] input shape: {1, 3, 640, 640}
|
||||
[ INFO ] outputs
|
||||
[ INFO ] output name: DetectionOutput
|
||||
[ INFO ] output type: f32
|
||||
[ INFO ] output shape: {1, 1, 100, 7}
|
||||
Reshape network to the image size = [512x512] with batch = 1
|
||||
[ INFO ] model name: ssd_mobilenet_v1_fpn_coco
|
||||
[ INFO ] inputs
|
||||
[ INFO ] input name: image_tensor
|
||||
[ INFO ] input type: f32
|
||||
[ INFO ] input shape: {1, 3, 512, 512}
|
||||
[ INFO ] outputs
|
||||
[ INFO ] output name: DetectionOutput
|
||||
[ INFO ] output type: f32
|
||||
[ INFO ] output shape: {1, 1, 100, 7}
|
||||
[0,18] element, prob = 0.781129 (109,52)-(342,441) batch id = 0
|
||||
The resulting image was saved in the file: hello_reshape_ssd_batch_0.bmp
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
@@ -2,263 +2,206 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <format_reader_ptr.h>
|
||||
|
||||
#include <inference_engine.hpp>
|
||||
#include <memory>
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include <samples/common.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "reshape_ssd_extension.hpp"
|
||||
// clang-format off
|
||||
#include "ngraph/ngraph.hpp"
|
||||
#include "openvino/openvino.hpp"
|
||||
|
||||
using namespace InferenceEngine;
|
||||
#include "samples/args_helper.hpp"
|
||||
#include "samples/common.hpp"
|
||||
#include "samples/slog.hpp"
|
||||
#include "format_reader_ptr.h"
|
||||
// clang-format on
|
||||
|
||||
// thickness of a line (in pixels) to be used for bounding boxes
|
||||
constexpr int BBOX_THICKNESS = 2;
|
||||
|
||||
using namespace ov::preprocess;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
// ------------------------------ Parsing and validation of input arguments
|
||||
// ---------------------------------
|
||||
if (argc != 5) {
|
||||
std::cout << "Usage : " << argv[0] << " <path_to_model> <path_to_image> <device> <batch>" << std::endl;
|
||||
// -------- Get OpenVINO runtime version -----------------------------
|
||||
slog::info << ov::get_openvino_version() << slog::endl;
|
||||
|
||||
// --------------------------- Parsing and validation of input arguments
|
||||
if (argc != 4) {
|
||||
std::cout << "Usage : " << argv[0] << " <path_to_model> <path_to_image> <device>" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const std::string input_model{argv[1]};
|
||||
const std::string input_image_path{argv[2]};
|
||||
const std::string model_path{argv[1]};
|
||||
const std::string image_path{argv[2]};
|
||||
const std::string device_name{argv[3]};
|
||||
const size_t batch_size{std::stoul(argv[4])};
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// --------------------------- Step 1. Initialize inference engine core
|
||||
// -------------------------------------
|
||||
Core ie;
|
||||
// Step 1. Initialize inference engine core
|
||||
ov::runtime::Core core;
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
IExtensionPtr inPlaceExtension;
|
||||
if (device_name.find("CPU") != std::string::npos) {
|
||||
inPlaceExtension = std::make_shared<InPlaceExtension>();
|
||||
// register sample's custom kernel (CustomReLU)
|
||||
ie.AddExtension(inPlaceExtension);
|
||||
// Step 2. Read a model
|
||||
slog::info << "Loading model files: " << model_path << slog::endl;
|
||||
std::shared_ptr<ov::Model> model = core.read_model(model_path);
|
||||
printInputAndOutputsInfo(*model);
|
||||
|
||||
// Step 3. Validate model inputs and outputs
|
||||
OPENVINO_ASSERT(model->get_parameters().size() == 1, "Sample supports models with 1 input only");
|
||||
OPENVINO_ASSERT(model->get_results().size() == 1, "Sample supports models with 1 output only");
|
||||
|
||||
// SSD has an additional post-processing DetectionOutput layer that simplifies output filtering,
|
||||
// try to find it.
|
||||
ov::NodeVector ops = model->get_ops();
|
||||
auto it = std::find_if(ops.begin(), ops.end(), [](std::shared_ptr<ov::Node> node) {
|
||||
return node->get_type_info() == ngraph::op::DetectionOutput::get_type_info_static();
|
||||
});
|
||||
if (it == ops.end()) {
|
||||
throw std::logic_error("model does not contain DetectionOutput layer");
|
||||
}
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and
|
||||
// .bin files) or ONNX (.onnx file) format
|
||||
CNNNetwork network = ie.ReadNetwork(input_model);
|
||||
// Step 4. Read input image
|
||||
|
||||
OutputsDataMap outputs_info(network.getOutputsInfo());
|
||||
InputsDataMap inputs_info(network.getInputsInfo());
|
||||
if (inputs_info.size() != 1 || outputs_info.size() != 1)
|
||||
throw std::logic_error("Sample supports clean SSD network with one input and one output");
|
||||
|
||||
// --------------------------- Resize network to match image sizes and given
|
||||
// batch----------------------
|
||||
auto input_shapes = network.getInputShapes();
|
||||
std::string input_name;
|
||||
SizeVector input_shape;
|
||||
std::tie(input_name, input_shape) = *input_shapes.begin();
|
||||
FormatReader::ReaderPtr reader(input_image_path.c_str());
|
||||
// Read input image without resize
|
||||
FormatReader::ReaderPtr reader(image_path.c_str());
|
||||
if (reader.get() == nullptr) {
|
||||
std::cout << "Image " + input_image_path + " cannot be read!" << std::endl;
|
||||
std::cout << "Image " + image_path + " cannot be read!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
size_t image_width, image_height;
|
||||
image_width = reader->width();
|
||||
image_height = reader->height();
|
||||
input_shape[0] = batch_size;
|
||||
input_shape[2] = image_height;
|
||||
input_shape[3] = image_width;
|
||||
input_shapes[input_name] = input_shape;
|
||||
std::cout << "Resizing network to the image size = [" << image_height << "x" << image_width << "] "
|
||||
<< "with batch = " << batch_size << std::endl;
|
||||
network.reshape(input_shapes);
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------- Step 3. Configure input & output
|
||||
// ---------------------------------------------
|
||||
// --------------------------- Prepare input blobs
|
||||
// -----------------------------------------------------
|
||||
InputInfo::Ptr input_info;
|
||||
std::tie(input_name, input_info) = *inputs_info.begin();
|
||||
// Set input layout and precision
|
||||
input_info->setLayout(Layout::NCHW);
|
||||
input_info->setPrecision(Precision::U8);
|
||||
// --------------------------- Prepare output blobs
|
||||
// ----------------------------------------------------
|
||||
DataPtr output_info;
|
||||
std::string output_name;
|
||||
std::tie(output_name, output_info) = *outputs_info.begin();
|
||||
// SSD has an additional post-processing DetectionOutput layer
|
||||
// that simplifies output filtering, try to find it.
|
||||
if (auto ngraphFunction = network.getFunction()) {
|
||||
for (const auto& op : ngraphFunction->get_ops()) {
|
||||
if (op->get_type_info() == ngraph::op::DetectionOutput::get_type_info_static()) {
|
||||
if (output_info->getName() != op->get_friendly_name()) {
|
||||
throw std::logic_error("Detection output op does not produce a network output");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::shared_ptr<unsigned char> image_data = reader->getData();
|
||||
size_t image_channels = 3;
|
||||
size_t image_width = reader->width();
|
||||
size_t image_height = reader->height();
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Step 5. Reshape model to image size and batch size
|
||||
// assume model layout NCHW
|
||||
const ov::Layout model_layout{"NCHW"};
|
||||
|
||||
ov::Shape tensor_shape = model->input().get_shape();
|
||||
|
||||
size_t batch_size = 1;
|
||||
|
||||
tensor_shape[ov::layout::batch_idx(model_layout)] = batch_size;
|
||||
tensor_shape[ov::layout::channels_idx(model_layout)] = image_channels;
|
||||
tensor_shape[ov::layout::height_idx(model_layout)] = image_height;
|
||||
tensor_shape[ov::layout::width_idx(model_layout)] = image_width;
|
||||
|
||||
std::cout << "Reshape network to the image size = [" << image_height << "x" << image_width << "] " << std::endl;
|
||||
model->reshape({{model->input().get_any_name(), tensor_shape}});
|
||||
printInputAndOutputsInfo(*model);
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Step 6. Configure model preprocessing
|
||||
const ov::Layout tensor_layout{"NHWC"};
|
||||
|
||||
// clang-format off
|
||||
ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(model);
|
||||
|
||||
// 1) input() with no args assumes a model has a single input
|
||||
ov::preprocess::InputInfo& input_info = ppp.input();
|
||||
// 2) Set input tensor information:
|
||||
// - precision of tensor is supposed to be 'u8'
|
||||
// - layout of data is 'NHWC'
|
||||
input_info.tensor().
|
||||
set_element_type(ov::element::u8).
|
||||
set_layout(tensor_layout);
|
||||
// 3) Adding explicit preprocessing steps:
|
||||
// - convert u8 to f32
|
||||
// - convert layout to 'NCHW' (from 'NHWC' specified above at tensor layout)
|
||||
ppp.input().preprocess().
|
||||
convert_element_type(ov::element::f32).
|
||||
convert_layout("NCHW");
|
||||
// 4) Here we suppose model has 'NCHW' layout for input
|
||||
input_info.model().set_layout("NCHW");
|
||||
// 5) output () with no args assumes a model has a single output
|
||||
ov::preprocess::OutputInfo& output_info = ppp.output();
|
||||
// 6) declare output element type as FP32
|
||||
output_info.tensor().set_element_type(ov::element::f32);
|
||||
|
||||
// 7) Apply preprocessing modifing the original 'model'
|
||||
model = ppp.build();
|
||||
// clang-format on
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Step 7. Loading a model to the device
|
||||
ov::runtime::ExecutableNetwork compiled_model = core.compile_model(model, device_name);
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Step 8. Create an infer request
|
||||
ov::runtime::InferRequest infer_request = compiled_model.create_infer_request();
|
||||
|
||||
// Step 9. Fill model with input data
|
||||
ov::runtime::Tensor input_tensor = infer_request.get_input_tensor();
|
||||
|
||||
// copy NHWC data from image to tensor with batch
|
||||
unsigned char* image_data_ptr = image_data.get();
|
||||
unsigned char* tensor_data_ptr = input_tensor.data<unsigned char>();
|
||||
size_t image_size = image_width * image_height * image_channels;
|
||||
for (size_t i = 0; i < image_size; i++) {
|
||||
tensor_data_ptr[i] = image_data_ptr[i];
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
const SizeVector output_shape = output_info->getTensorDesc().getDims();
|
||||
const size_t max_proposal_count = output_shape[2];
|
||||
const size_t object_size = output_shape[3];
|
||||
if (object_size != 7) {
|
||||
throw std::logic_error("Output item should have 7 as a last dimension");
|
||||
}
|
||||
if (output_shape.size() != 4) {
|
||||
throw std::logic_error("Incorrect output dimensions for SSD model");
|
||||
}
|
||||
if (output_info == nullptr) {
|
||||
IE_THROW() << "[SAMPLES] internal error - output information is empty";
|
||||
}
|
||||
// Step 10. Do inference synchronously
|
||||
infer_request.infer();
|
||||
|
||||
output_info->setPrecision(Precision::FP32);
|
||||
// Step 11. Get output data from the model
|
||||
ov::runtime::Tensor output_tensor = infer_request.get_output_tensor();
|
||||
|
||||
auto dumpVec = [](const SizeVector& vec) -> std::string {
|
||||
if (vec.empty())
|
||||
return "[]";
|
||||
std::stringstream oss;
|
||||
oss << "[" << vec[0];
|
||||
for (size_t i = 1; i < vec.size(); i++)
|
||||
oss << "," << vec[i];
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
};
|
||||
std::cout << "Resulting input shape = " << dumpVec(input_shape) << std::endl;
|
||||
std::cout << "Resulting output shape = " << dumpVec(output_shape) << std::endl;
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
ov::Shape output_shape = model->output().get_shape();
|
||||
const size_t ssd_object_count = output_shape[2];
|
||||
const size_t ssd_object_size = output_shape[3];
|
||||
|
||||
// --------------------------- Step 4. Loading a model to the device
|
||||
// ------------------------------------------
|
||||
ExecutableNetwork executable_network = ie.LoadNetwork(network, device_name);
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
const float* detections = output_tensor.data<const float>();
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// --------------------------- Step 5. Create an infer request
|
||||
// -------------------------------------------------
|
||||
InferRequest infer_request = executable_network.CreateInferRequest();
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::vector<int> boxes;
|
||||
std::vector<int> classes;
|
||||
|
||||
// --------------------------- Step 6. Prepare input
|
||||
// --------------------------------------------------------
|
||||
/** Collect images data ptrs **/
|
||||
std::shared_ptr<unsigned char> image_data, original_image_data;
|
||||
/** Store image data **/
|
||||
std::shared_ptr<unsigned char> original_data(reader->getData());
|
||||
std::shared_ptr<unsigned char> data_reader(
|
||||
reader->getData(input_info->getTensorDesc().getDims()[3], input_info->getTensorDesc().getDims()[2]));
|
||||
if (data_reader.get() != nullptr) {
|
||||
original_image_data = original_data;
|
||||
image_data = data_reader;
|
||||
} else {
|
||||
throw std::logic_error("Valid input images were not found!");
|
||||
}
|
||||
|
||||
/** Creating input blob **/
|
||||
Blob::Ptr image_input = infer_request.GetBlob(input_name);
|
||||
|
||||
/** Filling input tensor with images. First b channel, then g and r channels **/
|
||||
MemoryBlob::Ptr mimage = as<MemoryBlob>(image_input);
|
||||
if (!mimage) {
|
||||
std::cout << "We expect image blob to be inherited from MemoryBlob, but by fact we were not able "
|
||||
"to cast imageInput to MemoryBlob"
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
// locked memory holder should be alive all time while access to its buffer happens
|
||||
auto minputHolder = mimage->wmap();
|
||||
|
||||
size_t num_channels = mimage->getTensorDesc().getDims()[1];
|
||||
size_t image_size = mimage->getTensorDesc().getDims()[3] * mimage->getTensorDesc().getDims()[2];
|
||||
|
||||
unsigned char* data = minputHolder.as<unsigned char*>();
|
||||
|
||||
/** Iterate over all input images **/
|
||||
for (size_t image_id = 0; image_id < batch_size; ++image_id) {
|
||||
/** Iterate over all pixel in image (b,g,r) **/
|
||||
for (size_t pid = 0; pid < image_size; pid++) {
|
||||
/** Iterate over all channels **/
|
||||
for (size_t ch = 0; ch < num_channels; ++ch) {
|
||||
/** [images stride + channels stride + pixel id ] all in bytes **/
|
||||
data[image_id * image_size * num_channels + ch * image_size + pid] =
|
||||
image_data.get()[pid * num_channels + ch];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------- Step 7. Do inference
|
||||
// --------------------------------------------------------
|
||||
infer_request.Infer();
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------- Step 8. Process output
|
||||
// ------------------------------------------------------
|
||||
Blob::Ptr output = infer_request.GetBlob(output_name);
|
||||
MemoryBlob::CPtr moutput = as<MemoryBlob>(output);
|
||||
if (!moutput) {
|
||||
throw std::logic_error("We expect output to be inherited from MemoryBlob, "
|
||||
"but by fact we were not able to cast output to MemoryBlob");
|
||||
}
|
||||
// locked memory holder should be alive all time while access to its buffer
|
||||
// happens
|
||||
auto moutputHolder = moutput->rmap();
|
||||
const float* detection = moutputHolder.as<const float*>();
|
||||
|
||||
std::vector<std::vector<int>> boxes(batch_size);
|
||||
std::vector<std::vector<int>> classes(batch_size);
|
||||
|
||||
/* Each detection has image_id that denotes processed image */
|
||||
for (size_t cur_proposal = 0; cur_proposal < max_proposal_count; cur_proposal++) {
|
||||
auto image_id = static_cast<int>(detection[cur_proposal * object_size + 0]);
|
||||
// Step 12. Parse SSD output
|
||||
for (size_t object = 0; object < ssd_object_count; object++) {
|
||||
int image_id = static_cast<int>(detections[object * ssd_object_size + 0]);
|
||||
if (image_id < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
float confidence = detection[cur_proposal * object_size + 2];
|
||||
auto label = static_cast<int>(detection[cur_proposal * object_size + 1]);
|
||||
auto xmin = detection[cur_proposal * object_size + 3] * image_width;
|
||||
auto ymin = detection[cur_proposal * object_size + 4] * image_height;
|
||||
auto xmax = detection[cur_proposal * object_size + 5] * image_width;
|
||||
auto ymax = detection[cur_proposal * object_size + 6] * image_height;
|
||||
// detection, has the format: [image_id, label, conf, x_min, y_min, x_max, y_max]
|
||||
int label = static_cast<int>(detections[object * ssd_object_size + 1]);
|
||||
float confidence = detections[object * ssd_object_size + 2];
|
||||
int xmin = static_cast<int>(detections[object * ssd_object_size + 3] * image_width);
|
||||
int ymin = static_cast<int>(detections[object * ssd_object_size + 4] * image_height);
|
||||
int xmax = static_cast<int>(detections[object * ssd_object_size + 5] * image_width);
|
||||
int ymax = static_cast<int>(detections[object * ssd_object_size + 6] * image_height);
|
||||
|
||||
if (confidence > 0.5f) {
|
||||
/** Drawing only objects with >50% probability **/
|
||||
classes[image_id].push_back(label);
|
||||
boxes[image_id].push_back(static_cast<int>(xmin));
|
||||
boxes[image_id].push_back(static_cast<int>(ymin));
|
||||
boxes[image_id].push_back(static_cast<int>(xmax - xmin));
|
||||
boxes[image_id].push_back(static_cast<int>(ymax - ymin));
|
||||
// collect only objects with >50% probability
|
||||
classes.push_back(label);
|
||||
boxes.push_back(xmin);
|
||||
boxes.push_back(ymin);
|
||||
boxes.push_back(xmax - xmin);
|
||||
boxes.push_back(ymax - ymin);
|
||||
|
||||
std::cout << "[" << cur_proposal << "," << label << "] element, prob = " << confidence << ", bbox = ("
|
||||
<< xmin << "," << ymin << ")-(" << xmax << "," << ymax << ")"
|
||||
<< ", batch id = " << image_id << std::endl;
|
||||
std::cout << "[" << object << "," << label << "] element, prob = " << confidence << ", (" << xmin
|
||||
<< "," << ymin << ")-(" << xmax << "," << ymax << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t batch_id = 0; batch_id < batch_size; ++batch_id) {
|
||||
addRectangles(original_image_data.get(),
|
||||
image_height,
|
||||
image_width,
|
||||
boxes[batch_id],
|
||||
classes[batch_id],
|
||||
BBOX_THICKNESS);
|
||||
const std::string image_path = "hello_reshape_ssd_output.bmp";
|
||||
if (writeOutputBmp(image_path, original_image_data.get(), image_height, image_width)) {
|
||||
std::cout << "The resulting image was saved in the file: " + image_path << std::endl;
|
||||
} else {
|
||||
throw std::logic_error(std::string("Can't create a file: ") + image_path);
|
||||
}
|
||||
// draw bounding boxes on the image
|
||||
addRectangles(image_data.get(), image_height, image_width, boxes, classes, BBOX_THICKNESS);
|
||||
|
||||
const std::string image_name = "hello_reshape_ssd_output.bmp";
|
||||
if (writeOutputBmp(image_name, image_data.get(), image_height, image_width)) {
|
||||
std::cout << "The resulting image was saved in the file: " + image_name << std::endl;
|
||||
} else {
|
||||
throw std::logic_error(std::string("Can't create a file: ") + image_name);
|
||||
}
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << std::endl
|
||||
<< "This sample is an API example, for any performance measurements "
|
||||
"please use the dedicated benchmark_app tool"
|
||||
<< std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <inference_engine.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define CUSTOM_RELU_TYPE "CustomReLU"
|
||||
|
||||
/* thickness of a line (in pixels) to be used for bounding boxes */
|
||||
#define BBOX_THICKNESS 2
|
||||
|
||||
class CustomReLUImpl : public InferenceEngine::ILayerExecImpl {
|
||||
public:
|
||||
explicit CustomReLUImpl(const std::shared_ptr<ngraph::Node>& node) : _node(node) {}
|
||||
|
||||
InferenceEngine::StatusCode getSupportedConfigurations(std::vector<InferenceEngine::LayerConfig>& conf,
|
||||
InferenceEngine::ResponseDesc* /*resp*/) noexcept override {
|
||||
InferenceEngine::LayerConfig layerConfig;
|
||||
layerConfig.dynBatchSupport = true;
|
||||
|
||||
if (_node->outputs().size() != 1 && _node->inputs().size() != 1)
|
||||
return InferenceEngine::GENERAL_ERROR;
|
||||
|
||||
InferenceEngine::DataConfig cfg;
|
||||
cfg.constant = false;
|
||||
cfg.inPlace = 0;
|
||||
|
||||
InferenceEngine::SizeVector order;
|
||||
auto partialShape = _node->get_output_partial_shape(0);
|
||||
if (partialShape.is_dynamic())
|
||||
return InferenceEngine::GENERAL_ERROR;
|
||||
|
||||
auto shape = _node->get_output_shape(0);
|
||||
for (size_t i = 0; i < shape.size(); i++) {
|
||||
order.push_back(i);
|
||||
}
|
||||
cfg.desc = InferenceEngine::TensorDesc(InferenceEngine::Precision::FP32, shape, {shape, order});
|
||||
layerConfig.outConfs.push_back(cfg);
|
||||
layerConfig.inConfs.push_back(cfg);
|
||||
conf.push_back(layerConfig);
|
||||
return InferenceEngine::OK;
|
||||
}
|
||||
|
||||
InferenceEngine::StatusCode init(InferenceEngine::LayerConfig& /*config*/,
|
||||
InferenceEngine::ResponseDesc* /*resp*/) noexcept override {
|
||||
return InferenceEngine::StatusCode::OK;
|
||||
}
|
||||
|
||||
InferenceEngine::StatusCode execute(std::vector<InferenceEngine::Blob::Ptr>& inputs,
|
||||
std::vector<InferenceEngine::Blob::Ptr>& outputs,
|
||||
InferenceEngine::ResponseDesc* /*resp*/) noexcept override {
|
||||
static bool wasCalled = false;
|
||||
if (!wasCalled) {
|
||||
std::cout << "Running " + std::string(CUSTOM_RELU_TYPE) +
|
||||
" kernel for the first time (next messages won't be printed)"
|
||||
<< std::endl;
|
||||
wasCalled = true;
|
||||
}
|
||||
for (size_t i = 0; i < inputs.size(); i++) {
|
||||
InferenceEngine::MemoryBlob::CPtr minput = InferenceEngine::as<InferenceEngine::MemoryBlob>(inputs[i]);
|
||||
InferenceEngine::MemoryBlob::Ptr moutput = InferenceEngine::as<InferenceEngine::MemoryBlob>(outputs[i]);
|
||||
if (!moutput || !minput) {
|
||||
return InferenceEngine::StatusCode::PARAMETER_MISMATCH;
|
||||
}
|
||||
// locked memory holder should be alive all time while access to its buffer happens
|
||||
auto minputHolder = minput->rmap();
|
||||
auto moutputHolder = moutput->wmap();
|
||||
|
||||
auto inputData = minputHolder.as<const float*>();
|
||||
auto outputData = moutputHolder.as<float*>();
|
||||
for (size_t j = 0; j < minput->size(); j++) {
|
||||
outputData[j] = inputData[j] < 0 ? 0 : inputData[j];
|
||||
}
|
||||
}
|
||||
return InferenceEngine::StatusCode::OK;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ngraph::Node> _node;
|
||||
};
|
||||
|
||||
class CustomReluOp : public ngraph::op::Op {
|
||||
public:
|
||||
OPENVINO_OP("CustomReluOp", "experimental");
|
||||
|
||||
CustomReluOp() = default;
|
||||
explicit CustomReluOp(const ngraph::Output<ngraph::Node>& arg) : Op({arg}) {
|
||||
constructor_validate_and_infer_types();
|
||||
}
|
||||
|
||||
void validate_and_infer_types() override {
|
||||
auto input_shape = get_input_partial_shape(0).to_shape();
|
||||
|
||||
ngraph::Shape output_shape(input_shape);
|
||||
for (size_t i = 0; i < input_shape.size(); ++i) {
|
||||
output_shape[i] = input_shape[i];
|
||||
}
|
||||
|
||||
set_output_type(0, get_input_element_type(0), ngraph::PartialShape(output_shape));
|
||||
}
|
||||
|
||||
std::shared_ptr<ngraph::Node> clone_with_new_inputs(const ngraph::OutputVector& new_args) const override {
|
||||
if (new_args.size() != 1) {
|
||||
throw ngraph::ngraph_error("Incorrect number of new arguments");
|
||||
}
|
||||
|
||||
return std::make_shared<CustomReluOp>(new_args.at(0));
|
||||
}
|
||||
|
||||
bool visit_attributes(ngraph::AttributeVisitor&) override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class InPlaceExtension : public InferenceEngine::IExtension {
|
||||
public:
|
||||
InPlaceExtension() {
|
||||
impls[CUSTOM_RELU_TYPE] = [](const std::shared_ptr<ngraph::Node>& node) -> InferenceEngine::ILayerImpl::Ptr {
|
||||
return std::make_shared<CustomReLUImpl>(node);
|
||||
};
|
||||
}
|
||||
|
||||
void GetVersion(const InferenceEngine::Version*& versionInfo) const noexcept override {}
|
||||
|
||||
void Unload() noexcept override {}
|
||||
|
||||
std::vector<std::string> getImplTypes(const std::shared_ptr<ngraph::Node>& node) override {
|
||||
if (impls.find(node->description()) == impls.end())
|
||||
return {};
|
||||
return {"CPU"};
|
||||
}
|
||||
|
||||
InferenceEngine::ILayerImpl::Ptr getImplementation(const std::shared_ptr<ngraph::Node>& node,
|
||||
const std::string& implType) override {
|
||||
if (impls.find(node->description()) == impls.end() || implType != "CPU")
|
||||
return nullptr;
|
||||
return impls[node->description()](node);
|
||||
}
|
||||
|
||||
std::map<std::string, ngraph::OpSet> getOpSets() override {
|
||||
static std::map<std::string, ngraph::OpSet> opsets;
|
||||
if (opsets.empty()) {
|
||||
ngraph::OpSet opset;
|
||||
opset.insert<CustomReluOp>();
|
||||
opsets["experimental"] = opset;
|
||||
}
|
||||
return opsets;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::function<InferenceEngine::ILayerImpl::Ptr(const std::shared_ptr<ngraph::Node>)>> impls;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <transformations_visibility.hpp>
|
||||
#include <ngraph/pass/graph_rewrite.hpp>
|
||||
|
||||
namespace ngraph {
|
||||
namespace pass {
|
||||
|
||||
class TRANSFORMATIONS_API ConvertMaxPool1ToMaxPool8;
|
||||
|
||||
} // namespace pass
|
||||
} // namespace ngraph
|
||||
|
||||
/**
|
||||
* @ingroup ie_transformation_common_api
|
||||
* @brief ConvertMaxPool1ToMaxPool8 converts v1::MaxPool into v8::MaxPool.
|
||||
*/
|
||||
|
||||
class ngraph::pass::ConvertMaxPool1ToMaxPool8 : public ngraph::pass::MatcherPass {
|
||||
public:
|
||||
OPENVINO_RTTI("ConvertMaxPool1ToMaxPool8");
|
||||
ConvertMaxPool1ToMaxPool8();
|
||||
};
|
||||
@@ -85,6 +85,7 @@
|
||||
#include "transformations/op_conversions/gather_normalize_negative_indices.hpp"
|
||||
#include "transformations/op_conversions/convert_deformable_conv_v8_to_v1.hpp"
|
||||
#include "transformations/op_conversions/convert_maxpool_downgrade.hpp"
|
||||
#include "transformations/op_conversions/convert_maxpool_upgrade.hpp"
|
||||
#include "transformations/disable_decompression_convert_constant_folding.hpp"
|
||||
#include "transformations/op_conversions/convert_prior_box_v8_to_v0.hpp"
|
||||
|
||||
@@ -183,6 +184,7 @@ bool ngraph::pass::CommonOptimizations::run_on_model(const std::shared_ptr<ngrap
|
||||
manager.register_pass<ngraph::pass::ConvertSoftMax8ToSoftMax1>();
|
||||
manager.register_pass<ngraph::pass::ConvertSoftMax1ToSoftMax8, false>();
|
||||
manager.register_pass<ngraph::pass::ConvertMaxPool8ToMaxPool1>();
|
||||
manager.register_pass<ngraph::pass::ConvertMaxPool1ToMaxPool8, false>();
|
||||
manager.register_pass<ngraph::pass::ConvertPriorBox8To0>(); // not plugins implemented priorbox8
|
||||
manager.register_pass<ngraph::pass::ConvertDetectionOutput1ToDetectionOutput8, false>();
|
||||
manager.register_pass<ngraph::pass::ConvertDetectionOutput8ToDetectionOutput1>();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "transformations/op_conversions/convert_maxpool_upgrade.hpp"
|
||||
#include <ngraph/opsets/opset1.hpp>
|
||||
#include <ngraph/opsets/opset8.hpp>
|
||||
#include <ngraph/rt_info.hpp>
|
||||
#include <ngraph/pattern/op/wrap_type.hpp>
|
||||
#include <transformations/utils/utils.hpp>
|
||||
#include "itt.hpp"
|
||||
|
||||
ngraph::pass::ConvertMaxPool1ToMaxPool8::ConvertMaxPool1ToMaxPool8() {
|
||||
MATCHER_SCOPE(ConvertMaxPool1ToMaxPool8);
|
||||
// Replaces v1::MaxPool with v8::MaxPool with default dilations, axis and index_element_type attributes
|
||||
|
||||
auto input = pattern::any_input(pattern::has_static_rank());
|
||||
auto maxpool_v1_pattern = ngraph::pattern::wrap_type<ngraph::opset1::MaxPool>({input});
|
||||
|
||||
ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher& m) {
|
||||
auto maxpool_v1_node = std::dynamic_pointer_cast<ngraph::opset1::MaxPool>(m.get_match_root());
|
||||
|
||||
if (!maxpool_v1_node)
|
||||
return false;
|
||||
|
||||
auto spatial_dims = maxpool_v1_node->get_input_partial_shape(0).rank().get_length() - 2;
|
||||
if (spatial_dims <= 0)
|
||||
return false;
|
||||
ov::Strides dilations(spatial_dims, 1);
|
||||
|
||||
auto maxpool_v8_node = std::make_shared<ngraph::opset8::MaxPool>(maxpool_v1_node->input_value(0),
|
||||
maxpool_v1_node->get_strides(),
|
||||
dilations,
|
||||
maxpool_v1_node->get_pads_begin(),
|
||||
maxpool_v1_node->get_pads_end(),
|
||||
maxpool_v1_node->get_kernel(),
|
||||
maxpool_v1_node->get_rounding_type(),
|
||||
maxpool_v1_node->get_auto_pad(),
|
||||
ov::element::i64,
|
||||
0);
|
||||
|
||||
maxpool_v8_node->set_friendly_name(maxpool_v1_node->get_friendly_name());
|
||||
maxpool_v1_node->output(0).replace(maxpool_v8_node->output(0));
|
||||
ngraph::copy_runtime_info(maxpool_v1_node, maxpool_v8_node);
|
||||
maxpool_v1_node->clear_control_dependencies();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto m = std::make_shared<pattern::Matcher>(maxpool_v1_pattern, matcher_name);
|
||||
register_matcher(m, callback);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ These tests execute IE samples on pregenerated IR
|
||||
You can run tests not only from the <INSTALL_DIR>, but in this case you need to remember to adjust the environment variables like as WORKSPACE and SHARE
|
||||
|
||||
To install smoke tests:
|
||||
``` bash
|
||||
``` bash
|
||||
- cd <working directory>/tests/samples_tests/smoke_tests
|
||||
- mkdir build && cd build
|
||||
- cmake ../..
|
||||
|
||||
@@ -48,12 +48,10 @@ def parse_hello_reshape_ssd(stdout):
|
||||
log.error('Wrong output line: {}, while the test expects the following format: 4d shape'
|
||||
'(Example: Resulting output shape = [1,1,200,7])'.format(line))
|
||||
elif 'element, prob' in line:
|
||||
if re.match("^.*prob\s+=.*\d,\s+bbox\s+=\s+\(.*\d,.*\d\)-\(.*\d,.*\d\),"
|
||||
"\s+batch id\s+=\s+\d", line) is None:
|
||||
if re.match("^.*prob\\s+=.*\\d,\\s+\\(.*\\d,.*\\d\)-\\(.*\\d,.*\\d\\)", line) is None:
|
||||
is_ok = False
|
||||
log.error('Wrong output line: {}, while the test expects the following format: 4d shape'
|
||||
'(Example: [33,59] element, prob = 0.963015, bbox = (189.776,110.933)-(309.288,306.952), '
|
||||
'batch id = 0)'.format(line))
|
||||
log.error('Wrong output line: {}, while the test expects the following format: '
|
||||
'Example: [33,59] element, prob = 0.963015, (189,110)-(309,306)'.format(line))
|
||||
elif 'was saved' in line:
|
||||
path_result = os.path.join(os.getcwd(), line.split(' ')[-1].strip())
|
||||
if not os.path.isfile(path_result):
|
||||
|
||||
@@ -22,8 +22,8 @@ log.basicConfig(format="[ %(levelname)s ] %(message)s", level=log.INFO, stream=s
|
||||
|
||||
test_data_fp32 = get_tests(cmd_params={'i': [os.path.join('500x500', 'cat.bmp')],
|
||||
'm': [os.path.join('ssd512', 'FP32', 'ssd512.xml')],
|
||||
'd': ['CPU'],
|
||||
'batch': [1, 2, 4]}, use_device=['d'], use_batch=True
|
||||
'd': ['CPU']},
|
||||
use_device=['d'], use_batch=False
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user