Этот пример показывает, как переключиться между различными генераторами случайных чисел, которые поддерживаются на графическом процессоре.
Случайные числа являются ключевой ролью многих алгоритмы оценки или симуляция. Как правило, эти числа сгенерированы с помощью функций rand
, randi
и randn
. Parallel Computing Toolbox™ обеспечивает три соответствующих функции для генерации случайных чисел непосредственно на графическом процессоре: rand
, randi
и randn
. Эти функции могут использовать один из нескольких различных алгоритмов генерации номера.
d = gpuDevice; fprintf("This example is run on a " + d.Name + " GPU.")
This example is run on a GeForce GTX 1080 GPU.
Функциональный parallel.gpu.RandStream.list
предоставляет краткое описание доступных генераторов.
parallel.gpu.RandStream.list
The following random number generator algorithms are available: MRG32K3A: Combined multiple recursive generator (supports parallel streams) Philox4x32_10: Philox 4x32 generator with 10 rounds (supports parallel streams) Threefry4x64_20: Threefry 4x64 generator with 20 rounds (supports parallel streams)
Каждый из этих генераторов был разработан с параллельным использованием в памяти, обеспечив несколько независимых потоков случайных чисел. Однако у каждого из них есть некоторые преимущества и недостатки:
CombRecursive (также известный как MRG32k3a
): Этот генератор был введен в 1 999 и широко тестировался и использовался.
Philox (также известный как Philox4x32_10): Новый генератор введен в 2 011, специально предназначенный для высокой производительности в очень параллельных системах, таких как графические процессоры.
Threefry (также известный как Threefry4x64_20): Новый генератор ввел в 2 011 на основе существующего криптографического алгоритма ThreeFish, который широко тестируется и используется. Этот генератор был разработан, чтобы дать хорошую производительность в очень параллельных системах, таких как графические процессоры. Это - генератор по умолчанию для вычислений графического процессора.
Эти три генератора, доступные на графическом процессоре, также доступны для использования на центральном процессоре в MATLAB®. Генераторы MATLAB имеют то же имя и приводят к идентичным результатам, учитывая то же начальное состояние. Это полезно когда это необходимо, чтобы произвести те же наборы случайных чисел и на графическом процессоре и на центральном процессоре.
Все эти генераторы передают стандартный тестовый набор TestU01 [1].
Функциональный gpurng
может сохранить и сбросить состояние генератора для графического процессора. Можно также использовать gpurng
, чтобы переключиться между различными генераторами, которые обеспечиваются. Прежде, чем изменить генератор, сохраните существующее состояние так, чтобы это могло быть восстановлено в конце этих тестов.
oldState = gpurng;
gpurng(0, "Philox4x32-10");
disp(gpurng)
Type: 'philox' Seed: 0 State: [7×1 uint32]
Равномерно распределенные случайные числа сгенерированы на графическом процессоре с помощью или rand
или randi
. В терминах производительности эти две функции ведут себя очень похоже, и только
rand
измеряется здесь. gputimeit
используется, чтобы измерить уровень, чтобы гарантировать точные результаты синхронизации, автоматически вызывание функции много раз и правильно контакт с синхронизацией и другими проблемами синхронизации.
Чтобы сравнить производительность различных генераторов, используйте rand
, чтобы сгенерировать большое количество случайных чисел на графическом процессоре с помощью каждого генератора. В следующем коде rand
генерирует случайные числа и называются 100 раз для каждого генератора. Каждое выполнение синхронизировано с помощью gputimeit
. Генерация больших выборок случайных чисел может занять несколько минут. Результаты показывают на сравнение производительности этих трех генераторов случайных чисел, доступных на графическом процессоре.
generators = ["Philox","Threefry","CombRecursive"]; gputimesU = nan(100,3); for g=1:numel(generators) % Set the generator gpurng(0, generators{g}); % Perform calculation 100 times, timing the generator for rep=1:100 gputimesU(rep,g) = gputimeit(@() rand(10000,1000,"gpuArray")); end end
% Plot the results figure hold on histogram(gputimesU(:,1),"BinWidth",1e-4); histogram(gputimesU(:,2),"BinWidth",1e-4); histogram(gputimesU(:,3),"BinWidth",1e-4) legend(generators) xlabel("Time to generate 10^7 random numbers (sec)") ylabel("Frequency") title("Generating samples in U(0,1) using " + d.Name) hold off
Более новые генераторы Threefry и Philox имеют подобную производительность. Оба быстрее, чем CombRecursive.
Много симуляций полагаются на возмущения, выбранные от нормального распределения. Подобно универсальному тесту используйте randn
, чтобы сравнить производительность трех генераторов при генерации нормально распределенных случайных чисел. Генерация больших выборок случайных чисел может занять несколько минут.
generators = ["Philox","Threefry","CombRecursive"]; gputimesN = nan(100,3); for g=1:numel(generators) % Set the generator gpurng(0, generators{g}); % Perform calculation 100 times, timing the generator for rep=1:100 gputimesN(rep,g) = gputimeit(@() randn(10000,1000,"gpuArray")); end end
% Plot the results figure hold on histogram(gputimesN(:,1),"BinWidth",1e-4); histogram(gputimesN(:,2),"BinWidth",1e-4) histogram(gputimesN(:,3),"BinWidth",1e-4) legend(generators) xlabel("Time to generate 10^7 random numbers (sec)") ylabel("Frequency") title("Generating samples in N(0,1) using " + d.Name) hold off
Еще раз результаты показывают, что генераторы Threefry и Philox выполняют так же и оба особенно быстрее, чем CombRecursive. Дополнительная работа, требуемая произвести нормально распределенные значения, уменьшает уровень, на котором значения производятся каждым из генераторов.
Перед окончанием восстановите исходное состояние генератора.
gpurng(oldState);
В этом примере сравнены три генератора случайных чисел графического процессора. Точные результаты отличаются в зависимости от вашего графического процессора и вычислительной платформы. Каждый генератор обеспечивает некоторые преимущества (+
) и имеет некоторые протесты (-
).
Threefry
(+
) Быстро
(+
) На основе известного и хорошо протестированного алгоритма Threefish
(-
), Относительно новый в реальном использовании
Philox
(+
) Быстро
(-
), Относительно новый в реальном использовании
CombRecursive
(+
) послужной список Лонга в реальном использовании
Самый Медленный (-
)
[1] L'Ecuyer, P. и Р. Симард. "TestU01: библиотека C для эмпирического тестирования генераторов случайных чисел". Транзакции ACM на Mathematical Software. Издание 33, № 4, 2007, статья 22.
gpurng
| parallel.gpu.RandStream