Neural Network Training
This guide demonstrates how to train neural networks for various tasks using AiDotNet’s AiModelBuilder facade. You configure a model and a data loader, call BuildAsync(), and predict through the returned AiModelResult.
Overview
Every model in AiDotNet is built the same way: ConfigureModel(...) + ConfigureDataLoader(...) + BuildAsync(), then result.Predict(...).
Image Classification
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Enums;
using AiDotNet.NeuralNetworks;
using AiDotNet.Tensors.LinearAlgebra;
// 100 training samples of 784 features (28x28), one-hot labels for 10 digits.
// In production, load MNIST through a DataLoader instead of synthesising data.
var rng = new Random(42);
var trainX = new Tensor<double>(new[] { 100, 784 });
var trainY = new Tensor<double>(new[] { 100, 10 });
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 784; j++) trainX[new[] { i, j }] = rng.NextDouble();
trainY[new[] { i, i % 10 }] = 1.0;
}
// The architecture builds an appropriate network from the input/class counts.
var model = new NeuralNetwork<double>(new NeuralNetworkArchitecture<double>(
inputFeatures: 784, numClasses: 10, complexity: NetworkComplexity.Medium));
var result = await new AiModelBuilder<double, Tensor<double>, Tensor<double>>()
.ConfigureModel(model)
.ConfigureDataLoader(DataLoaders.FromTensors(trainX, trainY))
.BuildAsync();
// Predict class scores for a batch (here, the training batch) and read row 0.
var scores = result.Predict(trainX);
int predicted = 0;
for (int c = 1; c < 10; c++)
if (scores[new[] { 0, c }] > scores[new[] { 0, predicted }]) predicted = c;
Console.WriteLine($"Predicted digit for sample 0: {predicted}");
Binary Classification (Spam Detection)
using AiDotNet;
using AiDotNet.Classification.Ensemble;
using AiDotNet.Data.Loaders;
using AiDotNet.Models.Options;
using AiDotNet.Tensors.LinearAlgebra;
// Email features (word frequencies, etc.) and spam labels (1 = spam).
double[][] emailFeatures =
{
new[] { 0.1, 0.8, 0.0, 0.9 },
new[] { 0.9, 0.1, 0.7, 0.0 },
new[] { 0.2, 0.7, 0.1, 0.8 },
new[] { 0.3, 0.6, 0.2, 0.7 }
};
double[] isSpam = { 1, 0, 1, 1 };
var result = await new AiModelBuilder<double, Matrix<double>, Vector<double>>()
.ConfigureModel(new RandomForestClassifier<double>(
new RandomForestClassifierOptions<double> { NEstimators = 100 }))
.ConfigureDataLoader(DataLoaders.FromArrays(emailFeatures, isSpam))
.BuildAsync();
// Classify a new email (one-row matrix in, vector of class scores out).
var newEmail = new Matrix<double>(1, 4);
foreach (var (v, j) in new[] { 0.3, 0.6, 0.2, 0.7 }.Select((v, j) => (v, j)))
newEmail[0, j] = v;
Console.WriteLine($"Spam class: {(int)Math.Round(result.Predict(newEmail)[0])}");
Regression (Price Prediction)
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Models.Options;
using AiDotNet.Regression;
using AiDotNet.Tensors.LinearAlgebra;
double[][] productFeatures =
{
new[] { 100.0, 4.5, 1000.0, 2.0 },
new[] { 250.0, 4.2, 500.0, 1.0 },
new[] { 50.0, 4.8, 2000.0, 3.0 },
new[] { 150.0, 3.9, 750.0, 2.0 }
};
double[] prices = { 29.99, 59.99, 19.99, 39.99 };
var result = await new AiModelBuilder<double, Matrix<double>, Vector<double>>()
.ConfigureModel(new GradientBoostingRegression<double>(
new GradientBoostingRegressionOptions { NumberOfTrees = 100, MaxDepth = 3 }))
.ConfigureDataLoader(DataLoaders.FromArrays(productFeatures, prices))
.BuildAsync();
var newProduct = new Matrix<double>(1, 4);
foreach (var (v, j) in new[] { 150.0, 4.3, 750.0, 2.0 }.Select((v, j) => (v, j)))
newProduct[0, j] = v;
Console.WriteLine($"Predicted price: ${result.Predict(newProduct)[0]:F2}");
Time Series Forecasting
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Models.Options;
using AiDotNet.Regression;
using AiDotNet.Tensors.LinearAlgebra;
// Each row is a 5-day window of sales; the target is the next day's sales.
double[][] windows =
{
new[] { 100.0, 110.0, 105.0, 115.0, 120.0 },
new[] { 110.0, 105.0, 115.0, 120.0, 125.0 },
new[] { 105.0, 115.0, 120.0, 125.0, 130.0 },
new[] { 115.0, 120.0, 125.0, 130.0, 135.0 }
};
double[] nextDay = { 125, 130, 135, 140 };
var result = await new AiModelBuilder<double, Matrix<double>, Vector<double>>()
.ConfigureModel(new GradientBoostingRegression<double>(
new GradientBoostingRegressionOptions { NumberOfTrees = 100 }))
.ConfigureDataLoader(DataLoaders.FromArrays(windows, nextDay))
.BuildAsync();
var recent = new Matrix<double>(1, 5);
foreach (var (v, j) in new[] { 125.0, 130.0, 135.0, 140.0, 145.0 }.Select((v, j) => (v, j)))
recent[0, j] = v;
Console.WriteLine($"Forecasted sales: ${result.Predict(recent)[0]:F0}");
Multi-Class Classification with an Optimizer
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Enums;
using AiDotNet.NeuralNetworks;
using AiDotNet.Optimizers;
using AiDotNet.Tensors.LinearAlgebra;
var rng = new Random(7);
var x = new Tensor<double>(new[] { 200, 64 });
var y = new Tensor<double>(new[] { 200, 10 });
for (int i = 0; i < 200; i++)
{
for (int j = 0; j < 64; j++) x[new[] { i, j }] = rng.NextDouble();
y[new[] { i, i % 10 }] = 1.0;
}
var model = new NeuralNetwork<double>(new NeuralNetworkArchitecture<double>(
inputFeatures: 64, numClasses: 10, complexity: NetworkComplexity.Simple));
// ConfigureOptimizer plugs in a specific optimizer; other knobs (LR schedule,
// early stopping, regularization) have their own Configure* methods.
var result = await new AiModelBuilder<double, Tensor<double>, Tensor<double>>()
.ConfigureModel(model)
.ConfigureDataLoader(DataLoaders.FromTensors(x, y))
.ConfigureOptimizer(new AdamOptimizer<double, Tensor<double>, Tensor<double>>(model))
.BuildAsync();
var preds = result.Predict(x);
Console.WriteLine($"Output shape: [{string.Join(", ", preds.Shape)}]");
GPU Acceleration
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Enums;
using AiDotNet.NeuralNetworks;
using AiDotNet.Tensors.LinearAlgebra;
var rng = new Random(1);
var x = new Tensor<double>(new[] { 64, 32 });
var y = new Tensor<double>(new[] { 64, 3 });
for (int i = 0; i < 64; i++)
{
for (int j = 0; j < 32; j++) x[new[] { i, j }] = rng.NextDouble();
y[new[] { i, i % 3 }] = 1.0;
}
var model = new NeuralNetwork<double>(new NeuralNetworkArchitecture<double>(
inputFeatures: 32, numClasses: 3, complexity: NetworkComplexity.Simple));
// ConfigureGpuAcceleration enables the GPU path when a device is available;
// it transparently falls back to CPU otherwise.
var result = await new AiModelBuilder<double, Tensor<double>, Tensor<double>>()
.ConfigureModel(model)
.ConfigureDataLoader(DataLoaders.FromTensors(x, y))
.ConfigureGpuAcceleration()
.BuildAsync();
Console.WriteLine($"Trained; output shape [{string.Join(", ", result.Predict(x).Shape)}]");
Reading Training Metrics
Everything you need to evaluate a trained model hangs off the returned AiModelResult.
using AiDotNet;
using AiDotNet.Data.Loaders;
using AiDotNet.Enums;
using AiDotNet.NeuralNetworks;
using AiDotNet.Tensors.LinearAlgebra;
var rng = new Random(3);
var x = new Tensor<double>(new[] { 120, 16 });
var y = new Tensor<double>(new[] { 120, 4 });
for (int i = 0; i < 120; i++)
{
for (int j = 0; j < 16; j++) x[new[] { i, j }] = rng.NextDouble();
y[new[] { i, i % 4 }] = 1.0;
}
var result = await new AiModelBuilder<double, Tensor<double>, Tensor<double>>()
.ConfigureModel(new NeuralNetwork<double>(new NeuralNetworkArchitecture<double>(
inputFeatures: 16, numClasses: 4, complexity: NetworkComplexity.Simple)))
.ConfigureDataLoader(DataLoaders.FromTensors(x, y))
.BuildAsync();
// Model summary.
Console.WriteLine($"Layers: {result.LayerCount}, trainable params: {result.TotalTrainableParameters:N0}");
// Per-epoch training metrics (loss, accuracy, …) keyed by metric name, when recorded.
var history = result.GetTrainingMetricsHistory();
if (history is not null)
foreach (var (metric, values) in history)
Console.WriteLine($"{metric}: final = {values[^1]:F4} (over {values.Count} epochs)");
// If you add .ConfigureCrossValidation(...), the fold results land on result.CrossValidationResult.
Best Practices
- Start with small models: Begin simple and increase complexity only if needed.
- Use validation data: Always monitor validation metrics to detect overfitting.
- Normalize your data: Neural networks train better with normalized inputs (
ConfigurePreprocessing). - Use early stopping:
ConfigureStoppingCriterionprevents overfitting. - Experiment with learning rates: Usually the most important hyperparameter (
ConfigureOptimizer). - Use data augmentation:
ConfigureAugmentation, especially for image tasks with limited data.
Summary
AiDotNet’s AiModelBuilder makes neural network training accessible: configure a model + a data loader, BuildAsync(), and predict through the returned AiModelResult. Cross-cutting concerns (optimizer, GPU, preprocessing, augmentation, early stopping) are added with their own Configure* methods.