यादृच्छिक संख्या पीढ़ी

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

TensorFlow tf.random मॉड्यूल में छद्म यादृच्छिक संख्या जनरेटर (RNG) का एक सेट प्रदान करता है। यह दस्तावेज़ बताता है कि आप यादृच्छिक संख्या जनरेटर को कैसे नियंत्रित कर सकते हैं, और ये जनरेटर अन्य टेंसरफ़्लो उप-प्रणालियों के साथ कैसे इंटरैक्ट करते हैं।

TensorFlow यादृच्छिक संख्या पीढ़ी प्रक्रिया को नियंत्रित करने के लिए दो दृष्टिकोण प्रदान करता है:

  1. tf.random.Generator वस्तुओं के स्पष्ट उपयोग के माध्यम से। ऐसी प्रत्येक वस्तु एक राज्य ( tf.Variable में) बनाए रखती है जिसे प्रत्येक संख्या पीढ़ी के बाद बदल दिया जाएगा।

  2. 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 भी लेता है जो कि RNG एल्गोरिथम है जिसका उपयोग इस जनरेटर द्वारा किया जाएगा:

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 पर रखा जाएगा, और बाद में 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.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)
प्लेसहोल्डर17

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 इसके लिए 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 ऊपर) उनकी आरएनजी धाराओं को पिछले उदाहरणों की तरह ठीक से बहाल कर देगी। यह गारंटी उस मामले को कवर नहीं करती है जब एक जनरेटर को एक रणनीति के दायरे में सहेजा जाता है और किसी भी रणनीति के दायरे से बाहर बहाल किया जाता है या इसके विपरीत, क्योंकि रणनीति के बाहर एक उपकरण को रणनीति में किसी भी प्रतिकृति से अलग माना जाता है।

सहेजा गया मॉडल

tf.random.Generator को सहेजे गए मॉडल में सहेजा जा सकता है। जनरेटर को एक रणनीति के दायरे में बनाया जा सकता है। बचत एक रणनीति के दायरे में भी हो सकती है।

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)

एक वितरण रणनीति में tf.random.Generator युक्त एक सहेजे गए मॉडल को लोड करने की अनुशंसा नहीं की जाती है क्योंकि सभी प्रतिकृतियां एक ही यादृच्छिक-संख्या स्ट्रीम उत्पन्न करेंगी (ऐसा इसलिए है क्योंकि सहेजे गए मॉडल के ग्राफ़ में प्रतिकृति आईडी जमी हुई है)।

एक वितरित tf.random.Generator (एक वितरण रणनीति के भीतर बनाया गया जनरेटर) को गैर-रणनीति वाले वातावरण में लोड करना, जैसा कि उपरोक्त उदाहरण में भी एक चेतावनी है। आरएनजी राज्य को ठीक से बहाल किया जाएगा, लेकिन उत्पन्न यादृच्छिक संख्या अपनी रणनीति में मूल जनरेटर से अलग होगी (फिर से क्योंकि रणनीति के बाहर एक उपकरण को रणनीति में किसी भी प्रतिकृति से अलग माना जाता है)।

स्टेटलेस आरएनजी

स्टेटलेस 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.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)

प्रत्येक स्टेटलेस RNG को एक seed तर्क की आवश्यकता होती है, जिसे आकार का एक पूर्णांक टेंसर होना चाहिए [2] । ऑप के परिणाम पूरी तरह से इसी बीज से निर्धारित होते हैं।

स्टेटलेस RNG द्वारा उपयोग किया जाने वाला RNG एल्गोरिथम डिवाइस पर निर्भर है, जिसका अर्थ है कि एक अलग डिवाइस पर चलने वाला एक ही ऑप अलग-अलग आउटपुट दे सकता है।

एल्गोरिदम

आम

दोनों tf.random.Generator वर्ग और stateless फ़ंक्शन सभी उपकरणों पर Philox एल्गोरिथ्म ( "philox" या tf.random.Algorithm.PHILOX के रूप में लिखा गया) का समर्थन करते हैं।

यदि एक ही एल्गोरिदम का उपयोग करते हुए और एक ही राज्य से शुरू करते हैं, तो विभिन्न डिवाइस एक ही पूर्णांक संख्या उत्पन्न करेंगे। वे "लगभग समान" फ्लोट-पॉइंट नंबर भी उत्पन्न करेंगे, हालांकि विभिन्न तरीकों के कारण छोटी संख्यात्मक विसंगतियां हो सकती हैं जो डिवाइस फ्लोट-पॉइंट गणना (उदाहरण के लिए कमी क्रम) को पूरा करते हैं।

एक्सएलए डिवाइस

XLA-चालित उपकरणों पर (जैसे TPU, और XLA सक्षम होने पर CPU/GPU भी) थ्रीफ़्राई एल्गोरिथम ( "threefry" या tf.random.Algorithm.THREEFRY के रूप में लिखा गया) भी समर्थित है। यह एल्गोरिथम टीपीयू पर तेज है लेकिन फिलॉक्स की तुलना में सीपीयू/जीपीयू पर धीमा है।

इन एल्गोरिदम के बारे में अधिक जानकारी के लिए पेपर 'समानांतर यादृच्छिक संख्या: 1, 2, 3 के रूप में आसान' देखें।