Matrix Multiplication/Addition 在某些情况下在 GPU 上非常慢
Matrix Multiplication/Addition Very Slow on GPU in Certain Cases
我目前正在尝试让我的代码在我的 GPU 上 运行,而不是 CPU - 好吧,它是 运行ning,但不是很好。让我给出代码的相关部分:
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
已解决!问题是,当我将矩阵分配给 GPU 时,我定义了一个新矩阵 D_t
作为转置 - 这样我就不必每次都在 GPU 上进行矩阵转置,因此节省了大量时间 - 我没有将转置矩阵分配给 GPU!
正如 rayryeng 指出的那样,这样做的寓意是 确保您所有的数组都是 gpuArray
! 希望我的错误会阻止其他人犯同样的错误! :)
我目前正在尝试让我的代码在我的 GPU 上 运行,而不是 CPU - 好吧,它是 运行ning,但不是很好。让我给出代码的相关部分:
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
已解决!问题是,当我将矩阵分配给 GPU 时,我定义了一个新矩阵 D_t
作为转置 - 这样我就不必每次都在 GPU 上进行矩阵转置,因此节省了大量时间 - 我没有将转置矩阵分配给 GPU!
正如 rayryeng 指出的那样,这样做的寓意是 确保您所有的数组都是 gpuArray
! 希望我的错误会阻止其他人犯同样的错误! :)