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
Erwerben Sie ein Microsoft Fabric-Abonnement. Registrieren Sie sich alternativ für eine kostenlose Microsoft Fabric-Testversion.
Melden Sie sich bei Microsoft Fabric an.
Wechseln Sie zur Synapse-Data Science-Benutzeroberfläche, indem Sie den Umschalter für die Benutzeroberfläche auf der linken Seite Ihrer Homepage verwenden.
- Wenn Sie nicht über ein Microsoft Fabric Lakehouse verfügen, erstellen Sie eins, indem Sie die Schritte unter Erstellen eines Lakehouse in Microsoft Fabric ausführen.
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:
Wechseln Sie zur Synapse Data Science-Startseite.
Wählen Sie Beispiel verwenden aus.
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.
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:
- Wählen Sie Ihren Arbeitsbereich in der linken Navigation
- Suchen und wählen Sie den Namen des Experiments aus, in diesem Fall sample_aisample-textclassification
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.")