Skip to content

Dag pipelines#466

Open
pip3alfar0 wants to merge 24 commits intodevelopfrom
dag-pipelines
Open

Dag pipelines#466
pip3alfar0 wants to merge 24 commits intodevelopfrom
dag-pipelines

Conversation

@pip3alfar0
Copy link
Collaborator

Summary

Se cambiaron archivos para que pudiera funcionar el módulo de pipelines, es decir, que todos los nodos funcionaran como deberían y que al ejecutar el pipeline este entregue los resultados correctamente. Ahora los pipelines funcionan correctamente con modelos de regresión y de clasificación.

Además, al módulo de pipelines se le añadió la opción de poder verse en dark mode o light mode.

Me quedó pendiente revisar la funcionalidad del nodo Retrieve Model.


Changes (by file)

Important files that were modified:

  • .github/workflows/build-test.yaml: Se fuerza la reinstalación de setuptools, para asegurarse de que esté disponible. Esto fue necesario porque como en Python 3.12+ pkg_resources requiere de setuptools me fallaban los pytest. Tuve que forzar la reinstalación de este paquete para que pudieran funcionar los Build and Test.
  • back/api/api_v1/endpoints/datasets.py: Se agregaron métodos /load_preview e /infer_datatypes para poder subir datasets al nodo Data Selector. Esto fue porque no funcionaba el nodo Data Selector sin la nueva incorporación de esos métodos.
  • back/api/api_v1/endpoints/model_sessions.py: Se agregó un except extra para evitar que se caiga el servidor por un error no anticipado durante la validación.
  • back/job/base_job.py: Método run pasó de run() a run(self). Esto fue porque no me funcionaba ejecutar los pipelines hasta que hice este cambio.
  • back/metrics/regression_metric.py: Handle both DashAIDataset and numpy array inputs. Antes se asumía que y siempre era del tipo DashAIDataset, pero en algunos casos pasaba que este era un np.ndarray (example: al llamar la métrica directamente desde un pipeline que ya preprocesó los datos, la llamada a .to_pandas() fallaba porque los arrays de NumPy no tienen ese método). Ahora se verifica el tipo de dato.
  • back/models/hugging_face/distilbert_transformer.py: Se agregaron 4 parámetros de logging al guardar y cargar el modelo DistilBERT (log_train_every_n_epochs, log_train_every_n_steps, log_validation_every_n_epochs and log_validation_every_n_steps). Estos nuevos parámetros controlan cada cuánto se registran métricas durante el entrenamiento. Asegura que la configuración de logging del entrenamiento se guarde al serializar el modelo con save() y al cargarlo con load().
  • back/models/hugging_face/stable_diffusion_v1_depth_controlnet.py: Se reemplazaron las ocurrencias de DPTFeatureExtractor por DPTImageProcessor, ya que la clase DPTFeatureExtractor fue deprecada en las nuevas versiones de la librería transformers.
  • back/models/model_factory.py: Se agregó un chequeo de tipo antes de transformar los datos de salida (similar a lo que se hizo en regression_metric.py). Antes, se intentaba transformar y[split] llamando a prepare_output() o prepare_dataset(), asumiendo que era un DashAIDataset. Sin embargo, ocurría que y[split] era un np.ndarray, entonces fallaba.
  • back/optimizers/hyperopt_optimizer.py: se tuvo que modificar por error en pytest (3.12, ...). El from hyperopt import ... de la linea 3 se ejecutaba al recolectar los tests (conftest.py -> init.py -> ... -> hyperopt -> pkg_resources). Como en Python 3.12+ pkg_resources requiere de setuptools, y el CI no lo garantiza, la recolección falla. Se movieron los imports de hyperopt al interior de los métodos que los usan (search_space() y optimize()). Con esto se evita que hyperopt se importe durante la recolección de tests o al arrancar la aplicación.
  • front/src/components/datasets/DatasetModal.jsx: Se modificó el flujo de creación de datasets, dividiéndolo en 2 pasos. Antes, se llamaba directamente a enqueueDatasetRequest pasando el nombre del archivo. El endpoint creaba el registro en la DB y encolaba el job de carga en el mismo llamado. Ahora, createDataset(name) crea el registro del dataset en la db y se obtiene su "id", después enqueueDatasetRequest(data.id, ...) encola el job de carga, pasando en vez del nombre, el data.id. Esto lo hice para separar la creación del registro de la carga de datos, permitiendo que el dataset exista en la db antes de que empiece el job. Ahora el front puede rastrear el estado del dataset desde el momento en que se crea.
  • front/src/components/explorations/ExplorationRunner.jsx: Se corrigió la fuente del import de LoadingButton. Antes se importaba desde @mui/material, y ahora se importa desde @mui/Lab/LoadingButton.
  • front/src/components/explorations/Steps/ConfigureExplorersStep.jsx: Se corrige la ruta del import de ExplorersTable. Antes se importaba desde ../ExplorationsTable, y ahora desde ../explorers/ExplorersTable.
  • front/src/components/explorations/explorers/ExplorersTable.jsx: Se separó el import de EditParametersDialog y EditColumnsDialog en un import para cada uno. Esto fue por el cambio de ExplorersTable a la carpeta explorers. Además, se corrigió en valueGetter la columna "Type", ya que en las nuevas versiones de MUI DataGrid, valueGetter recibe (value, row) en vez del objeto params. En resumen, ahora el código evita errores cuando los datos tienen estructuras inesperadas: valueGetter antes asumía que params.row siempre existía (podía fallar), y ahora maneja casos donde calue podría tener estructura {row: ...} (usa eso) o usa row directamente, y en caso de que ambos fallaran devuelve string vacío, y además usa optional chaining ?. que es más seguro.

Adicionalmente, los cambios dentro de pipelines son:

  • back/api/api_v1/endpoints/pipelines.py: Se hace una distinción entre clasificación y regresión. Antes todos los datos numéricos se trataban como clasificación, y ahora se agregó una lógica para detectar si los datos son clasificación (lineas 135-145) o regresión (lineas 146-170). Además, se hizo un fix en el conteo de ocurrencias de clases. Antes se hacía data.count(int(class_name)), lo cual podía fallar con un ValueError si class_name no se podía convertir a entero. Ahora, se convierte el nombre de la clase a su tipo original, entonces ya no se necesita el try/except ValueError de antes.
  • back/job/pipeline_job.py: Se cambió el método run de asincrónico a sincrónico. Como antes el método run era async, tenía que ser ejecutado dentro de un event loop, pero como los jobs se ejecutan típicamente en threads de un pool de workers, llamar a un run async fallaba. Ahora se encapsuló la lógica asíncrona (linea 105) para tener un run sincrónico. Además, se cambió de Session a sessionmaker, ya que antes se recibía una sesión de DB ya abierta con self.kwargs["db"], lo cual generaba problema porque la sesión se creaba en otro hilo y se pasaba al job worker, y en caso de fallar el job, la sesión quedaba en estado corrupto. Con sessionmaker se crea una sesión nueva dentro del job. También, se agregaron los métodos set_status_as_error() y get_job_name(), y se añadió un log de debug al método set_status_as_delivered. Por último, se mejoraron las validaciones, antes habían validaciones duplicadas (if not steps aparecía dos veces).
  • back/pipeline/data_selector_node.py: Se agregaron dos nuevos métodos: set_status_as_error() y get_job_name(). set_status_as_error() registra un log de error cuando el nodo falla (es el método que se implementó en base_job y pipeline_job). get_job_name() devueve un nombre como "DataSelector: blabla_dataset", para identificar el nodo que se está ejecutando en los logs o en la UI.
  • back/pipeline/exploration_node.py: Primero, se volvieron a agregar los métodos set_status_as_error() y get_job_name(). Se eliminaron las dependencias del modelo Explorer de la DB. Antes, se importaba Explorer y se creaba una instancia de este modelo de db para pasarle metadata al explorer. Como Explorer es un modelo de SQLAlchemy, cuando se creaba una instancia de Explorer fuera del contexto de una sesión de DB ocurrían errores de SQLAlchemy. Por lo tanto, ahora se define una clase interna ExplorerInfo que es solo un contenedor de datos. Además, se renombró "id" como "explorer_id". Por último, se añadió un valor default para "name" (antes era None, y ahora es un string vacío, para evitar errores con el manejo de strings).
  • back/pipeline/prediction_node.py: Se agregaron los métodos set_status_as_error() y get_job_name(). Además, se corrigió el manejo de predicciones para soportar modelos de regresión (además de clasificación). Antes había dos casos: cuando la predicción era string, y en cualquier otro caso se aplicaba np.argmax(y_pred_proba, axis=1), asumiendo clasificación. El modelo de regresión retorna un array distinto al que soporta el "cualquier otro caso" anterior (en clasificación es un array 2D y en regresión es 1D), entonces ocurría error en ese caso. Ahora sí se hace la distinción entre clasificación y regresión para evitar errores.
  • back/pipeline/retrieve_model_node.py: Se agregaron los métodos set_status_as_error() y get_job_name().
  • back/pipeline/train_node.py: Se agregaron los métodos set_status_as_error() y get_job_name(). Además, se cambió prepare_for_task. Antes solo se pasaban como parámetros dataset y output_columns_names. Ahora se añadió input_columns como parámetro, para asegurarse de que la task reciba tanto las columnas de entrada como de salida, para validar correctamente el dataset. Por otra parte, se renombraron las variables x e y por x_splits e y_splits respectivamente, porque puede que los datos necesiten una transformación diferente según el tipo de modelo, y se reasignan x e y con el formato correcto. Finalmente, se hizo una distinción entre los modelos de texto y los modelos sklearn. Antes se asumía que todos los modelos usaban .fit() con arrays, pero los modelos de texto usando .train() y esperan recibir objetos DashAIDataset, no arrays. Entonces, ahora se hace la distinción para que x e y queden en el formato correcto para que factory.evaluate(x, y, metrics) funcione sin problemas.
  • front/src/components/pipelines/PipelineDesigner.jsx: Cambios de diseño con los colores del canvas.
  • front/src/components/pipelines/PipelineToolbar.jsx: Cambios de diseño, añadiendo la opción de dark mode y light mode.
  • front/src/components/pipelines/CustomNode.jsx: Se añadieron los cambios de colores por el cambio entre dark y light mode.
  • front/src/components/pipelines/nodes/DataSelectorNode.jsx: Se agregaron más mensajes para distintos casos (warnings, errores, "processing...", y "Save").
  • front/src/components/pipelines/nodes/TrainNode.jsx: Se añadieron errores de validación.
  • front/src/components/pipelines/results/Results.jsx: Se agregó un mensaje en el apartado de resultados de Pipeline is running. Results will appear automatically..., porque antes había que recargar manualmente el apartado de Results para poder visualizar los resultados de la ejecución del pipeline, ahora se recarga automáticamente cuando los resultados ya están disponibles.
  • front/src/components/pipelines/results/ResultsPredictionModal.jsx: Se reemplazaron los placeholders por la UI real, para alinearse con los cambios del back en pipelines.py, el cual retorna regresión y clasificación. Ahora muetra Tab 1 Regresión o Clasificación y Tab 2 las predicciones.
  • front/src/pages/pipelines/NewPipeline.jsx: Se agregaron los cambios de colores al canvas y al resto de apartados del módulo de pipelines.

feat: enhance PipelineJob with logging and error handling in run method
…e enqueuing job and add validation error handling in TrainNode
…in DataSelectorNode and PipelineResults components
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant