microsoft/AI-For-Beginners
Publicmirrored fromhttps://github.com/microsoft/AI-For-BeginnersAvailable
translations/es/lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb
495lines · modecode
| 1 | { |
| 2 | "cells": [ |
| 3 | { |
| 4 | "cell_type": "markdown", |
| 5 | "metadata": {}, |
| 6 | "source": [ |
| 7 | "# Redes generativas\n", |
| 8 | "\n", |
| 9 | "Las Redes Neuronales Recurrentes (RNNs) y sus variantes con celdas controladas, como las Celdas de Memoria a Largo Corto Plazo (LSTMs) y las Unidades Recurrentes Controladas (GRUs), proporcionaron un mecanismo para el modelado del lenguaje, es decir, pueden aprender el orden de las palabras y ofrecer predicciones para la siguiente palabra en una secuencia. Esto nos permite usar las RNNs para **tareas generativas**, como la generación de texto común, la traducción automática e incluso la generación de subtítulos para imágenes.\n", |
| 10 | "\n", |
| 11 | "En la arquitectura de RNN que discutimos en la unidad anterior, cada unidad RNN producía el siguiente estado oculto como salida. Sin embargo, también podemos añadir otra salida a cada unidad recurrente, lo que nos permitiría generar una **secuencia** (que tiene la misma longitud que la secuencia original). Además, podemos usar unidades RNN que no acepten una entrada en cada paso, y simplemente tomen un vector de estado inicial, para luego producir una secuencia de salidas.\n", |
| 12 | "\n", |
| 13 | "En este cuaderno, nos centraremos en modelos generativos simples que nos ayuden a generar texto. Para simplificar, construyamos una **red a nivel de caracteres**, que genera texto letra por letra. Durante el entrenamiento, necesitamos tomar un corpus de texto y dividirlo en secuencias de letras.\n" |
| 14 | ] |
| 15 | }, |
| 16 | { |
| 17 | "cell_type": "code", |
| 18 | "execution_count": 1, |
| 19 | "metadata": {}, |
| 20 | "outputs": [], |
| 21 | "source": [ |
| 22 | "import tensorflow as tf\n", |
| 23 | "from tensorflow import keras\n", |
| 24 | "import tensorflow_datasets as tfds\n", |
| 25 | "import numpy as np\n", |
| 26 | "\n", |
| 27 | "ds_train, ds_test = tfds.load('ag_news_subset').values()" |
| 28 | ] |
| 29 | }, |
| 30 | { |
| 31 | "cell_type": "markdown", |
| 32 | "metadata": {}, |
| 33 | "source": [ |
| 34 | "## Construyendo un vocabulario de caracteres\n", |
| 35 | "\n", |
| 36 | "Para construir una red generativa a nivel de caracteres, necesitamos dividir el texto en caracteres individuales en lugar de palabras. La capa `TextVectorization` que hemos estado utilizando antes no puede hacer eso, por lo que tenemos dos opciones:\n", |
| 37 | "\n", |
| 38 | "* Cargar el texto manualmente y realizar la tokenización 'a mano', como se muestra en [este ejemplo oficial de Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n", |
| 39 | "* Usar la clase `Tokenizer` para la tokenización a nivel de caracteres.\n", |
| 40 | "\n", |
| 41 | "Optaremos por la segunda opción. `Tokenizer` también se puede usar para tokenizar en palabras, por lo que debería ser fácil cambiar de tokenización a nivel de caracteres a nivel de palabras.\n", |
| 42 | "\n", |
| 43 | "Para realizar la tokenización a nivel de caracteres, necesitamos pasar el parámetro `char_level=True`:\n" |
| 44 | ] |
| 45 | }, |
| 46 | { |
| 47 | "cell_type": "code", |
| 48 | "execution_count": 2, |
| 49 | "metadata": {}, |
| 50 | "outputs": [], |
| 51 | "source": [ |
| 52 | "def extract_text(x):\n", |
| 53 | " return x['title']+' '+x['description']\n", |
| 54 | "\n", |
| 55 | "def tupelize(x):\n", |
| 56 | " return (extract_text(x),x['label'])\n", |
| 57 | "\n", |
| 58 | "tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n", |
| 59 | "tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])" |
| 60 | ] |
| 61 | }, |
| 62 | { |
| 63 | "cell_type": "markdown", |
| 64 | "metadata": {}, |
| 65 | "source": [ |
| 66 | "También queremos usar un token especial para indicar **fin de secuencia**, al que llamaremos `<eos>`. Vamos a añadirlo manualmente al vocabulario:\n" |
| 67 | ] |
| 68 | }, |
| 69 | { |
| 70 | "cell_type": "code", |
| 71 | "execution_count": 3, |
| 72 | "metadata": {}, |
| 73 | "outputs": [], |
| 74 | "source": [ |
| 75 | "eos_token = len(tokenizer.word_index)+1\n", |
| 76 | "tokenizer.word_index['<eos>'] = eos_token\n", |
| 77 | "\n", |
| 78 | "vocab_size = eos_token + 1" |
| 79 | ] |
| 80 | }, |
| 81 | { |
| 82 | "cell_type": "markdown", |
| 83 | "metadata": {}, |
| 84 | "source": [] |
| 85 | }, |
| 86 | { |
| 87 | "cell_type": "code", |
| 88 | "execution_count": 4, |
| 89 | "metadata": {}, |
| 90 | "outputs": [ |
| 91 | { |
| 92 | "data": { |
| 93 | "text/plain": [ |
| 94 | "[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]" |
| 95 | ] |
| 96 | }, |
| 97 | "execution_count": 4, |
| 98 | "metadata": {}, |
| 99 | "output_type": "execute_result" |
| 100 | } |
| 101 | ], |
| 102 | "source": [ |
| 103 | "tokenizer.texts_to_sequences(['Hello, world!'])" |
| 104 | ] |
| 105 | }, |
| 106 | { |
| 107 | "cell_type": "markdown", |
| 108 | "metadata": {}, |
| 109 | "source": [ |
| 110 | "## Entrenando una RNN generativa para generar títulos\n", |
| 111 | "\n", |
| 112 | "La forma en que entrenaremos una RNN para generar títulos de noticias es la siguiente. En cada paso, tomaremos un título, que será alimentado a una RNN, y para cada carácter de entrada le pediremos a la red que genere el siguiente carácter de salida:\n", |
| 113 | "\n", |
| 114 | "\n", |
| 115 | "\n", |
| 116 | "Para el último carácter de nuestra secuencia, le pediremos a la red que genere el token `<eos>`.\n", |
| 117 | "\n", |
| 118 | "La principal diferencia con la RNN generativa que estamos utilizando aquí es que tomaremos una salida de cada paso de la RNN, y no solo de la celda final. Esto se puede lograr especificando el parámetro `return_sequences` en la celda de la RNN.\n", |
| 119 | "\n", |
| 120 | "Así, durante el entrenamiento, una entrada para la red sería una secuencia de caracteres codificados de cierta longitud, y una salida sería una secuencia de la misma longitud, pero desplazada por un elemento y terminada con `<eos>`. El minibatch consistirá en varias de estas secuencias, y necesitaremos usar **padding** para alinear todas las secuencias.\n", |
| 121 | "\n", |
| 122 | "Vamos a crear funciones que transformen el conjunto de datos por nosotros. Debido a que queremos rellenar las secuencias a nivel de minibatch, primero agruparemos el conjunto de datos llamando `.batch()`, y luego usaremos `map` para realizar la transformación. Por lo tanto, la función de transformación tomará un minibatch completo como parámetro:\n" |
| 123 | ] |
| 124 | }, |
| 125 | { |
| 126 | "cell_type": "code", |
| 127 | "execution_count": 5, |
| 128 | "metadata": {}, |
| 129 | "outputs": [], |
| 130 | "source": [ |
| 131 | "def title_batch(x):\n", |
| 132 | " x = [t.numpy().decode('utf-8') for t in x]\n", |
| 133 | " z = tokenizer.texts_to_sequences(x)\n", |
| 134 | " z = tf.keras.preprocessing.sequence.pad_sequences(z)\n", |
| 135 | " return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)" |
| 136 | ] |
| 137 | }, |
| 138 | { |
| 139 | "cell_type": "markdown", |
| 140 | "metadata": {}, |
| 141 | "source": [ |
| 142 | "Algunas cosas importantes que hacemos aquí:\n", |
| 143 | "* Primero extraemos el texto real del tensor de cadenas\n", |
| 144 | "* `text_to_sequences` convierte la lista de cadenas en una lista de tensores de enteros\n", |
| 145 | "* `pad_sequences` rellena esos tensores hasta su longitud máxima\n", |
| 146 | "* Finalmente codificamos en formato one-hot todos los caracteres, y también realizamos el desplazamiento y la adición de `<eos>`. Pronto veremos por qué necesitamos caracteres codificados en formato one-hot.\n", |
| 147 | "\n", |
| 148 | "Sin embargo, esta función es **Pythonic**, es decir, no puede ser traducida automáticamente al gráfico computacional de Tensorflow. Obtendremos errores si intentamos usar esta función directamente en la función `Dataset.map`. Necesitamos encapsular esta llamada Pythonic utilizando el envoltorio `py_function`:\n" |
| 149 | ] |
| 150 | }, |
| 151 | { |
| 152 | "cell_type": "code", |
| 153 | "execution_count": 6, |
| 154 | "metadata": {}, |
| 155 | "outputs": [], |
| 156 | "source": [ |
| 157 | "def title_batch_fn(x):\n", |
| 158 | " x = x['title']\n", |
| 159 | " a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n", |
| 160 | " return a,b" |
| 161 | ] |
| 162 | }, |
| 163 | { |
| 164 | "cell_type": "markdown", |
| 165 | "metadata": {}, |
| 166 | "source": [ |
| 167 | "> **Nota**: Diferenciar entre las funciones de transformación de Python y Tensorflow puede parecer un poco complejo, y podrías estar preguntándote por qué no transformamos el conjunto de datos usando funciones estándar de Python antes de pasarlo a `fit`. Aunque esto definitivamente se puede hacer, usar `Dataset.map` tiene una gran ventaja, ya que la tubería de transformación de datos se ejecuta utilizando el gráfico computacional de Tensorflow, lo que aprovecha las capacidades de cálculo de la GPU y minimiza la necesidad de transferir datos entre la CPU y la GPU.\n", |
| 168 | "\n", |
| 169 | "Ahora podemos construir nuestra red generadora y comenzar el entrenamiento. Puede basarse en cualquier célula recurrente que discutimos en la unidad anterior (simple, LSTM o GRU). En nuestro ejemplo, utilizaremos LSTM.\n", |
| 170 | "\n", |
| 171 | "Dado que la red toma caracteres como entrada y el tamaño del vocabulario es bastante pequeño, no necesitamos una capa de embeddings; la entrada codificada en formato one-hot puede ir directamente a la célula LSTM. La capa de salida sería un clasificador `Dense` que convertirá la salida de LSTM en números de tokens codificados en formato one-hot.\n", |
| 172 | "\n", |
| 173 | "Además, dado que estamos trabajando con secuencias de longitud variable, podemos usar la capa `Masking` para crear una máscara que ignore la parte rellenada de la cadena. Esto no es estrictamente necesario, ya que no estamos muy interesados en todo lo que va más allá del token `<eos>`, pero lo utilizaremos con el propósito de adquirir experiencia con este tipo de capa. El `input_shape` sería `(None, vocab_size)`, donde `None` indica la secuencia de longitud variable, y la forma de salida es también `(None, vocab_size)`, como puedes ver en el `summary`:\n" |
| 174 | ] |
| 175 | }, |
| 176 | { |
| 177 | "cell_type": "code", |
| 178 | "execution_count": 7, |
| 179 | "metadata": {}, |
| 180 | "outputs": [ |
| 181 | { |
| 182 | "name": "stdout", |
| 183 | "output_type": "stream", |
| 184 | "text": [ |
| 185 | "Model: \"sequential\"\n", |
| 186 | "_________________________________________________________________\n", |
| 187 | "Layer (type) Output Shape Param # \n", |
| 188 | "=================================================================\n", |
| 189 | "masking (Masking) (None, None, 84) 0 \n", |
| 190 | "_________________________________________________________________\n", |
| 191 | "lstm (LSTM) (None, None, 128) 109056 \n", |
| 192 | "_________________________________________________________________\n", |
| 193 | "dense (Dense) (None, None, 84) 10836 \n", |
| 194 | "=================================================================\n", |
| 195 | "Total params: 119,892\n", |
| 196 | "Trainable params: 119,892\n", |
| 197 | "Non-trainable params: 0\n", |
| 198 | "_________________________________________________________________\n", |
| 199 | "15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n" |
| 200 | ] |
| 201 | }, |
| 202 | { |
| 203 | "data": { |
| 204 | "text/plain": [ |
| 205 | "<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>" |
| 206 | ] |
| 207 | }, |
| 208 | "execution_count": 7, |
| 209 | "metadata": {}, |
| 210 | "output_type": "execute_result" |
| 211 | } |
| 212 | ], |
| 213 | "source": [ |
| 214 | "model = keras.models.Sequential([\n", |
| 215 | " keras.layers.Masking(input_shape=(None,vocab_size)),\n", |
| 216 | " keras.layers.LSTM(128,return_sequences=True),\n", |
| 217 | " keras.layers.Dense(vocab_size,activation='softmax')\n", |
| 218 | "])\n", |
| 219 | "\n", |
| 220 | "model.summary()\n", |
| 221 | "model.compile(loss='categorical_crossentropy')\n", |
| 222 | "\n", |
| 223 | "model.fit(ds_train.batch(8).map(title_batch_fn))" |
| 224 | ] |
| 225 | }, |
| 226 | { |
| 227 | "cell_type": "markdown", |
| 228 | "metadata": {}, |
| 229 | "source": [ |
| 230 | "## Generando salida\n", |
| 231 | "\n", |
| 232 | "Ahora que hemos entrenado el modelo, queremos usarlo para generar algo de salida. Primero, necesitamos una forma de decodificar texto representado por una secuencia de números de tokens. Para ello, podríamos usar la función `tokenizer.sequences_to_texts`; sin embargo, no funciona bien con la tokenización a nivel de caracteres. Por lo tanto, tomaremos un diccionario de tokens del tokenizer (llamado `word_index`), construiremos un mapa inverso y escribiremos nuestra propia función de decodificación:\n" |
| 233 | ] |
| 234 | }, |
| 235 | { |
| 236 | "cell_type": "code", |
| 237 | "execution_count": 10, |
| 238 | "metadata": {}, |
| 239 | "outputs": [], |
| 240 | "source": [ |
| 241 | "reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n", |
| 242 | "\n", |
| 243 | "def decode(x):\n", |
| 244 | " return ''.join([reverse_map[t] for t in x])" |
| 245 | ] |
| 246 | }, |
| 247 | { |
| 248 | "cell_type": "markdown", |
| 249 | "metadata": {}, |
| 250 | "source": [ |
| 251 | "Ahora, vamos a generar. Comenzaremos con una cadena `start`, la codificaremos en una secuencia `inp`, y luego en cada paso llamaremos a nuestra red para inferir el siguiente carácter.\n", |
| 252 | "\n", |
| 253 | "La salida de la red `out` es un vector de `vocab_size` elementos que representa las probabilidades de cada token, y podemos encontrar el número del token más probable utilizando `argmax`. Luego, añadimos este carácter a la lista generada de tokens y continuamos con la generación. Este proceso de generar un carácter se repite `size` veces para generar el número requerido de caracteres, y terminamos antes si se encuentra el `eos_token`.\n" |
| 254 | ] |
| 255 | }, |
| 256 | { |
| 257 | "cell_type": "code", |
| 258 | "execution_count": 12, |
| 259 | "metadata": {}, |
| 260 | "outputs": [ |
| 261 | { |
| 262 | "data": { |
| 263 | "text/plain": [ |
| 264 | "'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'" |
| 265 | ] |
| 266 | }, |
| 267 | "execution_count": 12, |
| 268 | "metadata": {}, |
| 269 | "output_type": "execute_result" |
| 270 | } |
| 271 | ], |
| 272 | "source": [ |
| 273 | "def generate(model,size=100,start='Today '):\n", |
| 274 | " inp = tokenizer.texts_to_sequences([start])[0]\n", |
| 275 | " chars = inp\n", |
| 276 | " for i in range(size):\n", |
| 277 | " out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n", |
| 278 | " nc = tf.argmax(out)\n", |
| 279 | " if nc==eos_token:\n", |
| 280 | " break\n", |
| 281 | " chars.append(nc.numpy())\n", |
| 282 | " inp = inp+[nc]\n", |
| 283 | " return decode(chars)\n", |
| 284 | " \n", |
| 285 | "generate(model)" |
| 286 | ] |
| 287 | }, |
| 288 | { |
| 289 | "cell_type": "markdown", |
| 290 | "metadata": {}, |
| 291 | "source": [ |
| 292 | "## Muestreo de salida durante el entrenamiento\n", |
| 293 | "\n", |
| 294 | "Dado que no tenemos métricas útiles como *precisión*, la única forma de verificar que nuestro modelo está mejorando es **muestreando** cadenas generadas durante el entrenamiento. Para hacerlo, utilizaremos **callbacks**, es decir, funciones que podemos pasar a la función `fit` y que se llamarán periódicamente durante el entrenamiento.\n" |
| 295 | ] |
| 296 | }, |
| 297 | { |
| 298 | "cell_type": "code", |
| 299 | "execution_count": 13, |
| 300 | "metadata": {}, |
| 301 | "outputs": [ |
| 302 | { |
| 303 | "name": "stdout", |
| 304 | "output_type": "stream", |
| 305 | "text": [ |
| 306 | "Epoch 1/3\n", |
| 307 | "15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n", |
| 308 | "Today #39;s a lead in the company for the strike\n", |
| 309 | "Epoch 2/3\n", |
| 310 | "15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n", |
| 311 | "Today #39;s the Market Service on Security Start (AP)\n", |
| 312 | "Epoch 3/3\n", |
| 313 | "15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n", |
| 314 | "Today #39;s a line on the strike to start for the start\n" |
| 315 | ] |
| 316 | }, |
| 317 | { |
| 318 | "data": { |
| 319 | "text/plain": [ |
| 320 | "<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>" |
| 321 | ] |
| 322 | }, |
| 323 | "execution_count": 13, |
| 324 | "metadata": {}, |
| 325 | "output_type": "execute_result" |
| 326 | } |
| 327 | ], |
| 328 | "source": [ |
| 329 | "sampling_callback = keras.callbacks.LambdaCallback(\n", |
| 330 | " on_epoch_end = lambda batch, logs: print(generate(model))\n", |
| 331 | ")\n", |
| 332 | "\n", |
| 333 | "model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)" |
| 334 | ] |
| 335 | }, |
| 336 | { |
| 337 | "cell_type": "markdown", |
| 338 | "metadata": {}, |
| 339 | "source": [ |
| 340 | "Este ejemplo ya genera un texto bastante bueno, pero se puede mejorar de varias maneras:\n", |
| 341 | "\n", |
| 342 | "* **Más texto**. Solo hemos utilizado títulos para nuestra tarea, pero podrías experimentar con texto completo. Recuerda que las RNN no son muy buenas manejando secuencias largas, por lo que tiene sentido dividirlas en oraciones más cortas o entrenar siempre con una longitud de secuencia fija de algún valor predefinido `num_chars` (por ejemplo, 256). Podrías intentar modificar el ejemplo anterior para usar esta arquitectura, utilizando el [tutorial oficial de Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/) como inspiración.\n", |
| 343 | "\n", |
| 344 | "* **LSTM multicapa**. Tiene sentido probar con 2 o 3 capas de células LSTM. Como mencionamos en la unidad anterior, cada capa de LSTM extrae ciertos patrones del texto, y en el caso de un generador a nivel de caracteres, podemos esperar que el nivel inferior de LSTM sea responsable de extraer sílabas, y los niveles superiores de palabras y combinaciones de palabras. Esto se puede implementar fácilmente pasando un parámetro de número de capas al constructor de LSTM.\n", |
| 345 | "\n", |
| 346 | "* También podrías experimentar con **unidades GRU** y ver cuáles funcionan mejor, así como con **diferentes tamaños de capas ocultas**. Una capa oculta demasiado grande puede resultar en sobreajuste (por ejemplo, la red aprenderá el texto exacto), y un tamaño más pequeño podría no producir buenos resultados.\n" |
| 347 | ] |
| 348 | }, |
| 349 | { |
| 350 | "cell_type": "markdown", |
| 351 | "metadata": {}, |
| 352 | "source": [ |
| 353 | "## Generación de texto suave y temperatura\n", |
| 354 | "\n", |
| 355 | "En la definición anterior de `generate`, siempre tomábamos el carácter con la mayor probabilidad como el siguiente carácter en el texto generado. Esto daba como resultado que el texto a menudo \"ciclaba\" entre las mismas secuencias de caracteres una y otra vez, como en este ejemplo:\n", |
| 356 | "```\n", |
| 357 | "today of the second the company and a second the company ...\n", |
| 358 | "```\n", |
| 359 | "\n", |
| 360 | "Sin embargo, si observamos la distribución de probabilidad para el siguiente carácter, podría suceder que la diferencia entre algunas de las probabilidades más altas no sea muy grande, por ejemplo, un carácter puede tener una probabilidad de 0.2, otro de 0.19, etc. Por ejemplo, al buscar el siguiente carácter en la secuencia '*play*', el siguiente carácter podría ser igualmente un espacio o **e** (como en la palabra *player*).\n", |
| 361 | "\n", |
| 362 | "Esto nos lleva a la conclusión de que no siempre es \"justo\" seleccionar el carácter con mayor probabilidad, ya que elegir el segundo más alto aún podría llevarnos a un texto significativo. Es más sabio **muestrear** caracteres de la distribución de probabilidad proporcionada por la salida de la red.\n", |
| 363 | "\n", |
| 364 | "Este muestreo se puede realizar utilizando la función `np.multinomial`, que implementa la llamada **distribución multinomial**. Una función que implementa esta generación de texto **suave** se define a continuación:\n" |
| 365 | ] |
| 366 | }, |
| 367 | { |
| 368 | "cell_type": "code", |
| 369 | "execution_count": 33, |
| 370 | "metadata": { |
| 371 | "scrolled": true |
| 372 | }, |
| 373 | "outputs": [ |
| 374 | { |
| 375 | "name": "stdout", |
| 376 | "output_type": "stream", |
| 377 | "text": [ |
| 378 | "\n", |
| 379 | "--- Temperature = 0.3\n", |
| 380 | "Today #39;s strike #39; to start at the store return\n", |
| 381 | "On Sunday PO to Be Data Profit Up (Reuters)\n", |
| 382 | "Moscow, SP wins straight to the Microsoft #39;s control of the space start\n", |
| 383 | "President olding of the blast start for the strike to pay <b>...</b>\n", |
| 384 | "Little red riding hood ficed to the spam countered in European <b>...</b>\n", |
| 385 | "\n", |
| 386 | "--- Temperature = 0.8\n", |
| 387 | "Today countie strikes ryder missile faces food market blut\n", |
| 388 | "On Sunday collores lose-toppy of sale of Bullment in <b>...</b>\n", |
| 389 | "Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n", |
| 390 | "President Ol Luster for Profit Peaced Raised (AP)\n", |
| 391 | "Little red riding hood dace on depart talks #39; bank up\n", |
| 392 | "\n", |
| 393 | "--- Temperature = 1.0\n", |
| 394 | "Today wits House buiting debate fixes #39; supervice stake again\n", |
| 395 | "On Sunday arling digital poaching In for level\n", |
| 396 | "Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n", |
| 397 | "President teps help of roubler stepted lessabul-Dhalitics (AFP)\n", |
| 398 | "Little red riding hood signs on cash in Carter-youb\n", |
| 399 | "\n", |
| 400 | "--- Temperature = 1.3\n", |
| 401 | "Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n", |
| 402 | "On Sunday hround elitwing wint EU Powerburlinetien\n", |
| 403 | "Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n", |
| 404 | "President lost securitys from power Elections in Smiltrials\n", |
| 405 | "Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n", |
| 406 | "\n", |
| 407 | "--- Temperature = 1.8\n", |
| 408 | "Today #39;It: He deat: N.KA Asside\n", |
| 409 | "On Sunday i arry Par aldeup patient Wo stele1\n" |
| 410 | ] |
| 411 | }, |
| 412 | { |
| 413 | "ename": "KeyError", |
| 414 | "evalue": "0", |
| 415 | "output_type": "error", |
| 416 | "traceback": [ |
| 417 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", |
| 418 | "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", |
| 419 | "\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", |
| 420 | "\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", |
| 421 | "\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", |
| 422 | "\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", |
| 423 | "\u001b[0;31mKeyError\u001b[0m: 0" |
| 424 | ] |
| 425 | } |
| 426 | ], |
| 427 | "source": [ |
| 428 | "def generate_soft(model,size=100,start='Today ',temperature=1.0):\n", |
| 429 | " inp = tokenizer.texts_to_sequences([start])[0]\n", |
| 430 | " chars = inp\n", |
| 431 | " for i in range(size):\n", |
| 432 | " out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n", |
| 433 | " probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n", |
| 434 | " probs = probs/np.sum(probs)\n", |
| 435 | " nc = np.argmax(np.random.multinomial(1,probs,1))\n", |
| 436 | " if nc==eos_token:\n", |
| 437 | " break\n", |
| 438 | " chars.append(nc)\n", |
| 439 | " inp = inp+[nc]\n", |
| 440 | " return decode(chars)\n", |
| 441 | "\n", |
| 442 | "words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n", |
| 443 | " \n", |
| 444 | "for i in [0.3,0.8,1.0,1.3,1.8]:\n", |
| 445 | " print(f\"\\n--- Temperature = {i}\")\n", |
| 446 | " for j in range(5):\n", |
| 447 | " print(generate_soft(model,size=300,start=words[j],temperature=i))" |
| 448 | ] |
| 449 | }, |
| 450 | { |
| 451 | "cell_type": "markdown", |
| 452 | "metadata": {}, |
| 453 | "source": [ |
| 454 | "Hemos introducido un parámetro más llamado **temperatura**, que se utiliza para indicar qué tan estrictamente debemos adherirnos a la probabilidad más alta. Si la temperatura es 1.0, hacemos un muestreo multinomial justo, y cuando la temperatura se acerca al infinito, todas las probabilidades se vuelven iguales y seleccionamos el siguiente carácter al azar. En el ejemplo a continuación, podemos observar que el texto se vuelve sin sentido cuando aumentamos demasiado la temperatura, y se asemeja a un texto \"cíclico\" generado rígidamente cuando se acerca a 0.\n" |
| 455 | ] |
| 456 | }, |
| 457 | { |
| 458 | "cell_type": "markdown", |
| 459 | "metadata": {}, |
| 460 | "source": [ |
| 461 | "\n---\n\n**Descargo de responsabilidad**: \nEste documento ha sido traducido utilizando el servicio de traducción automática [Co-op Translator](https://github.com/Azure/co-op-translator). Si bien nos esforzamos por garantizar la precisión, tenga en cuenta que las traducciones automatizadas pueden contener errores o imprecisiones. El documento original en su idioma nativo debe considerarse la fuente autorizada. Para información crítica, se recomienda una traducción profesional realizada por humanos. No nos hacemos responsables de malentendidos o interpretaciones erróneas que puedan surgir del uso de esta traducción.\n" |
| 462 | ] |
| 463 | } |
| 464 | ], |
| 465 | "metadata": { |
| 466 | "interpreter": { |
| 467 | "hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f" |
| 468 | }, |
| 469 | "kernelspec": { |
| 470 | "display_name": "Python 3.8.12 ('py38')", |
| 471 | "language": "python", |
| 472 | "name": "python3" |
| 473 | }, |
| 474 | "language_info": { |
| 475 | "codemirror_mode": { |
| 476 | "name": "ipython", |
| 477 | "version": 3 |
| 478 | }, |
| 479 | "file_extension": ".py", |
| 480 | "mimetype": "text/x-python", |
| 481 | "name": "python", |
| 482 | "nbconvert_exporter": "python", |
| 483 | "pygments_lexer": "ipython3", |
| 484 | "version": "3.8.12" |
| 485 | }, |
| 486 | "coopTranslator": { |
| 487 | "original_hash": "9fbb7d5fda708537649f71f5f646fcde", |
| 488 | "translation_date": "2025-08-31T16:51:40+00:00", |
| 489 | "source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb", |
| 490 | "language_code": "es" |
| 491 | } |
| 492 | }, |
| 493 | "nbformat": 4, |
| 494 | "nbformat_minor": 4 |
| 495 | } |