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

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

Bu eğitimde, Federe Öğrenme (FL) TFF API katmanı, tanıtmak klasik MNIST eğitim örnek kullanalım tff.learning federe öğrenme görevlerinin ortak türlerini gerçekleştirmek için kullanılabilir üst düzey arabirimleri kümesi gibi - TensorFlow'da uygulanan kullanıcı tarafından sağlanan modellere karşı birleşik eğitim.

Bu öğretici ve Federated Learning API, öncelikle kendi TensorFlow modellerini TFF'ye bağlamak isteyen ve ikincisini çoğunlukla bir kara kutu olarak ele almak isteyen kullanıcılar için tasarlanmıştır. - Bir daha derinlemesine TFF anlayış ve nasıl kendi federe öğrenme algoritmaları uygulamak için, FC Core API üzerinde öğreticiler bkz Özel Federe Algoritmalar Bölüm 1 ve Bölüm 2 .

Hakkında daha fazlası için tff.learning , devam Metin Üretimi için Federe Öğrenme , öğretici tekrarlayan modelleri kapsayan ek olarak, aynı zamanda değerlendirme keras kullanılarak kombine federe öğrenme ile arıtma için bir ön eğitimli tefrika Keras modeli yüklenirken gösterir ki.

Başlamadan önce

Başlamadan önce, ortamınızın doğru şekilde kurulduğundan emin olmak için lütfen aşağıdakileri çalıştırın. Eğer bir selamlama görmüyorsanız, bakınız Kurulum talimatları için rehber.

# 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
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ştirilmiş öğrenme, birleşik bir veri seti, yani birden çok kullanıcıdan gelen bir veri koleksiyonu gerektirir. Federe veriler genellikle olmayan bir istatistiksel bağımsız zorlukları özel bir takım teşkil.

Deney kolaylaştırmak amacıyla, bir sürümünü içeren MNIST bir federe sürümü dahil olmak üzere birkaç veri setleri ile TFF depo, seribaşı orijinal NIST veri kümesi kullanılarak işlenir yeniden olmuştur Leaf veri orijinal yazar tarafından kamalıdır böylece rakamlar. Her yazarın benzersiz bir stili olduğundan, bu veri kümesi, birleşik 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()

Tarafından döndürülen veri setleri load_data() örnekleri olan tff.simulation.ClientData , bir inşa etmek, kullanıcıların kümesini sıralamak sağlayan bir arayüz tf.data.Dataset belirli bir kullanıcı verilerini temsil eder ve sorgulamak bireysel elemanların yapısı. Veri kümesinin içeriğini keşfetmek için bu arabirimi nasıl kullanabileceğiniz aşağıda açıklanmıştır. Bu arabirim, istemci kimlikleri üzerinde yineleme yapmanıza izin verirken, bunun yalnızca simülasyon verilerinin bir özelliği olduğunu unutmayın. Birazdan göreceğiniz gibi, müşteri kimlikleri federe öğrenme çerçevesi tarafından kullanılmaz - onları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([('label', TensorSpec(shape=(), dtype=tf.int32, name=None)), ('pixels', TensorSpec(shape=(28, 28), dtype=tf.float32, 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 verilerde heterojenliği keşfetme

Federe veriler genellikle olmayan bir istatistiksel bağımsız kullanıcılar genellikle kullanım şekline bağlı olarak farklı veri dağılımları vardır. Bazı müşteriler cihazda daha az eğitim örneğine sahip olabilir ve yerel olarak veri kıtlığından muzdarip olabilir, bazı müşteriler ise fazlasıyla yeterli eğitim örneğine sahip olabilir. Elimizdeki EMNIST verileriyle, federe bir sisteme özgü bu veri heterojenliği kavramını keşfedelim. Bir müşterinin verilerinin bu derin analizinin yalnızca bizim için mevcut olduğunu belirtmek önemlidir, çünkü bu, tüm verilerin bizim için yerel olarak mevcut olduğu bir simülasyon ortamıdır. Gerçek bir üretim federasyonu ortamında, tek bir müşterinin verilerini inceleyemezsiniz.

İlk olarak, simüle edilmiş bir cihazdaki örnekler hakkında fikir edinmek için bir müşterinin verilerinden bir örnek alalım. Kullandığımız veri kümesi benzersiz bir yazar tarafından anahtarlandığından, bir istemcinin verileri, bir kullanıcının benzersiz "kullanım düzenini" simüle ederek 0'dan 9'a kadar olan rakamlardan oluşan bir örnek 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 bir 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 biraz 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 müşteri 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. Her kişinin benzersiz el yazısı stili nedeniyle, bir müşterinin bir rakam için ortalama görüntüsünün, başka bir müşterinin aynı rakam için ortalama görüntüsünden farklı görüneceğini göreceğiz. O kullanıcının yerel turdaki kendi benzersiz verilerinden öğrendiğimiz için, her bir yerel eğitim turunun modeli her müşteride farklı bir yöne nasıl sürükleyeceğini düşünebiliriz. Eğitimin ilerleyen bölümlerinde, tüm istemcilerden modele yapılan her güncellemeyi nasıl alabileceğimizi ve bunları, her bir müşterimizin kendi benzersiz verilerinden öğrenmiş olan yeni küresel modelimizde nasıl birleştirebileceğ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ü ve güvenilmez bir şekilde etiketlenmiş olabilir. Ö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 yanlış etiketlenmiş bazı örneklerin olabileceğini görebiliriz.

Giriş verilerinin ön işlenmesi

Veriler zaten bir olduğundan tf.data.Dataset , Veri kümesi dönüşümler kullanılarak gerçekleştirilebilir ön işleme. Burada, dümdüz 28x28 içine görüntüleri 784 , bireysel örnekler karıştırmak, -eleman diziler toplu halinde organize ve gelen özellikler adlandırmak pixels ve label için x ve y keras ile kullanım için. Biz de bir atmak repeat birkaç dönemini çalıştırmak için veri seti üzerinde.

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, seed=1).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],
       [5],
       [7],
       [1],
       [7],
       [7],
       [1],
       [4],
       [7],
       [4],
       [2],
       [2],
       [5],
       [4],
       [1],
       [1],
       [0],
       [0],
       [9]], dtype=int32))])

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

Bir simülasyon TFF birleşik veri besleme yollarından biri olup, bir liste ya da bir şekilde, bir bireysel kullanıcının verilerini tutan listesinin her bir elemanı ile, basit bir Python'daki liste gibidir tf.data.Dataset . İkincisini sağlayan bir arayüzümüz olduğu için onu kullanalım.

Burada, bir eğitim veya değerlendirme turuna girdi olarak verilen kullanıcı kümesinden veri kümelerinin bir listesini 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, potansiyel olarak çok büyük bir kullanıcı cihazı popülasyonu ile ilgileniyoruz ve bunların yalnızca bir kısmı belirli bir zamanda eğitim için kullanılabilir olabilir. Örneğin, istemci cihazlar yalnızca bir güç kaynağına takıldığında, ölçülü bir ağ dışındayken ve başka bir şekilde boştayken eğitime katılan cep telefonları olduğunda durum böyledir.

Elbette bir simülasyon ortamındayız ve tüm veriler yerel olarak mevcut. Tipik olarak, simülasyonları çalıştırırken, her eğitim turunda yer alacak, genellikle her turda farklı olan istemcilerin rastgele bir alt kümesini örnekleyeceğiz.

Yani üzerinde kağıt inceleyerek öğrenebilirsiniz olarak, söz konusu Federe ortalamasının alınması biraz zaman alabilir her turda müşterilerin rastgele örneklenmiş alt kümeleri ile bir sistemde yakınlaşma sağlanması, algoritma ve içinde mermi yüzlerce çalıştırmak zorunda pratik olmaz bu etkileşimli öğretici.

Bunun yerine yapacağımız şey, istemci kümesini bir kez örneklemek ve yakınsamayı hızlandırmak için aynı kümeyi turlar arasında yeniden kullanmaktır (bilerek bu birkaç kullanıcının verilerine aşırı sığdırmak). Rastgele örneklemeyi simüle etmek için bu öğreticiyi değiştirmeyi okuyucuya bir alıştırma olarak bırakıyoruz - yapması oldukça kolaydır (bir kez yaptığınızda, modelin yakınsamasının 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 model oluşturma

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

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

TFF ile herhangi bir model kullanmak amacıyla, bir örneği sarılmış gereken tff.learning.Model keras benzer vb modelin ileri geçiren, meta veri özellikleri, damga için yöntemler sunar arayüzü, aynı zamanda ek getirmektedir birleşik metrikleri hesaplama sürecini kontrol etme yolları gibi öğeler. Şimdilik bunu dert etmeyelim; Eğer biz sadece yukarıda tanımladığınız gibi bir Keras modeli varsa, çağırarak sizin için sarmak TFF olabilir tff.learning.from_keras_model aşağıda gösterildiği gibi, model ve argümanlar olarak örnek bir veri toplu geçen.

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ştirilmiş veriler üzerinde eğitme

Şimdi biz sarılmış bir model olduğunu tff.learning.Model TFF ile kullanılmak üzere, biz TFF yardımcı fonksiyon çağırarak Federe Averaging algoritması inşa sağlayabilirsiniz tff.learning.build_federated_averaging_process olarak izler.

Argüman (örneğin bir yapıcı olması gerektiğini unutmayın model_fn , yukarıda) değil halihazırda inşa örneği böylece modelin yapımı için nedenleri hakkında ise sen merak (TFF tarafından kontrol edilen bir bağlamda başına gelebilecek Bu, biz takip öğretici okumanızı öneriyoruz özel algoritmalar ).

Bir _client iyileştirici ve _SERVER iyileştirici: Aşağıda Federe Averaging algoritması Bir önemli not, 2 optimize vardır. _Client iyileştirici sadece her istemci üzerinde yerel modeli güncellemelerini hesaplamak için kullanılır. _SERVER iyileştirici sunucuda küresel modele ortalama güncelleştirmeyi uygular. Bu özellikle, kullanılan optimize edici ve öğrenme hızı seçiminin, modeli standart bir iid veri kümesi üzerinde eğitmek için kullandığınızdan farklı olması gerekebileceği anlamına gelir. Normal SGD ile, muhtemelen normalden daha küçük bir öğrenme oranıyla başlamanızı öneririz. Kullandığımız öğrenme oranı dikkatli bir şekilde ayarlanmamıştır, 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 birleşik hesaplamaların bir çift oluşturulmuştur ve içine paketlenmiş tff.templates.IterativeProcess özelliklerinin bir çift olarak bu hesaplamalar mevcut olduğu initialize ve next .

Özetle, federe hesaplamaları çeşitli federe algoritmalar ifade edebilir TFF'nin iç dilinde programlardır (eğer daha bu konuda bulabilirsiniz özel algoritmalar öğretici). Bu durumda, iki hesaplamaları üretilen ve içine paketlenmiş iterative_process uygulamak Federe ortalamasını .

Hesaplamaları gerçek birleşik öğrenme ayarlarında yürütülebilecek şekilde tanımlamak TFF'nin bir hedefidir, ancak şu anda yalnızca yerel yürütme simülasyonu çalışma zamanı uygulanmaktadır. Bir simülatörde bir hesaplama yürütmek için onu bir Python işlevi gibi çağırmanız yeterlidir. Bu varsayılan yorumlanmış 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 süreleri sağlamayı umuyoruz.

İle başlayalım initialize hesaplama. Tüm birleşik hesaplamalarda olduğu gibi, bunu bir fonksiyon olarak düşünebilirsiniz. Hesaplama hiçbir argüman almaz ve bir sonuç döndürür - sunucudaki Birleşik Ortalama işleminin durumunun temsili. TFF'nin detaylarına girmek istemesek de bu durumun nasıl olduğunu 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=<value_sum_process=<>,weight_sum_process=<>>,model_broadcast_state=<>>@SERVER)'

Yukarıdaki tip imza birinci biraz şifreli gibi gözükse de, sunucu devletin oluştuğunu tanıyabilir model (tüm cihazlara dağıtılacak MNIST için başlangıç modeli parametreleri) ve optimizer_state (ek bilgi sunucu tarafından tutulan, hiperparametre programları için kullanılacak tur sayısı gibi).

Çağırmak edelim initialize hesaplama sunucusu devlet inşa etmek.

state = iterative_process.initialize()

Birleşik hesaplamalardan çiftinin ikinci, next , cihaz üzerinde yerel veri eğitim, toplama ve ortalama model güncellenir, müşterilere (model parametreleri de dahil olmak üzere), sunucu durum itme oluşur Federal ortalama tek bir de temsil etmektedir , ve sunucuda yeni bir güncellenmiş model üretmek.

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, bir düşünmesi gereken next() girdilerin bazı sunucu (tarafından sağlanmaktadır - bir sunucu üzerinde çalışır, ancak tüm merkezi olmayan hesaplama bildirge fonksiyonel gösterimi olmanın bir işlev olarak değil SERVER_STATE ), ancak her bir katılımcı cihaz kendi yerel veri setine katkıda bulunur.

Tek bir eğitim turu çalıştıralım ve sonuçları görselleştirelim. Bir kullanıcı örneği için yukarıda oluşturduğumuz birleşik verileri kullanabiliriz.

state, metrics = iterative_process.next(state, federated_train_data)
print('round  1, metrics={}'.format(metrics))
round  1, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.12345679), ('loss', 3.1193738)])), ('stat', OrderedDict([('num_examples', 4860)]))])

Birkaç tur daha koşalım. Daha önce belirtildiği gibi, tipik olarak bu noktada, kullanıcıların sürekli olarak gelip gittiği gerçekçi bir konuşlandırmayı 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österi amacıyla aynı kullanıcıları yeniden kullanacağız, böylece sistem hızla birleşecek.

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([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.13518518), ('loss', 2.9834728)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  3, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.14382716), ('loss', 2.861665)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  4, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.17407407), ('loss', 2.7957022)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  5, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.19917695), ('loss', 2.6146567)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  6, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.21975309), ('loss', 2.529761)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  7, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.2409465), ('loss', 2.4053504)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  8, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.2611111), ('loss', 2.315389)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  9, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.30823046), ('loss', 2.1240263)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round 10, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('sparse_categorical_accuracy', 0.33312756), ('loss', 2.1164262)])), ('stat', OrderedDict([('num_examples', 4860)]))])

Eğitim kaybı, birleştirilmiş eğitimin her turundan sonra azalmakta ve bu da modelin yakınsadığını göstermektedir. Bu eğitim ölçümler ile bazı önemli uyarılar, ancak daha sonra bu eğitimde Değerlendirilmesi bölümüne bakınız vardır.

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

Aynı özet yazıcıyla ilgili skaler metrikleri ç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'].items():
      tf.summary.scalar(name, value, step=round_num)

TensorBoard'u yukarıda belirtilen kök günlük dizini ile başlatın. Verilerin yüklenmesi birkaç saniye sürebilir.

!ls {logdir}
%tensorboard --logdir {logdir} --port=0
events.out.tfevents.1629557449.ebe6e776479e64ea-4903924a278.borgtask.google.com.458912.1.v2
Launching TensorBoard...
Reusing TensorBoard on port 50681 (pid 292785), started 0:30:30 ago. (Use '!kill 292785' to kill it.)
<IPython.core.display.Javascript at 0x7fd6617e02d0>
# 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/*

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

Model uygulamasını özelleştirme

Keras olan TensorFlow için önerilen üst düzey modeli API ve biz (aracılığıyla Keras modelleri kullanılarak teşvik tff.learning.from_keras_model mümkünse TFF'nin).

Bununla birlikte, tff.learning daha düşük bir seviyesi model bir arabirim sağlar tff.learning.Model birleşik öğrenme için bir model kullanmak için gereken minimum işlevselliği sunar. Doğrudan (muhtemelen hala gibi yapıtaşları kullanarak bu arayüzü uygulayan tf.keras.layers ) federe öğrenme algoritmalarının iç elemanların değiştirmeden maksimum özelleştirme için izin verir.

Öyleyse her şeyi sıfırdan tekrar yapalım.

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

İlk adım, birlikte ç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 gibi değişkenleri içerecektir weights ve bias gibi biz eğitim sırasında güncellenir çeşitli kümülatif istatistikler ve sayaçları, yapacak biz eğitim vereceğini, hem de değişkenleri loss_sum , accuracy_sum ve num_examples .

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

İşte değişkenleri oluşturan bir yöntem. Kolaylık olması açısından, biz tüm istatistikleri temsil tf.float32 bu daha sonraki bir aşamada tip dönüşümler ihtiyacını ortadan kaldıracaktır gibi. Lambdas gibi değişken başlatıcıları tamamlayan dayattığı bir gerekliliktir kaynak değişkenleri .

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 yerindeyken, artık kaybı hesaplayan, tahminler yayan 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 predict_on_batch(variables, x):
  return tf.nn.softmax(tf.matmul(x, variables.weights) + variables.bias)

def mnist_forward_pass(variables, batch):
  y = predict_on_batch(variables, batch['x'])
  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'u kullanarak bir dizi yerel metrik döndüren bir işlev tanımlarız. Bunlar, bir federe öğrenme veya değerlendirme sürecinde sunucuda toplanmaya uygun olan değerlerdir (otomatik olarak işlenen model güncellemelerine ek olarak).

Burada, biz sadece ortalama dönmek loss ve accuracy , hem de num_examples federe agrega hesaplarken doğru olarak farklı kullanıcılardan katkıları ağırlık gerekir.

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, biz yoluyla her cihazın yaydığı yerel metrikleri toplar nasıl belirlemek gerekir get_local_mnist_metrics . Bu TensorFlow yazılı değil kodun sadece bir parçası - bu TFF ifade federe hesaplama bu. Eğer derin kazmak istiyorsanız, göz gezdirmek özel algoritmalar öğretici, ama çoğu uygulamada, gerçekten gerek kalmayacak; Aşağıda gösterilen modelin varyantları yeterli olacaktır. İşte nasıl göründüğü:

@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 gibi TFF'nin federe operatörlerini kullanarak tff.federated_mean ve tff.federated_sum . Döndürülen global kümeler sözlüğü, sunucuda kullanılabilecek metrikler kümesini tanımlar.

Bir örneğini oluşturma tff.learning.Model

Yukarıdakilerin tümü yerinde olduğunda, TFF'nin bir Keras modelini almasına izin verdiğinizde sizin için oluşturulana benzer bir model gösterimi TFF ile kullanım için oluşturmaya hazırız.

from typing import Callable, List, OrderedDict

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 predict_on_batch(self, x, training=True):
    del training
    return predict_on_batch(self._variables, x)

  @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

  @tf.function
  def report_local_unfinalized_metrics(
      self) -> OrderedDict[str, List[tf.Tensor]]:
    """Creates an `OrderedDict` of metric names to unfinalized values."""
    return collections.OrderedDict(
        num_examples=[self._variables.num_examples],
        loss=[self._variables.loss_sum, self._variables.num_examples],
        accuracy=[self._variables.accuracy_sum, self._variables.num_examples])

  def metric_finalizers(
      self) -> OrderedDict[str, Callable[[List[tf.Tensor]], tf.Tensor]]:
    """Creates an `OrderedDict` of metric names to finalizers."""
    return collections.OrderedDict(
        num_examples=tf.function(func=lambda x: x[0]),
        loss=tf.function(func=lambda x: x[0] / x[1]),
        accuracy=tf.function(func=lambda x: x[0] / x[1]))

Görüldüğü gibi, tarafından tanımlanan soyut yöntemleri ve özellikleri tff.learning.Model değişkenleri kişiye kaybı ve istatistikleri tanımlanan önceki bölümde kod parçacıkları tekabül eder.

İşte vurgulamaya değer birkaç nokta:

  • TFF (çalışma zamanında Python kullanmak kodunuzu anımsamayacağından modeliniz, TensorFlow değişkenler olarak ele alınmalıdır kullanacağı tüm devlet mobil cihazlara dağıtılabilir şekilde yazılmalıdır; bkz özel algoritmalar daha derinlemesine için öğretici nedenleri hakkında yorum).
  • Modeliniz, (kabul verilerin ne şekilde açıklamalıdır input_spec TFF özellikle yazılan bir ortamdır ve tüm bileşenler için tip imzaları belirlemek istiyor genelde olduğu gibi). Modelinizin girdisinin biçimini bildirmek, bunun önemli bir parçasıdır.
  • Teknik olarak gerekli olmasa da, biz bütün TensorFlow mantığı (ileri pas, metrik hesaplamalar, vb) sarma tavsiye tf.function bu TensorFlow serileştirilebilir sağlamaya yardımcı olur ve açık kontrol bağımlılıkları olan ihtiyacı ortadan kaldırır olarak, s.

Yukarıdakiler, Federated SGD gibi değerlendirme ve algoritmalar için yeterlidir. Bununla birlikte, 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 optimize edici belirleyeceğiz.

Yeni modelle birleşik eğitim simülasyonu

Yukarıdakilerin tümü yerinde olduğunda, sürecin geri kalanı daha önce gördüğümüz gibi görünüyor - sadece model oluşturucuyu yeni model sınıfımızın yapıcısıyla değiştirin ve döngü yapmak için 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=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 3.0708053), ('accuracy', 0.12777779)])), ('stat', OrderedDict([('num_examples', 4860)]))])
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([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 3.011699), ('accuracy', 0.13024691)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  3, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.7408307), ('accuracy', 0.15576132)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  4, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.6761012), ('accuracy', 0.17921811)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  5, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.675567), ('accuracy', 0.1855967)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  6, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.5664043), ('accuracy', 0.20329218)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  7, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.4179392), ('accuracy', 0.24382716)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  8, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.3237286), ('accuracy', 0.26687244)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round  9, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.1861682), ('accuracy', 0.28209877)])), ('stat', OrderedDict([('num_examples', 4860)]))])
round 10, metrics=OrderedDict([('broadcast', ()), ('aggregation', OrderedDict([('mean_value', ()), ('mean_weight', ())])), ('train', OrderedDict([('num_examples', 4860.0), ('loss', 2.046388), ('accuracy', 0.32037038)])), ('stat', OrderedDict([('num_examples', 4860)]))])

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ştirilmiş eğitim metrikleri sundu - turdaki tüm istemciler arasında eğitilen tüm veri yığınları üzerindeki ortalama metrikler. Bu, özellikle basitlik için her turda aynı istemci grubunu kullandığımızdan, fazla uydurmayla ilgili normal endişeleri ortaya çıkarır, ancak Federated Averaging algoritmasına özgü eğitim metriklerinde ek bir fazla uydurma kavramı vardır. Bu, her müşterinin tek bir veri yığınına sahip olduğunu hayal edip etmediğimizi görmek en kolayıdır ve birçok yineleme (dönem) için bu toplu iş üzerinde eğitim alırız. Bu durumda, yerel model hızlı bir şekilde bu tek partiye tam olarak uyacak ve böylece ortalamasını aldığımız yerel doğruluk metriği 1.0'a yaklaşacaktır. Bu nedenle, bu eğitim metrikleri, eğitimin ilerlediğinin bir işareti olarak alınabilir, ancak çok daha fazlası değil.

Federe verilere değerlendirmesini gerçekleştirmek için, kullanmadan, sadece bu amaç için tasarlanmış bir başka federe hesaplama inşa edebilir tff.learning.build_federated_evaluation fonksiyonunu ve bir argüman olarak modeliniz yapıcısı geçiyordu. Biz kullandım Federe Ortalaması ile aksine o Not MnistTrainableModel , Geçmesi yeterli MnistModel . Değerlendirme, gradyan inişi gerçekleştirmez ve optimize ediciler oluşturmaya gerek yoktur.

Bir merkezi sınav veri kümesi kullanılabilir olduğunda deney ve araştırma için, Federe Öğrenme Metin Üretimi , federe öğrenmeden eğitilmiş ağırlıkları alarak standart bir Keras modeli uygulamadan ve daha sonra basitçe çağırarak: Başka bir değerlendirme seçeneği gösteriyor tf.keras.models.Model.evaluate() merkezi bir veri kümesi üzerinde.

evaluation = tff.learning.build_federated_evaluation(MnistModel)

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

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> -> <eval=<num_examples=float32,loss=float32,accuracy=float32>,stat=<num_examples=int64>>@SERVER)'

Gerek bu noktada detayları hakkında endişelenmek için, sadece benzer aşağıdaki genel formu, süreceğini unutmayın tff.templates.IterativeProcess.next ama iki önemli farkları var. İlk olarak, değerlendirme modeli veya durumun herhangi bir yönünü değiştirmediğinden sunucu durumunu döndürmüyoruz - bunu durumsuz olarak düşünebilirsiniz. İkincisi, değerlendirme yalnızca modele ihtiyaç duyar ve optimize edici değişkenler gibi eğitimle ilişkilendirilebilecek sunucu durumunun başka herhangi bir bölümünü gerektirmez.

SERVER_MODEL, FEDERATED_DATA -> TRAINING_METRICS

Eğitim sırasında geldiğimiz son duruma ilişkin değerlendirmeye başvuralım. Sunucu durumundan son eğitimli modelini çıkarmak için, sadece erişmek .model üyesi olarak izler.

train_metrics = evaluation(state.model, federated_train_data)

İşte aldığımız şey. Rakamların, yukarıdaki eğitimin son turunda bildirilenlerden marjinal olarak daha iyi göründüğüne dikkat edin. Geleneksel olarak, yinelemeli eğitim süreci tarafından rapor edilen eğitim ölçütleri, genellikle eğitim turunun başında modelin performansını yansıtır, bu nedenle değerlendirme ölçütleri her zaman bir adım önde olacaktır.

str(train_metrics)
"OrderedDict([('eval', OrderedDict([('num_examples', 4860.0), ('loss', 1.7510437), ('accuracy', 0.2788066)])), ('stat', OrderedDict([('num_examples', 4860)]))])"

Şimdi, birleşik 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 ayrı bir elde tutulan veri setinden 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)
"OrderedDict([('eval', OrderedDict([('num_examples', 580.0), ('loss', 1.8361608), ('accuracy', 0.2413793)])), ('stat', OrderedDict([('num_examples', 580)]))])"

Bu, öğreticiyi tamamlar. Her turda rastgele kullanıcı örnekleri üzerinde eğitimi simüle etmek için yukarıdaki kodu değiştirmek için parametrelerle (örneğin toplu iş boyutları, kullanıcı sayısı, dönemler, öğrenme oranları vb.) oynamanızı ve diğer öğreticileri keşfetmenizi öneririz. geliştirdik.