replace benchmark_app imean and iscale parameters (#14621)

* replace benchmark_app imean and iscale parameters

Tickets 80777 and 80900

* Warn about difference with imean and iscale, note that in help

* Clang format

* Clang format

* mean->scale

* Keep mean scale empty if not set

Co-authored-by: Andrei Kochin <andrei.kochin@intel.com>
This commit is contained in:
Zlobin Vladimir
2022-12-19 09:27:39 +04:00
committed by GitHub
parent 05159b8cfb
commit 787ba3de4f
11 changed files with 120 additions and 63 deletions

View File

@@ -183,14 +183,8 @@ Options:
Example: -iop "input:FP16, output:FP16".
Notice that quotes are required.
Overwrites precision from ip and op options for specified layers.
-iscale Optional. Scale values to be used for the input image per channel.
Values to be provided in the [R, G, B] format. Can be defined for desired input of the model.
Example: -iscale data[255,255,255],info[255,255,255]
-imean Optional. Mean values to be used for the input image per channel.
Values to be provided in the [R, G, B] format. Can be defined for desired input of the model,
Example: -imean data[255,255,255],info[255,255,255]
-mean_values [R,G,B] Optional. Mean values to be used for the input image per channel. Values to be provided in the [R,G,B] format. Can be defined for desired input of the model, for example: "--mean_values data[255,255,255],info[255,255,255]". The exact meaning and order of channels depend on how the original model was trained. Applying the values affects performance and may cause type conversion
-scale_values [R,G,B] Optional. Scale values to be used for the input image per channel. Values are provided in the [R,G,B] format. Can be defined for desired input of the model, for example: "--scale_values data[255,255,255],info[255,255,255]". The exact meaning and order of channels depend on how the original model was trained. If both --mean_values and --scale_values are specified, the mean is subtracted first and then scale is applied regardless of the order of options in command line. Applying the values affects performance and may cause type conversion
-inference_only Optional. Measure only inference stage. Default option for static models. Dynamic models are measured in full mode which includes inputs setup stage, inference only mode available for them with single input data shape only. To enable full mode for static models pass "false" value to this argument: ex. "-inference_only=false".
```

View File

@@ -244,10 +244,18 @@ static constexpr char input_image_scale_message[] =
"Values to be provided in the [R, G, B] format. Can be defined for desired input of the model.\n"
"Example: -iscale data[255,255,255],info[255,255,255]\n";
static constexpr char input_image_mean_message[] =
"Optional. Mean values to be used for the input image per channel.\n"
"Values to be provided in the [R, G, B] format. Can be defined for desired input of the model,\n"
"Example: -imean data[255,255,255],info[255,255,255]\n";
static constexpr char mean_values_message[] =
"Optional. Mean values to be used for the input image per channel. Values to be provided in the [R,G,B] format. "
"Can be defined for desired input of the model, for example: \"--mean_values "
"data[255,255,255],info[255,255,255]\". The exact meaning and order of channels depend on how the original model "
"was trained. Applying the values affects performance and may cause type conversion";
static constexpr char scale_values_message[] =
"Optional. Scale values to be used for the input image per channel. Values are provided in the [R,G,B] format. Can "
"be defined for desired input of the model, for example: \"--scale_values data[255,255,255],info[255,255,255]\". "
"The exact meaning and order of channels depend on how the original model was trained. If both --mean_values and "
"--scale_values are specified, the mean is subtracted first and then scale is applied regardless of the order of "
"options in command line. Applying the values affects performance and may cause type conversion";
static constexpr char inference_only_message[] =
"Optional. Measure only inference stage. Default option for static models. Dynamic models"
@@ -377,11 +385,11 @@ DEFINE_string(cache_dir, "", cache_dir_message);
/// @brief Define flag for load network from model file by name without ReadNetwork <br>
DEFINE_bool(load_from_file, false, load_from_file_message);
/// @brief Define flag for using input image scale <br>
DEFINE_string(iscale, "", input_image_scale_message);
/// @brief Define flag for using input image mean <br>
DEFINE_string(imean, "", input_image_mean_message);
DEFINE_string(mean_values, "", mean_values_message);
/// @brief Define flag for using input image scale <br>
DEFINE_string(scale_values, "", scale_values_message);
/// @brief Define flag for inference only mode <br>
DEFINE_bool(inference_only, true, inference_only_message);
@@ -435,7 +443,7 @@ static void show_usage() {
std::cout << " -ip <value> " << inputs_precision_message << std::endl;
std::cout << " -op <value> " << outputs_precision_message << std::endl;
std::cout << " -iop \"<value>\" " << iop_message << std::endl;
std::cout << " -iscale " << input_image_scale_message << std::endl;
std::cout << " -imean " << input_image_mean_message << std::endl;
std::cout << " -mean_values [R,G,B] " << mean_values_message << std::endl;
std::cout << " -scale_values [R,G,B] " << scale_values_message << std::endl;
std::cout << " -inference_only " << inference_only_message << std::endl;
}

View File

@@ -43,7 +43,7 @@ ov::Tensor create_tensor_from_image(const std::vector<std::string>& files,
if (!inputInfo.layout.empty() && ov::layout::has_batch(inputInfo.layout)) {
imgBatchSize = batchSize;
} else {
slog::warn << inputName << ": layout does not contain batch dimension. Assuming bath 1 for this input"
slog::warn << inputName << ": layout does not contain batch dimension. Assuming batch 1 for this input"
<< slog::endl;
}
@@ -83,10 +83,7 @@ ov::Tensor create_tensor_from_image(const std::vector<std::string>& files,
(((inputInfo.layout == "NCHW") || (inputInfo.layout == "CHW"))
? (ch * width * height + h * width + w)
: (h * width * numChannels + w * numChannels + ch));
data[offset] =
(static_cast<T>(vreader.at(b).get()[h * width * numChannels + w * numChannels + ch]) -
static_cast<T>(inputInfo.mean[ch])) /
static_cast<T>(inputInfo.scale[ch]);
data[offset] = static_cast<T>(vreader.at(b).get()[h * width * numChannels + w * numChannels + ch]);
}
}
}

View File

@@ -200,6 +200,35 @@ void warn_if_no_batch(const benchmark_app::InputsInfo& first_inputs) {
<< slog::endl;
}
}
void fuse_mean_scale(ov::preprocess::PrePostProcessor& preproc, const benchmark_app::InputsInfo& app_inputs_info) {
// TODO: remove warning after 23.3 release
bool warned = false;
constexpr char warn_msg[] = "Mean/scale values are fused into the model. This slows down performance compared to "
"--imean and --iscale which existed before";
for (const std::pair<std::string, benchmark_app::InputInfo>& input_info : app_inputs_info) {
if (!input_info.second.mean.empty()) {
if (!warned) {
slog::warn << warn_msg << slog::endl;
warned = true;
}
preproc.input(input_info.first)
.preprocess()
.convert_element_type(ov::element::f32)
.mean(input_info.second.mean);
}
if (!input_info.second.scale.empty()) {
if (!warned) {
slog::warn << warn_msg << slog::endl;
warned = true;
}
preproc.input(input_info.first)
.preprocess()
.convert_element_type(ov::element::f32)
.scale(input_info.second.scale);
}
}
}
} // namespace
/**
@@ -607,6 +636,10 @@ int main(int argc, char* argv[]) {
bool isDynamicNetwork = false;
if (FLAGS_load_from_file && !isNetworkCompiled) {
if (!FLAGS_mean_values.empty() || !FLAGS_scale_values.empty()) {
throw std::runtime_error("--mean_values and --scale_values aren't supported with --load_from_file. "
"The values can be set via model_optimizer while generating xml");
}
next_step();
slog::info << "Skipping the step for loading model from file" << slog::endl;
next_step();
@@ -631,8 +664,8 @@ int main(int argc, char* argv[]) {
batchSize,
FLAGS_data_shape,
inputFiles,
FLAGS_iscale,
FLAGS_imean,
FLAGS_scale_values,
FLAGS_mean_values,
compiledModel.inputs());
if (batchSize == 0) {
batchSize = 1;
@@ -678,8 +711,8 @@ int main(int argc, char* argv[]) {
FLAGS_b,
FLAGS_data_shape,
inputFiles,
FLAGS_iscale,
FLAGS_imean,
FLAGS_scale_values,
FLAGS_mean_values,
inputInfo,
reshape);
if (reshape) {
@@ -752,6 +785,8 @@ int main(int argc, char* argv[]) {
}
}
fuse_mean_scale(preproc, app_inputs_info.at(0));
const auto& outs = model->outputs();
for (int i = 0; i < outs.size(); i++) {
const auto& item = outs[i];
@@ -799,6 +834,10 @@ int main(int argc, char* argv[]) {
StatisticsReport::Category::EXECUTION_RESULTS,
{StatisticsVariant("compile model time (ms)", "load_model_time", duration_ms)});
} else {
if (!FLAGS_mean_values.empty() || !FLAGS_scale_values.empty()) {
throw std::runtime_error("--mean_values and --scale_values aren't supported for compiled model. "
"The values can be set via model_optimizer while generating xml");
}
next_step();
slog::info << "Skipping the step for compiled model" << slog::endl;
next_step();
@@ -833,8 +872,8 @@ int main(int argc, char* argv[]) {
FLAGS_b,
FLAGS_data_shape,
inputFiles,
FLAGS_iscale,
FLAGS_imean,
FLAGS_scale_values,
FLAGS_mean_values,
compiledModel.inputs());
if (batchSize == 0) {
batchSize = 1;

View File

@@ -223,7 +223,7 @@ std::string get_shapes_string(const benchmark_app::PartialShapes& shapes) {
std::map<std::string, std::vector<float>> parse_scale_or_mean(const std::string& scale_mean,
const benchmark_app::InputsInfo& inputs_info) {
// Format: data:[255,255,255],info[255,255,255]
// Format: data[255,255,255],info[255,255,255]
std::map<std::string, std::vector<float>> return_value;
std::string search_string = scale_mean;
@@ -630,9 +630,6 @@ std::vector<benchmark_app::InputsInfo> get_inputs_info(const std::string& shape_
for (auto& item : info_map) {
if (item.second.is_image()) {
item.second.scale.assign({1, 1, 1});
item.second.mean.assign({0, 0, 0});
if (scale_map.count(item.first)) {
item.second.scale = scale_map.at(item.first);
}

View File

@@ -108,7 +108,7 @@ usage: benchmark_app.py [-h [HELP]] [-i PATHS_TO_INPUT [PATHS_TO_INPUT ...]] -m
[-pin {YES,NO,NUMA,HYBRID_AWARE}] [-exec_graph_path EXEC_GRAPH_PATH] [-pc [PERF_COUNTS]] [-pcsort {no_sort,sort,simple_sort}] [-pcseq [PCSEQ]]
[-inference_only [INFERENCE_ONLY]] [-report_type {no_counters,average_counters,detailed_counters}] [-report_folder REPORT_FOLDER] [-dump_config DUMP_CONFIG]
[-load_config LOAD_CONFIG] [-infer_precision INFER_PRECISION] [-ip {u8,U8,f16,FP16,f32,FP32}] [-op {u8,U8,f16,FP16,f32,FP32}] [-iop INPUT_OUTPUT_PRECISION]
[-cdir CACHE_DIR] [-lfile [LOAD_FROM_FILE]] [-iscale INPUT_SCALE] [-imean INPUT_MEAN]
[-cdir CACHE_DIR] [-lfile [LOAD_FROM_FILE]] [--mean_values [R,G,B]] [--scale_values [R,G,B]]
Options:
-h [HELP], --help [HELP]
@@ -214,12 +214,16 @@ Options:
Optional. Enable model caching to specified directory
-lfile [LOAD_FROM_FILE], --load_from_file [LOAD_FROM_FILE]
Optional. Loads model from file directly without read_model.
-iscale INPUT_SCALE, --input_scale INPUT_SCALE
Optional. Scale values to be used for the input image per channel. Values to be provided in the [R, G, B] format. Can be defined for desired input of the model.
Example: -iscale data[255,255,255],info[255,255,255]
-imean INPUT_MEAN, --input_mean INPUT_MEAN
Optional. Mean values to be used for the input image per channel. Values to be provided in the [R, G, B] format. Can be defined for desired input of the model. Example:
-imean data[255,255,255],info[255,255,255]
--mean_values [R,G,B]
Optional. Mean values to be used for the input image per channel. Values to be provided in the [R,G,B] format. Can be defined for desired input
of the model, for example: "--mean_values data[255,255,255],info[255,255,255]". The exact meaning and order of channels depend on how the
original model was trained. Applying the values affects performance and may cause type conversion
--scale_values [R,G,B]
Optional. Scale values to be used for the input image per channel. Values are provided in the [R,G,B] format. Can be defined for desired input
of the model, for example: "--scale_values data[255,255,255],info[255,255,255]". The exact meaning and order of channels depend on how the
original model was trained. If both --mean_values and --scale_values are specified, the mean is subtracted first and then scale is applied
regardless of the order of options in command line. Applying the values affects performance and may cause type conversion
```
Running the application with the empty list of options yields the usage message given above and an error message.

View File

@@ -338,6 +338,9 @@ def main():
topology_name = ""
load_from_file_enabled = is_flag_set_in_command_line('load_from_file') or is_flag_set_in_command_line('lfile')
if load_from_file_enabled and not is_network_compiled:
if not args.mean_values or not args.scale_values:
raise RuntimeError("--mean_values and --scale_values aren't supported with --load_from_file. "
"The values can be set via model_optimizer while generating xml")
next_step()
print("Skipping the step for loading model from file")
next_step()
@@ -357,7 +360,7 @@ def main():
[
('compile model time (ms)', duration_ms)
])
app_inputs_info, _ = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.input_scale, args.input_mean, compiled_model.inputs)
app_inputs_info, _ = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.scale_values, args.mean_values, compiled_model.inputs)
batch_size = get_network_batch_size(app_inputs_info)
elif not is_network_compiled:
# --------------------- 4. Read the Intermediate Representation of the network -----------------------------
@@ -382,7 +385,7 @@ def main():
# --------------------- 5. Resizing network to match image sizes and given batch ---------------------------
next_step()
app_inputs_info, reshape = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.input_scale, args.input_mean, model.inputs)
app_inputs_info, reshape = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.scale_values, args.mean_values, model.inputs)
# use batch size according to provided layout and shapes
batch_size = get_network_batch_size(app_inputs_info)
@@ -421,6 +424,9 @@ def main():
('compile model time (ms)', duration_ms)
])
else:
if not args.mean_values or not args.scale_values:
raise RuntimeError("--mean_values and --scale_values aren't supported for compiled model. "
"The values can be set via model_optimizer while generating xml")
next_step()
print("Skipping the step for compiled model")
next_step()
@@ -440,7 +446,7 @@ def main():
[
('import model time (ms)', duration_ms)
])
app_inputs_info, _ = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.input_scale, args.input_mean, compiled_model.inputs)
app_inputs_info, _ = get_inputs_info(args.shape, args.data_shape, args.layout, args.batch_size, args.scale_values, args.mean_values, compiled_model.inputs)
batch_size = get_network_batch_size(app_inputs_info)
# --------------------- 8. Querying optimal runtime parameters --------------------------------------------------

View File

@@ -172,12 +172,15 @@ def parse_args():
help="Optional. Enable model caching to specified directory")
args.add_argument('-lfile', '--load_from_file', required=False, nargs='?', default=argparse.SUPPRESS,
help="Optional. Loads model from file directly without read_model.")
args.add_argument('-iscale', '--input_scale', type=str, required=False, default='',
help="Optional. Scale values to be used for the input image per channel.\n Values to be provided in the [R, G, B] format. Can be defined for desired input of the model.\n"
"Example: -iscale data[255,255,255],info[255,255,255]\n")
args.add_argument('-imean', '--input_mean', type=str, required=False, default='',
help="Optional. Mean values to be used for the input image per channel.\n Values to be provided in the [R, G, B] format. Can be defined for desired input of the model.\n"
"Example: -imean data[255,255,255],info[255,255,255]\n")
args.add_argument('--mean_values', type=str, required=False, default='', metavar='[R,G,B]',
help='Optional. Mean values to be used for the input image per channel. Values to be provided in the [R,G,B] format. Can be defined for '
'desired input of the model, for example: "--mean_values data[255,255,255],info[255,255,255]". The exact meaning and order of '
'channels depend on how the original model was trained')
args.add_argument('--scale_values', type=str, required=False, default='', metavar='[R,G,B]',
help='Optional. Scale values to be used for the input image per channel. Values are provided in the [R,G,B] format. Can be defined for '
'desired input of the model, for example: "--scale_values data[255,255,255],info[255,255,255]". The exact meaning and order of '
'channels depend on how the original model was trained. If both --mean_values and --scale_values are specified, the mean is '
'subtracted first and then scale is applied regardless of the order of options in command line')
parsed_args = parser.parse_args()
return parsed_args, parser

View File

@@ -169,18 +169,6 @@ def get_image_tensors(image_paths, info, batch_sizes):
logger.warning(f"Image is resized from ({image.shape[:-1]}) to ({new_im_size})")
image = cv2.resize(image, new_im_size)
if info.scale.size or info.mean.size:
blue, green, red = cv2.split(image)
if info.mean.size:
blue = np.subtract(blue, info.mean[0])
green = np.subtract(green, info.mean[1])
red = np.subtract(red, info.mean[2])
if info.scale.size:
blue = np.divide(blue, info.scale[0])
green = np.divide(green, info.scale[1])
red = np.divide(red, info.scale[2])
image = cv2.merge([blue, green, red])
model_channel = int(str(info.channels))
image_channel = image.shape[-1]
if model_channel == 1 and image_channel == 3:

View File

@@ -72,6 +72,25 @@ def get_element_type(precision):
raise Exception(f"Undefined precision: '{precision}' !")
def fuse_mean_scale(preproc: PrePostProcessor, app_inputs_info):
# TODO: remove warning after 23.3 release
warned = False;
warn_msg = 'Mean/scale values are fused into the model. This slows down performance compared to --imean and --iscale which existed before'
for input_info in app_inputs_info:
print(input_info)
print(input_info.mean)
if input_info.mean.size:
if not warned:
logger.warning(warn_msg)
warned = True
preproc.input(input_info.name).preprocess().convert_element_type(Type.f32).mean(input_info.mean)
if input_info.scale.size:
if not warned:
logger.warning(warn_msg)
warned = True
preproc.input(input_info.name).preprocess().convert_element_type(Type.f32).scale(input_info.scale)
def pre_post_processing(model: Model, app_inputs_info, input_precision: str, output_precision: str, input_output_precision: str):
pre_post_processor = PrePostProcessor(model)
if input_precision:
@@ -118,6 +137,8 @@ def pre_post_processing(model: Model, app_inputs_info, input_precision: str, out
app_inputs_info[i].element_type = Type.u8
pre_post_processor.input(i).tensor().set_element_type(Type.u8)
fuse_mean_scale(pre_post_processor, app_inputs_info)
# set layout for model input
for info in app_inputs_info:
pre_post_processor.input(info.name).model().set_layout(info.layout)

View File

@@ -464,7 +464,7 @@ mo_convert_params = {
'value. When a list of inputs is overridden by the --input ' +
'parameter, this scale ' +
'is not applied for any input that does not match with ' +
'the original input of the model.' +
'the original input of the model. ' +
'If both --mean_values and --scale are specified, ' +
'the mean is subtracted first and then scale is applied ' +
'regardless of the order of options in command line.', '', '', None),
@@ -526,7 +526,7 @@ mo_convert_params = {
'Can be defined for desired input of the model, for example: ' +
'"--scale_values data[255,255,255],info[255,255,255]". ' +
'The exact meaning and order ' +
'of channels depend on how the original model was trained.' +
'of channels depend on how the original model was trained. ' +
'If both --mean_values and --scale_values are specified, ' +
'the mean is subtracted first and then scale is applied ' +
'regardless of the order of options in command line.', '',