Google I/O-তে TensorFlow-এ যোগ দিন, 11-12 মে এখনই নিবন্ধন করুন

এলোমেলো সংখ্যা জেনারেশন

TensorFlow.org-এ দেখুন Google Colab-এ চালান GitHub-এ উৎস দেখুন নোটবুক ডাউনলোড করুন

tf.random মডিউলে ছদ্ম-র্যান্ডম নম্বর জেনারেটর (RNG) এর একটি সেট প্রদান করে। এই নথিটি বর্ণনা করে যে আপনি কীভাবে এলোমেলো নম্বর জেনারেটরগুলি নিয়ন্ত্রণ করতে পারেন এবং কীভাবে এই জেনারেটরগুলি অন্যান্য টেনসরফ্লো সাব-সিস্টেমের সাথে যোগাযোগ করে।

টেনসরফ্লো এলোমেলো সংখ্যা তৈরির প্রক্রিয়া নিয়ন্ত্রণের জন্য দুটি পন্থা প্রদান করে:

  1. tf.random.Generator অবজেক্টের সুস্পষ্ট ব্যবহারের মাধ্যমে। এই ধরনের প্রতিটি বস্তু একটি অবস্থা বজায় রাখে ( tf.Variable . 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 থেকে পরবর্তীতে গ্লোবাল জেনারেটর ব্যবহার করা হবে। একটি জিপিইউ-টু-সিপিইউ কপি নেওয়া।

গ্লোবাল জেনারেটরকে অন্য জেনারেটর অবজেক্টের সাথে প্রতিস্থাপন করার জন্য একটি ফাংশন 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.function-এর সাথে ব্যবহার করার সময় 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 এর 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)
}

আমরা আর Strategy.run এ আর্গুমেন্ট হিসাবে tf.random.Generator পাস করার পরামর্শ দিই না, কারণ Strategy.run সাধারণত আর্গুমেন্টগুলি টেনসর হওয়ার আশা করে, জেনারেটর নয়।

সেভিং জেনারেটর

সাধারণত সংরক্ষণ বা সিরিয়ালাইজ করার জন্য আপনি একটি tf.random.Generator পরিচালনা করতে পারেন যেভাবে আপনি একটি tf.Variable বা একটি tf.Module (বা এর সাবক্লাস) পরিচালনা করেন। টিএফ-এ সিরিয়ালাইজেশনের জন্য দুটি প্রক্রিয়া রয়েছে: চেকপয়েন্ট এবং সেভডমডেল

চেকপয়েন্ট

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 ) তাদের 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)

একটি বিতরণ কৌশলে tf.random.Generator ধারণকারী একটি SavedModel লোড করা বাঞ্ছনীয় নয় কারণ প্রতিলিপিগুলি একই র্যান্ডম-সংখ্যার স্ট্রীম তৈরি করবে (যার কারণ হল Replica ID SavedModel-এর গ্রাফে হিমায়িত করা হয়েছে)৷

একটি ডিস্ট্রিবিউটেড tf.random.Generator (একটি ডিস্ট্রিবিউশন কৌশলের মধ্যে তৈরি করা একটি জেনারেটর) একটি নন-স্ট্র্যাটেজি পরিবেশে লোড করা, উপরের উদাহরণের মতো, একটি সতর্কতাও রয়েছে। RNG অবস্থা সঠিকভাবে পুনরুদ্ধার করা হবে, কিন্তু উত্পন্ন র্যান্ডম সংখ্যাগুলি মূল জেনারেটরের থেকে তার কৌশলে ভিন্ন হবে (আবার কারণ কৌশলগুলির বাইরের একটি ডিভাইসকে একটি কৌশলের যেকোনো প্রতিলিপি থেকে আলাদা হিসাবে বিবেচনা করা হয়)।

রাষ্ট্রহীন 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)

প্রতিটি স্টেটলেস RNG-এর জন্য একটি seed যুক্তির প্রয়োজন হয়, যা আকৃতির একটি পূর্ণসংখ্যা টেনসর হওয়া প্রয়োজন [2] । অপের ফলাফল সম্পূর্ণরূপে এই বীজ দ্বারা নির্ধারিত হয়.

স্টেটলেস আরএনজি দ্বারা ব্যবহৃত RNG অ্যালগরিদমটি ডিভাইস-নির্ভর, যার অর্থ একটি ভিন্ন ডিভাইসে চলমান একই অপশন বিভিন্ন আউটপুট তৈরি করতে পারে।

অ্যালগরিদম

সাধারণ

tf.random.Generator ক্লাস এবং stateless ফাংশন উভয়ই সমস্ত ডিভাইসে Philox অ্যালগরিদম ( "philox" বা tf.random.Algorithm.PHILOX হিসাবে লেখা) সমর্থন করে।

একই অ্যালগরিদম ব্যবহার করে এবং একই অবস্থা থেকে শুরু করলে বিভিন্ন ডিভাইস একই পূর্ণসংখ্যা তৈরি করবে। তারা "প্রায় একই" ফ্লোট-পয়েন্ট সংখ্যাও তৈরি করবে, যদিও ডিভাইসগুলি ফ্লোট-পয়েন্ট গণনা (যেমন হ্রাস ক্রম) পরিচালনা করার বিভিন্ন উপায়ের কারণে ছোট সংখ্যাগত অসঙ্গতি হতে পারে।

XLA ডিভাইস

XLA-চালিত ডিভাইসগুলিতে (যেমন TPU, এবং এছাড়াও CPU/GPU যখন XLA সক্রিয় থাকে) থ্রিফ্রাই অ্যালগরিদম ( "threefry" বা tf.random.Algorithm.THREEFRY হিসাবে লেখা)ও সমর্থিত। এই অ্যালগরিদম টিপিইউতে দ্রুত কিন্তু ফিলক্সের তুলনায় সিপিইউ/জিপিইউতে ধীর।

এই অ্যালগরিদমগুলি সম্পর্কে আরও বিশদ বিবরণের জন্য 'সমান্তরাল র্যান্ডম সংখ্যা: 1, 2, 3 হিসাবে সহজ' কাগজটি দেখুন।