Улучшайте Производительность Поэлементного MATLAB® Functions на графическом процессоре с помощью ARRAYFUN

Этот пример показывает, как arrayfun может использоваться, чтобы запустить функцию MATLAB® исходно на графическом процессоре. Когда функция MATLAB содержит много поэлементных операций, arrayfun может обеспечить улучшенную производительность когда по сравнению с простым выполнением функции MATLAB непосредственно на графическом процессоре с gpuArray входными данными. Функция MATLAB может быть в ее собственном файле или может быть вложенной или анонимной функцией. Это должно содержать только скалярные операции и арифметику.

Мы помещаем пример в функцию, чтобы позволить вложенные функции:

function paralleldemo_gpu_arrayfun

Использование правила Горнера, чтобы вычислить экспоненциалы

Правило Горнера позволяет эффективную оценку расширений степенного ряда. Мы будем использовать его, чтобы вычислить первые 10 сроков расширения степенного ряда для показательной функции exp. Мы можем реализовать это как функцию MATLAB.

function y = horner(x)
%HORNER - series expansion for exp(x) using Horner's rule
y = 1 + x.*(1 + x.*((1 + x.*((1 + ...
        x.*((1 + x.*((1 + x.*((1 + x.*((1 + ...
        x.*((1 + x./9)./8))./7))./6))./5))./4))./3))./2));
end

Подготовка horner для графического процессора

Чтобы запустить эту функцию на графическом процессоре с минимальными изменениями кода, мы могли передать объект gpuArray, как введено функции horner. Поскольку horner содержит только отдельные поэлементные операции, мы не можем понять очень хорошую производительность на графическом процессоре при выполнении каждой операции по одному. Однако мы можем улучшать производительность путем выполнения всех поэлементных операций в функции horner когда-то использование arrayfun.

Чтобы запустить эту функцию на графическом процессоре с помощью arrayfun, мы используем указатель на функцию horner. horner автоматически адаптируется к различному размеру и входным параметрам типа. Мы можем сравнить результаты, вычисленные на графическом процессоре с помощью и объектов gpuArray и arrayfun со стандартным выполнением центрального процессора MATLAB просто путем выполнения функции непосредственно.

hornerFcn = @horner;

Создайте входные данные

Мы создаем некоторые входные параметры различных типов и размеров, и используем gpuArray, чтобы отправить их в графический процессор.

data1  = rand( 2000, 'single' );
data2  = rand( 1000, 'double' );
gdata1 = gpuArray( data1 );
gdata2 = gpuArray( data2 );

Оцените horner на графическом процессоре

Чтобы выполнить функцию horner на графическом процессоре, у нас есть два варианта. С минимальными изменениями кода мы можем выполнить исходную функцию на графическом процессоре путем обеспечения объекта gpuArray, как введено. Однако, чтобы улучшать производительность на графическом процессоре вызывают arrayfun, с помощью того же соглашения о вызовах в качестве исходной функции MATLAB.

Мы можем сравнить точность результатов путем выполнения исходной функции непосредственно в MATLAB на центральном процессоре. Мы ожидаем некоторые небольшие числовые различия, потому что арифметика с плавающей точкой на графическом процессоре точно не совпадает с арифметикой, выполняемой на центральном процессоре.

gresult1 = arrayfun( hornerFcn, gdata1 );
gresult2 = arrayfun( hornerFcn, gdata2 );

comparesingle = max( max( abs( gresult1 - horner( data1 ) ) ) );
comparedouble = max( max( abs( gresult2 - horner( data2 ) ) ) );
fprintf( 'Maximum discrepancy for single precision: %g\n', comparesingle );
fprintf( 'Maximum discrepancy for double precision: %g\n', comparedouble );
Maximum discrepancy for single precision: 2.38419e-07
Maximum discrepancy for double precision: 0

Сравнение производительности между графическим процессором и центральным процессором

Мы можем сравнить производительность версий графического процессора к нативной версии ЦП MATLAB. Текущие графические процессоры генерации имеют намного лучшую производительность в одинарной точности, таким образом, мы сравниваем это.

% CPU execution
tic
hornerFcn( data1 );
tcpu = toc;

% GPU execution using only gpuArray objects
tgpuObject = gputimeit(@() hornerFcn(gdata1));

% GPU execution using gpuArray objects with arrayfun
tgpuArrayfun = gputimeit(@() arrayfun(hornerFcn, gdata1));


fprintf( 'Speed-up achieved using gpuArray objects only: %g\n',...
    tcpu / tgpuObject );
fprintf( 'Speed-up achieved using gpuArray objects with arrayfun: %g\n',...
    tcpu / tgpuArrayfun );
Speed-up achieved using gpuArray objects only: 24.6764
Speed-up achieved using gpuArray objects with arrayfun: 98.3555
end