使用 Matlab 从 VLFeat 中的 SIFT 描述符中提取 VLAD 时的内存限制

Memory Limitation when Extracting VLAD from SIFT Descriptors in VLFeat with Matlab

我最近询问如何使用 Matlab 从 VLFeat 中的 SIFT 描述符中提取 VLAD。

但是,我 运行 遇到内存限制。我有 64GB 内存和 64GB 交换空间。

 all_descr = single([sift_descr{:}]);

... 产生内存错误:

Requested 128x258438583 (123.2GB) array exceeds maximum array size preference. Creation of arrays greater than this limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference panel for more information.

当我们有一个非常大的训练数据集时,提取 VLAD 的正确方法是什么?例如,我可以在 运行 vl_kmeans 之前对 SIFT 描述符进行子集化,如下所示:

all_descr = single([sift_descr{1:100000}]);

这在内存中有效,但它将如何影响我的 VLAD 功能?谢谢你。

这里的主要问题不是如何为这样的矩阵提取VLAD:你通过遍历所有图像并逐个计算VLAD来计算每个图像的VLAD向量,即内存问题那里没有出现。

当您尝试连接所有图像的 SIFT 描述符以使用最近邻搜索将它们聚类为视觉词时,您 运行 内存不足:

all_descr = single([sift_descr{:}]);
centroids = vl_kmeans(all_descr, 64);

我能想到的最简单的方法是切换到 MATLAB 自己的 kmeans 函数,它包含在 Statistics and Machine Learning 工具箱中。 它支持 Tall Arrays,即 MATLAB 的数据类型,用于不适合内存的数组。

为此,您可以使用 csvwrite:

将每个图像的 SIFT 描述符保存到 CSV 文件中
for k = 1:size(filelist, 1)
    I = imread([repo filelist(k).name]) ;
    I = single(rgb2gray(I)) ;
    [f,d] = vl_sift(I) ;
    csvwrite(sprintf('sift/im_%d.csv', k), single(d.'));
end

然后,您可以使用 datastore function and converting it to tall 将描述符加载为 Tall 数组。由于结果将是 table,您可以使用 table2array 将其转换为 tall 数组。

ds = datastore('sift/*.csv');
all_descriptors = table2array(tall(ds));

最后,您可以调用 kmeans 函数,并获取质心

[~, centroids] = kmeans(all_descriptors, 64);

现在您可以照常计算 VLAD 向量了。