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

Classificador de artigos em bengali com o TF Hub

Atenção: além de instalar pacotes Python com o pip, este notebook usa sudo apt install para instalar pacotes do sistema: unzip.

Este Colab é uma demonstração de uso do TensorFlow Hub para classificação de texto em idiomas locais/diferentes do inglês. Aqui, escolhemos bengali como o idioma local e usamos embeddings de palavras pré-treinados para resolver uma tarefa de classificação multiclasse, em que classificamos notícias em bengali em 5 categorias. Os embeddings pré-treinados para bengali vêm de fastText, uma biblioteca do Facebook com vetores de palavras pré-treinados lançados para 157 idiomas.

Primeiro, usaremos o exportador de embeddings pré-treinados do TF Hub para converter os embeddings de palavras em um módulo de embeddings de texto e depois usaremos o módulo para treinar um classificador usando tf.keras, uma API amigável de alto nível do TensorFlow para criar modelos de aprendizado profundo. Mesmo que estejamos usando embeddings de fastText, é possível exportar qualquer outro embedding pré-treinado a partir de outras tarefas e obter resultados rapidamente com o TensorFlow Hub.

Configuração

%%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

Dataset

Usaremos o BARD (dataset de notícias em bengali), que tem cerca de 376.226 notícias extraídas de diferentes portais de notícias em bengali e rotuladas em 5 categorias: economia, nacional, internacional, esportes e entretenimento. Baixamos o arquivo do Google Drive (bit.ly/BARD_DATASET). Esse link faz referência a este repositório do GitHub.

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

Exporte os vetores de palavras pré-treinados para o módulo do TF Hub

O TF Hub conta com alguns scripts úteis para converter embeddings de palavras em módulos de embeddings de texto do TF Hub aqui. Para criar o módulo para bengali ou qualquer outro idioma, basta baixar o arquivo de embeddings de palavras em .txt ou .vec para o mesmo diretório de export_v2.py e executar o script.

O exportador lê os vetores de embeddings e os exporta para um SavedModel do TensorFlow. O SavedModel contém um programa completo do TensorFlow, incluindo os pesos e o grafo. O TF Hub pode carregar o SavedModel como um módulo, que será usado para criar o modelo para classificação de texto. Como estamos usando tf.keras para criar o modelo, usaremos hub.KerasLayer, que conta com um encapsulador de um módulo do TF Hub para usar como uma Layer (camada) do Keras.

Primeiro, vamos baixar os embeddings de palavras em fastText e o exportador de embeddings no repositório do 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

Em seguida, vamos executar o script exportador em nosso arquivo de embeddings. Como os embeddings de fastText têm uma linha de cabeçalho e são muito grandes (cerca de 3,3 GB para bengali após converter para um módulo), ignoramos a primeira linha e exportamos somente os primeiros 100 mil tokens para o módulo de embeddings de texto.

%%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)

O módulo de embeddings de texto recebe um lote de frases em um tensor de strings unidimensional como entrada e gera como saída os vetores de embeddings com formato (batch_size, embedding_dim), correspondentes às frases. Ele pré-processa a entrada por meio da divisão em espaços. Os embeddings de palavras são combinados em embeddings de frases usando o combinador sqrtn (confira aqui). Para fins de demonstração, passamos uma lista de palavras em bengali como entrada e obtemos os vetores de embeddings correspondentes.

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

Converta para TensorFlow Dataset

Como o dataset é muito grande, em vez de carregar todo ele na memória, vamos usar um gerador para gerar amostras em tempo de execução nos lotes usando as funções do TensorFlow Dataset. O dataset também é bastante desequilibrado e, portanto, antes de usar o gerador, vamos embaralhar o dataset.

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]

Vamos verificar a distribuição de rótulos nos exemplos de treinamento e validação após embaralhar o dataset.

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 criar um dataset usando um gerador, primeiro escrevemos uma função geradora que lê cada uma das notícias em file_paths e os rótulos no array de rótulos e que gera um exemplo de treinamento em cada passo. Passamos essa função geradora para o método tf.data.Dataset.from_generator e especificamos os tipos de saída. Cada exemplo de treinamento é uma tupla contendo uma notícia com tipo de dados tf.string e um rótulo com codificação one-hot. Dividimos o dataset com uma divisão treinamento/validação de 80/20 utilizando os métodos tf.data.Dataset.skip e 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)

Treinamento e avaliação do modelo

Como já adicionamos um encapsulador ao nosso módulo para usá-lo como qualquer outra camada no Keras, podemos criar um modelo sequencial pequeno que seja uma pilha linear de camadas. Podemos adicionar o módulo de embeddings de texto usando model.add como qualquer outra camada. Para compilar o modelo, especificamos a perda e o otimizador e fazemos 10 épocas de treinamento. A API tf.keras consegue tratar TensorFlow Datasets como entrada, então podemos passar uma instância de Dataset para o método de ajuste a fim de treinar o modelo. Como estamos usando a função geradora, tf.data tratará da geração das amostras, da divisão dessas amostras em lotes e da alimentação delas no 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)

Treinamento

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

Avaliação

Podemos visualizar as curvas de exatidão e perda para os dados de treinamento e validação usando o objeto tf.keras.callbacks.History retornado pelo método tf.keras.Model.fit, que contém o valor de perda e exatidão 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()

Previsão

Podemos obter as previsões para os dados de validação e conferir a matriz de confusão para ver o desempenho do modelo para cada uma das 5 classes. Como o método tf.keras.Model.predict retorna um array de dimensão n para as probabilidades de cada classe, é possível converter em rótulos de classe usando 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()

Compare o desempenho

Agora podemos obter os rótulos corretos para os dados de validação em labels e compará-los com as previsões para obter um classification_report (relatório de classificação).

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

Também podemos comparar o desempenho do modelo com os resultados obtidos no artigo original, que teve uma precisão de 0,96. Os autores descreveram diversas etapas de pré-processamento realizadas no dataset, como a retirada de pontuações e numerais e a remoção das 25 palavras vazias mais frequentes. Como podemos ver no classification_report, também obtivemos uma precisão e exatidão de 0,96 após somente 5 épocas de treinamento sem qualquer pré-processamento!

Neste exemplo, quando criamos a camada do Keras do modelo de embeddings, definimos o parâmetro trainable=False, ou seja, os pesos dos embeddings não são atualizados durante o treinamento. Tente defini-lo como True para alcançar uma exatidão de cerca de 97% usando esse dataset após somente 2 épocas.