【问题标题】:Matrix Multiplication/Addition Very Slow on GPU in Certain Cases在某些情况下,GPU 上的矩阵乘法/加法非常慢
【发布时间】:2015-10-15 07:32:29
【问题描述】:

我目前正试图让我的代码在我的 GPU 而不是 CPU 上运行 - 嗯,它正在运行,但不是很好。让我给出代码的相关部分:

u = zeros(n*L,1  ,'gpuArray'); ubar = zeros(n*L,1  ,'gpuArray');
y = zeros(n*L*d,1,'gpuArray'); ybar = zeros(n*L*d,1,'gpuArray');
v = zeros(n*L*d,1,'gpuArray');
w = zeros(n,1    ,'gpuArray');
z = zeros(n*L*d,1,'gpuArray');

...

    v_arg = v + sigma * (D * ubar - T_t * ybar);   (1)
    w_arg = w + sigma * Q * ubar;
    z_arg = z + sigma * ybar;

    v_new = back.dual.v(v_arg,w_arg,z_arg);
    w_new = back.dual.w(v_arg,w_arg,z_arg);
    z_new = back.dual.z(v_arg,w_arg,z_arg);

    u_arg = u - tau * (D_t * v_new + Q_t * w_new);   (2)
    y_arg = y - tau * (z_new - T * v_new);

    u_new = back.prim.u(u_arg,y_arg);
    y_new = back.prim.y(u_arg,y_arg);

    ubar_new = u_new + theta*(u_new - u);
    ybar_new = y_new + theta*(y_new - y);

...

% The dimensions of the matrices are as follows:
% D is (n*L*d,n*L); T is (n*L*d,n*L*d); Q is (n,n*L).

% Finally, "_t" denotes the transpose of a matrix. I found that it is a lot
% faster to define a new matrix that is the transpose, instead of doing the
% transpose operation each time.

两个标记的方程 - (1) 和 (2) - 是瓶颈。请参阅下图了解我的一次跑步的时间。 .

最后,矩阵是稀疏矩阵 - 我使用的是 Matlab 2015a,所以 GPU 上的稀疏矩阵很好(2014b 不喜欢它们)。参数的特征大小如下:n = 60^2 = 3600, L = 48, d = 2

以下是 CPU 的相应时间。请注意,调用的次数是近 20 倍,这就是为什么有些时间实际上更长。

我认为有趣的是,比较 CPU 和 GPU 时,不同线路的效率如何变化。最后一行在 GPU 上稍快,但倒数第二行在 GPU 上慢了大约 6 倍,第一行在 GPU 上慢了大约 20 倍。

如果需要更多信息,请告诉我。


下面是一个 MVCE:

N = [50,50];
n = prod(N); d = numel(N);
L = 64;

sigma = 0.1;
tau   = 0.1;

D = spdiags([-ones(n*L*d,1), ones(n*L*d,1)],0:1,n*L*d,n*L);
D_t = D';

T = spdiags([-ones(L*d,1), ones(L*d,1)],0:1,L*d,L*d);
T = kron(T,speye(n));
T_t = T';

Q = sparse(n,n*L);
for j = 1:L
    Q(:,1+(j-1)*n:j*n) = speye(n); %#ok<SPRIX>
end
Q_t = Q';

u = zeros(n*L,1  ,'gpuArray');
y = zeros(n*L*d,1,'gpuArray');
v = zeros(n*L*d,1,'gpuArray');
w = zeros(n,1    ,'gpuArray');
z = zeros(n*L*d,1,'gpuArray');

count = 0;
count_max = 1000;   % Choose count_max as the maximum number of iterations
while count <= count_max
    v = v + sigma * (D * u - T_t * y);
    w = w + sigma * Q * u;
    z = z + sigma * y;

    u = u - tau * (D_t * v + Q_t * w);
    y = y - tau * (z - T * v);

    count = count + 1;

    if mod(count,10) == 0
        fprintf('count = %1g\n',count)
    end
end

【问题讨论】:

  • 在衡量性能时,通常包括数据大小。在调用每一行之前,矩阵的大小是多少?这很重要。除非您向我们提供有关如何重建问题的更多信息,否则我们无法判断出什么问题。我们只有您的代码。您能否为每个变量提供样本输入,以便我们进一步评估您的问题?
  • 糟糕,是的,忘记输入参数的大小了!我现在就更新。
  • 您还需要什么? :)
  • 是否可以为每个矩阵提供样本输入,以便您的示例是 MVCE? stackoverflow.com/help/mcve。如果我们能够真正重现您的结果以找出您的错误,那将会有所帮助。到目前为止,这两行的运行时间较大的原因可能是任何原因。
  • 另外,您是否尝试过使用基于 CPU 的数组并运行计算并比较结果? CPU版本比GPU版本快还是慢?

标签: performance matlab gpu


【解决方案1】:

解决了!问题是,当我将矩阵分配给 GPU 时,我将一个新矩阵 D_t 定义为转置 - 这样我就不必每次都在 GPU 上进行矩阵的转置,并且所以节省了大量时间 - 我没有将转置矩阵分配给 GPU!

正如 rayryeng 所指出的,这样做的寓意是确保你所有的数组都是gpuArray希望我的错误能阻止其他人犯同样的错误! :)

【讨论】:

  • 性能差异的另一个潜在来源是gpuArray 稀疏矩阵以 CSR 格式存储; MATLAB 的原生稀疏格式是 CSC。根据您是否正在转置参数,它们的表现非常不同。 通常最好让 MATLAB 看到您何时执行A' * B 之类的操作(即,而不是执行At = A'; C = At * B),因为在这种情况下它有时会表现得更好 - 但并非总是如此,正如您所观察到的(这可能是由于 CSR/CSC 格式的差异)。
  • 好的,感谢您的洞察力。老实说,我实际上并不知道 CSR 和 CSC 格式是什么;我刚刚发现在我的特定情况下首先定义转置矩阵要快得多(比喻!)。
  • 在 GPU 和 CPU 上它实际上仍然很慢。在计算稀疏矩阵和全向量的乘积A*x 时,Matlab 是否“智能”地计算它?通过这个,我的意思是它只需要将乘以非零分量的向量元素吗?我试图想办法加快速度,但我的矩阵非常稀疏 - 每行最多有两个非零条目(-11),并且位于 @ 区域987654329@.
  • MATLAB SpMV(稀疏矩阵-向量积)的细节是不透明的 - MATLAB 通常使用现有的高质量数值库来构建这种代数构建块,因此可以合理地假设考虑稀疏矩阵的结构。
  • 太好了,谢谢。通过在参数较小时显式编写矩阵向量乘积,我可以大大加快乘法速度 - 甚至快 50 倍,但当它们开始变大时,使用矩阵乘积会更快。谢谢你的帮助。 :)
猜你喜欢
  • 1970-01-01
  • 2017-12-09
  • 2022-01-01
  • 2013-01-11
  • 2018-12-30
  • 2013-12-11
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
相关资源
最近更新 更多