Bir sorunuz mu var? TensorFlow Forum Ziyaret Forumunda toplulukla bağlantı kurun

tff.federated_select ile Belirli İstemcilere Farklı Veri Gönderme

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 öğretici, farklı istemcilere farklı veriler gönderilmesini gerektiren özel birleşik algoritmaların TFF'de nasıl uygulanacağını gösterir. Tüm istemcilere tek bir sunucuya yerleştirilmiş değer gönderen tff.federated_broadcast zaten biliyor olabilirsiniz. Bu öğretici, sunucu tabanlı bir değerin farklı bölümlerinin farklı istemcilere gönderildiği durumlara odaklanır. Bu, tüm modeli herhangi bir tek istemciye göndermekten kaçınmak için bir modelin parçalarını farklı istemciler arasında bölmek için yararlı olabilir.

Hem tensorflow hem de tensorflow içe aktararak 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

Müşteri Verilerine Dayalı Farklı Değerler Gönderme

Bazı istemci tarafından yerleştirilmiş verilere dayanarak her istemciye birkaç öğe göndermek istediğimiz sunucu tarafından yerleştirilmiş bir listemiz olduğu durumu düşünün. Örneğin, sunucudaki ve istemcilerdeki dizelerin bir listesi, indirilecek virgülle ayrılmış bir dizin listesi. Bunu şu şekilde uygulayabiliriz:

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

Ardından, her istemci için sunucuya yerleştirilmiş dizelerin listesini ve ayrıca dize verilerini sağlayarak hesaplamamızı simüle edebiliriz:

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

Her Müşteriye Rastgele Bir Öğe Gönderme

Alternatif olarak, sunucu verilerinin rastgele bir bölümünü her istemciye göndermek faydalı olabilir. Bunu, önce her istemcide rastgele bir anahtar oluşturarak ve ardından yukarıda kullanılana benzer bir seçim sürecini izleyerek uygulayabiliriz:

@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 işlevimiz istemci tarafından yerleştirilmiş herhangi bir veriyi almadığından, TFF Simulation Runtime'ı kullanmak için varsayılan bir istemci sayısıyla yapılandırmamız gerekir:

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

Sonra seçimi simüle edebiliriz. Farklı sonuçlar oluşturmak için yukarıdaki default_num_clients ve aşağıdaki dize listesini değiştirebilir veya farklı rastgele çıktılar oluşturmak için hesaplamayı yeniden çalıştırabiliriz.

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