Python 如何在另一个numpy数组中对近似相同的矩阵进行配对

Python 如何在另一个numpy数组中对近似相同的矩阵进行配对,python,arrays,numpy,memory,siamese-network,Python,Arrays,Numpy,Memory,Siamese Network,背景 我有以下代码,其工作原理类似于咒语,用于为暹罗网络制作配对: def make_pairs(images, labels): # initialize two empty lists to hold the (image, image) pairs and # labels to indicate if a pair is positive or negative pairImages = [] pairLabels = [] # calculate the total number

背景

我有以下代码,其工作原理类似于咒语,用于为暹罗网络制作配对:

def make_pairs(images, labels):

# initialize two empty lists to hold the (image, image) pairs and
# labels to indicate if a pair is positive or negative
pairImages = []
pairLabels = []

# calculate the total number of classes present in the dataset
# and then build a list of indexes for each class label that
# provides the indexes for all examples with a given label
#np.unique function finds all unique class labels in our labels list. 
#Taking the len of the np.unique output yields the total number of unique class labels in the dataset. 
#In the case of the MNIST dataset, there are 10 unique class labels, corresponding to the digits 0-9.

numClasses = len(np.unique(labels))

#idxs have a list of indexes that belong to each class

idx = [np.where(labels == i)[0] for i in range(0, numClasses)]

#let’s now start generating our positive and negative pairs
for idxA in range(len(images)):
    
    # grab the current image and label belonging to the current
    # iteration
    currentImage = images[idxA]
    label = labels[idxA]
    
    # randomly pick an image that belongs to the *same* class
    # label
    idxB = np.random.choice(idx[label])
    posImage = images[idxB]
    
    # prepare a positive pair and update the images and labels
    # lists, respectively
    pairImages.append([currentImage, posImage])
    pairLabels.append([1])
    
    #grab the indices for each of the class labels *not* equal to
    #the current label and randomly pick an image corresponding
    #to a label *not* equal to the current label
    negIdx = np.where(labels != label)[0]
    negImage = images[np.random.choice(negIdx)]
    # prepare a negative pair of images and update our lists
    pairImages.append([currentImage, negImage])
    pairLabels.append([0])
#return a 2-tuple of our image pairs and labels
return (np.array(pairImages), np.array(pairLabels))
好的,这段代码通过为MNIST数据集中的每个图像选择对来工作。它通过随机选择同一类标签的另一个图像和不同类标签的另一个补丁来构建该图像的一对。通过运行代码,返回的两个矩阵的最终形状为:

# load MNIST dataset and scale the pixel values to the range of [0, 1]
print("[INFO] loading MNIST dataset...")
(trainX, trainY), (testX, testY) = mnist.load_data()

# build the positive and negative image pairs
print("[INFO] preparing positive and negative pairs...")
(pairTrain, labelTrain) = make_pairs(trainX, trainY)
(pairTest, labelTest) = make_pairs(testX, testY)

>> print(pairTrain.shape)
(120000, 2, 28, 28)
>> print(labelTrain.shape)
(120000, 1)
我的数据集

我想用另一个数据集做一些不同的事情。假设我有另一个包含5600个RGB图像的数据集,其尺寸为28x28x3,如下所示:

>>> images2.shape
(5600, 28, 28, 3)
>>> labels2.shape
(5600,)

>>> len(np.unique(labels2))
8

>>> (labels2==0).sum()
700
>>> (labels2==1).sum()
700
>>> (labels2==2).sum()
700
...
我有另一个数组,我们称之为labels2,它有8个标签用于所有5600个图像,每个标签700个图像,如下所示:

>>> images2.shape
(5600, 28, 28, 3)
>>> labels2.shape
(5600,)

>>> len(np.unique(labels2))
8

>>> (labels2==0).sum()
700
>>> (labels2==1).sum()
700
>>> (labels2==2).sum()
700
...
我想做什么

我的数据集不是MNIST数据集,因此来自同一类的图像不太相似。我希望通过以下方式构建大致相同的对:

对于数据集中的每个图像,我希望执行以下操作:

1.1。通过MSE计算该图像与数据集中所有其他图像之间的相似度

1.2对于具有与该图像相同标签的图像的MSE集,选择具有7个最小MSE的图像并构建7对,其中包含该图像加上7个最近的MSE图像。这些对表示来自我的暹罗网络的同一类的图像

1.3对于具有与该图像不同标签的图像的MSE集,对于每个不同标签,仅选择一个具有最小MSE的图像。因此,由于有7个标签与该图像的标签不同,因此该图像还有7对

由于我的数据集有5600个图像28x28x3,并且对于每个图像,我构建了14对相同类的7对和不同类的7对,因此我希望有一个大小为78400、2、28、28、3的成对训练矩阵

我做了什么

我有以下代码,完全符合我的要求:

def make_pairs(images, labels):

# initialize two empty lists to hold the (image, image) pairs and
# labels to indicate if a pair is positive or negative
pairImages = []
pairLabels = []


#In my dataset, there are 8 unique class labels, corresponding to the classes 0-7.
numClasses = len(np.unique(labels))

#Initial lists
pairLabels=[]
pairImages=[]

#let’s now start generating our positive and negative pairs for each image in the dataset
for idxA in range(len(images)):
        print("Image "+str(k)+ " out of " +str(len(images)))
        k=k+1  

        #For each image, I need to store the MSE between it and all the others
        mse_all=[]

        #Get each image and its label
        currentImage = images[idxA]
        label = labels[idxA]
        
        #Now we need to iterate through all the other images    
        for idxB in range(len(images)):
            candidateImage = images[idxB]
            #Calculate the mse and store all mses
            mse=np.mean(candidateImage - currentImage)**2
            mse_all.append(mse)
        
        mse_all=np.array(mse_all)

        #When we finished calculating mse between the currentImage ad all the others, 
        #let's add 7 pairs that have the smallest mse in the case of images from the 
        #same class and 1 pair for each different class 
        
        #For all classes, do                   
        for i in range(0,numClasses):

            #get indices of images for that class
            idxs=[np.where(labels == i)[0]] 
            
            #Get images of that class
            imgs=images[np.array(idxs)]
            imgs=np.squeeze(imgs, axis=0)
                
            #get MSEs between the currentImage and all the others of that class
            mse_that_class=mse_all[np.array(idxs)]
            mse_that_class=np.squeeze(mse_that_class, axis=0)
            
            #if the class is the same class of that image   
            if i==label:    
                #Get indices of that class that have the 7 smallest MSEs
                indices_sorted = np.argpartition(mse_that_class, numClasses-1)
            
            else:
                #Otherwise, get only the smallest MSE
                indices_sorted = np.argpartition(mse_that_class, 1)
            
            # Now, lets pair them
            for j in range(0,indices_sorted.shape[0]):

                image_to_pair=imgs[indices_sorted[j], :, :, :]
                pairImages.append([currentImage, image_to_pair])
                
                if i==label:
                    pairLabels.append([1])
                else:
                    pairLabels.append([0])
        del image_to_pair, currentImage, label, mse_that_class, imgs, indices_sorted, idxs, mse_all
return (np.array(pairImages), np.array(pairLabels))
我的问题

我的代码的问题是,当我运行图像编号2200的成对构造时,它只是冻结了我的计算机,我试图清理每个循环后的变量,正如您在上面的代码del image_to_pair、currentImage、label、mse_that_class、imgs、index_sorted、idxs、mse_all中看到的那样。问题是,一个120000,2,28,28对数矩阵并不难建立,但一个78400,2,28,28,3是。因此:

这可能是内存问题吗? 我可以清除代码中的更多变量以使其工作吗? 我是否必须对我的pairImages矩阵的最后一个维度进行分解,使其比第一个示例的维度更小,从而起作用? 有没有更简单的方法来解决我的问题?
您可以找到功能代码和输入矩阵

您可以尝试在每个循环的开始处运行gc.collect以主动运行垃圾收集器。在运行垃圾收集之前,Python中的内存不会被释放。我不清楚您当前的del声明是否在做您希望它做的事情。del递减refcount,但它不一定释放内存,而且您的代码实际上是向它提供一个新创建的元组,而不是变量

78400*2*28*28*3=368793600,乘以每段数据的大小(以字节为单位),这向我表明这应该是内存问题。我的猜测是,冻结是指计算机试图从使用RAM切换到使用驱动器上的交换文件,并且像这样密集地使用交换文件会导致任何计算机转储

您的图像也应该通过生成器一次加载一个,而不是打包到数组中

import gc
gc.collect()

生成器的功能与列表完全相同,它关注for循环和类似的东西,不同之处在于列表中的每个项目都是当场生成的,而不是加载到内存中。这有点技术性,但是tl;dr这是一个列表生成器,它只能动态加载图像。

您可以尝试在每个循环的开始处运行gc.collect以主动运行垃圾收集器。在运行垃圾收集之前,Python中的内存不会被释放。我不清楚您当前的del声明是否在做您希望它做的事情。del递减refcount,但它不一定释放内存,而且您的代码实际上是向它提供一个新创建的元组,而不是变量

78400*2*28*28*3=368793600,乘以每段数据的大小(以字节为单位),这向我表明这应该是内存问题。我的猜测是,冻结是指计算机试图从使用RAM切换到使用驱动器上的交换文件,并且像这样密集地使用交换文件会导致任何计算机转储

您的图像也应该通过生成器一次加载一个,而不是打包到数组中

import gc
gc.collect()
生成器的功能与列表完全相同,涉及for循环和类似的内容,不同之处在于每个
列表中的tem是现场生成的,而不是加载到内存中。这有点技术性,但是tl;dr它是一个列表生成器,只在运行时加载图像。

我相信您可以使代码的这一部分变得更简单,这对运行时也会有所帮助

#Now we need to iterate through all the other images    
for idxB in range(len(images)):
    candidateImage = images[idxB]
    #Calculate the mse and store all mses
    mse=np.mean(candidateImage - currentImage)**2
    mse_all.append(mse)
不必使用for循环迭代数据,只需这样做,然后让NumPy进行广播

# assuming images is a numpy array with shape 5600,28,28,3
mse_all = np.mean( ((images - currentImage)**2).reshape(images.shape[0],-1), axis=1 )
# mse_all.shape 5600,

我相信您可以使代码的这一部分变得更容易,这对运行时也会有所帮助

#Now we need to iterate through all the other images    
for idxB in range(len(images)):
    candidateImage = images[idxB]
    #Calculate the mse and store all mses
    mse=np.mean(candidateImage - currentImage)**2
    mse_all.append(mse)
不必使用for循环迭代数据,只需这样做,然后让NumPy进行广播

# assuming images is a numpy array with shape 5600,28,28,3
mse_all = np.mean( ((images - currentImage)**2).reshape(images.shape[0],-1), axis=1 )
# mse_all.shape 5600,
一些可能的问题和优化 除了尝试强制垃圾收集器释放未使用的内存,这似乎无法通过尝试解决您的问题之外,我认为您的代码中还有其他问题,除非我不明白发生了什么

通过查看以下代码段:

#Agora adiciono os 7 mais parecidos com aquele bloco, sendo 7 da mesma e 1 de cada das outras classes. 1 bloco 
   for j in range(0,indices_sorted.shape[0]):
似乎您正在为j迭代一些可能的问题和优化 除了尝试强制垃圾收集器释放未使用的内存,这似乎无法通过尝试解决您的问题之外,我认为您的代码中还有其他问题,除非我不明白发生了什么

通过查看以下代码段:

#Agora adiciono os 7 mais parecidos com aquele bloco, sendo 7 da mesma e 1 de cada das outras classes. 1 bloco 
   for j in range(0,indices_sorted.shape[0]):

似乎您正在为j进行迭代,您编写了mse=np.meancandidateImage-currentImage**2;我假设mse代表均方误差,在这种情况下,它应该是mse=np.meancandidateImage-currentImage**2。或者您可以使用sklearn.metrics导入均方误差;mse=均方误差候选图像,currentImage。我想你可以通过计算相似度Ex:kneighborseuclidean距离来解决这个问题,该距离由来自图像网最后一层的特征向量计算得出。你写了mse=np.mean候选图像-currentImage**2;我假设mse代表均方误差,在这种情况下,它应该是mse=np.meancandidateImage-currentImage**2。或者您可以使用sklearn.metrics导入均方误差;mse=均方误差候选图像,currentImage。我想你可以通过计算相似度ex:kneighborseuclidean距离来解决这个问题,该距离由来自最后一层图像的特征向量来计算