Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/framework/random_seed.py: 41%
44 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
16"""For seeding individual ops based on a graph-level seed.
17"""
19import weakref
21from tensorflow.python.eager import context
22from tensorflow.python.framework import config
23from tensorflow.python.framework import ops
24from tensorflow.python.util import deprecation
25from tensorflow.python.util.tf_export import tf_export
28DEFAULT_GRAPH_SEED = 87654321
29_MAXINT32 = 2**31 - 1
31_graph_to_seed_dict = weakref.WeakKeyDictionary()
34def _truncate_seed(seed):
35 return seed % _MAXINT32 # Truncate to fit into 32-bit integer
38@tf_export(v1=['random.get_seed', 'get_seed'])
39@deprecation.deprecated_endpoints('get_seed')
40def get_seed(op_seed):
41 """Returns the local seeds an operation should use given an op-specific seed.
43 Given operation-specific seed, `op_seed`, this helper function returns two
44 seeds derived from graph-level and op-level seeds. Many random operations
45 internally use the two seeds to allow user to change the seed globally for a
46 graph, or for only specific operations.
48 For details on how the graph-level seed interacts with op seeds, see
49 `tf.compat.v1.random.set_random_seed`.
51 Args:
52 op_seed: integer.
54 Returns:
55 A tuple of two integers that should be used for the local seed of this
56 operation.
57 """
58 eager = context.executing_eagerly()
60 if eager:
61 global_seed = context.global_seed()
62 else:
63 global_seed = ops.get_default_graph().seed
65 if global_seed is not None:
66 if op_seed is None:
67 # pylint: disable=protected-access
68 if hasattr(ops.get_default_graph(), '_seed_used'):
69 ops.get_default_graph()._seed_used = True
70 if eager:
71 op_seed = context.internal_operation_seed()
72 else:
73 op_seed = _graph_to_seed_dict.setdefault(ops.get_default_graph(), 0)
74 _graph_to_seed_dict[ops.get_default_graph()] += 1
76 seeds = _truncate_seed(global_seed), _truncate_seed(op_seed)
77 else:
78 if op_seed is not None:
79 seeds = DEFAULT_GRAPH_SEED, _truncate_seed(op_seed)
80 else:
81 seeds = None, None
83 if seeds == (None, None) and config.is_op_determinism_enabled():
84 raise RuntimeError( # pylint: disable=g-doc-exception
85 'Random ops require a seed to be set when determinism is enabled. '
86 'Please set a seed before running the op, e.g. by calling '
87 'tf.random.set_seed(1).')
89 # Avoid (0, 0) as the C++ ops interpret it as nondeterminism, which would
90 # be unexpected since Python docs say nondeterminism is (None, None).
91 if seeds == (0, 0):
92 return (0, _MAXINT32)
93 return seeds
96@tf_export(v1=['random.set_random_seed', 'set_random_seed'])
97def set_random_seed(seed):
98 """Sets the graph-level random seed for the default graph.
100 Operations that rely on a random seed actually derive it from two seeds:
101 the graph-level and operation-level seeds. This sets the graph-level seed.
103 Its interactions with operation-level seeds is as follows:
105 1. If neither the graph-level nor the operation seed is set:
106 A random seed is used for this op.
107 2. If the graph-level seed is set, but the operation seed is not:
108 The system deterministically picks an operation seed in conjunction with
109 the graph-level seed so that it gets a unique random sequence. Within the
110 same version of tensorflow and user code, this sequence is deterministic.
111 However across different versions, this sequence might change. If the
112 code depends on particular seeds to work, specify both graph-level
113 and operation-level seeds explicitly.
114 3. If the graph-level seed is not set, but the operation seed is set:
115 A default graph-level seed and the specified operation seed are used to
116 determine the random sequence.
117 4. If both the graph-level and the operation seed are set:
118 Both seeds are used in conjunction to determine the random sequence.
120 To illustrate the user-visible effects, consider these examples:
122 To generate different sequences across sessions, set neither
123 graph-level nor op-level seeds:
125 ```python
126 a = tf.random.uniform([1])
127 b = tf.random.normal([1])
129 print("Session 1")
130 with tf.compat.v1.Session() as sess1:
131 print(sess1.run(a)) # generates 'A1'
132 print(sess1.run(a)) # generates 'A2'
133 print(sess1.run(b)) # generates 'B1'
134 print(sess1.run(b)) # generates 'B2'
136 print("Session 2")
137 with tf.compat.v1.Session() as sess2:
138 print(sess2.run(a)) # generates 'A3'
139 print(sess2.run(a)) # generates 'A4'
140 print(sess2.run(b)) # generates 'B3'
141 print(sess2.run(b)) # generates 'B4'
142 ```
144 To generate the same repeatable sequence for an op across sessions, set the
145 seed for the op:
147 ```python
148 a = tf.random.uniform([1], seed=1)
149 b = tf.random.normal([1])
151 # Repeatedly running this block with the same graph will generate the same
152 # sequence of values for 'a', but different sequences of values for 'b'.
153 print("Session 1")
154 with tf.compat.v1.Session() as sess1:
155 print(sess1.run(a)) # generates 'A1'
156 print(sess1.run(a)) # generates 'A2'
157 print(sess1.run(b)) # generates 'B1'
158 print(sess1.run(b)) # generates 'B2'
160 print("Session 2")
161 with tf.compat.v1.Session() as sess2:
162 print(sess2.run(a)) # generates 'A1'
163 print(sess2.run(a)) # generates 'A2'
164 print(sess2.run(b)) # generates 'B3'
165 print(sess2.run(b)) # generates 'B4'
166 ```
168 To make the random sequences generated by all ops be repeatable across
169 sessions, set a graph-level seed:
171 ```python
172 tf.compat.v1.random.set_random_seed(1234)
173 a = tf.random.uniform([1])
174 b = tf.random.normal([1])
176 # Repeatedly running this block with the same graph will generate the same
177 # sequences of 'a' and 'b'.
178 print("Session 1")
179 with tf.compat.v1.Session() as sess1:
180 print(sess1.run(a)) # generates 'A1'
181 print(sess1.run(a)) # generates 'A2'
182 print(sess1.run(b)) # generates 'B1'
183 print(sess1.run(b)) # generates 'B2'
185 print("Session 2")
186 with tf.compat.v1.Session() as sess2:
187 print(sess2.run(a)) # generates 'A1'
188 print(sess2.run(a)) # generates 'A2'
189 print(sess2.run(b)) # generates 'B1'
190 print(sess2.run(b)) # generates 'B2'
191 ```
193 @compatibility(TF2)
194 'tf.compat.v1.set_random_seed' is compatible with eager mode. However,
195 in eager mode this API will set the global seed instead of the
196 graph-level seed of the default graph. In TF2 this API is changed to
197 [tf.random.set_seed]
198 (https://www.tensorflow.org/api_docs/python/tf/random/set_seed).
199 @end_compatibility
201 Args:
202 seed: integer.
203 """
204 if context.executing_eagerly():
205 context.set_global_seed(seed)
206 else:
207 ops.get_default_graph().seed = seed
210@tf_export('random.set_seed', v1=[])
211def set_seed(seed):
212 """Sets the global random seed.
214 Operations that rely on a random seed actually derive it from two seeds:
215 the global and operation-level seeds. This sets the global seed.
217 Its interactions with operation-level seeds is as follows:
219 1. If neither the global seed nor the operation seed is set: A randomly
220 picked seed is used for this op.
221 2. If the global seed is set, but the operation seed is not:
222 The system deterministically picks an operation seed in conjunction with
223 the global seed so that it gets a unique random sequence. Within the
224 same version of tensorflow and user code, this sequence is deterministic.
225 However across different versions, this sequence might change. If the
226 code depends on particular seeds to work, specify both global
227 and operation-level seeds explicitly.
228 3. If the operation seed is set, but the global seed is not set:
229 A default global seed and the specified operation seed are used to
230 determine the random sequence.
231 4. If both the global and the operation seed are set:
232 Both seeds are used in conjunction to determine the random sequence.
234 To illustrate the user-visible effects, consider these examples:
236 If neither the global seed nor the operation seed is set, we get different
237 results for every call to the random op and every re-run of the program:
239 ```python
240 print(tf.random.uniform([1])) # generates 'A1'
241 print(tf.random.uniform([1])) # generates 'A2'
242 ```
244 (now close the program and run it again)
246 ```python
247 print(tf.random.uniform([1])) # generates 'A3'
248 print(tf.random.uniform([1])) # generates 'A4'
249 ```
251 If the global seed is set but the operation seed is not set, we get different
252 results for every call to the random op, but the same sequence for every
253 re-run of the program:
255 ```python
256 tf.random.set_seed(1234)
257 print(tf.random.uniform([1])) # generates 'A1'
258 print(tf.random.uniform([1])) # generates 'A2'
259 ```
261 (now close the program and run it again)
263 ```python
264 tf.random.set_seed(1234)
265 print(tf.random.uniform([1])) # generates 'A1'
266 print(tf.random.uniform([1])) # generates 'A2'
267 ```
269 The reason we get 'A2' instead 'A1' on the second call of `tf.random.uniform`
270 above is because the second call uses a different operation seed.
272 Note that `tf.function` acts like a re-run of a program in this case. When
273 the global seed is set but operation seeds are not set, the sequence of random
274 numbers are the same for each `tf.function`. For example:
276 ```python
277 tf.random.set_seed(1234)
279 @tf.function
280 def f():
281 a = tf.random.uniform([1])
282 b = tf.random.uniform([1])
283 return a, b
285 @tf.function
286 def g():
287 a = tf.random.uniform([1])
288 b = tf.random.uniform([1])
289 return a, b
291 print(f()) # prints '(A1, A2)'
292 print(g()) # prints '(A1, A2)'
293 ```
295 If the operation seed is set, we get different results for every call to the
296 random op, but the same sequence for every re-run of the program:
298 ```python
299 print(tf.random.uniform([1], seed=1)) # generates 'A1'
300 print(tf.random.uniform([1], seed=1)) # generates 'A2'
301 ```
303 (now close the program and run it again)
305 ```python
306 print(tf.random.uniform([1], seed=1)) # generates 'A1'
307 print(tf.random.uniform([1], seed=1)) # generates 'A2'
308 ```
310 The reason we get 'A2' instead 'A1' on the second call of `tf.random.uniform`
311 above is because the same `tf.random.uniform` kernel (i.e. internal
312 representation) is used by TensorFlow for all calls of it with the same
313 arguments, and the kernel maintains an internal counter which is incremented
314 every time it is executed, generating different results.
316 Calling `tf.random.set_seed` will reset any such counters:
318 ```python
319 tf.random.set_seed(1234)
320 print(tf.random.uniform([1], seed=1)) # generates 'A1'
321 print(tf.random.uniform([1], seed=1)) # generates 'A2'
322 tf.random.set_seed(1234)
323 print(tf.random.uniform([1], seed=1)) # generates 'A1'
324 print(tf.random.uniform([1], seed=1)) # generates 'A2'
325 ```
327 When multiple identical random ops are wrapped in a `tf.function`, their
328 behaviors change because the ops no long share the same counter. For example:
330 ```python
331 @tf.function
332 def foo():
333 a = tf.random.uniform([1], seed=1)
334 b = tf.random.uniform([1], seed=1)
335 return a, b
336 print(foo()) # prints '(A1, A1)'
337 print(foo()) # prints '(A2, A2)'
339 @tf.function
340 def bar():
341 a = tf.random.uniform([1])
342 b = tf.random.uniform([1])
343 return a, b
344 print(bar()) # prints '(A1, A2)'
345 print(bar()) # prints '(A3, A4)'
346 ```
348 The second call of `foo` returns '(A2, A2)' instead of '(A1, A1)' because
349 `tf.random.uniform` maintains an internal counter. If you want `foo` to return
350 '(A1, A1)' every time, use the stateless random ops such as
351 `tf.random.stateless_uniform`. Also see `tf.random.experimental.Generator` for
352 a new set of stateful random ops that use external variables to manage their
353 states.
355 Args:
356 seed: integer.
357 """
358 set_random_seed(seed)