Генерация случайных чисел на графическом процессоре

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

Случайные числа являются ключевой ролью многих алгоритмы оценки или симуляция. Как правило, эти числа сгенерированы с помощью функций 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 генерирует 107 случайные числа и называются 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.

Смотрите также

|

Похожие темы