Condividi tramite


Esercitazione: creare, valutare e assegnare un punteggio a un modello di classificazione testo

Questa esercitazione presenta un esempio end-to-end di un flusso di lavoro di data science Synapse per un modello di classificazione testo in Microsoft Fabric. Lo scenario usa word2vec e la regressione logistica, in Spark, per determinare il genere di un libro dal set di dati dei libri della British Library, esclusivamente in base al titolo del libro.

L'esercitazione illustra questi passaggi:

  • Installare librerie personalizzate
  • Caricare i dati
  • Comprendere ed elaborare i dati con l'analisi esplorativa dei dati
  • Eseguire il training di un modello di Machine Learning con word2vec e regressione logistica e tenere traccia degli esperimenti con MLflow e la funzionalità di assegnazione automatica di Fabric
  • Caricare il modello di Machine Learning per l'assegnazione di punteggi e previsioni

Prerequisiti

Seguire la procedura in un notebook

È possibile scegliere una di queste opzioni per seguire la procedura in un notebook:

  • Aprire ed eseguire il notebook predefinito.
  • Carica il tuo notebook da GitHub.

Aprire il notebook predefinito

Il notebook di esempio per la classificazione dei generi del titolo accompagna questa esercitazione.

  1. Per aprire il notebook di esempio per questa esercitazione, seguire le istruzioni riportate in Preparare il sistema per le esercitazioni sull'analisi scientifica dei dati.

  2. Assicurarsi di collegare una lakehouse al notebook prima di iniziare a eseguire il codice.

Importare il notebook da GitHub

AIsample - Title Genre Classification.ipynb è il notebook che accompagna questa esercitazione.

Passaggio 1: installare librerie personalizzate

Per lo sviluppo di modelli di Machine Learning o l'analisi dei dati ad hoc, potrebbe essere necessario installare rapidamente una libreria personalizzata per la sessione di Apache Spark. Sono disponibili due opzioni per installare le librerie.

  • Usare le funzionalità di installazione inline (%pip o %conda) del notebook per installare una libreria solo nel notebook corrente.
  • In alternativa, è possibile creare un ambiente Fabric, installare librerie da origini pubbliche o caricarvi librerie personalizzate e quindi l'amministratore dell'area di lavoro può collegare l'ambiente come predefinito per l'area di lavoro. Tutte le librerie nell'ambiente diventano quindi disponibili per l'uso in qualsiasi notebook e definizioni di processo Spark nell'area di lavoro. Per altre informazioni sugli ambienti, vedere creare, configurare e usare un ambiente in Microsoft Fabric.

Per il modello di classificazione, usare la libreria wordcloud per rappresentare la frequenza delle parole nel testo, in cui la dimensione di una parola rappresenta la sua frequenza. Per questa esercitazione, usare %pip install per installare wordcloud nel notebook.

Nota

Il kernel PySpark viene riavviato dopo l'esecuzione di %pip install. Installare le librerie necessarie prima di eseguire qualsiasi altra cella.

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

Passaggio 2: caricare i dati

Il set di dati contiene i metadati relativi ai libri della British Library, digitalizzati in seguito a una collaborazione tra la libreria e Microsoft. I metadati sono informazioni di classificazione per indicare se un libro è di narrativa o di saggistica. Con questo set di dati, l'obiettivo è eseguire il training di un modello di classificazione che determina il genere di un libro, solo in base al titolo.

BL record ID Tipo di risorsa Nome Date associate al nome Tipo di nome Ruolo Tutti i nomi Title Titoli variante Titolo serie Numero all'interno della serie Paese di pubblicazione Luogo di pubblicazione Publisher Data di pubblicazione Edition Descrizione fisica Classificazione dewey Segnaposto BL Argomenti Genre Lingue Note ID del record BL per la risorsa fisica 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 Collegamento a un libro digitalizzato Annotato
014602826 Monografia Ann Yearsley 1753-1806 person More, Hannah, 1745-1833 [person]; Yearsley, Ann, 1753-1806 [person] Poems on several occasions [With a prefatory letter by Hannah More.] England Londra 1786 Fourth edition MANUSCRIPT note Digital Store 11644.d.32 italiano 003996603 Falso
014602830 Monografia A, T. person Oldham, John, 1653-1683 [person]; A, T. [person] A Satyr against Vertue. (A poem: supposed to be spoken by a Town-Hector [By John Oldham. The preface signed: T. A.]) England Londra 1679 15 pages (4°) Digital Store 11602.ee.10. (2) italiano 000001143 Falso

Definire i parametri seguenti in modo da poter applicare questo notebook in set di dati diversi:

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

Scaricare il set di dati e caricarlo nel lakehouse

Questo codice scarica una versione disponibile pubblicamente del set di dati e la archivia in un lakehouse di Fabric.

Importante

Aggiungere una lakehouse al notebook prima di eseguirlo. In caso contrario, verrà generato un errore.

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

Importare le librerie obbligatorie

Prima di qualsiasi elaborazione, è necessario importare le librerie necessarie, incluse le librerie per 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

Definire gli iperparametri

Definire gli iperparametri per il training dei modelli.

Importante

Modificare questi iperparametri solo se si comprende ogni parametro.

# 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

Avviare la registrazione del tempo necessario per eseguire questo notebook:

# Record the notebook running time
import time

ts = time.time()

Configurare il rilevamento dell'esperimento di MLflow

La registrazione automatica estende le funzionalità di registrazione di MLflow. La registrazione automatica acquisisce automaticamente i valori dei parametri di input e le metriche di output di un modello di Machine Learning durante il training. Si registrano quindi queste informazioni nell'area di lavoro. Nell'area di lavoro è possibile accedere e visualizzare le informazioni con le API MLflow o l'esperimento corrispondente nell'area di lavoro. Per altre informazioni sulla registrazione automatica, vedere Registrazione automatica in Microsoft Fabric.

# Set up Mlflow for experiment tracking

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

Per disabilitare la registrazione automatica di tag di Microsoft Fabric in una sessione del notebook, chiamare mlflow.autolog() e impostare disable=True:

Leggere i dati non elaborati di data dal lakehouse

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

Passaggio 3: eseguire l'analisi esplorativa dei dati

Esplorare il set di dati con il comando display per visualizzare le statistiche di alto livello per il set di dati e visualizzare le visualizzazioni del grafico:

display(raw_df.limit(20))

Preparare i dati

Rimuovere i duplicati per pulire i dati:

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

display(df.limit(20))

Applicare il bilanciamento della classe per risolvere eventuali distorsioni:

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

Suddividere i paragrafi e le frasi in unità più piccole per tokenizzare il set di dati. In questo modo, diventa più facile assegnare significato. Rimuovere quindi le parole non significative per migliorare le prestazioni. La rimozione delle parole non significative comporta la rimozione di parole che compaiono comunemente in tutti i documenti del corpus. La rimozione delle parole non significative è uno dei passaggi di pre-elaborazione usati più comunemente nelle applicazioni di elaborazione del linguaggio naturale (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))

Visualizzare la libreria wordcloud per ogni classe. Una libreria wordcloud è una presentazione visivamente prominente delle parole chiave che vengono visualizzate di frequente nei dati di testo. La libreria wordcloud è efficace perché il rendering delle parole chiave costituisce un'immagine a colori cloudlike, per acquisire meglio i dati di testo principali a colpo d'occhio. Altre informazioni sul wordcloud.

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

Usare infine word2vec per vettorizzare il testo. La tecnica word2vec crea una rappresentazione vettoriale di ogni parola nel testo. Le parole usate in contesti simili, o che hanno relazioni semantiche, vengono acquisite in modo efficace attraverso la loro vicinanza nello spazio vettoriale. Questa vicinanza indica che parole simili hanno vettori di parole simili.

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

Passaggio 4: eseguire il training e valutare il modello

Con i dati disponibili, definire il modello. In questa sezione viene eseguito il training di un modello di regressione logistica per classificare il testo vettorializzato.

Preparare i set di dati di training e di test

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

Rilevamento degli esperimenti di Machine Learning

Un esperimento di Machine Learning è l'unità primaria di organizzazione e controllo per tutte le esecuzioni di Machine Learning correlate. Un'esecuzione corrisponde a una singola esecuzione del codice dei modelli.

Il rilevamento degli esperimenti di Machine Learning gestisce tutti gli esperimenti e i relativi componenti, ad esempio parametri, metriche, modelli e altri artefatti. Il rilevamento consente l'organizzazione di tutti i componenti necessari di un esperimento di Machine Learning specifico. Consente inoltre di riprodurre facilmente i risultati precedenti con esperimenti salvati. Altre informazioni sugli esperimenti di Machine Learning in Microsoft Fabric.

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

Ottimizzare gli iperparametri

Creare una griglia di parametri per eseguire la ricerca sugli iperparametri. Compilare quindi uno strumento di stima incrociato per produrre un modello 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,
)

Valutare il modello

È possibile valutare i modelli nel set di dati di test per confrontarli. Un modello con training corretto deve dimostrare prestazioni elevate, sulle metriche pertinenti, quando vengono eseguite sui set di dati di convalida e test.

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

Rilevamento degli esperimenti tramite MLflow

Avviare il processo di training e valutazione. Usare MLflow per rilevare tutti gli esperimenti e registrare parametri, metriche e modelli. Tutte queste informazioni vengono registrate sotto il nome dell'esperimento nell'area di lavoro.

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,
        }
    )

Per visualizzare gli esperimenti:

  1. Selezionare un'area di lavoro nel riquadro di spostamento a sinistra
  2. Trovare e selezionare il nome dell'esperimento, in questo caso sample_aisample-textclassification

Screenshot di un esperimento.

Passaggio 5: assegnare un punteggio e salvare i risultati della previsione

Microsoft Fabric consente agli utenti di rendere operativi i modelli di Machine Learning con la funzione scalabile PREDICT. Questa funzione supporta l'assegnazione dei punteggi batch (o l'inferenza batch) in qualsiasi motore di calcolo. È possibile creare previsioni batch direttamente da un notebook o dalla pagina degli elementi per un determinato modello. Per altre informazioni su PREDICT e su come usarlo in Fabric, vedere Assegnazione dei punteggi dei modelli di Machine Learning con PREDICT in Microsoft Fabric.

Dai risultati di valutazione precedenti, il modello 1 ha i valori più alti sia per l'Area sotto la curva Precision-Recall (AUPRC) che per l'Area sotto la curva Receiver Operating Characteristic (AUC-ROC). Pertanto, è consigliabile usare il modello 1 per la previsione.

La misura AUC-ROC viene ampiamente usata per misurare le prestazioni dei classificatori binari. Tuttavia, a volte diventa più appropriato valutare il classificatore in base alle misurazioni AUPRC. Il grafico AUC-ROC visualizza il compromesso tra il tasso positivo reale (TPR) e il tasso falso positivo (FPR). La curva AUPRC combina la precisione (valore predittivo positivo o PPV) e il richiamo (tasso positivo reale o TPR) in una singola visualizzazione.

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