আপনার স্থানীয় টেনসরফ্লো সর্বত্র সর্বত্র ইভেন্টের জন্য আরএসভিপি!
This page was translated by the Cloud Translation API.
Switch to English

কাস্টম ফেডারেটেড অ্যালগরিদম, পর্ব 2: ফেডারেটেড গড় প্রয়োগ করছে Imp

টেনসরফ্লো.আর.জে দেখুন গুগল কোলাবে চালান গিটহাবের উত্স দেখুন নোটবুক ডাউনলোড করুন

এই টিউটোরিয়ালটি একটি দ্বি-অংশ সিরিজের দ্বিতীয় অংশ যা ফেডারেটেড কোর (এফসি) ব্যবহার করে কীভাবে টিএফএফ-তে সংযুক্ত প্রকারের ফেডারেশনযুক্ত অ্যালগরিদমগুলি প্রয়োগ করতে হয় তা প্রদর্শন করে যা ফেডারেটেড লার্নিং (এফএল) স্তরটির ( tff.learning ) ভিত্তি হিসাবে কাজ করে tff.learning

আমরা আপনাকে প্রথমে এই সিরিজের প্রথম অংশটি পড়তে উত্সাহিত করি, যা এখানে ব্যবহৃত কিছু মূল ধারণা এবং প্রোগ্রামিং বিমূর্ততা প্রবর্তন করে।

সিরিজের এই দ্বিতীয় অংশটি ফেডারেট প্রশিক্ষণ এবং মূল্যায়ন অ্যালগরিদমের একটি সাধারণ সংস্করণ বাস্তবায়নের জন্য প্রথম অংশে প্রবর্তিত প্রক্রিয়াগুলি ব্যবহার করে।

আমরা আপনাকে টিএফএফের ফেডারেটড লার্নিং এপিআইগুলির উচ্চ স্তরের এবং আরও মৃদু পরিচয়ের জন্য চিত্রের শ্রেণিবদ্ধকরণ এবং পাঠ্য প্রজন্মের টিউটোরিয়ালগুলি পর্যালোচনা করতে উত্সাহিত করি, কারণ তারা আমাদের এখানে বর্ণিত ধারণাগুলি প্রসঙ্গে বর্ণনা করতে সহায়তা করবে।

আমরা শুরু করার আগে

আমরা শুরু করার আগে, আপনার পরিবেশটি সঠিকভাবে সেট আপ হয়েছে তা নিশ্চিত করার জন্য নিম্নলিখিত "হ্যালো ওয়ার্ল্ড" উদাহরণটি চালানোর চেষ্টা করুন। যদি এটি কাজ না করে তবে দয়া করে নির্দেশাবলীর জন্য ইনস্টলেশন গাইড দেখুন।

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

import nest_asyncio
nest_asyncio.apply()
import collections

import numpy as np
import tensorflow as tf
import tensorflow_federated as tff

# TODO(b/148678573,b/148685415): must use the reference context because it
# supports unbounded references and tff.sequence_* intrinsics.
tff.backends.reference.set_reference_context()
@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
'Hello, World!'

ফেডারেটেড এভারেজিং বাস্তবায়ন করা হচ্ছে

চিত্র শ্রেণীবদ্ধের জন্য ফেডারেট লার্নিংয়ের মতো , আমরা এমএনআইএসটি উদাহরণটি ব্যবহার করতে যাচ্ছি, তবে যেহেতু এটি নিম্ন-স্তরের টিউটোরিয়াল হিসাবে লক্ষ্য করা হচ্ছে, আমরা কেরাস এপিআই এবং tff.simulation বাইপাস করতে যাচ্ছি, কাঁচা মডেল কোড লিখব, এবং একটি নির্মাণ করব স্ক্র্যাচ থেকে সংযুক্ত ডেটা সেট।

সংযুক্ত ডেটা সেট প্রস্তুত করা হচ্ছে

একটি বিক্ষোভের খাতিরে, আমরা এমন একটি দৃশ্যের সিমুলেট করতে যাচ্ছি যেখানে আমরা 10 ব্যবহারকারীর কাছ থেকে ডেটা পেয়েছি এবং ব্যবহারকারীরা প্রত্যেকে আলাদা আলাদা ডিজিটকে কীভাবে সনাক্ত করতে হয় তার জ্ঞানের অবদান রাখে। এটি যতটা নন- আইডি পায় তেমনটি

প্রথমে মানক এমএনআইএসটি ডেটা লোড করা যাক:

mnist_train, mnist_test = tf.keras.datasets.mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
11501568/11490434 [==============================] - 0s 0us/step

[(x.dtype, x.shape) for x in mnist_train]
[(dtype('uint8'), (60000, 28, 28)), (dtype('uint8'), (60000,))]

ডেটাটি নম্পি অ্যারে হিসাবে আসে, একটিতে চিত্রের সাথে এবং অন্যটি ডিজিটাল লেবেলযুক্ত, উভয়ই প্রথম মাত্রার স্বতন্ত্র উদাহরণগুলিতে যায়। আসুন একটি সহায়ক ফাংশন লিখুন যা এটি টিএফএফ গণনাগুলিতে ফেডারেট সিকোয়েন্সগুলিকে আমরা কীভাবে খাই তার সাথে সামঞ্জস্যপূর্ণ উপায়ে ফর্ম্যাট করি, অর্থাত তালিকার তালিকা হিসাবে - ব্যবহারকারীদের (অঙ্কগুলি) উপরের বাহ্যিক তালিকা, যার মধ্যে উপাত্তের ব্যাচগুলির উপরের অংশ রয়েছে প্রতিটি ক্লায়েন্টের ক্রম প্রচলিত হিসাবে, আমরা প্রতিটি ব্যাচকে x এবং y নামের এক দশকের টেনসর হিসাবে একেকটি কাঠামো তৈরি করব, যার প্রতিটি নেতৃস্থানীয় ব্যাচের মাত্রা থাকবে। এটি উপস্থিত থাকাকালীন, আমরা প্রতিটি চিত্র একটি 784-উপাদান ভেক্টরকে সমতল করব এবং এর মধ্যে পিক্সেলগুলি 0..1 , যাতে আমাদের তথ্য রূপান্তরকরণের মাধ্যমে মডেল যুক্তিকে বিশৃঙ্খলা না করতে হবে।

NUM_EXAMPLES_PER_USER = 1000
BATCH_SIZE = 100


def get_data_for_digit(source, digit):
  output_sequence = []
  all_samples = [i for i, d in enumerate(source[1]) if d == digit]
  for i in range(0, min(len(all_samples), NUM_EXAMPLES_PER_USER), BATCH_SIZE):
    batch_samples = all_samples[i:i + BATCH_SIZE]
    output_sequence.append({
        'x':
            np.array([source[0][i].flatten() / 255.0 for i in batch_samples],
                     dtype=np.float32),
        'y':
            np.array([source[1][i] for i in batch_samples], dtype=np.int32)
    })
  return output_sequence


federated_train_data = [get_data_for_digit(mnist_train, d) for d in range(10)]

federated_test_data = [get_data_for_digit(mnist_test, d) for d in range(10)]

দ্রুত বিচক্ষণতার পরীক্ষা হিসাবে, আসুন পঞ্চম ক্লায়েন্ট ( 5 সংখ্যার সাথে সম্পর্কিত একটি) দ্বারা অবদান করা ডেটার শেষ ব্যাচে Y টেনসরটি দেখি।

federated_train_data[5][-1]['y']
array([5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], dtype=int32)

কেবল নিশ্চিত হতে, আসুন সেই ব্যাচের শেষ উপাদানটির সাথে সম্পর্কিত চিত্রটিও দেখি।

from matplotlib import pyplot as plt

plt.imshow(federated_train_data[5][-1]['x'][-1].reshape(28, 28), cmap='gray')
plt.grid(False)
plt.show()

পিএনজি

টেনসরফ্লো এবং টিএফএফ সংমিশ্রণে

এই টিউটোরিয়ালে, সংক্ষিপ্ততার জন্য আমরা তাত্ক্ষণিকভাবে ফাংশনগুলি tff.tf_computation যা tff.tf_computation দিয়ে tff.tf_computation যুক্তি যুক্ত করে। তবে আরও জটিল যুক্তির জন্য, এটি আমাদের প্রস্তাবিত ধরণ নয় pattern ডিবাগিং টেনসরফ্লো ইতিমধ্যে একটি চ্যালেঞ্জ হতে পারে এবং টেনসরফ্লো পুরোপুরি সিরিয়ালাইজ হওয়ার পরে ডিবাগ করা এবং তারপরে পুনরায় আমদানি করা অগত্যা কিছু মেটাডেটা হারাতে পারে এবং আন্তঃক্রিয়াশীলতা সীমাবদ্ধ করে, ডিবাগিংকে আরও চ্যালেঞ্জ তৈরি করে।

অতএব, আমরা tff.tf_computation স্ট্যান্ড- tff.tf_computation পাইথন ফাংশন (এটি, tff.tf_computation সাজসজ্জা ছাড়াই) হিসাবে জটিল টিএফ যুক্তিটি লেখার জন্য tff.tf_computation । টিএফএফের জন্য tff.tf_computation সিরিয়ালকরণের আগে (যেমন, যুক্তি হিসাবে পাইথন ফাংশন দিয়ে tff.tf_computation আহ্বান করে) TFF সেরা অনুশীলন এবং সরঞ্জামগুলি (উত্সাহী মোডের মতো) ব্যবহার করে টেনসরফ্লো যুক্তিটি বিকশিত এবং পরীক্ষা করা যেতে পারে।

ক্ষতি ফাংশন সংজ্ঞায়িত করা

এখন আমাদের কাছে ডেটা রয়েছে, আসুন আমরা একটি ক্ষতির ফাংশনটি সংজ্ঞায়িত করি যা আমরা প্রশিক্ষণের জন্য ব্যবহার করতে পারি। প্রথমে টিপল নামের টিএফএফ হিসাবে ইনপুট প্রকারটি সংজ্ঞায়িত করা যাক। যেহেতু ডেটা ব্যাচের আকার পৃথক হতে পারে তাই আমরা এই ব্যাচের মাত্রাটি অজানা তা নির্দেশ করার জন্য None ব্যাচের মাত্রা সেট করি।

BATCH_SPEC = collections.OrderedDict(
    x=tf.TensorSpec(shape=[None, 784], dtype=tf.float32),
    y=tf.TensorSpec(shape=[None], dtype=tf.int32))
BATCH_TYPE = tff.to_type(BATCH_SPEC)

str(BATCH_TYPE)
'<x=float32[?,784],y=int32[?]>'

আপনি ভাবছেন যে আমরা কেন একটি সাধারণ পাইথন ধরণের সংজ্ঞা দিতে পারি না। প্রথম অংশের আলোচনার কথা স্মরণ করুন, যেখানে আমরা ব্যাখ্যা করেছি যে আমরা পাইথন ব্যবহার করে টিএফএফ কম্পিউটেশনের যুক্তিটি প্রকাশ করতে পারি, টিএমএফ হুডের নিচে পাইথন নয় । উপরে বর্ণিত BATCH_TYPE প্রতীকটি একটি বিমূর্ত টিএফএফ প্রকারের BATCH_TYPE উপস্থাপন করে। এই বিমূর্ত টিএফএফ প্রকারটি কংক্রিট পাইথনের উপস্থাপনের ধরণের থেকে পৃথক করা গুরুত্বপূর্ণ, উদাহরণস্বরূপ, dict বা collections.namedtuple হিসাবে নাম dict যা পাইথন ফাংশনের শরীরে টিএফএফ প্রকারের প্রতিনিধিত্ব করতে ব্যবহৃত হতে পারে। পাইথনের বিপরীতে, টিএফএফ-এ টিপল-জাতীয় পাত্রে একক বিমূর্ত প্রকারের কনস্ট্রাক্টর tff.StructType রয়েছে, এমন উপাদান রয়েছে যা পৃথকভাবে নামকরণ বা নামবিহীন রেখে দেওয়া যেতে পারে। এই ধরণের গণনাগুলির আনুষ্ঠানিক পরামিতিগুলি মডেল করার জন্যও ব্যবহৃত হয়, কারণ টিএফএফ গণনাগুলি আনুষ্ঠানিকভাবে কেবলমাত্র একটি পরামিতি এবং একটি ফলাফল ঘোষণা করতে পারে - আপনি শীঘ্রই এর উদাহরণগুলি দেখতে পাবেন।

আসুন এখন ওজনপক্ষপাত একটি TFF নামে tuple হিসাবে আবার, মডেল প্যারামিটার TFF টাইপ সংজ্ঞায়িত হচ্ছে।

MODEL_SPEC = collections.OrderedDict(
    weights=tf.TensorSpec(shape=[784, 10], dtype=tf.float32),
    bias=tf.TensorSpec(shape=[10], dtype=tf.float32))
MODEL_TYPE = tff.to_type(MODEL_SPEC)

print(MODEL_TYPE)
<weights=float32[784,10],bias=float32[10]>

এই সংজ্ঞাগুলি স্থানে রেখে এখন আমরা একটি মাত্র ব্যাচের ওপরে কোনও প্রদত্ত মডেলের ক্ষতির সংজ্ঞা দিতে পারি। ব্যবহারের দ্রষ্টব্য @tf.function ভিতরে প্রসাধক @tff.tf_computation প্রসাধক। এটি আমাদের টিএফ লেখার জন্য পাইথনটি শব্দার্থের মতো ব্যবহার করতে tff.tf_computation দ্বারা তৈরি একটি tf.Graph প্রসঙ্গে context

# NOTE: `forward_pass` is defined separately from `batch_loss` so that it can 
# be later called from within another tf.function. Necessary because a
# @tf.function  decorated method cannot invoke a @tff.tf_computation.

@tf.function
def forward_pass(model, batch):
  predicted_y = tf.nn.softmax(
      tf.matmul(batch['x'], model['weights']) + model['bias'])
  return -tf.reduce_mean(
      tf.reduce_sum(
          tf.one_hot(batch['y'], 10) * tf.math.log(predicted_y), axis=[1]))

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE)
def batch_loss(model, batch):
  return forward_pass(model, batch)

প্রত্যাশিত হিসাবে, গণনা batch_loss মডেল এবং একটি একক ডেটা ব্যাচকে দিয়ে float32 ক্ষতি প্রদান করে। নোট করুন যে কীভাবে MODEL_TYPE এবং BATCH_TYPE আনুষ্ঠানিক প্যারামিটারগুলির 2-টি- BATCH_TYPE করা হয়েছে; আপনি batch_loss (<MODEL_TYPE,BATCH_TYPE> -> float32) হিসাবে সনাক্ত করতে পারেন।

str(batch_loss.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,<x=float32[?,784],y=int32[?]>> -> float32)'

স্যানিটি চেক হিসাবে, আসুন জিরোতে ভরা একটি প্রাথমিক মডেলটি তৈরি করি এবং উপরে বর্ণিত ডেটা ব্যাচের উপর ক্ষতির পরিমাণ গণনা করি।

initial_model = collections.OrderedDict(
    weights=np.zeros([784, 10], dtype=np.float32),
    bias=np.zeros([10], dtype=np.float32))

sample_batch = federated_train_data[5][-1]

batch_loss(initial_model, sample_batch)
2.3025854

নোট করুন যে আমরা টিএফএফ গণনাটিকে dict হিসাবে সংজ্ঞায়িত প্রাথমিক মডেলের সাথে ফিড করি, যদিও পাইথন ফাংশনের যে এটির সংজ্ঞা দেওয়া হয় তার বডি model['weight'] এবং model['bias'] হিসাবে model['weight'] পরামিতি গ্রহণ করে। batch_loss কল করার আর্গুমেন্টগুলি কেবল সেই ফাংশনের শরীরে প্রেরণ করা হয় না।

আমরা যখন batch_loss তখন কী হয়? batch_loss পাইথন বডিটি ইতিমধ্যে উপরের ঘরে যেখানে এটি সংজ্ঞায়িত হয়েছিল তা চিহ্নিত করা হয়েছে এবং সিরিয়ালাইজড করা হয়েছে। টিএফএফ গণনা সংজ্ঞা সময়ে batch_loss আহ্বানকারী হিসাবে কাজ করে এবং সময় batch_loss জন্য batch_loss লক্ষ্য হিসাবে। উভয় ভূমিকাতেই, টিএফএফ টিএফএফ এর বিমূর্ত প্রকার সিস্টেম এবং পাইথনের উপস্থাপনের ধরণের মধ্যে সেতু হিসাবে কাজ করে। আবাহন সময়ে, TFF সবচেয়ে মান পাইথন ধারক প্রকার (গ্রহণ করবে dict , list , tuple , collections.namedtuple বিমূর্ত TFF tuples এর কংক্রিট উপস্থাপনা যেমন, ইত্যাদি)। এছাড়াও, যদিও উপরে উল্লিখিত রয়েছে, টিএফএফ গণনাগুলি আনুষ্ঠানিকভাবে কেবলমাত্র একটি প্যারামিটার গ্রহণ করে, প্যারামিটারের ধরণটি যেভাবে টুপল রয়েছে সে ক্ষেত্রে আপনি পরিচিত পাইথন কল সিনট্যাক্সটি অবস্থানগত এবং / অথবা কীওয়ার্ড আর্গুমেন্টের সাথে ব্যবহার করতে পারেন - এটি প্রত্যাশার মতো কাজ করে।

একক ব্যাচে গ্রেডিয়েন্ট বংশোদ্ভূত

এখন, আসুন এমন একটি সংজ্ঞা নির্ধারণ করুন যা গ্রেডিয়েন্ট বংশোদ্ভূত একক পদক্ষেপ সম্পাদন করতে এই ক্ষতি ফাংশনটি ব্যবহার করে। কীভাবে এই ফাংশনটি সংজ্ঞায়িত করা যায় তা লক্ষ করুন, আমরা batch_loss একটি উপ- batch_loss হিসাবে ব্যবহার batch_loss । আপনি অন্য গণনার শরীরে tff.tf_computation দিয়ে নির্মিত একটি গণনা আহ্বান করতে পারেন, যদিও সাধারণত এটি প্রয়োজন হয় না - যেমন উপরে উল্লিখিত রয়েছে, কারণ সিরিয়ালাইজেশন কিছু ডিবাগিং তথ্য হারিয়ে ফেলেছে, প্রায়শই সমস্ত টেনসরফ্লো লিখতে এবং পরীক্ষা করা আরও জটিল কমপুটেশনগুলির পক্ষে পছন্দনীয় is tff.tf_computation ডেকোরেটর ছাড়াই।

@tff.tf_computation(MODEL_TYPE, BATCH_TYPE, tf.float32)
def batch_train(initial_model, batch, learning_rate):
  # Define a group of model variables and set them to `initial_model`. Must
  # be defined outside the @tf.function.
  model_vars = collections.OrderedDict([
      (name, tf.Variable(name=name, initial_value=value))
      for name, value in initial_model.items()
  ])
  optimizer = tf.keras.optimizers.SGD(learning_rate)

  @tf.function
  def _train_on_batch(model_vars, batch):
    # Perform one step of gradient descent using loss from `batch_loss`.
    with tf.GradientTape() as tape:
      loss = forward_pass(model_vars, batch)
    grads = tape.gradient(loss, model_vars)
    optimizer.apply_gradients(
        zip(tf.nest.flatten(grads), tf.nest.flatten(model_vars)))
    return model_vars

  return _train_on_batch(model_vars, batch)
str(batch_train.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,<x=float32[?,784],y=int32[?]>,float32> -> <weights=float32[784,10],bias=float32[10]>)'

আপনি যখন এই জাতীয় অন্য কোনও ফাংশনের শরীরে tff.tf_computation দিয়ে সজ্জিত একটি পাইথন ফাংশনটি tff.tf_computation করেন, তখন অভ্যন্তরীণ টিএফএফ কম্পিউটেশনের যুক্তিটি tff.tf_computation যুক্তিতে এম্বেড করা হয় (মূলত, অন্তর্ভুক্ত)। উপরোক্ত আলোচনা লক্ষনীয়, আপনি যদি উভয় কম্পিউটেশন লিখছেন এটি সম্ভবত ভেতরের ফাংশনটি (করা বাঞ্ছনীয় batch_loss এই ক্ষেত্রে) একটি নিয়মিত পাইথন বা tf.function বদলে tff.tf_computation । তবে, এখানে আমরা চিত্রিত করেছি যে tff.tf_computation ভিতরে একটি tff.tf_computation কল করা প্রত্যাশা অনুযায়ী কাজ করে। এটি প্রয়োজনীয় হতে পারে, উদাহরণস্বরূপ, আপনার কাছে batch_loss সংজ্ঞায়িত পাইথন কোড না থাকলে কেবল এটির সিরিয়ালাইজড টিএফএফ উপস্থাপনা রয়েছে।

এখন, ক্ষতির পরিমাণ কমেছে কিনা তা দেখার জন্য প্রাথমিক মডেলটিতে কয়েকবার এই ফাংশনটি প্রয়োগ করুন।

model = initial_model
losses = []
for _ in range(5):
  model = batch_train(model, sample_batch, 0.1)
  losses.append(batch_loss(model, sample_batch))
losses
[0.19690022, 0.13176313, 0.10113226, 0.082738124, 0.0703014]

স্থানীয় তথ্যের ক্রম উপর গ্রেডিয়েন্ট বংশোদ্ভূত

এখন, যেহেতু batch_train কাজ করে বলে মনে হচ্ছে, আসুন একটি অনুরূপ প্রশিক্ষণ ফাংশন local_train যা কেবলমাত্র একটি একক ব্যাচের পরিবর্তে এক ব্যবহারকারী থেকে সমস্ত ব্যাচের পুরো ক্রম গ্রহণ করে local_train নতুন গণনার জন্য এখন tff.SequenceType(BATCH_TYPE) পরিবর্তে tff.SequenceType(BATCH_TYPE) গ্রহণ করা BATCH_TYPE

LOCAL_DATA_TYPE = tff.SequenceType(BATCH_TYPE)

@tff.federated_computation(MODEL_TYPE, tf.float32, LOCAL_DATA_TYPE)
def local_train(initial_model, learning_rate, all_batches):

  # Mapping function to apply to each batch.
  @tff.federated_computation(MODEL_TYPE, BATCH_TYPE)
  def batch_fn(model, batch):
    return batch_train(model, batch, learning_rate)

  return tff.sequence_reduce(all_batches, initial_model, batch_fn)
str(local_train.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,float32,<x=float32[?,784],y=int32[?]>*> -> <weights=float32[784,10],bias=float32[10]>)'

কোডের এই সংক্ষিপ্ত বিভাগে বেশ কয়েকটি বিশদ সমাহিত করা আছে, আসুন একে একে একে একে চলুন।

প্রথমত, আমরা যখন এই tf.data.Dataset.reduce সম্পূর্ণভাবে tf.data.Dataset.reduce প্রয়োগ করতে পারতাম, tf.data.Dataset.reduce উপর নির্ভর করে tf.data.Dataset.reduce প্রক্রিয়া করার জন্য একইভাবে আমরা এটি কীভাবে করেছি, আমরা আঠালো ভাষায় যুক্তিটি প্রকাশ করার জন্য tf.data.Dataset.reduce বেছে নিয়েছি , একটি tff.federated_computation হিসাবে। আমরা হ্রাস সম্পাদন করতে ফেডারেশন অপারেটর tff.sequence_reduce ব্যবহার করেছি।

অপারেটর tff.sequence_reduce একইভাবে ব্যবহার করা হয় tf.data.Dataset.reduce । আপনি এটিকে মূলত tf.data.Dataset.reduce হিসাবে একই হিসাবে tf.data.Dataset.reduce , তবে ফেডারেশনযুক্ত গণনার অভ্যন্তরে ব্যবহারের জন্য, যা আপনার মনে হতে পারে, টেনসরফ্লো কোড থাকতে পারে না। এটা যে একটা ক্রম নিয়ে গঠিত একটি আনুষ্ঠানিক প্যারামিটার 3-tuple সঙ্গে একটি টেমপ্লেট অপারেটর T উপাদানের -typed, হ্রাসের প্রাথমিক অবস্থায় কিছু টাইপ এর (আমরা এটি abstractly শূন্য হিসাবে পড়ুন করব) U , এবং হ্রাস অপারেটর (<U,T> -> U) টাইপ করুন যা কোনও একক উপাদানকে প্রক্রিয়াজাতকরণের মাধ্যমে হ্রাসের অবস্থার পরিবর্তন করে। ক্রমযুক্ত ক্রমে সমস্ত উপাদানকে প্রক্রিয়া করার পরে ফলাফল হ্রাসের চূড়ান্ত অবস্থা। আমাদের উদাহরণস্বরূপ, হ্রাসের রাষ্ট্রটি হ'ল ডেটার উপসর্গের উপর প্রশিক্ষিত মডেল এবং উপাদানগুলি হ'ল ডেটা ব্যাচ।

দ্বিতীয়ত, দ্রষ্টব্য যে আমরা আবার একটি গণনা ( batch_train ) অন্য ( local_train ) এর মধ্যে উপাদান হিসাবে ব্যবহার করেছি, তবে সরাসরি নয়। আমরা এটি হ্রাস অপারেটর হিসাবে ব্যবহার করতে পারি না কারণ এটি একটি অতিরিক্ত পরামিতি গ্রহণ করে - শিক্ষার হার। এই সমাধান করার জন্য, আমরা একটি এমবেডেড ফেডারেট গণনার সংজ্ঞায়িত batch_fn যে শুশ্রূষা local_train এর প্যারামিটার learning_rate তার শরীর। শিশু গণনার পক্ষে তার পিতামাতার একটি আনুষ্ঠানিক প্যারামিটার ক্যাপচার করার জন্য এইভাবে সংজ্ঞায়িত করার অনুমতি দেওয়া হয় যতক্ষণ না শিশু গণনা তার পিতামাতার শরীরের বাইরে না ডাকা হয়। আপনি এই প্যাটার্নটিকে পাইথনের functools.partial সমতুল্য হিসাবে ভাবতে পারেন।

ক্যাপচার ব্যবহারিক ইঙ্গিত learning_rate এই ভাবে যে একই শেখার হার মান সব ব্যাচে জুড়ে ব্যবহৃত হয় অবশ্যই, হয়।

এখন, নমুনা ব্যাচ (অঙ্ক 5 ) অবদানকারী একই ব্যবহারকারীর কাছ থেকে ডেটা পুরো ক্রম উপর নতুন সংজ্ঞায়িত স্থানীয় প্রশিক্ষণ ফাংশন চেষ্টা করুন।

locally_trained_model = local_train(initial_model, 0.1, federated_train_data[5])

এটা কি কাজ করেছিল? এই প্রশ্নের উত্তর দেওয়ার জন্য আমাদের মূল্যায়ন কার্যকর করতে হবে।

স্থানীয় মূল্যায়ন

সমস্ত ডেটা ব্যাচ জুড়ে লোকসান যোগ করে স্থানীয় মূল্যায়ন বাস্তবায়নের এক উপায় (আমরা গড়ের গড় তুলনা করতে পারতাম; আমরা এটিকে পাঠকের অনুশীলন হিসাবে ছেড়ে দেব)।

@tff.federated_computation(MODEL_TYPE, LOCAL_DATA_TYPE)
def local_eval(model, all_batches):
  # TODO(b/120157713): Replace with `tff.sequence_average()` once implemented.
  return tff.sequence_sum(
      tff.sequence_map(
          tff.federated_computation(lambda b: batch_loss(model, b), BATCH_TYPE),
          all_batches))
str(local_eval.type_signature)
'(<<weights=float32[784,10],bias=float32[10]>,<x=float32[?,784],y=int32[?]>*> -> float32)'

আবার, এই কোডটি দ্বারা চিত্রিত কয়েকটি নতুন উপাদান রয়েছে, আসুন একে একে তাদের উপরে।

প্রথমত, আমরা প্রক্রিয়াকরণের সিকোয়েন্স জন্য দুটি নতুন ফেডারেট অপারেটার ব্যবহার করেছেন: tff.sequence_map যে একটি ম্যাপিং ফাংশন লাগে T->U এবং একটি ক্রম T , এবং একটি ক্রম নির্গত U ম্যাপিং ফাংশন pointwise প্রয়োগের দ্বারা প্রাপ্ত, এবং tff.sequence_sum যে শুধু সমস্ত উপাদান যুক্ত। এখানে, আমরা প্রতিটি ডেটা ব্যাচকে একটি ক্ষতির মান হিসাবে ম্যাপ করি এবং তারপরে মোট ক্ষতির পরিমাণ গণনা করতে ফলাফল ক্ষতির মান যুক্ত করি।

মনে রাখবেন যে আমরা আবার tff.sequence_reduce ব্যবহার করতে tff.sequence_reduce , তবে এটি সেরা পছন্দ হবে না - হ্রাস প্রক্রিয়াটি সংজ্ঞা অনুসারে, ক্রমযুক্ত, যেখানে ম্যাপিং এবং যোগফলকে সমান্তরালে গণনা করা যায়। যখন কোনও পছন্দ দেওয়া হয়, তখন অপারেটরদের সাথে লেগে থাকা ভাল যা বাস্তবায়ন পছন্দগুলিকে বাধা দেয় না, যাতে ভবিষ্যতে যখন আমাদের টিএফএফ গণনা নির্দিষ্ট পরিবেশে স্থাপন করার জন্য সংকলিত হয়, তখন একজন দ্রুত সম্ভাবনার সমস্ত সুযোগের পুরোপুরি সুবিধা নিতে পারে , আরও পরিমাপযোগ্য, আরও সংস্থান-কার্যকর কার্যকরকরণ execution

দ্বিতীয়ত, নোট করুন যে ঠিক local_train যেমন আমাদের প্রয়োজন উপাদান ফাংশন ( batch_loss ) ফেডারেশন অপারেটর ( tff.sequence_map ) প্রত্যাশা করে তার চেয়ে বেশি পরামিতি নেয়, তাই আমরা আবার একটি আংশিক সংজ্ঞা দিই, এবার lambda সরাসরি tff.federated_computation হিসাবে মোড়ানো দ্বারা ইনলাইন tff.federated_computation । আর্গুমেন্ট হিসাবে একটি ফাংশন সহ tff.tf_computation ইনলাইন ব্যবহার করা টিএফএফ-তে tff.tf_computation যুক্তিকে এম্বেড করার জন্য tff.tf_computation ব্যবহার করার প্রস্তাবিত উপায়।

এখন, আসুন দেখুন আমাদের প্রশিক্ষণ কার্যকর হয়েছিল কিনা।

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[5]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[5]))
initial_model loss = 23.025854
locally_trained_model loss = 0.4348469

আসলে লোকসান কমেছে। কিন্তু যদি আমরা এটি অন্য ব্যবহারকারীর ডেটাতে মূল্যায়ন করি তবে কী হবে?

print('initial_model loss =', local_eval(initial_model,
                                         federated_train_data[0]))
print('locally_trained_model loss =',
      local_eval(locally_trained_model, federated_train_data[0]))
initial_model loss = 23.025854
locally_trained_model loss = 74.50075

যেমনটি প্রত্যাশা করা হয়েছিল, পরিস্থিতি আরও খারাপ হয়েছে। মডেলটি 5 সনাক্ত করতে প্রশিক্ষণ পেয়েছিল এবং কখনও 0 দেখেনি। এটি প্রশ্নটি নিয়ে আসে - স্থানীয় প্রশিক্ষণ কীভাবে বৈশ্বিক দৃষ্টিকোণ থেকে মডেলটির গুণমানকে প্রভাবিত করেছিল?

সংস্থার মূল্যায়ন

এটি আমাদের যাত্রার পয়েন্ট যেখানে অবশেষে আমরা আবার ফেডারেশনযুক্ত প্রকার এবং ফেডারেশনযুক্ত গণনাগুলিতে ফিরে আসি - আমরা যে বিষয়টি দিয়ে শুরু করেছি। সার্ভারে উত্পন্ন মডেলটির এবং ক্লায়েন্টদের কাছে থাকা ডেটাটির জন্য এখানে টিএফএফ ধরণের সংজ্ঞা রয়েছে।

SERVER_MODEL_TYPE = tff.type_at_server(MODEL_TYPE)
CLIENT_DATA_TYPE = tff.type_at_clients(LOCAL_DATA_TYPE)

এ পর্যন্ত প্রবর্তিত সমস্ত সংজ্ঞা সহ, টিএফএফ-তে সংঘবদ্ধ মূল্যায়ন প্রকাশ করা ওয়ান লাইনার - আমরা ক্লায়েন্টগুলিতে মডেলটি বিতরণ করি, প্রতিটি ক্লায়েন্ট তার স্থানীয় তথ্যের স্থানীয় অংশে স্থানীয় মূল্যায়নের জন্য প্রার্থনা করি এবং তারপরে লোকসানের পরিমাণটি নির্ধারণ করে। এটি লেখার একটি উপায় এখানে।

@tff.federated_computation(SERVER_MODEL_TYPE, CLIENT_DATA_TYPE)
def federated_eval(model, data):
  return tff.federated_mean(
      tff.federated_map(local_eval, [tff.federated_broadcast(model), data]))

আমরা ইতিমধ্যে সরল পরিস্থিতিতে tff.federated_mean এবং tff.federated_map এর উদাহরণ দেখেছি এবং স্বজ্ঞাত স্তরে তারা প্রত্যাশার মতো কাজ করে, তবে কোডের এই বিভাগে চোখের দেখা tff.federated_map তার চেয়ে আরও অনেক কিছু রয়েছে, তাই আসুন আমরা সাবধানতার সাথে এটিকে দেখি।

প্রথমে আসুন প্রতিটি ক্লায়েন্টকে স্থানীয় অংশের ডেটা অংশের স্থানীয় মূল্যায়নের জন্য অনুরোধ জানাতে দিন । আপনি পূর্ববর্তী বিভাগগুলি থেকে মনে করতে পারেন, local_eval একটি ধরণের স্বাক্ষর রয়েছে (<MODEL_TYPE, LOCAL_DATA_TYPE> -> float32)

ফেডারেটেড অপারেটর tff.federated_map একটি টেমপ্লেট যা 2- tff.federated_map হিসাবে প্যারামিটার হিসাবে গ্রহণ করে যা কিছু টাইপ T->U এর ম্যাপিং ফাংশন এবং {T}@CLIENTS টাইপের একটি {T}@CLIENTS মান (অর্থাত্, এর সদস্য উপাদান সহ) থাকে ম্যাপিং ফাংশনের প্যারামিটার হিসাবে একই ধরণের), এবং {U}@CLIENTS টাইপের ফলাফল প্রদান করে।

যেহেতু আমরা প্রতি ক্লায়েন্ট ভিত্তিতে প্রয়োগ করতে ম্যাপিং ফাংশন হিসাবে local_eval খাওয়াচ্ছি, দ্বিতীয় যুক্তিটি একটি ফেডারেশনযুক্ত ধরণের {<MODEL_TYPE, LOCAL_DATA_TYPE>}@CLIENTS , অর্থাৎ পূর্ববর্তী বিভাগগুলির নামকরণে, এটি হওয়া উচিত একটি সংঘবদ্ধ tuple হতে। প্রতিটি ক্লায়েন্টকে local_eval হিসাবে local_eval জন্য সম্পূর্ণ যুক্তি local_eval । পরিবর্তে, আমরা এটি একটি 2-উপাদান পাইথন list খাওয়ান। এখানে কি হচ্ছে?

প্রকৃতপক্ষে, এই TFF, অন্তর্নিহিত টাইপ কাস্ট আপনাকে অন্য কোথাও সম্মুখীন হতে পারে, উদাঃ অনুরূপ একটি অন্তর্নিহিত টাইপ কাস্ট একটি উদাহরণ যখন আপনি একটি ফিড নেই, int একটি ফাংশন যে একটি গ্রহণ করার float । অন্তর্নিহিত ingালাই এই সময়ে খুব কম ব্যবহার করা হয়, তবে আমরা বয়লারপ্লেট হ্রাস করার উপায় হিসাবে এটি টিএফএফকে আরও বিস্তৃত করার পরিকল্পনা করি।

এই ক্ষেত্রে প্রয়োগ করা হয়েছে এমন অন্তর্নিহিত cast <{X}@Z,{Y}@Z> {<X,Y>}@Z এবং ফেডারেটেড মানগুলির টিপলস <{X}@Z,{Y}@Z> {<X,Y>}@Z , {<X,Y>}@Z <{X}@Z,{Y}@Z> । আনুষ্ঠানিকভাবে, এই দুটি পৃথক স্বাক্ষর, প্রোগ্রামারদের দৃষ্টিকোণ থেকে এটি তাকান, Z প্রতিটি ডিভাইস X এবং Y দুটি ইউনিট ধারণ করে। এখানে যা ঘটে তা পাইথনের zip মতো নয়, এবং প্রকৃতপক্ষে আমরা একটি অপারেটর অফার tff.federated_zip অফার tff.federated_zip যা আপনাকে এ জাতীয় রূপান্তর স্পষ্টতা প্রদর্শন করতে দেয়। যখন tff.federated_map দ্বিতীয় আর্গুমেন্ট হিসাবে একটি টিপল সম্মুখীন হয়, এটি কেবল আপনার জন্য tff.federated_zip

উপরের দিক থেকে, আপনি এখন TFF টাইপ of {MODEL_TYPE}@CLIENTS , এবং data TFF টাইপের {LOCAL_DATA_TYPE}@CLIENTS (বা কেবল CLIENT_DATA_TYPE ) এর মান হিসাবে প্রতিনিধিত্ব হিসাবে tff.federated_broadcast(model) এক্সপ্রেশনটি সনাক্ত করতে সক্ষম হবেন দুই একটি অন্তর্নিহিত মাধ্যমে একসঙ্গে ফিল্টার পেয়ে tff.federated_zip দ্বিতীয় যুক্তি গঠনের tff.federated_map

অপারেটর tff.federated_broadcast , যেমনটি আপনি প্রত্যাশা করেন, কেবল সার্ভার থেকে ক্লায়েন্টগুলিতে ডেটা স্থানান্তর করে।

এখন, আসুন দেখুন কীভাবে আমাদের স্থানীয় প্রশিক্ষণ সিস্টেমের গড় ক্ষতিকে প্রভাবিত করে।

print('initial_model loss =', federated_eval(initial_model,
                                             federated_train_data))
print('locally_trained_model loss =',
      federated_eval(locally_trained_model, federated_train_data))
initial_model loss = 23.025852
locally_trained_model loss = 54.432625

প্রকৃতপক্ষে, প্রত্যাশা হিসাবে, ক্ষতি বৃদ্ধি পেয়েছে। সমস্ত ব্যবহারকারীর জন্য মডেলটি উন্নত করার জন্য, আমাদের প্রত্যেকের ডেটা প্রশিক্ষণ করতে হবে।

সংঘবদ্ধ প্রশিক্ষণ

ফেডারেট প্রশিক্ষণ বাস্তবায়নের সহজতম উপায় হ'ল স্থানীয়ভাবে প্রশিক্ষণ, এবং তারপরে মডেলগুলির গড়। এটি একই বিল্ডিং ব্লক এবং প্যাটারগুলি ব্যবহার করে যা আমরা ইতিমধ্যে আলোচনা করেছি, আপনি নীচে দেখতে পারেন।

SERVER_FLOAT_TYPE = tff.type_at_server(tf.float32)


@tff.federated_computation(SERVER_MODEL_TYPE, SERVER_FLOAT_TYPE,
                           CLIENT_DATA_TYPE)
def federated_train(model, learning_rate, data):
  return tff.federated_mean(
      tff.federated_map(local_train, [
          tff.federated_broadcast(model),
          tff.federated_broadcast(learning_rate), data
      ]))

নোট করুন যে মডেলগুলির গড় পরিবর্তনের পরিবর্তে tff.learning দ্বারা সরবরাহিত ফেডারেটেড এভারেজিংয়ের সম্পূর্ণ বৈশিষ্ট্যযুক্ত বাস্তবায়নে আমরা বেশ কয়েকটি কারণের জন্য গড় মডেল ডেল্টা পছন্দ করি, উদাহরণস্বরূপ, সংক্ষেপণের জন্য আপডেটের নিয়মগুলি ক্লিপ করার ক্ষমতা ইত্যাদি ।

আসুন দেখুন প্রশিক্ষণটি কয়েক দফা প্রশিক্ষণ চালিয়ে এবং আগে এবং পরে গড় ক্ষতির তুলনা করে কাজ করে কিনা।

model = initial_model
learning_rate = 0.1
for round_num in range(5):
  model = federated_train(model, learning_rate, federated_train_data)
  learning_rate = learning_rate * 0.9
  loss = federated_eval(model, federated_train_data)
  print('round {}, loss={}'.format(round_num, loss))
round 0, loss=21.60552406311035
round 1, loss=20.365678787231445
round 2, loss=19.27480125427246
round 3, loss=18.31110954284668
round 4, loss=17.45725440979004

সম্পূর্ণতার জন্য, আসুন এখন পরীক্ষার ডেটাও চালিয়ে আসুন তা নিশ্চিত করতে যে আমাদের মডেলটি ভাল জেনারেলাইজ করেছে।

print('initial_model test loss =',
      federated_eval(initial_model, federated_test_data))
print('trained_model test loss =', federated_eval(model, federated_test_data))
initial_model test loss = 22.795593
trained_model test loss = 17.278767

এটি আমাদের টিউটোরিয়ালটি শেষ করে।

অবশ্যই, আমাদের সরলীকৃত উদাহরণটি আপনাকে আরও বাস্তবসম্মত দৃশ্যে করতে হবে এমন অনেকগুলি বিষয় প্রতিফলিত করে না - উদাহরণস্বরূপ, আমাদের ক্ষতি ছাড়া অন্য কোনও মেট্রিক গণনা করা হয়নি। আমরা আপনাকে tff.learning আরও পরিপূর্ণ উদাহরণ হিসাবে tff.learning গড়ের বাস্তবায়ন বাস্তবায়ন অধ্যয়ন করতে উত্সাহিত করি এবং আমরা উত্সাহিত করতে চাই এমন কিছু কোডিং অনুশীলন প্রদর্শন করার উপায় হিসাবে।