Below is a class of my code which I will be using on the main program of a Windows Forms Application in Visual Studio.
My input values are in double[] vs = new double[120]; and the values are updated each second. So there is an incrementing value int t=0; which increments with time. But these two values are not in this class. They are on the main program.
This class Edited on 26th for the latest update
using Microsoft.ML;
using Microsoft.ML.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using Tensorflow;
class MLNET
{
private MLContext mlContext; // Declare mlContext at the class level
private ITransformer trainedModel; // Separate model for training
private PredictionEngine<TimeSeriesData, TimeSeriesPrediction> predictionEngine; // Separate prediction engine
int windowSize = 30; // Set the desired window size
public class TimeSeriesData
{
[LoadColumn(0, 30)]
public double[] Features;
[LoadColumn(1)]
public double[] Label;
}
public class TimeSeriesPrediction
{
[ColumnName("Score")]
public double[] Value { get; set; } = new double[10]; // Adjust the size
}
public ITransformer TrainModel(IEnumerable<TimeSeriesData> historicalData)
{
try
{
// Initialize mlContext
mlContext = new MLContext();
// Check Label column data type in training data
var labelColumnDataType = historicalData.First().Label.GetType();
Console.WriteLine($"Label Column Data Type in Training Data: {labelColumnDataType}");
// Load and prepare your time series data
var data = mlContext.Data.LoadFromEnumerable(historicalData);
// Define the pipeline
/*var pipeline = mlContext.Transforms.Conversion.MapValueToKey("Label", "Label")
.Append(mlContext.Transforms.Conversion.MapValueToKey("Features")) // Adjust based on your needs
.Append(mlContext.Transforms.Conversion.MapKeyToValue("Label"));*/// working code
// Define the pipeline
var pipeline = mlContext.Transforms.Conversion.MapValueToKey("Label")
.Append(mlContext.Transforms.Conversion.MapKeyToValue("Label"));
// Train the model
trainedModel = pipeline.Fit(data);
// Log some information about the training process
Console.WriteLine("Model trained successfully.");
//log some addtional information about the output schema
var originalSchema = data.Schema;
var transformedData = pipeline.Fit(data).Transform(data);
var transformedSchema = transformedData.Schema;
Console.WriteLine("Original Schema:");
foreach (var column in originalSchema)
{
Console.WriteLine($"Column Name: {column.Name}, Data Type: {column.Type}");
}
Console.WriteLine("\nTransformed Schema:");
foreach (var column in transformedSchema)
{
Console.WriteLine($"Column Name: {column.Name}, Data Type: {column.Type}");
}
return trainedModel;
}
catch (Exception ex)
{
// Log the full exception details
Console.WriteLine($"Error during training: {ex}");
// Propagate the exception to the caller
throw;
}
}
public double[] Predict(double[] inputValues)
{
// Check Label column data type in prediction data
var labelDataTypeInInput = inputValues.GetType();
Console.WriteLine($"Label Column Data Type in Prediction Input: {labelDataTypeInInput}");
// Check if the trained model is null and retrain if necessary
if (trainedModel == null)
{
// Log a warning or handle this differently based on your application
Console.WriteLine("Warning: Model is null. Retraining the model.");
trainedModel = TrainModelFromDoubleArray(inputValues, windowSize);
}
else
{
// Log a warning or handle this differently based on your application
Console.WriteLine("Warning: Model is not null. Retraining anyway.");
trainedModel = TrainModelFromDoubleArray(inputValues, windowSize);
}
// Debug: Output the model status
Console.WriteLine($"Model Status: {(trainedModel != null ? "Trained" : "Not Trained")}");
// Check if the prediction engine is null and create a new one if necessary
if (predictionEngine == null)
{
// Log a warning or handle this differently based on your application
Console.WriteLine("Warning: Prediction engine is null. Creating a new one.");
predictionEngine = mlContext.Model.CreatePredictionEngine<TimeSeriesData, TimeSeriesPrediction>(trainedModel);
}
// Add debug output
Console.WriteLine($"Input Values Length (Before Adjustment): {inputValues.Length}");
// Adjust the input array to match the expected window size
inputValues = inputValues.Skip(inputValues.Length - windowSize).ToArray();
// Add debug output
Console.WriteLine($"Input Values Length (After Adjustment): {inputValues.Length}");
// Create a new TimeSeriesData instance with the adjusted input values
var newData = new TimeSeriesData { Features = inputValues, Label = new double[10] };
//check if the features passed to the prediction engine are not null
Console.WriteLine($"Input Features: {string.Join(", ", inputValues)}");
// Make predictions
var prediction = predictionEngine.Predict(newData);
Console.WriteLine($"Prediction: {prediction.GetDataType()}");
// Check if prediction.Value is not null before attempting to join
if (prediction.Value != null)
{
// Log the predicted value
Console.WriteLine($"Predicted Value: {prediction.Value[9]}");
// Extract the predicted value
return prediction.Value;
}
else
{
// Handle the case where prediction.Value is null (log a warning or handle it based on your application's logic)
Console.WriteLine("Warning: Predicted values are null.");
return new double[0]; // or return another default value
}
}
public ITransformer TrainModelFromDoubleArray(double[] historicalData, int windowSize)
{
// Convert the double[] to a list of TimeSeriesData
var timeSeriesDataList = new List<TimeSeriesData>();
// Use values from vs[0] to vs[vs.Length - 31] for training
for (int i = 0; i < historicalData.Length - windowSize - 1; i++)
{
// Use the specified sliding window size
var windowValues = historicalData.Skip(i).Take(windowSize).ToArray();
// Adjusted code
var timeSeriesData = new TimeSeriesData
{
Features = windowValues,
Label = new double[] { historicalData[i + windowSize + 1] }
};
timeSeriesDataList.Add(timeSeriesData);
}
// Return the trained model with the specified window size
return TrainModel(timeSeriesDataList);
}
}
and this is what is logged in the console
Transformed Schema:
Column Name: Features, Data Type: Vector<Double>
Column Name: Label, Data Type: Vector<Double>
Column Name: Label, Data Type: Vector<Key<UInt32, 0-77>>
Column Name: Label, Data Type: Vector<Double>
Model Status: Trained
Input Values Length (Before Adjustment): 120
Input Values Length (After Adjustment): 30
Input Features: 1679.94, 1679.88, 1680.32, 1680.23, 1680.53, 1680.36, 1680.05, 1680.12, 1680.01, 1679.56, 1679.41, 1679.07, 1679.39, 1679.16, 1679.58, 1679.39, 1679.31, 1679.24, 1679.51, 1679.69, 1679.78, 1679.53, 1679.12, 1679, 1678.92, 1679.3, 1678.74, 1678.99, 1679.4, 1679.18
Prediction: DtInvalid
Predicted Value: 0
Although I tried my best, I couldn't get the predicted value to anything other than zero.
What am I doing wrong, and how can I make sure that the predicted values are not zero?