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

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

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

  • Philox (также известный как Philox4x32_10): Новый генератор, представленный в 2011 году, специально разработан для высокой эффективности в высоко параллельных системах, таких как графические процессоры.

  • Threefry (также известный как Threefry4x64_20): Новый генератор, представленный в 2011 году на основе существующего криптографического алгоритма 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., and R. Simard. «TestU01: библиотека C для эмпирической проверки генераторов случайных чисел». Транзакции ACM на математическом программном обеспечении. Том 33, № 4, 2007, статья 22.

См. также

|

Похожие темы