IA agente para la experimentación moderna del aprendizaje profundo

que lee sus métricas, detecta anomalías, aplica reglas de ajuste predefinidas, reinicia trabajos cuando es necesario y registra cada decisión, sin que usted tenga que mirar las curvas de pérdida a las 2 am

En este artículo, proporcionaré un agente liviano diseñado para investigadores de aprendizaje profundo e ingenieros de aprendizaje automático que pueden:

• Detectar fallas automáticamente
• Razonar visualmente las métricas de rendimiento.
• Aplique sus estrategias de hiperparámetros predefinidas
• Relanzar trabajos
• Documentar cada acción y resultado

Sin búsqueda de arquitectura. Sin AutoML. Sin reescrituras invasivas de su código base.

La implementación es intencionalmente mínima: incluya su script de entrenamiento en contenedores, agregue un pequeño agente basado en LangChain, defina hiperparámetros en YAML y exprese preferencias en Markdown. Probablemente ya estés haciendo el 50% de esto.

Coloque este agente en su flujo de trabajo manual de train.py y pase de 0️⃣ a 💯 en un solo día.

El problema con sus experimentos existentes

🤔 Reflexionas sin cesar sobre los hiperparámetros.

▶️ Ejecutas train.py.

🐛 Corriges el error en train.py.

🔁 Vuelves a ejecutar train.py

👀 Te quedas mirando TensorBoard.

🫠 Cuestionas la realidad.

🔄Repites.

Todo ingeniero practicante de aprendizaje profundo/aprendizaje automático en el campo hace esto. No te avergüences. Foto original de MART PRODUCTION vía Pexels. Gif imaginado por Grok

Deja de mirar a tu modelo escupiendo números

No eres un Jedi. Ninguna cantidad de miradas hará que mágicamente tu [pérdida de validación | precisión de clasificación | perplejidad | cualquier otra métrica que pueda nombrar] muévase en la dirección que desee.

¿Cuidar un modelo en mitad de la noche para detectar un gradiente NaN que desaparece/explota en una red profunda basada en transformadores que no se puede rastrear y que tal vez ni siquiera aparezca? También un rotundo no.

¿Cómo se supone que vas a resolver problemas de investigación reales cuando la mayor parte de tu tiempo lo dedicas a un trabajo que técnicamente debe hacerse, pero que contribuye muy poco al conocimiento real?

Si el 70% de su día lo consume la carga operativa, ¿cuándo surge la idea?

Cambio a experimentos impulsados ​​por agentes

La mayoría de los ingenieros e investigadores de aprendizaje profundo con los que trabajo todavía realizan experimentos manualmente. Una parte importante del día se dedica a: escanear Weights & Biases o TensorBoard para la ejecución de anoche, comparar ejecuciones, exportar métricas, ajustar hiperparámetros, registrar notas y reiniciar trabajos. Luego repitiendo el ciclo.

Es un trabajo seco, tedioso y repetitivo.

Vamos a descargar estas tareas repetitivas para que puedas centrarte en trabajos de alto valor.

El concepto de AutoML es, francamente, ridículo.

Su [nuevo] agente no tomará decisiones sobre cómo cambiar la topología de su red ni agregar funciones complejas; ese es su trabajo. Reemplazará el trabajo repetitivo de pegamento que consume un tiempo valioso con poco valor agregado.

Experimentos impulsados ​​por agentes (ADE)

Pasar de experimentos manuales a un flujo de trabajo impulsado por agentes es más sencillo de lo que parece inicialmente. Sin reescribir su pila, sin sistemas pesados, sin deuda tecnológica.

Imagen por autor

En esencia, un ADE requiere tres pasos:

Contenga su script de entrenamiento existente. Envuelva su train.py actual en un contenedor Docker. Sin refactorización de la lógica del modelo. Sin cambios arquitectónicos. Sólo un límite de ejecución reproducible. Agregue un agente liviano Introduzca un pequeño script basado en LangChain que lea métricas de su panel, aplique sus preferencias, decida cuándo y dónde reiniciar, detener o documentar y programarlo con cron o cualquier programador de trabajos Defina el comportamiento y las preferencias con lenguaje natural Use un archivo YAML para configuración e hiperparámetros Use un documento Markdown para comunicarse con su agente

Ese es todo el sistema. Ahora, repasemos cada paso.

Contenga su guión de entrenamiento

Se podría argumentar que deberías hacer esto de todos modos. Hace que el reinicio y la programación sean mucho más fáciles y, si se traslada a un clúster de Kubernetes para recibir capacitación, la interrupción de su proceso existente es mucho menor.

Si ya estás haciendo esto, salta a la siguiente sección. De lo contrario, aquí tienes un código útil que puedes utilizar para empezar.

Primero, definamos una estructura de proyecto que funcionará con Docker.

your experiment/ ├── scripts/ │ ├── train.py # Script de entrenamiento principal │ └── health_server.py # Servidor de verificación de estado ├── requisitos.txt # Dependencias de Python ├── Dockerfile # Definición de contenedor └── run.sh # Script para iniciar el entrenamiento + salud comprobar

Necesitamos asegurarnos de que su script train.py pueda cargar un archivo de configuración desde la nube, permitiendo al agente editarlo si es necesario.

Recomiendo usar GitHub para esto. A continuación se muestra un ejemplo de cómo leer un archivo de configuración remota. El agente tendrá una herramienta correspondiente para leer y modificar este archivo de configuración.

importar solicitudes de importación del sistema operativo importar yaml desde el cuadro importar cuadro # agregue esto a `train.py` GITHUB_RAW = ( "https://raw.githubusercontent.com/" "{owner}/{repo}/{ref}/{path}" ) def load_config_from_github(propietario, repositorio, ruta, ref="main", token=None): url = GITHUB_RAW.format(propietario=propietario, repo=repo, ref=ref, ruta=ruta) headers = {} if token: headers["Autorización"] = f"Portador {token}" r = request.get(url, headers=headers, timeout=10) r.raise_for_status() return Box(yaml.safe_load(r.text)) config = load_yaml_from_github(…) # usa parámetros en todo tu optimizador de script `train.py` = Adán(lr=config.lr)

También incluimos un servidor de verificación de estado para ejecutar junto con el proceso principal. Esto permite a los administradores de contenedores, como Kubernetes o su agente, monitorear el estado del trabajo sin inspeccionar los registros.

Si el estado del contenedor cambia inesperadamente, se puede reiniciar automáticamente. Esto simplifica la inspección del agente, ya que leer y resumir archivos de registro puede resultar más costoso en tokens que simplemente verificar el estado de un contenedor.

# health_server.py tiempo de importación desde pathlib import Ruta desde fastapi import FastAPI, aplicación de respuesta = FastAPI() HEARTBEAT = Path("/tmp/heartbeat") STATUS = Path("/tmp/status.json") # estado más rico opcional MAX_AGE = 300 # segundos def last_heartbeat_age(): si no HEARTBEAT.exists(): return float("inf") return time.time() – float(HEARTBEAT.read_text()) @app.get("/health") def health(): edad = last_heartbeat_age() # obsoleto -> el entrenamiento probablemente se bloqueó si edad > MAX_AGE: devuelve Respuesta("estancado", status_code=500) # opcional: detecta NaN o indicadores de error escritos por el entrenador si STATUS.exists() y "falló" en STATUS.read_text(): devuelve Respuesta("falló", status_code=500) return {"status": "ok", "heartbeat_age": edad}

Un pequeño script de shell, run.sh, que inicia el proceso health_server junto con train.py

#!/bin/bash # Inicie el servidor de verificación de estado en segundo plano python scripts/health_server.py & # Capture su PID si desea finalizar más tarde HEALTH_PID=$! # Inicie el script de entrenamiento principal python scripts/train.py

Y, por supuesto, nuestro Dockerfile, que se basa en la imagen base de NVIDIA para que su contenedor pueda usar el acelerador del host sin fricción. Este ejemplo es para Pytorch, pero simplemente puedes extenderlo a Jax o Tensorflow si es necesario.

DESDE nvidia/cuda:12.1.0-cudnn8-devel-ubuntu20.04 EJECUTE apt-get update && apt-get install -y python3 python3-pip git EJECUTE python3 -m pip install –upgrade pip # Instale PyTorch con soporte CUDA EJECUTE pip3 install torch torchvision torchaudio –extra-index-url https://download.pytorch.org/whl/cu121 WORKDIR /app COPIAR. /aplicación CMD ["sh", "run.sh"]

✅Estás en contenedores. Sencillo y minimalista.

Agregar un agente ligero

Hay muchos marcos de agentes para elegir. Para este agente, me gusta Langchain.

LangChain es un marco para construir sistemas basados ​​en LLM que combinan razonamiento y ejecución. Simplifica el encadenamiento de llamadas de modelos, la gestión de la memoria y la integración de capacidades externas para que su LLM pueda hacer más que generar texto.

En LangChain, las herramientas están definidas explícitamente y son funciones vinculadas a esquemas que el modelo puede llamar. Cada herramienta es una habilidad o tarea idempotente (por ejemplo, leer un archivo, consultar una API, modificar el estado).

Para que nuestro agente funcione, primero debemos definir las herramientas que puede utilizar para lograr nuestro objetivo.

Definiciones de herramientas

read_preferences Lee las preferencias del usuario y las notas del experimento de un documento de rebajas check_tensorboard Utiliza selenio con un controlador web de Chrome para realizar capturas de pantalla de métricas analyse_metric Utiliza razonamiento LLM multimodal para comprender lo que sucede en la captura de pantalla check_container_health Comprueba nuestro experimento en contenedores mediante una verificación de estado restart_container Reinicia el experimento si no está en buen estado o es necesario cambiar un hiperparámetro mod_config Modifica un archivo de configuración remota y se compromete con Github write_memory Escribe una cadena de acciones en una memoria persistente (rebaja)

Este conjunto de herramientas define los límites operativos de nuestro agente. Toda interacción con nuestro experimento a través de estas herramientas, haciendo que el comportamiento sea controlable y, con suerte, predecible.

En lugar de proporcionar estas herramientas en línea, aquí hay una esencia de github que contiene todas las herramientas descritas anteriormente. Puede conectarlos a su agente o modificarlos como mejor le parezca.

el agente

Para ser honesto, la primera vez que intenté asimilar la documentación oficial de Langchain, inmediatamente dejé de pensar en la idea.

Es demasiado detallado y más complejo de lo necesario. Si es nuevo en el mundo de los agentes o simplemente no quiere navegar por el laberinto que es la documentación de Langchain, continúe leyendo a continuación.

¿Langsmith? ¿Apartes al azar? ¿Pequeñas informaciones sobre herramientas por todas partes? Dejaré de atacar a este digno enemigo. Imaginado por Grok

En pocas palabras, así es como funcionan los agentes de Langchain:

Nuestro agente utiliza un mensaje para decidir qué hacer en cada paso.

Los pasos se crean dinámicamente completando el mensaje con el contexto actual y los resultados anteriores. Cada llamada de LLM [+ invocación de herramienta opcional] es un paso, y su salida alimenta el siguiente, formando una cadena.

Utilizando este bucle conceptualmente recursivo, el agente puede razonar y realizar la acción correcta prevista en todos los pasos requeridos. El número de pasos depende de la capacidad de razonamiento del agente y de la claridad con la que se define la condición de terminación.

Es una cadena Lang. ¿Consíguelo? 🤗

el aviso

Como se señaló, el mensaje es el pegamento recursivo que mantiene el contexto en todo el LLM y las invocaciones de herramientas. Verá marcadores de posición (definidos a continuación) utilizados cuando el agente se inicializa por primera vez.

Usamos un poco de las abstracciones de memoria integradas de LangChain, incluidas con cada llamada a la herramienta. Aparte de eso, el agente llena los vacíos y decide tanto el siguiente paso como a qué herramienta recurrir.

Para facilitar la lectura, el mensaje principal se encuentra a continuación. Puede conectarlo directamente al script del agente o cargarlo desde el sistema de archivos antes de ejecutarlo.

"Usted es un agente de automatización de experimentos responsable de monitorear y mantener los experimentos de aprendizaje automático. Contexto actual: {chat_history} Su flujo de trabajo: 1. Primero, lea las preferencias de preferencias.md para comprender los umbrales y la configuración. 2. Verifique TensorBoard en la URL especificada y capture una captura de pantalla. 3. Analice las métricas clave (pérdida de validación, pérdida de entrenamiento, precisión) de la captura de pantalla. 4. Verifique el estado del contenedor Docker para el contenedor de entrenamiento. 5. Tome acciones correctivas basadas en el análisis: – Reinicie contenedores en mal estado – Ajuste los hiperparámetros de acuerdo con las preferencias del usuario y los patrones anómalos, reiniciando el experimento si es necesario 6. Registre todas las observaciones y acciones en la memoria Pautas importantes: – Lea siempre las preferencias primero para obtener la configuración actual – Utilice el análisis visual para comprender las tendencias métricas – Sea conservador con los cambios de configuración (ajústelos solo si es claramente necesario) – Escriba entradas de memoria detalladas para referencia futura – Verifique el estado del contenedor antes y después de cualquier reinicio – Al modificar la configuración, use los valores apropiados de las preferencias Herramientas disponibles: {tool_names} Descripciones de herramientas: {tools} Tarea actual: {input} Piense paso a paso y utilice herramientas para completar el flujo de trabajo """

Ahora con aproximadamente 100 líneas, tenemos a nuestro agente. Se inicializa el agente, luego definimos una serie de pasos. Para cada paso, la directiva current_task se completa en nuestro mensaje y cada herramienta actualiza una instancia de memoria compartida ConverstationSummaryBufferMemory

Usaremos OpenAI para este agente; sin embargo, Langchain ofrece alternativas, incluido el alojamiento del suyo propio. Si el costo es un problema, existen modelos de código abierto que se pueden utilizar aquí.

importar sistema operativo desde datetime importar fecha y hora desde pathlib importar ruta desde langchain.agents importar AgentExecutor, create_react_agent desde langchain_openai importar ChatOpenAI desde langchain.prompts importar PromptTemplate desde langchain.memory importar ConversationSummaryBufferMemory # Importar herramientas desde tools.py desde herramientas importar (read_preferences, check_tensorboard, analyse_metric, check_container_health, restart_container, modificar_config, write_memory ) PROMPT=open("prompt.txt").read() clase ExperimentAutomation: def __init__(self, openai_key=None): """Inicializar el agente""" self.llm = ChatOpenAI( temperatura=0.8, model="gpt-4-turbo-preview", api_key=openai_key o os.getenv('OPENAI_API_KEY') ) # Inicializa la memoria para el contexto de conversación self.memory = ConversationSummaryBufferMemory( llm=self.llm, max_token_limit=32000, Memory_key="chat_history", return_messages=True ) def create_agent(self): """Crear agente LangChain con herramientas importadas""" tools = [ lambda **kwargs: read_preferences(memoria=self.memory, **kwargs), lambda **kwargs: check_tensorboard(memoria=self.memory, **kwargs), lambda **kwargs: analyse_metric(memoria=self.memory, **kwargs), lambda **kwargs: check_container_health(memoria=self.memory, **kwargs), lambda **kwargs: restart_container(memory=self.memory, **kwargs), lambda **kwargs: modifique_config(memory=self.memory, **kwargs), lambda **kwargs: write_memory(memory=self.memory, **kwargs) ] # Crear la plantilla de solicitud de aviso = PromptTemplate.from_template(PROMPT) agente = create_react_agent( llm=self.llm, herramientas=herramientas, solicitud=prompt) # Crear agente ejecutor con retorno de memoria AgentExecutor (agente=agente, herramientas=herramientas, memoria=self.memory, verbose=True, max_iterations=15, handle_parsing_errors=True, return_intermediate_steps=True) def run_automation_cycle(self): """Ejecutar el ciclo de automatización completo paso a paso step""" write_memory( Entry="Ciclo de automatización iniciado", categoría="SISTEMA", memoria=self.memory ) try: agent = self.create_agent() # Definir el flujo de trabajo como pasos individuales flujo de trabajo_steps = [ "Leer preferencias de preferencias.md para capturar umbrales y configuraciones", "Verificar TensorBoard en la URL especificada y capturar una captura de pantalla", "Analizar la pérdida de validación, la pérdida de entrenamiento y la precisión de la captura de pantalla", "Verificar el estado del contenedor Docker para el entrenamiento contenedor", "Reiniciar contenedores en mal estado si es necesario", "Ajustar los hiperparámetros según las preferencias y reiniciar el contenedor si es necesario", "Escribir todas las observaciones y acciones en la memoria" ] # Ejecutar cada paso individualmente para el paso en pasos_de_flujo de trabajo: resultado = agente.invoke({"input": paso}) # Escribir la salida del paso en la memoria if result.get("salida"): memoria_summary = f"Paso: {paso}nSalida: {resultado['output']}" write_memory(entry=memory_summary, categoría="STEP", memoria=self.memory) write_memory( entrada="Ciclo de automatización completado exitosamente", categoría="SISTEMA", memoria=self.memory ) devuelve el resultado excepto Excepción como e: error_msg = f"Falló el ciclo de automatización: {str(e)}" write_memory(entry=error_msg, categoría="ERROR", memoria=self.memory) elevar def principal(): intente: automatización = ExperimentAutomation(openai_key=os.environ["OPENAI_API_KEY"]) resultado = automatización.run_automation_cycle() if resultado.get('salida'): print(f"nSalida final:n{resultado['salida']}") if resultado.get('pasos_intermedios'): print(f"nPasos ejecutados: {len(resultado['intermediate_steps'])}") print("n ✓ Ciclo de automatización completado exitosamente") excepto excepción como e: print(f"n✗ Error de automatización: {e}") write_memory(entry=f"Fallo crítico: {str(e)}", categoría="ERROR") import sys sys.exit(1) if __name__ == "__main__": main()

Ahora que tenemos nuestro agente y nuestras herramientas, analicemos cómo expresamos realmente nuestra intención como investigador: la pieza más importante.

Definir comportamientos y preferencias con lenguaje natural.

Como se describió, definir lo que buscamos cuando iniciamos un experimento es vital para obtener el comportamiento correcto de un agente.

Aunque los modelos de razonamiento de imágenes han llegado bastante lejos y tienen bastante contexto, todavía les queda mucho camino por recorrer antes de poder comprender cómo se ve una buena curva de pérdida de políticas en la optimización de políticas jerárquicas, o cómo debería verse la perplejidad del libro de códigos en un codificador automático variacional cuantificado vectorial, algo que he estado optimizando durante la semana pasada.

Para ello, inicializamos cualquier razonamiento automatizado con preferencias.md.

Comencemos con algunas configuraciones generales.

# Preferencias del experimento Este archivo define mis preferencias para este experimento. El agente siempre debe leer esto primero antes de realizar cualquier acción. — ## Configuración general – nombre_experimento: vqvae – nombre_contenedor: vqvae-train – tensorboard_url: http://localhost:6006 – archivo_memoria: memoria.md – ajustes_máximo_por_ejecución: 4 — ## Más detalles Siempre puedes agregar más secciones aquí. La tarea read_preferences analizará y razonará cada sección.

Ahora, definamos métricas de interés. Esto es especialmente importante en el caso del razonamiento visual.

Dentro del documento de rebajas, defina bloques yaml que el agente analizará mediante la herramienta read_preferences. Agregar esta pequeña estructura es útil para usar las preferencias como argumentos para otras herramientas.

“`métricas de yaml: – nombre: patrón de perplejidad: debe permanecer alto durante el curso del entrenamiento condición_reinicio: colapso prematuro a cero hiperparámetros: | si colapsa, aumente `perplexity_weight` del valor actual a 0,2 – nombre: predict_loss patrón: debería disminuir durante el transcurso del entrenamiento restart_condition: aumenta o detiene los hiperparámetros: | si aumenta, aumente el valor `prediction_weight` de actual a 0,4 – nombre: patrón de uso del libro de códigos: debe permanecer fijo en > 90% condición_reinicio: cae por debajo del 90% durante muchas épocas hiperparámetros: | disminuya el parámetro `codebook_size` de 512 a 256. “`

La idea clave es que el archivo references.md debe proporcionar suficientes detalles estructurados y descriptivos para que el agente pueda:

Compare su análisis con su intención, por ejemplo, si el agente ve una pérdida de validación = 0,6 pero las preferencias dicen que val_loss_threshold debería ser 0,5, sabe cuál debería ser la acción correctiva.

Lea los umbrales y restricciones (YAML o valor-clave) para métricas, hiperparámetros y gestión de contenedores.

Comprenda la intención o los patrones de intención descritos en secciones legibles por humanos, como "ajuste la tasa de aprendizaje solo si la pérdida de validación excede el umbral y la precisión se está estancando".

Cableándolo todo junto

Ahora que tenemos un experimento en contenedores + un agente, debemos programar el agente. Esto es tan simple como ejecutar el proceso del agente mediante una tarea cron. Esto ejecuta nuestro agente una vez cada hora, lo que proporciona un equilibrio entre costo (en tokens) y eficiencia operativa.

0 * * * * /usr/bin/python3 /ruta/a/agent.py >> /var/log/agent.log 2>&1

Descubrí que este agente no necesita el último modelo de razonamiento y funciona bien con las generaciones anteriores de Anthropic y OpenAI.

Concluyendo

Si el tiempo de investigación es finito, debería dedicarse a la investigación, no a cuidar experimentos.

Su agente debe encargarse de la supervisión, los reinicios y los ajustes de parámetros sin supervisión constante. Cuando el obstáculo desaparece, lo que queda es el trabajo real: formular hipótesis, diseñar mejores modelos y probar ideas importantes.

Con suerte, este agente te liberará un poco para que puedas idear la próxima gran idea. Disfrutar.

Referencias

Müller, T., Smith, J. y Li, K. (2023). LangChain: un marco para desarrollar aplicaciones con grandes modelos de lenguaje. Repositorio de GitHub. https://github.com/hwchase17/langchain

OpenAI. (2023). Documentación de la API de OpenAI. https://platform.openai.com/docs