דף זה תורגם על ידי Cloud Translation API.
Switch to English

יצירת מספרים אקראיים

צפה ב TensorFlow.org הפעל ב- Google Colab צפה במקור ב- GitHub הורד מחברת

TensorFlow מספק קבוצה של מחוללי מספרים פסאודו אקראיים (RNG), במודול tf.random . מסמך זה מתאר כיצד ניתן לשלוט במחוללי המספרים האקראיים, וכיצד גנרטורים אלה מתקשרים עם מערכות משנה של זרימת טנסור.

TensorFlow מספק שתי גישות לבקרת תהליך יצירת המספרים האקראיים:

  1. באמצעות שימוש מפורש באובייקטים tf.random.Generator . כל אובייקט כזה שומר על מצב (ב- tf.Variable ) שישתנה לאחר כל דור מספרים.

  2. דרך פונקציות אקראיות tf.random.stateless_uniform פונקציה tf.random.stateless_uniform כמו tf.random.stateless_uniform . קריאה לפונקציות אלה עם אותם ארגומנטים (הכוללים את הזרע) ובאותו מכשיר תניב תמיד את אותן תוצאות.

להכין

 import tensorflow as tf

# Creates 2 virtual devices cpu:0 and cpu:1 for using distribution strategy
physical_devices = tf.config.experimental.list_physical_devices("CPU")
tf.config.experimental.set_virtual_device_configuration(
    physical_devices[0], [
        tf.config.experimental.VirtualDeviceConfiguration(),
        tf.config.experimental.VirtualDeviceConfiguration()
    ])
 

שיעור tf.random.Generator

מחלקת tf.random.Generator משמשת במקרים בהם אתה רוצה שכל שיחת RNG tf.random.Generator תוצאות שונות. הוא שומר על מצב פנימי (מנוהל על ידי אובייקט tf.Variable ) אשר יתעדכן בכל פעם שנוצרים מספרים אקראיים. מכיוון שהמדינה מנוהלת על ידי tf.Variable , היא נהנית מכל המתקנים המסופקים על ידי tf.Variable כגון tf.Variable בדיקה קלה, תלות בקרה אוטומטית ובטיחות חוט.

אתה יכול להשיג tf.random.Generator ידי יצירת ידנית של אובייקט מהמחלקה או להתקשר tf.random.get_global_generator() כדי לקבל את הגנרטור הגלובלי המוגדר כברירת מחדל:

 g1 = tf.random.Generator.from_seed(1)
print(g1.normal(shape=[2, 3]))
g2 = tf.random.get_global_generator()
print(g2.normal(shape=[2, 3]))
 
tf.Tensor(
[[ 0.43842274 -0.53439844 -0.07710262]
 [ 1.5658046  -0.1012345  -0.2744976 ]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[-0.6078218  3.162639  -1.0558378]
 [ 1.2078347  0.6414574  0.4019502]], shape=(2, 3), dtype=float32)

ישנן מספר דרכים ליצור אובייקט גנרטור. הקלה ביותר היא Generator.from_seed , כמוצג לעיל, שיוצר גנרטור מזרע. זרע הוא כל מספר שלם לא שלילי. from_seed לוקח גם from_seed טיעון alg שהוא האלגוריתם של RNG שישמש את הגנרטור הזה:

 g1 = tf.random.Generator.from_seed(1, alg='philox')
print(g1.normal(shape=[2, 3]))
 
tf.Tensor(
[[ 0.43842274 -0.53439844 -0.07710262]
 [ 1.5658046  -0.1012345  -0.2744976 ]], shape=(2, 3), dtype=float32)

עיין בסעיף האלגוריתמים למטה למידע נוסף עליו.

דרך נוספת ליצור גנרטור היא באמצעות Generator.from_non_deterministic_state . גנרטור שנוצר בדרך זו יתחיל ממצב לא דטרמיניסטי, תלוי למשל בזמן ובמערכת ההפעלה.

 g = tf.random.Generator.from_non_deterministic_state()
print(g.normal(shape=[2, 3]))
 
tf.Tensor(
[[ 1.1436943  1.729618   1.0391121]
 [-0.8502223 -1.8823647 -1.4051851]], shape=(2, 3), dtype=float32)

ישנן דרכים נוספות ליצור גנרטורים, למשל ממצבים מפורשים, שאינם מכוסים במדריך זה.

כשאתה משתמש tf.random.get_global_generator כדי להשיג את הגנרטור הגלובלי, עליך להיות זהיר לגבי מיקום המכשיר. הגנרטור הגלובלי נוצר (ממצב לא דטרמיניסטי) בפעם הראשונה נקרא tf.random.get_global_generator ומונח על מכשיר ברירת המחדל באותה שיחה. כך, למשל, אם האתר הראשון שאתה קורא לו tf.random.get_global_generator נמצא בתחום tf.device("gpu") , הגנרטור הגלובלי יונח על ה- GPU, ושימוש בגנרטור הגלובלי בהמשך מה- CPU לכלול עותק של GPU למעבד.

יש גם פונקציה tf.random.set_global_generator להחלפת הגנרטור הגלובלי באובייקט גנרטור אחר. יש להשתמש בפונקציה זו מתוך מחשבה בזהירות, מכיוון שאולי הגנרטור הגלובלי הישן נתפס על ידי פונקציה tf.function ( tf.function חלשה), והחלפתו תגרום לאיסוף האשפה tf.function את tf.function ה- tf.function . דרך טובה יותר לאפס את הגנרטור הגלובלי היא להשתמש באחת מהפונקציות "איפוס" כגון Generator.reset_from_seed , שלא תיצור אובייקטים חדשים של גנרטור.

 g = tf.random.Generator.from_seed(1)
print(g.normal([]))
print(g.normal([]))
g.reset_from_seed(1)
print(g.normal([]))
 
tf.Tensor(0.43842274, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)
tf.Tensor(0.43842274, shape=(), dtype=float32)

יצירת זרמים מספרים אקראיים עצמאיים

ביישומים רבים יש צורך בזרמים מרובים של מספרים אקראיים בלתי תלויים, בלתי תלויים במובן זה שהם לא יחפפו ולא יהיו להם שום קשרים סטטיסטיים הניתנים לגילוי. זה מושג על ידי שימוש ב- Generator.split ליצירת גנרטורים מרובים שמובטחים להיות בלתי תלויים זה בזה (כלומר, יצירת זרמים עצמאיים).

 g = tf.random.Generator.from_seed(1)
print(g.normal([]))
new_gs = g.split(3)
for new_g in new_gs:
  print(new_g.normal([]))
print(g.normal([]))
 
tf.Tensor(0.43842274, shape=(), dtype=float32)
tf.Tensor(2.536413, shape=(), dtype=float32)
tf.Tensor(0.33186463, shape=(), dtype=float32)
tf.Tensor(-0.07144657, shape=(), dtype=float32)
tf.Tensor(-0.79253083, shape=(), dtype=float32)

split ישנה את מצב הגנרטור עליו הוא נקרא ( g בדוגמה לעיל), בדומה לשיטת RNG כמו normal . בנוסף להיותם בלתי תלויים זה בזה, מובטחים גם שהגנרטורים החדשים ( new_gs ) יהיו בלתי תלויים ביניהם ( g ).

הפעלת גנרטורים חדשים מועילה גם כאשר ברצונך לוודא שהגנרטור בו אתה משתמש נמצא באותו מכשיר כמו חישובים אחרים, כדי למנוע את התקורה של העתקה בין מכשירים. לדוגמה:

 with tf.device("cpu"):  # change "cpu" to the device you want
  g = tf.random.get_global_generator().split(1)[0]  
  print(g.normal([]))  # use of g won't cause cross-device copy, unlike the global generator
 
tf.Tensor(-1.7580209, shape=(), dtype=float32)

אתה יכול לעשות פיצול רקורסיבי, לקרוא split על גנרטורים מפוצלים. אין גבולות (חסימת הצפת מספרים שלמים) בעומק החזרתיות.

אינטראקציה עם tf.function

tf.random.Generator מציית לאותם כללים כמו tf.Variable בעת שימוש tf.function . זה כולל שלושה היבטים.

יצירת גנרטורים מחוץ tf.function

tf.function יכול להשתמש בגנרטור שנוצר מחוצה לו.

 g = tf.random.Generator.from_seed(1)
@tf.function
def foo():
  return g.normal([])
print(foo())
 
tf.Tensor(0.43842274, shape=(), dtype=float32)

המשתמש צריך לוודא שאובייקט הגנרטור עדיין חי (לא נאסף זבל) כאשר נקראת הפונקציה.

יצירת גנרטורים בתוך tf.function

יצירת גנרטורים בתוך פונקציה tf.function יכולה רק tf.function במהלך tf.function הראשונה של הפונקציה.

 g = None
@tf.function
def foo():
  global g
  if g is None:
    g = tf.random.Generator.from_seed(1)
  return g.normal([])
print(foo())
print(foo())
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
tf.Tensor(0.43842274, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)

העברת גנרטורים כטיעונים tf.function

כשמשתמשים כטיעון tf.function , אובייקטים של גנרטור שונים בעלי גודל מצב זהה (גודל מצב נקבע על ידי אלגוריתם RNG) לא יגרום tf.function של tf.function , בעוד שאלו עם גודל מצב שונה.

 num_traces = 0
@tf.function
def foo(g):
  global num_traces
  num_traces += 1
  return g.normal([])
foo(tf.random.Generator.from_seed(1))
foo(tf.random.Generator.from_seed(2))
print(num_traces)
 
1

אינטראקציה עם אסטרטגיות הפצה

ישנן שלוש דרכים בהן Generator מקיים אינטראקציה עם אסטרטגיות הפצה.

יצירת גנרטורים מחוץ לאסטרטגיות הפצה

אם נוצר גנרטור מחוץ לטווחי אסטרטגיה, הגישה של כל העותקים המשוכפלים לגנרטור תועבר בהמשכים, ומכאן שהעתקים משוכפלים יקבלו מספרים אקראיים שונים.

 g = tf.random.Generator.from_seed(1)
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
  def f():
    print(g.normal([]))
  results = strat.run(f)
 
WARNING:tensorflow:There are non-GPU devices in `tf.distribute.Strategy`, not using nccl allreduce.
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
tf.Tensor(0.43842274, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)

שים לב שלשימוש זה עשויים להיות בעיות ביצועים מכיוון שהתקן של הגנרטור שונה מהעתיקות.

יצירת גנרטורים בתוך אסטרטגיות הפצה

יצירת גנרטורים בתוך טווחי אסטרטגיה אינה מותרת, מכיוון שיש אי בהירות כיצד לשכפל גנרטור (למשל, יש להעתיק אותו כך שכל העתק יקבל אותם מספרים אקראיים, או 'פיצול' כך שכל העתק יקבל מספרים אקראיים שונים).

 strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
  try:
    tf.random.Generator.from_seed(1)
  except ValueError as e:
    print("ValueError:", e)
 
WARNING:tensorflow:There are non-GPU devices in `tf.distribute.Strategy`, not using nccl allreduce.
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
ValueError: Creating a generator within a strategy scope is disallowed, because there is ambiguity on how to replicate a generator (e.g. should it be copied so that each replica gets the same random numbers, or 'split' so that each replica gets different random numbers).

שים לב כי Strategy.run תנהל את פונקציית הטיעון שלה באופן אסטרטגי באופן משתמע:

 strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
def f():
  tf.random.Generator.from_seed(1)
try:
  strat.run(f)
except ValueError as e:
  print("ValueError:", e)
 
WARNING:tensorflow:There are non-GPU devices in `tf.distribute.Strategy`, not using nccl allreduce.
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
INFO:tensorflow:Error reported to Coordinator: Creating a generator within a strategy scope is disallowed, because there is ambiguity on how to replicate a generator (e.g. should it be copied so that each replica gets the same random numbers, or 'split' so that each replica gets different random numbers).
Traceback (most recent call last):
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/coordinator.py", line 297, in stop_on_exception
    yield
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/distribute/mirrored_strategy.py", line 998, in run
    self.main_result = self.main_fn(*self.main_args, **self.main_kwargs)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py", line 282, in wrapper
    return func(*args, **kwargs)
  File "<ipython-input-14-2cd7806456bd>", line 3, in f
    tf.random.Generator.from_seed(1)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/stateful_random_ops.py", line 444, in from_seed
    return cls(state=state, alg=alg)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/stateful_random_ops.py", line 386, in __init__
    trainable=False)
  File "/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/stateful_random_ops.py", line 272, in _create_variable
    "Creating a generator within a strategy scope is disallowed, because "
ValueError: Creating a generator within a strategy scope is disallowed, because there is ambiguity on how to replicate a generator (e.g. should it be copied so that each replica gets the same random numbers, or 'split' so that each replica gets different random numbers).
ValueError: Creating a generator within a strategy scope is disallowed, because there is ambiguity on how to replicate a generator (e.g. should it be copied so that each replica gets the same random numbers, or 'split' so that each replica gets different random numbers).

העברת גנרטורים כוויכוחים ל- Strategy.run

אם אתה רוצה שכל העתק ישתמש בגנרטור משלו, עליך ליצור n גנרטורים (באמצעות העתקה או פיצול), כאשר n הוא מספר העותקים המשוכפלים, ואז להעביר אותם כטיעונים ל- Strategy.run .

 strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
gs = tf.random.get_global_generator().split(2)
# to_args is a workaround for the absence of APIs to create arguments for 
# run. It will be replaced when such APIs are available.
def to_args(gs):  
  with strat.scope():
    def f():
      return [gs[tf.distribute.get_replica_context().replica_id_in_sync_group]]
    return strat.run(f)
args = to_args(gs)
def f(g):
  print(g.normal([]))
results = strat.run(f, args=args)
 
WARNING:tensorflow:There are non-GPU devices in `tf.distribute.Strategy`, not using nccl allreduce.
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
tf.Tensor(-0.15682742, shape=(), dtype=float32)
tf.Tensor(-0.38042808, shape=(), dtype=float32)

RNGs חסרי מדינה

השימוש ברמת RNG נטולי מדינה הוא פשוט. מכיוון שמדובר בפונקציות טהורות בלבד, אין שום תופעה לוואי או תופעת לוואי.

 print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))
print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))
 
tf.Tensor(
[[ 0.5441101   0.20738031  0.07356433]
 [ 0.04643455 -1.3015898  -0.95385665]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[ 0.5441101   0.20738031  0.07356433]
 [ 0.04643455 -1.3015898  -0.95385665]], shape=(2, 3), dtype=float32)

כל RNG נטול מדינות דורש טיעון seed , שצריך להיות טנסור שלם של צורה [2] . תוצאות ה- OP נקבעות במלואן על ידי זרע זה.

אלגוריתמים

כללי

הוא tf.random.Generator בכיתה ואת stateless פונקציות תומכות אלגוריתם Philox (כפי שנכתב "philox" או tf.random.Algorithm.PHILOX ) על כל המכשירים.

מכשירים שונים יפיקו את אותם מספרים שלמים, אם משתמשים באותו אלגוריתם ומתחילים מאותו מצב. הם גם ייצרו "כמעט אותו הדבר" מספרים של נקודת הציפה, אם כי יתכנו פערים מספריים קטנים הנגרמים מהדרכים השונות בהן מכשירים מבצעים את חישוב נקודת הציפה (למשל, סדר הפחתה).

מכשירי XLA

במכשירים מונעי XLA (כגון TPU, וגם מעבד / GPU כש- XLA מופעל) תומך גם באלגוריתם ThreeFry (שנכתב כ- "threefry" או tf.random.Algorithm.THREEFRY ). אלגוריתם זה מהיר ב- TPU אך איטי ב- CPU / GPU לעומת Philox.

עיין במאמר 'מספרים אקראיים מקבילים: קל כמו 1, 2, 3' לפרטים נוספים על אלגוריתמים אלה.