इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

कस्टम फेडरेटेड एल्गोरिदम, भाग 2: फेडरेटेड एवरेजिंग को लागू करना

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें

यह ट्यूटोरियल दो-भाग श्रृंखला का दूसरा भाग है जो यह दर्शाता है कि फेडरेटेड लर्निंग (FL) लेयर ( tff.learning ) के लिए नींव के रूप में कार्य करने वाले Federated Core (FC) का उपयोग करके TFF में कस्टम प्रकार के एल्गोरिदम को कैसे लागू किया जाए। ।

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

श्रृंखला का यह दूसरा भाग पहले भाग में शुरू किए गए तंत्रों का उपयोग करता है, जो कि संघीकृत प्रशिक्षण और मूल्यांकन एल्गोरिदम का एक सरल संस्करण लागू करते हैं।

हम आपको 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

# TODO(b/148678573,b/148685415): must use the reference context because it
# supports unbounded references and tff.sequence_* intrinsics.
tff.backends.reference.set_reference_context()
@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
'Hello, World!'

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

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

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

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

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

02a4db8870
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
11501568/11490434 [==============================] - 0s 0us/step

[(x.dtype, x.shape) for x in mnist_train]
[(dtype('uint8'), (60000, 28, 28)), (dtype('uint8'), (60000,))]

डेटा Numpy सरणियों के रूप में आता है, एक छवियों के साथ और दूसरा अंकों के लेबल के साथ, दोनों पहले आयाम के साथ व्यक्तिगत उदाहरण पर जा रहे हैं। आइए एक सहायक फ़ंक्शन लिखें जो इसे एक तरह से प्रारूपित करता है जिसके साथ हम TFF संगणनाओं में फ़ेडरेटेड अनुक्रमों को कैसे फ़ीड करते हैं, अर्थात, सूचियों की सूची के रूप में - बाहरी सूची जो उपयोगकर्ताओं (अंकों) से अधिक होती है, आंतरिक डेटा के बैचों को लेकर प्रत्येक ग्राहक का क्रम। जैसा कि प्रथागत है, हम प्रत्येक बैच को x और y नाम के दसियों की एक जोड़ी के रूप में संरचना करेंगे, प्रत्येक प्रमुख बैच आयाम के साथ। इसके दौरान, हम प्रत्येक छवि को 784-तत्व वेक्टर में समतल करेंगे और इसमें पिक्सेल को 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)]

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

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()

png

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

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

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

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

अब जब हमारे पास डेटा है, तो एक नुकसान फ़ंक्शन को परिभाषित करें जिसे हम प्रशिक्षण के लिए उपयोग कर सकते हैं। सबसे पहले, एक TFF के नाम के रूप में इनपुट के प्रकार को परिभाषित करें, टुपल। चूंकि डेटा बैचों का आकार भिन्न हो सकता है, इसलिए हम यह इंगित करने के लिए कि None आयाम निर्धारित 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 कम्प्यूटेशन्स केवल औपचारिक रूप से एक पैरामीटर और एक परिणाम घोषित कर सकते हैं - आपको शीघ्र ही इसके उदाहरण दिखाई देंगे।

आइए, अब 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 डेकोरेटर। यह हमें tff.tf_computation डेकोरेटर द्वारा बनाए गए tf.Graph संदर्भ के अंदर होने पर भी शब्दार्थ की तरह Python का उपयोग करके TF लिखने की अनुमति देता है।

# 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-टपल में एक साथ BATCH_TYPE गया है; आप batch_loss के प्रकार को पहचान सकते हैं (<MODEL_TYPE,BATCH_TYPE> -> float32)

str(batch_loss.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,<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.3025854

ध्यान दें कि हम टीएफएफ अभिकलन को एक 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 के ठोस निरूपण के रूप में, आदि)। इसके अलावा, हालांकि जैसा कि ऊपर उल्लेख किया गया है, टीएफएफ अभिकलन केवल एक ही पैरामीटर को औपचारिक रूप से स्वीकार करते हैं, आप स्थिति और / या खोजशब्द तर्क के साथ परिचित पायथन कॉल सिंटैक्स का उपयोग कर सकते हैं, जहां पैरामीटर का प्रकार टपल है - यह अपेक्षित रूप से काम करता है।

एक एकल बैच पर धीरे-धीरे वंश

अब, आइए एक संगणना को परिभाषित करें जो इस नुकसान फ़ंक्शन का उपयोग ढाल वंश के एकल चरण को करने के लिए करती है। ध्यान दें कि इस फ़ंक्शन को कैसे परिभाषित किया जाए, हम एक batch_loss रूप में 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)
'(<<weights=float32[784,10],bias=float32[10]>,<x=float32[?,784],y=int32[?]>,float32> -> <weights=float32[784,10],bias=float32[10]>)'

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

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

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.19690022, 0.13176313, 0.10113226, 0.082738124, 0.0703014]

स्थानीय आंकड़ों के अनुक्रम पर धीरे-धीरे वंश

अब, चूंकि 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):

  # Mapping function to apply to each batch.
  @tff.federated_computation(MODEL_TYPE, BATCH_TYPE)
  def batch_fn(model, batch):
    return batch_train(model, batch, learning_rate)

  return tff.sequence_reduce(all_batches, initial_model, batch_fn)
str(local_train.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,float32,<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 के समान tf.data.Dataset.reduce , लेकिन फेडरेटेड कंप्यूटेशन के अंदर उपयोग के लिए, जिसे आप याद रख सकते हैं, में TensorFlow कोड नहीं हो सकता है। यह एक टेम्प्लेट ऑपरेटर है, जिसमें औपचारिक पैरामीटर 3-टपल होता है, जिसमें T टाइप किए गए तत्वों का एक अनुक्रम होता है, कुछ प्रकार के U की कमी की प्रारंभिक अवस्था (हम इसे शून्य के रूप में संदर्भित करेंगे), और कमी ऑपरेटर प्रकार (<U,T> -> U) जो एक तत्व को संसाधित करके कमी की स्थिति को बदल देता है। एक क्रमिक क्रम में सभी तत्वों को संसाधित करने के बाद, परिणाम में कमी की अंतिम स्थिति है। हमारे उदाहरण में, कमी की स्थिति डेटा के एक उपसर्ग पर प्रशिक्षित मॉडल है, और तत्व डेटा बैच हैं।

दूसरा, ध्यान दें कि हमने एक batch_train ( batch_train ) को एक घटक के रूप में दूसरे ( local_train ) के रूप में उपयोग किया है, लेकिन सीधे। हम इसे एक कमी ऑपरेटर के रूप में उपयोग नहीं कर सकते क्योंकि यह एक अतिरिक्त पैरामीटर लेता है - सीखने की दर। इसे हल करने के लिए, हम एक एम्बेडेड फ़ेडरेटेड कंप्यूटेशन batch_fn को परिभाषित करते हैं जो इसके शरीर में local_train के पैरामीटर learning_rate को बांधता है। जब तक बच्चे की गणना उसके माता-पिता के शरीर के बाहर नहीं की जाती है, तब तक उसे अपने माता-पिता के औपचारिक पैरामीटर पर कब्जा करने के लिए इस तरह परिभाषित एक बाल गणना के लिए अनुमति दी जाती है। आप इस पैटर्न को पायथन में functools.partial बराबर 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):
  # TODO(b/120157713): Replace with `tff.sequence_average()` once implemented.
  return tff.sequence_sum(
      tff.sequence_map(
          tff.federated_computation(lambda b: batch_loss(model, b), BATCH_TYPE),
          all_batches))
str(local_eval.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,<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.federated_computation एक तर्क के रूप में एक फ़ंक्शन के साथ रैपर इनलाइन का उपयोग करना TFF में TensorFlow तर्क को एम्बेड करने के लिए tff.tf_computation का उपयोग करने के लिए अनुशंसित तरीका है।

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

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.4348469

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

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.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 लिए तर्कों का एक पूरा सेट रखना चाहिए। इसके बजाय, हम इसे 2-तत्व पायथन list खिला रहे हैं। यहाँ क्या हो रहा है?

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

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

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

ऑपरेटर 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 द्वारा प्रदान किए गए Federated Averaging के पूर्ण-विशेषताओं वाले कार्यान्वयन में, हम कई कारणों से औसत मॉडल 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.60552406311035
round 1, loss=20.365678787231445
round 2, loss=19.27480125427246
round 3, loss=18.31110954284668
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 में फेडरेटेड औसत के कार्यान्वयन का अध्ययन करने के लिए प्रोत्साहित करते हैं, और कुछ कोडिंग प्रथाओं को प्रदर्शित करने के तरीके के रूप में हम प्रोत्साहित करना चाहते हैं।