عرض على TensorFlow.org | تشغيل في Google Colab | عرض المصدر على جيثب | تحميل دفتر |
يوفر TensorFlow مجموعة من مولدات الأرقام العشوائية الزائفة (RNG) ، في وحدة tf.random
. يصف هذا المستند كيف يمكنك التحكم في مولدات الأرقام العشوائية ، وكيف تتفاعل هذه المولدات مع أنظمة tensorflow الفرعية الأخرى.
يوفر TensorFlow طريقتين للتحكم في عملية توليد الأرقام العشوائية:
من خلال الاستخدام الصريح للكائنات
tf.random.Generator
. يحتفظ كل كائن بحالة (فيtf.Variable
) والتي سيتم تغييرها بعد كل إنشاء رقم.من خلال وظائف عشوائية عديمة الحالة وظيفية بحتة مثل
tf.random.stateless_uniform
. سيؤدي استدعاء هذه الوظائف باستخدام نفس الوسيطات (التي تشمل البداية) وعلى نفس الجهاز دائمًا إلى الحصول على نفس النتائج.
يثبت
import tensorflow as tf
# Creates some virtual devices (cpu:0, cpu:1, etc.) for using distribution strategy
physical_devices = tf.config.list_physical_devices("CPU")
tf.config.experimental.set_virtual_device_configuration(
physical_devices[0], [
tf.config.experimental.VirtualDeviceConfiguration(),
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.43842277 -0.53439844 -0.07710262] [ 1.5658046 -0.1012345 -0.2744976 ]], shape=(2, 3), dtype=float32) tf.Tensor( [[-0.5496427 0.24263908 -1.1436267 ] [ 1.861458 -0.6756685 -0.9900103 ]], shape=(2, 3), dtype=float32)
هناك عدة طرق لإنشاء كائن منشئ. الأسهل هو Generator.from_seed
، كما هو موضح أعلاه ، الذي ينشئ مولدًا من بذرة. البذرة هي أي عدد صحيح غير سالب. تأخذ from_seed
أيضًا الوسيطة الاختيارية وهي خوارزمية alg
التي سيتم استخدامها بواسطة هذا المولد:
g1 = tf.random.Generator.from_seed(1, alg='philox')
print(g1.normal(shape=[2, 3]))
tf.Tensor( [[ 0.43842277 -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( [[-0.9078738 0.11009752 1.037219 ] [ 0.661036 0.4169741 1.4539026 ]], shape=(2, 3), dtype=float32)
لا تزال هناك طرق أخرى لإنشاء المولدات ، مثل الحالات الصريحة ، والتي لا يغطيها هذا الدليل.
عند استخدام tf.random.get_global_generator
للحصول على المولد العالمي ، يجب أن تكون حذرًا بشأن وضع الجهاز. يتم إنشاء المولد العام (من حالة غير حتمية) في المرة الأولى التي يتم فيها استدعاء tf.random.get_global_generator
، ووضعه على الجهاز الافتراضي عند تلك المكالمة. لذلك ، على سبيل المثال ، إذا كان الموقع الأول الذي تتصل tf.random.get_global_generator
ضمن نطاق tf.device("gpu")
، فسيتم وضع المولد العام على وحدة معالجة الرسومات ، واستخدام المولد العام لاحقًا من وحدة المعالجة المركزية تحمل نسخة 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.43842277, shape=(), dtype=float32) tf.Tensor(1.6272374, shape=(), dtype=float32) tf.Tensor(0.43842277, 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.43842277, 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(0.4142675, 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.43842277, 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())
tf.Tensor(0.43842277, shape=(), dtype=float32) tf.Tensor(1.6272374, shape=(), dtype=float32)
تمرير المولدات tf.function
عند استخدامها كوسيطة 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)
2
لاحظ أن سلوك التصحيح هذا يتوافق مع tf.Variable
:
num_traces = 0
@tf.function
def foo(v):
global num_traces
num_traces += 1
return v.read_value()
foo(tf.Variable(1))
foo(tf.Variable(2))
print(num_traces)
2
التفاعل مع استراتيجيات التوزيع
هناك طريقتان يتفاعل بهما 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():
g = tf.random.Generator.from_seed(1)
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
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. PerReplica:{ 0: tf.Tensor(-0.87930447, shape=(), dtype=float32), 1: tf.Tensor(0.020661574, shape=(), dtype=float32) } 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. PerReplica:{ 0: tf.Tensor(-1.5822568, shape=(), dtype=float32), 1: tf.Tensor(0.77539235, shape=(), dtype=float32) }
إذا كان المولد مصنفًا (على سبيل المثال تم إنشاؤه بواسطة Generator.from_seed
) ، فسيتم تحديد الأرقام العشوائية بواسطة البذرة ، على الرغم من أن النسخ المتماثلة المختلفة تحصل على أرقام مختلفة وغير مرتبطة. يمكن للمرء أن يفكر في رقم عشوائي تم إنشاؤه على نسخة متماثلة باعتباره تجزئة لمعرف النسخة المتماثلة ورقم عشوائي "أساسي" شائع لجميع النسخ المتماثلة. ومن ثم ، فإن النظام برمته لا يزال حتميا.
يمكن أيضًا إنشاء tf.random.Generator
داخل Strategy.run
:
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
def f():
g = tf.random.Generator.from_seed(1)
a = g.normal([])
b = g.normal([])
return tf.stack([a, b])
print(strat.run(f))
print(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. PerReplica:{ 0: tf.Tensor([-0.87930447 -1.5822568 ], shape=(2,), dtype=float32), 1: tf.Tensor([0.02066157 0.77539235], shape=(2,), dtype=float32) } 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. PerReplica:{ 0: tf.Tensor([-0.87930447 -1.5822568 ], shape=(2,), dtype=float32), 1: tf.Tensor([0.02066157 0.77539235], shape=(2,), dtype=float32) }
لم نعد نوصي بتمرير tf.random.Generator
كحجج لـ Strategy.run
، لأن Strategy.run
تتوقع عمومًا أن تكون الحجج موترات وليست مولدات.
مولدات التوفير
بشكل عام للحفظ أو التسلسل ، يمكنك التعامل مع tf.random.Generator
بنفس الطريقة التي تتعامل بها مع tf.Variable
أو وحدة tf.Module
(أو الفئات الفرعية). في TF ، توجد آليتان للتسلسل: Checkpoint و SavedModel .
نقطة تفتيش
يمكن حفظ المولدات واستعادتها بحرية باستخدام tf.train.Checkpoint
. سيكون دفق الرقم العشوائي من نقطة الاستعادة هو نفسه من نقطة الحفظ.
filename = "./checkpoint"
g = tf.random.Generator.from_seed(1)
cp = tf.train.Checkpoint(generator=g)
print(g.normal([]))
tf.Tensor(0.43842277, shape=(), dtype=float32)
cp.write(filename)
print("RNG stream from saving point:")
print(g.normal([]))
print(g.normal([]))
RNG stream from saving point: tf.Tensor(1.6272374, shape=(), dtype=float32) tf.Tensor(1.6307176, shape=(), dtype=float32)
cp.restore(filename)
print("RNG stream from restoring point:")
print(g.normal([]))
print(g.normal([]))
RNG stream from restoring point: tf.Tensor(1.6272374, shape=(), dtype=float32) tf.Tensor(1.6307176, shape=(), dtype=float32)
يمكنك أيضًا الحفظ والاستعادة ضمن إستراتيجية التوزيع:
filename = "./checkpoint"
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
g = tf.random.Generator.from_seed(1)
cp = tf.train.Checkpoint(my_generator=g)
print(strat.run(lambda: g.normal([])))
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') PerReplica:{ 0: tf.Tensor(-0.87930447, shape=(), dtype=float32), 1: tf.Tensor(0.020661574, shape=(), dtype=float32) }
with strat.scope():
cp.write(filename)
print("RNG stream from saving point:")
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
RNG stream from saving point: PerReplica:{ 0: tf.Tensor(-1.5822568, shape=(), dtype=float32), 1: tf.Tensor(0.77539235, shape=(), dtype=float32) } PerReplica:{ 0: tf.Tensor(-0.5039703, shape=(), dtype=float32), 1: tf.Tensor(0.1251838, shape=(), dtype=float32) }
with strat.scope():
cp.restore(filename)
print("RNG stream from restoring point:")
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
RNG stream from restoring point: PerReplica:{ 0: tf.Tensor(-1.5822568, shape=(), dtype=float32), 1: tf.Tensor(0.77539235, shape=(), dtype=float32) } PerReplica:{ 0: tf.Tensor(-0.5039703, shape=(), dtype=float32), 1: tf.Tensor(0.1251838, shape=(), dtype=float32) }
يجب أن تتأكد من أن النسخ المتماثلة لا تتباعد في سجل مكالمات RNG (على سبيل المثال ، تقوم إحدى النسخ المتماثلة بإجراء مكالمة RNG بينما يقوم الآخر بإجراء مكالمتي RNG) قبل الحفظ. وإلا ، فإن حالات RNG الداخلية ستتباعد ولن tf.train.Checkpoint
(الذي يحفظ حالة النسخة المتماثلة الأولى فقط) جميع النسخ المتماثلة بشكل صحيح.
يمكنك أيضًا استعادة نقطة اختبار محفوظة إلى إستراتيجية توزيع مختلفة بعدد مختلف من النسخ المتماثلة. نظرًا لأن كائن tf.random.Generator
الذي تم إنشاؤه في إستراتيجية لا يمكن استخدامه إلا في نفس الإستراتيجية ، للاستعادة إلى إستراتيجية مختلفة ، يجب عليك إنشاء tf.random.Generator
جديد في الإستراتيجية المستهدفة و tf.train.Checkpoint
لها كما هو موضح في هذا المثال:
filename = "./checkpoint"
strat1 = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat1.scope():
g1 = tf.random.Generator.from_seed(1)
cp1 = tf.train.Checkpoint(my_generator=g1)
print(strat1.run(lambda: g1.normal([])))
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') PerReplica:{ 0: tf.Tensor(-0.87930447, shape=(), dtype=float32), 1: tf.Tensor(0.020661574, shape=(), dtype=float32) }
with strat1.scope():
cp1.write(filename)
print("RNG stream from saving point:")
print(strat1.run(lambda: g1.normal([])))
print(strat1.run(lambda: g1.normal([])))
RNG stream from saving point: PerReplica:{ 0: tf.Tensor(-1.5822568, shape=(), dtype=float32), 1: tf.Tensor(0.77539235, shape=(), dtype=float32) } PerReplica:{ 0: tf.Tensor(-0.5039703, shape=(), dtype=float32), 1: tf.Tensor(0.1251838, shape=(), dtype=float32) }
strat2 = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1", "cpu:2"])
with strat2.scope():
g2 = tf.random.Generator.from_seed(1)
cp2 = tf.train.Checkpoint(my_generator=g2)
cp2.restore(filename)
print("RNG stream from restoring point:")
print(strat2.run(lambda: g2.normal([])))
print(strat2.run(lambda: g2.normal([])))
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', '/job:localhost/replica:0/task:0/device:CPU:2') RNG stream from restoring point: PerReplica:{ 0: tf.Tensor(-1.5822568, shape=(), dtype=float32), 1: tf.Tensor(0.77539235, shape=(), dtype=float32), 2: tf.Tensor(0.6851049, shape=(), dtype=float32) } PerReplica:{ 0: tf.Tensor(-0.5039703, shape=(), dtype=float32), 1: tf.Tensor(0.1251838, shape=(), dtype=float32), 2: tf.Tensor(-0.58519536, shape=(), dtype=float32) }
على الرغم من أن g1
و cp1
عبارة عن كائنات مختلفة عن g2
و cp2
، إلا أنهما مرتبطان عبر اسم ملف نقطة التفتيش المشترك filename
الكائن my_generator
. النسخ المتماثلة المتداخلة بين الاستراتيجيات (على سبيل المثال cpu:0
ووحدة cpu:1
أعلاه) ستتم استعادة تدفقات RNG بشكل صحيح كما في الأمثلة السابقة. لا يغطي هذا الضمان الحالة عند حفظ أحد المولد في نطاق إستراتيجية واستعادته خارج أي نطاق إستراتيجية أو العكس ، لأن الجهاز خارج الإستراتيجيات يتم التعامل معه على أنه مختلف عن أي نسخة متماثلة في الإستراتيجية.
نموذج
يمكن حفظ tf.random.Generator
في SavedModel. يمكن إنشاء المولد ضمن نطاق إستراتيجية. يمكن أن يحدث التوفير أيضًا في نطاق إستراتيجية.
filename = "./saved_model"
class MyModule(tf.Module):
def __init__(self):
super(MyModule, self).__init__()
self.g = tf.random.Generator.from_seed(0)
@tf.function
def __call__(self):
return self.g.normal([])
@tf.function
def state(self):
return self.g.state
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
m = MyModule()
print(strat.run(m))
print("state:", m.state())
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') PerReplica:{ 0: tf.Tensor(-1.4154755, shape=(), dtype=float32), 1: tf.Tensor(-0.113884404, shape=(), dtype=float32) } state: tf.Tensor([256 0 0], shape=(3,), dtype=int64)
with strat.scope():
tf.saved_model.save(m, filename)
print("RNG stream from saving point:")
print(strat.run(m))
print("state:", m.state())
print(strat.run(m))
print("state:", m.state())
INFO:tensorflow:Assets written to: ./saved_model/assets RNG stream from saving point: PerReplica:{ 0: tf.Tensor(-0.68758255, shape=(), dtype=float32), 1: tf.Tensor(0.8084062, shape=(), dtype=float32) } state: tf.Tensor([512 0 0], shape=(3,), dtype=int64) PerReplica:{ 0: tf.Tensor(-0.27342677, shape=(), dtype=float32), 1: tf.Tensor(-0.53093255, shape=(), dtype=float32) } state: tf.Tensor([768 0 0], shape=(3,), dtype=int64) 2021-09-22 20:45:46.222281: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
imported = tf.saved_model.load(filename)
print("RNG stream from loading point:")
print("state:", imported.state())
print(imported())
print("state:", imported.state())
print(imported())
print("state:", imported.state())
RNG stream from loading point: state: tf.Tensor([256 0 0], shape=(3,), dtype=int64) tf.Tensor(-1.0359411, shape=(), dtype=float32) state: tf.Tensor([512 0 0], shape=(3,), dtype=int64) tf.Tensor(-0.06425078, shape=(), dtype=float32) state: tf.Tensor([768 0 0], shape=(3,), dtype=int64)
لا يوصى بتحميل SavedModel يحتوي على tf.random.Generator
في إستراتيجية التوزيع لأن النسخ المتماثلة ستنشئ جميعها نفس دفق الأرقام العشوائية (وهذا بسبب تجميد معرف النسخة المتماثلة في الرسم البياني لـ SavedModel).
تحميل tf.random.Generator
موزع (مولد تم إنشاؤه ضمن إستراتيجية توزيع) في بيئة غير إستراتيجية ، مثل المثال أعلاه ، له أيضًا تحذير. ستتم استعادة حالة RNG بشكل صحيح ، لكن الأرقام العشوائية التي تم إنشاؤها ستكون مختلفة عن المُنشئ الأصلي في استراتيجيتها (مرة أخرى لأنه يتم التعامل مع جهاز خارج الاستراتيجيات على أنه مختلف عن أي نسخة متماثلة في إستراتيجية).
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.30159 -0.95385665]], shape=(2, 3), dtype=float32) tf.Tensor( [[ 0.5441101 0.20738031 0.07356433] [ 0.04643455 -1.30159 -0.95385665]], shape=(2, 3), dtype=float32)
يتطلب كل seed
عديم الحالة وسيطة أولية ، والتي يجب أن تكون عددًا صحيحًا من موتر الشكل [2]
. يتم تحديد نتائج المرجع بالكامل بواسطة هذه البذرة.
تعتمد خوارزمية RNG التي تستخدمها مجموعات RNG عديمة الحالة على الجهاز ، مما يعني أن نفس العملية التي تعمل على جهاز مختلف قد تنتج مخرجات مختلفة.
الخوارزميات
عام
تدعم كل من فئة tf.random.Generator
والوظائف stateless
الحالة خوارزمية Philox (المكتوبة باسم "philox"
أو tf.random.Algorithm.PHILOX
) على جميع الأجهزة.
ستولد الأجهزة المختلفة نفس الأرقام الصحيحة ، في حالة استخدام نفس الخوارزمية والبدء من نفس الحالة. سوف يقومون أيضًا بتوليد "نفس أرقام الفاصلة العائمة تقريبًا" ، على الرغم من أنه قد يكون هناك اختلافات عددية صغيرة ناتجة عن الطرق المختلفة التي تنفذ بها الأجهزة حساب النقطة العائمة (على سبيل المثال ، ترتيب الاختزال).
أجهزة XLA
على الأجهزة التي تعتمد على XLA (مثل TPU ، وكذلك CPU / GPU عند تمكين XLA) ، يتم أيضًا دعم خوارزمية ThreeFry (مكتوبة كـ "threefry"
أو tf.random.Algorithm.THREEFRY
). هذه الخوارزمية سريعة على TPU ولكنها بطيئة على وحدة المعالجة المركزية / وحدة معالجة الرسومات مقارنةً بـ Philox.
راجع مقالة "أرقام عشوائية متوازية: سهلة مثل 1 ، 2 ، 3" لمزيد من التفاصيل حول هذه الخوارزميات.