左边是原图,右边是修图。是否是以为美女与右边图片的背景搭在一块儿,更有动感和帅气。但是不会修图啊,肿么办?
git
今天让咱们来看一个有意思的AI应用,让不会PS的你,也能立马拥有吊炸天的修图超能力,没准还能分分钟修完上万张图,秒杀全部PS修图大神。
如下是机器学习大神Gidi Shperber讲述,他是到底一步步把这个模型给搞出来的详细过程。你要不要本身也来训练一个呢?
翻译 | AI科技大本营(rgznai100)github
参与 | shawn算法
在机器学习领域摸爬滚打的这几年中,我一直想开发一个实用的机器学习产品。
spring
几个月前,我学完了 Fast.AI深度学习课程(http://www.fast.ai/%22),期待已久的机会终于闪如今我眼前:深度学习技术近几年日新月异,许多以前没法实现的事情如今也有了实现的可能。新的工具开发成功后,应用的实现变得比以往更加容易。在学习Fast.AI课程期间,我遇到了经验丰富的网站开发者Alon Burg(https://medium.com/@burgalon/35648f9dc5fb)。我俩一拍即合,决定一块儿追求这一目标。所以,咱们一块儿设定了如下小目标:编程
提升咱们在深度学习上的能力浏览器
提高咱们的AI产品应用能力服务器
开发一个有市场需求的使用产品网络
(让咱们和咱们的用户)享受到乐趣架构
分享咱们的经验dom
鉴于以上目标,咱们开发的产品须要知足如下要求:
别人还没开发出来(或者别人开发的不够好)
计划和实现起来不是很难——咱们计划在2-3个月内完成,每周工做一天。
用户界面简单有趣——咱们想开发一个既有演示做用又有实用价值的产品。
要求的训练数据能轻易得到——机器学习从业人员都知道,数据有时候要比算法贵不少。
使用先进的机器学习算法(谷歌、亚马逊等公司仍未在其云平台上提供的),但不要太过先进(这样咱们就还能在网上找到一些实例)
有实现“生产就绪”的潜力。
咱们早期的想法是从一些医疗项目下手,由于这个领域深得人心,咱们(仍然)感受深度学习在医疗领域有不少容易实现的应用。可是,咱们意识到咱们会在数据采集和法律及法规方面遇到一些问题,解决起来不会很容易。
若是使用某种“标识”和边缘识别工具,手动完成或半手动完成背景移除任务就至关容易(示例地址-https://clippingmagic.com/) 。可是,全自动背景移除却极具挑战。据咱们所知,有人作过尝试,可是如今尚未哪一个产品可以得出使人满意的结果。
(类)人类肖像背景移除
自拍图像有一个既明显又明确地前景(一个或多个“主角”),这样咱们就能很好地将对象(脸部和上身)和背景分离开来。此类图像每每角度单一,显示的对象也相同(人)。
有了这些假设,咱们开始进行研究、实现以及长达数小时的训练,以期作出一个简单易用的背景移除产品。
虽然咱们的主要工做是训练模型,可是咱们不能低估正确实现的重要性。好的背景分离模型仍然不像分类模型那样结构紧凑(例如SqueezeNet-https://arxiv.org/abs/1602.07360%22),咱们积极研究了产品在服务器和浏览器上的应用。
若是您想了解更多关于产品实现的内容,欢迎查看咱们在server side (https://medium.com/@burgalon/35648f9dc5fb)和 client side(https://medium.com/@burgalon/2e5a29589ad8)上发表的文章。
若是您想了解该模型及其训练过程,请继续阅读。
在研究与本任务相似的深度学习和计算机视觉任务时,咱们很快发现最好的策略是语义分割。
就咱们的目的而言,其余策略(如经过深度检测实现分割)好像不够成熟,例如经过深度检测实现背景分离(https://arxiv.org/pdf/1507.06821.pdf)。
除了分类和目标检测,众所周知的计算机视觉任务还有语义分割。从像素分类的角度来看,语义分割其实是一个分类任务。不一样于图像分类或图像检测,语义分割模型在必定程度上可以“理解”图像,它不仅能检测出“图像中有一只猫”,并且还能在像素级别上指出这只猫的品种以及它在图像中的位置。
语义分割模型的工做原理是什么?为了获得答案,咱们研究了该领域的一些早期成果。
咱们最先的想法是采用早期的分类网络,如VGG和Alexnet。回溯到2014年,VGG是当时最早进的图像分类模型,并且VGG结构简单易懂,时至今日仍十分有用。当观察VGG较浅的层时,能够看到要进行分类的对象周围汇集有激活单元,并且层越深上面的激活单元就越强。因为重复的pooling操做,VGG得出的结果在本质上比较粗糙。理解了这些,咱们假设分类训练在通过一些调整后也能够用于搜寻/分割对象。
分类算法出现后,语义分割的早期成果也应运而生。这篇文章给出了一些使用VGG得出的粗糙的语义分割结果。
这篇文章
http://warmspringwinds.github.io/tensorflow/tf-slim/2016/11/22/upsampling-and-image-segmentation-with-tensorflow-and-tf-slim/
公共汽车图像分割,亮紫色(29)表明校车类别
在双线性升采样后:
这些结果是这样得来的:将全链接层转化为(或维持)它的原始形状,维持其空间特征不变,得出一个全卷积神经网络(FCN)。在上面的例子中,咱们将一个768*1024的图像输入到VGG中,结果获得了一个24*32*1000的卷积层。24*32的图像是池化后的图像(1/32大小),1000是图像网络类别数,据此咱们能够推导出上文中的语义分割。
为了让模型能顺利地进行预测,研究人员使用了一个简单的双线性升采样层(bilienar upsampling layer)。
在这篇FCN论文(https://arxiv.org/abs/1411.4038)中,研究人员改进了上述方法。为了解释得更详细,他们将一些层链接在一块儿,根据升采样率的不一样将它们分别命名为FCN-3二、FCN-16 和FCN-8。
在层之间加一些skip connection,可使预测模型对原始图像中更细微的细节进行编码。通过进一步训练,得出的结果会更好。
试验证实,这种方法的效果并不像想象的那样糟糕;并且利用深度学习完成语义分割任务的确有实现的可能。
图4. 经过整合不一样步长的跨层信息来改善全卷积网络,改进分割细节。前三张图展现的分别是步长为3二、16和8像素的网络的输出。
FCN的提出揭示了语义分割的概念,为了解决这个任务研究人员尝试了不少不一样的架构。从一些新的模型能够看出,他们的主要思路仍然相似:使用已知的架构,进行升采样,采用skip connection。
您能够经过阅读 文章一、 文章2 和文章3来了解该领域的一些进展。您会发现,大多数架构采用的仍然是编码器—解码器架构。
在作了一些研究工做后,咱们最终肯定了三个模型:FCN、Unet(https://arxiv.org/pdf/1505.04597.pdf%22)和Tiramisu (https://arxiv.org/abs/1611.09326%22)。这三个模型都是很是深的编码器—解码器架构,并且都能找获得。咱们还有一些关于mask-RCNN的想法,可是这种模型的实现彷佛不在咱们项目涵盖的范围内。
因为FCN的结果不如咱们预期的那样好(甚至不及格),所以暂不考虑这种模型。另外两种模型的结果则相对不错:tiramisu 在CamVid (http://mi.eng.cam.ac.uk/research/projects/VideoRec/CamVid/%22)数据集上表现良好;Unet的主要优势在于结构紧凑、速度快。在实现方面,Unet实现起来很简单(咱们使用的是keras),Tiramisu 也可以成功实现。开始进行项目前,咱们在Jeremy Howard的深度学习课程(https://www.usfca.edu/data-institute/certificates/deep-learning-part-two)的最后一课中使用过一个很好的Tiramisu应用。
获取了两个模型(一个Unet和一个Tiramisu)后,咱们用一些数据集对它们进行了训练。值得指出的是,第一次试验咱们用的是Tiramisu模型,结果对咱们而言很理想,由于它能够捕捉图像中的尖锐边缘。而Unet模型处理得彷佛不够精细,得出的图像有点糊。
Unet 得出的结果有点糊
在肯定了该使用哪一种模型这个大方向后,咱们开始寻找合适的数据集。语义分割数据不像分类数据或者检测数据那样常见。并且,手动标记并不可行。语义分割最多见的数据集是COCO(http://mscoco.org/)数据集(大约包含8万张图像,90种类别)、VOC pascal(http://host.robots.ox.ac.uk/pascal/VOC/%22)数据集(大约包含11000万张图像,20种类别)以及相对较新的ADE20K(http://groups.csail.mit.edu/vision/datasets/ADE20K/%22)数据集。
咱们选择使用COCO数据集训练模型,由于它包含更多“人”像,这正是咱们感兴趣的一类图像。
针对任务,咱们思考了是只使用相关性很强的图像,仍是使用涵盖范围较广的数据集。一方面,涵盖范围较广的数据集每每包含更多的图像和类别,使用这种数据集的话,模型能够处理更多的场景和问题。另外一方面,模型一整夜的训练图像数超过15万张。若是咱们用整个COCO数据集训练模型,同一张图像模型最后(平均)会学习两次,所以稍微修剪一下数据集会有所帮助。另外,这样作的话咱们还能够获得一个目标性更强的模型。
CamVid数据集中的图像
COCO数据集支持很是简单的API,这使得咱们能够知道目标在每张图像中的具体位置(根据预先设定的90个类别)。
在进行了一些试验后,咱们决定对数据集进行稀释:首先咱们过滤了只显示有一人的图像,这样就只留下了4万张。而后,咱们剔除了全部显示有多我的的图像,留下只显示一人或两人的图像,此类图像就是咱们的产品应该识别的对象。最后,咱们只留下了20%-70%的内容都被标记为“人”的图像,剔除了那些显示有某种奇怪的巨物或者背景中有一个很小的人像的图像(惋惜没有剔除掉全部此类图像)。最后,该数据集留下了11000张图像,咱们感受在这个阶段这么多就足够了。
如上文所述,咱们曾在Jeremy Howard的课程中使用过Tiramisu模型。它的全名是“100层Tiramisu”,听起来像是一个很大的模型,可是它实际上很简洁,只有900万个参数。相比之下,VGG16的参数则多达1.3亿多。
Tiramisu模型基于DensNet,后者是近期提出的一种全部层都是全链接层的图像分类模型。并且同Unet同样,Tiramisu也在升采样层上添加了一些skip connection。
这种架构与FCN论文中阐述的想法相契合:使用分类架构,升采样,添加skip connection以改善模型。
咱们能够将DenseNet(https://arxiv.org/pdf/1608.06993.pdf%22)模型看做为Resnet模型的天然进化版,它记忆的是整个模型的全部层,而不是只在到达下一层以前“记忆”全部层。这些链接称为“highway connection”。这种链接会致使过滤器数量增长——定义为“增加率”(growth rate)。Tiramisu的增加率为16,所以咱们在每层上都添加16个新的过滤器,直到抵达过滤器总数为1072个的层。您可能会说模型是100层tiramisu模型,那不就是1600层吗。但事实并非这样,由于升采样层会损失一些过滤器。
Densenet模型简图——模型前面层的过滤器堆叠在一块儿
咱们按照原论文中阐述的训练安排训练咱们的模型:标准交叉熵损失函数,学习率为1e-3并且衰减很小的RMSProp优化器。咱们按比例这11000张图像分为训练图像(70%)、验证图像(20%)和测试图像(10%)。下文中的全部图像都来自于咱们的测试数据集。
为了使咱们的训练安排与原论文保持一致,咱们将epoch大小设为500张图像。这样的话,用于训练模型的数据就更多(本文中所用的CamVid数据集包含的图像数少于1000张),咱们能够经过改进结果周期性地改进模型。
另外,咱们只使用了2个类别的训练图像:背景和人像,原论文使用了12个类别。起先咱们用的是COCO的一些类别,可是却发现这对训练没有多大帮助。
某些数据集缺陷影响告终果:
动物——咱们的模型有时会语义分割动物,这必然会致使IOU值较小。在同一主类别中加入动物或将动物做为另外一主类别,可能会完全消除咱们的结果。
身体部位——因为使用编程的方法对数据集进行过滤,咱们没法判断“人”类别真的指的是人,仍是指人身体部位,如手部或脚部。这些图像虽然都不在咱们处理的范围内,可是仍然会出如今数据集中。
动物、身体部位、手持物体
手持物体——数据集中的许多图像都有运动有关,好比棒球棒、网球拍和滑雪板。咱们的模型在分割这些图像时会被迷惑。咱们认为,将动物做为主类别的一部分或者另外一单独类别会对模型的表现有帮助。
粗糙的ground truth——COCO数据集并未进行逐像素的标记,可是是用多边形标注的。有时效果很好,但有时ground truth却很粗糙,这会阻碍模型学习细节。
原图像和(很是)粗糙的ground truth
咱们的结果虽然使人满意,但仍是不够完美:咱们用测试数据集测试模型所获得的IOU值为84.6,而当前最优秀的模型的IoU值为85。这个数字很难统计,由于只要遇到不一样的数据集和类别,它就会波动。有些类别自己较为容易分割,例如房屋、道路等,模型处理这些类别时的IOU值能够达到90。较难处理的类别则包括数和人类,模型在处理这些类别时的IOU值在60上行波动。为了限定困难程度,咱们使模型只关注一个类别以及必定类型的图像。
咱们仍然感受咱们的产品并未实现预期的“生产就绪”,可是咱们认为这时候停下来讨论试验结果会更好,由于约50%的图像会得出好的结果。
如下是一些较好的实例,以便您了解咱们App的性能:
原图像、Ground truth、咱们的结果(来自于测试数据集)
调试是训练神经网络的一个很重要的环节。当刚开始进行工做时,很容易就会想直接获取数据和神经网络,开始训练,而后看看会得出什么样的结果。可是咱们发现,追踪每步操做极其重要,这样作的话咱们就能够对每一步的结果进行检查。
如下是一些常见的挑战以及咱们的应对方法:
早期问题——可能没法训练模型。多是由于一些内在问题或者某种预处理错误,如忘记正则化某部分数据。总之,对结果进行简单的可视化可能会有助于找出问题。这是一篇关于此论题的文章(https://blog.slavv.com/37-reasons-why-your-neural-network-is-not-working-4020854bd607)。
调试网络自己——在肯定无严重问题后,开始用预先定义的损失和metric进行训练。在分割任务中,主要的评价指标是检测评价函数(intersect over union,IoU)。在进行了几个阶段的工做后,咱们才开始将IoU做为模型的主要评价指标(而不是交叉熵损失)。另外一个有用的操做是给出模型在每个epoch的预测。这是一篇关于调试机器的优质文章(https://hackernoon.com/how-to-debug-neural-networks-manual-dc2a200f10f2)。注意IoU虽然不是Keras中标准的metric函数的或损失函数,可是在网上很容易就能够找到,例如此网站(https://github.com/udacity/self-driving-car/blob/master/vehicle-detection/u-net/README.md)。咱们还将这个gist(https://gist.github.com/shgidi/7c3fcf69b1eb3eaf4bac1112d10967ca)用于每个epoch的损失和某些预测的plotting中。
机器学习变体控制——当训练模型时,你会遇到不少参数,有些参数很难追踪。我必须认可咱们还没找到完美的解决方法,咱们的方法是频繁写入配置(以及利用Keras的callback自动保存表现最佳的模型,见下文)。
调试工具——在完成以上步骤后,咱们能够检查每一步的结果,可是不能无间断地检查。所以,最重要的步骤是整合上文中的步骤,生成一个Jupyter notebook,这样咱们就能够用它来无间断地加载每一个模型和每张图像,并快速检查结果。这样咱们就能轻易地观察到模型之间的差别、缺陷和其余问题。
如下是一些经过调整参数和增长训练而对模型实现的一些改进:
保存目前为止的最佳验证IoU:(Keras提供了一个很是好的工具——callbacks-https://keras.io/callbacks/%22 ,用于简化工做)
callbacks = [keras.callbacks.ModelCheckpoint(hist_model, verbose=1,save_best_only =True, monitor= ’val_IOU_calc_loss’), plot_losses]
除了对可能的代码错误进行的常规调试,咱们发现模型错误是“能够预测的”,好比“切割”不属于广义身体范畴的身体部位、大分割图像上的“缺口”、没必要要的身体部位持续延伸、光线很差、质量差以及等等细节错误。有些错误在从不一样数据集中提取特定图像时获得了处理,可是有些问题仍然未获得解决。为了改进下一版产品的结果,咱们将专门针对模型“难处理”的图像使用数据加强 (Data Augmentation)法。
上文探讨了这个问题以及数据集问题,如今咱们来看看咱们的模型遇到的一些问题:
衣服——颜色很是深或很是浅的衣服有时会被误看成为北京。
“缺口”——除了好的结果,得出的一些图像中存在缺口。
衣服和缺口
光线问题——光线不足和阴暗在图像中很常见,可是COCO数据集中的图像却没有这个问题。所以,处理可以解决一些标准的困难,咱们的模型如今还不能处理一些较难处理的图像。可是,咱们能够经过增长数据量以及数据加强法(data augmentation)来改进模型。另外,请避免在夜间使用咱们的App。
光线不足问题
在用训练数据完成了约300 epoch的训练后,咱们得出了生产结果。在此阶段结束后,模型开始过分拟合。咱们在发布产品前不久才得出了这些结果,所以咱们还没机会应用基本的数据加强操做。
在将图像尺寸调整为224X224后,咱们对模型进行了训练。使用更多的数据和更大的图像(COCO数据集图像的原始尺寸为600X1000)训练模型预计也能够改进结果。
在有些阶段中,咱们看到得出的图像在边缘有少量噪点。可使用CRF模型解决这个问题。在这篇博文中(http://warmspringwinds.github.io/tensorflow/tf-slim/2016/12/18/image-segmentation-with-tensorflow-using-cnns-and-conditional-random-fields/),做者给出了CRF。可是,CRF对咱们的工做帮助不大,也许是由于一般只有在结果较为粗糙时它才能有所帮助。
即便是咱们如今得出的结果,其分割效果也不完美。咱们永远也不能完美地分割头发、细致的衣服、树枝和其余精细的物体,就是由于ground truth分割图像不涵盖这些细节。分割此类细致分割图像的任务称为matting,这是一种不一样的挑战。这是一个优秀matting方案的实例(https://news.developer.nvidia.com/ai-software-automatically-removes-the-background-from-images/),发表在今年上半年内的NVIDIA会刊上。
Matting任务不一样于其余图像处理任务,由于它的输入不只包含一张图像,还有一个trimap——图像边缘的轮廓线,这使matting任务成了一个“半监督”问题。
咱们将分割图像做为trimap,进行了一些matting试验,可是得出的结果并很差。
还有一个问题时缺少训练所需的合适数据集。
正如文章开头说的那样,咱们的目标是开发一个有意义的深度学习产品。Alon在其文章中指出,机器学习的应用正变得愈来愈简单及快速。可是,模型训练倒是一个棘手的问题——训练(尤为是夜间训练)时须要仔细地进行计划、调试和记录结果。
要想平衡研究和创新、训练与改进之间的关系也不容易。由于使用的是深度学习方法,咱们总感受最好的模型或者最适合咱们的模型近在咫尺,也许谷歌再发布一项的研究或一篇论文,咱们就能找到实现的方法。可是实际上,咱们模型的改进其实是从原始模型中一点一点地“挤出来”的。就像我上文所说的,咱们仍然感受进步的空间还很大。
greenScreen.AI。感谢 Alon Burg.
做者:Gidi Shperber 机器学习发烧友
原文地址
https://medium.com/towards-data-science/background-removal-with-deep-learning-c4f2104b3157?nsukey=HjVxf540wVOL13ThjgEVgqK6yTM0j%2BlZf%2B56cPoPdFCFk%2F6NrblQg0ftuvs82azzYzUhxR4SKluuDZW6Hpk5849qrjCLB8VJg0ULIGW9dHP0nuecErk37IqJ%2Ff3A%2Bip8DzhS1EkpoXYPded2mOJbdA%3D%3D