Several samples moved to OpenVINO 2.0 (#7970)

* ngraph functio sample

* Fixes

* OV2.0: NV12 hello classification with new preprocessing API

* Fix clang-format

* Rewrote several samples

* Some updates

* clang-format

* Fixed TODO

* Fixed comments and improved samples

* Preprocessing comments

* clang-format

* Fixed comment

* Fixed Windows

* Added back Blob support to ClassificationResult

Co-authored-by: Michael Nosov <mikhail.nosov@intel.com>
This commit is contained in:
Ilya Lavrenov 2021-10-23 22:47:35 +03:00 committed by GitHub
parent c6eaa5d653
commit eb7f261d15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 550 additions and 524 deletions

View File

@ -3,7 +3,7 @@
//
/**
* @brief The entry point the Inference Engine sample application
* @brief The entry point the OpenVINO Runtime sample application
* @file classification_sample_async/main.cpp
* @example classification_sample_async/main.cpp
*/
@ -25,8 +25,9 @@
#include <vector>
#include "classification_sample_async.h"
#include "openvino/openvino.hpp"
using namespace InferenceEngine;
using namespace ov::preprocess;
/**
* @brief Checks input args
@ -62,170 +63,135 @@ bool ParseAndCheckCommandLine(int argc, char* argv[]) {
int main(int argc, char* argv[]) {
try {
// ------------------------------ Get Inference Engine version
// ------------------------------------------------------
slog::info << "InferenceEngine: " << GetInferenceEngineVersion() << slog::endl;
// -------- Get OpenVINO Runtime version --------
slog::info << "OpenVINO runtime: " << ov::get_openvino_version() << slog::endl;
// ------------------------------ Parsing and validation of input arguments
// ---------------------------------
// -------- Parsing and validation of input arguments --------
if (!ParseAndCheckCommandLine(argc, argv)) {
return 0;
return EXIT_SUCCESS;
}
// ------------------------------ Read input
// -----------------------------------------------------------
/** This vector stores paths to the processed images **/
std::vector<std::string> imageNames;
parseInputFilesArguments(imageNames);
if (imageNames.empty())
throw std::logic_error("No suitable images were found");
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
slog::info << "Loading Inference Engine" << slog::endl;
Core ie;
// ------------------------------ Get Available Devices
// ------------------------------------------------------
slog::info << "Device info: " << slog::endl;
std::cout << ie.GetVersions(FLAGS_d) << std::endl;
// -------- Read input --------
// This vector stores paths to the processed images
std::vector<std::string> image_names;
parseInputFilesArguments(image_names);
if (image_names.empty())
throw std::logic_error("No suitable images were found");
// -------- Step 1. Initialize OpenVINO Runtime Core --------
ov::runtime::Core core;
if (!FLAGS_l.empty()) {
// Custom CPU extension is loaded as a shared library and passed as a
// pointer to base extension
IExtensionPtr extension_ptr = std::make_shared<Extension>(FLAGS_l);
ie.AddExtension(extension_ptr);
slog::info << "CPU Extension loaded: " << FLAGS_l << slog::endl;
auto extension_ptr = std::make_shared<InferenceEngine::Extension>(FLAGS_l);
core.add_extension(extension_ptr);
slog::info << "Extension loaded: " << FLAGS_l << slog::endl;
}
if (!FLAGS_c.empty() && (FLAGS_d == "GPU" || FLAGS_d == "MYRIAD" || FLAGS_d == "HDDL")) {
// Config for device plugin custom extension is loaded from an .xml
// description
ie.SetConfig({{PluginConfigParams::KEY_CONFIG_FILE, FLAGS_c}}, FLAGS_d);
core.set_config({{InferenceEngine::PluginConfigParams::KEY_CONFIG_FILE, FLAGS_c}}, FLAGS_d);
slog::info << "Config for " << FLAGS_d << " device plugin custom extension loaded: " << FLAGS_c
<< slog::endl;
}
// -----------------------------------------------------------------------------------------------------
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and
// .bin files) or ONNX (.onnx file) format
slog::info << "Loading network files:" << slog::endl << FLAGS_m << slog::endl;
// -------- Step 2. Read a model --------
slog::info << "Loading model files:" << slog::endl << FLAGS_m << slog::endl;
std::shared_ptr<ov::Function> model = core.read_model(FLAGS_m);
/** Read network model **/
CNNNetwork network = ie.ReadNetwork(FLAGS_m);
// -----------------------------------------------------------------------------------------------------
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");
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
if (network.getOutputsInfo().size() != 1)
throw std::logic_error("Sample supports topologies with 1 output only");
// -------- Step 3. Apply preprocessing --------
const ov::Layout tensor_layout{"NHWC"};
// --------------------------- Prepare input blobs
// -----------------------------------------------------
slog::info << "Preparing input blobs" << slog::endl;
// clang-format off
model = PrePostProcessor().
// 1) InputInfo() with no args assumes a model has a single input
input(InputInfo().
// 2) Set input tensor information:
// - precision of tensor is supposed to be 'u8'
// - layout of data is 'NHWC'
tensor(InputTensorInfo().
set_element_type(ov::element::u8).
set_layout(tensor_layout)).
// 3) Here we suppose model has 'NCHW' layout for input
network(InputNetworkInfo().
set_layout("NCHW"))).
output(OutputInfo().
// 4) Set output tensor information:
// - precision of tensor is supposed to be 'f32'
tensor(OutputTensorInfo().
set_element_type(ov::element::f32))).
// 5) Once the build() method is called, the preprocessing steps
// for layout and precision conversions are inserted automatically
build(model);
// clang-format on
/** Taking information about all topology inputs **/
InputsDataMap inputInfo(network.getInputsInfo());
if (inputInfo.size() != 1)
throw std::logic_error("Sample supports topologies with 1 input only");
// -------- Step 4. read input images --------
slog::info << "Read input images" << slog::endl;
auto inputInfoItem = *inputInfo.begin();
ov::Shape input_shape = model->input().get_shape();
const size_t width = input_shape[ov::layout::width(tensor_layout)];
const size_t height = input_shape[ov::layout::height(tensor_layout)];
/** Specifying the precision and layout of input data provided by the user.
* This should be called before load of the network to the device **/
inputInfoItem.second->setPrecision(Precision::U8);
inputInfoItem.second->setLayout(Layout::NCHW);
std::vector<std::shared_ptr<unsigned char>> imagesData = {};
std::vector<std::string> validImageNames = {};
for (const auto& i : imageNames) {
std::vector<std::shared_ptr<unsigned char>> images_data;
std::vector<std::string> valid_image_names;
for (const auto& i : image_names) {
FormatReader::ReaderPtr reader(i.c_str());
if (reader.get() == nullptr) {
slog::warn << "Image " + i + " cannot be read!" << slog::endl;
continue;
}
/** Store image data **/
std::shared_ptr<unsigned char> data(reader->getData(inputInfoItem.second->getTensorDesc().getDims()[3],
inputInfoItem.second->getTensorDesc().getDims()[2]));
// Store image data
std::shared_ptr<unsigned char> data(reader->getData(width, height));
if (data != nullptr) {
imagesData.push_back(data);
validImageNames.push_back(i);
images_data.push_back(data);
valid_image_names.push_back(i);
}
}
if (imagesData.empty() || validImageNames.empty())
if (images_data.empty() || valid_image_names.empty())
throw std::logic_error("Valid input images were not found!");
/** Setting batch size using image count **/
network.setBatchSize(imagesData.size());
size_t batchSize = network.getBatchSize();
// -------- Step 5. Loading model to the device --------
// Setting batch size using image count
const size_t batchSize = images_data.size();
input_shape[ov::layout::batch(tensor_layout)] = batchSize;
model->reshape({{model->input().get_any_name(), input_shape}});
slog::info << "Batch size is " << std::to_string(batchSize) << slog::endl;
// -----------------------------------------------------------------------------------------------------
// -------- Step 6. Loading model to the device --------
slog::info << "Loading model to the device " << FLAGS_d << slog::endl;
ov::runtime::ExecutableNetwork executable_network = core.compile_model(model, FLAGS_d);
// --------------------------- Step 4. Loading model to the device
// ------------------------------------------
slog::info << "Loading model to the device" << slog::endl;
ExecutableNetwork executable_network = ie.LoadNetwork(network, FLAGS_d);
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create infer request
// -------------------------------------------------
// -------- Step 6. Create infer request --------
slog::info << "Create infer request" << slog::endl;
InferRequest inferRequest = executable_network.CreateInferRequest();
// -----------------------------------------------------------------------------------------------------
ov::runtime::InferRequest infer_request = executable_network.create_infer_request();
// --------------------------- Step 6. Prepare input
// --------------------------------------------------------
for (auto& item : inputInfo) {
Blob::Ptr inputBlob = inferRequest.GetBlob(item.first);
SizeVector dims = inputBlob->getTensorDesc().getDims();
/** Fill input tensor with images. First b channel, then g and r channels
* **/
size_t num_channels = dims[1];
size_t image_size = dims[3] * dims[2];
// -------- Step 7. Combine multiple input images as batch --------
ov::runtime::Tensor input_tensor = infer_request.get_input_tensor();
MemoryBlob::Ptr minput = as<MemoryBlob>(inputBlob);
if (!minput) {
slog::err << "We expect MemoryBlob from inferRequest, but by fact we "
"were not able to cast inputBlob to MemoryBlob"
<< slog::endl;
return 1;
}
// locked memory holder should be alive all time while access to its
// buffer happens
auto minputHolder = minput->wmap();
auto data = minputHolder.as<PrecisionTrait<Precision::U8>::value_type*>();
if (data == nullptr)
throw std::runtime_error("Input blob has not allocated buffer");
/** Iterate over all input images **/
for (size_t image_id = 0; image_id < imagesData.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] =
imagesData.at(image_id).get()[pid * num_channels + ch];
}
}
}
for (size_t image_id = 0; image_id < images_data.size(); ++image_id) {
const size_t image_size = shape_size(input_shape) / batchSize;
std::memcpy(input_tensor.data<std::uint8_t>() + image_id * image_size,
images_data[image_id].get(),
image_size);
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// ---------------------------------------------------------
size_t numIterations = 10;
size_t curIteration = 0;
// -------- Step 8. Do asynchronous inference --------
size_t num_iterations = 10;
size_t cur_iteration = 0;
std::condition_variable condVar;
inferRequest.SetCompletionCallback([&] {
curIteration++;
slog::info << "Completed " << curIteration << " async request execution" << slog::endl;
if (curIteration < numIterations) {
infer_request.set_callback([&](std::exception_ptr ex) {
if (ex)
throw ex;
cur_iteration++;
slog::info << "Completed " << cur_iteration << " async request execution" << slog::endl;
if (cur_iteration < num_iterations) {
/* here a user can read output containing inference results and put new
input to repeat async request again */
inferRequest.StartAsync();
infer_request.start_async();
} else {
/* continue sample execution after last Asynchronous inference request
* execution */
@ -234,30 +200,23 @@ int main(int argc, char* argv[]) {
});
/* Start async request for the first time */
slog::info << "Start inference (" << numIterations << " asynchronous executions)" << slog::endl;
inferRequest.StartAsync();
slog::info << "Start inference (" << num_iterations << " asynchronous executions)" << slog::endl;
infer_request.start_async();
/* Wait all repetitions of the async request */
/* Wait all iterations of the async request */
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
condVar.wait(lock, [&] {
return curIteration == numIterations;
return cur_iteration == num_iterations;
});
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 8. Process output
// -------------------------------------------------------
slog::info << "Processing output blobs" << slog::endl;
OutputsDataMap outputInfo(network.getOutputsInfo());
if (outputInfo.empty())
throw std::runtime_error("Can't get output blobs");
Blob::Ptr outputBlob = inferRequest.GetBlob(outputInfo.begin()->first);
// -------- Step 9. Process output --------
ov::runtime::Tensor output = infer_request.get_output_tensor();
/** Validating -nt value **/
const size_t resultsCnt = outputBlob->size() / batchSize;
const size_t resultsCnt = output.get_size() / batchSize;
if (FLAGS_nt > resultsCnt || FLAGS_nt < 1) {
slog::warn << "-nt " << FLAGS_nt << " is not available for this network (-nt should be less than "
slog::warn << "-nt " << FLAGS_nt << " is not available for this model (-nt should be less than "
<< resultsCnt + 1 << " and more than 0)\n Maximal value " << resultsCnt
<< " will be used." << slog::endl;
FLAGS_nt = resultsCnt;
@ -276,16 +235,16 @@ int main(int argc, char* argv[]) {
labels.push_back(strLine);
}
}
// Prints formatted classification results
ClassificationResult classificationResult(outputBlob, validImageNames, batchSize, FLAGS_nt, labels);
classificationResult.print();
// -----------------------------------------------------------------------------------------------------
ClassificationResult classificationResult(output, valid_image_names, batchSize, FLAGS_nt, labels);
classificationResult.show();
} catch (const std::exception& error) {
slog::err << error.what() << slog::endl;
return 1;
return EXIT_FAILURE;
} catch (...) {
slog::err << "Unknown/internal exception happened." << slog::endl;
return 1;
return EXIT_FAILURE;
}
slog::info << "Execution successful" << slog::endl;
@ -293,5 +252,5 @@ int main(int argc, char* argv[]) {
<< "This sample is an API example, for any performance measurements "
"please use the dedicated benchmark_app tool"
<< slog::endl;
return 0;
return EXIT_SUCCESS;
}

View File

@ -9,13 +9,15 @@
#pragma once
#include <algorithm>
#include <inference_engine.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "inference_engine.hpp"
#include "openvino/openvino.hpp"
/**
* @class ClassificationResult
* @brief A ClassificationResult creates an output table with results
@ -27,6 +29,7 @@ private:
const std::string _probabilityStr = "probability";
const std::string _labelStr = "label";
size_t _nTop;
ov::runtime::Tensor _outTensor;
InferenceEngine::Blob::Ptr _outBlob;
const std::vector<std::string> _labels;
const std::vector<strType> _imageNames;
@ -47,12 +50,41 @@ private:
}
/**
* @brief Gets the top n results from a tblob
* @brief Gets the top n results from a tensor
*
* @param n Top n count
* @param input 1D tblob that contains probabilities
* @param input 1D tensor that contains probabilities
* @param output Vector of indexes for the top n places
*/
template <class T>
void topResults(unsigned int n, const ov::runtime::Tensor& input, std::vector<unsigned>& output) {
ov::Shape shape = input.get_shape();
size_t input_rank = shape.size();
OPENVINO_ASSERT(input_rank != 0 && shape[0] != 0, "Input tensor has incorrect dimensions!");
size_t batchSize = shape[0];
std::vector<unsigned> indexes(input.get_size() / batchSize);
n = static_cast<unsigned>(std::min<size_t>((size_t)n, input.get_size()));
output.resize(n * batchSize);
for (size_t i = 0; i < batchSize; i++) {
const size_t offset = i * (input.get_size() / batchSize);
const T* batchData = input.data<const T>();
batchData += offset;
std::iota(std::begin(indexes), std::end(indexes), 0);
std::partial_sort(std::begin(indexes),
std::begin(indexes) + n,
std::end(indexes),
[&batchData](unsigned l, unsigned r) {
return batchData[l] > batchData[r];
});
for (unsigned j = 0; j < n; j++) {
output.at(i * n + j) = indexes.at(j);
}
}
}
template <class T>
void topResults(unsigned int n, InferenceEngine::Blob::Ptr& input, std::vector<unsigned>& output) {
InferenceEngine::SizeVector dims = input->getTensorDesc().getDims();
@ -97,6 +129,33 @@ private:
* @param input 1D blob that contains probabilities
* @param output Vector of indexes for the top n places
*/
void topResults(unsigned int n, const ov::runtime::Tensor& input, std::vector<unsigned>& output) {
#define TENSOR_TOP_RESULT(elem_type) \
case ov::element::Type_t::elem_type: { \
using tensor_type = ov::fundamental_type_for<ov::element::Type_t::elem_type>; \
topResults<tensor_type>(n, input, output); \
break; \
}
switch (input.get_element_type()) {
TENSOR_TOP_RESULT(f32);
TENSOR_TOP_RESULT(f64);
TENSOR_TOP_RESULT(f16);
TENSOR_TOP_RESULT(i16);
TENSOR_TOP_RESULT(u8);
TENSOR_TOP_RESULT(i8);
TENSOR_TOP_RESULT(u16);
TENSOR_TOP_RESULT(i32);
TENSOR_TOP_RESULT(u32);
TENSOR_TOP_RESULT(i64);
TENSOR_TOP_RESULT(u64);
default:
OPENVINO_ASSERT(false, "cannot locate tensor with element type: ", input.get_element_type());
}
#undef TENSOR_TOP_RESULT
}
void topResults(unsigned int n, InferenceEngine::Blob::Ptr& input, std::vector<unsigned>& output) {
#define TBLOB_TOP_RESULT(precision) \
case InferenceEngine::Precision::precision: { \
@ -143,9 +202,54 @@ public:
topResults(_nTop, _outBlob, _results);
}
explicit ClassificationResultT(const ov::runtime::Tensor& output_tensor,
const std::vector<strType>& image_names = {},
size_t batch_size = 1,
size_t num_of_top = 10,
const std::vector<std::string>& labels = {})
: _nTop(num_of_top),
_outTensor(output_tensor),
_labels(labels),
_imageNames(image_names),
_batchSize(batch_size),
_results() {
OPENVINO_ASSERT(_imageNames.size() == _batchSize, "Batch size should be equal to the number of images.");
topResults(_nTop, _outTensor, _results);
}
/**
* @brief prints formatted classification results
*/
void show() {
/** Print the result iterating over each batch **/
std::cout << std::endl << "Top " << _nTop << " results:" << std::endl << std::endl;
for (unsigned int image_id = 0; image_id < _batchSize; ++image_id) {
std::wstring out(_imageNames[image_id].begin(), _imageNames[image_id].end());
std::wcout << L"Image " << out;
std::wcout.flush();
std::wcout.clear();
std::wcout << std::endl << std::endl;
printHeader();
for (size_t id = image_id * _nTop, cnt = 0; id < (image_id + 1) * _nTop; ++cnt, ++id) {
std::cout.precision(7);
/** Getting probability for resulting class **/
const auto index = _results.at(id) + image_id * (_outTensor.get_size() / _batchSize);
const auto result = _outTensor.data<const float>()[index];
std::cout << std::setw(static_cast<int>(_classidStr.length())) << std::left << _results.at(id) << " ";
std::cout << std::left << std::setw(static_cast<int>(_probabilityStr.length())) << std::fixed << result;
if (!_labels.empty()) {
std::cout << " " + _labels[_results.at(id)];
}
std::cout << std::endl;
}
std::cout << std::endl;
}
}
void print() {
/** Print the result iterating over each batch **/
std::cout << std::endl << "Top " << _nTop << " results:" << std::endl << std::endl;

View File

@ -23,6 +23,8 @@
#include <utility>
#include <vector>
#include "openvino/openvino.hpp"
#ifndef UNUSED
# if defined(_MSC_VER) && !defined(__clang__)
# define UNUSED
@ -98,6 +100,16 @@ inline std::ostream& operator<<(std::ostream& os, const InferenceEngine::Version
return os;
}
inline std::ostream& operator<<(std::ostream& os, const ov::Version& version) {
os << "\t" << version.description << " version ......... ";
os << OPENVINO_VERSION_MAJOR << "." << OPENVINO_VERSION_MINOR << "." << OPENVINO_VERSION_PATCH;
os << "\n\tBuild ........... ";
os << version.buildNumber;
return os;
}
inline std::ostream& operator<<(std::ostream& os, const InferenceEngine::Version* version) {
if (nullptr != version) {
os << std::endl << *version;
@ -114,6 +126,15 @@ inline std::ostream& operator<<(std::ostream& os, const std::map<std::string, In
return os;
}
inline std::ostream& operator<<(std::ostream& os, const std::map<std::string, ov::Version>& versions) {
for (auto&& version : versions) {
os << "\t" << version.first << std::endl;
os << version.second << std::endl;
}
return os;
}
/**
* @class Color
* @brief A Color class stores channels of a given color

View File

@ -12,6 +12,8 @@
#include <opencv2/opencv.hpp>
#include <samples/common.hpp>
#include "openvino/openvino.hpp"
/**
* @brief Sets image data stored in cv::Mat object to a given Blob object.
* @param orig_image - given cv::Mat object with an image data.
@ -76,3 +78,17 @@ static UNUSED InferenceEngine::Blob::Ptr wrapMat2Blob(const cv::Mat& mat) {
return InferenceEngine::make_shared_blob<uint8_t>(tDesc, mat.data);
}
static UNUSED ov::runtime::Tensor wrapMat2Tensor(const cv::Mat& mat) {
const size_t channels = mat.channels();
const size_t height = mat.size().height;
const size_t width = mat.size().width;
const size_t strideH = mat.step.buf[0];
const size_t strideW = mat.step.buf[1];
const bool is_dense = strideW == channels && strideH == channels * width;
OPENVINO_ASSERT(is_dense, "Doesn't support conversion from not dense cv::Mat");
return ov::runtime::Tensor(ov::element::u8, ov::Shape{1, height, width, channels}, mat.data);
}

View File

@ -2,17 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
//
#include <samples/classification_results.h>
#include <inference_engine.hpp>
#include <iterator>
#include <memory>
#include <samples/common.hpp>
#include <samples/ocv_common.hpp>
#include <samples/slog.hpp>
#include <string>
#include <vector>
using namespace InferenceEngine;
#include "openvino/core/layout.hpp"
#include "openvino/openvino.hpp"
#include "samples/classification_results.h"
#include "samples/common.hpp"
#include "samples/ocv_common.hpp"
using namespace ov::preprocess;
/**
* @brief Define names based depends on Unicode path support
@ -78,8 +80,10 @@ int wmain(int argc, wchar_t* argv[]) {
int main(int argc, char* argv[]) {
#endif
try {
// ------------------------------ Parsing and validation of input arguments
// ---------------------------------
// -------- Get OpenVINO Runtime version --------
slog::info << "OpenVINO runtime: " << ov::get_openvino_version() << slog::endl;
// -------- Parsing and validation of input arguments --------
if (argc != 4) {
tcout << "Usage : " << argv[0] << " <path_to_model> <path_to_image> <device_name>" << std::endl;
return EXIT_FAILURE;
@ -92,81 +96,80 @@ int main(int argc, char* argv[]) {
#else
const std::string device_name{argv[3]};
#endif
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
Core ie;
// -----------------------------------------------------------------------------------------------------
// -------- Step 1. Initialize OpenVINO Runtime Core --------
ov::runtime::Core core;
// Step 2. Read a model in OpenVINO Intermediate Representation (.xml and
// .bin files) or ONNX (.onnx file) format
CNNNetwork network = ie.ReadNetwork(input_model);
if (network.getOutputsInfo().size() != 1)
throw std::logic_error("Sample supports topologies with 1 output only");
if (network.getInputsInfo().size() != 1)
throw std::logic_error("Sample supports topologies with 1 input only");
// -----------------------------------------------------------------------------------------------------
// -------- Step 2. Read a model --------
auto model = core.read_model(input_model);
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
// --------------------------- Prepare input blobs
// -----------------------------------------------------
InputInfo::Ptr input_info = network.getInputsInfo().begin()->second;
std::string input_name = network.getInputsInfo().begin()->first;
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");
/* Mark input as resizable by setting of a resize algorithm.
* In this case we will be able to set an input blob of any shape to an
* infer request. Resize and layout conversions are executed automatically
* during inference */
input_info->getPreProcess().setResizeAlgorithm(RESIZE_BILINEAR);
input_info->setLayout(Layout::NHWC);
input_info->setPrecision(Precision::U8);
// -------- Step 3. Initialize inference engine core
// --------------------------- Prepare output blobs
// ----------------------------------------------------
if (network.getOutputsInfo().empty()) {
std::cerr << "Network outputs info is empty" << std::endl;
return EXIT_FAILURE;
}
DataPtr output_info = network.getOutputsInfo().begin()->second;
std::string output_name = network.getOutputsInfo().begin()->first;
output_info->setPrecision(Precision::FP32);
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 4. Loading a model to the device
// ------------------------------------------
ExecutableNetwork executable_network = ie.LoadNetwork(network, device_name);
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create an infer request
// -------------------------------------------------
InferRequest infer_request = executable_network.CreateInferRequest();
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 6. Prepare input
// --------------------------------------------------------
/* Read input image to a blob and set it to an infer request without resize
* and layout conversions. */
// Read input image to a tensor and set it to an infer request
// without resize and layout conversions
cv::Mat image = imread_t(input_image_path);
Blob::Ptr imgBlob = wrapMat2Blob(image); // just wrap Mat data by Blob::Ptr
// without allocating of new memory
infer_request.SetBlob(input_name, imgBlob); // infer_request accepts input blob of any size
// just wrap Mat data by ov::runtime::Tensor without allocating of new memory
ov::runtime::Tensor input_tensor = wrapMat2Tensor(image);
const ov::Shape tensor_shape = input_tensor.get_shape();
// -------- Step 4. Apply preprocessing --------
const ov::Layout tensor_layout{"NHWC"};
// clang-format off
model = PrePostProcessor().
// 1) InputInfo() with no args assumes a model has a single input
input(InputInfo().
// 2) Set input tensor information:
// - precision of tensor is supposed to be 'u8'
// - layout of data is 'NHWC'
// - set static spatial dimensions to input tensor to resize from
tensor(InputTensorInfo().
set_element_type(ov::element::u8).
set_spatial_static_shape(
tensor_shape[ov::layout::height(tensor_layout)],
tensor_shape[ov::layout::width(tensor_layout)]).
set_layout(tensor_layout)).
// 3) Adding explicit preprocessing steps:
// - convert layout to 'NCHW' (from 'NHWC' specified above at tensor layout)
// - apply linear resize from tensor spatial dims to model spatial dims
preprocess(PreProcessSteps().
convert_element_type(ov::element::f32). // WA for CPU plugin
convert_layout("NCHW"). // WA for CPU plugin
resize(ResizeAlgorithm::RESIZE_LINEAR)).
// 4) Here we suppose model has 'NCHW' layout for input
network(InputNetworkInfo().
set_layout("NCHW"))).
output(OutputInfo().
// 5) Set output tensor information:
// - precision of tensor is supposed to be 'f32'
tensor(OutputTensorInfo().
set_element_type(ov::element::f32))).
// 6) Apply preprocessing modifing the original 'model'
build(model);
// clang-format on
// -------- Step 5. Loading a model to the device --------
ov::runtime::ExecutableNetwork executable_network = core.compile_model(model, device_name);
// -------- Step 6. Create an infer request --------
ov::runtime::InferRequest infer_request = executable_network.create_infer_request();
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// --------------------------------------------------------
/* Running the request synchronously */
infer_request.Infer();
// -----------------------------------------------------------------------------------------------------
// -------- Step 7. Prepare input --------
infer_request.set_input_tensor(input_tensor);
// -------- Step 8. Do inference synchronously --------
infer_request.infer();
// -------- Step 9. Process output
ov::runtime::Tensor output_tensor = infer_request.get_output_tensor();
// --------------------------- Step 8. Process output
// ------------------------------------------------------
Blob::Ptr output = infer_request.GetBlob(output_name);
// Print classification results
ClassificationResult_t classificationResult(output, {input_image_path});
classificationResult.print();
ClassificationResult_t classification_result(output_tensor, {input_image_path});
classification_result.show();
// -----------------------------------------------------------------------------------------------------
} catch (const std::exception& ex) {
std::cerr << ex.what() << std::endl;

View File

@ -3,8 +3,6 @@
//
#include <cstdlib>
#include <ie_plugin_config.hpp>
#include <inference_engine.hpp>
#include <iomanip>
#include <memory>
#include <samples/common.hpp>
@ -13,7 +11,8 @@
#include <tuple>
#include <vector>
using namespace InferenceEngine;
#include "ie_plugin_config.hpp"
#include "openvino/openvino.hpp"
namespace {
/**
@ -33,7 +32,7 @@ std::ostream& operator<<(std::ostream& stream, const std::vector<T>& v) {
* @param reference on IE Parameter
* @return void
*/
void printParameterValue(const Parameter& value) {
void printParameterValue(const ov::runtime::Parameter& value) {
if (value.empty()) {
std::cout << "EMPTY VALUE" << std::endl;
} else if (value.is<bool>()) {
@ -65,8 +64,8 @@ void printParameterValue(const Parameter& value) {
std::cout << std::get<2>(values);
std::cout << " }";
std::cout << std::endl;
} else if (value.is<Metrics::DeviceType>()) {
auto v = value.as<Metrics::DeviceType>();
} else if (value.is<InferenceEngine::Metrics::DeviceType>()) {
auto v = value.as<InferenceEngine::Metrics::DeviceType>();
std::cout << v << std::endl;
} else if (value.is<std::map<InferenceEngine::Precision, float>>()) {
auto values = value.as<std::map<InferenceEngine::Precision, float>>();
@ -92,46 +91,45 @@ void printParameterValue(const Parameter& value) {
int main(int argc, char* argv[]) {
try {
// ------------------------------ Parsing and validation of input arguments
// ---------------------------------
// -------- Parsing and validation of input arguments --------
if (argc != 1) {
std::cout << "Usage : " << argv[0] << std::endl;
return EXIT_FAILURE;
}
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
std::cout << "Loading Inference Engine" << std::endl;
Core ie;
// -------- Step 1. Initialize OpenVINO Runtime Core --------
std::cout << "Loading OpenVINO Runtime" << std::endl;
ov::runtime::Core core;
// --------------------------- Get list of available devices
// -------------------------------------
// -------- Step 2. Get list of available devices --------
std::vector<std::string> availableDevices = ie.GetAvailableDevices();
std::vector<std::string> availableDevices = core.get_available_devices();
// --------------------------- Query and print supported metrics and config
// keys--------------------
// -------- Step 3. Query and print supported metrics and config keys --------
std::cout << "Available devices: " << std::endl;
for (auto&& device : availableDevices) {
std::cout << device << std::endl;
// Query supported metrics and print all of them
std::cout << "\tSUPPORTED_METRICS: " << std::endl;
std::vector<std::string> supportedMetrics = ie.GetMetric(device, METRIC_KEY(SUPPORTED_METRICS));
std::vector<std::string> supportedMetrics = core.get_metric(device, METRIC_KEY(SUPPORTED_METRICS));
for (auto&& metricName : supportedMetrics) {
if (metricName != METRIC_KEY(SUPPORTED_METRICS) && metricName != METRIC_KEY(SUPPORTED_CONFIG_KEYS)) {
std::cout << "\t\t" << metricName << " : " << std::flush;
printParameterValue(ie.GetMetric(device, metricName));
printParameterValue(core.get_metric(device, metricName));
}
}
// Query supported config keys and print all of them
if (std::find(supportedMetrics.begin(), supportedMetrics.end(), METRIC_KEY(SUPPORTED_CONFIG_KEYS)) !=
supportedMetrics.end()) {
std::cout << "\tSUPPORTED_CONFIG_KEYS (default values): " << std::endl;
std::vector<std::string> supportedConfigKeys = ie.GetMetric(device, METRIC_KEY(SUPPORTED_CONFIG_KEYS));
std::vector<std::string> supportedConfigKeys =
core.get_metric(device, METRIC_KEY(SUPPORTED_CONFIG_KEYS));
for (auto&& configKey : supportedConfigKeys) {
std::cout << "\t\t" << configKey << " : " << std::flush;
printParameterValue(ie.GetConfig(device, configKey));
printParameterValue(core.get_config(device, configKey));
}
}
@ -141,5 +139,6 @@ int main(int argc, char* argv[]) {
std::cerr << std::endl << "Exception occurred: " << ex.what() << std::endl << std::flush;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -2,24 +2,26 @@
// SPDX-License-Identifier: Apache-2.0
//
#include <format_reader_ptr.h>
#include <gflags/gflags.h>
#include <samples/classification_results.h>
#include <inference_engine.hpp>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <memory>
#include <samples/args_helper.hpp>
#include <samples/common.hpp>
#include <samples/slog.hpp>
#include <string>
#include <vector>
#include "ngraph/ngraph.hpp"
#include "format_reader_ptr.h"
#include "gflags/gflags.h"
#include "ngraph/util.hpp"
#include "ngraph_function_creation_sample.hpp"
#include "openvino/openvino.hpp"
#include "openvino/opsets/opset8.hpp"
#include "samples/args_helper.hpp"
#include "samples/classification_results.h"
#include "samples/common.hpp"
#include "samples/slog.hpp"
using namespace InferenceEngine;
using namespace ngraph;
using namespace ov;
/**
* @brief Checks input args
@ -64,19 +66,19 @@ bool ParseAndCheckCommandLine(int argc, char* argv[]) {
* @return none
*/
void readFile(const std::string& file_name, void* buffer, size_t maxSize) {
std::ifstream inputFile;
std::ifstream input_file;
inputFile.open(file_name, std::ios::binary | std::ios::in);
if (!inputFile.is_open()) {
input_file.open(file_name, std::ios::binary | std::ios::in);
if (!input_file.is_open()) {
throw std::logic_error("Cannot open weights file");
}
if (!inputFile.read(reinterpret_cast<char*>(buffer), maxSize)) {
inputFile.close();
if (!input_file.read(reinterpret_cast<char*>(buffer), maxSize)) {
input_file.close();
throw std::logic_error("Cannot read bytes from weights file");
}
inputFile.close();
input_file.close();
}
/**
@ -84,252 +86,222 @@ void readFile(const std::string& file_name, void* buffer, size_t maxSize) {
* @param filepath string
* @return weightsPtr tensor blob
*/
TBlob<uint8_t>::CPtr ReadWeights(std::string filepath) {
ov::runtime::Tensor ReadWeights(const std::string& filepath) {
std::ifstream weightFile(filepath, std::ifstream::ate | std::ifstream::binary);
int64_t fileSize = weightFile.tellg();
OPENVINO_ASSERT(fileSize == 1724336,
"Incorrect weights file. This sample works only with LeNet "
"classification model.");
if (fileSize < 0) {
throw std::logic_error("Incorrect weights file");
}
ov::runtime::Tensor weights(ov::element::u8, {static_cast<size_t>(fileSize)});
readFile(filepath, weights.data(), weights.get_byte_size());
size_t ulFileSize = static_cast<size_t>(fileSize);
TBlob<uint8_t>::Ptr weightsPtr(new TBlob<uint8_t>({Precision::FP32, {ulFileSize}, Layout::C}));
weightsPtr->allocate();
readFile(filepath, weightsPtr->buffer(), ulFileSize);
return weightsPtr;
return std::move(weights);
}
/**
* @brief Create ngraph function
* @return Ptr to ngraph function
*/
std::shared_ptr<Function> createNgraphFunction() {
TBlob<uint8_t>::CPtr weightsPtr = ReadWeights(FLAGS_m);
if (weightsPtr->byteSize() != 6897344)
IE_THROW() << "Incorrect weights file. This sample works only with LeNet "
"classification network.";
std::shared_ptr<ov::Function> createNgraphFunction() {
auto weights = ReadWeights(FLAGS_m);
const std::uint8_t* data = weights.data<std::uint8_t>();
// -------input------
std::vector<ptrdiff_t> padBegin{0, 0};
std::vector<ptrdiff_t> padEnd{0, 0};
auto paramNode = std::make_shared<op::Parameter>(element::Type_t::f32, Shape(std::vector<size_t>{{64, 1, 28, 28}}));
paramNode->set_friendly_name("Parameter");
auto paramNode = std::make_shared<ov::opset8::Parameter>(ov::element::Type_t::f32, ov::Shape({64, 1, 28, 28}));
// -------convolution 1----
auto convFirstShape = Shape{20, 1, 5, 5};
std::shared_ptr<Node> convolutionFirstConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32, convFirstShape, weightsPtr->cbuffer().as<uint8_t*>());
auto convolutionFirstConstantNode = std::make_shared<opset8::Constant>(element::Type_t::f32, convFirstShape, data);
std::shared_ptr<Node> convolutionNodeFirst =
std::make_shared<op::v1::Convolution>(paramNode->output(0),
convolutionFirstConstantNode->output(0),
Strides(SizeVector{1, 1}),
CoordinateDiff(padBegin),
CoordinateDiff(padEnd),
Strides(SizeVector{1, 1}));
auto convolutionNodeFirst = std::make_shared<opset8::Convolution>(paramNode->output(0),
convolutionFirstConstantNode->output(0),
Strides({1, 1}),
CoordinateDiff(padBegin),
CoordinateDiff(padEnd),
Strides({1, 1}));
// -------Add--------------
auto addFirstShape = Shape{1, 20, 1, 1};
auto offset = shape_size(convFirstShape) * sizeof(float);
std::shared_ptr<Node> addFirstConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
addFirstShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto addFirstConstantNode = std::make_shared<opset8::Constant>(element::Type_t::f32, addFirstShape, data + offset);
std::shared_ptr<Node> addNodeFirst =
std::make_shared<op::v1::Add>(convolutionNodeFirst->output(0), addFirstConstantNode->output(0));
auto addNodeFirst = std::make_shared<opset8::Add>(convolutionNodeFirst->output(0), addFirstConstantNode->output(0));
// -------MAXPOOL----------
Shape padBeginShape{0, 0};
Shape padEndShape{0, 0};
std::shared_ptr<Node> maxPoolingNodeFirst = std::make_shared<op::v1::MaxPool>(addNodeFirst->output(0),
std::vector<size_t>{2, 2},
padBeginShape,
padEndShape,
std::vector<size_t>{2, 2},
op::RoundingType::CEIL,
op::PadType::EXPLICIT);
auto maxPoolingNodeFirst = std::make_shared<op::v1::MaxPool>(addNodeFirst->output(0),
Strides{2, 2},
padBeginShape,
padEndShape,
Shape{2, 2},
op::RoundingType::CEIL);
// -------convolution 2----
auto convSecondShape = Shape{50, 20, 5, 5};
offset += shape_size(addFirstShape) * sizeof(float);
std::shared_ptr<Node> convolutionSecondConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
convSecondShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto convolutionSecondConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::f32, convSecondShape, data + offset);
std::shared_ptr<Node> convolutionNodeSecond =
std::make_shared<op::v1::Convolution>(maxPoolingNodeFirst->output(0),
convolutionSecondConstantNode->output(0),
Strides({1, 1}),
CoordinateDiff(padBegin),
CoordinateDiff(padEnd),
Strides({1, 1}));
auto convolutionNodeSecond = std::make_shared<opset8::Convolution>(maxPoolingNodeFirst->output(0),
convolutionSecondConstantNode->output(0),
Strides({1, 1}),
CoordinateDiff(padBegin),
CoordinateDiff(padEnd),
Strides({1, 1}));
// -------Add 2------------
auto addSecondShape = Shape{1, 50, 1, 1};
offset += shape_size(convSecondShape) * sizeof(float);
std::shared_ptr<Node> addSecondConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
addSecondShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto addSecondConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::f32, addSecondShape, data + offset);
std::shared_ptr<Node> addNodeSecond =
std::make_shared<op::v1::Add>(convolutionNodeSecond->output(0), addSecondConstantNode->output(0));
auto addNodeSecond =
std::make_shared<opset8::Add>(convolutionNodeSecond->output(0), addSecondConstantNode->output(0));
// -------MAXPOOL 2--------
std::shared_ptr<Node> maxPoolingNodeSecond = std::make_shared<op::v1::MaxPool>(addNodeSecond->output(0),
Strides{2, 2},
padBeginShape,
padEndShape,
Shape{2, 2},
op::RoundingType::CEIL,
op::PadType::EXPLICIT);
auto maxPoolingNodeSecond = std::make_shared<op::v1::MaxPool>(addNodeSecond->output(0),
Strides{2, 2},
padBeginShape,
padEndShape,
Shape{2, 2},
op::RoundingType::CEIL);
// -------Reshape----------
auto reshapeFirstShape = Shape{2};
auto reshapeOffset = shape_size(addSecondShape) * sizeof(float) + offset;
std::shared_ptr<Node> reshapeFirstConstantNode =
std::make_shared<op::Constant>(element::Type_t::i64,
reshapeFirstShape,
(weightsPtr->cbuffer().as<uint8_t*>() + reshapeOffset));
auto reshapeFirstConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::i64, reshapeFirstShape, data + reshapeOffset);
std::shared_ptr<Node> reshapeFirstNode =
auto reshapeFirstNode =
std::make_shared<op::v1::Reshape>(maxPoolingNodeSecond->output(0), reshapeFirstConstantNode->output(0), true);
// -------MatMul 1---------
auto matMulFirstShape = Shape{500, 800};
offset = shape_size(reshapeFirstShape) * sizeof(int64_t) + reshapeOffset;
std::shared_ptr<Node> matMulFirstConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
matMulFirstShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto matMulFirstConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::f32, matMulFirstShape, data + offset);
std::shared_ptr<Node> matMulFirstNode =
std::make_shared<op::MatMul>(reshapeFirstNode->output(0), matMulFirstConstantNode->output(0), false, true);
auto matMulFirstNode =
std::make_shared<opset8::MatMul>(reshapeFirstNode->output(0), matMulFirstConstantNode->output(0), false, true);
// -------Add 3------------
auto addThirdShape = Shape{1, 500};
offset += shape_size(matMulFirstShape) * sizeof(float);
std::shared_ptr<Node> addThirdConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
addThirdShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto addThirdConstantNode = std::make_shared<opset8::Constant>(element::Type_t::f32, addThirdShape, data + offset);
std::shared_ptr<Node> addThirdNode =
std::make_shared<op::v1::Add>(matMulFirstNode->output(0), addThirdConstantNode->output(0));
auto addThirdNode = std::make_shared<opset8::Add>(matMulFirstNode->output(0), addThirdConstantNode->output(0));
// -------Relu-------------
std::shared_ptr<Node> reluNode = std::make_shared<op::Relu>(addThirdNode->output(0));
auto reluNode = std::make_shared<opset8::Relu>(addThirdNode->output(0));
// -------Reshape 2--------
auto reshapeSecondShape = Shape{2};
std::shared_ptr<Node> reshapeSecondConstantNode =
std::make_shared<op::Constant>(element::Type_t::i64,
reshapeSecondShape,
(weightsPtr->cbuffer().as<uint8_t*>() + reshapeOffset));
auto reshapeSecondConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::i64, reshapeSecondShape, data + reshapeOffset);
std::shared_ptr<Node> reshapeSecondNode =
auto reshapeSecondNode =
std::make_shared<op::v1::Reshape>(reluNode->output(0), reshapeSecondConstantNode->output(0), true);
// -------MatMul 2---------
auto matMulSecondShape = Shape{10, 500};
offset += shape_size(addThirdShape) * sizeof(float);
std::shared_ptr<Node> matMulSecondConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
matMulSecondShape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto matMulSecondConstantNode =
std::make_shared<opset8::Constant>(element::Type_t::f32, matMulSecondShape, data + offset);
std::shared_ptr<Node> matMulSecondNode =
std::make_shared<op::MatMul>(reshapeSecondNode->output(0), matMulSecondConstantNode->output(0), false, true);
auto matMulSecondNode = std::make_shared<opset8::MatMul>(reshapeSecondNode->output(0),
matMulSecondConstantNode->output(0),
false,
true);
// -------Add 4------------
auto add4Shape = Shape{1, 10};
offset += shape_size(matMulSecondShape) * sizeof(float);
std::shared_ptr<Node> add4ConstantNode =
std::make_shared<op::Constant>(element::Type_t::f32,
add4Shape,
(weightsPtr->cbuffer().as<uint8_t*>() + offset));
auto add4ConstantNode = std::make_shared<opset8::Constant>(element::Type_t::f32, add4Shape, data + offset);
std::shared_ptr<Node> add4Node =
std::make_shared<op::v1::Add>(matMulSecondNode->output(0), add4ConstantNode->output(0));
auto add4Node = std::make_shared<opset8::Add>(matMulSecondNode->output(0), add4ConstantNode->output(0));
// -------softMax----------
std::shared_ptr<Node> softMaxNode = std::make_shared<op::v1::Softmax>(add4Node->output(0), 1);
auto softMaxNode = std::make_shared<opset8::Softmax>(add4Node->output(0), 1);
softMaxNode->get_output_tensor(0).set_names({"output_tensor"});
// -------ngraph function--
auto result_full = std::make_shared<op::Result>(softMaxNode->output(0));
// ------- OpenVINO function--
auto result_full = std::make_shared<opset8::Result>(softMaxNode->output(0));
std::shared_ptr<ngraph::Function> fnPtr =
std::make_shared<ngraph::Function>(result_full, ngraph::ParameterVector{paramNode}, "lenet");
std::shared_ptr<ov::Function> fnPtr =
std::make_shared<ov::Function>(result_full, ov::ParameterVector{paramNode}, "lenet");
return fnPtr;
}
/**
* @brief The entry point for inference engine automatic ngraph function
* @brief The entry point for inference engine automatic ov::Function
* creation sample
* @file ngraph_function_creation_sample/main.cpp
* @example ngraph_function_creation_sample/main.cpp
*/
int main(int argc, char* argv[]) {
try {
// ------------------------------ Get Inference Engine version
// ------------------------------------------------------
slog::info << "InferenceEngine: " << GetInferenceEngineVersion() << slog::endl;
// ------------------------------ Parsing and validation of input arguments
// ---------------------------------
// -------- Get OpenVINO runtime version --------
slog::info << "OpenVINO Runtime: " << ov::get_openvino_version() << slog::endl;
// -------- Parsing and validation of input arguments --------
if (!ParseAndCheckCommandLine(argc, argv)) {
return 0;
return EXIT_SUCCESS;
}
// ------------------------------ Read input
// -----------------------------------------------------------
/** This vector stores paths to the processed images **/
// -------- Read input --------
std::vector<std::string> images;
parseInputFilesArguments(images);
if (images.empty()) {
throw std::logic_error("No suitable images were found");
}
// -----------------------------------------------------------------------------------------------------
OPENVINO_ASSERT(!images.empty(), "No suitable images were found");
// -------- Step 1. Initialize OpenVINO Runtime Core object --------
slog::info << "Loading OpenVINO runtime" << slog::endl;
runtime::Core core;
// --------------------------- Step 1. Initialize inference engine core
// -------------------------------------
slog::info << "Loading Inference Engine" << slog::endl;
Core ie;
// ------------------------------ Get Available Devices
// ------------------------------------------------------
slog::info << "Device info: " << slog::endl;
std::cout << ie.GetVersions(FLAGS_d) << std::endl;
// -----------------------------------------------------------------------------------------------------
std::cout << core.get_versions(FLAGS_d) << std::endl;
//--------------------------- Step 2. Create network using ngraph function
//-----------------------------------
// -------- Step 2. Create network using ov::Function --------
CNNNetwork network(createNgraphFunction());
// -----------------------------------------------------------------------------------------------------
auto model = createNgraphFunction();
// --------------------------- Step 3. Configure input & output
// ---------------------------------------------
// --------------------------- Prepare input blobs
// -----------------------------------------------------
slog::info << "Preparing input blobs" << slog::endl;
// -------- Step 3. Apply preprocessing --------
const Layout tensor_layout{"NHWC"};
InputsDataMap inputInfo = network.getInputsInfo();
if (inputInfo.size() != 1) {
throw std::logic_error("Sample supports topologies only with 1 input");
}
// apply preprocessing
// clang-format off
using namespace ov::preprocess;
model = PrePostProcessor()
// 1) InputInfo() with no args assumes a model has a single input
.input(InputInfo()
// 2) Set input tensor information:
// - precision of tensor is supposed to be 'u8'
// - layout of data is 'NHWC'
.tensor(InputTensorInfo()
.set_layout(tensor_layout)
.set_element_type(element::u8))
// 3) Here we suppose model has 'NCHW' layout for input
.network(InputNetworkInfo()
.set_layout("NCHW")))
// 4) Once the build() method is called, the preprocessing steps
// for layout and precision conversions are inserted automatically
.build(model);
// clang-format on
auto inputInfoItem = *inputInfo.begin();
// -------- Step 4. Read input images --------
/** Specifying the precision and layout of input data provided by the user.
* Call this before loading the network to the device **/
inputInfoItem.second->setPrecision(Precision::FP32);
inputInfoItem.second->setLayout(Layout::NCHW);
const auto input = model->input();
auto input_shape = input.get_shape();
const size_t width = input_shape[layout::width(tensor_layout)];
const size_t height = input_shape[layout::height(tensor_layout)];
std::vector<std::shared_ptr<unsigned char>> imagesData;
for (auto& i : images) {
@ -339,156 +311,95 @@ int main(int argc, char* argv[]) {
continue;
}
if (reader->size() != inputInfoItem.second->getTensorDesc().getDims()[2] *
inputInfoItem.second->getTensorDesc().getDims()[3]) {
if (reader->size() != width * height) {
throw std::logic_error("Not supported format. Only MNist ubyte images supported.");
}
/** Store image data **/
std::shared_ptr<unsigned char> data(reader->getData(inputInfoItem.second->getTensorDesc().getDims()[3],
inputInfoItem.second->getTensorDesc().getDims()[2]));
// Store image data
std::shared_ptr<unsigned char> data(reader->getData(width, height));
if (data.get() != nullptr) {
imagesData.push_back(data);
}
}
if (imagesData.empty()) {
throw std::logic_error("Valid input images were not found");
}
OPENVINO_ASSERT(!imagesData.empty(), "Valid input images were not found");
/** Setting batch size using image count **/
network.setBatchSize(imagesData.size());
size_t batchSize = network.getBatchSize();
slog::info << "Batch size is " << std::to_string(batchSize) << slog::endl;
// -------- Step 4. Reshape a model --------
// Setting batch size using image count
const size_t batch_size = imagesData.size();
input_shape[layout::batch(tensor_layout)] = batch_size;
model->reshape({{input.get_any_name(), input_shape}});
slog::info << "Batch size is " << std::to_string(batch_size) << slog::endl;
// --------------------------- Prepare output blobs
// -----------------------------------------------------
slog::info << "Checking that the outputs are as the sample expects" << slog::endl;
OutputsDataMap outputInfo(network.getOutputsInfo());
std::string firstOutputName;
const auto outputShape = model->output().get_shape();
OPENVINO_ASSERT(outputShape.size() == 2, "Incorrect output dimensions for LeNet");
for (auto& item : outputInfo) {
if (firstOutputName.empty()) {
firstOutputName = item.first;
}
DataPtr outputData = item.second;
if (!outputData) {
throw std::logic_error("Output data pointer is not valid");
}
const auto classCount = outputShape[1];
OPENVINO_ASSERT(classCount <= 10, "Incorrect number of output classes for LeNet model");
item.second->setPrecision(Precision::FP32);
}
// -------- Step 4. Compiling model for the device --------
slog::info << "Compiling a model for the " << FLAGS_d << " device" << slog::endl;
runtime::ExecutableNetwork exeNetwork = core.compile_model(model, FLAGS_d);
if (outputInfo.size() != 1) {
throw std::logic_error("This demo accepts networks with a single output");
}
DataPtr& output = outputInfo.begin()->second;
auto outputName = outputInfo.begin()->first;
const SizeVector outputDims = output->getTensorDesc().getDims();
const int classCount = outputDims[1];
if (classCount > 10) {
throw std::logic_error("Incorrect number of output classes for LeNet network");
}
if (outputDims.size() != 2) {
throw std::logic_error("Incorrect output dimensions for LeNet");
}
output->setPrecision(Precision::FP32);
output->setLayout(Layout::NC);
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 4. Loading model to the device
// ------------------------------------------
slog::info << "Loading model to the device" << slog::endl;
ExecutableNetwork exeNetwork = ie.LoadNetwork(network, FLAGS_d);
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 5. Create infer request
// -------------------------------------------------
// -------- Step 5. Create infer request --------
slog::info << "Create infer request" << slog::endl;
InferRequest infer_request = exeNetwork.CreateInferRequest();
// -----------------------------------------------------------------------------------------------------
runtime::InferRequest infer_request = exeNetwork.create_infer_request();
// --------------------------- Step 6. Prepare input
// --------------------------------------------------------
/** Iterate over all the input blobs **/
for (const auto& item : inputInfo) {
/** Creating input blob **/
Blob::Ptr input = infer_request.GetBlob(item.first);
// -------- Step 6. Combine multiple input images as batch --------
slog::info << "Combining a batch and set input tensor" << slog::endl;
runtime::Tensor input_tensor = infer_request.get_input_tensor();
/** Filling input tensor with images. First b channel, then g and r
* channels **/
size_t num_channels = input->getTensorDesc().getDims()[1];
size_t image_size = input->getTensorDesc().getDims()[2] * input->getTensorDesc().getDims()[3];
auto data = input->buffer().as<PrecisionTrait<Precision::FP32>::value_type*>();
/** Iterate over all input images **/
for (size_t image_id = 0; image_id < imagesData.size(); ++image_id) {
/** Iterate over all pixels 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] =
imagesData.at(image_id).get()[pid * num_channels + ch];
}
}
}
// Iterate over all input images
for (size_t image_id = 0; image_id < imagesData.size(); ++image_id) {
const size_t image_size = shape_size(input_shape) / batch_size;
std::memcpy(input_tensor.data<std::uint8_t>() + image_id * image_size,
imagesData[image_id].get(),
image_size);
}
inputInfo = {};
// -----------------------------------------------------------------------------------------------------
// --------------------------- Step 7. Do inference
// ---------------------------------------------------------
slog::info << "Start inference" << slog::endl;
infer_request.Infer();
// -----------------------------------------------------------------------------------------------------
// -------- Step 7. Do sync inference --------
slog::info << "Start sync inference" << slog::endl;
infer_request.infer();
// --------------------------- Step 8. Process output
// -------------------------------------------------------
slog::info << "Processing output blobs" << slog::endl;
// -------- Step 8. Process output --------
slog::info << "Processing output tensor" << slog::endl;
const runtime::Tensor output_tensor = infer_request.get_output_tensor();
const Blob::Ptr outputBlob = infer_request.GetBlob(firstOutputName);
/** Validating -nt value **/
const size_t resultsCnt = outputBlob->size() / batchSize;
if (FLAGS_nt > resultsCnt || FLAGS_nt < 1) {
slog::warn << "-nt " << FLAGS_nt << " is not available for this network (-nt should be less than "
<< resultsCnt + 1 << " and more than 0).\n Maximal value " << resultsCnt
// Validating -nt value
const size_t results_cnt = output_tensor.get_size() / batch_size;
if (FLAGS_nt > results_cnt || FLAGS_nt < 1) {
slog::warn << "-nt " << FLAGS_nt << " is not available for this model (-nt should be less than "
<< results_cnt + 1 << " and more than 0).\n Maximal value " << results_cnt
<< " will be used.";
FLAGS_nt = resultsCnt;
FLAGS_nt = results_cnt;
}
/** Read labels from file (e.x. LeNet.labels) **/
std::string labelFileName = fileNameNoExt(FLAGS_m) + ".labels";
// Read labels from file (e.x. LeNet.labels) **/
std::string label_file_name = fileNameNoExt(FLAGS_m) + ".labels";
std::vector<std::string> labels;
std::ifstream inputFile;
inputFile.open(labelFileName, std::ios::in);
if (inputFile.is_open()) {
std::ifstream input_file;
input_file.open(label_file_name, std::ios::in);
if (input_file.is_open()) {
std::string strLine;
while (std::getline(inputFile, strLine)) {
while (std::getline(input_file, strLine)) {
trim(strLine);
labels.push_back(strLine);
}
inputFile.close();
input_file.close();
}
// Prints formatted classification results
ClassificationResult classificationResult(outputBlob, images, batchSize, FLAGS_nt, labels);
classificationResult.print();
// -----------------------------------------------------------------------------------------------------
ClassificationResult classification_result(output_tensor, images, batch_size, FLAGS_nt, labels);
classification_result.show();
} catch (const std::exception& ex) {
slog::err << ex.what() << slog::endl;
return EXIT_FAILURE;
}
slog::info << "This sample is an API example, for performance measurements, "
"use the dedicated benchmark_app tool"
<< slog::endl;
return 0;
return EXIT_SUCCESS;
}

View File

@ -89,11 +89,9 @@ int main(int argc, char* argv[]) {
std::cout << ie.GetVersions(FLAGS_d) << std::endl;
if (!FLAGS_l.empty()) {
// Custom CPU extension is loaded as a shared library and passed as a
// pointer to base extension
IExtensionPtr extension_ptr = std::make_shared<Extension>(FLAGS_l);
ie.AddExtension(extension_ptr);
slog::info << "Custom extension loaded: " << FLAGS_l << slog::endl;
slog::info << "Extension loaded: " << FLAGS_l << slog::endl;
}
if (!FLAGS_c.empty() && (FLAGS_d == "GPU" || FLAGS_d == "MYRIAD" || FLAGS_d == "HDDL")) {

View File

@ -79,11 +79,9 @@ int main(int argc, char* argv[]) {
std::cout << ie.GetVersions(FLAGS_d) << std::endl;
if (!FLAGS_l.empty()) {
// Custom CPU extension is loaded as a shared library and passed as a
// pointer to base extension
IExtensionPtr extension_ptr = std::make_shared<Extension>(FLAGS_l);
ie.AddExtension(extension_ptr);
slog::info << "Custom Extension loaded: " << FLAGS_l << slog::endl;
slog::info << "Extension loaded: " << FLAGS_l << slog::endl;
}
if (!FLAGS_c.empty() && (FLAGS_d == "GPU" || FLAGS_d == "MYRIAD" || FLAGS_d == "HDDL")) {
// Config for device plugin custom extension is loaded from an .xml

View File

@ -0,0 +1,14 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
/**
* @brief This is a header file for the OpenVINO Runtime Components
*
* @file openvino/runtime/runtime.hpp
*/
#pragma once
#include "openvino/core/core.hpp"
#include "openvino/runtime/runtime.hpp"

View File

@ -7,6 +7,7 @@
*
* @file openvino/runtime/runtime.hpp
*/
#pragma once
#include "openvino/runtime/core.hpp"

View File

@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/core/core_visibility.hpp"
/**