当前位置: 首页 > 科技观察

如何使用深度学习去除人物背景

时间:2023-03-17 18:32:50 科技观察

近日,Medium上出现了一篇名为《Background removal with deep learning》的文章,描述了greenScreenAI在使用深度学习去除图像中人物背景方面的工作和研究。本着开发有意义的深度学习产品的初衷,他们将任务锁定在自拍和人像上,最终在稀释后的COCO数据集上实现了84.6的IoU,而目前最好的水平是85。在研究机器学习的过程中,我一直想构建真正的机器学习产品。几个月前,在上了Fast.AI的深度学习课程后,我清楚地意识到有一个机会:深度学习技术的进步可以让很多以前不可能的事情成为现实,新的工具被开发出来,它们它可以使部署比以前更容易。在上述课程中,我遇到了经验丰富的Web开发人员AlonBurg,我们同意共同完成这个目标。我们共同设定了以下目标:提高我们的深度学习技能提高我们的AI产品部署技能开发有用的、有市场的产品有趣的(不仅对我们,而且对用户)分享我们的经验基于上述目标,我们探索了一些想法:以前没有做过(或没有正确完成)的事情易于计划和实施-我们计划在两到三个月内完成,每周一个工作日。拥有简单而有吸引力的用户界面——我们的目标是制造人们可以使用的产品,而不是仅仅停留在演示的目标上。拥有易于获取的训练数据——众所周知,有时数据比算法更昂贵以使用尖端的深度学习技术(如果该技术尚未被GoogleAllo、亚马逊及其合作伙伴在云平台上商业化),但不是太前沿了(这种方式我们可以在网上找一些例子)有潜力达到“生产就绪”(productionready)的结果我们早期的想法是做一些医疗项目,因为这个领域和我们不一样切记,所感越近,医学领域还有很多唾手可得的果实。但是,我们意识到我们在收集数据和法律方面可能会遇到一些问题,这也是我们最终放弃医疗项目的原因。我们的第二个选择是图像背景去除。背景去除是手动或半手动完成的一项简单任务(Photoshop,甚至PowerPoint都有此类工具),如果您使用某种“标记”或边缘检测,这里有一个示例(https://clippingmagic.com/).然而,全自动背景去除是一项相当具有挑战性的任务,据我们所知,尽管有些产品正在尝试,但还没有产品取得令人满意的结果。我们要删除什么背景?这是一个重要的问题,因为模型在对象、角度方面越具体,分离的质量就越高。我们的工作始于一个伟大的想法:制作一个通用的背景去除器,可以识别所有类型图像中的前景和背景。但是在我们训练了第一个模型之后,我们意识到专注于特定的一组图像会更好。因此,我们决定专注于自拍和人像。人像(类人)人像的背景去除自拍具有鲜明且更聚焦的前景(一个或多个人),这使我们能够很好地将主体(面部+上半身)与背景分开,同时也具有相对固定的角度,并且始终是相同的对象(人)。有了这些假设,我们开始了研究、实施和数小时培训的旅程,以获得易于使用的背景去除产品。我们的主要工作是训练模型,但我们不能低估正确部署的重要性。好的分割模型仍然不如分类模型(例如SqueezeNet)那么严格,我们主动检查服务器和浏览器模型的部署选择。如果您想阅读有关我们产品部署过程的许多详细信息,可以转到我们的服务器端和客户端博客文章。如果您想阅读更多关于模型和培训的信息,请继续。语义分割我们研究了与我们类似的深度学习和计算机视觉任务,不难看出我们最好的选择是语义分割任务。其他策略,例如通过深度检测进行分割,也存在,但对于我们的目的而言还不成熟。语义分割是计算机视觉的经典任务,它是计算机视觉领域的三大课题之一,另外两个是分类和目标检测。从将每个像素归为一类来说,分割实际上是一个分类任务。然而,与图像分类和目标检测不同,分割模型实际上表现出对图像的某种“理解”。在像素级别,它不仅可以区分“这张图像中有一只猫”,还可以指出它是什么猫。那么,细分是如何工作的呢?为了更好地理解它,我们必须经历这个领域的一些早期工作。最早的想法是采用一些早期的分类神经网络,比如VGG、Alexnet。早在2014年,VGG就是图像分类任务的领先网络,由于其简单明了的结构,在今天非常有用。查看VGG的前几层时,您可能会注意到从每个项目到类别的高激活值。更深的层有更高的激活,但由于它们重复的池化作用,它们本质上是粗糙的。有了这种理解,可以假设,经过一些处理后,分类训练也可以用于查找/分割对象的任务。语义分割的早期结果来自分类算法。在本文中,您可以看到我们使用VGG得到的一些简单的分割结果:后面层的结果:buss图像的分割,浅紫色区域(29)代表校车类别双线性上采样后:这些结果仅来自简单的转换(或将全连接层修改为原来的形式,修改其空间特征,得到全连接的卷积神经网络。在上面的例子中,我们将一个768*1024的图像输入到VGG中,然后得到一个24*32*1000的层,24*32是图像的池化版本,1000是image-net的类别数,从这里我们可以得到上面的分割结果。为了平滑预测,研究人员还使用了一个简单的双线性上采样层。在关于全连接神经网络的论文(FullyConvolutionalNetworksforSemanticSegmentation,https://arxiv.org/abs/1411.4038)中,研究人员对上述思想进行了改进。为了有更丰富的解释,他们将一些层连接在一起,根据上采样率分别命名为FCN-32、FCN-16和FCN-8。在层之间添加一些跳跃连接使得从原始图像到编码的预测更加精细。进一步训练模型会得到更好的结果。该技术的性能并没有想象中的那么差,证明了使用深度学习进行语义分割确实有潜力。FCN论文中全连接神经网络的结果全连接神经网络开启了分割的概念,研究人员为此任务尝试了不同的架构。主要思想是相似的:使用已知的架构、上采样和使用跳跃连??接,这些在新模型中仍然占主导地位。研究完回到我们的项目,我们选择了三个合适的模型开始研究:FCN、Unet和Tiramisu——这是一个非常深的encoder-decoder架构。我们对mask-RCNN也有一些想法,但实现它似乎超出了我们项目的范围。FCN似乎不相关,因为它的结果不是我们想要的(即使在初始点),但我们提到的其他两个模型显示出良好的结果:提拉米苏模型和Unet模型的主要优点是紧凑和速度。在实现方面,Unet相当简单(使用keras),Tiramisu也可以实现。我们从JeremyHoward上一门深度学习课程中很好地实现了Tiramisu开始了我们的项目。我们使用这两个模型开始对一些数据集进行训练。不得不说,当我第一次训练Tiramisu时,我发现它的结果对我们来说更好,因为它能够捕捉图像中的锐利边缘,然而,Unet看起来并没有那么好,甚至有点滑稽。Unet的结果略显平淡数据一旦我们设定了模型的基本目标,我们就开始寻找合适的数据集。分割数据不像分类和检测那样常见。另外,人工标注也不现实。最常用的分割数据集是COCO(http://mscoco.org/),它包括大约80,000张图像(90个类别),VOCpascal数据集有11,000张图像(20个类别),以及更新的数据集ADE20K。我们选择使用COCO数据集,因为它有更多“人类”类的图像,这恰好是我们的兴趣所在。考虑到我们的任务,我们考虑是只使用与我们的任务超级相关的图像,还是使用更通用的数据集。一方面,更通用的数据集有更多的图像和类别,这使我们能够应对更多的场景和挑战。另一方面,通宵训练可以处理大约15k张图像。如果我们在整个COCO数据集上引入模型,事实证明模型处理每张图像的平均次数为2,因此稍作修改是有益的。此外,这使模型更专注于我们的目标。另外值得一提的是,Tiramisu模型最初是在CamVid数据集上训练的,它有一些缺陷,但最重要的是它的图像非常单调:所有图像都是路上的车辆。正如您很容易理解的那样,从这样的数据集中学习对我们的任务没有好处(即使图像包含人物),因此经过简短的实验,我们更改了数据集。CamVid数据集中的图像COCO数据集带有相当简单的API,可以让我们知道每张图像中的对象类型。经过一些实验,我们决定稀释数据集:首先我们过滤掉有人物的图像,最后我们得到了40,000张图像。然后,有很多人的图像被丢弃,只留下一两个人的图像,因为那是产品所需要的。最后,我们剩下20%-70%的图像被标记为人,删除了背景中有一小部分人的图像,以及那些有奇怪建筑物的图像(虽然不是全部。删除)。我们最终得到了只有11,000张图像的数据集,我们认为在这个阶段已经足够了。左:正常图像;中间:图片内容过多;右:对象太小提拉米苏模型如前所述,我们使用了杰里米霍华德课堂上教授的提拉米苏模型。虽然它的名字“100-layerTiramsiu”让它变得庞大,但它实际上是一个相当经济的模型,只有900万个参数。相比之下,VGG-16有130M个参数。Tiramisu模型基于DensNet,这是一种所有层都相互连接的最先进的图像分类模型。此外,与Unet类似,Tiramisu模型在上采样层上添加了跳跃连接。回想一下上一节,这种架构与FCN中提出的思想是一致的:使用分类架构、上采样并添加跳过连接进行微调。通用的Tiramisu架构DenseNet模型可以看作是自然进化的Reset模型。然而,DenseNet并不是简单地将一层的信息“记忆”到下一层,而是记忆了整个模型中的所有层。这些连接称为高速连接。它导致过滤器数量的膨胀,这被定义为“增长率”。提拉米苏的增长率为16,因此我们将向每一层添加16个过滤器,直到我们达到具有1072个过滤器的层。你可能期望一个层有1600个过滤器,因为这是Tiranisu有100个层,但是,上采样会丢弃一些过滤器。DenseNet模型框架——在整个模型中,第一层的过滤器被堆叠起来进行训练。我们按照原论文中的方案来训练模型:标准交叉熵损失,RMSPropoptimizerwithlearningrate0.001,smalldecay。我们将70%的数据用于训练,20%用于验证,10%用于测试。以下所有图片均来自我们的测试集。为了使我们的训练过程与原始论文保持一致,我们将epoch大小设置为500张图像。这也允许我们在每次处理结果时定期保存模型,因为我们在大量数据上训练模型(该论文中使用的CamVid数据集只有不到1000张图像)。此外,我们训练的模型只有两个类别:背景和人物,而该论文中的模型有12个类别。我们首先尝试在COCO的一些类上进行训练,但后来我们发现这对我们的训练没有多大帮助。1.数据问题一些数据集的缺陷阻碍了我们模型的评分:动物——我们的模型有时会分割动物,这自然会导致较低的IOU,并将动物添加到我们的主要分类中。身体部位——由于我们系统地过滤了数据集,因此无法区分图像中的人是真人还是手或脚等身体部位。这些画面虽然不在我们的考虑范围之内,但还是随处可见。动物、身体部位和手持物体——数据集中的许多图像都与运动相关。到处都是棒球棒、羽毛球拍和滑雪板。在某种程度上,我们的模型已经对如何拆分它们感到困惑。与动物示例一样,我们认为将它们添加到主要类别或单独的类别将有助于模型的性能。有一种真实情况是物体的运动图像是粗糙的——COCO数据集中的许多图像不是用像素标注的,而是用多边形标注的。有时这很好,但有时地面实况太粗糙,这会阻止模型学习细微的细节。逼真的粗糙图像2.结果我们的结果令人满意,但并不完美:我们在测试集上实现了84.6的IoU,而最先进的是85。但这个数字很微妙:它会随着不同的数据集而波动和类别,有些类别本身很容易分割,比如房屋,道路,这些例子中的很多模型可以很容易地达到90IoU。其他更具挑战性的类是树和人,其中许多模型只能达到大约60IoU。为了克服这个困难,我们帮助我们的网络专注于单一类别,并跨越有限数量的图像类型。我们仍然觉得我们的工作没有像我们希望的那样“准备好生产”,但现在是停下来讨论我们的结果的时候了,因为大约50%的图像产生了更好的结果。下面是一些很好的例子,它们给人的印象是一个好的应用程序。图像、真实数据、我们的结果(来自我们的测试集)调试和日志训练神经网络的一个非常重要的部分是调试。立即开始、获取数据和网络、开始训练并查看获得的结果是很诱人的。然而,我们会发现跟踪每一个动作是非常重要的,这样才能为我们自己创造出可以检查每一步结果的工具。以下是一些常见的挑战以及我们如何应对它们:前期问题——模型可能无法训练。可能有一些根本原因,或者一些预处理错误,例如忘记对某些数据块进行归一化。无论如何,对结果进行简单的可视化是有帮助的。这里有一篇关于此主题的博文(https://blog.slavv.com/37-reasons-why-your-neural-network-is-not-working-4020854bd607)。调试网络本身——在确保没有关键问题后,训练从预定义的损失和指标开始。在分割中,主要的动作是IoU-IntersectionoverUnion。使用IoU作为模型的主要手段(而不是交叉熵损失)确实需要一些时间。另一个有用的做法是显示模型在每个时期的一些预测。这里有一篇关于调试机器学习模型的好文章(https://hackernoon.com/how-to-debug-neural-networks-manual-dc2a200f10f2)。请注意,IoU不是keras中的标准度量/损失,但您可以轻松地在网上找到它,例如这里(https://github.com/udacity/self-driving-car/blob/master/vehicle-detection/u-网络/README.md)。我们还使用这个要点来绘制每个时期的损失和预测。机器学习版本控制——训练模型时,有很多参数,其中一些很微妙。不得不说,我们还没有找到完美的方法,只能心急火燎地记下我们的配置(下面用keras的回调记下最好的模型)。调试工具——做完上面所有的步骤之后,我们就可以一步一步的检查我们的工作了,然而,这并不是无缝的,所以,最重要的是把上面所有的步骤结合起来,创建一个jupyternotebook,让我们无缝地无缝加载每个模型和每个图像,并快速检查结果。通过这种方式,我们可以轻松发现模型之间的差异、陷阱和其他问题。这是我们在调整参数和额外训练后获得的模型性能改进的示例:保存目前为止验证过程中最好的模型:(keras提供了一个非常好的回调函数,使这一步更容易)回调=[keras.callbacks.ModelCheckpoint(hist_model,verbose=1,save_best_only=True,monitor='val_IOU_calc_loss'),plot_losses]除了对可能的代码错误进行正常调试外,我们还注意到模型错误是“可以预测的”,比如切掉身体部位似乎在正常身体之外,大段“间隙”,不必要地延伸的身体部位,光线不足,图像质量低,细节很多。在从数据集中添加特定图像时,已经解决了其中一些注意事项,但其他一些仍然是有待解决的难题。为了改进下一个版本的结果,我们将在“硬”图像上为我们的模型使用特定的扩展。我们在之前的数据集问题中提到过这个问题。现在让我们了解一下我们模型中的难点:1.衣服-很深或很浅的衣服很容易被解释为背景2.“差距”-即使是好的结果也会有衣服和差距的差距3.光照-光照条件差和模糊很常见在图像中,但是在COCO数据集中情况并非如此,因此我们的模型甚至没有Prepareforaharderimage。这可以通过获取更多数据来解决,此外,最好不要在晚上使用我们的应用程序。进一步处理光照条件差的实例的选项1.进一步训练我们的产品结果来自300个epoch的训练。在此阶段之后,模型开始过度拟合。我们的结果非常接近已发布的版本,因此无法进行数据扩充。将图像调整为224*224后,我们开始训练模型。使用更多更大的数据集进行进一步训练也有望改善结果(COCO数据集上的原始大小为600*1000图像)。2.CRF和其他改进在某个阶段,我们发现我们的结果在边缘有一些噪声。可以针对此类问题进行微调的一种模型是CRF。在下面的博客中,作者展示了使用CRF的示例(http://warmspringwinds.github.io/tensorflow/tf-slim/2016/12/18/image-segmentation-with-tensorflow-using-cnns-and-条件随机场/)。然而,这对我们的工作不是很有用,也许是因为它通常只在结果很粗糙时才有效。3.Cutout即使在我们目前的结果中,分割也不完美。头发、衣服、树枝和其他物体不可能完美分割,甚至因为在真人动作中没有包含这些细节的注释。分割这些片段的任务称为抠图,是另一个新挑战。这是今年早些时候在NVIDIA会议上展示的最先进抠图技术的示例(https://news.developer.nvidia.com/ai-software-automatically-removes-the-background-from-图片/)。抠图示例——输入还包括trimap抠图任务不同于其他图像相关的任务,因为它的输入不仅包括图片,还有trimap——也就是图像边缘的轮廓,这使得这个任务成为A“半监督”问题。我们用抠图做了一个小实验,使用我们的分割作为trimap,但是没有获得显着的结果。另一个问题是缺乏合适的训练数据库。总结正如开头所说,我们的目标是开发一个有意义的深度学习产品。正如您在Alon的博客(https://medium.com/@burgalon)中看到的那样,部署总是快速而简单。但是,训练模型很困难,尤其是通宵训练时,需要仔细规划、调试和记录结果。平衡研究、尝试新事物以及通常的培训和改进也不是一件容易的事。因为我们使用深度学习,所以我们总是觉得最好的模型或者最准确的模型离我们很近,也觉得谷歌搜索或者一篇论文会指引我们。但是,实际上,我们的实际改进只是来自对原始模型进行更多压缩。如上所述,我们仍然觉得我们可以从原始模型中挤出更多改进空间。原文:https://medium.com/towards-data-science/background-removal-with-deep-learning-c4f2104b3157【本文为机器之心专栏原文翻译,微信公众号》机器之心(id:almosthuman2014)》】点此阅读作者更多好文