wizyoung / YOLOv3_TensorFlow

Complete YOLO v3 TensorFlow implementation. Support training on your own dataset.
MIT License
1.55k stars 579 forks source link

about freeze graph and convert TFlite problem #8

Open PanJinquan opened 5 years ago

PanJinquan commented 5 years ago

Hi, thank you so much for sharing your code! I have some questions and hope you could help me.I try to freeze graph and convert *.pb to TFlite model, so that can transport to Android mobile phones.This is my source code as follow:

But,I get a unsupported operation error as shown below:

b'2019-01-29 16:12:22.550452: I tensorflow/contrib/lite/toco/import_tensorflow.cc:1080] Converting unsupported operation: ResizeNearestNeighbor\n

Yes, about TFlite unsupported operation error,Could you help how to modify the yolov3 source code to support operation?

PanJinquan commented 5 years ago

This is my source code as follow: `

--coding: utf-8 --

""" @Project: tensorflow-yolov3 @File : freeze.py @Author : panjq @E-mail : pan_jinquan@163.com @Date : 2019-01-22 18:39:28 """

import os import time import numpy as np import tensorflow as tf import cv2 from utils.nms_utils import gpu_nms from utils.misc_utils import parse_anchors, read_class_names import tensorflow.contrib.lite as lite from utils.plot_utils import get_color_table, plot_one_box from model import yolov3

def show_image(imgori,boxes,scores_,classes,numclass,labels,width_ori,height_ori,new_size):

rescale the coordinates to the original image

color_table = get_color_table(num_class)
boxes_[:, 0] *= (width_ori / float(new_size[0]))
boxes_[:, 2] *= (width_ori / float(new_size[0]))
boxes_[:, 1] *= (height_ori / float(new_size[1]))
boxes_[:, 3] *= (height_ori / float(new_size[1]))

print("box coords:")
print(boxes_)
print('*' * 30)
print("scores:")
print(scores_)
print('*' * 30)
print("labels:")
print(labels_)

for i in range(len(boxes_)):
    x0, y0, x1, y1 = boxes_[i]
    scores=scores_[i]
    plot_one_box(img_ori, [x0, y0, x1, y1], label=classes[labels_[i]]+':'+str(scores)[:6], color=color_table[labels_[i]])
cv2.imshow('Detection result', img_ori)
# cv2.imwrite('detection_result.jpg', img_ori)
cv2.waitKey(30)

def read_pb_return_tensors(pb_file, return_elements): with tf.gfile.FastGFile(pb_file, 'rb') as f: frozen_graph_def = tf.GraphDef() frozen_graph_def.ParseFromString(f.read()) return_elements = tf.import_graph_def(frozen_graph_def, return_elements=return_elements) input_tensor, output_tensors = return_elements[0], return_elements[1:] return input_tensor, output_tensors

def freeze(sess, output_file, output_node_names):

output_graph_def = tf.graph_util.convert_variables_to_constants(
    sess,
    sess.graph.as_graph_def(),
    output_node_names,
)

with tf.gfile.GFile(output_file, "wb") as f:
    f.write(output_graph_def.SerializeToString())

print("=> {} ops written to {}.".format(len(output_graph_def.node), output_file))

def freeze_graph():

input_checkpoint = 'checkpoint/yolov3.ckpt-99'

# cpu_pb_path='checkpoint/yolov3.pb'
ckpt_path = "./data/darknet_weights/yolov3.ckpt"
pb_path= "./data/darknet_weights/yolov3.pb"
# 指定输出的节点名称,该节点名称必须是原模型中存在的节点
output_node_names = ["yolov3/yolov3_head/feature_map_1",
                  "yolov3/yolov3_head/feature_map_2",
                  'yolov3/yolov3_head/feature_map_3']
saver = tf.train.import_meta_graph(ckpt_path + '.meta', clear_devices=True)
with tf.Session() as sess:
    saver.restore(sess, ckpt_path)  # 恢复图并得到数据
    for op in sess.graph.get_operations():
        print(op.name, op.values())
    freeze(sess, pb_path, output_node_names)

def get_feature_map(input_image,pb_path):

定义一个计算图graph,获得feature_map

input_node_names = ["Placeholder:0"]
output_node_names = ["yolov3/yolov3_head/feature_map_1:0",
                  "yolov3/yolov3_head/feature_map_2:0",
                  'yolov3/yolov3_head/feature_map_3:0']
graph=tf.Graph()
with graph.as_default():
    input_tensor, output_tensors = read_pb_return_tensors(pb_path,input_node_names+output_node_names)
with tf.Session(graph=graph) as sess:
    feature_map= sess.run(output_tensors, feed_dict={input_tensor: input_image})
return feature_map

def pb_test_tf(img_ori,feature_map,classes,num_class,anchors,score_threshold,iou_threshold): ''' :param img_ori: :param feature_map: :param classes: :param num_class: :param anchors: :param score_threshold: :param iou_threshold: :return: ''' height_ori, width_ori = img_ori.shape[:2] img_size = [416, 416]

定义一个计算图graph,获得输出结果:

graph = tf.Graph()
with graph.as_default():
    feature_map_1, feature_map_2, feature_map_3 = feature_map
    feature_map_1 = tf.constant(feature_map_1, dtype=tf.float32)
    feature_map_2 = tf.constant(feature_map_2, dtype=tf.float32)
    feature_map_3 = tf.constant(feature_map_3, dtype=tf.float32)
    tf_img_size = tf.constant(value=img_size, dtype=tf.int32)
    print("img_size:{}".format(img_size))

    # model = yolov3FeatureMap.tf_yolov3FeatureMap(num_classes=num_classes, anchors=anchors)
    yolo_model = yolov3(num_class, anchors)

with tf.Session(graph=graph) as sess:
    pred_boxes, pred_confs, pred_probs = yolo_model.predict2(feature_map_1, feature_map_2, feature_map_3,tf_img_size)
    pred_scores = pred_confs * pred_probs

    boxes, scores, labels = gpu_nms(pred_boxes, pred_scores, num_class, max_boxes=30, score_thresh=score_threshold,
                                    iou_thresh=iou_threshold)

    # saver = tf.train.Saver()
    # saver.restore(sess, ckpt_path)

    boxes_, scores_, labels_ = sess.run([boxes, scores, labels])

    show_image(img_ori, boxes_, scores_, classes, num_class, labels_, width_ori, height_ori,
                          img_size)

def freeze_graph_test(): image_path = './data/demo_data/dog.jpg' anchor_path = "./data/yolo_anchors.txt" input_size = [416, 416] class_name_path = "./data/coco.names" pb_path= "./data/darknet_weights/yolov3.pb" score_threshold = 0.5 iou_threshold = 0.5

anchors = parse_anchors(anchor_path)
classes = read_class_names(class_name_path)
num_class = len(classes)

# 读取图像数据
img_ori = cv2.imread(image_path)
img_resized = cv2.resize(img_ori, tuple(input_size))
img_resized = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
img_resized = np.asarray(img_resized, np.float32)
img_resized = img_resized[np.newaxis, :] / 255.

feature_map = get_feature_map(img_resized, pb_path)
pb_test_tf(img_ori, feature_map, classes, num_class, anchors, score_threshold, iou_threshold)

def convert_tflite(): pb_path= "./data/darknet_weights/yolov3.pb" out_tflite ='./data/darknet_weights/converted_model.tflite' SIZE=416 input_arrays = ['Placeholder'] output_node_names = ["yolov3/yolov3_head/feature_map_1", "yolov3/yolov3_head/feature_map_2", 'yolov3/yolov3_head/feature_map_3'] input_shapes = {"Placeholder": [1, SIZE, SIZE, 3]} converter = lite.TFLiteConverter.from_frozen_graph( pb_path, input_arrays, output_node_names, input_shapes) tflite_model = converter.convert() open(out_tflite, "wb").write(tflite_model)

if name == 'main': freeze_graph() print("freeze_graph done...") freeze_graph_test() print("freeze_graph_test done...") convert_tflite() print("convert_tflite done...")

`

wizyoung commented 5 years ago

Hi, I guess in your TFlite version, ResizeNearestNeighbor of tf.image module has not been supported. According to this Link, you can try newer tflite version. Or you may change this line to other resize functions in tf.image module, please refer to link and have a try.

BytesBrewer commented 5 years ago

@PanJinquan Can you please send code for freeze graph. The indentations are not proper above. And were you successful in converting the model to tflite? Please help. I am currently struggling to export model to tflite.

yuanzhedong commented 5 years ago

How do get the input node as Placeholder:0? I use that code to freeze the model but when I test it I got the error ValueError: Requested return tensor 'Placeholder:0' not found in graph def, thanks!

wizyoung commented 5 years ago

@yuanzhedong Hi, you can refer to my answer in stackoverflow https://stackoverflow.com/a/49768479/6631854 to get the correct placeholder name.

yuanzhedong commented 5 years ago

@wizyoung Thanks for the help!

After running your example I do find Placeholder in the graph, the shape is 1, -1, -1:

name: "phase_train"
op: "Placeholder"
attr {
  key: "dtype"
  value {
    type: DT_BOOL
  }
}
attr {
  key: "shape"
  value {
    shape {
      unknown_rank: true
    }
  }
}
name: "iterator_handle_flag"
op: "Placeholder"
attr {
  key: "dtype"
  value {
    type: DT_STRING
  }
}
attr {
  key: "shape"
  value {
    shape {
    }
  }
}
name: "Placeholder"
op: "Placeholder"
attr {
  key: "dtype"
  value {
    type: DT_FLOAT
  }
}
attr {
  key: "shape"
  value {
    shape {
      dim {
        size: 1
      }
      dim {
        size: -1
      }
      dim {
        size: -1
      }
    }
  }
}

Here're all the placehoders:

[<tf.Operation 'phase_train' type=Placeholder>, <tf.Operation 'iterator_handle_flag' type=Placeholder>, <tf.Operation 'Placeholder' type=Placeholder>, <tf.Operation 'Placeholder_1' type=Placeholder>, <tf.Operation 'phase_train_1' type=Placeholder>, <tf.Operation 'iterator_handle_flag_1' type=Placeholder>, <tf.Operation 'Placeholder_2' type=Placeholder>, <tf.Operation 'Placeholder_1_1' type=Placeholder>, <tf.Operation 'phase_train_2' type=Placeholder>, <tf.Operation 'iterator_handle_flag_2' type=Placeholder>, <tf.Operation 'Placeholder_3' type=Placeholder>, <tf.Operation 'Placeholder_1_2' type=Placeholder>]
yuanzhedong commented 5 years ago

But after I freeze it I can't find the placeholder from the pb file:

code:

import tensorflow as tf
gf = tf.GraphDef()
gf.ParseFromString(open('./to_freeze/model.pb','rb').read())
print([n.name + '=>' +  n.op for n in gf.node if n.op in ('Placeholder')])

output:

['phase_train=>Placeholder']
AnikaP commented 5 years ago

@yuanzhedong @wizyoung any news on this one? I am having the same error:

Merge/MergeSummary (<tf.Tensor 'Merge/MergeSummary:0' shape=() dtype=string>,) => 2243 ops written to ./. ['phase_train=>Placeholder'] freeze_graph done... WARNING:tensorflow:From freeze_graph.py:90: FastGFile.init (from tensorflow.python.platform.gfile) is deprecated and will be removed in a future version. Instructions for updating: Use tf.gfile.GFile. Traceback (most recent call last): File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/importer.py", line 418, in import_graph_def graph._c_graph, serialized, options) # pylint: disable=protected-access tensorflow.python.framework.errors_impl.InvalidArgumentError: Requested return node 'Placeholder' not found in graph def

When I change freeze_graph to load the model before as in

    with tf.name_scope('input'):
        input_data = tf.placeholder(dtype=tf.float32, shape=[ 1, input_shape[0], input_shape[1], 3], name='input_data')
    model = yolov3(len(classes), anchors)
    with tf.variable_scope('yolov3'):
        feature_map = model.forward(input_data)
    sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))
    saver = tf.train.Saver()
    saver.restore(sess, FLAGS.trained_checkpoint_prefix)

    # the op name of the Placeholder changes in different TensorFlow versions.
    # To find out the correct placeholder op name in the Graphdef part of the .meta file:
    imported_graph = tf.get_default_graph()
    graph_op = imported_graph.get_operations()
    with open(FLAGS.output_directory + 'graphdef_output.txt', 'w') as f:
        for i in graph_op:
            f.write(str(i))
    output_node_names = ["yolov3/yolov3_head/feature_map_1", "yolov3/yolov3_head/feature_map_2", 'yolov3/yolov3_head/feature_map_3']
    freeze(sess, FLAGS.output_directory, output_node_names)

my output.txt looks better, but I now get the placeholder ['input/input_data=>Placeholder']

omarabid59 commented 4 years ago

Hey everyone, I took the following steps:

  1. Change the utils/nms_utils.py lines 53-55 to:
    boxes = tf.concat(boxes_list, axis=0, name='output/box_output')
    score = tf.concat(score_list, axis=0, name='output/score_output')
    label = tf.concat(label_list, axis=0, name='output/label_output')
  2. Freeze the graph link
  3. Test that the model works link

Hope this helps!

zpge commented 4 years ago

Hey everyone, I took the following steps:

  1. Change the utils/nms_utils.py lines 53-55 to:
boxes = tf.concat(boxes_list, axis=0, name='output/box_output')
score = tf.concat(score_list, axis=0, name='output/score_output')
label = tf.concat(label_list, axis=0, name='output/label_output')
  1. Freeze the graph link
  2. Test that the model works link

Hope this helps!

If I did not change the utils/nms_utils.py lines 53-55 at the training phase, will it work?

zpge commented 4 years ago

After frozen to pb file, the model still takes over 5 Gb on GPU. Is it normal?

yjsdut commented 4 years ago

hello,can you tell me the out_node and input nodes,I think the output nodes are:yolov3/yolov3_head/feature_map_2", 'yolov3/yolov3_head/feature_map_3 But I don't know the input nodes?Help.....

aluds123 commented 4 years ago

https://lutzroeder.github.io/netron/ Maybe can use this to find it.

aluds123 commented 4 years ago

@wizyoung @omarabid59 @PanJinquan Can anyone guide me how to use tflite to test image or video ? (I maybe success to convert it to tflite) What should I modify in test_single_image.py?

bujianyiwang commented 4 years ago

请问有从rtsp流每隔n帧跑yolov3检测实时人数的脚本吗?

aluds123 commented 4 years ago

@wizyoung @omarabid59 @PanJinquan Can anyone guide me how to use tflite to test image or video ? (I maybe success to convert it to tflite) What should I modify in test_single_image.py?

I already success. Thanks.

balajib363 commented 4 years ago

@aluds123 could you share here how you able to achieve it?

Albert337 commented 4 years ago

hello,can you tell me the out_node and input nodes,I think the output nodes are:yolov3/yolov3_head/feature_map_2", 'yolov3/yolov3_head/feature_map_3 But I don't know the input nodes?Help.....

i got the same problems,had you solved it?

aluds123 commented 4 years ago

Hi, @BalajiB197 This is a part of code to convert .ckpt to .pb:


frozen_graph_def = graph_util.convert_variables_to_constants( sess, sess.graph_def, ["yolov3/yolov3_head/feature_map_1","yolov3/yolov3_head/feature_map_2","yolov3/yolov3_head/feature_map_3"]) tf.train.write_graph( frozen_graph_def, os.path.dirname(output_file), os.path.basename(output_file), as_text=False) tf.logging.info('Saved frozen graph to %s',output_file)


And I use toco to convert .pb to .tflite:


toco tflite_convert --graph_def_file=abc.pb --output_file=abc.tflite --input_format=TENSORFLOW_GRAPHDEF --output_format=TFLITE --inference_type=QUANTIZED_UINT8 --input_shape="1,416, 416,3" --input_array=input_data --output_array=yolov3/yolov3_head/feature_map_1,yolov3/yolov3_head/feature_map_2,yolov3/yolov3_head/feature_map_3 --mean_values 0 --std_dev_values 255 --default_ranges_min 0 --default_ranges_max 6 (I use quantization aware training, so you should modify some parameter like "input_format", "inference_type" .......)


github2016-yuan commented 4 years ago

@PanJinquan @aluds123 I have already get pb file but I do not know how to test it. From code above, I select some code.

def freeze_graph_test():
    image_path = './data/demo_data/dog.jpg'
    anchor_path = "./data/yolo_anchors.txt"
    input_size = [416, 416]
    class_name_path = "./data/coco.names"
    pb_path= "./data/darknet_weights/yolov3.pb"
    score_threshold = 0.5
    iou_threshold = 0.5

    anchors = parse_anchors(anchor_path)
    classes = read_class_names(class_name_path)
    num_class = len(classes)

    # 读取图像数据
    img_ori = cv2.imread(image_path)
    img_resized = cv2.resize(img_ori, tuple(input_size))
    img_resized = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
    img_resized = np.asarray(img_resized, np.float32)
    img_resized = img_resized[np.newaxis, :] / 255.

    feature_map = get_feature_map(img_resized, pb_path)
    pb_test_tf(img_ori, feature_map, classes, num_class, anchors, score_threshold, iou_threshold)
def pb_test_tf(img_ori,feature_map,classes,num_class,anchors,score_threshold,iou_threshold):
    '''
    :param img_ori:
    :param feature_map:
    :param classes:
    :param num_class:
    :param anchors:
    :param score_threshold:
    :param iou_threshold:
    :return:
    '''
    height_ori, width_ori = img_ori.shape[:2]
    img_size = [416, 416]
    # 定义一个计算图graph,获得输出结果:
    graph = tf.Graph()
    with graph.as_default():
        feature_map_1, feature_map_2, feature_map_3 = feature_map
        feature_map_1 = tf.constant(feature_map_1, dtype=tf.float32)
        feature_map_2 = tf.constant(feature_map_2, dtype=tf.float32)
        feature_map_3 = tf.constant(feature_map_3, dtype=tf.float32)
        tf_img_size = tf.constant(value=img_size, dtype=tf.int32)
        print("img_size:{}".format(img_size))

    # model = yolov3FeatureMap.tf_yolov3FeatureMap(num_classes=num_classes, anchors=anchors)
    yolo_model = yolov3(num_class, anchors)

    with tf.Session(graph=graph) as sess:
        pred_boxes, pred_confs, pred_probs = yolo_model.predict2(feature_map_1, feature_map_2, feature_map_3,tf_img_size)
        pred_scores = pred_confs * pred_probs

        boxes, scores, labels = gpu_nms(pred_boxes, pred_scores, num_class, max_boxes=30, score_thresh=score_threshold,
                                    iou_thresh=iou_threshold)

    # saver = tf.train.Saver()
    # saver.restore(sess, ckpt_path)

        boxes_, scores_, labels_ = sess.run([boxes, scores, labels])

        show_image(img_ori, boxes_, scores_, classes, num_class, labels_, width_ori, height_ori,
                          img_size)
def show_image(img_ori,boxes_,scores_,classes,num_class,labels_,width_ori,height_ori,new_size):
    #  rescale the coordinates to the original image
    color_table = get_color_table(num_class)
    boxes_[:, 0] *= (width_ori / float(new_size[0]))
    boxes_[:, 2] *= (width_ori / float(new_size[0]))
    boxes_[:, 1] *= (height_ori / float(new_size[1]))
    boxes_[:, 3] *= (height_ori / float(new_size[1]))

    print("box coords:")
    print(boxes_)
    print('*' * 30)
    print("scores:")
    print(scores_)
    print('*' * 30)
    print("labels:")
    print(labels_)

    for i in range(len(boxes_)):
        x0, y0, x1, y1 = boxes_[i]
        scores=scores_[i]
        plot_one_box(img_ori, [x0, y0, x1, y1], label=classes[labels_[i]]+':'+str(scores)[:6], color=color_table[labels_[i]])
    cv2.imshow('Detection result', img_ori)
    # cv2.imwrite('detection_result.jpg', img_ori)
    cv2.waitKey(30)

In function pb_test_tf()

yolo_model = yolov3(num_class, anchors)
pred_boxes, pred_confs, pred_probs = yolo_model.predict2(feature_map_1, feature_map_2, feature_map_3,tf_img_size)

It still uses yolov3 net structure, but it is known to us all that when inference with pb file, we do not need net structure. What we need are pb file, input_node_name(s) and out_put_name(s). Here is a sample code about using pb for inference. https://github.com/github2016-yuan/tensorflow-yolov3/blob/master/image_demo.py Need your help.