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 recommandations, également appelés outils de recommandation, sont une application très importante du machine learning. Les outils de recommandation vous aident à présenter à vos utilisateurs des contenus intéressants provenant d'un grand nombre de candidats. Par exemple, le Google Play Store propose des millions d'applications à installer, tandis que YouTube propose des milliards de vidéos à regarder. Et chaque jour, toujours plus d'applications et de vidéos sont ajoutées.

Dans cet atelier de programmation, vous allez apprendre à créer un outil de recommandation fullstack à l'aide des éléments suivants:

  • TensorFlow Recommenders pour entraîner une récupération et un modèle de classement pour les recommandations de films
  • TensorFlow Serving pour inférer les modèles
  • Flutter pour créer une application multiplate-forme permettant d'afficher des 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 sur les systèmes de recommandation
  • Vous disposez de connaissances de base sur Python, les terminaux et Docker.

Points abordés

  • Entraîner des modèles de récupération et classer des modèles à 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, cet atelier de programmation nécessite deux logiciels : le SDK Flutter et un éditeur.

Vous pouvez exécuter l'interface de l'atelier de programmation avec 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 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 dont vous avez besoin.

Pour cet atelier de programmation, vous n'avez besoin que des fichiers du sous-répertoire tfrs-flutter/ du 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 backend du moteur de recommandations, et un sous-dossier frontend, qui inclut le code de l'interface 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émarrage

  1. Ouvrez le fichier step0/frontend/lib/main.dart dans VS Code, puis 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 de requête au backend, qui exécute deux modèles de recommandation et renvoie une liste classée de recommandations de films. L'interface affiche le résultat dans l'interface utilisateur après avoir reçu la réponse.

d21427db9587560f.png 73e8272a5ce8dfbc.png

Si vous cliquez sur 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 recommandations

Dans la pratique, les moteurs de recommandations comportent souvent 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 ne 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. La phase de classement prend les résultats du modèle de récupération et les affine afin de sélectionner la meilleure série de recommandations possible. Son objectif est de réduire l'ensemble d'éléments susceptibles d'intéresser l'utilisateur afin de sélectionner une sélection de candidats probables de l'ordre de centaines.
  3. La phase de post-classement permet d'assurer la diversité, l'actualisation et l'équité, et de réorganiser les éléments candidats en un ensemble de recommandations utiles de l'ordre de 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 populaire MovieLens. 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 devez déployer les deux modèles en même temps à l'aide de TensorFlow Serving.

  • Dans votre terminal, accédez au dossier step2/backend de 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

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

  • Ajoutez le code suivant à 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 met en place un nouveau point de terminaison à l'adresse http://localhost:5000/recommend. Le journal doit s'afficher 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 renvoie 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 venez de 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 interroger les recommandations de films à partir de l'application Flutter.

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

  • Ajoutez le code suivant à 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 reçoit la réponse du backend, mettez à jour l'interface utilisateur afin d'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 le code

  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 Recommend (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 Recommend (Recommander).

2665514231033f1.png

Mac

  1. Sous Mac, vous devez configurer les droits d'accès appropriés, car l'application enverra 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 Recommend (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 Recommend (Recommander).

7d77c1e52a5927fc.png

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

Vous pouvez également ajouter la 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 a19a0c68bc4046e6.png Démarrer le débogage, puis attendez que l'application se charge dans le navigateur Chrome.
  3. Saisissez un ID utilisateur (par exemple, 42), puis sélectionnez Recommend (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 recommandations performant et vous avez acquis les compétences nécessaires pour appliquer 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 courtes vidéos).

En savoir plus