টিএফএফ -এ এলোমেলো শব্দ উৎপাদন

এই টিউটোরিয়াল টিএফএফ-এ এলোমেলো শব্দ তৈরির জন্য প্রস্তাবিত সেরা অনুশীলনগুলি নিয়ে আলোচনা করবে। ফেডারেটেড লার্নিং অ্যালগরিদম, যেমন, ডিফারেনশিয়াল প্রাইভেসিতে র্যান্ডম নয়েজ জেনারেশন অনেক গোপনীয়তা সুরক্ষা কৌশলের একটি গুরুত্বপূর্ণ উপাদান।

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

আমরা শুরু করার আগে

প্রথমে, আমরা নিশ্চিত করি যে নোটবুকটি এমন একটি ব্যাকএন্ডের সাথে সংযুক্ত রয়েছে যাতে প্রাসঙ্গিক উপাদানগুলি সংকলিত রয়েছে।

!pip install --quiet --upgrade tensorflow_federated_nightly
!pip install --quiet --upgrade nest_asyncio

import nest_asyncio
nest_asyncio.apply()
import numpy as np
import tensorflow as tf
import tensorflow_federated as tff

TFF পরিবেশ সঠিকভাবে সেটআপ করা হয়েছে তা নিশ্চিত করতে নিম্নলিখিত "হ্যালো ওয়ার্ল্ড" উদাহরণটি চালান। এটা কাজ করে না, তাহলে পড়ুন দয়া ইনস্টলেশন নির্দেশাবলীর জন্য গাইড।

@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
b'Hello, World!'

ক্লায়েন্টদের উপর র্যান্ডম গোলমাল

ক্লায়েন্টদের জন্য শব্দের প্রয়োজনীয়তা সাধারণত দুটি ক্ষেত্রে পড়ে: অভিন্ন নয়েজ এবং আইআইডি নয়েজ।

  • অভিন্ন গোলমালের জন্য, প্রস্তাবিত প্যাটার্ন সার্ভারে একটি বীজ, ক্লায়েন্ট তা সম্প্রচার বজায় রাখুন এবং ব্যবহার করা tf.random.stateless ফাংশন গোলমাল তৈরি করতে।
  • iid নয়েজের জন্য, tf.random.<distribution> ফাংশনগুলি এড়াতে TF-এর সুপারিশ মেনে from_non_deterministic_state সহ ক্লায়েন্টে শুরু করা tf.random.Generator ব্যবহার করুন।

ক্লায়েন্টের আচরণ সার্ভারের থেকে আলাদা (পরে আলোচনা করা সমস্যাগুলি থেকে ভোগে না) কারণ প্রতিটি ক্লায়েন্ট তাদের নিজস্ব গণনা গ্রাফ তৈরি করবে এবং তাদের নিজস্ব ডিফল্ট বীজ শুরু করবে।

ক্লায়েন্টদের উপর অভিন্ন গোলমাল

# Set to use 10 clients.
tff.backends.native.set_local_python_execution_context(num_clients=10)

@tff.tf_computation
def noise_from_seed(seed):
  return tf.random.stateless_normal((), seed=seed)

seed_type_at_server = tff.type_at_server(tff.to_type((tf.int64, [2])))

@tff.federated_computation(seed_type_at_server)
def get_random_min_and_max_deterministic(seed):
  # Broadcast seed to all clients.
  seed_on_clients = tff.federated_broadcast(seed)

  # Clients generate noise from seed deterministicly.
  noise_on_clients = tff.federated_map(noise_from_seed, seed_on_clients)

  # Aggregate and return the min and max of the values generated on clients.
  min = tff.aggregators.federated_min(noise_on_clients)
  max = tff.aggregators.federated_max(noise_on_clients)
  return min, max

seed = tf.constant([1, 1], dtype=tf.int64)
min, max = get_random_min_and_max_deterministic(seed)
assert min == max
print(f'Seed: {seed.numpy()}. All clients sampled value {min:8.3f}.')

seed += 1
min, max = get_random_min_and_max_deterministic(seed)
assert min == max
print(f'Seed: {seed.numpy()}. All clients sampled value {min:8.3f}.')
Seed: [1 1]. All clients sampled value    1.665.
Seed: [2 2]. All clients sampled value   -0.219.

ক্লায়েন্টদের উপর স্বাধীন গোলমাল

@tff.tf_computation
def nondeterministic_noise():
  gen = tf.random.Generator.from_non_deterministic_state()
  return gen.normal(())

@tff.federated_computation(seed_type_at_server)
def get_random_min_and_max_nondeterministic(seed):
  noise_on_clients = tff.federated_eval(nondeterministic_noise, tff.CLIENTS)
  min = tff.aggregators.federated_min(noise_on_clients)
  max = tff.aggregators.federated_max(noise_on_clients)
  return min, max

min, max = get_random_min_and_max_nondeterministic(seed)
assert min != max
print(f'Values differ across clients. {min:8.3f},{max:8.3f}.')

new_min, new_max = get_random_min_and_max_nondeterministic(seed)
assert new_min != new_max
assert new_min != min and new_max != max
print(f'Values differ across rounds.  {new_min:8.3f},{new_max:8.3f}.')
Values differ across clients.   -1.810,   1.079.
Values differ across rounds.    -1.205,   0.851.

সার্ভারে এলোমেলো শব্দ

নিরুৎসাহিত ব্যবহার: সরাসরি ব্যবহার tf.random.normal

TF1.x API গুলি মত tf.random.normal রান্ডম নয়েজ প্রজন্মের জন্য জোরালোভাবে অনুযায়ী TF2 মধ্যে নিরুৎসাহিত হয়ে মেমরি মধ্যে রান্ডম নয়েজ প্রজন্ম টিউটোরিয়াল । অবাক আচরণ যখন এই API গুলি একসাথে ব্যবহার করা হয় ঘটতে পারে tf.function এবং tf.random.set_seed । উদাহরণস্বরূপ, নিম্নলিখিত কোড প্রতিটি কলের সাথে একই মান তৈরি করবে। এই বিস্ময়কর আচরণ TF জন্য বলে আশা করা হচ্ছে, এবং ব্যাখ্যা খুঁজে পাওয়া যেতে পারে ডকুমেন্টেশন tf.random.set_seed

tf.random.set_seed(1)

@tf.function
def return_one_noise(_):
  return tf.random.normal([])

n1=return_one_noise(1)
n2=return_one_noise(2) 
assert n1 == n2
print(n1.numpy(), n2.numpy())
0.3052047 0.3052047

টিএফএফ-এ, জিনিসগুলি কিছুটা আলাদা। আমরা যত গোলমাল প্রজন্ম মোড়ানো তাহলে tff.tf_computation পরিবর্তে tf.function , অ-নির্ণায়ক রান্ডম নয়েজ তৈরি করা হবে। যাইহোক, যদি আমরা এই কোড স্নিপেট একাধিক বার চালানোর জন্য, বিভিন্ন সেট (n1, n2) প্রতিটি সময় তৈরি করা হবে। TFF এর জন্য বিশ্বব্যাপী র্যান্ডম বীজ সেট করার কোন সহজ উপায় নেই।

tf.random.set_seed(1)

@tff.tf_computation
def return_one_noise(_):
  return tf.random.normal([])

n1=return_one_noise(1)
n2=return_one_noise(2) 
assert n1 != n2
print(n1, n2)
1.3283143 0.45740178

তদুপরি, স্পষ্টভাবে একটি বীজ সেট না করেই TFF-এ নির্ধারক শব্দ তৈরি করা যেতে পারে। ফাংশন return_two_noise নিম্নলিখিত কোডে আয় snippet একই রকম দুটি শব্দ মান। এটি প্রত্যাশিত আচরণ কারণ TFF কার্যকর করার আগে গণনা গ্রাফ তৈরি করবে। যাইহোক, এই ব্যবহারকারীদের ব্যবহারের উপর বেতন মনোযোগ আছে দাড়ায় tf.random.normal TFF হবে।

@tff.tf_computation
def tff_return_one_noise():
  return tf.random.normal([])

@tff.federated_computation
def return_two_noise():
  return (tff_return_one_noise(), tff_return_one_noise())

n1, n2=return_two_noise() 
assert n1 == n2
print(n1, n2)
-0.15665223 -0.15665223

যত্নের সাথে ব্যবহার: tf.random.Generator

আমরা ব্যবহার করতে পারি tf.random.Generator হিসাবে প্রস্তাব করা মেমরি টিউটোরিয়াল

@tff.tf_computation
def tff_return_one_noise(i):
  g=tf.random.Generator.from_seed(i)
  @tf.function
  def tf_return_one_noise():
    return g.normal([])
  return tf_return_one_noise()

@tff.federated_computation
def return_two_noise():
  return (tff_return_one_noise(1), tff_return_one_noise(2))

n1, n2 = return_two_noise() 
assert n1 != n2
print(n1, n2)
0.3052047 -0.38260338

যাইহোক, ব্যবহারকারীদের এর ব্যবহারে সতর্ক থাকতে হবে

  • tf.random.Generator ব্যবহার tf.Variable RNG আলগোরিদিম জন্য রাজ্যের বজায় রাখার জন্য। TFF, এটা একটা ভিতরে জেনারেটরের contruct বাঞ্ছনীয় tff.tf_computation ; এবং এটি জেনারেটরের মধ্যে তার রাষ্ট্র পাস করা কঠিন tff.tf_computation ফাংশন।
  • পূর্ববর্তী কোড স্নিপেট জেনারেটরে সাবধানে বীজ সেট করার উপর নির্ভর করে। আমরা আশা হবে কিন্তু বিস্ময়কর ফলাফল (নির্ণায়ক n1==n2 ) আমরা ব্যবহার যদি tf.random.Generator.from_non_deterministic_state() পরিবর্তে।

সাধারণভাবে, TFF কার্মিক অপারেশন পছন্দ এবং আমরা ব্যবহার দেখানো হবে tf.random.stateless_* নিম্নলিখিত বিভাগে ফাংশন।

ফেডারেটেড লার্নিংয়ের জন্য TFF-এ, আমরা প্রায়শই স্কেলারের পরিবর্তে নেস্টেড স্ট্রাকচার নিয়ে কাজ করি এবং আগের কোড স্নিপেট স্বাভাবিকভাবেই নেস্টেড স্ট্রাকচারে প্রসারিত করা যেতে পারে।

@tff.tf_computation
def tff_return_one_noise(i):
  g=tf.random.Generator.from_seed(i)
  weights = [
         tf.ones([2, 2], dtype=tf.float32),
         tf.constant([2], dtype=tf.float32)
     ]
  @tf.function
  def tf_return_one_noise():
    return tf.nest.map_structure(lambda x: g.normal(tf.shape(x)), weights)
  return tf_return_one_noise()

@tff.federated_computation
def return_two_noise():
  return (tff_return_one_noise(1), tff_return_one_noise(2))

n1, n2 = return_two_noise() 
assert n1[1] != n2[1]
print('n1', n1)
print('n2', n2)
n1 [array([[0.3052047 , 0.5671378 ],
       [0.41852272, 0.2326421 ]], dtype=float32), array([1.1675092], dtype=float32)]
n2 [array([[-0.38260338, -0.47804865],
       [-0.5187485 , -1.8471988 ]], dtype=float32), array([-0.77835274], dtype=float32)]

TFF একটি সাধারণ সুপারিশ কার্মিক ব্যবহার করা tf.random.stateless_* রান্ডম নয়েজ প্রজন্মের জন্য ফাংশন। এই ফাংশন নিতে seed (আকৃতি সঙ্গে একটি টেন্সর [2] বা tuple একটি সুনির্দিষ্ট ইনপুট যুক্তি রান্ডম নয়েজ জেনারেট করতে দুটি স্কালে tensors এর)। বীজটিকে ছদ্ম অবস্থা হিসাবে বজায় রাখার জন্য আমরা প্রথমে একটি সহায়ক শ্রেণী সংজ্ঞায়িত করি। সাহায্যকারী RandomSeedGenerator একটি রাষ্ট্র-ইন-রাষ্ট্র-আউট ফ্যাশন কার্মিক অপারেটার হয়েছে। এটা তোলে জন্য ছদ্ম রাষ্ট্র হিসেবে একটি পাল্টা ব্যবহার করতে যুক্তিযুক্ত tf.random.stateless_* এই ফাংশন হামাগুড়ি দিয়া আরোহণ এটি ব্যবহার সম্পর্কিত বীজ পরিসংখ্যানগত সম্পর্কহীন দ্বারা উত্পন্ন শব্দ করতে সামনে বীজ।

def timestamp_seed():
  # tf.timestamp returns microseconds as decimal places, thus scaling by 1e6.
  return tf.math.cast(tf.timestamp() * 1e6, tf.int64)

class RandomSeedGenerator():

  def initialize(self, seed=None):
    if seed is None:
      return tf.stack([timestamp_seed(), 0])
    else:
      return tf.constant(self.seed, dtype=tf.int64, shape=(2,))

  def next(self, state):
    return state + tf.constant([0, 1], tf.int64)

  def structure_next(self, state, nest_structure):
    "Returns seed in nested structure and the next state seed."
    flat_structure = tf.nest.flatten(nest_structure)
    flat_seeds = [state + tf.constant([0, i], tf.int64) for
                  i in range(len(flat_structure))]
    nest_seeds = tf.nest.pack_sequence_as(nest_structure, flat_seeds)
    return nest_seeds, flat_seeds[-1] + tf.constant([0, 1], tf.int64)

এখন সাহায্যকারী শ্রেণী এবং ব্যবহার করার অনুমতি tf.random.stateless_normal জেনারেট করতে (এর নেস্টেড গঠন) TFF মধ্যে রান্ডম নয়েজ। নিম্নলিখিত কোড স্নিপেট একটি TFF প্রক্রিয়া পুনরাবৃত্ত মত অনেক, দেখতে দেখায় simple_fedavg TFF পুনরাবৃত্ত প্রক্রিয়া হিসেবে ফেডারেট লার্নিং আলগোরিদিম প্রকাশ একটি উদাহরণ হিসাবে। ছদ্ম বীজ রান্ডম নয়েজ প্রজন্মের জন্য এখানে রাষ্ট্র tf.Tensor সহজেই TFF এবং TF ফাংশন পরিবাহিত করা যেতে পারে।

@tff.tf_computation
def tff_return_one_noise(seed_state):
  g=RandomSeedGenerator()
  weights = [
         tf.ones([2, 2], dtype=tf.float32),
         tf.constant([2], dtype=tf.float32)
     ]
  @tf.function
  def tf_return_one_noise():
    nest_seeds, updated_state = g.structure_next(seed_state, weights)
    nest_noise = tf.nest.map_structure(lambda x,s: tf.random.stateless_normal(
        shape=tf.shape(x), seed=s), weights, nest_seeds)
    return nest_noise, updated_state
  return tf_return_one_noise()

@tff.tf_computation
def tff_init_state():
  g=RandomSeedGenerator()
  return g.initialize()

@tff.federated_computation
def return_two_noise():
  seed_state = tff_init_state()
  n1, seed_state = tff_return_one_noise(seed_state)
  n2, seed_state = tff_return_one_noise(seed_state)
  return (n1, n2)

n1, n2 = return_two_noise() 
assert n1[1] != n2[1]
print('n1', n1)
print('n2', n2)
n1 [array([[-0.21598858, -0.30700883],
       [ 0.7562299 , -0.21218438]], dtype=float32), array([-1.0359321], dtype=float32)]
n2 [array([[ 1.0722181 ,  0.81287116],
       [-0.7140338 ,  0.5896157 ]], dtype=float32), array([0.44190162], dtype=float32)]