【问题标题】:How to calculate user-similarity matrix in a more efficient manner?如何以更有效的方式计算用户相似度矩阵?
【发布时间】:2020-07-02 05:02:31
【问题描述】:

我有一组 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 张图片)。

那么,我该如何重写最后一部分以使代码运行得更快?

【问题讨论】:

    标签: python performance loops optimization time


    【解决方案1】:

    嵌套的 for 循环对 Python 来说尤其不利,但这里可以做一些改进。

    首先,您在比较中做了两次工作。对于所有对 i, juser_sim_df[user_i][user_j]user_sim_df[user_j][user_i] 具有相同的值。可以受益于使用已经计算的值,而不是在以后的迭代中再次计算它们。除此之外,计算对角线上的值 (user_sim_df[user_i][user_i]) 是否对您的应用程序是必要的?

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-15
      • 2018-08-01
      • 1970-01-01
      • 2019-04-22
      • 2017-06-17
      • 1970-01-01
      • 2017-11-07
      • 2016-06-15
      相关资源
      最近更新 更多