Raspberry Pi 上的云对象检测器视频

序幕

现在互联网上流传着一段视频,展示了特斯拉的自动驾驶仪如何看待道路。

很长一段时间以来,我一直渴望实时播放用探测器丰富的视频。

Raspberry Pi 上的云对象检测器视频

Проблема в том, что транслировать видео я хочу с Raspberry, а производительность нейросетевого детектора на ней оставляет желать лучшего.

英特尔神经计算机棒

我考虑了不同的解决方案。

В 上一篇文章 尝试了英特尔神经计算机棒。 硬件功能强大,但需要自己的网络格式。

尽管英特尔为主要框架提供了转换器,但仍然存在许多缺陷。

例如,所需网络的格式可能不兼容,如果兼容,则设备上可能不支持某些层,如果支持,则在转换过程中可能会出现错误,从而导致我们在输出中得到一些奇怪的东西。

一般来说,如果你想要某种任意的神经网络,那么它可能不适用于 NCS。 因此,我决定尝试使用最广泛且易于使用的工具来解决该问题。

本地硬件解决方案的明显替代方案是迁移到云端。

现成的选择——我的眼睛变得疯狂。

各位领导:

...还有几十个鲜为人知的。

在这个品种中进行选择并不容易。

我决定不选择,而是将 OpenCV 上良好的旧工作方案包装在 Docker 中并在云中运行。

这种方法的优点是灵活性和控制性——你可以改变神经网络、托管、服务器——一般来说,任何突发奇想。

服务器

让我们从本地原型开始。

传统上我使用 Flask 来实现 REST API、OpenCV 和 MobileSSD 网络。

在 Docker 上安装了当前版本后,我发现 OpenCV 4.1.2 不适用于 Mobile SSD v1_coco_2018_01_28,我不得不回滚到经过验证的 11/06_2017。

在服务启动时,我们加载类名和网络:

def init():
    tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
    return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)

在本地 docker 上(在一台不太年轻的笔记本电脑上)需要 0.3 秒,在 Raspberry 上需要 3.5 秒。

我们开始计算:

def inference(img):
    net.setInput(cv.dnn.blobFromImage(img, 1.0/127.5, (300, 300), (127.5, 127.5, 127.5), swapRB=True, crop=False))
    return net.forward()

Docker - 0.2 秒,Raspberry - 1.7。

将张量排气转换为可读的 json:

def build_detection(data, thr, rows, cols):
    ret = []
    for detection in data[0,0,:,:]:
        score = float(detection[2])
        if score > thr:
            cls = int(detection[1])
            a = {"class" : cls, "name" : tf_labels.getLabel(cls),  "score" : score}
            a["x"] = int(detection[3] * cols)
            a["y"] = int(detection[4] * rows)
            a["w"] = int(detection[5] * cols ) - a["x"]
            a["h"] = int(detection[6] * rows) - a["y"]
            ret.append(a)
    return ret

进一步 通过 Flask 导出此操作(输入是图片,输出是json格式的检测器结果)。

另一种选择是将更多工作转移到服务器:它本身会圈出找到的对象并返回完成的图像。

当我们不想将 opencv 拖到服务器时,此选项非常有用。

码头工人

我们收集图像。

代码梳理了一下,贴在 Github,docker会直接从那里获取它。

我们将使用与 Raspberry 相同的 Debian Stretch 作为平台 - 我们不会偏离经过验证的技术堆栈。

您需要安装flask、protobuf、requests、opencv_python、从Github下载Mobile SSD、服务器代码并启动服务器。

FROM python:3.7-stretch

RUN pip3 install flask
RUN pip3 install protobuf
RUN pip3 install requests
RUN pip3 install opencv_python

ADD http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_11_06_2017.tar.gz /
RUN tar -xvf /ssd_mobilenet_v1_coco_11_06_2017.tar.gz

ADD https://github.com/tprlab/docker-detect/archive/master.zip /
RUN unzip /master.zip

EXPOSE 80

CMD ["python3", "/docker-detect-master/detect-app/app.py"]

简单 探测器客户端 根据要求。

发布到 Docker Hub

Docker 注册表的倍增速度不亚于云检测器。

为了不打扰,我们会保守地经历 DockerHub.

  1. 登记
  2. 登录:
    码头登录
  3. 让我们起一个有意义的名字:
    docker 标签 opencv-检测 tprlab/opencv-检测-ssd
  4. 将图片上传到服务器:
    docker Push tprlab/opencv-检测-ssd

我们在云端启动

在哪里运行容器的选择也相当广泛。

所有大型企业(谷歌、微软、亚马逊)第一年都免费提供微型实例。
在尝试了 Microsoft Azure 和 Google Cloud 后,我选择了后者,因为它发展得更快。

我没有在这里写说明,因为这部分是针对所选提供商的。

我尝试了不同的硬件选项,
低级别(共享和专用)- 0.4 - 0.5 秒。
更强大的汽车 - 0.25 - 0.3。
嗯,即使在最坏的情况下,奖金也是三倍,你可以尝试一下。

视频

我们在 Raspberry 上启动了一个简单的 OpenCV 视频流传输器,通过 Google Cloud 进行检测。
在实验中,使用了曾经在随机十字路口拍摄的视频文件。


def handle_frame(frame):
    return detect.detect_draw_img(frame)
       
def generate():
    while True:
        rc, frame = vs.read()
        outFrame = handle_frame(frame)
        if outFrame is None:
            (rc, outFrame) = cv.imencode(".jpg", frame)
        yield(b'--framern' b'Content-Type: image/jpegrnrn' + bytearray(outFrame) + b'rn')

@app.route("/stream")
def video_feed():
    return Response(generate(), mimetype = "multipart/x-mixed-replace; boundary=frame")

使用探测器,我们每秒获得的帧数不超过三帧,一切都进行得很慢。
如果你把一台功能强大的机器放入GCloud,你可以每秒检测到4-5帧,但肉眼几乎看不到差别,它仍然很慢。

Raspberry Pi 上的云对象检测器视频

云和运输成本与此无关;探测器在常规硬件上运行并以该速度工作。

神经电脑棒

我无法抗拒并在 NCS 上运行了基准测试。

检测器的速度略慢于 0.1 秒,无论如何比弱机器上的云快 2-3 倍,即每秒 8-9 帧。

Raspberry Pi 上的云对象检测器视频

结果差异的原因是 NCS 运行的是移动 SSD 版本 2018_01_28。

PS 另外,实验表明,配备 I7 处理器的功能相当强大的台式机显示出稍微好一点的结果,并且可以在其上挤出每秒 10 帧的速度。

实验更进一步,我在 Google Kubernetes 的五个节点上安装了检测器。
Pod 本身很弱,每个 Pod 每秒处理的帧数不能超过 2 帧。
但是,如果您运行具有 N 个节点的集群并在 N 个线程中解析帧,那么通过足够数量的节点 (5),您可以实现所需的每秒 10 帧。

def generate():
    while True:
        rc, frame = vs.read()
        if frame is not None:
            future = executor.submit(handle_frame, (frame.copy()))
            Q.append(future)

        keep_polling = len(Q) > 0
        while(keep_polling):            
            top = Q[0]
            if top.done():
                outFrame = top.result()
                Q.popleft()
                if outFrame:
                    yield(b'--framern' b'Content-Type: image/jpegrnrn' + bytearray(outFrame) + b'rn')
                keep_polling = len(Q) > 0
            else:
                keep_polling = len(Q) >= M

这里发生了什么:

Raspberry Pi 上的云对象检测器视频

比 NCS 速度稍慢,但比单流更有活力。

当然,增益不是线性的——有用于同步和深度复制 opencv 图像的覆盖。

结论

总的来说,这个实验让我们得出这样的结论:如果你尝试,你就可以使用简单的云。

但是强大的桌面或本地硬件可以让您获得更好的结果,并且无需任何技巧。

引用

来源: habr.com

添加评论