Recommandations dans TensorFlow : créer le modèle

Cet article constitue la première partie d'une série de tutoriels qui expliquent comment mettre en œuvre un système de recommandation à base de machine learning (ML) à l'aide de TensorFlow et de Cloud Machine Learning Engine sur Google Cloud Platform (GCP). Dans cette partie, nous verrons comment installer le code du modèle TensorFlow sur un système de développement et l'exécuter sur l'ensemble de données MovieLens.

Le système de recommandation de ce tutoriel utilise l'algorithme des moindres carrés alternés pondérés (WALS, Weighted Alternating Least Squares). L'algorithme WALS est inclus dans le package contrib.factorization de la base de code TensorFlow, et permet de factoriser une grande matrice de notes d'utilisateurs et d'éléments. Pour plus d'informations sur l'algorithme WALS, consultez la présentation.

Cet article décrit en détail le code du modèle, y compris le prétraitement des données et l'exécution de l'algorithme WALS dans TensorFlow.

La série se compose des parties suivantes :

Objectifs

  • Comprendre la structure du code TensorFlow utilisé pour appliquer l'algorithme WALS à la factorisation matricielle
  • Exécuter l'exemple de code TensorFlow localement pour générer des recommandations basées sur l'ensemble de données MovieLens

Coûts

Ce tutoriel utilise les services facturables Cloud Storage et Cloud ML Engine. Vous pouvez vous servir du simulateur de coût pour générer une estimation des coûts en fonction de votre utilisation prévue. Le coût prévisionnel de ce tutoriel est de 0,15 $. Si vous êtes un nouvel utilisateur de GCP, vous pouvez éventuellement bénéficier d'un essai gratuit.

Avant de commencer

  1. Sélectionnez ou créez un projet Google Cloud Platform.

    Accéder à la page "Gérer les ressources"

  2. Assurez-vous que la facturation est activée pour votre projet Google Cloud Platform.

    Découvrir comment activer la facturation

  3. Activez Compute Engine and Cloud ML Engineles API requises.

    Activer les API.

  4. (Facultatif) Si vous souhaitez exécuter le tutoriel sur votre propre ordinateur (sans utiliser Cloud Shell), vérifiez que Python 2.7 est installé.

Exécuter le modèle TensorFlow

Vous pouvez effectuer les étapes décrites dans cette section sur une instance Compute Engine dotée d'un minimum de 7 Go de mémoire, comme indiqué dans la procédure ci-dessous. Vous pouvez également les effectuer sur un système local macOS ou Linux. Dans ce cas, vous n'avez pas besoin de créer d'instance Compute Engine.

Créer l'instance Compute Engine

  1. Dans la console Google Cloud Platform, accédez à la page Instances de VM.

    ACCÉDER À LA PAGE "INSTANCES DE VM"

  2. Cliquez sur Créer une instance.

  3. Donnez à votre instance le nom de votre choix et choisissez une zone. Si vous n'avez pas encore de zone préférée, choisissez-en une géographiquement proche de vous.

  4. Dans la liste déroulante Type de machine, sélectionnez 2 processeurs virtuels et n1-standard-2.

  5. Dans la section Champs d'application de l'accès, sélectionnez Autoriser l'accès complet à l'ensemble des API.

  6. Cliquez sur Créer.

Installer le code

  1. Connectez-vous à la nouvelle instance. Pour plus d'informations, consultez la page Se connecter à des instances.

  2. Dans la nouvelle instance, clonez le dépôt d'exemple de code :

    git clone https://github.com/GoogleCloudPlatform/tensorflow-recommendation-wals
  3. Installez miniconda. Le code d'exemple nécessite Python 2.7.

    wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh
    bash Miniconda2-latest-Linux-x86_64.sh
  4. Installez les packages Python et TensorFlow. Dans ce tutoriel, nous partons du principe que la version 1.4.1 de TensorFlow est installée.

    cd tensorflow-recommendation-wals
    conda create -n tfrec
    conda install -n tfrec --file conda.txt
    source activate tfrec
    pip install -r requirements.txt
    pip install tensorflow==1.4.1
  5. Dans Cloud Shell, téléchargez l'ensemble de données MovieLens. Il en existe plusieurs versions.

    1. Dans un contexte de développement, nous vous recommandons d'utiliser la version 100k, qui contient 100 000 notes attribuées par 943 utilisateurs à 1 682 éléments. Téléchargez-la à l'aide des commandes suivantes :

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-100k.zip'
      unzip ml-100k.zip
      mkdir -p data
      cp ml-100k/u.data data/
    2. Dans un contexte d'entraînement, nous vous recommandons d'utiliser l'ensemble de données 1m, qui contient un million de notes. Le format de l'ensemble 1m est légèrement différent de celui de l'ensemble 100k. Par exemple, le fichier de notes est délimité par des caractères ::. L'exemple de code vous permet d'utiliser l'argument --delimiter pour spécifier le délimiteur utilisé par l'ensemble de données.

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-1m.zip'
      unzip ml-1m.zip
      mkdir -p data
      cp ml-1m/ratings.dat data/
    3. Dans le cadre de ce projet, vous pouvez également utiliser l'ensemble de données 20m. Celui-ci est fourni sous forme de fichier CSV. Si vous utilisez cet ensemble de données, vous devez transmettre l'indicateur --headers, car le fichier contient une ligne d'en-tête.

      curl -O 'http://files.grouplens.org/datasets/movielens/ml-20m.zip'
      unzip ml-20m.zip
      mkdir -p data
      cp ml-20m/ratings.csv data/

Comprendre le code du modèle

Le code du modèle est hébergé dans le répertoire wals_ml_engine. Les fonctionnalités globales du code sont mises en œuvre par les fichiers suivants :

mltrain.sh
+ Lance différents types de tâches Cloud ML Engine. Ce script d'interface système accepte des arguments spécifiant l'emplacement du fichier de l'ensemble de données et le délimiteur utilisé pour séparer les valeurs dans ce fichier, et indiquant si le fichier de données comporte une ligne d'en-tête. Il est recommandé de créer un script qui configure et exécute automatiquement les tâches Cloud ML Engine.
task.py
+ Analyse les arguments de la tâche Cloud ML Engine et exécute l'entraînement.
model.py
+ Charge l'ensemble de données.
  • Crée deux matrices creuses à partir des données, une pour l'entraînement et une pour les tests. Exécute l'algorithme WALS sur la matrice de notes creuse destinée à l'entraînement.
wals.py
+ Crée le modèle WALS.
  • Exécute l'algorithme WALS.
  • Calcule la racine carrée de l'erreur quadratique moyenne (RMSE, Root-Mean-Square Error) pour un ensemble de facteurs de ligne/colonne et une matrice de notes.

Traiter des données par le modèle

Le code du modèle effectue un prétraitement des données afin de générer une matrice de notes creuse et de la préparer pour la factorisation matricielle. Cela implique les étapes suivantes :

  1. Le code du modèle charge les données à partir d'un fichier texte délimité. Chaque ligne contient une seule note.

    ratings_df = pd.read_csv(input_file,
                             sep=args['delimiter'],
                             names=headers,
                             header=header_row,
                             dtype={
                               'user_id': np.int32,
                               'item_id': np.int32,
                               'rating': np.float32,
                               'timestamp': np.int32,
                             })
  2. Le code établit un ensemble d'identifiants uniques, indexés à partir de 0, pour les utilisateurs et les éléments. Cela garantit qu'un identifiant unique correspond à des indices de ligne et de colonne spécifiques dans la matrice de notes creuse.

    • Les données de l'ensemble MovieLens 100k utilisent des identifiants indexés à partir de 1 lorsque l'indice minimal de l'ensemble unique est 1. Pour normaliser les données, le code soustrait 1 à chaque indice. Dans model.py :

      ratings = ratings_df.as_matrix(['user_id', 'item_id', 'rating'])
      # deal with 1-based user indices
      ratings[:,0] -= 1
      ratings[:,1] -= 1
    • Les ensembles de données MovieLens 1m et 20m ignorent certains ID d'utilisateurs et d'éléments. Cela entraîne un problème : vous devez établir une correspondance entre l'ensemble d'ID d'utilisateurs uniques et un ensemble d'indices égal à [0 ... num_users-1], et faire de même pour les ID d'éléments. Le mappage des éléments est réalisé à l'aide du code [numpy](http://www.numpy.org/) suivant. Le code crée un tableau de taille [0..max_item_id] pour effectuer le mappage. Par conséquent, si l'ID d'élément maximal est très grand, cette méthode risque de consommer trop de mémoire.

      np_items = ratings_df.item_id.as_matrix()
      unique_items = np.unique(np_items)
      n_items = unique_items.shape[0]
      max_item = unique_items[-1]
      
      # map unique items down to an array 0..n_items-1
      z = np.zeros(max_item+1, dtype=int)
      z[unique_items] = np.arange(n_items)
      i_r = z[np_items]
    • Le code de mappage des utilisateurs est, pour l'essentiel, identique à celui des éléments.

  3. Le code du modèle sélectionne des notes de manière aléatoire pour générer un ensemble de test. Par défaut, 10 % des notes sont choisies pour constituer l'ensemble de test. Ces notes sont retirées de l'ensemble d'entraînement, et seront utilisées ultérieurement pour évaluer la précision prédictive des facteurs utilisateur et élément.

    test_set_size = len(ratings) / TEST_SET_RATIO
    test_set_idx = np.random.choice(xrange(len(ratings)),
                                    size=test_set_size, replace=False)
    test_set_idx = sorted(test_set_idx)
    
    ts_ratings = ratings[test_set_idx]
    tr_ratings = np.delete(ratings, test_set_idx, axis=0)
  4. Enfin, le code crée une matrice creuse scipy sous forme de coordonnées (coo_matrix) qui inclut les indices et les notes des utilisateurs et des éléments. L'objet coo_matrix agit comme un wrapper pour une matrice creuse. Il procède également à la validation des indices des utilisateurs et des notes, en recherchant les erreurs au niveau du prétraitement.

    u_tr, i_tr, r_tr = zip(*tr_ratings)
    tr_sparse = coo_matrix((r_tr, (u_tr, i_tr)), shape=(n_users, n_items))

Mise en œuvre de l'algorithme WALS dans TensorFlow

Une fois les données prétraitées, le code transmet la matrice d'entraînement creuse au modèle TensorFlow WALS pour qu'elle soit factorisée en facteur de ligne X et en facteur de colonne Y.

Le code TensorFlow qui exécute le modèle est en réalité simple, car il repose sur la classe WALSModel incluse dans le module contrib.factorization_ops de TensorFlow.

  1. Un objet SparseTensor est initialisé avec les ID d'utilisateurs et d'éléments en guise d'indices, ainsi que les notes en guise de valeurs. Dans wals.py :

    input_tensor = tf.SparseTensor(indices=zip(data.row, data.col),
                                    values=(data.data).astype(np.float32),
                                    dense_shape=data.shape)

    La variable de données est l'objet coo_matrix contenant les notes d'entraînement, généré lors du prétraitement.

  2. Le modèle est instancié :

    model = factorization_ops.WALSModel(num_rows, num_cols, dim,
                                        unobserved_weight=unobs,
                                        regularization=reg,
                                        row_weights=row_wts,
                                        col_weights=col_wts)
  3. Les Tensors correspondant aux facteurs de ligne et de colonne sont créés automatiquement par la classe WALSModel, et sont extraits pour pouvoir être évalués après factorisation de la matrice :

    # retrieve the row and column factors
    row_factor = model.row_factors[0]
    col_factor = model.col_factors[0]
  4. Le processus d'entraînement exécute la boucle suivante dans une session TensorFlow utilisant la méthode simple_train dans wals.py :

    row_update_op = model.update_row_factors(sp_input=input_tensor)[1]
    col_update_op = model.update_col_factors(sp_input=input_tensor)[1]
    
    sess.run(model.initialize_op)
    sess.run(model.worker_init)
    for _ in xrange(num_iterations):
        sess.run(model.row_update_prep_gramian_op)
        sess.run(model.initialize_row_update_op)
        sess.run(row_update_op)
        sess.run(model.col_update_prep_gramian_op)
        sess.run(model.initialize_col_update_op)
        sess.run(col_update_op)
  5. Une fois que le nombre num_iterations d'itérations a été exécuté, les Tensors des facteurs de ligne et de colonne sont évalués dans la session pour produire des tableaux numpy pour chaque facteur :

    # evaluate output factor matrices
    output_row = row_factor.eval(session=session)
    output_col = col_factor.eval(session=session)

Ces tableaux de facteurs sont utilisés pour calculer l'erreur RMSE sur l'ensemble de notes de test. Les deux tableaux sont également enregistrés dans le répertoire de sortie au format numpy.

Entraîner le modèle

Dans ce contexte, entraîner le modèle implique de factoriser une matrice de notes creuse pour obtenir une matrice de facteurs utilisateur X et une matrice de facteurs élément Y. Les facteurs utilisateur et élément enregistrés peuvent servir de modèle de base pour un système de recommandation.

Ce système prend en entrée un utilisateur, extrait de X le vecteur de facteurs utilisateur qui lui correspond, multiplie ce vecteur par tous les facteurs élément Y, et renvoie les N éléments les mieux classés en termes de note prédite.

La partie 4 de cette série de tutoriels fournit des informations plus détaillées sur un système utilisant le modèle entraîné pour effectuer des prédictions et explique comment déployer un tel système sur GCP.

Entraîner le modèle localement

Entraîner le modèle localement est utile dans un contexte de développement. Cela vous permet de tester rapidement les modifications de code et d'inclure des points d'arrêt pour faciliter le débogage. Pour exécuter le modèle dans Cloud Shell ou sur votre système local, exécutez le script mltrain.sh à partir du répertoire de code à l'aide de l'option local.

  • Pour l'ensemble de données MovieLens 100k, spécifiez le chemin d'accès au fichier de données 100k :

    ./mltrain.sh local ./../data/u.data
  • Pour l'ensemble de données MovieLens 1m, incluez l'option --delimiter et spécifiez le chemin du fichier de données 1m :

    ./mltrain.sh local data/ratings.dat --delimiter ::
  • Pour l'ensemble de données MovieLens 20m, utilisez les options --delimiter et --header :

    ./mltrain.sh local data/ratings.csv --header --delimiter ,

La sortie de la tâche d'entraînement affiche l'erreur RMSE calculée sur l'ensemble de test. Pour l'ensemble de données 1m, en utilisant les hyperparamètres par défaut spécifiés dans le code source, le résultat devrait ressembler à ceci :

INFO:tensorflow:Train Start: <timestamp>
...
INFO:tensorflow:Train Finish: <timestamp>
INFO:tensorflow:train RMSE = 1.06
INFO:tensorflow:test RMSE = 1.11

Pour plus de détails, reportez-vous à la partie 2.

L'erreur RMSE correspond à l'erreur moyenne relevée dans les prédictions de notes par rapport à l'ensemble de test. En moyenne, chaque note produite par l'algorithme se situe à ± 1,11 de la note réelle donnée par un utilisateur dans l'ensemble de test 1m. L'algorithme WALS fonctionne beaucoup mieux après un réglage des hyperparamètres, comme illustré dans la partie 2 de cette série.

Effectuer un nettoyage

Si vous avez créé une instance Compute Engine pour exécuter TensorFlow, vous devez l'arrêter afin d'éviter que des frais ne soient facturés sur votre compte GCP. Cette instance n'est pas utilisée dans la partie 2 de la série. Toutefois, l'instance Compute Engine est requise pour la partie 3 et la partie 4.

Arrêter l'instance Compute Engine

  1. Dans la console GCP, ouvrez la page Instances de VM Compute Engine.
  2. Sélectionnez le nom de l'instance.
  3. Cliquez sur Arrêter et confirmez l'opération.

Supprimer le projet

Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.

Pour supprimer le projet, procédez comme suit :

  1. Dans la console GCP, accédez à la page "Projets".

    Accéder à la page Projets

  2. Dans la liste des projets, sélectionnez celui que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Étape suivante

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…