如何为数据集构建图像重复查找器?(附代码)

当您从互联网上下载图像时,通常会发现噪声数据。此外,相似的图片都在附近,一个接一个地看到它们并试图找到重复数据来清理数据集是很繁琐的。

考虑到这个问题,作者构建了一个重复的查找程序,为您找到重复项,您只需要选择是否要删除它们。您可以在fastai库(网址:https://github.com/fastai/fastai)中找到代码。在这篇文章中,作者将解释他是如何构建这个工具的。

这是算法找到的实际副本

第1步:获取激活

我们通常使用CNN对图像进行分类,只对网络末端的softmax输出感兴趣,它告诉我们网络认为图像标签是什么。在这种情况下,我们将比较网络的内层,希望网络学到的一些功能对于查找类似的图像很有用。为了实现这一点,我利用了fastai库中的强大callbacks 功能(代码页:https://docs.fast.ai/callbacks.hooks.html),它允许我们保存网络中任何子层的激活。

hook = hook_output(learn.model[0][7][2])

我使用的激活是Resnet架构的最后一个卷积块的输出,因为我注意到它们在经验上更好地工作。

第2步:合并

您可能知道,CNN中的隐藏层有四个维度:批量大小、高度、宽度和要素数量。假设我们正在谈论一个特定的图像,或者bs = 1。例如,在Resnet 50的情况下,最后一层的输出将具有尺寸(1,7,7,248 )。由于这里的维度非常高,计算相似性会非常耗时,这对用户来说是一种痛苦。这个问题的答案是使用Pooling(网址:http://deeplearning.stanford.edu/tutorial/supervised/Pooling/)   。我们将汇集每个7x7矩阵,以便得到一个维度张量(1,pool_dim,pool_dim,2048)。

我使用的池函数是AdaptiveConcatPooling(自适应平均池和自适应最大池连接在一起),使用的池维数是4,因为我发现它是速度和性能的良好组合。

第3步:展平

我们以四个维度的张量结束了最后一步。然而,为了计算不同示例之间的相似性,我们需要一维张量(向量)。我们将展平每个图像的激活以获得大小为pool_dim x pool_dim x 512的向量,并且我们将每个图像的向量连接成具有维度(n_exs,vector_dim)的矩阵。现在我们为每个n_exs图像都有一个特征向量。是时候计算相似之处了

def get_actns(learn:Learner, dl:DataLoader, hook:Hook, pool=AdaptiveConcatPool2d, pool_dim:int=4, train:bool=True):
"""Gets the activations at the layer specified by `hook`,
  applies `pool` of dim `pool_dim` and concatenates."""    pool = pool(pool_dim)
   
   actns = []
   learn.model.eval()
   with torch.no_grad():
       for i,(xb,yb) in enumerate(dl):
           learn.model(xb)
           actns.append((hook.stored).cpu())
                                   
   return pool(torch.cat(actns)).view(len(dl.x), -1)

第4步:计算相似之处

为了计算每个特征向量之间的相似性,我们将使用余弦相似度函数。请注意,如果我们将每个向量与每个其他向量组合在一起,则所有相似度将被计算两次。还要注意,如果我们计算矢量与其自身的相似性,相似性的度量显然将是最高的。因此,对于我们的相似性矩阵,我们将用零替换对角线和右上角部分。

def comb_similarity(t1: torch.Tensor, t2: torch.Tensor, sim_func=nn.CosineSimilarity(dim=0)):
   """Computes the similarity function `sim_func` between each embedding
      of `t1` and `t2` matrices.
      t1` and `t2` should have dimensions [n_embeddings, n_features]."""
   
   self_sim = False
   if torch.equal(t1, t2): self_sim = True
       
   sims = np.zeros((t1.shape[0], t2.shape[0]))
   for idx1 in range(t1.shape[0]):
       for idx2 in range(t2.shape[0]):
           if not self_sim or idx1>idx2:
               ex1 = t1[idx1,:]
               ex2 = t2[idx2,:]
               sims[idx1][idx2] = sim_func(ex1,ex2)
               
   return sims

第五步:结果

让我们看看我们的方法是否有效!我用来测试算法的数据集是Oxford-IIIT Pet Dataset(http://www.robots.ox.ac.uk/~vgg/data/pets/),有37只狗和猫品种。

完美的重复。该图像在数据集中包含5次。

重复(一个有签名)

相似但不重复

我还用计算机视觉中众所周知的数据集CIFAR10测试了算法,看看我是否能找到一些重复数据。这些是我发现的一些例子:

完美复制

几乎是一个重复的卡车,但有不同的标志

不重复,更像是数据扩充

我还运行了relabeler小部件,这是一个额外有趣的发现:

不是卡车

一旦我们有网络的重复建议,我们应该怎么做?好吧,我们应该选择那些实际上是重复的并从我们的数据集中删除它们,因为重复会导致网络过于重视这些图像。我们如何轻松删除重复项?使用fastai的交互式小部件(https://github.com/fpingham/dataset-cleaner)非常容易!你可以通过运行来试试:

来自fastai.widgets进口*ds,fns_idxs = DatasetFormatter.from_similars('learner')
ImageCleaner(ds,fns_idxs,duplicates = True)

课程中所提到的网址整理如下:

fastai库:

https://github.com/fastai/fastai

callbacks 功能:

https://docs.fast.ai/callbacks.hooks.html

Pooling:

http://deeplearning.stanford.edu/tutorial/supervised/Pooling/

Oxford-IIIT Pet Dataset:

http://www.robots.ox.ac.uk/~vgg/data/pets/

fastai的交互式小部件:

https://github.com/fpingham/dataset-cleaner

信息来源:https://towardsdatascience.com/how-to-build-an-image-duplicate-finder-f8714ddca9d2

(0)

相关推荐