Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting to tf-coreml #19

Open
mrgloom opened this issue Mar 14, 2019 · 1 comment
Open

Converting to tf-coreml #19

mrgloom opened this issue Mar 14, 2019 · 1 comment

Comments

@mrgloom
Copy link

mrgloom commented Mar 14, 2019

I'm trying to find out endpoints of model like is done here:
https://github.com/tf-coreml/tf-coreml/blob/master/examples/ssd_example.ipynb

Cause using default input/output node names produce error:

input_tensor_shapes {'image_tensor:0': [1, 256, 256, 3]}
output_tensor_names ['boxes:0', 'scores:0', 'num_boxes:0']

Loading the TF graph...
Graph Loaded.
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-15-3268ebb54f92> in <module>
     18         mlmodel_path=coreml_model_file,
     19         input_name_shape_dict=input_tensor_shapes,
---> 20         output_feature_names=output_tensor_names)

/usr/local/lib/python3.6/site-packages/tfcoreml/_tf_coreml_converter.py in convert(tf_model_path, mlmodel_path, output_feature_names, input_name_shape_dict, image_input_names, is_bgr, red_bias, green_bias, blue_bias, gray_bias, image_scale, class_labels, predicted_feature_name, predicted_probabilities_output, add_custom_layers, custom_conversion_functions)
    584       predicted_probabilities_output=predicted_probabilities_output,
    585       add_custom_layers=add_custom_layers,
--> 586       custom_conversion_functions=custom_conversion_functions)

/usr/local/lib/python3.6/site-packages/tfcoreml/_tf_coreml_converter.py in _convert_pb_to_mlmodel(tf_model_path, mlmodel_path, output_feature_names, input_name_shape_dict, image_input_names, is_bgr, red_bias, green_bias, blue_bias, gray_bias, image_scale, class_labels, predicted_feature_name, predicted_probabilities_output, add_custom_layers, custom_conversion_functions)
    165   print('Graph Loaded.')
    166   # Sort the ops in topological order and check whether the graph has cycles, if yes, error out
--> 167   OPS = _topological_sort_ops(OPS)
    168 
    169   SHAPE_DICT = {} #Tensor name --> shape ({str: list})

/usr/local/lib/python3.6/site-packages/tfcoreml/_tf_graph_transform.py in _topological_sort_ops(ops)
    192       node = _get_unvisited_child(G, stack[-1], not_visited)
    193       if node != -1:
--> 194         _push_stack(stack, node, in_stack)
    195       else:
    196         node = stack.pop()

/usr/local/lib/python3.6/site-packages/tfcoreml/_tf_graph_transform.py in _push_stack(stack, node, in_stack)
     36   stack.append(node)
     37   if node in in_stack:
---> 38     raise ValueError('Graph has cycles.')
     39   else:
     40     in_stack[node] = True

ValueError: Graph has cycles.

Screenshot 2019-03-14 at 14 39 35

On graph last block before nms is preprocessing, but I'm not sure what is output_tensor_names should be used.

I have tried to print node dimensions:

with tf.Graph().as_default() as graph:
    tf.import_graph_def(original_gdef, name='')
    for op in graph.get_operations():
        if 'postprocessing' in op.name:
            print('-'*60)
            print('str(op.name)', str(op.name))
            print('len(op.values())', len(op.values()))
            try:
                for i in range(len(op.values())):
                    print('op.values()[i].get_shape().as_list()', op.values()[i].get_shape().as_list())
            except:
                for i in range(len(op.values())):
                    print('op.values()[i].get_shape()', op.values()[i].get_shape())

Output:

------------------------------------------------------------
str(op.name) postprocessing/Shape
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice/stack
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice/stack_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice/stack_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/Shape_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_1/stack
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_1/stack_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_1/stack_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [1]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_1
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/ExpandDims/dim
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/ExpandDims
len(op.values()) 1
op.values()[i].get_shape().as_list() [1, 1364, 4]
------------------------------------------------------------
str(op.name) postprocessing/Tile/multiples/1
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/Tile/multiples/2
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/Tile/multiples
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/Tile
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 1364, 4]
------------------------------------------------------------
str(op.name) postprocessing/Reshape/shape
len(op.values()) 1
op.values()[i].get_shape().as_list() [2]
------------------------------------------------------------
str(op.name) postprocessing/Reshape
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 4]
------------------------------------------------------------
str(op.name) postprocessing/Reshape_1/shape
len(op.values()) 1
op.values()[i].get_shape().as_list() [2]
------------------------------------------------------------
str(op.name) postprocessing/Reshape_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 4]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/unstack
len(op.values()) 4
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/sub
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/sub_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/mul/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/mul
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/add
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/mul_1/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/mul_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_center_coordinates/add_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/unstack_1
len(op.values()) 4
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_1/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_2/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_3/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/truediv_3
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/Exp
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/mul
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/Exp_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/mul_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/mul_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/add
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/mul_3
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/add_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/sub
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_1/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/sub_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_2/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/add
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_3/x
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/mul_3
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/to_minmax_coordinates/add_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None]
------------------------------------------------------------
str(op.name) postprocessing/decode_predictions/stack
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 4]
------------------------------------------------------------
str(op.name) postprocessing/Reshape_2/shape/2
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/Reshape_2/shape
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/Reshape_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value/Minimum/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value/Minimum
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/truediv
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value_1/Minimum/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value_1/Minimum
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value_1/y
len(op.values()) 1
op.values()[i].get_shape().as_list() []
------------------------------------------------------------
str(op.name) postprocessing/clip_by_value_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 4]
------------------------------------------------------------
str(op.name) postprocessing/Softmax
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 2]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_2/stack
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_2/stack_1
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_2/stack_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [3]
------------------------------------------------------------
str(op.name) postprocessing/strided_slice_2
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None]

But I can't find out any meaningfull node name:

These looks like bboxes:

str(op.name) postprocessing/Tile
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 1364, 4]

str(op.name) postprocessing/ExpandDims
len(op.values()) 1
op.values()[i].get_shape().as_list() [1, 1364, 4]

Is it true that for 256x256 image we have 1364 bboxes?

With same approach I found node:

------------------------------------------------------------
str(op.name) postprocessing/Softmax
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, None, 2]

But not sure why it have shape [None, None, 2]?

Also here is postprocessing scope:

with tf.name_scope('postprocessing'):

It should have output boxes with [batch_size, num_anchors, 4] shape and scores with [batch_size, num_anchors] shape.

@mrgloom
Copy link
Author

mrgloom commented Mar 15, 2019

I have ended with layers after prediction_layers scope, looks like it's maximum that tf-coreml can support in terms of operations.

I can't figure out how to get tensor names in tensorboard, so I have added print to get tensor names and the run python save.py:

        for i in range(len(box_encodings)):
            print('DEBUG: box_encodings[i]', box_encodings[i])

        for i in range(len(class_predictions_with_background)):
            print('DEBUG: class_predictions_with_background[i]', class_predictions_with_background[i])

Here in the code:

# V1: after feature extractor
# [None, None, None, 128], [None, None, None, 256], [None, None, None, 256]
# output_node_names = ['inception3/concat', 'conv3_2/Relu', 'conv4_2/Relu']

# V2: real netwrok outputs
# ValueError: Graph has cycles.
# output_node_names = ['boxes', 'scores', 'num_boxes']

# V3: before NMS
# NotImplementedError: Unsupported Ops of type: Unpack,Pack
# [batch_size, num_anchors, 4], [batch_size, num_anchors]
# output_node_names = ['postprocessing/clip_by_value_1', 'postprocessing/strided_slice_2']

# V4: after reshaping scope
# AssertionError: Reshape: Currently only supported if target shape is rank 2, 3 or 4
# output_node_names = ['reshaping/concat', 'reshaping/concat_1']

# V5: after prediction_layers scope
output_node_names = ['prediction_layers/box_encoding_predictor_0/BiasAdd',
                     'prediction_layers/box_encoding_predictor_1/BiasAdd',
                     'prediction_layers/box_encoding_predictor_2/BiasAdd',
                     'prediction_layers/class_predictor_0/BiasAdd',
                     'prediction_layers/class_predictor_1/BiasAdd',
                     'prediction_layers/class_predictor_2/BiasAdd']

For 256x256 input image shapes of output tensors are:

------------------------------------------------------------
str(op.name) image_tensor
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 256, 256, 3]
------------------------------------------------------------
str(op.name) prediction_layers/box_encoding_predictor_0/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 8, 8, 84]
------------------------------------------------------------
str(op.name) prediction_layers/class_predictor_0/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 8, 8, 42]
------------------------------------------------------------
str(op.name) prediction_layers/box_encoding_predictor_1/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 4, 4, 4]
------------------------------------------------------------
str(op.name) prediction_layers/class_predictor_1/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 4, 4, 2]
------------------------------------------------------------
str(op.name) prediction_layers/box_encoding_predictor_2/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 2, 2, 4]
------------------------------------------------------------
str(op.name) prediction_layers/class_predictor_2/BiasAdd
len(op.values()) 1
op.values()[i].get_shape().as_list() [None, 2, 2, 2]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant