Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Construindo um modelo de aprendizado de máquina com SQL Server, ML.NET e C#


Este artigo faz parte da iniciativa The Fourth Annual C# Advent Calendar por Matthew D. Groves. Você encontrará outros artigos e tutoriais úteis publicados diariamente por membros da comunidade e especialistas, portanto, verifique-os todos os dias.

O ML.NET é uma estrutura de aprendizado de máquina gratuita, de código aberto e multiplataforma projetada para desenvolvedores .NET. O ML.NET permite que você reutilize todo o conhecimento, habilidades, código e bibliotecas que você já possui como desenvolvedor .NET para que possa integrar facilmente o aprendizado de máquina em seus aplicativos da Web, dispositivos móveis, desktop, jogos e IoT.



Você pode aplicá-lo para cenários de classificação, regressão, séries temporais e até visão computacional (aprendizagem profunda, classificação de imagens) com mais de 40 treinadores (algoritmos de ML baseados em tarefas) à sua disposição.

A partir da versão 1.4-preview, a classe DatabaseLoader é suportada, o que significa que agora podemos treinar e construir modelos diretamente em bancos de dados relacionais, incluindo SQL Server, Oracle, PostgreSQL, SQLite e outros.

Para este exemplo, vou construir um modelo que ajude a identificar se uma mulher pode desenvolver diabetes com base em dados históricos de outros pacientes. Estou usando um conjunto de dados Kaggle que você pode baixar aqui.



Depois disso, crie um Paciente tabela para armazenar as informações. O único requisito é usar um real tipo de dados para campos numéricos, pois o ML.NET só entenderá esse tipo. Outra opção é realizar uma operação CAST quando você recupera os dados e converte os campos em reais 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
)

E, claro, você precisa inserir todos os dados do arquivo csv na tabela .

Agora, vamos escrever algum código!

Etapa 1. Crie um novo projeto de aplicativo C# Console:



Etapa 2. Adicione os seguintes pacotes Nuget ao seu projeto:
  • Microsoft.ML
  • System.Data.SqlClient
  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.Json
  • Microsoft.Extensions.Configuration.FileExtensions



Etapa 3. Adicione um arquivo de configurações do aplicativo ao seu projeto.



Nesse arquivo, adicione um ConnectionStrings coleção com um DbConnection elemento. O valor, é claro, é a string de conexão com o banco de dados onde seus dados residem.

Por exemplo, vou me conectar a um banco de dados SQL do 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;"
  }
}

OBSERVAÇÃO:defina o diretório Copiar para saída propriedade para este arquivo, caso contrário, ele não será lido pelo programa posteriormente.

Etapa 4. Adicione um Modelos pasta para o seu projeto. Dentro, crie uma nova classe chamada Paciente , que inclui várias propriedades que correspondem à estrutura Table. Além disso, cada propriedade é decorada com o LoadColumnAttribute com um índice baseado em zero que representa a coluna que será mapeada da tabela do banco de dados.

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


Etapa 5. Adicione uma DiabetesMLPrediction classe que herda de Paciente e inclui propriedades adicionais. Isso será usado depois que o modelo de aprendizado de máquina for construído, para mostrar os dados previstos:

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

Etapa 6. No Program.cs Arquivo:

uma. Adicione estes namespaces:

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. Dentro da classe, adicione um GetDbConnection método que extrai a string de conexão do appsettings.json Arquivo:

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

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

c. No método Main:
  • Criar uma instância MLContext
  • Crie uma instância do DatabaseLoader com base na classe Patient
  • Chame o método GetDbConnection
  • Prepare uma instrução SQL que leia todos os dados (e converta o id em um campo real)
  • Prepare uma instância DatabaseSource que use a string de conexão e a instrução.
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);
  • Carregue os dados da tabela em um objeto IDataView e divida-o em dois outros IDataViews, um para treinamento e outro para avaliação:
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;
  • Crie um ITransformer preparando um pipeline de treinamento que criará um modelo de aprendizado de máquina BinaryClassification. Especifique a coluna que será prevista (Saída):
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")));
  • Agora, divida o conjunto de dados de treinamento em 10 partes. 9 dobras são usadas no treinamento e a dobra restante é usada para teste. Esse processo é repetido 10 vezes, alterando os conjuntos de dados de trem e teste. Esse processo é conhecido como validação cruzada de 10 vezes (é claro, você pode alterar o número). As métricas também são exibidas:
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($"*************************************************************************************************************");

  • Em seguida, você pode treinar o modelo chamando o método Fit:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Este processo leva algum tempo.
  • Depois que o modelo é criado, você pode começar a fazer previsões criando um PredictionEngine e passando um objeto Paciente para o método 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} ");

  • Finalmente, você pode salvar o modelo para usá-lo em outros projetos (Web Api, Azure Functions, etc.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Etapa 7. Execute o programa, você obterá os resultados e um modelo de ML pronto para algumas previsões:





O código está disponível no GitHub.

Espero que este post do blog tenha sido interessante e útil para você. Convido você a visitar meu blog para mais postagens técnicas sobre Xamarin, Azure e o ecossistema .NET . Escrevo em espanhol =)

Obrigado pelo seu tempo e aproveite o restante das publicações do C# Advent Calendar!

Vejo você na próxima vez,
Luís