En un proyecto que involucraba la construcción de modelos de propensión para predecir las posibles compras de los clientes, encontré problemas de ingeniería de características que había visto en numerosas ocasiones antes.
Estos desafíos se pueden clasificar en términos generales en dos categorías:
1) Gestión de funciones inadecuada
No se realizó un seguimiento sistemático de las definiciones, el linaje y las versiones de las características generadas por el equipo, lo que limitó la reutilización de las características y la reproducibilidad de las ejecuciones del modelo. La lógica de las características se mantenía manualmente en scripts de entrenamiento e inferencia separados, lo que generaba un riesgo de características inconsistentes para el entrenamiento y la inferencia (es decir, sesgo en el servicio de entrenamiento). Las características se almacenaban como archivos planos (por ejemplo, CSV), que carecen de aplicación de esquema y soporte para acceso escalable o de baja latencia.
2) Latencia de ingeniería de altas características
A menudo surgen cargas de trabajo pesadas de ingeniería de características cuando se trata de datos de series temporales, donde se deben calcular múltiples transformaciones basadas en ventanas. Cuando estos cálculos se ejecutan secuencialmente en lugar de optimizarse para la ejecución paralela, la latencia de la ingeniería de funciones puede aumentar significativamente.
En este artículo, explico claramente los conceptos y la implementación de almacenes de funciones (Feast) y marcos de computación distribuida (Ray) para la ingeniería de funciones en canalizaciones de aprendizaje automático (ML) de producción.
Contenido
(1) Caso de uso de ejemplo
(2) Entendiendo la Fiesta y el Rayo
(3) Funciones de Feast y Ray en la ingeniería de funciones
(4) Tutorial del código
Puede encontrar el repositorio de GitHub adjunto aquí.
(i) Objetivo
Para ilustrar las capacidades de Feast y Ray, nuestro escenario de ejemplo implica crear un canal de aprendizaje automático para entrenar y ofrecer un modelo de propensión de compra del cliente de 30 días.
(ii) Conjunto de datos
Utilizaremos el conjunto de datos UCI Online Retail (CC BY 4.0), que comprende transacciones de compra para un minorista en línea del Reino Unido entre diciembre de 2010 y diciembre de 2011.
(iii) Enfoque de ingeniería de características
Mantendremos simple el alcance de la ingeniería de características limitándolo a las siguientes características (basado en una ventana retrospectiva de 90 días a menos que se indique lo contrario):
Funciones de actualidad, frecuencia y valor monetario (RFM)
recency_days: Días desde la última compra Frecuencia: Número de pedidos distintos Monetario: Gasto monetario total tenure_days: Días desde la primera compra (todos los tiempos)
Características del comportamiento del cliente.
avg_order_value: gasto medio por pedido avg_basket_size: número medio de artículos por pedido n_unique_products: diversidad de productos return_rate: porcentaje de pedidos cancelados avg_days_between_purchases: promedio de días entre compras
(iv) Diseño de ventana enrollable
Las características se calculan a partir de un período de 90 días antes de cada fecha límite, y las etiquetas de compra (1 = al menos una compra, 0 = ninguna compra) se calculan a partir de un período de 30 días después de cada fecha límite.
Dado que las fechas límite están separadas por 30 días, se producen nueve instantáneas del conjunto de datos:
(i) Acerca de la fiesta
En primer lugar, comprendamos qué es una tienda de funciones.
Un almacén de funciones es un repositorio de datos centralizado que administra, almacena y ofrece funciones de aprendizaje automático, actuando como una única fuente de verdad tanto para la capacitación como para el servicio.
Las tiendas de funciones ofrecen beneficios clave en la gestión de canales de funciones:
Reforzar la coherencia entre los datos de entrenamiento y entrega. Prevenir la fuga de datos garantizando que las funciones utilicen solo los datos disponibles en el momento de la predicción (es decir, datos correctos en un momento dado). Permitir la reutilización de funciones y canalizaciones de funciones entre equipos. Seguimiento de versiones, linaje y metadatos de funciones para la gobernanza.
Feast (abreviatura de Feature Store) es una tienda de funciones de código abierto que ofrece datos de funciones a escala durante el entrenamiento y la inferencia.
Se integra con múltiples backends de bases de datos y marcos de aprendizaje automático que pueden funcionar dentro o fuera de plataformas en la nube.
Feast admite tanto en línea (para inferencia en tiempo real) como fuera de línea (para predicciones por lotes), aunque nos centramos en las funciones fuera de línea, ya que la predicción por lotes es más relevante para nuestro caso de uso de propensión a comprar.
(ii) Acerca de Ray
Ray es un marco informático distribuido de uso general y código abierto diseñado para escalar aplicaciones de aprendizaje automático desde una sola máquina hasta grandes clústeres. Puede ejecutarse en cualquier máquina, clúster, proveedor de nube o Kubernetes.
Ray ofrece una variedad de capacidades y la que usaremos es el tiempo de ejecución distribuido central llamado Ray Core.
Ray Core proporciona primitivas de bajo nivel para la ejecución paralela de funciones de Python como tareas distribuidas y para administrar tareas entre los recursos informáticos disponibles.
Veamos las áreas en las que Feast y Ray ayudan a abordar los desafíos de ingeniería de funciones.
(i) Configuración de la tienda de funciones con Feast
Para nuestro caso, configuraremos una tienda de funciones fuera de línea usando Feast. Nuestras funciones de RFM y comportamiento del cliente se registrarán en la tienda de funciones para un acceso centralizado.
En la terminología de Feast, las funciones fuera de línea también se denominan funciones "históricas".
(ii) Recuperación de funciones con Feast y Ray
Con nuestro almacén de características de Feast listo, permitiremos la recuperación de características relevantes durante ambas etapas de entrenamiento e inferencia del modelo.
Primero debemos tener claros estos tres conceptos: entidad, característica y vista de características.
Una entidad es la clave principal utilizada para recuperar funciones. Básicamente se refiere al identificador "objeto" para cada fila de características (p. ej., user_id, account_id, etc.) Una característica es un atributo de tipo único asociado con cada entidad (p. ej., avg_basket_size) Una vista de características define un grupo de características relacionadas para una entidad, provenientes de un conjunto de datos. Piense en ello como una tabla con una clave principal (por ejemplo, user_id) combinada con columnas de características relevantes.
Las marcas de tiempo de eventos son un componente esencial de las vistas de características, ya que nos permiten generar datos de características correctos en un momento dado para entrenamiento e inferencia.
Digamos que ahora queremos obtener estas funciones fuera de línea para entrenamiento o inferencia. Así es como se hace:
Primero se crea un DataFrame de entidad, que contiene las claves de entidad y una marca de tiempo del evento para cada fila. Corresponde a las dos columnas situadas más a la izquierda en la Fig. 5 anterior. Se produce una unión correcta en un momento dado entre la entidad DataFrame y las tablas de características definidas por las diferentes vistas de características
El resultado es un conjunto de datos combinado que contiene todas las funciones solicitadas para el conjunto especificado de entidades y marcas de tiempo.
Entonces, ¿dónde entra Ray aquí?
Ray Offline Store es un motor informático distribuido que permite una recuperación de funciones más rápida y escalable, especialmente para grandes conjuntos de datos. Lo hace paralelizando el acceso a datos y las operaciones de unión:
Acceso a datos (E/S): lecturas de datos distribuidos dividiendo archivos Parquet entre varios trabajadores, donde cada trabajador lee una partición diferente en paralelo. Operaciones de unión: divide el marco de datos de la entidad para que cada partición realice de forma independiente uniones temporales para recuperar los valores de las características por entidad antes de una marca de tiempo determinada. Con múltiples vistas de funciones, Ray paraleliza las uniones computacionalmente intensivas para escalar de manera eficiente.
(iii) Ingeniería de funciones con Ray
La función de ingeniería de características para generar RFM y características de comportamiento del cliente debe aplicarse a cada ventana de 90 días (es decir, nueve fechas límite independientes, cada una de las cuales requiere el mismo cálculo).
Ray Core convierte cada llamada a función en una tarea remota, lo que permite que la ingeniería de funciones se ejecute en paralelo en los núcleos disponibles (o máquinas en un clúster).
(4.1) Configuración inicial
Instalamos las siguientes dependencias de Python:
fiesta[rayo]==0.60.0 openpyxl==3.1.5 psycopg2-binary==2.9.11 ray==2.54.0 scikit-learn==1.8.0 xgboost==3.2.0
Como usaremos PostgreSQL para el registro de funciones, asegúrese de que Docker esté instalado y ejecutándose antes de ejecutar docker compose up -d para iniciar el contenedor de PostgreSQL.
(4.2) Preparar datos
Además de la ingesta y limpieza de datos, hay dos pasos de preparación a ejecutar:
Generación de corte rodante: crea nueve instantáneas con un intervalo de 30 días. Cada fecha límite define un punto de entrenamiento/predicción en el que las características se calculan a partir de los 90 días anteriores y las etiquetas de destino se calculan a partir de los 30 días posteriores. Creación de etiquetas: para cada límite, cree una etiqueta de destino binaria que indique si un cliente realizó al menos una compra dentro del período de 30 días posterior al límite.
(4.3) Ejecutar ingeniería de funciones basada en rayos
Después de definir el código para generar RFM y las características de comportamiento del cliente, paralelicemos la ejecución usando Ray para cada ventana móvil.
Comenzamos creando una función (compute_features_for_cutoff) para incluir todos los pasos de ingeniería de características relevantes para cada límite:
El decorador @ray.remote registra la función como una tarea remota que se ejecutará de forma asincrónica en trabajadores separados.
Luego, el proceso de preparación de datos e ingeniería de características se ejecuta de la siguiente manera:
Así es como Ray participa en el oleoducto:
ray.init() inicia un clúster Ray y habilita la ejecución distribuida en todos los núcleos locales de forma predeterminada. ray.put(df) almacena el DataFrame limpio en la memoria compartida de Ray (también conocido como almacén de objetos distribuidos) y devuelve una referencia (ObjectRef) para que todas las tareas paralelas puedan acceder al DataFrame sin copiarlo. Esto ayuda a mejorar la eficiencia de la memoria y el rendimiento del lanzamiento de tareas. Compute_features_for_cutoff.remote(…) envía nuestras tareas de cálculo de funciones al programador de Ray, donde Ray asigna cada tarea a un trabajador para su ejecución paralela y devuelve una referencia al resultado de cada tarea. futuros = […] almacena todas las referencias devueltas por cada llamada .remote(). Representan todas las tareas paralelas en vuelo que se han iniciado. ray.get(futures) recupera todos los valores de retorno reales de las ejecuciones de tareas paralelas de una sola vez. Luego, el script extrae y concatena RFM por corte y características de comportamiento en dos DataFrames, los guarda como archivos Parquet localmente. ray.shutdown() libera los recursos asignados al detener el tiempo de ejecución de Ray.
Si bien nuestras funciones se almacenan localmente en este caso, tenga en cuenta que los datos de funciones fuera de línea generalmente se almacenan en almacenes de datos o lagos de datos (por ejemplo, S3, BigQuery, etc.) en entornos de producción.
(4.4) Configurar el registro de funciones de Feast
Hasta ahora, hemos cubierto los aspectos de transformación y almacenamiento de la ingeniería de funciones. Pasemos al registro de funciones de Feast.
Un registro de características es el catálogo centralizado de definiciones de características y metadatos que sirve como fuente única de verdad para la información de características.
Hay dos componentes clave en la configuración del registro: Definiciones y Configuración.
Definiciones
Primero definimos los objetos de Python para representar las características diseñadas hasta ahora. Por ejemplo, uno de los primeros objetos a determinar es la Entidad (es decir, la clave principal que vincula las filas de características):
A continuación, definimos las fuentes de datos en las que se almacenan nuestros datos de características:
Tenga en cuenta que timestamp_field es fundamental ya que permite vistas y uniones de datos de un momento determinado correcto cuando se recuperan características para entrenamiento o inferencia.
Después de definir entidades y fuentes de datos, podemos definir las vistas de características. Dado que tenemos dos conjuntos de funciones (RFM y comportamiento del cliente), esperamos tener dos vistas de funciones:
El esquema (nombres de campo, tipos d) es importante para garantizar que los datos de las características se validen y registren correctamente.
Configuración
La configuración del registro de funciones se define en un archivo YAML llamado feature_store.yaml:
La configuración le dice a Feast qué infraestructura usar y dónde residen sus metadatos y datos de características, y generalmente comprende lo siguiente:
Nombre del proyecto: espacio de nombres para el proyecto Proveedor: entorno de ejecución (p. ej., local, Kubernetes, nube) Ubicación del registro: ubicación del almacenamiento de metadatos de funciones (archivo o bases de datos como PostgreSQL) Tienda fuera de línea: ubicación desde donde se leen los datos de funciones históricas Tienda en línea: ubicación desde donde se ofrecen funciones de baja latencia (no relevante en nuestro caso)
En nuestro caso, utilizamos PostgreSQL (que se ejecuta en un contenedor Docker) para el registro de funciones y el almacén fuera de línea de Ray para una recuperación optimizada de funciones.
Usamos PostgreSQL en lugar de SQLite local para simular una infraestructura de nivel de producción para la configuración del registro de funciones, donde múltiples servicios pueden acceder al registro simultáneamente.
Aplicar fiesta
Una vez que se establecen las definiciones y la configuración, ejecutamos la aplicación festiva para registrar y sincronizar las definiciones con el registro y aprovisionar la infraestructura requerida.
El comando se puede encontrar en el Makefile:
# Paso 2: Registrar las definiciones de funciones de Feast en el registro de PostgreSQL: cd feature_store && fiesta aplicar
(4.5) Recuperar funciones para el entrenamiento de modelos
Una vez que nuestra tienda de funciones esté lista, procedemos a entrenar el modelo ML.
Comenzamos creando la columna vertebral de la entidad para la recuperación (es decir, las dos columnas de customer_id y event_timestamp), que Feast utiliza para recuperar la instantánea de la característica correcta.
Luego ejecutamos la recuperación de funciones para el entrenamiento del modelo en tiempo de ejecución:
FeatureStore es el objeto Feast que se utiliza para definir, crear y recuperar funciones en tiempo de ejecución. get_historical_features() está diseñado para la recuperación de funciones sin conexión (a diferencia de get_online_features()), y espera que se recupere la entidad DataFrame y la lista de funciones. Las lecturas distribuidas y las uniones puntuales de datos de características tienen lugar aquí.
(4.7) Recuperar características para inferencia
Terminamos generando predicciones a partir de nuestro modelo entrenado.
Los códigos de recuperación de características para la inferencia son en gran medida similares a los de entrenamiento, ya que estamos cosechando los beneficios de un almacén de características consistente.
La principal diferencia proviene de las diferentes fechas límite utilizadas.
Resumiendo
La ingeniería de funciones es un componente vital en la creación de modelos de aprendizaje automático, pero también presenta desafíos en la gestión de datos si no se maneja adecuadamente.
En este artículo, demostramos claramente cómo utilizar Feast y Ray para mejorar la gestión, la reutilización y la eficiencia de la ingeniería de funciones.
Comprender y aplicar estos conceptos permitirá a los equipos crear canales de aprendizaje automático eficientes con capacidades de ingeniería de funciones escalables.