Как я могу векторизовать код, включающий несколько матричных операций на GPU в Matlab - PullRequest
0 голосов
/ 21 января 2020

Код ниже принимает 3 целых числа и создает большой блок данных. В более общем случае я хотел бы предоставить векторы q, p значительных размеров, скажем, 5000, и создать большую матрицу данных (здесь это будет 17x15000). Однако каждый block должен быть вычислен путем выполнения последовательности матричных операций. Из исследования сети я обнаружил, что Matlab поддерживает только операции с массивами на графическом процессоре, и вычисления обычно включают крупномасштабные матрицы , а не маленькие матрицы, такие как 3x3 матрицы в пример ниже. Кроме того, код должен быть правильно векторизован. Матричная документация упоминает матричные операции в документации , однако она относится только к некоторым встроенным функциям.

  1. Возможно ли поэтому выполнить мой код на GPU? Если я правильно понимаю, пользовательские функции (вызываемые с arrayfun) могут включать только поэтапные операции. Есть ли другой способ?

  2. Если, с другой стороны, это хороший случай для ускорения GPU, как я могу добиться этого с Matlab?

main script.m

fi = pi/2;
L = 0.4;                mass = 0.5;
p = 0.5;                pnext = 0.1;
sC1 = [-L/2; 0];        sC2 = [L/2; 0];
Icm = 1/12*mass*L^2;    M = diag([mass mass Icm]);
input = struct('M',M,'sC1_loc',sC1,'sC2_loc',sC2);

% fill data
s = 1000;
GlobalAsm = zeros(17, 3 * s);
tic
for i = 1 : s
    GlobalAsm(:,3*i-2:3*i) = createBlock2(0.5*i,i/2, i,input);
end
t2 = toc % t2 = 0.1 approx

createBlock.m

function block = createBlock(fi,p, pnext,input)
M = input.M;                sC2_loc = input.sC2_loc;
sC1_loc = input.sC1_loc;    s12_loc = sC1_loc-sC2_loc;
Om = [0, -1; 1, 0];         H = [0; 0; 1];

s12 = Rot(fi)*s12_loc;      s21 = -Rot(fi)*s12_loc;
s1C = -Rot(fi)*sC1_loc;     s2C = -Rot(fi)*sC2_loc;

S12 = eye(3);               S21 = eye(3);
S1c = eye(3);               S2c = eye(3);
S12(3,1:2) = (Om*s12).';    S21(3,1:2) = (Om*s21).';
S1c(3,1:2) = (Om*s1C).';    S2c(3,1:2) = (Om*s2C).'; 


M1 = S1c * M * S1c.';       M2 = S2c * M * S2c.';

KSI11 = inv(M1);    KSI12 = M1 \ S12;
KSI22 = inv(M2);    KSI21 = M2 \ S21;

KSI10 = M1 \ (+H*p   - S12*H*pnext);
KSI20 = M2 \ (-H*pnext + S21*H*p);

block = [KSI11; KSI12; KSI21; KSI22; KSI10.'; KSI20.'; S12];

function R = Rot(fi)
R = [cos(fi) -sin(fi);
     sin(fi)  cos(fi)];

РЕДАКТИРОВАТЬ: Основываясь на приведенном ниже преобразовании, я хочу показать простой пример. Теперь в main данные заполняются с помощью createBlock. Все выполняется на процессоре, и для его завершения требуется около 0,1 с.

Ниже приведен тот же код с переменными gpuArray. Это займет значительно больше времени (около 11 секунд). Как мне переформулировать код, чтобы воспользоваться ускорением графического процессора?


main script on GPU

s = 1000;
GlobalAsm = zeros(17, 3 * s, 'gpuArray');
tic
for i = 1 : s
    i = gpuArray(i);
    GlobalAsm(:,3*i-2:3*i) = createBlock2(0.5*i,i/2, i,input);
end
t = toc % t = 11.0s approx

createBlock2.m on GPU

function block = createBlock2(fi,p, pnext,input)
M = input.M;                sC2_loc = input.sC2_loc;
sC1_loc = input.sC1_loc;    s12_loc = sC1_loc-sC2_loc;
Om = gpuArray([0, -1; 1, 0]); H = gpuArray([0; 0; 1]);  % <- change in this line

s12 = Rot(fi)*s12_loc;      s21 = -Rot(fi)*s12_loc;
s1C = -Rot(fi)*sC1_loc;     s2C = -Rot(fi)*sC2_loc;

[S12, S21, S1c, S2c] = deal(gpuArray.eye(3));           % <- change in this line
S12(3,1:2) = (Om*s12).';    S21(3,1:2) = (Om*s21).';
S1c(3,1:2) = (Om*s1C).';    S2c(3,1:2) = (Om*s2C).'; 


M1 = S1c * M * S1c.';       M2 = S2c * M * S2c.';

KSI11 = inv(M1);    KSI12 = M1 \ S12;
KSI22 = inv(M2);    KSI21 = M2 \ S21;

KSI10 = M1 \ (+H*p   - S12*H*pnext);
KSI20 = M2 \ (-H*pnext + S21*H*p);

block = [KSI11; KSI12; KSI21; KSI22; KSI10.'; KSI20.'; S12];

function R = Rot(fi)
R = [cos(fi) -sin(fi);
     sin(fi)  cos(fi)];

...