关于Hoeffding的“D”(依赖)系数的GPU实现的想法?

时间:2012-02-14 01:24:53

标签: matlab statistics cuda gpu correlation

我正在尝试提出一种非常快速的算法来计算这个非常有趣的统计数据,它充分利用了强大GPU的功能。理想情况下,我将使用Jacket在Matlab中执行此操作,但CUDA代码或OpenCL中的其他想法也将非常受欢迎。基本上,我想收集大量巧妙的想法,我可以尝试将它们放在一起,然后我会尝试开源结果,以便其他人可以使用它。

尽管有这种依赖系数的强大功能(它甚至能够检测出“一对多”的依赖关系),但除了两个来源:SAS统计软件和优秀的R包外,几乎没有关于它的在线信息。弗兰克哈瑞尔的Hmisc。您可以在此处阅读算法说明:

http://support.sas.com/documentation/cdl/en/procstat/63104/HTML/default/viewer.htm#procstat_corr_sect016.htm

这里是Harrell在Fortran中的代码(如果你已经理解了计算,这个代码非常容易理解):

http://hmisc.sourcearchive.com/documentation/3.7-0/hoeffd_8f-source.html

(另外,Hmisc的pdf文档的第128页有更多细节。)

这是一个计算要求很高的算法 - 如果你想将它应用于数千行和几千列的数据集,即使使用快速的Fortran实现,你也会等待很多天才得到结果 - - 甚至在新机器上。我希望使用Nvidia GTX 580级卡,或者更好的是特斯拉,可以将其降低到几个小时。在这种情况下,无论是识别基因还是在实验数据中找到相关性,这种组合都是一个不可忽视的分析力量。

无论如何,我期待着各国人民的回应,并希望我们能够为Hoeffding的D制作一个基于GPU的快速算法。

提前感谢任何想法 - 请不要犹豫,提出部分或半生不熟的想法!

更新:所以,Jascha慷慨地在Matlab中提供了Hoeffding D的工作实现,这实现了我的一个目标。另一种是通过使用GPU从根本上提高速度,最好使用Jacket。是否有人在GPU上以聪明的方式看到了这样做的路径或策略?

2 个答案:

答案 0 :(得分:2)

我打算这只是一个评论,但它太长了。不用担心,如果你不想接受它作为答案或任何东西。

首先,您正在考虑如何将其映射到GPU,这是值得称道的。更多的科学家应该花时间为他们的算法考虑这样的想法。但是,在阅读了描述之后,我不相信GPU是并行化这种特定方法的理想方式。我之所以这么说是因为GP-GPU编程在“批处理”方面往往非常有效,即自然适用于基于元素的基本操作(线程级别)的算法。

除了在其他人已经提到过的总和/等级计算水平之外,还不清楚这个算法是否会对这些算法进行有用的划分(这些子函数在GPU上已经很好理解了) 。但是如果你缩小并开始尝试考虑如何使用GPU来加快列到列比较的速度,那么你无能为力。知道特定条目小于给定点的值的位置将不会让您在更改一个或另一个列时避免执行相同的计算。

简而言之,您将不得不在顶层执行N(N+1)/2次算法的不同迭代,并且无法避免这种情况。在每个算法中,都有足够的空间将列数组发送到GPU,并在线程级别进行比较,以快速计算各种排名统计数据。

更好的方法可能是在多处理器设置中使用MPI,以便将每个高级迭代分配到不同的处理器。如果您没有足够的处理器和/或您希望每个处理器在单个高级迭代中使用GPU,那么master-slave并行模型(非常命名)似乎是合适的。只要你想要计算的Hoeffding“协方差”矩阵的上三角形元素仍然存在,你就会继续将任务输出到可用的处理器。

其次,我认为Matlab和Jacket在这里比你想象的更具时间性问题。是的,Matlab针对一些线性代数运算进行了优化,但几乎总是比任何“真正的”编程语言慢得多。权衡的是,您可以使用商业级文档获得许多便利功能,这有时很有价值。

我建议您使用的另一种方法是在Python编程语言中使用PyCUDAmpi4py。使用NumPyCython,Python比Matlab更好,更快,即使在便利功能和易用性方面也是如此。如果您使用PyDev IDE的Eclipse插件,即使Matlab终端的用户体验基本相同。此外,您无需为Jacket支付许可证或任何额外费用。

你必须做一些工作才能让PyCUDA和mpi4py一起工作,但最后我认为开源会让你的努力对更多的人来说更有价值,代码可能会快得多。

另外,如果您确实坚持使用Matlab,您是否已经在单对列的情况下对现有的Fortran代码进行了定时,对于数千个条目,但只有两列?如果速度相当快,您应该能够使用mex文件为该Fortran编写包装器。在这种情况下,Matlab的简单多处理器会话可能就是您所需要的。

答案 1 :(得分:1)

下面是一个代码示例,在MATLAB中简单实现了Hoeffding的D依赖度量。这不是GPU化,但可能对想要计算此统计数据并且不使用Fortran的人有用,或者作为将其放在GPU上的起点。 (扩展标题说明了几种联合分布的Hoeffding D值。)

function [ D ] = hoeffdingsD( x, y )
%Compute's Hoeffding's D measure of dependence between x and y
%   inputs x and y are both N x 1 arrays
%   output D is a scalar
%     The formula for Hoeffding's D is taken from
%     http://support.sas.com/documentation/cdl/en/procstat/63104/HTML/default/viewer.htm#procstat_corr_sect016.htm
% Below is demonstration code for several types of dependencies.
%
% % this case should be 0 - there are no dependencies
% x = randn(1000,1);
% y = randn(1000,1);
% D = hoeffdingsD( x, y );
% desc = 'x = N( 0, 1 ), y and x independent';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% % the rest of these cases have dependencies of different types
% x = randn(1000,1);
% y = x;
% D = hoeffdingsD( x, y );
% desc = 'x = N( 0, 1 ), y = x';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% x = randn(1000,1);
% y = cos(10*x);
% D = hoeffdingsD( x, y );
% desc = 'x = N( 0, 1 ), y = cos(10x)';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% x = randn(1000,1);
% y = x.^2;
% D = hoeffdingsD( x, y );
% desc = 'x = N( 0, 1 ), y = x^2';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% x = randn(1000,1);
% y = x.^2 + randn(1000,1);
% D = hoeffdingsD( x, y );
% desc = 'x = N( 0, 1 ), y = x^2 + N( 0, 1 )';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% x = rand(1000,1);
% y = rand(1000,1);
% z = sign(randn(1000,1));
% x = z.*x; y = z.*y;
% D = hoeffdingsD( x, y );
% desc = 'x = z U( [0, 1) ), y = z U( [0, 1) ), z = U( {-1,1} )';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );
% 
% x = rand(1000,1);
% y = rand(1000,1);
% z = sign(randn(1000,1));
% x = z.*x; y = -z.*y;
% D = hoeffdingsD( x, y );
% desc = 'x = z U( [0, 1) ), y = -z U( [0, 1) ), z = U( {-1,1} )';
% desc = sprintf( '%s, Hoeffding''s D = %f', desc, D );
% fprintf( '%s\n', desc );
% figure; plot(x,y,'.'); title( desc );

N = size(x,1);

R = tiedrank( x );
S = tiedrank( y );

Q = zeros(N,1);
parfor i = 1:N
    Q(i) = 1 + sum( R < R(i) & S < S(i) );
    % and deal with cases where one or both values are ties, which contribute less
    Q(i) = Q(i) + 1/4 * (sum( R == R(i) & S == S(i) ) - 1); % both indices tie.  -1 because we know point i matches
    Q(i) = Q(i) + 1/2 * sum( R == R(i) & S < S(i) ); % one index ties.
    Q(i) = Q(i) + 1/2 * sum( R < R(i) & S == S(i) ); % one index ties.
end

D1 = sum( (Q-1).*(Q-2) );
D2 = sum( (R-1).*(R-2).*(S-1).*(S-2) );
D3 = sum( (R-2).*(S-2).*(Q-1) );

D = 30*((N-2)*(N-3)*D1 + D2 - 2*(N-2)*D3) / (N*(N-1)*(N-2)*(N-3)*(N-4));

end