走进Aribnb位于旧金山总部的办公楼,你会看到一个个装修各异的会议室。这些会议室正是Airbnb形形色色民宿的缩影。
Airbnb为数百万的民宿提供了一个平台,也因此囊获了一大批民俗房间细节照片和用户数据。
坐拥百万级别的用户数据,Airbnb的数据团队可谓将数据的价值发挥地淋漓尽致。传统的推荐系统、广告系统自是不用说,深度学习的应用更是让Airbnb的数据有了前所未有的价值。
今天,文摘菌就要分享一篇来自Airbnb数据团队的课题小报告。让我们一起来看看,Airbnb的数据科学家们(Shijing Yao, Qiang Zhu, Phillippe Siclait)是怎么将他们的图片数据玩出花样的。
Airbnb在旧金山总部的会议室
数据真的是新石油么?
如果把这个问题抛给Airbnb的数据团队,那他们一定会给出一个坚定的答复:一点儿没错!
Airbnb为数百万的民宿提供了一个平台。全世界的旅行者都在这个平台上为他们的旅行寻找到最满意的家。而对于这些房屋除了地段和价格外,房屋本身的照片是最能影响用户决策的因素之一了。
然而直到目前,我们对这些照片了解的甚少,Airbnb形态各异的民宿也增加了我们分析这些照片的难度。
当旅行者在浏览一张房屋的照片时,我们暂时无法为用户提供最能准确反映民宿情况的图片,也无法为房东提升照片的吸引力提供指导和建议。
客厅、厨房、卧室、浴室图片示例
得益于如今计算机视觉和深度学习的优势,我们终于可以规模化地解决这一问题了。
我们今天的目标是图片分类。这样,一方面我们能将具有相似风格的房源聚集到一起,方便用户浏览。另一方面,分类也可以帮助验证房间数量和房屋信息的准确性。在不久的未来,我们将对这些图片进行更深的研究,预计还能发掘出许多潜在的信息。文章的最后我们会展示一些实例。
图片分类
正确的图片分类对优化提升用户体验是极具意义的。从客户端来讲,分类便于对一系列照片的重新排序,确保最先看到的都是最感兴趣的内容;从房东的角度来讲,分类为审查照片的清单提供了便利,帮助房东确保自身能满足市场的高标准。而精准的照片分类是这些核心功能得以实现的基石。
我们最先进行分类的对象房屋类型包含了卧室、浴室、客厅、厨房、游泳池和园景,我们后期还会根据产品团队的需要,添加房间其他的元素。
房间类型分类问题类似于ImageNet上的图片分类,期望输出的是具有用户个性化的结果。这就使得诸如VGG,ResNet这样的现成又先进的深度神经网络模型(DNN)是没办法直接使用的。
当然,网上有许多很棒的帖子,告诉人们如何使用这些模型来解决这类问题。其中,最基本的两步是:1.修改DNN模型的最顶层以保证输出结果符合要求;2.重新训练DNN网络以确保达到想要的预期。
通过几次实验,我们选取了ResNet50网络作为驱动,由于它在模型性能和计算时间上具有良好的平衡性。同时,为了确保与用例的兼容性,我们加入了两个额外的全连接层和一个Softmax激活函数。
相关链接:
https://arxiv.org/abs/1512.03385
重新训练ResNet50模型
修改后的RESNET50的体系结构基础模型图
ResNet50模型的重训练有三种方法:
保持基础ResNet模型,仅以最小的数据量重新训练新添加的两层。也称作微调。
同1一样的微调,但数据量更大。
重新训练整个ResNet50模型。
绝大多数的在线教程会使用第一种方法,计算省时且结果可观。我们也确实通过第一种方法得出了合理的最初结果,然而为了满足分类结果质量的高标准,我们需要更显著地提高模型性能——保证95%+的高精度和80%+的召回率。
为了兼顾精确率和高召回率,我们意识到必然要用到海量的数据对DNN模型进行重训练,然而这里存在两个挑战:1.即使拥有大量来自用户上传的照片数据,我们却无法对其打上精确的标签;2.重新训练ResNet50的DNN模型任务量非常重要—需要2500万训练参数,对GPU要求极高。下面,我们就来详细介绍我们是如何应对这两个挑战的。
图片标题管理
许多公司会依托第三方供应商来获取高质量的图片标签。然而在数以百万计的照片需要标签的情况下,这显然不是最具性价比的解决方案。
为了权衡成本和性能,我们采取一种混合的方案,一方面,委托第三方对少量打标签,通常是成千上万张照片。以这些具有标签的数据作为模型的评估标准,采用随机抽样法来建立这一标准,以确保标准数据的平衡性;另一方面,利用房东上传的照片标题数据作为房屋类型信息的代表,并从中提取标签。
这种方案对我们来说是非常有意义的,明显降低了标签所需的高昂成本。我们仅仅需要一套明智的方法来确保从图片标题中提炼的房屋类型标签准确可靠。
从图像标题中提取房间类型的标签似乎是一种可行的方法:如果某张图片的标签中包含有某种明确的房屋类型关键词,那么图片就该加以相应房屋类型的标签。然而现实情况往往更加复杂:这种方法的结果是令人失望的。太多的情况下,图片标签与图片实际内容相差甚远,如下一些例子:
错误的标签提炼示例
为了筛除这些错误的情况,我们又额外增加了一条规则。经过几轮筛选和检查,标签质量有了明显的提升。以下就是一个实例,展示了我们是如何将标签中含有“厨房”关键字的数据进行筛选,以获得真正描述“厨房”的图片。
代码段:
AND LOWER(caption) like '%kitchen%' AND LENGTH(caption) <= 22 AND LOWER(caption) NOT LIKE '%bed%' AND LOWER(caption) NOT LIKE '%bath%' AND LOWER(caption) NOT LIKE '%pool%' AND LOWER(caption) NOT LIKE '%living%' AND LOWER(caption) NOT LIKE '%view%' AND LOWER(caption) NOT LIKE '%door%' AND LOWER(caption) NOT LIKE '%table%' AND LOWER(caption) NOT LIKE '%deck%' AND LOWER(caption) NOT LIKE '%cabinet%' AND LOWER(caption) NOT LIKE '%entrance%'
由于这些额外的过滤器,我们丢失了许多图片数据。但是这没有明显的不良影响:即便采用了如此激进的筛选方法,我们仍然为每个房屋类型获取了成百上千张照片,累计达几百万张。
而且,通过与标准平衡数据集的对比,我们发现标签的质量显著提升了。这里我们假设数据分布没有随着过滤而改变。究竟是不是这样,那就要看模型在测试数据集上的表现了。
未来,我们希望利用NLP技术对图片标题进行动态聚类,取代目前基于规则的启发式算法。然而就目前而言,还是会继续采用启发式算法。
建模、评估、求解
左:8核并行训练的GPU性能,右:分布式SGD:从Quoc v.Le中引用的图表
要想用几百万张图像重新训练像ResNet50那样的DNN模型需要大量的计算资源。我们在带有英伟达8核K80GPU的AWS P2.8xlarge实例上进行训练,在每个训练步骤中,我们向8个GPU发送一批样本(batch),每一批样本共128张图像。
我们使用Tensorflow作为后端进行并行训练,在并行后进行编译,否则训练无法进行。为了进一步加快训练速度,我们从keras.applications.resnet50.ResNet50中加载已经训练好的图像网络权重,用这些权重对模型权重进行初始化。
经过3个训练时期(epoch),历时约6个小时后,模型达到了最好效果,之后模型便开始过拟合,验证集的效果也不再提升了。
值得注意的是,我们对房间做分类时采用的是多个二分类模型,而不是采用一个包括所有房间类型的多分类模型。这么做并不理想,但由于我们的模型主要还是离线(offline)的,多次调用模型造成的额外延迟对我们的影响很小。以后我们很快就会转为训练多分类模型。
我们用精确率(precision)和召回率(recall)对模型进行评估,并用F1分数(F1-score)和准确率(accuracy)等指标对模型进行监控。
这里再重新回顾一下这几个指标的定义:简而言之,精确率描述了预测为正的样本中有多少为真正的正样本,召回率描述了样本中的正例有多少被正确预测了,精确率和召回率通常是互相制约的。
在我们这个例子中,我们对精确率设定了一个比较高的标准(95%),因为当我们说这张照片属于某种房间类型时,我们应该对这个说法有很高的信心。
混淆矩阵与精确率、召回率、F1分数、准确率的定义
混淆矩阵是计算这些矩阵的关键。我们模型的原始输出是对每个图像给出一个范围在0到1内的概率分数,要计算出一组预测值的混淆矩阵,首先要设置一个阈值,将预测分数转换为0或1,然后通过从0到1调整阈值取值,生成精确率-召回率(PR)曲线。原则上,PR曲线的AUC(曲线下面积)越接近1,模型越精确。
人为标记的标签作为真实标签。有趣的是,我们发现不同房间类型的模型准确率不大一样。房间类型为卧室和浴室时的模型是最准确的模型,而房间类型为其他时的模型则不太准确。简洁起见,我们只展示房间类型为卧室和客厅时的P-R曲线,其中虚线的交叉点表示给定某个阈值时的模型效果,图中还展示了此时各个指标的摘要。
房间类型为卧室时的PR曲线
房间类型为客厅时的PR曲线
这里有两个重要的发现:
房间类型为卧室时模型的整体表现远胜于房间类型为客厅时的模型表现。对此有两种可能的解释:1.卧室比客厅更容易分类,因为卧室的布置相对标准,而客厅的布置则相对更加多样化。2.从卧室照片中提取的标签比从客厅照片中提取的标签质量更高,因为客厅照片有时还包括饭厅或厨房。
无论是哪种房间类型,完全重新训练的模型(红色曲线)要比部分重新训练的模型(蓝色曲线)具有更好的表现,而且房间类型为客厅时,这两个模型之间的差距比房间类型为卧室时的更大。这表明重新培训一个完整的ResNet50模型对于不同的房间类型有不同的影响。
在我们训练的6个模型中,精确率一般在95%以上,召回率一般在50%以上,人们可以通过设置不同的阈值对这两个指标进行权衡。这个模型旨在为Airbnb内部的多个产品团队提供多种不同的产品。
用户将我们的结果与一些有名的第三方图像识别API进行了比较。根据他们反映,我们这个对房子内部结构进行分类的模型,总体上优于第三方的模型,这说明当我们做某个自己感兴趣的任务时,通过使用自己的数据,我们也有机会超越业界最先进的模型。
最后,我们想展示一些具体例子来说明这个模型的强大功能。
左边两张照片被正确地预测为卧室,右边两张照片被正确地预测为“不是卧室”
左边两张照片被正确地预测为浴室,右边两张照片被正确地预测为“不是浴室”
左边两张照片被正确地预测为泳池,右边水族馆和海滨的两张照片被正确地预测为“不是泳池”
除了分类以外,我们还做了些别的
在做这个项目时,我们也尝试了一些除了对房间类型进行分类以外的有趣想法。在这里我们想展示两个例子,让人们了解到这些问题有多令人振奋。
非监督的场景分类
在我们刚开始尝试使用预先训练好的ResNet50模型对房间类型进行分类时,我们生成了图像的嵌入向量(维度为2048x1的向量)。为了解释这些向量意味着什么,我们使用PCA技术将这些长向量投影到2D平面上。
令我们惊讶的是,投影后的数据被自然地聚为两类。纵观这两个分类,我们发现左边的分类几乎都是室内的场景,右边的分类则几乎都是户外场景。这意味着无需再进行任何训练,只需在图像嵌入向量的第一个主成分上设置一条切割线,就可以确定室内和室外场景。这一发现为无监督的迁移学习(嵌入)等有趣的领域开启了大门。
室内和室外的照片被自动聚类为第一和第二主成分
目标检测
我们尝试努力的另一个领域是目标检测。预先训练好的Faster R-CNN已经在开放的图像数据集上达到了惊人的效果。
在下面的例子中你会看到,该模型能够检测到门、窗、餐桌及其位置。 通过使用Tensorflow Object Detection API,我们对房主上传的照片做了一些快速评估。使用现成的结果已经可以检测到很多家居设施。
未来,我们计划使用Airbnb定制的便利标签重新训练Faster R-CNN模型。由于开源数据中缺少一些这样的标签,我们可能会自己创建标签。通过用这些算法检测到的设施,我们可以房主上传的图片质量,并帮助客人更方便地找到具有特定环境需求的房屋,这将把Airbnb的照片智能前沿推向更高水平。
门、窗、餐桌被成功检测
结论
以下是一些重要结论,可能会对各位深度学习实践者有用:
首先,深度学习不过是一种特殊的有监督学习,我们不能高估高质量标签对数据的重要性。由于深度学习通常需要大量的训练数据才能达到出色的表现,因此寻找一种有效的标记方法显得至关重要。幸运的是,我们发现了一种经济的、可扩展的且可靠的组合方法。
其次,从零开始训练像ResNet50这样的DNN模型可能会相当复杂。不妨试试以简单快速的方式开始——使用小的数据集只对网络最上面的层进行训练。如果您确实有大量可训练数据集,从头开始重新训练DNN可能能让模型能达到更好的表现。
第三,如果可以的话,进行并行训练。在我们的例子中,我们通过使用8个GPU获得了大约6倍(准线性)的加速。这使得建立复杂的DNN模型在计算上可行,而且也让超参数和模型结构上的迭代变得更加容易。
原作者按
这项工作是与Krishna Puttaswamy、Xiaohan Zeng 和Alfredo Luque合作完成的,整个公司的员工帮忙推出了这个产品的功能。我们还要感谢Keras、Tensorflow、Open Images Data、ImageNet等开源库的贡献者和和ResNet的发明者,我们从这个友好的开源社区获益匪浅。最后,我们要感谢Jeff Feng和Rebecca Rosenfelt在校对方面的热情帮助。