Réseau profond et croisé (DCN)

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Ce didacticiel montre comment utiliser Deep & Cross Network (DCN) pour apprendre efficacement les croisements de fonctionnalités.

Fond

Que sont les croisements de caractéristiques et pourquoi sont-ils importants ? Imaginez que nous construisons un système de recommandation pour vendre un mélangeur aux clients. Puis, passé historique d'achat d'un client, comme purchased_bananas et purchased_cooking_books , ou les caractéristiques géographiques, sont caractéristiques simples. Si l' on a acheté les bananes et les livres de cuisine, puis ce client cliquera plus probablement sur le mélangeur recommandé. La combinaison de purchased_bananas et purchased_cooking_books est appelée croix caractéristique, qui fournit des informations d'interaction supplémentaire au - delà des caractéristiques individuelles.

Quels sont les défis liés à l'apprentissage des croisements de fonctionnalités ? Dans les applications à l'échelle du Web, les données sont principalement catégorielles, ce qui conduit à un espace de fonctionnalités important et épars. L'identification de croisements de caractéristiques efficaces dans ce cadre nécessite souvent une ingénierie manuelle des caractéristiques ou une recherche exhaustive. Les modèles traditionnels de perceptrons multicouches à anticipation (MLP) sont des approximateurs de fonctions universels ; Cependant, ils ne peuvent pas approcher efficacement même 2ème ou 3ème ordre caractéristique croix [ 1 , 2 ].

Qu'est-ce que le Deep & Cross Network (DCN) ? DCN a été conçu pour apprendre plus efficacement les fonctionnalités croisées explicites et à degré limité. Il commence par une couche d'entrée (typiquement une couche enrobage), suivie par un réseau contenant des couches croisées transversales multiples interactions que les modèles d'entités explicites, puis se combine avec un réseau profond que les modèles interactions de caractéristiques implicites.

  • Réseau croisé. C'est le cœur de DCN. Il applique explicitement le croisement d'entités à chaque couche, et le degré polynomial le plus élevé augmente avec la profondeur de la couche. La figure suivante montre le \((i+1)\)-ième couche transversale.
  • Réseau profond. Il s'agit d'un perceptron multicouche traditionnel (MLP).

Le réseau profond et réseau croix sont ensuite combinés pour former DCN [ 1 ]. Généralement, nous pourrions empiler un réseau profond au-dessus du réseau croisé (structure empilée); on pourrait aussi les mettre en parallèle (structure parallèle).

Dans ce qui suit, nous allons d'abord montrer les avantages de DCN avec un exemple de jouet, puis nous vous expliquerons quelques manières courantes d'utiliser DCN à l'aide de l'ensemble de données MovieLen-1M.

Commençons par installer et importer les packages nécessaires pour cette collaboration.

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
import pprint

%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

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

import tensorflow_recommenders as tfrs

Exemple de jouet

Pour illustrer les avantages de DCN, prenons un exemple simple. Supposons que nous ayons un ensemble de données dans lequel nous essayons de modéliser la probabilité qu'un client clique sur une annonce de blender, avec ses caractéristiques et son étiquette décrites comme suit.

Caractéristiques / Étiquette La description Type de valeur/plage
\(x_1\) = pays le pays dans lequel ce client vit Int dans [0, 199]
\(x_2\) = bananes # bananes achetées par le client Int dans [0, 23]
\(x_3\) = livres de cuisine # livres de cuisine que le client a achetés Int dans [0, 5]
\(y\) la probabilité de cliquer sur une annonce de blender --

Ensuite, nous laissons les données suivre la distribution sous-jacente suivante :

\[y = f(x_1, x_2, x_3) = 0.1x_1 + 0.4x_2+0.7x_3 + 0.1x_1x_2+3.1x_2x_3+0.1x_3^2\]

où la probabilité \(y\) dépend linéairement à la fois sur les caractéristiques \(x_i\)« s, mais aussi sur les interactions entre la multiplicatifs \(x_i\)» s. Dans notre cas, nous dirions que la probabilité d'achat d' un mélangeur (\(y\)) ne dépend pas seulement d' acheter des bananes (\(x_2\)) ou les livres de cuisine (\(x_3\)), mais aussi sur l' achat des bananes et des livres de cuisine ensemble (\(x_2x_3\)).

Nous pouvons générer les données pour cela comme suit :

Génération de données synthétiques

Nous définissons d' abord \(f(x_1, x_2, x_3)\) comme décrit ci - dessus.

def get_mixer_data(data_size=100_000, random_seed=42):
  # We need to fix the random seed
  # to make colab runs repeatable.
  rng = np.random.RandomState(random_seed)
  country = rng.randint(200, size=[data_size, 1]) / 200.
  bananas = rng.randint(24, size=[data_size, 1]) / 24.
  coockbooks = rng.randint(6, size=[data_size, 1]) / 6.

  x = np.concatenate([country, bananas, coockbooks], axis=1)

  # # Create 1st-order terms.
  y = 0.1 * country + 0.4 * bananas + 0.7 * coockbooks

  # Create 2nd-order cross terms.
  y += 0.1 * country * bananas + 3.1 * bananas * coockbooks + (
        0.1 * coockbooks * coockbooks)

  return x, y

Générons les données qui suivent la distribution et divisons les données en 90 % pour l'entraînement et 10 % pour les tests.

x, y = get_mixer_data()
num_train = 90000
train_x = x[:num_train]
train_y = y[:num_train]
eval_x = x[num_train:]
eval_y = y[num_train:]

Modèle de construction

Nous allons essayer à la fois le réseau croisé et le réseau profond pour illustrer l'avantage qu'un réseau croisé peut apporter aux recommandateurs. Comme les données que nous venons de créer ne contiennent que des interactions de caractéristiques de second ordre, il suffirait d'illustrer avec un réseau croisé à une seule couche. Si nous voulions modéliser des interactions de caractéristiques d'ordre supérieur, nous pourrions empiler plusieurs couches croisées et utiliser un réseau croisé multicouche. Les deux modèles que nous allons construire sont :

  1. Réseau croisé avec une seule couche croisée ;
  2. Réseau profond avec des couches ReLU plus larges et plus profondes.

Nous construisons d'abord une classe de modèle unifiée dont la perte est l'erreur quadratique moyenne.

class Model(tfrs.Model):

  def __init__(self, model):
    super().__init__()
    self._model = model
    self._logit_layer = tf.keras.layers.Dense(1)

    self.task = tfrs.tasks.Ranking(
      loss=tf.keras.losses.MeanSquaredError(),
      metrics=[
        tf.keras.metrics.RootMeanSquaredError("RMSE")
      ]
    )

  def call(self, x):
    x = self._model(x)
    return self._logit_layer(x)

  def compute_loss(self, features, training=False):
    x, labels = features
    scores = self(x)

    return self.task(
        labels=labels,
        predictions=scores,
    )

Ensuite, nous spécifions le réseau croisé (avec 1 couche croisée de taille 3) et le DNN basé sur ReLU (avec des tailles de couche [512, 256, 128]) :

crossnet = Model(tfrs.layers.dcn.Cross())
deepnet = Model(
    tf.keras.Sequential([
      tf.keras.layers.Dense(512, activation="relu"),
      tf.keras.layers.Dense(256, activation="relu"),
      tf.keras.layers.Dense(128, activation="relu")
    ])
)

Formation de modèle

Maintenant que nous avons les données et les modèles prêts, nous allons entraîner les modèles. Nous mélangeons et regroupons d'abord les données pour préparer l'apprentissage du modèle.

train_data = tf.data.Dataset.from_tensor_slices((train_x, train_y)).batch(1000)
eval_data = tf.data.Dataset.from_tensor_slices((eval_x, eval_y)).batch(1000)

Ensuite, nous définissons le nombre d'époques ainsi que le taux d'apprentissage.

epochs = 100
learning_rate = 0.4

Très bien, tout est prêt maintenant et compilons et entraînons les modèles. Vous pouvez définir verbose=True si vous voulez voir comment les progrès du modèle.

crossnet.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate))
crossnet.fit(train_data, epochs=epochs, verbose=False)
<keras.callbacks.History at 0x7f27d82ef390>
deepnet.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate))
deepnet.fit(train_data, epochs=epochs, verbose=False)
<keras.callbacks.History at 0x7f27d07a3dd0>

Évaluation du modèle

Nous vérifions les performances du modèle sur l'ensemble de données d'évaluation et rapportons l'erreur quadratique moyenne (RMSE, le plus bas est le mieux).

crossnet_result = crossnet.evaluate(eval_data, return_dict=True, verbose=False)
print(f"CrossNet(1 layer) RMSE is {crossnet_result['RMSE']:.4f} "
      f"using {crossnet.count_params()} parameters.")

deepnet_result = deepnet.evaluate(eval_data, return_dict=True, verbose=False)
print(f"DeepNet(large) RMSE is {deepnet_result['RMSE']:.4f} "
      f"using {deepnet.count_params()} parameters.")
CrossNet(1 layer) RMSE is 0.0011 using 16 parameters.
DeepNet(large) RMSE is 0.1258 using 166401 parameters.

Nous voyons que le réseau croix magnitudes atteint RMSE inférieur à un DNN à base Relu, avec des magnitudes moins de paramètres. Cela a suggéré l'efficacité d'un réseau croisé dans l'apprentissage des croisements de fonctionnalités.

Compréhension du modèle

Nous savons déjà quelles croix de caractéristiques sont importantes dans nos données, il serait amusant de vérifier si notre modèle a bien appris la croix de caractéristiques importante. Cela peut être fait en visualisant la matrice de poids apprise dans DCN. Le poids \(W_{ij}\) représente l'importance de l' interaction entre appris fonction \(x_i\) et \(x_j\).

mat = crossnet._model._dense.kernel
features = ["country", "purchased_bananas", "purchased_cookbooks"]

plt.figure(figsize=(9,9))
im = plt.matshow(np.abs(mat.numpy()), cmap=plt.cm.Blues)
ax = plt.gca()
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
cax.tick_params(labelsize=10) 
_ = ax.set_xticklabels([''] + features, rotation=45, fontsize=10)
_ = ax.set_yticklabels([''] + features, fontsize=10)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: FixedFormatter should only be used together with FixedLocator
  # This is added back by InteractiveShellApp.init_path()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: FixedFormatter should only be used together with FixedLocator
  if sys.path[0] == '':
<Figure size 648x648 with 0 Axes>

png

Les couleurs plus foncées représentent des interactions apprises plus fortes - dans ce cas, il est clair que le modèle a appris qu'il est important d'acheter des babanas et des livres de cuisine ensemble.

Si vous êtes intéressé à essayer des données synthétiques plus complexes, ne hésitez pas à consulter cet article .

Exemple d'objectif Movielens 1M

Nous examinons maintenant l'efficacité de DCN sur un ensemble de données du monde réel: MovieLens 1M [ 3 ]. Movielens 1M est un ensemble de données populaire pour la recherche de recommandations. Il prédit les notes des utilisateurs sur les films en fonction des fonctionnalités liées aux utilisateurs et aux fonctionnalités liées aux films. Nous utilisons cet ensemble de données pour montrer quelques façons courantes d'utiliser DCN.

Traitement de l'information

La procédure de traitement de données suit une procédure similaire à celle du tutoriel classement de base .

ratings = tfds.load("movie_lens/100k-ratings", split="train")
ratings = ratings.map(lambda x: {
    "movie_id": x["movie_id"],
    "user_id": x["user_id"],
    "user_rating": x["user_rating"],
    "user_gender": int(x["user_gender"]),
    "user_zip_code": x["user_zip_code"],
    "user_occupation_text": x["user_occupation_text"],
    "bucketized_user_age": int(x["bucketized_user_age"]),
})
WARNING:absl:The handle "movie_lens" for the MovieLens dataset is deprecated. Prefer using "movielens" instead.

Ensuite, nous avons divisé au hasard les données en 80 % pour l'entraînement et 20 % pour les tests.

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)

Ensuite, nous créons un vocabulaire pour chaque fonctionnalité.

feature_names = ["movie_id", "user_id", "user_gender", "user_zip_code",
                 "user_occupation_text", "bucketized_user_age"]

vocabularies = {}

for feature_name in feature_names:
  vocab = ratings.batch(1_000_000).map(lambda x: x[feature_name])
  vocabularies[feature_name] = np.unique(np.concatenate(list(vocab)))

Modèle de construction

L'architecture du modèle que nous allons construire commence par une couche d'intégration, qui est introduite dans un réseau croisé suivi d'un réseau profond. La dimension d'intégration est définie sur 32 pour toutes les entités. Vous pouvez également utiliser différentes tailles d'intégration pour différentes fonctionnalités.

class DCN(tfrs.Model):

  def __init__(self, use_cross_layer, deep_layer_sizes, projection_dim=None):
    super().__init__()

    self.embedding_dimension = 32

    str_features = ["movie_id", "user_id", "user_zip_code",
                    "user_occupation_text"]
    int_features = ["user_gender", "bucketized_user_age"]

    self._all_features = str_features + int_features
    self._embeddings = {}

    # Compute embeddings for string features.
    for feature_name in str_features:
      vocabulary = vocabularies[feature_name]
      self._embeddings[feature_name] = tf.keras.Sequential(
          [tf.keras.layers.StringLookup(
              vocabulary=vocabulary, mask_token=None),
           tf.keras.layers.Embedding(len(vocabulary) + 1,
                                     self.embedding_dimension)
    ])

    # Compute embeddings for int features.
    for feature_name in int_features:
      vocabulary = vocabularies[feature_name]
      self._embeddings[feature_name] = tf.keras.Sequential(
          [tf.keras.layers.IntegerLookup(
              vocabulary=vocabulary, mask_value=None),
           tf.keras.layers.Embedding(len(vocabulary) + 1,
                                     self.embedding_dimension)
    ])

    if use_cross_layer:
      self._cross_layer = tfrs.layers.dcn.Cross(
          projection_dim=projection_dim,
          kernel_initializer="glorot_uniform")
    else:
      self._cross_layer = None

    self._deep_layers = [tf.keras.layers.Dense(layer_size, activation="relu")
      for layer_size in deep_layer_sizes]

    self._logit_layer = tf.keras.layers.Dense(1)

    self.task = tfrs.tasks.Ranking(
      loss=tf.keras.losses.MeanSquaredError(),
      metrics=[tf.keras.metrics.RootMeanSquaredError("RMSE")]
    )

  def call(self, features):
    # Concatenate embeddings
    embeddings = []
    for feature_name in self._all_features:
      embedding_fn = self._embeddings[feature_name]
      embeddings.append(embedding_fn(features[feature_name]))

    x = tf.concat(embeddings, axis=1)

    # Build Cross Network
    if self._cross_layer is not None:
      x = self._cross_layer(x)

    # Build Deep Network
    for deep_layer in self._deep_layers:
      x = deep_layer(x)

    return self._logit_layer(x)

  def compute_loss(self, features, training=False):
    labels = features.pop("user_rating")
    scores = self(features)
    return self.task(
        labels=labels,
        predictions=scores,
    )

Formation de modèle

Nous mélangeons, mettons en lots et mettons en cache les données d'entraînement et de test.

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

Définissons une fonction qui exécute un modèle plusieurs fois et renvoie la moyenne et l'écart type RMSE du modèle sur plusieurs exécutions.

def run_models(use_cross_layer, deep_layer_sizes, projection_dim=None, num_runs=5):
  models = []
  rmses = []

  for i in range(num_runs):
    model = DCN(use_cross_layer=use_cross_layer,
                deep_layer_sizes=deep_layer_sizes,
                projection_dim=projection_dim)
    model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate))
    models.append(model)

    model.fit(cached_train, epochs=epochs, verbose=False)
    metrics = model.evaluate(cached_test, return_dict=True)
    rmses.append(metrics["RMSE"])

  mean, stdv = np.average(rmses), np.std(rmses)

  return {"model": models, "mean": mean, "stdv": stdv}

Nous avons défini des hyper-paramètres pour les modèles. Notez que ces hyper-paramètres sont définis globalement pour tous les modèles à des fins de démonstration. Si vous souhaitez obtenir les meilleures performances pour chaque modèle, ou effectuer une comparaison équitable entre les modèles, nous vous suggérons d'affiner les hyper-paramètres. N'oubliez pas que l'architecture du modèle et les schémas d'optimisation sont étroitement liés.

epochs = 8
learning_rate = 0.01

DCN (empilé). Nous formons d'abord un modèle DCN avec une structure empilée, c'est-à-dire que les entrées sont transmises à un réseau croisé suivi d'un réseau profond.

dcn_result = run_models(use_cross_layer=True,
                        deep_layer_sizes=[192, 192])
WARNING:tensorflow:mask_value is deprecated, use mask_token instead.
WARNING:tensorflow:mask_value is deprecated, use mask_token instead.
5/5 [==============================] - 3s 24ms/step - RMSE: 0.9312 - loss: 0.8674 - regularization_loss: 0.0000e+00 - total_loss: 0.8674
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9339 - loss: 0.8726 - regularization_loss: 0.0000e+00 - total_loss: 0.8726
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9326 - loss: 0.8703 - regularization_loss: 0.0000e+00 - total_loss: 0.8703
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9351 - loss: 0.8752 - regularization_loss: 0.0000e+00 - total_loss: 0.8752
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9339 - loss: 0.8729 - regularization_loss: 0.0000e+00 - total_loss: 0.8729

DCN de rang inférieur. Pour réduire les coûts de formation et de service, nous utilisons des techniques de bas rang pour approximer les matrices de poids DCN. Le rang est passé à travers l' argument projection_dim ; un plus petit projection_dim se traduit par un moindre coût. Notez que projection_dim a besoin d'être plus petite que (taille d'entrée) / 2 pour réduire le coût. En pratique, nous avons observé que l'utilisation d'un DCN de rang inférieur avec un rang (taille d'entrée)/4 préservait systématiquement la précision d'un DCN de rang complet.

dcn_lr_result = run_models(use_cross_layer=True,
                           projection_dim=20,
                           deep_layer_sizes=[192, 192])
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9307 - loss: 0.8669 - regularization_loss: 0.0000e+00 - total_loss: 0.8669
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9312 - loss: 0.8668 - regularization_loss: 0.0000e+00 - total_loss: 0.8668
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9303 - loss: 0.8666 - regularization_loss: 0.0000e+00 - total_loss: 0.8666
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9337 - loss: 0.8723 - regularization_loss: 0.0000e+00 - total_loss: 0.8723
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9300 - loss: 0.8657 - regularization_loss: 0.0000e+00 - total_loss: 0.8657

DNN. Nous formons un modèle DNN de même taille comme référence.

dnn_result = run_models(use_cross_layer=False,
                        deep_layer_sizes=[192, 192, 192])
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9462 - loss: 0.8989 - regularization_loss: 0.0000e+00 - total_loss: 0.8989
5/5 [==============================] - 0s 4ms/step - RMSE: 0.9352 - loss: 0.8765 - regularization_loss: 0.0000e+00 - total_loss: 0.8765
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9393 - loss: 0.8840 - regularization_loss: 0.0000e+00 - total_loss: 0.8840
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9362 - loss: 0.8772 - regularization_loss: 0.0000e+00 - total_loss: 0.8772
5/5 [==============================] - 0s 3ms/step - RMSE: 0.9377 - loss: 0.8798 - regularization_loss: 0.0000e+00 - total_loss: 0.8798

Nous évaluons le modèle sur les données de test et rapportons la moyenne et l'écart type sur 5 séries.

print("DCN            RMSE mean: {:.4f}, stdv: {:.4f}".format(
    dcn_result["mean"], dcn_result["stdv"]))
print("DCN (low-rank) RMSE mean: {:.4f}, stdv: {:.4f}".format(
    dcn_lr_result["mean"], dcn_lr_result["stdv"]))
print("DNN            RMSE mean: {:.4f}, stdv: {:.4f}".format(
    dnn_result["mean"], dnn_result["stdv"]))
DCN            RMSE mean: 0.9333, stdv: 0.0013
DCN (low-rank) RMSE mean: 0.9312, stdv: 0.0013
DNN            RMSE mean: 0.9389, stdv: 0.0039

Nous voyons que le DCN a obtenu de meilleures performances qu'un DNN de même taille avec des couches ReLU. De plus, le DCN de bas rang a pu réduire les paramètres tout en maintenant la précision.

En savoir plus sur DCN. En plus Qu'as été démontré ci - dessus, il y a plus des moyens créatifs encore utiles dans la pratique d'utiliser DCN [ 1 ].

  • DCN avec une structure parallèle. Les entrées alimentent en parallèle un réseau croisé et un réseau profond.

  • Concaténation des couches croisées. Les entrées sont alimentées en parallèle à plusieurs couches croisées pour capturer des croisements de caractéristiques complémentaires.

A gauche: DCN avec une structure parallèle; A droite: Concaténation couches croisées.

Compréhension du modèle

La matrice de poids \(W\) DCN révèle ce qui traverse le modèle caractéristique a appris à être important. Rappelons que dans l'exemple de jouet précédent, l'importance des interactions entre le \(i\)-ième et \(j\)-ième dispose est capturé par le (\(i, j\)) -ième élément de \(W\).

Qu'est - ce qu'un autre bit est ici que la fonction incorporations sont de taille 32 au lieu de la taille 1. Par conséquent, l'importance sera caractérisée par le \((i, j)\)bloc -ème\(W_{i,j}\) qui est de dimension 32 par 32. Dans ce qui suit, nous visualiser la norme Frobenius [ 4 ] \(||W_{i,j}||_F\) de chaque bloc, et une norme plus grande suggère une plus grande importance ( en supposant les incorporations des caractéristiques sont des échelles similaires).

Outre la norme de bloc, nous pourrions également visualiser la matrice entière, ou la valeur moyenne/médiane/max de chaque bloc.

model = dcn_result["model"][0]
mat = model._cross_layer._dense.kernel
features = model._all_features

block_norm = np.ones([len(features), len(features)])

dim = model.embedding_dimension

# Compute the norms of the blocks.
for i in range(len(features)):
  for j in range(len(features)):
    block = mat[i * dim:(i + 1) * dim,
                j * dim:(j + 1) * dim]
    block_norm[i,j] = np.linalg.norm(block, ord="fro")

plt.figure(figsize=(9,9))
im = plt.matshow(block_norm, cmap=plt.cm.Blues)
ax = plt.gca()
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
cax.tick_params(labelsize=10) 
_ = ax.set_xticklabels([""] + features, rotation=45, ha="left", fontsize=10)
_ = ax.set_yticklabels([""] + features, fontsize=10)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:23: UserWarning: FixedFormatter should only be used together with FixedLocator
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:24: UserWarning: FixedFormatter should only be used together with FixedLocator
<Figure size 648x648 with 0 Axes>

png

C'est tout pour ce colab ! Nous espérons que vous avez apprécié l'apprentissage des principes de base de DCN et des façons courantes de l'utiliser. Si vous souhaitez en savoir plus, vous pouvez consulter deux documents pertinents: DCN-v1-papier , DCN-v2-papier .


Les références

V2 DCN: Réseau Deep & Cross et leçons pratiques améliorées pour l' apprentissage à l' échelle Web Rank Systems .
Ruoxi Wang, Rakesh Shivanna, Derek Zhiyuan Cheng, Sagar Jain, Dong Lin, Lichan Hong, Ed Chi. (2020)

Réseau Deep & Cross pour la prévision Cliquez sur Ad .
Ruoxi Wang, Bin Fu, Gang Fu, Mingliang Wang. (AdKDD 2017)