Demon1212122 commited on
Commit
ffccd2d
·
1 Parent(s): 9a609ed

Initial deployment with Git LFS

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.data-00000-of-00001 filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,12 +1,117 @@
1
  ---
2
- title: Gan Mnist Interactive
3
- emoji: 🐢
4
- colorFrom: blue
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- 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,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # Convertir a PIL Image para Gradio
72
+ pil_image = Image.fromarray(image, mode='L')
73
+
74
+ return pil_image, f"Vector latente: {latent_vector[0, :5]}... (primeros 5 valores)"
75
+
76
+ def generate_from_sliders(*slider_values):
77
+ """Genera un dígito desde valores de sliders (primeras 10 dimensiones)"""
78
+ if generator is None:
79
+ return None, "Modelo no disponible"
80
+
81
+ # Crear vector latente: primeras 10 dimensiones desde sliders, resto aleatorio
82
+ latent_vector = np.random.normal(0, 1, (1, LATENT_DIM))
83
+ latent_vector[0, :10] = slider_values
84
+
85
+ # Generar imagen
86
+ generated_image = generator(latent_vector, training=False)
87
+ image = generated_image[0, :, :, 0].numpy()
88
+
89
+ # Desnormalizar
90
+ image = (image * 127.5 + 127.5).astype(np.uint8)
91
+
92
+ # Convertir a PIL Image para Gradio
93
+ pil_image = Image.fromarray(image, mode='L')
94
+
95
+ return pil_image
96
+
97
+ def interpolate_digits(start_seed, end_seed, steps):
98
+ """Interpola entre dos dígitos generados desde semillas"""
99
+ if generator is None:
100
+ return None
101
+
102
+ # Generar vectores latentes desde semillas
103
+ np.random.seed(int(start_seed))
104
+ latent_start = np.random.normal(0, 1, (1, LATENT_DIM))
105
+
106
+ np.random.seed(int(end_seed))
107
+ latent_end = np.random.normal(0, 1, (1, LATENT_DIM))
108
+
109
+ # Crear interpolación lineal
110
+ alphas = np.linspace(0, 1, int(steps))
111
+
112
+ # Generar imágenes interpoladas
113
+ images = []
114
+ for alpha in alphas:
115
+ latent_interp = (1 - alpha) * latent_start + alpha * latent_end
116
+ generated = generator(latent_interp, training=False)
117
+ image = generated[0, :, :, 0].numpy()
118
+ image = (image * 127.5 + 127.5).astype(np.uint8)
119
+ images.append(image)
120
+
121
+ # Crear grid de imágenes
122
+ n_images = len(images)
123
+ cols = min(10, n_images)
124
+ rows = (n_images + cols - 1) // cols
125
+
126
+ fig, axes = plt.subplots(rows, cols, figsize=(cols * 1.5, rows * 1.5))
127
+ if rows == 1:
128
+ axes = axes.reshape(1, -1)
129
+
130
+ for idx, image in enumerate(images):
131
+ row = idx // cols
132
+ col = idx % cols
133
+ axes[row, col].imshow(image, cmap='gray')
134
+ axes[row, col].axis('off')
135
+ axes[row, col].set_title(f'{idx+1}', fontsize=8)
136
+
137
+ # Ocultar ejes vacíos
138
+ for idx in range(n_images, rows * cols):
139
+ row = idx // cols
140
+ col = idx % cols
141
+ axes[row, col].axis('off')
142
+
143
+ plt.tight_layout()
144
+
145
+ # Convertir a imagen
146
+ buf = io.BytesIO()
147
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
148
+ buf.seek(0)
149
+ plt.close()
150
+
151
+ return Image.open(buf)
152
+
153
+ def visualize_latent_space_pca():
154
+ """Visualiza el espacio latente en 3D usando PCA"""
155
+ fig = go.Figure(data=[go.Scatter3d(
156
+ x=latent_pca[:, 0],
157
+ y=latent_pca[:, 1],
158
+ z=latent_pca[:, 2],
159
+ mode='markers',
160
+ marker=dict(
161
+ size=3,
162
+ color=latent_pca[:, 2],
163
+ colorscale='Viridis',
164
+ showscale=True,
165
+ colorbar=dict(title="PC3"),
166
+ opacity=0.7
167
+ ),
168
+ text=[f'Punto {i}' for i in range(len(latent_pca))],
169
+ hovertemplate='<b>Punto %{text}</b><br>PC1: %{x:.2f}<br>PC2: %{y:.2f}<br>PC3: %{z:.2f}<extra></extra>'
170
+ )])
171
+
172
+ fig.update_layout(
173
+ title='Espacio Latente - Visualización PCA 3D',
174
+ scene=dict(
175
+ xaxis_title='Componente Principal 1',
176
+ yaxis_title='Componente Principal 2',
177
+ zaxis_title='Componente Principal 3',
178
+ bgcolor='rgba(240, 240, 240, 0.9)'
179
+ ),
180
+ width=800,
181
+ height=600,
182
+ showlegend=False
183
+ )
184
+
185
+ return fig
186
+
187
+ def visualize_latent_space_tsne():
188
+ """Visualiza el espacio latente en 2D usando t-SNE"""
189
+ fig = go.Figure(data=[go.Scatter(
190
+ x=latent_tsne[:, 0],
191
+ y=latent_tsne[:, 1],
192
+ mode='markers',
193
+ marker=dict(
194
+ size=6,
195
+ color=np.arange(len(latent_tsne)),
196
+ colorscale='Plasma',
197
+ showscale=True,
198
+ colorbar=dict(title="Índice"),
199
+ opacity=0.7
200
+ ),
201
+ text=[f'Punto {i}' for i in range(len(latent_tsne))],
202
+ hovertemplate='<b>Punto %{text}</b><br>t-SNE 1: %{x:.2f}<br>t-SNE 2: %{y:.2f}<extra></extra>'
203
+ )])
204
+
205
+ fig.update_layout(
206
+ title='Espacio Latente - Visualización t-SNE 2D',
207
+ xaxis_title='Dimensión t-SNE 1',
208
+ yaxis_title='Dimensión t-SNE 2',
209
+ width=800,
210
+ height=600,
211
+ plot_bgcolor='rgba(240, 240, 240, 0.9)'
212
+ )
213
+
214
+ return fig
215
+
216
+ def generate_from_latent_index(index):
217
+ """Genera imagen desde un índice del espacio latente pre-calculado"""
218
+ if generated_images_cache is None:
219
+ return None, "Cache no disponible"
220
+
221
+ index = int(index) % len(generated_images_cache)
222
+ image = generated_images_cache[index, :, :, 0]
223
+ image = (image * 127.5 + 127.5).astype(np.uint8)
224
+
225
+ # Convertir a PIL Image para Gradio
226
+ pil_image = Image.fromarray(image, mode='L')
227
+
228
+ return pil_image, f"Índice: {index}\nVector latente: {latent_vectors[index, :5]}..."
229
+
230
+ def generate_grid_comparison():
231
+ """Genera un grid de comparación de múltiples dígitos"""
232
+ if generator is None:
233
+ return None
234
+
235
+ # Generar 16 dígitos aleatorios
236
+ latent_vectors_batch = np.random.normal(0, 1, (16, LATENT_DIM))
237
+ generated_images = generator(latent_vectors_batch, training=False)
238
+
239
+ # Crear grid
240
+ fig, axes = plt.subplots(4, 4, figsize=(10, 10))
241
+
242
+ for i in range(4):
243
+ for j in range(4):
244
+ idx = i * 4 + j
245
+ image = generated_images[idx, :, :, 0].numpy()
246
+ image = (image * 127.5 + 127.5).astype(np.uint8)
247
+
248
+ axes[i, j].imshow(image, cmap='gray')
249
+ axes[i, j].axis('off')
250
+
251
+ plt.tight_layout()
252
+
253
+ # Convertir a imagen
254
+ buf = io.BytesIO()
255
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
256
+ buf.seek(0)
257
+ plt.close()
258
+
259
+ return Image.open(buf)
260
+
261
+ # ==================== INTERFAZ GRADIO ====================
262
+
263
+ # CSS personalizado
264
+ custom_css = """
265
+ .gradio-container {
266
+ font-family: 'Arial', sans-serif;
267
+ }
268
+ .tab-nav button {
269
+ font-size: 16px;
270
+ font-weight: bold;
271
+ }
272
+ """
273
+
274
+ # Crear interfaz
275
+ with gr.Blocks(css=custom_css, title="GAN Interactive Demo - MNIST", theme=gr.themes.Soft()) as demo:
276
+
277
+ gr.Markdown("""
278
+ # 🎨 GAN Interactive Demo - Exploración del Espacio Latente
279
+
280
+ ### Generative Adversarial Network entrenada en MNIST
281
+
282
+ Explora cómo una GAN aprende a generar dígitos manuscritos desde vectores de ruido aleatorio.
283
+ Inspirado en el TensorFlow Projector, esta demo te permite navegar el espacio latente de 100 dimensiones.
284
+ """)
285
+
286
+ with gr.Tabs():
287
+
288
+ # TAB 1: Generación Simple
289
+ with gr.Tab("🎲 Generación Aleatoria"):
290
+ gr.Markdown("### Genera dígitos aleatorios con un clic")
291
+
292
+ with gr.Row():
293
+ with gr.Column(scale=1):
294
+ btn_generate = gr.Button("🎲 Generar Dígito Aleatorio", variant="primary", size="lg")
295
+ latent_info = gr.Textbox(label="Información del Vector Latente", lines=2)
296
+
297
+ with gr.Column(scale=1):
298
+ output_image = gr.Image(label="Dígito Generado", type="pil")
299
+
300
+ btn_generate.click(
301
+ fn=generate_random_digit,
302
+ outputs=[output_image, latent_info]
303
+ )
304
+
305
+ # TAB 2: Control Manual
306
+ with gr.Tab("🎛️ Control Manual"):
307
+ gr.Markdown("### Controla las primeras 10 dimensiones del vector latente")
308
+ gr.Markdown("Ajusta los sliders para ver cómo cada dimensión afecta la generación")
309
+
310
+ with gr.Row():
311
+ with gr.Column(scale=1):
312
+ sliders = []
313
+ for i in range(10):
314
+ slider = gr.Slider(
315
+ minimum=-3,
316
+ maximum=3,
317
+ value=0,
318
+ step=0.1,
319
+ label=f"Dimensión {i+1}"
320
+ )
321
+ sliders.append(slider)
322
+
323
+ btn_generate_sliders = gr.Button("Generar desde Sliders", variant="primary")
324
+
325
+ with gr.Column(scale=1):
326
+ output_image_sliders = gr.Image(label="Dígito Generado", type="pil")
327
+
328
+ btn_generate_sliders.click(
329
+ fn=generate_from_sliders,
330
+ inputs=sliders,
331
+ outputs=output_image_sliders
332
+ )
333
+
334
+ # TAB 3: Interpolación
335
+ with gr.Tab("🔄 Interpolación"):
336
+ gr.Markdown("### Morphing entre dos dígitos")
337
+ gr.Markdown("Observa cómo la GAN transforma suavemente un dígito en otro")
338
+
339
+ with gr.Row():
340
+ with gr.Column(scale=1):
341
+ start_seed = gr.Number(label="Semilla Inicial", value=42)
342
+ end_seed = gr.Number(label="Semilla Final", value=123)
343
+ steps = gr.Slider(
344
+ minimum=5,
345
+ maximum=20,
346
+ value=10,
347
+ step=1,
348
+ label="Número de Pasos"
349
+ )
350
+ btn_interpolate = gr.Button("🔄 Generar Interpolación", variant="primary")
351
+
352
+ with gr.Column(scale=2):
353
+ output_interpolation = gr.Image(label="Secuencia de Interpolación")
354
+
355
+ btn_interpolate.click(
356
+ fn=interpolate_digits,
357
+ inputs=[start_seed, end_seed, steps],
358
+ outputs=output_interpolation
359
+ )
360
+
361
+ # TAB 4: Exploración del Espacio Latente
362
+ with gr.Tab("🌌 Espacio Latente"):
363
+ gr.Markdown("### Visualización del Espacio Latente de 100 Dimensiones")
364
+ gr.Markdown("Similar al TensorFlow Projector: explora cómo se distribuyen los vectores latentes")
365
+
366
+ with gr.Row():
367
+ with gr.Column(scale=1):
368
+ gr.Markdown("#### Visualización 3D (PCA)")
369
+ btn_pca = gr.Button("Mostrar PCA 3D", variant="secondary")
370
+ plot_pca = gr.Plot(label="Espacio Latente - PCA")
371
+
372
+ btn_pca.click(
373
+ fn=visualize_latent_space_pca,
374
+ outputs=plot_pca
375
+ )
376
+
377
+ with gr.Column(scale=1):
378
+ gr.Markdown("#### Visualización 2D (t-SNE)")
379
+ btn_tsne = gr.Button("Mostrar t-SNE 2D", variant="secondary")
380
+ plot_tsne = gr.Plot(label="Espacio Latente - t-SNE")
381
+
382
+ btn_tsne.click(
383
+ fn=visualize_latent_space_tsne,
384
+ outputs=plot_tsne
385
+ )
386
+
387
+ gr.Markdown("---")
388
+ gr.Markdown("#### Genera desde un punto específico del espacio")
389
+
390
+ with gr.Row():
391
+ with gr.Column(scale=1):
392
+ latent_index = gr.Slider(
393
+ minimum=0,
394
+ maximum=999,
395
+ value=0,
396
+ step=1,
397
+ label="Índice del Vector Latente"
398
+ )
399
+ btn_generate_index = gr.Button("Generar desde Índice", variant="primary")
400
+ latent_index_info = gr.Textbox(label="Información", lines=2)
401
+
402
+ with gr.Column(scale=1):
403
+ output_image_index = gr.Image(label="Dígito Generado", type="pil")
404
+
405
+ btn_generate_index.click(
406
+ fn=generate_from_latent_index,
407
+ inputs=latent_index,
408
+ outputs=[output_image_index, latent_index_info]
409
+ )
410
+
411
+ # TAB 5: Grid de Comparación
412
+ with gr.Tab("📊 Grid de Dígitos"):
413
+ gr.Markdown("### Genera múltiples dígitos simultáneamente")
414
+ gr.Markdown("Observa la diversidad y calidad de las generaciones")
415
+
416
+ with gr.Row():
417
+ with gr.Column(scale=1):
418
+ btn_grid = gr.Button("🎨 Generar Grid 4×4", variant="primary", size="lg")
419
+
420
+ with gr.Column(scale=2):
421
+ output_grid = gr.Image(label="Grid de 16 Dígitos Generados")
422
+
423
+ btn_grid.click(
424
+ fn=generate_grid_comparison,
425
+ outputs=output_grid
426
+ )
427
+
428
+ gr.Markdown("""
429
+ ---
430
+ ### 📚 Sobre esta Demo
431
+
432
+ Esta aplicación interactiva demuestra el poder de las **Redes Generativas Adversarias (GANs)** entrenadas en el dataset MNIST.
433
+
434
+ **Características:**
435
+ - **Espacio Latente de 100 dimensiones**: Cada dígito es generado desde un vector de 100 números aleatorios
436
+ - **Visualización dimensional**: PCA y t-SNE reducen las 100 dimensiones a 2D/3D para visualización
437
+ - **Interpolación suave**: Demuestra que el espacio latente es continuo y significativo
438
+ - **Generación instantánea**: Sin necesidad de re-entrenar
439
+
440
+ **Arquitectura:**
441
+ - **Generador**: 7×7×256 → 14×14×64 → 28×28×1 (Conv2DTranspose + BatchNorm + LeakyReLU)
442
+ - **Discriminador**: 28×28×1 → 14×14×64 → 7×7×128 → Logit (Conv2D + Dropout)
443
+ - **Entrenamiento**: 50 épocas, Adam optimizer, Binary Cross-Entropy loss
444
+
445
+ 🎓 **Creado para la clase de Machine Learning**
446
+ """)
447
+
448
+ # Lanzar aplicación
449
+ if __name__ == "__main__":
450
+ demo.launch(
451
+ server_name="0.0.0.0",
452
+ server_port=7860,
453
+ share=False
454
+ )
455
+
models/discriminator.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d4c7a7eb2c30e6f8eea1e2261d6d2b41d0925ba1df198fb472c6547faf302dc1
3
+ size 873256
models/discriminator_savedmodel/fingerprint.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:99a353251f83551ff81f574cd31085dad05eae44b36b07400c367579886b0d52
3
+ size 55
models/discriminator_savedmodel/keras_metadata.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b5bf683f66c81bbb8eb1d548b5b5e3de72b0e378dcfefb0d864124f1197ecfae
3
+ size 13555
models/discriminator_savedmodel/saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:34c409dc55def9e2f0e58f75eea3e7412d3b2d4f7f3a9fe86eab2b3d5afc9c4f
3
+ size 92712
models/discriminator_savedmodel/variables/variables.data-00000-of-00001 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:59280875c454706a80950787a59a4e2a223e35b8b1e25134c06bfc8108c35638
3
+ size 857347
models/discriminator_savedmodel/variables/variables.index ADDED
Binary file (531 Bytes). View file
 
models/generated_images.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5e5381c6c3e45fe55c4d45423f6faf6b8d466b012a826a69234111f8b4778fa1
3
+ size 3136128
models/generator.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cb6036b3d1bc563a009cb864abe82c1f87458cbd6e72763cdc9cdae574ca2ca9
3
+ size 9360360
models/generator_savedmodel/fingerprint.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5f84ba1ef8470a5cf24820da346580becc43aa9fa88c00c403652e2e0085f902
3
+ size 58
models/generator_savedmodel/keras_metadata.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2fd33ef59514d53bbbedc05f85a6be41d5af12170c7a897cdb7d55b68a871eff
3
+ size 23085
models/generator_savedmodel/saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3e71a0961140f3f0de62738b44c259d65bf84e914fb2f78a6dc766e03716b816
3
+ size 206137
models/generator_savedmodel/variables/variables.data-00000-of-00001 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4d2567eba9c76db107ad63b4634d3b8846da019eaeaaf024d35f92b24fa1b48f
3
+ size 9333142
models/generator_savedmodel/variables/variables.index ADDED
Binary file (1.2 kB). View file
 
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/image_at_epoch_0025.png ADDED
models/image_at_epoch_0030.png ADDED
models/image_at_epoch_0035.png ADDED
models/image_at_epoch_0040.png ADDED
models/image_at_epoch_0045.png ADDED
models/image_at_epoch_0050.png ADDED
models/latent_vectors.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2b3e61ba71dcc0fe80561e9c39aa7cb651893b18e6548c54dae3eedc1d63b37d
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
+