Повышение эффективности поэлементных функций MATLAB ® на графическом процессоре с помощью 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 со стандартным выполнением Центральный Процессор просто путем непосредственной оценки функции.

hornerFcn = @horner;

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

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

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

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

Чтобы оценить horner функция на графическом процессоре, у нас есть два выбора. С минимальными изменениями кода мы можем оценить исходную функцию на графическом процессоре, предоставив gpuArray объект как вход. Однако для повышения эффективности при вызове GPU 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

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

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

% 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