गहन पुनर्प्राप्ति मॉडल बनाना

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

में featurization ट्यूटोरियल हम अपने मॉडल में कई सुविधाओं को शामिल किया है, लेकिन मॉडल केवल एक embedding परत से मिलकर। हम अपने मॉडलों की अभिव्यंजक शक्ति बढ़ाने के लिए और अधिक सघन परतें जोड़ सकते हैं।

सामान्य तौर पर, गहरे मॉडल उथले मॉडल की तुलना में अधिक जटिल पैटर्न सीखने में सक्षम होते हैं। उदाहरण के लिए, हमारे उपयोगकर्ता मॉडल समय में एक बिंदु पर मॉडल उपयोगकर्ता वरीयताओं के लिए उपयोगकर्ता आईडी और timestamps को शामिल किया गया। एक उथला मॉडल (जैसे, एक एकल एम्बेडिंग परत) केवल उन सुविधाओं और फिल्मों के बीच सबसे सरल संबंधों को सीखने में सक्षम हो सकता है: एक दी गई फिल्म रिलीज होने के समय सबसे लोकप्रिय है, और एक दिया गया उपयोगकर्ता आमतौर पर हॉरर फिल्मों को कॉमेडी के लिए पसंद करता है। अधिक जटिल संबंधों को पकड़ने के लिए, जैसे कि समय के साथ उपयोगकर्ता प्राथमिकताएं विकसित हो रही हैं, हमें कई स्टैक्ड घने परतों के साथ एक गहरे मॉडल की आवश्यकता हो सकती है।

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

एक वास्तविक दुनिया recommender प्रणाली के लिए एक अच्छा वास्तुकला ढूँढना एक जटिल कला, अच्छा अंतर्ज्ञान और सावधान की आवश्यकता होती है hyperparameter ट्यूनिंग । उदाहरण के लिए, मॉडल की गहराई और चौड़ाई, सक्रियण फ़ंक्शन, सीखने की दर और अनुकूलक जैसे कारक मॉडल के प्रदर्शन को मौलिक रूप से बदल सकते हैं। मॉडलिंग के विकल्प इस तथ्य से और अधिक जटिल हैं कि अच्छे ऑफ़लाइन मूल्यांकन मेट्रिक्स अच्छे ऑनलाइन प्रदर्शन के अनुरूप नहीं हो सकते हैं, और यह कि मॉडल की पसंद की तुलना में किसके लिए अनुकूलित करना है इसका चुनाव अक्सर अधिक महत्वपूर्ण होता है।

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

प्रारंभिक

हम पहले आवश्यक पैकेज आयात करते हैं।

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
import os
import tempfile

%matplotlib inline
import matplotlib.pyplot as plt

import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds

import tensorflow_recommenders as tfrs

plt.style.use('seaborn-whitegrid')

इस ट्यूटोरियल में हम से मॉडल का उपयोग करेगा featurization ट्यूटोरियल embeddings उत्पन्न करने के लिए। इसलिए हम केवल यूजर आईडी, टाइमस्टैम्प और मूवी टाइटल फीचर्स का उपयोग करेंगे।

ratings = tfds.load("movielens/100k-ratings", split="train")
movies = tfds.load("movielens/100k-movies", split="train")

ratings = ratings.map(lambda x: {
    "movie_title": x["movie_title"],
    "user_id": x["user_id"],
    "timestamp": x["timestamp"],
})
movies = movies.map(lambda x: x["movie_title"])
2021-10-02 11:11:47.672650: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

फीचर शब्दसंग्रह तैयार करने के लिए हम कुछ हाउसकीपिंग भी करते हैं।

timestamps = np.concatenate(list(ratings.map(lambda x: x["timestamp"]).batch(100)))

max_timestamp = timestamps.max()
min_timestamp = timestamps.min()

timestamp_buckets = np.linspace(
    min_timestamp, max_timestamp, num=1000,
)

unique_movie_titles = np.unique(np.concatenate(list(movies.batch(1000))))
unique_user_ids = np.unique(np.concatenate(list(ratings.batch(1_000).map(
    lambda x: x["user_id"]))))

मॉडल परिभाषा

क्वेरी मॉडल

हम उपयोगकर्ता मॉडल में परिभाषित के साथ शुरू featurization ट्यूटोरियल हमारे मॉडल की पहली परत के रूप में, सुविधा embeddings में कच्चे इनपुट उदाहरण परिवर्तित करने का काम सौंपा।

class UserModel(tf.keras.Model):

  def __init__(self):
    super().__init__()

    self.user_embedding = tf.keras.Sequential([
        tf.keras.layers.StringLookup(
            vocabulary=unique_user_ids, mask_token=None),
        tf.keras.layers.Embedding(len(unique_user_ids) + 1, 32),
    ])
    self.timestamp_embedding = tf.keras.Sequential([
        tf.keras.layers.Discretization(timestamp_buckets.tolist()),
        tf.keras.layers.Embedding(len(timestamp_buckets) + 1, 32),
    ])
    self.normalized_timestamp = tf.keras.layers.Normalization(
        axis=None
    )

    self.normalized_timestamp.adapt(timestamps)

  def call(self, inputs):
    # Take the input dictionary, pass it through each input layer,
    # and concatenate the result.
    return tf.concat([
        self.user_embedding(inputs["user_id"]),
        self.timestamp_embedding(inputs["timestamp"]),
        tf.reshape(self.normalized_timestamp(inputs["timestamp"]), (-1, 1)),
    ], axis=1)

गहरे मॉडल को परिभाषित करने के लिए हमें इस पहले इनपुट के शीर्ष पर मोड परतों को ढेर करने की आवश्यकता होगी। एक सक्रियण फ़ंक्शन द्वारा अलग की गई परतों का एक उत्तरोत्तर संकरा ढेर, एक सामान्य पैटर्न है:

                            +----------------------+
                            |      128 x 64        |
                            +----------------------+
                                       | relu
                          +--------------------------+
                          |        256 x 128         |
                          +--------------------------+
                                       | relu
                        +------------------------------+
                        |          ... x 256           |
                        +------------------------------+

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

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

class QueryModel(tf.keras.Model):
  """Model for encoding user queries."""

  def __init__(self, layer_sizes):
    """Model for encoding user queries.

    Args:
      layer_sizes:
        A list of integers where the i-th entry represents the number of units
        the i-th layer contains.
    """
    super().__init__()

    # We first use the user model for generating embeddings.
    self.embedding_model = UserModel()

    # Then construct the layers.
    self.dense_layers = tf.keras.Sequential()

    # Use the ReLU activation for all but the last layer.
    for layer_size in layer_sizes[:-1]:
      self.dense_layers.add(tf.keras.layers.Dense(layer_size, activation="relu"))

    # No activation for the last layer.
    for layer_size in layer_sizes[-1:]:
      self.dense_layers.add(tf.keras.layers.Dense(layer_size))

  def call(self, inputs):
    feature_embedding = self.embedding_model(inputs)
    return self.dense_layers(feature_embedding)

layer_sizes पैरामीटर हमें गहराई और मॉडल की चौड़ाई देता है। हम इसे उथले या गहरे मॉडल के साथ प्रयोग करने के लिए बदल सकते हैं।

उम्मीदवार मॉडल

हम फिल्म मॉडल के लिए भी यही तरीका अपना सकते हैं। फिर, हम के साथ शुरू MovieModel से featurization ट्यूटोरियल:

class MovieModel(tf.keras.Model):

  def __init__(self):
    super().__init__()

    max_tokens = 10_000

    self.title_embedding = tf.keras.Sequential([
      tf.keras.layers.StringLookup(
          vocabulary=unique_movie_titles,mask_token=None),
      tf.keras.layers.Embedding(len(unique_movie_titles) + 1, 32)
    ])

    self.title_vectorizer = tf.keras.layers.TextVectorization(
        max_tokens=max_tokens)

    self.title_text_embedding = tf.keras.Sequential([
      self.title_vectorizer,
      tf.keras.layers.Embedding(max_tokens, 32, mask_zero=True),
      tf.keras.layers.GlobalAveragePooling1D(),
    ])

    self.title_vectorizer.adapt(movies)

  def call(self, titles):
    return tf.concat([
        self.title_embedding(titles),
        self.title_text_embedding(titles),
    ], axis=1)

और छिपी हुई परतों के साथ इसका विस्तार करें:

class CandidateModel(tf.keras.Model):
  """Model for encoding movies."""

  def __init__(self, layer_sizes):
    """Model for encoding movies.

    Args:
      layer_sizes:
        A list of integers where the i-th entry represents the number of units
        the i-th layer contains.
    """
    super().__init__()

    self.embedding_model = MovieModel()

    # Then construct the layers.
    self.dense_layers = tf.keras.Sequential()

    # Use the ReLU activation for all but the last layer.
    for layer_size in layer_sizes[:-1]:
      self.dense_layers.add(tf.keras.layers.Dense(layer_size, activation="relu"))

    # No activation for the last layer.
    for layer_size in layer_sizes[-1:]:
      self.dense_layers.add(tf.keras.layers.Dense(layer_size))

  def call(self, inputs):
    feature_embedding = self.embedding_model(inputs)
    return self.dense_layers(feature_embedding)

संयुक्त मॉडल

दोनों के साथ QueryModel और CandidateModel परिभाषित है, हम एक संयुक्त मॉडल को एक साथ रखा और हमारे नुकसान और मीट्रिक तर्क लागू कर सकते हैं। चीजों को सरल बनाने के लिए, हम लागू करेंगे कि मॉडल संरचना क्वेरी और उम्मीदवार मॉडल में समान है।

class MovielensModel(tfrs.models.Model):

  def __init__(self, layer_sizes):
    super().__init__()
    self.query_model = QueryModel(layer_sizes)
    self.candidate_model = CandidateModel(layer_sizes)
    self.task = tfrs.tasks.Retrieval(
        metrics=tfrs.metrics.FactorizedTopK(
            candidates=movies.batch(128).map(self.candidate_model),
        ),
    )

  def compute_loss(self, features, training=False):
    # We only pass the user id and timestamp features into the query model. This
    # is to ensure that the training inputs would have the same keys as the
    # query inputs. Otherwise the discrepancy in input structure would cause an
    # error when loading the query model after saving it.
    query_embeddings = self.query_model({
        "user_id": features["user_id"],
        "timestamp": features["timestamp"],
    })
    movie_embeddings = self.candidate_model(features["movie_title"])

    return self.task(
        query_embeddings, movie_embeddings, compute_metrics=not training)

मॉडल का प्रशिक्षण

डेटा तैयार करें

हम पहले डेटा को एक प्रशिक्षण सेट और एक परीक्षण सेट में विभाजित करते हैं।

tf.random.set_seed(42)
shuffled = ratings.shuffle(100_000, seed=42, reshuffle_each_iteration=False)

train = shuffled.take(80_000)
test = shuffled.skip(80_000).take(20_000)

cached_train = train.shuffle(100_000).batch(2048)
cached_test = test.batch(4096).cache()

उथला मॉडल

हम अपना पहला, उथला, मॉडल आज़माने के लिए तैयार हैं!

num_epochs = 300

model = MovielensModel([32])
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))

one_layer_history = model.fit(
    cached_train,
    validation_data=cached_test,
    validation_freq=5,
    epochs=num_epochs,
    verbose=0)

accuracy = one_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"][-1]
print(f"Top-100 accuracy: {accuracy:.2f}.")
Top-100 accuracy: 0.27.

यह हमें लगभग 0.27 की शीर्ष -100 सटीकता प्रदान करता है। हम इसे गहन मॉडल के मूल्यांकन के लिए एक संदर्भ बिंदु के रूप में उपयोग कर सकते हैं।

गहरा मॉडल

दो परतों वाले गहरे मॉडल के बारे में क्या?

model = MovielensModel([64, 32])
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))

two_layer_history = model.fit(
    cached_train,
    validation_data=cached_test,
    validation_freq=5,
    epochs=num_epochs,
    verbose=0)

accuracy = two_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"][-1]
print(f"Top-100 accuracy: {accuracy:.2f}.")
Top-100 accuracy: 0.29.

यहाँ सटीकता 0.29 है, जो उथले मॉडल से काफी बेहतर है।

हम इसे स्पष्ट करने के लिए सत्यापन सटीकता वक्रों को प्लॉट कर सकते हैं:

num_validation_runs = len(one_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"])
epochs = [(x + 1)* 5 for x in range(num_validation_runs)]

plt.plot(epochs, one_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"], label="1 layer")
plt.plot(epochs, two_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"], label="2 layers")
plt.title("Accuracy vs epoch")
plt.xlabel("epoch")
plt.ylabel("Top-100 accuracy");
plt.legend()
<matplotlib.legend.Legend at 0x7f841c7513d0>

पीएनजी

प्रशिक्षण की शुरुआत में भी, बड़े मॉडल के पास उथले मॉडल पर एक स्पष्ट और स्थिर बढ़त होती है, यह सुझाव देता है कि गहराई जोड़ने से मॉडल को डेटा में अधिक सूक्ष्म संबंधों को पकड़ने में मदद मिलती है।

हालांकि, जरूरी नहीं कि गहरे मॉडल भी बेहतर हों। निम्नलिखित मॉडल गहराई को तीन परतों तक बढ़ाता है:

model = MovielensModel([128, 64, 32])
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))

three_layer_history = model.fit(
    cached_train,
    validation_data=cached_test,
    validation_freq=5,
    epochs=num_epochs,
    verbose=0)

accuracy = three_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"][-1]
print(f"Top-100 accuracy: {accuracy:.2f}.")
Top-100 accuracy: 0.26.

वास्तव में, हम उथले मॉडल में सुधार नहीं देखते हैं:

plt.plot(epochs, one_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"], label="1 layer")
plt.plot(epochs, two_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"], label="2 layers")
plt.plot(epochs, three_layer_history.history["val_factorized_top_k/top_100_categorical_accuracy"], label="3 layers")
plt.title("Accuracy vs epoch")
plt.xlabel("epoch")
plt.ylabel("Top-100 accuracy");
plt.legend()
<matplotlib.legend.Legend at 0x7f841c6d8590>

पीएनजी

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

उपयुक्त ट्यूनिंग और पर्याप्त डेटा के साथ, बड़े और गहरे मॉडल बनाने में किए गए प्रयास कई मामलों में इसके लायक हैं: बड़े मॉडल भविष्यवाणी सटीकता में पर्याप्त सुधार ला सकते हैं।

अगले कदम

इस ट्यूटोरियल में हमने सघन लेयर्स और एक्टिवेशन फंक्शन के साथ अपने रिट्रीवल मॉडल का विस्तार किया। एक मॉडल है कि न केवल पुनर्प्राप्ति कार्यों लेकिन यह भी रेटिंग कार्य कर सकते हैं बनाने का तरीका देखने के लिए, पर एक नज़र डालें बहु-कार्य ट्यूटोरियल