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
- SDK de Flutter
- Configuración de iOS y Android para Flutter
- Configuración de Flutter para computadoras
- Configuración de Flutter para la Web
- Configuración de Visual Studio Code (VS Code) para Flutter y Dart
- Docker
- Bash
- Python 3.7 y versiones posteriores
- Acceso a Colab
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:
- Navega al repositorio de GitHub de este codelab.
- Haz clic en Code > Download ZIP para descargar todo el código de este codelab.
- 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
astep5
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 subcarpetafrontend
, 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
- En VS Code, haz clic en Archivo > Abrir carpeta y, luego, selecciona la carpeta
step0
del código fuente que descargaste antes. - 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. - Si no ves este diálogo, abre la terminal y, luego, ejecuta el comando
flutter pub get
en la carpetastep0/frontend
.
5. Paso 0: Ejecuta la app de partida
- 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:
A continuación, se muestra lo que ves cuando usas un iPhone 13 con el simulador de iOS:
- Haz clic en 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.
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:
- 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.
- 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.
- 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.
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 archivostep2/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 archivostep3/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
- Haz clic en Start debugging y espera a que se cargue la app.
- Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.
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
- Asegúrate de que el dispositivo de destino esté configurado como en la barra de estado de VSCode.
- Haz clic en Start debugging y espera a que se cargue la app.
- Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.
Mac
- 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/>
- Asegúrate de que el dispositivo de destino esté configurado como en la barra de estado de VSCode.
- Haz clic en Start debugging y espera a que se cargue la app.
- Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.
Windows
- Asegúrate de que el dispositivo de destino esté configurado como en la barra de estado de VSCode.
- Haz clic en Start debugging y espera a que se cargue la app.
- Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.
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.
- Asegúrate de que el dispositivo de destino esté configurado como en la barra de estado de VSCode.
- Haz clic en Start debugging y espera a que la app se cargue en el navegador Chrome.
- Ingresa un ID de usuario (p.ej., 42) y, luego, selecciona Recomendar.
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).