Özel Birleşik Algoritmalar, Bölüm 2: Birleşik Ortalamanın Uygulanması

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 öğretici kullanarak TFF'nin federe algoritmaların özel türleri nasıl uygulanacağını gösteren iki bölümlü serisinin ikinci kısmıdır Federe Çekirdek (FC) için bir temel olarak hizmet veren, Federe Öğrenme (FL) katmana ( tff.learning ) .

Biz ilk okumanızı öneririz bu serinin ilk bölümü temel kavramlarından bazılarını ve burada kullanılan programlama soyutlamalar tanıtmak.

Serinin bu ikinci kısmı, birleşik eğitim ve değerlendirme algoritmalarının basit bir versiyonunu uygulamak için ilk kısımda tanıtılan mekanizmaları kullanır.

Biz incelemenizi öneriyoruz görüntü sınıflandırma ve metin oluşturma onlar biz bağlamda burada tarif kavramları koymak yardımcı olacaktır, TFF'nin Federe Öğrenme API'leri için daha yüksek bir düzey ve daha nazik tanıtımı için öğreticiler.

Başlamadan önce

Başlamadan önce, ortamınızın doğru şekilde kurulduğundan emin olmak için aşağıdaki "Merhaba Dünya" örneğini çalıştırmayı deneyin. İşe yaramazsa, bakınız Kurulum talimatları için rehber.

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

import nest_asyncio
nest_asyncio.apply()
import collections

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

# Must use the Python context because it
# supports tff.sequence_* intrinsics.
executor_factory = tff.framework.local_executor_factory(
    support_sequence_ops=True)
execution_context = tff.framework.ExecutionContext(
    executor_fn=executor_factory)
tff.framework.set_default_context(execution_context)
@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
b'Hello, World!'

Birleşik Ortalamanın Uygulanması

Olduğu gibi Görüntü Sınıflandırma için Federe Öğrenme , biz MNIST örneği kullanacağız, ancak bu düşük seviye öğretici olarak tasarlanmıştır beri, biz Keras API ve baypas olacak tff.simulation , ham model kodu yazmak ve yapı, bir sıfırdan federe veri seti.

Birleştirilmiş veri kümelerinin hazırlanması

Bir gösteri uğruna, 10 kullanıcıdan veri aldığımız bir senaryoyu simüle edeceğiz ve her kullanıcının farklı bir basamağı nasıl tanıyacağına dair bilgi katkısında bulunacağız. Bu olmayan şekilde ilgili iid o alır gibi.

Önce standart MNIST verilerini yükleyelim:

mnist_train, mnist_test = tf.keras.datasets.mnist.load_data()
[(x.dtype, x.shape) for x in mnist_train]
[(dtype('uint8'), (60000, 28, 28)), (dtype('uint8'), (60000,))]

Veriler, her ikisi de ilk boyutun bireysel örneklerin üzerinden geçtiği, biri resimlerle, diğeri rakam etiketleriyle birlikte Numpy dizileri olarak gelir. Birleştirilmiş dizileri TFF hesaplamalarına nasıl beslediğimiz ile uyumlu bir şekilde biçimlendiren bir yardımcı fonksiyon yazalım, yani bir liste listesi olarak - kullanıcılar (rakamlar) üzerinde değişen dış liste, içindekiler veri yığınları arasında değişen iç listeler. her müşterinin sırası. Alışılmış olarak, adı tansörleri bir çift her parti yapısı olacaktır x ve y , önde gelen toplu boyutu ile her biri. Ona ederken, aynı zamanda bir 784-eleman vektörü içine her görüntüyü düzleştirmek ve içine o pikselleri rescale edeceğiz 0..1 biz veri dönüşüm ile modeli mantığı yığılmayı gerekmez böylece, menzil.

NUM_EXAMPLES_PER_USER = 1000
BATCH_SIZE = 100


def get_data_for_digit(source, digit):
  output_sequence = []
  all_samples = [i for i, d in enumerate(source[1]) if d == digit]
  for i in range(0, min(len(all_samples), NUM_EXAMPLES_PER_USER), BATCH_SIZE):
    batch_samples = all_samples[i:i + BATCH_SIZE]
    output_sequence.append({
        'x':
            np.array([source[0][i].flatten() / 255.0 for i in batch_samples],
                     dtype=np.float32),
        'y':
            np.array([source[1][i] for i in batch_samples], dtype=np.int32)
    })
  return output_sequence


federated_train_data = [get_data_for_digit(mnist_train, d) for d in range(10)]

federated_test_data = [get_data_for_digit(mnist_test, d) for d in range(10)]

Hızlı bir sağlamlık denetimi en edelim görünüm olarak Y beşinci istemci tarafından katkıda verilerin son toplu tensör (basamağa karşılık gelen biri 5 ).

federated_train_data[5][-1]['y']
array([5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], dtype=int32)

Emin olmak için, o grubun son elemanına karşılık gelen resme de bakalım.

from matplotlib import pyplot as plt

plt.imshow(federated_train_data[5][-1]['x'][-1].reshape(28, 28), cmap='gray')
plt.grid(False)
plt.show()

png

TensorFlow ve TFF'yi birleştirme hakkında

Bu eğitimde, kompakt için biz hemen ile TensorFlow mantığı tanıtmak fonksiyonlarını süslemeleri tff.tf_computation . Ancak, daha karmaşık mantık için önerdiğimiz model bu değildir. TensorFlow'da hata ayıklama zaten zor olabilir ve TensorFlow tamamen serileştirildikten ve ardından yeniden içe aktarıldıktan sonra hata ayıklamak zorunlu olarak bazı meta verileri kaybeder ve etkileşimi sınırlar, hata ayıklamayı daha da zorlaştırır.

Bu nedenle, güçlü (olmadan olduğunu tek başına Python fonksiyonları gibi karmaşık TF mantığı yazma tavsiye tff.tf_computation dekorasyon). Bu şekilde TensorFlow mantık (örneğin çağırarak TFF için hesaplama seri önce, (istekli modu gibi) TF iyi uygulamaları ve araçları kullanarak geliştirilen ve test edilebilir tff.tf_computation argüman olarak bir Python fonksiyonu ile).

Bir kayıp fonksiyonu tanımlama

Artık elimizde veriler olduğuna göre, eğitim için kullanabileceğimiz bir kayıp fonksiyonu tanımlayalım. İlk olarak girdi tipini tuple isimli bir TFF olarak tanımlayalım. Veri serilerin boyutu değişebilir bu yana, toplu boyut ayarlamak None bu boyutun büyüklüğü bilinmemektedir olduğunu belirtmek için.

BATCH_SPEC = collections.OrderedDict(
    x=tf.TensorSpec(shape=[None, 784], dtype=tf.float32),
    y=tf.TensorSpec(shape=[None], dtype=tf.int32))
BATCH_TYPE = tff.to_type(BATCH_SPEC)

str(BATCH_TYPE)
'<x=float32[?,784],y=int32[?]>'

Neden sıradan bir Python tipi tanımlayamadığımızı merak ediyor olabilirsiniz. Tartışmaya hatırlayın part 1 biz kaput TFF hesaplamaları altında Python kullanarak TFF hesaplamaların mantığı, ifade edebilir ederken Python olmadıklarını açıkladı. Sembol BATCH_TYPE yukarıda tarif edilen bir soyut TFF tipi detaylarını gösterir. Beton Python temsil türleri, örneğin, gibi kaplardan, bu özet TFF türü ayırt edilmesi önemlidir dict veya collections.namedtuple Python fonksiyon gövdesinde TFF tipini temsil etmek için kullanılabilir. Python farklı TFF, tek bir soyut bir tipte olan tff.StructType için demet benzeri tek tek ismi verilen ya da adsız bırakılabilir elemanları ile kaplar. TFF hesaplamaları resmi olarak yalnızca bir parametre ve bir sonuç bildirebildiğinden, bu tür aynı zamanda hesaplamaların resmi parametrelerini modellemek için kullanılır - bunun örneklerini birazdan göreceksiniz.

Let şimdi ağırlıkları ve önyargı bir TFF adlı başlığın olarak yine model parametrelerinin TFF türünü tanımlamak ediyor.

MODEL_SPEC = collections.OrderedDict(
    weights=tf.TensorSpec(shape=[784, 10], dtype=tf.float32),
    bias=tf.TensorSpec(shape=[10], dtype=tf.float32))
MODEL_TYPE = tff.to_type(MODEL_SPEC)
print(MODEL_TYPE)
<weights=float32[784,10],bias=float32[10]>

Bu tanımlar yapıldığında, artık belirli bir model için kaybı tek bir parti üzerinden tanımlayabiliriz. Kullanımını Not @tf.function içinde dekoratör @tff.tf_computation dekoratör. Bu bize semantik gibi Python kullanarak rağmen bir içindeydin TF yazmasına olanak tanır tf.Graph yarattığı bağlamda tff.tf_computation dekoratörü.

# NOTE: `forward_pass` is defined separately from `batch_loss` so that it can 
# be later called from within another tf.function. Necessary because a
# @tf.function  decorated method cannot invoke a @tff.tf_computation.

@tf.function
def forward_pass(model, batch):
  predicted_y = tf.nn.softmax(
      tf.matmul(batch['x'], model['weights']) + model['bias'])
  return -tf.reduce_mean(
      tf.reduce_sum(
          tf.one_hot(batch['y'], 10) * tf.math.log(predicted_y), axis=[1]))

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE)
def batch_loss(model, batch):
  return forward_pass(model, batch)

Beklendiği gibi, hesaplama batch_loss döndürüyor float32 kaybı modeli ve tek bir veri toplu verilen. Nasıl Not MODEL_TYPE ve BATCH_TYPE yasal parametrelerin 2 başlığın içine araya toplanmakta; Eğer türünü tanıyabilir batch_loss olarak (<MODEL_TYPE,BATCH_TYPE> -> float32) .

str(batch_loss.type_signature)
'(<model=<weights=float32[784,10],bias=float32[10]>,batch=<x=float32[?,784],y=int32[?]>> -> float32)'

Akıl sağlığı kontrolü olarak, sıfırlarla dolu bir başlangıç ​​modeli oluşturalım ve yukarıda görselleştirdiğimiz veri yığını üzerindeki kaybı hesaplayalım.

initial_model = collections.OrderedDict(
    weights=np.zeros([784, 10], dtype=np.float32),
    bias=np.zeros([10], dtype=np.float32))

sample_batch = federated_train_data[5][-1]

batch_loss(initial_model, sample_batch)
2.3025851

Bir şekilde tanımlanmış başlangıç modeli ile TFF hesaplama beslemesidir Not dict , olsa bile Python fonksiyon gövdesi o kadar model parametreleri tüketir tanımlar model['weight'] ve model['bias'] . Çağrısına argümanları batch_loss sadece o fonksiyonun vücuda geçmedi.

Ne çağırmak ne zaman olur batch_loss ? Python vücut batch_loss zaten takip ve tanımlandı yukarıdaki hücrede seri olmuştur. TFF için arayan olarak hareket batch_loss hesaplama tanımı zamanda ve süre içinde çağırma hedefi olarak batch_loss çağrılır. Her iki rolde de TFF, TFF'nin soyut tip sistemi ile Python temsil tipleri arasında köprü görevi görür. Çağırma zamanda, TFF çoğu standart Python konteyner tipleri (kabul edecek dict , list , tuple , collections.namedtuple soyut TFF dizilerini somut temsilleri olarak, vs.). Ayrıca, yukarıda belirtildiği gibi, TFF hesaplamaları resmi olarak yalnızca tek bir parametreyi kabul etse de, parametre türünün bir Tuple olması durumunda, tanıdık Python çağrı sözdizimini konumsal ve/veya anahtar sözcük argümanlarıyla kullanabilirsiniz - beklendiği gibi çalışır.

Tek bir partide gradyan iniş

Şimdi, tek bir gradyan iniş adımını gerçekleştirmek için bu kayıp fonksiyonunu kullanan bir hesaplama tanımlayalım. Bu işlevi tanımlarken, kullandığımız nasıl Not batch_loss bir alt bileşen olarak. Sen ile yapılmış bir hesaplama çağırabileceği tff.tf_computation yukarıda belirtildiği gibi seri bazı hata ayıklama bilgisini kaybeder çünkü genellikle yazma daha karmaşık hesaplamalar için tercih edilir, ve tüm TensorFlow sınamak - gerçi genellikle bu gerekli değildir, başka hesaplama vücudun içinde olmadan tff.tf_computation dekoratör.

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE, tf.float32)
def batch_train(initial_model, batch, learning_rate):
  # Define a group of model variables and set them to `initial_model`. Must
  # be defined outside the @tf.function.
  model_vars = collections.OrderedDict([
      (name, tf.Variable(name=name, initial_value=value))
      for name, value in initial_model.items()
  ])
  optimizer = tf.keras.optimizers.SGD(learning_rate)

  @tf.function
  def _train_on_batch(model_vars, batch):
    # Perform one step of gradient descent using loss from `batch_loss`.
    with tf.GradientTape() as tape:
      loss = forward_pass(model_vars, batch)
    grads = tape.gradient(loss, model_vars)
    optimizer.apply_gradients(
        zip(tf.nest.flatten(grads), tf.nest.flatten(model_vars)))
    return model_vars

  return _train_on_batch(model_vars, batch)
str(batch_train.type_signature)
'(<initial_model=<weights=float32[784,10],bias=float32[10]>,batch=<x=float32[?,784],y=int32[?]>,learning_rate=float32> -> <weights=float32[784,10],bias=float32[10]>)'

Eğer dekore bir Python işlevini çağırmak tff.tf_computation gibi bir başka fonksiyonu gövdesi içinde, iç TFF hesaplama mantığı gömülü olduğu dış bir mantığı (esas olarak, inlined). Yukarıda belirtildiği gibi her iki hesaplamaları yazıyorsanız eğer, iç fonksiyonunu (yapma olasılığı tercih edilir batch_loss bu durumda) normal bir Python veya tf.function yerine bir tff.tf_computation . Ancak, burada biz böyle hitap biri göstermek tff.tf_computation beklendiği gibi başka temelde çalışır içeride. Örneğin, tanımlama Python kodunu yoksa, eğer bu gerekli olabilir batch_loss ama sadece tefrika TFF temsilini.

Şimdi, kaybın azalıp azalmadığını görmek için bu fonksiyonu birkaç kez ilk modele uygulayalım.

model = initial_model
losses = []
for _ in range(5):
  model = batch_train(model, sample_batch, 0.1)
  losses.append(batch_loss(model, sample_batch))
losses
[0.19690023, 0.13176313, 0.10113225, 0.08273812, 0.070301384]

Bir dizi yerel veri üzerinde gradyan inişi

Şimdi bu yana, batch_train çalışmaları görünüyor en benzer eğitim fonksiyonu yazalım local_train o tükettiğini yerine sadece tek grubundan birisi kullanıcıdan tüm serilerin tüm dizisi. Şimdi tüketmek yeni hesaplama gerekecektir tff.SequenceType(BATCH_TYPE) yerine BATCH_TYPE .

LOCAL_DATA_TYPE = tff.SequenceType(BATCH_TYPE)

@tff.federated_computation(MODEL_TYPE, tf.float32, LOCAL_DATA_TYPE)
def local_train(initial_model, learning_rate, all_batches):

  @tff.tf_computation(LOCAL_DATA_TYPE, tf.float32)
  def _insert_learning_rate_to_sequence(dataset, learning_rate):
    return dataset.map(lambda x: (x, learning_rate))

  batches_with_learning_rate = _insert_learning_rate_to_sequence(all_batches, learning_rate)

  # Mapping function to apply to each batch.
  @tff.federated_computation(MODEL_TYPE, batches_with_learning_rate.type_signature.element)
  def batch_fn(model, batch_with_lr):
    batch, lr = batch_with_lr
    return batch_train(model, batch, lr)

  return tff.sequence_reduce(batches_with_learning_rate, initial_model, batch_fn)
str(local_train.type_signature)
'(<initial_model=<weights=float32[784,10],bias=float32[10]>,learning_rate=float32,all_batches=<x=float32[?,784],y=int32[?]>*> -> <weights=float32[784,10],bias=float32[10]>)'

Bu kısa kod bölümünde gömülü epeyce detay var, hadi bunları tek tek gözden geçirelim.

Biz güvenerek tamamen TensorFlow bu mantık, hayata olabilirdi ederken Birincisi, tf.data.Dataset.reduce benzer biz daha önce yaptık nasıl dizisini işlemek için, biz tutkal dilinde mantığı ifade etmek bu kez seçtiğinizi bir şekilde tff.federated_computation . Biz federe operatör kullandım tff.sequence_reduce azalma gerçekleştirmek için.

Operatör tff.sequence_reduce benzer bir şekilde kullanılır tf.data.Dataset.reduce . Sen temelde aynı olarak düşünmek olabilir tf.data.Dataset.reduce ama Hatırlayacağınız olarak federe hesaplamaları, içeride kullanılmak üzere, TensorFlow kodunu içeremez. Bu bir dizisinden oluşan bir resmi parametre 3-başlığın bir şablon operatörü T elemanları -typed redüksiyon ilk durumu bazı tipi (biz sıfır soyut başvurmak gerekir) U ve indirgeme operatörü tip (<U,T> -> U) olduğu değiştiren tek bir öğe işleyerek redüksiyon durumu. Sonuç, tüm öğeleri sıralı bir düzende işledikten sonra, indirgemenin son halidir. Örneğimizde, azaltma durumu, verilerin bir öneki üzerinde eğitilen modeldir ve öğeler, veri yığınlarıdır.

Yine bir hesaplama (kullanmış olduğu İkincisi, not batch_train başka (içinde bir bileşen olarak) local_train ), ancak doğrudan. İndirgeme operatörü olarak kullanamayız çünkü ek bir parametre alır - öğrenme oranı. Bu sorunu çözmek için, gömülü bir birleşik hesaplama tanımlamak batch_fn edilene bağlanır local_train 's parametresi learning_rate kendi gövdesi. Bu şekilde tanımlanan bir alt hesaplamanın, alt hesaplama ebeveyninin gövdesi dışında çağrılmadığı sürece ebeveyninin resmi bir parametresini yakalamasına izin verilir. Sen bir eşdeğeri olarak bu desen düşünebiliriz functools.partial Python.

Yakalama pratik ima learning_rate bu şekilde aynı öğrenme hızı değeri, tüm gruplar arasında kullanıldığını, tabii ki.

Şimdi, hadi örnek toplu (haneli katkıda aynı kullanıcıdan gelen verinin bütün dizisi üzerinde yeni tanımlanan yerel eğitim işlevini deneyin 5 ).

locally_trained_model = local_train(initial_model, 0.1, federated_train_data[5])

İşe yaradı mı? Bu soruyu cevaplamak için değerlendirmeyi uygulamamız gerekiyor.

Yerel değerlendirme

İşte tüm veri grupları arasındaki kayıpları toplayarak yerel değerlendirmeyi uygulamanın bir yolu (ortalamayı da hesaplayabilirdik; bunu okuyucu için bir alıştırma olarak bırakacağız).

@tff.federated_computation(MODEL_TYPE, LOCAL_DATA_TYPE)
def local_eval(model, all_batches):

  @tff.tf_computation(MODEL_TYPE, LOCAL_DATA_TYPE)
  def _insert_model_to_sequence(model, dataset):
    return dataset.map(lambda x: (model, x))

  model_plus_data = _insert_model_to_sequence(model, all_batches)

  @tff.tf_computation(tf.float32, batch_loss.type_signature.result)
  def tff_add(accumulator, arg):
    return accumulator + arg

  return tff.sequence_reduce(
      tff.sequence_map(
          batch_loss,
          model_plus_data), 0., tff_add)
str(local_eval.type_signature)
'(<model=<weights=float32[784,10],bias=float32[10]>,all_batches=<x=float32[?,784],y=int32[?]>*> -> float32)'

Yine, bu kodla gösterilen birkaç yeni öğe var, bunları tek tek inceleyelim.

İlk olarak, işlemleri sırasında iki yeni birleşik operatörler kullandık: tff.sequence_map bir eşleştirme işlevi alır T->U ve bir dizi T ve bir dizi yayan U eşleme fonksiyonu noktasal uygulanarak elde edildi ve tff.sequence_sum bu sadece tüm öğeleri ekler. Burada, her bir veri grubunu bir kayıp değerine eşler ve ardından toplam kaybı hesaplamak için ortaya çıkan kayıp değerlerini toplarız.

Tekrar kullanmış olabilir Not tff.sequence_reduce haritalama ve toplamı paralel olarak hesaplanabilir oysa azaltma işlemidir, tanım, sıralı tarafından - ama bu en iyi seçenek olmaz. Bir seçenek verildiğinde, uygulama seçimlerini kısıtlamayan operatörlere bağlı kalmak en iyisidir, böylece TFF hesaplamamız gelecekte belirli bir ortama dağıtılmak üzere derlendiğinde, daha hızlı için tüm potansiyel fırsatlardan tam olarak yararlanılabilir. , daha ölçeklenebilir, daha verimli kaynak yürütme.

İkincisi, sadece olduğu gibi bu notu local_train , biz gerekmez bileşen fonksiyonu ( batch_loss ) Ne federe operatörü daha fazla parametre alır ( tff.sequence_map ) beklediği, yine doğrudan sararak bu sefer inline kısmi tanımlamak böylece lambda bir şekilde tff.federated_computation . Bağımsız değişken olarak bir işlevle satır içi sarmalayıcılarını kullanma kullanmak için önerilen bir yoldur tff.tf_computation TFF 'de embed TensorFlow mantığı.

Şimdi, eğitimimizin işe yarayıp yaramadığını görelim.

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[5]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[5]))
initial_model loss = 23.025854
locally_trained_model loss = 0.43484688

Nitekim kayıp azaldı. Ama bunu başka bir kullanıcının verileri üzerinde değerlendirirsek ne olur?

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[0]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[0]))
initial_model loss = 23.025854
locally_trained_model loss = 74.50075

Beklendiği gibi, işler daha da kötüye gitti. Modeli tanımak için eğitildim 5 ve görmediği 0 . Bu, şu soruyu getiriyor: yerel eğitim, modelin kalitesini küresel perspektiften nasıl etkiledi?

Birleşik değerlendirme

Bu, yolculuğumuzda nihayet federe türlere ve federe hesaplamalara geri döndüğümüz noktadır - başladığımız konu. Sunucudan kaynaklanan model ve istemcilerde kalan veriler için bir çift TFF türü tanımı.

SERVER_MODEL_TYPE = tff.type_at_server(MODEL_TYPE)
CLIENT_DATA_TYPE = tff.type_at_clients(LOCAL_DATA_TYPE)

Şimdiye kadar tanıtılan tüm tanımlarla birlikte, TFF'de birleşik değerlendirmeyi ifade etmek tek yönlüdür - modeli müşterilere dağıtırız, her müşterinin yerel veri kısmı üzerinde yerel değerlendirme başlatmasına izin veririz ve ardından kaybın ortalamasını alırız. İşte bunu yazmanın bir yolu.

@tff.federated_computation(SERVER_MODEL_TYPE, CLIENT_DATA_TYPE)
def federated_eval(model, data):
  return tff.federated_mean(
      tff.federated_map(local_eval, [tff.federated_broadcast(model),  data]))

Zaten örneklerini gördüğümüz tff.federated_mean ve tff.federated_map daha basit senaryolarda ve sezgisel düzeyde, onlar beklendiği gibi çalışır, ancak o yüzden dikkatli üzerinden geçelim, daha göründüğünden daha kod bu bölümde var.

İlk olarak, aşağı edelim kırılma veri parçasının kendi yerel bölümünü yerel değerlendirmede çağırmak her müşteri bildirin. Eğer önceki bölümlerden Hatırlayacağınız gibi, local_eval formu türüdür imzası vardır (<MODEL_TYPE, LOCAL_DATA_TYPE> -> float32) .

Birleşik operatör tff.federated_map bir parametre olarak bir tür eşleştirme işlevi oluşan bir 2-tuple kabul eden bir şablon T->U ve tip bir birleşik değeri {T}@CLIENTS üye bileşenleri ile, (örneğin, aynı eşleştirme işlevi parametresi olarak türü) ve döner tip bir sonucu {U}@CLIENTS .

Bizler beslenme yana local_eval başına istemci bazında uygulamak için bir eşleme fonksiyonu olarak, ikinci argüman federe tür olmalıdır {<MODEL_TYPE, LOCAL_DATA_TYPE>}@CLIENTS önceki bölümlerden terminolojideki yani, olması gerektiği federe bir demet ol. Her istemci için bağımsız değişkenlerin tam bir set tutmak gerekir local_eval üye consituent olarak. Bunun yerine, biz bunu 2 öğeli Python besliyorlar list . Burada neler oluyor?

Bir beslerken Aslında bu, örneğin başka bir yerde karşılaşmış olabilirsiniz örtülü tip alçı, benzer TFF, bir örtülü tip döküm örneğidir int bir kabul eden bir işleve float . Bu noktada örtülü döküm çok az kullanılır, ancak kazan plakasını en aza indirmenin bir yolu olarak bunu TFF'de daha yaygın hale getirmeyi planlıyoruz.

Bu durumda uygulandığında örtülü döküm birleşik formunun dizilerini arasında muadilidir {<X,Y>}@Z ve birleşik değerleri küpe <{X}@Z,{Y}@Z> . Resmen olsa da, bu iki programcılar perspektifinden bakarak, farklı tip imzaları vardır, her cihaz Z veri iki ünite tutan X ve Y . Burada yapılan budur benzemez zip Python ve gerçekten de, biz bir operatör sunuyoruz tff.federated_zip böyle dönüşümler explicity gerçekleştirmesini sağlar. Ne zaman tff.federated_map ikinci argüman olarak bir demet karşılaştığında, basitçe çağırır tff.federated_zip senin için.

Yukarıda verilen, artık ifade tanıması gerekir tff.federated_broadcast(model) TFF tipi bir değerini temsil olarak {MODEL_TYPE}@CLIENTS ve data TFF tipte bir değer olarak {LOCAL_DATA_TYPE}@CLIENTS (veya sadece CLIENT_DATA_TYPE ) iki örtülü bir yoluyla birbirine süzüldü elde tff.federated_zip ikinci bağımsız değişken oluşturmak üzere tff.federated_map .

Operatör tff.federated_broadcast beklediğiniz gibi, basitçe müşterilerine sunucudan veri aktarır.

Şimdi yerel eğitimimizin sistemdeki ortalama kaybı nasıl etkilediğini görelim.

print('initial_model loss =', federated_eval(initial_model,
                                             federated_train_data))
print('locally_trained_model loss =',
      federated_eval(locally_trained_model, federated_train_data))
initial_model loss = 23.025852
locally_trained_model loss = 54.432625

Gerçekten de, beklendiği gibi, kayıp arttı. Modeli tüm kullanıcılar için geliştirmek amacıyla herkesin verilerini eğitmemiz gerekecek.

birleşik eğitim

Birleşik eğitimi uygulamanın en basit yolu, yerel olarak eğitmek ve ardından modellerin ortalamasını almaktır. Bu, aşağıda görebileceğiniz gibi, daha önce tartıştığımız yapı taşlarını ve kalıpları kullanır.

SERVER_FLOAT_TYPE = tff.type_at_server(tf.float32)


@tff.federated_computation(SERVER_MODEL_TYPE, SERVER_FLOAT_TYPE,
                           CLIENT_DATA_TYPE)
def federated_train(model, learning_rate, data):
  return tff.federated_mean(
      tff.federated_map(local_train, [
          tff.federated_broadcast(model),
          tff.federated_broadcast(learning_rate), data
      ]))

Not sağladığı Federe Ortalaması Alma tam özellikli uygulanmasında olduğunu tff.learning yerine modellerini ortalama biz bir takım nedenlerden, örneğin, güncelleme normları klibi yeteneği sıkıştırma için, vs için, ortalama modeli deltaları tercih .

Birkaç tur antrenman yaparak ve öncesi ve sonrası ortalama kaybı karşılaştırarak antrenmanın işe yarayıp yaramadığını görelim.

model = initial_model
learning_rate = 0.1
for round_num in range(5):
  model = federated_train(model, learning_rate, federated_train_data)
  learning_rate = learning_rate * 0.9
  loss = federated_eval(model, federated_train_data)
  print('round {}, loss={}'.format(round_num, loss))
round 0, loss=21.60552215576172
round 1, loss=20.365678787231445
round 2, loss=19.27480125427246
round 3, loss=18.311111450195312
round 4, loss=17.45725440979004

Tamamlanması için, şimdi modelimizin iyi bir şekilde genelleştiğini doğrulamak için test verileri üzerinde de çalışalım.

print('initial_model test loss =',
      federated_eval(initial_model, federated_test_data))
print('trained_model test loss =', federated_eval(model, federated_test_data))
initial_model test loss = 22.795593
trained_model test loss = 17.278767

Bu, eğitimimizi tamamlıyor.

Tabii ki, basitleştirilmiş örneğimiz daha gerçekçi bir senaryoda yapmanız gereken bir dizi şeyi yansıtmaz - örneğin, kayıp dışında metrikleri hesaplamadık. Biz çalışmak için teşvik uygulanmasını içinde federe ortalama alınmasının tff.learning Daha kapsamlı bir örnek olarak ve biz teşvik etmek istiyoruz kodlama uygulamalardan bazıları göstermek için bir yol olarak.