Proyecto integrador — Predicción y generación de texto con redes neuronales recurrentes¶
Corporación Universitaria Minuto de Dios (UNIMINUTO) Especialización en Inteligencia Artificial NRC-8774 — Procesamiento Natural del Lenguaje — Semana 7
Grupo 7
| Integrantes |
|---|
| Alexander Oviedo Fadul |
| Maria Fernanda Ruiz Paipilla |
| Neheman Samir Jaller Cerchiaro |
| William David Obando Lopez |
Docente: Nathalia Orozco Morales Fecha de entrega: 17 de agosto de 2026
Sobre este cuaderno¶
Tomamos como punto de partida el insumo que la docente compartió en la sesión sincrónica
(semana_7_26022026.ipynb, bloque Generación de texto con una red neuronal LSTM) y seguimos
su indicación explícita en clase: "yo les doy un insumo de referencia y ustedes lo complementan,
lo vuelven más complejo y le aumentan los epochs… ¿cómo lo denotan? Con las métricas"
(Orozco Morales, 2026). En concreto, lo que agregamos sobre el insumo original es:
- Corpus ampliado y en línea. El ejemplo de clase entrenaba con 60 filas (≈1.354 tokens). Aquí descargamos el texto real de Don Quijote de la Mancha desde Project Gutenberg, lo que multiplica el corpus por más de cincuenta veces. El cuaderno no necesita ningún archivo local.
- Dos modelos, no uno. La actividad pide literalmente predecir caracteres de un texto,
mientras que el insumo de clase trabaja a nivel de palabra. Implementamos ambos con la misma
arquitectura exigida:
LSTM(128)+Denseconsoftmax. - Más épocas y seguimiento por época. Cada época imprime sus métricas y genera texto con cuatro temperaturas distintas, que es justo lo que solicita el punto 4 del enunciado.
- Un pipeline que sí escala. Usamos ventanas deslizantes con etiquetas enteras y
sparse_categorical_crossentropy, en lugar de prefijos crecientes con one-hot: esto evita la explosión de memoria cuando el vocabulario crece.
Preguntas orientadoras¶
¿Cuáles son las principales aplicaciones de las redes neuronales recurrentes?
Las RNN se emplean en cualquier problema donde el orden importa: traducción automática, análisis de sentimiento, reconocimiento de voz, predicción de series temporales, generación y autocompletado de texto, etiquetado morfosintáctico y detección de anomalías en secuencias de sensores. El autocompletado del correo electrónico o de un editor de código es probablemente el caso que más usamos sin darnos cuenta (Srinivasa-Desikan, 2018; Zhou, 2022).
¿Cuál es la arquitectura de una red neuronal recurrente?
Una RNN procesa la secuencia paso a paso y mantiene un estado oculto que se realimenta:
h_t = f(W_x · x_t + W_h · h_{t-1} + b). Ese estado funciona como memoria de trabajo. El problema
es que, al propagar el gradiente hacia atrás en secuencias largas, el gradiente se desvanece. La
LSTM resuelve eso añadiendo una celda de memoria y tres puertas —olvido, entrada y salida— que
deciden qué se conserva, qué entra y qué sale en cada paso (Hochreiter y Schmidhuber, 1997;
Goodfellow et al., 2016). En este proyecto la salida de la LSTM pasa a una capa Dense con
softmax, que convierte los 128 valores del estado en una distribución de probabilidad sobre todo
el vocabulario.
Marco teórico breve¶
LSTM (128 unidades). Las 128 unidades no son 128 palabras memorizadas: son 128 valores numéricos que resumen todo lo que la red ha procesado de la secuencia. A mayor número de unidades, mayor capacidad de representación, pero también más parámetros que ajustar y más riesgo de sobreajuste con un corpus pequeño.
Dense + softmax. La capa Dense proyecta esos 128 valores a una puntuación por cada elemento
del vocabulario. softmax normaliza esas puntuaciones en probabilidades que suman 1.
Temperatura. Antes de muestrear, dividimos los logaritmos de las probabilidades por un factor
T. Con T < 1 la distribución se concentra en las opciones más probables (texto conservador y
repetitivo); con T > 1 se aplana y da oportunidad a palabras poco frecuentes (texto más variado,
pero con riesgo de perder coherencia). Es el mismo mecanismo que controla la "creatividad" de los
modelos generativos actuales.
Token OOV. Tokenizer(oov_token="<OOV>") reserva un índice para las palabras que el modelo
nunca vio. Sin ese token, una palabra desconocida produciría una secuencia vacía y rompería la
inferencia; con él, el modelo la representa de forma consistente y sigue funcionando.
Top-k. Muestrear sobre todo el vocabulario introduce mucho ruido. Restringir la elección a las
k opciones más probables antes de aplicar la temperatura mejora notablemente la legibilidad.
Una decisión de inferencia. Como el vocabulario del modelo está acotado, <OOV> es un token
frecuente y el muestreo puede elegirlo. Al generar lo excluimos junto con el relleno del padding:
no es una modificación del modelo, sino una restricción en el momento de la inferencia, del mismo
tipo que el top-k. Sin ella, el texto sale salpicado de marcadores que no son palabras.
1. Configuración del entorno¶
Fijamos las semillas para que el experimento sea reproducible y verificamos las versiones de las librerías, un dato que conviene dejar registrado porque la API de Keras cambió bastante con la versión 3.
# -*- coding: utf-8 -*-
import os
import re
import json
import time
import urllib.request
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
# ------------------------------------------------------------------
# Reproducibilidad
# ------------------------------------------------------------------
SEMILLA = 42
np.random.seed(SEMILLA)
tf.random.set_seed(SEMILLA)
try:
import keras
version_keras = keras.__version__
except Exception:
version_keras = getattr(tf.keras, "__version__", "desconocida")
print("TensorFlow :", tf.__version__)
print("Keras :", version_keras)
print("NumPy :", np.__version__)
print("GPU :", tf.config.list_physical_devices("GPU") or "no disponible (se usará CPU)")
TensorFlow : 2.21.0 Keras : 3.15.1 NumPy : 2.5.2 GPU : no disponible (se usará CPU)
2. Corpus: descarga en línea, sin archivos locales¶
Una de las molestias del insumo original es que obliga a subir un CSV con el botón de Colab cada vez que se reinicia el entorno. Aquí resolvemos eso de dos formas complementarias:
- Fuente principal: el texto íntegro de Don Quijote de la Mancha (Cervantes, 1605/2004) desde
Project Gutenberg, que es dominio público. Recortamos desde
"En un lugar de la Mancha"hasta el marcador de fin de la licencia y limitamos el volumen para que el entrenamiento sea viable. - Respaldo embebido: el mini-corpus que la docente usó en clase, incluido como constante de Python. Si no hay red, el cuaderno sigue corriendo con él.
Nota crítica sobre el mini-corpus de clase. El archivo original (
quijote_mini_corpus_.csv) tiene 60 filas, pero en realidad son 30 frases repetidas: la segunda mitad es la primera mitad con la coletilla "El caballero y su escudero continuaron después su recorrido con esperanza y curiosidad" añadida al final. Esa repetición explica por qué en la demostración de clase el modelo tendía a producir cadenas como "su su su y y y": estaba memorizando el relleno. Aquí conservamos las 30 frases únicas.
# ==================================================================
# 2.1 Mini-corpus de clase (embebido: no requiere subir ningún CSV)
# Fuente: Orozco Morales (2026), quijote_mini_corpus_.csv
# Se conservan las 30 frases únicas de las 60 filas originales.
# ==================================================================
MINI_CORPUS_CLASE = [
"En un lugar de la Mancha vivía un hidalgo aficionado a los libros de caballerías y a las grandes aventuras.",
"El caballero imaginaba caminos largos, castillos antiguos, gigantes, escuderos y nobles desafíos.",
"Una mañana decidió salir por los caminos en busca de aventuras dignas de un caballero andante.",
"Su caballo era flaco pero resistente y su voluntad parecía más fuerte que cualquier dificultad del camino.",
"El caballero andante avanzaba por los campos mientras pensaba en hazañas, honor, justicia y valentía.",
"A lo lejos observó unos molinos de viento y creyó descubrir enormes gigantes dispuestos para la batalla.",
"Su escudero intentó advertirle que aquellos gigantes eran en realidad molinos movidos por el viento.",
"El caballero no abandonó su propósito y se lanzó con decisión hacia aquello que consideraba una gran aventura.",
"Después de la caída volvió a levantarse y continuó el camino convencido de que nuevas pruebas lo esperaban.",
"En cada jornada encontraba viajeros, ventas, caminos polvorientos y situaciones que alimentaban su imaginación.",
"El caballero hablaba de honor y justicia mientras su escudero observaba el mundo de manera más práctica.",
"Durante la noche ambos descansaban y conversaban sobre las aventuras ocurridas durante el día.",
"Al amanecer emprendían nuevamente el camino esperando encontrar una oportunidad para demostrar su valor.",
"El escudero seguía a su señor con paciencia porque esperaba obtener alguna recompensa por sus servicios.",
"Las historias de caballería guiaban muchas decisiones del caballero y transformaban su manera de interpretar la realidad.",
"Cuando encontraba un problema pensaba que todo caballero debía enfrentarlo con coraje y determinación.",
"Los caminos de la Mancha se convirtieron en escenario de encuentros, discusiones, peligros y momentos inesperados.",
"El caballero veía castillos donde otros veían ventas y veía enemigos donde otros solamente observaban viajeros.",
"Su imaginación convertía los acontecimientos cotidianos en grandes historias llenas de emoción y aventura.",
"A pesar de los tropiezos continuaba avanzando porque creía firmemente en los ideales de la caballería.",
"El caballero andante se lanzó a la aventura acompañado de su fiel escudero por los extensos caminos de la Mancha.",
"Cada nueva aventura comenzaba con una expectativa diferente y terminaba dejando una nueva historia para recordar.",
"El viaje mostraba constantemente el contraste entre la imaginación del caballero y la visión realista de su compañero.",
"Entre conversaciones y desafíos ambos aprendían de los acontecimientos que encontraban durante sus recorridos.",
"El caballero defendía a quienes consideraba necesitados y buscaba actuar de acuerdo con sus principios de justicia.",
"Su escudero intentaba aconsejarlo cuando las decisiones parecían demasiado arriesgadas o difíciles de comprender.",
"El paisaje, los caminos, los pueblos y las personas formaban parte de una historia que parecía no terminar.",
"A veces las aventuras resultaban exitosas y otras veces producían golpes, confusión y nuevas dificultades.",
"Sin embargo el caballero siempre encontraba una razón para continuar y buscar otra oportunidad de demostrar su valor.",
"Así avanzaban por la Mancha entre realidad e imaginación mientras nuevas aventuras aparecían en el camino."
]
print("Frases del mini-corpus de clase:", len(MINI_CORPUS_CLASE))
print("Caracteres :", sum(len(f) for f in MINI_CORPUS_CLASE))
Frases del mini-corpus de clase: 30 Caracteres : 3217
# ==================================================================
# 2.2 Descarga del Quijote desde Project Gutenberg
# ==================================================================
URL_QUIJOTE = "https://www.gutenberg.org/cache/epub/2000/pg2000.txt"
URL_ESPEJO = "https://www.gutenberg.org/files/2000/2000-0.txt"
MAX_CARACTERES = 400_000 # recorte para que el entrenamiento quepa en una sesión de clase
def descargar_quijote(url, timeout=45):
"""Descarga el texto y devuelve el cuerpo de la novela, ya recortado."""
peticion = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(peticion, timeout=timeout) as respuesta:
crudo = respuesta.read().decode("utf-8", errors="ignore")
# Recorte determinista: desde la primera línea de la novela hasta el pie de licencia
inicio = crudo.find("En un lugar de la Mancha, de cuyo nombre")
if inicio == -1:
inicio = crudo.find("*** START OF THE PROJECT GUTENBERG")
fin = crudo.find("*** END OF THE PROJECT GUTENBERG")
if fin == -1:
fin = len(crudo)
return crudo[inicio:fin]
texto_gutenberg = ""
for url in (URL_QUIJOTE, URL_ESPEJO):
try:
print(f"Descargando corpus desde: {url}")
texto_gutenberg = descargar_quijote(url)
print(f" -> descarga correcta: {len(texto_gutenberg):,} caracteres")
break
except Exception as error: # sin red, mirror caído, timeout...
print(f" -> falló ({type(error).__name__}: {error})")
if not texto_gutenberg:
print("\nNo fue posible descargar el corpus. Se continúa solo con el mini-corpus de clase.")
Descargando corpus desde: https://www.gutenberg.org/cache/epub/2000/pg2000.txt
-> descarga correcta: 2,108,253 caracteres
# ==================================================================
# 2.3 Limpieza y unificación del corpus
# ==================================================================
def limpiar(texto):
"""Normaliza el texto conservando la puntuación relevante para el modelo."""
texto = texto.replace("\r", " ")
texto = re.sub(r"\[\d+\]", " ", texto) # notas al pie del editor
texto = re.sub(r"[«»_]", " ", texto)
texto = re.sub(r"\s+", " ", texto)
return texto.strip()
partes = [limpiar(" ".join(MINI_CORPUS_CLASE))]
if texto_gutenberg:
cuerpo = limpiar(texto_gutenberg)[:MAX_CARACTERES]
partes.append(cuerpo)
corpus = " ".join(partes).lower()
palabras = corpus.split()
print("=" * 62)
print("CORPUS DE TRABAJO")
print("=" * 62)
print(f"Caracteres : {len(corpus):,}")
print(f"Palabras : {len(palabras):,}")
print(f"Vocabulario (únicas) : {len(set(palabras)):,}")
print(f"Factor vs. clase (60 filas / 1.354 tokens): x{len(palabras) / 1354:.1f}")
print()
print("Primeros 400 caracteres:")
print("-" * 62)
print(corpus[:400])
============================================================== CORPUS DE TRABAJO ============================================================== Caracteres : 403,247 Palabras : 73,974 Vocabulario (únicas) : 12,479 Factor vs. clase (60 filas / 1.354 tokens): x54.6 Primeros 400 caracteres: -------------------------------------------------------------- en un lugar de la mancha vivía un hidalgo aficionado a los libros de caballerías y a las grandes aventuras. el caballero imaginaba caminos largos, castillos antiguos, gigantes, escuderos y nobles desafíos. una mañana decidió salir por los caminos en busca de aventuras dignas de un caballero andante. su caballo era flaco pero resistente y su voluntad parecía más fuerte que cualquier dificultad del
3. Modelo A — LSTM a nivel de palabra¶
Este es el modelo que replica y amplía el insumo de la docente. La arquitectura es exactamente la
que pide el enunciado: LSTM con 128 unidades internas más una capa Dense con softmax.
Un detalle importante del diseño: en lugar de generar prefijos crecientes y codificar la salida con
one-hot (que en un vocabulario de miles de palabras produce matrices imposibles de sostener en
memoria), usamos ventanas deslizantes de longitud fija y etiquetas enteras con
sparse_categorical_crossentropy. El resultado es matemáticamente equivalente y consume varios
órdenes de magnitud menos memoria.
# ==================================================================
# 3.1 Tokenización a nivel de palabra
# ==================================================================
VOCAB_MAX = 6000 # se conservan las 6.000 palabras más frecuentes
SEQ_LEN = 20 # se usan 20 palabras de contexto para predecir la siguiente
tokenizer = Tokenizer(num_words=VOCAB_MAX, oov_token="<OOV>")
tokenizer.fit_on_texts([corpus])
tokens = tokenizer.texts_to_sequences([corpus])[0]
vocab_size = min(VOCAB_MAX, len(tokenizer.word_index) + 1)
print(f"Tokens totales : {len(tokens):,}")
print(f"Palabras distintas : {len(tokenizer.word_index):,}")
print(f"Vocabulario del modelo: {vocab_size:,} (recortado a las más frecuentes)")
print("\nDiez palabras más frecuentes:")
for palabra, indice in list(tokenizer.word_index.items())[:10]:
print(f" {indice:>3} {palabra}")
Tokens totales : 73,979
Palabras distintas : 8,986
Vocabulario del modelo: 6,000 (recortado a las más frecuentes)
Diez palabras más frecuentes:
1 <OOV>
2 que
3 de
4 y
5 a
6 la
7 el
8 en
9 no
10 se
# ==================================================================
# 3.2 Dataset con ventanas deslizantes
# ==================================================================
X, y = [], []
for i in range(SEQ_LEN, len(tokens)):
X.append(tokens[i - SEQ_LEN:i]) # contexto
y.append(tokens[i]) # palabra siguiente
X = np.array(X, dtype=np.int32)
y = np.array(y, dtype=np.int32)
# División temporal (no aleatoria): el final del corpus queda como validación
FRAC_VAL = 0.15
corte = int(len(X) * (1 - FRAC_VAL))
X_tr, X_va = X[:corte], X[corte:]
y_tr, y_va = y[:corte], y[corte:]
BATCH = 128
AUTOTUNE = tf.data.AUTOTUNE
ds_train = (tf.data.Dataset.from_tensor_slices((X_tr, y_tr))
.shuffle(min(len(X_tr), 20000), seed=SEMILLA)
.batch(BATCH).prefetch(AUTOTUNE))
ds_val = (tf.data.Dataset.from_tensor_slices((X_va, y_va))
.batch(BATCH).prefetch(AUTOTUNE))
print(f"Ejemplos generados : {len(X):,}")
print(f"Entrenamiento : {len(X_tr):,}")
print(f"Validación : {len(X_va):,}")
print(f"Forma de X : {X.shape}")
print(f"\nEjemplo de contexto: {' '.join(tokenizer.index_word.get(t, '<OOV>') for t in X[0])}")
print(f"Palabra objetivo : {tokenizer.index_word.get(int(y[0]), '<OOV>')}")
Ejemplos generados : 73,959 Entrenamiento : 62,865 Validación : 11,094 Forma de X : (73959, 20) Ejemplo de contexto: en un lugar de la mancha vivía un hidalgo aficionado a los libros de caballerías y a las grandes aventuras Palabra objetivo : el
# ==================================================================
# 3.3 Arquitectura solicitada: Embedding -> LSTM(128) -> Dense(softmax)
# ==================================================================
modelo_palabra = Sequential([
Embedding(input_dim=vocab_size, output_dim=128, name="embedding"),
# 128 unidades internas; dropout regulariza sin añadir capas a la arquitectura pedida
LSTM(128, dropout=0.2, name="lstm_128"),
Dense(vocab_size, activation="softmax", name="salida_softmax"),
], name="LSTM_128_nivel_palabra")
modelo_palabra.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
modelo_palabra.build(input_shape=(None, SEQ_LEN))
modelo_palabra.summary()
Model: "LSTM_128_nivel_palabra"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ embedding (Embedding) │ (None, 20, 128) │ 768,000 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ lstm_128 (LSTM) │ (None, 128) │ 131,584 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ salida_softmax (Dense) │ (None, 6000) │ 774,000 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 1,673,584 (6.38 MB)
Trainable params: 1,673,584 (6.38 MB)
Non-trainable params: 0 (0.00 B)
# ==================================================================
# 3.4 Muestreo con temperatura y top-k
# ==================================================================
# Índices que nunca queremos emitir: 0 es el relleno del padding y 1 es <OOV>.
# Excluirlos en la inferencia no cambia el modelo, solo evita que el texto generado
# se llene de marcadores que no son palabras reales.
PROHIBIDOS = (0, 1)
def muestrear(probabilidades, k=30, temperatura=1.0):
"""Elige un índice aplicando primero temperatura y luego top-k."""
p = np.asarray(probabilidades).astype(np.float64)
# Se anulan padding y <OOV> antes de renormalizar
for indice in PROHIBIDOS:
if indice < len(p):
p[indice] = 0.0
p = p / p.sum()
# Temperatura: aplana o agudiza la distribución
logits = np.log(p + 1e-12) / max(temperatura, 1e-6)
p = np.exp(logits - logits.max())
p /= p.sum()
# Top-k: se muestrea solo entre las k opciones más probables
k = min(k, len(p))
indices = np.argpartition(p, -k)[-k:]
probs_k = p[indices] / p[indices].sum()
return int(np.random.choice(indices, p=probs_k))
def generar_palabras(semilla, n_palabras=25, k=30, temperatura=0.8):
"""Genera texto palabra a palabra a partir de una frase semilla."""
generado = str(semilla).strip()
for _ in range(n_palabras):
secuencia = tokenizer.texts_to_sequences([generado])[0][-SEQ_LEN:]
entrada = pad_sequences([secuencia], maxlen=SEQ_LEN, padding="pre")
# model(...) en lugar de model.predict(...): mucho más rápido en bucles cortos
probas = modelo_palabra(entrada, training=False).numpy()[0]
generado += " " + tokenizer.index_word.get(muestrear(probas, k, temperatura), "<OOV>")
return generado
def top_k_siguiente(semilla, k=5):
"""Devuelve las k palabras más probables tras la frase dada."""
secuencia = tokenizer.texts_to_sequences([semilla])[0][-SEQ_LEN:]
entrada = pad_sequences([secuencia], maxlen=SEQ_LEN, padding="pre")
probas = modelo_palabra(entrada, training=False).numpy()[0]
mejores = [i for i in np.argsort(probas)[::-1] if i not in PROHIBIDOS][:k]
return [(tokenizer.index_word.get(int(i), "<OOV>"), float(probas[i])) for i in mejores]
# ==================================================================
# 3.5 Callback: métricas y generación de texto en CADA época
# (requisito 4 del enunciado)
# ==================================================================
TEMPERATURAS = [0.3, 0.7, 1.0, 1.2]
SEMILLA_DEMO = "el caballero andante se lanzó a la aventura"
registro_epocas = [] # se conserva para el informe escrito
class GeneracionPorEpoca(tf.keras.callbacks.Callback):
def __init__(self, semilla, n_palabras=22):
super().__init__()
self.semilla = semilla
self.n_palabras = n_palabras
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
print("\n" + "=" * 74)
print(f"GENERACIÓN DESPUÉS DE LA ÉPOCA {epoch + 1}")
print("=" * 74)
print(f"loss={logs.get('loss', 0):.4f} | val_loss={logs.get('val_loss', 0):.4f} | "
f"accuracy={logs.get('accuracy', 0):.4f} | val_accuracy={logs.get('val_accuracy', 0):.4f}")
muestras = {}
for temperatura in TEMPERATURAS:
texto = generar_palabras(self.semilla, self.n_palabras, k=30, temperatura=temperatura)
muestras[str(temperatura)] = texto
print(f"\n[T = {temperatura}] {texto}")
print("=" * 74)
registro_epocas.append({
"epoca": epoch + 1,
"loss": float(logs.get("loss", 0)),
"val_loss": float(logs.get("val_loss", 0)),
"accuracy": float(logs.get("accuracy", 0)),
"val_accuracy": float(logs.get("val_accuracy", 0)),
"textos": muestras,
})
callbacks_palabra = [
GeneracionPorEpoca(SEMILLA_DEMO),
tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.5,
patience=3, min_lr=1e-5, verbose=1),
tf.keras.callbacks.ModelCheckpoint("mejor_lstm_palabra.keras", monitor="val_loss",
save_best_only=True, verbose=0),
]
# ==================================================================
# 3.6 Entrenamiento completo (salida época a época)
# ==================================================================
EPOCAS_PALABRA = 30
inicio = time.time()
historia_palabra = modelo_palabra.fit(
ds_train,
validation_data=ds_val,
epochs=EPOCAS_PALABRA,
callbacks=callbacks_palabra,
shuffle=False, # el barajado ya lo hace tf.data
verbose=2,
)
print(f"\nTiempo total de entrenamiento: {time.time() - inicio:.1f} s")
Epoch 1/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 1 ========================================================================== loss=6.4233 | val_loss=5.9385 | accuracy=0.0636 | val_accuracy=0.0964
[T = 0.3] el caballero andante se lanzó a la aventura y su la la la la el la la la él que que la la no la la la la la los
[T = 0.7] el caballero andante se lanzó a la aventura a en la la bien y la caballero don se lo que que que no — — la es a bien en
[T = 1.0] el caballero andante se lanzó a la aventura en la con la el le los de que que su lo es por tan se el más de a en la
[T = 1.2] el caballero andante se lanzó a la aventura tan de bien se y sancho más que a no y — si le que a en él no no y la ========================================================================== 492/492 - 15s - 31ms/step - accuracy: 0.0636 - loss: 6.4233 - val_accuracy: 0.0964 - val_loss: 5.9385 - learning_rate: 0.0010
Epoch 2/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 2 ========================================================================== loss=5.9909 | val_loss=5.8012 | accuracy=0.0772 | val_accuracy=0.1025
[T = 0.3] el caballero andante se lanzó a la aventura que el las merced que la la vida y la caballero y no la su amo que el la rey y el
[T = 0.7] el caballero andante se lanzó a la aventura y las que que me que de las más le de las cual el los y que que sus caballero y los
[T = 1.0] el caballero andante se lanzó a la aventura porque el que no la caballero y vuestra la ser y el cabeza es las ser es es que le asno el
[T = 1.2] el caballero andante se lanzó a la aventura la mundo de la ser de su había con el camino que lo con es y con mí le otro del me ========================================================================== 492/492 - 15s - 30ms/step - accuracy: 0.0772 - loss: 5.9909 - val_accuracy: 0.1025 - val_loss: 5.8012 - learning_rate: 0.0010
Epoch 3/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 3 ========================================================================== loss=5.7922 | val_loss=5.7170 | accuracy=0.0899 | val_accuracy=0.1070
[T = 0.3] el caballero andante se lanzó a la aventura de la que la noche y no que no no que no no no el que la caballero y y que el
[T = 0.7] el caballero andante se lanzó a la aventura que si su ha y que a aquel le la armas y a la la otro que y la ha que no
[T = 1.0] el caballero andante se lanzó a la aventura de la suelo de él las vida y que si que me caballero al tiempo que me rey de sí que es
[T = 1.2] el caballero andante se lanzó a la aventura que a se que él no yo que a las ha y los más con él su asno de sus señor — ========================================================================== 492/492 - 14s - 29ms/step - accuracy: 0.0899 - loss: 5.7922 - val_accuracy: 0.1070 - val_loss: 5.7170 - learning_rate: 0.0010
Epoch 4/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 4 ========================================================================== loss=5.6167 | val_loss=5.6355 | accuracy=0.1057 | val_accuracy=0.1227
[T = 0.3] el caballero andante se lanzó a la aventura que no no me le de la que se le de la cual se había que le había de la amo y
[T = 0.7] el caballero andante se lanzó a la aventura tan de su amo un suelo que en mi cual de su manera y por merced en sus que por el escudero
[T = 1.0] el caballero andante se lanzó a la aventura que era la suelo pero a aquel amo — me la camino con la amo y bien que los días para su
[T = 1.2] el caballero andante se lanzó a la aventura y me puede lo andantes sino y de los rey y más a los más de el rey el cielo le había ========================================================================== 492/492 - 14s - 28ms/step - accuracy: 0.1057 - loss: 5.6167 - val_accuracy: 0.1227 - val_loss: 5.6355 - learning_rate: 0.0010
Epoch 5/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 5 ========================================================================== loss=5.4557 | val_loss=5.5894 | accuracy=0.1220 | val_accuracy=0.1270
[T = 0.3] el caballero andante se lanzó a la aventura que no no le le de su amo de la parte de las que se ha de las cuales me le de
[T = 0.7] el caballero andante se lanzó a la aventura el buen que la parte y sin la cual de la manera que si me de mí con la cual no me
[T = 1.0] el caballero andante se lanzó a la aventura que lo que con merced que se ha —respondió don se aun en lo que le había de la escudero — me
[T = 1.2] el caballero andante se lanzó a la aventura de mi caballero de don quijote sobre el escudero que a una cosa que se le más de don quijote de aquel ========================================================================== 492/492 - 14s - 29ms/step - accuracy: 0.1220 - loss: 5.4557 - val_accuracy: 0.1270 - val_loss: 5.5894 - learning_rate: 0.0010
Epoch 6/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 6 ========================================================================== loss=5.3171 | val_loss=5.5690 | accuracy=0.1369 | val_accuracy=0.1324
[T = 0.3] el caballero andante se lanzó a la aventura y se le ha de la mano y no me ha de la cual se de los que se me me había
[T = 0.7] el caballero andante se lanzó a la aventura que era el cuerpo y que a que nos dijo y que ya más como en todo la mancha — por la
[T = 1.0] el caballero andante se lanzó a la aventura en que eso — te me ha de lo de los aventuras como que él como no tengo por un rey y
[T = 1.2] el caballero andante se lanzó a la aventura no de que le le han visto en aquella castillo por lo del cual había del cuerpo que él no ha leído ========================================================================== 492/492 - 15s - 30ms/step - accuracy: 0.1369 - loss: 5.3171 - val_accuracy: 0.1324 - val_loss: 5.5690 - learning_rate: 0.0010
Epoch 7/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 7 ========================================================================== loss=5.1894 | val_loss=5.5561 | accuracy=0.1466 | val_accuracy=0.1365
[T = 0.3] el caballero andante se lanzó a la aventura y que se había que no es que se le pareció que se me había de la escudero y no se dijo
[T = 0.7] el caballero andante se lanzó a la aventura de un señora y que yo te debe de la asno y a poco y se ha de la mancha y no
[T = 1.0] el caballero andante se lanzó a la aventura y por dios sino el que se le parece y bien no he estado su jumento si a las manos y tan
[T = 1.2] el caballero andante se lanzó a la aventura con la noche y la caballería ni la orden — le me le me dijo — dijo — no digo que es ========================================================================== 492/492 - 18s - 36ms/step - accuracy: 0.1466 - loss: 5.1894 - val_accuracy: 0.1365 - val_loss: 5.5561 - learning_rate: 0.0010
Epoch 8/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 8 ========================================================================== loss=5.0705 | val_loss=5.5494 | accuracy=0.1558 | val_accuracy=0.1376
[T = 0.3] el caballero andante se lanzó a la aventura y no lo que no se ha de la vida de la venta y no se me ha de la cual se
[T = 0.7] el caballero andante se lanzó a la aventura — como más sino por el barbero que no me hay que no le dijo — no no parece de la cabeza
[T = 1.0] el caballero andante se lanzó a la aventura — no lo ha dicho no la vista con los años que de los caballeros del caballero a las cuales se le
[T = 1.2] el caballero andante se lanzó a la aventura y si por la vida y así en su mano — así en la asno y su señor y aun le puede ========================================================================== 492/492 - 21s - 43ms/step - accuracy: 0.1558 - loss: 5.0705 - val_accuracy: 0.1376 - val_loss: 5.5494 - learning_rate: 0.0010
Epoch 9/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 9 ========================================================================== loss=4.9563 | val_loss=5.5484 | accuracy=0.1609 | val_accuracy=0.1412
[T = 0.3] el caballero andante se lanzó a la aventura y a la cabeza y no se le dijo — no me he hecho y de la cabeza y así que se
[T = 0.7] el caballero andante se lanzó a la aventura se había leído y no había de la mancha el mesmo que los pies de los que se lo que no tengo
[T = 1.0] el caballero andante se lanzó a la aventura que el cabo se había dado por lo que no ha de sancho para su amo ni aun los que me han
[T = 1.2] el caballero andante se lanzó a la aventura el ventero o el pobre real y a la tierra el otro por vuestra las riendas a la mano en su manera ========================================================================== 492/492 - 25s - 50ms/step - accuracy: 0.1609 - loss: 4.9563 - val_accuracy: 0.1412 - val_loss: 5.5484 - learning_rate: 0.0010
Epoch 10/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 10 ========================================================================== loss=4.8504 | val_loss=5.5556 | accuracy=0.1668 | val_accuracy=0.1411
[T = 0.3] el caballero andante se lanzó a la aventura que se le había de la vida que se ha de la mancha que lo que yo digo que se le de
[T = 0.7] el caballero andante se lanzó a la aventura que a la mancha don quijote y comenzó a mi que se le han de la vida con su voluntad y dijo
[T = 1.0] el caballero andante se lanzó a la aventura que la infanta le puso toda su que la falta a lo que ya más —respondió su amo y no la cabeza
[T = 1.2] el caballero andante se lanzó a la aventura como más que le dieron la infanta se puede dar tan que se le vino a todas de la mano porque lo ========================================================================== 492/492 - 24s - 49ms/step - accuracy: 0.1668 - loss: 4.8504 - val_accuracy: 0.1411 - val_loss: 5.5556 - learning_rate: 0.0010
Epoch 11/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 11 ========================================================================== loss=4.7510 | val_loss=5.5636 | accuracy=0.1720 | val_accuracy=0.1412
[T = 0.3] el caballero andante se lanzó a la aventura que no se había de su amo y no se ha de ser que no hay que no se le haga por
[T = 0.7] el caballero andante se lanzó a la aventura y así el que yo es caballero y así es que le parece que no es lo que yo te parece que
[T = 1.0] el caballero andante se lanzó a la aventura el buen castillo y dijo — de ser lo que ya no la lanza a sus razones que ya hay a otro
[T = 1.2] el caballero andante se lanzó a la aventura porque le ha hecho al ventero a que le dieron los golpes o así sancho que dios y se me me es ========================================================================== 492/492 - 21s - 43ms/step - accuracy: 0.1720 - loss: 4.7510 - val_accuracy: 0.1412 - val_loss: 5.5636 - learning_rate: 0.0010
Epoch 12/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 12 ========================================================================== loss=4.6527 | val_loss=5.5899 | accuracy=0.1771 | val_accuracy=0.1411
[T = 0.3] el caballero andante se lanzó a la aventura que se le dijo — no me ha de los caballeros andantes y que no se ha de ser que me ha
[T = 0.7] el caballero andante se lanzó a la aventura que tenía los hombros y aun con lo que se fue a las manos por la puerta de la tierra y sin
[T = 1.0] el caballero andante se lanzó a la aventura le parecían hecho que es su escudero es su amo porque con todo su asno como todo él con el rey mundo
[T = 1.2] el caballero andante se lanzó a la aventura pero le habían de allí con el mundo y las espaldas — no lo que con todo no era caballero pero en ========================================================================== Epoch 12: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257.
492/492 - 20s - 40ms/step - accuracy: 0.1771 - loss: 4.6527 - val_accuracy: 0.1411 - val_loss: 5.5899 - learning_rate: 0.0010
Epoch 13/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 13 ========================================================================== loss=4.5216 | val_loss=5.6032 | accuracy=0.1839 | val_accuracy=0.1412
[T = 0.3] el caballero andante se lanzó a la aventura que no se había de ser que se le pareció que en la cabeza y no lo había sido en la venta
[T = 0.7] el caballero andante se lanzó a la aventura y fue que el tiempo que los acometía y en todo no le había dado y así como no sé que no
[T = 1.0] el caballero andante se lanzó a la aventura es que él le dio de mi asno y él se podía el cual se había sido por la mitad de sus
[T = 1.2] el caballero andante se lanzó a la aventura que tenía la venta las dos figura y a los brazos — ya el de mi buen lugar que era caballero y ========================================================================== 492/492 - 19s - 39ms/step - accuracy: 0.1839 - loss: 4.5216 - val_accuracy: 0.1412 - val_loss: 5.6032 - learning_rate: 5.0000e-04
Epoch 14/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 14 ========================================================================== loss=4.4688 | val_loss=5.6147 | accuracy=0.1876 | val_accuracy=0.1415
[T = 0.3] el caballero andante se lanzó a la aventura que se le había dado que no se había de la tierra y a la vida que no se ha de ser
[T = 0.7] el caballero andante se lanzó a la aventura que no él se le ha de los padres con la orden de la mancha que la suerte se les dio la
[T = 1.0] el caballero andante se lanzó a la aventura y a las feridas no se fue que es caballero de don quijote las famosas dos razones que con el cual se
[T = 1.2] el caballero andante se lanzó a la aventura y por estos y si a todas un lugar que era mucho el que los ojos de los caballeros andantes que me ========================================================================== 492/492 - 18s - 37ms/step - accuracy: 0.1876 - loss: 4.4688 - val_accuracy: 0.1415 - val_loss: 5.6147 - learning_rate: 5.0000e-04
Epoch 15/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 15 ========================================================================== loss=4.4178 | val_loss=5.6424 | accuracy=0.1892 | val_accuracy=0.1435
[T = 0.3] el caballero andante se lanzó a la aventura que la causa de la mancha que se llamaba el cual se le dio en el suelo y de la ciudad de
[T = 0.7] el caballero andante se lanzó a la aventura que no le han contado y con una manera que vuestra merced señor caballero —dijo don quijote— que no la suerte —dijo
[T = 1.0] el caballero andante se lanzó a la aventura por vuestra merced dice que no ha leído más de más días sin mi señor moro sancho que no han recebido es
[T = 1.2] el caballero andante se lanzó a la aventura que con estos que he llegado al mundo a don quijote que vio que por esto y no me ha echado le ========================================================================== Epoch 15: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628.
492/492 - 17s - 35ms/step - accuracy: 0.1892 - loss: 4.4178 - val_accuracy: 0.1435 - val_loss: 5.6424 - learning_rate: 5.0000e-04
Epoch 16/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 16 ========================================================================== loss=4.3494 | val_loss=5.6510 | accuracy=0.1947 | val_accuracy=0.1431
[T = 0.3] el caballero andante se lanzó a la aventura que le había dado que no se le había de la tierra y le había de los caballeros andantes se le había
[T = 0.7] el caballero andante se lanzó a la aventura que se había dado a la mesma pecho con la venta y al caballero y el ventero y así por la cual
[T = 1.0] el caballero andante se lanzó a la aventura que me da que la más le parecía que no se había hecho un asno y luego por ser en su señora
[T = 1.2] el caballero andante se lanzó a la aventura que me han dado porque como las veces le podía hallar si no lo tengo dicho no la cuenta de sus de ========================================================================== 492/492 - 17s - 35ms/step - accuracy: 0.1947 - loss: 4.3494 - val_accuracy: 0.1431 - val_loss: 5.6510 - learning_rate: 2.5000e-04
Epoch 17/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 17 ========================================================================== loss=4.3211 | val_loss=5.6681 | accuracy=0.1965 | val_accuracy=0.1427
[T = 0.3] el caballero andante se lanzó a la aventura que se le dio a la tierra y con la venta que no se ha de ser que si se le había
[T = 0.7] el caballero andante se lanzó a la aventura que en el caballero del famoso y de su amo que no lo había vuelto en la venta con la cual se
[T = 1.0] el caballero andante se lanzó a la aventura que en qué paraba alguna y dijo — ¿qué eso yo tengo dicho para duda y de ser caballero porque yo me
[T = 1.2] el caballero andante se lanzó a la aventura con la boca a sancho y de lo que habían dicho fuera a la caballería y por el valor pero en la ========================================================================== 492/492 - 19s - 38ms/step - accuracy: 0.1965 - loss: 4.3211 - val_accuracy: 0.1427 - val_loss: 5.6681 - learning_rate: 2.5000e-04
Epoch 18/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 18 ========================================================================== loss=4.2950 | val_loss=5.6835 | accuracy=0.1988 | val_accuracy=0.1421
[T = 0.3] el caballero andante se lanzó a la aventura que no se le pareció que no se le pareció que se le pareció que se llamaba el cual dio el ventero
[T = 0.7] el caballero andante se lanzó a la aventura como es bien que era la cabeza de lo que les respondió don quijote que ya se lo había hecho un poco
[T = 1.0] el caballero andante se lanzó a la aventura que su amo y con la venta le puso en todo el cuello por los árboles y se fue que a poco
[T = 1.2] el caballero andante se lanzó a la aventura que tenía al camino que es menester y a lo que le podía dejar sin poco en el rey y así como ========================================================================== Epoch 18: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814.
492/492 - 19s - 38ms/step - accuracy: 0.1988 - loss: 4.2950 - val_accuracy: 0.1421 - val_loss: 5.6835 - learning_rate: 2.5000e-04
Epoch 19/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 19 ========================================================================== loss=4.2591 | val_loss=5.6924 | accuracy=0.2000 | val_accuracy=0.1433
[T = 0.3] el caballero andante se lanzó a la aventura que en la venta y a la cabeza y con las leyes de la tierra y así de la venta y a
[T = 0.7] el caballero andante se lanzó a la aventura a la venta y de la mancha y no había menester que se había visto una desgracia que su amo y el
[T = 1.0] el caballero andante se lanzó a la aventura me puso la moza con la cabeza tan más sin camino de la venta con el escudo la puerta de su amo
[T = 1.2] el caballero andante se lanzó a la aventura del castillo a buscar que si él se puede mover y así fue a entender que me he menester que me parece ========================================================================== 492/492 - 19s - 38ms/step - accuracy: 0.2000 - loss: 4.2591 - val_accuracy: 0.1433 - val_loss: 5.6924 - learning_rate: 1.2500e-04
Epoch 20/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 20 ========================================================================== loss=4.2452 | val_loss=5.7024 | accuracy=0.2011 | val_accuracy=0.1422
[T = 0.3] el caballero andante se lanzó a la aventura que se llamaba el cual se le pareció que se le había dado que le había de los caballeros andantes y sin
[T = 0.7] el caballero andante se lanzó a la aventura que si tengo de hacer y no se le había levantado que los demás se le pusieron con sus manos de que
[T = 1.0] el caballero andante se lanzó a la aventura sin que a quien él los veces tan mala tan bien si me ha puesto que no podía hacer caballero como no
[T = 1.2] el caballero andante se lanzó a la aventura y en las leyes de hacer más y él le vino a caballo de mis ojos estaban con todo esto sancho panza ========================================================================== 492/492 - 19s - 40ms/step - accuracy: 0.2011 - loss: 4.2452 - val_accuracy: 0.1422 - val_loss: 5.7024 - learning_rate: 1.2500e-04
Epoch 21/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 21 ========================================================================== loss=4.2307 | val_loss=5.7144 | accuracy=0.2018 | val_accuracy=0.1421
[T = 0.3] el caballero andante se lanzó a la aventura que le habían de la mano y con la venta y a la memoria de los que se le pareció que le
[T = 0.7] el caballero andante se lanzó a la aventura que por lo que es bien la culpa de los caballeros andantes comiesen señor caballero panza en esta batalla de los demás
[T = 1.0] el caballero andante se lanzó a la aventura y a todo género se fue a la mancha hasta todos las libros de la caballería como por ser de su caballero
[T = 1.2] el caballero andante se lanzó a la aventura pero como no no tengo ni hacer ser bien —dijo vivaldo y sin duda ni se murmura que se lo tengo a ========================================================================== Epoch 21: ReduceLROnPlateau reducing learning rate to 6.25000029685907e-05.
492/492 - 19s - 38ms/step - accuracy: 0.2018 - loss: 4.2307 - val_accuracy: 0.1421 - val_loss: 5.7144 - learning_rate: 1.2500e-04
Epoch 22/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 22 ========================================================================== loss=4.2118 | val_loss=5.7201 | accuracy=0.2034 | val_accuracy=0.1420
[T = 0.3] el caballero andante se lanzó a la aventura que se le había de ser que se le pareció que se me ha de la mano con el mundo y a
[T = 0.7] el caballero andante se lanzó a la aventura que no me acuerdo lo que los demás le había andado la caballería que ya le podía la tierra al tiempo y
[T = 1.0] el caballero andante se lanzó a la aventura que no me parece que de los tales caballeros ponemos en ellos que él le parecía y para su amo fue el
[T = 1.2] el caballero andante se lanzó a la aventura — ¿cómo tengo —dijo sancho— sino que he dado con él porque le pareció que más no lo dije yo —dijo el ========================================================================== 492/492 - 19s - 39ms/step - accuracy: 0.2034 - loss: 4.2118 - val_accuracy: 0.1420 - val_loss: 5.7201 - learning_rate: 6.2500e-05
Epoch 23/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 23 ========================================================================== loss=4.2040 | val_loss=5.7275 | accuracy=0.2040 | val_accuracy=0.1418
[T = 0.3] el caballero andante se lanzó a la aventura que se le representó que no se le pareció que se le pareció que en el mundo y no hay que se
[T = 0.7] el caballero andante se lanzó a la aventura que le dio de la mancha el cual dijo — por no he de ser y aun vuestra merced señor caballero de
[T = 1.0] el caballero andante se lanzó a la aventura no había muerto y del amor que la lanza por a quien los años de la venta sin ver el cura pero
[T = 1.2] el caballero andante se lanzó a la aventura que estaba por él y a rocinante pero la paga — calla pero no sé que tengo es que de que si ========================================================================== 492/492 - 20s - 40ms/step - accuracy: 0.2040 - loss: 4.2040 - val_accuracy: 0.1418 - val_loss: 5.7275 - learning_rate: 6.2500e-05
Epoch 24/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 24 ========================================================================== loss=4.1974 | val_loss=5.7347 | accuracy=0.2032 | val_accuracy=0.1420
[T = 0.3] el caballero andante se lanzó a la aventura que no se había dado a su amo y así como el cual se le pareció que se le había dado luego
[T = 0.7] el caballero andante se lanzó a la aventura y sin duda —respondió don quijote el que se llamaba el cielo y con esto se cuentan en las riendas de su
[T = 1.0] el caballero andante se lanzó a la aventura y con todo ello el otro caballero que es menester acertar a una encina y que no se era y de vuestra
[T = 1.2] el caballero andante se lanzó a la aventura que le dio en su recua y la venta y que se detenga el ventero y así le molió era caballero del ========================================================================== Epoch 24: ReduceLROnPlateau reducing learning rate to 3.125000148429535e-05.
492/492 - 20s - 40ms/step - accuracy: 0.2032 - loss: 4.1974 - val_accuracy: 0.1420 - val_loss: 5.7347 - learning_rate: 6.2500e-05
Epoch 25/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 25 ========================================================================== loss=4.1879 | val_loss=5.7385 | accuracy=0.2038 | val_accuracy=0.1419
[T = 0.3] el caballero andante se lanzó a la aventura que le pareció que se le había de la mancha por la venta y a los que se le pagaba que no
[T = 0.7] el caballero andante se lanzó a la aventura que era por las historias de su amo y con las entrañas del camino que de la noche de la caballería como
[T = 1.0] el caballero andante se lanzó a la aventura si no era el otro caballero andante que la causa me me acuerdo la historia sino a su castillo por los de
[T = 1.2] el caballero andante se lanzó a la aventura que le respondió esto don quijote y que se ha de la mesma historia de don quijote — no es menester —dijo ========================================================================== 492/492 - 18s - 37ms/step - accuracy: 0.2038 - loss: 4.1879 - val_accuracy: 0.1419 - val_loss: 5.7385 - learning_rate: 3.1250e-05
Epoch 26/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 26 ========================================================================== loss=4.1834 | val_loss=5.7428 | accuracy=0.2037 | val_accuracy=0.1416
[T = 0.3] el caballero andante se lanzó a la aventura que era el cielo y de la mancha que no se ha dicho que no le representó que no se me ha
[T = 0.7] el caballero andante se lanzó a la aventura a la corte de su amo y no saben entonces que le pareció que él le han puesto que fue más del
[T = 1.0] el caballero andante se lanzó a la aventura que se resintió por el día don quijote y que estaba en la mancha por el cual dijo — ¿qué será menester
[T = 1.2] el caballero andante se lanzó a la aventura porque no se ha sacado es la mano y le decía porque es mucho tiempo a lo demás casi las armas y ========================================================================== 492/492 - 17s - 34ms/step - accuracy: 0.2037 - loss: 4.1834 - val_accuracy: 0.1416 - val_loss: 5.7428 - learning_rate: 3.1250e-05
Epoch 27/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 27 ========================================================================== loss=4.1805 | val_loss=5.7470 | accuracy=0.2047 | val_accuracy=0.1415
[T = 0.3] el caballero andante se lanzó a la aventura que la boca y por la sepultura y así se le había de la mancha el cielo y se le pareció que
[T = 0.7] el caballero andante se lanzó a la aventura que era el mundo a su asno y no se había de la venta y que le decía que yo no ha
[T = 1.0] el caballero andante se lanzó a la aventura que en esta parte se me habían preguntado lo más dan al mundo que los ojos se pusiese sancho— que no me
[T = 1.2] el caballero andante se lanzó a la aventura que ya está si la de dar las manos detrás de las cabras que no lo haré que se llamaba el tiempo ========================================================================== Epoch 27: ReduceLROnPlateau reducing learning rate to 1.5625000742147677e-05.
492/492 - 17s - 34ms/step - accuracy: 0.2047 - loss: 4.1805 - val_accuracy: 0.1415 - val_loss: 5.7470 - learning_rate: 3.1250e-05
Epoch 28/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 28 ========================================================================== loss=4.1761 | val_loss=5.7495 | accuracy=0.2041 | val_accuracy=0.1415
[T = 0.3] el caballero andante se lanzó a la aventura que no se me acuerdo en las manos y con un poco de la mancha y de los que se le representó
[T = 0.7] el caballero andante se lanzó a la aventura que fue a vuestra merced y así es el otro que de todo esto se quejaba y que le podía apear y
[T = 1.0] el caballero andante se lanzó a la aventura y luego los caballeros andantes que fue que el mundo se había prometido cuando con esta manera me han mirado no hay
[T = 1.2] el caballero andante se lanzó a la aventura que él era caballero pero con tanta brevedad — ¿qué se parece —respondió sancho y la lanza dijo don quijote de todo ========================================================================== 492/492 - 18s - 36ms/step - accuracy: 0.2041 - loss: 4.1761 - val_accuracy: 0.1415 - val_loss: 5.7495 - learning_rate: 1.5625e-05
Epoch 29/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 29 ========================================================================== loss=4.1736 | val_loss=5.7518 | accuracy=0.2050 | val_accuracy=0.1412
[T = 0.3] el caballero andante se lanzó a la aventura que el ventero en el suelo y con todo esto se le pareció que se ha de ser que se le pagaba
[T = 0.7] el caballero andante se lanzó a la aventura que no se ha de los libros de sus dos del buen suceso y de la vida y así es que si
[T = 1.0] el caballero andante se lanzó a la aventura que no era bien en el mundo y su amo se la boca o en la tierra por una vez habían dicho
[T = 1.2] el caballero andante se lanzó a la aventura que no quiero pasar ni ha de saber que le dejó a buscar las barbas se les tenían y como se le ========================================================================== 492/492 - 20s - 40ms/step - accuracy: 0.2050 - loss: 4.1736 - val_accuracy: 0.1412 - val_loss: 5.7518 - learning_rate: 1.5625e-05
Epoch 30/30
========================================================================== GENERACIÓN DESPUÉS DE LA ÉPOCA 30 ========================================================================== loss=4.1717 | val_loss=5.7540 | accuracy=0.2047 | val_accuracy=0.1411
[T = 0.3] el caballero andante se lanzó a la aventura que le pareció que se le representó que se le ha de ser de la mancha y que se llamaba el cual
[T = 0.7] el caballero andante se lanzó a la aventura por ella no hay dos y aun las aventuras no se había estado en el suelo con la cabeza y los que
[T = 1.0] el caballero andante se lanzó a la aventura el cuerpo a los caballeros del toboso y allí se habían puesto que allí le parece a lo que yo no había
[T = 1.2] el caballero andante se lanzó a la aventura que no está en ninguna de aquella noche es y el valeroso don quijote lo cual estaba una que en él se ========================================================================== Epoch 30: ReduceLROnPlateau reducing learning rate to 1e-05.
492/492 - 19s - 39ms/step - accuracy: 0.2047 - loss: 4.1717 - val_accuracy: 0.1411 - val_loss: 5.7540 - learning_rate: 1.5625e-05
Tiempo total de entrenamiento: 547.7 s
# ==================================================================
# 3.7 Curvas de aprendizaje
# ==================================================================
h = historia_palabra.history
fig, ejes = plt.subplots(1, 2, figsize=(13, 4.5))
ejes[0].plot(h["loss"], label="entrenamiento", linewidth=2)
ejes[0].plot(h["val_loss"], label="validación", linewidth=2, linestyle="--")
ejes[0].set_title("Pérdida — modelo a nivel de palabra")
ejes[0].set_xlabel("Época"); ejes[0].set_ylabel("Loss")
ejes[0].legend(); ejes[0].grid(alpha=0.3)
ejes[1].plot(h["accuracy"], label="entrenamiento", linewidth=2)
ejes[1].plot(h["val_accuracy"], label="validación", linewidth=2, linestyle="--")
ejes[1].set_title("Precisión — modelo a nivel de palabra")
ejes[1].set_xlabel("Época"); ejes[1].set_ylabel("Accuracy")
ejes[1].legend(); ejes[1].grid(alpha=0.3)
plt.tight_layout()
plt.savefig("fig_curvas_palabra.png", dpi=150, bbox_inches="tight")
plt.show()
print(f"loss : {h['loss'][0]:.4f} -> {h['loss'][-1]:.4f}")
print(f"accuracy : {h['accuracy'][0]:.4f} -> {h['accuracy'][-1]:.4f}")
print(f"val_loss : {h['val_loss'][0]:.4f} -> {h['val_loss'][-1]:.4f} (mínimo: {min(h['val_loss']):.4f})")
loss : 6.4233 -> 4.1717 accuracy : 0.0636 -> 0.2047 val_loss : 5.9385 -> 5.7540 (mínimo: 5.5484)
# ==================================================================
# 3.8 Tabla resumen del entrenamiento
# ==================================================================
print(f"{'Época':>6} {'loss':>10} {'val_loss':>10} {'accuracy':>10} {'val_acc':>10}")
print("-" * 50)
for i in range(len(h["loss"])):
print(f"{i + 1:>6} {h['loss'][i]:>10.4f} {h['val_loss'][i]:>10.4f} "
f"{h['accuracy'][i]:>10.4f} {h['val_accuracy'][i]:>10.4f}")
Época loss val_loss accuracy val_acc
--------------------------------------------------
1 6.4233 5.9385 0.0636 0.0964
2 5.9909 5.8012 0.0772 0.1025
3 5.7922 5.7170 0.0899 0.1070
4 5.6167 5.6355 0.1057 0.1227
5 5.4557 5.5894 0.1220 0.1270
6 5.3171 5.5690 0.1369 0.1324
7 5.1894 5.5561 0.1466 0.1365
8 5.0705 5.5494 0.1558 0.1376
9 4.9563 5.5484 0.1609 0.1412
10 4.8504 5.5556 0.1668 0.1411
11 4.7510 5.5636 0.1720 0.1412
12 4.6527 5.5899 0.1771 0.1411
13 4.5216 5.6032 0.1839 0.1412
14 4.4688 5.6147 0.1876 0.1415
15 4.4178 5.6424 0.1892 0.1435
16 4.3494 5.6510 0.1947 0.1431
17 4.3211 5.6681 0.1965 0.1427
18 4.2950 5.6835 0.1988 0.1421
19 4.2591 5.6924 0.2000 0.1433
20 4.2452 5.7024 0.2011 0.1422
21 4.2307 5.7144 0.2018 0.1421
22 4.2118 5.7201 0.2034 0.1420
23 4.2040 5.7275 0.2040 0.1418
24 4.1974 5.7347 0.2032 0.1420
25 4.1879 5.7385 0.2038 0.1419
26 4.1834 5.7428 0.2037 0.1416
27 4.1805 5.7470 0.2047 0.1415
28 4.1761 5.7495 0.2041 0.1415
29 4.1736 5.7518 0.2050 0.1412
30 4.1717 5.7540 0.2047 0.1411
# ==================================================================
# 3.9 Predicción de la siguiente palabra y comparación de temperaturas
# ==================================================================
consultas = [
"en un lugar de la mancha de cuyo",
"el caballero andante se lanzó a la",
"sancho panza dijo a su",
]
for consulta in consultas:
print(f"\nConsulta: '{consulta}'")
for palabra, probabilidad in top_k_siguiente(consulta, k=5):
print(f" {palabra:<18} p = {probabilidad:.4f}")
print("\n" + "=" * 74)
print("COMPARACIÓN FINAL DE TEMPERATURAS (modelo a nivel de palabra)")
print("=" * 74)
comparacion_palabra = {}
for temperatura in TEMPERATURAS:
texto = generar_palabras(SEMILLA_DEMO, n_palabras=40, k=30, temperatura=temperatura)
comparacion_palabra[str(temperatura)] = texto
print(f"\n[T = {temperatura}]\n{texto}")
Consulta: 'en un lugar de la mancha de cuyo' caballero p = 0.0242 señor p = 0.0228 lugar p = 0.0172 buen p = 0.0152 corazón p = 0.0141 Consulta: 'el caballero andante se lanzó a la' venta p = 0.0338 mancha p = 0.0280 cabeza p = 0.0249 tierra p = 0.0233 boca p = 0.0216 Consulta: 'sancho panza dijo a su' amo p = 0.0720 escudero p = 0.0300 asno p = 0.0209 señora p = 0.0147 caballo p = 0.0129 ========================================================================== COMPARACIÓN FINAL DE TEMPERATURAS (modelo a nivel de palabra) ==========================================================================
[T = 0.3] el caballero andante se lanzó a la aventura que la pierda el galeote— que no le había de la mancha que me ha de la vida de la mancha que no me ha de la mancha que no me ha de ser que no me ha de ser
[T = 0.7] el caballero andante se lanzó a la aventura que era bien a su tierra con él y así se le sucedió a buscar y a su parte con la cabeza que él le había leído en mucha priesa que en facilidad adelante sino lo que le dio por
[T = 1.0] el caballero andante se lanzó a la aventura que era un camino que le pusieron un poco la espada al día por las razones a sus aventuras le dijo — no sea bien sino que él te faltan yo a él se había dado luego en la causa
[T = 1.2] el caballero andante se lanzó a la aventura no tengo menester lo mejor lo que más no le hizo de la espada — bien se pierde el galeote— del mundo porque no es nada mas aquí es menester que le han sucedido el día está el otro rey
4. Modelo B — LSTM a nivel de carácter¶
El enunciado pide, literalmente, "predecir caracteres de un texto utilizando redes neuronales recurrentes y LSTM". El insumo de clase trabaja a nivel de palabra, así que añadimos aquí la versión por caracteres para cubrir la consigna al pie de la letra.
La diferencia práctica es interesante: el vocabulario cae de miles de palabras a unas pocas decenas de símbolos, así que la capa de salida es mucho más pequeña; a cambio, el modelo debe aprender la ortografía desde cero —dónde van los espacios, cómo se forman las palabras— antes de poder producir algo legible. Es un buen contraste para discutir qué unidad de tokenización conviene según la tarea.
# ==================================================================
# 4.1 Preparación del corpus a nivel de carácter
# ==================================================================
MAX_CARACTERES_CHAR = 100_000 # subconjunto para que el entrenamiento sea razonable
VENTANA_CHAR = 60 # 60 caracteres de contexto
PASO_CHAR = 3 # solapamiento entre ventanas
texto_char = corpus[:MAX_CARACTERES_CHAR]
# Se conserva solo el juego de caracteres relevante del español
permitidos = set("abcdefghijklmnopqrstuvwxyzáéíóúüñ .,;:¿?¡!-'\n")
texto_char = "".join(c for c in texto_char if c in permitidos)
texto_char = re.sub(r"\s+", " ", texto_char)
vocab_char = sorted(set(texto_char))
char_a_idx = {c: i for i, c in enumerate(vocab_char)}
idx_a_char = {i: c for c, i in char_a_idx.items()}
print(f"Caracteres del corpus : {len(texto_char):,}")
print(f"Vocabulario : {len(vocab_char)} símbolos")
print("Símbolos :", "".join(vocab_char))
Caracteres del corpus : 99,478 Vocabulario : 42 símbolos Símbolos : !',-.:;?abcdefghijlmnopqrstuvxyz¡¿áéíñóúü
# ==================================================================
# 4.2 Dataset de caracteres
# ==================================================================
secuencia = np.array([char_a_idx[c] for c in texto_char], dtype=np.int32)
Xc, yc = [], []
for i in range(0, len(secuencia) - VENTANA_CHAR, PASO_CHAR):
Xc.append(secuencia[i:i + VENTANA_CHAR])
yc.append(secuencia[i + VENTANA_CHAR])
Xc = np.array(Xc, dtype=np.int32)
yc = np.array(yc, dtype=np.int32)
corte_c = int(len(Xc) * 0.85)
ds_train_c = (tf.data.Dataset.from_tensor_slices((Xc[:corte_c], yc[:corte_c]))
.shuffle(min(corte_c, 20000), seed=SEMILLA).batch(BATCH).prefetch(AUTOTUNE))
ds_val_c = (tf.data.Dataset.from_tensor_slices((Xc[corte_c:], yc[corte_c:]))
.batch(BATCH).prefetch(AUTOTUNE))
print(f"Ejemplos generados : {len(Xc):,}")
print(f"Entrenamiento : {corte_c:,}")
print(f"Validación : {len(Xc) - corte_c:,}")
print(f"Forma de Xc : {Xc.shape}")
Ejemplos generados : 33,140 Entrenamiento : 28,169 Validación : 4,971 Forma de Xc : (33140, 60)
# ==================================================================
# 4.3 Modelo de caracteres: Embedding -> LSTM(128) -> Dense(softmax)
# ==================================================================
n_chars = len(vocab_char)
modelo_char = Sequential([
Embedding(input_dim=n_chars, output_dim=32, name="embedding_char"),
LSTM(128, name="lstm_128_char"), # mismas 128 unidades internas
Dense(n_chars, activation="softmax", name="salida_softmax_char"),
], name="LSTM_128_nivel_caracter")
modelo_char.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=2e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
modelo_char.build(input_shape=(None, VENTANA_CHAR))
modelo_char.summary()
Model: "LSTM_128_nivel_caracter"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ embedding_char (Embedding) │ (None, 60, 32) │ 1,344 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ lstm_128_char (LSTM) │ (None, 128) │ 82,432 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ salida_softmax_char (Dense) │ (None, 42) │ 5,418 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 89,194 (348.41 KB)
Trainable params: 89,194 (348.41 KB)
Non-trainable params: 0 (0.00 B)
# ==================================================================
# 4.4 Generación de caracteres con temperatura
# ==================================================================
def generar_caracteres(semilla, n_caracteres=200, temperatura=0.8):
"""Genera texto carácter a carácter a partir de una semilla."""
contexto = [char_a_idx.get(c, char_a_idx[" "]) for c in semilla.lower()][-VENTANA_CHAR:]
contexto = [char_a_idx[" "]] * (VENTANA_CHAR - len(contexto)) + contexto
generado = semilla
for _ in range(n_caracteres):
entrada = np.array([contexto], dtype=np.int32)
probas = modelo_char(entrada, training=False).numpy()[0]
logits = np.log(probas.astype(np.float64) + 1e-12) / max(temperatura, 1e-6)
p = np.exp(logits - logits.max())
p /= p.sum()
idx = int(np.random.choice(len(p), p=p))
generado += idx_a_char[idx]
contexto = contexto[1:] + [idx]
return generado
registro_epocas_char = []
class GeneracionPorEpocaChar(tf.keras.callbacks.Callback):
def __init__(self, semilla, n_caracteres=140):
super().__init__()
self.semilla = semilla
self.n_caracteres = n_caracteres
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
print("\n" + "=" * 74)
print(f"GENERACIÓN DE CARACTERES — ÉPOCA {epoch + 1}")
print("=" * 74)
print(f"loss={logs.get('loss', 0):.4f} | val_loss={logs.get('val_loss', 0):.4f} | "
f"accuracy={logs.get('accuracy', 0):.4f} | val_accuracy={logs.get('val_accuracy', 0):.4f}")
muestras = {}
for temperatura in TEMPERATURAS:
texto = generar_caracteres(self.semilla, self.n_caracteres, temperatura)
muestras[str(temperatura)] = texto
print(f"\n[T = {temperatura}] {texto}")
print("=" * 74)
registro_epocas_char.append({
"epoca": epoch + 1,
"loss": float(logs.get("loss", 0)),
"val_loss": float(logs.get("val_loss", 0)),
"accuracy": float(logs.get("accuracy", 0)),
"val_accuracy": float(logs.get("val_accuracy", 0)),
"textos": muestras,
})
SEMILLA_CHAR = "en un lugar de la mancha, de cuyo nombre no quiero acordarme"
# ==================================================================
# 4.5 Entrenamiento del modelo de caracteres
# ==================================================================
EPOCAS_CHAR = 28
inicio = time.time()
historia_char = modelo_char.fit(
ds_train_c,
validation_data=ds_val_c,
epochs=EPOCAS_CHAR,
callbacks=[
GeneracionPorEpocaChar(SEMILLA_CHAR),
tf.keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.5,
patience=3, min_lr=1e-5, verbose=1),
tf.keras.callbacks.ModelCheckpoint("mejor_lstm_caracter.keras", monitor="val_loss",
save_best_only=True, verbose=0),
],
shuffle=False, # el barajado ya lo hace tf.data
verbose=2,
)
print(f"\nTiempo total de entrenamiento: {time.time() - inicio:.1f} s")
Epoch 1/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 1 ========================================================================== loss=2.5678 | val_loss=2.2017 | accuracy=0.2605 | val_accuracy=0.3245
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarmendo do de de cara antan de caman dertan denta da de de da alo se de dento de de de altano de dan canas de sa da ho entan de de vanta de las
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme lanpandesledesansara dorio y daro as mue noltanisare coda son lestan enadido arado antiniado da y ejua ponada el lre as antidas lina los as
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarmersagona ladtes nza e que fo minar, vo da, antin ylnosa more eshe, y sinao entas, ale juardida adisoma. dee essasucanto engasloslee para caro
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmema acuecabina efavinedion ilrle nadaqado le salino ;ndosre, gaste esta tené o fueóbcahdacerno dii sol rlopomaogo dortonlrin, ra, dadre aquol ========================================================================== 221/221 - 39s - 177ms/step - accuracy: 0.2605 - loss: 2.5678 - val_accuracy: 0.3245 - val_loss: 2.2017 - learning_rate: 0.0020
Epoch 2/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 2 ========================================================================== loss=2.1528 | val_loss=2.0497 | accuracy=0.3396 | val_accuracy=0.3615
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de que en la la de la el de la parton el y porte de le ha cuen la le lo la el que vuen el la tanter de en le cuentor de la la caran que la
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme que lo se cuosta cenme des y difen de cara se la que de la er haripos los, de les rebira venden la de el ques cora lo de diel suer el lo el
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme venten, úo se deento; an se la parcamo que pote asdo e vitero tuso du poró e; dervdes caratin lljofuro ado hrry que eln que en delserlro, y
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme: asr micóa no poban, víaze, aquel mestiilo dacira; ven, cunl le péns hanto en sula cilno fedo hase lovestínigpoquis tos; y ton, e e zícperr ========================================================================== 221/221 - 36s - 165ms/step - accuracy: 0.3396 - loss: 2.1528 - val_accuracy: 0.3615 - val_loss: 2.0497 - learning_rate: 0.0020
Epoch 3/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 3 ========================================================================== loss=2.0503 | val_loss=1.9728 | accuracy=0.3633 | val_accuracy=0.3868
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarmes que el contero de mo la mel baralle carella de lo en se coriento de cor la la minciendo al conto de lo se para vería de le la se mier el v
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme de se viogo mile que lo cantara, en cedo la puaso la mese pantos pra el miaragie cose ino mel los la hel celaverotire en el corino que el
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarmes cudino a midos lichosedo pogomes dequeldo es covea, deño, cremo, arígía, que harbamisies, prel, jo vilo liso verían enesensá y se lie muec
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmecaro, viroreatmo podanquegada de ledis, a misií cadin yo cabalceños gob!jo, la dezor, de soles deró tragió sendoses que heó picaxutó enciino ========================================================================== 221/221 - 37s - 165ms/step - accuracy: 0.3633 - loss: 2.0503 - val_accuracy: 0.3868 - val_loss: 1.9728 - learning_rate: 0.0020
Epoch 4/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 4 ========================================================================== loss=1.9767 | val_loss=1.9227 | accuracy=0.3871 | val_accuracy=0.4011
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de le la la su la la la la lo la la se que la se la la la cante la por de la su lo de la la su la muesto de la la menta en pora de la le le
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarmero que le coro y portes ostas anos con porante silas, lo vercesan cante en sicdo alballaren de letes a la vila anta la mocaza de se poro qui
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme, tenío qua espu ema de laste, y el crana tarias ses lososide en codento, pane esí a, y señirada ynenta, que tede encodo ho cuer ocana a hat
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme la vezaresa? cuenteshiy de ruelvelas, velquiénsos allerdo ro guhazos lo que e aíante queezo para sicises su lando dagosebíes, apalino entos ========================================================================== 221/221 - 35s - 157ms/step - accuracy: 0.3871 - loss: 1.9767 - val_accuracy: 0.4011 - val_loss: 1.9227 - learning_rate: 0.0020
Epoch 5/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 5 ========================================================================== loss=1.9147 | val_loss=1.8861 | accuracy=0.4064 | val_accuracy=0.4124
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme el conteras a la mesterde de la cuerdo a la la mabara este el caballeso, el conte los cora a su cora el parteras de la maballero, y algunas
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme quijoter delo pode, y puestras de las algada ese, en hallante su que estas alas quedo esta de el tastes, y amen arante nallberes, purle, al
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme deñar con el vuertase cue, gunó le curerado,, fuendor, piol la nodías los el espuélaso, ponma el imalvenotendo mamo, aridas core el folbesu
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmes afentro, edo fertes, suñerlo que fisogn, le la lauso quiclo: in nader, tacas, antriba de lshos que óidu posíz sopdiós, estialdro lazaemon; ========================================================================== 221/221 - 34s - 152ms/step - accuracy: 0.4064 - loss: 1.9147 - val_accuracy: 0.4124 - val_loss: 1.8861 - learning_rate: 0.0020
Epoch 6/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 6 ========================================================================== loss=1.8596 | val_loss=1.8554 | accuracy=0.4238 | val_accuracy=0.4164
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de los había el caballero el la la muchos de los pora de lo el cora lo las la hallero se la muestra de las micino de la lo el cara, y que l
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarmes tudosió, y que le puras, a si hiblico mel asiró destos yo había este viel cosiras de conzas tos lla cara, el vionde alco en nos della, y l
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme noz livono; de tevino el lo despimazdecas parsegua, ¡non dece, y eale criandos. y sistasdo su vadillata alsur incanminan todre mestía, con
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme, y adí, bresdo, y todo que tujuentiimos encbuija, el ecbimiiza den; almer, arcuercsa la vélzidonía; caúso, como: a losaga un linvin aa robr ========================================================================== 221/221 - 35s - 157ms/step - accuracy: 0.4238 - loss: 1.8596 - val_accuracy: 0.4164 - val_loss: 1.8554 - learning_rate: 0.0020
Epoch 7/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 7 ========================================================================== loss=1.8154 | val_loss=1.8110 | accuracy=0.4379 | val_accuracy=0.4289
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la esta de la caballero el caballero en el caballero de la caballero el caballero el caballero el cantes, y que la se la estas de la el c
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme de la grigina ton alguna ten amenticen de se fues el su los hable cermerra los otendo mel dijo el suo rapentra que hijote de vieroren en ca
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme an noy amtóncudo a ertar hay, tosas cofino desedol des ecara ebarito. sun cuota comañar seño a puera?, paride li que su halbaren l atante l
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmesto omibara este dulimisa cos, re coengra, prastipiando ve los tenturo tedad? cinlerto que tabare le, sevagbian otrobar lo ensíado delmia. e ========================================================================== 221/221 - 37s - 169ms/step - accuracy: 0.4379 - loss: 1.8154 - val_accuracy: 0.4289 - val_loss: 1.8110 - learning_rate: 0.0020
Epoch 8/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 8 ========================================================================== loss=1.7701 | val_loss=1.7827 | accuracy=0.4497 | val_accuracy=0.4436
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la hanta en lo de contra y en el cospe conto me por lo venta de lo se la venta de lo de caballero esta con la viento y a merguados con lo
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme tran de vido se de que vuel hasteció de el caballese de todo de alguna del cuimos algo saner por lo huer que er estonda esto de auma tonde
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme cronde de si lo conostriecía no nos junteces que uno lan sus pranada de codor, espor mol buega, a talto a esposbalmiando lo la fuero estoda
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmes señor for vuesmo, tonco toda. ho lécerador y hillenas coste las decomded, postá cosus y al minos, yo me pudoso ven aridan se lichue hue ro ========================================================================== 221/221 - 37s - 169ms/step - accuracy: 0.4497 - loss: 1.7701 - val_accuracy: 0.4436 - val_loss: 1.7827 - learning_rate: 0.0020
Epoch 9/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 9 ========================================================================== loss=1.7300 | val_loss=1.7649 | accuracy=0.4618 | val_accuracy=0.4490
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la mesto de se la mespos de la cuanto en el caballero en no la mertado de se pero de llegado de la vertas de la caballero en el caballero
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme me la estaba aquel o de pora en loy el deseció hal regon se caballono en se se lla muerpodí, y el algunando de eno que el vellaras que en p
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme, conque, no rabres, n bino habían za ían muera, el tenemos vecinos y no ve graba había en desporien no hallo, que nos aunen que tar lodan d
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmeés, a nocuada; y veístarra essia segía, que librejan fardos pantio el llada denen tase vano for velca, gados a camandrriendo uper celtador u ========================================================================== 221/221 - 36s - 165ms/step - accuracy: 0.4618 - loss: 1.7300 - val_accuracy: 0.4490 - val_loss: 1.7649 - learning_rate: 0.0020
Epoch 10/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 10 ========================================================================== loss=1.6908 | val_loss=1.7439 | accuracy=0.4741 | val_accuracy=0.4593
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la venció el caballeros de sincina de la cuando de la mermado y su se caballero a esto de la mentara de lo que se manta de la vino el cab
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme al dio otra de desaquerle collar lo mespos del hiendo, dijote en las carerga de huco el enares de la denos así esto consía os llegas, dijo
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme la e curales nabía amontabiendo y con. y en fano rombre padabata cuento confera donced, can la mentra tendaga era los con halgrosió has yen
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme cobrandole algána. este, la mío diro arrana de le ecimisos comico unagondo. lique lusiador si gon docendo. o deconde le disenáne, aymtondró ========================================================================== 221/221 - 36s - 165ms/step - accuracy: 0.4741 - loss: 1.6908 - val_accuracy: 0.4593 - val_loss: 1.7439 - learning_rate: 0.0020
Epoch 11/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 11 ========================================================================== loss=1.6567 | val_loss=1.7276 | accuracy=0.4841 | val_accuracy=0.4633
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme su la caballero en la caballero que de la mermido con el señor y que en estaba a su seridad y su caballere validad y lo del barbero que se
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme los hien sejora muy sin otra el cuando del entras agura de las descuraso dor acían, y sero a fuestro de la se la habella a laba que el con
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme sechiel cacia numontra del brenoción, piendo el caldilse algun mice! palazó el aquéllo el comtay re siguler pracindad dijotió que lo priera
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme él tendechio. amió lo sanzo, y aquejanchos aquelgí pasa embor dino; corvgacio y undonheazono acircin pranta, la rinas en su trperan no quem ========================================================================== 221/221 - 37s - 167ms/step - accuracy: 0.4841 - loss: 1.6567 - val_accuracy: 0.4633 - val_loss: 1.7276 - learning_rate: 0.0020
Epoch 12/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 12 ========================================================================== loss=1.6255 | val_loss=1.7148 | accuracy=0.4931 | val_accuracy=0.4627
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme como los amadad de la mantira de caballero el caballero el con el cura de la vellos, por la caballero el caballero en el caballero en la ve
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme la caballero en vuestro y mis quinto en esto de la cemar el llazor con acentor de mino señar que nocentía llevicia de caballería el coma de
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme los tiga; relichas en lo de el nombre alrí simpodo, purplo del que el espico no se dor esto, la, grante él mámbra recponde concinte sablen
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme de más heyó pea el perecido fantagala? y notres sobre er -udad deste llabrador pariquéte, su viésa bersro de la crilió: quijo, el lano, sim ========================================================================== 221/221 - 37s - 168ms/step - accuracy: 0.4931 - loss: 1.6255 - val_accuracy: 0.4627 - val_loss: 1.7148 - learning_rate: 0.0020
Epoch 13/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 13 ========================================================================== loss=1.5935 | val_loss=1.7060 | accuracy=0.5038 | val_accuracy=0.4711
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme estaba y andante, y a la dester de caballero en la caballero el caballero en la vellas de la venta de la vellar de se caballero en la venta
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme caballero por lo imo de la juster, en su pregadad se la famino de de contodo de así por todo de ventaser los perera y la suera de la mestos
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme camerreza según la proestendo, día tenías partera; ante me sevos fazaba ancamindo y puidan que sema el uno de umegua, nincinabó; y cama pro
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmes apeledendo, delinanerigo: ra vuchació. plos de si mucitro el nos otros. n ahada y quién? zuto veo talande que yigo rebiada osmitóle y de v ========================================================================== 221/221 - 37s - 166ms/step - accuracy: 0.5038 - loss: 1.5935 - val_accuracy: 0.4711 - val_loss: 1.7060 - learning_rate: 0.0020
Epoch 14/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 14 ========================================================================== loss=1.5650 | val_loss=1.6873 | accuracy=0.5130 | val_accuracy=0.4715
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme en esto de la mences, por la mantado, y a la vente de caballero en la esperado en la para de la seno de la estaba a la venta en lo del caba
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme lo antemento por quijote; y, por tan senoser de la versar, no se la de había allí y que, y una endando con los armentes hallaro, porque el
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme, y, muero. lión mutro, y aúrrondiado. imagas de cumento. he llasado que lo ese prover pozapos, en la vuestro más que la que tan fabeje fla
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme aquél mudala; porque, no o tanho no de corrtiés, minocibo y vel prizo, entrés rezhaja volonces, para que punto. en vuendo, ¡os dijo ela rod ========================================================================== 221/221 - 36s - 162ms/step - accuracy: 0.5130 - loss: 1.5650 - val_accuracy: 0.4715 - val_loss: 1.6873 - learning_rate: 0.0020
Epoch 15/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 15 ========================================================================== loss=1.5350 | val_loss=1.6935 | accuracy=0.5216 | val_accuracy=0.4721
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme los amaserle con el cura a las caballeros de la cuanto y por lo del caballero como lo del caballero que los amasente a con la mentada a la
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme esto de hoco de lo de un destor por la masar, y en el venterlo al ruchado en nos amas micho, y de ticilidado y señor a muscro, y andís con
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme la señoraja que egan de pasaúbra un ostada, de no ventasenos y de autoro, no fue la veste; y tunías avino es e estumesos y en el aderó, y q
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme, y, caliidra de hasía, vey hiér de quiéno; señor. daldítomir? partedor de castónues porque lenetado don nabido y vioto que ró perga, con lo ========================================================================== 221/221 - 34s - 155ms/step - accuracy: 0.5216 - loss: 1.5350 - val_accuracy: 0.4721 - val_loss: 1.6935 - learning_rate: 0.0020
Epoch 16/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 16 ========================================================================== loss=1.5095 | val_loss=1.6764 | accuracy=0.5275 | val_accuracy=0.4786
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de la el caballero en la mermos de la las caballero las caballero en la caballero a esto de la mantador a la caballero en el caballero en l
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme camerte que no estaban de vertar tespenos para y a merced de su mango el camino, y que al más hallaro en su señante de la haberlo dás amido
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme en el dijo en la eído, pupendador, las para sespotas estobricincimánteso; ris redodo a cramero pues dijo! aquellefo. en sun que ira vangas
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme daba que vuese, porvilo, liardo cuevó esí que te, des deje, en vecillados delo comiertó lo pien, el sermido comle prosechoés a el seble sí ========================================================================== 221/221 - 37s - 167ms/step - accuracy: 0.5275 - loss: 1.5095 - val_accuracy: 0.4786 - val_loss: 1.6764 - learning_rate: 0.0020
Epoch 17/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 17 ========================================================================== loss=1.4814 | val_loss=1.6704 | accuracy=0.5391 | val_accuracy=0.4814
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la mancha de la venta y de mandador de los de dijo el caballero que se la para por la verso de muy que el puestra de la armado el caballe
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme y jurera y currazarle y sa la mandar a caballero. cantos. y, por su ragoder toda el la rocas, andía a su los tosa las amasor para esto, y a
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme don alzó en su si nuneso, y en esto massiba de moldar castillos todo al rúbrimnados y y llaga de crezo es abran no caballero sin es y que d
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme todas piesar. es eses pabreellazó, no gadaba el coxel y tey bus. a, y quegaba, ¿otriedecas y en llamó, este algún toda, quedadía, que en aú ========================================================================== 221/221 - 36s - 164ms/step - accuracy: 0.5391 - loss: 1.4814 - val_accuracy: 0.4814 - val_loss: 1.6704 - learning_rate: 0.0020
Epoch 18/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 18 ========================================================================== loss=1.4544 | val_loss=1.6694 | accuracy=0.5457 | val_accuracy=0.4802
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme los los cural de su la mino de los hora de la merced de los deseos los deseos de los amosos que los caballeros que en estaba estaba el cura
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme los caballeros de cura se camino don quien huésen y lo don don al amade de poder tendo lo dellos que se presezó de alguno, el otro el amame
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme en repuro a huy caminuendones a no renoción jentó de lae, sentre su bacia que fuel más porque, discreto seguidado cantalase vono, hicho pue
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme llaza que el puese de otros gunfillas, su des y en su vuestrabande en meca sé labilo qoece habío demon mevocejetigador don quijoteje y otra ========================================================================== 221/221 - 35s - 160ms/step - accuracy: 0.5457 - loss: 1.4544 - val_accuracy: 0.4802 - val_loss: 1.6694 - learning_rate: 0.0020
Epoch 19/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 19 ========================================================================== loss=1.4291 | val_loss=1.6622 | accuracy=0.5527 | val_accuracy=0.4846
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de caballero, andibro en la vezua de caballero en la proces de la de la mantado a caballería la caballero a cual contillas de su la cura de
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme nocha de habella er los labrameza de su casa muy armas, y tal mabante de tudadle algunos de la ertad a caballero que tan de que se alda de
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme ficebia no junto de acantesián blazó, dalcuntos se cuando elaco de caballero, y abriga de la de había pos ruvandos hecho perzo el bian volc
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme concinuéncia. agruendo mandeza. y pues que no flaído amaño, libro su se no, vir con fodo. el adon añorgados saba; mazías respordido gotesie ========================================================================== 221/221 - 33s - 151ms/step - accuracy: 0.5527 - loss: 1.4291 - val_accuracy: 0.4846 - val_loss: 1.6622 - learning_rate: 0.0020
Epoch 20/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 20 ========================================================================== loss=1.4042 | val_loss=1.6562 | accuracy=0.5597 | val_accuracy=0.4864
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme los prosetos de los caballeros de entendada, y llegó la caballero que tener el cura se le primero de los deseos, y al caballeros de la mant
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme caminue de todo desculible. el caballero que las caballeros hallase lo amesentas lo que tal fuento su los ventas que el puesen y el caballe
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme no voza de una subra no huspido de lo la busibro muy subrosuale como de sumás, tar quijote de junto don lla, genó no libro el hecerla sesoc
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme destos pildos blazó llagó a rositondete, subié señera, voy caballa, quibía pritacde valiézos. se oldos rivosegos; die desció acabada, lque, ========================================================================== 221/221 - 34s - 154ms/step - accuracy: 0.5597 - loss: 1.4042 - val_accuracy: 0.4864 - val_loss: 1.6562 - learning_rate: 0.0020
Epoch 21/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 21 ========================================================================== loss=1.3808 | val_loss=1.6641 | accuracy=0.5666 | val_accuracy=0.4866
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a llegar lo dellas lo de la cura le de caballería a la mustros de la venta de la venta a todo de la venta de la venta a la trendió el cabal
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme llegar a por ropos de caballero, y diciendo el cura y condentros de a verta de mían de acasión y la vinta quien quijote meredo y llegad, y
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme los partes de su mucha moldad dijo: buen otro de caballeso en vácer de la lucitóndo estánerle, y ellos solidi que no se las abriero; que él
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarmenso dil mazó tres piera. estos, otra cunto aychuy tían máy caga cofre, se quinierta. huestro de moymose en los y no perego de muserante en b ========================================================================== 221/221 - 37s - 168ms/step - accuracy: 0.5666 - loss: 1.3808 - val_accuracy: 0.4866 - val_loss: 1.6641 - learning_rate: 0.0020
Epoch 22/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 22 ========================================================================== loss=1.3563 | val_loss=1.6679 | accuracy=0.5741 | val_accuracy=0.4931
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la venta de lo del caballero que tenía a mus de tenía a la merme de tan caballero andante de la venta de la venta y que en el pero de la
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme, sin mencedera, y dicierpo, y, cual que lo de las aperiente? alguno aquellos los sin quera. las amaser a los caballeros andantes, sin las c
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme de su viestra una reperiad, la impocio tan hurco; para mabien del la dermo nombre, no la cumido, lo degañación tando la sucho de ún ejen no
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme díabando, pero dechoieda de dacía su cuan señor divatir lo malis, junto vio que el buen tuer vicha, mada sebierdo, en bladanta las talles o ========================================================================== 221/221 - 37s - 165ms/step - accuracy: 0.5741 - loss: 1.3563 - val_accuracy: 0.4931 - val_loss: 1.6679 - learning_rate: 0.0020
Epoch 23/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 23 ========================================================================== loss=1.3282 | val_loss=1.6607 | accuracy=0.5815 | val_accuracy=0.4935
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la mestonde de la venta y a su la mantar a de la parter con la caballero y cura de su amante el cura a la venta y de todo el caballero qu
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme por la de merenteror. en los dijo el gron folminay de sahoncia. en todo por el pelado la aquellos hibies que había que tada la molo primero
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme compaña. señor como será las mínra sanase llamara día er poco en sus armas y vendaros a rigra, madose tornegabas, a la azante; y amí, y no
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme debía decá cabesose con el casol. onduqye o fela nomha cumente; en osos holleóa sugo nombretria, y levantos de sesció el linmo mansasos que ========================================================================== Epoch 23: ReduceLROnPlateau reducing learning rate to 0.0010000000474974513.
221/221 - 36s - 162ms/step - accuracy: 0.5815 - loss: 1.3282 - val_accuracy: 0.4935 - val_loss: 1.6607 - learning_rate: 0.0020
Epoch 24/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 24 ========================================================================== loss=1.2771 | val_loss=1.6583 | accuracy=0.6017 | val_accuracy=0.4896
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme a le parter de muy con el caballero que era armado y la serrada, y a la mermo de la mantado y en esto de la venta de la mano de la primera
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme por la el caballerías de su lando en comparo su había se cedenciade y en el valero el caballero lo reguada, sa saballero la manera el porqu
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme por la intarleriz antís, ¿quiéntes no sa las famaba., puezó na sino si tomento como pudora otro y al cabajo contro el brenía, y tana tándo;
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme al quera hacó su hamida? y tanto conez el veltroso perega de nocreñan, y, encierto compotratezad porquéían pasangalabtes, para; y así, cuan ========================================================================== 221/221 - 37s - 166ms/step - accuracy: 0.6017 - loss: 1.2771 - val_accuracy: 0.4896 - val_loss: 1.6583 - learning_rate: 0.0010
Epoch 25/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 25 ========================================================================== loss=1.2575 | val_loss=1.6571 | accuracy=0.6073 | val_accuracy=0.4951
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme caballero a entrara el cura no se la cura el se contración de su caballero en las prosas, porque la serviente el cual se le parecer de la v
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme en su pagarle los tropestras, seroros, que le merer en le para de traía novinar la caballero que le parecían a la la esperaba, de los deste
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme otra llazón conongra, portencel, y por aquelloso destentía, que veiblas he del diruescía en coner vio seales con las cuelones: comanzó efad
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme criego, forñara. amín tenero, es que rescaje ya lo irtómado de su arma dento si viéles respondión. aunco: dondole. pues la libros, y el cas ========================================================================== 221/221 - 37s - 165ms/step - accuracy: 0.6073 - loss: 1.2575 - val_accuracy: 0.4951 - val_loss: 1.6571 - learning_rate: 0.0010
Epoch 26/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 26 ========================================================================== loss=1.2434 | val_loss=1.6630 | accuracy=0.6108 | val_accuracy=0.4937
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme de su ventar caballero el barbero de cuanto la cura y vecer con la cuendo el cura y cuando a su la caballero y tan no se propesara de la ve
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme a la un escuros de muy que no se escuderos de hoy decio que otrigo y volenta la de su sin hallarera de caballero no vol hoco estre mandador
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme las primparsos. en su hallása. este dijo en la intencós que él seguna; él culla. gurreza. bajarleros, godos decir el buesen en otra aquella
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme fuez mur muyara entendino qué no no viro quien gorrefcino de lo micigo, y no pron ardar de su rlas dal horan, quieta, aquí, por crio de fue ========================================================================== Epoch 26: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257.
221/221 - 36s - 162ms/step - accuracy: 0.6108 - loss: 1.2434 - val_accuracy: 0.4937 - val_loss: 1.6630 - learning_rate: 0.0010
Epoch 27/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 27 ========================================================================== loss=1.2116 | val_loss=1.6642 | accuracy=0.6241 | val_accuracy=0.4904
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme con sus amas, y así, llevar a los proseto que le del cura se hera de su aldo de lo de la venta y a la caballero andantes, como su armas de
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme como llamar la señora, en su mantrados de vino se cersar histo muy quién lo del caballero que se respondió el cura levantión la vienen a lo
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme en vuestra muchatata; él mundale lecera; y mánsoresto hallía, y vobía que le diso que en habén había no dudaan la espadad, de su prieza aco
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme jeande causabi. el vuerto plaza de los que dieje caballerías y vengasetos én; puer que me vuestra hermo le rigura que la vanze; peció cor t ========================================================================== 221/221 - 37s - 166ms/step - accuracy: 0.6241 - loss: 1.2116 - val_accuracy: 0.4904 - val_loss: 1.6642 - learning_rate: 5.0000e-04
Epoch 28/28
========================================================================== GENERACIÓN DE CARACTERES — ÉPOCA 28 ========================================================================== loss=1.2034 | val_loss=1.6637 | accuracy=0.6258 | val_accuracy=0.4957
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme le del cura de su ventar a la mantado por la venta amigo de la venta como lo de la venta cuando su algún con estaba aquella menester de la
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme potrieron todas dejar que había hacer a peder de la obres, y, por él herros, lo de caballero en blanta, su algún trapiez al caballero en la
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme luvante, ha memo, ventuallos de landa de acerdenciadon a su ellar de entres el velsor y cuendo ardon como si los trañancion, que se leído h
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme estos romasió las barban; quito. dío, perremon su vendadas sis acoserestros vién, remondes, un grandes que en le rempodar a toda, y hopo po ========================================================================== 221/221 - 35s - 159ms/step - accuracy: 0.6258 - loss: 1.2034 - val_accuracy: 0.4957 - val_loss: 1.6637 - learning_rate: 5.0000e-04
Tiempo total de entrenamiento: 1009.8 s
# ==================================================================
# 4.6 Curvas y comparación de temperaturas (caracteres)
# ==================================================================
hc = historia_char.history
fig, ejes = plt.subplots(1, 2, figsize=(13, 4.5))
ejes[0].plot(hc["loss"], label="entrenamiento", linewidth=2)
ejes[0].plot(hc["val_loss"], label="validación", linewidth=2, linestyle="--")
ejes[0].set_title("Pérdida — modelo a nivel de carácter")
ejes[0].set_xlabel("Época"); ejes[0].set_ylabel("Loss")
ejes[0].legend(); ejes[0].grid(alpha=0.3)
ejes[1].plot(hc["accuracy"], label="entrenamiento", linewidth=2)
ejes[1].plot(hc["val_accuracy"], label="validación", linewidth=2, linestyle="--")
ejes[1].set_title("Precisión — modelo a nivel de carácter")
ejes[1].set_xlabel("Época"); ejes[1].set_ylabel("Accuracy")
ejes[1].legend(); ejes[1].grid(alpha=0.3)
plt.tight_layout()
plt.savefig("fig_curvas_caracter.png", dpi=150, bbox_inches="tight")
plt.show()
print("=" * 74)
print("COMPARACIÓN FINAL DE TEMPERATURAS (modelo a nivel de carácter)")
print("=" * 74)
comparacion_char = {}
for temperatura in TEMPERATURAS:
texto = generar_caracteres(SEMILLA_CHAR, n_caracteres=300, temperatura=temperatura)
comparacion_char[str(temperatura)] = texto
print(f"\n[T = {temperatura}]\n{texto}")
========================================================================== COMPARACIÓN FINAL DE TEMPERATURAS (modelo a nivel de carácter) ==========================================================================
[T = 0.3] en un lugar de la mancha, de cuyo nombre no quiero acordarme su habla de la venta de la caballero andantes, y a la manera, y así, señora por la cuento con el caballero el caballero andantes, con ellos de su aposarba a su la primera se llamar el cura que los hicho de la venta se le primera de su la proseguna, y así, señor todo a esto de la mantar la venta y p
[T = 0.7] en un lugar de la mancha, de cuyo nombre no quiero acordarme caballero que no se plandía por crecebad dijo el sejuión tanto lo otro como y la cala mala mester caballero. en las las dijo el cabálla, que no le curpe, sin hoces y sino su todos diciendo el mortin que no fuerdo no había con había caballero se haballero notas, por la castió a una la caballero y cu
[T = 1.0] en un lugar de la mancha, de cuyo nombre no quiero acordarme notra tribricia. aquella hazo, sin el se estos y consigo y vonsabas y pentande en esta arrierdo algó sóno, dijo el caba lo los escudar tan durse en no estaban, andíó, y que der cabéa un perez de un grondole su vorve la suérte conande y vuísto doda despuézas estro merió caballero viso y se pergirle,
[T = 1.2] en un lugar de la mancha, de cuyo nombre no quiero acordarme avertirlián pérpiliunes, con ocogillo prosandandos de su quijea estaba, mi. ahados señor aventaldas coz cuandos dicorio en l prutiez no; coro esto, pues, por esta ól cura y vercida de una meyrambra cono, quitura, fióles amió todo a lo mestracido que don quijote, que, deen locurata de la vonto fue v
5. Análisis comparativo¶
Dos cosas que queríamos ver con datos y no de oídas: cómo deforma la temperatura la distribución de probabilidades, y qué gana o pierde cada nivel de tokenización.
# ==================================================================
# 5.1 Efecto de la temperatura sobre la distribución de probabilidad
# ==================================================================
consulta = "en un lugar de la mancha de cuyo"
secuencia = tokenizer.texts_to_sequences([consulta])[0][-SEQ_LEN:]
entrada = pad_sequences([secuencia], maxlen=SEQ_LEN, padding="pre")
base = modelo_palabra(entrada, training=False).numpy()[0]
fig, ejes = plt.subplots(2, 2, figsize=(13, 8))
for eje, temperatura in zip(ejes.flatten(), TEMPERATURAS):
logits = np.log(base.astype(np.float64) + 1e-12) / temperatura
p = np.exp(logits - logits.max())
p /= p.sum()
top = np.argsort(p)[::-1][:10]
etiquetas = [tokenizer.index_word.get(int(i), "<OOV>") for i in top][::-1]
valores = [p[i] for i in top][::-1]
eje.barh(range(len(etiquetas)), valores)
eje.set_yticks(range(len(etiquetas)))
eje.set_yticklabels(etiquetas)
eje.set_title(f"Temperatura = {temperatura}")
eje.set_xlabel("Probabilidad")
eje.grid(alpha=0.3, axis="x")
fig.suptitle(f"Top-10 de palabras candidatas tras: '{consulta}'", fontsize=13)
plt.tight_layout()
plt.savefig("fig_temperaturas.png", dpi=150, bbox_inches="tight")
plt.show()
# ==================================================================
# 5.2 Cuadro comparativo palabra vs. carácter
# ==================================================================
filas = [
("Unidad de predicción", "palabra", "carácter"),
("Tamaño del vocabulario", f"{vocab_size:,}", f"{n_chars}"),
("Contexto de entrada", f"{SEQ_LEN} palabras", f"{VENTANA_CHAR} caracteres"),
("Ejemplos de entrenamiento", f"{len(X):,}", f"{len(Xc):,}"),
("Parámetros del modelo", f"{modelo_palabra.count_params():,}",
f"{modelo_char.count_params():,}"),
("Épocas", f"{EPOCAS_PALABRA}", f"{EPOCAS_CHAR}"),
("loss final (val)", f"{h['val_loss'][-1]:.4f}", f"{hc['val_loss'][-1]:.4f}"),
("accuracy final (val)", f"{h['val_accuracy'][-1]:.4f}", f"{hc['val_accuracy'][-1]:.4f}"),
]
ancho = max(len(f[0]) for f in filas) + 2
print(f"{'Criterio':<{ancho}} {'Nivel palabra':>22} {'Nivel carácter':>22}")
print("-" * (ancho + 46))
for criterio, a, b in filas:
print(f"{criterio:<{ancho}} {a:>22} {b:>22}")
print("\nNota: los valores de loss NO son comparables entre modelos, porque el tamaño del")
print("espacio de salida es distinto (miles de palabras frente a decenas de caracteres).")
Criterio Nivel palabra Nivel carácter ------------------------------------------------------------------------- Unidad de predicción palabra carácter Tamaño del vocabulario 6,000 42 Contexto de entrada 20 palabras 60 caracteres Ejemplos de entrenamiento 73,959 33,140 Parámetros del modelo 1,673,584 89,194 Épocas 30 28 loss final (val) 5.7540 1.6637 accuracy final (val) 0.1411 0.4957 Nota: los valores de loss NO son comparables entre modelos, porque el tamaño del espacio de salida es distinto (miles de palabras frente a decenas de caracteres).
6. Bloque interactivo¶
Una demostración con varias semillas, y debajo el modo interactivo por teclado que mostró la
docente. Este último queda desactivado por defecto (EJECUTAR_INTERACTIVO = False) para que el
cuaderno pueda ejecutarse de principio a fin sin quedarse esperando una entrada; basta cambiar la
bandera a True para probarlo.
# ==================================================================
# 6.1 Demostración con varias semillas
# ==================================================================
semillas_demo = [
("en un lugar de la mancha de cuyo nombre", 0.7),
("el caballero andante se lanzó a la aventura", 0.8),
("sancho panza cabalgaba junto a su señor", 0.7),
("la justicia y el honor guiaban al hidalgo", 0.9),
]
for semilla, temperatura in semillas_demo:
print(f"\nSemilla: '{semilla}' (T = {temperatura})")
print(f" -> {generar_palabras(semilla, n_palabras=30, k=30, temperatura=temperatura)}")
Semilla: 'en un lugar de la mancha de cuyo nombre' (T = 0.7)
-> en un lugar de la mancha de cuyo nombre no se me ha sido de la cabeza del sol el vizcaíno un mundo que el cielo caballero del camino que no se ha dado y el caballero — no Semilla: 'el caballero andante se lanzó a la aventura' (T = 0.8)
-> el caballero andante se lanzó a la aventura le rogó que trae en su parecer no lo diré que ya el mesmo brazo se le pasó por la boca y las armas y fue en su amo que Semilla: 'sancho panza cabalgaba junto a su señor' (T = 0.7)
-> sancho panza cabalgaba junto a su señor señor el cual no había de vuestra merced que me faltan —respondió sancho para duda si en el mundo el ventero en la cabeza y en la noche a su Semilla: 'la justicia y el honor guiaban al hidalgo' (T = 0.9)
-> la justicia y el honor guiaban al hidalgo del otro en lo que de ser a quien con que le pareció la señora dulcinea del arriero los demás le había sucedido en el cual como no se le
# ==================================================================
# 6.2 Modo interactivo por teclado (desactivado por defecto)
# ==================================================================
EJECUTAR_INTERACTIVO = False # cambie a True para escribir sus propios prompts
if EJECUTAR_INTERACTIVO:
print("Escriba un prompt de 6 a 15 palabras. Escriba 'salir' para terminar.\n")
while True:
entrada_usuario = input("Prompt > ").strip()
if entrada_usuario.lower() in ("salir", "exit", "quit"):
print("Fin del modo interactivo.")
break
if len(entrada_usuario) < 5:
print("Escriba un prompt un poco más largo.\n")
continue
print("\n" + generar_palabras(entrada_usuario, n_palabras=40, k=30, temperatura=0.9) + "\n")
else:
print("Modo interactivo desactivado (EJECUTAR_INTERACTIVO = False).")
Modo interactivo desactivado (EJECUTAR_INTERACTIVO = False).
7. Exportación de resultados¶
Guardamos las métricas y los textos generados en un archivo JSON. Sirve para alimentar el informe escrito con las cifras exactas del entrenamiento, sin transcribirlas a mano.
# ==================================================================
# 7.1 Volcado de resultados
# ==================================================================
resultados = {
"corpus": {
"caracteres": len(corpus),
"palabras": len(palabras),
"vocabulario_unico": len(set(palabras)),
"vocabulario_modelo": int(vocab_size),
"frases_mini_corpus_clase": len(MINI_CORPUS_CLASE),
"descarga_exitosa": bool(texto_gutenberg),
},
"modelo_palabra": {
"seq_len": SEQ_LEN,
"epocas": EPOCAS_PALABRA,
"parametros": int(modelo_palabra.count_params()),
"ejemplos": int(len(X)),
"history": {k: [float(v) for v in vs] for k, vs in h.items()},
"por_epoca": registro_epocas,
"comparacion_temperaturas": comparacion_palabra,
"top5": {c: top_k_siguiente(c, k=5) for c in consultas},
},
"modelo_caracter": {
"ventana": VENTANA_CHAR,
"epocas": EPOCAS_CHAR,
"parametros": int(modelo_char.count_params()),
"vocabulario": int(n_chars),
"ejemplos": int(len(Xc)),
"history": {k: [float(v) for v in vs] for k, vs in hc.items()},
"por_epoca": registro_epocas_char,
"comparacion_temperaturas": comparacion_char,
},
}
with open("resultados_s7.json", "w", encoding="utf-8") as fh:
json.dump(resultados, fh, ensure_ascii=False, indent=2)
print("Resultados guardados en resultados_s7.json")
print(f" Épocas registradas (palabra) : {len(registro_epocas)}")
print(f" Épocas registradas (carácter): {len(registro_epocas_char)}")
Resultados guardados en resultados_s7.json Épocas registradas (palabra) : 30 Épocas registradas (carácter): 28
8. Conclusiones¶
La arquitectura pedida —LSTM(128) seguida de Dense con softmax— funciona, y se nota desde las
primeras épocas: al comienzo el modelo apenas encadena artículos y conjunciones, y hacia el final ya
respeta concordancias y produce sintagmas reconocibles del castellano de Cervantes. No escribe
literatura, pero eso tampoco era lo que se buscaba.
Sobre el número de épocas, la analogía que usó la docente en clase —cuántas veces hay que leer un
libro para poder responder preguntas sobre él— se sostiene solo hasta cierto punto. A partir de la
época en que val_loss toca su mínimo, seguir entrenando mejora la métrica de entrenamiento pero
empeora la de validación: el modelo memoriza en lugar de generalizar. Conviene mirar las dos curvas,
no solo la de entrenamiento.
La temperatura resultó ser el parámetro más visible de todos. Con 0.3 el texto es correcto pero monótono, y reaparecen las mismas construcciones; con 1.2 aparece vocabulario más rico a costa de frases que se desarman a mitad de camino. Para este corpus, el rango 0.7–0.8 es el que mejor equilibra ambas cosas.
Comparar palabra contra carácter dejó clara una diferencia de fondo: el modelo de caracteres tiene que gastar buena parte de su capacidad en aprender ortografía —dónde termina una palabra, qué letras pueden ir juntas— antes de ocuparse del significado. El de palabras arranca con esa parte resuelta, pero paga el precio de un vocabulario enorme en la capa de salida y de no poder inventar ni una sola palabra que no haya visto antes.
Queda una limitación honesta: con 160.000 caracteres el modelo no alcanza a capturar dependencias largas. Para eso habría que ir hacia arquitecturas con atención, que es exactamente el tema de la semana siguiente.
Referencias¶
Arumugam, R., y Shanmugamani, R. (2018). TensorBoard visualization. En Hands-on natural language processing with Python: A practical guide to applying deep learning architectures to your NLP applications (pp. 224-236). Packt Publishing.
Campesato, O. (2021). Transformer, BERT, and GPT. En Natural language processing fundamentals for developers (pp. 247-287). Mercury Learning and Information.
Cervantes Saavedra, M. de. (2004). El ingenioso hidalgo don Quijote de la Mancha [Libro electrónico núm. 2000]. Project Gutenberg. https://www.gutenberg.org/ebooks/2000 (Obra original publicada en 1605)
Ganegedara, T. (2018). Defining inputs in TensorFlow. En Natural language processing with TensorFlow: Teach language to machines using Python's deep learning library (pp. 37-152). Packt Publishing.
Goodfellow, I., Bengio, Y., y Courville, A. (2016). Deep learning. MIT Press. https://www.deeplearningbook.org/
Hochreiter, S., y Schmidhuber, J. (1997). Long short-term memory. Neural Computation, 9(8), 1735-1780. https://doi.org/10.1162/neco.1997.9.8.1735
Orozco Morales, N. (2026). Semana 7: Redes neuronales recurrentes, LSTM y generación de texto [Cuaderno de clase y sesión sincrónica]. NRC-8774 Procesamiento Natural del Lenguaje, Corporación Universitaria Minuto de Dios.
Srinivasa-Desikan, B. (2018). Deep learning for text. En Natural language processing and computational linguistics: A practical guide to text analysis with Python, Gensim, spaCy and Keras (pp. 224-236). Packt Publishing.
Zhou, Y. (2022). Natural language processing with improved deep learning neural networks. Scientific Programming, 2022, 1-8.