Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

Görüntü Sınıflandırma için Birleşik Öğrenme

TensorFlow.org'da görüntüleyin Google Colab'de çalıştırın Kaynağı GitHub'da görüntüleyin

Bu öğreticide, klasik MNIST eğitim örneğini, TFF'nin Federated Learning (FL) API katmanı olan tff.learning tanıtmak için tff.learning - örneğin, ortak türdeki federe öğrenme görevlerini gerçekleştirmek için kullanılabilecek bir dizi üst düzey arabirim: TensorFlow'da uygulanan kullanıcı tarafından sağlanan modellere karşı birleşik eğitim.

Bu eğitim ve Federated Learning API, öncelikle kendi TensorFlow modellerini TFF'ye bağlamak isteyen kullanıcılar için tasarlanmıştır ve ikincisini çoğunlukla kara kutu olarak ele alır. TFF hakkında daha derinlemesine bir anlayış ve kendi birleşik öğrenme algoritmalarınızı nasıl uygulayacağınız için, FC Core API - Özel Birleşik Algoritmalar Bölüm 1 ve Bölüm 2'deki öğreticilere bakın.

tff.learning hakkında daha fazla bilgi için , Yinelenen modelleri kapsamaya ek olarak, tff.learning kullanarak değerlendirmeyle birlikte federe öğrenme ile iyileştirme için önceden eğitilmiş serileştirilmiş bir Keras modelinin yüklenmesini de gösteren Metin Oluşturma için Federasyon Öğrenimi ile devam edin.

Başlamadan önce

Başlamadan önce, lütfen ortamınızın doğru kurulduğundan emin olmak için aşağıdakileri çalıştırın. Bir karşılama mesajı görmezseniz, talimatlar için lütfen Kurulum kılavuzuna bakın.


!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!'

Giriş verilerinin hazırlanması

Verilerle başlayalım. Birleşik öğrenme, birleşik bir veri kümesi, yani birden çok kullanıcıdan bir veri koleksiyonu gerektirir. Birleşik veriler tipik olarak iid değildir ve bu da benzersiz bir dizi zorluk oluşturur.

Denemeyi kolaylaştırmak için, TFF havuzunu, verinin orijinal yazarı tarafından anahtarlanacak şekilde Leaf kullanılarak yeniden işlenen orijinal NIST veri kümesinin bir sürümünü içeren birleştirilmiş MNIST sürümü de dahil olmak üzere birkaç veri kümesiyle tohumladık. rakamlar. Her yazarın benzersiz bir stili olduğundan, bu veri kümesi, federe veri kümelerinden beklenen iid olmayan davranış türünü sergiler.

İşte nasıl yükleyebileceğimiz.

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

load_data() tarafından döndürülen veri kümeleri, kullanıcı kümesini numaralandırmanıza, belirli bir kullanıcının verilerini temsil eden bir tf.data.Dataset oluşturmanıza ve belirli bir kullanıcının verilerini sorgulamanıza olanak tanıyan bir arabirim olan tff.simulation.ClientData örnekleridir. bireysel elemanların yapısı. Veri kümesinin içeriğini keşfetmek için bu arayüzü nasıl kullanabileceğiniz aşağıda açıklanmıştır. Bu arayüz istemci kimlikleri üzerinde yineleme yapmanıza izin verirken, bunun yalnızca simülasyon verilerinin bir özelliği olduğunu unutmayın. Kısaca göreceğiniz gibi, müşteri kimlikleri federe öğrenme çerçevesi tarafından kullanılmaz - bunların tek amacı, simülasyonlar için verilerin alt kümelerini seçmenize izin vermektir.

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

Birleşik verilerdeki heterojenliği keşfetmek

Birleşik veriler tipik olarak iid değildir , kullanıcılar tipik olarak kullanım modellerine bağlı olarak farklı veri dağıtımlarına sahiptir. Bazı müşteriler cihazda daha az eğitim örneğine sahip olabilir ve yerel olarak veri kıtlığından muzdarip olabilirken, bazı müşterilerde yeterince eğitim örneği olacaktır. Elimizdeki EMNIST verileriyle, federe bir sisteme özgü bu veri heterojenliği kavramını inceleyelim. Bir müşterinin verilerinin bu derin analizinin yalnızca bizim için mevcut olduğunu unutmamak önemlidir çünkü bu, tüm verilerin yerel olarak bizim için erişilebilir olduğu bir simülasyon ortamıdır. Gerçek bir üretim birleşik ortamında, tek bir müşterinin verilerini inceleyemezsiniz.

İlk olarak, simüle edilmiş bir cihazdaki örneklere bir fikir vermek için bir müşterinin verilerinden bir örnek alalım. Kullandığımız veri kümesi benzersiz bir yazar tarafından anahtarlandığı için, bir müşterinin verileri, bir kullanıcının benzersiz "kullanım modelini" simüle ederek, 0'dan 9'a kadar olan rakamların bir örneği için bir kişinin el yazısını temsil eder.

## 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

Şimdi her MNIST basamak etiketi için her istemcideki örnek sayısını görselleştirelim. Federasyon ortamında, her istemcideki örnek sayısı, kullanıcı davranışına bağlı olarak oldukça değişebilir.

# 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

Şimdi her MNIST etiketi için istemci başına ortalama görüntüyü görselleştirelim. Bu kod, bir etiket için tüm kullanıcı örnekleri için her piksel değerinin ortalamasını üretecektir. Bir müşterinin bir basamak için ortalama görüntüsünün, her bir kişinin benzersiz el yazısı stili nedeniyle, aynı basamak için başka bir müşterinin ortalama görüntüsünden farklı görüneceğini göreceğiz. Her bir yerel eğitim turunun, o yerel turda o kullanıcının kendi benzersiz verilerinden öğrenirken, her bir müşteride modeli farklı bir yöne nasıl sürükleyeceğini düşünebiliriz. Öğreticinin ilerleyen kısımlarında, tüm müşterilerden modele yönelik her bir güncellemeyi nasıl alabileceğimizi ve bunları müşterimizin her birinden kendi benzersiz verilerinden öğrenen yeni küresel modelimizde nasıl bir araya getirebileceğimizi göreceğiz.

# 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

Kullanıcı verileri gürültülü olabilir ve güvenilir olmayan şekilde etiketlenebilir. Örneğin, Müşteri # 2'nin yukarıdaki verilerine baktığımızda, etiket 2 için, daha gürültülü bir ortalama görüntü oluşturan bazı yanlış etiketlenmiş örneklerin olabileceğini görebiliriz.

Giriş verilerini ön işleme

Veriler zaten bir tf.data.Dataset , ön işleme Veri Kümesi dönüşümleri kullanılarak gerçekleştirilebilir. Burada, 28x28 görüntüleri 784 28x28 diziler halinde düzleştiriyoruz, tek tek örnekleri karıştırıyoruz, bunları gruplar halinde organize ediyoruz ve 28x28 için özellikleri pixels ve label x ve y yeniden adlandırıyoruz. Ayrıca, birkaç dönemi çalıştırmak için veri kümesinin üzerine bir repeat atıyoruz.

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)

Bunun işe yaradığını doğrulayalım.

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

Birleşik veri kümeleri oluşturmak için neredeyse tüm yapı taşlarına sahibiz.

Bir simülasyonda birleşik verileri TFF'ye beslemenin yollarından biri, basitçe bir Python listesi gibidir; listenin her öğesi, ister liste olarak ister tf.data.Dataset olarak tek bir kullanıcının verilerini tf.data.Dataset . Zaten ikincisini sağlayan bir arayüzümüz olduğundan, onu kullanalım.

Burada, bir eğitim veya değerlendirme turuna girdi olarak verilen kullanıcı kümesinden bir veri kümesi listesi oluşturacak basit bir yardımcı işlev bulunmaktadır.

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

Şimdi, müşterileri nasıl seçeceğiz?

Tipik bir birleşik eğitim senaryosunda, belirli bir noktada eğitim için yalnızca küçük bir kısmının mevcut olabileceği potansiyel olarak çok büyük bir kullanıcı cihazı popülasyonuyla uğraşıyoruz. Bu, örneğin, istemci cihazların yalnızca bir güç kaynağına takıldığında, ölçülü bir ağa bağlı olmadığında veya başka şekilde boşta olduğunda eğitime katılan cep telefonları olduğu durumlarda geçerlidir.

Elbette bir simülasyon ortamındayız ve tüm veriler yerel olarak mevcut. Tipik olarak, simülasyonları çalıştırırken, genellikle her turda farklı olmak üzere, her eğitim turuna dahil olacak istemcilerin rastgele bir alt kümesini örneklemekteyiz.

Bununla birlikte, Federe Ortalama algoritması hakkındaki makaleyi inceleyerek de bulabileceğiniz gibi, her turda rastgele örneklenmiş müşteri alt kümeleri olan bir sistemde yakınsama elde etmek biraz zaman alabilir ve içinde yüzlerce tur koşmak pratik olmazdı. bu etkileşimli öğretici.

Bunun yerine yapacağımız şey, istemci kümesini bir kez örneklemek ve yakınsamayı hızlandırmak için (kasıtlı olarak bu birkaç kullanıcı verilerine kasıtlı olarak fazla uymak) aynı kümeyi turlar boyunca yeniden kullanmaktır. Okuyucunun bu öğreticiyi rastgele örneklemeyi simüle edecek şekilde değiştirmesini bir alıştırma olarak bırakıyoruz - bunu yapmak oldukça kolaydır (bir kez yaptıktan sonra, modeli bir araya getirmenin biraz zaman alabileceğini unutmayın).

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 ile bir model oluşturma

Keras kullanıyorsanız, muhtemelen bir Keras modeli oluşturan koda sahipsinizdir. İşte ihtiyaçlarımıza yetecek basit bir model örneği.

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 ile herhangi bir modeli kullanmak için, tff.learning.Model benzer şekilde modelin ileri geçişini, meta veri özelliklerini vb. tff.learning.Model yöntemleri ortaya çıkaran tff.learning.Model arabiriminin bir örneğine sarılması gerekir, ancak aynı zamanda ek federe ölçümleri hesaplama sürecini kontrol etme yolları gibi öğeler. Şimdilik bunun için endişelenmeyelim; Yukarıda tanımladığımız gibi bir tff.learning.from_keras_model modeliniz tff.learning.from_keras_model , aşağıda gösterildiği gibi tff.learning.from_keras_model çağırarak, modeli ve örnek bir veri grubunu bağımsız değişken olarak geçirerek TFF'nin onu sizin için sarmalamasını sağlayabilirsiniz.

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

Modeli birleşik veriler üzerinde eğitme

Artık TFF ile kullanmak için tff.learning.Model olarak sarılmış bir modelimiz tff.learning.Model , TFF'nin aşağıdaki gibi yardımcı işlevi tff.learning.build_federated_averaging_process çağırarak bir Birleşik Ortalama algoritması oluşturmasına izin verebiliriz.

Modelinizin inşasının TFF tarafından kontrol edilen bir bağlamda gerçekleşebilmesi için argümanın önceden oluşturulmuş bir örnek değil (yukarıdaki model_fn gibi) bir yapıcı olması gerektiğini unutmayın (nedenlerini merak ediyorsanız bu, özel algoritmalarla ilgili takip eğitimini okumanızı öneririz).

Aşağıdaki Birleşik Ortalama algoritmasıyla ilgili kritik bir not, 2 iyileştirici vardır: bir _client iyileştirici ve bir _server iyileştirici . _Client iyileştirici , yalnızca her istemcide yerel model güncellemelerini hesaplamak için kullanılır. _Server iyileştirici , ortalama güncellemeyi sunucudaki genel modele uygular. Özellikle bu, kullanılan optimize edici ve öğrenme oranının, modeli standart bir kimlik veri setinde eğitmek için kullandıklarınızdan farklı olması gerekebileceği anlamına gelir. Normal SGD ile başlamanızı öneririz, muhtemelen normalden daha düşük bir öğrenme oranıyla. Kullandığımız öğrenme oranı dikkatlice ayarlanmadı, denemekten çekinmeyin.

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

Az önce ne oldu? TFF, bir çift birleşik hesaplama oluşturdu ve bunları bir tff.templates.IterativeProcess . Bu hesaplamaların, bir özellik çifti initialize next kullanılabilir olduğu tff.templates.IterativeProcess .

Özetle, federe hesaplamalar , çeşitli federe algoritmaları ifade edebilen TFF'nin dahili dilinde programlardır (bu konuda daha fazla bilgiyi özel algoritmalar eğitiminde bulabilirsiniz). Bu durumda, üretilen ve iterative_process içine paketlenen iki hesaplama Federated Averaging'i uygular.

Hesaplamaları gerçek federe öğrenme ayarlarında yürütülebilecek şekilde tanımlamak TFF'nin bir amacıdır, ancak şu anda yalnızca yerel yürütme simülasyonu çalışma zamanı uygulanmaktadır. Bir simülatörde bir hesaplama yapmak için, onu bir Python işlevi gibi çalıştırmanız yeterlidir. Bu varsayılan olarak yorumlanan ortam, yüksek performans için tasarlanmamıştır, ancak bu eğitim için yeterli olacaktır; Gelecekteki sürümlerde daha büyük ölçekli araştırmaları kolaylaştırmak için daha yüksek performanslı simülasyon çalışma zamanları sağlamayı umuyoruz.

initialize hesaplamasıyla başlayalım. Tüm federe hesaplamalarda olduğu gibi, bunu bir işlev olarak düşünebilirsiniz. Hesaplama hiçbir argüman almaz ve tek bir sonuç döndürür - Sunucuda Birleşik Ortalama Alma işleminin durumunun temsili. TFF'nin ayrıntılarına dalmak istemesek de, bu durumun neye benzediğini görmek öğretici olabilir. Aşağıdaki gibi görselleştirebilirsiniz.

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

Yukarıdaki tip imzası ilk başta biraz şifreli görünse de, sunucu durumunun bir model (tüm cihazlara dağıtılacak olan MNIST için ilk model parametreleri) ve optimizer_state (sunucu tarafından tutulan ek bilgiler, hiperparametre programları için kullanılacak tur sayısı gibi).

Sunucu durumunu oluşturmak için initialize hesaplamasını çağıralım.

state = iterative_process.initialize()

Bir next hesaplama çiftinin ikincisi, sunucu durumunun (model parametreleri dahil) istemcilere iletilmesinden, yerel verileri üzerinde cihaz üzerinde eğitimden, model güncellemelerinin toplanmasından ve ortalamasının alınmasından oluşan tek bir Federasyon Ortalama Alma turunu temsil eder. ve sunucuda yeni bir güncellenmiş model üretme.

Kavramsal olarak, aklınıza gelebilecek next bakışlar olarak izler fonksiyonel tip imzasını sahip olarak.

SERVER_STATE, FEDERATED_DATA -> SERVER_STATE, TRAINING_METRICS

Özellikle next() 'yi bir sunucuda çalışan bir işlev olarak değil, tüm merkezi olmayan hesaplamanın bildirimsel işlevsel bir temsili olarak düşünmek gerekir - bazı girdiler sunucu ( SERVER_STATE ) tarafından sağlanır, ancak her katılımcı cihaz kendi yerel veri kümesine katkıda bulunur.

Tek bir eğitim turu yapalım ve sonuçları görselleştirelim. Yukarıda oluşturduğumuz federe verileri bir kullanıcı grubu için kullanabiliriz.

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

Birkaç tur daha koşalım. Daha önce belirtildiği gibi, tipik olarak bu noktada, kullanıcıların sürekli gelip gittiği gerçekçi bir dağıtımı simüle etmek için her tur için rastgele seçilen yeni bir kullanıcı örneğinden simülasyon verilerinizin bir alt kümesini seçersiniz, ancak bu etkileşimli not defterinde, Gösterim uğruna, sistemin hızlı bir şekilde yakınlaşması için aynı kullanıcıları yeniden kullanacağız.

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

Eğitim kaybı, her bir federe eğitim turundan sonra azalıyor, bu da modelin yakınsadığını gösteriyor. Bu eğitim metrikleriyle ilgili bazı önemli uyarılar vardır, ancak bu eğitimde daha sonra yer alan Değerlendirme bölümüne bakın.

TensorBoard'da model ölçümlerini görüntüleme

Ardından, Tensorboard kullanarak bu birleşik hesaplamalardan gelen ölçümleri görselleştirelim.

Metriklerin yazılacağı dizini ve karşılık gelen özet yazıcısını oluşturarak başlayalım.


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

İlgili skaler metrikleri aynı özet yazarı ile çizin.


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'u yukarıda belirtilen kök günlük diziniyle başlatın. Verilerin yüklenmesi birkaç saniye sürebilir.


%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/*

Değerlendirme metriklerini aynı şekilde görüntülemek için, TensorBoard'a yazmak üzere "logs / scalars / eval" gibi ayrı bir eval klasörü oluşturabilirsiniz.

Model uygulamasını özelleştirme

Keras , TensorFlow için önerilen üst düzey model API'sidir ve mümkün olduğunda tff.learning.from_keras_model modellerini ( tff.learning.from_keras_model aracılığıyla) kullanmanızı öneririz.

Bununla birlikte, tff.learning , federe öğrenme için bir model kullanmak için gereken minimum işlevselliği ortaya çıkaran daha düşük düzey bir model arabirimi olan tff.learning.Model . Bu arabirimi doğrudan uygulamak (muhtemelen hala tf.keras.layers gibi yapı taşlarını kullanmak), birleşik öğrenme algoritmalarının iç tf.keras.layers değiştirmeden maksimum özelleştirmeye izin verir.

Öyleyse her şeyi en baştan yapalım.

Model değişkenlerini, ileri geçişi ve metrikleri tanımlama

İlk adım, üzerinde çalışacağımız TensorFlow değişkenlerini belirlemektir. Aşağıdaki kodu daha okunaklı hale getirmek için tüm seti temsil edecek bir veri yapısı tanımlayalım. Bu, eğiteceğimiz weights ve bias gibi değişkenlerin yanı sıra, çeşitli kümülatif istatistikleri ve loss_sum , accuracy_sum ve num_examples gibi eğitim sırasında güncelleyeceğimiz sayaçları içerecek değişkenleri num_examples .

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

İşte değişkenleri oluşturan bir yöntem. Basitlik adına, tüm istatistikleri tf.float32 olarak tf.float32 , çünkü bu, daha sonraki bir aşamada tür dönüştürme ihtiyacını ortadan kaldıracaktır. Değişken başlatıcıları lambdas olarak sarmak, kaynak değişkenleri tarafından empoze edilen bir gereksinimdir.

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

Model parametreleri ve kümülatif istatistikler için değişkenler ile, artık kaybı hesaplayan, tahminleri yayınlayan ve tek bir girdi verisi grubu için kümülatif istatistikleri güncelleyen ileri geçiş yöntemini aşağıdaki gibi tanımlayabiliriz.

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

Ardından, yine TensorFlow kullanarak bir dizi yerel ölçüm döndüren bir işlev tanımlıyoruz. Bunlar, federe bir öğrenme veya değerlendirme sürecinde sunucuda toplanmaya uygun değerlerdir (otomatik olarak işlenen model güncellemelerine ek olarak).

Burada, federe kümeleri hesaplarken farklı kullanıcılardan gelen katkıları doğru şekilde ağırlıklandırmamız için ihtiyaç duyacağımız num_examples birlikte ortalama loss ve 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)

Son olarak, get_local_mnist_metrics aracılığıyla her cihaz tarafından yayılan yerel ölçümlerin nasıl get_local_mnist_metrics . Bu, kodun TensorFlow'da yazılmayan tek bölümüdür - TFF'de ifade edilen birleşik bir hesaplamadır . Daha derine inmek istiyorsanız, özel algoritmalar öğreticisine göz atın, ancak çoğu uygulamada, gerçekten yapmanız gerekmeyecek; aşağıda gösterilen modelin varyantları yeterli olmalıdır. Göründüğü gibi:

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

Giriş metrics argümanı karşılık gelir OrderedDict tarafından döndürülen get_local_mnist_metrics yukarıda ama eleştirel değerler artık tf.Tensors - onlar "kutulu" dir tff.Value ancak, bu artık TensorFlow kullanarak bunları manipüle edebilir temizlemek yapmak, s TFF'nin tff.federated_mean ve tff.federated_sum gibi federe operatörlerini kullanarak. Döndürülen küresel toplamalar sözlüğü, sunucuda bulunacak ölçüm kümesini tanımlar.

tff.learning.Model örneğinin oluşturulması

Yukarıdakilerin tümü uygulandığında, TFF'nin bir Keras modelini almasına izin verdiğinizde sizin için oluşturulana benzer bir model temsili, TFF ile kullanım için oluşturmaya hazırız.

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

Gördüğünüz gibi, tff.learning.Model tarafından tanımlanan soyut yöntemler ve özellikler, değişkenleri tanıtan ve kayıp ve istatistikleri tanımlayan önceki bölümde yer alan kod parçacıklarına karşılık gelir.

İşte vurgulamaya değer birkaç nokta:

  • TFF çalışma zamanında Python kullanmadığından, modelinizin kullanacağı tüm durumlar TensorFlow değişkenleri olarak yakalanmalıdır (kodunuzun mobil cihazlara dağıtılabilecek şekilde yazılması gerektiğini unutmayın; daha ayrıntılı bilgi için özel algoritmalar öğreticisine bakın nedenleri hakkında yorum).
  • Modeliniz hangi veri biçimini kabul input_spec ( input_spec ) açıklamalıdır, çünkü genel olarak TFF türü kesin belirlenmiş bir ortamdır ve tüm bileşenler için tür imzalarını belirlemek ister. Modelinizin girdisinin formatını beyan etmek, onun önemli bir parçasıdır.
  • Teknik olarak gerekli olmasa da, tüm TensorFlow mantığını (ileri geçiş, metrik hesaplamalar, vb.) tf.function s olarak tf.function , çünkü bu, TensorFlow'un serileştirilebilmesini sağlar ve açık kontrol bağımlılıklarına olan ihtiyacı ortadan kaldırır.

Yukarıdakiler, Federated SGD gibi değerlendirme ve algoritmalar için yeterlidir. Ancak, Birleşik Ortalama için, modelin her partide yerel olarak nasıl eğitilmesi gerektiğini belirtmemiz gerekir. Birleşik Ortalama algoritmasını oluştururken yerel bir iyileştirici belirleyeceğiz.

Yeni modelle federe eğitimi simüle etme

Yukarıdakilerin tümü yerine getirildiğinde, sürecin geri kalanı daha önce gördüğümüz gibi görünür - sadece model yapıcısını yeni model sınıfımızın kurucusuyla değiştirin ve oluşturduğunuz yinelemeli süreçte iki birleşik hesaplamayı kullanın. eğitim turları.

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

Bu ölçümleri TensorBoard'da görmek için yukarıda "TensorBoard'da model ölçümlerini görüntüleme" bölümünde listelenen adımlara bakın.

Değerlendirme

Şimdiye kadarki tüm deneylerimiz yalnızca birleşik eğitim ölçümlerini sundu - turdaki tüm istemcilerde eğitilen tüm veri yığınları üzerindeki ortalama ölçümler. Bu, özellikle basitlik için her turda aynı müşteri setini kullandığımızdan, aşırı uydurma ile ilgili normal endişeleri ortaya çıkarır, ancak Federe Ortalama Alma algoritmasına özgü eğitim ölçümlerinde fazladan bir uyum kavramı vardır. Bu, her müşterinin tek bir veri kümesine sahip olduğunu hayal edip edemeyeceğimizi görmenin en kolayıdır ve birçok yineleme (dönem) için bu toplu iş üzerinde eğitim yaparız. Bu durumda, yerel model hızlı bir şekilde tek bir partiye tam olarak uyacak ve böylece ortalamasını aldığımız yerel doğruluk ölçüsü 1.0'a yaklaşacaktır. Bu nedenle, bu eğitim ölçütleri, eğitimin ilerlediğinin bir işareti olarak alınabilir, ancak daha fazlası değil.

Birleşik veriler üzerinde değerlendirme yapmak için, tff.learning.build_federated_evaluation işlevini kullanarak ve model oluşturucunuzu bağımsız değişken olarak ileterek, yalnızca bu amaç için tasarlanmış başka bir federe hesaplama oluşturabilirsiniz. MnistTrainableModel kullandığımız Federated Averaging'den farklı olarak, MnistModel geçmek için yeterli olduğunu MnistModel . Değerlendirme, gradyan inişi gerçekleştirmez ve optimize ediciler oluşturmaya gerek yoktur.

Deney ve araştırma için, merkezi bir test veri kümesi mevcut olduğunda, Metin Oluşturma için Federated Learning başka bir değerlendirme seçeneği gösterir: eğitimli ağırlıkları federe öğrenmeden almak, bunları standart bir tf.keras.models.Model.evaluate() modeline uygulamak ve ardından tf.keras.models.Model.evaluate() çağırmak merkezi bir veri kümesinde tf.keras.models.Model.evaluate() .

evaluation = tff.learning.build_federated_evaluation(MnistModel)

Değerlendirme fonksiyonunun soyut tip imzasını aşağıdaki gibi inceleyebilirsiniz.

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

Bu noktada ayrıntılar hakkında endişelenmenize gerek yok, tff.templates.IterativeProcess.next benzer ancak iki önemli farkla aşağıdaki genel biçimi tff.templates.IterativeProcess.next farkında olun. İlk olarak, değerlendirme modeli veya durumun başka herhangi bir yönünü değiştirmediğinden, sunucu durumunu geri getirmiyoruz - bunu durumsuz olarak düşünebilirsiniz. İkinci olarak, değerlendirme yalnızca modele ihtiyaç duyar ve optimize edici değişkenler gibi eğitimle ilişkilendirilebilecek sunucu durumunun başka bir parçasını gerektirmez.

SERVER_MODEL, FEDERATED_DATA -> TRAINING_METRICS

Eğitim sırasında ulaştığımız son durum hakkında değerlendirmeye gidelim. En son eğitilmiş modeli sunucu durumundan çıkarmak için, aşağıdaki gibi .model üyesine erişmeniz yeterlidir.

train_metrics = evaluation(state.model, federated_train_data)

İşte aldığımız şey. Rakamların, yukarıdaki son eğitim turunda bildirilenden marjinal olarak daha iyi göründüğünü unutmayın. Geleneksel olarak, yinelemeli eğitim süreci tarafından bildirilen eğitim ölçütleri genellikle eğitim turunun başlangıcındaki modelin performansını yansıtır, bu nedenle değerlendirme ölçütleri her zaman bir adım önde olacaktır.

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

Şimdi, federe verilerin bir test örneğini derleyelim ve test verileri üzerinde değerlendirmeyi yeniden çalıştıralım. Veriler, aynı gerçek kullanıcı örneğinden, ancak farklı bir uzatılmış veri kümesinden gelecektir.

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>'

Bu öğreticiyi sonlandırır. Her turda rastgele kullanıcı örnekleri üzerinde eğitimi simüle etmek için yukarıdaki kodu değiştirmenizi ve diğer öğreticileri keşfetmenizi öneririz. geliştirdik.