Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Erstellen eines Modells für maschinelles Lernen mit SQL Server, ML.NET und C#

Dieser Artikel ist Teil der Initiative The Fourth Annual C# Advent Calendar von Matthew D. Groves. Dort finden Sie weitere hilfreiche Artikel und Anleitungen, die täglich von Community-Mitgliedern und Experten veröffentlicht werden. Schauen Sie also täglich rein.

ML.NET ist ein kostenloses, quelloffenes und plattformübergreifendes Framework für maschinelles Lernen, das für .NET-Entwickler entwickelt wurde. Mit ML.NET können Sie alle Kenntnisse, Fähigkeiten, Codes und Bibliotheken, die Sie bereits als .NET-Entwickler haben, wiederverwenden, sodass Sie maschinelles Lernen einfach in Ihre Web-, Mobil-, Desktop-, Spiele- und IoT-Apps integrieren können.

Sie können es für Klassifizierungs-, Regressions-, Zeitreihen- und sogar Computervisionsszenarien (Deep Learning, Bildklassifizierung) mit mehr als 40 Trainern (aufgabenbasierte ML-Algorithmen) anwenden, die Ihnen zur Verfügung stehen.

Ab Version 1.4-Vorschau wird die DatabaseLoader-Klasse unterstützt, was bedeutet, dass wir jetzt Modelle direkt mit relationalen Datenbanken trainieren und erstellen können, einschließlich SQL Server, Oracle, PostgreSQL, SQLite und anderen.

Für dieses Beispiel werde ich ein Modell erstellen, das hilft zu erkennen, ob eine Frau Diabetes entwickeln kann, basierend auf historischen Daten von anderen Patienten. Ich verwende einen Kaggle-Datensatz, den Sie hier herunterladen können.

Erstellen Sie danach einen Patienten Tabelle zum Speichern der Informationen. Die einzige Voraussetzung ist die Verwendung eines real Datentyp für numerische Felder, da ML.NET nur diesen Typ versteht. Eine weitere Option besteht darin, eine CAST-Operation auszuführen, wenn Sie die Daten abrufen und die Felder on the fly in echte umwandeln .

CREATE TABLE Patient(
  Id int identity(1,1) primary key,
  Pregnancies real not null,
  Glucose real not null,
  BloodPressure real not null,
  SkinThickness real not null,
  Insulin real not null,
  BMI real not null,
  DiabetesPedigreeFunction real not null,
  Age real not null,
  Output varchar(1) not null
)

Und natürlich müssen Sie alle Daten aus der CSV-Datei in die Tabelle einfügen .

Lassen Sie uns jetzt etwas Code schreiben!

Schritt 1. Erstellen Sie ein neues C#-Konsolenanwendungsprojekt:

Schritt 2. Fügen Sie Ihrem Projekt die folgenden Nuget-Pakete hinzu:

  • Microsoft.ML
  • System.Data.SqlClient
  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.Json
  • Microsoft.Extensions.Configuration.FileExtensions

Schritt 3. Fügen Sie Ihrem Projekt eine App-Einstellungsdatei hinzu.

Fügen Sie in dieser Datei einen ConnectionStrings hinzu Sammlung mit einer DbConnection Element. Der Wert ist natürlich die Verbindungszeichenfolge zu der Datenbank, in der sich Ihre Daten befinden.

Beispielsweise werde ich eine Verbindung zu einer Azure SQL-Datenbank herstellen :

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "DbConnection": "Server=tcp:myserver.database.windows.net,1433;Initial Catalog=mydatabase;Persist Security Info=False;User ID=myadmin;Password=MYadm1n;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
  }
}

HINWEIS:Stellen Sie In Ausgabeverzeichnis kopieren ein Eigenschaft für diese Datei, sonst wird sie später nicht vom Programm gelesen.

Schritt 4. Fügen Sie ein Modell hinzu Ordner zu Ihrem Projekt. Erstellen Sie darin eine neue Klasse mit dem Namen Patient , die mehrere Eigenschaften enthält, die der Tabellenstruktur entsprechen. Außerdem wird jede Eigenschaft mit dem LoadColumnAttribute versehen mit einem nullbasierten Index, der die Spalte darstellt, die aus der Datenbanktabelle zugeordnet wird.

using Microsoft.ML.Data;

namespace DiabetesPrediction.Models
{
    public class Patient
    {
        [LoadColumn(0)]
        public float Id { get; set; }

        [LoadColumn(1)]
        public float Pregnancies { get; set; }

        [LoadColumn(2)]
        public float Glucose { get; set; }

        [LoadColumn(3)]
        public float BloodPressure { get; set; }

        [LoadColumn(4)]
        public float SkinThickness { get; set; }

        [LoadColumn(5)]
        public float Insulin { get; set; }

        [LoadColumn(6)]
        public float BMI { get; set; }

        [LoadColumn(7)]
        public float DiabetesPedigreeFunction { get; set; }

        [LoadColumn(8)]
        public float Age { get; set; }

        [LoadColumn(9)]
        public float Output { get; set; }
    }
}

Schritt 5. Fügen Sie eine DiabetesMLPrediction hinzu Klasse, die von Patient erbt und zusätzliche Eigenschaften enthält. Dies wird verwendet, nachdem das maschinelle Lernmodell erstellt wurde, um vorhergesagte Daten anzuzeigen:

using Microsoft.ML.Data;

namespace DiabetesPrediction.Models
{
    public class DiabetesMLPrediction : Patient
    {
        [ColumnName("PredictedLabel")]
        public float Prediction { get; set; }

        public float Probability { get; set; }

        public float[] Score { get; set; }
    }
}

Schritt 6. In der Program.cs Datei:

a. Fügen Sie diese Namespaces hinzu:

using System;
using System.IO;
using System.Linq;
using System.Data.SqlClient;

using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.Extensions.Configuration;

using DiabetesPrediction.Models;

b. Fügen Sie innerhalb der Klasse eine GetDbConnection hinzu Methode, die die Verbindungszeichenfolge aus appsettings.json extrahiert Datei:

private static string GetDbConnection()
{
   var builder = new ConfigurationBuilder()
      .SetBasePath(Directory.GetCurrentDirectory())
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

   return builder.Build().GetConnectionString("DbConnection");
}

c. In der Main-Methode:

  • Erstellen Sie eine MLContext-Instanz
  • Erstellen Sie eine DatabaseLoader-Instanz basierend auf der Patient-Klasse
  • Rufen Sie die GetDbConnection-Methode auf
  • Bereiten Sie eine SQL-Anweisung vor, die alle Daten liest (und die ID in ein echtes Feld umwandelt)
  • Bereiten Sie eine DatabaseSource-Instanz vor, die die Verbindungszeichenfolge und die Anweisung verwendet.
var context = new MLContext();

var loader = context.Data.CreateDatabaseLoader<Patient>();

var connectionString = GetDbConnection();

var sqlCommand = "Select CAST(Id as REAL) as Id, Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age, CAST(Output as REAL) as Output From Patient";

var dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, sqlCommand);
  • Laden Sie die Daten aus der Tabelle in ein IDataView-Objekt und teilen Sie es in zwei weitere IDataViews auf, eine für das Training und eine für die Auswertung:
Console.WriteLine("Loading data from database...");
var data = loader.Load(dbSource);

var set = context.Data.TrainTestSplit(data, testFraction: 0.2);
var trainingData = set.TrainSet;
var testData = set.TestSet;
  • Erstellen Sie einen ITransformer, indem Sie eine Trainingspipeline vorbereiten, die ein maschinelles Lernmodell für BinaryClassification erstellt. Geben Sie die Spalte an, die vorhergesagt wird (Ausgabe):
Console.WriteLine("Preparing training operations...");
var pipeline = context.Transforms
       .Conversion.MapValueToKey(outputColumnName: "Label", inputColumnName: "Output")
       .Append(context.Transforms.Concatenate("Features", "Pregnancies", "Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI", "DiabetesPedigreeFunction", "Age"))
       .Append(context.MulticlassClassification.Trainers.OneVersusAll(context.BinaryClassification.Trainers.AveragedPerceptron("Label", "Features", numberOfIterations: 10))
       .Append(context.Transforms.Conversion.MapKeyToValue("PredictedLabel")));
  • Unterteilen Sie nun den Trainingsdatensatz in 10 Falten. 9 Falten werden im Training verwendet und die verbleibende Falte wird zum Testen verwendet. Dieser Vorgang wird 10 Mal wiederholt, wobei die Zug- und Testdatensätze geändert werden. Dieser Vorgang wird als 10-fache Kreuzvalidierung bezeichnet (Sie können die Anzahl natürlich ändern). Metriken werden ebenfalls angezeigt:
Console.WriteLine("=============== Starting 10 fold cross validation ===============");
var crossValResults = context.MulticlassClassification.CrossValidate(data: trainingData, estimator: pipeline, numberOfFolds: 10, labelColumnName: "Label");
var metricsInMultipleFolds = crossValResults.Select(r => r.Metrics);
var microAccuracyValues = metricsInMultipleFolds.Select(m => m.MicroAccuracy);
var microAccuracyAverage = microAccuracyValues.Average();
var macroAccuracyValues = metricsInMultipleFolds.Select(m => m.MacroAccuracy);
var macroAccuracyAverage = macroAccuracyValues.Average();
var logLossValues = metricsInMultipleFolds.Select(m => m.LogLoss);
var logLossAverage = logLossValues.Average();
var logLossReductionValues = metricsInMultipleFolds.Select(m => m.LogLossReduction);
var logLossReductionAverage = logLossReductionValues.Average(); Console.WriteLine($"*************************************************************************************************************");

Console.WriteLine($"*       Metrics Multi-class Classification model      ");
Console.WriteLine($"*------------------------------------------------------------------------------------------------------------");
Console.WriteLine($"*       Average MicroAccuracy:   {microAccuracyAverage:0.###} ");
Console.WriteLine($"*       Average MacroAccuracy:    {macroAccuracyAverage:0.###} ");
Console.WriteLine($"*       Average LogLoss:          {logLossAverage:#.###} ");
Console.WriteLine($"*       Average LogLossReduction: {logLossReductionAverage:#.###} ");
Console.WriteLine($"*************************************************************************************************************");

  • Als Nächstes können Sie das Modell trainieren, indem Sie die Fit-Methode aufrufen:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Dieser Vorgang dauert einige Zeit.

  • Nachdem das Modell erstellt wurde, können Sie mit dem Erstellen von Vorhersagen beginnen, indem Sie eine PredictionEngine erstellen und ein Patient-Objekt an die Predict-Methode übergeben:
var predictionEngine = context.Model.CreatePredictionEngine<Patient, DiabetesMLPrediction>(model);

var patient = new Patient()
{
  Age = 42,
  BloodPressure = 81,
  BMI = 30.1f,
  DiabetesPedigreeFunction = 0.987f,
  Glucose = 120,
  Insulin = 100,
  Pregnancies = 1,
  SkinThickness = 26,
  Id = 0,
  Output = 0
};

var prediction = predictionEngine.Predict(patient);
Console.WriteLine($"Diabetes? {prediction.Output} | Prediction: {(Convert.ToBoolean(prediction.Prediction) ? "Yes" : "No")} | Probability: {prediction.Probability} ");

  • Schließlich können Sie das Modell speichern, um es in anderen Projekten (Web Api, Azure Functions usw.) zu verwenden
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Schritt 7. Führen Sie das Programm aus, Sie erhalten die Ergebnisse und ein ML-Modell für einige Vorhersagen:

Der Code ist auf GitHub verfügbar.

Ich hoffe, dass dieser Blogbeitrag für Sie interessant und nützlich war. Ich lade Sie ein, meinen Blog zu besuchen, um weitere technische Beiträge zu Xamarin, Azure und dem .NET-Ökosystem zu erhalten . Ich schreibe in spanischer Sprache =)

Vielen Dank für Ihre Zeit und viel Spaß mit den restlichen Veröffentlichungen zum C#-Adventskalender!

Bis zum nächsten Mal,
Luis