[tools] Allow to use node name in command line parameters in python benchmark app (#9874)

* support node names in model specific parameters

* allow to use node name in -i parameter
This commit is contained in:
Alexey Lebedev 2022-01-25 11:16:56 +03:00 committed by GitHub
parent 41d4fcdf25
commit fe5c16ba6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 26 deletions

View File

@ -155,13 +155,13 @@ def get_image_tensors(image_paths, info, batch_sizes):
logger.warning(f"Image is resized from ({image.shape[:-1]}) to ({new_im_size})") logger.warning(f"Image is resized from ({image.shape[:-1]}) to ({new_im_size})")
image = cv2.resize(image, new_im_size) image = cv2.resize(image, new_im_size)
if info.scale or info.mean: if info.scale.size or info.mean.size:
blue, green, red = cv2.split(image) blue, green, red = cv2.split(image)
if info.mean: if info.mean.size:
blue = np.subtract(blue, info.mean[0]) blue = np.subtract(blue, info.mean[0])
green = np.subtract(green, info.mean[1]) green = np.subtract(green, info.mean[1])
red = np.subtract(red, info.mean[2]) red = np.subtract(red, info.mean[2])
if info.scale: if info.scale.size:
blue = np.divide(blue, info.scale[0]) blue = np.divide(blue, info.scale[0])
green = np.divide(green, info.scale[1]) green = np.divide(green, info.scale[1])
red = np.divide(red, info.scale[2]) red = np.divide(red, info.scale[2])
@ -314,20 +314,22 @@ def parse_path(path, app_input_info):
""" """
Parse "input_1:file1/dir1,file2/dir2,input_2:file3/dir3 or file1/dir1,file2/dir2" into two dicts - with binary files and with images Parse "input_1:file1/dir1,file2/dir2,input_2:file3/dir3 or file1/dir1,file2/dir2" into two dicts - with binary files and with images
""" """
input_names = sorted(list(info.name for info in app_input_info)) input_names = list(info.name for info in app_input_info)
input_node_names = list(info.node_name for info in app_input_info)
parsed_names = re.findall(r"([^,]\w+):", path) parsed_names = re.findall(r"([^,]\w+):", path)
wrong_names = list(name for name in parsed_names if name not in input_names) wrong_names = list(name for name in parsed_names if name not in input_names + input_node_names)
if wrong_names: if wrong_names:
raise Exception( raise Exception(
f"Wrong input mapping! Cannot find inputs: {wrong_names}. " f"Wrong input mapping! Cannot find inputs: {wrong_names}. "
f"Available inputs: {input_names}. " f"Available inputs: {input_names}. "
"Please check `-i` input data" "Please check `-i` input data"
) )
tensor_names = [parsed_name if parsed_name in input_names else input_names[input_node_names.index(parsed_name)] for parsed_name in parsed_names]
input_pathes = [path for path in re.split(r"[^,]\w+:", path) if path] input_pathes = [path for path in re.split(r"[^,]\w+:", path) if path]
input_path_mapping = defaultdict(list) input_path_mapping = defaultdict(list)
# input mapping is used # input mapping is used
if parsed_names: if tensor_names:
input_path_mapping = {input_: files.strip(",").split(",") for input_, files in zip(parsed_names, input_pathes)} input_path_mapping = {input_: files.strip(",").split(",") for input_, files in zip(tensor_names, input_pathes)}
else: else:
input_files = list() input_files = list()
_input_pathes = input_pathes[0].strip(",").split(",") _input_pathes = input_pathes[0].strip(",").split(",")

View File

@ -86,27 +86,35 @@ def pre_post_processing(model: Model, app_inputs_info, input_precision: str, out
pre_post_processor.output(i).tensor().set_element_type(element_type) pre_post_processor.output(i).tensor().set_element_type(element_type)
user_precision_map = {} user_precision_map = {}
if input_output_precision: if input_output_precision:
user_precision_map = _parse_arg_map(input_output_precision) user_precision_map = parse_input_output_precision(input_output_precision)
input_names = get_input_output_names(model.inputs) input_names = get_input_output_names(model.inputs)
input_node_names = get_node_names(model.inputs)
output_names = get_input_output_names(model.outputs) output_names = get_input_output_names(model.outputs)
output_node_names = get_node_names(model.outputs)
for node_name, precision in user_precision_map.items(): for node_name, precision in user_precision_map.items():
user_precision_map[node_name] = get_element_type(precision) user_precision_map[node_name] = get_element_type(precision)
for name, element_type in user_precision_map.items(): for name, element_type in user_precision_map.items():
if name in input_names: if name in input_names or name in input_node_names:
port = input_names.index(name) input_index = input_names.index(name) if name in input_names else input_node_names.index(name)
app_inputs_info[port].element_type = element_type app_inputs_info[input_index].element_type = element_type
pre_post_processor.input(name).tensor().set_element_type(element_type) pre_post_processor.input(input_index).tensor().set_element_type(element_type)
elif name in output_names: elif name in output_names or name in output_node_names:
pre_post_processor.output(name).tensor().set_element_type(element_type) if name in output_names:
pre_post_processor.output(name).tensor().set_element_type(element_type)
else:
pre_post_processor.output(output_node_names.index(name)).tensor().set_element_type(element_type)
else: else:
raise Exception(f"Node '{name}' does not exist in network") raise Exception(f"Node '{name}' does not exist in model")
# update app_inputs_info # update app_inputs_info
if not input_precision: if not input_precision:
inputs = model.inputs inputs = model.inputs
input_node_names = get_node_names(model.inputs)
for i in range(len(inputs)): for i in range(len(inputs)):
if app_inputs_info[i].name in user_precision_map.keys(): if app_inputs_info[i].name in user_precision_map:
app_inputs_info[i].element_type = user_precision_map[app_inputs_info[i].name] app_inputs_info[i].element_type = user_precision_map[app_inputs_info[i].name]
elif input_node_names[i] in user_precision_map:
app_inputs_info[i].element_type = user_precision_map[input_node_names[i]]
elif app_inputs_info[i].is_image: elif app_inputs_info[i].is_image:
app_inputs_info[i].element_type = Type.u8 app_inputs_info[i].element_type = Type.u8
pre_post_processor.input(i).tensor().set_element_type(Type.u8) pre_post_processor.input(i).tensor().set_element_type(Type.u8)
@ -118,14 +126,19 @@ def pre_post_processing(model: Model, app_inputs_info, input_precision: str, out
model = pre_post_processor.build() model = pre_post_processor.build()
def _parse_arg_map(arg_map: str): def parse_input_output_precision(arg_map: str):
arg_map = arg_map.replace(" ", "") arg_map = arg_map.replace(" ", "")
pairs = [x.strip() for x in arg_map.split(',')] pairs = [x.strip() for x in arg_map.split(',')]
parsed_map = {} parsed_map = {}
for pair in pairs: for pair in pairs:
key_value = [x.strip() for x in pair.split(':')] key_value = [x.strip() for x in pair.split(':')]
parsed_map.update({key_value[0]:key_value[1]}) name, precision = key_value[0], key_value[1]
# input's name can contain ':'
if len(key_value) == 3:
name = key_value[0] + ':' + key_value[1]
precision = key_value[2]
parsed_map.update({name:precision})
return parsed_map return parsed_map
@ -346,6 +359,8 @@ def get_command_line_arguments(argv):
def get_input_output_names(ports): def get_input_output_names(ports):
return [port.any_name for port in ports] return [port.any_name for port in ports]
def get_node_names(ports):
return [port.node.friendly_name for port in ports]
def get_data_shapes_map(data_shape_string, input_names): def get_data_shapes_map(data_shape_string, input_names):
# Parse parameter string like "input0[shape1][shape2],input1[shape1]" or "[shape1][shape2]" (applied to all inputs) # Parse parameter string like "input0[shape1][shape2],input1[shape1]" or "[shape1][shape2]" (applied to all inputs)
@ -419,9 +434,10 @@ class AppInputInfo:
self.original_shape = None self.original_shape = None
self.partial_shape = None self.partial_shape = None
self.data_shapes = [] self.data_shapes = []
self.scale = [] self.scale = np.empty([0])
self.mean = [] self.mean = np.empty([0])
self.name = None self.name = None
self.node_name = None
@property @property
def is_image(self): def is_image(self):
@ -528,6 +544,7 @@ def parse_batch_size(batch_size_str):
def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size, scale_string, mean_string, inputs): def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size, scale_string, mean_string, inputs):
input_names = get_input_output_names(inputs) input_names = get_input_output_names(inputs)
input_node_names = get_node_names(inputs)
shape_map = parse_input_parameters(shape_string, input_names) shape_map = parse_input_parameters(shape_string, input_names)
data_shape_map = get_data_shapes_map(data_shape_string, input_names) data_shape_map = get_data_shapes_map(data_shape_string, input_names)
layout_map = parse_input_parameters(layout_string, input_names) layout_map = parse_input_parameters(layout_string, input_names)
@ -539,19 +556,26 @@ def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size,
info = AppInputInfo() info = AppInputInfo()
# Input name # Input name
info.name = input_names[i] info.name = input_names[i]
# Input node name
info.node_name = input_node_names[i]
# Input precision # Input precision
info.element_type = inputs[i].element_type info.element_type = inputs[i].element_type
# Shape # Shape
info.original_shape = inputs[i].partial_shape info.original_shape = inputs[i].partial_shape
if info.name in shape_map.keys(): if info.name in shape_map:
info.partial_shape = parse_partial_shape(shape_map[info.name]) info.partial_shape = parse_partial_shape(shape_map[info.name])
reshape = True reshape = True
elif info.node_name in shape_map:
info.partial_shape = parse_partial_shape(shape_map[info.node_name])
reshape = True
else: else:
info.partial_shape = inputs[i].partial_shape info.partial_shape = inputs[i].partial_shape
# Layout # Layout
if info.name in layout_map.keys(): if info.name in layout_map:
info.layout = Layout(layout_map[info.name]) info.layout = Layout(layout_map[info.name])
elif info.node_name in layout_map:
info.layout = Layout(layout_map[info.node_name])
elif inputs[i].node.layout != Layout(): elif inputs[i].node.layout != Layout():
info.layout = inputs[i].node.layout info.layout = inputs[i].node.layout
else: else:
@ -592,8 +616,9 @@ def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size,
raise Exception(f"Batch dimension is not specified for this model!") raise Exception(f"Batch dimension is not specified for this model!")
# Data shape # Data shape
if info.name in data_shape_map.keys() and info.is_dynamic: if (info.name in data_shape_map or info.node_name in data_shape_map) and info.is_dynamic:
for p_shape in data_shape_map[info.name]: used_name = info.name if info.name in data_shape_map else info.node_name
for p_shape in data_shape_map[used_name]:
if p_shape.is_dynamic: if p_shape.is_dynamic:
raise Exception(f"Data shape always should be static, {str(p_shape)} is dynamic.") raise Exception(f"Data shape always should be static, {str(p_shape)} is dynamic.")
elif info.partial_shape.compatible(p_shape): elif info.partial_shape.compatible(p_shape):
@ -601,7 +626,7 @@ def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size,
else: else:
raise Exception(f"Data shape '{str(p_shape)}' provided for input '{info.name}' " raise Exception(f"Data shape '{str(p_shape)}' provided for input '{info.name}' "
f"is not compatible with partial shape '{str(info.partial_shape)}' for this input.") f"is not compatible with partial shape '{str(info.partial_shape)}' for this input.")
elif info.name in data_shape_map.keys(): elif info.name in data_shape_map or input_node_names[i] in data_shape_map:
logger.warning(f"Input '{info.name}' has static shape. Provided data shapes for this input will be ignored.") logger.warning(f"Input '{info.name}' has static shape. Provided data shapes for this input will be ignored.")
input_info.append(info) input_info.append(info)
@ -612,9 +637,13 @@ def get_inputs_info(shape_string, data_shape_string, layout_string, batch_size,
for input in input_info: for input in input_info:
if input.name in scale_map: if input.name in scale_map:
input.scale = scale_map[input.name] input.scale = scale_map[input.name]
elif input.node_name in scale_map:
input.scale = scale_map[input.node_name]
if input.name in mean_map: if input.name in mean_map:
input.mean = mean_map[input.name] input.mean = mean_map[input.name]
elif input.node_name in mean_map:
input.mean = mean_map[input.node_name]
return input_info, reshape return input_info, reshape