神经网络的Python实时图像分类问题

use*_*300 30 python gpgpu multiprocessing deep-learning caffe

我正在尝试使用caffe和python进行实时图像分类.我在一个过程中使用OpenCV从我的网络摄像头流式传输,并在一个单独的过程中,使用caffe对从网络摄像头拉出的帧执行图像分类.然后我将分类结果传回主线程以标注网络摄像头流.

问题是即使我有一个NVIDIA GPU并且正在执行GPU上的caffe预测,主线程也会变慢.通常没有做任何预测,我的网络摄像头流以30 fps运行; 但是,根据预测,我的网络摄像头流最多可获得15 fps.

我已经验证了caffe在执行预测时确实使用了GPU,而且我的GPU或GPU内存并没有最大化.我还验证了我的CPU内核在程序中的任何时候都没有达到最大限度.我想知道我是做错了什么,或者是否有办法让这两个过程真正分开.任何建议表示赞赏.这是我的代码供参考

class Consumer(multiprocessing.Process):

    def __init__(self, task_queue, result_queue):
        multiprocessing.Process.__init__(self)
        self.task_queue = task_queue
        self.result_queue = result_queue
        #other initialization stuff

    def run(self):
        caffe.set_mode_gpu()
        caffe.set_device(0)
        #Load caffe net -- code omitted 
        while True:
            image = self.task_queue.get()
            #crop image -- code omitted
            text = net.predict(image)
            self.result_queue.put(text)

        return

import cv2
import caffe
import multiprocessing
import Queue 

tasks = multiprocessing.Queue()
results = multiprocessing.Queue()
consumer = Consumer(tasks,results)
consumer.start()

#Creating window and starting video capturer from camera
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
#Try to get the first frame
if vc.isOpened():
    rval, frame = vc.read()
else:
    rval = False
frame_copy[:] = frame
task_empty = True
while rval:
    if task_empty:
       tasks.put(frame_copy)
       task_empty = False
    if not results.empty():
       text = results.get()
       #Add text to frame
       cv2.putText(frame,text)
       task_empty = True

    #Showing the frame with all the applied modifications
    cv2.imshow("preview", frame)

    #Getting next frame from camera
    rval, frame = vc.read()
    frame_copy[:] = frame
    #Getting keyboard input 
    key = cv2.waitKey(1)
    #exit on ESC
    if key == 27:
        break
Run Code Online (Sandbox Code Playgroud)

我很确定这是因为caffe预测减慢了一切,因为当我评论预测并在进程之间来回传递虚拟文本时,我再次获得30 fps.

class Consumer(multiprocessing.Process):

    def __init__(self, task_queue, result_queue):
        multiprocessing.Process.__init__(self)
        self.task_queue = task_queue
        self.result_queue = result_queue
        #other initialization stuff

    def run(self):
        caffe.set_mode_gpu()
        caffe.set_device(0)
        #Load caffe net -- code omitted
        while True:
            image = self.task_queue.get()
            #crop image -- code omitted
            #text = net.predict(image)
            text = "dummy text"
            self.result_queue.put(text)

        return

import cv2
import caffe
import multiprocessing
import Queue 

tasks = multiprocessing.Queue()
results = multiprocessing.Queue()
consumer = Consumer(tasks,results)
consumer.start()

#Creating window and starting video capturer from camera
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
#Try to get the first frame
if vc.isOpened():
    rval, frame = vc.read()
else:
    rval = False
frame_copy[:] = frame
task_empty = True
while rval:
    if task_empty:
       tasks.put(frame_copy)
       task_empty = False
    if not results.empty():
       text = results.get()
       #Add text to frame
       cv2.putText(frame,text)
       task_empty = True

    #Showing the frame with all the applied modifications
    cv2.imshow("preview", frame)

    #Getting next frame from camera
    rval, frame = vc.read()
    frame_copy[:] = frame
    #Getting keyboard input 
    key = cv2.waitKey(1)
    #exit on ESC
    if key == 27:
        break
Run Code Online (Sandbox Code Playgroud)

MD.*_*ria 0

一种想法可能会发生在您的代码中,即第一次调用时它在 GPU 模式下工作,而在以后的调用中,它会在 cpu 模式下计算分类,因为它是默认模式。在旧版本的caffe上设置gpu模式一次就足够了,现在新版本每次都需要设置模式。您可以尝试进行以下更改:

def run(self):

        #Load caffe net -- code omitted 
        while True:
            caffe.set_mode_gpu()
            caffe.set_device(0)
            image = self.task_queue.get()
            #crop image -- code omitted
            text = net.predict(image)
            self.result_queue.put(text)

        return
Run Code Online (Sandbox Code Playgroud)

另请查看消费者线程运行时的 GPU 计时。对于 nvidia,您可以使用以下命令:

nvidia-smi
Run Code Online (Sandbox Code Playgroud)

上面的命令将显示运行时的 GPU 利用率。

如果还不能解决,另一种解决方案是,将opencv帧提取代码放在一个线程下。由于它与 I/O 和设备访问相关,因此在与 GUI 线程/主线程不同的线程上运行它可能会带来好处。该线程将把帧推送到队列中,当前的消费者线程将进行预测。在这种情况下,请小心处理具有关键块的队列。