Press "Enter" to skip to content

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

这是算法找到的实际副本

 

第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/) 。我们将汇集每个 7×7 矩阵,以便得到一个维度张量 (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

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注