-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[Relay][PRNG] Add uniform distribution generator wrt threefry PRNG #8041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7baf726
fd68ff4
135da62
cbaec73
024e176
fd1368b
bf577e4
aa372d4
c707ce0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -466,3 +466,69 @@ def gen_ir(out_ptr): | |
| out_ary = tvm.nd.array(np.ones((1,), "uint64"), device) | ||
| tvm.build(s, [f], target=target)(out_ary) | ||
| return out_ary.asnumpy()[0] == 0 | ||
|
|
||
|
|
||
| def uniform(gen, low, high, out_shape, out_dtype): | ||
| """Draw samples from a uniform distribution. | ||
|
|
||
| Samples are uniformly distributed over the half-open interval [low, high) | ||
| (includes low, but excludes high). In other words, any value within the | ||
| given interval is equally likely to be drawn by uniform. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| gen : ThreefryKey | ||
| Generator state. Can be create with :py:func:`tvm.relay.threefry_key`. This should not be | ||
| reused in another function, otherwise random numbers will be repeated. | ||
|
|
||
| low : Tensor[(), out_dtype] | ||
| Lower boundary of the output interval. All values generated will be | ||
| greater than or equal to low. | ||
|
|
||
| high : Tensor[(), out_dtype] | ||
| Upper boundary of the output interval. All values generated will be | ||
| less than high. | ||
|
|
||
| out_shape : Sequence[int] | ||
| Output shape of the random numbers. Product of all dimensions must be a multiple of 4. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the reason of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the property of the threefry key. Please refer to this comment: #7083 (comment)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I just rethink about this problem. There should not be any restriction to the output shape... We could change the input restriction of the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you mind sending a PR for updating the threefry_generate output, or rather what approach do you have in mind? I tried to avoid this problem by truncating output buffer but this required an extra copy, wonder if you have something else
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @altanh Sorry that I'm not familiar with the threefry algorithm. Is it possible to call out_array = irb.buffer_ptr(out_array_ptr)
# deal with most of the array
_threefry(irb, tmp, 0, tmp, 4, out_array, 0, out_len // 4)
if out_len % 4 != 0:
# generate remainders in a small tmp buffer
tmp_array = irb.allocate(gen.dtype, 4, name="tmp", scope="global")
# may need to update the tmp key in between
# ...
_threefry(irb, tmp, 0, tmp, 4, tmp_array, 0, out_len // 4)
# only copy the tmp buffer
for i in range(out_len // 4 * 4, out_len):
out_array[i] = tmp_array[i%4]In this way, we coud avoid copying the whole generated tensor.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, you could do that. Maybe submit it in a new PR?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tkonolige Sure, I will submit one. Could you tell me what kind of update on key
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You'll need to update the counter buffer to be equal to out_len |
||
|
|
||
| out_dtype : str | ||
| The output dtype. | ||
|
|
||
| Returns | ||
| ------- | ||
| new_gen : ThreefryKey | ||
| New generator state that is distinct from `gen`. | ||
|
|
||
| out : Tensor[out_shape, out_dtype] | ||
| Tensor of random numbers with shape `out_shape` and type `out_dtype`. | ||
| """ | ||
| new_gen, random_bits = threefry_generate(gen, out_shape) | ||
| assert out_dtype in ("float32", "float64"), ( | ||
| "Only support float32 or float64 for now, got %s" % out_dtype | ||
| ) | ||
| if out_dtype == "float32": | ||
| random_dtype = "uint32" | ||
| nbits = 32 | ||
| nfraction = 23 | ||
| elif out_dtype == "float64": | ||
| random_dtype = "uint64" | ||
| nbits = 64 | ||
| nfraction = 52 | ||
| nexp = nbits - nfraction - 1 | ||
| random_bits = random_bits.astype(random_dtype) | ||
|
|
||
zhuzilin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| fraction = tvm.topi.right_shift( | ||
| random_bits, tvm.tir.const(nbits - nfraction, dtype=random_dtype) | ||
| ) | ||
| exponent = tvm.topi.left_shift( | ||
| tvm.topi.full(out_shape, random_dtype, (1 << (nexp - 1)) - 1), | ||
| tvm.tir.const(nfraction, dtype=random_dtype), | ||
| ) | ||
| mantissa = tvm.topi.bitwise_or(fraction, exponent).astype(random_dtype) | ||
| standard_uniform_values = tvm.topi.reinterpret(mantissa, out_dtype) - tvm.tir.const( | ||
| 1, dtype=out_dtype | ||
| ) | ||
| uniform_values = tvm.topi.add(tvm.topi.multiply(standard_uniform_values, high - low), low) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How well does this approach work when we have a large range (high - low)? It seems like we would be loosing a lot of potential randomness. |
||
|
|
||
| return new_gen, uniform_values | ||
Uh oh!
There was an error while loading. Please reload this page.