---
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.
