Compartilhar via


Tutorial: Criar, avaliar e pontuar um modelo de classificação de textos

Este tutorial apresenta um exemplo de ponta a ponta de um fluxo de trabalho do Synapse Data Science para um modelo de classificação de textos, no Microsoft Fabric. O cenário usa word2vec e regressão logística, no Spark, para determinar o gênero de um livro do conjunto de dados de livros da British Library, apenas com base no título do livro.

Este tutorial cobre estas etapas:

  • Instalar bibliotecas personalizadas
  • Carregar os dados
  • Entender e processar os dados com a análise exploratória de dados
  • Treinar um modelo de machine learning com word2vec e regressão logística e acompanhar experimentos com MLflow e o recurso de registro automático do Fabric
  • Carregar o modelo de machine learning para pontuação e previsões

Pré-requisitos

Acompanhar em um notebook

Você pode escolher uma dessas opções para acompanhar em um notebook:

  • Abra e execute o Notebook interno na experiência de Ciência de Dados Synapse
  • Carregue seu Notebook do GitHub para a experiência de ciência de dados Synapse

Abrir o Notebook interno

A amostra de Notebook de classificação de gênero de título acompanha este tutorial.

Para abrir o Notebook de amostra interno do tutorial na experiência de Synapse Data Science:

  1. Vá para a página inicial de Synapse Data Science.

  2. Selecione Usar um exemplo.

  3. Selecione o exemplo correspondente:

    • Na guia padrão fluxos de trabalho de ponta a ponta (Python), se o exemplo for para um tutorial do Python.
    • Na guia fluxos de trabalho de ponta a ponta (R), se o exemplo for para um tutorial do R.
    • Na guia Tutoriais rápidos, se o exemplo for para um tutorial rápido.
  4. Anexe um lakehouse ao notebook antes de começar a executar o código.

Importar o Notebook do GitHub

AIsample - Title Genre Classification.ipynb é o notebook que acompanha esse tutorial.

Para abrir o notebook que acompanha este tutorial, siga as instruções em Preparar seu sistema para tutoriais de ciência de dados para importar os notebooks para seu workspace.

Se preferir copiar e colar o código a partir dessa página, você poderá criar um novo notebook.

Certifique-se de anexar um lakehouse ao notebook antes de começar a executar o código.

Etapa 1: Instalar bibliotecas personalizadas

Para o desenvolvimento de modelo de machine learning ou análise de dados ad-hoc, talvez seja necessário instalar rapidamente uma biblioteca personalizada para sua sessão do Apache Spark. Você tem duas opções para instalar bibliotecas.

  • Usar os recursos de instalação embutido (%pip ou %conda) do notebook para instalar a biblioteca somente no notebook atual.
  • Como alternativa, você pode criar um ambiente de Fabric, instalar bibliotecas de fontes públicas ou carregar bibliotecas personalizadas para ele e, em seguida, o administrador do espaço de trabalho pode anexar o ambiente como padrão para o espaço de trabalho. Todas as bibliotecas no ambiente ficarão disponíveis para uso em quaisquer notebooks e definições de trabalho do Spark no espaço de trabalho. Para obter mais informações sobre ambientes, confira Criar, configurar e usar um ambiente no Microsoft Fabric.

Para o modelo de classificação, use a biblioteca wordcloud para representar a frequência da palavra no texto, onde o tamanho de uma palavra representa sua frequência. Para este tutorial, use %pip install para instalar wordcloud no seu notebook.

Observação

O kernel do PySpark é reiniciado após executar %pip install. Instale as bibliotecas necessárias antes de executar quaisquer outras células.

# Install wordcloud for text visualization by using pip
%pip install wordcloud

Etapa 2: Carregar os dados

O conjunto de dados contém metadados sobre livros da British Library que foram digitalizados em colaboração entre a biblioteca e a Microsoft. Os metadados são informações de classificação para indicar se um livro é ficção ou não-ficção. Com esse conjunto de dados, o objetivo é treinar um modelo de classificação que determine o gênero de um livro, apenas com base em seu título.

ID de registro da BL Tipo de recurso Nome Datas associadas ao nome Tipo de nome Função Todos os nomes Título Títulos de variantes Título da série Número dentro da série País de publicação Local de publicação Editor Data de publicação Edição Descrição física Classificação Dewey Símbolos de livro da BL Tópicos Gênero Idiomas Observações ID do registro da BL para recurso físico classification_id user_id created_at subject_ids annotator_date_pub annotator_normalised_date_pub annotator_edition_statement annotator_genre annotator_FAST_genre_terms annotator_FAST_subject_terms annotator_comments annotator_main_language annotator_other_languages_summaries annotator_summaries_language annotator_translation annotator_original_language annotator_publisher annotator_place_pub annotator_country annotator_title Link para um livro digitalizado anotado
014602826 Monografia Yearsley, Ann 1753-1806 pessoa More, Hannah, 1745-1833 [person]; Yearsley, Ann, 1753-1806 [person] Poemas em várias ocasiões [Com uma carta prefacial de Hannah More.] Inglaterra London 1786 4ª Edição Digital Store 11644.d.32 Inglês 003996603 Falso
014602830 Monografia A, T. pessoa Oldham, John, 1653-1683 [person]; A, T. [person] A Satyr against Vertue. (Um poema: suposto ser falado por um Town-Hector [Por John Oldham. Prefácio assinado: T. A.]) Inglaterra London 1679 15 páginas (4°) Digital Store 11602.ee.10. (2.) Inglês 000001143 Falso

Defina os seguintes parâmetros para que você possa aplicar este notebook em diferentes conjuntos de dados:

IS_CUSTOM_DATA = False  # If True, the user must manually upload the dataset
DATA_FOLDER = "Files/title-genre-classification"
DATA_FILE = "blbooksgenre.csv"

# Data schema
TEXT_COL = "Title"
LABEL_COL = "annotator_genre"
LABELS = ["Fiction", "Non-fiction"]

EXPERIMENT_NAME = "sample-aisample-textclassification"  # MLflow experiment name

Baixar o conjunto de dados e carregar no lakehouse

Esse código faz o download de uma versão disponível publicamente do conjunto de dados e, em seguida, o armazena em um lakehouse do Fabric.

Importante

Adicione um lakehouse ao notebook antes de você executá-lo. Se você não fizer isso, receberá um erro.

if not IS_CUSTOM_DATA:
    # Download demo data files into the lakehouse, if they don't exist
    import os, requests

    remote_url = "https://synapseaisolutionsa.blob.core.windows.net/public/Title_Genre_Classification"
    fname = "blbooksgenre.csv"
    download_path = f"/lakehouse/default/{DATA_FOLDER}/raw"

    if not os.path.exists("/lakehouse/default"):
        # Add a lakehouse, if no default lakehouse was added to the notebook
        # A new notebook won't link to any lakehouse by default
        raise FileNotFoundError(
            "Default lakehouse not found, please add a lakehouse and restart the session."
        )
    os.makedirs(download_path, exist_ok=True)
    if not os.path.exists(f"{download_path}/{fname}"):
        r = requests.get(f"{remote_url}/{fname}", timeout=30)
        with open(f"{download_path}/{fname}", "wb") as f:
            f.write(r.content)
    print("Downloaded demo data files into lakehouse.")

Importe as bibliotecas necessárias

Antes de qualquer processamento, você precisa importar as bibliotecas necessárias, incluindo as bibliotecas do Spark e SynapseML:

import numpy as np
from itertools import chain

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import seaborn as sns

import pyspark.sql.functions as F

from pyspark.ml import Pipeline
from pyspark.ml.feature import *
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import (
    BinaryClassificationEvaluator,
    MulticlassClassificationEvaluator,
)

from synapse.ml.stages import ClassBalancer
from synapse.ml.train import ComputeModelStatistics

import mlflow

Definir hiperparâmetros

Defina os hiperparâmetros para o treinamento do modelo.

Importante

Modifique esses hiperparâmetros somente se você compreender cada parâmetro.

# Hyperparameters 
word2vec_size = 128  # The length of the vector for each word
min_word_count = 3  # The minimum number of times that a word must appear to be considered
max_iter = 10  # The maximum number of training iterations
k_folds = 3  # The number of folds for cross-validation

Comece a gravar o tempo necessário para executar esse notebook:

# Record the notebook running time
import time

ts = time.time()

Configurar o acompanhamento de experimentos do MLflow

O registro automático amplia os recursos de registrar em log do MLflow. O registro automático captura automaticamente os valores dos parâmetros de entrada e as métricas de saída de um modelo de machine learning à medida que você o treina. Em seguida, registre essas informações no espaço de trabalho. No espaço de trabalho, você pode acessar e visualizar as informações com as APIs do MLflow, ou a experiência correspondente, no espaço de trabalho. Para saber mais sobre o log automático, confira Log Automático no Microsoft Fabric.

# Set up Mlflow for experiment tracking

mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True)  # Disable Mlflow autologging

Para desabilitar o log automático do Microsoft Fabric em uma sessão do notebook, chame mlflow.autolog() e configure como disable=True:

Ler dados de data brutos do lakehouse

raw_df = spark.read.csv(f"{DATA_FOLDER}/raw/{DATA_FILE}", header=True, inferSchema=True)

Etapa 3: Executar análise exploratória de dados

Explore o conjunto de dados com o comando display para ver estatísticas de alto nível do conjunto de dados e mostrar as exibições de gráfico:

display(raw_df.limit(20))

Preparar os dados

Remova as duplicatas para limpar os dados:

df = (
    raw_df.select([TEXT_COL, LABEL_COL])
    .where(F.col(LABEL_COL).isin(LABELS))
    .dropDuplicates([TEXT_COL])
    .cache()
)

display(df.limit(20))

Aplique o balanceamento de classes para resolver qualquer desvio:

# Create a ClassBalancer instance, and set the input column to LABEL_COL
cb = ClassBalancer().setInputCol(LABEL_COL)

# Fit the ClassBalancer instance to the input DataFrame, and transform the DataFrame
df = cb.fit(df).transform(df)

# Display the first 20 rows of the transformed DataFrame
display(df.limit(20))

Divida os parágrafos e frases em unidades menores, para tokenizar o conjunto de dados. Dessa forma, fica mais fácil atribuir significado. Em seguida, remova as palavras irrelevantes para aprimorar o desempenho. A remoção de palavras irrelevantes envolve a remoção de palavras que comumente ocorrem em todos os documentos do corpus. A remoção de palavras irrelevantes é uma das etapas de pré-processamento mais comumente usadas em aplicativos de processamento de linguagem natural (NLP).

# Text transformer
tokenizer = Tokenizer(inputCol=TEXT_COL, outputCol="tokens")
stopwords_remover = StopWordsRemover(inputCol="tokens", outputCol="filtered_tokens")

# Build the pipeline
pipeline = Pipeline(stages=[tokenizer, stopwords_remover])

token_df = pipeline.fit(df).transform(df)

display(token_df.limit(20))

Mostre uma biblioteca de nuvem de palavras para cada classe. Uma biblioteca de nuvem de palavras é uma apresentação visualmente proeminente de palavras-chave que aparecem com frequência nos dados de textos. A biblioteca de nuvem de palavras é eficaz porque a renderização de palavras-chave forma uma imagem colorida semelhante a uma nuvem para capturar melhor os principais dados de textos em um único olhar. Saiba mais sobre a nuvem de palavras.

# WordCloud
for label in LABELS:
    tokens = (
        token_df.where(F.col(LABEL_COL) == label)
        .select(F.explode("filtered_tokens").alias("token"))
        .where(F.col("token").rlike(r"^\w+$"))
    )

    top50_tokens = (
        tokens.groupBy("token").count().orderBy(F.desc("count")).limit(50).collect()
    )

    # Generate a wordcloud image
    wordcloud = WordCloud(
        scale=10,
        background_color="white",
        random_state=42,  # Make sure the output is always the same for the same input
    ).generate_from_frequencies(dict(top50_tokens))

    # Display the generated image by using matplotlib
    plt.figure(figsize=(10, 10))
    plt.title(label, fontsize=20)
    plt.axis("off")
    plt.imshow(wordcloud, interpolation="bilinear")

Para terminar, use o word2vec para vetorizar o texto. A técnica word2vec cria uma representação vetorial de cada palavra no texto. As palavras utilizadas em contextos semelhantes, ou que possuem relações semânticas, são captadas de forma eficaz por meio de sua proximidade no espaço vetorial. Essa proximidade indica que palavras semelhantes têm vetores de palavras semelhantes.

# Label transformer
label_indexer = StringIndexer(inputCol=LABEL_COL, outputCol="labelIdx")
vectorizer = Word2Vec(
    vectorSize=word2vec_size,
    minCount=min_word_count,
    inputCol="filtered_tokens",
    outputCol="features",
)

# Build the pipeline
pipeline = Pipeline(stages=[label_indexer, vectorizer])
vec_df = (
    pipeline.fit(token_df)
    .transform(token_df)
    .select([TEXT_COL, LABEL_COL, "features", "labelIdx", "weight"])
)

display(vec_df.limit(20))

Etapa 4: Treinar e avaliar o modelo

Com os dados disponíveis, defina o modelo. Nessa seção, você treina com um modelo de regressão logística para classificar o texto vetorizado.

Preparar conjuntos de dados de treinamento e teste

# Split the dataset into training and testing
(train_df, test_df) = vec_df.randomSplit((0.8, 0.2), seed=42)

Acompanhe experimentos de aprendizado de máquina

Um experimento de machine learning é a principal unidade de organização e controle para todas as execuções de aprendizado de máquina relacionadas. Uma execução corresponde a uma única execução do código do modelo.

O acompanhamento de experimentos de aprendizado de máquina gerencia todos os diferentes experimentos e seus componentes, por exemplo parâmetros, métricas, modelos e outros artefatos. O acompanhamento permite a organização de todos os componentes necessários de um experimento específico de aprendizado de máquina. Ele também permite a reprodução fácil de resultados passados com experimentos salvos. Saiba mais sobre experimentos de aprendizado de máquina no Microsoft Fabric.

# Build the logistic regression classifier
lr = (
    LogisticRegression()
    .setMaxIter(max_iter)
    .setFeaturesCol("features")
    .setLabelCol("labelIdx")
    .setWeightCol("weight")
)

Ajustar hiperparâmetros

Crie uma grade de parâmetros para pesquisar sobre os hiperparâmetros. Em seguida, construa um estimador entre avaliadores, para produzir um modelo CrossValidator:

# Build a grid search to select the best values for the training parameters
param_grid = (
    ParamGridBuilder()
    .addGrid(lr.regParam, [0.03, 0.1])
    .addGrid(lr.elasticNetParam, [0.0, 0.1])
    .build()
)

if len(LABELS) > 2:
    evaluator_cls = MulticlassClassificationEvaluator
    evaluator_metrics = ["f1", "accuracy"]
else:
    evaluator_cls = BinaryClassificationEvaluator
    evaluator_metrics = ["areaUnderROC", "areaUnderPR"]
evaluator = evaluator_cls(labelCol="labelIdx", weightCol="weight")

# Build a cross-evaluator estimator
crossval = CrossValidator(
    estimator=lr,
    estimatorParamMaps=param_grid,
    evaluator=evaluator,
    numFolds=k_folds,
    collectSubModels=True,
)

Avaliar o modelo

Podemos avaliar os modelos no conjunto de dados de teste, para compará-los. Um modelo bem treinado deve demonstrar alto desempenho, nas métricas relevantes, quando executado em relação aos conjuntos de dados de validação e teste.

def evaluate(model, df):
    log_metric = {}
    prediction = model.transform(df)
    for metric in evaluator_metrics:
        value = evaluator.evaluate(prediction, {evaluator.metricName: metric})
        log_metric[metric] = value
        print(f"{metric}: {value:.4f}")
    return prediction, log_metric

Acompanhe experimentos usando o MLflow

Iniciar o processo de treinamento e avaliação. Use o MLflow para acompanhar todos os experimentos e registrar parâmetros, métricas e modelos. Todas essas informações são registradas em log com o nome do experimento no workspace.

with mlflow.start_run(run_name="lr"):
    models = crossval.fit(train_df)
    best_metrics = {k: 0 for k in evaluator_metrics}
    best_index = 0
    for idx, model in enumerate(models.subModels[0]):
        with mlflow.start_run(nested=True, run_name=f"lr_{idx}") as run:
            print("\nEvaluating on test data:")
            print(f"subModel No. {idx + 1}")
            prediction, log_metric = evaluate(model, test_df)

            if log_metric[evaluator_metrics[0]] > best_metrics[evaluator_metrics[0]]:
                best_metrics = log_metric
                best_index = idx

            print("log model")
            mlflow.spark.log_model(
                model,
                f"{EXPERIMENT_NAME}-lrmodel",
                registered_model_name=f"{EXPERIMENT_NAME}-lrmodel",
                dfs_tmpdir="Files/spark",
            )

            print("log metrics")
            mlflow.log_metrics(log_metric)

            print("log parameters")
            mlflow.log_params(
                {
                    "word2vec_size": word2vec_size,
                    "min_word_count": min_word_count,
                    "max_iter": max_iter,
                    "k_folds": k_folds,
                    "DATA_FILE": DATA_FILE,
                }
            )

    # Log the best model and its relevant metrics and parameters to the parent run
    mlflow.spark.log_model(
        models.subModels[0][best_index],
        f"{EXPERIMENT_NAME}-lrmodel",
        registered_model_name=f"{EXPERIMENT_NAME}-lrmodel",
        dfs_tmpdir="Files/spark",
    )
    mlflow.log_metrics(best_metrics)
    mlflow.log_params(
        {
            "word2vec_size": word2vec_size,
            "min_word_count": min_word_count,
            "max_iter": max_iter,
            "k_folds": k_folds,
            "DATA_FILE": DATA_FILE,
        }
    )

Para ver seus experimentos:

  1. Selecione seu espaço de trabalho na navegação esquerda
  2. Encontre e selecione o nome do experimento. Neste caso,sample_aisample-textclassification

Screenshot of an experiment.

Etapa 5: Pontuar e salvar os resultados da previsão

O Microsoft Fabric permite que os usuários operacionalizem modelo de machine learning com a função escalonável PREDICT. Essa função dá suporte à pontuação em lote (ou inferência em lote) em qualquer mecanismo de computação. Você pode criar previsões em lote diretamente de um notebook ou da página de um item para um modelo específico. Para saber mais sobre o PREDICT e como usá-lo no Fabric, consulte Pontuação de modelo de machine learning com PREDICT no Microsoft Fabric.

A partir dos resultados da avaliação anterior, o modelo 1 tem as maiores métricas tanto para a área sob a curva de precisão/recall (AUPRC) quanto para a área sob a curva da característica de operação do receptor (AUC-ROC). Portanto, você deve usar o modelo 1 para a previsão.

A medida AUC-ROC é amplamente usada para medir o desempenho de classificadores binários. No entanto, às vezes torna-se mais apropriado avaliar o classificador com base nas medições da AUPRC. O gráfico AUC-ROC visualiza as compensações entre a taxa de positivos verdadeiros (TPR) e a taxa de falsos positivos (FPR). A curva da AUPRC combina precisão (valor preditivo positivo ou PPV) e Recall (taxa de positivos verdadeiros ou TPR) em uma única visualização.

# Load the best model
model_uri = f"models:/{EXPERIMENT_NAME}-lrmodel/1"
loaded_model = mlflow.spark.load_model(model_uri, dfs_tmpdir="Files/spark")

# Verify the loaded model
batch_predictions = loaded_model.transform(test_df)
batch_predictions.show(5)
# Code to save userRecs in the lakehouse
batch_predictions.write.format("delta").mode("overwrite").save(
    f"{DATA_FOLDER}/predictions/batch_predictions"
)
# Determine the entire runtime
print(f"Full run cost {int(time.time() - ts)} seconds.")