上下文
作为一家保险公司,我们在Moonshot-Insurance不断尝试寻找新的方法来保护客户,同时为他们提供尽可能好的体验。
这种心态的一个例子是我们的碎屏保险产品。我们创建了一个快速、简单的索赔流程,可以用几句话来总结:如果您的智能手机屏幕坏了,只需发送一张图片,我们将直接赔偿您。没有文书工作,没有冗长的过程!
为了实现这一点,我们使用了一个计算机视觉模型,它可以自动检测智能手机屏幕上的任何损坏。目前的流程需要一张关机手机的照片来检测划痕,另一张照片来捕捉IMEI号码。
这种方法已经被证明是成功的,但我们想知道是否可以让这个过程更加直观。我们决定直接从网络浏览器测试视频流的实时分析。
2.如何执行图像检测
在深入视频检测之前,让我们快速讨论一下单个图像上的目标检测。在这里,我们的目标是拥有一个模型,我们向该模型发送图像,该模型返回我们感兴趣的特定功能。在我们的案例中,我们感兴趣的是:
- 图片中是否有智能手机
- 如果有,它的屏幕是否损坏。
这项技术现在已经变得相当普遍,人们可以很容易地找到涉及这个问题的理论和实践方面的文章和媒体帖子。最有效的模型之一,也是我们在本项目中使用的模型,是YOLO算法。该模型的体系结构是一个开放源码的神经网络Darknet,它具有预先训练好的权值,以及帮助我们进行训练和预测的方法。Darknet
为了训练这种计算机视觉模型,我们需要尽可能多的受损智能手机的图像。一旦我们有了足够的训练样本,在我们的例子中大约有200幅图像,下一步是为我们希望能够检测到的每个类别(智能手机和损坏)手动选择边界框。
一旦我们有了带注释的训练数据集,我们就可以使用它来训练我们的自定义YOLO模型。在训练过程中,模型将学习预测我们给出注释的每个类的概率图,目标是预测每个对象的边界框。这一步需要很大的计算能力,即使在高端计算机上也可能需要很长时间。我们使用两个RTX 2070 GPU来训练我们的定制模型,每个训练需要8到10个小时来完成。
训练完成后,YOLO模型可以返回找到图像的对象列表,以及相关的边界框和置信度。
使用OpenCV进行快速预测
我们现有的流程基于聊天机器人,它引导客户完成索赔申报的不同步骤,并收集电话图片。图片被发送到AWS S3存储桶;上传触发Lambda函数,该函数对图像运行预测模型。然后,聊天机器人使用分析结果来确定索赔过程中的下一步。
因此,模型需要快速且在Lambda函数的小计算能力内运行。
这种限制使我们无法使用Darknet模型的内置函数,因为使用Lambda函数基础设施预测它需要花费太多时间。幸运的是,OpenCV(最常用的计算机视觉库)有一个模块可以加载深度神经网络(DNN),如Darknet。只需几行代码来加载模型和自定义权重,我们就可以预测找到的对象的边界框和置信度。这需要我们再编写几行代码来处理该检测,并注意删除不相关的检测,在不到一秒的时间内,我们就可以知道图像是否真的是屏幕损坏的智能手机。
3.如何将其应用于视频
作为基本帧流的视频
正如我们在简介中提到的,我们的最终目标是分析实时视频流;这将提供更无缝的客户体验,并允许我们运行高级欺诈检测。
第一步是让模型在本地对预先录制的视频起作用。这很简单,因为视频基本上是一系列的单一图像。我们只需要循环遍历每一帧,并为每一帧做对象检测,我们就完成了™!
这种天真的方法工作得很好,但是太长了,在CPU推断的情况下勉强达到每秒1帧,在GPU的情况下大约达到5FPS。
由于我们希望用户在录制视频时实时看到边界框预测,这些帧率不足以提供流畅的体验。这意味着我们现在有两个问题要处理:让我们的模型在客户的™设备的实况流上运行(而不是在预先录制的视频上),以及提高预测速度以便能够实时显示它。
用于处理实时通信的aiortc
要撞击解决第一个问题,我们需要直接在浏览器中从设备摄像头获取视频源,因为我们希望无需安装应用程序就可以访问我们的索赔流程。幸运的是,这正是Web RTC的用途!更好的是,该标准有一个称为aiortc的python实现,允许我们轻松设置Web RTC服务器。它甚至有一个非常类似于我们在GitHub repo中的项目的很好的例子,该项目的œ演示了如何从网络摄像头读取帧并将其发送到浏览器�。这个示例和来自同一个repo的-euroœ服务器-euro�示例成为我们与客户端通信并从中获取实时视频流的工作画布。Web RTC aiortc GitHub repo
(对于我们对aiortc示例的修改感兴趣,您可以在这里找到server.py文件的完整代码:用于检测损坏电话的自定义服务器代码)Custom server code for damaged phone detection
该库另一个有趣的方面是数据通道(也是WebRTC规范的一部分)的实现,它使我们能够将动态数据从服务器发送到客户端。我们主要使用它在开发/测试时传输一些统计信息,但将部分工作委托给客户端或作为控制通道也可能非常有用。
有了这个实现,我们现在基本上可以与客户端浏览器进行实时通信,将从摄像机拍摄的实时视频发送到服务器,在那里我们可以进行艰苦的对象检测工作。一旦帧被处理,我们就可以将预测信息发送回客户端并显示它。我们仍然有一个问题,就是一得到帧就进行预测,以便实时显示。
用于快速推理的GPU
如前所述,在处理计算机视觉深度神经网络时,GPU比CPU带来了巨大的性能提升。我们在本地服务器上进行了测试,性能提升是不可否认的,但我们希望依赖云基础设施来完成此任务。我们选择使用AWS EC2 g4dn.xLarge实例来完成此任务,因为它们使用起来相对简单,而且GPU使用成本较低。在虚拟机上设置服务器和预测代码非常简单,一旦正确配置,我们就能够预测高达20 FPS,这对于Fluid显示器来说已经足够了。
优化和自定义规则
随着基本的视频处理流水线的运行,我们专注于如何优化我们的治疗。20fps的预测是不错的,但视频源仍然给我们提供了60fps的处理速度,这意味着当我们对1张图像进行预测时,我们还会有2张正在进行中。您可以清楚地看到,这会导致检测后录制和显示之间的延迟呈指数级增加。
我们的第一步是天真地只分析来自客户端的三分之一的图像。如果预测到帧,我们会显示真正的检测,如果不是,我们只会显示最后一次检测,因为在3帧中,对象在图像中没有移动太多。对这种幼稚的方法有一个简单的改进:我们不是任意处理3个图像中的1个,而是只处理最后一个传入的帧。这意味着当模型忙于推断时,我们丢弃每个传入的帧(并显示最后预测的帧),一旦预测完成,我们就开始处理客户端发送的最新帧。即使我们仍粗略评估1/3的整体帧,此比率现在也会根据服务器的性能动态调整。
在此特定用例中需要处理的另一个方面是确保在视频检测期间严格使用一部智能手机。我们的逻辑是这样的:在没有检测到手机的情况下,我们搜索一个。当我们第一次找到一部手机时,我们必须确保它不会退出图像,也不会在视频过程中出现另一部手机,这可能是欺诈行为(例如,在损坏检测和IMEI步骤之间切换手机)。要做到这一点,我们使用能够跟踪移动对象的对象跟踪器,即使它们被其他东西隐藏了几帧(或者只是模型没有检测到它),也可以跟踪移动的对象(œ�)。一旦检测到手机,就会给它分配一个跟踪器ID,如果用户移动摄像头,如果它退出画面和/或另一部手机也在图像中,我们就可以跟踪它。
# centroid tracking
objects = ct.update(prev_phone_bbox, last_objects = objects)
for (objectID, centroid) in objects.items():
text = "ID {}".format(objectID)
cv2.putText(img, text, (centroid[0] - 10, centroid[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 3)
cv2.circle(img, (centroid[0], centroid[1]), 10, (0, 255, 0), -1)
链接到本项目中使用的质心跟踪器类:Neoanarika/object-tracking-DetectionNeoanarika/object-tracking-detection
有了这些跟踪器,我们就可以实现自定义规则来确定是否接受声明。这些规则的定义非常简单:
- 手机不能离开录像带;
- 对于一定数量的连续帧,我们必须检测智能手机及其损坏情况。
当然,可以对这些规则进行调整以进行扩展,以跟踪我们想要实现的其他业务规则。
4.结论
下面您可以找到视频检测过程的gif。我们拥有有效的概念验证,可以远程分析实时视频流,向用户提供实时反馈,并根据分析做出业务决策。
那么,欧元™的下一步是什么呢?还有一些工作要改进检测逻辑和如何在视频中向用户显示信息。为此,通过数据通道将检测数据发送回浏览器,并让浏览器将相关信息覆盖在视频源上似乎很有趣。
我们还需要改进的另一个主要轴心是这个项目的可伸缩性。实际上,在这个阶段,我们只能处理数量非常有限的并发会话,因为我们每秒预测的总帧数是有上限的。解决这一问题的一种显而易见的方法是扩展设置,要么垂直扩展(租用更大的EC2实例,使用更多GPU),要么水平扩展(负载均衡器后面的几个实例)。这将是可行的,但也会产生重大的成本和运营影响。利用无服务器技术,就像我们为我们的基础设施的睡觉所做的那样是很好的,但不幸的是,目前ğŸ˜欧元还没有GPU的Lambda功能
原创文章,作者:fendouai,如若转载,请注明出处:https://panchuang.net/2021/06/10/%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e8%a7%86%e9%a2%91%e5%af%b9%e8%b1%a1%e6%a3%80%e6%b5%8b/