Partilhar via


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

Este tutorial apresenta um exemplo completo de um fluxo de trabalho Synapse Data Science para um modelo de classificação de texto, no Microsoft Fabric. O cenário utiliza tanto o processamento de linguagem natural (NLP) do Word2vec como a regressão logística, no Spark, para determinar o género de um livro a partir do conjunto de dados de livros da British Library. A decisão baseia-se unicamente no título do livro.

Este tutorial aborda estas etapas:

  • Instalar bibliotecas personalizadas
  • Carregue os dados
  • Compreender e processar os dados com análise exploratória de dados
  • Treine um modelo de aprendizagem automática com NLP Word2vec e regressão logística, e acompanhe experiências com MLflow e a funcionalidade de autologging Fabric
  • Carregue o modelo de aprendizado de máquina para pontuações e previsões

Pré-requisitos

  • Obtenha uma assinatura do Microsoft Fabric. Ou inscreva-se para obter uma avaliação gratuita do Microsoft Fabric.

  • Inicie sessão em Microsoft Fabric.

  • Altera para o Fabric usando o alternador de experiência no canto inferior esquerdo da sua página inicial.

    Captura de ecrã que mostra a seleção de Fabric no menu do comutador de experiências.

Tome notas num caderno

Para acompanhar num caderno, tens estas opções:

  • Abra e execute o bloco de notas incorporado.
  • Carregue seu bloco de anotações do GitHub.

Abra o bloco de notas incorporado

O notebook de classificação de género do exemplo Título acompanha este tutorial.

  1. Para abrir o bloco de anotações de exemplo para este tutorial, siga as instruções em Preparar seu sistema para tutoriais de ciência de dados.

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

Importar o notebook do GitHub

AIsample - Title Genre Classification.ipynb é o caderno que acompanha este tutorial.

Etapa 1: Instalar bibliotecas personalizadas

Para desenvolvimento de modelo de aprendizado de máquina ou análise de dados ad-hoc, talvez seja necessário instalar rapidamente uma biblioteca personalizada para sua sessão do Apache Spark. Tens duas opções para instalar uma biblioteca.

  • Para instalar uma biblioteca, apenas no seu notebook atual, utilize as funcionalidades de instalação embutida (%pip ou %conda) do seu notebook.
  • Como alternativa, pode criar um ambiente Fabric e instalar bibliotecas a partir de fontes públicas ou carregar bibliotecas personalizadas para ele. Depois, o administrador do seu espaço de trabalho pode associar o ambiente como padrão para o espaço de trabalho. Nesse momento, todas as bibliotecas do ambiente ficam disponíveis para uso em todos os notebooks e em todas as definições de funções do Spark nesse espaço de trabalho. Para mais informações sobre ambientes, visite o recurso criar, configurar e usar um ambiente no Microsoft Fabric .

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

Observação

O kernel do PySpark é reiniciado após %pip install execuções. Instala as bibliotecas de que precisas antes de usares outras células.

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

Passo 2: Carregue os dados

O conjunto de dados de livros da British Library contém metadados sobre livros da British Library. Uma colaboração entre a biblioteca e a Microsoft digitalizou os recursos originais que se tornaram o conjunto de dados. Os metadados são informações de classificação que indicam se um livro é ficção ou não-ficção. O diagrama seguinte mostra uma amostra de linhas do conjunto de dados.

ID de registo BL Tipo de recurso Nome Datas associadas ao nome Tipo de nome Funções Todos os nomes Título Títulos variantes Título da série Número dentro da série País de publicação Local de publicação Editora Data de publicação Edição Descrição física Classificação de Dewey Sinalização BL Tópicos Gênero Idiomas Observações ID de registro BL para recurso físico id_classificação identificador_de_utilizador criado_em identificadores_de_sujeito annotator_date_pub annotator_normalised_date_pub declaração_de_edição_do_anotador annotator_genre anotador_RÁPIDO_género_termos anotador_TERMO_SUBJECTIVO_FAST comentários_do_anotador annotador_idioma_principal resumos_do_annotador_em_outras_línguas annotator_summaries_language tradução de anotador anotador_idioma_original annotator_publisher annotator_place_pub país_do_annotador título_do_anotador Link para livro digitalizado anotado
014602826 Monografia Yearsley, Ana 1753-1806 pessoa More, Hannah, 1745-1833 [pessoa]; Yearsley, Ann, 1753-1806 [pessoa] Poemas em Diversas Ocasiões [Com uma carta de apresentação de Hannah More.] Inglaterra Lisboa 1786 Quarta edição NOTA MANUSCRITA Loja Digital 11644.d.32 Inglês 003996603 Falso
014602830 Monografia A, T. pessoa Oldham, John, 1653-1683 [pessoa]; A, T. [pessoa] Um sátiro contra Vertue. (Um poema: supostamente falado por um Town-Hector [Por John Oldham. O prefácio assinado: T. A.]) Inglaterra Lisboa 1679 15 páginas (4°) Loja Digital 11602.ee.10. (2.) Inglês 000001143 Falso

Com este conjunto de dados, o nosso objetivo é treinar um modelo de classificação que determine o género de um livro, com base apenas no título do livro.

Defina os seguintes parâmetros para aplicar este caderno 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

Faça o download do conjunto de dados e faça o upload para a casa do lago

O seguinte excerto de código descarrega uma versão pública do conjunto de dados e depois armazena-a numa casa de lago Fabric:

Importante

Adicione um lakehouse ao bloco de anotações antes de executá-lo. Não o fazer resulta num 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.z13.web.core.windows.net/data/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.")

Importar bibliotecas necessárias

Antes de qualquer processamento, deve importar as bibliotecas necessárias, incluindo as bibliotecas do Spark e do 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

O seguinte excerto de código define os hiperparâmetros necessários para o treino do modelo:

Importante

Modifique esses hiperparâmetros somente se você entender 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 registar o tempo necessário para correr este notebook:

# Record the notebook running time
import time

ts = time.time()

Configurar o rastreamento de experimentos MLflow

O registro automático estende os recursos de 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 aprendizado de máquina à 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 MLflow, ou o experimento correspondente, no espaço de trabalho. Para mais informações sobre autologging, visite o recurso Autologging no Microsoft Fabric.

Para desabilitar o registro automático do Microsoft Fabric em uma sessão de bloco de anotações, chame mlflow.autolog() e defina disable=True:

# Set up Mlflow for experiment tracking

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

Leia os dados brutos de data da casa do lago

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

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

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

display(raw_df.limit(20))

Preparar os dados

Para limpar os dados, remova os duplicados:

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 viés:

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

Para tokenizar o conjunto de dados, divida os parágrafos e frases em unidades menores. Desta forma, torna-se mais fácil atribuir significado. De seguida, remova as palavras finais para melhorar o desempenho. A remoção de palavras paradas envolve a remoção de palavras que normalmente ocorrem em todos os documentos do corpus. A remoção de palavras paradas é uma das etapas de pré-processamento mais usadas em aplicativos de processamento de linguagem natural (NLP). O seguinte excerto de código cobre estes passos:

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

Exiba a biblioteca wordcloud para cada classe. Uma biblioteca de nube de palavras apresenta palavras-chave que aparecem frequentemente em dados de texto e é uma apresentação visualmente proeminente. A biblioteca wordcloud é eficaz porque a renderização das palavras-chave forma uma imagem colorida semelhante a uma nuvem, para captar melhor os dados principais do texto num instante. Visite este recurso para mais informações sobre o wordcloud.

O seguinte excerto de código cobre estes passos:

# 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")

Por fim, use o Word2vec NLP para vetorizar o texto. A técnica Word2vec NLP cria uma representação vetorial de cada palavra no texto. Palavras usadas em contextos semelhantes, ou que têm relações semânticas, são capturadas efetivamente através de sua proximidade no espaço vetorial. Esta proximidade indica que palavras semelhantes têm vetores de palavras semelhantes. O seguinte excerto de código cobre estes passos:

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

Passo 4: Treinar e avaliar o modelo

Com os dados em vigor, defina o modelo. Nesta seção, você treina um modelo de regressão logística para classificar o texto vetorizado.

Preparar conjuntos de dados de treinamento e teste

O seguinte excerto de código divide o conjunto de dados:

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

Rastreie experimentos de aprendizado de máquina

O rastreamento de experiências por aprendizagem automática gere todas as experiências e os seus componentes – por exemplo, parâmetros, métricas, modelos e outros artefactos. O rastreamento permite a organização e gestão de todos os componentes que um experimento específico de aprendizagem automática exige. Ele também permite a reprodução fácil de resultados passados com experimentos salvos. Visite Experiências de aprendizagem automática no Microsoft Fabric para mais informações.

Um experimento de aprendizado de máquina é 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 seguinte excerto de código cobre estes passos:

# 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, cria um estimador de avaliação cruzada para gerar um modelo CrossValidator, conforme apresentado no excerto de código a seguir.

# 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 elevado desempenho, nas métricas relevantes, quando executado em comparação com os conjuntos de dados de validação e teste. O seguinte excerto de código cobre estes passos:

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

Rastreie experimentos usando MLflow

Iniciar o processo de formação e avaliação. Use o MLflow para acompanhar todos os experimentos e registar os parâmetros, métricas e modelos. No espaço de trabalho, toda esta informação é registada sob o nome do experimento. O seguinte excerto de código cobre estes passos:

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 as suas experiências:

  1. Selecione seu espaço de trabalho no painel de navegação esquerdo
  2. Encontre e selecione o nome do experimento - neste caso, sample_aisample-textclassification

Captura de tela de um experimento.

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

O Microsoft Fabric permite aos utilizadores operacionalizar modelos de aprendizagem automática com a função escalável PREDICT . Esta função suporta pontuação em lote (ou inferência em lote) em qualquer mecanismo de computação. Pode criar previsões em lote diretamente de um caderno ou da página do item para um modelo específico. Para mais informações sobre a função PREDICT e sobre como utilizá-la no Fabric, visite Avaliação de modelos de aprendizagem automática com PREDICT no Microsoft Fabric.

A partir dos nossos resultados de avaliação, o modelo 1 tem as maiores métricas tanto para a Área Sob a Curva Precision-Recall (AUPRC) como para a Área Sob a Curva Característica de Operação do Recetor (AUC-ROC). Portanto, você deve usar o modelo 1 para previsão.

A medida AUC-ROC é amplamente utilizada para medir o desempenho de classificadores binários. No entanto, por vezes torna-se mais apropriado avaliar o classificador com base nas medições AUPRC. O gráfico de AUC-ROC visualiza o trade-off entre taxa de verdadeiro positivo (TPR) e taxa de falso positivo (FPR). A curva AUPRC combina precisão (valor preditivo positivo ou PPV) e recordação (taxa verdadeira positiva ou TPR) numa única visualização. Os seguintes excertos de código cobrem estes passos:

# 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.")