این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

آموزش فدرال شده برای طبقه بندی تصویر

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub

در این آموزش ، ما از نمونه آموزش کلاسیک MNIST برای معرفی لایه API Federated Learning (FL) TFF ، tff.learning - مجموعه ای از رابط های سطح بالاتر استفاده می کنیم که می تواند برای انجام انواع متداول کارهای یادگیری فدرال مانند موارد زیر استفاده شود. آموزش فدرال ، در برابر مدل های ارائه شده توسط کاربر که در TensorFlow اجرا شده اند.

این آموزش و API Federated Learning برای کاربرانی که می خواهند مدل های TensorFlow خود را به TFF وصل کنند ، در نظر گرفته شده اند و اکثراً به عنوان یک جعبه سیاه رفتار می کنند. برای درک عمیق تر TFF و نحوه اجرای الگوریتم های یادگیری فدرال خود ، به آموزش های مربوط به FC Core API - الگوریتم های فدرال شده سفارشی قسمت 1 و قسمت 2 مراجعه کنید .

برای کسب اطلاعات بیشتر در مورد tff.learning ، با آموزش فدرال شده برای تولید متن ادامه دهید ، آموزش که علاوه بر پوشش مدلهای مکرر ، بارگیری یک مدل از پیش آماده شده سریال Keras را نیز برای پالایش با یادگیری فدرال به همراه ارزیابی با استفاده از Keras نشان می دهد.

قبل از اینکه شروع کنیم

قبل از شروع کار ، لطفاً موارد زیر را اجرا کنید تا مطمئن شوید محیط شما به درستی تنظیم شده است. اگر سلامی نمی بینید ، برای راهنمایی به راهنمای نصب مراجعه کنید.


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

import nest_asyncio
nest_asyncio.apply()

%load_ext tensorboard
import collections

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

np.random.seed(0)

tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

تهیه داده های ورودی

بیایید با داده شروع کنیم. یادگیری فدرال نیاز به یک مجموعه داده فدرال دارد ، یعنی مجموعه ای از داده ها از چندین کاربر. داده های فدرال به طور معمول غیرقابل توصیف هستند ، که مجموعه ای از چالش های منحصر به فرد را ایجاد می کند.

به منظور تسهیل آزمایش ، مخزن TFF را با چند مجموعه داده از جمله نسخه فدرال شده MNIST که شامل نسخه ای از مجموعه داده اصلی NIST است که با استفاده از Leaf دوباره پردازش شده است ، کاشته ایم تا داده ها توسط نویسنده اصلی ارقام از آنجا که هر نویسنده یک سبک منحصر به فرد دارد ، این مجموعه داده نوع رفتار غیر Iid مورد انتظار از مجموعه داده های فدرال را نشان می دهد.

در اینجا چگونگی بارگذاری آن آورده شده است.

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

مجموعه داده های برگردانده شده توسط load_data() نمونه هایی از tff.simulation.ClientData ، رابطی است که به شما امکان می دهد مجموعه ای از کاربران را tf.data.Dataset ، برای ساختن یک tf.data.Dataset که نمایانگر داده های یک کاربر خاص است ، و پرس و جو کنید ساختار عناصر فردی. در اینجا چگونگی استفاده از این رابط برای کشف محتوای مجموعه داده آورده شده است. به خاطر داشته باشید که در حالی که این رابط به شما امکان می دهد تا بیش از IID های مشتری تکرار کنید ، این تنها ویژگی ای از داده های شبیه سازی است. همانطور که به زودی مشاهده خواهید کرد ، هویت مشتری توسط چارچوب یادگیری فدرال استفاده نمی شود - تنها هدف آنها این است که به شما امکان دهد زیر مجموعه داده ها را برای شبیه سازی انتخاب کنید.

len(emnist_train.client_ids)
3383
emnist_train.element_type_structure
OrderedDict([('pixels', TensorSpec(shape=(28, 28), dtype=tf.float32, name=None)), ('label', TensorSpec(shape=(), dtype=tf.int32, name=None))])
example_dataset = emnist_train.create_tf_dataset_for_client(
    emnist_train.client_ids[0])

example_element = next(iter(example_dataset))

example_element['label'].numpy()
1
from matplotlib import pyplot as plt
plt.imshow(example_element['pixels'].numpy(), cmap='gray', aspect='equal')
plt.grid(False)
_ = plt.show()

png

بررسی ناهمگونی در داده های فدرال

داده های فدرال به طور معمول غیرقابل استفاده هستند ، کاربران معمولاً بسته به الگوهای استفاده توزیع داده های متفاوتی دارند. برخی از مشتری ها ممکن است نمونه های آموزشی کمتری در دستگاه داشته باشند و از کمبود داده در محلی رنج می برند ، در حالی که برخی از مشتریان بیش از نمونه های آموزشی کافی را دارند. بیایید این مفهوم ناهمگونی داده ها را که معمولاً یک سیستم فدرال است با داده های EMNIST که در دسترس داریم ، کشف کنیم. توجه به این نکته حائز اهمیت است که این تحلیل عمیق از داده های مشتری فقط در دسترس ما است زیرا این یک محیط شبیه سازی است که در آن همه داده ها به صورت محلی در دسترس ما قرار می گیرند. در یک محیط واقعی با تولید فدرال ، شما قادر به بازرسی از داده های مشتری تنها نخواهید بود.

ابتدا بیایید نمونه ای از داده های یک مشتری را بگیرید تا از نمونه های موجود در یک دستگاه شبیه سازی شده بهره مند شوید. از آنجا که مجموعه داده ای که ما از آن استفاده می کنیم توسط نویسنده منحصر به فرد کلید خورده است ، داده های یک مشتری نشان دهنده دستنوشت یک شخص برای نمونه ارقام 0 تا 9 است و شبیه سازی الگوی منحصر به فرد استفاده یک کاربر را نشان می دهد.

## Example MNIST digits for one client
figure = plt.figure(figsize=(20, 4))
j = 0

for example in example_dataset.take(40):
  plt.subplot(4, 10, j+1)
  plt.imshow(example['pixels'].numpy(), cmap='gray', aspect='equal')
  plt.axis('off')
  j += 1

png

حال بیایید تعداد نمونه های مربوط به هر مشتری برای هر برچسب رقمی MNIST را تجسم کنیم. در محیط فدرال ، بسته به رفتار کاربر ، تعداد نمونه های مربوط به هر مشتری می تواند کاملاً متفاوت باشد.

# Number of examples per layer for a sample of clients
f = plt.figure(figsize=(12, 7))
f.suptitle('Label Counts for a Sample of Clients')
for i in range(6):
  client_dataset = emnist_train.create_tf_dataset_for_client(
      emnist_train.client_ids[i])
  plot_data = collections.defaultdict(list)
  for example in client_dataset:
    # Append counts individually per label to make plots
    # more colorful instead of one color per plot.
    label = example['label'].numpy()
    plot_data[label].append(label)
  plt.subplot(2, 3, i+1)
  plt.title('Client {}'.format(i))
  for j in range(10):
    plt.hist(
        plot_data[j],
        density=False,
        bins=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

png

حال بیایید میانگین تصویر را برای هر مشتری برای هر برچسب MNIST تجسم کنیم. این کد میانگین هر مقدار پیکسل را برای همه نمونه های کاربر برای یک برچسب تولید می کند. خواهیم دید که میانگین تصویر یک مشتری برای یک رقم متفاوت از میانگین مشتری مشتری برای یک رقم متفاوت است ، این به دلیل سبک دستنویس منحصر به فرد هر شخص است. ما می توانیم درباره اینکه چگونه هر دور آموزش محلی می تواند مدل را در جهت متفاوت برای هر مشتری تنظیم کند ، سرگرم شویم ، همانطور که ما از اطلاعات منحصر به فرد خود کاربر در آن دور محلی می آموزیم. بعداً در این آموزش خواهیم دید که چگونه می توانیم از هر مشتری به روزرسانی کنیم و از آنها استفاده کنیم و مدل جدید جهانی خود را که از داده های منحصر به فرد مشتری خود یاد گرفته است ، جمع کنیم.

# Each client has different mean images, meaning each client will be nudging
# the model in their own directions locally.

for i in range(5):
  client_dataset = emnist_train.create_tf_dataset_for_client(
      emnist_train.client_ids[i])
  plot_data = collections.defaultdict(list)
  for example in client_dataset:
    plot_data[example['label'].numpy()].append(example['pixels'].numpy())
  f = plt.figure(i, figsize=(12, 5))
  f.suptitle("Client #{}'s Mean Image Per Label".format(i))
  for j in range(10):
    mean_img = np.mean(plot_data[j], 0)
    plt.subplot(2, 5, j+1)
    plt.imshow(mean_img.reshape((28, 28)))
    plt.axis('off')

png

png

png

png

png

داده های کاربر می توانند پر سروصدا و غیرقابل اعتماد باشند. به عنوان مثال ، با نگاهی به داده های Client # 2 در بالا ، می توانیم ببینیم که برای برچسب 2 ، ممکن است وجود داشته باشد که برخی از نمونه های اشتباه دارای ایجاد یک تصویر متوسط ​​noisier باشند.

پردازش داده های ورودی

از آنجا که داده ها قبلاً tf.data.Dataset ، پردازش با استفاده از تحولات Dataset می تواند انجام شود. در اینجا ، ما تصاویر 28x28 را در آرایه های 784 مسطح قرار می دهیم ، نمونه های جداگانه را تغییر می دهیم ، آنها را به صورت دسته ای سازمان می دهیم و ویژگی ها را از pixels و label به x و y برای استفاده با Keras تغییر می دهیم. ما همچنین به repeat مجموعه داده ها برای اجرای چندین دوره می پردازیم.

NUM_CLIENTS = 10
NUM_EPOCHS = 5
BATCH_SIZE = 20
SHUFFLE_BUFFER = 100
PREFETCH_BUFFER= 10

def preprocess(dataset):

  def batch_format_fn(element):
    """Flatten a batch `pixels` and return the features as an `OrderedDict`."""
    return collections.OrderedDict(
        x=tf.reshape(element['pixels'], [-1, 784]),
        y=tf.reshape(element['label'], [-1, 1]))

  return dataset.repeat(NUM_EPOCHS).shuffle(SHUFFLE_BUFFER).batch(
      BATCH_SIZE).map(batch_format_fn).prefetch(PREFETCH_BUFFER)

بیایید این کار را تأیید کنیم.

preprocessed_example_dataset = preprocess(example_dataset)

sample_batch = tf.nest.map_structure(lambda x: x.numpy(),
                                     next(iter(preprocessed_example_dataset)))

sample_batch
OrderedDict([('x', array([[1., 1., 1., ..., 1., 1., 1.],
       [1., 1., 1., ..., 1., 1., 1.],
       [1., 1., 1., ..., 1., 1., 1.],
       ...,
       [1., 1., 1., ..., 1., 1., 1.],
       [1., 1., 1., ..., 1., 1., 1.],
       [1., 1., 1., ..., 1., 1., 1.]], dtype=float32)), ('y', array([[2],
       [1],
       [2],
       [3],
       [6],
       [0],
       [1],
       [4],
       [1],
       [0],
       [6],
       [9],
       [9],
       [3],
       [6],
       [1],
       [4],
       [8],
       [0],
       [2]], dtype=int32))])

تقریباً کلیه بلوک های ساختمانی برای ساخت مجموعه داده های فدرال وجود دارد.

یکی از راه های تهیه داده های فدرال شده به TFF در یک شبیه سازی ، صرفاً به عنوان یک لیست پایتون است که هر یک از عناصر لیست ، داده های یک کاربر را ، چه به عنوان لیست و چه به عنوان tf.data.Dataset . از آنجا که ما در حال حاضر یک رابط داریم که دومی را ارائه می دهد ، بیایید از آن استفاده کنیم.

در اینجا یک تابع کمکی ساده وجود دارد که لیستی از مجموعه داده ها را از مجموعه داده های کاربران به عنوان ورودی برای یک دور از آموزش یا ارزیابی ایجاد می کند.

def make_federated_data(client_data, client_ids):
  return [
      preprocess(client_data.create_tf_dataset_for_client(x))
      for x in client_ids
  ]

حال ، چگونه مشتری را انتخاب می کنیم؟

در یک سناریوی آموزش فدراسیون معمولی ، ما با جمعیت بالایی از دستگاههای کاربر سر و کار داریم که تنها بخشی از آن ممکن است در یک زمان معین برای آموزش در دسترس باشد. به عنوان مثال ، هنگامی که دستگاه های سرویس گیرنده تلفن های همراه هستند که فقط با وصل شدن به منبع تغذیه ، خاموش کردن یک شبکه اندازه گیری شده و در غیر این صورت بیکار ، در آموزش شرکت می کنند.

البته ما در یک محیط شبیه سازی قرار داریم و همه داده ها بصورت محلی در دسترس هستند. به طور معمول ، در هنگام اجرای شبیه سازی ها ، ما به سادگی یک زیر مجموعه تصادفی از مشتری ها را انتخاب می کنیم تا در هر دور از آموزش ، به طور کلی در هر دور متفاوت باشند.

این گفته همانطور که می توانید با مطالعه مقاله در مورد الگوریتم Federated Averaging ، دستیابی به همگرایی در یک سیستم با زیرمجموعه های تصادفی از مشتری در هر دور می تواند مدتی طول بکشد ، و غیرممکن است که مجبور به اجرای صدها دور در آن باشید این آموزش تعاملی.

آنچه ما در عوض خواهیم کرد اینست که یک بار از مشتری ها یک بار نمونه برداری کنیم و از همان مجموعه در دور استفاده مجدد برای سرعت بخشیدن به همگرایی (عمداً متناسب با این چند کاربر کاربر) استفاده مجدد کنید. ما آن را به عنوان یک تمرین برای خواننده می گذاریم که این آموزش را برای شبیه سازی نمونه گیری تصادفی اصلاح کند - انجام این کار بسیار ساده است (پس از انجام این کار ، این را بخاطر بسپارید که گرفتن مدل برای همگرایی ممکن است مدتی طول بکشد).

sample_clients = emnist_train.client_ids[0:NUM_CLIENTS]

federated_train_data = make_federated_data(emnist_train, sample_clients)

print('Number of client datasets: {l}'.format(l=len(federated_train_data)))
print('First dataset: {d}'.format(d=federated_train_data[0]))
Number of client datasets: 10
First dataset: <DatasetV1Adapter shapes: OrderedDict([(x, (None, 784)), (y, (None, 1))]), types: OrderedDict([(x, tf.float32), (y, tf.int32)])>

ایجاد یک مدل با کراس

اگر از Keras استفاده می کنید ، احتمالاً قبلاً کدی دارید که یک مدل Keras را ساخته است. در اینجا نمونه ای از یک مدل ساده است که برای نیازهای ما کافی خواهد بود.

def create_keras_model():
  return tf.keras.models.Sequential([
      tf.keras.layers.Input(shape=(784,)),
      tf.keras.layers.Dense(10, kernel_initializer='zeros'),
      tf.keras.layers.Softmax(),
  ])

برای استفاده از هر مدل با TFF ، باید به عنوان نمونه ای از رابط tff.learning.Model شود ، که روش هایی را برای نشان دادن گذرگاه مدل جلو ، خصوصیات ابرداده و غیره ، به طور مشابه با tff.learning.Model معرض دید قرار می دهد ، بلکه معرفی اضافی را نیز ارائه می دهد. عناصر مانند روش های کنترل فرآیند محاسبه معیارهای فدراسیون. اکنون نگران این موضوع نباشیم. اگر یک مدل Keras مانند نمونه ای که قبلاً در بالا تعریف کرده ایم ، دارید می توانید با مراجعه به tff.learning.from_keras_model ، عبور از مدل و یک دسته از داده های نمونه به عنوان آرگومان ، همانطور که در زیر آمده است ، آن را برای شما tff.learning.from_keras_model .

def model_fn():
  # We _must_ create a new model here, and _not_ capture it from an external
  # scope. TFF will call this within different graph contexts.
  keras_model = create_keras_model()
  return tff.learning.from_keras_model(
      keras_model,
      input_spec=preprocessed_example_dataset.element_spec,
      loss=tf.keras.losses.SparseCategoricalCrossentropy(),
      metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])

آموزش مدل در مورد داده های فدرال

اکنون که مدلی را برای استفاده از TFF به عنوان tff.learning.Model ایم ، می توانیم با استناد به عملکرد helper tff.learning.build_federated_averaging_process ، TFF ساخت یک الگوریتم Federated tff.learning.build_federated_averaging_process ، به شرح زیر است.

به خاطر داشته باشید که آرگومان نیاز به سازنده دارد (مانند model_fn بالا) ، نه یک نمونه از قبل ساخته شده ، به طوری که ساختن مدل شما می تواند در بستر کنترل شده توسط TFF اتفاق بیفتد (اگر به دلایل کنجکاو هستید این ، ما شما را تشویق می کنیم تا آموزش پیگیری الگوریتم های سفارشی را بخوانید).

یک نکته مهم در مورد الگوریتم Federated Averaging در زیر ، 2 بهینه ساز وجود دارد: یک بهینه ساز _client و یک بهینه ساز _server. بهینه ساز _client فقط برای محاسبه بروزرسانی های مدل محلی در هر مشتری استفاده می شود. بهینه ساز _server بروزرسانی متوسط ​​را به مدل جهانی در سرور اعمال می کند. به طور خاص ، این بدان معنی است که انتخاب بهینه ساز و میزان یادگیری مورد استفاده ممکن است متفاوت از مواردی باشد که شما برای آموزش مدل در یک مجموعه داده استاندارد iid استفاده کرده اید. توصیه می کنیم با SGD معمولی شروع کنید ، احتمالاً با میزان یادگیری کمتری از حد معمول. میزان یادگیری که ما استفاده می کنیم با دقت تنظیم نشده است ، احساس آزمایشی کنید.

iterative_process = tff.learning.build_federated_averaging_process(
    model_fn,
    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=0.02),
    server_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=1.0))

چه اتفاقی افتاده؟ TFF یک جفت محاسبات فدرال ایجاد کرده و آنها را در یک tff.templates.IterativeProcess بسته بندی کرده است که در آن این محاسبات به صورت یک جفت از خصوصیات initialize و next در دسترس هستند.

به طور خلاصه ، محاسبات federated برنامه هایی به زبان داخلی TFF هستند که می توانند الگوریتم های مختلف فدراسیون را بیان کنند (می توانید اطلاعات بیشتر در مورد این را در آموزش الگوریتم های سفارشی بیابید). در این حالت ، دو محاسبه تولید و بسته بندی شده در iterative_process Federated Averaging را پیاده سازی می کنند.

این هدف از TFF تعریف محاسبات به شکلی است که بتوان آنها را در تنظیمات یادگیری فدراسیون واقعی انجام داد ، اما در حال حاضر فقط زمان اجرای شبیه سازی محلی اجرا است. برای اجرای یک محاسبه در یک شبیه ساز ، شما به سادگی آن را مانند یک عملکرد پایتون فراخوانی می کنید. این محیط تفسیر پیش فرض برای کارایی بالا طراحی نشده است ، اما برای این آموزش کافی است. ما انتظار داریم برای تسهیل تحقیقات در مقیاس بزرگتر در نسخه های آینده ، زمان های شبیه سازی عملکرد بالاتر را فراهم کنیم.

بیایید با محاسبه initialize شروع کنیم. همانطور که برای همه محاسبات فدراسیون وجود دارد ، می توانید به عنوان یک عملکرد به آن فکر کنید. محاسبه هیچ استدلالی به دست نمی آورد و یک نتیجه را به دست می آورد - بازنمایی وضعیت فرایند میانگین Federated Averaging روی سرور. اگرچه ما نمی خواهیم به جزئیات TFF شیرجه بزنیم ، ممکن است آموزنده باشد که ببینیم این حالت چگونه به نظر می رسد. شما می توانید آن را به شرح زیر تجسم کنید.

str(iterative_process.initialize.type_signature)
'( -> <model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<>,model_broadcast_state=<>>@SERVER)'

در حالی که امضای نوع فوق در ابتدا ممکن است کمی رمزنگار به نظر برسد ، می توانید تشخیص دهید که حالت سرور از یک model (پارامترهای مدل اولیه برای MNIST که برای همه دستگاه ها توزیع می شود) ، و optimizer_state (اطلاعات اضافی که توسط سرور نگهداری می شود ، تشکیل شده است. مانند تعداد دورهایی که برای برنامه هایپرپارامتر و غیره استفاده می شود).

بیایید برای محاسبه حالت سرور از محاسبات initialize استفاده کنیم.

state = iterative_process.initialize()

دوم این جفت محاسبات فدرال ، next ، نشان دهنده یک دور واحد از Federated Averaging است که شامل فشار دادن حالت سرور (از جمله پارامترهای مدل) به مشتری ها ، آموزش دستگاه در مورد داده های محلی آنها ، جمع آوری و به روز رسانی میانگین مدل ، و تولید یک مدل جدید به روز شده در سرور.

از نظر مفهومی ، شما می توانید از next به عنوان داشتن یک امضا از نوع کاربردی فکر کنید که به شرح زیر است.

SERVER_STATE, FEDERATED_DATA -> SERVER_STATE, TRAINING_METRICS

به طور خاص ، باید در مورد next() نه به عنوان تابعی که بر روی یک سرور اجرا می شود ، فکر کنیم بلکه باید یک عملکرد کاربردی اعلانی از کل محاسبه غیر متمرکز باشد - برخی از ورودی ها توسط سرور ( SERVER_STATE ) ارائه می شود ، اما هرکدام شرکت می کنند. دستگاه مجموعه داده محلی خود را ارائه می دهد.

بیایید یک دور آموزش را اجرا کنیم و نتایج را تجسم کنیم. ما می توانیم از داده های فدرال شده ای که قبلاً در بالا تولید کرده ایم برای نمونه ای از کاربران استفاده کنیم.

state, metrics = iterative_process.next(state, federated_train_data)
print('round  1, metrics={}'.format(metrics))
round  1, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.12037037312984467,loss=3.0108425617218018>>

بیایید چند دور دیگر اجرا کنیم. همانطور که قبلاً نیز اشاره شد ، به طور معمول در این مرحله زیر مجموعه ای از داده های شبیه سازی خود را از یک نمونه جدید به طور تصادفی از کاربران برای هر دور انتخاب می کنید تا بتوانید یک استقرار واقع بینانه را که در آن کاربران به طور مداوم در می آیند و می روند ، انتخاب کنید اما در این نوت بوک تعاملی به خاطر تظاهرات ، ما فقط از همان کاربران استفاده مجدد خواهیم کرد تا سیستم به سرعت همگرا شود.

NUM_ROUNDS = 11
for round_num in range(2, NUM_ROUNDS):
  state, metrics = iterative_process.next(state, federated_train_data)
  print('round {:2d}, metrics={}'.format(round_num, metrics))
round  2, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.14814814925193787,loss=2.8865506649017334>>
round  3, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.148765429854393,loss=2.9079062938690186>>
round  4, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.17633745074272156,loss=2.724686622619629>>
round  5, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.20226337015628815,loss=2.6334855556488037>>
round  6, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.22427983582019806,loss=2.5482592582702637>>
round  7, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.24094650149345398,loss=2.4472343921661377>>
round  8, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.259876549243927,loss=2.3809611797332764>>
round  9, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.29814815521240234,loss=2.156442403793335>>
round 10, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.31687241792678833,loss=2.122845411300659>>

افت تحصیلی بعد از هر دور از آموزش فدراسیون کاهش می یابد ، نشان می دهد که این مدل در حال همگرایی است. برخی از موارد محرمانه مهم با این معیارهای آموزشی وجود دارد ، با این وجود ، بخش بعدی ارزیابی را بعداً در این آموزش مشاهده کنید.

نمایش معیارهای مدل در TensorBoard

در مرحله بعد ، بیایید معیارهای این محاسبات فدرال را با استفاده از Tensorboard تجسم کنیم.

بیایید با ایجاد فهرست و نویسنده خلاصه مربوطه برای نوشتن معیارها شروع کنیم.


logdir = "/tmp/logs/scalars/training/"
summary_writer = tf.summary.create_file_writer(logdir)
state = iterative_process.initialize()

معیارهای مقیاس مربوطه را با همان خلاصه نویسنده ترسیم کنید.


with summary_writer.as_default():
  for round_num in range(1, NUM_ROUNDS):
    state, metrics = iterative_process.next(state, federated_train_data)
    for name, value in metrics.train._asdict().items():
      tf.summary.scalar(name, value, step=round_num)

TensorBoard را با فهرست راهنمای ریشه مشخص شده در بالا شروع کنید. بارگیری داده ها می تواند چند ثانیه طول بکشد.


%tensorboard --logdir /tmp/logs/scalars/ --port=0

# Run this this cell to clean your directory of old output for future graphs from this directory.
!rm -R /tmp/logs/scalars/*

به منظور مشاهده معیارهای ارزیابی به همین روش ، می توانید یک پوشه Eval جداگانه مانند "logs / scalars / eval" ایجاد کنید تا به TensorBoard بنویسید.

سفارشی سازی اجرای مدل

کراس API مدل سطح بالا برای TensorFlow است که توصیه می شود ، و ما استفاده از مدل های Keras (از طریق tff.learning.from_keras_model ) را در TFF هر زمان ممکن ترغیب می کنیم.

با این حال، tff.learning یک رابط مدل های پایین تر، فراهم می کند tff.learning.Model ، که در معرض قابلیت حداقل لازم برای استفاده از یک مدل برای یادگیری فدرال. اجرای مستقیم این رابط (احتمالاً هنوز هم از بلوک های ساختمانی مانند tf.keras.layers ) اجازه می دهد تا حداکثر سفارشی سازی را بدون تغییر درونی الگوریتم های یادگیری فدرال انجام دهید.

بنابراین بیایید دوباره همه را از ابتدا انجام دهیم.

تعیین متغیرهای مدل ، گذر به جلو و اندازه گیری

اولین قدم شناسایی متغیرهای TensorFlow است که می خواهیم با آنها کار کنیم. برای اینکه خواندن کد زیر قابل خواندن تر باشد ، اجازه دهید یک ساختار داده را تعریف کنیم تا کل مجموعه را نمایندگی کند. این شامل متغیرهایی مانند weights و bias که ما آموزش، و همچنین به عنوان متغیرهای که آمار های مختلف تجمعی و شمارنده ما در طول آموزش به روز رسانی، مانند نگه loss_sum ، accuracy_sum و num_examples .

MnistVariables = collections.namedtuple(
    'MnistVariables', 'weights bias num_examples loss_sum accuracy_sum')

در اینجا روشی است که متغیرها را ایجاد می کند. به خاطر سادگی ، ما تمام آمارها را به عنوان tf.float32 ، زیرا این امر نیاز به تبدیل نوع را در مرحله بعدی از بین می برد. بستن متغیرهای اولیه متغیر به عنوان لامبدا یک الزام است که توسط متغیرهای منابع تحمیل می شود.

def create_mnist_variables():
  return MnistVariables(
      weights=tf.Variable(
          lambda: tf.zeros(dtype=tf.float32, shape=(784, 10)),
          name='weights',
          trainable=True),
      bias=tf.Variable(
          lambda: tf.zeros(dtype=tf.float32, shape=(10)),
          name='bias',
          trainable=True),
      num_examples=tf.Variable(0.0, name='num_examples', trainable=False),
      loss_sum=tf.Variable(0.0, name='loss_sum', trainable=False),
      accuracy_sum=tf.Variable(0.0, name='accuracy_sum', trainable=False))

با متغیرهای متغیرهای پارامترهای مدل و آمارهای تجمعی موجود ، اکنون می توانیم روش عبور پیش رو را که محاسبه تلفات است ، پیش بینی ها را منتشر می کند و آمار تجمعی برای یک دسته از داده های ورودی را به شرح زیر تعریف کنیم.

def mnist_forward_pass(variables, batch):
  y = tf.nn.softmax(tf.matmul(batch['x'], variables.weights) + variables.bias)
  predictions = tf.cast(tf.argmax(y, 1), tf.int32)

  flat_labels = tf.reshape(batch['y'], [-1])
  loss = -tf.reduce_mean(
      tf.reduce_sum(tf.one_hot(flat_labels, 10) * tf.math.log(y), axis=[1]))
  accuracy = tf.reduce_mean(
      tf.cast(tf.equal(predictions, flat_labels), tf.float32))

  num_examples = tf.cast(tf.size(batch['y']), tf.float32)

  variables.num_examples.assign_add(num_examples)
  variables.loss_sum.assign_add(loss * num_examples)
  variables.accuracy_sum.assign_add(accuracy * num_examples)

  return loss, predictions

بعد ، ما تابعی را تعریف می کنیم که مجموعه ای از معیارهای محلی را برمی گرداند ، دوباره با استفاده از TensorFlow. این مقادیر هستند (علاوه بر به روز رسانی های مدل ، که به صورت خودکار انجام می شوند) که واجد شرایط لازم برای سرور در یک فرآیند یادگیری یا ارزیابی فدرال هستند.

در اینجا ، ما به طور متوسط loss و accuracy متوسط ​​، و همچنین num_examples ، که هنگام محاسبه مصالح فدرال شده ، باید به درستی سهم های کاربران مختلف را وزن کنیم.

def get_local_mnist_metrics(variables):
  return collections.OrderedDict(
      num_examples=variables.num_examples,
      loss=variables.loss_sum / variables.num_examples,
      accuracy=variables.accuracy_sum / variables.num_examples)

در آخر ، ما باید نحوه جمع آوری معیارهای محلی منتشر شده توسط هر دستگاه را از طریق get_local_mnist_metrics . این تنها بخشی از کد است که در TensorFlow نوشته نشده است - این یک محاسبه فدرال است که در TFF بیان شده است. اگر می خواهید عمیق تر حفر کنید ، بیش از آموزش الگوریتم های سفارشی بپیچید ، اما در بیشتر برنامه ها ، دیگر نیازی به این کار نخواهید داشت. انواع الگوی نشان داده شده در زیر کافی است. در اینجا به نظر می رسد:

@tff.federated_computation
def aggregate_mnist_metrics_across_clients(metrics):
  return collections.OrderedDict(
      num_examples=tff.federated_sum(metrics.num_examples),
      loss=tff.federated_mean(metrics.loss, metrics.num_examples),
      accuracy=tff.federated_mean(metrics.accuracy, metrics.num_examples))
  

ورودی metrics مربوط آرگومان به OrderedDict بازگردانده شده توسط get_local_mnist_metrics بالا، اما به شدت از ارزش دیگر هستند tf.Tensors - آنها "جعبه" را به عنوان tff.Value S، آن را به روشن شما دیگر نمی تواند آنها را دستکاری با استفاده از TensorFlow، اما تنها با استفاده از اپراتورهای فدراسیون TFF مانند tff.federated_mean و tff.federated_sum . فرهنگ لغت بازگشتی از مجموعه جهانی مجموعه ای از معیارهای موجود در سرور را تعریف می کند.

ساخت نمونه ای از tff.learning.Model

با وجود همه موارد فوق ، ما آماده هستیم تا نمایشی از مدل را برای استفاده با TFF مشابه آنچه که برای شما ایجاد می شود بسازیم.

class MnistModel(tff.learning.Model):

  def __init__(self):
    self._variables = create_mnist_variables()

  @property
  def trainable_variables(self):
    return [self._variables.weights, self._variables.bias]

  @property
  def non_trainable_variables(self):
    return []

  @property
  def local_variables(self):
    return [
        self._variables.num_examples, self._variables.loss_sum,
        self._variables.accuracy_sum
    ]

  @property
  def input_spec(self):
    return collections.OrderedDict(
        x=tf.TensorSpec([None, 784], tf.float32),
        y=tf.TensorSpec([None, 1], tf.int32))

  @tf.function
  def forward_pass(self, batch, training=True):
    del training
    loss, predictions = mnist_forward_pass(self._variables, batch)
    num_exmaples = tf.shape(batch['x'])[0]
    return tff.learning.BatchOutput(
        loss=loss, predictions=predictions, num_examples=num_exmaples)

  @tf.function
  def report_local_outputs(self):
    return get_local_mnist_metrics(self._variables)

  @property
  def federated_output_computation(self):
    return aggregate_mnist_metrics_across_clients

همانطور که مشاهده می کنید ، روشها و خصوصیات انتزاعی تعریف شده توسط tff.learning.Model با قطعه کد در بخش قبل که متغیرها را معرفی کرده و از بین رفته و آمار را تعریف می tff.learning.Model مطابقت دارد.

در اینجا چند نکته قابل ذکر است:

  • تمام حالت هایی که از مدل شما استفاده می شود باید به عنوان متغیرهای TensorFlow ضبط شود ، زیرا TFF در زمان اجرا از پایتون استفاده نمی کند (به یاد داشته باشید که کد شما باید به گونه ای نوشته شود که بتواند در دستگاه های تلفن همراه مستقر شود ؛ برای آموزش عمیق تر به آموزش الگوریتم های سفارشی مراجعه کنید. اظهار نظر در مورد دلایل).
  • مدل شما باید آنچه را شکل داده آن را می پذیرد ( input_spec به طور کلی)، به عنوان، TFF یک محیط به شدت تایپ است و می خواهد برای تعیین امضا نوع برای تمام اجزای. اعلام قالب ورودی مدل شما بخش اساسی آن است.
  • اگرچه از نظر فنی لازم نیست ، ما توصیه می کنیم تمام منطق TensorFlow (پاس رو به جلو ، محاسبات متریک ، و غیره) را به عنوان tf.function s tf.function ، زیرا این امر به اطمینان از سریال شدن tf.function کمک می کند ، و نیاز به وابستگی های کنترل صریح را برطرف می کند.

موارد فوق برای ارزیابی و الگوریتم هایی مانند Federated SGD کافی است. با این حال ، برای Federated Averaging ، باید مشخص کنیم که چگونه این مدل باید به صورت محلی در هر دسته آموزش دهد. ما هنگام ساخت الگوریتم Federated Averaging بهینه ساز محلی را مشخص خواهیم کرد.

شبیه سازی آموزش فدراسیون با مدل جدید

با وجود تمام موارد فوق ، باقی مانده روند مانند آنچه قبلاً دیده بودیم به نظر می رسد - فقط سازنده مدل را با سازنده کلاس مدل جدید خود جایگزین کنید و از دو محاسبه فدرال در فرآیند تکراری که ایجاد کرده اید استفاده کنید. دورهای آموزشی

iterative_process = tff.learning.build_federated_averaging_process(
    MnistModel,
    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=0.02))
state = iterative_process.initialize()
state, metrics = iterative_process.next(state, federated_train_data)
print('round  1, metrics={}'.format(metrics))
round  1, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.9713594913482666,accuracy=0.13518518209457397>>

for round_num in range(2, 11):
  state, metrics = iterative_process.next(state, federated_train_data)
  print('round {:2d}, metrics={}'.format(round_num, metrics))
round  2, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.975412607192993,accuracy=0.14032921195030212>>
round  3, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.9395227432250977,accuracy=0.1594650149345398>>
round  4, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.710164785385132,accuracy=0.17139917612075806>>
round  5, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.5891618728637695,accuracy=0.20267489552497864>>
round  6, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.5148487091064453,accuracy=0.21666666865348816>>
round  7, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.2816808223724365,accuracy=0.2580246925354004>>
round  8, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.3656885623931885,accuracy=0.25884774327278137>>
round  9, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.23549222946167,accuracy=0.28477364778518677>>
round 10, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=1.974222183227539,accuracy=0.35329216718673706>>

برای دیدن این معیارها در TensorBoard ، به مراحل ذکر شده در بالا "نمایش اندازه گیری مدل در TensorBoard" مراجعه کنید.

ارزیابی

تمام آزمایش های ما تاکنون فقط معیارهای آموزش فدرال را ارائه داده اند - میانگین معیارهای مربوط به دادههای آموزش داده شده در تمام مشتریها در طول دور. این نگرانی های عادی راجع به بیش از حد اتصالات ایجاد می کند ، به خصوص اینکه ما در هر دور برای همین سادگی از همان مجموعه مشتری استفاده می کردیم ، اما در معیارهای آموزشی مخصوص الگوریتم Federated Averaging یک مفهوم اضافی نیز وجود دارد. این ساده ترین است برای دیدن اینکه آیا تصور می کنیم هر مشتری یک دسته داده واحد داشته باشد یا خیر ، برای بسیاری از تکرارها (دوره ها) روی آن دسته از آموزشها آموزش می دهیم. در این حالت ، مدل محلی به سرعت دقیقاً متناسب با آن یک دسته خواهد بود و بنابراین ، اندازه گیری دقت محلی که به طور متوسط ​​داریم به 1.0 خواهد رسید. بنابراین ، این معیارهای آموزشی می تواند به عنوان نشانه پیشرفت آموزش در نظر گرفته شود ، اما نه بیشتر.

برای انجام ارزیابی بر روی داده های فدرال ، می توانید محاسبه فدرال شده دیگری را که فقط برای این منظور طراحی شده است ، با استفاده از عملکرد tff.learning.build_federated_evaluation ، و عبور در سازنده مدل خود به عنوان آرگومان ساخت. توجه داشته باشید که برخلاف Federated MnistTrainableModel ، جایی که ما از MnistTrainableModel استفاده کرده MnistTrainableModel ، کافی است که MnistModel را تصویب کنید. ارزیابی نزولی شیب ایجاد نمی کند ، و نیازی به ساخت بهینه ساز نیست.

برای آزمایش و تحقیق ، هنگامی که یک مجموعه داده های آزمون متمرکز موجود است ، Federated Learning for Generation گزینه دیگری برای ارزیابی نشان می دهد: گرفتن وزنه های آموزش دیده از یادگیری فدرال ، استفاده از آنها در یک مدل استاندارد tf.keras.models.Model.evaluate() و سپس به سادگی با tf.keras.models.Model.evaluate() در tf.keras.models.Model.evaluate() در یک مجموعه داده متمرکز.

evaluation = tff.learning.build_federated_evaluation(MnistModel)

می توانید امضای نوع انتزاعی تابع ارزیابی را به شرح زیر بازرسی کنید.

str(evaluation.type_signature)
'(<<trainable=<float32[784,10],float32[10]>,non_trainable=<>>@SERVER,{<x=float32[?,784],y=int32[?,1]>*}@CLIENTS> -> <num_examples=float32@SERVER,loss=float32@SERVER,accuracy=float32@SERVER>)'

نیازی به نگرانی در مورد جزئیات در این مرحله نیست ، فقط توجه داشته باشید که شکل کلی زیر را می گیرد ، مشابه tff.templates.IterativeProcess.next اما با دو تفاوت مهم. اول ، ما حالت سرور را برنمی گردانیم ، زیرا ارزیابی مدل یا هر جنبه ای از حالت دیگر را تغییر نمی دهد - می توانید درباره آن بی تابعیت فکر کنید. دوم ، ارزیابی فقط به مدل احتیاج دارد و به بخش دیگری از حالت سرور که ممکن است با آموزش همراه باشد ، مانند متغیرهای بهینه ساز ، نیازی ندارد.

SERVER_MODEL, FEDERATED_DATA -> TRAINING_METRICS

بیایید از آخرین وضعیتی که در طی آموزش به آن رسیده ایم ، ارزیابی کنیم. برای استخراج آخرین مدل آموزش دیده از حالت سرور ، شما به سادگی به عنوان .model دسترسی دارید ، به شرح زیر است.

train_metrics = evaluation(state.model, federated_train_data)

این چیزی است که ما دریافت می کنیم. توجه داشته باشید که اعداد از نظر ظاهری بسیار بهتر از آنچه در آخرین دوره آموزش فوق گزارش شده است. طبق کنوانسیون ، معیارهای آموزشی گزارش شده توسط فرآیند آموزش تکراری ، عموماً عملکرد مدل را در ابتدای دوره آموزش منعکس می کنند ، بنابراین معیارهای ارزیابی همیشه یک قدم جلوتر خواهند بود.

str(train_metrics)
'<num_examples=4860.0,loss=1.7142657041549683,accuracy=0.38683128356933594>'

حال ، بیایید یک نمونه آزمایشی از داده های فدرال شده و ارزیابی مجدد در داده های آزمون را جمع آوری کنیم. داده ها از همان نمونه کاربران واقعی تهیه می شوند ، اما از یک مجموعه داده جداگانه برگزار می شود.

federated_test_data = make_federated_data(emnist_test, sample_clients)

len(federated_test_data), federated_test_data[0]
(10,
 <DatasetV1Adapter shapes: OrderedDict([(x, (None, 784)), (y, (None, 1))]), types: OrderedDict([(x, tf.float32), (y, tf.int32)])>)
test_metrics = evaluation(state.model, federated_test_data)
str(test_metrics)
'<num_examples=580.0,loss=1.861915111541748,accuracy=0.3362068831920624>'

این نتیجه گیری آموزش است. ما شما را ترغیب می کنیم که با پارامترها (به عنوان مثال ، تعداد دسته ها ، تعداد کاربران ، دوره ها ، نرخ یادگیری و غیره) بازی کنید ، برای تغییر کد فوق ، برای شبیه سازی آموزش در نمونه های تصادفی کاربران در هر دور ، و کشف سایر آموزش ها ما توسعه داده ایم