2022-01-19 01:07:49 +03:00
|
|
|
// Copyright (C) 2018-2022 Intel Corporation
|
2018-11-23 16:19:43 +03:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2018-10-16 13:45:03 +03:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
/**
|
2021-10-23 22:47:35 +03:00
|
|
|
* @brief The entry point the OpenVINO Runtime sample application
|
2021-04-22 14:02:54 +03:00
|
|
|
* @file classification_sample_async/main.cpp
|
|
|
|
|
* @example classification_sample_async/main.cpp
|
|
|
|
|
*/
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-04-22 14:02:54 +03:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
#include <condition_variable>
|
2018-10-16 13:45:03 +03:00
|
|
|
#include <fstream>
|
|
|
|
|
#include <map>
|
2021-04-22 14:02:54 +03:00
|
|
|
#include <memory>
|
2019-08-09 19:02:42 +03:00
|
|
|
#include <mutex>
|
2021-04-22 14:02:54 +03:00
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// clang-format off
|
2021-10-23 22:47:35 +03:00
|
|
|
#include "openvino/openvino.hpp"
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
#include "samples/args_helper.hpp"
|
|
|
|
|
#include "samples/common.hpp"
|
|
|
|
|
#include "samples/classification_results.h"
|
|
|
|
|
#include "samples/slog.hpp"
|
|
|
|
|
#include "format_reader_ptr.h"
|
|
|
|
|
|
|
|
|
|
#include "classification_sample_async.h"
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
constexpr auto N_TOP_RESULTS = 10;
|
|
|
|
|
|
|
|
|
|
using namespace ov::preprocess;
|
|
|
|
|
|
2021-04-15 13:42:46 +03:00
|
|
|
/**
|
2021-04-22 14:02:54 +03:00
|
|
|
* @brief Checks input args
|
|
|
|
|
* @param argc number of args
|
|
|
|
|
* @param argv list of input arguments
|
|
|
|
|
* @return bool status true(Success) or false(Fail)
|
|
|
|
|
*/
|
2021-12-29 15:36:33 +03:00
|
|
|
bool parse_and_check_command_line(int argc, char* argv[]) {
|
2018-10-16 13:45:03 +03:00
|
|
|
gflags::ParseCommandLineNonHelpFlags(&argc, &argv, true);
|
|
|
|
|
if (FLAGS_h) {
|
2021-12-29 15:36:33 +03:00
|
|
|
show_usage();
|
2019-08-09 19:02:42 +03:00
|
|
|
showAvailableDevices();
|
2018-10-16 13:45:03 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
slog::info << "Parsing input parameters" << slog::endl;
|
|
|
|
|
|
2020-11-16 01:26:04 -08:00
|
|
|
if (FLAGS_m.empty()) {
|
2021-12-29 15:36:33 +03:00
|
|
|
show_usage();
|
2020-11-16 01:26:04 -08:00
|
|
|
throw std::logic_error("Model is required but not set. Please set -m option.");
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
|
|
|
|
|
2020-11-16 01:26:04 -08:00
|
|
|
if (FLAGS_i.empty()) {
|
2021-12-29 15:36:33 +03:00
|
|
|
show_usage();
|
2020-11-16 01:26:04 -08:00
|
|
|
throw std::logic_error("Input is required but not set. Please set -i option.");
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 14:02:54 +03:00
|
|
|
int main(int argc, char* argv[]) {
|
2018-10-16 13:45:03 +03:00
|
|
|
try {
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Get OpenVINO Runtime version --------
|
2021-11-22 15:21:09 +03:00
|
|
|
slog::info << ov::get_openvino_version() << slog::endl;
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Parsing and validation of input arguments --------
|
2021-12-29 15:36:33 +03:00
|
|
|
if (!parse_and_check_command_line(argc, argv)) {
|
2021-10-23 22:47:35 +03:00
|
|
|
return EXIT_SUCCESS;
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
2021-10-23 22:47:35 +03:00
|
|
|
|
|
|
|
|
// -------- Read input --------
|
|
|
|
|
// This vector stores paths to the processed images
|
|
|
|
|
std::vector<std::string> image_names;
|
|
|
|
|
parseInputFilesArguments(image_names);
|
|
|
|
|
if (image_names.empty())
|
2021-04-22 14:02:54 +03:00
|
|
|
throw std::logic_error("No suitable images were found");
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Step 1. Initialize OpenVINO Runtime Core --------
|
2022-01-20 16:17:57 +03:00
|
|
|
ov::Core core;
|
2019-08-09 19:02:42 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Step 2. Read a model --------
|
|
|
|
|
slog::info << "Loading model files:" << slog::endl << FLAGS_m << slog::endl;
|
2021-12-10 13:08:38 +03:00
|
|
|
std::shared_ptr<ov::Model> model = core.read_model(FLAGS_m);
|
2021-12-13 11:30:58 +03:00
|
|
|
printInputAndOutputsInfo(*model);
|
2021-10-23 22:47:35 +03:00
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 3. Configure preprocessing --------
|
2021-10-23 22:47:35 +03:00
|
|
|
const ov::Layout tensor_layout{"NHWC"};
|
|
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
ov::preprocess::PrePostProcessor ppp(model);
|
2021-11-17 00:51:19 +03:00
|
|
|
// 1) input() with no args assumes a model has a single input
|
2021-12-13 11:30:58 +03:00
|
|
|
ov::preprocess::InputInfo& input_info = ppp.input();
|
2021-11-17 00:51:19 +03:00
|
|
|
// 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) Here we suppose model has 'NCHW' layout for input
|
2021-12-07 19:26:27 +03:00
|
|
|
input_info.model().set_layout("NCHW");
|
2021-11-17 00:51:19 +03:00
|
|
|
// 4) output() with no args assumes a model has a single result
|
|
|
|
|
// - output() with no args assumes a model has a single result
|
|
|
|
|
// - precision of tensor is supposed to be 'f32'
|
2021-12-13 11:30:58 +03:00
|
|
|
ppp.output().tensor().set_element_type(ov::element::f32);
|
|
|
|
|
|
2021-11-17 00:51:19 +03:00
|
|
|
// 5) Once the build() method is called, the pre(post)processing steps
|
|
|
|
|
// for layout and precision conversions are inserted automatically
|
2021-12-13 11:30:58 +03:00
|
|
|
model = ppp.build();
|
2021-10-23 22:47:35 +03:00
|
|
|
|
|
|
|
|
// -------- Step 4. read input images --------
|
|
|
|
|
slog::info << "Read input images" << slog::endl;
|
|
|
|
|
|
|
|
|
|
ov::Shape input_shape = model->input().get_shape();
|
2021-10-28 11:26:55 +03:00
|
|
|
const size_t width = input_shape[ov::layout::width_idx(tensor_layout)];
|
|
|
|
|
const size_t height = input_shape[ov::layout::height_idx(tensor_layout)];
|
2021-10-23 22:47:35 +03:00
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<unsigned char>> images_data;
|
|
|
|
|
std::vector<std::string> valid_image_names;
|
|
|
|
|
for (const auto& i : image_names) {
|
2018-10-16 13:45:03 +03:00
|
|
|
FormatReader::ReaderPtr reader(i.c_str());
|
|
|
|
|
if (reader.get() == nullptr) {
|
|
|
|
|
slog::warn << "Image " + i + " cannot be read!" << slog::endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-12-13 11:30:58 +03:00
|
|
|
// Collect image data
|
2021-10-23 22:47:35 +03:00
|
|
|
std::shared_ptr<unsigned char> data(reader->getData(width, height));
|
2019-08-09 19:02:42 +03:00
|
|
|
if (data != nullptr) {
|
2021-10-23 22:47:35 +03:00
|
|
|
images_data.push_back(data);
|
|
|
|
|
valid_image_names.push_back(i);
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-23 22:47:35 +03:00
|
|
|
if (images_data.empty() || valid_image_names.empty())
|
2021-04-22 14:02:54 +03:00
|
|
|
throw std::logic_error("Valid input images were not found!");
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Step 5. Loading model to the device --------
|
|
|
|
|
// Setting batch size using image count
|
|
|
|
|
const size_t batchSize = images_data.size();
|
2021-12-13 11:30:58 +03:00
|
|
|
slog::info << "Set batch size " << std::to_string(batchSize) << slog::endl;
|
|
|
|
|
ov::set_batch(model, batchSize);
|
|
|
|
|
printInputAndOutputsInfo(*model);
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
// -------- Step 6. Loading model to the device --------
|
|
|
|
|
slog::info << "Loading model to the device " << FLAGS_d << slog::endl;
|
2022-01-20 16:17:57 +03:00
|
|
|
ov::CompiledModel compiled_model = core.compile_model(model, FLAGS_d);
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 7. Create infer request --------
|
2019-08-09 19:02:42 +03:00
|
|
|
slog::info << "Create infer request" << slog::endl;
|
2022-01-20 16:17:57 +03:00
|
|
|
ov::InferRequest infer_request = compiled_model.create_infer_request();
|
2021-10-23 22:47:35 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 8. Combine multiple input images as batch --------
|
2022-01-20 16:17:57 +03:00
|
|
|
ov::Tensor input_tensor = infer_request.get_input_tensor();
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
for (size_t image_id = 0; image_id < images_data.size(); ++image_id) {
|
2021-12-13 11:30:58 +03:00
|
|
|
const size_t image_size = shape_size(model->input().get_shape()) / batchSize;
|
2021-10-23 22:47:35 +03:00
|
|
|
std::memcpy(input_tensor.data<std::uint8_t>() + image_id * image_size,
|
|
|
|
|
images_data[image_id].get(),
|
|
|
|
|
image_size);
|
|
|
|
|
}
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 9. Do asynchronous inference --------
|
2021-10-23 22:47:35 +03:00
|
|
|
size_t num_iterations = 10;
|
|
|
|
|
size_t cur_iteration = 0;
|
2019-08-09 19:02:42 +03:00
|
|
|
std::condition_variable condVar;
|
2021-10-27 12:29:21 +03:00
|
|
|
std::mutex mutex;
|
2019-08-09 19:02:42 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 10. Do asynchronous inference --------
|
2021-10-23 22:47:35 +03:00
|
|
|
infer_request.set_callback([&](std::exception_ptr ex) {
|
|
|
|
|
if (ex)
|
|
|
|
|
throw ex;
|
2021-12-13 11:30:58 +03:00
|
|
|
|
2021-10-27 12:29:21 +03:00
|
|
|
std::lock_guard<std::mutex> l(mutex);
|
2021-10-23 22:47:35 +03:00
|
|
|
cur_iteration++;
|
|
|
|
|
slog::info << "Completed " << cur_iteration << " async request execution" << slog::endl;
|
|
|
|
|
if (cur_iteration < num_iterations) {
|
2021-12-13 11:30:58 +03:00
|
|
|
// here a user can read output containing inference results and put new
|
|
|
|
|
// input to repeat async request again
|
2021-10-23 22:47:35 +03:00
|
|
|
infer_request.start_async();
|
2021-04-22 14:02:54 +03:00
|
|
|
} else {
|
2021-12-13 11:30:58 +03:00
|
|
|
// continue sample execution after last Asynchronous inference request
|
|
|
|
|
// execution
|
2021-04-22 14:02:54 +03:00
|
|
|
condVar.notify_one();
|
|
|
|
|
}
|
|
|
|
|
});
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// Start async request for the first time
|
|
|
|
|
slog::info << "Start inference (asynchronous executions)" << slog::endl;
|
2021-10-23 22:47:35 +03:00
|
|
|
infer_request.start_async();
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// Wait all iterations of the async request
|
2019-08-09 19:02:42 +03:00
|
|
|
std::unique_lock<std::mutex> lock(mutex);
|
2021-04-22 14:02:54 +03:00
|
|
|
condVar.wait(lock, [&] {
|
2021-10-23 22:47:35 +03:00
|
|
|
return cur_iteration == num_iterations;
|
2021-04-22 14:02:54 +03:00
|
|
|
});
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
slog::info << "Completed async requests execution" << slog::endl;
|
2019-08-09 19:02:42 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// -------- Step 11. Process output --------
|
2022-01-20 16:17:57 +03:00
|
|
|
ov::Tensor output = infer_request.get_output_tensor();
|
2018-10-16 13:45:03 +03:00
|
|
|
|
2021-12-13 11:30:58 +03:00
|
|
|
// Read labels from file (e.x. AlexNet.labels)
|
2019-08-09 19:02:42 +03:00
|
|
|
std::string labelFileName = fileNameNoExt(FLAGS_m) + ".labels";
|
|
|
|
|
std::vector<std::string> labels;
|
|
|
|
|
|
|
|
|
|
std::ifstream inputFile;
|
|
|
|
|
inputFile.open(labelFileName, std::ios::in);
|
|
|
|
|
if (inputFile.is_open()) {
|
|
|
|
|
std::string strLine;
|
|
|
|
|
while (std::getline(inputFile, strLine)) {
|
|
|
|
|
trim(strLine);
|
|
|
|
|
labels.push_back(strLine);
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-23 22:47:35 +03:00
|
|
|
|
2021-04-15 13:42:46 +03:00
|
|
|
// Prints formatted classification results
|
2021-12-13 11:30:58 +03:00
|
|
|
ClassificationResult classificationResult(output, valid_image_names, batchSize, N_TOP_RESULTS, labels);
|
2021-10-23 22:47:35 +03:00
|
|
|
classificationResult.show();
|
2021-12-13 11:30:58 +03:00
|
|
|
} catch (const std::exception& ex) {
|
|
|
|
|
slog::err << ex.what() << slog::endl;
|
2021-10-23 22:47:35 +03:00
|
|
|
return EXIT_FAILURE;
|
2021-04-22 14:02:54 +03:00
|
|
|
} catch (...) {
|
2018-10-16 13:45:03 +03:00
|
|
|
slog::err << "Unknown/internal exception happened." << slog::endl;
|
2021-10-23 22:47:35 +03:00
|
|
|
return EXIT_FAILURE;
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|
|
|
|
|
|
2021-10-23 22:47:35 +03:00
|
|
|
return EXIT_SUCCESS;
|
2018-10-16 13:45:03 +03:00
|
|
|
}
|