Tff.fedrated_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
tff.backends.native.set_local_python_execution_context()

ক্লায়েন্ট ডেটার উপর ভিত্তি করে বিভিন্ন মান পাঠানো

সেই ক্ষেত্রে বিবেচনা করুন যেখানে আমাদের কিছু সার্ভার-স্থাপিত তালিকা রয়েছে যেখান থেকে আমরা কিছু ক্লায়েন্ট-স্থাপিত ডেটার উপর ভিত্তি করে প্রতিটি ক্লায়েন্টকে কয়েকটি উপাদান পাঠাতে চাই। উদাহরণস্বরূপ, সার্ভারে স্ট্রিংগুলির একটি তালিকা এবং ক্লায়েন্টে, ডাউনলোড করার জন্য সূচকগুলির একটি কমা দ্বারা পৃথক করা তালিকা৷ আমরা এটি নিম্নরূপ বাস্তবায়ন করতে পারি:

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