def UNSUPPORTED(op): # type: (ONNXOperation)->typing.Tuple[typing.List[typing.List[int]], typing.List[str]] raise utils.NNEFToolsException( 'ONNX shape prop: Unsupported op: {}'.format(op.name))
def create_input(input_source, np_dtype, shape, allow_bigger_batch=False): assert isinstance(input_source, (DefaultInput, RandomInput, ImageInput, NNEFTensorInput)) np_dtype = np.dtype(np_dtype) if isinstance(input_source, DefaultInput): if 'float' in np_dtype.name: input_source = RandomInput('normal', 0.0, 1.0) elif 'int' in np_dtype.name: input_source = RandomInput('binomial', 255, 0.5) elif 'bool' == np_dtype.name: input_source = RandomInput('bernoulli', 0.5) else: raise utils.NNEFToolsException( "Random does not support this dtype: {}".format(np_dtype.name)) if isinstance(input_source, RandomInput): if input_source.algo == 'uniform': if 'float' in np_dtype.name: return np.random.uniform(input_source.args[0], input_source.args[1], shape).astype(np_dtype) elif 'int' in np_dtype.name: return np.random.randint( int(math.ceil(input_source.args[0])), int(math.floor(input_source.args[1])) + 1, shape, np_dtype) else: raise Exception( "Random 'uniform' can not be applied to: {}".format( np_dtype.name)) elif input_source.algo == 'normal': if 'float' in np_dtype.name: return np.random.normal(input_source.args[0], input_source.args[1], shape).astype(np_dtype) else: raise Exception( "Random 'normal' can not be applied to: {}".format( np_dtype.name)) elif input_source.algo == 'binomial': if 'int' in np_dtype.name: return np.random.binomial(input_source.args[0], input_source.args[1], shape).astype(np_dtype) else: raise Exception( "Random 'normal' can not be applied to: {}".format( np_dtype.name)) elif input_source.algo == 'bernoulli': if 'bool' == np_dtype.name: return np.random.uniform(0.0, 1.0, shape) <= input_source.args[0] else: raise Exception( "Random 'bernoulli' can not be applied to: {}".format( np_dtype.name)) else: assert False elif isinstance(input_source, ImageInput): import skimage import skimage.io import skimage.color import skimage.transform assert shape is None or len( shape) == 4, "ImageInput can only produce tensors with rank=4" assert input_source.data_format.upper() in [ ImageInput.DATA_FORMAT_NCHW, ImageInput.DATA_FORMAT_NHWC ] assert input_source.color_format.upper() in [ ImageInput.COLOR_FORMAT_RGB, ImageInput.COLOR_FORMAT_BGR ] imgs = [] for pattern in input_source.filenames: filenames = sorted(glob.glob(os.path.expanduser(pattern))) assert filenames, "No files found for path: {}".format(pattern) for filename in filenames: target_size = None if shape is not None: if input_source.data_format.upper( ) == ImageInput.DATA_FORMAT_NCHW: if shape[1] != 3: raise utils.NNEFToolsException( 'NCHW image is specified as input, but channel dimension of input tensor is not 3.' ) target_size = [shape[2], shape[3]] else: if shape[3] != 3: raise utils.NNEFToolsException( 'NHWC image is specified as input, but channel dimension of input tensor is not 3.' ) target_size = [shape[1], shape[2]] img = skimage.img_as_ubyte(skimage.io.imread(filename)) if len(img.shape) == 2: img = skimage.color.gray2rgb(img) img = img.astype(np.float32) if input_source.color_format.upper( ) == ImageInput.COLOR_FORMAT_RGB: img = img[..., (0, 1, 2)] # remove alpha channel if present else: img = img[..., (2, 1, 0)] if input_source.range: min_ = np.array(input_source.range[0], dtype=np.float32) max_ = np.array(input_source.range[1], dtype=np.float32) scale = (max_ - min_) / 255.0 bias = min_ img = img * scale + bias if input_source.norm: mean = np.array(input_source.norm[0], dtype=np.float32) std = np.array(input_source.norm[1], dtype=np.float32) img = (img - mean) / std if target_size is not None: img = skimage.transform.resize(img, target_size, preserve_range=True, anti_aliasing=True, mode='reflect') img = img.astype(np_dtype) if input_source.data_format.upper( ) == ImageInput.DATA_FORMAT_NCHW: img = img.transpose((2, 0, 1)) img = np.expand_dims(img, 0) imgs.append(img) if shape is not None and len(imgs) < shape[0]: print( "Info: Network batch size bigger than supplied data, repeating it", file=sys.stderr) imgs = imgs * ((shape[0] + len(imgs) - 1) // len(imgs)) imgs = imgs[:shape[0]] assert len(imgs) == shape[0] assert shape is None or len(imgs) == shape[0] or allow_bigger_batch if not all(img.shape == imgs[0].shape for img in imgs): raise utils.NNEFToolsException( "The size of all images must be the same, or --size must be specified" ) return np.concatenate(tuple(imgs), 0) elif isinstance(input_source, NNEFTensorInput): with open(input_source.filename) as f: return nnef.read_tensor(f) else: assert False
def run_using_argv(argv): try: args = get_args(argv) write_outputs = args.output_names is None or args.output_names if args.input is None: if sys.stdin.isatty(): raise utils.NNEFToolsException("No input provided!") utils.set_stdin_to_binary() if write_outputs: if args.output is None: if sys.stdout.isatty(): raise utils.NNEFToolsException("No output provided!") utils.set_stdout_to_binary() parent_dir_of_input_model = os.path.dirname( utils.path_without_trailing_separator(args.network)) tmp_dir = None if args.network.endswith('.tgz'): nnef_path = tmp_dir = tempfile.mkdtemp( prefix="nnef_", dir=parent_dir_of_input_model) utils.tgz_extract(args.network, nnef_path) else: nnef_path = args.network try: parser_configs = NNEFParserConfig.load_configs( args.custom_operations, load_standard=True) # read without weights reader = nnef_io.Reader(parser_configs=parser_configs, infer_shapes=False) graph = reader( os.path.join(nnef_path, 'graph.nnef') if os.path. isdir(nnef_path) else nnef_path) if args.input is None: inputs = tuple( nnef.read_tensor(sys.stdin) for _ in range(len(graph.inputs))) elif len(args.input) == 1 and os.path.isdir(args.input[0]): inputs = tuple( nnef_io.read_nnef_tensor( os.path.join(args.input[0], tensor.name + '.dat')) for tensor in graph.inputs) else: inputs = tuple( nnef_io.read_nnef_tensor(path) for path in args.input) reader = nnef_io.Reader(parser_configs=parser_configs, input_shape=tuple( list(input.shape) for input in inputs)) graph = reader(nnef_path) tensor_hooks = [] stats_hook = None if args.stats: stats_hook = backend.StatisticsHook() tensor_hooks.append(stats_hook) if write_outputs and args.output_names is not None: if '*' in args.output_names: tensor_hooks.append( backend.ActivationExportHook( tensor_names=[ t.name for t in graph.tensors if not t.is_constant and not t.is_variable ], output_directory=args.output)) else: tensor_hooks.append( backend.ActivationExportHook( tensor_names=args.output_names, output_directory=args.output)) if args.permissive: backend.try_to_fix_unsupported_attributes(graph) outputs = backend.run(nnef_graph=graph, inputs=inputs, device=args.device, custom_operations=get_custom_runners( args.custom_operations), tensor_hooks=tensor_hooks) if write_outputs and args.output_names is None: if args.output is None: for array in outputs: nnef.write_tensor(sys.stdout, array) else: for tensor, array in zip(graph.outputs, outputs): nnef_io.write_nnef_tensor( os.path.join(args.output, tensor.name + '.dat'), array) if stats_hook: if args.stats.endswith('/') or args.stats.endswith('\\'): stats_path = os.path.join(nnef_path, args.stats, 'graph.stats') else: stats_path = os.path.join(nnef_path, args.stats) stats_hook.save_statistics(stats_path) if tmp_dir and (args.stats and _is_inside(nnef_path, args.stats)): if args.network.endswith('.tgz'): print("Info: Changing input archive", file=sys.stderr) shutil.move(args.network, args.network + '.nnef-tools-backup') utils.tgz_compress(dir_path=nnef_path, file_path=args.network) os.remove(args.network + '.nnef-tools-backup') else: output_path = args.network.rsplit('.', 1)[0] + '.nnef.tgz' backup_path = output_path + '.nnef-tools-backup' if os.path.exists(output_path): shutil.move(output_path, backup_path) utils.tgz_compress(dir_path=nnef_path, file_path=output_path) if os.path.exists(backup_path): os.remove(backup_path) finally: if tmp_dir: shutil.rmtree(tmp_dir) except utils.NNEFToolsException as e: print("Error: " + str(e), file=sys.stderr) exit(1) except nnef.Error as e: print("Error: " + str(e), file=sys.stderr) exit(1)
def get_args(argv): parser = argparse.ArgumentParser( description="NNEF inference tool", formatter_class=argparse.RawTextHelpFormatter, epilog="""Tips: - If you refer to a Python package or module that is not in the current directory, please add its location to PYTHONPATH. - Quote parameters if they contain spaces or special characters. """) parser.add_argument("network", help="Path of NNEF file, directory or archive") parser.add_argument( '--input', required=False, nargs='+', help="Path of input tensors.\n" "By default they are read from the standard input through a pipe or redirect." ) parser.add_argument( '--output', required=False, help="The path of the output directory.\n" "By default the standard output is used, but only if the command is piped or redirected." ) parser.add_argument( "--output-names", nargs='*', help="""List tensor names to ensure that those tensors are exported. If this option is not specified the graph's output tensors are exported. --output-names: Export nothing --output-names a b c: Export the tensors a, b and c --output-names '*': Export all activation tensors """) parser.add_argument("--stats", nargs='?', default=None, const='graph.stats', help="""Set this to export statistics. If a path is given it must be relative to the directory of the NNEF model. --stats: Write stats to graph.stats --stats stats.txt: Write stats to stats.txt""") parser.add_argument("--permissive", action="store_true", help="""Allow some imprecise evaluations""") parser.add_argument("--device", required=False, help="""Set device: cpu, cuda, cuda:0, cuda:1, etc. Default: cuda if available, cpu otherwise.""") parser.add_argument( '--custom-operations', nargs='*', help="""Custom modules: e.g. package.module1 package.module2""") args = parser.parse_args(args=argv[1:]) has_weights = not (os.path.isfile(args.network) and not args.network.endswith('.tgz')) if not has_weights: raise utils.NNEFToolsException( "Error: Seems like you have specified an NNEF file without weights. " "Please use generate_weights.py") return args
def merge_pads(g): # type: (NNEFGraph)->None t = matcher.Tensor() pad = matcher.Operation(name=['box', 'pad'], outputs=t) sliding = matcher.Operation(name=[ 'argmax_pool', 'max_pool', 'max_pool_with_index', 'avg_pool', 'conv' ], inputs={0: t}) def condition(m): # type: (matcher.Match)->bool if not (m[pad].name == 'pad' or (m[pad].name == 'box' and all(s == 1 for s in m[pad].attribs.get('size', [])) and all(s == 1 for s in m[pad].attribs.get('stride', [])) and all(s == 1 for s in m[pad].attribs.get('dilation', [])) and not m[pad].attribs.get('normalize', False))): return False value = m[pad].attribs.get('_value', 0.0) if value not in [0.0, float('-inf')]: return False if value == float('-inf'): if not m[sliding].name in [ 'argmax_pool', 'max_pool', 'max_pool_with_index' ]: return False if m[pad].attribs.get('border', 'constant') != 'constant': return False if (m[sliding].attribs.get('border', 'constant') != 'constant' and any(p != 0 or q != 0 for p, q in m[sliding].attribs.get('padding', []))): return False if m[sliding].name in ['conv'] and any( p != 0 or q != 0 for p, q in m[pad].attribs.get('padding', [])[:2]): return False return True def action(m): # type: (matcher.Match)->None value = m[pad].attribs.get('_value', 0.0) pad_padding = m[pad].attribs.get('padding', [(0, 0) * m[t].rank]) sliding_padding = m[sliding].attribs.get('padding', [(0, 0) * m[t].rank]) if m[sliding].name in ['conv']: pad_padding = pad_padding[2:] assert len(pad_padding) == len(sliding_padding) m[sliding].attribs['padding'] = [ (p + pp, q + qq) for (p, q), (pp, qq) in zip(pad_padding, sliding_padding) ] m[sliding].attribs['border'] = 'ignore' if value == float( '-inf') else 'constant' graph_utils.remove_passthrough(g, m[pad]) matcher.for_each(graph=g, pattern=sliding, action=action, condition=condition) for op in g.operations: if op.name in ['box', 'pad'] and '_value' in op.attribs: raise utils.NNEFToolsException( 'Could not export {} with value={}'.format( op.name, op.attribs['_value']))
def UNSUPPORTED(op): # print(op) # for i in op.inputs: # print(i) raise utils.NNEFToolsException( 'TFLITE to TF_PY: Unsupported op: {}'.format(op.name))
def read_tf_graph_from_protobuf(filename): graph_def = tf_pb.GraphDef() with open(filename, 'rb') as file: graph_def.ParseFromString(file.read()) graph = TFGraph() attrib_graph = TFGraph( ) # just a graph to contain the tensors that are in attributes, no need to return this attributes_by_node_name = {} outputs_by_node_name = {} detected_output_count = _detect_output_counts(graph_def) for node in graph_def.node: outputs = [] attributes = _get_attributes(node.attr, attrib_graph) output_count = _OutputCount.get(node.op, 1) if isinstance(output_count, str): output_count = attributes[output_count] output_count = max(output_count, detected_output_count.get(node.op, 1)) assert isinstance(output_count, int) if output_count >= 1: output = TFTensor(graph, utils.anystr_to_str(node.name)) outputs.append(output) for i in range(1, output_count): tensor_name = utils.anystr_to_str(node.name) + ':' + str(i) output = TFTensor(graph, tensor_name) outputs.append(output) outputs_by_node_name[node.name] = outputs attributes_by_node_name[node.name] = attributes tensor_by_name = { tensor.name: tensor for outputs in six.itervalues(outputs_by_node_name) for tensor in outputs } placeholders = [] for node in graph_def.node: attributes = attributes_by_node_name[node.name] outputs = outputs_by_node_name[node.name] if node.op == 'Placeholder': assert len(outputs) == 1 tensor = outputs[0] tensor.shape = attributes[ 'shape'] if 'shape' in attributes else None tensor.dtype = attributes[ 'dtype'] if 'dtype' in attributes else None placeholders.append(tensor) elif node.op == 'Const': assert len(outputs) == 1 tensor = outputs[0] value = attributes['value'] if isinstance(value, TFTensor): tensor.shape = value.shape tensor.dtype = value.dtype tensor.data = value.data else: tensor.data = value else: input_names = [ name[:-2] if name.endswith(':0') else name for name in node.input ] input_names = [ name[1:] if name.startswith('^') else name for name in input_names ] for name in input_names: if name not in tensor_by_name: print('Info: List of node types in graph: {}\n'.format( sorted(list({node.op for node in graph_def.node})))) raise utils.NNEFToolsException( "Tensor {} is used, but it is not clear which operation produced it. " "Probably the graph has unsupported dynamic operations." .format(name)) inputs = tuple([tensor_by_name[name] for name in input_names]) TFOperation(graph, name=utils.anystr_to_str(node.op), inputs=inputs, outputs=outputs, attribs=attributes) for tensor in graph.tensors: if tensor.name is not None and ':' not in tensor.name: tensor.name += ':0' graph.inputs = OrderedDict([(tensor.name.split(':')[0], tensor) for tensor in placeholders]) graph_outputs = [] for op in graph.operations: if all(len(output.consumers) == 0 for output in op.outputs): for output in op.outputs: graph_outputs.append(output) graph.outputs = OrderedDict([ ('output' + str(i) if len(graph_outputs) > 1 else 'output', tensor) for i, tensor in enumerate(graph_outputs) ]) return graph
def get_args(argv): parser = argparse.ArgumentParser( description="Create an NNEF tensor from (a batch of) image(s)", formatter_class=argparse.RawTextHelpFormatter, epilog="""Image processing steps: 1. The image is loaded as float32 with range [0, 255]. 2. The image is resized to the given size if specified. 3. The image is transformed to RGB or BGR as requested. 4. The image is transformed to the specified range. 5. The image is normalized as follows: image = (image - mean) / std 6. The image is transformed to NCHW or NHWC as requested. 7. The image is cast to the requested dtype.""") parser.add_argument( 'input', nargs='+', help="The path or paths of images, e.g. image.jpg, *.jpg, etc.") parser.add_argument( '--output', required=False, help="The path of the output tensor, e.g. tensor.dat.\n" "By default the standard output is used, but only if the command is piped or redirected." ) parser.add_argument("--color", choices=['RGB', 'BGR'], default='RGB', type=str.upper, help="Input color format. Default: RGB") parser.add_argument("--format", choices=['NCHW', 'NHWC'], default='NCHW', type=str.upper, help="Input data format. Default: NCHW") parser.add_argument( "--range", nargs=2, type=float, default=[0, 255], help="Range for representing the image. Default: 0 255") parser.add_argument("--mean", nargs='+', type=float, default=[0], help="Mean to subtract from the image. Default: 0\n" "Can be channel-wise, e.g. 127 128 129") parser.add_argument( "--std", nargs='+', type=float, default=[1], help="Standard deviation to divide the image with. Default: 1\n" "Can be channel-wise, e.g. 127 128 129") parser.add_argument( "--size", nargs='+', required=False, type=int, help= "Target image size: width [height]. Default: The size of the given image(s).\n" "E.g. 224 or 640 480") parser.add_argument( "--dtype", default="float32", help="Numpy dtype of the generated tensor. Default: float32") args = parser.parse_args(args=argv[1:]) if args.size is not None: if len(args.size) == 1: args.size *= 2 if len(args.size) != 2: raise utils.NNEFToolsException( "The --size parameter must have 1 or 2 arguments if given!") return args
def read( path, # type: str parser_configs=None, # type: typing.Optional[typing.List[NNEFParserConfig]] input_shape=None, # type: _InputShapeType ): # type: (...)->NNEFGraph if not (path.endswith('.tgz') or path.endswith('.nnef') or path.endswith('.txt') or os.path.isdir(path)): raise utils.NNEFToolsException( "Only .tgz or .nnef or .txt files or directories are supported") parser_config = NNEFParserConfig.combine_configs( parser_configs if parser_configs else []) path_to_load = None compressed = False try: if os.path.isdir(path): compressed = False with_weights = True path_to_load = path elif path.endswith('.tgz'): compressed = True with_weights = True path_to_load = tempfile.mkdtemp(prefix="nnef_") utils.tgz_extract(path, path_to_load) elif path.endswith('.nnef') or path.endswith('.txt'): compressed = False with_weights = False path_to_load = path else: assert False # If there are fragments in the graph and also in parser_config # we remove the non-standard fragments from parser_config to avoid duplicate fragment definition if parser_config.fragments: re_graph = re.compile(r"^graph\s|\sgraph\s") re_fragment = re.compile(r"^fragment\s|\sfragment\s") graph_nnef_path = os.path.join( path_to_load, 'graph.nnef') if os.path.isdir(path_to_load) else path_to_load with open(graph_nnef_path, 'r') as f: while True: line = f.readline() if not line: break if re_fragment.search(line): parser_config.fragments = NNEFParserConfig.STANDARD_CONFIG.fragments break if re_graph.search(line): break parser_graph = parser_config.load_graph(path_to_load) if input_shape is not None: if not isinstance(input_shape, (tuple, list, dict)): raise utils.NNEFToolsException( "input_shape must be list or dict") for op in parser_graph.operations: if op.name == 'external': name = op.outputs['output'] if isinstance(input_shape, dict): if name in input_shape: op.attribs['shape'] = input_shape[name] elif isinstance(input_shape, tuple): op.attribs['shape'] = input_shape[ parser_graph.inputs.index(name)] else: op.attribs['shape'] = input_shape parser_config.infer_shapes(parser_graph) return _read(parser_graph=parser_graph, with_weights=with_weights) finally: if compressed and path_to_load: shutil.rmtree(path_to_load)
def generic_convert_binary( converter, # type: Converter nnef_op, # type: NNEFOperation caffe_graph, # type: CaffeGraph is_commutative=False, # type: bool eltwise_name=None, # type: typing.Optional[str] eltwise_axis_needed=False, # type: typing.Optional[bool] eltwise_operation=None, # type: typing.Optional[int] eltwise_coeff=None, # type: typing.Optional[typing.List[float]] learnable_name=None, # type: typing.Optional[str] scalar_name=None, # type: typing.Optional[str] scalar_arg_name=None, # type: typing.Optional[str] scalar_transform=None, # type: typing.Optional[typing.Callable[[float], float]] scalar_name_left=None, # type: typing.Optional[str] scalar_arg_name_left=None, # type: typing.Optional[str] ): # type: (...)->None if not scalar_transform: scalar_transform = lambda x: x def make_learnable(input, variable, output): # type: (CaffeTensor, CaffeTensor, CaffeTensor)->None axis = -1 for j, (i, v) in enumerate(zip(input.shape, variable.shape)): if i == v and v != 1: axis = j break if axis == -1: if not utils.has_gt_1(variable.shape): if variable.rank >= 2 and input.rank >= 2: axis = 1 else: axis = 0 else: raise utils.NNEFToolsException( "Cannot convert binary op: Variable and input shapes are incompatible" ) num_axes = variable.rank - axis variable.shape = variable.shape[axis:] variable.data = variable.data.reshape(variable.shape) CaffeOperation(graph=caffe_graph, name=learnable_name, inputs=(input, variable), outputs=output, attribs=dict(axis=axis, num_axes=num_axes)) def make_eltwise(input1, input2, output): # type: (CaffeTensor, CaffeTensor, CaffeTensor)->None if eltwise_axis_needed: axis = -1 for index, (i, j) in enumerate(zip(input1.shape, input2.shape)): if i == j and j != 1: axis = index break if axis == -1: if not utils.has_gt_1(input2.shape): if input2.rank >= 2 and input1.rank >= 2: axis = 1 else: axis = 0 else: raise utils.NNEFToolsException( "Cannot convert binary op: Input shapes are incompatible" ) if axis > 0: input2 = CaffeOperation( graph=caffe_graph, name="Reshape", inputs=input2, outputs=CaffeTensor(graph=caffe_graph, shape=input2.shape[axis:]), attribs=dict(shape=input2.shape[axis:])).output else: axis = None eltwise = CaffeOperation(graph=caffe_graph, name=eltwise_name, inputs=(input1, input2), outputs=output) if eltwise_operation is not None: eltwise.attribs['operation'] = eltwise_operation if eltwise_coeff is not None: eltwise.attribs['coeff'] = eltwise_coeff if axis is not None: eltwise.attribs['axis'] = axis def make_scalar(input, output, scalar): # type: (CaffeTensor, CaffeTensor, typing.Union[bool, int, float])->None CaffeOperation(graph=caffe_graph, name=scalar_name, inputs=input, outputs=output, attribs={scalar_arg_name: scalar_transform(scalar)}) def make_scalar_left(input, output, scalar): # type: (CaffeTensor, CaffeTensor, typing.Union[bool, int, float])->None CaffeOperation(graph=caffe_graph, name=scalar_name_left, inputs=input, outputs=output, attribs={scalar_arg_name_left: scalar}) nnef_x, nnef_y = nnef_op.inputs x, y = converter.converted_tensors((nnef_x, nnef_y)) z = converter.converted_tensor(nnef_op.output) if (learnable_name and nnef_x.data is None and converter.is_unique_variable_or_constant(nnef_y) and nnef_y.shape != []): make_learnable(input=x, variable=y, output=z) elif (learnable_name and is_commutative and nnef_y.data is None and converter.is_unique_variable_or_constant(nnef_x) and nnef_y.shape != []): make_learnable(input=y, variable=x, output=z) elif (scalar_name and nnef_x.data is None and nnef_y.data is not None and nnef_y.shape == []): make_scalar(input=x, output=z, scalar=float(nnef_y.get_numpy_array())) elif (scalar_name_left and nnef_y.data is None and nnef_x.data is not None and nnef_x.shape == []): make_scalar_left(input=y, output=z, scalar=float(nnef_x.get_numpy_array())) elif (scalar_name and is_commutative and nnef_y.data is None and nnef_x.data is not None and nnef_x.shape == []): make_scalar(input=y, output=z, scalar=float(nnef_x.get_numpy_array())) elif (eltwise_name is not None and nnef_x.data is None and nnef_y.data is None): make_eltwise(input1=x, input2=y, output=z) else: raise utils.NNEFToolsException( "Unsupported binary operation: {}".format(nnef_op))
def caffe_pad(nnef_padding): if not all(p == q for p, q in nnef_padding): raise utils.NNEFToolsException( "Asymmetric padding not supported, padding={}".format( nnef_padding)) return [p for p, _q in nnef_padding]
def export( output_path, # type: str feed_dict, # type: typing.Dict[typing.Any, np.ndarray] conversion_info, # type: ConversionInfo graph=None, # type: typing.Optional[tf.Graph] checkpoint_path=None, # type: str tensors_per_iter=25, # type: int verbose=False, # type: bool init_variables=False, # type: bool input_output_only=False, # type: bool ): # type: (...)->None if graph is None: graph = tf.get_default_graph() has_error = False tensor_infos = [] for tensor_info in conversion_info.tensors: if tensor_info.is_variable or (input_output_only and not tensor_info.is_input and not tensor_info.is_output): continue try: tensor = graph.get_tensor_by_name(tensor_info.source_name) if not graph.is_fetchable(tensor): print("Warning: Tensor is not fetchable: {}".format( tensor_info.source_name)) elif not isinstance(tensor, tf.Tensor): print("Warning: Not a tensor: {}".format( tensor_info.source_name)) else: tensor_infos.append( _TensorInfo(internal_name=tensor_info.source_name, external_name=tensor_info.target_name, transforms=tensor_info.transforms, tensor=tensor, target_shape=tensor_info.target_shape)) except KeyError: print("Warning: Tensor not found: {}".format( tensor_info.source_name)) with tf.Session() as sess: saver = tf.train.Saver() if checkpoint_path else None start = 0 while start < len(tensor_infos): tensors = [ info.tensor for info in tensor_infos[start:start + tensors_per_iter] ] if init_variables: sess.run(tf.global_variables_initializer()) if checkpoint_path is not None: if os.path.isdir(checkpoint_path): saver.restore(sess, tf.train.latest_checkpoint(checkpoint_path)) else: saver.restore(sess, checkpoint_path) values = sess.run(tensors, feed_dict) for i, arr in enumerate(values): info = tensor_infos[start + i] filename = os.path.join(output_path, info.external_name + ".dat") if np.isnan(arr).any(): print("Error: '{}' has nan's".format(info.external_name)) has_error = True elif not np.isfinite(arr).all(): print("Error: '{}' has inf's".format(info.external_name)) has_error = True try: for transform in info.transforms: arr = transform.apply_np(arr) write_nnef_tensor(filename, np.asarray(arr, order='C')) except ValueError as e: print("Error: Can not export '{}': {}".format( info.external_name, e)) start += len(tensors) if verbose: print("Info: Exported {}/{}".format(start, len(tensor_infos))) if has_error: raise utils.NNEFToolsException("There were errors!")
def tf_get_input_shapes(input_shape=None): def get_shape_for(name): if isinstance(input_shape, dict) and name in input_shape: return input_shape[name] elif isinstance(input_shape, list): return list(input_shape) elif utils.is_anyint(input_shape): return utils.anyint_to_int(input_shape) return None if isinstance(input_shape, dict): input_shape = {(k + ':0' if ':' not in k else k): v for k, v in six.iteritems(input_shape)} placeholders = tf_get_placeholders() new_input_shapes = {} if input_shape is None: if any( tf_shape_normalize(tensor.shape) is None or -1 in tf_shape_normalize(tensor.shape) for tensor in placeholders): for tensor in placeholders: print("Info: Input shape: {}: {}".format( tensor.name, tf_shape_normalize(tensor.shape))) for tensor in placeholders: tensor_shape = tf_shape_normalize(tensor.shape) shape_for_this = get_shape_for(tensor.name) if tensor.name else None if isinstance(shape_for_this, list): if not utils.compatible_shapes(tensor_shape, shape_for_this): raise utils.NNEFToolsException( "The specified shape is incompatible with the original shape for {}. {} vs. {}" .format(tensor.name, shape_for_this, tensor_shape)) tensor_shape = shape_for_this elif shape_for_this is None or isinstance(shape_for_this, int): if tensor_shape is None: raise utils.NNEFToolsException( "The full shape must be specified for {}, because it is unknown." .format(tensor.name)) elif -1 in tensor_shape: if shape_for_this is None: shape_for_this = 1 print( "Warning: Incomplete input shape is auto-fixed: {}. {} -> {}. " "Use --input-shape if other shape is desired.".format( tensor.name, tensor_shape, [ shape_for_this if dim == -1 else dim for dim in tensor_shape ])) tensor_shape = [ shape_for_this if dim == -1 else dim for dim in tensor_shape ] else: assert False if tensor.dtype is None: raise utils.NNEFToolsException( "An input tensor has incomplete dtype, " "we have thought that this is impossible, " "please file a bug report to NNEF Tools.") new_input_shapes[tensor.name] = (tensor.dtype.name, tensor_shape) return new_input_shapes