From fc5a416423dff36a0642ea36c532319d46032c92 Mon Sep 17 00:00:00 2001 From: Nadezhda Ageeva Date: Wed, 16 Feb 2022 13:23:50 +0300 Subject: [PATCH] [SAMPLES][GNA] Update C++ speech sample with new config API (#10357) * [SAMPLES][GNA] Update speech sample with new cofig API * Review comments * Some additional checks --- samples/cpp/speech_sample/main.cpp | 57 ++++---- samples/cpp/speech_sample/speech_sample.hpp | 3 +- samples/cpp/speech_sample/utils.hpp | 125 +++++++++++++++--- .../smoke_tests/test_speech_sample.py | 2 + 4 files changed, 138 insertions(+), 49 deletions(-) diff --git a/samples/cpp/speech_sample/main.cpp b/samples/cpp/speech_sample/main.cpp index 1b4a57fdec2..0389a412cae 100644 --- a/samples/cpp/speech_sample/main.cpp +++ b/samples/cpp/speech_sample/main.cpp @@ -19,7 +19,7 @@ // clang-format off #include -#include +#include #include #include @@ -141,8 +141,15 @@ int main(int argc, char* argv[]) { if (useGna) { std::string gnaDevice = useHetero ? FLAGS_d.substr(FLAGS_d.find("GNA"), FLAGS_d.find(",") - FLAGS_d.find("GNA")) : FLAGS_d; - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_DEVICE_MODE] = - gnaDevice.find("_") == std::string::npos ? "GNA_AUTO" : gnaDevice; + auto parse_gna_device = [&](const std::string& device) -> ov::intel_gna::ExecutionMode { + ov::intel_gna::ExecutionMode mode; + std::stringstream ss(device); + ss >> mode; + return mode; + }; + gnaPluginConfig[ov::intel_gna::execution_mode.name()] = gnaDevice.find("_") == std::string::npos + ? ov::intel_gna::ExecutionMode::AUTO + : parse_gna_device(gnaDevice); } if (FLAGS_pc) { genericPluginConfig.emplace(ov::enable_profiling(true)); @@ -151,23 +158,23 @@ int main(int argc, char* argv[]) { if (!FLAGS_rg.empty()) { slog::warn << "Custom scale factor will be used for imported gna model: " << FLAGS_rg << slog::endl; } - auto scaleFactorInput = parse_scale_factors(FLAGS_sf); - if (numInputFiles != scaleFactorInput.size()) { + auto scale_factors_per_input = parse_scale_factors(model->inputs(), FLAGS_sf); + if (numInputFiles != scale_factors_per_input.size()) { std::string errMessage( - "Incorrect command line for multiple inputs: " + std::to_string(scaleFactorInput.size()) + + "Incorrect command line for multiple inputs: " + std::to_string(scale_factors_per_input.size()) + " scale factors provided for " + std::to_string(numInputFiles) + " input files."); throw std::logic_error(errMessage); } - for (size_t i = 0; i < scaleFactorInput.size(); ++i) { - slog::info << "For input " << i << " using scale factor of " << scaleFactorInput[i] << slog::endl; - std::string scaleFactorConfigKey = GNA_CONFIG_KEY(SCALE_FACTOR) + std::string("_") + std::to_string(i); - gnaPluginConfig[scaleFactorConfigKey] = scaleFactorInput[i]; + for (auto&& sf : scale_factors_per_input) { + slog::info << "For input " << sf.first << " using scale factor of " << sf.second << slog::endl; } + gnaPluginConfig[ov::intel_gna::scale_factors_per_input.name()] = scale_factors_per_input; } else { // "static" quantization with calculated scale factor if (!FLAGS_rg.empty()) { slog::info << "Using scale factor from provided imported gna model: " << FLAGS_rg << slog::endl; } else { + std::map scale_factors_per_input; for (size_t i = 0; i < numInputFiles; i++) { auto inputFileName = inputFiles[i].c_str(); std::string name; @@ -187,30 +194,26 @@ int main(int argc, char* argv[]) { numFrames * numFrameElements); slog::info << "Using scale factor of " << floatScaleFactor << " calculated from first utterance." << slog::endl; - std::string scaleFactorConfigKey = - GNA_CONFIG_KEY(SCALE_FACTOR) + std::string("_") + std::to_string(i); - gnaPluginConfig[scaleFactorConfigKey] = std::to_string(floatScaleFactor); + scale_factors_per_input[model->input(i).get_any_name()] = floatScaleFactor; } + gnaPluginConfig[ov::intel_gna::scale_factors_per_input.name()] = scale_factors_per_input; } } - if (FLAGS_qb == 8) { - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_PRECISION] = "I8"; - } else { - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_PRECISION] = "I16"; - } - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_EXEC_TARGET] = FLAGS_exec_target; - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_COMPILE_TARGET] = FLAGS_compile_target; - gnaPluginConfig[GNA_CONFIG_KEY(COMPACT_MODE)] = CONFIG_VALUE(NO); - IE_SUPPRESS_DEPRECATED_START - gnaPluginConfig[GNA_CONFIG_KEY(PWL_MAX_ERROR_PERCENT)] = std::to_string(FLAGS_pwl_me); - IE_SUPPRESS_DEPRECATED_END + gnaPluginConfig[ov::hint::inference_precision.name()] = (FLAGS_qb == 8) ? ov::element::i8 : ov::element::i16; + auto parse_target = [&](const std::string& target) -> ov::intel_gna::HWGeneration { + return (target == "GNA_TARGET_2_0") ? ov::intel_gna::HWGeneration::GNA_2_0 + : (target == "GNA_TARGET_3_0") ? ov::intel_gna::HWGeneration::GNA_3_0 + : ov::intel_gna::HWGeneration::UNDEFINED; + }; + gnaPluginConfig[ov::intel_gna::execution_target.name()] = parse_target(FLAGS_exec_target); + gnaPluginConfig[ov::intel_gna::compile_target.name()] = parse_target(FLAGS_compile_target); + gnaPluginConfig[ov::intel_gna::memory_reuse.name()] = false; + gnaPluginConfig[ov::intel_gna::pwl_max_error_percent.name()] = FLAGS_pwl_me; // ----------------------------------------------------------------------------------------------------- // --------------------------- Write model to file -------------------------------------------------- // Embedded GNA model dumping (for Intel(R) Speech Enabling Developer Kit) if (!FLAGS_we.empty()) { - IE_SUPPRESS_DEPRECATED_START - gnaPluginConfig[InferenceEngine::GNAConfigParams::KEY_GNA_FIRMWARE_MODEL_IMAGE] = FLAGS_we; - IE_SUPPRESS_DEPRECATED_END + gnaPluginConfig[ov::intel_gna::firmware_model_image_path.name()] = FLAGS_we; } // ----------------------------------------------------------------------------------------------------- // --------------------------- Step 2. Loading model to the device ------------------------------------------ diff --git a/samples/cpp/speech_sample/speech_sample.hpp b/samples/cpp/speech_sample/speech_sample.hpp index c0e5e96f3e2..90322c89d68 100644 --- a/samples/cpp/speech_sample/speech_sample.hpp +++ b/samples/cpp/speech_sample/speech_sample.hpp @@ -90,7 +90,8 @@ static const char quantization_bits_message[] = "Optional. Weight bits for quant static const char scale_factor_message[] = "Optional. User-specified input scale factor for quantization (use with -q user). " "If the network contains multiple inputs, provide scale factors by separating them with " - "commas."; + "commas. " + "For example: :,: or just to be applied to all inputs"; /// @brief message for batch size argument static const char batch_size_message[] = "Optional. Batch size 1-8 (default 1)"; diff --git a/samples/cpp/speech_sample/utils.hpp b/samples/cpp/speech_sample/utils.hpp index ee17953e2b1..f49f2827dff 100644 --- a/samples/cpp/speech_sample/utils.hpp +++ b/samples/cpp/speech_sample/utils.hpp @@ -361,30 +361,113 @@ void sum_performance_counters(std::map const& pe } /** - * @brief Parse scale factors - * @param str reference to user-specified input scale factor for quantization, can be separated by comma - * @return vector scale factors + * @brief Split string by delimeter + * @param s input string + * @param delim delimeter + * @return vector of chunks */ -std::vector parse_scale_factors(const std::string& str) { - std::vector scaleFactorInput; +std::vector split(const std::string& s, char delim) { + std::vector result; + std::stringstream ss(s); + std::string item; - if (!str.empty()) { - std::string outStr; - std::istringstream stream(str); - int i = 0; - while (getline(stream, outStr, ',')) { - auto floatScaleFactor = std::stof(outStr); - if (floatScaleFactor <= 0.0f) { - throw std::logic_error("Scale factor for input #" + std::to_string(i) + - " (counting from zero) is out of range (must be positive)."); - } - scaleFactorInput.push_back(outStr); - i++; - } - } else { - throw std::logic_error("Scale factor need to be specified via -sf option if you are using -q user"); + while (getline(ss, item, delim)) { + result.push_back(item); } - return scaleFactorInput; + return result; +} + +/** + * @brief Concat strings using delimeter + * @param chunks input chunks + * @param delim delimeter + * @return concatenated string + */ +std::string concat(const std::vector& chunks, char delim) { + std::stringstream ss; + for (auto&& chunk : chunks) { + if (!ss.str().empty()) { + ss << delim; + } + ss << chunk; + } + return ss.str(); +} + +/** + * @brief Check whether name is present in node vector + * @param nodes nodes + * @param node_name name + * @return false or true + */ +bool check_name(const ov::OutputVector& nodes, const std::string& node_name) { + std::vector any_names; + bool count = false; + for (auto& node : nodes) { + any_names.push_back(node.get_any_name()); + auto names = node.get_names(); + count = std::count(names.begin(), names.end(), node_name); + if (count) + break; + } + if (!count) { + std::stringstream ss; + ss << "Incorrect node name '" + node_name << "'! "; + ss << "Try one of the following names: [ "; + for (auto&& name : any_names) { + ss << name << " "; + } + ss << "]"; + throw std::logic_error(ss.str()); + } + return count; +} + +/** + * @brief Parse scale factors per input + * Format : :,: or just + * @param inputs model inputs + * @param values_string values_string input string + * @return map of scale factors per input + */ +std::map parse_scale_factors(const ov::OutputVector& inputs, const std::string& values_string) { + auto get_sf = [&](const std::string& sf_string, const std::string& input_name = "") -> float { + float sf; + try { + sf = std::stof(sf_string); + } catch (...) { + throw std::logic_error("Can't get float scale factor from: " + sf_string); + } + if (sf <= 0.0f) { + throw std::logic_error("Scale factor for input '" + input_name + + "' (counting from zero) is out of range (must be positive)."); + } + return sf; + }; + std::map result; + auto scale_factor_strings = split(values_string, ','); + for (auto& scale_factor_string : scale_factor_strings) { + auto values = split(scale_factor_string, ':'); + if (values.size() == 1) { + if (scale_factor_strings.size() != 1) { + throw std::logic_error("Unrecognized scale factor format! " + "Please specify :,: or " + "just to be applied to all inputs"); + } + auto scale_factor = get_sf(values.at(0)); + for (auto& input : inputs) { + result[input.get_any_name()] = scale_factor; + } + } else if (values.size() > 0) { + auto sf_sting = values.back(); + values.pop_back(); + // input name can contain port, concat back + auto input_name = concat(values, ':'); + check_name(inputs, input_name); + result[input_name] = get_sf(sf_sting, input_name); + } + } + return result; } /** diff --git a/tests/samples_tests/smoke_tests/test_speech_sample.py b/tests/samples_tests/smoke_tests/test_speech_sample.py index 2e5106847d6..840e1541c72 100644 --- a/tests/samples_tests/smoke_tests/test_speech_sample.py +++ b/tests/samples_tests/smoke_tests/test_speech_sample.py @@ -26,6 +26,8 @@ test_data = get_tests(cmd_params={'i': [os.path.join('ark', 'dev93_10.ark')], 'o': ['res_output.ark'], 'r': [os.path.join('ark', 'dev93_scores_10.ark')], 'qb': [8, 16], + 'sf': ["Parameter:2175.43", "2175.43"], + 'q': ["static", "user"], 'd': ['GNA_SW_EXACT']}, use_device=False )