بناء خوارزمية التعلم الموحدة الخاصة بك

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

قبل أن نبدأ

قبل أن نبدأ ، يرجى تشغيل ما يلي للتأكد من إعداد بيئتك بشكل صحيح. إذا كنت لا ترى تحية، يرجى الرجوع إلى تركيب دليل للتعليمات.

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

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

في تصنيف الصور و النص جيل الدروس، وتعلمنا كيفية إعداد نموذج وبيانات خطوط أنابيب للاتحاد التعلم (FL)، وتنفيذ التدريب الاتحادية عبر tff.learning طبقة API من TFF.

هذا ليس سوى غيض من فيض عندما يتعلق الأمر بأبحاث FL. في هذا البرنامج التعليمي، ونحن نناقش كيفية تطبيق خوارزميات التعلم الاتحادية دون تأجيل إلى tff.learning API. نهدف إلى تحقيق ما يلي:

الأهداف:

  • فهم الهيكل العام لخوارزميات التعلم الموحد.
  • استكشاف الاتحادية الأساسية من TFF.
  • استخدم المركز الموحد لتنفيذ المتوسطات الموحدة مباشرة.

في حين أن هذا البرنامج التعليمي هو بذاته، ونحن نوصي القراءة الأولى ل تصنيف الصور و توليد النص الدروس.

تجهيز بيانات الإدخال

نقوم أولاً بتحميل مجموعة بيانات EMNIST المضمنة في TFF ومعالجتها مسبقًا. لمزيد من التفاصيل، راجع تصنيف الصور البرنامج التعليمي.

emnist_train, emnist_test = tff.simulation.datasets.emnist.load_data()

من أجل إطعام مجموعة البيانات في نموذج لدينا، وتتسطح البيانات، وتحويل كل المثال في الصفوف (tuple) من النموذج (flattened_image_vector, label) .

NUM_CLIENTS = 10
BATCH_SIZE = 20

def preprocess(dataset):

  def batch_format_fn(element):
    """Flatten a batch of EMNIST data and return a (features, label) tuple."""
    return (tf.reshape(element['pixels'], [-1, 784]), 
            tf.reshape(element['label'], [-1, 1]))

  return dataset.batch(BATCH_SIZE).map(batch_format_fn)

نختار الآن عددًا صغيرًا من العملاء ، ونطبق المعالجة المسبقة أعلاه على مجموعات البيانات الخاصة بهم.

client_ids = sorted(emnist_train.client_ids)[:NUM_CLIENTS]
federated_train_data = [preprocess(emnist_train.create_tf_dataset_for_client(x))
  for x in client_ids
]

تحضير النموذج

نحن نستخدم نفس النموذج كما هو الحال في تصنيف الصور البرنامج التعليمي. هذا النموذج (نفذت عبر tf.keras ) يحتوي على طبقة مخفية واحدة، تليها طبقة softmax.

def create_keras_model():
  initializer = tf.keras.initializers.GlorotNormal(seed=0)
  return tf.keras.models.Sequential([
      tf.keras.layers.Input(shape=(784,)),
      tf.keras.layers.Dense(10, kernel_initializer=initializer),
      tf.keras.layers.Softmax(),
  ])

من أجل استخدام هذا النموذج في TFF، نحن التفاف نموذج Keras باعتباره tff.learning.Model . وهذا يسمح لنا لأداء النموذج تمريرة إلى الأمام داخل TFF، و مخرجات استخراج النموذج . لمزيد من التفاصيل، انظر أيضا تصنيف الصور البرنامج التعليمي.

def model_fn():
  keras_model = create_keras_model()
  return tff.learning.from_keras_model(
      keras_model,
      input_spec=federated_train_data[0].element_spec,
      loss=tf.keras.losses.SparseCategoricalCrossentropy(),
      metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])

بينما كنا tf.keras لخلق tff.learning.Model ، TFF تدعم نماذج أعم من ذلك بكثير. تحتوي هذه النماذج على السمات التالية ذات الصلة التي تلتقط أوزان النموذج:

  • trainable_variables : وiterable من التنسورات الموافق طبقات قابلة للتدريب.
  • non_trainable_variables : وiterable من التنسورات الموافق طبقات غير قابلة للتدريب.

لأغراضنا، سوف نستخدم فقط trainable_variables . (لأن نموذجنا لديه هؤلاء فقط!).

بناء خوارزمية التعلم الموحدة الخاصة بك

في حين أن tff.learning API يسمح احد لإنشاء العديد من المتغيرات من اتحاد المتوسط، وهناك خوارزميات الاتحادية الأخرى التي لا تتفق تماما مع هذا الإطار. على سبيل المثال، قد ترغب في إضافة التنظيم، لقطة، أو خوارزميات أكثر تعقيدا مثل التدريب GAN الاتحادية . يمكن أيضا أن تكون بدلا من ذلك تكون مهتمة في تحليلات الاتحادية .

بالنسبة لهذه الخوارزميات الأكثر تقدمًا ، سيتعين علينا كتابة خوارزمية مخصصة خاصة بنا باستخدام TFF. في كثير من الحالات ، تحتوي الخوارزميات الموحدة على 4 مكونات رئيسية:

  1. خطوة بث من خادم إلى عميل.
  2. خطوة تحديث العميل المحلي.
  3. خطوة تحميل من عميل إلى خادم.
  4. خطوة تحديث الخادم.

في TFF، التي نمثلها عموما خوارزميات الاتحادية باعتبارها tff.templates.IterativeProcess (والذي نطلق عليه مجرد IterativeProcess طوال). هذا هو الفئة التي تحتوي initialize و next الوظائف. هنا، initialize يستخدم لتهيئة الخادم، و next سوف تؤدي جولة اتصال واحد من الخوارزمية الاتحادية. لنكتب هيكلًا لما يجب أن تبدو عليه عمليتنا التكرارية لـ FedAvg.

أولا، لدينا وظيفة تهيئة ببساطة يخلق tff.learning.Model ، وإرجاع الأوزان لها المدربة.

def initialize_fn():
  model = model_fn()
  return model.trainable_variables

تبدو هذه الوظيفة جيدة ، ولكن كما سنرى لاحقًا ، سنحتاج إلى إجراء تعديل بسيط لجعلها "حساب TFF".

نحن نريد أيضا أن أرسم next_fn .

def next_fn(server_weights, federated_dataset):
  # Broadcast the server weights to the clients.
  server_weights_at_client = broadcast(server_weights)

  # Each client computes their updated weights.
  client_weights = client_update(federated_dataset, server_weights_at_client)

  # The server averages these updates.
  mean_client_weights = mean(client_weights)

  # The server updates its model.
  server_weights = server_update(mean_client_weights)

  return server_weights

سنركز على تنفيذ هذه المكونات الأربعة بشكل منفصل. نركز أولاً على الأجزاء التي يمكن تنفيذها في TensorFlow الخالص ، أي خطوات تحديث العميل والخادم.

كتل TensorFlow

تحديث العميل

سوف نستخدم لدينا tff.learning.Model للقيام التدريب العميل في الأساس بنفس الطريقة التي تدرب نموذج TensorFlow. على وجه الخصوص، سوف نستخدم tf.GradientTape لحساب التدرج على دفعات من البيانات، ثم تطبيق هذه التدرج باستخدام client_optimizer . نحن نركز فقط على الأوزان القابلة للتدريب.

@tf.function
def client_update(model, dataset, server_weights, client_optimizer):
  """Performs training (using the server model weights) on the client's dataset."""
  # Initialize the client model with the current server weights.
  client_weights = model.trainable_variables
  # Assign the server weights to the client model.
  tf.nest.map_structure(lambda x, y: x.assign(y),
                        client_weights, server_weights)

  # Use the client_optimizer to update the local model.
  for batch in dataset:
    with tf.GradientTape() as tape:
      # Compute a forward pass on the batch of data
      outputs = model.forward_pass(batch)

    # Compute the corresponding gradient
    grads = tape.gradient(outputs.loss, client_weights)
    grads_and_vars = zip(grads, client_weights)

    # Apply the gradient using a client optimizer.
    client_optimizer.apply_gradients(grads_and_vars)

  return client_weights

تحديث الخادم

تحديث الخادم لـ FedAvg أبسط من تحديث العميل. سنقوم بتنفيذ متوسط ​​"الفانيليا" الموحد ، حيث نقوم ببساطة باستبدال أوزان نموذج الخادم بمتوسط ​​أوزان نموذج العميل. مرة أخرى ، نحن نركز فقط على الأوزان القابلة للتدريب.

@tf.function
def server_update(model, mean_client_weights):
  """Updates the server model weights as the average of the client model weights."""
  model_weights = model.trainable_variables
  # Assign the mean client weights to the server model.
  tf.nest.map_structure(lambda x, y: x.assign(y),
                        model_weights, mean_client_weights)
  return model_weights

يمكن تبسيط المتكررة ببساطة عن طريق إعادة mean_client_weights . ومع ذلك، تطبيقات أكثر تقدما من الاتحادية استخدام المتوسط mean_client_weights مع تقنيات أكثر تطورا، مثل الزخم أو قابلية التكيف.

التحدي: تنفيذ نسخة من server_update يقوم بتحديث أوزان الخادم لتكون نقطة الوسط من model_weights وmean_client_weights. (ملاحظة: هذا النوع من النهج "منتصف" مشابه لعمل مؤخرا على محسن Lookahead !).

حتى الآن ، قمنا فقط بكتابة كود TensorFlow النقي. هذا حسب التصميم ، حيث يتيح لك TFF استخدام الكثير من كود TensorFlow الذي تعرفه بالفعل. ومع ذلك، والآن لدينا لتحديد المنطق تزامن، وهذا هو، والمنطق الذي تمليه ما لبث الملقم إلى العميل، وما هي الإضافات العميل إلى الملقم.

وسوف يتطلب ذلك ميكرونيزيا الأساسية من TFF.

مقدمة في النواة الموحدة

وميكرونيزيا الأساسية (FC) هو مجموعة من واجهات أقل من المستوى التي تشكل الأساس ل tff.learning API. ومع ذلك ، لا تقتصر هذه الواجهات على التعلم. في الواقع ، يمكن استخدامها للتحليلات والعديد من الحسابات الأخرى على البيانات الموزعة.

على مستوى عالٍ ، فإن النواة الموحدة هي بيئة تطوير تتيح لمنطق البرنامج المعبر عنه بشكل مضغوط دمج كود TensorFlow مع مشغلي الاتصالات الموزعة (مثل المبالغ الموزعة والبث). الهدف هو منح الباحثين والممارسين التحكم في الاتصال الموزع في أنظمتهم ، دون الحاجة إلى تفاصيل تنفيذ النظام (مثل تحديد تبادل رسائل الشبكة من نقطة إلى نقطة).

تتمثل إحدى النقاط الرئيسية في أن TFF مصمم للحفاظ على الخصوصية. لذلك ، فإنه يسمح بالتحكم الصريح في مكان تواجد البيانات ، لمنع التراكم غير المرغوب فيه للبيانات في موقع الخادم المركزي.

البيانات الموحدة

المفهوم الرئيسي في TFF هو "البيانات الموحدة" ، والتي تشير إلى مجموعة من عناصر البيانات المستضافة عبر مجموعة من الأجهزة في نظام موزع (على سبيل المثال ، مجموعات بيانات العميل ، أو أوزان نموذج الخادم). نحن نموذج لمجموعة كاملة من عناصر البيانات عبر جميع الأجهزة كقيمة الاتحادية واحدة.

على سبيل المثال ، لنفترض أن لدينا أجهزة عميل لكل منها عوامة تمثل درجة حرارة المستشعر. نحن يمكن أن تمثل أنها تطفو الاتحادية من قبل

federated_float_on_clients = tff.FederatedType(tf.float32, tff.CLIENTS)

يتم تحديد أنواع الاتحادية من نوع T المكونات الأعضاء فيها (على سبيل المثال. tf.float32 ) ومجموعة G من الأجهزة. وسوف نركز على الحالات التي يكون فيها G إما tff.CLIENTS أو tff.SERVER . ويمثل هذا النوع الاتحادية كما {T}@G ، كما هو مبين أدناه.

str(federated_float_on_clients)
'{float32}@CLIENTS'

لماذا نهتم كثيرًا بالمواضع؟ الهدف الرئيسي من TFF هو تمكين كتابة التعليمات البرمجية التي يمكن نشرها على نظام موزع حقيقي. هذا يعني أنه من الضروري التفكير في أي مجموعات فرعية من الأجهزة تنفذ أي كود ، وأين توجد أجزاء مختلفة من البيانات.

يركز TFF على ثلاثة أمور: البيانات، حيث يتم وضع البيانات، وكيف يتم تحويل البيانات. يتم تغليف الأولين في أنواع الاتحادية، في حين يتم تغليف الأخير في الحسابات الاتحادية.

الحسابات الموحدة

TFF هي بيئة البرمجة الوظيفية كتابة بشدة التي هي الحسابات الاتحادية الوحدات الأساسية. هذه أجزاء من المنطق تقبل القيم الموحدة كمدخلات ، وترجع القيم الموحدة كمخرجات.

على سبيل المثال ، لنفترض أننا أردنا حساب متوسط ​​درجات الحرارة على أجهزة استشعار عملائنا. يمكننا تحديد ما يلي (باستخدام تعويمنا الموحد):

@tff.federated_computation(tff.FederatedType(tf.float32, tff.CLIENTS))
def get_average_temperature(client_temperatures):
  return tff.federated_mean(client_temperatures)

قد تسأل، كيف يختلف هذا من tf.function الديكور في TensorFlow؟ الجواب الرئيسية هي أن الشفرة التي تم إنشاؤها من قبل tff.federated_computation ليست TensorFlow ولا بيثون المدونه؛ ومن مواصفات نظام توزيع في منصة مستقلة لغة الغراء الداخلية.

في حين أن هذا قد يبدو معقدًا ، يمكنك التفكير في حسابات TFF كوظائف ذات توقيعات كتابة محددة جيدًا. يمكن الاستعلام مباشرة عن هذه التواقيع.

str(get_average_temperature.type_signature)
'({float32}@CLIENTS -> float32@SERVER)'

هذا tff.federated_computation يقبل حجج من نوع الاتحادية {float32}@CLIENTS ، والقيم عوائد نوع الاتحادية {float32}@SERVER . قد تنتقل الحسابات الموحدة أيضًا من خادم إلى عميل ، أو من عميل إلى عميل ، أو من خادم إلى خادم. يمكن أيضًا تكوين الحسابات الموحدة مثل الوظائف العادية ، طالما أن تواقيع النوع الخاصة بها تتطابق.

لدعم التنمية، TFF يسمح لك لاستدعاء tff.federated_computation بوصفها وظيفة بيثون. على سبيل المثال ، يمكننا الاتصال

get_average_temperature([68.5, 70.3, 69.8])
69.53334

الحسابات غير المتلهفة و TensorFlow

هناك نوعان من القيود الرئيسية التي يجب أن تكون على دراية بها. أولا، عندما يصادف مترجم Python ل tff.federated_computation الديكور، وتتبع وظيفة مرة واحدة وتسلسل للاستخدام مستقبلا. نظرًا للطبيعة اللامركزية للتعلم الفيدرالي ، فقد يحدث هذا الاستخدام المستقبلي في مكان آخر ، مثل بيئة التنفيذ عن بُعد. ولذلك، حسابات TFF هي في الأساس غير متحمسة. هذا السلوك هو مشابه إلى حد ما من tf.function الديكور في TensorFlow.

ثانيا، يمكن للحساب اتحادية تتكون فقط من مشغلي الاتحادية (مثل tff.federated_mean )، فإنها لا يمكن أن تحتوي على عمليات TensorFlow. يجب أن يقتصر كود TensorFlow إلى كتل مزينة tff.tf_computation . معظم كود TensorFlow العاديين يمكن تزيين مباشرة، مثل الدالة التالية التي تأخذ رقما ويضيف 0.5 إليها.

@tff.tf_computation(tf.float32)
def add_half(x):
  return tf.add(x, 0.5)

هذه أيضا نوع التوقيعات، ولكن من دون المواضع. على سبيل المثال ، يمكننا الاتصال

str(add_half.type_signature)
'(float32 -> float32)'

وهنا نرى فارقا مهما بين tff.federated_computation و tff.tf_computation . يحتوي الأول على مواضع صريحة ، بينما لا يحتوي الأخير على مواضع أخرى.

يمكننا استخدام tff.tf_computation الكتل في الحسابات الاتحادية لتحديد المواضع. لنقم بإنشاء دالة تضيف النصف ، ولكن فقط إلى العوامات الموحدة عند العملاء. يمكننا القيام بذلك عن طريق استخدام tff.federated_map ، وهو ما ينطبق معين tff.tf_computation ، مع الحفاظ على التنسيب.

@tff.federated_computation(tff.FederatedType(tf.float32, tff.CLIENTS))
def add_half_on_clients(x):
  return tff.federated_map(add_half, x)

هذه هي وظيفة مماثلة تقريبا ل add_half ، إلا أنه لا يقبل إلا القيم مع وضع في tff.CLIENTS ، والقيم العائدات مع نفس وضع. يمكننا أن نرى هذا في توقيعه النوع:

str(add_half_on_clients.type_signature)
'({float32}@CLIENTS -> {float32}@CLIENTS)'

باختصار:

  • TFF يعمل على القيم الموحدة.
  • كل قيمة الاتحادية لديها نوع الاتحادية، مع نوع (على سبيل المثال. tf.float32 ) ووضع (على سبيل المثال. tff.CLIENTS ).
  • يمكن أن تتحول القيم الاتحادية باستخدام العمليات الحسابية الاتحادية، والتي يجب أن تكون مزينة tff.federated_computation ونوع توقيع الاتحادية.
  • يجب أن تكون موجودة كود TensorFlow في كتل مع tff.tf_computation الديكور.
  • يمكن بعد ذلك دمج هذه الكتل في الحسابات الموحدة.

إعادة بناء خوارزمية التعلم الموحد الخاصة بك

الآن وقد حصلنا على لمحة عن Federated Core ، يمكننا بناء خوارزمية التعلم الموحدة الخاصة بنا. تذكر أن أعلاه، حددنا ل initialize_fn و next_fn لخوارزمية لدينا. و next_fn والاستفادة من client_update و server_update حددنا باستخدام رمز TensorFlow النقي.

ومع ذلك، من أجل جعل خوارزمية لدينا عملية حسابية الاتحادية، فإننا سوف تحتاج إلى كل من next_fn و initialize_fn الى ان تكون كل و tff.federated_computation .

كتل TensorFlow الموحدة

إنشاء حساب التهيئة

فإن وظيفة تهيئة تكون بسيطة جدا: سوف نقوم إنشاء نموذج باستخدام model_fn . ومع ذلك، تذكر أنه يجب علينا أن فصل كود TensorFlow لدينا باستخدام tff.tf_computation .

@tff.tf_computation
def server_init():
  model = model_fn()
  return model.trainable_variables

يمكننا ثم تمرير هذا مباشرة إلى حساب الاتحادية باستخدام tff.federated_value .

@tff.federated_computation
def initialize_fn():
  return tff.federated_value(server_init(), tff.SERVER)

إنشاء next_fn

نستخدم الآن كود تحديث العميل والخادم لكتابة الخوارزمية الفعلية. سوف ننتقل أولا لدينا client_update إلى tff.tf_computation يقبل مجموعات البيانات العميل والأوزان الخادم، والنواتج محدث الأوزان العميل الموترة.

سنحتاج إلى الأنواع المقابلة لتزيين وظيفتنا بشكل صحيح. لحسن الحظ ، يمكن استخراج نوع أوزان الخادم مباشرة من نموذجنا.

whimsy_model = model_fn()
tf_dataset_type = tff.SequenceType(whimsy_model.input_spec)

لنلقِ نظرة على توقيع نوع مجموعة البيانات. تذكر أننا أخذنا 28 × 28 صورة (مع تسميات عدد صحيح) وقمنا بتسويتها.

str(tf_dataset_type)
'<float32[?,784],int32[?,1]>*'

يمكننا أيضا استخراج نوع الأوزان نموذج عن طريق استخدام server_init وظيفة أعلاه.

model_weights_type = server_init.type_signature.result

عند فحص توقيع النوع ، سنتمكن من رؤية بنية نموذجنا!

str(model_weights_type)
'<float32[784,10],float32[10]>'

يمكننا الآن إنشاء لدينا tff.tf_computation لتحديث العميل.

@tff.tf_computation(tf_dataset_type, model_weights_type)
def client_update_fn(tf_dataset, server_weights):
  model = model_fn()
  client_optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
  return client_update(model, tf_dataset, server_weights, client_optimizer)

و tff.tf_computation يمكن تعريف إصدار التحديث الخادم بطريقة مماثلة، وذلك باستخدام أنواع لقد انتزعت بالفعل.

@tff.tf_computation(model_weights_type)
def server_update_fn(mean_client_weights):
  model = model_fn()
  return server_update(model, mean_client_weights)

وأخيرا، وليس آخرا، نحن بحاجة إلى خلق tff.federated_computation الذي يجمع كل هذا معا. وهذه وظيفة قبول قيمتين الاتحادية، واحدة الموافق الأوزان الخادم (مع وضع tff.SERVER )، والمقابلة البعض لمجموعات البيانات العميل (مع وضع tff.CLIENTS ).

لاحظ أن كلا النوعين تم تعريفهما أعلاه! نحتاج ببساطة لمنحهم وضع مناسب باستخدام tff.FederatedType .

federated_server_type = tff.FederatedType(model_weights_type, tff.SERVER)
federated_dataset_type = tff.FederatedType(tf_dataset_type, tff.CLIENTS)

تذكر العناصر الأربعة لخوارزمية FL؟

  1. خطوة بث من خادم إلى عميل.
  2. خطوة تحديث العميل المحلي.
  3. خطوة تحميل من عميل إلى خادم.
  4. خطوة تحديث الخادم.

الآن بعد أن قمنا ببناء ما سبق ، يمكن تمثيل كل جزء بشكل مضغوط كسطر واحد من كود TFF. هذه البساطة هي سبب وجوب توخي الحذر الشديد لتحديد أشياء مثل الأنواع الموحدة!

@tff.federated_computation(federated_server_type, federated_dataset_type)
def next_fn(server_weights, federated_dataset):
  # Broadcast the server weights to the clients.
  server_weights_at_client = tff.federated_broadcast(server_weights)

  # Each client computes their updated weights.
  client_weights = tff.federated_map(
      client_update_fn, (federated_dataset, server_weights_at_client))

  # The server averages these updates.
  mean_client_weights = tff.federated_mean(client_weights)

  # The server updates its model.
  server_weights = tff.federated_map(server_update_fn, mean_client_weights)

  return server_weights

لدينا الآن tff.federated_computation لكل من التهيئة الخوارزمية، ولتشغيل خطوة واحدة من الخوارزمية. لإنهاء خوارزمية لدينا، وتمرير هذه إلى tff.templates.IterativeProcess .

federated_algorithm = tff.templates.IterativeProcess(
    initialize_fn=initialize_fn,
    next_fn=next_fn
)

دعونا ننظر نوع التوقيع على initialize و next مهام عملية تكرارية لدينا.

str(federated_algorithm.initialize.type_signature)
'( -> <float32[784,10],float32[10]>@SERVER)'

وهذا يعكس حقيقة أن federated_algorithm.initialize هي وظيفة عدم ARG أن عائدات نموذج طبقة واحدة (مع الوزن مصفوفة 784-ب-10، و 10 وحدات التحيز).

str(federated_algorithm.next.type_signature)
'(<server_weights=<float32[784,10],float32[10]>@SERVER,federated_dataset={<float32[?,784],int32[?,1]>*}@CLIENTS> -> <float32[784,10],float32[10]>@SERVER)'

هنا، نرى أن federated_algorithm.next يقبل نموذج الخادم وبيانات العملاء، والعوائد نموذج الخادم المحدثة.

تقييم الخوارزمية

دعونا نجري بضع جولات ، ونرى كيف تتغير الخسارة. أولا، فإننا سوف تحديد وظيفة التقييم باستخدام النهج المركزي مناقشتها في البرنامج التعليمي الثاني.

نقوم أولاً بإنشاء مجموعة بيانات تقييم مركزية ، ثم نطبق نفس المعالجة المسبقة التي استخدمناها لبيانات التدريب.

central_emnist_test = emnist_test.create_tf_dataset_from_all_clients()
central_emnist_test = preprocess(central_emnist_test)

بعد ذلك ، نكتب دالة تقبل حالة الخادم ، وتستخدم Keras للتقييم على مجموعة بيانات الاختبار. إذا كنت على دراية tf.Keras ، وهذا سوف جميع تبدو مألوفة، على الرغم من ملاحظة استخدام set_weights !

def evaluate(server_state):
  keras_model = create_keras_model()
  keras_model.compile(
      loss=tf.keras.losses.SparseCategoricalCrossentropy(),
      metrics=[tf.keras.metrics.SparseCategoricalAccuracy()]  
  )
  keras_model.set_weights(server_state)
  keras_model.evaluate(central_emnist_test)

الآن ، دعنا نبدأ الخوارزمية ونقيم الاختبار على مجموعة الاختبار.

server_state = federated_algorithm.initialize()
evaluate(server_state)
2042/2042 [==============================] - 2s 767us/step - loss: 2.8479 - sparse_categorical_accuracy: 0.1027

دعنا نتدرب لبضع جولات ونرى ما إذا كان أي شيء يتغير.

for round in range(15):
  server_state = federated_algorithm.next(server_state, federated_train_data)
evaluate(server_state)
2042/2042 [==============================] - 2s 738us/step - loss: 2.5867 - sparse_categorical_accuracy: 0.0980

نرى انخفاضًا طفيفًا في وظيفة الخسارة. في حين أن القفزة صغيرة ، فقد أجرينا 15 جولة تدريبية فقط ، وعلى مجموعة فرعية صغيرة من العملاء. لرؤية نتائج أفضل ، قد نضطر إلى القيام بالمئات إن لم يكن الآلاف من الجولات.

تعديل خوارزمية لدينا

في هذه المرحلة ، دعنا نتوقف ونفكر فيما أنجزناه. لقد قمنا بتنفيذ Federated Averaging مباشرة من خلال الجمع بين كود TensorFlow الخالص (لتحديثات العميل والخادم) مع الحسابات الموحدة من Federated Core of TFF.

لأداء المزيد من التعلم المتطور ، يمكننا ببساطة تغيير ما لدينا أعلاه. على وجه الخصوص ، من خلال تحرير رمز TF النقي أعلاه ، يمكننا تغيير كيفية أداء العميل للتدريب ، أو كيفية تحديث الخادم لنموذجه.

التحدي: إضافة لقطة الانحدار إلى client_update وظيفة.

إذا أردنا إجراء تغييرات أكبر ، فيمكننا أيضًا الحصول على مخزن الخادم وبث المزيد من البيانات. على سبيل المثال ، يمكن للخادم أيضًا تخزين معدل تعلم العميل ، وجعله يتحلل بمرور الوقت! لاحظ أن هذا سوف يتطلب تغييرات على التوقيعات النوع الذي يستخدم في tff.tf_computation تدعو أعلاه.

أصعب تحدي: تنفيذ اتحاد المتوسط مع تعلم تسوس سعر الفائدة على العملاء.

في هذه المرحلة ، قد تبدأ في إدراك مقدار المرونة الموجودة في ما يمكنك تنفيذه في هذا الإطار. للحصول على أفكار (بما في ذلك الإجابة على التحدي الصعب أعلاه) تستطيع أن ترى في التعليمات البرمجية المصدر ل tff.learning.build_federated_averaging_process ، أو تحقق من مختلف المشاريع البحثية باستخدام TFF.