如何基于numpy向量化实现VLAD特征计算,优化现有循环实现
VLAD计算向量化实现方案
完全可以实现全向量化的VLAD计算,消除所有循环逻辑,实现代码如下:
import numpy as np # 提前获取常量 T, N, F = feats.shape K = kmeans.n_clusters centers = kmeans.cluster_centers_ # (K, F) # 1. 批量预测所有描述符的聚类标签 feats_flat = feats.reshape(-1, F) # (T*N, F) labels_flat = kmeans.predict(feats_flat) # (T*N, ) labels = labels_flat.reshape(T, N) # (T, N) # 2. 生成聚类的one-hot掩码 (T, N, K) mask = np.eye(K)[labels] # 3. 计算每个样本、每个聚类下的所有特征总和 (T, K, F) sum_feats = np.einsum('tnf,tnk->tkf', feats, mask) # 4. 计算每个样本、每个聚类的中心总和:中心 * 聚类内特征数量 (T, K, F) cluster_count = mask.sum(axis=1) # (T, K) sum_centers = cluster_count[..., np.newaxis] * centers[np.newaxis, ...] # 5. 计算残差和,得到VLAD特征张量 vlad = sum_feats - sum_centers # (T, K, F) # 6. 扁平化 + L2归一化 vlad = vlad.reshape(T, -1) # (T, K*F) vlad = vlad / np.linalg.norm(vlad, axis=1, keepdims=True)
逻辑说明
- 所有循环逻辑都替换为广播和矩阵运算,和原始实现的计算结果完全一致
- 没有描述符的聚类位置计算结果自动为0,不需要额外做存在性判断
- 当特征规模较大时,相比原始双重循环实现性能可以提升1~2个数量级
内存优化建议
如果聚类数K非常大导致one-hot掩码占用内存过高,可以替换einsum的计算逻辑,用np.bincount逐维度统计特征和,进一步降低内存占用。
内容的提问来源于stack exchange,提问作者ashnair1
相关产品推荐
相关产品推荐

