Matlab 用于寻址大型阵列的内存不足算法
我正在尝试处理一个非常大的数据集。我有k=~4200个矩阵(大小不同),它们必须进行组合比较,跳过非唯一和自比较。每个k(k-1)/2比较都会产生一个矩阵,该矩阵必须针对其父级进行索引(即,可以找出它的来源)。实现这一点的便捷方法是(三角形地)用每次比较的结果填充一个k×k单元数组。这些平均为~100x~100个矩阵。使用单精度浮点运算,它的总容量达到400 GB。Matlab 用于寻址大型阵列的内存不足算法,matlab,file-io,memory-management,out-of-memory,Matlab,File Io,Memory Management,Out Of Memory,我正在尝试处理一个非常大的数据集。我有k=~4200个矩阵(大小不同),它们必须进行组合比较,跳过非唯一和自比较。每个k(k-1)/2比较都会产生一个矩阵,该矩阵必须针对其父级进行索引(即,可以找出它的来源)。实现这一点的便捷方法是(三角形地)用每次比较的结果填充一个k×k单元数组。这些平均为~100x~100个矩阵。使用单精度浮点运算,它的总容量达到400 GB。 我需要1)生成一个或多个单元格数组,而无需将整个内容放在内存中;2)以类似方式访问其元素(及其元素)。由于依赖MATLAB的eva
我需要1)生成一个或多个单元格数组,而无需将整个内容放在内存中;2)以类似方式访问其元素(及其元素)。由于依赖MATLAB的
eval()
以及循环中出现的save
和clear
,我的尝试效率低下
for i=1:k
[~,m] = size(data{i});
cur_var = ['H' int2str(i)];
%# if i == 1; save('FileName'); end; %# If using a single MAT file and need to create it.
eval([cur_var ' = cell(1,k-i);']);
for j=i+1:k
[~,n] = size(data{j});
eval([cur_var '{i,j} = zeros(m,n,''single'');']);
eval([cur_var '{i,j} = compare(data{i},data{j});']);
end
save(cur_var,cur_var); %# Add '-append' when using a single MAT file.
clear(cur_var);
end
我做的另一件事是在mod((I+j-1)/2,max(factor(k(k-1)/2))==0时执行拆分。这将结果划分为最大数量的相同大小的块,这似乎是合乎逻辑的。索引稍微复杂一点,但也不太糟糕,因为可以使用线性索引
有人知道/看到更好的方法吗?您可以通过分别分配文件名来摆脱eval
和clear
调用
for i=1:k
[~,m] = size(data{i});
file_name = ['H' int2str(i)];
cur_var = cell(1, k-i);
for j=i+1:k
[~,n] = size(data{j});
cur_var{i,j} = zeros(m, n, 'single');
cur_var{i,j} = compare(data{i}, data{j});
end
save(file_name, cur_var);
end
如果需要保存的变量采用不同的名称,请使用-struct
选项进行保存
str.(file_name);
save(file_name, '-struct', str);
这是一个结合快速运行和使用最小内存的版本
我使用fwrite/fread,这样您仍然可以使用parfor
(这一次,我确保它可以工作:)
在这个问题中,我/我们正在尝试制作一个内存版本/fast/:使用EVAL
创建具有动态生成名称的变量是一种不好的做法,请使用STRUCT
和动态字段引用:不幸的是,save()
不能在parfor
@reve\u etrange:Oops中调用。啊,那么你必须使用例如fwrite。
%# assume data is loaded an k is known
%# find the index pairs for comparisons. This could be done more elegantly, I guess.
%# I'm constructing a lower triangular array, i.e. an array that has ones wherever
%# we want to compare i (row) and j (col). Then I use find to get i and j
[iIdx,jIdx] = find(tril(ones(k,k),-1));
%# create a directory to store the comparisons
mkdir('H_matrix_elements')
savePath = fullfile(pwd,'H_matrix_elements');
%# loop through all comparisons in parallel. This way there may be a bit more overhead from
%# the individual function calls. However, parfor is most efficient if there are
%# a lot of relatively similarly fast iterations.
parfor ct = 1:length(iIdx)
%# make the comparison - do double b/c there shouldn't be a memory issue
currentComparison = compare(data{iIdx(ct)},data{jIdx{ct});
%# create save-name as H_i_j, e.g. H_104_23
saveName = fullfile(savePath,sprintf('H_%i_%i',iIdx(ct),jIdx(ct)));
%# save. Since 'save' is not allowed, use fwrite to write the data to disk
fid = fopen(saveName,'w');
%# for simplicity: save data as vector, add two elements to the beginning
%# to store the size of the array
fwrite(fid,[size(currentComparison)';currentComparison(:)]); % ' #SO formatting
%# close file
fclose(fid)
end
%# to read e.g. comparison H_104_23
fid = fopen(fullfile(savePath,'H_104_23'),'r');
tmp = fread(fid);
fclose(fid);
%# reshape into 2D array.
data = reshape(tmp(3:end),tmp(1),tmp(2));