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

详细讲解如何使用深度学习去除背景实现抠图

时间:2023-03-21 21:26:14 科技观察

在上面的课程中,我认识了AlonBurg,一位经验丰富的web开发者,我们恰好有相似的兴趣。所以为了实现这样一个产品,我们给自己定下了一些目标:提高我们的深度学习能力提高我们的AI产品部署能力满足市场需求,开发具有实用价值的产品。分享我们的经验很有趣。综合考虑针对以上目标,我们集思广益:哪些事情还没有做(或者不够完善)产品的设计和实现应该不会太难——因为我们的计划是花2-3个月,只花1天每周都在上面。用户界面应该足够简单易用——因为我们希望用户可以轻松学习如何使用该产品。毕竟,这款产品开发的初衷并不是为了科学验证训练深度学习模型,数据应该很容易获得——因为有机器学习经验的人基本都知道,有时候数据比算法更重要。会用到最新的深度学习技术(该技术还没有被谷歌和亚马逊等公司商业化应用),但不会太新奇(这样我们就可以在互联网上找到参考例子)产品将有潜力成为产生了我们最早的想法是做一个医疗项目,因为医疗领域和我们的初衷很接近,而且当时认为(现在仍然认为)医疗领域有很多深度学习的机会。然而,我们意识到这将违反数据收集应易于访问的原则。所以我们退而求其次,选择了去除背景(Backgroundremoval)。如果完全由人工或借助Photoshop、PowerPoint等工具完成,背景去除的任务非常简单。但是,全自动背景去除是一项具有挑战性的任务。并且据我们了解,目前还没有一款产品能够在后台去除任务上取得非常好的效果,但是已经有一些厂商进行了尝试。那么问题来了,我们需要去掉什么样的背景呢?这是一个非常重要的问题。因为一个模型越是具体(比如对物体、角度等都有详细的规定),它的分割效果就越好。当我们刚开始的时候,我们定义的范围很广:一个通用的背景去除器能够从任何类型的图像中自动识别前景和背景。但是在我们训练了第一个模型之后,我们意识到,如果我们专注于一组特定的图像,我们可以获得更好的结果。因此,我们决定专注于人像和自拍类型的照片。背景去除示例自拍的图像具有突出且聚焦的前景(一个或多个“人”),可以很好地分割背景和物体(面部和上半身)并保持相对稳定的角度。在做出这些基本假设后,我们开始了理论研究、代码实现和长达数小时的模型训练的旅程,以创建一个可以轻松一键去除背景的服务。这项工作最重要的部分是训练模型,但不能低估正确部署模型的重要性。此外,当前最先进的分割模型不如分类模型(如SqueezeNet)紧凑。我们主动检查了服务器和浏览器部署选项。如果你想详细了解我们产品的部署过程,推荐你阅读这两篇文章,分别从服务端和客户端的角度介绍了项目。如果您只是想了解模型及其训练过程,请继续阅读。语义分割当我们开始认真思考深度学习和计算机视觉中的各种技术时,很明显最适合背景去除任务的技术是语义分割。当然,还有其他策略,比如通过深度检测器进行分割,但这对我们来说似乎还不够成熟。语义分割(Semanticsegmentation)是一项众所周知的计算机视觉任务,与图像分类、目标检测并列为计算机视觉领域的三大挑战。分割的过程可以看作是将图像中的每个像素点归类到图像中的某个物体类别,所以分割实际上是一个分类任务。与图像分类或检测不同,语义分割真正展示了对图像的“理解”。因为它不是简单的表示“图像中有一只猫”,而是在像素级别上直接表示猫在图片中的位置,以及猫占据的范围。那么分裂究竟是如何实现的呢?为了更好地理解这一点,我们将回顾该领域的一些早期工作。最早的想法是采用一些早期的分类网络,如VGG和Alexnet。VGG是2014年图像分类任务的最先进模型,由于其简单的网络结构,它在今天仍然非常有用。在VGG的较早网络层中,待分类对象周围会有较高的激活,并且在更深的层中会有更强的激活。但是由于重复的池化操作,这些激活的性质相对粗糙。有了这个基本的理解,我们可以假设为分类训练的模型也可以通过一些调整应用于查找或分割图像中的对象。语义分割的早期结果与分类算法一起出现。在本文中,您将看到一些由VGG实现的分割结果,但结果很粗糙。后期网络的结果:schoolbus的分割结果,浅紫色(29)代表校车类别双线性上采样后:这些结果只是将全连接层转换为原始形状,同时保持原始空间特征。在上图的例子中,我们将一张768*1024的图像输入到VGG中,然后得到一个24*32*1000的层,其中24*32是imagepooled版本,1000是指Image-net的类别数从中可以得出分割结果。为了实现平滑的预测,研究人员使用了一个简单的双线性上采样层。在FCN论文中,研究人员进一步改进了上述方法。它们连接一些层以获得更多的特征解释,根据上采样率分别命名为FCN-32、FCN-16和FCN-8。在层之间添加一些跳跃连接允许预测器从原始图像中获取更精细的细节。进一步的培训可以进一步改善结果。该技术本身并没有之前想象的那么糟糕,并且展示了深度学习在语义分割领域的潜力。FCN的处理结果,图片来自论文FCN为语义分割打开了一扇新世界的大门,研究人员为此任务尝试了不同的网络结构。但核心思想保持不变:使用已知结构、上采样和跳过网络层之间的连接。这些技巧在较新的模型中仍然很常见。您可以在这些帖子中找到语义分割领域的进一步发展:http://blog.qure.ai/notes/semantic-segmentation-deep-learning-reviewhttps://blog.athelas.com/a-brief-history-of-cnns-in-image-segmentation-from-r-cnn-to-mask-r-cnn-34ea83205de4-https://meetshah1995.github.io/semantic-segmentation/deep-learning/pytorch/visdom/2017/06/01/semantic-segmentation-over-the-years.html另外,你可能还会发现大部分语义分割方法都保持着Encoder-decoder的架构模式。回到项目经过一些研究,我们关注了三个模型:FCN和Unet。其中,提拉米苏采用了非常深的编码-解码架构。我们对Mask-RCNN也有一些想法,但实现它似乎超出了这个项目的范围。FCN最早是因为效果不好而被我们丢弃的。其他两个模型的结果还不错:Tiramisu和Unet的主要优点是模型紧凑和计算速度快。在实现方面,Unet非常容易实现(使用Keras),Tiramisu也可以。而且我们还使用了JeremyHoward的深度学习课程最后一节课提供的Tiramisu实现代码。剩下两个候选模型,我们进入下一步——开始训练模型。不得不说,当我第一次尝试Tiramisu模型时,我被它惊人的结果所震撼,因为它能够捕捉到图像中的锐利边缘。另一方面,Unet似乎还不够好,其结果也不尽如人意。既然数据在模型选择方面有了大致的方向,那我们就开始寻找合适的训练数据。用于训练分割模型的数据不像用于分类或检测的数据那样常见。事实上,图像分割最常用的数据集是COCO,它包含90个类别和大约80,000张图像;VOCpascal,包含20个类别和11,000张图像;以及最近发布的ADE20K。最终我们选择使用COCO数据集,因为它包含了很多“人物”这一类别的图像,这也是我们感兴趣的。考虑到产品要实现的任务,我们还需要考虑是否只使用与任务最相关的部分数据集,还是使用越来越多的通用数据?一方面,使用具有更多图像和类别的更通用的数据集将使模型能够处理更多场景和更具挑战性的图像;另一方面,我们可以在一夜之间训练150,000张图像。所以如果我们使用完整的COCO数据集来训练模型,平均而言,每张图像将在一夜之间使用大约2次。所以使用更精简的部分数据将有利于模型训练,除此之外,还会让模型更专注。还有一点值得一提的是,Tiramisu模型最初是在CamVid数据集上训练的,它有一些缺陷,但最重要的是它非常单调的图像内容——所有图像都是道路和汽车。我相信你很容易理解,从这样的数据集(即使它包含人)中学习对我们的最终目的没有任何好处,所以经过短暂的考虑,我们选择放弃,转而使用COCO。来自CamVid数据集的示例COCO数据集带有一个非常简单的API,它使我们能够准确地知道每个图像中包含哪些对象(根据90个预定义的类别)。经过一些实验,我们决定减少数据集。首先,我们选择了那些包含人的图像,这样的图像有40,000张。然后我们继续剔除那些包含太多人的图像,剩下的图像只包含1或2个人,因为这样的图像最适合我们的产品目标。最后,我们只留下图片中20%到70%的区域被标记为人的图像,并继续去除背景中的人太小,或者有一些奇怪的东西的图像。最终,缩减后的数据集包含11,000张图像,我们认为这在现阶段已经足够了。左:很好的例子,中:包含太多元素,右:TargetbodytoosmallTiramisumodel上面提到,我们在JeremyHoward的课程中??学习了Tiramisu模型。虽然它的全名“100-layerTiramisu”可能暗示它是一个巨大的模型,但实际上它非常经济,即使只有900万个参数,而VGG16有超过1.3亿个参数。Tiramisu模型是参考DensNet的设计提出的。而DensNet是最近提出的一种图像分类模型,其中所有层都相互连接。此外,Tiramisu还在上采样层加入了跳跃连接(Skipconnections),这一点与Unet相同。如果你还记得,这个架构符合FCN提出的想法:使用分类架构进行细化、上采样和跳过连接。Tiramisu的通用架构DenseNet模型可以看作是ResNet模型的自然进化,但DenseNet不是“记住”层与层之间的关系,而是记住模型中的所有层。这样的连接称为高速公路连接。它导致过滤器数量激增,这被定义为“增长率”。提拉米苏的增长率为16,因此在每一层我们都需要添加16个新过滤器,直到我们达到具有1072个过滤器的层。您可能期望有1600层,因为模型的名称是“100层提拉米苏”,但是上采样层会丢弃一些过滤器。Densenet模型草图,跨模型训练的早期过滤器堆栈我们按照原始论文中的描述训练模型:标准交叉熵、具有1e-3学习率的RMSProp优化器和小衰减值。我们将减少的11k图像分成70%的训练集、20%的验证集和10%的测试集。接下来显示的所有图像均来自测试集。为了使我们的训练过程与论文保持一致,我将Epoch大小设置为每500张图像,这允许我们定期保存模型,因为随着我们训练更多数据(原始论文中使用的CamVid数据集包含少于1k图像)。此外,与论文中使用的12个类别相比,我们仅训练两个类别:背景和人物。我们最初尝试在COCO类别上进行训练,但发现这对训练帮助不大。数据问题一些数据集的缺陷阻碍了模型的表现力:动物——我们的模型有时会分割动物,这会导致较低的IoU。在我们任务的主要类中添加动物或其他东西会导致更糟糕的结果。躯干-由于我们通过程序自动过滤数据集,因此无法判断包含人物的图像是否真的有一个人,或者只是一些躯干,例如手或脚。这些图像不在我们的目标范围内,但它们仍然出现在数据集中。动物、躯干、手持物体——数据集中的许多图像都与运动有关,人们总是带着棒球棒、网球拍和滑雪板等物品出现。我们的模型不知何故混淆了如何区分图片中的人和物体。与动物一样,将它们归类为主体的一部分或对其进行区分,将有助于提高模型的表现力。粗略的真实数据(Groundtruth)——COCO数据集不是逐像素标注,而是使用多边形进行标注。有时,这种级别的注释就足够了,但其他时候,这样的真实数据仍然太粗糙,阻碍了模型的学习。原图和粗略的真实数据的结果都很满意,虽然还是有一些美中不足的地方:我们在测试集上的IoU是84.6,而目前最好的结果是85。这个数据(IoU)也是trickyas它在不同的数据集和类别中波动。有些类别天生就比较容易分割,比如房屋、道路等,很多模型可以轻松做到90IoU。其他更具挑战性的类别是树和人,其中大多数模型只能达到60IoU。为了衡量这个难度,我们帮助网络专注于单一类别和有限类型的照片。虽然我们仍然觉得目前的结果还不足以达到“生产就绪”的标准要求,但现在是暂停和讨论结果的好时机,因为大约50%的照片给出了好的结果。这里有一些很好的例子。从左到右:图像、真实数据、输出(来自测试集)调试和记录神经网络训练的很大一部分是调试。开始训练神经网络非常容易,只需将数据输入网络,然后开始训练,最后看看输出是什么。但是我们发现跟踪网络训练的每一步是非常重要的,所以我们为自己构建了相应的工具,以便我们可以检查每一步的结果。以下是一些常见的挑战,以及我们已经完成的工作:早期问题——模型可能无法训练。这可能是由于某些固有问题,或由于某种预处理错误,例如忘记对数据块进行归一化。无论如何,将结果可视化将非常有帮助。这是关于该主题的主题。调试网络——在确定没有重大问题后,网络将开始使用预定义的损失进行训练。语义分割领域的主要衡量指标是IoU(Intersectoverunion)。我们花了一段时间才开始采用IoU作为模型训练的主要指标(而不是交叉熵)。另一个有用的做法是在每个时期显示一些模型预测。这篇文章很好地介绍了如何调试机器学习模型。另外要注意IoU在keras中并不是标准的损失函数,但是网上很容易找到现成的,比如这个。我们还使用这个Gist来绘制每个时期的损失和预测结果。机器学习的版本控制——通常一个模型会有很多参数,其中一些很难跟踪。我不得不说,我们还没有找到解决这个问题的完美方法,除了更频繁地写出配置信息(以及使用keras回调自动保存最新模型,见下文)。调试工具——完成上述所有措施后,我们将能够验证我们每一步的工作,但仍然无法实现无缝检测。因此,最重要的一步是结合上述步骤,创建一个Jupyternotebook,我们可以通过它无缝加载每个模型和每个图像,并能够快速检查其结果。这使我们能够轻松发现模型之间的差异、模型缺陷和其他问题。下面是我们模型的改进示例,包括参数调整和额外训练。保存在验证集上获得最佳IoU分数的模型(Keras提供了一个很棒的回调函数,使这非常容易):'),plot_losses]除了正常调试可能出现的代码错误,我们还注意到模型的错误是“可预测的”。例如“切割”超出正常躯干范围的身体部位、不必要的躯干伸展、光线不足、低质量照片和照片中的细节过多等。其中一些在添加来自不同数据集的特定图像时已处理,但其他仍然保留公开挑战。为了在下一个版本中改进结果,我们将使用特定于“硬”图像的增强来训练模型。我们之前讲过的数据集问题。现在让我们看看模型面临的一些挑战:衣服-有时可以将非常亮或非常暗的衣服用作背景“洞”-有些应该是很好的效果,类似于衣服上的洞和“DigHoles”3.照明-虽然光线不足和图像模糊在照片中很常见,但COCO数据集并非如此。因此,除了使用标准难度模型之外,我们不准备应对那些具有挑战性的图像。这个问题可以通过获取更多数据或增强数据(Dataaugmentation)来解决。在超过300个epoch的训练数据上进一步训练了underlit示例,之后模型开始过度拟合。由于我们的结果已经非常接近公布的结果,我们还没有机会应用数据增强的基本实践。用于训练的输入图像统一resize为224*224。此外,使用更多的数据和更大分辨率的图像(COCO图像的原始大小约为600*1000)训练模型也有助于提高最终结果。CRF和其他增强在某个阶段,我们发现一些结果在边缘有噪声。CRF模型可以用来改善这个问题。在这篇博客中,作者展示了CRF的一个简单使用示例。但是这种方法对我们的工作帮助不是很大,可能是因为它只在结果很粗糙的时候才有帮助。Matting虽然目前已经达到了这样的效果,但在实际分割中还不够完善。头发、精致衣物、树枝和其他精致物品等物品永远不能物理分割。事实上,这种非常精细的分割任务称为抠图,它定义了一种不同的挑战。这是今年早些时候在NVIDIA会议上展示的最先进抠图作品的示例。抠图例子,输入包含Trimap抠图任务与其他图像相关任务不一样,因为它的输入不仅包括原始图像,还包括三维图(Trimap)。三方指的是图像边缘的轮廓,这也使其成为“半监督”问题。我们用抠图做了一些实验,使用我们的分割图像作为三元图,但没有取得任何有意义的结果。另一个问题是缺乏使用的训练数据集。总结正如开头所述,我们的目标是开发一个有意义的深度学习产品。正如您在Alon的帖子中看到的那样,部署相对容易且快速。另一方面,模型训练是最棘手的部分——尤其是如果训练需要一个晚上,这需要仔细规划、调试和记录结果。事实证明,在研究和尝试新事物与训练和改进模型之间取得平衡并不容易。由于使用了深度学习,我们总觉得最好的模型或最适合我们的模型就藏在角落里,只要多谷歌搜索或多一篇论文就会让我们找到它。但在实践中,我们实际的改进来自于对原有模型一点一点的“压榨”。而且如上所述,我们仍然觉得还有更多的改进空间。