Ten artykuł jest częścią inicjatywy Matthew D. Grovesa Czwarty doroczny kalendarz adwentowy C#. Znajdziesz tam inne pomocne artykuły i samouczki publikowane codziennie przez członków społeczności i ekspertów, więc sprawdzaj je codziennie.
ML.NET to bezpłatna, otwarta i wieloplatformowa platforma uczenia maszynowego przeznaczona dla programistów .NET. ML.NET umożliwia ponowne wykorzystanie całej wiedzy, umiejętności, kodu i bibliotek, które już posiadasz jako programista .NET, dzięki czemu możesz łatwo zintegrować uczenie maszynowe z aplikacjami internetowymi, mobilnymi, komputerowymi, grami i aplikacjami IoT.
Możesz go zastosować do scenariuszy klasyfikacji, regresji, szeregów czasowych, a nawet wizji komputerowej (uczenie głębokie, klasyfikacja obrazów) z ponad 40 trenerami (algorytmy ML oparte na zadaniach) do Twojej dyspozycji.
Począwszy od wersji 1.4-preview, obsługiwana jest klasa DatabaseLoader, co oznacza, że teraz możemy trenować i budować modele bezpośrednio na relacyjnych bazach danych, w tym SQL Server, Oracle, PostgreSQL, SQLite i innych.
Na potrzeby tego przykładu zamierzam zbudować model, który pomoże określić, czy kobieta może zachorować na cukrzycę na podstawie danych historycznych od innych pacjentów. Używam zestawu danych Kaggle, który możesz pobrać stąd.
Następnie utwórz pacjenta tabeli do przechowywania informacji. Jedynym wymaganiem jest użycie prawdziwego typ danych dla pól liczbowych, ponieważ ML.NET zrozumie tylko ten typ. Inną opcją jest wykonanie operacji CAST podczas pobierania danych i konwertowania pól na rzeczywiste w locie .
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
)
I oczywiście musisz wstawić wszystkie dane z pliku csv do tabeli .
Teraz napiszmy trochę kodu!
Krok 1. Utwórz nowy projekt aplikacji C# Console:
Krok 2. Dodaj następujące pakiety Nuget do swojego projektu:
- Microsoft.ML
- System.Data.SqlClient
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.Configuration.FileExtensions
Krok 3. Dodaj plik ustawień aplikacji do swojego projektu.
W tym pliku dodaj ConnectionStrings kolekcja z DbConnection element. Wartością jest oczywiście ciąg połączenia z bazą danych, w której znajdują się Twoje dane.
Na przykład połączę się z bazą danych 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;"
}
}
UWAGA:Ustaw Kopiuj do katalogu wyjściowego dla tego pliku, w przeciwnym razie nie zostanie on później odczytany przez program.
Krok 4. Dodaj Modele folder do swojego projektu. Wewnątrz utwórz nową klasę o nazwie Pacjent , który zawiera kilka właściwości zgodnych ze strukturą Table. Ponadto każda właściwość jest ozdobiona LoadColumnAttribute z indeksem liczonym od zera, który reprezentuje kolumnę, która zostanie zmapowana z tabeli bazy danych.
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; }
}
}
Krok 5. Dodaj Przewidywanie cukrzycy klasa, która dziedziczy po Patient i zawiera dodatkowe właściwości. Będzie to używane po zbudowaniu modelu uczenia maszynowego, aby wyświetlić przewidywane dane:
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; }
}
}
Krok 6. W Program.cs plik:
a. Dodaj te przestrzenie nazw:
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. Wewnątrz klasy dodaj GetDbConnection metoda, która wyodrębnia parametry połączenia z pliku appsettings.json plik:
private static string GetDbConnection()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
return builder.Build().GetConnectionString("DbConnection");
}
c. W metodzie głównej:
- Utwórz instancję MLContext
- Utwórz instancję DatabaseLoader na podstawie klasy Patient
- Wywołaj metodę GetDbConnection
- Przygotuj instrukcję SQL, która odczytuje wszystkie dane (i konwertuje identyfikator na rzeczywiste pole)
- Przygotuj instancję DatabaseSource, która używa ciągu połączenia i instrukcji.
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);
- Załaduj dane z tabeli do obiektu IDataView i podziel je na dwa inne IDataViews, jeden do trenowania, a drugi do oceny:
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;
- Utwórz ITransformer, przygotowując potok szkolenia, który zbuduje model uczenia maszynowego BinaryClassification. Określ kolumnę, która będzie przewidywana (wyjście):
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")));
- Teraz podziel treningowy zestaw danych na 10 części. 9 fałd jest wykorzystywanych w treningu, a pozostała fałda jest wykorzystywana do testowania. Ten proces jest powtarzany 10 razy, zmieniając zestawy danych pociągu i testu. Ten proces jest znany jako 10-krotna weryfikacja krzyżowa (oczywiście możesz zmienić liczbę). Wyświetlane są również dane:
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($"*************************************************************************************************************");
- Następnie możesz trenować model, wywołując metodę Fit:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");
Ten proces zajmuje trochę czasu.
- Po utworzeniu modelu możesz rozpocząć tworzenie prognoz, budując PredictionEngine i przekazując obiekt Patient do metody 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} ");
- Na koniec możesz zapisać model, aby użyć go w innych projektach (Web Api, Azure Functions itp.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");
Krok 7. Uruchom program, otrzymasz wyniki i model ML gotowy na pewne prognozy:
Kod jest dostępny na GitHub.
Mam nadzieję, że ten wpis na blogu był dla Ciebie interesujący i przydatny. Zapraszam do odwiedzenia mojego bloga, gdzie znajdziesz więcej technicznych postów na temat Xamarin, Azure i ekosystemu .NET . Piszę po hiszpańsku =)
Dziękujemy za poświęcony czas i ciesz się resztą publikacji kalendarza adwentowego C#!
Do zobaczenia następnym razem,
Luis