Использование многопоточности для вывода в Tensorflow с OpenCV

Я знаю, что использование многопоточности полезно для обучения DNN с помощью Tensorflow.

Но есть ли смысл использовать его для вывода? Например, если вы используете API обнаружения объектов Google для обнаружения объектов в реальном времени в видеопотоках? И если да, то как это реализовано?

Я создал репозиторий github (https://github.com/GustavZ/realtime_object_detection), который позволяет легко Обнаружение объекта времени, но меня не устраивает сгенерированный FPS, поэтому я подумал об использовании многопоточности для его ускорения.

Есть ли у кого-нибудь опыт с этим или может помочь мне реализовать его в моем коде?

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Thu Dec 21 12:01:40 2017
@author: GustavZ
"""
import numpy as np
import os
import six.moves.urllib as urllib
import tarfile
import tensorflow as tf
import cv2


# Protobuf Compilation (once necessary)
os.system('protoc object_detection/protos/*.proto --python_out=.')

from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util
from stuff.helper import FPS2

# Define Video Input
# Must be OpenCV readable
# 0 = Default Camera
video_input = 0
width = 640
height = 480
fps_interval = 3

# Model preparation
# What model to download.
MODEL_NAME = 'ssd_mobilenet_v1_coco_2017_11_17'
MODEL_FILE = MODEL_NAME + '.tar.gz'
DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'
# Path to frozen detection graph. This is the actual model that is used for the object detection.
PATH_TO_CKPT = 'models/' + MODEL_NAME + '/frozen_inference_graph.pb'
# List of the strings that is used to add correct label for each box.
LABEL_MAP = 'mscoco_label_map.pbtxt'
PATH_TO_LABELS = 'object_detection/data/' + LABEL_MAP
NUM_CLASSES = 90

# Download Model    
if not os.path.isfile(PATH_TO_CKPT):
    print('Model not found. Downloading it now.')
    opener = urllib.request.URLopener()
    opener.retrieve(DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE)
    tar_file = tarfile.open(MODEL_FILE)
    for file in tar_file.getmembers():
      file_name = os.path.basename(file.name)
      if 'frozen_inference_graph.pb' in file_name:
        tar_file.extract(file, os.getcwd())
    os.remove('../' + MODEL_FILE)
else:
    print('Model found. Proceed.')

# Load a (frozen) Tensorflow model into memory.
detection_graph = tf.Graph()
with detection_graph.as_default():
  od_graph_def = tf.GraphDef()
  with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
    serialized_graph = fid.read()
    od_graph_def.ParseFromString(serialized_graph)
    tf.import_graph_def(od_graph_def, name='')

# Loading label map
label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)

# Start Video Stream
video_stream = cv2.VideoCapture(video_input)
video_stream.set(cv2.CAP_PROP_FRAME_WIDTH, width)
video_stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height)

# Detection
print ("Press 'q' to Exit")
with detection_graph.as_default():
  with tf.Session(graph=detection_graph) as sess: # config=tf.ConfigProto(log_device_placement=True)
    # Definite input and output Tensors for detection_graph
    image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
    # Each box represents a part of the image where a particular object was detected.
    detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
    # Each score represent how level of confidence for each of the objects.
    # Score is shown on the result image, together with the class label.
    detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
    detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')
    num_detections = detection_graph.get_tensor_by_name('num_detections:0')
    # fps calculation
    fps = FPS2(fps_interval).start()
    while video_stream.isOpened():
      ret_val,image_np = video_stream.read()
      # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
      image_np_expanded = np.expand_dims(image_np, axis=0)
      # Actual detection.
      (boxes, scores, classes, num) = sess.run(
          [detection_boxes, detection_scores, detection_classes, num_detections],
          feed_dict={image_tensor: image_np_expanded})
      # Visualization of the results of a detection.
      vis_util.visualize_boxes_and_labels_on_image_array(
          image_np,
          np.squeeze(boxes),
          np.squeeze(classes).astype(np.int32),
          np.squeeze(scores),
          category_index,
          use_normalized_coordinates=True,
          line_thickness=8)
      cv2.imshow('object_detection', image_np)
      # Exit Option
      if cv2.waitKey(1) & 0xFF == ord('q'):
          break
      fps.update()

# End everything
video_stream.release()     
cv2.destroyAllWindows()
fps.stop()
print('[INFO] elapsed time (total): {:.2f}'.format(fps.elapsed()))
print('[INFO] approx. FPS: {:.2f}'.format(fps.fps()))

person gustavz    schedule 03.01.2018    source источник
comment
Я бы не ожидал, что вызов sess.run() из нескольких потоков улучшит вашу пропускную способность. Основная среда выполнения TensorFlow уже сильно многопоточная. Ваш код Python просто запускает выполнение. Одна вещь, которая может улучшить вашу пропускную способность, — это объединить множество изображений и один раз вызвать sess.run(). Я мало знаю о других вызовах, которые вы делаете (например, video_stream.read()), чтобы предположить, может ли многопоточность помочь с ними.   -  person iga    schedule 04.01.2018
comment
Вероятно, вы не сможете ускорить вызовы sess.run() с помощью многопоточности. Я не знаю, можете ли вы для video_stream.read(), я тоже не знаком с этим. Но у вас может быть один процесс, читающий видеопоток, и другой, делающий выводы, так что ни один из них не должен ждать завершения другого. Это может быть интересно только в том случае, если две операции занимают примерно одинаковое время, что, вероятно, не так, как есть (чтение изображений из потока должно быть намного быстрее), но может стать случаем с большим размером пакета.   -  person gdelab    schedule 08.01.2018


Ответы (1)


Это имеет смысл только в том случае, если вы запускаете его на устройстве, где ваши вычислительные мощности ограничены. По сути, вы должны запускать в разных потоках обработку изображений и вывод. Результатом будет плавное отображение видео, а ваш вывод будет отставать, не влияя на частоту кадров вашего дисплея. Вы можете увидеть на этот файл (просто черновик, еще не проверенный) о том, как будет выглядеть многопоточность.

Я загружаю свою модель и начинаю свою сессию, затем просматриваю захваченное видео, загружая свою очередь прогнозов, если у меня есть возможности сделать это.

person Vincent Teyssier    schedule 08.04.2018