หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

การสร้างตัวเลขสุ่ม

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดสมุดบันทึก

TensorFlow จัดเตรียมชุดของตัวสร้างตัวเลขสุ่ม (RNG) ในโมดูล tf.random เอกสารนี้อธิบายถึงวิธีการที่คุณสามารถควบคุมเครื่องกำเนิดเลขสุ่มและวิธีที่เครื่องกำเนิดไฟฟ้าเหล่านี้โต้ตอบกับระบบย่อย tenorflow อื่น ๆ

TensorFlow มีสองวิธีในการควบคุมกระบวนการสร้างหมายเลขสุ่ม:

  1. ผ่านการใช้งานอย่างชัดเจนของวัตถุ tf.random.Generator แต่ละวัตถุดังกล่าวรักษาสถานะ (ใน tf.Variable ) ที่จะเปลี่ยนไปหลังจากการสร้างหมายเลขแต่ละ

  2. ผ่านฟังก์ชั่นการสุ่มไร้สัญชาติที่ทำงานได้อย่างหมดจดเช่น 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.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 ยังใช้อาร์กิวเมนต์ 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-to-CPU

นอกจากนี้ยังมีฟังก์ชัน tf.random.set_global_generator เพื่อแทนที่ตัวสร้างส่วนกลางด้วยวัตถุตัวสร้างอื่น ฟังก์ชั่นนี้ควรใช้ด้วยความระมัดระวังคิดเพราะกำเนิดโลกเก่าอาจจะได้รับการบันทึกโดย 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 สามารถเกิดขึ้นได้เฉพาะในช่วงแรกของการทำงาน

 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

การใช้ RNGs ไร้สัญชาตินั้นง่าย เนื่องจากเป็นเพียงฟังก์ชั่นที่บริสุทธิ์ไม่มีรัฐหรือผลข้างเคียงที่เกี่ยวข้อง

 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 และ CPU / GPU เมื่อเปิดใช้งาน XLA) อัลกอริทึม ThreeFry (เขียนเป็น "threefry" หรือ tf.random.Algorithm.THREEFRY ) ก็รองรับเช่นกัน อัลกอริทึมนี้เร็วสำหรับ TPU แต่ใช้ CPU / GPU ช้ากว่า Philox

ดูรายละเอียดเพิ่มเติมเกี่ยวกับอัลกอริธึมเหล่านี้ได้ที่ 'หมายเลขสุ่มแบบขนาน: ง่ายเหมือน 1, 2, 3'