Selbst lernt die Maschine
Installation und Training
Zur Nutzung von ML.NET AutoML müssen Sie lediglich die Bibliotheken Microsoft.ML und Microsoft.ML.AutoML installieren, zum Beispiel mittels NuGet in Visual Studio. Greifen Sie ruhig zur neuesten Version, auch wenn sie noch als instabil gekennzeichnet ist. In der Tat treten bei einzelnen Trainingsdurchläufen gelegentlich Exceptions auf, was aber verschmerzbar ist – durch Abfangen der Exception geht nur das Ergebnis des aktuellen Durchlaufs verloren.
Zur Demonstration der Vorgehensweise dient das Beispiel „Brustkrebsdiagnose“, das auch schon in [12] beschrieben und dort mit R Services implementiert wurde. Bei diesem Beispiel liegen Gewebebiopsie-Daten aus der Untersuchung des Tumorgewebes von Brustkrebspatientinnen vor (Tabelle 3). Basierend auf diesen Eingangswerten soll das trainierte Modell eine Entscheidung fällen, ob bei einer Person bösartiger Brustkrebs vorliegt oder nicht (binäre Klassifikation).
Listing 1 zeigt anhand einer Konsolenanwendung, wie es geht. Zuerst müssen Sie als Basis ein MLContext-Objekt erzeugen. Hier können Sie optional einen Seed (Startwert) übergeben, der sicherstellt, dass die Ergebnisse reproduzierbar sind. Danach können Sie die Trainingsdaten einlesen, zum Beispiel aus einer CSV-Datei. Dabei erfolgt eine Typisierung auf die Eingangsdaten, wie sie in der Klasse BiopsyData vorgegeben sind (Listing 2). Jedes Feld muss dabei mit dem LoadColumn-Attribut versehen werden. Erlaubte Datentypen innerhalb von BiopsyData sind string, float und bool, da AutoML nur mit diesen umgehen kann. Die Eingangsdaten sollten entsprechend angepasst werden (true/false statt malignant/benign).
Listing 1: Automatisches Training mit Ausgabe des Gewinnermodells
using Microsoft.ML;
using Microsoft.ML.AutoML;
using Microsoft.ML.Data;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AutoMLExample
{
public static class Program
{
const string trainDataFilename =
"BiopsyTrainData.csv";
const string modelFilename = "Model.bin";
const uint trainingTimeInSeconds = 10;
static List<TrainingResult> trainingResults =
new List<TrainingResult>();
public static void Main(string[] args)
{
MLContext mlContext = new MLContext();
IDataView trainDataView = mlContext.Data.LoadFrom
TextFile<BiopsyData>(trainDataFilename, ';',
true);
var experimentSettings =
new BinaryExperimentSettings();
experimentSettings.MaxExperimentTimeInSeconds =
trainingTimeInSeconds;
var metricValues = Enum.GetValues(typeof(
BinaryClassificationMetric));
// Loop through all metrics
foreach (BinaryClassificationMetric metricValue
in metricValues)
{
experimentSettings.OptimizingMetric =
metricValue;
var experiment = mlContext.Auto().CreateBinary
ClassificationExperiment(experimentSettings);
ExperimentResult<BinaryClassificationMetrics>
experimentResult;
try
{
// Run training
experimentResult = experiment.Execute(
trainDataView, "class");
}
// Workaround for bug in Execute() Method
catch (ArgumentOutOfRangeException)
{
continue;
}
var bestRun = experimentResult.BestRun;
var metrics = bestRun.ValidationMetrics;
trainingResults.Add(
new TrainingResult
{
ExperimentTimeInSeconds =
trainingTimeInSeconds,
Model = bestRun.Model,
Metric = metricValue,
Trainer = bestRun.TrainerName,
Accuracy = metrics.Accuracy,
AreaUnderPrecisionRecallCurve =
metrics.AreaUnderPrecisionRecallCurve,
AreaUnderRocCurve =
metrics.AreaUnderRocCurve,
F1Score = metrics.F1Score,
PositiveRecall = metrics.PositiveRecall,
NegativeRecall = metrics.NegativeRecall,
PositivePrecision =
metrics.PositivePrecision,
NegativePrecision =
metrics.NegativePrecision,
Matrix = metrics.ConfusionMatrix
});
}
trainingResults = trainingResults
.OrderByDescending(result =>
result.NegativePrecision)
.ThenByDescending(result =>
result.PositivePrecision)
.ToList<TrainingResult>();
// Save best model to disk
var bestTrainingResults = trainingResults[0];
mlContext.Model.Save(bestTrainingResults.Model,
trainDataView.Schema, "Model.bin");
// Print results to console window
Console.WriteLine($"Training Time: {
bestTrainingResults.ExperimentTimeInSeconds}");
Console.WriteLine($"Metric: {
bestTrainingResults.Metric.ToString()}");
Console.WriteLine($"Trainer: {
bestTrainingResults.Trainer}");
Console.WriteLine($"Accuracy: {
bestTrainingResults.Accuracy:0.###}");
Console.WriteLine($"AreaUnderPrecisionRecallCurve:
{bestTrainingResults.AreaUnderPrecisionRecall
Curve:0.###}");
Console.WriteLine($"AreaUnderRocCurve: {
bestTrainingResults.AreaUnderRocCurve:0.###}");
Console.WriteLine($"F1Score: {
bestTrainingResults.F1Score:0.###}");
Console.WriteLine($"PositiveRecall: {
bestTrainingResults.PositiveRecall:0.###}");
Console.WriteLine($"NegativeRecall: {
bestTrainingResults.NegativeRecall:0.###}");
Console.WriteLine($"Positive Precision: {
bestTrainingResults.PositivePrecision:0.###}");
Console.WriteLine($"Negative Precision: {
bestTrainingResults.NegativePrecision:0.###}");
Console.WriteLine();
Console.WriteLine(bestTrainingResults.Matrix.Get
FormattedConfusionTable());
}
}
}
using Microsoft.ML.AutoML;
using Microsoft.ML.Data;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AutoMLExample
{
public static class Program
{
const string trainDataFilename =
"BiopsyTrainData.csv";
const string modelFilename = "Model.bin";
const uint trainingTimeInSeconds = 10;
static List<TrainingResult> trainingResults =
new List<TrainingResult>();
public static void Main(string[] args)
{
MLContext mlContext = new MLContext();
IDataView trainDataView = mlContext.Data.LoadFrom
TextFile<BiopsyData>(trainDataFilename, ';',
true);
var experimentSettings =
new BinaryExperimentSettings();
experimentSettings.MaxExperimentTimeInSeconds =
trainingTimeInSeconds;
var metricValues = Enum.GetValues(typeof(
BinaryClassificationMetric));
// Loop through all metrics
foreach (BinaryClassificationMetric metricValue
in metricValues)
{
experimentSettings.OptimizingMetric =
metricValue;
var experiment = mlContext.Auto().CreateBinary
ClassificationExperiment(experimentSettings);
ExperimentResult<BinaryClassificationMetrics>
experimentResult;
try
{
// Run training
experimentResult = experiment.Execute(
trainDataView, "class");
}
// Workaround for bug in Execute() Method
catch (ArgumentOutOfRangeException)
{
continue;
}
var bestRun = experimentResult.BestRun;
var metrics = bestRun.ValidationMetrics;
trainingResults.Add(
new TrainingResult
{
ExperimentTimeInSeconds =
trainingTimeInSeconds,
Model = bestRun.Model,
Metric = metricValue,
Trainer = bestRun.TrainerName,
Accuracy = metrics.Accuracy,
AreaUnderPrecisionRecallCurve =
metrics.AreaUnderPrecisionRecallCurve,
AreaUnderRocCurve =
metrics.AreaUnderRocCurve,
F1Score = metrics.F1Score,
PositiveRecall = metrics.PositiveRecall,
NegativeRecall = metrics.NegativeRecall,
PositivePrecision =
metrics.PositivePrecision,
NegativePrecision =
metrics.NegativePrecision,
Matrix = metrics.ConfusionMatrix
});
}
trainingResults = trainingResults
.OrderByDescending(result =>
result.NegativePrecision)
.ThenByDescending(result =>
result.PositivePrecision)
.ToList<TrainingResult>();
// Save best model to disk
var bestTrainingResults = trainingResults[0];
mlContext.Model.Save(bestTrainingResults.Model,
trainDataView.Schema, "Model.bin");
// Print results to console window
Console.WriteLine($"Training Time: {
bestTrainingResults.ExperimentTimeInSeconds}");
Console.WriteLine($"Metric: {
bestTrainingResults.Metric.ToString()}");
Console.WriteLine($"Trainer: {
bestTrainingResults.Trainer}");
Console.WriteLine($"Accuracy: {
bestTrainingResults.Accuracy:0.###}");
Console.WriteLine($"AreaUnderPrecisionRecallCurve:
{bestTrainingResults.AreaUnderPrecisionRecall
Curve:0.###}");
Console.WriteLine($"AreaUnderRocCurve: {
bestTrainingResults.AreaUnderRocCurve:0.###}");
Console.WriteLine($"F1Score: {
bestTrainingResults.F1Score:0.###}");
Console.WriteLine($"PositiveRecall: {
bestTrainingResults.PositiveRecall:0.###}");
Console.WriteLine($"NegativeRecall: {
bestTrainingResults.NegativeRecall:0.###}");
Console.WriteLine($"Positive Precision: {
bestTrainingResults.PositivePrecision:0.###}");
Console.WriteLine($"Negative Precision: {
bestTrainingResults.NegativePrecision:0.###}");
Console.WriteLine();
Console.WriteLine(bestTrainingResults.Matrix.Get
FormattedConfusionTable());
}
}
}
Listing 2: Eingangsfelder in einer Klasse deklarieren
using Microsoft.ML.Data;
namespace AutoMLExample
{
public class BiopsyData
{
[LoadColumn(0)] public float ID;
[LoadColumn(1)] public float V1;
[LoadColumn(2)] public float V2;
[LoadColumn(3)] public float V3;
[LoadColumn(4)] public float V4;
[LoadColumn(5)] public float V5;
[LoadColumn(6)] public float V6;
[LoadColumn(7)] public float V7;
[LoadColumn(8)] public float V8;
[LoadColumn(9)] public float V9;
[LoadColumn(10)] public bool @class;
}
}
namespace AutoMLExample
{
public class BiopsyData
{
[LoadColumn(0)] public float ID;
[LoadColumn(1)] public float V1;
[LoadColumn(2)] public float V2;
[LoadColumn(3)] public float V3;
[LoadColumn(4)] public float V4;
[LoadColumn(5)] public float V5;
[LoadColumn(6)] public float V6;
[LoadColumn(7)] public float V7;
[LoadColumn(8)] public float V8;
[LoadColumn(9)] public float V9;
[LoadColumn(10)] public bool @class;
}
}
Im Anschluss erstellen Sie ein BinaryExperimentSettings-Objekt, mit dem das Training konfiguriert wird (Microsoft nennt das Training ein „Experiment“). Einer der Konfigurationswerte ist die zu verwendende Optimierungsmetrik. Um die Automatisierung noch einen Schritt weiter zu treiben, setzen Sie eine Schleife um den darauffolgenden Trainingscode und iterieren dabei durch alle verfügbaren Metriken.
Für das eigentliche Training wird ein BinaryClassificationExperiment-Objekt benötigt, das Sie aus mlContext erzeugen können. Durch Aufruf der Execute-Methode wird das Training angestossen. Legen Sie nach jedem Durchlauf das trainierte Modell mitsamt seiner Konfiguration und den ermittelten Messgrössen (Listing 3) in einer Liste ab. Am Ende picken Sie sich das geeignetste Modell durch Sortieren der Liste heraus. Im vorliegenden Beispiel wird zuerst nach negativer Genauigkeit (NegativePrecision), dann nach positiver Genauigkeit (PositivePrecision) sortiert, weil es wichtig ist, wenige falsch negative Ergebnisse zu bekommen (ein übersehener bösartiger Tumor ist viel problematischer als einige irrtümlich als bösartig erkannte gutartige Tumoren).
Listing 3: Hilfsklasse als Container für die trainierten Modelle
using Microsoft.ML;
using Microsoft.ML.AutoML;
using Microsoft.ML.Data;
namespace AutoMLExample
{
public class TrainingResult
{
// Configuration
public uint ExperimentTimeInSeconds { get; set; }
public ITransformer Model { get; set; }
public string Trainer { get; set; }
public BinaryClassificationMetric Metric { get; set; }
// Metrics
public double Accuracy { get; set; }
public double AreaUnderPrecisionRecallCurve { get; set; }
public double AreaUnderRocCurve { get; set; }
public double F1Score { get; set; }
public double PositiveRecall { get; set; }
public double NegativeRecall { get; set; }
public double PositivePrecision { get; set; }
public double NegativePrecision { get; set; }
public ConfusionMatrix Matrix { get; set; }
}
}
using Microsoft.ML.AutoML;
using Microsoft.ML.Data;
namespace AutoMLExample
{
public class TrainingResult
{
// Configuration
public uint ExperimentTimeInSeconds { get; set; }
public ITransformer Model { get; set; }
public string Trainer { get; set; }
public BinaryClassificationMetric Metric { get; set; }
// Metrics
public double Accuracy { get; set; }
public double AreaUnderPrecisionRecallCurve { get; set; }
public double AreaUnderRocCurve { get; set; }
public double F1Score { get; set; }
public double PositiveRecall { get; set; }
public double NegativeRecall { get; set; }
public double PositivePrecision { get; set; }
public double NegativePrecision { get; set; }
public ConfusionMatrix Matrix { get; set; }
}
}
Im letzten Schritt persistieren Sie das Gewinnermodell in eine Binärdatei und geben einige Kenngrössen in der Konsole aus. Besonders übersichtlich ist dabei die sogenannte Confusion Matrix, die mehrere Grössen tabellenartig wiedergibt [13]. Ein typisches Ergebnis sehen Sie in Bild 1.
Ausgabe der Kenngrössen des Gewinnermodells (Bild 1)
Quelle: Autor
Fußnoten
- [1] Top Machine Learning Algorithms You Should Know to Become a Data Scientist
- [2] Google Cloud AutoML
- [3] Auto-Keras
- [4] ML.NET AutoML
- [5] ML.NET Documentation
- [6] BinaryClassificationTrainer Enum
- [7] MulticlassClassificationTrainer Enum
- [8] RegressionTrainer Enum
- [9] BinaryClassificationMetric Enum
- MulticlassClassificationMetric Enum
- RegressionMetric Enum
- Martin Gossen, Smarte Datenbank, dotnetpro 10/2017, Seite 92 ff.
- Confusion matrix
- Metrics to Evaluate your Machine Learning Algorithm
- Hyperparameters in Deep Learning
Autor(in)
Martin
Gossen