Python 如何更有效地计算用户相似度矩阵?

Python 如何更有效地计算用户相似度矩阵?,python,performance,loops,optimization,time,Python,Performance,Loops,Optimization,Time,我有一组10个用户,每个用户都有自己的文件夹/目录,其中包含25-30张他们共享的图片(比如在一些社交媒体中)。我想根据用户共享的图像计算他们之间的相似性 为此,我使用一个特征提取器将每个图像转换成一个224x224x3数组,然后循环遍历每个用户及其文件夹中的每个图像,以找到每对图像之间的余弦相似性,然后对每对用户的所有成对图像相似性取平均值,以找到用户相似性。(顺便说一下,如果这个逻辑有错误,请告诉我) 我的代码如下所示: from tensorflow.keras.applications.

我有一组10个用户,每个用户都有自己的文件夹/目录,其中包含25-30张他们共享的图片(比如在一些社交媒体中)。我想根据用户共享的图像计算他们之间的相似性

为此,我使用一个特征提取器将每个图像转换成一个224x224x3数组,然后循环遍历每个用户及其文件夹中的每个图像,以找到每对图像之间的余弦相似性,然后对每对用户的所有成对图像相似性取平均值,以找到用户相似性。(顺便说一下,如果这个逻辑有错误,请告诉我)

我的代码如下所示:

from tensorflow.keras.applications.imagenet_utils import preprocess_input
from tensorflow.keras.applications import vgg16
from tensorflow.keras.preprocessing.image import load_img,img_to_array
from tensorflow.keras.models import Model

import os
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd

# load the model
vgg_model = vgg16.VGG16(weights='imagenet')

# remove the last layers in order to get features instead of predictions
feat_extractor = Model(inputs=vgg_model.input, outputs=vgg_model.get_layer("fc2").output)

def processed_image(image):
    original = load_img(image, target_size=(224, 224))
    numpy_image = img_to_array(original)
    image_batch = np.expand_dims(numpy_image, axis=0)
    processed_image = preprocess_input(image_batch.copy())
    img_features = feat_extractor.predict(processed_image)
    return img_features

def image_similarity(image1, image2):
    image1 = processed_image(image1)
    image2 = processed_image(image2)
    sim = cosine_similarity(image1, image2)
    return sim[0][0]

user_list = ['User '+str(i) for i in range(1,11)]
user_sim_df = pd.DataFrame(columns=user_list, index=user_list)
for user1 in user_list:
    for user2 in user_list:
        sum_img_sim = 0
        user1_files = [imgs_path + x for x in os.listdir('All_Users/'+user1) if "jpg" in x]
        user2_files = [imgs_path + x for x in os.listdir('All_Users/'+user2) if "jpg" in x]
        
        for image1 in user1_files:
            for image2 in user2_files:
                sum_img_sim += image_similarity(image1, image2)
        
        user_sim_df[user1][user2] = 2*sum_img_sim/(len(user1_files)+len(user2_files))
现在,由于计算用户相似性矩阵时涉及到4个
for
循环,因此代码运行时间太长(键入此问题时已超过30分钟,代码已运行了10个用户,每个用户有25-30张图像)


那么,如何重写本文的最后一部分以加快代码的运行速度呢?

嵌套for循环对于Python来说尤其糟糕,但是这里可以做一些工作来改进

首先,你在比较中做了两次工作<对于所有对
i,j
,code>user\u-sim\u-df[user\u i][user\u j]与
user\u-sim\u-df[user\u j][user\u i]
具有相同的值。可以从使用已计算的值中获益,而不是在以后的迭代中再次计算它们。除此之外,计算对角线上的值(
user\u sim\u df[user\u i][user\u i]
)是否是应用程序所必需的

这些简单的更改将把执行时间减少一半。够了吗?也许不是。进一步的改进措施:

  • img\u to\u array()
    操作多次应用于每个图像(每次计算与另一个图像的相似性时)。这是一个瓶颈吗?在这种情况下,如果您首先在所有图像上运行循环,并创建一个新文件供numpy稍后读取(例如使用
    numpy.read()
    ),或者只保存从当前使用的Tensorflow输出的预处理文件,性能也会得到提高
  • 如果您使用的是标准Python解释器,那么(通常)更改为PyPy会有所帮助。您还可以尝试调整代码,使其仅包含numpy结构上的操作(例如,调整pandas部分),并以类似的方式使用Numba。使用Numba还可以从并行性中获益。参见一些实用指南