Performance 在matlab中高效地计算双和?
我正在寻找一种优化的方法来编程这个求和比率。作为输入,我有两个向量Performance 在matlab中高效地计算双和?,performance,matlab,Performance,Matlab,我正在寻找一种优化的方法来编程这个求和比率。作为输入,我有两个向量v_mn和x_mn,每个向量都有(M*N)x1元素 比率的形式如下: 向量x_mn是0-1向量,因此当x_mn=1时,比率为r,当x_mn=0时,比率为0 向量v_mn是一个包含实数的向量 我像这样做分母,但它需要很多次 function r_ij = denominator(v_mn, M, N, i, j) %here x_ij=1, to get r_ij. S = []; for m = 1:M for n = 1:
v_mn
和x_mn
,每个向量都有(M*N)x1
元素
比率的形式如下:
向量x_mn
是0-1
向量,因此当x_mn=1
时,比率为r
,当x_mn=0
时,比率为0
向量v_mn
是一个包含实数的向量
我像这样做分母,但它需要很多次
function r_ij = denominator(v_mn, M, N, i, j)
%here x_ij=1, to get r_ij.
S = [];
for m = 1:M
for n = 1:N
if (m ~= i)
if (n ~= j)
S = [S v_mn(i, n)];
else
S = [S 0];
end
else
S = [S 0];
end
end
end
r_ij = 1+S;
end
你能给出一个在matlab中实现的好方法吗。你可以忽略比率,给我分母,它更复杂
编辑:很抱歉我没有写得很好。
i
和j
分别是介于1..M
和1..N
之间的一些数字。如您所见,比率r
是许多值(M*N
值)。所以我只计算了I
和j
的值。更准确地说,我假设x_ij=1
。此外,我将向量v\u mn
转换为矩阵,这就是我使用双索引的原因。首先,您需要预先计算s矩阵。它会改变每个循环的大小,所以
S = zeros(m*n, 1)
在您的功能开始时。这也将允许您删除else条件语句,即它们将简化为:
if (m ~= i)
if (n ~= j)
S(m*M + n) = v_mn(i, n);
否则,因为你必须访问每一个元素,我担心它可能无法更快
如果您迫切需要更高的速度,您可以考虑执行一些mex
编码,这是c/c++中的代码,但在matlab中运行
您可能需要修改上述内容,以确保它符合您的要求,而不是首先跳入双循环的矢量化。在该代码中,没有数据求和,而是在每次迭代时调整向量
S
的大小。同样,签名可以包括矩阵V和X,这样乘法就如公式中所示发生(而不仅仅依赖于X的值为零或一,让我们将该矩阵传递进来)
该函数看起来更像以下内容(我已将I,j输入替换为m,n,更像方程式):
注意第一个
if
如何位于内部for循环之外,因为它不依赖于j
。试试上面的方法,看看会发生什么 您可以从Matlab中进行矢量化,以加快计算速度。每次您使用诸如“^”或“*”之类的运算或任何矩阵运算时,Matlab都会并行执行这些运算,这比迭代每个项快得多
在这种情况下,看看你在矩阵方面做了什么。首先,在您的循环中,您只处理$V_{nm}$的第m行,我们可以将其本身用作向量
如果你仔细看一下你的公式,你会发现,如果你把这个行向量写成一个列向量,然后用标准的矩阵乘法从左边把矩阵$X_{nm}$乘以它,你几乎可以达到目的。结果向量包含所有n的和。要得到最终结果,只需将此向量求和
function result = denominator_vectorized(V,X,m,n)
% get the part of V with the first index m
Vm = V(m,:)';
% remove the parts of X you don't want to iterate over. Note that, since I
% am inside the function, I am only editing the value of X within the scope
% of this function.
X(m,:) = 0;
X(:,n) = 0;
%do the matrix multiplication and the summation at once
result = 1-sum(X*Vm);
为了向您展示这如何优化您的操作,我将把它与另一位评论者提出的代码进行比较:
function result = denominator(V,X,m,n)
% use the size of V to determine M and N
[M,N] = size(V);
% initialize the summed value to one (to account for one at the end)
result = 1;
% outer loop
for i=1:M
% ignore the case where m==i
if i~=m
for j=1:N
% ignore the case where n==j
if j~=n
result = result + V(m,j)*X(i,j);
end
end
end
end
测试:
V=rand(10000,10000);
X=rand(10000,10000);
disp('looped version')
tic
denominator(V,X,1,1)
toc
disp('matrix operation')
tic
denominator_vectorized(V,X,1,1)
toc
结果是:
looped version
ans =
2.5197e+07
Elapsed time is 4.648021 seconds.
matrix operation
ans =
2.5197e+07
Elapsed time is 0.563072 seconds.
这几乎是循环迭代速度的十倍。因此,请始终注意代码中可能存在的矩阵操作。如果您安装了并行计算工具箱并安装了支持CUDA的图形卡,那么Matlab甚至可以在图形卡上执行这些操作,而无需您付出任何进一步的努力
编辑:最后一点并非完全正确。您仍然需要采取一些步骤在CUDA硬件上进行操作,但这些步骤并不多。请参阅Matlab文档。如果重新塑造数据,那么求和就是重复的矩阵/向量乘法 下面是单个
m
和n
的实现,以及一个简单的速度/平等性测试:
clc
%# some arbitrary test parameters
M = 250;
N = 1000;
v = rand(M,N); %# (you call it v_mn)
x = rand(M,N); %# (you call it x_mn)
m0 = randi(M,1); %# m of interest
n0 = randi(N,1); %# n of interest
%# "Naive" version
tic
S1 = 0;
for mm = 1:M %# (you call this m')
if mm == m0, continue; end
for nn = 1:N %# (you call this n')
if nn == n0, continue; end
S1 = S1 + v(m0,nn) * x(mm,nn);
end
end
r1 = v(m0,n0)*x(m0,n0) / (1+S1);
toc
%# MATLAB version: use matrix multiplication!
tic
ninds = [1:m0-1 m0+1:M];
minds = [1:n0-1 n0+1:N];
S2 = sum( x(minds, ninds) * v(m0, ninds).' );
r2 = v(m0,n0)*x(m0,n0) / (1+S2);
toc
%# Test if values are equal
abs(r1-r2) < 1e-12
因此,加速比约为133倍
现在这是针对单个值m
和n
。要对m
和n
的所有值执行此操作,可以在其周围使用(优化的)双循环:
r = zeros(M,N);
for m0 = 1:M
xx = x([1:m0-1 m0+1:M], :);
vv = v(m0,:).';
for n0 = 1:N
ninds = [1:n0-1 n0+1:N];
denom = 1 + sum( xx(:,ninds) * vv(ninds) );
r(m0,n0) = v(m0,n0)*x(m0,n0)/denom;
end
end
对于M=250,N=1000
(R2010a),在我的电脑上大约15秒钟即可完成
编辑:实际上,经过一点思考,我能够将其简化为:
denom = zeros(M,N);
for mm = 1:M
xx = x([1:mm-1 mm+1:M],:);
denom(mm,:) = sum( xx*v(mm,:).' ) - sum( bsxfun(@times, xx, v(mm,:)) );
end
denom = denom + 1;
r_mn = x.*v./denom;
对于
N=250
和M=1000
:)您说v_mn
是M*N
x1
,但您将其索引为v_mn(i,N)
。它真的是M*N
x1
,还是M
xN
?另外,您的函数中的i
和j
是什么?在哪里(或如何)初始化i
和j
?函数中的返回值是r
-设置在哪里?非常抱歉。我写得不好。我相应地修改了问题@路易斯门多和杰夫·海斯。谢谢。看我更新的答案。这个答案更好@x、 你应该把这个答案标对。
r = zeros(M,N);
for m0 = 1:M
xx = x([1:m0-1 m0+1:M], :);
vv = v(m0,:).';
for n0 = 1:N
ninds = [1:n0-1 n0+1:N];
denom = 1 + sum( xx(:,ninds) * vv(ninds) );
r(m0,n0) = v(m0,n0)*x(m0,n0)/denom;
end
end
denom = zeros(M,N);
for mm = 1:M
xx = x([1:mm-1 mm+1:M],:);
denom(mm,:) = sum( xx*v(mm,:).' ) - sum( bsxfun(@times, xx, v(mm,:)) );
end
denom = denom + 1;
r_mn = x.*v./denom;