--- id: "0083" title: "imagegen — notebook 02 validacion cruzada diffusers vs sdcpp_python" status: pendiente type: feature domain: - imagegen scope: multi-app priority: alta depends: [] blocks: [] related: [] created: 2026-05-13 updated: 2026-05-17 tags: [] --- ## Objetivo Notebook `02_cross_validation.ipynb` que ejecuta los mismos `GenerationConfig` con los dos backends operativos (diffusers GPU + sdcpp_python CPU) sobre SD Turbo, genera grid lado-a-lado con `image_compare_side_by_side_py_ml` y decide cuales configs portan bien entre backends y cuales requieren ajuste. ## Contexto - Backend diffusers GPU operativo (Ola 3.A) — 192ms/imagen warm, VRAM 3097MB. - Backend sdcpp_python CPU operativo (Ola 3.B) — 27s/imagen 512x512 4 steps. - Funcion `image_compare_side_by_side_py_ml` lista (Ola 3.D) con grid + diff perceptual + pHash + pixel MSE. - Documento `Stack de generacion de imagenes` (raiz proyecto imagegen) dice: "Bit-exact entre backends es imposible. Aceptamos diff perceptual." ## Arquitectura Archivos NUEVOS: - `projects/imagegen/analysis/spike_diffusers_vs_sdcpp/notebooks/02_cross_validation.ipynb` - `~/vaults/imagegen_models/configs/cross_validated/*.json` — configs que pasan - `~/vaults/imagegen_models/outputs/cross/*.png` — grids A | diff | B NO se crean funciones nuevas — todo se compone de funciones existentes del registry. ## Tareas 1. Plan del notebook (declarar al usuario antes de escribirlo) 1.1. Titulo, objetivo, criterio PASS (pHash distance < umbral X, pixel_mse < Y) 1.2. Lista de celdas y output esperado por celda 2. Notebook 2.1. Celda hardware check + GPU info (reuse). 2.2. Definir 4 configs base (seeds 42, 123, 7, 999), SD Turbo, 1-step euler_a, 512x512. 2.3. Loop config: generar A=diffusers, B=sdcpp_python. 2.4. `image_compare_side_by_side(A, B, label_a="diffusers", label_b="sdcpp")` por par. 2.5. Tabla resumen: pHash distance, pixel MSE, duration_a, duration_b. 2.6. Veredicto por config: PASS si pHash<=N (a calibrar), FAIL si no. 2.7. Guardar grids comparativos a vault. 3. Ejecutar el notebook desde la sesion claude 3.1. Lanzar Jupyter si no esta arriba. 3.2. Ejecutar celdas 1..N via `jupyter_exec_py_notebook cell`. 3.3. Reportar veredicto por config. 4. Conclusion 4.1. Si todos los configs PASS → contrato `GenerationConfig` es portable. 4.2. Si alguno FAIL → documentar campo problematico (sampler, cfg_scale, ...) y abrir proposal de ajuste. ## Ejemplo de uso Output esperado al final: ``` seed=42 pHash_dist=12 pixel_mse=812.4 diffusers=189ms sdcpp=26200ms PASS seed=123 pHash_dist=14 pixel_mse=901.0 diffusers=192ms sdcpp=27100ms PASS seed=7 pHash_dist=11 pixel_mse=750.8 diffusers=187ms sdcpp=26800ms PASS seed=999 pHash_dist=18 pixel_mse=1102.3 diffusers=194ms sdcpp=27500ms PASS VEREDICTO GLOBAL: PASS (contrato portable) ``` ## Decisiones - **Umbrales pHash y MSE** se calibran en este notebook — no hay valor previo. Empezar con pHash<=20 (bastante permisivo), pixel_mse<=2000. - **`imagehash` puede no estar instalado** en el venv — `pip install imagehash` como primera celda si falta. - **Solo SD Turbo en este notebook** — modelos mayores (SDXL Turbo, FLUX) iran en notebooks separados cuando se descarguen. ## Prerequisitos - Backends 3.A + 3.B operativos (hechos). - SD Turbo en vault (hecho). - Jupyter del analysis levantado (script `run-jupyter-lab.sh`). ## Riesgos - sdcpp_python tarda ~27s por imagen en CPU → 4 imagenes x 2 backends = ~2 min de espera real, aceptable. - pHash de imagehash requiere instalar el paquete — documentar en cell 0. - Si el sampler de sd.cpp difiere demasiado del de diffusers (ej. trailing timesteps de SD Turbo), la diff sera grande aunque la implementacion sea OK.