sql >> Database >  >> RDS >> Sqlserver

Een machine learning-model bouwen met SQL Server, ML.NET en C#

Dit artikel maakt deel uit van het initiatief The Fourth Annual C# Advent Calendar van Matthew D. Groves. Je vindt daar andere nuttige artikelen en tutorials die dagelijks door leden van de community en experts worden gepubliceerd, dus zorg ervoor dat je deze elke dag bekijkt.

ML.NET is een gratis, open-source en platformonafhankelijk machine learning-framework dat is ontworpen voor .NET-ontwikkelaars. Met ML.NET kun je alle kennis, vaardigheden, code en bibliotheken hergebruiken die je al hebt als .NET-ontwikkelaar, zodat je machine learning eenvoudig kunt integreren in je web-, mobiel-, desktop-, games- en IoT-apps.

U kunt het toepassen op scenario's voor classificatie, regressie, tijdreeksen en zelfs computervisie (deep learning, beeldclassificatie) met meer dan 40 trainers (taakgebaseerde ML-algoritmen) tot uw beschikking.

Vanaf versie 1.4-preview wordt de klasse DatabaseLoader ondersteund, wat betekent dat we nu modellen rechtstreeks kunnen trainen en bouwen tegen relationele databases, waaronder SQL Server, Oracle, PostgreSQL, SQLite en andere.

Voor dit voorbeeld ga ik een model bouwen dat helpt te identificeren of een vrouw diabetes kan ontwikkelen op basis van historische gegevens van andere patiënten. Ik gebruik een Kaggle-dataset die je hier kunt downloaden.

Maak daarna een Patiënt tabel om de informatie op te slaan. De enige vereiste is het gebruik van een echte gegevenstype voor numerieke velden, aangezien ML.NET alleen dit type begrijpt. Een andere optie is om een ​​CAST-bewerking uit te voeren wanneer u de gegevens ophaalt en de velden converteert naar echt on the fly .

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
)

En natuurlijk moet je alle gegevens uit het csv-bestand in de tabel invoegen .

Laten we nu wat code schrijven!

Stap 1. Maak een nieuw C# Console-toepassingsproject:

Stap 2. Voeg de volgende Nuget-pakketten toe aan uw project:

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

Stap 3. Voeg een app-instellingenbestand toe aan uw project.

Voeg in dit bestand een ConnectionStrings . toe verzameling met een DbConnection element. De waarde is natuurlijk de verbindingsreeks met de database waarin uw gegevens zich bevinden.

Ik zal bijvoorbeeld verbinding maken met een Azure SQL-database :

{
  "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;"
  }
}

OPMERKING:stel de Kopieer naar uitvoermap . in eigenschap voor dit bestand, anders wordt het later niet door het programma gelezen.

Stap 4. Voeg een Modellen . toe map naar uw project. Maak binnen een nieuwe klas met de naam Patiënt , die verschillende eigenschappen bevat die overeenkomen met de tabelstructuur. Elke eigenschap is ook versierd met het LoadColumnAttribute met een op nul gebaseerde index die de kolom vertegenwoordigt die wordt toegewezen vanuit de databasetabel.

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; }
    }
}

Stap 5. Voeg een DiabetesMLPrediction toe klasse die van Patiënt erft en aanvullende eigenschappen bevat. Dit wordt gebruikt nadat het machine learning-model is gebouwd om voorspelde gegevens weer te geven:

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; }
    }
}

Stap 6. In de Program.cs bestand:

a. Voeg deze naamruimten toe:

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. Voeg binnen de klas een GetDbConnection . toe methode die de verbindingsreeks extraheert uit de appsettings.json het dossier:

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 de hoofdmethode:

  • Maak een MLContext-instantie
  • Maak een DatabaseLoader-instantie op basis van de klasse Patiënt
  • Bel de GetDbConnection-methode
  • Maak een SQL-instructie die alle gegevens leest (en de id omzet in een echt veld)
  • Maak een DatabaseSource-instantie die gebruikmaakt van de verbindingsreeks en het statement.
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);
  • Laad de gegevens uit de tabel in een IDataView-object en splits het in twee andere IDataViews, een voor training en een andere voor evaluatie:
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;
  • Maak een ITransformer door een trainingspijplijn voor te bereiden die een machineleermodel voor binaire classificatie zal bouwen. Specificeer de kolom die zal worden voorspeld (Output):
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")));
  • Verdeel nu de trainingsdataset in 10 vouwen. 9 vouwen worden gebruikt in training en de resterende vouw wordt gebruikt voor testen. Dit proces wordt 10 keer herhaald, waarbij de trein- en testdatasets worden gewijzigd. Dit proces staat bekend als 10-voudige kruisvalidatie (u kunt het aantal natuurlijk wijzigen). Statistieken worden ook weergegeven:
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($"*************************************************************************************************************");

  • Vervolgens kun je het model trainen door de Fit-methode aan te roepen:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Dit proces duurt enige tijd.

  • Nadat het model is gemaakt, kunt u beginnen met het maken van voorspellingen door een PredictionEngine te bouwen en een patiëntobject door te geven aan de Predict-methode:
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} ");

  • Ten slotte kunt u het model opslaan om het in andere projecten te gebruiken (web-API, Azure Functions, enz.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Stap 7. Voer het programma uit, u krijgt de resultaten en een ML-model klaar voor enkele voorspellingen:

De code is beschikbaar op GitHub.

Ik hoop dat deze blogpost interessant en nuttig voor je was. Ik nodig je uit om mijn blog te bezoeken voor meer technische berichten over Xamarin, Azure en het .NET-ecosysteem . Ik schrijf in de Spaanse taal =)

Bedankt voor uw tijd, en geniet van de rest van de C# Advent Calendar-publicaties!

Tot de volgende keer,
Luis


  1. Een lijst krijgen van alle functies en procedures in een Oracle-database

  2. H2 postgresql-modus lijkt niet te werken voor mij

  3. Wanneer selecteert voor update vergrendelen en ontgrendelen?

  4. SCHEMABINDING verwijderen uit een door de gebruiker gedefinieerde functie in SQL Server