作者 | 行书
项目背景
根据经验,休闲好玩易上手的互动小游戏能够显著提高用户活跃度,这也是用户参与双十一非常重要的一种形式,然而传统小游戏由于用户互动性不强、商家参与度不高,并没有对品牌做到很好的宣传和转化。与此同时我们注意到,随着近些年深度学习的兴起,基于计算机视觉的AI技术得到了长足的发展,这些技术可以为传统游戏插上智能的翅膀,从而为用户提供更自然、更新奇、更有趣的交互方式。
为此,我们联合十五大品牌在双十一前的预热活动期间上线了“与明星一起猜拳”的互动游戏。该游戏脱胎于人民群众喜闻乐见的“石头、剪刀、布”,利用手机前置摄像头实时识别用户当前所做的手势动作,同时产品交互上加入为品牌代言的明星元素,让用户与自己喜爱的明星进行比赛互动,极大地增加了游戏的趣味性和可玩性。在游戏结束的时候,通过发放优惠券等形式将用户导流到商家店铺内以促成成交。
一方面,这种新型的游戏形式能够极大地引起用户的参与热情,另一方面,商家可以借此更加充分地利用代言明星资源,将其更直接地转化为品牌背书和产品销量。据统计,整个活动期间的PV达到了1600w+,UV达到了1000w+,得到了用户和商家的一致好评。
值得一提的是,蓝月亮在看到线上超预期的效果后主动联系我们帮助支持他们线下的快闪活动,现场用户的参与热情非常高。
蓝月亮线下快闪活动
问题定义
猜拳游戏中我们需要实时识别出用户当前所做的手势动作,这在计算机视觉中叫做手势识别。对于手势识别,有些方法将其看作是分类问题,也就是只给出一个结果,因为其输入图片中只有一只手,可是这样用在猜拳游戏中会有两个问题:
- 手的个数是不确定的,比如有些用户可能会通过同时做出多种不同的手势来作弊,这是分类无法解决的。
- 手的位置和大小是不确定的,用户在用前置摄像头玩游戏的时候图像中大部分都是脸和背景,手并不是图像中的主要物体,如果看成分类问题算法会很难进行学习。
为了解决这两个问题,很自然地,我们应该先从图中找到手的位置,然后再对其进行分类,这也就是目标检测要做的事情。
困难挑战
作为人民群众喜闻乐见的一种游戏形式,猜拳可以说是真正做到了跨国家、跨文化、跨种族,基于其公平简单易上手的特性开发的“终端分歧机”甚至都让我们敬爱的大忽悠葛优同学获得了200万英镑的风投(见《非诚勿扰》),因此将其开发为互动游戏对于用户来说几乎没有学习成本。
这对产品来说是好事,但对算法来说却不是那么友好。因为伟大作家莎士比亚曾说过,一千个人里有一千种剪刀石头布,每个人在玩游戏时候的动作姿势都不尽相同。如果是一个大家不曾见过或不熟悉的新手势,那我们可以定义其标准,只要跟标准手势不符合的都可以判别为错,用户在模仿这种手势的时候也会有意按照标准去做,但是对于大家从小玩到大的猜拳,我们无法做这种标准定义,因为每个人都会觉得自己的动作浑然天成毫无瑕疵最为标准。另外,除了目标手势,我们还需要识别出不属于目标的其他手势,而这些手势更加没有标准,唯一的标准就是不属于目标手势(石头、剪刀、布)。
没有明确的标准定义除了会导致上面的问题外,还会引发其他严重的问题。由于手是非刚体,形变极大,同一个手势会表现出很多形态,再加上角度等问题,使得我们几乎不可能穷举所有可能的情况。
另外,用户在切换手势的过程中会出现很多中间形态,这些形态的类别也很难确定。其他的诸如“同样的手在不同位置时的手势是否相同(比如同样是张开的手,放在面前的时候是“布”,放在腿上的时候还是”布“吗)”,“不同的手势由于角度问题导致呈现出相似的形态”,“不同标注人员对同一手势图片的不同理解”等等,都是实际开发过程中遇到的问题。
猜拳游戏的手势识别其实是一个动态的过程,用户在游戏准备阶段一般会先握紧拳头,等提示说出“石头剪刀布”的时候才会做出最终的手势类型。因为每个人的反应时间不一样,所以我们在明星说出“布”的前后时间段内会设置一个区间,只有在该时间区间内的手势才会被算法识别,过早或过晚都不行。因为是时间区间,因此会有多帧图片产生,而最终的结果则是取识别次数最多的手势。
但是该时间段不能设置得太长也不能设置得太短,时间太长容易让人作弊,而且会将准备阶段识别为石头,时间太短用户则会反应不过来。考虑到要识别多张图片(一般十几到几十张),为了给用户提供如丝般顺滑的体验,我们要求整个检测识别的过程能够在手机上实时运行,但是不同手机的性能差距很大,尤其是安卓机器,这就需要我们的算法模型对资源的要求不能太高且运行速度要够快。除此以外,因为我们的算法模型是动态下发的,用户在第一次玩的时候需要下载模型,所以模型不能够太大,也就是说我们的算法既要小又要快还要好。
总结起来,猜拳游戏在技术上主要有两个难点:
- 目标手势没有明确定义
- 模型既要小又要快还要好
算法解析
目标检测
相比于分类任务只给出整张图像的一个描述,检测更多的是关注局部特定的物体目标,其要求同时给出图像中所有目标的类别信息和位置信息,因此检测模型的输出是一个列表,列表的每一项给出了检出目标的类别和位置(常用矩形检测框的坐标表示)。
分类与检测的区别
现代的检测模型整体上由主干网络(Backbone Network)和头部网络(Head Network)两部分构成,前者作为特征提取器,给出图像不同大小、不同抽象层次的表示,后者则依据这些表示和监督信息进行类别和位置学习,其中头部网络负责的类别预测和位置回归两个任务常常是并行的,从而构成多任务联合训练。
目前主流的目标检测方法可以大致分为两类:one-stage和two-stage。One-stage的代表算法是YOLO系列1[3]、SSD[4]、RetinaNet[5]等,当然今年也涌现了很多AnchorFree的方法,比如CornerNet[15]、CenterNet[16]等。Two-stage的代表算法则是RCNN系列,如Faster-RCNN[7]、RFCN[8]、Mask-RCNN[9]等。
Two-stage模型对检测任务进行了分解,即先用主干网络做前背景的分类,再用头部网络做物体的细粒度分类,因此其主干网络和头部网络是串行连接的,主干网络完成前背景分类和回归后,把预测结果作为头部网络的输入再进行细粒度分类和位置回归。这种设计使得监督信息可以在不同阶段对网络参数的学习进行针对性的指导,同时前背景的预测结果为头部网络提供了良好的先验知识,减轻了头部网络的学习负担。然而这种串行设计使得大量中间结果的存在拖累了模型的推断速度,而且还存在网络重复计算的弊端。
Two-stage代表算法Faster RCNN流程图
与此相反,one-stage模型只做一次类别预测和位置回归,卷积运算的共享程度更高,因此拥有更快的速度和更小的内存占用。考虑到我们的模型要在移动端实时运行,因此选用one-stage模型更加合适。
SSD简介
SSD(Single-Shot Multibox Detector)是one-stage模型中的代表算法,其速度快、效果好、易扩展,在各方面的表现都比较均衡,因此成为移动端目标检测应用的首选。SSD主要有三个特点:
- 多尺度特征图预测
所谓多尺度指的是同时采用网络中不同大小的特征图。CNN网络一般前面的特征图比较大,后面会逐渐采用stride=2的卷积或者pooling来降低特征图大小,如下图所示,一个比较大的特征图和一个比较小的特征图都被用来做检测,大特征图因为保留了更多的细节信息所以可以用来检测相对较小的物体,而小特征图因为感受野更大特征更抽象所以可以用来检测大的物体。
多尺度预测
- 多尺寸多比例先验框
SSD借鉴了Faster RCNN中锚框(anchor)的概念,每个单元设置尺度和长宽比不同的先验框,预测的边界框是以这些先验框为基准的,这样可以在一定程度上降低训练难度。通常来说,每个单元会设置多个先验框,其尺度和长宽比存在差异,如下图所示,可以看到每个单元使用了4个不同的先验框,图片中猫和狗分别采用最适合它们形状的先验框来进行训练学习。
anchor示例
- 全卷积
SSD整个网络架构中全部使用卷积方式进行特征抽取,没有用到全链接,所以运算更高效、更省内存。
SSD网络架构
主干网络
在当前计算机视觉的研究中,无论是分类、检测、分割还是其他任务,只要采用了深度学习框架,主干网络的选择几乎都是决定算法速度和效果的最主要因素。但天下没有免费的午餐又决定了速度和效果是很难兼得的,一般来说,模型越深越复杂效果越好,但速度也会越慢,反之亦是如此。如上图中所示的原始SSD使用的主干网络是VGG,先不论效果和速度,单是模型大小就有几百M,这是根本不可能用在移动端上的。
为了能够在资源受限的设备上取得更好更快的效果,业界相继提出了SqueezeNet[10]、ShuffleNet[11]、MobileNet12、MNasNet[14]等经典结构,其中MNasNet是Google发布的专为移动设备打造的网络架构,其构建过程采用了强化学习的思路,同时将模型运行速度显示地结合到优化目标中,这样模型在学习过程中就可以取得准确性和实时性的最佳平衡,而且由于其直接在手机平台(Pixel phones等)上运行模型,得到的结果具有很高的参考价值和实用价值。
MNasNet与其他模型对比
但无论是哪种网络,要想直接拿过来大规模地用在各种机型上都是难以满足要求的,为此我们在SSD的基础上对主干网络进行了大量优化,使其能够在大部分设备上都能够达到游戏运行要求。
特征融合
上面讲到SSD是多尺度进行学习预测,所以其会用到浅层的网络特征,然而浅层特征虽然细节内容丰富但是语义信息却很少,导致SSD对小目标的检测效果不是很好。为了解决小目标检测的问题,人们提出了很多方法,但基本思想都是特征融合,即将深层特征与浅层特征进行融合以达到兼顾高层语义和底层细节的目的。融合方法有很多,比如FPN[6]、DSSD[17]、RFBNet[18]等等,每种方法都有自己的优缺点,这里重点介绍下大家最常用的特征金字塔网络FPN。
如下图所示,FPN包含三部分:自底向上,自顶向下,横向连接(lateral connection)。自底向上其实就是主干网络的前向过程,在前向过程中,特征图的大小在经过某些层后会改变,而在经过其他层的时候不会改变,我们将不改变特征图大小的层归为一个stage,抽取的特征是每个stage最后一层的输出,这样就能构成特征金字塔。自顶向下的过程采用上采样(upsampling)进行,而横向连接则是将上采样的结果和自底向上生成的相同尺寸大小的特征图进行融合。在融合之后还会再采用3x3的卷积核对每个融合结果进行卷积,目的是消除上采样的混叠效应。
特征融合FPN
损失函数
目标检测的损失函数可以分为两部分,即定位损失(loc loss)加分类损失(cls loss),总损失为两者的加权和。SSD中定位损失采用了常用的smooth L1 loss,分类损失采用了softmax loss。
对于猜拳来说,我们的目标手势类别有三种:剪刀、石头、布,但除此以外我们还需要将其他手势跟这三种手势区分开来,再加上背景类,其实是一个五分类问题(剪刀、石头、布、其他、背景)。对于上面提到的softmax loss,这个损失函数隐含要求了必须从候选类里选一个作为目标类别,因为所有候选类的预测概率和要等于1。
如果是一般的分类问题用这种loss没有任何问题,但是当遇到了我们之前提到的问题——手势没有明确的定义,则会衍生出来一个非常严重的问题:手是非刚体,其形变几乎是无穷的,但我们的数据却是有限的,永远无法覆盖所有情况,而“其他手势”这个类别的存在会使得模型非常容易将没有见过的“剪刀石头布”错分为“其他”!
如下图所示,紫色的大圆圈代表的是所有手势的分布,内部三个中等尺寸大小的圆圈分别代表真实的剪刀、石头、布手势的分布,这三个手势互有重叠,代表有部分手势无法判断类别。三个小尺寸的圆圈代表采集到的数据分布,其与真实的数据分布是有差异的。如果我们保留其他手势,则模型容易将真实数据分布与采集数据分布之间的差异区域判别为其他手势。
数据分布
为此,我们选择了sigmoid loss作为目标损失,也就是变成多个二分类问题,同时将“其他”类别去掉,只保留“剪刀、石头、布、背景”四个类别。对于一个目标框,我们只要一个类别一个类别地单独判断就可以了,即判断其“是否是剪刀”、“是否是石头”等等,所以对于其他手势,其不属于任何一个类别,对任何一个类别来说都是负样本。
此外为了解决类别不平衡问题,[5]在sigmoid loss基础上提出了改进版的focal loss。Focal loss的意图非常简单直观,即在学习过程中不断减小易分类样本的权重,从而使模型更加关注困难样本,实验表明其可大幅提高性能而对速度没有任何影响。我们在训练过程中也借鉴了focal loss。
总结来说,算法方面我们主要做了以下几个工作:
- 采用高效的目标检测框架,同时对模型进行深度优化以提高速度、减小参数
- 通过特征融合方式改善小目标的检测效果
- 采用合适的损失函数,降低手势无定义带来的影响
最终我们的模型大小达到了1.9M,双十一手淘的线上环境下ios设备的平均耗时做到了17ms,满足了游戏实时性的要求。此外在我们自己的测试数据上AP(0.5)达到了0.984,游戏效果也得到了保证。
数据解析
在资源受限的情况下,模型算法能够施展的空间是有限的,尤其是在数据驱动的深度学习面前,真正的壁垒不是算法而是数据,模型见到的corner case越多效果就越好。然而手势识别相关的数据集并不多,且这些数据跟实际应用的场景差别太大,所以我们需要从头开始采集数据。另外,除了数量,数据的质量也非常关键,如果噪声很大,模型的学习效果也不会好。
数据采集
我们通过众包的方式采集了几百个小视频,每个视频20s,视频的内容就是让采集人员对着手机做剪刀石头布。但这种方式采集的数据跟真实的线上数据还是有差异的,因为用户在采集过程中并没有交互,只是干巴巴地做动作,另外因为有视频质量考核的顾虑,用户会下意识地对着demo视频的动作来做,而不是像真正猜拳游戏那样随心所欲。所以虽然20s的视频可以解析出几百张图片,但是真正有价值的图片并没有多少。
数据标注
标注检测数据和分类数据的成本是不一样的,前者需要先标出矩形框再对框选择类别,后者只需要选择类别即可,因此前者的成本要比后者高很多。为了尽量降低标注成本,我们将将标注分为了两步。首先我们用网络上收集的公开数据训练了一个手部检测模型,然后用该模型将采集数据中的手部抠出来,最后只需要标注抠出来的手部图片的类别即可。
数据的标注也是通过众包平台来进行的,跟一般的标注规则差不多,但前面我们提过,有些手势是很难判断其类别的,为此我们添加了“不确定”的选项,具体的:
- 如果手势清晰可辨且类别为“石头”,则标注为“石头”。
- 如果手势清晰可辨且类别为“剪刀”,则标注为“剪刀”。
- 如果手势清晰可辨且类别为“布”,则标注为“布”。
- 如果手势清晰可辨且类别明确不是“石头、剪刀、布”中的任何一种,则标注为“其他”。
- 如果手势不清晰或无法判断属于“石头、剪刀、布”中的哪个类别,则标注为“不确定”。
然而,即使定义了上述规则,实际标注的时候仍然有很多情况难以判断。另外由于我们是做目标检测,所以理论上手的位置不应该影响其类别选择,比如拳头无论放在什么位置都应该标注为“石头”,张开的手掌无论放在什么位置也应该都标注为“布”,然而众包人员由于没有经过培训,其往往容易标注错误,导致标注质量较低。大家可以看下图,思考下应该选择什么类别。
困难样本
数据使用
我们在上面提到过,在实际使用的时候是将“其他手势”这个类别去掉的,但这些类别的样本仍然是有价值的,我们会将其作为每个类别的负样本加入到训练中。除此以外,最困难的是“不确定”样本的使用,这些样本如果处理不好会非常影响模型的性能,但如果只是将其简单地丢弃不用则会非常浪费,为此我们在训练过程中将这些标注为“不确定”的样本的类别设为-1或者weight设为0,意思是这些样本是困难样本或难以判断的样本,至于其究竟属于哪个类别,可以由模型自己学习决定,这些样本对loss的计算并不会作出实际的贡献。
总结
猜拳游戏本质上是一个目标检测的问题,而目标检测相对来说已经是一个比较成熟的领域,但是具体到我们的业务层面还是会遇到很多难题,如之前提到的“端上实时运行所需的模型大小和速度”以及“手势没有明确定义”的问题及其一系列衍生问题,这都需要我们针对业务思考解决方法。
目前猜拳游戏已基本达到了线上产品化的要求,且在双十一活动中得到了验证,但如果将其运用在线下我们还有很多问题需要解决,比如:
- 线下场景比较复杂,当背景中出现很多人很多手时如何解决
- 线下场景拍摄的一般是全身照,手部所占的面积会很小,如何进一步提高现有模型对小目标的检测性能
- 线下设备的处理器性能一般较弱,如何在保证效果的前提下进一步地提高模型运行速度
注:文中图片来源于网络。
参考资料:
[1] Redmon J, Divvala S, Girshick R, et al. You only look once: Unified, real-time object detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 779-788.
[2] Redmon J, Farhadi A. YOLO9000: better, faster, stronger[J]. arXiv preprint, 2017.
[3] Redmon J, Farhadi A. Yolov3: An incremental improvement[J]. arXiv preprint arXiv:1804.02767, 2018.
[4] Liu W, Anguelov D, Erhan D, et al. Ssd: Single shot multibox detector[C]//European conference on computer vision. Springer, Cham, 2016: 21-37.
[5] Lin T Y, Goyal P, Girshick R, et al. Focal loss for dense object detection[J]. IEEE transactions on pattern analysis and machine intelligence, 2018.
[6] Lin T Y, Dollár P, Girshick R B, et al. Feature Pyramid Networks for Object Detection[C]//CVPR. 2017, 1(2): 4.
[7] Ren S, He K, Girshick R, et al. Faster r-cnn: Towards real-time object detection with region proposal networks[C]//Advances in neural information processing systems. 2015: 91-99.
[8] Dai J, Li Y, He K, et al. R-fcn: Object detection via region-based fully convolutional networks[C]//Advances in neural information processing systems. 2016: 379-387.
[9] He K, Gkioxari G, Dollár P, et al. Mask r-cnn[C]//Proceedings of the IEEE international conference on computer vision. 2017: 2961-2969.
[10] Iandola F N, Han S, Moskewicz M W, et al. Squeezenet: Alexnet-level accuracy with 50x fewer parameters and< 0.5 mb model size[J]. arXiv preprint arXiv:1602.07360, 2016.
[11] Zhang, X.; Zhou, X.; Lin, M.; and Sun, J. 2018. Shufflenet:
An extremely efficient convolutional neural network for mobile
- arXiv preprint arXiv:1707.01083.
[12] Howard, A. G.; Zhu, M.; Chen, B.; Kalenichenko, D.; Wang, W.; Weyand, T.; Andreetto, M.; and Adam, H. 2017. Mobilenets: Efficient convolutional neural networks for mobile vision applications. arXiv preprint arXiv:1704.04861.
[13] Sandler, M.; Howard, A.; Zhu, M.; Zhmoginov, A.; and Chen, L.-C. 2018. Mobilenetv2: Inverted residuals and linear bottlenecks. CVPR.
[14] Tan M, Chen B, Pang R, et al. Mnasnet: Platform-aware neural architecture search for mobile[J]. arXiv preprint arXiv:1807.11626, 2018.
[15] Law H, Deng J. Cornernet: Detecting objects as paired keypoints[C]//Proceedings of the European Conference on Computer Vision (ECCV). 2018: 734-750.
[16] Duan K, Bai S, Xie L, et al. Centernet: Keypoint triplets for object detection[C]//Proceedings of the IEEE International Conference on Computer Vision. 2019: 6569-6578.
[17] Fu C Y, Liu W, Ranga A, et al. Dssd: Deconvolutional single shot detector[J]. arXiv preprint arXiv:1701.06659, 2017.
[18] Liu S, Huang D. Receptive field block net for accurate and fast object detection[C]//Proceedings of the European Conference on Computer Vision (ECCV). 2018: 385-400.