Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Construire un modèle d'apprentissage automatique avec SQL Server, ML.NET et C#

Cet article fait partie de l'initiative The Fourth Annual C# Advent Calendar de Matthew D. Groves. Vous y trouverez d'autres articles et tutoriels utiles publiés quotidiennement par des membres de la communauté et des experts, alors assurez-vous de les consulter tous les jours.

ML.NET est un framework d'apprentissage automatique gratuit, open source et multiplateforme conçu pour les développeurs .NET. ML.NET vous permet de réutiliser toutes les connaissances, compétences, codes et bibliothèques dont vous disposez déjà en tant que développeur .NET afin que vous puissiez facilement intégrer l'apprentissage automatique dans vos applications Web, mobiles, de bureau, de jeux et IoT.

Vous pouvez l'appliquer à des scénarios de classification, de régression, de séries chronologiques et même de vision par ordinateur (apprentissage profond, classification d'images) avec plus de 40 formateurs (algorithmes de ML basés sur des tâches) à votre disposition.

À partir de la version 1.4-preview, la classe DatabaseLoader est prise en charge, ce qui signifie que nous pouvons désormais former et créer des modèles directement sur des bases de données relationnelles, notamment SQL Server, Oracle, PostgreSQL, SQLite et autres.

Pour cet exemple, je vais construire un modèle qui aide à identifier si une femme peut développer un diabète sur la base des données historiques d'autres patients. J'utilise un jeu de données Kaggle que vous pouvez télécharger ici.

Après cela, créez un Patient table pour stocker les informations. La seule exigence est d'utiliser un réel type de données pour les champs numériques, car ML.NET ne comprendra que ce type. Une autre option consiste à effectuer une opération CAST lorsque vous récupérez les données et convertissez les champs en réels à la volée .

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
)

Et bien sûr, vous devez insérer toutes les données du fichier csv dans le tableau .

Maintenant, écrivons du code !

Étape 1. Créez un nouveau projet d'application de console C# :

Étape 2. Ajoutez les packages Nuget suivants à votre projet :

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

Étape 3. Ajoutez un fichier de paramètres d'application à votre projet.

Dans ce fichier, ajoutez un ConnectionStrings collection avec une DbConnection élément. La valeur, bien sûr, est la chaîne de connexion à la base de données où résident vos données.

Par exemple, je vais me connecter à une base de données Azure SQL :

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

REMARQUE :Définissez le Copier dans le répertoire de sortie propriété pour ce fichier, sinon il ne sera pas lu par le programme plus tard.

Étape 4. Ajouter un modèles dossier à votre projet. À l'intérieur, créez une nouvelle classe nommée Patient , qui comprend plusieurs propriétés qui correspondent à la structure Table. De plus, chaque propriété est décorée avec le LoadColumnAttribute avec un index de base zéro qui représente la colonne qui sera mappée à partir de la table de base de données.

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

Étape 5. Ajouter une DiabetesMLPrediction classe qui hérite de Patient et inclut des propriétés supplémentaires. Cela sera utilisé après la construction du modèle d'apprentissage automatique, pour afficher les données prédites :

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

Étape 6. Dans Program.cs fichier :

un. Ajoutez ces espaces de noms :

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. Dans la classe, ajoutez un GetDbConnection méthode qui extrait la chaîne de connexion de appsettings.json 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. Dans la méthode Main :

  • Créer une instance MLContext
  • Créer une instance DatabaseLoader basée sur la classe Patient
  • Appelez la méthode GetDbConnection
  • Préparez une instruction SQL qui lit toutes les données (et convertit l'identifiant en un champ réel)
  • Préparez une instance DatabaseSource qui utilise la chaîne de connexion et l'instruction.
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);
  • Chargez les données de la table dans un objet IDataView et divisez-le en deux autres IDataViews, un pour la formation et un autre pour l'évaluation :
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;
  • Créez un ITransformer en préparant un pipeline de formation qui créera un modèle de machine learning BinaryClassification. Spécifiez la colonne qui sera prédite (Sortie) :
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")));
  • Maintenant, divisez l'ensemble de données d'entraînement en 10 plis. 9 plis sont utilisés pour l'entraînement et le pli restant est utilisé pour les tests. Ce processus est répété 10 fois en modifiant les ensembles de données d'apprentissage et de test. Ce processus est connu sous le nom de validation croisée 10 fois (bien sûr, vous pouvez modifier le nombre). Les statistiques sont également affichées :
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($"*************************************************************************************************************");

  • Ensuite, vous pouvez entraîner le modèle en appelant la méthode Fit :
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Ce processus prend un certain temps.

  • Une fois le modèle créé, vous pouvez commencer à faire des prédictions en créant un PredictionEngine et en transmettant un objet Patient à la méthode 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} ");

  • Enfin, vous pouvez enregistrer le modèle pour l'utiliser dans d'autres projets (Web Api, Azure Functions, etc.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Étape 7. Exécutez le programme, vous obtiendrez les résultats et un modèle ML prêt pour certaines prédictions :

Le code est disponible sur GitHub.

J'espère que ce billet de blog a été intéressant et utile pour vous. Je vous invite à visiter mon blog pour des articles plus techniques sur Xamarin, Azure et l'écosystème .NET . J'écris en espagnol =)

Merci pour votre temps et profitez du reste des publications du calendrier de l'Avent C# !

À la prochaine,
Luis