// Copyright (C) 2018-2023 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // #include #include #include #include #include #include #include // clang-format off #include #include #include #include "utils.hpp" // clang-format on #ifdef JSON_HEADER # include #else # include #endif #ifdef USE_OPENCV # include #endif namespace benchmark_app { bool InputInfo::is_image() const { if ((layout != "NCHW") && (layout != "NHWC") && (layout != "CHW") && (layout != "HWC")) return false; // If data_shape is still empty, assume this is still an Image and tensor shape will be filled later return (dataShape.empty() || channels() == 3); } bool InputInfo::is_image_info() const { if (layout != "NC") return false; return (channels() >= 2); } size_t InputInfo::width() const { return dataShape.at(ov::layout::width_idx(layout)); } size_t InputInfo::height() const { return dataShape.at(ov::layout::height_idx(layout)); } size_t InputInfo::channels() const { return dataShape.at(ov::layout::channels_idx(layout)); } size_t InputInfo::batch() const { return dataShape.at(ov::layout::batch_idx(layout)); } size_t InputInfo::depth() const { return dataShape.at(ov::layout::depth_idx(layout)); } } // namespace benchmark_app uint32_t device_default_device_duration_in_seconds(const std::string& device) { static const std::map deviceDefaultDurationInSeconds{{"CPU", 60}, {"GPU", 60}, {"UNKNOWN", 120}}; uint32_t duration = 0; for (const auto& deviceDurationInSeconds : deviceDefaultDurationInSeconds) { if (device.find(deviceDurationInSeconds.first) != std::string::npos) { duration = std::max(duration, deviceDurationInSeconds.second); } } if (duration == 0) { const auto unknownDeviceIt = find_if(deviceDefaultDurationInSeconds.begin(), deviceDefaultDurationInSeconds.end(), [](std::pair deviceDuration) { return deviceDuration.first == "UNKNOWN"; }); if (unknownDeviceIt == deviceDefaultDurationInSeconds.end()) { throw std::logic_error("UNKNOWN device was not found in the device duration list"); } duration = unknownDeviceIt->second; slog::warn << "Default duration " << duration << " seconds for unknown device '" << device << "' is used" << slog::endl; } return duration; } std::vector split(const std::string& s, char delim) { std::vector result; std::stringstream ss(s); std::string item; while (getline(ss, item, delim)) { result.push_back(item); } return result; } std::vector split_float(const std::string& s, char delim) { std::vector result; std::stringstream ss(s); std::string item; while (getline(ss, item, delim)) { result.push_back(std::stof(item)); } return result; } static const std::vector meta_plugins{"MULTI", "HETERO", "AUTO"}; bool is_virtual_device(const std::string& device_name) { return std::find(meta_plugins.begin(), meta_plugins.end(), device_name) != meta_plugins.end(); } bool is_virtual_device_found(const std::vector& device_names) { for (const auto& device_name : device_names) { if (is_virtual_device(device_name)) { return true; } } return false; } void update_device_properties_setting(const std::string& device_name, ov::AnyMap& config, std::pair device_property) { // overriding if property {key, value} is already existed in config["DEVICE_PROPERTIES"][device_name], // if not, insert this {key, value} into config["DEVICE_PROPERTIES"][device_name]. // check and create property {"DEVICE_PROPERTIES": ov::AnyMap{hw_device, ov::AnyMap{}}} if not exist in config if (config.find(ov::device::properties.name()) == config.end()) { config[ov::device::properties.name()] = ov::AnyMap{}; config[ov::device::properties.name()].as().insert({device_name, ov::AnyMap{device_property}}); return; } // because of legacy API 1.0. eg the config from JSON file. if (config[ov::device::properties.name()].is()) { config[ov::device::properties.name()] = config[ov::device::properties.name()].as(); } auto& device_properties = config[ov::device::properties.name()].as(); if (device_properties.find(device_name) == device_properties.end()) { device_properties.insert({device_name, ov::AnyMap{device_property}}); return; } // because of legacy API 1.0. eg the config from JSON file. if (device_properties[device_name].is()) { device_properties[device_name] = device_properties[device_name].as(); } auto& secondary_property = device_properties[device_name].as(); // overwrite if this config existed secondary_property.erase(device_property.first); secondary_property.insert(device_property); } std::vector parse_devices(const std::string& device_string) { std::string comma_separated_devices = device_string; auto colon = comma_separated_devices.find(":"); std::vector result; if (colon != std::string::npos) { auto target_device = comma_separated_devices.substr(0, colon); if (is_virtual_device(target_device)) { result.push_back(target_device); } auto bracket = comma_separated_devices.find("("); // e.g. in BATCH:GPU(4) comma_separated_devices = comma_separated_devices.substr(colon + 1, bracket - colon - 1); } auto devices = split(comma_separated_devices, ','); for (auto&& device : devices) { // e.g. in AUTO:-CPU,-GPU if (device.front() == '-') device.erase(device.begin()); result.push_back(device); } return result; } void parse_value_for_virtual_device(const std::string& device, std::map& values_string) { auto item_virtual = values_string.find(device); if (item_virtual != values_string.end() && values_string.size() > 1) { if (device == "MULTI") { // Remove the element that the key is virtual device MULTI // e.g. MULTI:xxx -nstreams 2 will set nstreams 2 to xxx. values_string.erase(item_virtual); } else if ((device == "AUTO") || (device == "HETERO")) { // Just keep the element that the key is virtual device AUTO/HETERO // e.g. AUTO:xxx,xxx -nstreams 2 will trigger exception that AUTO plugin didn't support nstream property. auto value = item_virtual->second; values_string.clear(); values_string[device] = value; return; } } std::stringstream ss; auto iter = values_string.begin(); while (iter != values_string.end()) { if (iter->first == device) { iter++; continue; } if (ss.str().empty()) ss << '{'; else ss << ','; ss << iter->first << ":" << iter->second; iter = values_string.erase(iter); } if (!ss.str().empty()) { ss << '}'; values_string[device] = ss.str(); } return; } template void update_device_config_for_virtual_device(const std::string& value, ov::AnyMap& device_config, ov::Property property) { // check if the element contains the hardware device property if (split(value, ':').size() == 1) { device_config[property.name()] = value; } else { // set device nstreams properties in the AUTO/MULTI/HETERO plugin std::stringstream strm(value); std::map devices_property; ov::util::Read>{}(strm, devices_property); for (const auto& it : devices_property) { const auto& device_name = it.first; const auto& device_value = it.second; update_device_properties_setting(device_name, device_config, property(device_value)); } } } void update_device_config_for_virtual_device(const std::string& value, ov::AnyMap& device_config, ov::Property property) { return update_device_config_for_virtual_device(value, device_config, property); } void update_device_config_for_virtual_device(const std::string& value, ov::AnyMap& device_config, ov::Property property) { return update_device_config_for_virtual_device(value, device_config, property); } std::map parse_value_per_device(const std::vector& devices, const std::string& values_string) { // Format: :,: or just std::map result; auto device_value_strings = split(values_string, ','); for (auto& device_value_string : device_value_strings) { auto device_value_vec = split(device_value_string, ':'); if (device_value_vec.size() == 2) { auto device_name = device_value_vec.at(0); auto value = device_value_vec.at(1); auto it = std::find(devices.begin(), devices.end(), device_name); if (it != devices.end()) { result[device_name] = value; } else { std::string devices_list = ""; for (auto& device : devices) devices_list += device + " "; devices_list.pop_back(); throw std::logic_error("Failed to set property to '" + device_name + "' which is not found whthin the target devices list '" + devices_list + "'!"); } } else if (device_value_vec.size() == 1) { auto value = device_value_vec.at(0); for (auto& device : devices) { result[device] = value; } } else if (device_value_vec.size() != 0) { throw std::runtime_error("Unknown string format: " + values_string); } } return result; } size_t get_batch_size(const benchmark_app::InputsInfo& inputs_info) { size_t batch_size = 0; for (auto& info : inputs_info) { if (ov::layout::has_batch(info.second.layout)) { if (batch_size == 0) batch_size = info.second.batch(); else if (batch_size != info.second.batch()) throw std::logic_error("Can't deterimine batch size: batch is " "different for different inputs!"); } } if (batch_size == 0) { batch_size = 1; } return batch_size; } std::string get_shapes_string(const benchmark_app::PartialShapes& shapes) { std::stringstream ss; for (auto& shape : shapes) { if (!ss.str().empty()) ss << ", "; ss << "\'" << shape.first << "': " << shape.second; } return ss.str(); } std::map> parse_scale_or_mean(const std::string& scale_mean, const benchmark_app::InputsInfo& inputs_info) { // Format: data[255,255,255],info[255,255,255] std::map> return_value; std::string search_string = scale_mean; auto start_pos = search_string.find_first_of('['); while (start_pos != std::string::npos) { auto end_pos = search_string.find_first_of(']'); if (end_pos == std::string::npos) break; auto input_name = search_string.substr(0, start_pos); auto input_value_string = search_string.substr(start_pos + 1, end_pos - start_pos - 1); auto input_value = split_float(input_value_string, ','); if (!input_name.empty()) { if (inputs_info.count(input_name)) { return_value[input_name] = input_value; } // ignore wrong input name } else { for (auto& item : inputs_info) { if (item.second.is_image()) return_value[item.first] = input_value; } search_string.clear(); break; } search_string = search_string.substr(end_pos + 1); if (search_string.empty() || search_string.front() != ',') break; search_string = search_string.substr(1); start_pos = search_string.find_first_of('['); } if (!search_string.empty()) throw std::logic_error("Can't parse input parameter string: " + scale_mean); return return_value; } std::pair> parse_input_files(const std::string& file_paths_string) { auto search_string = file_paths_string; std::string input_name = ""; std::vector file_paths; // parse strings like :file1,file2,file3 and get name from them size_t semicolon_pos = search_string.find_first_of(":"); size_t quote_pos = search_string.find_first_of("\""); if (semicolon_pos != std::string::npos && quote_pos != std::string::npos && semicolon_pos > quote_pos) { // if : is found after opening " symbol - this means that " belongs to pathname semicolon_pos = std::string::npos; } if (search_string.length() > 2 && semicolon_pos == 1 && search_string[2] == '\\') { // Special case like C:\ denotes drive name, not an input name semicolon_pos = std::string::npos; } if (semicolon_pos != std::string::npos) { input_name = search_string.substr(0, semicolon_pos); search_string = search_string.substr(semicolon_pos + 1); } // parse file1,file2,file3 and get vector of paths size_t coma_pos = 0; do { coma_pos = search_string.find_first_of(','); file_paths.push_back(search_string.substr(0, coma_pos)); if (coma_pos == std::string::npos) { search_string = ""; break; } search_string = search_string.substr(coma_pos + 1); } while (coma_pos != std::string::npos); if (!search_string.empty()) throw std::logic_error("Can't parse file paths for input " + input_name + " in input parameter string: " + file_paths_string); return {input_name, file_paths}; } std::map> parse_input_arguments(const std::vector& args) { std::map> mapped_files = {}; auto args_it = begin(args); const auto is_image_arg = [](const std::string& s) { return s == "-i"; }; const auto is_arg = [](const std::string& s) { return s.front() == '-'; }; while (args_it != args.end()) { const auto files_start = std::find_if(args_it, end(args), is_image_arg); if (files_start == end(args)) { break; } const auto files_begin = std::next(files_start); const auto files_end = std::find_if(files_begin, end(args), is_arg); for (auto f = files_begin; f != files_end; ++f) { auto files = parse_input_files(*f); if (mapped_files.find(files.first) == mapped_files.end()) { mapped_files[files.first] = {}; } for (auto& file : files.second) { if (file == "image_info" || file == "random") { mapped_files[files.first].push_back(file); } else { readInputFilesArguments(mapped_files[files.first], file); } } } args_it = files_end; } size_t max_files = 20; for (auto& files : mapped_files) { if (files.second.size() <= max_files) { slog::info << "For input " << files.first << " " << files.second.size() << " files were added. " << slog::endl; } else { slog::info << "For input " << files.first << " " << files.second.size() << " files were added. " << " The number of files will be limited to " << max_files << "." << slog::endl; files.second.resize(20); } } return mapped_files; } std::map> parse_input_parameters( const std::string& parameter_string, const std::vector>& input_info) { // Parse parameter string like "input0[value0],input1[value1]" or "[value]" (applied to all // inputs) std::map> return_value; std::string search_string = parameter_string; auto start_pos = search_string.find_first_of('['); auto input_name = search_string.substr(0, start_pos); while (start_pos != std::string::npos) { auto end_pos = search_string.find_first_of(']'); if (end_pos == std::string::npos) break; if (start_pos) input_name = search_string.substr(0, start_pos); auto input_value = search_string.substr(start_pos + 1, end_pos - start_pos - 1); if (!input_name.empty()) { return_value[parameter_name_to_tensor_name(input_name, input_info)].push_back(input_value); } else { for (auto& item : input_info) { return_value[item.get_any_name()].push_back(input_value); } } search_string = search_string.substr(end_pos + 1); if (search_string.empty() || (search_string.front() != ',' && search_string.front() != '[')) break; if (search_string.front() == ',') search_string = search_string.substr(1); start_pos = search_string.find_first_of('['); } if (!search_string.empty()) throw std::logic_error("Can't parse input parameter string: " + parameter_string); return return_value; } std::vector get_inputs_info(const std::string& shape_string, const std::string& layout_string, const size_t batch_size, const std::string& data_shapes_string, const std::map>& fileNames, const std::string& scale_string, const std::string& mean_string, const std::vector>& input_info, bool& reshape_required) { std::map> shape_map = parse_input_parameters(shape_string, input_info); std::map> data_shapes_map = parse_input_parameters(data_shapes_string, input_info); std::map> layout_map = parse_input_parameters(layout_string, input_info); size_t min_size = 1, max_size = 1; if (!data_shapes_map.empty()) { min_size = std::min_element(data_shapes_map.begin(), data_shapes_map.end(), [](std::pair> a, std::pair> b) { return a.second.size() < b.second.size() && a.second.size() != 1; }) ->second.size(); max_size = std::max_element(data_shapes_map.begin(), data_shapes_map.end(), [](std::pair> a, std::pair> b) { return a.second.size() < b.second.size(); }) ->second.size(); if (min_size != max_size) { throw std::logic_error( "Shapes number for every input should be either 1 or should be equal to shapes number of other inputs"); } slog::info << "Number of test configurations is calculated basing on -data_shape parameter" << slog::endl; } else if (fileNames.size() > 0) { slog::info << "Number of test configurations is calculated basing on number of input images" << slog::endl; min_size = std::min_element(fileNames.begin(), fileNames.end(), [](std::pair> a, std::pair> b) { return a.second.size() < b.second.size() && a.second.size() != 1; }) ->second.size(); max_size = std::max_element(fileNames.begin(), fileNames.end(), [](std::pair> a, std::pair> b) { return a.second.size() < b.second.size(); }) ->second.size(); if (min_size != max_size) { slog::warn << "Number of input files is different for some inputs, minimal number of files will be used (" << min_size << ")" << slog::endl; } } reshape_required = false; std::map currentFileCounters; for (auto& item : input_info) { currentFileCounters[item.get_any_name()] = 0; } std::vector info_maps; for (size_t input_id = 0; input_id < min_size; ++input_id) { benchmark_app::InputsInfo info_map; bool is_there_at_least_one_batch_dim = false; for (auto& item : input_info) { benchmark_app::InputInfo info; auto name = item.get_any_name(); // Layout if (layout_map.count(name)) { if (layout_map.at(name).size() > 1) { throw std::logic_error( "layout command line parameter doesn't support multiple layouts for one input."); } info.layout = ov::Layout(layout_map.at(name)[0]); } else { info.layout = dynamic_cast(*item.get_node()).get_layout(); } // Calculating default layout values if needed std::string newLayout = ""; if (info.layout.empty()) { switch (item.get_partial_shape().size()) { case 3: newLayout = (item.get_partial_shape()[2].get_max_length() <= 4 && item.get_partial_shape()[0].get_max_length() > 4) ? "HWC" : "CHW"; break; case 4: // Rough check for layout type, basing on max number of image channels newLayout = (item.get_partial_shape()[3].get_max_length() <= 4 && item.get_partial_shape()[1].get_max_length() > 4) ? "NHWC" : "NCHW"; break; } if (newLayout != "") { info.layout = ov::Layout(newLayout); } if (info_maps.empty()) { // Show warnings only for 1st test case config, as for other test cases // they will be the same slog::warn << item.get_any_name() << ": layout is not set explicitly" << (newLayout != "" ? std::string(", so it is defaulted to ") + newLayout : "") << ". It is STRONGLY recommended to set layout manually to avoid further issues." << slog::endl; } } // Precision info.type = item.get_element_type(); // Partial Shape if (shape_map.count(name)) { if (shape_map.at(name).size() > 1) { throw std::logic_error( "shape command line parameter doesn't support multiple shapes for one input."); } info.partialShape = shape_map.at(name)[0]; reshape_required = true; } else { info.partialShape = item.get_partial_shape(); } // Files might be mapped without input name. In case of only one input we may map them to the only input // directly std::string filesInputName = fileNames.size() == 1 && input_info.size() == 1 && fileNames.begin()->first == "" ? "" : name; // Tensor Shape if (info.partialShape.is_dynamic() && data_shapes_map.count(name)) { info.dataShape = data_shapes_map.at(name)[input_id % data_shapes_map.at(name).size()]; } else if (info.partialShape.is_dynamic() && fileNames.count(filesInputName) && info.is_image()) { auto& namesVector = fileNames.at(filesInputName); if (contains_binaries(namesVector)) { throw std::logic_error("Input files list for input " + item.get_any_name() + " contains binary file(s) and input shape is dynamic. Tensor shape should " "be defined explicitly (using -data_shape)."); } info.dataShape = ov::Shape(info.partialShape.size(), 0); for (size_t i = 0; i < info.partialShape.size(); i++) { auto& dim = info.partialShape[i]; if (dim.is_static()) { info.dataShape[i] = dim.get_length(); } } size_t tensorBatchSize = std::max(batch_size, (size_t)1); if (ov::layout::has_batch(info.layout)) { if (info.batch()) { tensorBatchSize = std::max(tensorBatchSize, info.batch()); } else { info.dataShape[ov::layout::batch_idx(info.layout)] = tensorBatchSize; } } size_t h = 0; size_t w = 0; std::vector shape; size_t fileIdx = currentFileCounters[item.get_any_name()]; for (; fileIdx < currentFileCounters[item.get_any_name()] + tensorBatchSize; fileIdx++) { if (fileIdx >= namesVector.size()) { throw std::logic_error( "Not enough files to fill in full batch (number of files should be a multiple of batch " "size if -data_shape parameter is omitted and shape is dynamic)"); } FormatReader::ReaderPtr reader(namesVector[fileIdx].c_str()); if ((w && w != reader->width()) || (h && h != reader->height()) || (!shape.empty() && shape != reader->shape())) { throw std::logic_error( "File dimensions putting into one batch should be of the same dimensionality if input " "shape is dynamic and -data_shape is omitted. Problem file: " + namesVector[fileIdx]); } h = reader->height(); w = reader->width(); shape = reader->shape(); } currentFileCounters[item.get_any_name()] = fileIdx; if (shape.size() == 2) { // Has only h and w if (!info.dataShape[ov::layout::height_idx(info.layout)]) { info.dataShape[ov::layout::height_idx(info.layout)] = h; } if (!info.dataShape[ov::layout::width_idx(info.layout)]) { info.dataShape[ov::layout::width_idx(info.layout)] = w; } } else { // Is numpy array size_t shape_idx = 0; if (info.dataShape.size() != shape.size()) { throw std::logic_error("Shape required by the input and file shape do not have the same rank. " "Input: " + item.get_any_name() + ", File name: " + namesVector[fileIdx - 1]); } for (size_t i = ov::layout::batch_idx(info.layout); i < ov::layout::batch_idx(info.layout) + info.dataShape.size(); ++i) { if (!info.dataShape[i]) { info.dataShape[i] = shape.at(shape_idx); } shape_idx++; } } if (std::any_of(info.dataShape.begin(), info.dataShape.end(), [](size_t d) { return d == 0; })) { throw std::logic_error("Not enough information in shape and file to determine tensor shape " "autmatically. Input: " + item.get_any_name() + ", File name: " + namesVector[fileIdx - 1]); } } else if (info.partialShape.is_static()) { info.dataShape = info.partialShape.get_shape(); if (data_shapes_map.find(name) != data_shapes_map.end()) { throw std::logic_error( "Model's input \"" + name + "\" is static. Use -shape argument for static inputs instead of -data_shape."); } } else if (!data_shapes_map.empty()) { throw std::logic_error("Can't find model input name \"" + name + "\" in \"-data_shape " + data_shapes_string + "\" command line parameter"); } else { throw std::logic_error("-i or -data_shape command line parameter should be set for all inputs in case " "of model with dynamic shapes."); } // Update shape with batch if needed (only in static shape case) // Update blob shape only not affecting network shape to trigger dynamic batch size case if (batch_size != 0) { if (ov::layout::has_batch(info.layout)) { std::size_t batch_index = ov::layout::batch_idx(info.layout); if (info.dataShape.at(batch_index) != batch_size) { if (info.partialShape.is_static()) { info.partialShape[batch_index] = batch_size; } info.dataShape[batch_index] = batch_size; reshape_required = true; is_there_at_least_one_batch_dim = true; } } else { slog::warn << "Input '" << item.get_any_name() << "' doesn't have batch dimension in layout. -b option will be ignored for this input." << slog::endl; } } info_map[name] = info; } if (batch_size > 1 && !is_there_at_least_one_batch_dim) { throw std::runtime_error("-b option is provided in command line, but there's no inputs with batch(B) " "dimension in input layout, so batch cannot be set. " "You may specify layout explicitly using -layout option."); } // Update scale and mean std::map> scale_map = parse_scale_or_mean(scale_string, info_map); std::map> mean_map = parse_scale_or_mean(mean_string, info_map); for (auto& item : info_map) { if (item.second.is_image()) { if (scale_map.count(item.first)) { item.second.scale = scale_map.at(item.first); } if (mean_map.count(item.first)) { item.second.mean = mean_map.at(item.first); } } } info_maps.push_back(info_map); } return info_maps; } std::vector get_inputs_info(const std::string& shape_string, const std::string& layout_string, const size_t batch_size, const std::string& tensors_shape_string, const std::map>& fileNames, const std::string& scale_string, const std::string& mean_string, const std::vector>& input_info) { bool reshape_required = false; return get_inputs_info(shape_string, layout_string, batch_size, tensors_shape_string, fileNames, scale_string, mean_string, input_info, reshape_required); } void dump_config(const std::string& filename, const std::map& config) { nlohmann::json jsonConfig; for (const auto& item : config) { std::string deviceName = item.first; for (const auto& option : item.second) { // primary property std::stringstream strm; option.second.print(strm); auto property_string = strm.str(); jsonConfig[deviceName][option.first] = property_string; } } std::ofstream ofs(filename); if (!ofs.is_open()) { throw std::runtime_error("Can't load config file \"" + filename + "\"."); } ofs << jsonConfig; } void load_config(const std::string& filename, std::map& config) { std::ifstream ifs(filename); if (!ifs.is_open()) { throw std::runtime_error("Can't load config file \"" + filename + "\"."); } nlohmann::json jsonConfig; try { ifs >> jsonConfig; } catch (const std::exception& e) { throw std::runtime_error("Can't parse config file \"" + filename + "\".\n" + e.what()); } for (auto item = jsonConfig.cbegin(), end = jsonConfig.cend(); item != end; ++item) { const std::string& deviceName = item.key(); const auto& itemValue = item.value(); for (auto option = itemValue.cbegin(), itemValueEnd = itemValue.cend(); option != itemValueEnd; ++option) { config[deviceName][option.key()] = option.value().get(); } } } std::string get_extension(const std::string& name) { auto extensionPosition = name.rfind('.', name.size()); return extensionPosition == std::string::npos ? "" : name.substr(extensionPosition + 1, name.size() - 1); }; bool is_binary_file(const std::string& filePath) { auto extension = get_extension(filePath); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); return supported_binary_extensions.find(extension) != supported_binary_extensions.end(); } bool is_numpy_file(const std::string& filePath) { auto extension = get_extension(filePath); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); return supported_numpy_extensions.find(extension) != supported_numpy_extensions.end(); } bool is_image_file(const std::string& filePath) { auto extension = get_extension(filePath); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); return supported_image_extensions.find(extension) != supported_image_extensions.end(); } bool contains_binaries(const std::vector& filePaths) { std::vector filtered; for (auto& filePath : filePaths) { if (is_binary_file(filePath)) { return true; } } return false; } std::vector filter_files_by_extensions(const std::vector& filePaths, const std::unordered_set& extensions) { std::vector filtered; for (auto& filePath : filePaths) { auto extension = get_extension(filePath); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); if (extensions.find(extension) != extensions.end()) { filtered.push_back(filePath); } } return filtered; } std::string parameter_name_to_tensor_name(const std::string& name, const std::vector>& inputs_info, const std::vector>& outputs_info) { if (std::any_of(inputs_info.begin(), inputs_info.end(), [name](const ov::Output& port) { try { return port.get_names().count(name) > 0; } catch (const ov::Exception&) { return false; // Some ports might have no names - so this is workaround } })) { return name; } else if (std::any_of(outputs_info.begin(), outputs_info.end(), [name](const ov::Output& port) { try { return port.get_names().count(name) > 0; } catch (const ov::Exception&) { return false; // Some ports might have no names - so this is workaround } })) { return name; } else { for (const auto& port : inputs_info) { if (name == port.get_node()->get_friendly_name()) { return port.get_any_name(); } } for (const auto& port : outputs_info) { if (name == port.get_node()->get_input_node_ptr(0)->get_friendly_name()) { return port.get_any_name(); } } } throw std::runtime_error("Provided I/O name \"" + name + "\" is not found neither in tensor names nor in nodes names."); }