Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Cargar texto

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Este tutorial proporciona un ejemplo de cómo usar tf.data.TextLineDataset para cargar ejemplos de archivos de texto. TextLineDataset está diseñado para crear un conjunto de datos a partir de un archivo de texto, en el que cada ejemplo es una línea de texto del archivo original. Esto es potencialmente útil para cualquier dato de texto que se base principalmente en líneas (por ejemplo, poesía o registros de errores).

En este tutorial, usaremos tres traducciones al inglés diferentes del mismo trabajo, Homer's Illiad, y entrenaremos un modelo para identificar al traductor dada una sola línea de texto.

Preparar

pip install -q tfds-nightly
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

camab0b9eca

Los textos de las tres traducciones son por:

Los archivos de texto utilizados en este tutorial se han sometido a algunas tareas de preprocesamiento típicas, en su mayoría eliminando cosas: encabezado y pie de página del documento, números de línea, títulos de capítulo. Descargue estos archivos ligeramente modificados localmente.

DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']

for name in FILE_NAMES:
  text_dir = tf.keras.utils.get_file(name, origin=DIRECTORY_URL+name)
  
parent_dir = os.path.dirname(text_dir)

parent_dir
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt
819200/815980 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt
811008/809730 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt
811008/807992 [==============================] - 0s 0us/step

'/home/kbuilder/.keras/datasets'

Cargar texto en conjuntos de datos

Repita los archivos y cargue cada uno en su propio conjunto de datos.

Cada ejemplo debe etiquetarse individualmente, así que use tf.data.Dataset.map para aplicar una función de etiquetado a cada uno. Esto iterará sobre cada ejemplo en el conjunto de datos, devolviendo pares ( example, label ).

def labeler(example, index):
  return example, tf.cast(index, tf.int64)  

labeled_data_sets = []

for i, file_name in enumerate(FILE_NAMES):
  lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir, file_name))
  labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i))
  labeled_data_sets.append(labeled_dataset)

Combine estos conjuntos de datos etiquetados en un solo conjunto de datos y mezcle.

BUFFER_SIZE = 50000
BATCH_SIZE = 64
TAKE_SIZE = 5000
all_labeled_data = labeled_data_sets[0]
for labeled_dataset in labeled_data_sets[1:]:
  all_labeled_data = all_labeled_data.concatenate(labeled_dataset)
  
all_labeled_data = all_labeled_data.shuffle(
    BUFFER_SIZE, reshuffle_each_iteration=False)

Puede usar tf.data.Dataset.take e print para ver cómo se ven los pares (example, label) . La propiedad numpy muestra el valor de cada tensor.

for ex in all_labeled_data.take(5):
  print(ex)
(<tf.Tensor: shape=(), dtype=string, numpy=b'Of Troy, seeing the body borne away,'>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
(<tf.Tensor: shape=(), dtype=string, numpy=b"With her own children, for her husband's sake.">, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
(<tf.Tensor: shape=(), dtype=string, numpy=b'That task refused, but went; yet neither swift'>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
(<tf.Tensor: shape=(), dtype=string, numpy=b'Shouldst thou from spear or sword receive a wound,'>, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
(<tf.Tensor: shape=(), dtype=string, numpy=b'Then to Idaean Jove, the cloud-girt son'>, <tf.Tensor: shape=(), dtype=int64, numpy=1>)

Codificar líneas de texto como números

Los modelos de aprendizaje automático funcionan con números, no con palabras, por lo que los valores de las cadenas deben convertirse en listas de números. Para hacer eso, asigne cada palabra única a un número entero único.

Desarrollar vocabulario

Primero, construya un vocabulario al convertir el texto en una colección de palabras individuales únicas. Hay algunas formas de hacer esto tanto en TensorFlow como en Python. Para este tutorial:

  1. numpy valor numpy cada ejemplo.
  2. Utilice tfds.deprecated.text.Tokenizer para dividirlo en tokens.
  3. Reúna estos tokens en un conjunto de Python para eliminar los duplicados.
  4. Obtenga el tamaño del vocabulario para su uso posterior.
tokenizer = tfds.deprecated.text.Tokenizer()

vocabulary_set = set()
for text_tensor, _ in all_labeled_data:
  some_tokens = tokenizer.tokenize(text_tensor.numpy())
  vocabulary_set.update(some_tokens)

vocab_size = len(vocabulary_set)
vocab_size
17178

Ejemplos de codificación

Cree un codificador pasando vocabulary_set a tfds.deprecated.text.TokenTextEncoder . El método de encode del encode toma una cadena de texto y devuelve una lista de números enteros.

encoder = tfds.deprecated.text.TokenTextEncoder(vocabulary_set)

Puede probar esto en una sola línea para ver cómo se ve la salida.

example_text = next(iter(all_labeled_data))[0].numpy()
print(example_text)
b'Of Troy, seeing the body borne away,'

encoded_example = encoder.encode(example_text)
print(encoded_example)
[16791, 1581, 325, 1885, 16189, 15504, 15638]

Ahora ejecute el codificador en el conjunto de datos envolviéndolo en tf.py_function y pasándolo al método de map del conjunto de datos.

def encode(text_tensor, label):
  encoded_text = encoder.encode(text_tensor.numpy())
  return encoded_text, label

Desea utilizar Dataset.map para aplicar esta función a cada elemento del conjunto de datos. Dataset.map ejecuta en modo gráfico.

  • Los tensores de gráfico no tienen valor.
  • En el modo gráfico, solo puedes usar TensorFlow Ops y funciones.

Por lo tanto, no puede .map esta función directamente: debe envolverla en un tf.py_function . La función tf.py_function pasará tensores regulares (con un valor y un método .numpy() para acceder a él), a la función de Python envuelta.

def encode_map_fn(text, label):
  # py_func doesn't set the shape of the returned tensors.
  encoded_text, label = tf.py_function(encode, 
                                       inp=[text, label], 
                                       Tout=(tf.int64, tf.int64))

  # `tf.data.Datasets` work best if all components have a shape set
  #  so set the shapes manually: 
  encoded_text.set_shape([None])
  label.set_shape([])

  return encoded_text, label


all_encoded_data = all_labeled_data.map(encode_map_fn)

Divida el conjunto de datos en lotes de prueba y entrenamiento

Usa tf.data.Dataset.take y tf.data.Dataset.skip para crear un pequeño conjunto de datos de prueba y un conjunto de entrenamiento más grande.

Antes de pasar al modelo, los conjuntos de datos deben agruparse. Normalmente, los ejemplos dentro de un lote deben tener el mismo tamaño y forma. Pero, los ejemplos en estos conjuntos de datos no son todos del mismo tamaño: cada línea de texto tiene un número diferente de palabras. Entonces use tf.data.Dataset.padded_batch (en lugar de batch ) para rellenar los ejemplos al mismo tamaño.

train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE)
train_data = train_data.padded_batch(BATCH_SIZE)

test_data = all_encoded_data.take(TAKE_SIZE)
test_data = test_data.padded_batch(BATCH_SIZE)

Ahora, test_data y train_data no son colecciones de pares ( example, label ), sino colecciones de lotes. Cada lote es un par de ( muchos ejemplos , muchas etiquetas ) representados como matrices.

Para ilustrar:

sample_text, sample_labels = next(iter(test_data))

sample_text[0], sample_labels[0]
(<tf.Tensor: shape=(16,), dtype=int64, numpy=
 array([16791,  1581,   325,  1885, 16189, 15504, 15638,     0,     0,
            0,     0,     0,     0,     0,     0,     0])>,
 <tf.Tensor: shape=(), dtype=int64, numpy=0>)

Desde que introdujimos una nueva codificación de token (el cero utilizado para el relleno), el tamaño del vocabulario ha aumentado en uno.

vocab_size += 1

Construye el modelo

model = tf.keras.Sequential()

La primera capa convierte representaciones enteras en incrustaciones de vectores densos. Vea el tutorial de incrustaciones de palabras o más detalles.

model.add(tf.keras.layers.Embedding(vocab_size, 64))

La siguiente capa es una capa de memoria a corto plazo , que permite al modelo comprender palabras en su contexto con otras palabras. Un contenedor bidireccional en el LSTM le ayuda a conocer los puntos de datos en relación con los puntos de datos anteriores y posteriores.

model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)))

Finalmente tendremos una serie de una o más capas densamente conectadas, siendo la última la capa de salida. La capa de salida produce una probabilidad para todas las etiquetas. El que tiene la mayor probabilidad es el modelo de predicción de la etiqueta de un ejemplo.

# One or more dense layers.
# Edit the list in the `for` line to experiment with layer sizes.
for units in [64, 64]:
  model.add(tf.keras.layers.Dense(units, activation='relu'))

# Output layer. The first argument is the number of labels.
model.add(tf.keras.layers.Dense(3))

Finalmente, compile el modelo. Para un modelo de categorización softmax, use sparse_categorical_crossentropy como función de pérdida. Puedes probar otros optimizadores, pero adam es muy común.

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

Entrena el modelo

Este modelo que se basa en estos datos produce resultados decentes (alrededor del 83%).

model.fit(train_data, epochs=3, validation_data=test_data)
Epoch 1/3
697/697 [==============================] - 9s 13ms/step - loss: 0.4998 - accuracy: 0.7583 - val_loss: 0.3916 - val_accuracy: 0.8204
Epoch 2/3
697/697 [==============================] - 9s 12ms/step - loss: 0.2875 - accuracy: 0.8772 - val_loss: 0.3948 - val_accuracy: 0.8234
Epoch 3/3
697/697 [==============================] - 8s 12ms/step - loss: 0.2151 - accuracy: 0.9089 - val_loss: 0.4081 - val_accuracy: 0.8228

<tensorflow.python.keras.callbacks.History at 0x7f54dc018dd8>
eval_loss, eval_acc = model.evaluate(test_data)

print('\nEval loss: {:.3f}, Eval accuracy: {:.3f}'.format(eval_loss, eval_acc))
79/79 [==============================] - 1s 17ms/step - loss: 0.4081 - accuracy: 0.8228

Eval loss: 0.408, Eval accuracy: 0.823