Metin Oluşturma 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 kavramlar üzerine inşa Görüntü Sınıflandırma için Federe Öğrenme öğretici ve federe öğrenme için çeşitli diğer yararlı yaklaşımlar ortaya koymaktadır.

Özellikle, önceden eğitilmiş bir Keras modelini yüklüyoruz ve (simüle edilmiş) merkezi olmayan bir veri kümesinde birleşik eğitim kullanarak onu iyileştiriyoruz. Bu, birkaç nedenden dolayı pratik olarak önemlidir. Serileştirilmiş modelleri kullanma yeteneği, federe öğrenmeyi diğer makine öğrenimi yaklaşımlarıyla karıştırmayı kolaylaştırır. Dahası, bu ön-eğitimli modeller giderek artan aralığının kullanımına izin sayısız önceden eğitilmiş modelleri (bakınız, örneğin, artık yaygın olarak mevcuttur olarak --- örneğin, sıfırdan eğitim dil modelleri, nadiren gereklidir TF Hub ). Bunun yerine, önceden eğitilmiş bir modelden başlamak ve belirli bir uygulama için merkezi olmayan verilerin belirli özelliklerine uyum sağlayarak Federated Learning kullanarak onu iyileştirmek daha mantıklıdır.

Bu öğretici için, ASCII karakterleri üreten bir RNN ile başlıyoruz ve bunu birleşik öğrenme yoluyla iyileştiriyoruz. Ayrıca son ağırlıkların orijinal Keras modeline nasıl geri beslenebileceğini ve standart araçları kullanarak kolay değerlendirme ve metin oluşturmaya olanak sağladığını gösteriyoruz.

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

import nest_asyncio
nest_asyncio.apply()
import collections
import functools
import os
import time

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

np.random.seed(0)

# Test the TFF is working:
tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

Önceden eğitilmiş bir model yükleyin

Biz TensorFlow öğretici aşağıdaki önceden eğitildi bir model yük istekli yürütme ile bir RNN kullanarak metin nesil . Ancak, daha doğrusu üzerinde eğitim daha Shakespeare Complete Works , biz Charles Dickens'ın gelen metin üzerinde modeli önceden eğitilmiş İki Şehrin Hikayesi ve A Christmas Carol .

Kelime dağarcığını genişletmekten başka, orijinal öğreticiyi değiştirmedik, bu nedenle bu ilk model son teknoloji değil, ancak makul tahminler üretiyor ve eğitim amaçlarımız için yeterli. Son model ile kurtarıldı tf.keras.models.save_model(include_optimizer=False) .

Bu öğreticide, TFF tarafından sağlanan verilerin birleşik bir sürümünü kullanarak bu modelde Shakespeare için ince ayar yapmak için birleşik öğrenmeyi kullanacağız.

Kelime arama tablolarını oluşturun

# A fixed vocabularly of ASCII chars that occur in the works of Shakespeare and Dickens:
vocab = list('dhlptx@DHLPTX $(,048cgkoswCGKOSW[_#\'/37;?bfjnrvzBFJNRVZ"&*.26:\naeimquyAEIMQUY]!%)-159\r')

# Creating a mapping from unique characters to indices
char2idx = {u:i for i, u in enumerate(vocab)}
idx2char = np.array(vocab)

Önceden eğitilmiş modeli yükleyin ve biraz metin oluşturun

def load_model(batch_size):
  urls = {
      1: 'https://storage.googleapis.com/tff-models-public/dickens_rnn.batch1.kerasmodel',
      8: 'https://storage.googleapis.com/tff-models-public/dickens_rnn.batch8.kerasmodel'}
  assert batch_size in urls, 'batch_size must be in ' + str(urls.keys())
  url = urls[batch_size]
  local_file = tf.keras.utils.get_file(os.path.basename(url), origin=url)  
  return tf.keras.models.load_model(local_file, compile=False)
def generate_text(model, start_string):
  # From https://www.tensorflow.org/tutorials/sequences/text_generation
  num_generate = 200
  input_eval = [char2idx[s] for s in start_string]
  input_eval = tf.expand_dims(input_eval, 0)
  text_generated = []
  temperature = 1.0

  model.reset_states()
  for i in range(num_generate):
    predictions = model(input_eval)
    predictions = tf.squeeze(predictions, 0)
    predictions = predictions / temperature
    predicted_id = tf.random.categorical(
        predictions, num_samples=1)[-1, 0].numpy()
    input_eval = tf.expand_dims([predicted_id], 0)
    text_generated.append(idx2char[predicted_id])

  return (start_string + ''.join(text_generated))
# Text generation requires a batch_size=1 model.
keras_model_batch1 = load_model(batch_size=1)
print(generate_text(keras_model_batch1, 'What of TensorFlow Federated, you ask? '))
Downloading data from https://storage.googleapis.com/tff-models-public/dickens_rnn.batch1.kerasmodel
16195584/16193984 [==============================] - 0s 0us/step
16203776/16193984 [==============================] - 0s 0us/step
What of TensorFlow Federated, you ask? Sall
yesterday. Received the Bailey."

"Mr. Lorry, grimmering himself, or low varked thends the winter, and the eyes of Monsieur
Defarge. "Let his mind, hon in his
life and message; four declare

Birleşik Shakespeare Verilerini Yükleyin ve Ön İşleme Alın

tff.simulation.datasets paketi "müşteri", bölünür veri kümeleri çeşitli sağlamaktadır ki burada birleşik öğrenme katılabilir belirli bir cihazda bir veri kümesi için her istemci denk gelmektedir.

Bu veri kümeleri, gerçek merkezi olmayan veriler üzerinde eğitimin zorluklarını simülasyonda çoğaltan gerçekçi IID olmayan veri dağılımları sağlar. Bu verilerin ön işleme bazıları gelen araçları kullanılarak yapıldı Yaprak projesi ( github ).

train_data, test_data = tff.simulation.datasets.shakespeare.load_data()

Tarafından sağlanan veri kümeleri shakespeare.load_data() dizisi bir dizi meydana Tensors , Shakespeare oyunun belli bir karakter konuştuğu her hat için bir. İstemci tuşları böylece örneğin karakterin adı ile direkten oyun adının oluşur MUCH_ADO_ABOUT_NOTHING_OTHELLO oyun Yok Yere Yaygara karakter Othello için hatlar karşılık gelir. Gerçek bir federe öğrenme senaryosunda istemcilerin asla kimlikler tarafından tanımlanmadığını veya izlenmediğini, ancak simülasyon için anahtarlı veri kümeleriyle çalışmanın faydalı olduğunu unutmayın.

Örneğin burada King Lear'dan bazı verilere bakabiliriz:

# Here the play is "The Tragedy of King Lear" and the character is "King".
raw_example_dataset = train_data.create_tf_dataset_for_client(
    'THE_TRAGEDY_OF_KING_LEAR_KING')
# To allow for future extensions, each entry x
# is an OrderedDict with a single key 'snippets' which contains the text.
for x in raw_example_dataset.take(2):
  print(x['snippets'])
tf.Tensor(b'', shape=(), dtype=string)
tf.Tensor(b'What?', shape=(), dtype=string)

Biz artık kullanıma tf.data.Dataset RYSA yukarıda yüklenen kömürü eğitimi için bu verileri hazırlamak için dönüşümleri.

# Input pre-processing parameters
SEQ_LENGTH = 100
BATCH_SIZE = 8
BUFFER_SIZE = 100  # For dataset shuffling
# Construct a lookup table to map string chars to indexes,
# using the vocab loaded above:
table = tf.lookup.StaticHashTable(
    tf.lookup.KeyValueTensorInitializer(
        keys=vocab, values=tf.constant(list(range(len(vocab))),
                                       dtype=tf.int64)),
    default_value=0)


def to_ids(x):
  s = tf.reshape(x['snippets'], shape=[1])
  chars = tf.strings.bytes_split(s).values
  ids = table.lookup(chars)
  return ids


def split_input_target(chunk):
  input_text = tf.map_fn(lambda x: x[:-1], chunk)
  target_text = tf.map_fn(lambda x: x[1:], chunk)
  return (input_text, target_text)


def preprocess(dataset):
  return (
      # Map ASCII chars to int64 indexes using the vocab
      dataset.map(to_ids)
      # Split into individual chars
      .unbatch()
      # Form example sequences of SEQ_LENGTH +1
      .batch(SEQ_LENGTH + 1, drop_remainder=True)
      # Shuffle and form minibatches
      .shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)
      # And finally split into (input, target) tuples,
      # each of length SEQ_LENGTH.
      .map(split_input_target))

Not orijinal dizilerin yukarıda gruplar oluşumunda oluşumunda, kullandığımız bu drop_remainder=True basitlik için. Bu araçlar içermeyen tüm karakterler (istemciler) en azından (SEQ_LENGTH + 1) * BATCH_SIZE metnin karakter boş veri setlerini sahip olacaktır. Bunu ele almak için tipik bir yaklaşım, grupları özel bir jetonla doldurmak ve ardından dolgu jetonlarını hesaba katmamak için kaybı maskelemek olacaktır.

Bu nedenle bu eğitim için biz sadece olduğu gibi, tam toplu kullanmak, biraz örnek karmaşık hale getireceği standart öğretici . Ancak, federasyon ayarında bu sorun daha önemlidir, çünkü birçok kullanıcının küçük veri kümeleri olabilir.

Şimdi bizim için ön işlemeden edebilir raw_example_dataset ve türlerini kontrol edin:

example_dataset = preprocess(raw_example_dataset)
print(example_dataset.element_spec)
(TensorSpec(shape=(8, 100), dtype=tf.int64, name=None), TensorSpec(shape=(8, 100), dtype=tf.int64, name=None))

Modeli derleyin ve önceden işlenmiş veriler üzerinde test edin

Biz bir uncompiled keras modeli yüklendi, ancak çalışma amacıyla keras_model.evaluate , bir kayıp ve ölçümler ile derlemek gerekiyor. Ayrıca Federated Learning'de cihaz üzerinde optimize edici olarak kullanılacak bir optimize edicide derleyeceğiz.

Orijinal öğretici, karakter düzeyinde doğruluğa sahip değildi (en yüksek olasılığın bir sonraki doğru karaktere yerleştirildiği tahminlerin oranı). Bu yararlı bir ölçümdür, bu yüzden onu ekliyoruz. Ancak, bizim tahminler rütbe 3 (her biri için logits vektör var çünkü bunun için yeni bir metrik sınıfını tanımlamak gerekir BATCH_SIZE * SEQ_LENGTH tahminleri) ve SparseCategoricalAccuracy sadece rütbe 2 tahminler bekliyor.

class FlattenedCategoricalAccuracy(tf.keras.metrics.SparseCategoricalAccuracy):

  def __init__(self, name='accuracy', dtype=tf.float32):
    super().__init__(name, dtype=dtype)

  def update_state(self, y_true, y_pred, sample_weight=None):
    y_true = tf.reshape(y_true, [-1, 1])
    y_pred = tf.reshape(y_pred, [-1, len(vocab), 1])
    return super().update_state(y_true, y_pred, sample_weight)

Şimdi bir model derlemek ve bizim üzerinde değerlendirebilir example_dataset .

BATCH_SIZE = 8  # The training and eval batch size for the rest of this tutorial.
keras_model = load_model(batch_size=BATCH_SIZE)
keras_model.compile(
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=[FlattenedCategoricalAccuracy()])

# Confirm that loss is much lower on Shakespeare than on random data
loss, accuracy = keras_model.evaluate(example_dataset.take(5), verbose=0)
print(
    'Evaluating on an example Shakespeare character: {a:3f}'.format(a=accuracy))

# As a sanity check, we can construct some completely random data, where we expect
# the accuracy to be essentially random:
random_guessed_accuracy = 1.0 / len(vocab)
print('Expected accuracy for random guessing: {a:.3f}'.format(
    a=random_guessed_accuracy))
random_indexes = np.random.randint(
    low=0, high=len(vocab), size=1 * BATCH_SIZE * (SEQ_LENGTH + 1))
data = collections.OrderedDict(
    snippets=tf.constant(
        ''.join(np.array(vocab)[random_indexes]), shape=[1, 1]))
random_dataset = preprocess(tf.data.Dataset.from_tensor_slices(data))
loss, accuracy = keras_model.evaluate(random_dataset, steps=10, verbose=0)
print('Evaluating on completely random data: {a:.3f}'.format(a=accuracy))
Downloading data from https://storage.googleapis.com/tff-models-public/dickens_rnn.batch8.kerasmodel
16195584/16193984 [==============================] - 0s 0us/step
16203776/16193984 [==============================] - 0s 0us/step
Evaluating on an example Shakespeare character: 0.402000
Expected accuracy for random guessing: 0.012
Evaluating on completely random data: 0.011

Federated Learning ile modelde ince ayar yapın

TFF, tüm TensorFlow hesaplamalarını potansiyel olarak Python dışı bir ortamda çalıştırılabilmesi için seri hale getirir (şu anda yalnızca Python'da uygulanan bir simülasyon çalışma zamanı mevcut olsa da). Biz istekli modunda (TF 2.0) çalışan rağmen, şu anda TFF serializes TensorFlow hesaplamaları bir "bağlamında içine gerekli op inşa ederek with tf.Graph.as_default() " ifadesi. Bu nedenle, modelimizi kontrol ettiği bir grafiğe tanıtmak için TFF'nin kullanabileceği bir fonksiyon sağlamamız gerekiyor. Bunu şu şekilde yapıyoruz:

# Clone the keras_model inside `create_tff_model()`, which TFF will
# call to produce a new copy of the model inside the graph that it will 
# serialize. Note: we want to construct all the necessary objects we'll need 
# _inside_ this method.
def create_tff_model():
  # TFF uses an `input_spec` so it knows the types and shapes
  # that your model expects.
  input_spec = example_dataset.element_spec
  keras_model_clone = tf.keras.models.clone_model(keras_model)
  return tff.learning.from_keras_model(
      keras_model_clone,
      input_spec=input_spec,
      loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
      metrics=[FlattenedCategoricalAccuracy()])

Şimdi biz modelini geliştirmek için kullanacağı bir Federe Averaging iteratif süreç, inşa etmeye hazır (Federe Averaging algoritması ile ilgili ayrıntılar için, kağıt bkz Yerinden Verilerden Derin Ağların Haberleşme-Verimli Öğrenme ).

Her federe eğitim turundan sonra standart (federe olmayan) değerlendirme yapmak için derlenmiş bir Keras modeli kullanıyoruz. Bu, simüle edilmiş birleşik öğrenme yaparken araştırma amaçları için kullanışlıdır ve standart bir test veri seti vardır.

Gerçekçi bir üretim ortamında, bu aynı teknik, birleşik öğrenme ile eğitilmiş modelleri almak ve bunları test veya kalite güvence amaçları için merkezi bir kıyaslama veri kümesinde değerlendirmek için kullanılabilir.

# This command builds all the TensorFlow graphs and serializes them: 
fed_avg = tff.learning.build_federated_averaging_process(
    model_fn=create_tff_model,
    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(lr=0.5))

Tek bir toplu iş üzerinde tek bir istemcide bir tur için birleşik ortalamayı çalıştırdığımız olası en basit döngü aşağıda verilmiştir:

state = fed_avg.initialize()
state, metrics = fed_avg.next(state, [example_dataset.take(5)])
train_metrics = metrics['train']
print('loss={l:.3f}, accuracy={a:.3f}'.format(
    l=train_metrics['loss'], a=train_metrics['accuracy']))
loss=4.403, accuracy=0.132

Şimdi biraz daha ilginç bir eğitim ve değerlendirme döngüsü yazalım.

Bu simülasyonun hala nispeten hızlı çalışması için, her turda aynı üç müşteri üzerinde, her biri için sadece iki mini partiyi dikkate alarak eğitim alıyoruz.

def data(client, source=train_data):
  return preprocess(source.create_tf_dataset_for_client(client)).take(5)


clients = [
    'ALL_S_WELL_THAT_ENDS_WELL_CELIA', 'MUCH_ADO_ABOUT_NOTHING_OTHELLO',
]

train_datasets = [data(client) for client in clients]

# We concatenate the test datasets for evaluation with Keras by creating a 
# Dataset of Datasets, and then identity flat mapping across all the examples.
test_dataset = tf.data.Dataset.from_tensor_slices(
    [data(client, test_data) for client in clients]).flat_map(lambda x: x)

Tarafından üretilen modelinin başlangıç durumu fed_avg.initialize() beri Keras modeli değil, yüklenen ağırlığı için rasgele başlatıcıları dayanır clone_model() ağırlıkları değil klon yapar. Eğitime önceden eğitilmiş bir modelden başlamak için, sunucu durumundaki model ağırlıklarını doğrudan yüklenen modelden ayarladık.

NUM_ROUNDS = 5

# The state of the FL server, containing the model and optimization state.
state = fed_avg.initialize()

# Load our pre-trained Keras model weights into the global model state.
state = tff.learning.state_with_new_model_weights(
    state,
    trainable_weights=[v.numpy() for v in keras_model.trainable_weights],
    non_trainable_weights=[
        v.numpy() for v in keras_model.non_trainable_weights
    ])


def keras_evaluate(state, round_num):
  # Take our global model weights and push them back into a Keras model to
  # use its standard `.evaluate()` method.
  keras_model = load_model(batch_size=BATCH_SIZE)
  keras_model.compile(
      loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
      metrics=[FlattenedCategoricalAccuracy()])
  state.model.assign_weights_to(keras_model)
  loss, accuracy = keras_model.evaluate(example_dataset, steps=2, verbose=0)
  print('\tEval: loss={l:.3f}, accuracy={a:.3f}'.format(l=loss, a=accuracy))


for round_num in range(NUM_ROUNDS):
  print('Round {r}'.format(r=round_num))
  keras_evaluate(state, round_num)
  state, metrics = fed_avg.next(state, train_datasets)
  train_metrics = metrics['train']
  print('\tTrain: loss={l:.3f}, accuracy={a:.3f}'.format(
      l=train_metrics['loss'], a=train_metrics['accuracy']))

print('Final evaluation')
keras_evaluate(state, NUM_ROUNDS + 1)
Round 0
    Eval: loss=3.324, accuracy=0.401
    Train: loss=4.360, accuracy=0.155
Round 1
    Eval: loss=4.361, accuracy=0.049
    Train: loss=4.235, accuracy=0.164
Round 2
    Eval: loss=4.219, accuracy=0.177
    Train: loss=4.081, accuracy=0.221
Round 3
    Eval: loss=4.080, accuracy=0.174
    Train: loss=3.940, accuracy=0.226
Round 4
    Eval: loss=3.991, accuracy=0.176
    Train: loss=3.840, accuracy=0.226
Final evaluation
    Eval: loss=3.909, accuracy=0.171

Varsayılan değişikliklerle, büyük bir fark yaratacak kadar eğitim yapmadık, ancak daha fazla Shakespeare verisi üzerinde daha uzun süre çalışırsanız, güncellenmiş modelle oluşturulan metnin stilinde bir fark görmelisiniz:

# Set our newly trained weights back in the originally created model.
keras_model_batch1.set_weights([v.numpy() for v in keras_model.weights])
# Text generation requires batch_size=1
print(generate_text(keras_model_batch1, 'What of TensorFlow Federated, you ask? '))
What of TensorFlow Federated, you ask? Shalways, I will call your
compet with any city brought their faces uncompany," besumed him. "When he
sticked Madame Defarge pushed the lamps.

"Have I often but no unison. She had probably come,

Önerilen uzantılar

Bu eğitim sadece ilk adımdır! İşte bu not defterini genişletmeyi nasıl deneyebileceğinize dair bazı fikirler:

  • Müşterileri rastgele eğitmek için örneklediğiniz daha gerçekçi bir eğitim döngüsü yazın.
  • Kullanımı " .repeat(NUM_EPOCHS) istemci veri setleri üzerinde" (olduğu gibi örneğin yerel eğitim birden dönemini denemek McMahan ve. Al. ). Ayrıca bkz Görüntü Sınıflandırma için Federe Öğrenme yapar.
  • Değişim compile() istemci üzerinde farklı optimizasyon algoritmaları kullanarak deneye komutu.
  • Deneyin server_optimizer için argüman build_federated_averaging_process sunucusunda modeli güncellemelerini uygulamak için farklı algoritmalar denemek için.
  • Deneyin client_weight_fn için argüman build_federated_averaging_process müşterilerin farklı ağırlıklara denemek için. Varsayılan ağırlıkları istemci istemci üzerinde örneklerle sayısına göre güncellenir, ancak yapabilirsiniz mesela client_weight_fn=lambda _: tf.constant(1.0) .