Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/hub/tutorials/bangla_article_classifier.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. # ==============================================================================

Clasificación de artículos en bengalí con TF-Hub

Precaución: Además de instalar paquetes de Python con pip, en este bloc de notas se usa sudo apt install para instalar paquetes del sistema: unzip.

En esta colaboración se demuestra el uso de TensorFlow Hub para la clasificación de idiomas diferentes del inglés. En este caso, elegimos bengalí como idioma local y utilizamos incorporaciones de palabras previamente entrenadas para resolver tareas de clasificación multiclase, donde clasificamos artículos de noticias en bengalí de fastText, una biblioteca de Facebook con vectores de palabras preentrenados para 157 idiomas.

Usaremos el exportador de incorporaciones preentrenadas de TF-Hub para convertir las incorporaciones de palabras en un módulo de incorporación de textos y luego usarlo para entrenar un clasificador con tf.keras, la API de alto nivel, fácil de usar, de Tensorflow para crear modelos de aprendizaje profundo. Incluso aunque usemos incorporaciones fastText en este caso, es posible exportar cualquier otra incorporación previamente entrenada de otras tareas y obtener rápidamente resultados con Tensorflow Hub.

Preparación

%%bash # https://github.com/pypa/setuptools/issues/1694#issuecomment-466010982 pip install gdown --no-use-pep517
%%bash sudo apt-get install -y unzip
import os import tensorflow as tf import tensorflow_hub as hub import gdown import numpy as np from sklearn.metrics import classification_report import matplotlib.pyplot as plt import seaborn as sns

Conjunto de datos

Utilizaremos BARD (Bangla Article Dataset, el conjunto de datos de artículos en bengalí) que tiene alrededor de 376 226 artículos recolectados a partir de diferentes portales de noticias en bengalí y están etiquetados según 5 categorías: economía, política, internacionales, deportes y entretenimiento. Descargamos el archivo de Google Drive. Este enlace (bit.ly/BARD_DATASET) conecta con este repositorio de GitHub.

gdown.download( url='https://drive.google.com/uc?id=1Ag0jd21oRwJhVFIBohmX_ogeojVtapLy', output='bard.zip', quiet=True )
%%bash unzip -qo bard.zip

Exportación de vectores de palabras previamente entrenados para módulo de TF-Hub

TF-Hub ofrece scripts útiles para convertir incorporaciones de palabras en módulos de incorporación de textos para TF-hub aquí. Para hacer el módulo de bengalí o cualquier otro idioma, simplemente debemos descargar un archivo .txt o .vec de incorporación de textos en el mismo directorio que export_v2.py y ejecutar el script.

El exportador lee los vectores de incorporación y los exporta a un SavedModel de Tensorflow. El SavedModel contiene un programa completo de TensorFlow que incluye los pesos y el grafo. TF-Hub puede cargar el SavedModel como un módulo que usaremos para construir el modelo para clasificación de textos. Como estamos usando tf.keras para crear el modelo, utilizaremos hub.KerasLayer, que ofrece un encapsulador (wrapper) para que el módulo de TF-Hub lo use como una capa Keras.

Primero, obtendremos las incorporaciones de palabras de fastText y el exportador de incorporaciones del repositorio de TF-Hub.

%%bash curl -O https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.bn.300.vec.gz curl -O https://raw.githubusercontent.com/tensorflow/hub/master/examples/text_embeddings_v2/export_v2.py gunzip -qf cc.bn.300.vec.gz --k

Después, ejecutaremos el script exportador en nuestro archivo de incorporaciones. Como las incorporaciones de fastText tienen una línea de encabezado y son bastante grandes (alrededor de 3.3 GB para bengalí después de la conversión a un módulo) ignoramos la primera línea y exportamos solamente los primeros 100 000 tokens al módulo de incorporación de textos.

%%bash python export_v2.py --embedding_file=cc.bn.300.vec --export_path=text_module --num_lines_to_ignore=1 --num_lines_to_use=100000
module_path = "text_module" embedding_layer = hub.KerasLayer(module_path, trainable=False)

El módulo de incorporación de textos toma un lote de oraciones en un tensor de 1 D de strings como entrada y emite como salida vectores de incorporación, con la forma (batch_size, embedding_dim), correspondientes a las oraciones. Se preprocesa la entrada dividiendo por los espacios. Las incorporaciones de textos se combinan en incorporaciones de oraciones con el combinador sqrtn (ver aquí). Para demostrarlo pasamos una lista de palabras en bengalí como entrada y obtuvimos los vectores de incorporación correspondientes.

embedding_layer(['বাস', 'বসবাস', 'ট্রেন', 'যাত্রী', 'ট্রাক'])

Conversión a conjunto de datos de Tensorflow

Dado que el conjunto de datos es realmente grande, en vez de cargarlo completo en la memoria, usaremos un generador que produzca muestras en tiempo de ejecución, en lotes. Lo haremos utilizando las funciones del conjunto de datos de Tensorflow. El conjunto de datos también está muy desbalanceado, entonces, antes de usar el generador, lo aleatorizaremos.

dir_names = ['economy', 'sports', 'entertainment', 'state', 'international'] file_paths = [] labels = [] for i, dir in enumerate(dir_names): file_names = ["/".join([dir, name]) for name in os.listdir(dir)] file_paths += file_names labels += [i] * len(os.listdir(dir)) np.random.seed(42) permutation = np.random.permutation(len(file_paths)) file_paths = np.array(file_paths)[permutation] labels = np.array(labels)[permutation]

Podemos verificar la distribución de etiquetas en los ejemplos de entrenamiento y validación, después de la aleatorización.

train_frac = 0.8 train_size = int(len(file_paths) * train_frac)
# plot training vs validation distribution plt.subplot(1, 2, 1) plt.hist(labels[0:train_size]) plt.title("Train labels") plt.subplot(1, 2, 2) plt.hist(labels[train_size:]) plt.title("Validation labels") plt.tight_layout()

Para crear un conjunto de datos con un generador, primero escribimos la función del generador que lee cada uno de los artículos de file_paths y las etiquetas del arreglo de etiquetas y produce un ejemplo de entrenamiento a cada paso. Pasamos esta función generadora al método tf.data.Dataset.from_generator y especificamos los tipos de salida. Cada ejemplo de entrenamiento es una tupla que contiene un artículo de tipo de datos tf.string y una etiqueta codificada en un solo paso (one-hot). Dividimos el conjunto de datos con una separación para validación de entrenamiento de 80-20 con los métodos tf.data.Dataset.skip y tf.data.Dataset.take.

def load_file(path, label): return tf.io.read_file(path), label
def make_datasets(train_size): batch_size = 256 train_files = file_paths[:train_size] train_labels = labels[:train_size] train_ds = tf.data.Dataset.from_tensor_slices((train_files, train_labels)) train_ds = train_ds.map(load_file).shuffle(5000) train_ds = train_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE) test_files = file_paths[train_size:] test_labels = labels[train_size:] test_ds = tf.data.Dataset.from_tensor_slices((test_files, test_labels)) test_ds = test_ds.map(load_file) test_ds = test_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE) return train_ds, test_ds
train_data, validation_data = make_datasets(train_size)

Entrenamiento y evaluación del modelo

Como ya hemos agregado un encapsulador en torno a nuestro módulo para usarlo como cualquier otra capa de Keras, ahora podemos crear un modelo secuencial pequeño que sea una acumulación (pila) lineal de capas. Podemos agregar nuestro módulo de incorporación de textos con model.add, del mismo modo que con cualquier otra capa. Compilamos el modelo mediante la especificación de la pérdida y el optimizador, y lo entrenamos por 10 épocas. La API tf.keras puede tratar a los conjuntos de datos de TensorFlow como entradas, lo que nos permite pasar una instancia de un conjunto de datos al método adecuado para el entrenamiento del modelo. Dado que usamos la función del generador, tf.data trabajará con las muestras generadoras, agrupará en lotes y las enviará al modelo.

Modelo

def create_model(): model = tf.keras.Sequential([ tf.keras.layers.Input(shape=[], dtype=tf.string), embedding_layer, tf.keras.layers.Dense(64, activation="relu"), tf.keras.layers.Dense(16, activation="relu"), tf.keras.layers.Dense(5), ]) model.compile(loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True), optimizer="adam", metrics=['accuracy']) return model
model = create_model() # Create earlystopping callback early_stopping_callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=3)

Entrenamiento

history = model.fit(train_data, validation_data=validation_data, epochs=5, callbacks=[early_stopping_callback])

Evaluación

Podemos visualizar las curvas de exactitud y pérdida para los datos de entrenamiento y validación con el objeto tf.keras.callbacks.History devuelto por el método tf.keras.Model.fit, que contiene los valores de pérdida y exactitud para cada época.

# Plot training & validation accuracy values plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.title('Model accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(['Train', 'Test'], loc='upper left') plt.show() # Plot training & validation loss values plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['Train', 'Test'], loc='upper left') plt.show()

Predicción

Podemos obtener las predicciones para los datos de validación y controlar la matriz de confusión para ver el desempeño del modelo en cada una de las 5 clases. Porque el método tf.keras.Model.predict devuelve un arreglo n-d para las probabilidades de cada clase, que se pueden convertir en etiquetas de clase con np.argmax.

y_pred = model.predict(validation_data)
y_pred = np.argmax(y_pred, axis=1)
samples = file_paths[0:3] for i, sample in enumerate(samples): f = open(sample) text = f.read() print(text[0:100]) print("True Class: ", sample.split("/")[0]) print("Predicted Class: ", dir_names[y_pred[i]]) f.close()

Comparación del desempeño

Ahora podemos tomar de labels las etiquetas correctas para los datos de validación y podemos compararlas con nuestras predicciones para obtener un classification_report.

y_true = np.array(labels[train_size:])
print(classification_report(y_true, y_pred, target_names=dir_names))

También podemos comparar el desempeño de nuestro modelo con los resultados publicados obtenidos en la publicación original, que tenían una precisión de 0.96. Los autores originales describen muchos pasos de preprocesamiento efectuados al conjunto de datos; tales como dejar caer puntuaciones y dígitos, quitando las primeras 25 palabras vacías frecuentes. Como podemos ver en el classification_report, ¡también logramos obtener una precisión y exactitud del 0.96 después de entrenar solamente durante 5 épocas sin ningún procesamiento previo!

En este ejemplo, cuando creamos la capa Keras a partir de nuestro módulo de incorporaciones, preparamos el parámetro trainable=False; significa que los pesos de las incorporaciones no se actualizarán durante el entrenamiento. Pruebe definiéndolo como True para alcanzar una exactitud de aproximadamente el 97% con este conjunto de datos después de solamente 2 épocas.