前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无论如何,这是哪条鲸鱼?利用深度学习对鲸鱼进行人脸识别

无论如何,这是哪条鲸鱼?利用深度学习对鲸鱼进行人脸识别

作者头像
HesionBlack
发布2018-06-01 10:46:34
1.3K0
发布2018-06-01 10:46:34

“正确的鲸鱼识别”是一个由NOAA Fisheries在Kaggle.com数据科学平台上组织的计算机视觉竞赛。我们在deepsense.io的机器学习团队已经在竞赛中获得了第一名!在这篇文章中,我们将描述了我们的解决方案

挑战

比赛的目标是航拍识别单个露脊鲸鱼。凭借肉眼观察,这些庞然大物长达18米以上,重达91吨。数据集中有447种不同的右侧鲸(这应该是露脊鲸鱼的总数)。尽管这个数字对于一个物种来说(惊人的)已经很小了,但是唯一识别一只鲸鱼对一个人来说是一个巨大的挑战。别过程的自动化(至少部分自动化)对拯救露脊鲸是非常有益的。

“研究者正致力于解救被渔具意外捕获的鲸鱼,而实时识别鲸鱼能够让研究者获得相关健康和渔网缠绕的历史记录,有助于研究者拯救鲸鱼”

-----摘自竞争者的描述页面。

这些航拍的照片是在不同时间,使用不同设备拍摄的,质量参差不齐:有的非常清晰,鲸鱼正好居中;有的拍摄距离很远,聚焦很差。

来自数据集的非随机样本。

预计这些团队将建立一个模型,以确认照片中捕获了447只鲸鱼中的哪一只。更具体地说,对于每张照片,我们被要求提供所有447只鲸鱼的概率分布。该解决方案通过多类对数损失来判断,也称为交叉熵损失。

值得注意的是,数据集并不平衡。每只鲸鱼的图片数量差异很大:有一些“名人”有四十多个,十几个有很多,大约二十个只有一张照片!另一个挑战是,表示不同类别(即不同鲸鱼)的图像彼此非常相似。这与我们试图在狗,猫,袋熊和飞机之间进行区分的情况有所不同。这给我们一直训练的神经网络带来了一些困难——构成单个鲸鱼的独特特征,或者将这种特殊的鲸鱼与其他鲸鱼分开,只占据图像的一小部分,并不是很明显。帮助我们的分类器专注于正确的功能,即鲸鱼的头部和他们的皮肤斑纹。

我们解决方案的核心

卷积神经网络(CNNs)已经被证明在图像识别任务中做得非常好,所以我们很自然地将我们的解决方案放在它们身上。事实上,据我们所知,所有的顶级参赛选手几乎在每一步都使用过它们。尽管有人说这些技术需要大量的数据(而且我们只有4544个训练图像可用,而一些鲸鱼在整个训练集中只出现一次),但我们仍然能够生成一个性能良好的模型,证明了这一点即使在有限的数据上,CNNs也是一个强大的工具。

事实上,我们的解决方案由多个步骤组成:

  • 头部定位器(使用CNNs),
  • 头部对准器(使用CNN),
  • 培训几个有关特征的鲸鱼照片(从以前的步骤中获得)的CNNs,
  • 平均和调整预测(不使用CNN)。

另一个诀窍在于为网络提供了一些额外的目标,即使这些额外的目标不一定在事后使用或以任何方式需要它。但如果额外的目标取决于我们特别感兴趣的图像部分(例如在这种情况下的头部和皮肤粗糙程度),这个技巧应该强制网络专注于这个领域。此外,网络有更多的刺激去学习,因此不得不开发更强健的功能(适用于多个任务),这应该限制过度拟合。

软硬件

我们使用Python,NumPy和Theano来实现我们的解决方案。为了创建手动注释(并且保证在长时间里不失去理智),我们使用了Sloth(一种通用标签工具)以及特殊的Julia脚本。

为了训练我们的模型,我们使用了两种Nvidia显卡:Tesla K80和GRID K520。

领域知识

尽管人类识别鲸鱼的难度似乎远远大于区别其他人,但神经网络不会因为这个明显的原因而遭受这种问题的困扰。即便如此,维基百科对鲸鱼的研究也显示,“露脊鲸最大的特征是由于鲸鱼虱寄生而导致的头皮上的白色,粗糙的皮肤”原来,它不仅能区分它们是来自其他种类的鲸鱼,也可以作为鉴别标本的绝佳方式。我们的解决方案使用这个依据来做很深远的事。除了这个稍微微不足道的提示(由组织者提供)以外,我们(可惜)没有关于正确的鲸鱼的领域知识。

准备工作

在深入细节之前,需要一个免责声明。在比赛中,人们(或应该)更倾向于测试新方法,而不是对现有方法进行微调和清理。因此,在一个想法被证明工作得很好之后不久,我们通常会对它进行选定,并将其保留“原样”。这样的一个副作用就是,算法的某些过于复杂,有缺陷的部分可能也应该被解决,但我们在比赛中并没有着手解决。本文中也不会涉及到这些问题。

人们不需要从数据集中看到许多图像,为了意识到到鲸鱼姿态不佳(或者至少在这种特殊的情况下不愿意这样做)。

不太合作的鲸鱼。

因此,在训练最终分类器之前,我们花了一些时间(和精力)来说明这个事实。这种方法的总体思想可以被认为是从主体处于任意位置的随机图片中获取护照照片。这归结成训练头部定位器和头部对准器。第一个拍摄照片并在头部周围产生边框,头部可以任意旋转,而不一定在照片的中间。第二个拍摄头部照片并对其进行调整和重新调整,以使喷水孔(blowhead)和帽尖(bonnet-tip)始终处于相同位置,并且它们之间的距离是恒定的。这两个步骤都是通过对训练数据的手动注释训练神经网络来完成的。

帽尖(红色)和吹气头(蓝色)。

定位鲸鱼

这是实现高质量护照照片的第一步。为了获得训练数据,我们在训练数据中手动注释了所有的鲸鱼,并在其头部装上了边界框(特别感谢我们的人力资源部门提供了很大的帮助!)。

头部定位器产生的边界框。

这些注释等同于给训练集中的每个图像提供四个数字:矩形的左下角和右上角的坐标。然后我们开始训练一个采用原始图像的CNN(调整为256×256)并输出边界框的两个坐标。尽管这显然是一个递归任务,但我们在将输出量化为分箱并将Softmax与交叉熵损耗一起使用方面取得了更大的成功,取代使用L2损失。我们还尝试了几种不同的方法,包括培训CNN来区分头部照片和非头部照片,甚至是一些无监督的方法。尽管如此,他们的结果却很差。

鲸鱼图片示例
鲸鱼图片示例

此外,头部定位网络还必须预测喷头和阀盖罩尖的坐标(以相同的量化方式),然而它在这项任务中不太成功,所以我们忽略了这个输出。

我们训练了5个不同的神经网络,他们都有几乎相同的架构。

头定位器的架构。

他们不同的是用于量化坐标的buckets数量。我们尝试了20,40,60,128,还有一个使用20的buckets,另一个(稍微小一点的)网络。

在将图像馈送到网络之前,我们已经使用了以下数据增强(将其调整为256×256之后):

  • 旋转:最大10°(注意,如果你允许更大的角度,仅仅简单旋转点是不满足的 - 你必须实现一些逻辑来重新计算边界框 - 我们懒得这样做),
  • 重新调整比例:1 / 1.2和1.2之间的随机比例,
  • 色彩扰动(如Krizhevsky等,2012),比例为0.01。

虽然我们没有在这里使用测试时增强(test-time augmentation)技术,但是我们合并了所有5个网络的输出。每次作物传递到下一步(头部对齐)时,选择来自所有5个变体的随机一个。以上可以看出,这些网络提供的产物非常令人满意。说实话 , 我们并没有真正地“物理”裁剪图像(即产生一组较小的图像)。我们做了一些替换,而结果是非常容易取得的,生成了一个带有边界框坐标的json文件。这可能看起来微不足道,但这样做会鼓励我们轻松地尝试它们。

鲸鱼的“护照照片

这个“使分类器的生存更简单”管道的最后一步是调整照片,使它们都符合相同的标准。这个想法是训练一个CNN来估算喷头和阀帽罩的坐标。有了它们,人们可以轻松想出一个将原始图像映射到两个点始终处于相同位置的转换。由于Anil Thomas注释,我们有了训练集的坐标。所以,我们再次开始训练CNN来预测量化的坐标。虽然我们并没有声称使用整个图像精确定位这些点,这是不可能的(即避免前一步),但我们现在面临着一个更容易的任务 - 我们知道头部的大致位置。

另外,网络还有一些额外的任务需要解决!首先它需要预测图像上的鲸鱼(即解决原始任务)。此外,它需要判断鲸鱼头部的粗糙模式是否连续(再次进行手动注释训练,尽管这次的工作量少得多,因为每只鲸鱼观看2-3个图像就足够了)。

不连续(左)和连续(右)的皮肤斑纹

我们使用了以下架构。

头部对准器的架构。

作为头部对准器的输入,我们从头部定位器中取出了作物。这次我们敢于使用更加大胆的增强功能:

  • 翻译:随机最多4个像素,
  • 旋转:最高360°,
  • 缩放比例:1.0和1.5之间的随机比例,
  • 随机翻转,
  • 色阶0.01的色彩扰动。

另外,我们使用了数据时增强技术 - 结果是在5次随机增量上进行平均(并不多,但仍然是!)。这个学习网络取得了惊人的好成绩。为了更加(或更低)精确,在手动检查过程中,几乎所有图像都可以很好地预测喷头和阀帽位置。此外,作为一种副产品(或者它是否是另一种方式?),我们开始看到一些有前途的结果,用于识别鲸鱼的最初任务。(相当悲观)验证损失在2.2左右。

把所有模块放在一起

在流水线中链接多个机器学习算法时,需要谨慎。如果我们对训练数据进行头部定位器和头部对准器的训练,并使用它们为训练和测试集制作“护照照片”,我们可能会得到质量差别很大(可能还有其他一些属性)的照片。当在这些作物上面训练分类器时,这可能变成一个严重的困难 - 如果在测试时它面临的输入与它习惯的输入不相似,那么它就不会执行。

虽然我们知道这一事实,但在检查农作物时,我们发现培训和测试数据之间的质量差异不大。而且,我们看到了对数损失的巨大改进。遵循“更多想法,更少居住”的思想,我们决定解决这种不纯的方法并继续努力。

鲸鱼的“护照照片”。

最终分类器

网络架构

几乎我们所有的模型都使用256×256图像并共享相同的体系结构。所有的卷积层都有3×3的滤波器,并没有改变图像的大小,所有的聚合层都是3×3,2步(它们的大小减半)。另外,所有的卷积层都遵循批量归一化和ReLU非线性。

主网络的架构。

在最终的融合中,我们也使用了一些具有类似架构的网络,但是处理512×512图像,并且一个网络具有这种架构的“双”版本(具有独立的堆叠卷积层副本,仅合并在完全连接层之前)。

再一次,我们通过增加一个额外的目标来违反网络的舒适区域 - 确定不确定性模式的连续性(与头部对齐方式相同)。我们也尝试添加更多来自其他手动注释的目标,其中一个目标是“面对称多少”。不幸的是,它没有进一步改善结果。

数据增强

在这一点上数据增强比平常有点棘手。其原因在于,您必须在丰富数据集之间进行平衡,而不是破坏从前一步获得的对齐和归一化。我们最终使用了非常温和的增强。虽然所有模型中的确切参数并不一致,但最常见的是:

  • 翻译:随机最多4个像素,
  • Totation:高达8°,
  • 重新缩放:1.0和1.3之间的随机比例,
  • 随机翻转,
  • 色阶0.01的色彩扰动。

我们还使用了测试时增强,并对20多个随机增强进行了平均。

初始化

我们使用了一个非常简单的初始化规则,零中心的正态分布,卷积层为std 0.01,全连接的层为0.001。这已经运行得很好了。

正则

对于所有模型,我们只使用L2正则化。不过卷积层和全连接层使用了单独的超参数。对于卷积层,我们使用较小的正则化,大约为0.0005,而对于全连接层,我们优选较高的值,通常在0.01-0.05左右。

还应该记得我们正在为网络添加补充额外的目标。这对权重施加了额外的限制,导致网络更多地关注鲸鱼的头部(而不是说水上的一些随机图案),这种方法很好地抑制了过拟合。

训练

我们用随机梯度下降(SGD)结合0.9动量训练了几乎所有的模型。通常我们在大约500-1000个周期之后才能停下来(确切的时间并不重要,因为不会过度拟合)。在训练过程中,我们对学习速率(0.9955)采用非常缓慢的指数衰减,并且经常进行手动调整学习速率。比如突然手动提高学习率(然后继续缓慢指数衰减),这时网络的错误(在训练集和验证集上)都上升了很多。然而,在几个周期后,他降到了更低的水平。我们最好的模式也使用了另一个想法 - 它首先用Nesterov动力训练了一百多个周期,然后我们转向使用Adam(自适应矩估计)。从一开始就一直使用Adam,我们无法实现类似的损失。初始学习率可能并不重要,但我们使用的值大约为0.0005的初值。

验证

我们随机使用了10%的培训数据进行验证。对亏了我们最喜欢的7300号种子,我们对所有模式都使用了这个种子。虽然,我们知道这种方法导致一些鲸鱼在训练集不存在,但它工作得很好。验证损失效果相当差,并与排行榜有很好的相关性。

放弃一个相对较小的数据集的10%不是毫无犹豫地决定做的事情。因此,在我们确定一个模型足够好之后,我们继续重新使用验证集进行培训(这很简单,因为我们没有任何过度拟合问题)。这是通过在整个训练集上重新运行一切(很少这样做)或者(更经常地)将验证集添加到训练集并运行50-100个附加周期来完成的。这也是为了解决仅在我们的验证集中出现的单张鲸鱼照片的问题。

预测结合

根据我们的验证(实际测试得分实际上更好),我们最终得到了一系列0.97到1.3的评分模型。由于保持了一致的验证集,我们能够测试一些混合技术以及基本转换。我们得出的结论是,使用更复杂的合成方法并不合理,因为我们的验证集没有包括所有的不同鲸鱼,实际上它们非常小。我们没有时间像集合那样进行一些巧妙的交叉验证,我们决定采用专门和简单的方式来验证。

尽管对预测的结果进行简单加权平均并不没有比单独的最佳模型有更好的分数(除非我们明显提高最佳模型的权重),但如果将预测提升到中等功率(在我们使用的最终解决方案是1.45)。这在对数损失中转化为约0.1的改善。我们还没有仔细研究这一点,但我们可以推测这个技巧是有效的,因为我们全连接层是强制规范化的,并不容易产生更多极端的概率。

我们还使用了一些“安全”转换,即将所有预测增加一个ε的量,并稍微偏向训练集中发现的鲸鱼分布。这些措施并没有对我们的分数有太大的影响。

加载图片

在我们解决方案的最后和中期阶段,我们从磁盘加载的映像是原始图像。这些图像很大。为了有效地使GPU ,我们必须并行加载它们。我们认为主要时间开销是从磁盘加载图像。事实证明,这并不是主要是时间开销。相反,主要时间开销是在JPEG文件解码为一个numpy数组的过程中。我们做了一个快速的基准测试,数据集中有111个随机原始图像,总计85Mb。读取它们,当它们没有被缓存在RAM中花费了约420毫秒。读取和解码到numpy数组花费了大约10秒。这是一个巨大的差别。解决这一问题可能的解决方案是使用其他图像格式,以提供更好的编码速度(以图像大小为代价),GPU解码等。

一些小技巧

尽管如此,很难说一个技术能够超过其他一切其他技术(除非进行仔细的分析),这里只提供关键技巧方面的知识。

获取高质量的裁剪图像,以及校准头部

我们已经通过两个阶段完成了这项工作,其结果远远超过了我们在一个阶段中观察到的结果。

人工标注,为神经网络提供额外的目标

这是基于向原始图像添加注释。它需要人工检查数以千计的鲸鱼图像,最终我们会在各个阶段(头部定位,头部对齐和分类)使用人工标注的结果。

Kicking(加速)学习率

虽然这可能是一个随意的初始化,一个糟糕的学习率衰减策略,以及一个不够奇特的SGD。但事实证明,Kicking(加速)学习率可以做得很好。

Kicking(加速)学习率后的损失函数。

校准概率

将预测提升到[1.1 - 1.6]范围内的中等功率对几乎所有模型或者混合模型都有帮助。这个技巧是在比赛结束时发现的,而且将得分提高了0.1。

重用验证集

合并验证和训练集并运行额外的50-100个新周期,这使我们的得分有了稳定地提升。

结论

总的来说,这是一个令人惊讶的难题,我们参加了一场令人惊叹的比赛。在这个过程中我们团队学到了很多东西,并且对深度学习的超强能力真的感到非常惊讶!

特别感谢Christin Khan和NOAA向数据科学界提出这一超常的挑战。我们希望这会激励更多人。当然,如果没有Kaggle.com这个平台很好的支持,这些都将变得不复存在。我们还要感谢Nvidia让我们使用Nvidia K80 GPU——他们起到了很大的作用。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 挑战
    • 我们解决方案的核心
      • 软硬件
        • 领域知识
          • 准备工作
            • 定位鲸鱼
            • 鲸鱼的“护照照片”
            • 把所有模块放在一起
          • 最终分类器
            • 网络架构
            • 数据增强
            • 初始化
            • 正则
            • 训练
            • 验证
          • 预测结合
            • 加载图片
              • 一些小技巧
                • 人工标注,为神经网络提供额外的目标
                • Kicking(加速)学习率
                • 校准概率
                • 重用验证集
              • 结论
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档