تاریخ را ذخیره کنید! Google I / O 18-20 مه بازمی گردد اکنون ثبت نام کنید
این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

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

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

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

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

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

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

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

# tensorflow_federated_nightly also bring in tf_nightly, which
# can causes a duplicate tensorboard install, leading to errors.
!pip uninstall --yes tensorboard tb-nightly

!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio
!pip install --quiet --upgrade tb-nightly  # or tensorboard, but not both

import nest_asyncio
nest_asyncio.apply()
%load_ext tensorboard
Fetching TensorBoard MPM... done.
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 که نشان دهنده داده های یک کاربر خاص است ، و پرس و جو کنید ساختار عناصر منفرد در اینجا نحوه استفاده از این رابط برای کشف محتوای مجموعه داده ها آورده شده است. بخاطر داشته باشید که گرچه این رابط به شما امکان می دهد تا از طریق شناسه های مشتری تکرار شوید ، این تنها ویژگی داده های شبیه سازی است. همانطور که به زودی خواهید دید ، هویت مشتری توسط چارچوب یادگیری فدرال استفاده نمی شود - تنها هدف آنها این است که به شما امکان انتخاب زیر مجموعه داده ها را برای شبیه سازی بدهد.

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

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

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

از آنجا که داده ها در حال حاضر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([[0],
       [5],
       [0],
       [1],
       [3],
       [0],
       [5],
       [4],
       [1],
       [7],
       [0],
       [4],
       [0],
       [1],
       [7],
       [2],
       [2],
       [0],
       [7],
       [1]], 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
  ]

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

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

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

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

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

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 استفاده می کنید ، احتمالاً قبلاً کدی دارید که مدل 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 بسته بندی شود ، که روش هایی را برای مهر زدن به جلو مدل ، خصوصیات متادیتا و غیره مانند Keras نشان می دهد ، اما همچنین موارد اضافی را نیز معرفی می کند. عناصر ، مانند روش های کنترل روند محاسبه معیارهای فدراسیون. فعلاً نگران این موضوع نباشیم. اگر شما یک مدل Keras دارید مانند نمونه ای که ما در بالا تعریف کردیم ، می توانید TFF را با فراخوانی 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.learning.Model پیچیده شده است. tff.learning.Model برای استفاده با TFF ، می توانیم با فراخوانی از تابع helper tff.learning.build_federated_averaging_process به شرح زیر ، به TFF الگوریتم متوسط ​​سازی فدرال را tff.learning.build_federated_averaging_process .

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

یک نکته مهم در مورد الگوریتم میانگین فدراسیون در زیر ، 2 بهینه ساز وجود دارد: یک بهینه ساز برای مشتری و یک بهینه ساز برای سرور. _client optimizer فقط برای محاسبه به روزرسانی های مدل محلی روی هر مشتری استفاده می شود. _server optimizer میانگین بروزرسانی را در مدل جهانی در سرور اعمال می کند. به طور خاص ، این بدان معنی است که انتخاب بهینه ساز و میزان یادگیری مورد استفاده ممکن است متفاوت از مواردی باشد که شما برای آموزش مدل در یک مجموعه داده استاندارد 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 .

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

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

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

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

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

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

state = iterative_process.initialize()

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

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

SERVER_STATE, FEDERATED_DATA -> SERVER_STATE, TRAINING_METRICS

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

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

state, metrics = iterative_process.next(state, federated_train_data)
print('round  1, metrics={}'.format(metrics))
round  1, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.11502057), ('loss', 3.244929)]))])

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

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=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.14609054), ('loss', 2.9141645)]))])
round  3, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.15205762), ('loss', 2.9237952)]))])
round  4, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.18600823), ('loss', 2.7629454)]))])
round  5, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.20884773), ('loss', 2.622908)]))])
round  6, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.21872428), ('loss', 2.543587)]))])
round  7, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.2372428), ('loss', 2.4210362)]))])
round  8, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.28209877), ('loss', 2.2297976)]))])
round  9, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.2685185), ('loss', 2.195803)]))])
round 10, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.33868313), ('loss', 2.0523348)]))])

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

نمایش معیارهای مدل در 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'].items():
      tf.summary.scalar(name, value, step=round_num)

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

!ls {logdir}
%tensorboard --logdir {logdir} --port=0
events.out.tfevents.1604020204.isim77-20020ad609500000b02900f40f27a5f6.prod.google.com.686098.10633.v2
events.out.tfevents.1604020602.isim77-20020ad609500000b02900f40f27a5f6.prod.google.com.794554.10607.v2
Launching TensorBoard...
<IPython.core.display.Javascript at 0x7fc5e8d3c128>
# Uncomment and run this this cell to clean your directory of old output for
# future graphs from this directory. We don't run it by default so that if 
# you do a "Runtime > Run all" you don't lose your results.

# !rm -R /tmp/logs/scalars/*

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

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

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

با این حال، tff.learning یک رابط مدل های پایین تر، فراهم می کند tff.learning.Model ، که در معرض قابلیت حداقل لازم برای استفاده از یک مدل برای یادگیری فدرال. اجرای مستقیم این رابط (احتمالاً هنوز با استفاده از بلوک هایtf.keras.layers مانند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 ، زیرا در مرحله بعد دیگر نیازی به تبدیل نوع نیست. بسته بندی مقادیر اولیه به عنوان lambdas الزامی است که توسط متغیرهای منابع تحمیل می شود.

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 نیستند. tf.Tensors - آنها به عنوان tff.Value "جعبه" tff.Value ، برای اینکه روشن شود دیگر نمی توانید آنها را با استفاده از TensorFlow دستکاری کنید ، اما فقط با استفاده از اپراتورهای فدراسیون TFF مانند tff.federated_mean و tff.federated_sum . فرهنگ نامه گردآوری شده از مجموعه های جهانی مجموعه معیارهایی را که در سرور در دسترس خواهد بود ، تعریف می کند.

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

با در نظر گرفتن تمام موارد ذکر شده ، ما آماده ساختن یک نمایش مدل برای استفاده با TFF مشابه نمونه ای هستیم که برای شما ایجاد می شود وقتی اجازه می دهید TFF یک مدل Keras را مصرف کند.

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 مربوط به قطعه های کد موجود در بخش قبلی است که متغیرها را معرفی کرده و میزان تلفات و آمار را تعریف می کند.

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

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

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

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

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

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=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 3.1527398), ('accuracy', 0.12469136)]))])
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=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.941014), ('accuracy', 0.14218107)]))])
round  3, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.9052832), ('accuracy', 0.14444445)]))])
round  4, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.7491086), ('accuracy', 0.17962962)]))])
round  5, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.5129666), ('accuracy', 0.19526748)]))])
round  6, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.4175923), ('accuracy', 0.23600823)]))])
round  7, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.4273515), ('accuracy', 0.24176955)]))])
round  8, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.2426176), ('accuracy', 0.2802469)]))])
round  9, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.1567981), ('accuracy', 0.295679)]))])
round 10, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('value_sum_process', ()), ('weight_sum_process', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.1092515), ('accuracy', 0.30843621)]))])

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

ارزیابی

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

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

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

evaluation = tff.learning.build_federated_evaluation(MnistModel)

می توانید امضای انتزاعی نوع عملکرد را به صورت زیر بازبینی کنید.

str(evaluation.type_signature)
'(<server_model_weights=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>@SERVER,federated_dataset={<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>'

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