我寫了一個相當大的類來計算測量不確定性,但它非常緩慢。分析代碼表明,到目前為止,最慢的操作是將計算結果插入到一個大的稀疏矩陣中。大約 97% 的時間都花在該操作上。矩陣保留了所有測量資料的不確定性,我無法在不破壞許多其他代碼的情況下更改資料結構。所以我唯一的選擇是優化資料插入步驟。這在我的基準測驗中完成了大約 5700 次,并且每次資料量都會增加。
第一個解決方案,非常慢:
% this automatically sums up duplicate yInd entries
[zInd_grid, yInd_grid] = ndgrid(1:numel(z), yInd(:));
Uzw = sparse(zInd_grid(:), yInd_grid(:), Uzy(:), numel(z), numel(obj.w));
% this automatically sums up duplicate yInd entries
dz_dw = sparse(zInd_grid(:), yInd_grid(:), dz_dy(:), numel(z), numel(obj.w));
obj.w = [obj.w; z(:)]; % insert new measurement results into the column vector obj.w
obj.Uww = [obj.Uww, transpose(Uzw); Uzw, Uzz]; % insert new uncertainties of the measurement results
obj.dw_dw = [obj.dw_dw, transpose(dz_dw); dz_dw, dz_dz]; % insert "dependencies" of new measurements on old results
obj.Uww = [obj.Uww, transpose(Uzw); Uzw, Uzz];到目前為止,這條線路是最慢的。也許它很慢,因為 Matlab 需要為所有內容分配一個新的、更大的緩沖區obj.Uww并將其復制過來。因此,我將代碼更改為以下內容:
% Preallocation in the class constructor
obj.w = spalloc(nnz_w, 1, nnz_w);
obj.Uww = spalloc(nnz_w, nnz_w, nnz_Uww);
obj.dw_dw = spalloc(nnz_w, nnz_w, nnz_dw_dw);
obj.num_w = 0; % to manually keep track of the "real" size of obj.w, obj.Uww and obj.dw_dw
類建構式使用三個屬性的大小呼叫w,Uww并且dw_dw在計算結束時將具有(nzz_w大約為 10 萬,大約為nzz_Uww900 萬,nzz_dw_dw大約為 160 萬)。因此,不需要新的記憶體分配。這是現在的插入步驟:
% this automatically sums up duplicate yInd entries
[zInd_grid, yInd_grid] = ndgrid(1:numel(z), yInd(:));
Uzw = sparse(zInd_grid(:), yInd_grid(:), Uzy(:), numel(z), obj.num_w);
% this automatically sums up duplicate yInd entries
dz_dw = sparse(zInd_grid(:), yInd_grid(:), dz_dy(:), numel(z), obj.num_w);
wInd = 1:obj.num_w;
obj.w(zInd, 1) = z(:); % insert new measurement results
obj.num_w = zInd(end); % new "real" size of w, Uww and dw_dw
obj.Uww(zInd, wInd) = Uzw; % about 51% of all computation time
obj.Uww(wInd, zInd) = transpose(Uzw); % about 15% of all computation time
obj.Uww(zInd, zInd) = Uzz; % about 14.4% of all computation time
obj.dw_dw(zInd, wInd) = dz_dw; % about 13% of all computation time
obj.dw_dw(wInd, zInd) = transpose(dz_dw); % about 3.5% of all computation time
obj.dw_dw(zInd, zInd) = dz_dz; % less than 3.5% of all computation time
盡管如此,這些行占所有計算時間的 97%,并且沒有速度提升。因此我嘗試了版本三:
obj.w = [obj.w; z(:)];
[zInd_zy, yInd_zy] = ndgrid(zInd, yInd(:));
[zzInd_i, zzInd_j] = ndgrid(zInd, zInd);
[Uww_i, Uww_j, Uww_v] = find(obj.Uww); % 14% of all computation time
Uww_new = sparse( ... % this statement takes 66% of all computation time
[Uww_i; zInd_zy(:); yInd_zy(:); zzInd_i(:)], ...
[Uww_j; yInd_zy(:); zInd_zy(:); zzInd_j(:)], ...
[Uww_v; Uzy(:); Uzy(:); Uzz(:)], ...
numel(obj.w), numel(obj.w));
[dw_dw_i, dw_dw_j, dw_dw_v] = find(obj.dw_dw);
dw_dw_new = sparse( ... % 14% of all computation time
[dw_dw_i; zInd_zy(:); yInd_zy(:); zzInd_i(:)], ...
[dw_dw_j; yInd_zy(:); zInd_zy(:); zzInd_j(:)], ...
[dw_dw_v; dz_dy(:); dz_dy(:); dz_dz(:)], ...
numel(obj.w), numel(obj.w));
obj.Uww = Uww_new;
obj.dw_dw = dw_dw_new;
這比其他兩個版本還要慢。為什么插入一個已經預分配的陣列這么慢?我怎樣才能加快速度?
(所有矩陣都是對稱的,但我還沒有嘗試利用它。)
uj5u.com熱心網友回復:
我不了解您的更新模式的細節,但請記住,Matlab 在內部以壓縮稀疏列格式存盤稀疏矩陣。因此,逐列添加條目比其他順序要快得多。例如,在我的舊版 Matlab (R2006a) 上,這個:
n=10000;
nz=400000;
v=floor(n*rand(nz,3)) 1;
fprintf('Random\n');
A=sparse(n, n);
tic
for k=1:nz
A(v(k,1), v(k,2))=v(k,3);
end
toc
fprintf('Row-wise\n');
v=sortrows(v);
A=sparse(n, n);
tic
for k=1:nz
A(v(k,1), v(k,2))=v(k,3);
end
toc
fprintf('Column-wise\n');
v=sortrows(v, [2 1]);
A=sparse(n, n);
tic
for k=1:nz
A(v(k,1), v(k,2))=v(k,3);
end
toc
給出了這個:
>> sparsetest
Random
Elapsed time is 19.276089 seconds.
Row-wise
Elapsed time is 20.714324 seconds.
Column-wise
Elapsed time is 1.498150 seconds.
可能最好的是,如果您能以某種方式以適合于spconvertor的形式收集非零值sparse,然后在最后制作整個稀疏矩陣,但我認為您可能無法做到這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/366700.html
