Skip to content

Make RNG seed optional and improve per-core seed generation for bernoulli/uniform/rand#37906

Open
suzusuzu wants to merge 1 commit intotenstorrent:mainfrom
suzusuzu:fix-seed-optional
Open

Make RNG seed optional and improve per-core seed generation for bernoulli/uniform/rand#37906
suzusuzu wants to merge 1 commit intotenstorrent:mainfrom
suzusuzu:fix-seed-optional

Conversation

@suzusuzu
Copy link

Ticket

Problem description

ttnn.bernoulli, ttnn.uniform, and ttnn.rand currently take a uint32_t seed with 0 acting as a "no-seed / random" sentinel.
This has two issues:

  1. The API cannot express "no seed" explicitly, and seed=0 is ambiguous (it could be a valid user seed).
  2. The device program previously derived per-core seeds by incrementing the base seed. In practice, this can lead to highly correlated/random streams across adjacent seeds (e.g., results for seed=1 and seed=2 end up looking almost identical), reducing randomness quality and surprising users expecting independent outputs.

What's changed

  • Updated the APIs to use std::optional<uint32_t> for seeds:
    • Python bindings now default seed=None instead of 0.
    • Operation attributes store std::optional<uint32_t> rather than a uint32_t with a sentinel.
  • Updated program hash computation to ignore seeds by setting the cached seed to std::nullopt (consistent with prior behavior where the seed should not affect compilation/caching).
  • Reworked per-core seed generation:
    • Instead of incrementing the base seed, we now initialize an std::mt19937 once per program creation/override using either the user-provided seed or std::time(nullptr) when no seed is provided.
    • Each core receives a fresh seed sampled from a uniform distribution, improving independence between cores and avoiding the "seed=1 vs seed=2 are almost the same" behavior.

Checklist

  • All post-commit tests
  • Blackhole Post commit
  • cpp-unit-tests
  • New/Existing tests provide coverage for changes

Model tests

If your changes cover model-related code, you should run tests corresponding to affected models and platforms (Single card, T3K, Galaxy). "Choose your pipeline" workflows facilitate running multiple kinds of tests in a single run. Each offers models-mandatory and models-extended presets.
The former includes a minimal set of tests, to be run always. The latter extends that with additional ones - use your best judgement in deciding which is the most appropriate for your PR.

@suzusuzu suzusuzu requested review from a team and nsextonTT as code owners February 14, 2026 14:23
@suzusuzu
Copy link
Author

I verified the behavior of the updated bernoulli / uniform / rand operations as follows:

>>> ttnn.rand([3, 3], device=device)
ttnn.Tensor([[ 0.2637,  0.6328,  0.0532],
             [ 0.8672,  0.9336,  0.4629],
             [ 0.6523,  0.8281,  0.6133]], shape=Shape([3, 3]), dtype=DataType::BFLOAT16, layout=Layout::TILE)

>>> input = ttnn.to_device(ttnn.from_torch(torch.empty(3, 3, dtype=torch.bfloat16).uniform_(0, 1), layout=ttnn.TILE_LAYOUT), dev
ice=device)
>>> ttnn.bernoulli(input)
ttnn.Tensor([[ 0.0000,  1.0000,  1.0000],
             [ 1.0000,  0.0000,  1.0000],
             [ 0.0000,  0.0000,  0.0000]], shape=Shape([3, 3]), dtype=DataType::FLOAT32, layout=Layout::TILE)

>>> input = ttnn.to_device(ttnn.from_torch(torch.ones(3, 3, dtype=torch.bfloat16), layout=ttnn.TILE_LAYOUT), device=device)
>>> ttnn.uniform(input)
ttnn.Tensor([[ 0.9102,  0.9531,  0.6406],
             [ 0.4531,  0.2266,  0.8164],
             [ 0.5195,  0.7578,  0.0889]], shape=Shape([3, 3]), dtype=DataType::BFLOAT16, layout=Layout::TILE)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant