def _write_content_to_acl_json(acl_json_path, model_name, npu_data_output_dir): load_dict = { "dump": { "dump_list": [{ "model_name": model_name }], "dump_path": npu_data_output_dir, "dump_mode": "all", "dump_op_switch": "off" } } if os.access(acl_json_path, os.W_OK): try: with open(acl_json_path, "w") as write_json: try: json.dump(load_dict, write_json) except ValueError as write_json_except: print(str(write_json_except)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_WRITE_JSON_FILE_ERROR) except IOError as acl_json_file_except: utils.print_error_log('Failed to open"' + acl_json_path + '", ' + str(acl_json_file_except)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_OPEN_FILE_ERROR) else: utils.print_error_log( "The path {} does not have permission to write.Please check the path permission" .format(acl_json_path)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PATH_ERROR)
def _make_inputs_data(self, inputs_tensor): if "" == self.args.input_path: input_path_list = [] for index, tensor in enumerate(inputs_tensor): if not tensor.shape: utils.print_error_log( "The shape of %s is unknown. Please usr -i to assign the input path." % tensor.name) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR) input_data = np.random.random(tf_common.convert_tensor_shape(tensor.shape)) \ .astype(tf_common.convert_to_numpy_type(tensor.dtype)) input_path = os.path.join(self.data_dir, "input_" + str(index) + ".bin") input_path_list.append(input_path) try: input_data.tofile(input_path) except Exception as err: utils.print_error_log("Failed to generate data %s. %s" % (input_path, err)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR) utils.print_info_log( "file name: {}, shape: {}, dtype: {}".format( input_path, input_data.shape, input_data.dtype)) self.input_path = ','.join(input_path_list) else: input_path = self.args.input_path.split(",") if len(inputs_tensor) != len(input_path): utils.print_error_log( "the number of model inputs tensor is not equal the number of " "inputs data, inputs tensor is: {}, inputs data is: {}". format(len(inputs_tensor), len(input_path))) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR)
def _shape_size_vs_bin_file_size(self, shape_size_array, bin_files_size_array): if len(shape_size_array) < len(bin_files_size_array): utils.print_error_log( "The number of input bin files is incorrect.") raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR) if self.om_parser.shape_range: for bin_file_size in bin_files_size_array: if bin_file_size not in shape_size_array: utils.print_error_log( "The size (%d) of bin file can not match the input of the model." % bin_file_size) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR) else: for shape_size, bin_file_size in zip(shape_size_array, bin_files_size_array): if shape_size == 0: continue if shape_size != bin_file_size: utils.print_error_log( "The shape value is different from the size of the bin file." ) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR)
def msame_run(self, msame_dir): """ Function Description: run msame project Parameter: msame_dir: msame project directory Return Value: npu dump data path Exception Description: when invalid npu dump data path throw exception """ self._compare_shape_vs_bin_file() npu_data_output_dir = os.path.join(self.arguments.out_path, NPU_DUMP_DATA_BASE_PATH) utils.create_directory(npu_data_output_dir) model_name, extension = utils.get_model_name_and_extension( self.arguments.offline_model_path) acl_json_path = os.path.join(msame_dir, ACL_JSON_PATH) if not os.path.exists(acl_json_path): os.mknod(acl_json_path, mode=0o600) self._write_content_to_acl_json(acl_json_path, model_name, npu_data_output_dir) msame_cmd = [ "./" + MSAME_COMMAND_PATH, "--model", self.arguments.offline_model_path, "--input", self.arguments.input_path, "--device", self.arguments.device, "--output", npu_data_output_dir ] self._make_msame_cmd_for_shape_range(msame_cmd) os.chdir(os.path.join(msame_dir, OUT_PATH)) # do msame command utils.print_info_log( "Run command line: cd %s && %s" % (os.path.join(msame_dir, OUT_PATH), " ".join(msame_cmd))) utils.execute_command(msame_cmd) npu_dump_data_path, file_is_exist = utils.get_dump_data_path( npu_data_output_dir) if not file_is_exist: utils.print_error_log("The path {} dump data is not exist.".format( npu_dump_data_path)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PATH_ERROR) # net output data path npu_net_output_data_path, file_is_exist = utils.get_dump_data_path( npu_data_output_dir, True) if not file_is_exist: utils.print_error_log( "The path {} net output data is not exist.".format( npu_net_output_data_path)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PATH_ERROR) self._convert_net_output_to_numpy(npu_net_output_data_path) return npu_dump_data_path, npu_net_output_data_path
def _check_python_command_valid(cmd): try: output_bytes = subprocess.check_output(cmd, stderr=subprocess.STDOUT) output_text = output_bytes.decode("utf-8") if "Python 3" not in output_text: utils.print_error_log( "The python version only supports the python 3 version family, %s" % " ".join(cmd)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_PYTHON_VERSION_ERROR) python_version = output_text.split(" ")[1].strip() return python_version except subprocess.CalledProcessError as check_output_except: print(str(check_output_except)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_PYTHON_COMMAND_ERROR)
def _check_input_shape_fix_value(op_name, model_shape, input_shape): message = "fixed input tensor dim not equal to model input dim." \ "tensor_name:%s, %s vs %s" % (op_name, str(input_shape), str(model_shape)) if len(model_shape) != len(input_shape): utils.print_error_log(message) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR) for index, value in enumerate(model_shape): if value is None or isinstance(value, str): continue if input_shape[index] != value: utils.print_error_log(message) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR)
def _process_inputs(self, input_desc_array): value = [] for input_object in input_desc_array: if SHAPE_OBJECT not in input_object: value.append(0) continue data_type = DTYPE_MAP.get(input_object.get(DTYPE_OBJECT)) if not data_type: utils.print_error_log( "The dtype attribute does not support {} value.".format( input_object[DTYPE_OBJECT])) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_KEY_ERROR) data_type_size = np.dtype(data_type).itemsize if self.shape_range: range_shape_size_list = self._get_range_shape_size_list( input_object) for item in range_shape_size_list: value.append(item * data_type_size) else: item_sum = 1 for num in input_object.get(SHAPE_OBJECT).get(DIM_OBJECT): item_sum *= num value.append(item_sum * data_type_size) return value
def net_output_compare(self, npu_net_output_data_path, golden_net_output_info): """ net_output_compare """ if not golden_net_output_info: return npu_dump_file = {} file_index = 0 cmd = ["python3", "-V"] python_version = self._check_python_command_valid(cmd) msaccucmp_command_dir_path = os.path.join(self.arguments.cann_path, MSACCUCMP_DIR_PATH) msaccucmp_command_file_path = self._check_msaccucmp_file(msaccucmp_command_dir_path) utils.print_info_log("=================================compare Node_output=================================") utils.print_info_log("start to compare the Node_output at now, compare result is:") utils.print_warn_log("The comparison of Node_output may be incorrect in certain scenarios. If the precision" " is abnormal, please check whether the mapping between the comparison" " data is correct.") for dir_path, subs_paths, files in os.walk(npu_net_output_data_path): for each_file in sorted(files): if each_file.endswith(".npy"): npu_dump_file[file_index] = os.path.join(dir_path, each_file) msaccucmp_cmd = ["python" + python_version, msaccucmp_command_file_path, "compare", "-m", npu_dump_file.get(file_index), "-g", golden_net_output_info.get(file_index)] status, compare_result = self.execute_msaccucmp_command(msaccucmp_cmd, True) if status == 2 or status == 0: self.save_net_output_result_to_csv(npu_dump_file.get(file_index), golden_net_output_info.get(file_index), compare_result) utils.print_info_log("Compare Node_output:{} completely.".format(file_index)) else: utils.print_error_log("Failed to execute command: %s" % " ".join(msaccucmp_cmd)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR) file_index += 1 return
def save_net_output_result_to_csv(self, npu_file, golden_file, result): """ save_net_output_result_to_csv """ result_file_path = None result_file_backup_path = None npu_file_name = os.path.basename(npu_file) golden_file_name = os.path.basename(golden_file) for dir_path, subs_paths, files in os.walk(self.arguments.out_path): if len(files) != 0: result_file_path = os.path.join(dir_path, files[0]) result_file_backup = "{}_bak.csv".format(files[0].split(".")[0]) result_file_backup_path = os.path.join(dir_path, result_file_backup) break try: # read result file and write it to backup file,update the result of compare Node_output with open(result_file_path, "r") as fp_read: with os.fdopen(os.open(result_file_backup_path, WRITE_FLAGS, WRITE_MODES), 'w', newline="") as fp_write: self._process_result_one_line(fp_write, fp_read, npu_file_name, golden_file_name, result) os.remove(result_file_path) os.rename(result_file_backup_path, result_file_path) except (OSError, SystemError, ValueError, TypeError, RuntimeError, MemoryError) as error: utils.print_error_log('Failed to write Net_output compare result') raise AccuracyCompareException(utils.ACCURACY_COMPARISON_NET_OUTPUT_ERROR) finally: pass
def get_csv_object_by_cosine(self): """ Function Description: get operators whose cosine value is less than 0.9 Return Value: operators object or None Exception Description: when invalid data throw exception """ result_data = os.walk(self.arguments.out_path) result_file_path = None for dir_path, subs_paths, files in result_data: if len(files) != 0: result_file_path = os.path.join(dir_path, files[0]) break try: with open(result_file_path, "r") as csv_file: csv_object = csv.DictReader(csv_file) rows = [row for row in csv_object] for item in rows: if float(item.get("CosineSimilarity")) < 0.9: return item except IOError as csv_file_except: utils.print_error_log('Failed to open"' + result_file_path + '", ' + str(csv_file_except)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_OPEN_FILE_ERROR) return None
def _get_inputs_data(self, data_dir, inputs_tensor_info): inputs_map = {} if "" == self.args.input_path: for i, tensor_info in enumerate(inputs_tensor_info): input_data = np.random.random(tensor_info["shape"]).astype( self._convert_to_numpy_type(tensor_info["type"])) inputs_map[tensor_info["name"]] = input_data file_name = "input_" + str(i) + ".bin" input_data.tofile(os.path.join(data_dir, file_name)) utils.print_info_log( "save input file name: {}, shape: {}, dtype: {}".format( file_name, input_data.shape, input_data.dtype)) else: input_path = self.args.input_path.split(",") if len(inputs_tensor_info) != len(input_path): utils.print_error_log( "the number of model inputs tensor_info is not equal the number of " "inputs data, inputs tensor_info is: {}, inputs data is: {}" .format(len(inputs_tensor_info), len(input_path))) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR) for i, tensor_info in enumerate(inputs_tensor_info): input_data = np.fromfile( input_path[i], self._convert_to_numpy_type(tensor_info["type"])).reshape( tensor_info["shape"]) inputs_map[tensor_info["name"]] = input_data utils.print_info_log( "load input file name: {}, shape: {}, dtype: {}".format( os.path.basename(input_path[i]), input_data.shape, input_data.dtype)) return inputs_map
def _convert_to_numpy_type(self, tensor_type): numpy_data_type = NODE_TYPE_TO_DTYPE_MAP.get(tensor_type) if numpy_data_type: return numpy_data_type else: utils.print_error_log( "unsupported tensor type: {}".format(tensor_type)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_TENSOR_TYPE_ERROR)
def _make_msame_cmd_for_shape_range(self, msame_cmd): pattern = re.compile(r'^[0-9]+$') count = self.om_parser.get_net_output_count() if self.om_parser.shape_range: if not self.arguments.input_shape: utils.print_error_log( 'In the dynamic shape scenario, the "-s" or "--input-shape" is mandatory.' ) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) msame_cmd.append('--dymShape') msame_cmd.append('"%s"' % self.arguments.input_shape) if not self.arguments.output_size: if count > 0: count_list = [] for _ in range(count): count_list.append("90000000") self.arguments.output_size = ",".join(count_list) if self.arguments.output_size: output_size_list = self.arguments.output_size.split(',') if len(output_size_list) != count: utils.print_error_log( 'The output size (%d) is not equal %d in model. Please check the "--output-size" argument.' % (len(output_size_list), count)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) for item in output_size_list: item = item.strip() match = pattern.match(item) if match is None: utils.print_error_log( "The size (%s) is invalid. Please check the output size." % self.arguments.output_size) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) if int(item) <= 0: utils.print_error_log( "The size (%s) must be large than zero. Please check the output size." % self.arguments.output_size) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) msame_cmd.append('--outputSize') msame_cmd.append(self.arguments.output_size)
def _check_msaccucmp_file(msaccucmp_command_dir_path): for file_name in MSACCUCMP_FILE_NAME: msaccucmp_command_file_path = os.path.join(msaccucmp_command_dir_path, file_name) if os.path.exists(msaccucmp_command_file_path): return msaccucmp_command_file_path else: utils.print_warn_log( 'The path {} is not exist.Please check the file'.format(msaccucmp_command_file_path)) utils.print_error_log( 'Does not exist in {} directory msaccucmp.py and msaccucmp.pyc file'.format(msaccucmp_command_dir_path)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_INVALID_PATH_ERROR)
def _generate_golden_data_model(args): model_name, extension = utils.get_model_name_and_extension(args.model_path) if ".pb" == extension: from tf.tf_dump_data import TfDumpData return TfDumpData(args) elif ".onnx" == extension: from onnx_model.onnx_dump_data import OnnxDumpData return OnnxDumpData(args) else: utils.print_error_log( "Only model files whose names end with .pb or .onnx are supported") raise AccuracyCompareException( utils.ACCURACY_COMPARISON_MODEL_TYPE_ERROR)
def _run_tf_dbg_dump(self, cmd_line): """Run tf debug with pexpect, should set tf debug ui_type='readline'""" tf_dbg = pexpect.spawn(cmd_line) tf_dbg.logfile = sys.stdout.buffer try: tf_dbg.expect('tfdbg>', timeout=tf_common.TF_DEBUG_TIMEOUT) utils.print_info_log("Start to run. Please wait....") tf_dbg.sendline('run') index = tf_dbg.expect( ['An error occurred during the run', 'tfdbg>'], timeout=tf_common.TF_DEBUG_TIMEOUT) if index == 0: raise AccuracyCompareException( utils.ACCURACY_COMPARISON_PYTHON_COMMAND_ERROR) except Exception as ex: tf_dbg.sendline('exit') utils.print_error_log("Failed to run command: %s. %s" % (cmd_line, ex)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_PYTHON_COMMAND_ERROR) tensor_name_path = os.path.join(self.tmp_dir, 'tf_tensor_names.txt') tf_dbg.sendline('lt > %s' % tensor_name_path) tf_dbg.expect('tfdbg>', timeout=tf_common.TF_DEBUG_TIMEOUT) if not os.path.exists(tensor_name_path): tf_dbg.sendline('exit') utils.print_error_log("Failed to save tensor name to file.") raise AccuracyCompareException( utils.ACCURACY_COMPARISON_PYTHON_COMMAND_ERROR) utils.print_info_log("Save tensor name to %s successfully." % tensor_name_path) pt_command_list = self._make_pt_command(tensor_name_path) utils.print_info_log("Start to run %d pt commands. Please wait..." % len(pt_command_list)) for cmd in pt_command_list: tf_dbg.sendline(cmd.strip()) tf_dbg.expect('tfdbg>', timeout=tf_common.TF_DEBUG_TIMEOUT) tf_dbg.sendline('exit') utils.print_info_log('Finish dump tf data.')
def _load_graph(self): try: with tf.io.gfile.GFile(self.args.model_path, 'rb') as f: global_graph_def = tf.compat.v1.GraphDef.FromString(f.read()) self.global_graph = tf.Graph() with self.global_graph.as_default(): tf.import_graph_def(global_graph_def, name='') except Exception as err: utils.print_error_log("Failed to load the model %s. %s" % (self.args.model_path, err)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_OPEN_FILE_ERROR) utils.print_info_log("Load the model %s successfully." % self.args.model_path)
def _load_json_file(json_file_path): """ Function Description: load json file Parameter: json_file_path: json file path Return Value: json object Exception Description: when invalid json file path throw exception """ try: with open(json_file_path, "r") as input_file: try: return json.load(input_file) except Exception as load_input_file_except: print(str(load_input_file_except)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_PARSER_JSON_FILE_ERROR) except IOError as input_file_open_except: utils.print_error_log('Failed to open"' + json_file_path + '", ' + str(input_file_open_except)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_OPEN_FILE_ERROR)
def get_inputs_data(inputs_tensor, input_paths): inputs_map = {} input_path = input_paths.split(",") for index, tensor in enumerate(inputs_tensor): try: input_data = np.fromfile(input_path[index], convert_to_numpy_type(tensor.dtype)) if tensor.shape: input_data = input_data.reshape(tensor.shape) inputs_map[tensor] = input_data utils.print_info_log( "load file name: {}, shape: {}, dtype: {}".format( os.path.basename(input_path[index]), input_data.shape, input_data.dtype)) except Exception as err: utils.print_error_log("Failed to load data %s. %s" % (input_path[index], err)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_BIN_FILE_ERROR) return inputs_map
def _catch_compare_result(log_line, catch): result = [] try: if catch: # get the compare result info = log_line.decode().split(INFO_FLAG) if len(info) > 1: info_content = info[1].strip().split(" ") info_content = [item for item in info_content if item != ''] pattern_num = re.compile(r'^([0-9]+)\.?([0-9]+)?') pattern_nan = re.compile(r'NaN', re.I) match = pattern_num.match(info_content[0]) if match: result = info_content if not match and pattern_nan.match(info_content[0]): result = info_content return result except (OSError, SystemError, ValueError, TypeError, RuntimeError, MemoryError): utils.print_warn_log('Failed to parse the alg compare result!') raise AccuracyCompareException(utils.ACCURACY_COMPARISON_NET_OUTPUT_ERROR) finally: pass
def accuracy_network_compare(self): """ Function Description: invoke the interface for network-wide comparsion Exception Description: when invalid msaccucmp command throw exception """ cmd = ["python3", "-V"] python_version = self._check_python_command_valid(cmd) msaccucmp_command_dir_path = os.path.join(self.arguments.cann_path, MSACCUCMP_DIR_PATH) msaccucmp_command_file_path = self._check_msaccucmp_file(msaccucmp_command_dir_path) self._check_pyc_to_python_version(msaccucmp_command_file_path, python_version) msaccucmp_cmd = ["python" + python_version, msaccucmp_command_file_path, "compare", "-m", self.npu_dump_data_path, "-g", self.cpu_dump_data_path, "-f", self.output_json_path, "-out", self.arguments.out_path] utils.print_info_log("msaccucmp command line: %s " % " ".join(msaccucmp_cmd)) status_code, _ = self.execute_msaccucmp_command(msaccucmp_cmd) if status_code == 2 or status_code == 0: utils.print_info_log("Finish compare the files in directory %s with those in directory %s." % ( self.npu_dump_data_path, self.cpu_dump_data_path)) else: utils.print_error_log("Failed to execute command: %s" % " ".join(msaccucmp_cmd)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_INVALID_DATA_ERROR)
def _check_output_nodes_valid(self, outputs_tensor, node_list): for tensor in outputs_tensor: tensor_info = tensor.strip().split(':') if len(tensor_info) != 2: utils.print_error_log( 'Invalid output nodes (%s). Only support "name1:0;name2:1". Please check the output node.' % tensor) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) node_name = tensor_info[0].strip() # 0 for node_name if not node_name: utils.print_error_log( 'Invalid output nodes (%s). Only support "name1:0;name2:1". Please check the output node.' % tensor) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) if node_name not in node_list: utils.print_error_log( "The output node (%s) is not in the graph. Please check the output node." % node_name) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) index = tensor_info[1].strip() # 1 for tensor_index if not index: utils.print_error_log( 'Invalid output nodes (%s). Only support "name1:0;name2:1". Please check the output node.' % tensor) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) op = self.global_graph.get_operation_by_name(node_name) pattern = re.compile(r'^[0-9]+$') match = pattern.match(index) if match is None: utils.print_error_log( "The index (%s) of %s is invalid. Please check the output node." % (index, node_name)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR) if int(index) < 0 or int(index) >= len(op.outputs): utils.print_error_log( "The index (%s) of %s out of range [0, %d). Please check the output node." % (index, node_name, len(op.outputs))) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_INVALID_PARAM_ERROR)
def convert_model_to_json(self): """ Function Description: convert om model to json Return Value: output json path Exception Description: when the model type is wrong throw exception """ model_name, extension = utils.get_model_name_and_extension( self.arguments.offline_model_path) if ".om" != extension: utils.print_error_log( 'The offline model file ends with an .om file.Please check {} file.' .format(self.arguments.offline_model_path)) raise AccuracyCompareException( utils.ACCURACY_COMPARISON_MODEL_TYPE_ERROR) utils.check_file_or_directory_path( (os.path.realpath(self.arguments.cann_path)), True) atc_command_file_path = os.path.join(self.arguments.cann_path, ATC_FILE_PATH) utils.check_file_or_directory_path(atc_command_file_path) output_json_path = os.path.join(self.arguments.out_path, "model", model_name + ".json") # do the atc command to convert om to json utils.print_info_log('Start to converting the model to json') atc_cmd = [ atc_command_file_path, "--mode=1", "--om=" + self.arguments.offline_model_path, "--json=" + output_json_path ] utils.print_info_log("ATC command line %s" % " ".join(atc_cmd)) utils.execute_command(atc_cmd) utils.print_info_log("Complete model conversion to json %s." % output_json_path) return output_json_path
def _check_pyc_to_python_version(msaccucmp_command_file_path, python_version): if msaccucmp_command_file_path.endswith(".pyc"): if python_version != PYC_FILE_TO_PYTHON_VERSION: utils.print_error_log( "The python version for executing {} must be 3.7.5".format(msaccucmp_command_file_path)) raise AccuracyCompareException(utils.ACCURACY_COMPARISON_PYTHON_VERSION_ERROR)