Cómo compilar un sistema de recomendación de películas de pila completa

1. Antes de comenzar

Desde recomendar películas o restaurantes hasta destacar videos entretenidos, los motores de recomendaciones, también conocidos como recomendadores, son una aplicación muy importante del aprendizaje automático. Los recomendadores te ayudan a mostrarles a los usuarios contenido atractivo de un gran grupo de candidatos. Por ejemplo, Google Play Store ofrece millones de apps para instalar, mientras que YouTube ofrece miles de millones de videos para mirar. Además, cada día se agregan más aplicaciones y videos.

En este codelab, aprenderás a compilar un recomendador de pila completa usando lo siguiente:

  • TensorFlow Recommenders para entrenar una recuperación y un modelo de clasificación para las recomendaciones de películas
  • TensorFlow Serving para entregar los modelos
  • Flutter para crear una app multiplataforma que muestre películas recomendadas

Requisitos previos

  • Conocimientos básicos sobre el desarrollo de Flutter con Dart
  • Conocimientos básicos del aprendizaje automático con TensorFlow, como el entrenamiento y la implementación
  • Conocimientos básicos sobre los sistemas de recomendación
  • Conocimientos básicos de Python, terminales y Docker

Qué aprenderás

  • Cómo entrenar modelos de recuperación y clasificación con TensorFlow Recommenders
  • Cómo entregar los modelos de recomendaciones entrenados con TensorFlow Serving
  • Cómo compilar una app multiplataforma de Flutter para mostrar los elementos recomendados

Requisitos

2. Configura tu entorno de desarrollo de Flutter

Para el desarrollo de Flutter, necesitas dos tipos de software para completar este codelab: el SDK de Flutter y un editor.

Puedes ejecutar el frontend del codelab con cualquiera de estos dispositivos:

  • El simulador de iOS (requiere instalar las herramientas de Xcode)
  • Android Emulator (requiere configuración en Android Studio)
  • Un navegador (se requiere Chrome para la depuración)
  • Como una aplicación para computadoras que ejecuten Windows, Linux o macOS (debes desarrollarla en la plataforma donde tengas pensado realizar la implementación; por lo tanto, si quieres desarrollar una app de escritorio para Windows, debes desarrollarla en ese SO a fin de obtener acceso a la cadena de compilación correcta; encuentra detalles sobre los requisitos específicos del sistema operativo en docs.flutter.dev/desktop).

Para el backend, necesitarás lo siguiente:

  • Una máquina con Linux o una Mac con procesador Intel.

3. Prepárate

Para descargar el código de este codelab, haz lo siguiente:

  1. Navega al repositorio de GitHub de este codelab.
  2. Haz clic en Code > Download ZIP para descargar todo el código de este codelab.

2cd45599f51fb8a2.png

  1. Descomprime el archivo ZIP descargado para desempaquetar una carpeta raíz codelabs-main con todos los recursos que necesitas.

Para este codelab, solo necesitas los archivos del subdirectorio tfrs-flutter/ del repositorio, que contiene varias carpetas:

  • Las carpetas step0 a step5 contienen el código de partida en el que se basa cada paso de este codelab.
  • La carpeta finished contiene el código completado de la app de ejemplo finalizada.
  • Cada carpeta contiene una subcarpeta backend, que incluye el código de backend del motor de recomendaciones y una subcarpeta frontend, que incluye el código del frontend de Flutter.

4. Descarga las dependencias del proyecto

Backend

Usaremos Flask para crear nuestro backend. Abre tu terminal y ejecuta lo siguiente:

pip install Flask flask-cors requests numpy

Frontend

  1. En VS Code, haz clic en Archivo > Abrir carpeta y, luego, selecciona la carpeta step0 del código fuente que descargaste antes.
  2. Abre el archivo step0/frontend/lib/main.dart. Si aparece un diálogo de VS Code en el que se te solicita que descargues los paquetes necesarios para la app de partida, haz clic en Get packages.
  3. Si no ves este diálogo, abre la terminal y, luego, ejecuta el comando flutter pub get en la carpeta step0/frontend.

7ada07c300f166a6.png

5. Paso 0: Ejecuta la app de partida

  1. Abre el archivo step0/frontend/lib/main.dart en VS Code y asegúrate de que Android Emulator o el simulador de iOS estén configurados correctamente y aparezcan en la barra de estado.

Por ejemplo, a continuación, se muestra lo que ves cuando usas un Pixel 5 con Android Emulator:

9767649231898791.png

A continuación, se muestra lo que ves cuando usas un iPhone 13 con el simulador de iOS:

95529e3a682268b2.png

  1. Haz clic en a19a0c68bc4046e6.png Start debugging.

Ejecuta y explora la app

La app debe iniciarse en Android Emulator o el simulador de iOS. La IU es bastante sencilla. Hay un campo de texto que le permite al usuario escribir el texto como el ID del usuario. La app de Flutter enviará la solicitud de consulta al backend, que ejecuta 2 modelos de recomendación y muestra una lista clasificada de recomendaciones de películas. El frontend mostrará el resultado en la IU después de recibir la respuesta.

d21427db9587560f.png 73e8272a5ce8dfbc.png

Si haces clic en Recomendar ahora, no sucederá nada porque la app aún no puede comunicarse con el backend.

6. Paso 1: Crea los modelos de recuperación y clasificación para el motor de recomendaciones

Los motores de recomendaciones del mundo real suelen estar compuestos por varias etapas:

  1. La etapa de recuperación es responsable de seleccionar un conjunto inicial de cientos de candidatos de todos los posibles candidatos. El objetivo principal de este modelo es eliminar de forma eficiente todos los candidatos que no le interesan al usuario. Debido a que el modelo de recuperación puede trabajar con millones de candidatos, debe ser eficiente en términos de procesamiento.
  2. La etapa de clasificación toma los resultados del modelo de recuperación y los ajusta para seleccionar el mejor puñado posible de recomendaciones. Su tarea es reducir el conjunto de elementos que podrían interesarle al usuario a una lista reducida de cientos de posibles candidatos.
  3. La etapa posterior a la clasificación ayuda a garantizar la diversidad, frescura y equidad, y reorganiza los elementos candidatos en un conjunto de recomendaciones útiles en orden de decenas.

80dfc0d7e989164f.png

En este codelab, entrenarás un modelo de recuperación y un modelo de clasificación con el popular conjunto de datos de MovieLens. Puedes abrir el siguiente código de entrenamiento en Colab y seguir las instrucciones:

7. Paso 2: Crea el backend del motor de recomendaciones

Ahora que entrenaste los modelos de recuperación y clasificación, puedes implementarlos y crear un backend.

Inicia TensorFlow Serving

Dado que necesitas usar los modelos de recuperación y de clasificación para generar la lista de películas recomendadas, implementa ambos al mismo tiempo con TensorFlow Serving.

  • En tu terminal, ve a la carpeta step2/backend en tu computadora y, luego, inicia TensorFlow Serving con Docker:
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config

Docker descarga automáticamente la imagen de TensorFlow Serving primero, lo cual tarda un minuto. Luego, TensorFlow Serving debería iniciarse. El registro debería verse como este fragmento de código:

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 ...

Crea un extremo nuevo

Dado que TensorFlow Serving no admite el “encadenamiento” varios modelos secuenciales, debes crear un nuevo servicio que conecte los modelos de recuperación y clasificación.

  • Agrega este código a la función get_recommendations() en el archivo 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)

Inicia el servicio Flask

Ahora puedes iniciar el servicio Flask.

  • En la terminal, ve a la carpeta step2/backend/ y ejecuta lo siguiente:
FLASK_APP=recommender.py FLASK_ENV=development flask run

Flask creará un extremo nuevo en http://localhost:5000/recommend. Deberías ver el registro como se muestra a continuación:

 * 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 -

Puedes enviar una solicitud de muestra al extremo para asegurarte de que funcione según lo esperado:

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

El extremo mostrará una lista de películas recomendadas para el usuario 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)"
  ]
}

Eso es todo. Compilaste correctamente un backend para recomendar películas según un ID de usuario.

8. Paso 3: Crea la app de Flutter para iOS y Android

El backend está listo. Puedes comenzar a enviarle solicitudes para consultar recomendaciones de películas desde la app de Flutter.

La app del frontend es bastante simple. Solo tiene un TextField que recibe el ID del usuario y envía la solicitud (en la función recommend()) al backend que acabas de compilar. Después de recibir la respuesta, la IU de la app muestra las películas recomendadas en una ListView.

  • Agrega este código a la función recommend() en el archivo 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,
  }),
);

Una vez que la app recibe la respuesta del backend, debes actualizar la IU para mostrar la lista de películas recomendadas para el usuario especificado.

  • Agrega este código justo debajo del código anterior:
if (response.statusCode == 200) {
  return List<String>.from(jsonDecode(response.body)['movies']);
} else {
  throw Exception('Error response');
}

Ejecuta la app

  1. Haz clic en a19a0c68bc4046e6.png Start debugging y espera a que se cargue la app.
  2. Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.

badb59d8b96959ae.png a0d2d4020aebfb0a.png

9. Paso 4: Ejecuta la app de Flutter en las plataformas de escritorio

Además de iOS y Android, Flutter también admite plataformas de escritorio, como Linux, Mac y Windows.

Linux

  1. Asegúrate de que el dispositivo de destino esté configurado como 86cba523de82b4f9.png en la barra de estado de VSCode.
  2. Haz clic en a19a0c68bc4046e6.png Start debugging y espera a que se cargue la app.
  3. Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.

2665514231033f1.png

Mac

  1. En Mac, deberás configurar los derechos adecuados, ya que la app enviará solicitudes HTTP al backend. Para obtener más información, consulta Derechos y zona de pruebas de apps.

Agrega este código a step4/frontend/macOS/Runner/DebugProfile.entitlements y step4/frontend/macOS/Runner/Release.entitlements respectivamente:

<key>com.apple.security.network.client</key>
<true/>
  1. Asegúrate de que el dispositivo de destino esté configurado como eb4b0b5563824138.png en la barra de estado de VSCode.
  2. Haz clic en a19a0c68bc4046e6.png Start debugging y espera a que se cargue la app.
  3. Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.

860d523a7ac537e0.png

Windows

  1. Asegúrate de que el dispositivo de destino esté configurado como 9587be1bb375bc0f.png en la barra de estado de VSCode.
  2. Haz clic en a19a0c68bc4046e6.png Start debugging y espera a que se cargue la app.
  3. Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.

7d77c1e52a5927fc.png

10. Paso 5: Ejecuta la app de Flutter en la plataforma web

Algo más que puedes hacer es agregar compatibilidad web a la app de Flutter. De forma predeterminada, la plataforma web se habilita automáticamente para las apps de Flutter, por lo que solo debes iniciarla.

  1. Asegúrate de que el dispositivo de destino esté configurado como 71db93efa928d15d.png en la barra de estado de VSCode.
  2. Haz clic en a19a0c68bc4046e6.png Start debugging y espera a que la app se cargue en el navegador Chrome.
  3. Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.

9376e1e432c18bef.png

11. Felicitaciones

Creaste una app de pila completa para recomendar películas a los usuarios.

Si bien la app solo recomienda películas, aprendiste el flujo de trabajo general para compilar un motor de recomendaciones potente y dominaste la habilidad para utilizar las recomendaciones en una app creada con Flutter. Puedes aplicar fácilmente lo que aprendiste en otras situaciones (p.ej., comercio electrónico, alimentos y videos cortos).

Más información