dpnp random number generation
Purpose
Generates random data with dpnp.random, which is backed by oneMKL on Intel CPUs
and GPUs and mirrors the NumPy API for the distributions it implements. Covers
what is implemented, what seeding actually guarantees, how to fall back to NumPy
for a missing distribution, and how to keep generation from becoming a stream of
host-device copies.
The reproducibility part is the reason this skill exists: the API looks like
NumPy's and the numbers are different, which is correct behaviour and reliably
surprises people.
When to Use This Skill
Use this skill when:
- NumPy random calls are being moved to
dpnp.
- A seeded
dpnp run does not reproduce a seeded NumPy run.
- A distribution raises
NotImplementedError or is missing.
- Results must be reproducible across machines or devices.
- Random data feeds a training loop, dropout, augmentation, or an initializer.
Do not use this skill when the arrays are small — NumPy is the better answer
there — and do not use it to claim a generation speedup: there are no measured
numbers here.
Quick Start
import dpnp
dpnp.random.seed(42)
x = dpnp.random.randn(1000, 1000) # standard normal
y = dpnp.random.uniform(0, 1, size=10000) # uniform [0, 1)
z = dpnp.random.randint(0, 100, size=500) # integers [0, 100)
Seeding twice with the same value on the same device reproduces the same
sequence. It does not reproduce NumPy's sequence — see the Guide.
Implementation Guide
Use the NumPy spelling for what is implemented. rand, randn,
random, uniform, normal, randint, choice, shuffle, and the common
univariate distributions — exponential, poisson, binomial, geometric, gamma,
beta — keep their NumPy signatures. Confirm the specific one against the
installed release rather than a remembered list.
Set the seed once, at the top. Reseeding inside a loop resets generator
state on every iteration and produces neither speed nor determinism:
dpnp.random.seed(42)
noise = dpnp.random.randn(1000, 256, 256) # one call, all iterations
for index in range(1000):
image = clean + noise[index]
Do not expect NumPy's numbers. dpnp.random and numpy.random use
different generators — oneMKL's on one side, NumPy's PCG64 on the other — so
the same seed gives different sequences. This is expected, not a bug, and it
means a reproducibility chain must not mix the two:
import numpy
numpy.random.seed(42)
dpnp.random.seed(42)
# numpy.random.randn(5) and dpnp.random.randn(5) do not match, by design
Fall back on the host for a missing distribution. Generate with NumPy,
then move the batch across once — the cost is the transfer, so make the batch
large:
host = numpy.random.beta(a=2.0, b=5.0, size=100_000)
device_array = dpnp.array(host)
result = dpnp.mean(device_array ** 2)
Distributions commonly missing include the multivariate ones — dirichlet,
multivariate_normal, multinomial — and several of the long tail such as
chisquare, triangular, vonmises, wald, zipf. Check before promising
one.
Persist the draw when a result has to be reproducible elsewhere. Seeding
guarantees a sequence on the same device and release; a different device type,
or a different version, may produce a different one. When an experiment has to
be replayed exactly, save the numbers rather than the seed — through NumPy,
because dpnp has no binary writer of its own:
dpnp.random.seed(42)
numpy.save("random_state.npy", dpnp.asnumpy(dpnp.random.randn(1_000_000)))
later = dpnp.array(numpy.load("random_state.npy"))
Generate where the data is consumed. Random values that feed device
compute should be drawn on the device; values that immediately go back to the
host should be drawn with NumPy. Offsets for a crop, a dropout mask, or an
initializer belong on the device:
def dropout(x, p=0.5, training=True):
if not training:
return x
mask = dpnp.random.rand(*x.shape) > p
return x * mask / (1 - p)
Performance
No measured numbers ship with this skill. Generation is memory-bandwidth bound
rather than compute bound, which shapes what is worth measuring:
- There is a size below which kernel launch overhead dominates and NumPy wins.
It is in the thousands of elements, not the millions; measure the real shapes.
- The first call pays for plan creation, and later calls of the same size reuse
it. Warm up before timing, and never time a reseeded loop.
- One large draw beats many small ones, because the fixed cost is paid once.
- A host fallback costs a transfer per batch. Batch size, not distribution, is
what makes that acceptable.
Gotchas & Limitations
- Same seed, different numbers from NumPy. Different generator, by design. A
test that compares sequences across the two libraries is testing the wrong
thing; compare distributions or statistics instead.
- Reseeding in a loop is the classic mistake. It is slower and it does not
make anything more deterministic.
- Cross-device reproducibility is not guaranteed. Same seed on the same device
reproduces; CPU versus GPU may not, and neither may two
dpnp releases.
dpnp has no binary save. Persisting a draw goes through
numpy.save(dpnp.asnumpy(...)); see dpnp-io.
- Coverage claims expire. Any list of supported or unsupported distributions
describes one release. Check
dir(dpnp.random) and the documentation.
- Not covered: parallel independent streams, counter-based generator state, and
the
Generator/default_rng object API.
References
| File |
Load it when |
references/official-sources.md |
you need the distributions a specific dpnp release implements, the oneMKL generator behind them, or NumPy's own generator semantics to explain a difference |
Two questions here should not be answered from memory: which distributions the
installed release implements and which generator oneMKL uses for a given
call, which is what makes a cross-library difference explainable instead of
suspicious.
1---2name: dpnp-random3description: Random number generation with dpnp on Intel CPUs and GPUs, backed by oneMKL. Use when NumPy random calls move to dpnp, when a seeded dpnp run does not reproduce a NumPy sequence, when a distribution turns out not to be implemented, when results have to be reproducible across machines, or when random data feeds a training or augmentation loop. Covers the supported distributions, what seeding does and does not guarantee, the host fallback, and where to generate data so it does not bounce between host and device.4license: Apache-2.05---67# dpnp random number generation89## Purpose1011Generates random data with `dpnp.random`, which is backed by oneMKL on Intel CPUs12and GPUs and mirrors the NumPy API for the distributions it implements. Covers13what is implemented, what seeding actually guarantees, how to fall back to NumPy14for a missing distribution, and how to keep generation from becoming a stream of15host-device copies.1617The reproducibility part is the reason this skill exists: the API looks like18NumPy's and the numbers are different, which is correct behaviour and reliably19surprises people.2021## When to Use This Skill2223Use this skill when:2425- NumPy random calls are being moved to `dpnp`.26- A seeded `dpnp` run does not reproduce a seeded NumPy run.27- A distribution raises `NotImplementedError` or is missing.28- Results must be reproducible across machines or devices.29- Random data feeds a training loop, dropout, augmentation, or an initializer.3031Do **not** use this skill when the arrays are small — NumPy is the better answer32there — and do not use it to claim a generation speedup: there are no measured33numbers here.3435## Quick Start3637```python38import dpnp3940dpnp.random.seed(42)41x = dpnp.random.randn(1000, 1000) # standard normal42y = dpnp.random.uniform(0, 1, size=10000) # uniform [0, 1)43z = dpnp.random.randint(0, 100, size=500) # integers [0, 100)44```4546Seeding twice with the same value on the same device reproduces the same47sequence. It does **not** reproduce NumPy's sequence — see the Guide.4849## Implementation Guide50511. **Use the NumPy spelling for what is implemented.** `rand`, `randn`,52 `random`, `uniform`, `normal`, `randint`, `choice`, `shuffle`, and the common53 univariate distributions — exponential, poisson, binomial, geometric, gamma,54 beta — keep their NumPy signatures. Confirm the specific one against the55 installed release rather than a remembered list.56572. **Set the seed once, at the top.** Reseeding inside a loop resets generator58 state on every iteration and produces neither speed nor determinism:5960 ```python61 dpnp.random.seed(42)62 noise = dpnp.random.randn(1000, 256, 256) # one call, all iterations63 for index in range(1000):64 image = clean + noise[index]65 ```66673. **Do not expect NumPy's numbers.** `dpnp.random` and `numpy.random` use68 different generators — oneMKL's on one side, NumPy's PCG64 on the other — so69 the same seed gives different sequences. This is expected, not a bug, and it70 means a reproducibility chain must not mix the two:7172 ```python73 import numpy7475 numpy.random.seed(42)76 dpnp.random.seed(42)77 # numpy.random.randn(5) and dpnp.random.randn(5) do not match, by design78 ```79804. **Fall back on the host for a missing distribution.** Generate with NumPy,81 then move the batch across once — the cost is the transfer, so make the batch82 large:8384 ```python85 host = numpy.random.beta(a=2.0, b=5.0, size=100_000)86 device_array = dpnp.array(host)87 result = dpnp.mean(device_array ** 2)88 ```8990 Distributions commonly missing include the multivariate ones — `dirichlet`,91 `multivariate_normal`, `multinomial` — and several of the long tail such as92 `chisquare`, `triangular`, `vonmises`, `wald`, `zipf`. Check before promising93 one.94955. **Persist the draw when a result has to be reproducible elsewhere.** Seeding96 guarantees a sequence on the same device and release; a different device type,97 or a different version, may produce a different one. When an experiment has to98 be replayed exactly, save the numbers rather than the seed — through NumPy,99 because `dpnp` has no binary writer of its own:100101 ```python102 dpnp.random.seed(42)103 numpy.save("random_state.npy", dpnp.asnumpy(dpnp.random.randn(1_000_000)))104 later = dpnp.array(numpy.load("random_state.npy"))105 ```1061076. **Generate where the data is consumed.** Random values that feed device108 compute should be drawn on the device; values that immediately go back to the109 host should be drawn with NumPy. Offsets for a crop, a dropout mask, or an110 initializer belong on the device:111112 ```python113 def dropout(x, p=0.5, training=True):114 if not training:115 return x116 mask = dpnp.random.rand(*x.shape) > p117 return x * mask / (1 - p)118 ```119120## Performance121122No measured numbers ship with this skill. Generation is memory-bandwidth bound123rather than compute bound, which shapes what is worth measuring:124125- There is a size below which kernel launch overhead dominates and NumPy wins.126 It is in the thousands of elements, not the millions; measure the real shapes.127- The first call pays for plan creation, and later calls of the same size reuse128 it. Warm up before timing, and never time a reseeded loop.129- One large draw beats many small ones, because the fixed cost is paid once.130- A host fallback costs a transfer per batch. Batch size, not distribution, is131 what makes that acceptable.132133## Gotchas & Limitations134135- **Same seed, different numbers from NumPy.** Different generator, by design. A136 test that compares sequences across the two libraries is testing the wrong137 thing; compare distributions or statistics instead.138- **Reseeding in a loop is the classic mistake.** It is slower and it does not139 make anything more deterministic.140- **Cross-device reproducibility is not guaranteed.** Same seed on the same device141 reproduces; CPU versus GPU may not, and neither may two `dpnp` releases.142- **`dpnp` has no binary save.** Persisting a draw goes through143 `numpy.save(dpnp.asnumpy(...))`; see `dpnp-io`.144- **Coverage claims expire.** Any list of supported or unsupported distributions145 describes one release. Check `dir(dpnp.random)` and the documentation.146- Not covered: parallel independent streams, counter-based generator state, and147 the `Generator`/`default_rng` object API.148149## References150151| File | Load it when |152|---|---|153| [`references/official-sources.md`](references/official-sources.md) | you need the distributions a specific dpnp release implements, the oneMKL generator behind them, or NumPy's own generator semantics to explain a difference |154155Two questions here should not be answered from memory: **which distributions the156installed release implements** and **which generator oneMKL uses for a given157call**, which is what makes a cross-library difference explainable instead of158suspicious.