कस्टम फ़ेडरेटेड एल्गोरिदम, भाग 2: फ़ेडरेटेड औसत लागू करना

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

इस ट्यूटोरियल दर्शाता है कि कैसे का उपयोग कर फ़ेडरेटेड एल्गोरिदम के कस्टम प्रकार लागू करने के लिए TFF में एक दो भाग श्रृंखला का दूसरा हिस्सा है संघीय कोर (एफसी) , जिसके लिए एक आधार के रूप में कार्य करता है संघीय लर्निंग (FL) परत ( tff.learning ) .

हम पहले पढ़ने के लिए प्रोत्साहित इस श्रृंखला का पहला हिस्सा है, जो महत्वपूर्ण अवधारणाओं के कुछ और यहां इस्तेमाल किया प्रोग्रामिंग कपोल-कल्पना परिचय।

श्रृंखला का यह दूसरा भाग फ़ेडरेटेड प्रशिक्षण और मूल्यांकन एल्गोरिदम के एक सरल संस्करण को लागू करने के लिए पहले भाग में पेश किए गए तंत्र का उपयोग करता है।

हमें यह समीक्षा करने के लिए प्रोत्साहित करते छवि वर्गीकरण और पाठ पीढ़ी TFF के संघीय लर्निंग एपीआई के लिए एक उच्च स्तरीय और अधिक सौम्य परिचय के लिए ट्यूटोरियल, के रूप में वे मदद से आप अवधारणाओं हम यहाँ संदर्भ में वर्णन डाल दिया।

हमारे शुरू करने से पहले

शुरू करने से पहले, यह सुनिश्चित करने के लिए कि आपका वातावरण सही ढंग से सेटअप है, निम्नलिखित "हैलो वर्ल्ड" उदाहरण चलाने का प्रयास करें। यह काम नहीं करता है, तो कृपया स्थापना निर्देश के लिए गाइड।

!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio

import nest_asyncio
nest_asyncio.apply()
import collections

import numpy as np
import tensorflow as tf
import tensorflow_federated as tff

# Must use the Python context because it
# supports tff.sequence_* intrinsics.
executor_factory = tff.framework.local_executor_factory(
    support_sequence_ops=True)
execution_context = tff.framework.ExecutionContext(
    executor_fn=executor_factory)
tff.framework.set_default_context(execution_context)
@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
b'Hello, World!'

फ़ेडरेटेड एवरेजिंग लागू करना

के रूप में छवि वर्गीकरण के लिए संघीय लर्निंग , हम MNIST उदाहरण का उपयोग करने जा रहे हैं, लेकिन जब से यह एक निम्न स्तर के ट्यूटोरियल के रूप में करना है, हम Keras एपीआई और बाईपास करने जा रहे हैं tff.simulation , कच्चे मॉडल कोड लिखते हैं, और निर्माण एक फ़ेडरेटेड डेटा स्क्रैच से सेट किया गया।

फ़ेडरेटेड डेटा सेट तैयार करना

एक प्रदर्शन के लिए, हम एक ऐसे परिदृश्य का अनुकरण करने जा रहे हैं जिसमें हमारे पास 10 उपयोगकर्ताओं का डेटा है, और प्रत्येक उपयोगकर्ता ज्ञान का योगदान देता है कि किसी भिन्न अंक को कैसे पहचाना जाए। यह गैर के रूप में के बारे में है आईआईडी के रूप में यह हो जाता है।

सबसे पहले, मानक MNIST डेटा लोड करते हैं:

mnist_train, mnist_test = tf.keras.datasets.mnist.load_data()
[(x.dtype, x.shape) for x in mnist_train]
[(dtype('uint8'), (60000, 28, 28)), (dtype('uint8'), (60000,))]

डेटा Numpy सरणियों के रूप में आता है, एक छवियों के साथ और दूसरा अंक लेबल के साथ, दोनों पहले आयाम के साथ व्यक्तिगत उदाहरणों पर जा रहे हैं। आइए एक सहायक फ़ंक्शन लिखें जो इसे इस तरह से प्रारूपित करता है कि हम TFF संगणनाओं में फ़ेडरेटेड अनुक्रमों को कैसे खिलाते हैं, अर्थात, सूचियों की एक सूची के रूप में - उपयोगकर्ताओं (अंकों) से अधिक की बाहरी सूची, डेटा के बैचों में आंतरिक वाले प्रत्येक ग्राहक के अनुक्रम। के रूप में प्रथागत है, हम नामित tensors की एक जोड़ी के रूप में प्रत्येक बैच संरचना होगा x और y , अग्रणी बैच आयाम के साथ प्रत्येक। यह कम से करते हैं, हम भी एक 784-तत्व वेक्टर में प्रत्येक छवि समतल और में उस में पिक्सल rescale जाएगा 0..1 रेंज है, ताकि हम डेटा रूपांतरण के साथ मॉडल तर्क को अस्त-व्यस्त करने के लिए नहीं है।

NUM_EXAMPLES_PER_USER = 1000
BATCH_SIZE = 100


def get_data_for_digit(source, digit):
  output_sequence = []
  all_samples = [i for i, d in enumerate(source[1]) if d == digit]
  for i in range(0, min(len(all_samples), NUM_EXAMPLES_PER_USER), BATCH_SIZE):
    batch_samples = all_samples[i:i + BATCH_SIZE]
    output_sequence.append({
        'x':
            np.array([source[0][i].flatten() / 255.0 for i in batch_samples],
                     dtype=np.float32),
        'y':
            np.array([source[1][i] for i in batch_samples], dtype=np.int32)
    })
  return output_sequence


federated_train_data = [get_data_for_digit(mnist_train, d) for d in range(10)]

federated_test_data = [get_data_for_digit(mnist_test, d) for d in range(10)]

एक त्वरित मानसिक स्वास्थ्य की जांच, पर आइए नज़र के रूप में Y पांचवें ग्राहक के योगदान डेटा के अंतिम बैच में टेन्सर (एक अंक के लिए इसी 5 )।

federated_train_data[5][-1]['y']
array([5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], dtype=int32)

बस सुनिश्चित करने के लिए, आइए उस बैच के अंतिम तत्व से संबंधित छवि को भी देखें।

from matplotlib import pyplot as plt

plt.imshow(federated_train_data[5][-1]['x'][-1].reshape(28, 28), cmap='gray')
plt.grid(False)
plt.show()

पीएनजी

TensorFlow और TFF के संयोजन पर

इस ट्यूटोरियल में, सघनता के लिए हम तुरंत कार्यों कि साथ TensorFlow तर्क परिचय सजाने tff.tf_computation । हालांकि, अधिक जटिल तर्क के लिए, यह वह पैटर्न नहीं है जिसकी हम अनुशंसा करते हैं। TensorFlow को डिबग करना पहले से ही एक चुनौती हो सकती है, और TensorFlow को पूरी तरह से क्रमबद्ध करने और फिर से आयात करने के बाद डिबग करना आवश्यक रूप से कुछ मेटाडेटा खो देता है और अंतःक्रियाशीलता को सीमित कर देता है, जिससे डिबगिंग और भी एक चुनौती बन जाती है।

इसलिए, हम दृढ़ता से स्टैंड-अलोन अजगर कार्यों के रूप में जटिल TF तर्क लेखन की सलाह देते हैं (कि बिना है, tff.tf_computation सजावट)। इस तरह TensorFlow तर्क विकसित किया जा सकता है और परीक्षण किया TF सर्वोत्तम प्रथाओं और उपकरण (उत्सुक मोड की तरह) का उपयोग करते हुए, TFF के लिए गणना serializing (जैसे, लागू करने से पहले tff.tf_computation तर्क के रूप में एक अजगर समारोह के साथ)।

हानि फ़ंक्शन को परिभाषित करना

अब जब हमारे पास डेटा है, तो आइए एक हानि फ़ंक्शन को परिभाषित करें जिसका उपयोग हम प्रशिक्षण के लिए कर सकते हैं। सबसे पहले, आइए इनपुट के प्रकार को टपल नाम के TFF के रूप में परिभाषित करें। के बाद से डेटा बैचों के आकार भिन्न हो सकते हैं, हम करने के लिए बैच आयाम सेट None इंगित करने के लिए इस आयाम का आकार अज्ञात है।

BATCH_SPEC = collections.OrderedDict(
    x=tf.TensorSpec(shape=[None, 784], dtype=tf.float32),
    y=tf.TensorSpec(shape=[None], dtype=tf.int32))
BATCH_TYPE = tff.to_type(BATCH_SPEC)

str(BATCH_TYPE)
'<x=float32[?,784],y=int32[?]>'

आप सोच रहे होंगे कि हम सिर्फ एक साधारण पायथन प्रकार को परिभाषित क्यों नहीं कर सकते। में चर्चा याद भाग 1 , जहां हमने बताया था कि अजगर का उपयोग कर TFF संगणना के तर्क, हुड TFF संगणना के तहत व्यक्त कर सकते हैं, जबकि अजगर नहीं हैं। प्रतीक BATCH_TYPE ऊपर परिभाषित एक सार TFF प्रकार विनिर्देश प्रतिनिधित्व करता है। यह ठोस अजगर प्रतिनिधित्व प्रकार, जैसे, इस तरह के रूप कंटेनरों से इस सार TFF प्रकार भेद करने के लिए महत्वपूर्ण है dict या collections.namedtuple है कि एक अजगर समारोह के मुख्य भाग में TFF प्रकार का प्रतिनिधित्व करने के लिए इस्तेमाल किया जा सकता है। अजगर के विपरीत, TFF एक भी सार प्रकार निर्माता है tff.StructType के लिए टपल जैसे तत्वों है कि अलग-अलग नाम दिया जा सकता है या अज्ञात छोड़ दिया साथ कंटेनर,। इस प्रकार का उपयोग संगणना के औपचारिक मापदंडों को मॉडल करने के लिए भी किया जाता है, क्योंकि TFF संगणना औपचारिक रूप से केवल एक पैरामीटर और एक परिणाम घोषित कर सकती है - आप जल्द ही इसके उदाहरण देखेंगे।

Let अब वजन और पूर्वाग्रह का एक TFF नामित टपल के रूप में फिर से, मॉडल मापदंडों के TFF प्रकार को परिभाषित कर रहा है।

MODEL_SPEC = collections.OrderedDict(
    weights=tf.TensorSpec(shape=[784, 10], dtype=tf.float32),
    bias=tf.TensorSpec(shape=[10], dtype=tf.float32))
MODEL_TYPE = tff.to_type(MODEL_SPEC)
print(MODEL_TYPE)
<weights=float32[784,10],bias=float32[10]>

उन परिभाषाओं के साथ, अब हम किसी दिए गए मॉडल के नुकसान को एक बैच में परिभाषित कर सकते हैं। के उपयोग के नोट @tf.function अंदर डेकोरेटर @tff.tf_computation डेकोरेटर। यह हमें अर्थ विज्ञान की तरह अजगर का उपयोग कर TF लिखने के लिए भले ही एक के अंदर थे की अनुमति देता है tf.Graph द्वारा बनाई संदर्भ tff.tf_computation डेकोरेटर।

# NOTE: `forward_pass` is defined separately from `batch_loss` so that it can 
# be later called from within another tf.function. Necessary because a
# @tf.function  decorated method cannot invoke a @tff.tf_computation.

@tf.function
def forward_pass(model, batch):
  predicted_y = tf.nn.softmax(
      tf.matmul(batch['x'], model['weights']) + model['bias'])
  return -tf.reduce_mean(
      tf.reduce_sum(
          tf.one_hot(batch['y'], 10) * tf.math.log(predicted_y), axis=[1]))

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE)
def batch_loss(model, batch):
  return forward_pass(model, batch)

जैसी उम्मीद थी, गणना batch_loss रिटर्न float32 नुकसान मॉडल और एक ही डेटा बैच दिया। नोट कैसे MODEL_TYPE और BATCH_TYPE औपचारिक मानकों का एक 2-टपल में एक साथ lumped किया गया है; आप के प्रकार को पहचान सकते हैं batch_loss के रूप में (<MODEL_TYPE,BATCH_TYPE> -> float32)

str(batch_loss.type_signature)
'(<model=<weights=float32[784,10],bias=float32[10]>,batch=<x=float32[?,784],y=int32[?]>> -> float32)'

एक विवेकपूर्ण जाँच के रूप में, आइए शून्य से भरे एक प्रारंभिक मॉडल का निर्माण करें और ऊपर देखे गए डेटा के बैच पर नुकसान की गणना करें।

initial_model = collections.OrderedDict(
    weights=np.zeros([784, 10], dtype=np.float32),
    bias=np.zeros([10], dtype=np.float32))

sample_batch = federated_train_data[5][-1]

batch_loss(initial_model, sample_batch)
2.3025851

ध्यान दें कि हम प्रारंभिक मॉडल एक के रूप में परिभाषित साथ TFF गणना फ़ीड dict , भले ही अजगर समारोह के शरीर है कि परिभाषित करता है यह रूप में मॉडल मापदंडों की खपत model['weight'] और model['bias'] । करने के लिए कॉल के तर्कों batch_loss बस उस समारोह के शरीर को पास नहीं कर रहे हैं।

क्या जब हम आह्वान होता है batch_loss ? के अजगर शरीर batch_loss पहले से ही पता लगाया और इसके बाद के संस्करण सेल जहां यह परिभाषित किया गया था में श्रृंखलाबद्ध किया गया है। TFF के लिए फोन करने वाले के रूप में कार्य batch_loss गणना परिभाषा समय में, और समय में मंगलाचरण के लक्ष्य के रूप में batch_loss शुरू हो जाती है। दोनों भूमिकाओं में, TFF, TFF के सार प्रकार प्रणाली और पायथन प्रतिनिधित्व प्रकारों के बीच सेतु का काम करता है। मंगलाचरण समय, TFF सबसे मानक अजगर कंटेनर प्रकार (स्वीकार करेंगे dict , list , tuple , collections.namedtuple सार TFF tuples के ठोस निरूपण के रूप में, आदि)। इसके अलावा, जैसा कि ऊपर उल्लेख किया गया है, TFF गणना औपचारिक रूप से केवल एक पैरामीटर को स्वीकार करती है, आप स्थिति और/या कीवर्ड तर्कों के साथ परिचित पायथन कॉल सिंटैक्स का उपयोग कर सकते हैं, जहां पैरामीटर का प्रकार एक टपल है - यह अपेक्षा के अनुरूप काम करता है।

एक बैच पर ग्रेडिएंट डिसेंट

अब, एक गणना को परिभाषित करते हैं जो इस नुकसान फ़ंक्शन का उपयोग ग्रेडिएंट डिसेंट के एकल चरण को करने के लिए करता है। नोट कैसे इस समारोह को परिभाषित करने में, हम का उपयोग batch_loss एक उप-घटक के रूप में। तुम एक गणना के साथ निर्माण किया आह्वान कर सकते हैं tff.tf_computation एक और गणना के शरीर के अंदर है, हालांकि आम तौर पर यह आवश्यक नहीं है - के रूप में ऊपर वर्णित है, क्योंकि क्रमबद्धता कुछ डिबगिंग जानकारी खो देता है, यह अक्सर लिखने के लिए और अधिक जटिल गणनाओं के लिए बेहतर है और सभी TensorFlow का परीक्षण बिना tff.tf_computation डेकोरेटर।

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE, tf.float32)
def batch_train(initial_model, batch, learning_rate):
  # Define a group of model variables and set them to `initial_model`. Must
  # be defined outside the @tf.function.
  model_vars = collections.OrderedDict([
      (name, tf.Variable(name=name, initial_value=value))
      for name, value in initial_model.items()
  ])
  optimizer = tf.keras.optimizers.SGD(learning_rate)

  @tf.function
  def _train_on_batch(model_vars, batch):
    # Perform one step of gradient descent using loss from `batch_loss`.
    with tf.GradientTape() as tape:
      loss = forward_pass(model_vars, batch)
    grads = tape.gradient(loss, model_vars)
    optimizer.apply_gradients(
        zip(tf.nest.flatten(grads), tf.nest.flatten(model_vars)))
    return model_vars

  return _train_on_batch(model_vars, batch)
str(batch_train.type_signature)
'(<initial_model=<weights=float32[784,10],bias=float32[10]>,batch=<x=float32[?,784],y=int32[?]>,learning_rate=float32> -> <weights=float32[784,10],bias=float32[10]>)'

जब आप एक अजगर समारोह के साथ सजाया आह्वान tff.tf_computation एक और ऐसे समारोह के मुख्य भाग में, भीतरी TFF गणना के तर्क एम्बेडेड है बाहरी एक के तर्क में (अनिवार्य रूप से, inlined)। जैसा कि ऊपर बताया, यदि आप दोनों संगणना लिख रहे हैं, यह संभावना भीतरी समारोह (बनाने के लिए बेहतर है batch_loss इस मामले में) एक नियमित रूप से अजगर या tf.function बजाय एक tff.tf_computation । हालांकि, यहां हम चाहते हैं कि बुला एक उदाहरण देकर स्पष्ट करना tff.tf_computation अपेक्षा के अनुरूप अंदर एक और मूल रूप से काम करता है। अगर, उदाहरण के लिए, आप को परिभाषित करने अजगर कोड नहीं है यह आवश्यक हो सकता है batch_loss , लेकिन केवल अपने धारावाहिक TFF प्रतिनिधित्व।

अब, इस फ़ंक्शन को प्रारंभिक मॉडल पर कुछ बार लागू करते हैं यह देखने के लिए कि क्या नुकसान कम होता है।

model = initial_model
losses = []
for _ in range(5):
  model = batch_train(model, sample_batch, 0.1)
  losses.append(batch_loss(model, sample_batch))
losses
[0.19690023, 0.13176313, 0.10113225, 0.08273812, 0.070301384]

स्थानीय डेटा के अनुक्रम पर क्रमिक अवरोहण

अब, के बाद से batch_train काम प्रतीत होता है, के लिए एक समान प्रशिक्षण समारोह लिख जाने local_train कि खपत बस एक ही बैच के बजाय एक उपयोगकर्ता से सभी बैचों का पूरा अनुक्रम। नई गणना अब उपभोग करने के लिए की आवश्यकता होगी tff.SequenceType(BATCH_TYPE) के बजाय BATCH_TYPE

LOCAL_DATA_TYPE = tff.SequenceType(BATCH_TYPE)

@tff.federated_computation(MODEL_TYPE, tf.float32, LOCAL_DATA_TYPE)
def local_train(initial_model, learning_rate, all_batches):

  @tff.tf_computation(LOCAL_DATA_TYPE, tf.float32)
  def _insert_learning_rate_to_sequence(dataset, learning_rate):
    return dataset.map(lambda x: (x, learning_rate))

  batches_with_learning_rate = _insert_learning_rate_to_sequence(all_batches, learning_rate)

  # Mapping function to apply to each batch.
  @tff.federated_computation(MODEL_TYPE, batches_with_learning_rate.type_signature.element)
  def batch_fn(model, batch_with_lr):
    batch, lr = batch_with_lr
    return batch_train(model, batch, lr)

  return tff.sequence_reduce(batches_with_learning_rate, initial_model, batch_fn)
str(local_train.type_signature)
'(<initial_model=<weights=float32[784,10],bias=float32[10]>,learning_rate=float32,all_batches=<x=float32[?,784],y=int32[?]>*> -> <weights=float32[784,10],bias=float32[10]>)'

कोड के इस छोटे से खंड में काफी कुछ विवरण दबे हुए हैं, आइए एक-एक करके उन पर चलते हैं।

सबसे पहले, हम TensorFlow में पूरी तरह से इस तर्क, पर निर्भर कार्यान्वित किया जा सकता था, जबकि tf.data.Dataset.reduce इसी तरह हम कैसे यह पहले किया है करने के लिए अनुक्रम कार्रवाई करने के लिए, हम इस समय गोंद भाषा में तर्क को व्यक्त करने का विकल्प चुना है , एक के रूप में tff.federated_computation । हम फ़ेडरेटेड ऑपरेटर का उपयोग किया है tff.sequence_reduce कमी करने के लिए।

ऑपरेटर tff.sequence_reduce की तरह ही उपयोग किया जाता है tf.data.Dataset.reduce । आप के रूप में के रूप में मूलतः एक ही इसके बारे में सोच सकते हैं tf.data.Dataset.reduce , लेकिन फ़ेडरेटेड संगणना, जो के रूप में आप याद कर सकते हैं के अंदर उपयोग के लिए, TensorFlow कोड नहीं हो सकता। यह इस बात का एक दृश्य के होते हैं एक औपचारिक पैरामीटर 3-टपल के साथ एक टेम्पलेट ऑपरेटर है T तत्वों -typed, कमी की प्रारंभिक अवस्था किसी प्रकार की (हम इसे करने के लिए सिद्धांत के रूप में शून्य पर गौर करेंगे) U , और की कमी ऑपरेटर टाइप (<U,T> -> U) कि बदलती जाती है एक भी तत्व प्रसंस्करण द्वारा कमी की स्थिति। अनुक्रमिक क्रम में सभी तत्वों को संसाधित करने के बाद, परिणाम कमी की अंतिम स्थिति है। हमारे उदाहरण में, कमी की स्थिति डेटा के उपसर्ग पर प्रशिक्षित मॉडल है, और तत्व डेटा बैच हैं।

दूसरा, ध्यान दें कि हम फिर से एक गणना (इस्तेमाल किया है batch_train एक और (के भीतर एक घटक के रूप में) local_train ), लेकिन सीधे नहीं। हम इसे एक कमी ऑपरेटर के रूप में उपयोग नहीं कर सकते क्योंकि यह एक अतिरिक्त पैरामीटर लेता है - सीखने की दर। इसके समाधान के लिए, हम एक एम्बेडेड फ़ेडरेटेड गणना को परिभाषित batch_fn कि को बांधता है local_train के पैरामीटर learning_rate में अपने शरीर। जब तक बच्चे की गणना उसके माता-पिता के शरीर के बाहर नहीं की जाती है, तब तक उसके माता-पिता के औपचारिक पैरामीटर को कैप्चर करने के लिए इस तरह परिभाषित बच्चे की गणना की अनुमति है। आप का एक समकक्ष के रूप में इस पद्धति के बारे में सोच सकते हैं functools.partial अजगर में।

पर कब्जा करने के व्यावहारिक निहितार्थ learning_rate इस तरह से है कि एक ही सीखने दर मूल्य सभी बैचों भर में प्रयोग किया जाता है, ज़ाहिर है, है।

अब, चलो एक ही उपयोगकर्ता जो नमूना बैच (अंकों योगदान से डेटा का पूरा अनुक्रम पर नव परिभाषित स्थानीय प्रशिक्षण समारोह की कोशिश 5 )।

locally_trained_model = local_train(initial_model, 0.1, federated_train_data[5])

काम किया? इस प्रश्न का उत्तर देने के लिए, हमें मूल्यांकन को लागू करने की आवश्यकता है।

स्थानीय मूल्यांकन

सभी डेटा बैचों में नुकसान को जोड़कर स्थानीय मूल्यांकन को लागू करने का एक तरीका यहां दिया गया है (हम औसत की गणना भी कर सकते थे; हम इसे पाठक के लिए एक अभ्यास के रूप में छोड़ देंगे)।

@tff.federated_computation(MODEL_TYPE, LOCAL_DATA_TYPE)
def local_eval(model, all_batches):

  @tff.tf_computation(MODEL_TYPE, LOCAL_DATA_TYPE)
  def _insert_model_to_sequence(model, dataset):
    return dataset.map(lambda x: (model, x))

  model_plus_data = _insert_model_to_sequence(model, all_batches)

  @tff.tf_computation(tf.float32, batch_loss.type_signature.result)
  def tff_add(accumulator, arg):
    return accumulator + arg

  return tff.sequence_reduce(
      tff.sequence_map(
          batch_loss,
          model_plus_data), 0., tff_add)
str(local_eval.type_signature)
'(<model=<weights=float32[784,10],bias=float32[10]>,all_batches=<x=float32[?,784],y=int32[?]>*> -> float32)'

फिर से, इस कोड द्वारा कुछ नए तत्वों का चित्रण किया गया है, आइए एक-एक करके उन पर चलते हैं।

सबसे पहले, हम प्रसंस्करण दृश्यों के लिए दो नए फ़ेडरेटेड ऑपरेटरों का इस्तेमाल किया है: tff.sequence_map कि एक मानचित्रण समारोह लेता T->U और के अनुक्रम T , और का एक अनुक्रम का उत्सर्जन करता है U मानचित्रण समारोह pointwise लगाने से प्राप्त की, और tff.sequence_sum कि बस सभी तत्वों को जोड़ता है। यहां, हम प्रत्येक डेटा बैच को हानि मान पर मैप करते हैं, और फिर कुल हानि की गणना करने के लिए परिणामी हानि मान जोड़ते हैं।

ध्यान दें कि हम फिर से इस्तेमाल किया जा सकता था tff.sequence_reduce , लेकिन यह सबसे अच्छा विकल्प नहीं होगा -, कमी प्रक्रिया है, परिभाषा, अनुक्रमिक द्वारा जबकि मानचित्रण और योग समानांतर में गणना की जा सकती। जब कोई विकल्प दिया जाता है, तो उन ऑपरेटरों के साथ रहना सबसे अच्छा होता है जो कार्यान्वयन विकल्पों को बाधित नहीं करते हैं, ताकि जब भविष्य में हमारी TFF गणना को एक विशिष्ट वातावरण में तैनात करने के लिए संकलित किया जाए, तो कोई भी तेजी से सभी संभावित अवसरों का पूरा लाभ उठा सकता है। , अधिक स्केलेबल, अधिक संसाधन-कुशल निष्पादन।

दूसरा, टिप्पणी है कि बस के रूप में local_train , घटक समारोह हम जरूरत ( batch_loss ) क्या फ़ेडरेटेड ऑपरेटर की तुलना में अधिक पैरामीटर लेता है ( tff.sequence_map ) को उम्मीद है, तो हम फिर से सीधे एक लपेटकर द्वारा एक आंशिक, इस बार इनलाइन परिभाषित lambda एक के रूप में tff.federated_computation । रैपर एक तर्क के रूप में एक समारोह के साथ इनलाइन का उपयोग का उपयोग करने की तरीका है tff.tf_computation TFF में करने के लिए एम्बेड TensorFlow तर्क।

अब, देखते हैं कि हमारा प्रशिक्षण काम करता है या नहीं।

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[5]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[5]))
initial_model loss = 23.025854
locally_trained_model loss = 0.43484688

दरअसल घाटा कम हुआ है। लेकिन क्या होता है यदि हम किसी अन्य उपयोगकर्ता के डेटा पर इसका मूल्यांकन करते हैं?

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[0]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[0]))
initial_model loss = 23.025854
locally_trained_model loss = 74.50075

जैसी कि उम्मीद थी, चीजें बदतर होती गईं। मॉडल पहचान करने के लिए प्रशिक्षित किया गया था 5 , और कभी नहीं देखा गया है एक 0 । यह प्रश्न लाता है - स्थानीय प्रशिक्षण ने वैश्विक परिप्रेक्ष्य से मॉडल की गुणवत्ता को कैसे प्रभावित किया?

संघीय मूल्यांकन

यह हमारी यात्रा का वह बिंदु है जहां हम अंत में फ़ेडरेटेड प्रकारों और फ़ेडरेटेड कंप्यूटेशंस पर वापस जाते हैं - जिस विषय से हमने शुरुआत की थी। यहाँ मॉडल के लिए TFF प्रकार की परिभाषाओं की एक जोड़ी है जो सर्वर से उत्पन्न होती है, और डेटा जो क्लाइंट पर रहता है।

SERVER_MODEL_TYPE = tff.type_at_server(MODEL_TYPE)
CLIENT_DATA_TYPE = tff.type_at_clients(LOCAL_DATA_TYPE)

अब तक पेश की गई सभी परिभाषाओं के साथ, TFF में फ़ेडरेटेड मूल्यांकन व्यक्त करना एक-लाइनर है - हम ग्राहकों को मॉडल वितरित करते हैं, प्रत्येक क्लाइंट को डेटा के अपने स्थानीय हिस्से पर स्थानीय मूल्यांकन का आह्वान करने देते हैं, और फिर नुकसान का औसत निकालते हैं। इसे लिखने का एक तरीका ये है।

@tff.federated_computation(SERVER_MODEL_TYPE, CLIENT_DATA_TYPE)
def federated_eval(model, data):
  return tff.federated_mean(
      tff.federated_map(local_eval, [tff.federated_broadcast(model),  data]))

हम पहले से ही के उदाहरण देखा है tff.federated_mean और tff.federated_map सरल परिदृश्यों में, और सहज ज्ञान युक्त स्तर पर, वे अपेक्षा के अनुरूप काम है, लेकिन वहाँ कोड में उससे कहीं के इस अनुभाग में अधिक है, तो चलो ध्यान से इस पर चलते हैं।

सबसे पहले, नीचा दिखाया के टूटने डेटा भाग के अपने स्थानीय वाले हिस्से पर स्थानीय मूल्यांकन आह्वान प्रत्येक ग्राहक करते हैं। आप पूर्ववर्ती वर्गों से याद होगा कि local_eval प्रपत्र का एक प्रकार हस्ताक्षर हैं (<MODEL_TYPE, LOCAL_DATA_TYPE> -> float32)

फ़ेडरेटेड ऑपरेटर tff.federated_map कि एक 2-टपल कि किसी प्रकार की मानचित्रण समारोह के होते हैं एक पैरामीटर के रूप में स्वीकार करता एक टेम्पलेट है T->U और प्रकार का एक फ़ेडरेटेड मूल्य {T}@CLIENTS (यानी, के सदस्य घटकों के साथ मानचित्रण समारोह के पैरामीटर के रूप में एक ही प्रकार के), और रिटर्न प्रकार का एक परिणाम {U}@CLIENTS

हम खिला के बाद से local_eval एक प्रति ग्राहक आधार पर लागू करने के लिए एक मानचित्रण समारोह के रूप में, दूसरा तर्क एक फ़ेडरेटेड प्रकार की होनी चाहिए {<MODEL_TYPE, LOCAL_DATA_TYPE>}@CLIENTS पूर्ववर्ती वर्गों के नामकरण में, यानी,, यह होना चाहिए एक फ़ेडरेटेड टपल बनें। प्रत्येक ग्राहक के लिए तर्क का एक पूरा सेट धारण करना चाहिए local_eval एक सदस्य के रूप में consituent। इसके बजाय, हम यह एक 2-तत्व अजगर खिला रहे हैं list । यहाँ क्या हो रहा है?

दरअसल, इस TFF, अंतर्निहित प्रकार डाले आप कहीं और का सामना करना पड़ा हो सकता है, उदाहरण के लिए के लिए इसी तरह का एक अंतर्निहित प्रकार डाली का एक उदाहरण है जब आप एक फ़ीड है, int एक समारोह है कि एक को स्वीकार करता है करने के लिए float । इस बिंदु पर निहित कास्टिंग का बहुत कम उपयोग किया जाता है, लेकिन हम बॉयलरप्लेट को कम करने के तरीके के रूप में टीएफएफ में इसे और अधिक व्यापक बनाने की योजना बना रहे हैं।

अंतर्निहित डाली कि इस मामले में लागू की गई फार्म के फ़ेडरेटेड tuples के बीच तुल्यता है {<X,Y>}@Z , और फ़ेडरेटेड मूल्यों की tuples <{X}@Z,{Y}@Z> । जबकि औपचारिक रूप से, इन दो अलग अलग प्रकार के हस्ताक्षर हैं, प्रोग्रामर के नजरिए से इसे देख, में प्रत्येक डिवाइस Z डेटा की दो इकाइयों रखती है X और Y । यहां होता विपरीत नहीं है zip अजगर में, और वास्तव में, हम एक ऑपरेटर की पेशकश tff.federated_zip है कि आप इस तरह के रूपांतरण स्पष्ट रूप से प्रदर्शन करने के लिए अनुमति देता है। जब tff.federated_map एक दूसरा तर्क के रूप में एक टपल सामना करता है, यह बस का आह्वान tff.federated_zip आप के लिए।

ऊपर देखते हुए, आप अब अभिव्यक्ति पहचान करने में सक्षम होना चाहिए tff.federated_broadcast(model) TFF प्रकार का एक मूल्य का प्रतिनिधित्व के रूप में {MODEL_TYPE}@CLIENTS , और data TFF प्रकार का एक मूल्य के रूप में {LOCAL_DATA_TYPE}@CLIENTS (या बस CLIENT_DATA_TYPE ) दो एक अंतर्निहित माध्यम से एक साथ फ़िल्टर किया जा रहा tff.federated_zip को दूसरा तर्क के रूप में tff.federated_map

ऑपरेटर tff.federated_broadcast , जैसा कि आप उम्मीद थी, बस डेटा ग्राहकों के लिए सर्वर से स्थानांतरित कर दिया।

अब, देखते हैं कि हमारे स्थानीय प्रशिक्षण ने सिस्टम में औसत नुकसान को कैसे प्रभावित किया।

print('initial_model loss =', federated_eval(initial_model,
                                             federated_train_data))
print('locally_trained_model loss =',
      federated_eval(locally_trained_model, federated_train_data))
initial_model loss = 23.025852
locally_trained_model loss = 54.432625

दरअसल, उम्मीद के मुताबिक घाटा बढ़ गया है। सभी उपयोगकर्ताओं के लिए मॉडल को बेहतर बनाने के लिए, हमें सभी के डेटा को प्रशिक्षित करने की आवश्यकता होगी।

संघीय प्रशिक्षण

फ़ेडरेटेड प्रशिक्षण को लागू करने का सबसे सरल तरीका स्थानीय रूप से प्रशिक्षित करना है, और फिर मॉडल को औसत करना है। यह उसी बिल्डिंग ब्लॉक्स और पैटर्स का उपयोग करता है जिसकी हम पहले ही चर्चा कर चुके हैं, जैसा कि आप नीचे देख सकते हैं।

SERVER_FLOAT_TYPE = tff.type_at_server(tf.float32)


@tff.federated_computation(SERVER_MODEL_TYPE, SERVER_FLOAT_TYPE,
                           CLIENT_DATA_TYPE)
def federated_train(model, learning_rate, data):
  return tff.federated_mean(
      tff.federated_map(local_train, [
          tff.federated_broadcast(model),
          tff.federated_broadcast(learning_rate), data
      ]))

नोट द्वारा प्रदान की संघीय औसत का पूर्ण विशेषताओं कार्यान्वयन में है कि tff.learning , बजाय मॉडल औसत, हम औसत मॉडल डेल्टा करना पसंद करते हैं कई कारणों से, जैसे, अद्यतन मानदंडों क्लिप करने की क्षमता, संपीड़न के लिए, आदि के लिए .

आइए देखें कि प्रशिक्षण के कुछ दौर चलाकर और पहले और बाद में औसत नुकसान की तुलना करके प्रशिक्षण काम करता है या नहीं।

model = initial_model
learning_rate = 0.1
for round_num in range(5):
  model = federated_train(model, learning_rate, federated_train_data)
  learning_rate = learning_rate * 0.9
  loss = federated_eval(model, federated_train_data)
  print('round {}, loss={}'.format(round_num, loss))
round 0, loss=21.60552215576172
round 1, loss=20.365678787231445
round 2, loss=19.27480125427246
round 3, loss=18.311111450195312
round 4, loss=17.45725440979004

पूर्णता के लिए, आइए अब यह पुष्टि करने के लिए परीक्षण डेटा पर भी चलते हैं कि हमारा मॉडल अच्छी तरह से सामान्य है।

print('initial_model test loss =',
      federated_eval(initial_model, federated_test_data))
print('trained_model test loss =', federated_eval(model, federated_test_data))
initial_model test loss = 22.795593
trained_model test loss = 17.278767

यह हमारे ट्यूटोरियल का समापन करता है।

बेशक, हमारा सरलीकृत उदाहरण कई चीजों को प्रतिबिंबित नहीं करता है जिन्हें आपको अधिक यथार्थवादी परिदृश्य में करने की आवश्यकता होगी - उदाहरण के लिए, हमने नुकसान के अलावा अन्य मीट्रिक की गणना नहीं की है। हम अध्ययन करने के लिए प्रोत्साहित करते हैं कार्यान्वयन में फ़ेडरेटेड औसत के tff.learning अधिक पूर्ण उदाहरण के रूप में, और एक तरह से कोडिंग प्रथाओं हम प्रोत्साहित करना चाहते हैं में से कुछ का प्रदर्शन करने के रूप में।