如何使用查找有效地替换函数?

时间:2015-11-04 14:12:36

标签: matlab matrix vector

我正在尝试提高对大型数据集进行操作的代码的速度。我需要执行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

4 个答案:

答案 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)

假设ndy的整数倍且位于mmax(x(:))范围内。要获得LookUp索引(即1numel(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