我正在尝试提高对大型数据集进行操作的代码的速度。我需要执行out = sinc(x)
函数,其中x
是 2048 -by- 37499 双精度矩阵。这是非常昂贵的,并且是我的程序的瓶颈(即使在GPU上计算)。
我正在寻找能够提高此操作速度的任何解决方案。
我希望这可以通过预先计算向量LookUp = sinc(y)
来实现,其中y
是向量y = min(min(x)):dy:max(max(x))
,即跨越整个预期x
元素范围的向量。 / p>
如何从此sinc(x)
向量中有效生成LookUp
的近似值?
我需要避免生成三维数组,因为这会占用比我可用的内存更多的内存。
以下是interp1解决方案的测试:
a = -15;
b = 15;
rands = (b-a).*rand(1024,37499) + a;
sincx = -15:0.000005:15;
sincy = sinc(sincx);
tic
res1 = interp1(sincx,sincy,rands);
toc
tic
res2 = sinc(rands);
toc'
sincx = gpuArray(sincx);
sincy = gpuArray(sincy);
r = gpuArray(rands);
tic
r = interp1(sincx,sincy,r);
toc
r = gpuArray(rands);
tic
r = sinc(r);
toc
经过的时间是0.426091秒 经过的时间是0.472551秒 经过时间为0.004311秒 经过的时间是0.130904秒。
分别对应CPU interp1,CPU sinc,GPU interp1,GPU sinc
答案 0 :(得分:3)
不确定我完全理解你的问题。
但是一旦你有LookUp = sinc(y)
,就可以使用Matlab函数interp1
out = interp1(y,LookUp,x)
其中x可以是任何大小的矩阵
答案 1 :(得分:3)
我得出的结论是,您的代码无法显着改进。最快的查找表基于简单的索引。对于性能测试,我们只需根据随机数据执行测试:
%test data:
x=rand(2048,37499);
%relevant code:
out = sinc(x);
现在基于整数索引的查找:
a=min(x(:));
b=max(x(:));
n=1000;
x2=round((x-a)/(b-a)*(n-1)+1);
lookup=sinc(1:n);
out2=lookup(x2);
无论查找表或输入数据的大小如何,两个代码块中的最后几行大致相同。 sinc
评估的速度与索引操作一样快,我只能假设它已经使用查找表实现了。
答案 2 :(得分:2)
m = min(x(:));
y = m:dy:max(x(:));
LookUp = sinc(y);
现在sinc(n)
应该等于
LookUp((n-m)/dy + 1)
假设n
是dy
的整数倍且位于m
和max(x(:))
范围内。要获得LookUp
索引(即1
和numel(y)
之间的整数,我们首先将n
移至最小m
,然后将其缩放dy
1}}并最后添加1
,因为MATLAB索引来自1
而不是0
。
我不知道这对你的效率有什么影响,但试一试。
此外,您可以将其放入匿名函数中以帮助提高可读性:
sinc_lookup = @(n)(LookUp((n-m)/dy + 1))
现在你可以打电话了
sinc_lookup(n)
答案 3 :(得分:2)
我找到了一种更快的方式(如果您的PC上有NVIDIA GPU),但是NaN
会返回x=0
,但如果出于任何原因,您可以处理NaN
1}}或者你知道它永远不会为零:
如果您定义r = gpuArray(rands);
并在GPU中自己评估sinc
函数:
tic
r=rdivide(sin(pi*r),pi*r);
toc
这通常给我的速度是GPU中interp1
版本的3.2倍,并且更准确(使用上面的代码测试,使用不同的随机数据迭代100次,两种方法类似std)
这是有效的,因为sin
和元素分割rdivide
也是GPU实现的(虽然由于某种原因sinc
不是)。请参阅:http://uk.mathworks.com/help/distcomp/run-built-in-functions-on-a-gpu.html