Créer un système full stack de recommandation de films

1. Avant de commencer

Qu'il s'agisse de recommander des films ou des restaurants, ou de mettre en avant des vidéos divertissantes, les moteurs de recommandation sont une application très importante du machine learning. Les systèmes de recommandation vous aident à proposer à vos utilisateurs du contenu intéressant parmi un grand nombre de candidats. Par exemple, le Google Play Store propose des millions d'applications à installer, tandis que YouTube fournit des milliards de vidéos à regarder. De plus, de nouvelles applications et vidéos sont ajoutées chaque jour.

Dans cet atelier de programmation, vous allez apprendre à créer un système de recommandation complet à l'aide des éléments suivants :

  • TensorFlow Recommenders pour entraîner un modèle de récupération et de classement pour les recommandations de films
  • TensorFlow Serving pour diffuser les modèles
  • Flutter pour créer une application multiplate-forme qui affiche les films recommandés

Prérequis

  • Connaissances de base du développement Flutter avec Dart
  • Connaissances de base du machine learning avec TensorFlow, telles que l'entraînement par rapport au déploiement
  • Connaissances de base des systèmes de recommandation
  • Connaissances de base de Python, des terminaux et de Docker

Points abordés

  • Entraîner des modèles de récupération et de classement à l'aide de TensorFlow Recommenders
  • Diffuser les modèles de recommandation entraînés à l'aide de TensorFlow Serving
  • Créer une application Flutter multiplate-forme pour afficher les éléments recommandés

Prérequis

2. Configurer votre environnement de développement Flutter

Pour le développement Flutter, vous avez besoin de deux logiciels pour réaliser cet atelier de programmation : le SDK Flutter et un éditeur.

Vous pouvez exécuter le frontend de l'atelier de programmation sur l'un des appareils suivants :

  • Le simulateur iOS (les outils Xcode doivent être installés)
  • Android Emulator (à configurer dans Android Studio)
  • Un navigateur (Chrome est requis pour le débogage)
  • En tant qu'application de bureau Windows, Linux ou macOS. Vous devez développer votre application sur la plate-forme où vous comptez la déployer. Par exemple, si vous voulez développer une application de bureau Windows, vous devez le faire sous Windows pour accéder à la chaîne de compilation appropriée. Les exigences spécifiques aux systèmes d'exploitation sont détaillées sur docs.flutter.dev/desktop.

Pour le backend, vous aurez besoin des éléments suivants :

  • Une machine Linux ou un Mac basé sur Intel.

3. Configuration

Pour télécharger le code de cet atelier de programmation, procédez comme suit :

  1. Accédez au dépôt GitHub pour cet atelier de programmation.
  2. Cliquez sur Code > Download ZIP (Code > Télécharger le fichier ZIP) afin de télécharger l'ensemble du code pour cet atelier de programmation.

2cd45599f51fb8a2.png

  1. Décompressez le fichier ZIP téléchargé pour accéder au dossier racine codelabs-main contenant toutes les ressources nécessaires.

Pour cet atelier de programmation, vous n'avez besoin que des fichiers du sous-répertoire tfrs-flutter/ dans le dépôt, qui contient plusieurs dossiers :

  • Les dossiers step0 à step5 contiennent le code de démarrage sur lequel s'appuie chaque étape de cet atelier de programmation.
  • Le dossier finished contient le code final de l'application exemple.
  • Chaque dossier contient un sous-dossier backend, qui inclut le code de backend du moteur de recommandation, et un sous-dossier frontend, qui inclut le code de frontend Flutter.

4. Télécharger les dépendances pour le projet

Backend

Nous allons utiliser Flask pour créer notre backend. Ouvrez votre terminal et exécutez la commande suivante :

pip install Flask flask-cors requests numpy

Interface

  1. Dans VS Code, cliquez sur File > Open folder (Fichier > Ouvrir le dossier), puis sélectionnez le dossier step0 dans le code source que vous avez téléchargé précédemment.
  2. Ouvrir le fichier step0/frontend/lib/main.dart. Si une boîte de dialogue VS Code vous invite à télécharger les packages requis pour l'application de démarrage, cliquez sur Get packages (Télécharger les packages).
  3. Si cette boîte de dialogue ne s'affiche pas, ouvrez votre terminal, puis exécutez la commande flutter pub get dans le dossier step0/frontend.

7ada07c300f166a6.png

5. Étape 0 : Exécuter l'application de départ

  1. Ouvrez le fichier step0/frontend/lib/main.dart dans VS Code, assurez-vous qu'Android Emulator ou le simulateur iOS est correctement configuré et s'affiche dans la barre d'état.

Par exemple, voici ce que vous voyez lorsque vous utilisez le Pixel 5 avec Android Emulator :

9767649231898791.png

Voici ce qui s'affiche lorsque vous utilisez l'iPhone 13 avec le simulateur iOS :

95529e3a682268b2.png

  1. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png.

Exécuter et explorer l'application

L'application devrait se lancer sur Android Emulator ou le simulateur iOS. L'UI est assez simple. Un champ de texte permet à l'utilisateur de saisir du texte en tant qu'ID utilisateur. L'application Flutter envoie la requête au backend, qui exécute deux modèles de recommandation et renvoie une liste classée de recommandations de films. Une fois la réponse reçue, le frontend affichera le résultat dans l'UI.

d21427db9587560f.png 73e8272a5ce8dfbc.png

Si vous cliquez sur Recommend (Recommander) maintenant, rien ne se passe, car l'application ne peut pas encore communiquer avec le backend.

6. Étape 1 : Créer les modèles de récupération et de classement pour le moteur de recommandation

Les moteurs de recommandation réels sont souvent composés de plusieurs étapes :

  1. L'étape de récupération consiste à sélectionner un ensemble initial de centaines de candidats parmi tous les candidats possibles. L'objectif principal de ce modèle est d'éliminer efficacement tous les candidats qui n'intéressent pas l'utilisateur. Comme le modèle de récupération peut traiter des millions de candidats, il doit être efficace en termes de calcul.
  2. L'étape de classement prend les sorties du modèle de récupération et les affine pour sélectionner le meilleur ensemble de recommandations possible. Sa tâche consiste à réduire l'ensemble des éléments susceptibles d'intéresser l'utilisateur à une présélection de candidats probables de l'ordre de centaines.
  3. L'étape de post-classement permet de garantir la diversité, la fraîcheur et l'équité. Elle réorganise les éléments candidats en un ensemble de recommandations utiles, par dizaines.

70dfc0d7e989164f.png

Dans cet atelier de programmation, vous allez entraîner un modèle de récupération et un modèle de classement à l'aide de l'ensemble de données MovieLens, qui est très populaire. Vous pouvez ouvrir le code d'entraînement ci-dessous via Colab et suivre les instructions :

7. Étape 2 : Créez le backend du moteur de recommandations

Maintenant que vous avez entraîné les modèles de récupération et de classement, vous pouvez les déployer et créer un backend.

Démarrer TensorFlow Serving

Étant donné que vous devez utiliser à la fois les modèles de récupération et de classement pour générer la liste de films recommandés, vous les déployez en même temps à l'aide de TensorFlow Serving.

  • Dans votre terminal, accédez au dossier step2/backend sur votre ordinateur et démarrez TensorFlow Serving avec Docker :
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config

Docker commence par télécharger automatiquement l'image TensorFlow Serving, ce qui prend une minute. Le service TensorFlow Serving devrait alors démarrer. Le journal doit se présenter comme cet extrait de code :

2022-04-24 09:32:06.461702: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models.
2022-04-24 09:32:06.461843: I tensorflow_serving/model_servers/server_core.cc:591]  (Re-)adding model: retrieval
2022-04-24 09:32:06.461907: I tensorflow_serving/model_servers/server_core.cc:591]  (Re-)adding model: ranking
2022-04-24 09:32:06.576920: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: retrieval version: 123}
2022-04-24 09:32:06.576993: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577011: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577848: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.583809: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.583879: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.584970: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-04-24 09:32:06.629900: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.634662: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2800000000 Hz
2022-04-24 09:32:06.672534: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.673629: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: ranking version: 123}
2022-04-24 09:32:06.673765: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: ranking version: 123}
2022-04-24 09:32:06.673786: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: ranking version: 123}
2022-04-24 09:32:06.674731: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.683557: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.683601: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.688665: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 110815 microseconds.
2022-04-24 09:32:06.690019: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/retrieval/exported-retrieval/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.693025: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: retrieval version: 123}
2022-04-24 09:32:06.702594: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.745361: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.772363: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 97633 microseconds.
2022-04-24 09:32:06.774853: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ranking/exported-ranking/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.777706: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: ranking version: 123}
2022-04-24 09:32:06.778969: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-04-24 09:32:06.779030: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-04-24 09:32:06.784217: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-04-24 09:32:06.785748: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...

Créer un point de terminaison

Étant donné que TensorFlow Serving n'est pas compatible avec l'enchaînement de plusieurs modèles séquentiels, vous devez créer un service qui connecte les modèles de récupération et de classement.

  • Ajoutez ce code à la fonction get_recommendations() dans le fichier step2/backend/recommendations.py :
user_id = request.get_json()["user_id"]
retrieval_request = json.dumps({"instances": [user_id]})
retrieval_response = requests.post(RETRIEVAL_URL, data=retrieval_request)
movie_candidates = retrieval_response.json()["predictions"][0]["output_2"]

ranking_queries = [
    {"user_id": u, "movie_title": m}
    for (u, m) in zip([user_id] * NUM_OF_CANDIDATES, movie_candidates)
]
ranking_request = json.dumps({"instances": ranking_queries})
ranking_response = requests.post(RANKING_URL, data=ranking_request)
movies_scores = list(np.squeeze(ranking_response.json()["predictions"]))
ranked_movies = [
    m[1] for m in sorted(list(zip(movies_scores, movie_candidates)), reverse=True)
]

return make_response(jsonify({"movies": ranked_movies}), 200)

Démarrer le service Flask

Vous pouvez maintenant démarrer le service Flask.

  • Dans votre terminal, accédez au dossier step2/backend/ et exécutez la commande suivante :
FLASK_APP=recommender.py FLASK_ENV=development flask run

Flask va créer un nouveau point de terminaison à l'adresse http://localhost:5000/recommend. Le journal doit se présenter comme suit :

 * Serving Flask app 'recommender.py' (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 705-382-264
127.0.0.1 - - [25/Apr/2022 19:44:47] "POST /recommend HTTP/1.1" 200 -

Vous pouvez envoyer un exemple de requête au point de terminaison pour vous assurer qu'il fonctionne comme prévu :

curl -X POST -H "Content-Type: application/json" -d '{"user_id":"42"}' http://localhost:5000/recommend

Le point de terminaison renverra une liste de films recommandés pour l'utilisateur 42 :

{
  "movies": [
    "While You Were Sleeping (1995)",
    "Preacher's Wife, The (1996)",
    "Michael (1996)",
    "Lion King, The (1994)",
    "Father of the Bride Part II (1995)",
    "Sleepless in Seattle (1993)",
    "101 Dalmatians (1996)",
    "Bridges of Madison County, The (1995)",
    "Rudy (1993)",
    "Jack (1996)"
  ]
}

Et voilà ! Vous avez réussi à créer un backend pour recommander des films en fonction d'un ID utilisateur.

8. Étape 3 : Créez l'application Flutter pour Android et iOS

Le backend est prêt. Vous pouvez commencer à lui envoyer des requêtes pour obtenir des recommandations de films depuis l'application Flutter.

L'application d'interface est assez simple. Il ne comporte qu'un TextField qui accepte l'ID utilisateur et envoie la requête (dans la fonction recommend()) au backend que vous venez de créer. Une fois la réponse reçue, l'UI de l'application affiche les films recommandés dans une ListView.

  • Ajoutez ce code à la fonction recommend() dans le fichier step3/frontend/lib/main.dart :
final response = await http.post(
  Uri.parse('http://' + _server + ':5000/recommend'),
  headers: <String, String>{
    'Content-Type': 'application/json',
  },
  body: jsonEncode(<String, String>{
    'user_id': _userIDController.text,
  }),
);

Une fois que l'application a reçu la réponse du backend, vous mettez à jour l'UI pour afficher la liste des films recommandés pour l'utilisateur spécifié.

  • Ajoutez ce code juste en dessous du code ci-dessus :
if (response.statusCode == 200) {
  return List<String>.from(jsonDecode(response.body)['movies']);
} else {
  throw Exception('Error response');
}

Exécuter l'application

  1. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png, puis attendez que l'application se charge.
  2. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommander.

badb59d8b96959ae.png a0d2d4020aebfb0a.png

9. Étape 4 : Exécutez l'application Flutter sur les plates-formes de bureau

En plus d'Android et d'iOS, Flutter est également compatible avec les plates-formes de bureau, y compris Linux, Mac et Windows.

Linux

  1. Assurez-vous que l'appareil cible est défini sur 86cba523de82b4f9.png dans la barre d'état de VSCode.
  2. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png, puis attendez que l'application se charge.
  3. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommander.

2665514231033f1.png

Mac

  1. Pour Mac, vous devez configurer les droits d'accès appropriés, car l'application envoie des requêtes HTTP au backend. Pour en savoir plus, consultez Droits d'accès et bac à sable de l'application.

Ajoutez ce code à step4/frontend/macOS/Runner/DebugProfile.entitlements et step4/frontend/macOS/Runner/Release.entitlements, respectivement :

<key>com.apple.security.network.client</key>
<true/>
  1. Assurez-vous que l'appareil cible est défini sur eb4b0b5563824138.png dans la barre d'état de VSCode.
  2. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png, puis attendez que l'application se charge.
  3. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommander.

860d523a7ac537e0.png

Windows

  1. Assurez-vous que l'appareil cible est défini sur 9587be1bb375bc0f.png dans la barre d'état de VSCode.
  2. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png, puis attendez que l'application se charge.
  3. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommander.

7d77c1e52a5927fc.png

10. Étape 5 : Exécuter l'application Flutter sur la plate-forme Web

Vous pouvez également ajouter une compatibilité Web à l'application Flutter. Par défaut, la plate-forme Web est automatiquement activée pour les applications Flutter. Il vous suffit donc de la lancer.

  1. Assurez-vous que l'appareil cible est défini sur 71db93efa928d15d.png dans la barre d'état de VSCode.
  2. Cliquez sur l'icône Démarrer le débogage a19a0c68bc4046e6.png, puis attendez que l'application se charge dans le navigateur Chrome.
  3. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommander.

9376e1e432c18bef.png

11. Félicitations

Vous avez créé une application full stack pour recommander des films à vos utilisateurs.

Bien que l'application ne recommande que des films, vous avez appris le workflow global de création d'un moteur de recommandation puissant et maîtrisé la compétence permettant de consommer les recommandations dans une application Flutter. Vous pouvez facilement appliquer ce que vous avez appris à d'autres scénarios (par exemple, l'e-commerce, l'alimentation et les vidéos courtes).

En savoir plus