मैट्रिक्स फैक्टराइजेशन के लिए संघीय पुनर्निर्माण

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

इस ट्यूटोरियल आंशिक रूप से स्थानीय फ़ेडरेटेड सीखने, जहां कुछ ग्राहक मापदंडों सर्वर पर एकत्रित किया कभी नहीं कर रहे हैं की पड़ताल। यह उपयोगकर्ता-विशिष्ट मापदंडों (जैसे मैट्रिक्स फ़ैक्टराइज़ेशन मॉडल) वाले मॉडल और संचार-सीमित सेटिंग्स में प्रशिक्षण के लिए उपयोगी है। हम में पेश अवधारणाओं पर निर्माण छवि वर्गीकरण के लिए संघीय लर्निंग ट्यूटोरियल; कि ट्यूटोरियल में के रूप में, हम में उच्च स्तर एपीआई परिचय tff.learning फ़ेडरेटेड प्रशिक्षण और मूल्यांकन के लिए।

हम के लिए आंशिक रूप से स्थानीय फ़ेडरेटेड सीखने को प्रेरित करने के द्वारा शुरू मैट्रिक्स गुणन । हम वर्णन संघीय पुनर्निर्माण , बड़े पैमाने पर आंशिक रूप से स्थानीय फ़ेडरेटेड सीखने के लिए एक व्यावहारिक एल्गोरिथ्म। हम MovieLens 1M डेटासेट तैयार करते हैं, आंशिक रूप से स्थानीय मॉडल बनाते हैं, और इसका प्रशिक्षण और मूल्यांकन करते हैं।

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

import nest_asyncio
nest_asyncio.apply()
import collections
import functools
import io
import os
import requests
import zipfile
from typing import List, Optional, Tuple

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
import tensorflow_federated as tff

np.random.seed(42)

पृष्ठभूमि: मैट्रिक्स फैक्टराइजेशन

मैट्रिक्स गुणन सिफारिशों सीखने और उपयोगकर्ता सहभागिता के आधार पर मदों के लिए अभ्यावेदन एम्बेड करने के लिए एक ऐतिहासिक लोकप्रिय तकनीक किया गया है। विहित उदाहरण फिल्म सिफारिश देखते हैं जहां है, \(n\) उपयोगकर्ताओं और \(m\) फिल्में, और उन कुछ फिल्मों दर्जा दिया है। एक उपयोगकर्ता को देखते हुए, हम उनके रेटिंग इतिहास और समान उपयोगकर्ताओं की रेटिंग का उपयोग करके उन फिल्मों के लिए उपयोगकर्ता की रेटिंग का अनुमान लगाते हैं जो उन्होंने नहीं देखी हैं। यदि हमारे पास एक मॉडल है जो रेटिंग का अनुमान लगा सकता है, तो उपयोगकर्ताओं को नई फिल्मों की सिफारिश करना आसान है जो उन्हें पसंद आएंगी।

इस कार्य के लिए, यह एक के रूप में उपयोगकर्ताओं की रेटिंग प्रतिनिधित्व करने के लिए उपयोगी है \(n \times m\) मैट्रिक्स \(R\):

मैट्रिक्स फैक्टराइजेशन मोटिवेशन (CC BY-SA 3.0; विकिपीडिया उपयोगकर्ता Moshanin)

यह मैट्रिक्स आम तौर पर विरल है, क्योंकि उपयोगकर्ता आमतौर पर डेटासेट में फिल्मों का एक छोटा सा अंश ही देखते हैं। मैट्रिक्स गुणन के उत्पादन में दो मैट्रिक्स है: एक \(n \times k\) मैट्रिक्स \(U\) का प्रतिनिधित्व \(k\)प्रत्येक उपयोगकर्ता के लिए आयामी उपयोगकर्ता embeddings, और एक \(m \times k\) मैट्रिक्स \(I\) का प्रतिनिधित्व \(k\)प्रत्येक आइटम के लिए आयामी आइटम embeddings। सबसे सरल प्रशिक्षण उद्देश्य यह सुनिश्चित करना है कि उपयोगकर्ता और आइटम embeddings की डॉट उत्पाद मनाया रेटिंग्स की भविष्यवाणी कर रहे हैं \(O\):

\[argmin_{U,I} \sum_{(u, i) \in O} (R_{ui} - U_u I_i^T)^2\]

यह संबंधित उपयोगकर्ता और आइटम एम्बेडिंग के डॉट उत्पाद को लेकर अनुमानित रेटिंग और रेटिंग के बीच औसत वर्ग त्रुटि को कम करने के बराबर है। एक अन्य तरीका यह व्याख्या करने के लिए है कि यह सुनिश्चित करता है कि है \(R \approx UI^T\) जाना जाता रेटिंग के लिए, इसलिए "मैट्रिक्स गुणन"। यदि यह भ्रमित करने वाला है, तो चिंता न करें-हमें शेष ट्यूटोरियल के लिए मैट्रिक्स फ़ैक्टराइज़ेशन के विवरण जानने की आवश्यकता नहीं होगी।

MovieLens डेटा की खोज

के लोड करके शुरू करते हैं MovieLens 1M डेटा, 3706 फिल्मों पर 6040 उपयोगकर्ताओं से 1,000,209 फिल्म रेटिंग्स के होते हैं जो।

def download_movielens_data(dataset_path):
  """Downloads and copies MovieLens data to local /tmp directory."""
  if dataset_path.startswith('http'):
    r = requests.get(dataset_path)
    z = zipfile.ZipFile(io.BytesIO(r.content))
    z.extractall(path='/tmp')
  else:
    tf.io.gfile.makedirs('/tmp/ml-1m/')
    for filename in ['ratings.dat', 'movies.dat', 'users.dat']:
      tf.io.gfile.copy(
          os.path.join(dataset_path, filename),
          os.path.join('/tmp/ml-1m/', filename),
          overwrite=True)

download_movielens_data('http://files.grouplens.org/datasets/movielens/ml-1m.zip')
def load_movielens_data(
    data_directory: str = "/tmp",
) -> Tuple[pd.DataFrame, pd.DataFrame]:
  """Loads pandas DataFrames for ratings, movies, users from data directory."""
  # Load pandas DataFrames from data directory. Assuming data is formatted as
  # specified in http://files.grouplens.org/datasets/movielens/ml-1m-README.txt.
  ratings_df = pd.read_csv(
      os.path.join(data_directory, "ml-1m", "ratings.dat"),
      sep="::",
      names=["UserID", "MovieID", "Rating", "Timestamp"], engine="python")
  movies_df = pd.read_csv(
      os.path.join(data_directory, "ml-1m", "movies.dat"),
      sep="::",
      names=["MovieID", "Title", "Genres"], engine="python")

  # Create dictionaries mapping from old IDs to new (remapped) IDs for both
  # MovieID and UserID. Use the movies and users present in ratings_df to
  # determine the mapping, since movies and users without ratings are unneeded.
  movie_mapping = {
      old_movie: new_movie for new_movie, old_movie in enumerate(
          ratings_df.MovieID.astype("category").cat.categories)
  }
  user_mapping = {
      old_user: new_user for new_user, old_user in enumerate(
          ratings_df.UserID.astype("category").cat.categories)
  }

  # Map each DataFrame consistently using the now-fixed mapping.
  ratings_df.MovieID = ratings_df.MovieID.map(movie_mapping)
  ratings_df.UserID = ratings_df.UserID.map(user_mapping)
  movies_df.MovieID = movies_df.MovieID.map(movie_mapping)

  # Remove nulls resulting from some movies being in movies_df but not
  # ratings_df.
  movies_df = movies_df[pd.notnull(movies_df.MovieID)]

  return ratings_df, movies_df

आइए कुछ पंडों डेटाफ़्रेम को लोड और एक्सप्लोर करें जिनमें रेटिंग और मूवी डेटा शामिल हैं।

ratings_df, movies_df = load_movielens_data()

हम देख सकते हैं कि प्रत्येक रेटिंग उदाहरण में 1-5 से रेटिंग, एक संबंधित UserID, एक संबंधित MovieID और एक टाइमस्टैम्प है।

ratings_df.head()

प्रत्येक फिल्म का एक शीर्षक और संभावित रूप से कई विधाएं होती हैं।

movies_df.head()

डेटासेट के बुनियादी आंकड़ों को समझना हमेशा एक अच्छा विचार है:

print('Num users:', len(set(ratings_df.UserID)))
print('Num movies:', len(set(ratings_df.MovieID)))
Num users: 6040
Num movies: 3706
ratings = ratings_df.Rating.tolist()

plt.hist(ratings, bins=5)
plt.xticks([1, 2, 3, 4, 5])
plt.ylabel('Count')
plt.xlabel('Rating')
plt.show()

print('Average rating:', np.mean(ratings))
print('Median rating:', np.median(ratings))

पीएनजी

Average rating: 3.581564453029317
Median rating: 4.0

हम सबसे लोकप्रिय फिल्म शैलियों को भी प्लॉट कर सकते हैं।

movie_genres_list = movies_df.Genres.tolist()
# Count the number of times each genre describes a movie.
genre_count = collections.defaultdict(int)
for genres in movie_genres_list:
  curr_genres_list = genres.split('|')
  for genre in curr_genres_list:
    genre_count[genre] += 1
genre_name_list, genre_count_list = zip(*genre_count.items())

plt.figure(figsize=(11, 11))
plt.pie(genre_count_list, labels=genre_name_list)
plt.title('MovieLens Movie Genres')
plt.show()

पीएनजी

यह डेटा स्वाभाविक रूप से विभिन्न उपयोगकर्ताओं की रेटिंग में विभाजित है, इसलिए हम ग्राहकों के बीच डेटा में कुछ विविधता की अपेक्षा करेंगे। नीचे हम विभिन्न उपयोगकर्ताओं के लिए सबसे अधिक रेटिंग वाली मूवी शैलियों को प्रदर्शित करते हैं। हम उपयोगकर्ताओं के बीच महत्वपूर्ण अंतर देख सकते हैं।

def print_top_genres_for_user(ratings_df, movies_df, user_id):
  """Prints top movie genres for user with ID user_id."""
  user_ratings_df = ratings_df[ratings_df.UserID == user_id]
  movie_ids = user_ratings_df.MovieID

  genre_count = collections.Counter()
  for movie_id in movie_ids:
    genres_string = movies_df[movies_df.MovieID == movie_id].Genres.tolist()[0]
    for genre in genres_string.split('|'):
      genre_count[genre] += 1

  print(f'\nFor user {user_id}:')
  for (genre, freq) in genre_count.most_common(5):
    print(f'{genre} was rated {freq} times')

print_top_genres_for_user(ratings_df, movies_df, user_id=0)
print_top_genres_for_user(ratings_df, movies_df, user_id=10)
print_top_genres_for_user(ratings_df, movies_df, user_id=19)
For user 0:
Drama was rated 21 times
Children's was rated 20 times
Animation was rated 18 times
Musical was rated 14 times
Comedy was rated 14 times

For user 10:
Comedy was rated 84 times
Drama was rated 54 times
Romance was rated 22 times
Thriller was rated 18 times
Action was rated 9 times

For user 19:
Action was rated 17 times
Sci-Fi was rated 9 times
Thriller was rated 9 times
Drama was rated 6 times
Crime was rated 5 times

मूवीलेंस डेटा को प्रीप्रोसेस करना

अब हम की एक सूची के रूप में MovieLens डाटासेट तैयार करते tf.data.Dataset रों TFF साथ प्रयोग के लिए प्रत्येक उपयोगकर्ता के डेटा का प्रतिनिधित्व।

हम दो कार्यों को लागू करते हैं:

  • create_tf_datasets : हमारी रेटिंग DataFrame लेता है और के उपयोगकर्ता विभाजन एक सूची tf.data.Dataset रों।
  • split_tf_datasets :, डेटासेट और ट्रेन / वैल / परीक्षण उपयोगकर्ता द्वारा में विभाजन उनमें से एक सूची लेता है तो वैल / परीक्षण सेट केवल प्रशिक्षण के दौरान अनदेखी उपयोगकर्ताओं से रेटिंग होते हैं। आमतौर पर मानक केंद्रीकृत मैट्रिक्स गुणन में हम वास्तव में इतना विभाजित है कि वैल / परीक्षण सेट देखे गए उपयोगकर्ताओं से आयोजित बाहर रेटिंग्स होते हैं, के बाद से अनदेखी उन उपयोगकर्ता embeddings जरूरत नहीं है। हमारे मामले में, हम बाद में देखेंगे कि FL में मैट्रिक्स फैक्टराइजेशन को सक्षम करने के लिए हम जिस दृष्टिकोण का उपयोग करते हैं, वह अनदेखी उपयोगकर्ताओं के लिए उपयोगकर्ता एम्बेडिंग को जल्दी से पुनर्निर्माण करने में सक्षम बनाता है।
def create_tf_datasets(ratings_df: pd.DataFrame,
                       batch_size: int = 1,
                       max_examples_per_user: Optional[int] = None,
                       max_clients: Optional[int] = None) -> List[tf.data.Dataset]:
  """Creates TF Datasets containing the movies and ratings for all users."""
  num_users = len(set(ratings_df.UserID))
  # Optionally limit to `max_clients` to speed up data loading.
  if max_clients is not None:
    num_users = min(num_users, max_clients)

  def rating_batch_map_fn(rating_batch):
    """Maps a rating batch to an OrderedDict with tensor values."""
    # Each example looks like: {x: movie_id, y: rating}.
    # We won't need the UserID since each client will only look at their own
    # data.
    return collections.OrderedDict([
        ("x", tf.cast(rating_batch[:, 1:2], tf.int64)),
        ("y", tf.cast(rating_batch[:, 2:3], tf.float32))
    ])

  tf_datasets = []
  for user_id in range(num_users):
    # Get subset of ratings_df belonging to a particular user.
    user_ratings_df = ratings_df[ratings_df.UserID == user_id]

    tf_dataset = tf.data.Dataset.from_tensor_slices(user_ratings_df)

    # Define preprocessing operations.
    tf_dataset = tf_dataset.take(max_examples_per_user).shuffle(
        buffer_size=max_examples_per_user, seed=42).batch(batch_size).map(
        rating_batch_map_fn,
        num_parallel_calls=tf.data.experimental.AUTOTUNE)
    tf_datasets.append(tf_dataset)

  return tf_datasets


def split_tf_datasets(
    tf_datasets: List[tf.data.Dataset],
    train_fraction: float = 0.8,
    val_fraction: float = 0.1,
) -> Tuple[List[tf.data.Dataset], List[tf.data.Dataset], List[tf.data.Dataset]]:
  """Splits a list of user TF datasets into train/val/test by user.
  """
  np.random.seed(42)
  np.random.shuffle(tf_datasets)

  train_idx = int(len(tf_datasets) * train_fraction)
  val_idx = int(len(tf_datasets) * (train_fraction + val_fraction))

  # Note that the val and test data contains completely different users, not
  # just unseen ratings from train users.
  return (tf_datasets[:train_idx], tf_datasets[train_idx:val_idx],
          tf_datasets[val_idx:])
# We limit the number of clients to speed up dataset creation. Feel free to pass
# max_clients=None to load all clients' data.
tf_datasets = create_tf_datasets(
    ratings_df=ratings_df,
    batch_size=5,
    max_examples_per_user=300,
    max_clients=2000)

# Split the ratings into training/val/test by client.
tf_train_datasets, tf_val_datasets, tf_test_datasets = split_tf_datasets(
    tf_datasets,
    train_fraction=0.8,
    val_fraction=0.1)

एक त्वरित जांच के रूप में, हम प्रशिक्षण डेटा के एक बैच को प्रिंट कर सकते हैं। हम देख सकते हैं कि प्रत्येक व्यक्तिगत उदाहरण में "x" कुंजी के अंतर्गत एक MovieID और "y" कुंजी के अंतर्गत एक रेटिंग है। ध्यान दें कि हमें UserID की आवश्यकता नहीं होगी क्योंकि प्रत्येक उपयोगकर्ता केवल अपना डेटा देखता है।

print(next(iter(tf_train_datasets[0])))
OrderedDict([('x', <tf.Tensor: shape=(5, 1), dtype=int64, numpy=
array([[1907],
       [2891],
       [1574],
       [2785],
       [2775]])>), ('y', <tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[3.],
       [3.],
       [3.],
       [4.],
       [3.]], dtype=float32)>)])

हम प्रति उपयोगकर्ता रेटिंग की संख्या दिखाते हुए एक हिस्टोग्राम प्लॉट कर सकते हैं।

def count_examples(curr_count, batch):
  return curr_count + tf.size(batch['x'])

num_examples_list = []
# Compute number of examples for every other user.
for i in range(0, len(tf_train_datasets), 2):
  num_examples = tf_train_datasets[i].reduce(tf.constant(0), count_examples).numpy()
  num_examples_list.append(num_examples)

plt.hist(num_examples_list, bins=10)
plt.ylabel('Count')
plt.xlabel('Number of Examples')
plt.show()

पीएनजी

अब जब हमने डेटा लोड और एक्सप्लोर कर लिया है, तो हम चर्चा करेंगे कि फ़ेडरेटेड लर्निंग के लिए मैट्रिक्स फ़ैक्टराइज़ेशन कैसे लाया जाए। साथ ही, हम आंशिक रूप से स्थानीय फ़ेडरेटेड लर्निंग को प्रेरित करेंगे।

FL . में मैट्रिक्स फैक्टराइजेशन लाना

जबकि मैट्रिक्स फ़ैक्टराइजेशन पारंपरिक रूप से केंद्रीकृत सेटिंग्स में उपयोग किया गया है, यह विशेष रूप से फ़ेडरेटेड लर्निंग में प्रासंगिक है: उपयोगकर्ता रेटिंग अलग क्लाइंट डिवाइस पर लाइव हो सकती है, और हम डेटा को केंद्रीकृत किए बिना उपयोगकर्ताओं और आइटम के लिए एम्बेडिंग और अनुशंसाएं सीखना चाहते हैं। चूंकि प्रत्येक उपयोगकर्ता के पास एक संबंधित उपयोगकर्ता एम्बेडिंग होता है, इसलिए यह स्वाभाविक है कि प्रत्येक क्लाइंट अपने उपयोगकर्ता एम्बेडिंग को स्टोर करे-यह सभी उपयोगकर्ता एम्बेडिंग को संग्रहीत करने वाले केंद्रीय सर्वर से काफी बेहतर है।

FL में मैट्रिक्स फ़ैक्टराइज़ेशन लाने का एक प्रस्ताव इस प्रकार है:

  1. सर्वर की दुकानों और आइटम मैट्रिक्स भेजता \(I\) नमूना ग्राहकों के लिए हर दौर
  2. ग्राहकों आइटम मैट्रिक्स को अद्यतन करने और उनके व्यक्तिगत उपयोगकर्ता embedding \(U_u\) ऊपर उद्देश्य पर SGD का उपयोग कर
  3. के लिए नई जानकारियां \(I\) सर्वर पर एकत्रित कर रहे हैं, के सर्वर प्रतिलिपि को अद्यतन करने \(I\) अगले दौर के लिए

यह दृष्टिकोण आंशिक रूप से स्थानीय क्योकि कुछ ग्राहक मापदंडों सर्वर द्वारा कभी नहीं एकत्रित कर रहे हैं है। हालांकि यह दृष्टिकोण आकर्षक है, इसके लिए ग्राहकों को पूरे दौर में स्थिति बनाए रखने की आवश्यकता होती है, अर्थात् उनके उपयोगकर्ता एम्बेडिंग। क्रॉस-डिवाइस FL सेटिंग्स के लिए स्टेटफुल फ़ेडरेटेड एल्गोरिदम कम उपयुक्त होते हैं: इन सेटिंग्स में जनसंख्या का आकार अक्सर प्रत्येक राउंड में भाग लेने वाले क्लाइंट्स की संख्या से बहुत बड़ा होता है, और क्लाइंट आमतौर पर प्रशिक्षण प्रक्रिया के दौरान अधिकतम एक बार भाग लेता है। राज्य कि आरंभ नहीं किया जा सकता है पर निर्भर इसके अलावा, स्टेटफुल एल्गोरिदम राज्य हो रही बासी की वजह से क्रॉस-उपकरण सेटिंग में प्रदर्शन गिरावट में परिणाम कर सकते जब ग्राहकों बार बार नमूने दिए जाते हैं। महत्वपूर्ण रूप से, मैट्रिक्स फ़ैक्टराइज़ेशन सेटिंग में, एक स्टेटफुल एल्गोरिथम सभी अनदेखी ग्राहकों को प्रशिक्षित उपयोगकर्ता एम्बेडिंग गायब कर देता है, और बड़े पैमाने पर प्रशिक्षण में अधिकांश उपयोगकर्ता अनदेखी हो सकते हैं। क्रॉस-उपकरण फ्लोरिडा में राज्यविहीन एल्गोरिदम के लिए प्रेरणा के बारे में अधिक के लिए, देखें वांग एट अल। 2021 सेक। 3.1.1 और रेड्डी एट अल। 2020 सेक। 5.1

संघीय पुनर्निर्माण ( सिंघल एट अल। 2021 ) ऊपर उल्लिखित दृष्टिकोण करने के लिए एक राज्यविहीन विकल्प नहीं है। मुख्य विचार यह है कि उपयोगकर्ता एम्बेडिंग को राउंड में संग्रहीत करने के बजाय, क्लाइंट आवश्यकता पड़ने पर उपयोगकर्ता एम्बेडिंग का पुनर्निर्माण करते हैं। जब FedRecon को मैट्रिक्स फ़ैक्टराइज़ेशन पर लागू किया जाता है, तो प्रशिक्षण निम्नानुसार होता है:

  1. सर्वर की दुकानों और आइटम मैट्रिक्स भेजता \(I\) नमूना ग्राहकों के लिए हर दौर
  2. प्रत्येक ग्राहक जमा \(I\) और उनके उपयोगकर्ता embedding गाड़ियों \(U_u\) SGD के एक या अधिक चरणों का उपयोग कर (पुनर्निर्माण)
  3. प्रत्येक ग्राहक जमा \(U_u\) और गाड़ियों \(I\) SGD के एक या अधिक चरणों का उपयोग
  4. के लिए नई जानकारियां \(I\) उपयोगकर्ताओं भर में एकत्रित कर रहे हैं, के सर्वर प्रतिलिपि को अद्यतन करने \(I\) अगले दौर के लिए

इस दृष्टिकोण के लिए ग्राहकों को पूरे दौर में राज्य बनाए रखने की आवश्यकता नहीं होती है। लेखक कागज में यह भी दिखाते हैं कि इस पद्धति से अनदेखी ग्राहकों के लिए उपयोगकर्ता एम्बेडिंग का तेजी से पुनर्निर्माण होता है (खंड 4.2, चित्र 3, और तालिका 1), जो प्रशिक्षण में भाग नहीं लेने वाले अधिकांश ग्राहकों को प्रशिक्षित मॉडल रखने की अनुमति देता है। , इन ग्राहकों के लिए अनुशंसाओं को सक्षम करना।

मॉडल को परिभाषित करना

आगे हम क्लाइंट डिवाइस पर प्रशिक्षित होने के लिए स्थानीय मैट्रिक्स फ़ैक्टराइज़ेशन मॉडल को परिभाषित करेंगे। यह मॉडल पूर्ण आइटम मैट्रिक्स शामिल होंगे \(I\) और एक एकल उपयोगकर्ता एम्बेडिंग \(U_u\) ग्राहक के लिए \(u\)। ध्यान दें कि ग्राहकों को पूर्ण उपयोगकर्ता मैट्रिक्स स्टोर करने के लिए की जरूरत नहीं होगी \(U\)।

हम निम्नलिखित को परिभाषित करेंगे:

  • UserEmbedding : एक सरल Keras परत एक एकल का प्रतिनिधित्व num_latent_factors आयामी उपयोगकर्ता एम्बेडिंग।
  • get_matrix_factorization_model : एक समारोह है कि रिटर्न एक tff.learning.reconstruction.Model सहित जो परतों विश्व स्तर पर सर्वर पर एकत्रित कर रहे हैं और जो परतों स्थानीय रहने मॉडल तर्क, युक्त। फ़ेडरेटेड पुनर्निर्माण प्रशिक्षण प्रक्रिया को प्रारंभ करने के लिए हमें इस अतिरिक्त जानकारी की आवश्यकता है। यहाँ हम उत्पादन tff.learning.reconstruction.Model एक Keras मॉडल का उपयोग करने से tff.learning.reconstruction.from_keras_model । करने के लिए इसी तरह के tff.learning.Model , हम भी एक कस्टम लागू कर सकते हैं tff.learning.reconstruction.Model वर्ग इंटरफेस को लागू करने से।
class UserEmbedding(tf.keras.layers.Layer):
  """Keras layer representing an embedding for a single user, used below."""

  def __init__(self, num_latent_factors, **kwargs):
    super().__init__(**kwargs)
    self.num_latent_factors = num_latent_factors

  def build(self, input_shape):
    self.embedding = self.add_weight(
        shape=(1, self.num_latent_factors),
        initializer='uniform',
        dtype=tf.float32,
        name='UserEmbeddingKernel')
    super().build(input_shape)

  def call(self, inputs):
    return self.embedding

  def compute_output_shape(self):
    return (1, self.num_latent_factors)


def get_matrix_factorization_model(
    num_items: int,
    num_latent_factors: int) -> tff.learning.reconstruction.Model:
  """Defines a Keras matrix factorization model."""
  # Layers with variables will be partitioned into global and local layers.
  # We'll pass this to `tff.learning.reconstruction.from_keras_model`.
  global_layers = []
  local_layers = []

  # Extract the item embedding.
  item_input = tf.keras.layers.Input(shape=[1], name='Item')
  item_embedding_layer = tf.keras.layers.Embedding(
      num_items,
      num_latent_factors,
      name='ItemEmbedding')
  global_layers.append(item_embedding_layer)
  flat_item_vec = tf.keras.layers.Flatten(name='FlattenItems')(
      item_embedding_layer(item_input))

  # Extract the user embedding.
  user_embedding_layer = UserEmbedding(
      num_latent_factors,
      name='UserEmbedding')
  local_layers.append(user_embedding_layer)

  # The item_input never gets used by the user embedding layer,
  # but this allows the model to directly use the user embedding.
  flat_user_vec = user_embedding_layer(item_input)

  # Compute the dot product between the user embedding, and the item one.
  pred = tf.keras.layers.Dot(
      1, normalize=False, name='Dot')([flat_user_vec, flat_item_vec])

  input_spec = collections.OrderedDict(
      x=tf.TensorSpec(shape=[None, 1], dtype=tf.int64),
      y=tf.TensorSpec(shape=[None, 1], dtype=tf.float32))

  model = tf.keras.Model(inputs=item_input, outputs=pred)

  return tff.learning.reconstruction.from_keras_model(
      keras_model=model,
      global_layers=global_layers,
      local_layers=local_layers,
      input_spec=input_spec)

संघीय औसत के लिए इंटरफ़ेस के लिए Analagous, संघीय पुनर्निर्माण के लिए इंटरफ़ेस एक उम्मीद model_fn कोई तर्क है कि रिटर्न एक साथ tff.learning.reconstruction.Model

# This will be used to produce our training process.
# User and item embeddings will be 50-dimensional.
model_fn = functools.partial(
    get_matrix_factorization_model,
    num_items=3706,
    num_latent_factors=50)

हम अगले परिभाषित करेंगे loss_fn और metrics_fn , जहां loss_fn नो तर्क एक Keras नुकसान लौटने मॉडल प्रशिक्षित करने के लिए उपयोग करने के लिए समारोह है, और metrics_fn मूल्यांकन के लिए Keras मैट्रिक्स की एक सूची लौट नो तर्क कार्य है। प्रशिक्षण और मूल्यांकन संगणनाओं के निर्माण के लिए इनकी आवश्यकता होती है।

जैसा कि ऊपर बताया गया है, हम नुकसान के रूप में माध्य चुकता त्रुटि का उपयोग करेंगे। मूल्यांकन के लिए हम रेटिंग सटीकता का उपयोग करेंगे (जब मॉडल के अनुमानित डॉट उत्पाद को निकटतम पूर्ण संख्या में गोल किया जाता है, तो यह कितनी बार लेबल रेटिंग से मेल खाता है?)

class RatingAccuracy(tf.keras.metrics.Mean):
  """Keras metric computing accuracy of reconstructed ratings."""

  def __init__(self,
               name: str = 'rating_accuracy',
               **kwargs):
    super().__init__(name=name, **kwargs)

  def update_state(self,
                   y_true: tf.Tensor,
                   y_pred: tf.Tensor,
                   sample_weight: Optional[tf.Tensor] = None):
    absolute_diffs = tf.abs(y_true - y_pred)
    # A [batch_size, 1] tf.bool tensor indicating correctness within the
    # threshold for each example in a batch. A 0.5 threshold corresponds
    # to correctness when predictions are rounded to the nearest whole
    # number.
    example_accuracies = tf.less_equal(absolute_diffs, 0.5)
    super().update_state(example_accuracies, sample_weight=sample_weight)


loss_fn = lambda: tf.keras.losses.MeanSquaredError()
metrics_fn = lambda: [RatingAccuracy()]

प्रशिक्षण और मूल्यांकन

अब हमारे पास प्रशिक्षण प्रक्रिया को परिभाषित करने के लिए आवश्यक सब कुछ है। से एक महत्वपूर्ण अंतर संघीय औसत के लिए इंटरफ़ेस है कि अब हम एक में पारित है reconstruction_optimizer_fn , जो जब स्थानीय मानकों के पुनर्निर्माण (हमारे मामले, उपयोगकर्ता embeddings में) का उपयोग किया जाएगा। यह उपयोग करने के लिए आम तौर पर उचित है SGD एक समान के साथ यहाँ, या थोड़ा दर सीखने अनुकूलक ग्राहक से दर सीखने को कम। हम नीचे एक कार्यशील विन्यास प्रदान करते हैं। इसे सावधानीपूर्वक ट्यून नहीं किया गया है, इसलिए बेझिझक विभिन्न मूल्यों के साथ खेलें।

की जाँच करें प्रलेखन अधिक जानकारी और विकल्प के लिए।

# We'll use this by doing:
# state = training_process.initialize()
# state, metrics = training_process.next(state, federated_train_data)
training_process = tff.learning.reconstruction.build_training_process(
    model_fn=model_fn,
    loss_fn=loss_fn,
    metrics_fn=metrics_fn,
    server_optimizer_fn=lambda: tf.keras.optimizers.SGD(1.0),
    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(0.5),
    reconstruction_optimizer_fn=lambda: tf.keras.optimizers.SGD(0.1))

हम अपने प्रशिक्षित वैश्विक मॉडल के मूल्यांकन के लिए गणना को भी परिभाषित कर सकते हैं।

# We'll use this by doing:
# eval_metrics = evaluation_computation(state.model, tf_val_datasets)
# where `state` is the state from the training process above.
evaluation_computation = tff.learning.reconstruction.build_federated_evaluation(
    model_fn,
    loss_fn=loss_fn,
    metrics_fn=metrics_fn,
    reconstruction_optimizer_fn=functools.partial(
            tf.keras.optimizers.SGD, 0.1))

हम प्रशिक्षण प्रक्रिया की स्थिति को इनिशियलाइज़ कर सकते हैं और इसकी जांच कर सकते हैं। सबसे महत्वपूर्ण बात यह है कि हम देख सकते हैं कि यह सर्वर स्थिति केवल आइटम चर (वर्तमान में यादृच्छिक रूप से प्रारंभ) को संग्रहीत करती है, न कि कोई उपयोगकर्ता एम्बेडिंग।

state = training_process.initialize()
print(state.model)
print('Item variables shape:', state.model.trainable[0].shape)
ModelWeights(trainable=[array([[-0.02840446,  0.01196523, -0.01864688, ...,  0.03020107,
         0.00121176,  0.00146852],
       [ 0.01330637,  0.04741272, -0.01487445, ..., -0.03352419,
         0.0104811 ,  0.03506917],
       [-0.04132779,  0.04883525, -0.04799002, ...,  0.00246904,
         0.00586842,  0.01506213],
       ...,
       [ 0.0216659 ,  0.00734354,  0.00471039, ...,  0.01596491,
        -0.00220431, -0.01559857],
       [-0.00319657, -0.01740328,  0.02808609, ..., -0.00501985,
        -0.03850871, -0.03844522],
       [ 0.03791947, -0.00035037,  0.04217024, ...,  0.00365371,
         0.00283421,  0.00897921]], dtype=float32)], non_trainable=[])
Item variables shape: (3706, 50)

हम सत्यापन क्लाइंट पर हमारे यादृच्छिक रूप से प्रारंभ किए गए मॉडल का मूल्यांकन करने का भी प्रयास कर सकते हैं। यहां संघीय पुनर्निर्माण मूल्यांकन में निम्नलिखित शामिल हैं:

  1. सर्वर आइटम मैट्रिक्स भेजता \(I\) नमूना मूल्यांकन ग्राहकों को
  2. प्रत्येक ग्राहक जमा \(I\) और उनके उपयोगकर्ता embedding गाड़ियों \(U_u\) SGD के एक या अधिक चरणों का उपयोग कर (पुनर्निर्माण)
  3. प्रत्येक ग्राहक गणना नुकसान और मीट्रिक सर्वर का उपयोग कर \(I\) और पुनर्निर्मित \(U_u\) उनके स्थानीय डेटा की एक अदृश्य भाग पर
  4. समग्र हानि और मीट्रिक की गणना करने के लिए उपयोगकर्ताओं के बीच हानियों और मीट्रिक का औसत निकाला जाता है

ध्यान दें कि चरण 1 और 2 प्रशिक्षण के समान ही हैं। इस संबंध में महत्वपूर्ण है, मेटा-लर्निंग, या जानने के लिए कैसे सीखने का एक रूप है उसी तरह हम सुराग का मूल्यांकन प्रशिक्षण के बाद से। इस मामले में, मॉडल सीख रहा है कि वैश्विक चर (आइटम मैट्रिक्स) कैसे सीखें जो स्थानीय चर (उपयोगकर्ता एम्बेडिंग) के प्रदर्शनकारी पुनर्निर्माण की ओर ले जाते हैं। इस बारे में अधिक के लिए, देखें सेक। 4.2 कागज के।

निष्पक्ष मूल्यांकन सुनिश्चित करने के लिए, ग्राहकों के स्थानीय डेटा के अलग-अलग हिस्सों का उपयोग करके चरण 2 और 3 को निष्पादित करना भी महत्वपूर्ण है। डिफ़ॉल्ट रूप से, प्रशिक्षण प्रक्रिया और मूल्यांकन गणना दोनों पुनर्निर्माण के लिए हर दूसरे उदाहरण का उपयोग करते हैं और पुनर्निर्माण के बाद के आधे हिस्से का उपयोग करते हैं। यह व्यवहार का उपयोग कर अनुकूलित किया जा सकता dataset_split_fn तर्क (हम इस आगे बाद में पता लगाने जाएगा)।

# We shouldn't expect good evaluation results here, since we haven't trained
# yet!
eval_metrics = evaluation_computation(state.model, tf_val_datasets)
print('Initial Eval:', eval_metrics['eval'])
Initial Eval: OrderedDict([('loss', 14.340279), ('rating_accuracy', 0.0)])

हम अगली बार प्रशिक्षण का एक दौर चलाने का प्रयास कर सकते हैं। चीजों को और अधिक यथार्थवादी बनाने के लिए, हम बिना प्रतिस्थापन के यादृच्छिक रूप से प्रति दौर 50 ग्राहकों का नमूना लेंगे। हमें अभी भी ट्रेन मेट्रिक्स के खराब होने की उम्मीद करनी चाहिए, क्योंकि हम केवल एक दौर का प्रशिक्षण कर रहे हैं।

federated_train_data = np.random.choice(tf_train_datasets, size=50, replace=False).tolist()
state, metrics = training_process.next(state, federated_train_data)
print(f'Train metrics:', metrics['train'])
Train metrics: OrderedDict([('rating_accuracy', 0.0), ('loss', 14.317455)])

आइए अब कई राउंड में प्रशिक्षित करने के लिए एक प्रशिक्षण लूप सेट करें।

NUM_ROUNDS = 20

train_losses = []
train_accs = []

state = training_process.initialize()

# This may take a couple minutes to run.
for i in range(NUM_ROUNDS):
  federated_train_data = np.random.choice(tf_train_datasets, size=50, replace=False).tolist()
  state, metrics = training_process.next(state, federated_train_data)
  print(f'Train round {i}:', metrics['train'])
  train_losses.append(metrics['train']['loss'])
  train_accs.append(metrics['train']['rating_accuracy'])


eval_metrics = evaluation_computation(state.model, tf_val_datasets)
print('Final Eval:', eval_metrics['eval'])
Train round 0: OrderedDict([('rating_accuracy', 0.0), ('loss', 14.7013445)])
Train round 1: OrderedDict([('rating_accuracy', 0.0), ('loss', 14.459233)])
Train round 2: OrderedDict([('rating_accuracy', 0.0), ('loss', 14.52466)])
Train round 3: OrderedDict([('rating_accuracy', 0.0), ('loss', 14.087793)])
Train round 4: OrderedDict([('rating_accuracy', 0.011243612), ('loss', 11.110232)])
Train round 5: OrderedDict([('rating_accuracy', 0.06366048), ('loss', 8.267054)])
Train round 6: OrderedDict([('rating_accuracy', 0.12331288), ('loss', 5.2693872)])
Train round 7: OrderedDict([('rating_accuracy', 0.14264487), ('loss', 5.1511016)])
Train round 8: OrderedDict([('rating_accuracy', 0.21046545), ('loss', 3.8246362)])
Train round 9: OrderedDict([('rating_accuracy', 0.21320973), ('loss', 3.303812)])
Train round 10: OrderedDict([('rating_accuracy', 0.21651311), ('loss', 3.4864292)])
Train round 11: OrderedDict([('rating_accuracy', 0.23476052), ('loss', 3.0105433)])
Train round 12: OrderedDict([('rating_accuracy', 0.21981856), ('loss', 3.1807854)])
Train round 13: OrderedDict([('rating_accuracy', 0.27683082), ('loss', 2.3382564)])
Train round 14: OrderedDict([('rating_accuracy', 0.26080742), ('loss', 2.7009728)])
Train round 15: OrderedDict([('rating_accuracy', 0.2733109), ('loss', 2.2993557)])
Train round 16: OrderedDict([('rating_accuracy', 0.29282996), ('loss', 2.5278995)])
Train round 17: OrderedDict([('rating_accuracy', 0.30204678), ('loss', 2.060092)])
Train round 18: OrderedDict([('rating_accuracy', 0.2940266), ('loss', 2.0976772)])
Train round 19: OrderedDict([('rating_accuracy', 0.3086304), ('loss', 2.0626144)])
Final Eval: OrderedDict([('loss', 1.9961331), ('rating_accuracy', 0.30322924)])

हम राउंड में प्रशिक्षण हानि और सटीकता की साजिश रच सकते हैं। इस नोटबुक में हाइपरपैरामीटर सावधानी से ट्यून नहीं किए गए हैं, इसलिए इन परिणामों को बेहतर बनाने के लिए हर दौर में अलग-अलग क्लाइंट, सीखने की दर, राउंड की संख्या और ग्राहकों की कुल संख्या को आज़माने के लिए स्वतंत्र महसूस करें।

plt.plot(range(NUM_ROUNDS), train_losses)
plt.ylabel('Train Loss')
plt.xlabel('Round')
plt.title('Train Loss')
plt.show()

plt.plot(range(NUM_ROUNDS), train_accs)
plt.ylabel('Train Accuracy')
plt.xlabel('Round')
plt.title('Train Accuracy')
plt.show()

पीएनजी

पीएनजी

अंत में, जब हम ट्यूनिंग समाप्त कर लेंगे तो हम एक अनदेखी परीक्षण सेट पर मीट्रिक की गणना कर सकते हैं।

eval_metrics = evaluation_computation(state.model, tf_test_datasets)
print('Final Test:', eval_metrics['eval'])
Final Test: OrderedDict([('loss', 1.9566978), ('rating_accuracy', 0.30792442)])

आगे की खोज

इस नोटबुक को पूरा करने पर अच्छा काम। हम आंशिक रूप से स्थानीय फ़ेडरेटेड लर्निंग को आगे बढ़ाने के लिए निम्नलिखित अभ्यासों का सुझाव देते हैं, मोटे तौर पर बढ़ती कठिनाई के आधार पर:

  • फ़ेडरेटेड एवरेजिंग के विशिष्ट कार्यान्वयन डेटा पर कई स्थानीय पास (युग) लेते हैं (कई बैचों में डेटा पर एक पास लेने के अलावा)। संघीय पुनर्निर्माण के लिए हम पुनर्निर्माण और पुनर्निर्माण के बाद के प्रशिक्षण के लिए अलग-अलग चरणों की संख्या को नियंत्रित करना चाह सकते हैं। पासिंग dataset_split_fn प्रशिक्षण और मूल्यांकन गणना बिल्डरों के लिए तर्क कदम और दोनों पुनर्निर्माण और बाद के पुनर्निर्माण डेटासेट से अधिक अवधियों की संख्या के नियंत्रण सक्षम बनाता है। एक अभ्यास के रूप में, पुनर्निर्माण प्रशिक्षण के 3 स्थानीय युगों को निष्पादित करने का प्रयास करें, जो 50 चरणों में सीमित हैं और पुनर्निर्माण के बाद के प्रशिक्षण के 1 स्थानीय युग, 50 चरणों में सीमित हैं। संकेत: आप मिल जाएगा tff.learning.reconstruction.build_dataset_split_fn उपयोगी। एक बार ऐसा करने के बाद, बेहतर परिणाम प्राप्त करने के लिए इन हाइपरपैरामीटर और अन्य संबंधित जैसे सीखने की दर और बैच आकार को ट्यून करने का प्रयास करें।

  • फ़ेडरेटेड पुनर्निर्माण प्रशिक्षण और मूल्यांकन का डिफ़ॉल्ट व्यवहार प्रत्येक पुनर्निर्माण और पुनर्निर्माण के बाद ग्राहकों के स्थानीय डेटा को आधे में विभाजित करना है। ऐसे मामलों में जहां ग्राहकों के पास बहुत कम स्थानीय डेटा होता है, केवल प्रशिक्षण प्रक्रिया के लिए पुनर्निर्माण और पुनर्निर्माण के बाद डेटा का पुन: उपयोग करना उचित हो सकता है (मूल्यांकन के लिए नहीं, इससे अनुचित मूल्यांकन होगा)। , प्रशिक्षण प्रक्रिया के लिए यह परिवर्तन करने को सुनिश्चित करने का प्रयास करें dataset_split_fn मूल्यांकन के लिए अभी भी पुनर्निर्माण और बाद के पुनर्निर्माण डेटा संबंध तोड़ना रहता है। संकेत: tff.learning.reconstruction.simple_dataset_split_fn उपयोगी हो सकता है।

  • इन सबसे ऊपर, हम एक उत्पादन tff.learning.Model का उपयोग कर एक Keras मॉडल से tff.learning.reconstruction.from_keras_model । हम यह भी द्वारा शुद्ध TensorFlow 2.0 का उपयोग कर कस्टम मॉडल लागू कर सकते हैं मॉडल इंटरफेस को लागू करने । संशोधित करने का प्रयास get_matrix_factorization_model का निर्माण और एक वर्ग है कि फैली वापस जाने के लिए tff.learning.reconstruction.Model , अपने तरीकों को लागू करने। संकेत: के स्रोत कोड tff.learning.reconstruction.from_keras_model विस्तार का एक उदाहरण देता tff.learning.reconstruction.Model वर्ग। को भी देखें EMNIST छवि वर्गीकरण ट्यूटोरियल में कस्टम मॉडल कार्यान्वयन एक विस्तार में एक ऐसी ही व्यायाम के लिए tff.learning.Model

  • इस ट्यूटोरियल में, हमने मैट्रिक्स फ़ैक्टराइज़ेशन के संदर्भ में आंशिक रूप से स्थानीय फ़ेडरेटेड लर्निंग को प्रेरित किया है, जहाँ सर्वर पर उपयोगकर्ता एम्बेडिंग भेजने से उपयोगकर्ता की प्राथमिकताएँ लीक हो जाती हैं। हम संचार को कम करते हुए (क्योंकि स्थानीय पैरामीटर सर्वर पर नहीं भेजे जाते हैं) अधिक व्यक्तिगत मॉडल (क्योंकि मॉडल का हिस्सा प्रत्येक उपयोगकर्ता के लिए पूरी तरह से स्थानीय है) को प्रशिक्षित करने के तरीके के रूप में अन्य सेटिंग्स में फेडरेटेड पुनर्निर्माण भी लागू कर सकते हैं। सामान्य तौर पर, यहां प्रस्तुत इंटरफ़ेस का उपयोग करके हम कोई भी फ़ेडरेटेड मॉडल ले सकते हैं जो आमतौर पर पूरी तरह से विश्व स्तर पर प्रशिक्षित होता है और इसके बजाय इसके चर को वैश्विक चर और स्थानीय चर में विभाजित करता है। उदाहरण में पता लगाया संघीय पुनर्निर्माण कागज व्यक्तिगत अगले शब्द का पूर्वानुमान है: यहाँ, प्रत्येक उपयोगकर्ता के बाहर के शब्दावली शब्द के लिए शब्द embeddings की अपनी स्थानीय सेट है, पर कब्जा उपयोगकर्ताओं की खिचड़ी के लिए मॉडल को सक्षम करने और अतिरिक्त संचार के बिना निजीकरण को प्राप्त। एक अभ्यास के रूप में, संघीय पुनर्निर्माण के साथ उपयोग के लिए एक अलग मॉडल को लागू करने का प्रयास करें (या तो एक केरस मॉडल या एक कस्टम टेंसरफ्लो 2.0 मॉडल के रूप में)। एक सुझाव: एक व्यक्तिगत उपयोगकर्ता एम्बेडिंग के साथ एक EMNIST वर्गीकरण मॉडल को लागू करें, जहां व्यक्तिगत उपयोगकर्ता एम्बेडिंग को मॉडल की अंतिम सघन परत से पहले CNN छवि सुविधाओं से जोड़ा जाता है। आप इस ट्यूटोरियल से कोड (जैसे की ज्यादा का पुन: उपयोग कर सकते हैं UserEmbedding वर्ग) और छवि वर्गीकरण ट्यूटोरियल


आप अभी भी आंशिक रूप से स्थानीय फ़ेडरेटेड सीखने के बारे में अधिक के लिए देख रहे हैं, बाहर की जाँच संघीय पुनर्निर्माण कागज और खुला स्रोत प्रयोग कोड