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

مشاهده در 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 استفاده خواهیم کرد.

جداول جستجوی vocab را ایجاد کنید

# 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 کاراکتر از متن خواهد مجموعه داده خالی داشته باشد. یک رویکرد معمولی برای رسیدگی به این موضوع این است که دسته‌ها را با یک توکن خاص بپوشانیم و سپس ضرر را بپوشانیم تا توکن‌های padding را در نظر نگیریم.

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

حالا ما می توانیم ما پیش پردازش 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 ، ما نیاز به آن را کامپایل با از دست دادن و معیارهای. ما همچنین یک بهینه ساز را کامپایل خواهیم کرد که به عنوان بهینه ساز روی دستگاه در آموزش فدرال استفاده می شود.

آموزش اصلی دقت در سطح کاراکتر نداشت (کسری از پیش‌بینی‌ها که در آن بیشترین احتمال در کاراکتر صحیح بعدی قرار داده شد). این یک معیار مفید است، بنابراین ما آن را اضافه می کنیم. با این حال، ما نیاز به تعریف یک کلاس متریک جدید برای این به دلیل پیش بینی های ما رتبه 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) .