本文提供了有关在图像恢复任务中使用的推荐方法的背景信息。阅读本文后,您将能够从头开始为您的目标创建相似图像的搜索引擎(不包括开发生产解决方案的过程)。
关于该项目
相似图像检索(也称为基于内容的图像检索或 CBIR)是涉及图像的任何搜索。
如今,“按照片搜索”方法正在积极使用,特别是在电子商务服务(全球速卖通、Wildberries 等)中。“关键字搜索”(理解图片内容)早已入驻Google、Yandex等搜索引擎,但尚未进入市场和其他私人搜索引擎。我认为自从耸人听闻的出现剪辑:连接文本和图像在计算机视觉领域,这种方法的全球化将会加速。
由于我们的团队专门研究计算机视觉中的神经网络,因此在本文中我将只关注按照片搜索方法。
基础服务组件
步骤 1. 训练模型。 该模型可以在经典 CV 或神经网络的基础上制作。模型输入 - 图像,输出 - D 维描述符/嵌入。在经典的情况下,它可以是 SIFT-描述符 + Bag of Visual Words 的组合。就神经网络而言,ResNet、EfficientNet 等标准主干 + 复杂的池化层 + 巧妙的学习技术,我们稍后会讲到。我可以说,如果你有足够的数据或良好的实践,神经网络几乎总是会受益匪浅(我们检查过),所以我们将专注于它们。
步骤 2. 索引图像库。 索引是在所有图像上运行经过训练的模型并将嵌入写入特殊索引以进行快速搜索。
步骤 3. 搜索。 使用用户上传的图像,运行模型,获得嵌入,并将该嵌入与数据库中的其他嵌入进行比较。搜索结果是按照相关性排序的搜索结果。
神经网络和度量学习
寻找相似性任务中的神经网络被用作特征提取器(主干)。骨干网的选择取决于数据的数量和复杂性——你可以考虑从ResNet18到视觉变形金刚.
图像检索中模型的第一个特征是神经网络头部的魔力。在 __ Image Retrieval 排行榜上,他们正在为构建最佳描述符而战——有带有并行池的 Combined Global Descriptors 和 Batch Drop Block,用于在输出特征图上更均匀地分布激活。
第二个主要特征是损失函数。他们有很多。在深度图像检索:一项调查仅此一项,就有十几种推荐的损失对。也有相同数量的分类。所有这些损失的要点是训练神经网络将图像转换为线性可分空间的向量,以便进一步可以通过余弦或欧几里得距离来比较这些向量:相似的图像将具有紧密的嵌入,不同的图像将具有遥远的。让我们仔细看看。
损失函数
对比损失
这是双重损失,即对象通过彼此之间的距离进行比较。
如果这些图像实际上相似,则神经网络会因图像 p 和 q 的嵌入彼此之间的距离而受到惩罚。类似地,嵌入的接近度也会受到惩罚,其图像实际上彼此不同。在这种情况下,在后一种情况下,我们设置边界 m(例如 0.5),克服它,我们认为神经网络已经完成了“分离”不同图像的任务。
三重损失
这里我们的目标是最小化anchor到positive的距离,最大化anchor到negative的距离。Triplet Loss 最早出现在谷歌的FaceNet文章、关于面部识别,长期以来一直是最先进的解决方案。
N元组损失
N-tupled Loss - Triplet Loss 的一种发展,它也采用锚点和正值,但使用多个负值而不是一个负值。
角度附加边距 (ArcFace)
成对损失的问题在于选择正、负和锚点的组合——如果它们只是从数据集中均匀随机地取出,那么就会出现“光对”的问题。这些是损失将为 0 的简单图像对。事实证明,网络收敛到一种状态的速度足够快,批次中的大多数元素对它来说都“容易”,并且它们的损失会结果为零 - 网络将停止学习。为了避免这个问题,他们开始提出复杂的成对挖掘技术——hard negative 和 hard positive 挖掘。您可以在本文中阅读有关此问题的更多信息。还有一个PML库,它实现了许多挖掘方法,总的来说,该库包含很多关于 PyTorch 上的度量学习任务的有用信息。
该问题的另一个解决方案是分类损失。想一想三年前导致最先进的面部识别的一个流行错误功能——ArcFace。
主要思想是在通常的交叉熵上添加一个缩进 m,它将一个类的图像嵌入分布在该类的质心区域,以便它们与其他类的嵌入簇分开至少一个角度 m。
这似乎是完美的损失特征,尤其是当您查看MegaFace 基准时。但是你需要记住,只有在有分类标记的情况下它才会起作用。如果你没有,你将不得不处理配对损失。
在这里,我直观地向您展示了当您具有单类和多类标记时最好使用哪些损失函数(您可以通过计算示例的多标签向量之间的交集百分比从后者导出成对标记)。
池化
让我们回到神经网络架构并考虑图像检索任务中使用的几个池化层。
MAC
Regional Maximum Activation of Convolutions (R-MAC)是一个池化层,它接受神经网络的输出图(在全局池化层或分类层之前)并返回一个描述符向量,计算为输出图不同窗口中的激活总和. 这里,窗口的激活是为每个通道独立地取这个窗口的最大值。
生成的描述符考虑了图像在不同尺度下的局部特征,从而创建了丰富的特征描述。这个描述符本身可以是一个embedding,所以可以直接送入loss function。
[广义平均数]
Generalized Mean (GeM) 是一种简单的池化方法,可以提高输出描述符的质量。最重要的是,经典平均池可以推广到 lambda 范数。通过增加 lambda,我们使网络专注于图像的重要部分,这在某些任务中可能很重要。
测距
指数
高质量搜索相似图像的关键是排名,即显示与给定查询最相关的示例。它的特点是构建描述符索引的速度、搜索的速度和消耗的内存。
最简单的方法是保持嵌入“正面”并对其进行强力搜索,例如,使用余弦距离。当有很多嵌入时就会出现问题——数百万、数千万甚至更多。搜索速度明显降低,堆占用量增加。一件积极的事情仍然存在——现有嵌入的搜索质量是完美的。
这些问题可以以牺牲质量为代价来解决——存储嵌入,不是以它们的原始形式,而是压缩(量化)。还要改变搜索策略——不是暴力搜索,而是尝试进行最少的比较,以找到最接近给定查询的所需数量。有大量用于近似搜索最近的框架的有效框架。一个特别的基准已为他们创建,您可以在其中查看每个库在不同数据集上的行为方式。
最受欢迎:网络图书馆,Spotify 烦恼,脸书费斯,谷歌扫描. 此外,如果您想使用开箱即用的 REST API 进行索引,您可以考虑吉娜申请
重新排名
信息检索领域的研究人员早就了解到,在收到原始搜索结果后,可以通过某种方式对项目进行重新排序来改进有序搜索结果。
一种这样的方法是查询扩展。这个想法是使用最接近元素的 top-k 来生成新的嵌入。在最简单的情况下,您可以采用平均向量,如上图所示。您还可以加权嵌入,例如,通过问题中的距离或与请求的余弦距离。这些改进在文章中的单个框架中进行了描述基于注意力的查询扩展学习. 或者,您可以递归地应用查询扩展。
k-倒数
k-reciprocal - 来自 top-k 的一组元素,包括最近的 k 个是请求本身。在此集合的基础上,构建了对结果重排序的过程,其中一个在文章中有所描述使用 k-reciprocal 编码重新排序行人重识别. 根据定义,k-reciprocal 比 k-nearest neighbors 更接近查询。因此,可以粗略地将 k 倒数集合中的元素视为有意为正,并更改权重规则,例如,对于查询扩展。在本文中,开发了一种机制,用于使用 top-k 中元素本身的 k 倒数集重新计算距离。文中包含大量的计算,这超出了本文的范围,建议读者熟悉一下。
验证
我们来检查类似搜索的质量。此任务中有许多微妙之处,初学者在刚开始从事图像检索项目时可能不会注意到。
指标
让我们考虑图像检索任务中的这些流行指标:precision@k、recall@k、R-precision、mAP 和 nDCG。
精度@R
优点
- 显示相关的前 k 个响应的百分比。
缺点
- 对给定查询的相关示例数量非常敏感,这不允许对搜索质量进行客观评估,其中不同查询的相关示例数量不同
- 只有当所有查询的相关数 >= k 时,才有可能达到值 1
R精度
与 precision@k 相同,其中 k 设置为等于相关查询的数量。
优点
- precision@k 中对数字 k 的敏感性消失,指标变得稳定
缺点
- 你必须知道与请求相关的总数(如果不是所有相关的都被标记,这可能是一个问题)
召回@k
显示在 top-k 中找到的相关项目的比例
优点
- 回答是否在 top-k 中发现原则上相关的问题
- 稳定且平均请求
mAP(平均精度)
显示我们用相关示例填充搜索结果顶部的密集程度。您可以将此视为搜索引擎用户收到的信息量,该用户阅读的页面数最少。因此,信息量与阅读页数之比越大,指标就越高。
优点
- 客观稳定地评估搜索质量
- 是precision-recall曲线的一位数表示,本身就有丰富的分析信息
缺点
- 你必须知道与请求相关的总数(如果不是所有相关的都被标记,这可能是一个问题)
nDCG(标准化贴现增益)
这个指标显示了 top-k 中的元素在它们之间排序的正确程度。我们不会考虑这个指标的优缺点,因为这是我们列表中唯一考虑元素顺序的指标。但是,有研究表明,在需要考虑顺序的情况下,该指标是相当稳定的,可以适用于大多数情况。
估计
宏: 为每个请求计算一个指标,对所有请求进行平均
优点:与此查询相关的不同数量没有显着波动
缺点:所有查询都被认为是平等的,即使有些查询比其他查询更相关
微观: 标记相关和单独成功找到相关的数量在所有查询中求和,然后参与相应指标的分数
优点:评估查询时会考虑与每个查询相关的标记数量
缺点:如果某些请求有很多标记的相关项并且系统未成功/成功地将它们带到顶部,则指标可能会变得非常低/非常高
验证系统
建议考虑两个验证选项
验证一组查询和选定的相关查询
输入:图像请求和与其相关的图像。存在与此查询相关的列表形式的标记。
要计算指标,您可以计算每个元素的相关矩阵,并根据有关元素相关性的二进制信息计算指标。
全碱基验证
输入:图像请求,以及与之相关的图像。还应该有一个图像验证数据库,最好在其中标记所有相关查询。此外,它不应包含查询图像,否则,它们必须在搜索阶段进行清理,以免阻塞 top-1。验证基础作为否定基础参与——我们的任务是找出与之相关的那些。
要计算指标,您可以遍历所有请求,计算到所有元素(包括相关元素)的距离,并将它们发送到指标计算函数。