Teilen über


Lernprogramm: Erstellen, Auswerten und Bewerten eines Textklassifizierungsmodells

Dieses Lernprogramm zeigt ein End-to-End-Beispiel eines Synapse Data Science-Workflows für ein Textklassifizierungsmodell in Microsoft Fabric. Das Szenario verwendet sowohl die Verarbeitung natürlicher Sprache (Word2vec Natural Language Processing, NLP) als auch die logistische Regression auf Spark, um das Genre eines Buchs aus dem Datensatz des British Library-Buchs zu bestimmen. Die Bestimmung basiert ausschließlich auf dem Titel des Buchs.

In diesem Lernprogramm werden die folgenden Schritte behandelt:

  • Installieren von benutzerdefinierten Bibliotheken
  • Laden der Daten
  • Verstehen und Verarbeiten der Daten mit explorativer Datenanalyse
  • Trainieren eines Machine Learning-Modells mit Word2vec NLP und logistischer Regression und Verfolgen von Experimenten mit MLflow und der Fabric-Autoprotokollierungsfunktion
  • Laden des Machine Learning-Modells zum Bewerten und Vorhersagen

Voraussetzungen

Notebook für das Tutorial

Um in einem Notizbuch mitzuarbeiten, haben Sie folgende Optionen:

  • Öffnen sie das integrierte Notizbuch, und führen Sie es aus.
  • Laden Sie Ihr Notizbuch von GitHub hoch.

Öffnen des integrierten Notizbuchs

Das Beispiel-Notizbuch zur Titel-Genre-Klassifizierung begleitet dieses Lernprogramm.

  1. Um das Beispielnotizbuch für dieses Lernprogramm zu öffnen, befolgen Sie die Anweisungen in Vorbereiten Ihres Systems für Data Science-Lernprogramme.

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

Importieren des Notizbuchs aus GitHub

In diesem Tutorial wird das Notebook AIsample – Title Genre Classification.ipynb verwendet.

Schritt 1: Installieren von benutzerdefinierten Bibliotheken

Für die Entwicklung von Machine Learning-Modell oder ad-hoc-Datenanalysen müssen Sie möglicherweise schnell eine benutzerdefinierte Bibliothek für Ihre Apache Spark-Sitzung installieren. Sie haben zwei Optionen zum Installieren einer Bibliothek.

  • Verwenden Sie zum Installieren einer Bibliothek nur in Ihrem aktuellen Notizbuch die Inlineinstallationsfunktionen (%pip oder %conda) Ihres Notizbuchs.
  • Alternativ können Sie eine Fabric-Umgebung erstellen und Bibliotheken aus öffentlichen Quellen installieren oder benutzerdefinierte Bibliotheken darauf hochladen. Anschließend kann Ihr Arbeitsbereichsadministrator die Umgebung als Standard für den Arbeitsbereich anfügen. Zu diesem Zeitpunkt sind alle Bibliotheken in der Umgebung für die Verwendung in allen Notizbüchern und allen Spark-Auftragsdefinitionen in diesem Arbeitsbereich verfügbar. Weitere Informationen zu Umgebungen finden Sie in der Microsoft Fabric-Ressource zum Erstellen, Konfigurieren und Verwenden einer Umgebung .

Verwenden Sie für das Klassifizierungsmodell die wordcloud Bibliothek, um die Worthäufigkeit im Text darzustellen. In wordcloud Ressourcen stellt die Größe eines Worts seine Häufigkeit dar. Verwenden Sie für dieses Tutorial %pip install, um wordcloud in Ihrem Notizbuch zu installieren.

Anmerkung

Der PySpark-Kernel wird neu gestartet, nachdem %pip install ausgeführt wurde. 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 Buch-Dataset der British Library enthält Metadaten zu den Büchern der British Library. Eine Zusammenarbeit zwischen der Bibliothek und Microsoft digitalisierte die ursprünglichen Ressourcen, die zum Dataset wurden. Die Metadaten sind Klassifizierungsinformationen, die angibt, ob ein Buch Fiktion oder Nonfiction ist oder nicht. Das folgende Diagramm zeigt ein Zeilenbeispiel des Datasets.

BL-Datensatz-ID Ressourcentyp Name Datumsangaben, die dem Namen zugeordnet sind Nametyp Rolle Alle Namen Titel Variantentitel Titel der Reihe Zahl innerhalb von Datenreihen Veröffentlichungsland Ort der Veröffentlichung Verlag Datum der Veröffentlichung Edition Physische Beschreibung Dewey-Klassifizierung BL-Signatur Themen Genre Sprachen Notizen BL-Datensatz-ID für physische Ressource Klassifizierungs-ID Benutzer-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 Anmerkungen des Annotators 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 Annotiert
014602826 Monographie Yearsley, Ann 1753-1806 person Mehr, Hannah, 1745-1833 [Person]; Yearsley, Ann, 1753-1806 [Person] Gedichte zu verschiedenen Anlässen [Mit einem Vorwort von Hannah More.] England London 1786 Vierte Ausgabe Handschrift Anmerkung Digital Store 11644.d.32 Englisch 003996603 Falsch
014602830 Monographie A, T. person Oldham, John, 1653-1683 [Person]; A, T. [Person] Ein Satyr gegen Vertue. (Ein Gedicht: soll von einem Town-Hector gesprochen werden [Von John Oldham. Das Vorwort signiert: T. A.]) England London 1679 15 Seiten (4°) Digital Store 11602.ee.10. (2.) Englisch 000001143 Falsch

Mit diesem Dataset ist unser Ziel, ein Klassifikationsmodell zu trainieren, das das Genre eines Buches bestimmt, das nur auf dem Buchtitel basiert.

Definieren Sie die folgenden Parameter, um dieses Notizbuch auf verschiedene Datasets anzuwenden:

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

Laden Sie das Dataset herunter und laden Sie es in das Seehaus hoch.

Der folgende Codeausschnitt lädt eine öffentlich verfügbare Version des Datasets herunter und speichert sie dann in einem Fabric Lakehouse:

Wichtig

Fügen Sie ein Lakehouse zum Notebook hinzu, bevor Sie es ausführen. Wenn dies nicht getan wird, tritt ein Fehler auf.

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

Importieren erforderlicher Bibliotheken

Vor jeder Verarbeitung müssen Sie die erforderlichen Bibliotheken importieren, einschließlich der Bibliotheken für Spark und 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

Definieren von Hyperparametern

Der folgende Codeausschnitt definiert die erforderlichen Hyperparameter für die Modellschulung:

Wichtig

Ändern Sie diese Hyperparameter nur, wenn Sie jeden Parameter verstehen.

# 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 erforderlich ist:

# Record the notebook running time
import time

ts = time.time()

Einrichten der MLflow-Experimentnachverfolgung

Die automatische Protokollierung erweitert die MLflow-Protokollierungsfunktionen. Die automatische Erfassung 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 im Arbeitsbereich zugreifen und visualisieren. Weitere Informationen zum automatischen Logging finden Sie in der Microsoft Fabric-Ressource 'Autologging'.

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

# Set up Mlflow for experiment tracking

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

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 mit dem Befehl display, um allgemeine Statistiken für das Dataset anzuzeigen und die Diagrammansichten anzuzeigen:

display(raw_df.limit(20))

Vorbereiten der Daten

Um die Daten zu bereinigen, entfernen Sie die Duplikate:

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

display(df.limit(20))

Wenden Sie den Klassenausgleich an, um alle Verzerrungen zu beheben:

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

Um das Dataset zu tokenisieren, teilen Sie die Absätze und Sätze in kleinere Einheiten auf. Auf diese Weise wird es einfacher, Bedeutung zuzuweisen. Entfernen Sie als Nächstes 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 Verarbeitung natürlicher Sprachen (Natural Language Processing, NLP). Der folgende Codeausschnitt behandelt die folgenden Schritte:

# 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 Wordcloud-Bibliothek für jede Klasse an. Eine Wordcloud-Bibliothek stellt Schlüsselwörter dar, die häufig in Textdaten angezeigt werden, ist eine visuell prominente Präsentation. Die Wordcloud-Bibliothek ist effektiv, da das Schlüsselwortrendering ein cloudähnliches Farbbild bildet, um die Haupttextdaten auf einen Blick besser zu erfassen. Besuchen Sie diese Ressource , um weitere Informationen zu wordcloud zu finden.

Der folgende Codeausschnitt behandelt die folgenden Schritte:

# 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 NLP, um den Text zu vektorisieren. Die Word2vec NLP-Technik erstellt eine Vektordarstellung jedes Worts im Text. Wörter, die in ähnlichen Kontexten verwendet werden oder über semantische Beziehungen verfügen, werden effektiv durch ihre Nähe im Vektorraum erfasst. Diese Nähe weist darauf hin, dass ähnliche Wörter ähnliche Wortvektoren haben. Der folgende Codeausschnitt behandelt die folgenden Schritte:

# 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 Bewerten des Modells

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

Vorbereiten von Schulungs- und Testdatensätzen

Der folgende Codeausschnitt teilt das Dataset auf:

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

Nachverfolgen von Machine Learning-Experimenten

Das Tracking von Machine-Learning-Experimenten verwaltet alle Experimente und deren Komponenten, z. B. Parameter, Metriken, Modelle und andere Artefakte. Die Nachverfolgung ermöglicht die Organisation und Verwaltung aller Komponenten, die ein bestimmtes Machine Learning-Experiment erfordert. Es ermöglicht auch die einfache Reproduktion vergangener Ergebnisse mit gespeicherten Experimenten. Weitere Informationen finden Sie unter Machine Learning-Experimente in Microsoft Fabric .

Ein Machine Learning-Experiment ist die primäre Einheit der Organisation und Kontrolle für alle zugehörigen Machine Learning-Ausführungen. Eine Ausführung entspricht einer einzelnen Ausführung von Modellcode. Der folgende Codeausschnitt behandelt die folgenden Schritte:

# 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 eine auswertungsübergreifende Schätzung, um ein CrossValidator Modell zu erstellen, wie im folgenden Codeausschnitt dargestellt:

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

Auswerten des Modells

Wir können die Modelle im Testdatensatz auswerten, um sie zu vergleichen. Ein gut geschultes Modell sollte bei der Ausführung mit den Validierungs- und Testdatensätzen eine hohe Leistung bei den relevanten Metriken demonstrieren. Der folgende Codeausschnitt behandelt die folgenden Schritte:

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

Nachverfolgen von Experimenten mithilfe von MLflow

Starten Sie den Schulungs- und Evaluierungsprozess. Verwenden Sie MLflow, um alle Experimente nachzuverfolgen und die Parameter, Metriken und Modelle zu protokollieren. Im Arbeitsbereich werden alle diese Informationen unter dem Namen des Experiments protokolliert. Der folgende Codeausschnitt behandelt die folgenden Schritte:

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

Zeigen Sie Ihre Experimente wie folgt an:

  1. Wählen Sie ihren Arbeitsbereich im linken Navigationsbereich aus.
  2. Suchen Sie den Experimentnamen, und wählen Sie ihn aus (in diesem Fall sample_aisample-textclassification).

Screenshot eines Experiments.

Schritt 5: Bewertung und Speichern von Vorhersageergebnissen

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

Aus unseren Auswertungsergebnissen weist Modell 1 die größten Metriken sowohl für Area Under the Precision-Recall Curve (AUPRC) als auch für Area Under the Curve Receiver Operating Characteristic (AUC-ROC) auf. Daher sollten Sie Modell 1 für die Vorhersage verwenden.

Das AUC-ROC Measure wird häufig verwendet, um die Leistung binärer Klassifizierer zu messen. Es ist jedoch manchmal besser geeignet, den Klassifizierer basierend auf AUPRC-Messungen zu bewerten. Das AUC-ROC Diagramm visualisiert den Kompromiss zwischen wahrer positiver Rate (TPR) und falsch positiver Rate (FPR). Die AUPRC-Kurve kombiniert sowohl Genauigkeit (positiver Prädikdikwert oder PPV) als auch Rückruf (wahr positive Rate oder TPR) in einer einzigen Visualisierung. Die folgenden Codeausschnitte behandeln die folgenden Schritte:

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