![]() | ![]() | ![]() | ![]() |
Bu eğitim, Görüntü Sınıflandırma için Federe Öğrenme eğitimindeki kavramları temel alır ve birleşik öğrenme için diğer birkaç yararlı yaklaşımı gösterir.
Özellikle, önceden eğitilmiş bir Keras modelini yüklüyoruz ve merkezi olmayan bir veri kümesinde (simüle edilmiş) 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 ML yaklaşımlarıyla karıştırmayı kolaylaştırır. Dahası, bu, önceden eğitilmiş modellerin artan bir yelpazesinin kullanımına izin verir - örneğin, çok sayıda önceden eğitilmiş model artık yaygın olarak mevcut olduğundan, dil modellerini sıfırdan eğitmek nadiren gereklidir (bkz., Örneğin, TF Hub ). Bunun yerine, önceden eğitilmiş bir modelden başlamak ve belirli bir uygulama için merkezi olmayan verilerin belirli özelliklerine uyarlanarak bunu Federe Öğrenme kullanarak iyileştirmek daha mantıklıdır.
Bu eğitim için, ASCII karakterleri üreten bir RNN ile başlıyoruz ve bunu federe öğrenme yoluyla iyileştiriyoruz. Ayrıca, nihai ağırlıkların orijinal Keras modeline nasıl geri beslenebileceğini göstererek, standart araçlar kullanılarak kolay değerlendirme ve metin oluşturma olanağı sağlıyoruz.
!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
TensorFlow öğretici Metin oluşturmayı takiben, hevesli yürütme ile bir RNN kullanarak önceden eğitilmiş bir model yüklüyoruz. Ancak The Complete Works of Shakespeare'in eğitimi yerine, Charles Dickens'ın A Tale of Two Cities and A Christmas Carol kitabından alınan metin üzerinde modele önceden eğitim verdik.
Kelime dağarcığını genişletmekten başka, orijinal öğreticiyi değiştirmedik, bu nedenle bu ilk model son teknoloji ürünü değildir, ancak makul tahminler üretir ve eğitim amaçlarımız için yeterlidir. Son model tf.keras.models.save_model(include_optimizer=False)
ile kaydedildi.
TFF tarafından sağlanan verilerin birleşik bir sürümünü kullanarak, bu öğreticide Shakespeare için bu modele ince ayar yapmak için federe öğ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 bazı metinler 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
Federe Shakespeare Verilerini Yükleme ve Ön İşleme
tff.simulation.datasets
paketi, her bir istemcinin federe öğrenmeye katılabilecek belirli bir cihazdaki bir veri kümesine karşılık geldiği "istemciler" olarak bölünmüş çeşitli veri kümeleri sağlar.
Bu veri kümeleri, simülasyonda gerçek merkezi olmayan veriler üzerinde eğitimin zorluklarını kopyalayan gerçekçi IID olmayan veri dağıtımları sağlar. Bu verilerin ön işlemlerinden bazıları Leaf projesindeki ( github ) araçlar kullanılarak yapıldı.
train_data, test_data = tff.simulation.datasets.shakespeare.load_data()
shakespeare.load_data()
tarafından sağlanan veri kümeleri, bir Shakespeare oyununda belirli bir karakter tarafından söylenen her satır için bir tane olmak üzere bir dizi Tensors
dizisinden oluşur. İstemci anahtarları, karakterin adıyla birleştirilen oyunun adından oluşur, bu nedenle örneğin MUCH_ADO_ABOUT_NOTHING_OTHELLO
, Much Ado About Nothing oyununda Othello karakterinin satırlarına karşılık gelir. Gerçek bir federe öğrenme senaryosunda istemcilerin hiçbir zaman kimliklerle tanımlanmadığını veya izlenmediğini, ancak simülasyon için anahtarlı veri kümeleriyle çalışmanın yararlı olduğunu unutmayın.
Burada, örneğin, 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)
Şimdi bu verileri yukarıda yüklenen chartf.data.Dataset
için hazırlamak içintf.data.Dataset
dönüşümlerini kullanıyoruz.
# 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))
Orijinal dizilerin oluşumunda ve yukarıdaki grupların oluşumunda, basitlik için drop_remainder=True
kullandığımıza drop_remainder=True
. Bu, en az (SEQ_LENGTH + 1) * BATCH_SIZE
metin karakterine sahip olmayan tüm karakterlerin (istemcilerin) boş veri kümelerine sahip olacağı anlamına gelir. Bunu ele almak için tipik bir yaklaşım, partileri özel bir jetonla doldurmak ve ardından doldurma jetonlarını hesaba katmamak için kaybı maskelemek olacaktır.
Bu, örneği biraz karmaşıklaştıracaktır, bu nedenle bu eğitim için standart eğitimde olduğu gibi yalnızca tam grupları kullanıyoruz. Ancak, federe ayarda bu sorun daha önemlidir, çünkü birçok kullanıcı küçük veri kümelerine sahip olabilir.
Şimdi raw_example_dataset
önceden raw_example_dataset
ve türleri kontrol edebiliriz:
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
Derlenmemiş bir keras modeli yükledik, ancak keras_model.evaluate
çalıştırmak için onu bir kayıp ve keras_model.evaluate
gerekiyor. Ayrıca Federated Learning'de cihaz üzerinde iyileştirici olarak kullanılacak bir optimize edici de derleyeceğiz.
Orijinal eğitimde karakter düzeyinde doğruluk yoktu (en yüksek olasılığın doğru sonraki karaktere konulduğu tahminlerin oranı). Bu yararlı bir ölçüdür, bu yüzden onu ekliyoruz. Bununla birlikte, bunun için yeni bir metrik sınıf tanımlamamız gerekir çünkü tahminlerimiz 3. BATCH_SIZE * SEQ_LENGTH
sahiptir ( BATCH_SIZE * SEQ_LENGTH
tahminlerinin her biri için bir BATCH_SIZE * SEQ_LENGTH
) ve SparseCategoricalAccuracy
yalnızca 2. sıra tahminleri bekler.
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 derleyebilir ve onu example_dataset
değerlendirebiliriz.
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
Modele Federe Öğrenme ile ince ayar yapın
TFF, tüm TensorFlow hesaplamalarını, potansiyel olarak Python dışı bir ortamda çalıştırılabilmeleri için serileştirir (şu anda yalnızca Python'da uygulanan bir simülasyon çalışma zamanı mevcut olsa da). İstekli modda (TF 2.0) çalıştırıyor olsak da, şu anda TFF " with tf.Graph.as_default()
" ifadesi bağlamında gerekli işlemleri oluşturarak TensorFlow hesaplamalarını serileştiriyor. Bu nedenle, modelimizi kontrol ettiği bir grafiğe sokmak için TFF'nin kullanabileceği bir işlev sağlamamız gerekir. 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, modeli iyileştirmek için kullanacağımız bir Federe Ortalama Alma yinelemeli süreci oluşturmaya hazırız (Birleşik Ortalama algoritmasıyla ilgili ayrıntılar için, Merkezi Olmayan Verilerden Derin Ağların İletişim-Verimli Öğrenimi adlı makaleye bakın).
Her bir 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 kümesi vardır.
Gerçekçi bir üretim ortamında bu aynı teknik, federe öğrenme ile eğitilmiş modelleri almak ve bunları test veya kalite güvence amacıyla 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))
İşte 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ü:
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üşteriye eğitim veriyoruz, her biri için sadece iki mini parti düşünü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)
fed_avg.initialize()
tarafından üretilen modelin başlangıç durumu, fed_avg.initialize()
ağırlıkları klonlamadığından, yüklenen ağırlıklara değil, clone_model()
modeli için rastgele başlatıcılara dayanır. Önceden eğitilmiş bir modelden eğitime başlamak için, sunucu durumunda model ağırlıklarını doğrudan yüklenen modelden belirliyoruz.
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 yaratmak için yeterince eğitim yapmadık, ancak daha fazla Shakespeare verisi üzerinde daha uzun süre eğitim alırsanız, güncellenmiş modelle oluşturulan metnin tarzında bir fark görmeniz gerekir:
# 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 defteri 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.
- Birden çok yerel eğitim dönemini denemek için istemci veri kümelerinde "
.repeat(NUM_EPOCHS)
" kullanın (örneğin, McMahan ve diğerlerinde olduğu gibi). Ayrıca bunu yapan Görüntü Sınıflandırması için Federe Öğrenmeye bakın. - İstemcide farklı optimizasyon algoritmaları kullanmayı denemek için
compile()
komutunu değiştirin. -
server_optimizer
model güncellemelerini uygulamak için farklı algoritmalar denemek içinbuild_federated_averaging_process
içinserver_optimizer
bağımsız değişkenini deneyin. -
client_weight_fn
farklı ağırlıklarını denemek içinbuild_federated_averaging_process
içinclient_weight_fn
argümanını deneyin. Varsayılan, istemci güncellemelerini istemcideki örnek sayısına göre ağırlıklandırır, ancak örneğinclient_weight_fn=lambda _: tf.constant(1.0)
.