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

jgwigjjp  于 2023-03-13  发布在  Matlab
关注(0)|答案(2)|浏览(227)

我正在尝试提出一个非常快速的算法来计算这个非常有趣的统计数据,它充分利用了强大GPU的功能。理想情况下,我会使用Jacket在Matlab中完成这项工作,但CUDA代码或OpenCL中的其他想法也会非常受欢迎。基本上,我希望众包大量聪明的想法,我可以尝试把它们放在一起。然后我会尝试开源这个结果,这样其他人就可以使用它。
尽管这个依赖系数很强大(它甚至能够检测“一对多”的依赖关系),但除了两个来源外,网上几乎没有关于它的任何信息:SAS统计软件,以及Frank Harrell的优秀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
(also,Hmisc的pdf文档第128页有一些更详细的信息。)
这是一个计算要求非常高的算法--如果您想将其应用于数千行和数千列的数据集,即使使用快速的Fortran实现,您也需要等待很多天才能得到结果--即使是在一台新机器上。我希望使用Nvidia GTX 580级别的卡,或者更好的是,使用Tesla,可以将时间缩短到几个小时。在这种情况下,无论是鉴定基因还是在实验数据中寻找相关性,这种结合都将是一种不可忽视的分析力量。
无论如何,我期待着人们的React,并希望我们可以使一个快速的,基于GPU的算法Hoeffding的D成为现实。
提前感谢你的任何想法--请不要犹豫,给予部分或半生不熟的想法!
更新:Jascha慷慨地提供了Hoeffding的D在Matlab中的工作实现,这实现了我的一个目标。另一个目标是通过使用GPU(最好是使用Jacket)从根本上提高速度。有人看到在GPU上以一种聪明的方式实现这一目标的路径或策略吗?

mccptt67

mccptt671#

下面是一个代码示例,其中包含在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
gc0ot86w

gc0ot86w2#

我本打算只是一个评论,但它太长了。如果你不想接受它作为一个答案或任何东西,不用担心。
首先,值得赞扬的是,你正在考虑如何将此Map到GPU。更多的科学家应该花时间为他们的算法考虑这样的想法。然而,在阅读了描述之后,我并不确信GPU是并行化这种特定方法的理想方式。我这么说的原因是GP-GPU编程往往在“批处理”方面非常有效,即自然地使其自身适合于元素方式的基本操作(线程级)的算法。
除了其他人已经提到的求和/秩计算级别之外,还不清楚沿着这些路线是否有有用的算法划分(这些类型的子功能在GPU上已经很好理解了)。但是如果您缩小范围,开始尝试思考如何使用GPU在列到列的比较级别上加快速度,你能做的并不多,知道特定条目小于给定点的值的位置并不能让你避免在一列或另一列改变时做同样的计算。
简而言之,您必须在顶层执行N(N+1)/2次不同的算法迭代,这是无法避免的。在每个算法中,都有足够的空间将列数组发送到GPU,并在线程级执行比较,以快速计算各种排名统计信息。
更好的方法可能是在多处理器设置中使用MPI,以便将每个高级迭代外包给不同的处理器。如果您没有足够的处理器和/或希望每个处理器在单个高级迭代中利用GPU,则(名称很糟糕)似乎是合适的。只要Hoeffding“协方差”的上三角元素继续存在,你要计算的矩阵,你不断地把任务分配给可用的处理器。
其次,我认为Matlab和Jacket在这里比你想象的更像是一个时间问题。是的,Matlab针对一些线性代数运算进行了优化,但几乎总是比任何“真实的的”编程语言都要慢。代价是你可以通过商业级文档获得许多方便的函数,这有时是有价值的。
我向您建议的另一种方法是在Python编程语言中同时使用PyCUDAmpi4py。使用NumPyCython,Python比Matlab更好更快,甚至在方便的函数和易用性方面也是如此。如果您使用Eclipse IDE的PyDev插件,甚至Matlab终端的用户体验也基本相同。另外,你不必为Jacket支付许可证或任何额外费用。
你必须做一些工作才能让PyCUDA和mpi 4py一起工作,但最终我认为开源性会让你的努力对更多的人更有价值,而且代码可能会更快。
另外,如果你确实坚持使用Matlab,你有没有在单对列的情况下为现有的Fortran代码计时,即数千个条目,但只有两列?如果这相当快,你应该能够用一个mex文件为该Fortran编写一个 Package 器。在这种情况下,简单的Matlab多处理器会话可能就是你所需要的。

相关问题