naisy / realtime_object_detection

Plug and Play Real-Time Object Detection App with Tensorflow and OpenCV. No Bugs No Worries. Enjoy!
MIT License
101 stars 36 forks source link

Splitting FRCNN graph #53

Open abhigoku10 opened 5 years ago

abhigoku10 commented 5 years ago

@naisy Hi Nasy , i tried splitting the graph for FRCNN i had used the TF to generate the model , since squeeze 2 and 3 are not there so i have commented the following section . pls find the code section below

import tensorflow as tf from tensorflow.core.framework import graph_pb2 import copy

class LoadFrozenGraph(): """ LOAD FROZEN GRAPH """ def init(self,cfg,sliptmodel=True):

    self.split_model= sliptmodel
    self.model_path=cfg
    return

def load_graph(self):
    print('Building Graph')
    if not self.split_model:
        return self.load_frozen_graph_without_split()
        print("i am inside without split")
    else:
        return self.load_frozen_graph_with_split()

def print_graph(self, graph):
    """
    PRINT GRAPH OPERATIONS
    """
    print("{:-^32}".format(" operations in graph "))
    for op in graph.get_operations():
        print(op.name,op.outputs)
    return

def print_graph_def(self, graph_def):
    """
    PRINT GRAPHDEF NODE NAMES
    """
    print("{:-^32}".format(" nodes in graph_def "))
    for node in graph_def.node:
        print(node)
    return

def print_graph_operation_by_name(self, graph, name):
    """
    PRINT GRAPH OPERATION DETAILS
    """
    op = graph.get_operation_by_name(name=name)
    print("{:-^32}".format(" operations in graph "))
    print("{:-^32}\n{}".format(" op ", op))
    print("{:-^32}\n{}".format(" op.name ", op.name))
    print("{:-^32}\n{}".format(" op.outputs ", op.outputs))
    print("{:-^32}\n{}".format(" op.inputs ", op.inputs))
    print("{:-^32}\n{}".format(" op.device ", op.device))
    print("{:-^32}\n{}".format(" op.graph ", op.graph))
    print("{:-^32}\n{}".format(" op.values ", op.values()))
    print("{:-^32}\n{}".format(" op.op_def ", op.op_def))
    print("{:-^32}\n{}".format(" op.colocation_groups ", op.colocation_groups))
    print("{:-^32}\n{}".format(" op.get_attr ", op.get_attr("T")))
    i = 0
    for output in op.outputs:
        op_tensor = output
        tensor_shape = op_tensor.get_shape().as_list()
        print("{:-^32}\n{}".format(" outputs["+str(i)+"] shape ", tensor_shape))
        i += 1
    return

# helper function for split model
def node_name(self, n):
    if n.startswith("^"):
        return n[1:]
    else:
        return n.split(":")[0]

def load_frozen_graph_without_split(self):
    """
    Load frozen_graph.
    """
    model_path = self.model_path

    tf.reset_default_graph()

    graph_def = tf.GraphDef()
    with tf.gfile.GFile(model_path, 'rb') as fid:
        serialized_graph = fid.read()
        graph_def.ParseFromString(serialized_graph)
        # force CPU device placement for NMS ops
        for node in graph_def.node:
            if 'BatchMultiClassNonMaxSuppression' in node.name:
                node.device = '/device:CPU:0'
            else:
                node.device = '/device:GPU:0'
        tf.import_graph_def(graph_def, name='')

    #self.print_graph_operation_by_name(detection_graph, "Postprocessor/Slice")
    #self.print_graph_operation_by_name(detection_graph, "Postprocessor/ExpandDims_1")
    #self.print_graph_operation_by_name(detection_graph, "Postprocessor/stack_1")
    """
    return
    """
    return tf.get_default_graph()

def load_frozen_graph_with_split(self):
    """
    Load frozen_graph and split it into half of GPU and CPU.
    """
    model_path = self.model_path
    #split_shape = self.cfg['split_shape']
    num_classes = 4#self.cfg['num_classes']

    """ SPLIT TARGET NAME """
    SPLIT_TARGET_NAME = ['SecondStagePostprocessor/ToFloat',
                          'SecondStagePostprocessor/BatchMultiClassNonMaxSuppression/map/strided_slice',
                          'BatchMultiClassNonMaxSuppression/map/TensorArrayStack_4/TensorArrayGatherV3',
                          #'Squeeze_2',
                          #'Squeeze_3',
                          #'SecondStagePostprocessor/Reshape_4',
     ]
    #BAD SPLIT POINT
    # SPLIT_TARGET_NAME = ['ExpandDims_4',
    #                      'Preprocessor/map/TensorArrayStack_1/TensorArrayGatherV3',
    #                      'Shape',
    #                      'ExpandDims_1',
    #                      'Reshape_4',
    #                      'Reshape_3',
    #                      'FirstStageFeatureExtractor/InceptionV2/InceptionV2/Mixed_4e/concat',
    # ]

    tf.reset_default_graph()

    """ ADD CPU INPUT """
    target_in = [tf.placeholder(tf.float32, shape=(None), name=SPLIT_TARGET_NAME[0]),
                 tf.placeholder(tf.int32, shape=(None), name=SPLIT_TARGET_NAME[1]),
                 tf.placeholder(tf.int32, shape=(None), name=SPLIT_TARGET_NAME[2]),
                 #tf.placeholder(tf.float32, shape=(None, num_classes, 4), name=SPLIT_TARGET_NAME[3]),
                 #tf.placeholder(tf.float32, shape=(None, num_classes+1), name=SPLIT_TARGET_NAME[4]),
                 #tf.placeholder(tf.float32, shape=(None, None, num_classes, 4), name=SPLIT_TARGET_NAME[5]),
    ]

     #BAD SPLIT POINT
    # target_in = [tf.placeholder(tf.float32, shape=(None, None, 1, 4), name=SPLIT_TARGET_NAME[0]),
    #              tf.placeholder(tf.int32, shape=(None), name=SPLIT_TARGET_NAME[1]),
    #              tf.placeholder(tf.int32, shape=(None), name=SPLIT_TARGET_NAME[2]),
    #              tf.placeholder(tf.float32, shape=(None, None, 1, 4), name=SPLIT_TARGET_NAME[3]),
    #              tf.placeholder(tf.float32, shape=(None, None, 2), name=SPLIT_TARGET_NAME[4]),
    #              tf.placeholder(tf.float32, shape=(None, None), name=SPLIT_TARGET_NAME[5]),
    #              tf.placeholder(tf.float32, shape=(None), name=SPLIT_TARGET_NAME[6]),
    # ]

    """
    Load placeholder's graph_def.
    """
    target_def = []
    for node in tf.get_default_graph().as_graph_def().node:
        for stn in SPLIT_TARGET_NAME:
            if node.name == stn:
                target_def += [node]
    tf.reset_default_graph()

    graph_def = tf.GraphDef()
    with tf.gfile.GFile(model_path, 'rb') as fid:
        serialized_graph = fid.read()
        graph_def.ParseFromString(serialized_graph)

        """
        Check the connection of all nodes.
        edges[] variable has input information for all nodes.
        """
        edges = {}
        name_to_node_map = {}
        node_seq = {}
        seq = 0
        for node in graph_def.node:
            n = self.node_name(node.name)
            name_to_node_map[n] = node
            edges[n] = [self.node_name(x) for x in node.input]
            node_seq[n] = seq
            seq += 1

        """
        Alert if split target is not in the graph.
        """
        dest_nodes = SPLIT_TARGET_NAME
        for d in dest_nodes:
            assert d in name_to_node_map, "%s is not in graph" % d

        """
        Making GPU part.
        Follow all input nodes from the split point and add it into keep_list.
        """
        nodes_to_keep = set()
        next_to_visit = dest_nodes

        while next_to_visit:
            n = next_to_visit[0]
            del next_to_visit[0]
            if n in nodes_to_keep:
                continue
            nodes_to_keep.add(n)
            next_to_visit += edges[n]

        nodes_to_keep_list = sorted(list(nodes_to_keep), key=lambda n: node_seq[n])

        keep = graph_pb2.GraphDef()
        for n in nodes_to_keep_list:
            keep.node.extend([copy.deepcopy(name_to_node_map[n])])

        """
        Making CPU part.
        It removes GPU part from loaded graph and add new inputs.
        """
        nodes_to_remove = set()
        for n in node_seq:
            if n in nodes_to_keep_list: continue
            nodes_to_remove.add(n)
        nodes_to_remove_list = sorted(list(nodes_to_remove), key=lambda n: node_seq[n])

        remove = graph_pb2.GraphDef()
        for td in target_def:
            remove.node.extend([td])
        for n in nodes_to_remove_list:
            remove.node.extend([copy.deepcopy(name_to_node_map[n])])

        """
        Import graph_def into default graph.
        """
        with tf.device('/gpu:0'):
            tf.import_graph_def(keep, name='')

        with tf.device('/cpu:0'):
            tf.import_graph_def(remove, name='')

    """
    return    
    """
    return tf.get_default_graph()

model_path ='pth to the modelfile' split_model = True print(model_path) print(split_model) b = LoadFrozenGraph(model_path) graph2 = b.load_graph()

i get up this error File "/home/abilash-sk/.local/lib/python3.5/site-packages/tensorflow/python/framework/importer.py", line 663, in import_graph_def % (input_name,))) ValueError: graph_def is invalid at node 'SecondStageBoxPredictor/ClassPredictor/MatMul': Input tensor 'SecondStageBoxPredictor/Flatten/flatten/Reshape:0' not found in graph_def..

naisy commented 5 years ago

Hi @abhigoku10,

Is your Faster R-CNN based on a model before 2018_01_28? If not 2018_01_28 model, the split nodes will differ, probably because the graph is different. I do not know the exact places without looking at the graph. Do you know which graph is based?

abhigoku10 commented 5 years ago

@naisy hi Naisy ya we trained our faster rcnn on tensorflow1.8, can share the graph pls provide the email id or link .

naisy commented 5 years ago

Hi @abhigoku10,

My mail address is takanashi@gclue.jp

tesfagabir commented 5 years ago

I also got the same error when converting my own model as the above. @abhigoku10 how did you solve the issue?

abhigoku10 commented 5 years ago

@tesfagabir Hi i tried couple of ways i was not able to solve it , so i paused the activity . Do let me know if you solve that activity