Main project: SmartBrew.WebApp (Blazor) Primary NuGet:
Microsoft.MLOfficial site: dot.net/ml
Table of Contents
- Module 1 — Understanding Machine Learning and ML.NET
- Module 2 — Using Data Classification
- Module 3 — Working with Image Classification
- ML.NET In-Depth Technical Reference
- Model Builder Generated Code — Detailed Analysis
- Key Concepts and Quick Reference
- Overall Project Architecture
Module 1 — Understanding Machine Learning and ML.NET
What is Machine Learning?
Machine learning (ML) is a branch of artificial intelligence (AI). It allows machines to learn and perform tasks autonomously. In other words, machine learning allows us to program the unprogrammable.
Problems Difficult to Solve with Traditional Programming
With traditional programming (if/else, switch, while/foreach loops), certain questions are very difficult to handle:
| Question | ML Problem Type |
|---|---|
| Is there a coffee cup in this image? | Image classification |
| What language is this text written in? | Data / text classification |
| Is this review negative? | Binary classification (sentiment) |
| What should this product’s price be? | Regression |
| Does this X-ray show a fracture? | Medical image classification |
| Is this bank transaction fraudulent? | Anomaly detection |
| Which product should we recommend to this user? | Recommendation |
Key concept: With machine learning, you provide data and an algorithm — the machine learns the rules. In contrast to traditional programming where you write the rules manually.
The Machine Learning Workflow
flowchart LR
A[Define the problem] --> B[Prepare the data]
B --> C[Choose a training\nalgorithm]
C --> D[Tune the parameters\nhyperparameter tuning]
D --> E[Evaluate the model]
E -->|Model insufficient| C
E -->|Model satisfactory| F[Deploy and use]
- Define the problem: What is the prediction objective?
- Prepare the data: Collect and clean the training data.
- Choose a training algorithm: Select from many available algorithms.
- Tune parameters (hyperparameter tuning): Optimize the algorithm.
- Evaluate the model: Measure performance on unseen data (validation data).
Understanding ML.NET
ML.NET is an open-source machine learning framework for .NET developers.
Key Characteristics
| Characteristic | Detail |
|---|---|
| NuGet package | Microsoft.ML |
| Execution | Offline (cloud and on-premises) |
| Cross-platform | Windows, Linux, macOS (anywhere .NET runs) |
| Architectures | 64-bit (all platforms), 32-bit Windows (except TensorFlow/ONNX/LightGBM) |
| Official site | dot.net/ml |
| Pre-trained models | ONNX and TensorFlow support in addition to custom models |
Basic ML.NET Workflow in Code
// 1. Create the ML context (central entry point)
var mlContext = new MLContext(seed: 42);
// 2. Load training data into an IDataView
IDataView trainingData = mlContext.Data.LoadFromTextFile<ModelInput>(
path: "languageDetection.csv",
hasHeader: true,
separatorChar: ',');
// 3. Build the processing and training pipeline
var pipeline = mlContext.Transforms.Text.FeaturizeText("Features", "Text")
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(
labelColumnName: "Language",
featureColumnName: "Features"))
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
// 4. Train the model (call Fit())
ITransformer model = pipeline.Fit(trainingData);
// 5. Use the model to make predictions
var predictionEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(model);
var prediction = predictionEngine.Predict(new ModelInput { Text = "I love coffee!" });
Console.WriteLine(prediction.PredictedLabel); // "English"
Note: Without AutoML or Model Builder, choosing the right training algorithm requires machine learning expertise. For example, for binary classification (classifying data into two categories: 0 or 1), ML.NET offers many different algorithms.
Full Example — Linear Regression (House Prices)
using Microsoft.ML;
using Microsoft.ML.Data;
// Data models
public record HouseData
{
public float SquareFootage { get; set; }
public float Price { get; set; }
}
public record Prediction
{
[ColumnName("Score")]
public float Price { get; set; }
}
// Program
var mlContext = new MLContext();
// Training data
HouseData[] houseData = [
new() { SquareFootage = 1.1F, Price = 1.2F },
new() { SquareFootage = 1.9F, Price = 2.3F },
new() { SquareFootage = 2.8F, Price = 3.0F },
new() { SquareFootage = 3.4F, Price = 3.7F }
];
IDataView trainingData = mlContext.Data.LoadFromEnumerable(houseData);
// Pipeline: Concatenate features + SDCA trainer
var pipeline = mlContext.Transforms.Concatenate("Features", ["SquareFootage"])
.Append(mlContext.Regression.Trainers.Sdca(
labelColumnName: "Price",
maximumNumberOfIterations: 100));
// Training
var model = pipeline.Fit(trainingData);
// Prediction
var predEngine = mlContext.Model.CreatePredictionEngine<HouseData, Prediction>(model);
var price = predEngine.Predict(new HouseData { SquareFootage = 2.5F });
Console.WriteLine($"Predicted price: {price.Price * 100:C}k"); // ~261.98k
// Evaluation
var metrics = mlContext.Regression.Evaluate(model.Transform(trainingData), labelColumnName: "Price");
Console.WriteLine($"R2: {metrics.RSquared:0.##}");
Console.WriteLine($"RMS error: {metrics.RootMeanSquaredError:0.##}");
// Save
mlContext.Model.Save(model, trainingData.Schema, "model.zip");
ML.NET Internal Architecture
MLContext — Central Catalog
The MLContext object is the singleton entry point for ML.NET. It exposes catalogs which are component factories:
| Catalog | C# Type | Role |
|---|---|---|
Data | DataOperationsCatalog | Loading and saving data |
Transforms | TransformsCatalog | Data preparation and transformation |
BinaryClassification | BinaryClassificationCatalog | Binary classification tasks |
MulticlassClassification | MulticlassClassificationCatalog | Multiclass classification tasks |
Regression | RegressionCatalog | Regression tasks |
AnomalyDetection | AnomalyDetectionCatalog | Anomaly detection |
Clustering | ClusteringCatalog | Data clustering |
Forecasting | ForecastingCatalog | Time series forecasting |
Ranking | RankingCatalog | Ranking |
Recommendation | RecommendationCatalog | Recommendation systems |
Model | ModelOperationsCatalog | Creating PredictionEngine, saving/loading |
graph TD
CTX["MLContext\n(singleton)"]
CTX --> DATA["Data\n(DataOperationsCatalog)"]
CTX --> TRANS["Transforms\n(TransformsCatalog)"]
CTX --> BIN["BinaryClassification"]
CTX --> MULTI["MulticlassClassification"]
CTX --> REG["Regression"]
CTX --> ANOM["AnomalyDetection"]
CTX --> CLUST["Clustering"]
CTX --> MOD["Model\n(save/load/predict)"]
IDataView — Lazy Data View
IDataView is the central interface for representing data in ML.NET. It is lazily evaluated: data is only loaded and processed when needed.
// Load from a CSV file
IDataView dataView = mlContext.Data.LoadFromTextFile<ModelInput>(
path: "data.csv",
hasHeader: true,
separatorChar: ',');
// Load from an in-memory collection
IDataView dataView2 = mlContext.Data.LoadFromEnumerable(myList);
// Preview for debugging (DO NOT use in production)
var debug = dataView.Preview();
IDataView characteristics:
- Named columns with types and lengths
- Lazy evaluation: loading only happens during
Fit()orTransform() - All ML.NET algorithms expect a vector column named
Features
Pipeline: IEstimator and ITransformer
flowchart LR
EST["IEstimator\n(before training)\nDefines operations"]
IDATAVIEW["IDataView\n(training data)"]
FIT["pipeline.Fit(data)"]
TRANS["ITransformer\n(after training)\nContains learned parameters"]
EST --> FIT
IDATAVIEW --> FIT
FIT --> TRANS
TRANS -->|"Transform(data)"| PRED["IDataView\n(predictions)"]
| Interface | Timing | Description |
|---|---|---|
IEstimator<T> | Before training | Defines the pipeline operations |
ITransformer | After training | The trained model with its parameters |
// pipeline is an IEstimator
var pipeline = mlContext.Transforms.Concatenate("Features", ["SquareFootage"])
.Append(mlContext.Regression.Trainers.Sdca(labelColumnName: "Price"));
// model is an ITransformer (after Fit)
ITransformer model = pipeline.Fit(trainingData);
// Use the transformer to make bulk predictions
IDataView predictions = model.Transform(inputData);
AutoML and Model Builder
AutoML
AutoML (Automated Machine Learning) automates the complex steps of the ML workflow:
flowchart LR
DEV[".NET Developer\n(you)"] -->|Defines| P["Problem"]
DEV -->|Prepares| D["Data"]
P --> AUTO["AutoML\n(Microsoft.ML.AutoML)"]
D --> AUTO
AUTO -->|Automatically chooses| A["Training algorithm"]
AUTO -->|Automatically tunes| H["Hyperparameters"]
AUTO -->|Evaluates and selects| M["Best final model"]
| Step | Responsible |
|---|---|
| Define the problem | You |
| Prepare the data | You |
| Choose an algorithm | AutoML |
| Tune parameters | AutoML |
| Evaluate the model | AutoML |
NuGet: Microsoft.ML.AutoML (depends on Microsoft.ML)
Model Builder
Model Builder is a Visual Studio extension built on AutoML and ML.NET.
graph TD
MB["Model Builder\n(Visual Studio Extension)"]
AUTO["AutoML\n(Microsoft.ML.AutoML)"]
MLNET["ML.NET\n(Microsoft.ML)"]
MB --> AUTO
AUTO --> MLNET
Model Builder Workflow in Visual Studio
flowchart LR
S1["1. Scenario\n(what type of ML?)"] --> S2["2. Environment\n(CPU / GPU / Azure)"]
S2 --> S3["3. Data\n(CSV / SQL / Images)"]
S3 --> S4["4. Training\n(AutoML explores)"]
S4 --> S5["5. Evaluation\n(test the model)"]
S5 --> S6["6. Consumption\n(generated C# code)"]
Environment Setup
Prerequisites
- Visual Studio 2022 (Community, Professional, or Enterprise)
- Workload: ASP.NET and web development
- Extension: ML.NET Model Builder 2022
Verifying the Installation
- Open Visual Studio Installer
- Click Modify on Visual Studio 2022
- Workloads tab → verify ASP.NET and web development
- Individual components tab → search
ML.NET→ verify ML.NET Model Builder 2022
Warning: There are two extensions — VS 2019 (without the “2022” suffix) and VS 2022. Make sure to have the 2022 version.
Exploring the Starter Project
The SmartBrew.WebApp project is a Blazor application representing the fictional company Smart Brew Coffee.
Application Structure
SmartBrew.WebApp/
+-- Components/
| +-- Pages/
| +-- LanguageDetection.razor <- Scenario 1: Data classification
| +-- BeverageDetection.razor <- Scenario 2: Image classification
+-- (other Blazor files)
Two ML Scenarios to Implement
| Scenario | ML Type | Goal |
|---|---|---|
| Language detection | Data classification | Detect the language of entered text |
| Beverage detection | Image classification | Detect whether an image contains a coffee beverage |
Difference: Data Classification vs Text Classification
| Data classification | Text classification | |
|---|---|---|
| Data | Tabular data (numbers + text) | Raw text only |
| Example | Detect a language, classify GitHub issues | Sentiment analysis |
| Flexibility | More flexible | Text-specialized |
Module 2 — Using Data Classification
Understanding the Task: Language Detection
The goal is to automatically detect the language of input text. Target languages: English, French, German, Italian (then Spanish after retraining).
Training Data
The file languageDetection.csv contains two columns:
Language,Message
German,"Ich lerne gerne Deutsch"
French,"J aime apprendre le francais"
Italian,"Mi piace imparare l italiano"
English,"I like learning new languages"
German,"Ich liebe Kaffee"
French,"J aime le cafe"
Italian,"Mi piace il caffe"
English,"I love coffee"
| Column | ML Role | Description |
|---|---|---|
Language | Label | Value to predict |
Message | Feature | Data used for the prediction |
ML advantage: To add new languages, simply retrain the model with new data — no need to modify the application code.
Creating a Model Builder Configuration File
Steps in Visual Studio
- Right-click the project in Solution Explorer
- Add → Machine Learning Model…
- Select Machine Learning Model (ML.NET) type
- Name it:
LanguageDetectionModel→ Add
Generated File: .mbconfig
The .mbconfig file is a JSON file:
{
"Scenario": "Classification",
"DataSource": {
"Type": "TabularFile",
"FilePath": "languageDetection.csv",
"Delimiter": ",",
"DecimalMarker": ".",
"HasHeader": true,
"ColumnProperties": [
{ "ColumnName": "Language", "Purpose": "Label", "Type": "String" },
{ "ColumnName": "Message", "Purpose": "Feature", "Type": "String" }
]
},
"Environment": { "Type": "LocalCPU" },
"MLConfig": {
"TrainingTime": 20,
"Scenario": { "Type": "Classification", "LabelColumnName": "Language" }
}
}
Selecting a Scenario
Scenario Types in Model Builder
| Category | Scenarios | Status | Environments |
|---|---|---|---|
| Tabular | Data classification | Stable | Local CPU |
| Tabular | Value prediction (regression) | Stable | Local CPU |
| Tabular | Recommendation | Stable | Local CPU |
| Computer Vision | Image classification | Stable | CPU / GPU / Azure |
| Computer Vision | Object detection | Preview | CPU / Azure |
| NLP | Text classification | Preview | CPU / Azure |
For Language Detection
- Selected scenario: Data classification
- Environment: Local (CPU) — the only available option for this scenario
Specifying Training Data
Supported Data Sources
flowchart LR
DS["Data Source\nModel Builder"] --> F["CSV / TSV File\n(TabularFile)"]
DS --> SQL["SQL Server Table\n(SqlServerTable)"]
Column Settings — Purposes
| Purpose | Description | Example |
|---|---|---|
| Label | Column to predict — only one per dataset | Language |
| Feature | Column used for prediction | Message |
| Ignore | Column not used | RowId |
Default split: 80% training / 20% validation
Training the Model
Training Parameters
| Parameter | Value |
|---|---|
| Scenario | Data classification |
| Environment | Local (CPU) |
| Data | languageDetection.csv |
| Training time | 20 seconds |
AutoML Process
flowchart TD
START["Click: Start Training"] --> EXPLORE["AutoML explores different\ntraining algorithms"]
EXPLORE --> EVAL["Evaluation of each algorithm\n(accuracy, F1-score, macro accuracy...)"]
EVAL --> BEST["Best model selected\ne.g.: LbfgsMaximumEntropyMulti"]
BEST --> GEN["Generated:\n- model.mlnet (binary)\n- .consumption.cs\n- .training.cs"]
Example result: 69 models explored in 18.9 seconds → best model:
LbfgsMaximumEntropyMulti
Files Generated After Training
SmartBrew.WebApp/
+-- LanguageDetectionModel.mbconfig
+-- LanguageDetectionModel.mlnet <- Trained model (binary, zip format)
+-- LanguageDetectionModel.training.cs <- C# code for retraining
+-- LanguageDetectionModel.consumption.cs <- C# code for using the model
Advanced Training Options
| Option | Description |
|---|---|
| Optimization metric | Measure used to select the best model (e.g., Macro Accuracy) |
| Include/exclude algorithms | Exclude poorly-performing algorithms |
| AutoML hyperparameter tuners | SMAC, CostFrugal… configuration |
| Stop/sample strategies | Control of exploration stopping |
Evaluating the Model
| Test message | Predicted language | Probability |
|---|---|---|
| ”I like learning new languages” | English | 86% |
| “Ich lerne gerne Deutsch” | German | 90% |
| “J aime apprendre le francais” | French | 56% |
If the model doesn’t perform well:
- Increase the training time
- In Advanced training options → Trainers, exclude poorly-performing algorithms
- Add more training data (more CSV rows)
Consuming the Model in the Application
Code Generated by Model Builder
// LanguageDetection.razor — @code block
private string? detectedLanguage;
private void TextChanged(string? text)
{
if (string.IsNullOrEmpty(text))
{
detectedLanguage = null;
return;
}
// 1. Create the input object (the features)
var input = new LanguageDetectionModel.ModelInput()
{
Message = text,
};
// 2. Call Predict() — returns the best label
var output = LanguageDetectionModel.Predict(input);
// 3. Retrieve the predicted label
detectedLanguage = output.PredictedLabel;
}
Full Data Flow — Data Classification
sequenceDiagram
participant U as User
participant B as Blazor Component
participant M as LanguageDetectionModel
U->>B: Types text in the TextArea
B->>B: TextChanged(text) fires
B->>B: new ModelInput { Message = text }
B->>M: LanguageDetectionModel.Predict(input)
note over M: Internal pipeline:\n1. FeaturizeText\n2. LbfgsMaximumEntropy\n3. MapKeyToValue
M-->>B: ModelOutput { PredictedLabel: "English" }
B->>U: Displays "Detected language: English"
Predicting All Labels
// LanguageDetection.razor — complete @code block
private string? detectedLanguage;
private IOrderedEnumerable<KeyValuePair<string, float>>? allLabels;
private void TextChanged(string? text)
{
if (string.IsNullOrEmpty(text))
{
detectedLanguage = null;
allLabels = null;
return;
}
var input = new LanguageDetectionModel.ModelInput { Message = text };
// Predict the best label
var output = LanguageDetectionModel.Predict(input);
detectedLanguage = output.PredictedLabel;
// All labels with their scores (sorted descending)
allLabels = LanguageDetectionModel.PredictAllLabels(input);
}
Blazor Template
<div>Detected language: @detectedLanguage</div>
@if (allLabels != null)
{
<ul>
@foreach (var label in allLabels)
{
<li>@label.Key : @(label.Value.ToString("P0"))</li>
}
</ul>
}
Note:
floatbetween 0 and 1.PredictAllLabels()returnsIOrderedEnumerable<KeyValuePair<string, float>>sorted by descending score.
Retraining the Model
To add new languages (e.g., Spanish), simply modify the training data and retrain — without changing the application code.
Retraining Process
flowchart LR
A["Add rows\n(Spanish in CSV)"] --> B["Save the CSV"]
B --> C["Model Builder -> Train tab"]
C --> D["Click Train again"]
D --> E["AutoML re-explores\nthe algorithms"]
E --> F["New model\ne.g.: SdcaMaximumEntropyMulti"]
F --> G[".mlnet and .cs files\nautomatically updated"]
Example Spanish Data Added
Spanish,"Me gusta aprender idiomas nuevos"
Spanish,"Hola, como estas?"
Spanish,"Bienvenido a Smart Brew Coffee"
Spanish,"El cafe es delicioso"
Spanish,"Me encanta el machine learning"
Spanish,"Estoy aprendiendo con esta plataforma"
Result After Retraining
| Before | After |
|---|---|
LbfgsMaximumEntropyMulti | SdcaMaximumEntropyMulti |
| 4 languages (EN/FR/DE/IT) | 5 languages + Spanish |
| C# code unchanged | C# code unchanged |
Module 3 — Working with Image Classification
Understanding the Task: Beverage Detection
The goal is to automatically detect the content of an image across three categories: coffee, goat, other.
Training Data
Images/
+-- coffee/ <- 15 coffee images
+-- goat/ <- 6 goat images
+-- other/ <- 7 images of other subjects
Selecting the Scenario and Configuring the GPU
Available Environments for Image Classification
| Environment | Description | Performance |
|---|---|---|
| Local (CPU) | Standard processor | Slow |
| Local (GPU) | NVIDIA GPU with CUDA | Fast |
| Azure | Microsoft cloud | Variable |
GPU Configuration (NVIDIA CUDA)
graph TD
GPU["NVIDIA GPU\n(CUDA-compatible)"]
CUDA["CUDA 10.1\nCompute Unified Device Architecture"]
CUDNN["cuDNN 7.6.4\nCUDA Deep Neural Network library"]
MLVISION["Microsoft.ML.Vision\n(NuGet — auto-installed)"]
GPU --> CUDA
CUDA --> CUDNN
CUDNN --> MLVISION
| Component | Required Version | Role |
|---|---|---|
| CUDA | 10.1 (exactly) | Framework for GPU access |
| cuDNN | 7.6.4 (exactly) | Deep neural networks library |
Microsoft.ML.Vision | Auto-installed | ML.NET NuGet for vision |
CUDA = framework allowing developers to access the raw computing power of the GPU cuDNN = library built on CUDA providing primitives for deep neural networks
Specifying Image Training Data
Required Folder Structure
Model Builder expects each subfolder to be a label for the images it contains:
Images/ <- root folder selected
+-- coffee/ <- label "coffee" (15 images)
+-- goat/ <- label "goat" (6 images)
+-- other/ <- label "other" (7 images)
Data Split
| Parameter | Default value |
|---|---|
| Training data | 80% of images |
| Validation data | 20% of images |
Training the Image Model
Configuration Summary
| Parameter | Value |
|---|---|
| Scenario | Image classification |
| Environment | Local (GPU) |
| Data | Images/ folder |
Automatically Installed NuGet Packages
<PackageReference Include="Microsoft.ML" />
<PackageReference Include="Microsoft.ML.Vision" />
<PackageReference Include="Microsoft.ML.ImageAnalytics" />
Generated Files
SmartBrew.WebApp/
+-- BeverageDetectionModel.mbconfig
+-- BeverageDetectionModel.mlnet <- Trained model (binary)
+-- BeverageDetectionModel.training.cs <- Retraining code
+-- BeverageDetectionModel.consumption.cs <- Consumption code
Difference: For Image classification, Model Builder does not generate a separate evaluation file.
Evaluating the Image Model
| Tested image | Prediction | Probability |
|---|---|---|
| Coffee image (training data) | coffee | 100% |
| Person drinking a coffee | coffee | 97% |
| Goat image (training data) | goat | 97% |
| Smart Brew Coffee logo (cup) | coffee | 82% |
| Portrait photo | other | 62% |
Recommendation: Test the model with images not present in the training data to get a realistic evaluation.
Consuming the Image Model in the Application
Implementation in BeverageDetection.razor
// BeverageDetection.razor — @code block
private string detectedContent = "None";
private async Task LoadFileAsync(InputFileChangeEventArgs e)
{
// 1. Read image file -> byte[]
var file = e.File;
using var stream = file.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024);
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
byte[] imageData = memoryStream.ToArray();
// 2. Create model input (ImageSource = byte[])
var input = new BeverageDetectionModel.ModelInput()
{
ImageSource = imageData,
};
// 3. Call Predict()
var output = BeverageDetectionModel.Predict(input);
// 4. Assign the predicted label
detectedContent = output.PredictedLabel; // "coffee", "goat", or "other"
}
ModelInput / ModelOutput Classes for Image Classification
public class ModelInput
{
// Image as a byte array
public byte[] ImageSource { get; set; }
}
public class ModelOutput
{
[ColumnName("PredictedLabel")]
public string PredictedLabel { get; set; }
// Scores for each label (between 0 and 1, sum = 1)
public float[] Score { get; set; }
}
Data Flow — Image Classification
sequenceDiagram
participant U as User
participant B as BeverageDetection.razor
participant M as BeverageDetectionModel
U->>B: Selects an image
B->>B: file.OpenReadStream() -> byte[]
B->>B: new ModelInput { ImageSource = bytes }
B->>M: BeverageDetectionModel.Predict(input)
note over M: Pipeline:\n1. LoadRawImageBytes\n2. ResizeImages\n3. ExtractPixels\n4. DnnFeaturizeImage\n5. Softmax -> PredictedLabel
M-->>B: ModelOutput { PredictedLabel: "coffee" }
B->>U: Displays "Detected content: coffee"
Predicting All Image Labels
// BeverageDetection.razor — enriched @code block
private string detectedContent = "None";
private IOrderedEnumerable<KeyValuePair<string, float>>? allLabels;
private async Task LoadFileAsync(InputFileChangeEventArgs e)
{
using var ms = new MemoryStream();
await e.File.OpenReadStream(10 * 1024 * 1024).CopyToAsync(ms);
byte[] imageData = ms.ToArray();
var input = new BeverageDetectionModel.ModelInput { ImageSource = imageData };
// Predict the best label
var output = BeverageDetectionModel.Predict(input);
detectedContent = output.PredictedLabel;
// All labels with their scores
allLabels = BeverageDetectionModel.PredictAllLabels(input);
}
Blazor Template
<p>Detected content: <strong>@detectedContent</strong></p>
@if (allLabels != null)
{
<ul>
@foreach (var label in allLabels)
{
<li>@label.Key : @(label.Value.ToString("P0"))</li>
}
</ul>
}
Example output:
Detected content: coffee
- coffee : 98%
- other : 1%
- goat : 1%
ML.NET In-Depth Technical Reference
IDataView — Data View
// Load from a CSV file
IDataView dataView = mlContext.Data.LoadFromTextFile<ModelInput>(
path: "data.csv", hasHeader: true, separatorChar: ',');
// Load from a collection
IDataView dataView2 = mlContext.Data.LoadFromEnumerable(myList);
// Save
using var fileStream = File.Create("output.csv");
mlContext.Data.SaveAsText(dataView, fileStream, separatorChar: ',');
// Preview for debugging ONLY (degrades performance in production)
var preview = dataView.Preview(maxRows: 10);
IDataView properties:
- Lazy evaluation: data is read and processed only during
Fit()orTransform() - Schema: each column has a name, type, and size
- All ML.NET algorithms expect a vector column named
Features - Algorithms create output columns with fixed names (
Score,PredictedLabel)
Pipeline: IEstimator and ITransformer
// Building the pipeline (no execution at this point)
var pipeline = mlContext.Transforms.Text.FeaturizeText(
outputColumnName: "Features",
inputColumnName: "Message")
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(
labelColumnName: "Language",
featureColumnName: "Features"))
.Append(mlContext.Transforms.Conversion.MapKeyToValue(
outputColumnName: "PredictedLabel"));
// Training -> ITransformer
ITransformer model = pipeline.Fit(trainingData);
// Bulk transformation (batch predictions)
IDataView predictions = model.Transform(testData);
// Multiclass evaluation
var metrics = mlContext.MulticlassClassification.Evaluate(
predictions,
labelColumnName: "Language",
predictedLabelColumnName: "PredictedLabel");
Console.WriteLine($"Macro Accuracy: {metrics.MacroAccuracy:P2}");
Console.WriteLine($"Micro Accuracy: {metrics.MicroAccuracy:P2}");
Console.WriteLine($"Log-loss: {metrics.LogLoss:F4}");
PredictionEngine vs PredictionEnginePool
PredictionEngine<TInput, TOutput> is not thread-safe. For web applications, use PredictionEnginePool.
// Not thread-safe (OK for console, WinForms, Blazor WASM)
var predEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(model);
var result = predEngine.Predict(input);
// Thread-safe for ASP.NET Core / Blazor Server
// In Program.cs:
builder.Services.AddPredictionEnginePool<ModelInput, ModelOutput>()
.FromFile(modelName: "LanguageModel", filePath: "model.zip", watchForChanges: true);
// In an injectable service:
public class LanguageService
{
private readonly PredictionEnginePool<ModelInput, ModelOutput> _pool;
public LanguageService(PredictionEnginePool<ModelInput, ModelOutput> pool)
=> _pool = pool;
public string Predict(string message)
{
var input = new ModelInput { Message = message };
var output = _pool.Predict(modelName: "LanguageModel", example: input);
return output.PredictedLabel;
}
}
In the SmartBrew.WebApp course: Blazor WebAssembly runs client-side, so the standard
PredictionEngineis used without threading issues. In production with Blazor Server or ASP.NET Core, preferPredictionEnginePool.
Available Transformations
Column Transformations
| Transformation | Description |
|---|---|
Concatenate | Combine multiple columns into a Features vector |
CopyColumns | Copy and rename a column |
DropColumns | Remove unnecessary columns |
SelectColumns | Keep only certain columns |
Normalization and Scaling
| Transformation | Description |
|---|---|
NormalizeMeanVariance | Subtracts the mean, divides by variance |
NormalizeMinMax | Normalizes between 0 and 1 |
NormalizeLpNorm | L1, L2, or infinity norm |
NormalizeRobustScaling | Robust to outliers |
Text Transformations
| Transformation | Description |
|---|---|
FeaturizeText | Transforms text -> float vector (n-grams + char-grams) |
TokenizeIntoWords | Split text into words |
NormalizeText | Normalize case, punctuation, diacritics |
RemoveDefaultStopWords | Remove stop words (the, le, der…) |
ApplyWordEmbedding | Convert tokens into semantic vectors (Word2Vec…) |
LatentDirichletAllocation | Topic modeling |
Image Transformations
| Transformation | Description |
|---|---|
LoadImages | Load images from a folder |
LoadRawImageBytes | Load an image from a byte[] |
ResizeImages | Resize images |
ExtractPixels | Convert image -> number vector |
ConvertToGrayscale | Convert to grayscale |
DnnFeaturizeImage | Transform image via pre-trained DNN |
Categorical Transformations
| Transformation | Description |
|---|---|
OneHotEncoding | Encode categories into binary vectors |
MapValueToKey | Map string values to numeric keys |
MapKeyToValue | Convert keys back to original values |
Deep Learning Transformations
| Transformation | Description |
|---|---|
ApplyOnnxModel | Apply an imported ONNX model |
LoadTensorFlowModel | Apply an imported TensorFlow model |
Training Algorithms (Trainers)
Binary Classification (mlContext.BinaryClassification.Trainers)
| Algorithm | Typical Use |
|---|---|
SdcaLogisticRegression | General purpose |
LbfgsLogisticRegression | Small datasets |
FastTree | Tabular data (gradient boosting) |
FastForest | Random forest — robust to noise |
LinearSvm | Large datasets |
AveragedPerceptron | Linearly separable data |
Multiclass Classification (mlContext.MulticlassClassification.Trainers)
| Algorithm | Description | Course result |
|---|---|---|
LbfgsMaximumEntropy | Maximum entropy with L-BFGS | Initial training (4 languages) |
SdcaMaximumEntropy | Maximum entropy with SDCA | Retraining (5 languages) |
NaiveBayes | Naive Bayesian classifier | Quick baseline |
OneVersusAll | One-versus-all (wrapper) | Extends binary classifiers |
Regression (mlContext.Regression.Trainers)
| Algorithm | Description |
|---|---|
Sdca | Stochastic Dual Coordinate Ascent |
LbfgsPoissonRegression | Poisson regression with L-BFGS |
FastTree | Gradient boosted trees |
LightGbm | Light Gradient Boosting Machine |
Saving and Loading a Model
// SAVE
mlContext.Model.Save(
model: trainedModel,
inputSchema: trainingData.Schema,
filePath: "model.zip");
// LOAD
ITransformer loadedModel = mlContext.Model.Load(
filePath: "model.zip",
inputSchema: out DataViewSchema modelSchema);
// Recreate the PredictionEngine after loading
var predEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(loadedModel);
Note:
.mlnetfiles are ZIP archives containing the serialized model.Save/Loaduse the same format.
ONNX Integration with ML.NET
ONNX (Open Neural Network Exchange) is an open format for machine learning models. ML.NET can import and use pre-trained ONNX models.
// Using a pre-trained ONNX model
var pipeline = mlContext.Transforms.ApplyOnnxModel(
modelFile: "model.onnx",
outputColumnNames: new[] { "output" },
inputColumnNames: new[] { "input" });
// Example: YOLOv4 for object detection
var onnxPipeline = mlContext.Transforms
.ResizeImages("input_image", 416, 416, "image")
.Append(mlContext.Transforms.ExtractPixels("input", "input_image"))
.Append(mlContext.Transforms.ApplyOnnxModel(
modelFile: "yolov4.onnx",
outputColumnNames: new[] { "Identity:0", "Identity_1:0", "Identity_2:0" },
inputColumnNames: new[] { "input_1:0" }));
ONNX use cases:
- Pre-trained models from PyTorch, scikit-learn, etc.
- Object detection models (YOLO, SSD)
- NLP models (BERT, GPT)
- Reusing models trained in other frameworks
Constraint: Requires
Microsoft.ML.OnnxTransformer. x64 only, not x86.
TensorFlow Integration with ML.NET
ML.NET can import TensorFlow SavedModel models for scoring and transfer learning.
// Loading a TensorFlow SavedModel
var pipeline = mlContext.Model.LoadTensorFlowModel("./tensorflow_model")
.ScoreTensorFlowModel(
outputColumnNames: new[] { "softmax2" },
inputColumnNames: new[] { "input" },
addBatchDimensionInput: true);
// Transfer Learning with TensorFlow Inception v3
var retrainedPipeline = mlContext.Model.LoadTensorFlowModel(inceptionV3ModelPath)
.RetrainTensorFlowModel(
inputTensorNames: new[] { "input" },
outputTensorNames: new[] { "InceptionV3/Predictions/Reshape_1" },
labelColumnName: "LabelAsKey",
inputColumnName: "input",
arch: ImageClassificationTrainer.Architecture.InceptionV3);
Constraint: Requires
Microsoft.ML.TensorFlow. Not supported on x86.
Model Builder Generated Code — Detailed Analysis
.consumption.cs File
// LanguageDetectionModel.consumption.cs
// Code automatically generated by ML.NET Model Builder
using Microsoft.ML;
using Microsoft.ML.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public partial class LanguageDetectionModel
{
private static string MLNetModelPath = Path.GetFullPath("LanguageDetectionModel.mlnet");
// Lazy initialization of PredictionEngine
public static readonly Lazy<PredictionEngine<ModelInput, ModelOutput>> PredictEngine =
new Lazy<PredictionEngine<ModelInput, ModelOutput>>(
() => CreatePredictEngine(), true);
/// <summary>Input class — the model's features</summary>
public class ModelInput
{
[LoadColumn(0), ColumnName("Language")]
public string Language { get; set; }
[LoadColumn(1), ColumnName("Message")]
public string Message { get; set; }
}
/// <summary>Output class — the prediction</summary>
public class ModelOutput
{
[ColumnName("PredictedLabel")]
public string PredictedLabel { get; set; }
public float[] Score { get; set; }
}
private static PredictionEngine<ModelInput, ModelOutput> CreatePredictEngine()
{
var mlContext = new MLContext();
ITransformer mlModel = mlContext.Model.Load(MLNetModelPath, out var _);
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
}
/// <summary>Predicts the best label</summary>
public static ModelOutput Predict(ModelInput input)
=> PredictEngine.Value.Predict(input);
/// <summary>Predicts all labels with their scores, sorted by descending probability</summary>
public static IOrderedEnumerable<KeyValuePair<string, float>> PredictAllLabels(ModelInput input)
{
var predEngine = PredictEngine.Value;
var result = predEngine.Predict(input);
predEngine.OutputSchema[nameof(ModelOutput.Score)]
.GetSlotNames<string>(out var slotNamesBuffer);
var labelScores = slotNamesBuffer.DenseValues()
.Select((name, index) => new KeyValuePair<string, float>(name, result.Score[index]));
return labelScores.OrderByDescending(kv => kv.Value);
}
}
.training.cs File
// LanguageDetectionModel.training.cs
// Code automatically generated by ML.NET Model Builder
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Trainers;
public partial class LanguageDetectionModel
{
private const string TRAIN_DATA_FILEPATH = @"languageDetection.csv";
private const int TRAINING_TIME = 20;
/// <summary>Retrain the model with the current data</summary>
public static ITransformer RetrainPipeline(MLContext mlContext, IDataView trainData)
{
var pipeline = BuildPipeline(mlContext);
return pipeline.Fit(trainData);
}
/// <summary>Build the ML.NET pipeline</summary>
public static IEstimator<ITransformer> BuildPipeline(MLContext mlContext)
{
var pipeline = mlContext.Transforms.Conversion
.MapValueToKey(outputColumnName: "Language", inputColumnName: "Language")
.Append(mlContext.Transforms.Text.FeaturizeText(
outputColumnName: "Message_tf", inputColumnName: "Message"))
.Append(mlContext.Transforms.CopyColumns(
outputColumnName: "Features", inputColumnName: "Message_tf"))
.Append(mlContext.Transforms.NormalizeMinMax(
outputColumnName: "Features", inputColumnName: "Features"))
.AppendCacheCheckpoint(mlContext)
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(
new LbfgsMaximumEntropyMulticlassTrainer.Options
{
L1Regularization = 0.03125F,
L2Regularization = 0.2158F,
LabelColumnName = "Language",
FeatureColumnName = "Features"
}))
.Append(mlContext.Transforms.Conversion.MapKeyToValue(
outputColumnName: "PredictedLabel",
inputColumnName: "PredictedLabel"));
return pipeline;
}
}
Standalone Retraining Program
// Console program to manually retrain the model
class RetrainingProgram
{
static void Main(string[] args)
{
var mlContext = new MLContext(seed: 1);
IDataView trainData = mlContext.Data.LoadFromTextFile<LanguageDetectionModel.ModelInput>(
path: "languageDetection.csv",
hasHeader: true,
separatorChar: ',');
Console.WriteLine("Starting training...");
var model = LanguageDetectionModel.RetrainPipeline(mlContext, trainData);
Console.WriteLine("Training complete.");
// Evaluation
var predictions = model.Transform(trainData);
var metrics = mlContext.MulticlassClassification.Evaluate(
predictions, labelColumnName: "Language");
Console.WriteLine($"Macro Accuracy: {metrics.MacroAccuracy:P2}");
Console.WriteLine($"Micro Accuracy: {metrics.MicroAccuracy:P2}");
// Save
mlContext.Model.Save(model, trainData.Schema, "LanguageDetectionModel.mlnet");
Console.WriteLine("Model saved: LanguageDetectionModel.mlnet");
}
}
Key Concepts and Quick Reference
Comparison of the Two Implemented Scenarios
| Language Detection | Beverage Detection | |
|---|---|---|
| Scenario type | Data classification | Image classification |
| Model Builder config | LanguageDetectionModel.mbconfig | BeverageDetectionModel.mbconfig |
| Input data | CSV with text columns | Image folder with subfolders per label |
| Input type | string Message | byte[] ImageSource |
| Labels | English, French, German, Italian, Spanish | coffee, goat, other |
| Environment | Local CPU only | Local CPU / GPU / Azure |
| Best algorithm (initial) | LbfgsMaximumEntropyMulti | Deep Neural Network (cuDNN) |
| Best algorithm (retrain) | SdcaMaximumEntropyMulti | — |
| Additional NuGet | — | Microsoft.ML.Vision, Microsoft.ML.ImageAnalytics |
| Data split | N/A | 80% train / 20% validation |
Universal ML.NET Model Consumption Pattern
// =======================================================
// UNIVERSAL PATTERN — ML.NET Model Consumption
// =======================================================
// 1. Define the INPUT (the features)
var input = new MyModel.ModelInput
{
Message = "text to analyze", // Data classification
// OR
ImageSource = imageByteArray, // Image classification
};
// 2. PREDICT the best label
var output = MyModel.Predict(input);
string label = output.PredictedLabel; // e.g.: "English" or "coffee"
float[] scores = output.Score; // array of scores 0-1
// 3. (Optional) ALL labels with their scores
IOrderedEnumerable<KeyValuePair<string, float>> allLabels =
MyModel.PredictAllLabels(input);
// Key = label (string), Value = score (float 0-1), sorted desc
Available ML.NET Tasks
| Task | Description | Example |
|---|---|---|
| Binary Classification | 2 categories (0/1) | Spam/not spam |
| Multiclass Classification | 3+ categories | Language detection |
| Regression | Continuous value | House price |
| Anomaly Detection | Abnormal values | Bank fraud |
| Recommendation | Recommend items | E-commerce |
| Clustering | Group without labels | Customer segmentation |
| Image Classification | Categorize images | Coffee/goat/other |
| Object Detection | Locate objects | Bounding boxes |
| Time Series | Temporal data | Sales forecasting |
| Text Classification | Categorize text | NLP, sentiment |
ML Glossary
| Term | Definition |
|---|---|
| Feature | Input data used to make a prediction |
| Label | Value to predict (target column) |
| Training data | Data used to train the model (80%) |
| Validation data | Data used to validate performance (20%) |
| Pipeline | Chain of transformations and training (IEstimator) |
| MLContext | Central entry point for ML.NET (singleton) |
| IDataView | Lazy data view interface |
| IEstimator | Pipeline interface before training |
| ITransformer | Model interface after training (Fit) |
| PredictionEngine | Prediction engine for individual examples (not thread-safe) |
| PredictionEnginePool | Thread-safe prediction engine for web apps |
| Binary classification | Classification into 2 categories (0/1) |
| Multiclass classification | Classification into more than 2 categories |
| Score | Probability associated with each label (float 0 to 1) |
| PredictedLabel | The label with the highest probability |
| AutoML | Automated Machine Learning — automates algorithm selection |
| Hyperparameter tuning | Adjustment of an ML algorithm’s parameters |
| mbconfig | Model Builder configuration file (JSON) |
| mlnet | Binary ZIP file containing the trained model |
| ONNX | Open Neural Network Exchange — interoperable format |
| CUDA | Compute Unified Device Architecture — NVIDIA GPU framework |
| cuDNN | CUDA Deep Neural Network library |
| Transfer learning | Reuse a pre-trained model as a base |
| Fit() | Pipeline training method |
| Transform() | Method to apply the model to data |
| Predict() | Prediction method for a single example |
NuGet Packages
| Package | Role |
|---|---|
Microsoft.ML | Core ML.NET framework |
Microsoft.ML.AutoML | AutoML for automatic algorithm selection |
Microsoft.ML.Vision | Image classification |
Microsoft.ML.ImageAnalytics | Image processing and transformation |
Microsoft.ML.OnnxTransformer | Import and use ONNX models |
Microsoft.ML.TensorFlow | Import and use TensorFlow models |
Microsoft.ML.LightGbm | LightGBM algorithms (gradient boosting) |
Microsoft.Extensions.ML | ASP.NET Core integration (PredictionEnginePool) |
Overall Project Architecture
graph TB
subgraph "SmartBrew.WebApp — Blazor"
LD["LanguageDetection.razor\nTextChanged() -> Predict()"]
CD["BeverageDetection.razor\nLoadFileAsync() -> Predict()"]
end
subgraph "ML.NET Models — Generated by Model Builder"
LDM["LanguageDetectionModel\n.mbconfig / .mlnet\n.consumption.cs / .training.cs"]
CDM["BeverageDetectionModel\n.mbconfig / .mlnet\n.consumption.cs / .training.cs"]
end
subgraph "Training Data"
CSV["languageDetection.csv\nLanguage, Message\n4->5 languages"]
IMG["Images/\ncoffee/ goat/ other/\n28 images total"]
end
subgraph "ML Tools"
MB["Model Builder\n(VS 2022 Extension)"]
AUTO["AutoML\nMicrosoft.ML.AutoML"]
MLNET["ML.NET\nMicrosoft.ML"]
end
subgraph "Infrastructure"
CPU["Local CPU\n(Data classification)"]
GPU["Local GPU NVIDIA CUDA\n(Image classification)"]
end
LD -->|"string Message -> PredictedLabel"| LDM
CD -->|"byte[] ImageSource -> PredictedLabel"| CDM
CSV -->|trains| LDM
IMG -->|trains| CDM
MB -->|"generates C# code + .mlnet"| LDM
MB -->|"generates C# code + .mlnet"| CDM
MB --> AUTO
AUTO --> MLNET
LDM -->|"SDCA / L-BFGS"| CPU
CDM -->|"deep neural network"| GPU
End-to-End Flow — From Raw Data to Prediction
flowchart TD
RAW["Raw data\n(CSV or images)"]
PREP["Data preparation\n(cleaning, structuring)"]
MB["Model Builder / AutoML\n(scenario, data, training)"]
MLNET_MODEL[".mlnet\n(trained model)"]
CS_CODE[".consumption.cs\n(generated C# code)"]
APP[".NET Application\n(Blazor, ASP.NET, console...)"]
PRED["Prediction\n(PredictedLabel + Score[])"]
UI["User interface\n(display result)"]
RAW --> PREP
PREP --> MB
MB --> MLNET_MODEL
MB --> CS_CODE
MLNET_MODEL --> CS_CODE
CS_CODE --> APP
APP -->|"ModelInput"| PRED
PRED --> UI
Documentation enriched from the “Building Apps with Machine Learning in .NET” course and the official documentation at learn.microsoft.com/dotnet/machine-learning.
Search Terms
.net · apps · machine · ml · platforms · deployment · data · science · model · image · classification · ml.net · builder · transformations · generated · retraining · application · automl · available · configuration · detection · flow · scenario · workflow