首页 > 解决方案 > 在 numpy 中矢量化 VLAD 计算

问题描述

我想知道是否可以对 VLAD 计算的这种实现进行矢量化。

对于上下文:

feats=形状的numpy数组(T, N, F)

kmeans= 使用集群初始化的 scikit-learn 中的 KMeans 对象K

当前方法

k = kmeans.n_clusters # K
centers = kmeans.cluster_centers_ # (K, F)
vlad_feats = []

for feat in feats:
    # feat shape - (N, F) 
    cluster_label = kmeans.predict(feat) #(N,)
    vlad = np.zeros((k, feat.shape[1])) # (K, F)

    # computing the differences for all the clusters (visual words)
    for i in range(k):
        # if there is at least one descriptor in that cluster
        if np.sum(cluster_label == i) > 0:
            # add the differences
            vlad[i] = np.sum(feat[cluster_label == i, :] - centers[i], axis=0)
    vlad = vlad.flatten() # (K*F,)
    # L2 normalization
    vlad = vlad / np.sqrt(np.dot(vlad, vlad))
    vlad_feats.append(vlad)

vlad_feats = np.array(vlad_feats) # (T, K*F)

批量获取 kmeans 预测不是问题,我们可以执行以下操作:

feats2 = feats.reshape(-1, F) # (T*N, F)
labels = kmeans.predict(feats2) # (T*N, )

但我被困在计算集群距离上。

标签: pythonnumpyvectorizationvlad-vector

解决方案


您已经开始采用正确的方法。让我们尝试将所有行一一拉出循环。首先,预测:

cluster_label = kmeans.predict(feats.reshape(-1, F)).reshape(T, N)  # T, N

您实际上并不需要 check np.sum(cluster_label == i) > 0,因为无论如何总和都会变成零。您的目标是将每个和特征K中的每个标签与中心的距离相加。T

您可以使用简单的广播来计算k掩码。cluster_label == i你会希望最后一个维度是K

mask = cluster_label[..., None] == np.arange(k)   # T, N, K

您还可以使用更复杂的广播来计算k差异:feats - centers[i]

delta = feats[..., None, :] - centers # T, N, K, F

您现在可以将差异乘以掩码并N通过求和沿维度减少:

vlad = (delta * mask[..., None]).sum(axis=1).reshape(T, -1)  # T, K * F

从这里开始,标准化应该是微不足道的:

vlad /= np.linalg.norm(vlad, axis=1, keepdims=True)

推荐阅读