TFF में यादृच्छिक शोर उत्पन्न करना

यह ट्यूटोरियल TFF में यादृच्छिक शोर उत्पन्न करने के लिए अनुशंसित सर्वोत्तम प्रथाओं पर चर्चा करेगा। फ़ेडरेटेड लर्निंग एल्गोरिदम, जैसे, डिफरेंशियल प्राइवेसी में कई गोपनीयता सुरक्षा तकनीकों का एक महत्वपूर्ण घटक यादृच्छिक शोर पीढ़ी है।

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.<वितरण> फ़ंक्शन से बचने के लिए 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 एपीआई की तरह tf.random.normal यादृच्छिक शोर पीढ़ी के लिए दृढ़ता से के अनुसार TF2 में हतोत्साहित किया जाता है TF में यादृच्छिक शोर पीढ़ी ट्यूटोरियल । आश्चर्य की बात व्यवहार जब इन 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 में, चीजें थोड़ी अलग हैं। हम के रूप में शोर पीढ़ी लपेट तो 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

इसके अलावा, टीएफएफ में स्पष्ट रूप से एक बीज स्थापित किए बिना नियतात्मक शोर उत्पन्न किया जा सकता है। समारोह return_two_noise निम्नलिखित कोड में रिटर्न झलकी दो समान शोर मूल्यों। यह अपेक्षित व्यवहार है क्योंकि 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 के रूप में सुझाव दिया TF ट्यूटोरियल

@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)]