Skip to content

Commit 6f9a086

Browse files
ratgrtensorflower-gardener
authored andcommitted
This change updates the random number generation utility to use tf.uint64 for bitwise operations and constants. The seed generation function (next_seed_fn) has been rewritten to implement a proper 7-bit LFSR (PRBS7) using bitwise operations, replacing the previous power-based approximation.
PiperOrigin-RevId: 915708863
1 parent 73055fc commit 6f9a086

1 file changed

Lines changed: 36 additions & 11 deletions

File tree

  • tensorflow_model_optimization/python/core/internal/tensor_encoding/utils

tensorflow_model_optimization/python/core/internal/tensor_encoding/utils/tf_utils.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,33 +153,57 @@ def _cmwc_random_sequence(num_elements, seed):
153153

154154
# Create constants needed for the algorithm. The constants and notation
155155
# follows from the above reference.
156-
a = tf.tile(tf.constant([3636507990], tf.int64), [parallelism])
157-
b = tf.tile(tf.constant([2**32], tf.int64), [parallelism])
158-
logb_scalar = tf.constant(32, tf.int64)
156+
a = tf.tile(tf.constant([3636507990], tf.uint64), [parallelism])
157+
b = tf.tile(tf.constant([2**32], tf.uint64), [parallelism])
158+
logb_scalar = tf.constant(32, tf.uint64)
159159
logb = tf.tile([logb_scalar], [parallelism])
160-
f = tf.tile(tf.constant([0], dtype=tf.int64), [parallelism])
161-
bits = tf.constant(0, dtype=tf.int64, name='bits')
160+
f = tf.tile(tf.constant([0], dtype=tf.uint64), [parallelism])
161+
bits = tf.constant(0, dtype=tf.uint64, name='bits')
162162

163163
# TensorArray used in tf.while_loop for efficiency.
164164
values = tf.TensorArray(
165165
dtype=tf.float64, size=num_iters, element_shape=[parallelism])
166166
# Iteration counter.
167167
num = tf.constant(0, dtype=tf.int32, name='num')
168168
# TensorFlow constant to be used at multiple places.
169-
val_53 = tf.constant(53, tf.int64, name='val_53')
169+
val_53 = tf.constant(53, tf.uint64, name='val_53')
170170

171171
# Construct initial sequence of seeds.
172172
# From a single input seed, we construct multiple starting seeds for the
173173
# sequences to be computed in parallel.
174174
def next_seed_fn(i, val, q):
175-
val = val**7 + val**6 + 1 # PRBS7.
175+
# Proper 7-bit LFSR (Fibonacci) for polynomial x^7 + x^6 + 1.
176+
# We take lower 7 bits of val as state.
177+
state = tf.bitwise.bitwise_and(val, tf.constant(0x7F, tf.uint64))
178+
# Avoid zero state which gets stuck in LFSR.
179+
state = tf.bitwise.bitwise_or(
180+
state,
181+
tf.cast(tf.equal(state, tf.constant(0, tf.uint64)), tf.uint64)
182+
)
183+
# Feedback bit = bit 7 (index 6) ^ bit 6 (index 5)
184+
feedback = tf.bitwise.bitwise_and(
185+
tf.bitwise.bitwise_xor(
186+
tf.bitwise.right_shift(state, tf.constant(6, tf.uint64)),
187+
tf.bitwise.right_shift(state, tf.constant(5, tf.uint64))
188+
),
189+
tf.constant(1, tf.uint64)
190+
)
191+
# Shift left and insert feedback
192+
val = tf.bitwise.bitwise_and(
193+
tf.bitwise.bitwise_or(
194+
tf.bitwise.left_shift(state, tf.constant(1, tf.uint64)),
195+
feedback
196+
),
197+
tf.constant(0x7F, tf.uint64)
198+
)
176199
q = q.write(i, val)
177200
return i + 1, val, q
178201

179-
q = tf.TensorArray(dtype=tf.int64, size=parallelism, element_shape=())
202+
q = tf.TensorArray(dtype=tf.uint64, size=parallelism, element_shape=())
203+
seed_u64 = tf.cast(seed, tf.uint64)
180204
_, _, q = tf.while_loop(lambda i, _, __: i < parallelism,
181205
next_seed_fn,
182-
[tf.constant(0), seed, q])
206+
[tf.constant(0), seed_u64, q])
183207
c = q = q.stack()
184208

185209
# The random sequence generation code.
@@ -193,9 +217,10 @@ def cmwc_step(f, bits, q, c, num, values):
193217
f.set_shape((1,)) # Correct for failed shape inference.
194218
bits += logb_scalar
195219
def add_val(bits, f, values, num):
220+
mask_53 = tf.constant(2**53 - 1, tf.uint64)
196221
new_val = tf.cast(
197-
tf.bitwise.bitwise_and(f, (2**val_53 - 1)),
198-
dtype=tf.float64) * (1 / 2**val_53)
222+
tf.bitwise.bitwise_and(f, mask_53),
223+
dtype=tf.float64) * (1.0 / 2.0**53)
199224
values = values.write(num, new_val)
200225
f += tf.bitwise.right_shift(f, val_53)
201226
bits -= val_53

0 commit comments

Comments
 (0)