Manuela Larrea commited on
Commit
29099e4
·
1 Parent(s): b481d58

Initial commit: GAN Interactive Demo

Browse files
DEPLOYMENT_GUIDE.md ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚀 Guía de Deployment en Hugging Face Spaces
2
+
3
+ ## Opción 1: Deployment Automático (Recomendado)
4
+
5
+ ### Paso 1: Crear cuenta en Hugging Face
6
+ 1. Ve a https://huggingface.co/join
7
+ 2. Crea una cuenta gratuita
8
+ 3. Verifica tu email
9
+
10
+ ### Paso 2: Crear un nuevo Space
11
+ 1. Ve a https://huggingface.co/new-space
12
+ 2. Configura tu Space:
13
+ - **Owner**: Tu usuario
14
+ - **Space name**: `gan-interactive-demo` (o el nombre que prefieras)
15
+ - **License**: MIT
16
+ - **Select the Space SDK**: Gradio
17
+ - **Space hardware**: CPU basic (gratuito)
18
+ - **Visibility**: Public
19
+
20
+ 3. Haz clic en "Create Space"
21
+
22
+ ### Paso 3: Subir archivos
23
+ Hay dos formas de subir los archivos:
24
+
25
+ #### Método A: Interfaz Web (Más fácil)
26
+ 1. En tu Space recién creado, haz clic en "Files" → "Add file" → "Upload files"
27
+ 2. Arrastra y suelta estos archivos:
28
+ - `app.py`
29
+ - `requirements.txt`
30
+ - `README.md`
31
+ - Carpeta `models/` completa (con generator.h5, discriminator.h5, etc.)
32
+
33
+ #### Método B: Git (Más profesional)
34
+ ```bash
35
+ # Clonar el repositorio del Space
36
+ git clone https://huggingface.co/spaces/TU_USUARIO/gan-interactive-demo
37
+ cd gan-interactive-demo
38
+
39
+ # Copiar archivos
40
+ cp /home/ubuntu/gan_interactive_demo/app.py .
41
+ cp /home/ubuntu/gan_interactive_demo/requirements.txt .
42
+ cp /home/ubuntu/gan_interactive_demo/README.md .
43
+ cp -r /home/ubuntu/gan_interactive_demo/models .
44
+
45
+ # Commit y push
46
+ git add .
47
+ git commit -m "Initial commit: GAN Interactive Demo"
48
+ git push
49
+ ```
50
+
51
+ ### Paso 4: Esperar el build
52
+ - Hugging Face Spaces automáticamente detectará los archivos
53
+ - Instalará las dependencias de `requirements.txt`
54
+ - Lanzará la aplicación `app.py`
55
+ - El proceso toma ~2-3 minutos
56
+
57
+ ### Paso 5: ¡Listo!
58
+ Tu aplicación estará disponible en:
59
+ `https://huggingface.co/spaces/TU_USUARIO/gan-interactive-demo`
60
+
61
+ ---
62
+
63
+ ## Opción 2: Deployment Local para Pruebas
64
+
65
+ ### Requisitos
66
+ ```bash
67
+ pip install -r requirements.txt
68
+ ```
69
+
70
+ ### Ejecutar localmente
71
+ ```bash
72
+ python app.py
73
+ ```
74
+
75
+ La aplicación estará disponible en: `http://localhost:7860`
76
+
77
+ ---
78
+
79
+ ## Opción 3: Usar Hugging Face CLI
80
+
81
+ ### Instalar CLI
82
+ ```bash
83
+ pip install huggingface_hub
84
+ ```
85
+
86
+ ### Login
87
+ ```bash
88
+ huggingface-cli login
89
+ ```
90
+
91
+ ### Crear y subir Space
92
+ ```bash
93
+ cd /home/ubuntu/gan_interactive_demo
94
+
95
+ # Crear Space
96
+ huggingface-cli repo create gan-interactive-demo --type space --space_sdk gradio
97
+
98
+ # Subir archivos
99
+ huggingface-cli upload gan-interactive-demo . --repo-type space
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Troubleshooting
105
+
106
+ ### Error: "No module named 'tensorflow'"
107
+ - Asegúrate de que `requirements.txt` esté en el directorio raíz
108
+ - Verifica que incluya `tensorflow==2.15.0`
109
+
110
+ ### Error: "Cannot load model"
111
+ - Verifica que la carpeta `models/` esté subida correctamente
112
+ - Asegúrate de que contenga:
113
+ - `generator.h5`
114
+ - `discriminator.h5`
115
+ - `latent_vectors.npy`
116
+ - `generated_images.npy`
117
+
118
+ ### La aplicación es muy lenta
119
+ - Considera usar un Space con GPU (requiere suscripción)
120
+ - O reduce el número de vectores latentes pre-calculados en el código
121
+
122
+ ### Error de memoria
123
+ - Reduce `BATCH_SIZE` en el código de entrenamiento
124
+ - Usa menos vectores latentes para visualización (de 1000 a 500)
125
+
126
+ ---
127
+
128
+ ## Configuración Avanzada
129
+
130
+ ### Usar GPU en Hugging Face Spaces
131
+ 1. Ve a Settings de tu Space
132
+ 2. Cambia "Space hardware" a "T4 small" o superior
133
+ 3. Nota: Requiere suscripción PRO ($9/mes)
134
+
135
+ ### Personalizar la interfaz
136
+ Edita `app.py` y modifica:
137
+ - `custom_css`: Para cambiar estilos
138
+ - `theme=gr.themes.Soft()`: Prueba otros temas como `Base()`, `Glass()`, `Monochrome()`
139
+ - Añade más tabs con `with gr.Tab("Nombre"):`
140
+
141
+ ### Optimizar rendimiento
142
+ ```python
143
+ # En app.py, añade cache
144
+ @functools.lru_cache(maxsize=100)
145
+ def generate_from_latent_index(index):
146
+ # ... código ...
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Recursos Adicionales
152
+
153
+ - **Documentación de Gradio**: https://gradio.app/docs/
154
+ - **Hugging Face Spaces Docs**: https://huggingface.co/docs/hub/spaces
155
+ - **Ejemplos de Spaces**: https://huggingface.co/spaces
156
+
157
+ ---
158
+
159
+ ## Compartir con tus Estudiantes
160
+
161
+ Una vez desplegado, simplemente comparte el URL:
162
+ ```
163
+ https://huggingface.co/spaces/TU_USUARIO/gan-interactive-demo
164
+ ```
165
+
166
+ Tus estudiantes podrán:
167
+ - ✅ Acceder sin necesidad de cuenta
168
+ - ✅ Usar la aplicación sin instalar nada
169
+ - ✅ Experimentar con la GAN en tiempo real
170
+ - ✅ Ver el código fuente (si el Space es público)
171
+
172
+ ---
173
+
174
+ ## Para la Clase
175
+
176
+ ### Antes de la clase:
177
+ 1. Despliega la aplicación
178
+ 2. Prueba que funcione correctamente
179
+ 3. Ten el URL listo para compartir
180
+
181
+ ### Durante la clase:
182
+ 1. Proyecta la aplicación
183
+ 2. Demuestra cada tab interactivamente
184
+ 3. Deja que los estudiantes experimenten desde sus dispositivos
185
+ 4. Usa la visualización del espacio latente como "momento wow"
186
+
187
+ ### Después de la clase:
188
+ - Los estudiantes pueden seguir experimentando
189
+ - Pueden clonar el Space para su proyecto final
190
+ - Pueden modificar el código para sus propias GANs
191
+
192
+ ---
193
+
194
+ ¡Buena suerte con tu clase! 🎓✨
195
+
README.md CHANGED
@@ -1,13 +1,117 @@
1
  ---
2
- title: Gan Interactive Dem
3
- emoji: 🏃
4
- colorFrom: blue
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: GAN Interactive Demo - MNIST
3
+ emoji: 🎨
4
+ colorFrom: purple
5
+ colorTo: pink
6
  sdk: gradio
7
+ sdk_version: 4.44.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
  ---
12
 
13
+ # 🎨 GAN Interactive Demo - Exploración del Espacio Latente
14
+
15
+ Una aplicación interactiva para explorar cómo funcionan las **Redes Generativas Adversarias (GANs)** entrenadas en el dataset MNIST de dígitos manuscritos.
16
+
17
+ ## 🌟 Características
18
+
19
+ ### 1. Generación Aleatoria
20
+ Genera dígitos manuscritos desde vectores de ruido aleatorio con un solo clic.
21
+
22
+ ### 2. Control Manual
23
+ Ajusta las primeras 10 dimensiones del vector latente (de 100 dimensiones totales) usando sliders interactivos para ver cómo cada dimensión afecta la generación.
24
+
25
+ ### 3. Interpolación
26
+ Observa el **morphing suave** entre dos dígitos diferentes. Esto demuestra que el espacio latente aprendido por la GAN es continuo y significativo.
27
+
28
+ ### 4. Visualización del Espacio Latente
29
+ Inspirado en el **TensorFlow Projector**, esta sección te permite:
30
+ - Visualizar el espacio latente de 100 dimensiones reducido a 3D usando **PCA**
31
+ - Explorar agrupaciones usando **t-SNE** en 2D
32
+ - Generar dígitos desde puntos específicos del espacio
33
+
34
+ ### 5. Grid de Comparación
35
+ Genera múltiples dígitos simultáneamente para observar la diversidad y calidad de las generaciones.
36
+
37
+ ## 🏗️ Arquitectura
38
+
39
+ ### Generador
40
+ ```
41
+ Input: Vector latente (100D) ~ N(0,1)
42
+
43
+ Dense (7×7×256) + BatchNorm + LeakyReLU
44
+
45
+ Reshape (7, 7, 256)
46
+
47
+ Conv2DTranspose (7×7×128) + BatchNorm + LeakyReLU
48
+
49
+ Conv2DTranspose (14×14×64) + BatchNorm + LeakyReLU
50
+
51
+ Conv2DTranspose (28×28×1) + Tanh
52
+
53
+ Output: Imagen (28×28×1) en rango [-1, 1]
54
+ ```
55
+
56
+ ### Discriminador
57
+ ```
58
+ Input: Imagen (28×28×1)
59
+
60
+ Conv2D (14×14×64) + LeakyReLU + Dropout(0.3)
61
+
62
+ Conv2D (7×7×128) + LeakyReLU + Dropout(0.3)
63
+
64
+ Flatten + Dense(1)
65
+
66
+ Output: Logit (clasificación binaria: real/falso)
67
+ ```
68
+
69
+ ## 📊 Entrenamiento
70
+
71
+ - **Dataset**: MNIST (60,000 imágenes de entrenamiento)
72
+ - **Épocas**: 50
73
+ - **Batch Size**: 256
74
+ - **Optimizer**: Adam (learning rate = 1e-4)
75
+ - **Loss**: Binary Cross-Entropy
76
+ - **Tiempo de entrenamiento**: ~20 minutos en CPU
77
+
78
+ ## 🎓 Propósito Educativo
79
+
80
+ Esta demo fue creada para una clase de Machine Learning para:
81
+ 1. Demostrar visualmente cómo las GANs aprenden distribuciones de datos
82
+ 2. Mostrar que el espacio latente es continuo y navegable
83
+ 3. Permitir experimentación interactiva con los conceptos
84
+ 4. Inspirar a los estudiantes para su proyecto final de GANs
85
+
86
+ ## 🚀 Uso Local
87
+
88
+ ```bash
89
+ # Clonar el repositorio
90
+ git clone https://huggingface.co/spaces/[username]/gan-interactive-demo
91
+ cd gan-interactive-demo
92
+
93
+ # Instalar dependencias
94
+ pip install -r requirements.txt
95
+
96
+ # Ejecutar la aplicación
97
+ python app.py
98
+ ```
99
+
100
+ ## 📚 Referencias
101
+
102
+ - **Paper Original de GANs**: [Generative Adversarial Networks](https://arxiv.org/abs/1406.2661) (Goodfellow et al., 2014)
103
+ - **DCGAN**: [Unsupervised Representation Learning with Deep Convolutional GANs](https://arxiv.org/abs/1511.06434) (Radford et al., 2015)
104
+ - **GAN Lab**: [Understanding Complex Deep Generative Models](https://poloclub.github.io/ganlab/)
105
+
106
+ ## 📝 Licencia
107
+
108
+ MIT License - Siéntete libre de usar este código para propósitos educativos.
109
+
110
+ ## 🤝 Contribuciones
111
+
112
+ ¡Contribuciones, issues y sugerencias son bienvenidas!
113
+
114
+ ---
115
+
116
+ **Creado con ❤️ para la clase de Machine Learning**
117
+
app.py ADDED
@@ -0,0 +1,446 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GAN Interactive Demo - Aplicación Gradio
3
+ Visualización interactiva del espacio latente y generación de dígitos MNIST
4
+ """
5
+ import gradio as gr
6
+ import tensorflow as tf
7
+ from tensorflow import keras
8
+ import numpy as np
9
+ import matplotlib.pyplot as plt
10
+ from sklearn.decomposition import PCA
11
+ from sklearn.manifold import TSNE
12
+ import plotly.graph_objects as go
13
+ import plotly.express as px
14
+ from PIL import Image
15
+ import io
16
+ import os
17
+
18
+ # Configuración
19
+ LATENT_DIM = 100
20
+ MODEL_DIR = "models"
21
+
22
+ # Cargar el generador
23
+ print("Cargando modelo generador...")
24
+ try:
25
+ generator = keras.models.load_model(f'{MODEL_DIR}/generator.h5', compile=False)
26
+ print("✓ Generador cargado exitosamente")
27
+ except Exception as e:
28
+ print(f"Error cargando generador: {e}")
29
+ generator = None
30
+
31
+ # Cargar vectores latentes pre-generados para exploración
32
+ try:
33
+ latent_vectors = np.load(f'{MODEL_DIR}/latent_vectors.npy')
34
+ generated_images_cache = np.load(f'{MODEL_DIR}/generated_images.npy')
35
+ print(f"✓ Vectores latentes cargados: {latent_vectors.shape}")
36
+ except Exception as e:
37
+ print(f"Generando nuevos vectores latentes...")
38
+ latent_vectors = np.random.normal(0, 1, (1000, LATENT_DIM))
39
+ if generator:
40
+ generated_images_cache = generator(latent_vectors, training=False).numpy()
41
+ else:
42
+ generated_images_cache = None
43
+
44
+ # Calcular reducción dimensional para visualización
45
+ print("Calculando reducción dimensional...")
46
+ pca = PCA(n_components=3)
47
+ latent_pca = pca.fit_transform(latent_vectors)
48
+
49
+ tsne = TSNE(n_components=2, random_state=42, perplexity=30)
50
+ latent_tsne = tsne.fit_transform(latent_vectors[:500]) # Usar subset para velocidad
51
+
52
+ print("✓ Aplicación lista")
53
+
54
+ # ==================== FUNCIONES DE GENERACIÓN ====================
55
+
56
+ def generate_random_digit():
57
+ """Genera un dígito aleatorio desde un vector latente random"""
58
+ if generator is None:
59
+ return None, "Modelo no disponible"
60
+
61
+ # Generar vector latente aleatorio
62
+ latent_vector = np.random.normal(0, 1, (1, LATENT_DIM))
63
+
64
+ # Generar imagen
65
+ generated_image = generator(latent_vector, training=False)
66
+ image = generated_image[0, :, :, 0].numpy()
67
+
68
+ # Desnormalizar
69
+ image = (image * 127.5 + 127.5).astype(np.uint8)
70
+
71
+ return image, f"Vector latente: {latent_vector[0, :5]}... (primeros 5 valores)"
72
+
73
+ def generate_from_sliders(*slider_values):
74
+ """Genera un dígito desde valores de sliders (primeras 10 dimensiones)"""
75
+ if generator is None:
76
+ return None, "Modelo no disponible"
77
+
78
+ # Crear vector latente: primeras 10 dimensiones desde sliders, resto aleatorio
79
+ latent_vector = np.random.normal(0, 1, (1, LATENT_DIM))
80
+ latent_vector[0, :10] = slider_values
81
+
82
+ # Generar imagen
83
+ generated_image = generator(latent_vector, training=False)
84
+ image = generated_image[0, :, :, 0].numpy()
85
+
86
+ # Desnormalizar
87
+ image = (image * 127.5 + 127.5).astype(np.uint8)
88
+
89
+ return image
90
+
91
+ def interpolate_digits(start_seed, end_seed, steps):
92
+ """Interpola entre dos dígitos generados desde semillas"""
93
+ if generator is None:
94
+ return None
95
+
96
+ # Generar vectores latentes desde semillas
97
+ np.random.seed(int(start_seed))
98
+ latent_start = np.random.normal(0, 1, (1, LATENT_DIM))
99
+
100
+ np.random.seed(int(end_seed))
101
+ latent_end = np.random.normal(0, 1, (1, LATENT_DIM))
102
+
103
+ # Crear interpolación lineal
104
+ alphas = np.linspace(0, 1, int(steps))
105
+
106
+ # Generar imágenes interpoladas
107
+ images = []
108
+ for alpha in alphas:
109
+ latent_interp = (1 - alpha) * latent_start + alpha * latent_end
110
+ generated = generator(latent_interp, training=False)
111
+ image = generated[0, :, :, 0].numpy()
112
+ image = (image * 127.5 + 127.5).astype(np.uint8)
113
+ images.append(image)
114
+
115
+ # Crear grid de imágenes
116
+ n_images = len(images)
117
+ cols = min(10, n_images)
118
+ rows = (n_images + cols - 1) // cols
119
+
120
+ fig, axes = plt.subplots(rows, cols, figsize=(cols * 1.5, rows * 1.5))
121
+ if rows == 1:
122
+ axes = axes.reshape(1, -1)
123
+
124
+ for idx, image in enumerate(images):
125
+ row = idx // cols
126
+ col = idx % cols
127
+ axes[row, col].imshow(image, cmap='gray')
128
+ axes[row, col].axis('off')
129
+ axes[row, col].set_title(f'{idx+1}', fontsize=8)
130
+
131
+ # Ocultar ejes vacíos
132
+ for idx in range(n_images, rows * cols):
133
+ row = idx // cols
134
+ col = idx % cols
135
+ axes[row, col].axis('off')
136
+
137
+ plt.tight_layout()
138
+
139
+ # Convertir a imagen
140
+ buf = io.BytesIO()
141
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
142
+ buf.seek(0)
143
+ plt.close()
144
+
145
+ return Image.open(buf)
146
+
147
+ def visualize_latent_space_pca():
148
+ """Visualiza el espacio latente en 3D usando PCA"""
149
+ fig = go.Figure(data=[go.Scatter3d(
150
+ x=latent_pca[:, 0],
151
+ y=latent_pca[:, 1],
152
+ z=latent_pca[:, 2],
153
+ mode='markers',
154
+ marker=dict(
155
+ size=3,
156
+ color=latent_pca[:, 2],
157
+ colorscale='Viridis',
158
+ showscale=True,
159
+ colorbar=dict(title="PC3"),
160
+ opacity=0.7
161
+ ),
162
+ text=[f'Punto {i}' for i in range(len(latent_pca))],
163
+ hovertemplate='<b>Punto %{text}</b><br>PC1: %{x:.2f}<br>PC2: %{y:.2f}<br>PC3: %{z:.2f}<extra></extra>'
164
+ )])
165
+
166
+ fig.update_layout(
167
+ title='Espacio Latente - Visualización PCA 3D',
168
+ scene=dict(
169
+ xaxis_title='Componente Principal 1',
170
+ yaxis_title='Componente Principal 2',
171
+ zaxis_title='Componente Principal 3',
172
+ bgcolor='rgba(240, 240, 240, 0.9)'
173
+ ),
174
+ width=800,
175
+ height=600,
176
+ showlegend=False
177
+ )
178
+
179
+ return fig
180
+
181
+ def visualize_latent_space_tsne():
182
+ """Visualiza el espacio latente en 2D usando t-SNE"""
183
+ fig = go.Figure(data=[go.Scatter(
184
+ x=latent_tsne[:, 0],
185
+ y=latent_tsne[:, 1],
186
+ mode='markers',
187
+ marker=dict(
188
+ size=6,
189
+ color=np.arange(len(latent_tsne)),
190
+ colorscale='Plasma',
191
+ showscale=True,
192
+ colorbar=dict(title="Índice"),
193
+ opacity=0.7
194
+ ),
195
+ text=[f'Punto {i}' for i in range(len(latent_tsne))],
196
+ hovertemplate='<b>Punto %{text}</b><br>t-SNE 1: %{x:.2f}<br>t-SNE 2: %{y:.2f}<extra></extra>'
197
+ )])
198
+
199
+ fig.update_layout(
200
+ title='Espacio Latente - Visualización t-SNE 2D',
201
+ xaxis_title='Dimensión t-SNE 1',
202
+ yaxis_title='Dimensión t-SNE 2',
203
+ width=800,
204
+ height=600,
205
+ plot_bgcolor='rgba(240, 240, 240, 0.9)'
206
+ )
207
+
208
+ return fig
209
+
210
+ def generate_from_latent_index(index):
211
+ """Genera imagen desde un índice del espacio latente pre-calculado"""
212
+ if generated_images_cache is None:
213
+ return None, "Cache no disponible"
214
+
215
+ index = int(index) % len(generated_images_cache)
216
+ image = generated_images_cache[index, :, :, 0]
217
+ image = (image * 127.5 + 127.5).astype(np.uint8)
218
+
219
+ return image, f"Índice: {index}\nVector latente: {latent_vectors[index, :5]}..."
220
+
221
+ def generate_grid_comparison():
222
+ """Genera un grid de comparación de múltiples dígitos"""
223
+ if generator is None:
224
+ return None
225
+
226
+ # Generar 16 dígitos aleatorios
227
+ latent_vectors_batch = np.random.normal(0, 1, (16, LATENT_DIM))
228
+ generated_images = generator(latent_vectors_batch, training=False)
229
+
230
+ # Crear grid
231
+ fig, axes = plt.subplots(4, 4, figsize=(10, 10))
232
+
233
+ for i in range(4):
234
+ for j in range(4):
235
+ idx = i * 4 + j
236
+ image = generated_images[idx, :, :, 0].numpy()
237
+ image = (image * 127.5 + 127.5).astype(np.uint8)
238
+
239
+ axes[i, j].imshow(image, cmap='gray')
240
+ axes[i, j].axis('off')
241
+
242
+ plt.tight_layout()
243
+
244
+ # Convertir a imagen
245
+ buf = io.BytesIO()
246
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
247
+ buf.seek(0)
248
+ plt.close()
249
+
250
+ return Image.open(buf)
251
+
252
+ # ==================== INTERFAZ GRADIO ====================
253
+
254
+ # CSS personalizado
255
+ custom_css = """
256
+ .gradio-container {
257
+ font-family: 'Arial', sans-serif;
258
+ }
259
+ .tab-nav button {
260
+ font-size: 16px;
261
+ font-weight: bold;
262
+ }
263
+ """
264
+
265
+ # Crear interfaz
266
+ with gr.Blocks(css=custom_css, title="GAN Interactive Demo - MNIST", theme=gr.themes.Soft()) as demo:
267
+
268
+ gr.Markdown("""
269
+ # 🎨 GAN Interactive Demo - Exploración del Espacio Latente
270
+
271
+ ### Generative Adversarial Network entrenada en MNIST
272
+
273
+ Explora cómo una GAN aprende a generar dígitos manuscritos desde vectores de ruido aleatorio.
274
+ Inspirado en el TensorFlow Projector, esta demo te permite navegar el espacio latente de 100 dimensiones.
275
+ """)
276
+
277
+ with gr.Tabs():
278
+
279
+ # TAB 1: Generación Simple
280
+ with gr.Tab("🎲 Generación Aleatoria"):
281
+ gr.Markdown("### Genera dígitos aleatorios con un clic")
282
+
283
+ with gr.Row():
284
+ with gr.Column(scale=1):
285
+ btn_generate = gr.Button("🎲 Generar Dígito Aleatorio", variant="primary", size="lg")
286
+ latent_info = gr.Textbox(label="Información del Vector Latente", lines=2)
287
+
288
+ with gr.Column(scale=1):
289
+ output_image = gr.Image(label="Dígito Generado", type="numpy")
290
+
291
+ btn_generate.click(
292
+ fn=generate_random_digit,
293
+ outputs=[output_image, latent_info]
294
+ )
295
+
296
+ # TAB 2: Control Manual
297
+ with gr.Tab("🎛️ Control Manual"):
298
+ gr.Markdown("### Controla las primeras 10 dimensiones del vector latente")
299
+ gr.Markdown("Ajusta los sliders para ver cómo cada dimensión afecta la generación")
300
+
301
+ with gr.Row():
302
+ with gr.Column(scale=1):
303
+ sliders = []
304
+ for i in range(10):
305
+ slider = gr.Slider(
306
+ minimum=-3,
307
+ maximum=3,
308
+ value=0,
309
+ step=0.1,
310
+ label=f"Dimensión {i+1}"
311
+ )
312
+ sliders.append(slider)
313
+
314
+ btn_generate_sliders = gr.Button("Generar desde Sliders", variant="primary")
315
+
316
+ with gr.Column(scale=1):
317
+ output_image_sliders = gr.Image(label="Dígito Generado", type="numpy")
318
+
319
+ btn_generate_sliders.click(
320
+ fn=generate_from_sliders,
321
+ inputs=sliders,
322
+ outputs=output_image_sliders
323
+ )
324
+
325
+ # TAB 3: Interpolación
326
+ with gr.Tab("🔄 Interpolación"):
327
+ gr.Markdown("### Morphing entre dos dígitos")
328
+ gr.Markdown("Observa cómo la GAN transforma suavemente un dígito en otro")
329
+
330
+ with gr.Row():
331
+ with gr.Column(scale=1):
332
+ start_seed = gr.Number(label="Semilla Inicial", value=42)
333
+ end_seed = gr.Number(label="Semilla Final", value=123)
334
+ steps = gr.Slider(
335
+ minimum=5,
336
+ maximum=20,
337
+ value=10,
338
+ step=1,
339
+ label="Número de Pasos"
340
+ )
341
+ btn_interpolate = gr.Button("🔄 Generar Interpolación", variant="primary")
342
+
343
+ with gr.Column(scale=2):
344
+ output_interpolation = gr.Image(label="Secuencia de Interpolación")
345
+
346
+ btn_interpolate.click(
347
+ fn=interpolate_digits,
348
+ inputs=[start_seed, end_seed, steps],
349
+ outputs=output_interpolation
350
+ )
351
+
352
+ # TAB 4: Exploración del Espacio Latente
353
+ with gr.Tab("🌌 Espacio Latente"):
354
+ gr.Markdown("### Visualización del Espacio Latente de 100 Dimensiones")
355
+ gr.Markdown("Similar al TensorFlow Projector: explora cómo se distribuyen los vectores latentes")
356
+
357
+ with gr.Row():
358
+ with gr.Column(scale=1):
359
+ gr.Markdown("#### Visualización 3D (PCA)")
360
+ btn_pca = gr.Button("Mostrar PCA 3D", variant="secondary")
361
+ plot_pca = gr.Plot(label="Espacio Latente - PCA")
362
+
363
+ btn_pca.click(
364
+ fn=visualize_latent_space_pca,
365
+ outputs=plot_pca
366
+ )
367
+
368
+ with gr.Column(scale=1):
369
+ gr.Markdown("#### Visualización 2D (t-SNE)")
370
+ btn_tsne = gr.Button("Mostrar t-SNE 2D", variant="secondary")
371
+ plot_tsne = gr.Plot(label="Espacio Latente - t-SNE")
372
+
373
+ btn_tsne.click(
374
+ fn=visualize_latent_space_tsne,
375
+ outputs=plot_tsne
376
+ )
377
+
378
+ gr.Markdown("---")
379
+ gr.Markdown("#### Genera desde un punto específico del espacio")
380
+
381
+ with gr.Row():
382
+ with gr.Column(scale=1):
383
+ latent_index = gr.Slider(
384
+ minimum=0,
385
+ maximum=999,
386
+ value=0,
387
+ step=1,
388
+ label="Índice del Vector Latente"
389
+ )
390
+ btn_generate_index = gr.Button("Generar desde Índice", variant="primary")
391
+ latent_index_info = gr.Textbox(label="Información", lines=2)
392
+
393
+ with gr.Column(scale=1):
394
+ output_image_index = gr.Image(label="Dígito Generado", type="numpy")
395
+
396
+ btn_generate_index.click(
397
+ fn=generate_from_latent_index,
398
+ inputs=latent_index,
399
+ outputs=[output_image_index, latent_index_info]
400
+ )
401
+
402
+ # TAB 5: Grid de Comparación
403
+ with gr.Tab("📊 Grid de Dígitos"):
404
+ gr.Markdown("### Genera múltiples dígitos simultáneamente")
405
+ gr.Markdown("Observa la diversidad y calidad de las generaciones")
406
+
407
+ with gr.Row():
408
+ with gr.Column(scale=1):
409
+ btn_grid = gr.Button("🎨 Generar Grid 4×4", variant="primary", size="lg")
410
+
411
+ with gr.Column(scale=2):
412
+ output_grid = gr.Image(label="Grid de 16 Dígitos Generados")
413
+
414
+ btn_grid.click(
415
+ fn=generate_grid_comparison,
416
+ outputs=output_grid
417
+ )
418
+
419
+ gr.Markdown("""
420
+ ---
421
+ ### 📚 Sobre esta Demo
422
+
423
+ Esta aplicación interactiva demuestra el poder de las **Redes Generativas Adversarias (GANs)** entrenadas en el dataset MNIST.
424
+
425
+ **Características:**
426
+ - **Espacio Latente de 100 dimensiones**: Cada dígito es generado desde un vector de 100 números aleatorios
427
+ - **Visualización dimensional**: PCA y t-SNE reducen las 100 dimensiones a 2D/3D para visualización
428
+ - **Interpolación suave**: Demuestra que el espacio latente es continuo y significativo
429
+ - **Generación instantánea**: Sin necesidad de re-entrenar
430
+
431
+ **Arquitectura:**
432
+ - **Generador**: 7×7×256 → 14×14×64 → 28×28×1 (Conv2DTranspose + BatchNorm + LeakyReLU)
433
+ - **Discriminador**: 28×28×1 → 14×14×64 → 7×7×128 → Logit (Conv2D + Dropout)
434
+ - **Entrenamiento**: 50 épocas, Adam optimizer, Binary Cross-Entropy loss
435
+
436
+ 🎓 **Creado para la clase de Machine Learning**
437
+ """)
438
+
439
+ # Lanzar aplicación
440
+ if __name__ == "__main__":
441
+ demo.launch(
442
+ server_name="0.0.0.0",
443
+ server_port=7860,
444
+ share=False
445
+ )
446
+
models/discriminator.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:79d02aa90dabd5f869c3dc00cedf48e6edcbef328998a63140820013e6f23f72
3
+ size 873256
models/generated_images.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2c1dff63b3d7f9e3dc41ca7582d79a2d9dc708780d7e3d13eda63cfb88980b65
3
+ size 3136128
models/generator.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:300c4e8d048303c86e27c947768417511fe97a9cfe349c45e169b7edb312a524
3
+ size 9360360
models/image_at_epoch_0005.png ADDED
models/image_at_epoch_0010.png ADDED
models/image_at_epoch_0015.png ADDED
models/image_at_epoch_0020.png ADDED
models/latent_vectors.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:af9b6be5a792ebbdcd3c20e1766808114540297ba475e6958c65724e355662c7
3
+ size 400128
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ tensorflow==2.15.0
3
+ numpy==1.24.3
4
+ matplotlib==3.7.1
5
+ plotly==5.18.0
6
+ scikit-learn==1.3.2
7
+ Pillow==10.1.0
8
+