Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

generasi nomor acak

Lihat di TensorFlow.org Jalankan di Google CoLab Lihat sumber di GitHub notebook Download

TensorFlow menyediakan satu set generator nomor pseudo-acak (RNG), di tf.random modul. Dokumen ini menjelaskan bagaimana Anda dapat mengontrol generator nomor acak, dan bagaimana generator ini berinteraksi dengan sub-sistem tensorflow lainnya.

TensorFlow menyediakan dua pendekatan untuk mengontrol proses nomor generasi acak:

  1. Melalui penggunaan eksplisit tf.random.Generator objek. Setiap objek seperti mempertahankan negara (di tf.Variable ) yang akan berubah setelah setiap generasi nomor.

  2. Melalui fungsi acak stateless murni-fungsional seperti tf.random.stateless_uniform . Memanggil fungsi-fungsi ini dengan argumen yang sama (yang meliputi benih) dan pada perangkat yang sama akan selalu menghasilkan hasil yang sama.

Mempersiapkan

 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()
    ])
 

The tf.random.Generator kelas

The tf.random.Generator kelas digunakan dalam kasus-kasus di mana Anda ingin setiap panggilan RNG untuk menghasilkan hasil yang berbeda. Ini mempertahankan keadaan internal (dikelola oleh tf.Variable objek) yang akan diperbarui setiap kali nomor acak yang dihasilkan. Karena negara dikelola oleh tf.Variable , itu menikmati semua fasilitas yang disediakan oleh tf.Variable seperti checkpointing mudah, otomatis kontrol ketergantungan dan keselamatan benang.

Anda bisa mendapatkan tf.random.Generator dengan menciptakan secara manual sebuah objek dari kelas atau panggilan tf.random.get_global_generator() untuk mendapatkan generator global yang default:

 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)

Ada beberapa cara untuk membuat objek pembangkit. Cara termudah adalah Generator.from_seed , seperti yang ditunjukkan di atas, yang menciptakan generator dari benih. Sebuah benih adalah setiap bilangan bulat non-negatif. from_seed juga membawa argumen opsional alg yang merupakan algoritma RNG yang akan digunakan oleh generator ini:

 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)

Lihat bagian Algoritma bawah untuk informasi lebih lanjut tentang hal itu.

Cara lain untuk membuat generator adalah dengan Generator.from_non_deterministic_state . Sebuah generator dibuat dengan cara ini akan dimulai dari negara non-deterministik, tergantung pada misalnya waktu dan OS.

 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)

Ada cara belum lain untuk membuat generator, seperti dari negara eksplisit, yang tidak tercakup oleh panduan ini.

Bila menggunakan tf.random.get_global_generator untuk mendapatkan generator global, Anda perlu berhati-hati tentang penempatan perangkat. Generator global dibuat (dari negara non-deterministik) pada saat pertama tf.random.get_global_generator disebut, dan ditempatkan pada perangkat default di panggilan itu. Jadi, misalnya, jika situs pertama yang Anda sebut tf.random.get_global_generator adalah dalam tf.device("gpu") lingkup, generator global yang akan ditempatkan pada GPU, dan menggunakan generator global yang kemudian dari CPU akan dikenakan salinan GPU-to-CPU.

Ada juga fungsi tf.random.set_global_generator untuk menggantikan generator global dengan objek pembangkit lain. Fungsi ini harus digunakan dengan hati-hati berpikir, karena generator global yang lama mungkin telah ditangkap oleh tf.function (sebagai referensi lemah), dan menggantikan itu akan menyebabkan hal itu terjadi sampah yang dikumpulkan, melanggar tf.function . Cara yang lebih baik untuk me-reset generator global adalah dengan menggunakan salah satu dari "ulang" fungsi seperti Generator.reset_from_seed , yang tidak akan membuat objek pembangkit baru.

 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)

Membuat nomor acak independen sungai

Dalam banyak aplikasi salah satu kebutuhan beberapa nomor acak independen sungai, independen dalam arti bahwa mereka tidak akan tumpang tindih dan tidak akan memiliki korelasi statistik terdeteksi. Hal ini dicapai dengan menggunakan Generator.split untuk membuat beberapa generator yang dijamin akan independen satu sama lain (yaitu pembangkit aliran independen).

 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 akan mengubah keadaan generator yang disebut ( g dalam contoh di atas), mirip dengan metode Ping seperti normal . Selain menjadi independen satu sama lain, generator baru ( new_gs ) juga dijamin untuk menjadi independen dari yang lama ( g ).

Pemijahan generator baru ini juga berguna bila Anda ingin memastikan generator Anda gunakan adalah pada perangkat yang sama seperti perhitungan lainnya, untuk menghindari overhead copy lintas-perangkat. Sebagai contoh:

 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)

Anda dapat melakukan membelah secara rekursif, menyerukan split pada generator split. Tidak ada batas (pembatasan bilangan bulat overflow) pada kedalaman recursions.

Interaksi dengan tf.function

tf.random.Generator mematuhi aturan yang sama seperti tf.Variable bila digunakan dengan tf.function . Ini mencakup tiga aspek.

Menciptakan generator luar tf.function

tf.function dapat menggunakan generator dibuat di luar itu.

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

kebutuhan pengguna untuk memastikan bahwa objek generator masih hidup (bukan sampah-dikumpulkan) ketika fungsi ini dipanggil.

Menciptakan generator dalam tf.function

Penciptaan generator di dalam tf.function hanya dapat happend selama menjalankan pertama dari fungsi.

 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)

Melewati generator sebagai argumen untuk tf.function

Ketika digunakan sebagai argumen untuk tf.function , pembangkit objek yang berbeda dengan ukuran negara yang sama (ukuran negara ditentukan oleh algoritma RNG) tidak akan menyebabkan menapak dari tf.function , sementara mereka dengan ukuran negara yang berbeda akan.

 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

Interaksi dengan strategi distribusi

Ada tiga cara di mana Generator berinteraksi dengan strategi distribusi.

Menciptakan generator luar strategi distribusi

Jika generator dibuat di luar lingkup strategi, akses semua replika ke generator akan serial, dan karenanya replika akan mendapatkan nomor acak yang berbeda.

 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)

Perhatikan bahwa penggunaan ini mungkin memiliki masalah kinerja karena perangkat generator berbeda dengan replika.

Menciptakan generator dalam strategi distribusi

Menciptakan generator dalam lingkup strategi dianulir, karena ada ambiguitas tentang cara meniru generator (misalnya harus itu disalin sehingga setiap replika mendapat nomor acak yang sama, atau 'perpecahan' sehingga setiap replika mendapat nomor acak yang berbeda).

 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).

Perhatikan bahwa Strategy.run akan menjalankan fungsi argumen dalam lingkup strategi implisit:

 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).

Melewati generator sebagai argumen untuk Strategy.run

Jika Anda ingin setiap replika menggunakan generator sendiri, Anda perlu membuat n generator (baik dengan menyalin atau pemisahan), di mana n adalah jumlah replika, dan kemudian lulus mereka sebagai argumen untuk 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 stateless

Penggunaan RNGs stateless sederhana. Karena mereka hanya fungsi murni, tidak ada negara atau efek samping yang terlibat.

 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)

Setiap stateless RNG membutuhkan seed argumen, yang perlu menjadi integer Tensor bentuk [2] . Hasil op sepenuhnya ditentukan oleh benih ini.

algoritma

Umum

Kedua tf.random.Generator kelas dan stateless fungsi mendukung algoritma Philox (ditulis sebagai "philox" atau tf.random.Algorithm.PHILOX ) pada semua perangkat.

perangkat yang berbeda akan menghasilkan angka integer yang sama, jika menggunakan algoritma yang sama dan mulai dari negara yang sama. Mereka juga akan menghasilkan "hampir sama" angka float-titik, meskipun mungkin ada perbedaan numerik kecil yang disebabkan oleh cara yang berbeda perangkat melaksanakan perhitungan mengapung-titik (misalnya urutan reduksi).

perangkat XLA

Pada perangkat XLA-driven (seperti TPU, dan juga CPU / GPU ketika XLA diaktifkan) algoritma ThreeFry (ditulis sebagai "threefry" atau tf.random.Algorithm.THREEFRY ) juga didukung. Algoritma ini cepat di TPU tapi lambat pada CPU / GPU dibandingkan dengan Philox.

Lihat kertas 'Paralel Nomor Acak: Sebagai Mudah 1, 2, 3' untuk rincian lebih lanjut tentang algoritma ini.