Performance Matlab:用较少的内存和计算量构造非常大的稀疏带矩阵

Performance Matlab:用较少的内存和计算量构造非常大的稀疏带矩阵,performance,matlab,memory,vectorization,sparse-matrix,Performance,Matlab,Memory,Vectorization,Sparse Matrix,我需要构造一个大的NxN稀疏带矩阵a,其中N=570*720=410400(#个图像像素) 数学上,A(m,n)=C1*exp(-m-n^2);m=1:N,N=1:N 基本上,它是一个高斯函数,在每一行计算,行索引是平均值和一些任意但很小的标准偏差 对于N=100,它看起来像: 不幸的是,由于不必要的计算,它在N=410400时运行非常慢 1) 用于循环 A=稀疏(N,N) 对于i=1:N A(i,:)=normpdf(1:N,i,30) 结束 这是浪费和缓慢的,因为调用了N次 2) 使用N处的

我需要构造一个大的NxN稀疏带矩阵a,其中N=570*720=410400(#个图像像素)

数学上,A(m,n)=C1*exp(-m-n^2);m=1:N,N=1:N

基本上,它是一个高斯函数,在每一行计算,行索引是平均值和一些任意但很小的标准偏差

对于N=100,它看起来像:

不幸的是,由于不必要的计算,它在N=410400时运行非常慢

1) 用于循环

A=稀疏(N,N)
对于i=1:N
A(i,:)=normpdf(1:N,i,30)
结束

这是浪费和缓慢的,因为调用了N次

2) 使用N处的平均值计算1:2N的normpdf一次,然后根据索引使用适当的平均值循环移动A中的行。matlab中的CirchShift无法按列移动矩阵 不同大小的班次。再次需要调用circshift N次-->浪费

3) 可能使用mvnpdf,但它需要输入向量,使用网格网格生成这些向量将
消耗大量内存

4) 将bsxfun与用户定义的高斯函数(具有固定SD)一起使用,因为bsxfun不接受>3个参数,因此接受两个参数

关于如何有效地实现这一点,有什么想法吗


谢谢

首先,你真的不需要稀疏矩阵,除非你至少有50%的零,但是你的矩阵是满的

以一个普通的pdf文件为例

您可以通过调用
bsxfun()
轻松实现它:

一个简单的例子是
mean=1
sigma=30
,它将阐明:

pdf = @(x) 1/(sqrt(2*pi)*30)*exp(-0.5*((x-1)/30).^2);
pdf(1)
ans =
        0.0132980760133811

normpdf(1, 1, 30)
ans =
        0.0132980760133811

我可以建议另一种方法吗

使用一个
2*N-by-1
向量,可以通过对索引的简单转换来索引,有什么反对的?像这样:

% Oli's solution, and your request: NxN matrix
N   = 100;
s   = 30;    
pdf = @(x) 1/(sqrt(2*pi)*s)*exp(-0.5*(bsxfun(@minus,x(:),1:N)/s).^2);
A   = pdf(1:N);

% My solution: 2*N x 1 vector
B = exp(-0.5*((-N:N)/s).^2) / s/sqrt(2*pi);
诀窍是找到一个好的通用索引规则。以下是如何做到这一点:

% Indexing goes like this:
fromB = @(ii,jj) B(N+1 + bsxfun(@minus, jj(:), ii)).';

ii = 30; 
jj = 23;

from_A = A(ii,jj)
from_B = fromB(ii,jj)

ii = 1:2;    
jj = 4:6;      

from_A = A(ii, jj)
from_B = fromB(ii,jj)
结果:

from_A =
   0.012940955690785
from_B =
   0.012940955690785

from_A =
   0.013231751582567   0.013180394696194   0.013114657203398
   0.013268557543798   0.013231751582567   0.013180394696194
from_B =
   0.013231751582567   0.013180394696194   0.013114657203398
   0.013268557543798   0.013231751582567   0.013180394696194

我相信你会明白如何使用冒号索引和使用
end
关键字:)

为什么需要矩阵?i、 例如,为什么不在需要的地方计算A(i,j)的值呢?@Rody矩阵是一个更大的优化方程的一部分。显式地计算A(i,j)N次,特别是当N非常大时,你不认为是浪费吗?我正在尝试尽可能地矢量化和减少循环计算。您不需要重新计算值,只需计算对称
2*Nx1
向量的
normpdf
,并在需要某些值时对该向量进行智能索引。似乎比只有第一行和最后一行的副本的NxN矩阵要少浪费很多…没错!我需要构造这样一个矩阵,但我想对索引进行矢量化……我正在调查bsxfun目前是否可以用于此目的。即使是50%的零也不值得创建稀疏矩阵。通过使这样的矩阵稀疏,你不会得到任何好处。@Oleg&wood不,我的矩阵非常稀疏,这显然取决于标准偏差。考虑:N=720*570;A=稀疏(N,N);A(1,:)=normpdf(1:N,1,50);长度(find(A(1,:)=1924;大小(A(1,:),2)=410400bsxfun()很好的解决方案。目前正在学习bsxfun,但它将在形成中间向量/矩阵时运行内存。你的循环示例与你之前的注释不一致。如果你创建的每一行
1:N
都是从法线绘制的,那么它就不能稀疏。我的方法只是复制你的循环示例,使用更少的内存。Gaussian和normal是同义词。不管怎样,我开始理解你在做什么,问题是
find(normpdf(1:N,396,50)
是792,不管有多大
N
你只需要从normal计算792个值一次,然后用稀疏索引进行传播。没有bsxfun()需要。但是,eps上有多少值取决于sigma。
查找(normpdf(1:N,396,50)
显示了如何计算更小的B。但这肯定是要走的路,而不是
bsxfun()
@OlegKomarov:你不应该在那里使用
eps
,而应该使用
realmin
。例如,你给出的例子是
ans=2272
。比OP的
N
小,但不是那么小:)@Rody就是这样做的。谢谢:)刚刚发现bsxfun…非常方便@OlegKomarov:(
realmin==eps(0)
,它是最小的
double
。命令
eps
本身意味着
eps(1)
)@snowmonkey:很乐意帮忙:)
from_A =
   0.012940955690785
from_B =
   0.012940955690785

from_A =
   0.013231751582567   0.013180394696194   0.013114657203398
   0.013268557543798   0.013231751582567   0.013180394696194
from_B =
   0.013231751582567   0.013180394696194   0.013114657203398
   0.013268557543798   0.013231751582567   0.013180394696194