Tutorial: Erstellen, Auswerten und Bewerten eines Textklassifizierungsmodells

In diesem Tutorial wird ein End-to-End-Beispiel für einen Synapse Data Science-Workflow für ein Textklassifizierungsmodell in Microsoft Fabric vorgestellt. Das Szenario verwendet word2vec und logistische Regression auf Spark, um das Genre eines Buches aus dem Buchdatensatz der British Library allein auf der Grundlage des Buchtitels zu bestimmen.

Dieses Tutorial enthält diese Schritte:

  • Installieren von benutzerdefinierten Bibliotheken
  • Laden der Daten
  • Verstehen und Verarbeiten der Daten durch explorative Datenanalyse
  • Trainieren Sie ein Machine-Learning-Modell mit word2vec und logistischer Regression und verfolgen Sie die Experimente mit MLflow und der Fabric-Autologging-Feature
  • Laden des Machine Learning-Modells zum Bewerten von Vorhersagen

Voraussetzungen

Ein Notebook für das Tutorial

Für das Notebook können Sie eine der folgenden Optionen wählen:

  • Öffnen Sie das integrierte Notebook in der Synapse Data Science-Umgebung, und führen Sie es aus
  • Laden Sie Ihr Notebook von GitHub in die Synapse Data Science-Umgebung hoch

Öffnen des integrierten Notebooks

Das Notebook zur Klassifizierung des Titelgenres liegt diesem Tutorial als Beispiel bei.

So öffnen Sie das integrierte Beispiel-Notebook für das Tutorial in der Synapse Data Science-Umgebung:

  1. Wechseln Sie zur Synapse Data Science-Startseite.

  2. Wählen Sie Beispiel verwenden aus.

  3. Wählen Sie das zugehörige Beispiel aus:

    • Wählen Sie es auf der Standardregisterkarte End-to-End-Workflows (Python) aus, wenn es sich bei dem Beispiel um ein Python-Tutorial handelt.
    • Wählen Sie es auf der Registerkarte End-to-End-Workflows (R) aus, wenn es sich bei dem Beispiel um ein R-Tutorial handelt.
    • Wählen Sie es auf der Registerkarte Schnelltutorials aus, wenn es sich bei dem Beispiel um ein Schnelltutorial handelt.
  4. Fügen Sie ein Lakehouse an das Notebook an, bevor Sie mit der Ausführung von Code beginnen.

Importieren des Notebooks von GitHub

AIsample – Title Genre Classification.ipynb ist das Notebook, das dieses Tutorial begleitet.

Um das zugehörige Notebook für dieses Tutorial zu öffnen, befolgen Sie die Anweisungen unter Vorbereiten Ihres Systems für Data-Science-Tutorials zum Importieren des Notebooks in Ihren Arbeitsbereich.

Wenn Sie den Code lieber von dieser Seite kopieren und einfügen möchten, können Sie auch ein neues Notebook erstellen.

Fügen Sie unbedingt ein Lakehouse an das Notebook an, bevor Sie mit der Ausführung von Code beginnen.

Schritt 1: Installieren von benutzerdefinierten Bibliotheken

Für die Entwicklung eines Machine Learning-Modells oder für Ad-hoc-Datenanalysen müssen Sie u. U. schnell eine benutzerdefinierte Bibliothek für Ihre Apache Spark-Sitzung installieren. Sie haben zwei Optionen zum Installieren von Bibliotheken.

  • Verwenden Sie die Inline-Installationsfunktionen (%pip oder %conda) Ihres Notebooks zum Erstellen einer Bibliothek nur in Ihrem aktuellen Notebook.
  • Alternativ können Sie eine Fabric-Umgebung erstellen, Bibliotheken aus öffentlichen Quellen installieren oder benutzerdefinierte Bibliotheken darauf hochladen, und dann kann Ihr Arbeitsbereichsadministrator die Umgebung als Standard für den Arbeitsbereich anfügen. Alle Bibliotheken in der Umgebung werden dann für die Verwendung in allen Notebooks und Spark-Auftragsdefinitionen im Arbeitsbereich verfügbar. Weitere Informationen zu Umgebungen finden Sie unter Erstellen, Konfigurieren und Verwenden einer Umgebung in Microsoft Fabric.

Für das Klassifizierungsmodell verwenden Sie die wordcloud-Bibliothek, um die Worthäufigkeit im Text darzustellen, wobei die Größe eines Wortes seine Häufigkeit darstellt. Verwenden Sie für dieses Tutorial %pip install zum Installieren von wordcloud in Ihrem Notebook.

Hinweis

Der PySpark-Kernel startet neu, nachdem %pip install gelaufen ist. Installieren Sie die benötigten Bibliotheken, bevor Sie andere Zellen ausführen.

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

Schritt 2: Laden der Daten

Das Dataset enthält Metadaten über Bücher aus der British Library, die in Zusammenarbeit zwischen der Bibliothek und Microsoft digitalisiert wurden. Die Metadaten sind Klassifizierungsinformationen, um anzugeben, ob es sich bei einem Buch um Belletristik oder ein Sachbuch handelt. Mit diesem Dataset soll ein Klassifikationsmodell trainiert werden, das das Genre eines Buchs ausschließlich basierend auf seinem Titel bestimmt.

Datensatz-ID in der BL Ressourcentyp Name Dem Namen zugeordnete Datumsangaben Typ des Namens Role Alle Namen Titel Variantentitel Titel der Reihe Nummer innerhalb der Reihe Land der Veröffentlichung Ort der Veröffentlichung Herausgeber Datum der Veröffentlichung Edition Physische Beschreibung Dewey-Klassifizierung BL-Regalmarke Themen Genre Sprachen Hinweise BL-Datensatz-ID für physische Ressource 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 zum digitalisierten Buch kommentiert
014602826 Monograph Yearsley, Ann 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 London 1786 Fourth edition MANUSCRIPT note Digital Store 11644.d.32 Englisch 003996603 False
014602830 Monograph 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 London 1679 15 pages (4°) Digital Store 11602.ee.10. (2.) Englisch 000001143 False

Definieren Sie die folgenden Parameter, damit Sie dieses Notebook auf verschiedene Datasets anwenden können:

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

Herunterladen des Datensatzes und Hochladen in Lakehouse

Dieser Code lädt eine öffentlich verfügbare Version des Datensatzes herunter und speichert ihn dann in einem Fabric Lakehouse.

Wichtig

Fügen Sie ein Lakehouse zum Notebook hinzu, bevor Sie es ausführen. Andernfalls kommt es zu einem Fehler.

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

Importieren der erforderlichen Bibliotheken

Vor jeder Verarbeitung müssen Sie erforderliche Bibliotheken einschließlich der Bibliotheken für Spark und SynapseML importieren:

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

Definieren von Hyperparametern

Definieren Sie einige Hyperparameter für das Modelltraining.

Wichtig

Ändern Sie diese Hyperparameter nur, wenn Sie ein Verständnis für jeden Parameter haben.

# 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

Starten Sie die Aufzeichnung der Zeit, die zum Ausführen dieses Notizbuchs benötigt wird:

# Record the notebook running time
import time

ts = time.time()

Einrichten der MLflow-Experimentnachverfolgung

Die automatische Protokollierung erweitert die MLflow-Protokollierungsfunktionen. Autologging erfasst automatisch die Eingabeparameterwerte und Ausgabemetriken eines Machine-Learning-Modells, während Sie es trainieren. Anschließend protokollieren Sie diese Informationen im Arbeitsbereich. Im Arbeitsbereich können Sie auf die Informationen mit den MLflow-APIs oder dem entsprechenden Experiment zugreifen und diese visualisieren. Weitere Informationen zur automatischen Protokollierung finden Sie unter Automatische Protokollierung in Microsoft Fabric.

# Set up Mlflow for experiment tracking

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

Um die automatische Microsoft Fabric-Protokollierung in einer Notebooksitzung zu deaktivieren, rufen Sie mlflow.autolog() auf und legen Sie disable=True fest:

Lesen von Rohdatumsdaten aus dem Lakehouse

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

Schritt 3: Durchführen einer explorativen Datenanalyse

Erkunden Sie das Dataset mithilfe des Befehls display, um allgemeine Statistiken für das Dataset und die Diagrammansichten anzuzeigen:

display(raw_df.limit(20))

Vorbereiten der Daten

Entfernen Sie die Duplikate, um die Daten zu bereinigen:

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

display(df.limit(20))

Führen Sie einen Klassenausgleich durch, um etwaige Verzerrungen zu beseitigen:

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

Teilen Sie die Absätze und Sätze in kleinere Einheiten auf, um das Dataset zu tokenisieren. Auf diese Weise wird es einfacher, Bedeutung zuzuweisen. Entfernen Sie dann die Stoppwörter, um die Leistung zu verbessern. Das Entfernen von Stoppwörtern umfasst das Entfernen von Wörtern, die häufig in allen Dokumenten im Korpus auftreten. Das Entfernen von Stoppwörtern ist eine der am häufigsten verwendeten Vorverarbeitungsschritte in Anwendungen für die linguistische Datenverarbeitung (Natural Language Processing, 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))

Zeigen Sie die Wortwolkenbibliothek für jede Klasse an. Eine Wortwolkenbibliothek ist eine visuell prominente Darstellung von „Schlüsselwörtern“, die häufig in Textdaten angezeigt werden. Die Wortwolkenbibliothek ist effektiv, da das Rendern von Schlüsselwörtern ein cloudähnliches Farbbild bildet, sodass die Haupttextdaten auf einen Blick besser erfasst werden können. Erfahren Sie mehr über 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")

Verwenden Sie schließlich word2vec, um den Text zu vektorisieren. Die word2vec-Technik erstellt eine Vektordarstellung jedes Worts im Text. Wörter, die in ähnlichen Kontexten verwendet werden oder die semantische Beziehungen aufweisen, werden durch ihre Nähe im Vektorraum effektiv erfasst. Dies weit darauf hin, dass ähnliche Wörter ähnliche Wortvektoren haben.

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

Schritt 4: Trainieren und Auswerten des Modells

Wenn die Daten vorhanden sind, definieren Sie das Modell. In diesem Abschnitt trainieren Sie ein logistisches Regressionsmodell, um den vektorisierten Text zu klassifizieren.

Erstellen von Trainings- und Testdatensätzen

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

Machine Learning-Experimente verfolgen

Ein Machine Learning-Experiment ist die primäre Einheit für die Organisation und Steuerung aller zugehörigen Machine Learning-Ausführungen. Eine Ausführung entspricht einer einzelnen Ausführung des Modellcodes.

Die Nachverfolgung von Machine Learning-Experimenten verwaltet alle Experimente und ihre Komponenten, z. B. Parameter, Metriken, Modelle und anderer Artefakte. Die Nachverfolgung ermöglicht die Organisation aller erforderlichen Komponenten eines bestimmten Experiments zum maschinellen Lernen. Sie ermöglicht auch die einfache Reproduktion vergangener Ergebnisse mit gespeicherten Experimenten. Weitere Informationen zu Machine-Learning-Experimenten in Microsoft Fabric.

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

Optimieren von Hyperparametern

Erstellen Sie ein Raster mit Parametern, um über die Hyperparameter zu suchen. Erstellen Sie dann einen Schätzwert für einen Querwerter, um ein CrossValidator-Modell zu erstellen:

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

Evaluieren des Modells

Wir können die Modelle im Testdatensatz auswerten, um sie zu vergleichen. Ein gut trainiertes Modell sollte bei den relevanten Metriken eine hohe Leistung zeigen, wenn es mit den Validierungs- und Testdatensätzen verglichen wird.

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

Experimente mit MLflow verfolgen

Beginnen Sie mit dem Trainings- und Bewertungsprozess. Verwenden Sie MLflow, um alle Experimente zu verfolgen und Parameter, Metriken und Modelle zu protokollieren. Alle diese Informationen werden unter dem Namen des Experiments im Arbeitsbereich protokolliert.

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

So zeigen Sie Ihre Experimente an:

  1. Wählen Sie Ihren Arbeitsbereich in der linken Navigation
  2. Suchen und wählen Sie den Namen des Experiments aus, in diesem Fall sample_aisample-textclassification

Screenshot of an experiment.

Schritt 5: Scoring und Speichern der Vorhersageergebnisse

Microsoft Fabric ermöglicht es Benutzern, Machine-Learning-Modelle mit der skalierbaren Funktion PREDICT zu operationalisieren. Diese Funktion unterstützt die Batchbewertung (oder den Batchrückschluss) in jeder Compute-Engine. Sie können Batchvorhersagen direkt aus einem Notebook oder der Elementseite für ein bestimmtes Modell erstellen. Weitere Informationen zu PREDICT und dessen Verwendung in Fabric finden Sie unter Bewertung von Machine Learning-Modellen mit PREDICT in Microsoft Fabric.

Aus den vorangegangenen Auswertungsergebnissen weist Modell 1 den größten Bereich unter der Precision-Recall Curve (AUPRC) und den Bereich unter den Metriken „Curve Receiver Operating Characteristic“ (AUC-ROC) auf. Daher sollten Sie Modell 1 für die Vorhersage verwenden.

Das AUC-ROC-Measure wird häufig zur Messung der Leistung binärer Klassifizierer verwendet. Manchmal ist es jedoch sinnvoller, den Klassifizierer anhand von AUPRC-Messungen zu bewerten. Das AUC-ROC-Diagramm visualisiert den Kompromiss zwischen der richtig positiv-Rate (TPR) und der falsch positive-Rate (FPR). Die AUPRC-Kurve kombiniert die Genauigkeit (positiver Prädikdikationswert oder PPV) und Rückruf (wahr positive Rate oder TPR) in einer einzigen Visualisierung.

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