Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/hub/tutorials/tf2_text_classification.ipynb
25118 views
Kernel: Python 3

Licensed under the Apache License, Version 2.0 (the "License");

# Copyright 2019 The TensorFlow Hub Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ==============================================================================
#@title MIT License # # Copyright (c) 2017 François Chollet # IGNORE_COPYRIGHT: cleared by OSS licensing # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE.

Clasificación de textos con revisiones de películas

En este bloc de notas se clasifican reseñas de películas como positiva o negativa a partir del texto de la reseña. Este es un ejemplo de clasificación binaria (o de dos clases), un tipo de problema de aprendizaje automático importante y ampliamente aplicable.

Usaremo los conjuntos de datos de IMDB que contiene el texto de 50 000 reseñas de películas del Conjunto de datos de películas de Internet. Se divide en 25 000 reseñas para entrenamiento y 25 000 reseñas para prueba. Los conjuntos de entrenamiento y prueba están equilibrados, lo que significa que contienen la misma cantidad de reseñas positivas y negativas.

En este bloc de notas se usa tf.keras, una API de alto nivel para generar y entrenar modelos en TensorFlow, y TensorFlow Hub, una biblioteca y plataforma para aprendizaje por transferencia. Si desea obtener un tutorial más avanzado sobre clasificación de textos con tf.keras, consulte la Guía de clasificación de textos de MLCC.

Más modelos

Aquí puede encontrar modelos más expresivos o de mayor rendimiento que puede usar para generar la incorporación de texto.

Preparación

import numpy as np import tensorflow as tf import tensorflow_hub as hub import tensorflow_datasets as tfds import matplotlib.pyplot as plt print("Version: ", tf.__version__) print("Eager mode: ", tf.executing_eagerly()) print("Hub version: ", hub.__version__) print("GPU is", "available" if tf.config.list_physical_devices('GPU') else "NOT AVAILABLE")

Descargar el conjunto de datos de IMDB

El conjunto de datos de IMDB está disponible en conjuntos de datos de TensorFlow. El siguiente código sirve para descargar el conjunto de datos de IMDB en su computadora (o en el tiempo de ejecución de Colab):

train_data, test_data = tfds.load(name="imdb_reviews", split=["train", "test"], batch_size=-1, as_supervised=True) train_examples, train_labels = tfds.as_numpy(train_data) test_examples, test_labels = tfds.as_numpy(test_data)

Explorar los datos

Tomémonos un momento para comprender el formato de los datos. Cada ejemplo es una frase que representa la reseña de película y una etiqueta correspondiente. La frase no se preprocesa de ninguna manera. La etiqueta es un valor de número entero que puede ser 0 o 1, donde 0 corresponde a una reseña negativa y 1 corresponde a una reseña positiva.

print("Training entries: {}, test entries: {}".format(len(train_examples), len(test_examples)))

Imprimamos los primeros 10 ejemplos.

train_examples[:10]

Imprimamos también las primeras 10 etiquetas.

train_labels[:10]

Generar el modelo

La red neuronal se crea apilando capas, lo que implica tomar tres decisiones principales en términos de arquitectura:

  • ¿Cómo se representará el texto?

  • ¿Cuántas capas se usarán en el modelo?

  • ¿Cuántas unidades ocultas se usarán para cada capa?

En este ejemplo, los datos de entrada están compuestos por oraciones. Las etiquetas que se deben predecir son 0 o 1.

Una forma de representar el texto es convertir las oraciones en vectores incorporados. Podemos usar una incorporación de texto preentrenada como la primera capa, lo que nos dará dos ventajas:

  • No hay que preocuparse por el preprocesamiento del texto.

  • Podemos sacar provecho del aprendizaje por transferencia.

Para este ejemplo usaremos un modelo de TensorFlow Hub llamado google/nnlm-en-dim50/2.

Hay otros dos modelos para probar en este tutorial:

Primero crearemos una capa de Keras que use un modelo de TensorFlow Hub para incorporar las oraciones y la probaremos en un par de ejemplos de entrada. Observe como la forma de salida de las incorporaciones que se producen es la requerida: (num_examples, embedding_dimension).

model = "https://tfhub.dev/google/nnlm-en-dim50/2" hub_layer = hub.KerasLayer(model, input_shape=[], dtype=tf.string, trainable=True) hub_layer(train_examples[:3])

Ahora vamos a generar un modelo completo:

model = tf.keras.Sequential() model.add(hub_layer) model.add(tf.keras.layers.Dense(16, activation='relu')) model.add(tf.keras.layers.Dense(1)) model.summary()

Las capas se apilan secuencialmente para generar el clasificador:

  1. La primera capa es una capa de TensorFlow Hub. Esta capa usa un modelo guardado preentrenado para asignar una oración a su vector de incorporación. El modelo que estamos usando (google/nnlm-en-dim50/2) divide la oración en tokens, incorpora cada token y luego combina la incorporación. Las dimensiones resultantes son: (num_examples, embedding_dimension).

  2. Este vector de salida de longitud fija se canaliza a través de una capa (Dense) completamente conectada con 16 unidades ocultas.

  3. La última capa está densamente conectada con un único nodo de salida. Esto genera logits: las probabilidades logarítmicas de la clase verdadera, según el modelo.

Unidades ocultas

El modelo anterior tiene dos capas intermedias u "ocultas" entre la entrada y la salida. La cantidad de salidas (unidades, nodos o neuronas) es la dimensión del espacio de representación para la capa. En otras palabras, la cantidad de libertad que se le permite a la capa cuando aprende una representación interna.

Si un modelo tiene más unidades ocultas (un espacio de representación de alta dimensionalidad) o más capas, la red puede aprender representaciones más complejas. Sin embargo, la red se vuelve computacionalmente más costosa y puede derivar en patrones indeseados de aprendizaje; patrones que mejoran el rendimiento de los datos de entrenamiento pero no de los datos de prueba. A esto se lo denomina "sobreajuste" (overfitting) y lo veremos más adelante.

Función de pérdida y optimizador

Un modelo necesita una función de pérdida y un optimizador para el entrenamiento. Dado que este es un problema de clasificación binaria y el modelo genera una probabilidad (una capa de una sola unidad con una activación sigmoide), usaremos la función de pérdida binary_crossentropy.

Esta no es la única opción para una función de pérdida, usted podría, por ejemplo, elegir mean_squared_error. Pero, por lo general, binary_crossentropy es mejor para trabajar con probabilidades; mide la "distancia" entre las distribuciones de probabilidad o, en nuestro caso, entre la distribución real y las predicciones.

Más adelante, cuando exploremos los problemas de regresión (por ejemplo, para predecir el precio de una vivienda), veremos cómo usar otra función de pérdida conocida como error cuadrático medio.

Ahora, configure el modelo para usar un optimizador y una función de pérdida:

model.compile(optimizer='adam', loss=tf.losses.BinaryCrossentropy(from_logits=True), metrics=[tf.metrics.BinaryAccuracy(threshold=0.0, name='accuracy')])

Crear un conjunto de validación

Durante el entrenamiento, nos conviene comprobar la exactitud del modelo con datos que no haya visto antes. Crea un conjunto de validación. Para crearlo separamos 10 000 ejemplos de los datos de entrenamiento originales. (¿Por qué no usamos el conjunto de prueba ahora? Nuestro objetivo es desarrollar y ajustar el modelo usando solamente los datos de entrenamiento y después, usar los datos de prueba una sola vez para evaluar la precisión).

x_val = train_examples[:10000] partial_x_train = train_examples[10000:] y_val = train_labels[:10000] partial_y_train = train_labels[10000:]

Entrenar el modelo

Entrene el modelo durante 40 épocas en minilotes de 512 muestras. Es decir, 40 iteraciones sobre todas las muestras en los tensores x_train y y_train. Durante el entrenamiento, monitoree la pérdida y la precisión del modelo en las 10 000 muestras del conjunto de validación:

history = model.fit(partial_x_train, partial_y_train, epochs=40, batch_size=512, validation_data=(x_val, y_val), verbose=1)

Evaluar el modelo

Veamos el desempeño del modelo. Nos devolverá dos valores; la pérdida (un número que representa nuestro error, los valores bajos son mejores) y la precisión.

results = model.evaluate(test_examples, test_labels) print(results)

Este enfoque, relativamente sencillo, alcanza una precisión de aproximadamente un 87 %. Con enfoques más avanzados, el modelo debería acercarse al 95 %.

Crear un gráfico de precisión y pérdida a lo largo del tiempo

model.fit() devuelve un objeto History que contiene un diccionario con todo lo que ocurrió durante el entrenamiento:

history_dict = history.history history_dict.keys()

Hay cuatro entradas: una por cada métrica que se monitoreó durante el entrenamiento y la validación. Podemos usarlas para trazar la pérdida y validación del entrenamiento, para compararlas. Podemos hacer lo mismo con la precisión de entrenamiento y validación:

acc = history_dict['accuracy'] val_acc = history_dict['val_accuracy'] loss = history_dict['loss'] val_loss = history_dict['val_loss'] epochs = range(1, len(acc) + 1) # "bo" is for "blue dot" plt.plot(epochs, loss, 'bo', label='Training loss') # b is for "solid blue line" plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.show()
plt.clf() # clear figure plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.show()

En este gráfico, los puntos representan la pérdida y la precisión del entrenamiento y las líneas continuas reflejan la pérdida y la precisión de la validación.

Como puede ver, la pérdida del entrenamiento se reduce época tras época y la precisión del entrenamiento aumenta a medida que pasan las épocas. Esto es lo que suele pasar cuando se usa una optimización con descenso de gradiente, debe reducir al mínimo la cantidad deseada en cada iteración.

Esto no es lo que sucede en el caso de la pérdida y la precisión de la validación, al parecer llegan a su punto máximo después de aproximadamente veinte épocas. Este es un ejemplo de sobreajuste: el modelo funciona mejor con los datos de entrenamiento que con los datos que no ha visto anteriormente. Pasado este punto, el modelo se sobreoptimiza y aprende representaciones específicas de los datos de entrenamiento que no se generalizan a los datos de prueba.

Para este caso particular, podríamos evitar el sobreajuste con tan solo detener el entrenamiento después de aproximadamente veinte épocas. Más adelante verá cómo hacer esto automáticamente con una retrollamada.