Skip to content

roberto3554/TFG

Repository files navigation

TFG de Roberto Retamero Jiménez

Este trabajo estudia un sistema de IA autoevolutiva para generación y mejora de código, tomando como base OpenEvolve y complementándolo con OptiLLM para poder usar modelos locales o remotos a través de una API compatible con OpenAI.

La idea central trata de analizar un ciclo completo de investigación: generación, evaluación, retroalimentación, selección, mutación, checkpointing y comparación entre configuraciones. Eso permite estudiar qué decisiones de diseño funcionan mejor según el problema, el modelo y los hiperparámetros.

Qué contiene este repositorio

  • openevolve-main/: motor principal de evolución, evaluadores, ejemplos y configuración del sistema.
  • optillm-main/: proxy OpenAI-compatible para modelos locales o para usar técnicas de inferencia más avanzadas.
  • runner.py: orquesta una ejecución completa, levantando OptiLLM, lanzando OpenEvolve y notificando por Telegram.
  • recover_benchmark_logs.py: recupera logs de ejecuciones de benchmark y genera comandos SFTP o un fichero de reparación de configuración.
  • extract_metrics.py: resume métricas a partir de logs de ejecución.
  • resultados/: resultados consolidados de las campañas experimentales del TFG.

Visión general del sistema

La arquitectura combina varios componentes que colaboran en bucle:

  1. OpenEvolve carga un programa inicial y un evaluador.
  2. Un PromptSampler construye el prompt con programas top, programas diversos y artefactos de ejecuciones previas.
  3. Un LLMEnsemble genera candidatos con uno o varios modelos ponderados.
  4. El Evaluator ejecuta el programa, impone timeouts y devuelve métricas y artefactos.
  5. ProgramDatabase almacena programas, puntuaciones, linaje, islas, archivo de élite y el mejor programa global.
  6. El controlador paralelo coordina la evaluación y el guardado de checkpoints.

El sistema hace una búsqueda iterativa guiada por resultados reales de ejecución. Eso es lo que lo acerca a la línea de trabajo de sistemas como AlphaEvolve.

Estructura del código

openevolve-main/openevolve/

  • controller.py: orquesta la evolución completa.
  • database.py: almacén de programas, selección, archivo y soporte de islas.
  • evaluator.py: interfaz de evaluación de programas.
  • config.py: carga y valida configuración desde YAML.
  • iteration.py: lógica asociada a cada iteración evolutiva.
  • llm/: clientes y ensambles de modelos.
  • prompt/: generación de prompts y plantillas.
  • threaded_parallel.py: ejecución paralela y coordinación.
  • utils/: utilidades de código, formato y métricas.

openevolve-main/examples/

Contiene problemas de referencia y benchmarks reales, entre ellos:

  • function_minimization
  • circle_packing
  • alphaevolve_math_problems/sums_diffs_finite_sets
  • alphaevolve_math_problems/heilbronn_triangle
  • alphaevolve_math_problems/minimizing_max_min_dist/2
  • alphaevolve_math_problems/minimizing_max_min_dist/3
  • alphaevolve_math_problems/erdos_min_overlap
  • alphaevolve_math_problems/second_autocorr_ineq

resultados/

Aquí se almacenan las campañas del TFG, separadas por ejecución y por problema/modelo. Dentro de cada ejecución aparecen:

  • logs: trazas completas de la ejecución.
  • iteraciones.csv: recultado de procesar los logs para extraer distintas metricas.

Ejecuciones

El flujo de una ejecución es este:

  1. Se define un programa inicial con una zona evolucionable marcada por comentarios # EVOLVE-BLOCK-START y # EVOLVE-BLOCK-END.
  2. Se implementa un evaluador que ejecuta ese programa y devuelve métricas objetivas.
  3. OpenEvolve crea la población inicial y evalúa el programa base.
  4. El sistema selecciona padres e inspiraciones a partir de la base de datos interna.
  5. El LLM propone una variante del código.
  6. El evaluador la ejecuta y devuelve puntuaciones, errores y artefactos.
  7. El sistema actualiza la base de datos, conserva el mejor programa y genera checkpoints.
  8. Se comparan resultados entre iteraciones, configuraciones y modelos.

Cada decisión de diseño puede medirse en términos de rendimiento, robustez, estabilidad y coste computacional.

Requisitos prácticos

Para trabajar con el proyecto conviene tener:

  • Python 3.9 o superior.
  • Un entorno virtual dedicado.
  • Acceso a una API compatible con OpenAI, ya sea remota o local.
  • Opcionalmente, un servidor OptiLLM si se quiere usar modelos locales o combinar técnicas de inferencia.

Instalación rápida

Una forma de preparar el entorno es:

python3 -m venv .venv
source .venv/bin/activate
pip install -r openevolve-main/requirements.txt
pip install -r optillm-main/requirements.txt

Si prefieres instalar cada subproyecto en modo editable, puedes hacerlo desde cada carpeta:

cd openevolve-main
pip install -e .

cd ../optillm-main
pip install -e .

Ejemplo de ejecución con un problema real

Un ejemplo reproducible y fácil de entender es function_minimization:

cd openevolve-main
source ../.venv/bin/activate
export OPENAI_API_KEY="sk-no-key"

python openevolve-run.py \
  examples/function_minimization/initial_program.py \
  examples/function_minimization/evaluator.py \
  --config examples/function_minimization/config.yaml \
  --iterations 10

Si estás usando un proxy local con OptiLLM, la configuración del problema debe apuntar a la API del proxy:

llm:
  api_key: "sk-no-key"
  api_base: "http://127.0.0.1:8000/v1"

El mismo patrón se aplica a otros benchmarks: cambias initial_program.py, evaluator.py y el config.yaml del problema.

Uso de OptiLLM

OptiLLM actúa como proxy compatible con OpenAI. En este TFG es importante porque permite que OpenEvolve trabaje con modelos locales o con estrategias de inferencia más sofisticadas sin tener que modificar el núcleo evolutivo.

Ejemplo con un backend local tipo Ollama:

cd optillm-main
source ../.venv/bin/activate
python optillm.py --base_url http://localhost:11434/v1

Uso de OpenEvolve

El punto de entrada principal es openevolve-run.py, que llama a la CLI del paquete openevolve.

Opciones relevantes:

  • --config: archivo YAML con hiperparámetros y modelos.
  • --iterations: número máximo de iteraciones.
  • --checkpoint: reanudación desde un checkpoint previo.
  • --api-base, --primary-model, --secondary-model: sobrescrituras rápidas desde línea de comandos.

También existe soporte para reanudar una ejecución guardada:

python openevolve-run.py \
  examples/function_minimization/initial_program.py \
  examples/function_minimization/evaluator.py \
  --checkpoint examples/function_minimization/openevolve_output/checkpoints/checkpoint_50 \
  --iterations 50

runner.py: ejecución completa del benchmark

runner.py automatiza la campaña experimental completa:

  • lanza OptiLLM en segundo plano;
  • arranca OpenEvolve con la configuración elegida;
  • controla PIDs y procesos auxiliares;
  • registra logs separados por ejecución;
  • envía notificaciones por Telegram;
  • permite consultar estado, logs, errores, mejor solución y checkpoints desde Telegram.

Entre los comandos soportados en el bot están /status, /log, /errores, /best, /checkpoint, /code, /optillm y /stop.

recover_benchmark_logs.py

Este script está pensado para consolidar campañas largas desde una máquina remota o un servidor de experimentación.

Hace varias cosas útiles:

  • detecta logs válidos de OpenEvolve dentro de examples/;
  • infiere qué problema y qué combinación de modelos hay detrás de cada log;
  • valida que la ejecución tenga un inicio y un cierre coherentes;
  • genera un comando sftp para descargar automáticamente los ficheros;
  • puede crear una versión de configuración reparada para ejecutar de nuevo sólo lo problemático.

extract_metrics.py

Resume logs por modelo y problema, calculando métricas como:

  • tiempo total acumulado;
  • número de mejores soluciones encontradas;
  • número de errores;
  • número de iteraciones completadas;
  • tiempo medio por iteración;
  • mejor puntuación observada.

Es útil para comparar ejecuiones y construir tablas para memoria, defensa o capítulo de resultados.

openevolve-main/parser.py

Este script toma logs de OpenEvolve desde la entrada estándar y los transforma en un CSV de iteraciones y métricas.

Su utilidad principal es convertir la salida textual de las ejecuciones en un formato más cómodo para análisis posterior.

Hace lo siguiente:

  • detecta la iteración actual a partir de líneas que contienen Iteration;
  • extrae el bloque Metrics: de cada iteración;
  • separa pares clave-valor como score=... o error=...;
  • añade campos auxiliares como has_error y error_msg;
  • genera un CSV ordenado por iteración.

Uso:

cd openevolve-main
cat logs/openevolve_YYYYMMDD_HHMMSS.log | python parser.py --outdir resultados --outfile iteraciones.csv

Es especialmente útil cuando se quiere comparar muchas ejecuciones.

run_parser_on_results.py

Este script automatiza la ejecución de parser.py sobre todos los logs contenidos en una carpeta de resultados (por ejemplo, dentro de resultados/Segunda ejecución).

Recorre recursivamente el directorio indicado, encuentra todos los subdirectorios que contengan archivos .log, los ordena por nombre y genera los CSVs correspondientes junto a cada log, siguiendo la convención de nombres utilizada en el repositorio.

Además, realiza una validación ligera tras generar cada CSV: cuenta el número de líneas del fichero y muestra una advertencia si el CSV contiene una o cero líneas (es decir, solo cabecera o vacío). Esto suele indicar que el log original no contenía métricas de iteración parseables (por ejemplo, porque la ejecución falló o hubo errores en las llamadas al LLM).

Uso:

python run_parser_on_results.py "resultados/Segunda ejecución"

Opciones disponibles:

  • --dry-run: muestra qué archivos se generarían sin ejecutar realmente el parser.
  • --parser-script: ruta alternativa al script parser.py de OpenEvolve.

Convención de nombres de salida:

El script distingue según el nombre del problema:

  • Para circle_packingprimera_fase.csv, segunda_fase.csv
  • Para minimazing_max_min_dist_2 y minimazing_max_min_dist_3primera_mitad.csv, segunda_mitad.csv
  • Para el resto de problemas → iteraciones.csv

Si hay más logs de los que hay nombres predefinidos, genera automáticamente nombres como iteraciones_2.csv, iteraciones_3.csv, etc.

Ejemplo de salida:

[OK] resultados/Segunda ejecución/circle_packing/qwen-coder/logs/openevolve_20250320_120000.log -> resultados/Segunda ejecución/circle_packing/qwen-coder/primera_fase.csv (42 lines)
[WARN] El CSV resultados/Segunda ejecución/function_minimization/llama3/iteraciones.csv contiene 1 líneas. El log puede no contener iteraciones parseables.
[DONE] Procesados 12 logs en resultados/Segunda ejecución

parse_metrics.py

Este script actúa como un filtro de líneas sobre la salida de ejecuciones o logs, extrayendo únicamente las filas de métricas con formato tabular y transformándolas a un formato más sencillo y consistente.

Está pensado para procesar directamente la salida de extract_metrics.

Funcionamiento: El script lee desde la entrada estándar línea por línea y:

  1. Detecta líneas que contienen el carácter | (separador de tablas).
  2. Descarta líneas de separadores (---, ===) y cabeceras (líneas con PROBLEM o TIME).
  3. Valida que la línea tenga al menos 7 columnas.
  4. Comprueba que el campo de tiempo tenga formato hh:mm:ss.
  5. Extrae: tiempo, mejor puntuación, mejores soluciones encontradas, errores, iteraciones y tiempo medio.
  6. Convierte los puntos decimales a comas (formato europeo).
  7. Añade la letra s al tiempo medio si no está presente.
  8. Imprime las líneas resultantes separadas por tabuladores (\t).

Uso:

# Desde la salida de un analisis
python extract_metrics.py ... | python parse_metrics.py

# Redirigir a un fichero
python extract_metrics.py ... | python parse_metrics.py > metricas_resumidas.txt

Formato de entrada esperado:

| PROBLEM              | TIME     | BEST SCORE | #BETTER SOLS | #ERRORS | ITERS | AVG TIME |
|----------------------|----------|------------|--------------|---------|-------|----------|
| circle_packing       | 00:05:23 | 0.8742     | 12           | 3       | 50    | 6.47s    |

Formato de salida generado:

00:05:23	0,8742	12	3	50	6,47s

Cada campo está separado por tabulador, lo que facilita su importación en hojas de cálculo o su procesamiento posterior con herramientas como awk, cut o scripts de análisis.

Configuraciones y modelos

El proyecto trabaja con varios modelos y combinaciones:

  • qwen-coder
  • llama3
  • mistral-small
  • deepseek-coder
  • qwen-math

Y también ensambles como:

  • qwen-coder + qwen-math
  • qwen-coder + deepseek-coder
  • deepseek-coder + mistral-small

La parte importante no es sólo qué modelo se usa, sino cómo se combinan las decisiones: temperatura, pesos del ensamble, tamaño de población, intervalos de checkpoint, tolerancia a fallos y selección de programas de referencia.

Configuración del sistema

Las opciones globales se concentran en openevolve-main/configs/default_config.yaml y en archivos específicos de cada problema.

Algunos parámetros relevantes:

  • max_iterations: número máximo de iteraciones.
  • checkpoint_interval: frecuencia de guardado.
  • random_seed: reproducibilidad.
  • llm.models: modelos usados para evolución.
  • database.num_islands: particionado de la población.
  • database.feature_dimensions: dimensiones del esquema tipo MAP-Elites.
  • evaluator.timeout: límite de tiempo por evaluación.
  • evaluator.cascade_evaluation: evaluación por etapas.

Cómo adaptar el sistema a un problema nuevo

Para crear un nuevo benchmark o adaptar uno existente:

  1. Define un initial_program.py con la parte evolucionable delimitada.
  2. Implementa un evaluator.py que exponga evaluate(program_path).
  3. Crea un config.yaml con el modelo, los timeouts y los hiperparámetros.
  4. Lanza OpenEvolve sobre ese directorio.
  5. Analiza checkpoints, logs y métricas para comparar variantes.

Referencias

About

TFG en Ingeniería Informática con mención en Computación y sistemas inteligentes

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors