Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Creazione di un modello di machine learning con SQL Server, ML.NET e C#

Questo articolo fa parte dell'iniziativa The Fourth Annual C# Advent Calendar di Matthew D. Groves. Troverai altri utili articoli e tutorial pubblicati quotidianamente dai membri della community e dagli esperti, quindi assicurati di controllarli ogni giorno.

ML.NET è un framework di machine learning gratuito, open source e multipiattaforma progettato per gli sviluppatori .NET. ML.NET ti consente di riutilizzare tutte le conoscenze, le competenze, il codice e le librerie che hai già come sviluppatore .NET in modo da poter integrare facilmente l'apprendimento automatico nelle tue app Web, mobili, desktop, giochi e IoT.

Puoi applicarlo a scenari di classificazione, regressione, serie temporali e persino di visione artificiale (apprendimento profondo, classificazione di immagini) con più di 40 trainer (algoritmi ML basati su attività) a tua disposizione.

Dalla versione 1.4-anteprima in poi, la classe DatabaseLoader è supportata, il che significa che ora possiamo addestrare e creare modelli direttamente su database relazionali, inclusi SQL Server, Oracle, PostgreSQL, SQLite e altri.

Per questo esempio, costruirò un modello che aiuta a identificare se una donna può sviluppare il diabete sulla base dei dati storici di altri pazienti. Sto usando un set di dati Kaggle che puoi scaricare da qui.

Successivamente, crea un Paziente tabella per memorizzare le informazioni. L'unico requisito è utilizzare un reale tipo di dati per i campi numerici, poiché ML.NET comprenderà solo questo tipo. Un'altra opzione consiste nell'eseguire un'operazione CAST quando si recuperano i dati e si convertono i campi in real al volo .

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
)

E, naturalmente, devi inserire tutti i dati dal file CSV nella tabella .

Ora scriviamo un po' di codice!

Passaggio 1. Crea un nuovo progetto di applicazione C# Console:

Passaggio 2. Aggiungi i seguenti pacchetti Nuget al tuo progetto:

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

Passaggio 3. Aggiungi un file delle impostazioni dell'app al tuo progetto.

In questo file, aggiungi un ConnectionStrings raccolta con una DbConnection elemento. Il valore, ovviamente, è la stringa di connessione al database in cui risiedono i tuoi dati.

Ad esempio, mi collegherò a un database SQL di Azure :

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

NOTA:imposta la Copia nella directory di output proprietà per questo file, altrimenti non verrà letto dal programma in seguito.

Passaggio 4. Aggiungi un Modelli cartella nel tuo progetto. All'interno, crea una nuova classe denominata Paziente , che include diverse proprietà che corrispondono alla struttura della tabella. Inoltre, ogni proprietà è decorata con LoadColumnAttribute con un indice in base zero che rappresenta la colonna che verrà mappata dalla tabella del database.

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

Passaggio 5. Aggiungi un DiabetesMLPrediction classe che eredita da Patient e include proprietà aggiuntive. Verrà utilizzato dopo la creazione del modello di apprendimento automatico per mostrare i dati previsti:

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

Passaggio 6. In Program.cs file:

un. Aggiungi questi spazi dei nomi:

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. All'interno della classe, aggiungi un GetDbConnection metodo che estrae la stringa di connessione da appsettings.json file:

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

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

c. Nel metodo principale:

  • Crea un'istanza MLContext
  • Crea un'istanza DatabaseLoader basata sulla classe Patient
  • Chiama il metodo GetDbConnection
  • Prepara un'istruzione SQL che legga tutti i dati (e converta l'id in un campo reale)
  • Prepara un'istanza DatabaseSource che utilizzi la stringa di connessione e l'istruzione.
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);
  • Carica i dati dalla tabella in un oggetto IDataView e dividilo in altri due IDataView, uno per l'addestramento e un altro per la valutazione:
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;
  • Crea un ITransformer preparando una pipeline di formazione che creerà un modello di machine learning di BinaryClassification. Specificare la colonna che verrà prevista (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")));
  • Ora, dividi il set di dati di addestramento in 10 parti. 9 pieghe vengono utilizzate nell'allenamento e la piega rimanente viene utilizzata per i test. Questo processo viene ripetuto 10 volte modificando i set di dati del treno e del test. Questo processo è noto come convalida incrociata 10 volte (ovviamente, puoi modificare il numero). Vengono visualizzate anche le metriche:
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($"*************************************************************************************************************");

  • In seguito, puoi addestrare il modello chiamando il metodo Fit:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Questo processo richiede del tempo.

  • Dopo aver creato il modello, puoi iniziare a fare previsioni creando un PredictionEngine e passando un oggetto Patient al metodo Predict:
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} ");

  • Infine, puoi salvare il modello per usarlo in altri progetti (Web Api, Funzioni di Azure, ecc.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Passaggio 7. Esegui il programma, otterrai i risultati e un modello ML pronto per alcune previsioni:

Il codice è disponibile su GitHub.

Spero che questo post sul blog sia stato interessante e utile per te. Ti invito a visitare il mio blog per ulteriori post tecnici su Xamarin, Azure e l'ecosistema .NET . Scrivo in spagnolo =)

Grazie per il tuo tempo e goditi il ​​resto delle pubblicazioni del Calendario dell'Avvento in C#!

Arrivederci alla prossima,
Luis