آموزش فدراسیون برای تولید متن

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

این آموزش بر اساس مفاهیم در یادگیری فدرال برای تصویر طبقه بندی آموزش، و نشان می دهد چندین روش مفید دیگر برای یادگیری فدرال.

به طور خاص ، ما یک مدل Keras قبلاً آموزش دیده را بارگذاری می کنیم و آن را با استفاده از آموزش های فدرال بر روی یک مجموعه داده غیر متمرکز (شبیه سازی شده) اصلاح می کنیم. این امر به چند دلیل عملاً مهم است. توانایی استفاده از مدلهای سریالی باعث می شود که یادگیری فدرال با سایر روشهای ML ترکیب شود. به علاوه، این اجازه می دهد تا استفاده از افزایش دامنه مدل های از پیش آموزش دیده --- برای مثال، مدل آموزش زبان از ابتدا به ندرت لازم است، به عنوان مدل های متعدد از پیش آموزش دیده اکنون به طور گسترده ای در دسترس (برای مثال نگاه کنید، TF توپی ). در عوض ، منطقی تر است که از یک مدل از پیش آموزش دیده شروع کرده و آن را با استفاده از آموزش فدرال ، با ویژگی های خاص داده های غیر متمرکز برای یک برنامه خاص تطبیق دهید.

برای این آموزش ، ما با یک RNN شروع می کنیم که کاراکترهای ASCII را تولید می کند ، و آن را از طریق یادگیری یکپارچه اصلاح می کنیم. ما همچنین نشان می دهیم که چگونه می توان وزنهای نهایی را به مدل اصلی Keras بازگردانده و امکان ارزیابی آسان و تولید متن با استفاده از ابزارهای استاندارد را فراهم آورد.

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

یک مدل از پیش آموزش داده شده را بارگذاری کنید

ما یک مدل است که قبل از آموزش دیده بود پس از آموزش TensorFlow بار نسل متن با استفاده از یک RNN با اجرای مشتاق . با این حال، به جای آموزش در آثار کامل شکسپیر ، ما قبل از آموزش دیده مدل در متن از چارلز دیکنز داستان دو شهر و سرود کریسمس .

ما به جز گسترش واژگان ، آموزش اصلی را تغییر ندادیم ، بنابراین این مدل اولیه پیشرفته نیست ، اما پیش بینی های منطقی را ایجاد می کند و برای اهداف آموزشی ما کافی است. مدل نهایی با ذخیره شد tf.keras.models.save_model(include_optimizer=False) .

ما از آموزش فدرال برای تنظیم دقیق این مدل برای شکسپیر در این آموزش ، با استفاده از نسخه فدراسیون داده های ارائه شده توسط TFF استفاده خواهیم کرد.

ایجاد جداول جستجوی واژگان

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

مدل از پیش آموزش داده شده را بارگذاری کرده و مقداری متن تولید کنید

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

بارگیری و پیش پردازش داده های فدراسیون شکسپیر

tff.simulation.datasets بسته انواع مجموعه داده است که به "مشتری"، تقسیم فراهم می کند که در آن هر مشتری مربوط به یک مجموعه داده در یک دستگاه خاص که ممکن است در یادگیری فدرال شرکت کنند.

این مجموعه داده ها توزیع واقعی داده های غیر IID را ارائه می دهند که در شبیه سازی چالش های آموزش داده های غیر متمرکز واقعی تکرار می شود. برخی از پیش پردازش این داده ها با استفاده از ابزار از انجام شد پروژه برگ ( گیتهاب ).

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

مجموعه داده های ارائه شده توسط shakespeare.load_data() شامل دنباله ای از رشته Tensors ، یکی برای هر خط به یک شخصیت خاص در یک نمایشنامه شکسپیر سخن گفته است. کلید مشتری از نام بازی پیوست با نام از شخصیت های تشکیل شده، به طوری که برای مثال MUCH_ADO_ABOUT_NOTHING_OTHELLO مربوط به خطوط برای شخصیت اتللو در بازی هیاهوی بسیار برای هیچ. توجه داشته باشید که در یک سناریوی یادگیری واقعی فدرال مشتری ها هرگز شناسایی یا ردیابی نمی شوند ، اما برای شبیه سازی کار با مجموعه داده های کلیدی مفید است.

در اینجا ، برای مثال ، می توانیم برخی از داده های شاه لیر را مشاهده کنیم:

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

ما در حال حاضر استفاده tf.data.Dataset تحولات برای آماده سازی این داده ها برای آموزش کاراکتر RNN لود کنید.

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

توجه داشته باشید که در شکل گیری توالی های اصلی و در شکل گیری دسته فوق، ما با استفاده از drop_remainder=True برای سادگی. به این معنی که هر کاراکتر (مشتریان) است که لازم نیست حداقل (SEQ_LENGTH + 1) * BATCH_SIZE کاراکتر از متن خواهد مجموعه داده خالی داشته باشد. یک رویکرد معمولی برای رسیدگی به این امر این است که دسته ها را با یک نشان مخصوص قرار دهید و سپس ضرر را برای درنظر نگرفتن نشانه های پر کردن مخفی کنید.

در این صورت، به عنوان مثال تا حدودی پیچیده است، بنابراین برای این آموزش ما تنها با استفاده از دسته های کامل، به عنوان در آموزش استاندارد . با این حال ، در تنظیمات فدراسیون این مسئله اهمیت بیشتری دارد ، زیرا بسیاری از کاربران ممکن است مجموعه داده های کوچکی داشته باشند.

حالا ما می توانیم ما پیش پردازش raw_example_dataset ، و بررسی انواع:

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

مدل را کامپایل کرده و روی داده های از پیش پردازش شده آزمایش کنید

ما لود مدل keras uncompiled، اما به منظور اجرای keras_model.evaluate ، ما نیاز به آن را کامپایل با از دست دادن و معیارهای. ما همچنین در یک بهینه ساز ، که به عنوان بهینه ساز روی دستگاه در یادگیری فدرال استفاده می شود ، کامپایل می کنیم.

آموزش اصلی از دقت سطح char برخوردار نبود (کسری از پیش بینی ها که بیشترین احتمال را روی کاراکتر صحیح بعدی قرار می داد). این یک معیار مفید است ، بنابراین ما آن را اضافه می کنیم. با این حال، ما نیاز به تعریف یک کلاس متریک جدید برای این به دلیل پیش بینی های ما رتبه 3 (یک بردار از logits برای هر یک از BATCH_SIZE * SEQ_LENGTH پیش بینی) و SparseCategoricalAccuracy انتظار تنها رتبه 2 پیش بینی.

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)

حالا ما می توانیم یک مدل کامپایل، و ارزیابی آن در ما 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

مدل را با آموزش فدرال تنظیم کنید

TFF تمام محاسبات TensorFlow را سریال می کند تا بتوان آنها را به طور بالقوه در محیطی غیر از پایتون اجرا کرد (حتی اگر در حال حاضر ، فقط زمان اجرای شبیه سازی اجرا شده در پایتون در دسترس باشد). حتی اگر ما در حال اجرا هستند را در حالت مشتاق، (TF 2.0)، در حال حاضر TFF serializes TensorFlow محاسبات بوسیله ساختن عملیات لازم در داخل قالب " with tf.Graph.as_default() " بیانیه. بنابراین ، ما باید یک تابع ارائه دهیم که TFF بتواند از آن برای معرفی مدل ما در نمودار مورد کنترل خود استفاده کند. این کار را به صورت زیر انجام می دهیم:

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

حالا ما آماده برای ساخت یک فرآیند تکرار شونده فدرال به طور متوسط، که ما استفاده خواهیم به منظور بهبود مدل (برای جزئیات بیشتر در مورد الگوریتم به طور متوسط فدرال، مقاله را ببینید ارتباطات کارآمد آموزش شبکه عمیق از غیر متمرکز داده ).

ما از مدل Keras تدوین شده برای ارزیابی استاندارد (غیر فدراسیون) بعد از هر دور آموزش فدراسیون استفاده می کنیم. این امر برای اهداف تحقیقاتی هنگام انجام یادگیری فدرال شبیه سازی شده و مجموعه داده استاندارد آزمون وجود دارد.

در یک محیط تولید واقع بینانه ، ممکن است از این تکنیک برای مدل هایی استفاده شود که با یادگیری فدراسیون آموزش دیده اند و آنها را بر اساس یک مجموعه داده معیار متمرکز برای آزمایش یا اهداف تضمین کیفیت ارزیابی می کند.

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

در اینجا ساده ترین حلقه ممکن است ، جایی که ما میانگین فدرال را برای یک دور در یک مشتری واحد در یک دسته واحد اجرا می کنیم:

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

حالا بیایید یک حلقه آموزشی و ارزیابی کمی جالب تر بنویسیم.

به طوری که این شبیه سازی هنوز نسبتاً سریع اجرا می شود ، ما در هر دور روی سه مشتری یکسان تمرین می کنیم ، فقط دو مینی دسته برای هر کدام در نظر می گیریم.

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() بر Initializer نام تصادفی برای مدل Keras، نه وزن که لود شد بر اساس، از clone_model() می کند وزن نمی کلون. برای شروع آموزش از یک مدل از پیش آموزش دیده ، وزن مدل را در حالت سرور مستقیماً از مدل بارگذاری شده تنظیم می کنیم.

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

با تغییرات پیش فرض ، ما آموزش کافی را برای ایجاد تغییر بزرگ انجام نداده ایم ، اما اگر مدت طولانی تری روی داده های بیشتر شکسپیر تمرین کنید ، باید تفاوت در سبک متن ایجاد شده با مدل به روز شده را مشاهده کنید:

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

افزونه های پیشنهادی

این آموزش فقط اولین قدم است! در اینجا چند ایده برای نحوه استفاده از این نوت بوک وجود دارد:

  • یک حلقه آموزشی واقع بینانه بنویسید که در آن از مشتریان برای آموزش تصادفی نمونه می گیرید.
  • استفاده از " .repeat(NUM_EPOCHS) " در مجموعه داده مشتری را امتحان کنید دوره های متعدد آموزش محلی (به عنوان مثال، همانطور که در مکماهان و همکاران ). همچنین نگاه فدرال آموزشی برای طبقه بندی تصویر که این کار را.
  • تغییر compile() فرمان به آزمایش با استفاده از الگوریتم های بهینه سازی های مختلف بر روی سرویس گیرنده.
  • سعی کنید server_optimizer آرگومان به build_federated_averaging_process به تلاش الگوریتم های مختلف برای استفاده از به روز رسانی مدل بر روی سرور.
  • سعی کنید client_weight_fn استدلال به build_federated_averaging_process به سعی کنید وزن های مختلف از مشتریان. به روز رسانی وزن به طور پیش فرض مشتری شده توسط تعدادی از نمونه بر روی سرویس گیرنده، اما شما می توانید انجام دهید به عنوان مثال client_weight_fn=lambda _: tf.constant(1.0) .