ارسال داده های مختلف برای مشتریان خاص با tff.federated_select

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

این آموزش نحوه پیاده سازی الگوریتم های فدراسیون سفارشی در TFF را نشان می دهد که نیاز به ارسال داده های مختلف به مشتریان مختلف دارد. شما در حال حاضر ممکن است با آن آشنا tff.federated_broadcast که یک مقدار تک سرور قرار داده شده به تمام مشتریان می فرستد. این آموزش بر مواردی تمرکز می کند که قسمت های مختلف یک مقدار مبتنی بر سرور به کلاینت های مختلف ارسال می شود. این ممکن است برای تقسیم بخش هایی از یک مدل در کلاینت های مختلف مفید باشد تا از ارسال کل مدل به هر کلاینت جدا خودداری شود.

بیایید آغاز شده توسط وارد کردن هر دو tensorflow و tensorflow_federated .

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

import nest_asyncio
nest_asyncio.apply()
import tensorflow as tf
import tensorflow_federated as tff

ارسال مقادیر مختلف بر اساس داده های مشتری

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

list_of_strings_type = tff.TensorType(tf.string, [None])
# We only ever send exactly two values to each client. The number of keys per
# client must be a fixed number across all clients.
number_of_keys_per_client = 2
keys_type = tff.TensorType(tf.int32, [number_of_keys_per_client])
get_size = tff.tf_computation(lambda x: tf.size(x))
select_fn = tff.tf_computation(lambda val, index: tf.gather(val, index))
client_data_type = tf.string

# A function from our client data to the indices of the values we'd like to
# select from the server.
@tff.tf_computation(client_data_type)
@tff.check_returns_type(keys_type)
def keys_for_client(client_string):
  # We assume our client data is a single string consisting of exactly three
  # comma-separated integers indicating which values to grab from the server.
  split = tf.strings.split([client_string], sep=',')[0]
  return tf.strings.to_number([split[0], split[1]], tf.int32)

@tff.tf_computation(tff.SequenceType(tf.string))
@tff.check_returns_type(tf.string)
def concatenate(values):
  def reduce_fn(acc, item):
    return tf.cond(tf.math.equal(acc, ''),
                   lambda: item,
                   lambda: tf.strings.join([acc, item], ','))
  return values.reduce('', reduce_fn)

@tff.federated_computation(tff.type_at_server(list_of_strings_type), tff.type_at_clients(client_data_type))
def broadcast_based_on_client_data(list_of_strings_at_server, client_data):
  keys_at_clients = tff.federated_map(keys_for_client, client_data)
  max_key = tff.federated_map(get_size, list_of_strings_at_server)
  values_at_clients = tff.federated_select(keys_at_clients, max_key, list_of_strings_at_server, select_fn)
  value_at_clients = tff.federated_map(concatenate, values_at_clients)
  return value_at_clients

سپس می توان محاسبه خود را با ارائه لیست رشته ها و داده های رشته برای هر مشتری ، شبیه سازی کرد:

client_data = ['0,1', '1,2', '2,0']
broadcast_based_on_client_data(['a', 'b', 'c'], client_data)
[<tf.Tensor: shape=(), dtype=string, numpy=b'a,b'>,
 <tf.Tensor: shape=(), dtype=string, numpy=b'b,c'>,
 <tf.Tensor: shape=(), dtype=string, numpy=b'c,a'>]

ارسال یک عنصر تصادفی به هر مشتری

از طرف دیگر ، ممکن است ارسال یک قسمت تصادفی از داده های سرور برای هر مشتری مفید باشد. ما می توانیم آن را با ایجاد یک کلید تصادفی در هر مشتری و سپس پیروی از یک فرآیند انتخاب مشابه با مورد استفاده شده در بالا پیاده سازی کنیم:

@tff.tf_computation(tf.int32)
@tff.check_returns_type(tff.TensorType(tf.int32, [1]))
def get_random_key(max_key):
  return tf.random.uniform(shape=[1], minval=0, maxval=max_key, dtype=tf.int32)

list_of_strings_type = tff.TensorType(tf.string, [None])
get_size = tff.tf_computation(lambda x: tf.size(x))
select_fn = tff.tf_computation(lambda val, index: tf.gather(val, index))

@tff.tf_computation(tff.SequenceType(tf.string))
@tff.check_returns_type(tf.string)
def get_last_element(sequence):
  return sequence.reduce('', lambda _initial_state, val: val)

@tff.federated_computation(tff.type_at_server(list_of_strings_type))
def broadcast_random_element(list_of_strings_at_server):
  max_key_at_server = tff.federated_map(get_size, list_of_strings_at_server)
  max_key_at_clients = tff.federated_broadcast(max_key_at_server)
  key_at_clients = tff.federated_map(get_random_key, max_key_at_clients)
  random_string_sequence_at_clients = tff.federated_select(
      key_at_clients, max_key_at_server, list_of_strings_at_server, select_fn)
  # Even though we only passed in a single key, `federated_select` returns a
  # sequence for each client. We only care about the last (and only) element.
  random_string_at_clients = tff.federated_map(get_last_element, random_string_sequence_at_clients)
  return random_string_at_clients

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

tff.backends.native.set_local_python_execution_context(default_num_clients=3)

سپس می توانیم انتخاب را شبیه سازی کنیم. ما می توانیم تغییر default_num_clients بالا و لیستی از رشته های زیر را برای تولید نتایج مختلف، و یا به سادگی دوباره اجرا محاسبات برای تولید خروجی های مختلف به صورت تصادفی.

broadcast_random_element(tf.convert_to_tensor(['foo', 'bar', 'baz']))