Comprender los componentes personalizados de TFX

Las canalizaciones de TFX le permiten orquestar su flujo de trabajo de aprendizaje automático (ML) en orquestadores, como: Apache Airflow, Apache Beam y Kubeflow Pipelines. Las canalizaciones organizan su flujo de trabajo en una secuencia de componentes, donde cada componente realiza un paso en su flujo de trabajo de ML. Los componentes estándar de TFX brindan una funcionalidad comprobada para ayudarlo a comenzar a crear fácilmente un flujo de trabajo de ML. También puede incluir componentes personalizados en su flujo de trabajo. Los componentes personalizados le permiten ampliar su flujo de trabajo de ML al:

  • Componentes de creación que se adaptan a sus necesidades, como la ingesta de datos de un sistema propietario.
  • Aplicar aumento de datos, muestreo ascendente o descendente.
  • Realice la detección de anomalías en función de los intervalos de confianza o del error de reproducción del codificador automático.
  • Interfaz con sistemas externos como mesas de ayuda para alertas y monitoreo.
  • Aplicar etiquetas a ejemplos sin etiquetar.
  • Integrar herramientas creadas con lenguajes que no sean Python en su flujo de trabajo de ML, como realizar análisis de datos con R.

Al combinar componentes estándar y componentes personalizados, puede crear un flujo de trabajo de ML que satisfaga sus necesidades mientras aprovecha las mejores prácticas integradas en los componentes estándar de TFX.

Esta guía describe los conceptos necesarios para comprender los componentes personalizados de TFX y las diferentes formas en que puede crear componentes personalizados.

Anatomía de un componente TFX

Esta sección proporciona una descripción general de alto nivel de la composición de un componente TFX. Si es nuevo en las canalizaciones de TFX, aprenda los conceptos básicos leyendo la guía para comprender las canalizaciones de TFX .

Los componentes TFX se componen de una especificación de componente y una clase de ejecutor que se empaquetan en una clase de interfaz de componente.

Una especificación de componente define el contrato de entrada y salida del componente. Este contrato especifica los artefactos de entrada y salida del componente y los parámetros que se utilizan para la ejecución del componente.

La clase de ejecutor de un componente proporciona la implementación del trabajo realizado por el componente.

Una clase de interfaz de componente combina la especificación del componente con el ejecutor para su uso como componente en una canalización TFX.

Componentes TFX en tiempo de ejecución

Cuando una canalización ejecuta un componente TFX, el componente se ejecuta en tres fases:

  1. En primer lugar, el controlador usa la especificación del componente para recuperar los artefactos necesarios del almacén de metadatos y pasarlos al componente.
  2. A continuación, el Ejecutor realiza el trabajo del componente.
  3. Luego, el publicador usa la especificación del componente y los resultados del ejecutor para almacenar los resultados del componente en el almacén de metadatos.

Anatomía del componente

La mayoría de las implementaciones de componentes personalizados no requieren que personalice el controlador o el publicador. Por lo general, las modificaciones al controlador y al publicador deberían ser necesarias solo si desea cambiar la interacción entre los componentes de su canalización y el almacén de metadatos. Si solo desea cambiar las entradas, salidas o parámetros de su componente, solo necesita modificar la especificación del componente .

Tipos de componentes personalizados

Hay tres tipos de componentes personalizados: componentes basados ​​en funciones de Python, componentes basados ​​en contenedores y componentes totalmente personalizados. Las siguientes secciones describen los diferentes tipos de componentes y los casos en los que debe utilizar cada enfoque.

Componentes basados ​​en funciones de Python

Los componentes basados ​​en funciones de Python son más fáciles de construir que los componentes basados ​​en contenedores o los componentes completamente personalizados. La especificación del componente se define en los argumentos de la función de Python mediante anotaciones de tipo que describen si un argumento es un artefacto de entrada, un artefacto de salida o un parámetro. El cuerpo de la función define el ejecutor del componente. La interfaz del componente se define agregando el decorador @component a su función.

Al decorar su función con el decorador @component y definir los argumentos de la función con anotaciones de tipo, puede crear un componente sin la complejidad de crear una especificación de componente, un ejecutor y una interfaz de componente.

Aprenda a crear componentes basados ​​en funciones de Python .

Componentes basados ​​en contenedores

Los componentes basados ​​en contenedores brindan la flexibilidad de integrar código escrito en cualquier idioma en su canalización, siempre que pueda ejecutar ese código en un contenedor de Docker. Para crear un componente basado en contenedor, debe crear una imagen de contenedor de Docker que contenga el código ejecutable de su componente. Luego debe llamar a la función create_container_component para definir:

  • Las entradas, salidas y parámetros de la especificación de su componente.
  • La imagen del contenedor y el comando que ejecuta el ejecutor del componente.

Esta función devuelve una instancia de un componente que puede incluir en su definición de canalización.

Este enfoque es más complejo que crear un componente basado en funciones de Python, ya que requiere empaquetar su código como una imagen de contenedor. Este enfoque es más adecuado para incluir código que no sea de Python en su canalización o para crear componentes de Python con dependencias o entornos de tiempo de ejecución complejos.

Aprenda a crear componentes basados ​​en contenedores .

Componentes totalmente personalizados

Los componentes completamente personalizados le permiten crear componentes definiendo la especificación del componente, el ejecutor y las clases de interfaz del componente. Este enfoque le permite reutilizar y ampliar un componente estándar para que se ajuste a sus necesidades.

Si un componente existente se define con las mismas entradas y salidas que el componente personalizado que está desarrollando, simplemente puede anular la clase Executor del componente existente. Esto significa que puede reutilizar la especificación de un componente e implementar un nuevo ejecutor que derive de un componente existente. De esta manera, reutiliza la funcionalidad integrada en los componentes existentes e implementa solo la funcionalidad que se requiere.

Sin embargo, si las entradas y salidas de su nuevo componente son únicas, puede definir una especificación de componente completamente nueva.

Este enfoque es mejor para reutilizar ejecutores y especificaciones de componentes existentes.

Aprenda a crear componentes totalmente personalizados .