Add RandomUniform-28 with deterministic generator attribute (MT19937) - #2
Open
strimo378 wants to merge 5 commits into
Open
Add RandomUniform-28 with deterministic generator attribute (MT19937)#2strimo378 wants to merge 5 commits into
strimo378 wants to merge 5 commits into
Conversation
RandomUniform is non-deterministic, which makes its output unverifiable in backend node tests (the operator had no node tests at all). This adds an optional string attribute 'generator' (default "default") that can select a fully specified pseudo-random number generator, making the operator optionally deterministic and therefore testable. - "default": implementation-defined generator, previous behavior - "mersenne_twister": standard 32-bit MT19937 seeded with init_genrand (the std::mt19937 seeding) from the mandatory 'seed' attribute, doubles drawn with the genrand_res53 method in row-major order, scaled to [low, high) in double precision, then cast to dtype The value list is extensible: more algorithms can be added in future opset versions. - defs.cc: RandomUniform-28 schema with generator attribute and attribute validation in the inference function - old.cc: RandomUniform-22 schema preserved - operator_sets.h: register RandomUniform in OpSet_Onnx_ver28 - convert.h: 27->28 CompatibleAdapter; 28->27 adapter that drops generator="default" and rejects deterministic generators - reference implementation: _MT19937 class (verified against the canonical MT19937 test vector and std::mt19937) wired into RandomUniform - node test cases with exact expected outputs plus schema, shape inference, version converter and reference evaluator tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp Signed-off-by: Claude <noreply@anthropic.com>
- docs/Operators.md, docs/Changelog.md via onnx/defs/gen_doc.py - docs/TestCoverage.md via onnx/backend/test/stat_coverage.py - backend node test data via cmd_tools.py generate-data -t RandomUniform - ruff format on the reference implementation files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp Signed-off-by: Claude <noreply@anthropic.com>
The previous wording only said results are not reproducible across implementations. Make explicit that in "default" mode an implementation may produce reproducible results but is not required to, even for a fixed seed and even across runs of the same implementation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp Signed-off-by: Claude <noreply@anthropic.com>
"default" only described that the value is the attribute default, not its meaning. "unspecified" states the semantics directly: the generator algorithm is left unspecified and implementation-defined, with no determinism guarantee. It also stays accurate if a future opset ever recommends a different generator as the default choice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp Signed-off-by: Claude <noreply@anthropic.com>
Double precision is now only used for dtype=double (two 32-bit outputs via genrand_res53, as before). For bfloat16/float16/float, each element draws a single 32-bit output and forms r = (a >> (32-p)) / 2^p with p significand bits, which is exactly representable in the target type. low + r * (high - low) is evaluated in the target type with IEEE 754 round-to-nearest-even instead of double-then-cast, so implementations never need double arithmetic unless dtype is double. The double test data is unchanged; float32/float16 expected values are regenerated. The node test case now carries its own independent MT19937 implementation to cross-check the reference runtime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp Signed-off-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional
generatorattribute toRandomUniform(new opset-28 schema) that makes the operator optionally deterministic — and therefore testable.RandomUniformwas previously the only generator op with no backend node tests at all, because its output could not be verified.generator="unspecified"(default value): the PRNG remains implementation-defined; fully backward compatible. This mode gives no determinism guarantee: results may differ across implementations and even across runs of the same implementation, even whenseedis specified. An implementation may produce reproducible results here, but is not required to.generator="mersenne_twister": fully specified 32-bit MT19937 withinit_genrandseeding (identical to C++std::mt19937). Values are produced in the target data type — double arithmetic is only required whendtypeis double:dtype=double: two 32-bit outputs per element via thegenrand_res53method (r = (⌊a/2^5⌋·2^26 + ⌊b/2^6⌋) / 2^53).r = ⌊a / 2^(32-p)⌋ / 2^pwithpsignificand bits (8/11/24), exactly representable in the target type.low + r * (high - low), withlow/highconverted todtypeand all arithmetic performed indtypeunder IEEE 754 round-to-nearest-even — bit-identical across conforming implementations for a givenseed.seedis required in this mode (enforced by shape inference, as is rejection of unknown generator names).The attribute value set is deliberately extensible: the same pattern is intended to be rolled out to the other non-deterministic operators later (
RandomNormal,RandomUniformLike,RandomNormalLike,Bernoulli,Multinomial), and future opset versions can add further generator algorithms. The MT19937 implementation already lives in the shared_CommonRandombase of the reference runtime in preparation for that.Changes
RandomUniform-28withgeneratorattribute and attribute validation in the inference function; old.cc: v22 schema preserved; operator_sets.h: registered under opset 28; new doc string describing the exact MT19937 algorithm and the (non-)guarantees of both modesCompatibleAdapter; 28→27 custom adapter that dropsgenerator="unspecified"and rejects deterministic generators (not expressible in older opsets)_MT19937class (init_genrand,genrand_res53, per-precision draws) in_op_common_random.py, wired intoRandomUniform; verified against the canonical MT19937 test vector (10000th output for seed 5489 = 4123659995) and thestd::mt19937uint32 streamRandomUniform(4 cases: default range, low/high, double, float16) with exact expected outputs generated by an independent inline MT19937 implementation in the test case, verified bit-exactly by the reference backend runnerstd::mt19937docs/Operators.md,docs/Changelog.md,docs/TestCoverage.md, and backend test dataMotivation and Context
The random-number operators are non-deterministic per spec: even with
seedset, results differ across implementations, so conformance tests cannot verify their output. As a consequence, the random operators are effectively invisible to conformance tracking such as the ONNX Backend Scoreboard: there are no node tests whose results a backend could be checked against. With an opt-in, fully specified generator (Mersenne Twister for now, extensible later), the output becomes reproducible and bit-exactly verifiable, so random operators can be covered by the standard backend test suite and their support becomes measurable on the scoreboard — while the default behavior, including its freedom to be non-deterministic, stays unchanged. Computing in the target data type keeps the requirement on implementations minimal: no double-precision arithmetic is needed unlessdtypeis double.🤖 Generated with Claude Code
https://claude.ai/code/session_01PVuibCDPDmYP2zoMawf9sp