BuildDivisorTransitions application added.
This commit is contained in:
1 parent
97fd041ec0
commit
046cfe7d26
12 files changed
+976
-1
No files matched your search
@@ -8,6 +8,9 @@ EvenPerfectBitScanner.ResultsParser/bin/*
|
|||||||
EvenPerfectBitScanner.ResultsParser/obj/*
|
EvenPerfectBitScanner.ResultsParser/obj/*
|
||||||
EvenPerfectBitScanner.Tests/bin/*
|
EvenPerfectBitScanner.Tests/bin/*
|
||||||
EvenPerfectBitScanner.Tests/obj/*
|
EvenPerfectBitScanner.Tests/obj/*
|
||||||
|
BuildDivisorTransitions/bin/*
|
||||||
|
BuildDivisorTransitions/obj/*
|
||||||
PerfectNumbers.Core.Tests/bin/*
|
PerfectNumbers.Core.Tests/bin/*
|
||||||
PerfectNumbers.Core.Tests/obj/*
|
PerfectNumbers.Core.Tests/obj/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.vs/*
|
||||||
Vendored
+29
-1
@@ -8,7 +8,8 @@
|
|||||||
"options": [
|
"options": [
|
||||||
"EvenPerfectBitScanner",
|
"EvenPerfectBitScanner",
|
||||||
"EvenPerfectBitScanner.ResultsParser",
|
"EvenPerfectBitScanner.ResultsParser",
|
||||||
"EvenPerfectBitScanner.Benchmarks"
|
"EvenPerfectBitScanner.Benchmarks",
|
||||||
|
"BuildDivisorTransitions"
|
||||||
],
|
],
|
||||||
"default": "EvenPerfectBitScanner"
|
"default": "EvenPerfectBitScanner"
|
||||||
}
|
}
|
||||||
@@ -68,6 +69,33 @@
|
|||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
"justMyCode": false
|
"justMyCode": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Run BuildDivisorTransitions",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"noDebug": true,
|
||||||
|
"preLaunchTask": "Build BuildDivisorTransitions Release",
|
||||||
|
"program": "${workspaceFolder}/BuildDivisorTransitions/bin/Release/net8.0/BuildDivisorTransitions.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
"justMyCode": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug BuildDivisorTransitions",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "Build BuildDivisorTransitions Debug",
|
||||||
|
"program": "${workspaceFolder}/BuildDivisorTransitions/bin/Debug/net8.0/BuildDivisorTransitions.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
"justMyCode": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Run EvenPerfectBitScanner.ResultsParser",
|
"name": "Run EvenPerfectBitScanner.ResultsParser",
|
||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
|
|||||||
Vendored
+45
@@ -94,6 +94,36 @@
|
|||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Build BuildDivisorTransitions Debug",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
|
||||||
|
"--configuration",
|
||||||
|
"Debug",
|
||||||
|
"--framework",
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build BuildDivisorTransitions Release",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
|
||||||
|
"--configuration",
|
||||||
|
"Release",
|
||||||
|
"--framework",
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Run EvenPerfectBitScanner",
|
"label": "Run EvenPerfectBitScanner",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
@@ -124,6 +154,21 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Run BuildDivisorTransitions",
|
||||||
|
"type": "process",
|
||||||
|
"command": "dotnet",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/BuildDivisorTransitions/BuildDivisorTransitions.csproj",
|
||||||
|
"--configuration",
|
||||||
|
"Release",
|
||||||
|
"--framework",
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Run Release (no debug)",
|
"label": "Run Release (no debug)",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace BuildDivisorTransitions;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
private const string OutputFileName = "NextKForecastTraning.csv";
|
||||||
|
|
||||||
|
private static int Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 2)
|
||||||
|
{
|
||||||
|
PrintUsage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string candidatesPath = args[0];
|
||||||
|
string divisorsPath = args[1];
|
||||||
|
|
||||||
|
if (!File.Exists(candidatesPath))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Candidates file not found: {candidatesPath}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(divisorsPath))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Divisors file not found: {divisorsPath}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<long> candidatePs = LoadCandidates(candidatesPath);
|
||||||
|
Dictionary<long, BigInteger> divisors = LoadDivisors(divisorsPath);
|
||||||
|
List<Transition> transitions = BuildTransitions(candidatePs, divisors);
|
||||||
|
|
||||||
|
WriteOutput(transitions);
|
||||||
|
|
||||||
|
Console.WriteLine($"Saved {transitions.Count} transitions to {OutputFileName}.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintUsage()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Usage: BuildDivisorTransitions <candidatesCsv> <divisorsCsv>");
|
||||||
|
Console.WriteLine(" candidatesCsv: CSV with columns p,searchedMersenne,detailedCheck,passedAllTests");
|
||||||
|
Console.WriteLine(" divisorsCsv: CSV with columns p,divisor");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<long> LoadCandidates(string path)
|
||||||
|
{
|
||||||
|
var result = new List<long>();
|
||||||
|
var seen = new HashSet<long>();
|
||||||
|
|
||||||
|
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
|
||||||
|
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
string? line = reader.ReadLine();
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string trimmedLine = line.Trim();
|
||||||
|
if (trimmedLine.StartsWith("p", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = trimmedLine.Split(',', StringSplitOptions.TrimEntries);
|
||||||
|
if (parts.Length == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!long.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out long p))
|
||||||
|
{
|
||||||
|
throw new FormatException($"Invalid p value '{parts[0]}' in {path}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seen.Add(p))
|
||||||
|
{
|
||||||
|
result.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<long, BigInteger> LoadDivisors(string path)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<long, BigInteger>();
|
||||||
|
|
||||||
|
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
|
||||||
|
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
string? line = reader.ReadLine();
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string trimmedLine = line.Trim();
|
||||||
|
if (trimmedLine.StartsWith("p", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = trimmedLine.Split(',', StringSplitOptions.TrimEntries);
|
||||||
|
if (parts.Length < 2)
|
||||||
|
{
|
||||||
|
throw new FormatException($"Line '{line}' in {path} does not contain both p and divisor columns.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!long.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out long p))
|
||||||
|
{
|
||||||
|
throw new FormatException($"Invalid p value '{parts[0]}' in {path}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BigInteger.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out BigInteger divisor))
|
||||||
|
{
|
||||||
|
throw new FormatException($"Invalid divisor value '{parts[1]}' for p={p} in {path}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result[p] = divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Transition> BuildTransitions(IReadOnlyList<long> candidatePs, IReadOnlyDictionary<long, BigInteger> divisors)
|
||||||
|
{
|
||||||
|
var transitions = new List<Transition>();
|
||||||
|
|
||||||
|
for (int i = 0; i < candidatePs.Count - 1; i++)
|
||||||
|
{
|
||||||
|
long currentP = candidatePs[i];
|
||||||
|
long nextP = candidatePs[i + 1];
|
||||||
|
|
||||||
|
if (!divisors.TryGetValue(currentP, out BigInteger currentDivisor))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!divisors.TryGetValue(nextP, out BigInteger nextDivisor))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger currentK = CalculateK(currentP, currentDivisor);
|
||||||
|
BigInteger nextK = CalculateK(nextP, nextDivisor);
|
||||||
|
bool isNextKHigher = nextK > currentK;
|
||||||
|
transitions.Add(new Transition(currentP, currentDivisor, LastDigit(currentP), currentK, LastMersenneDigit(currentP), isNextKHigher));
|
||||||
|
}
|
||||||
|
|
||||||
|
return transitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger CalculateK(long p, BigInteger divisor)
|
||||||
|
{
|
||||||
|
BigInteger numerator = divisor - BigInteger.One;
|
||||||
|
BigInteger denominator = new BigInteger(p) << 1;
|
||||||
|
|
||||||
|
if (denominator <= BigInteger.Zero)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Computed 2p is not positive for p={p}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger remainder = numerator % denominator;
|
||||||
|
if (remainder != BigInteger.Zero)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Divisor {divisor} is not congruent to 1 mod 2p for p={p}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger k = numerator / denominator;
|
||||||
|
if (k < BigInteger.One)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Calculated k={k} is less than 1 for p={p}, divisor={divisor}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteOutput(IReadOnlyCollection<Transition> transitions)
|
||||||
|
{
|
||||||
|
using var writer = new StreamWriter(OutputFileName, false, Encoding.UTF8);
|
||||||
|
writer.WriteLine("p,divisor,lastDigit,k,lastMersenneDigit,isNextKHigher");
|
||||||
|
|
||||||
|
foreach (Transition transition in transitions)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"{transition.P.ToString(CultureInfo.InvariantCulture)},{FormatBigInteger(transition.Divisor)},{transition.LastDigit},{FormatBigInteger(transition.CurrentK)},{transition.LastMersenneDigit},{(transition.IsNextKHigher ? "1" : "0")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int LastDigit(long p) => (int)(Math.Abs(p) % 10);
|
||||||
|
|
||||||
|
private static int LastMersenneDigit(long p)
|
||||||
|
{
|
||||||
|
long mod = p & 3;
|
||||||
|
return mod == 1 ? 1 : 7; // odd primes give p%4 == 1 or 3; 2^p mod 10 cycles -> 1 or 7 after subtracting 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatBigInteger(in BigInteger value) => value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
private sealed record Transition(long P, BigInteger Divisor, int LastDigit, BigInteger CurrentK, int LastMersenneDigit, bool IsNextKHigher);
|
||||||
|
}
|
||||||
@@ -13,7 +13,16 @@
|
|||||||
</AssemblyAttribute>
|
</AssemblyAttribute>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.ML" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.ML.LightGbm" Version="3.0.1" />
|
||||||
<PackageReference Include="Open.Numeric" Version="3.0.1" />
|
<PackageReference Include="Open.Numeric" Version="3.0.1" />
|
||||||
<PackageReference Include="Open.Numeric.Primes" Version="4.0.4" />
|
<PackageReference Include="Open.Numeric.Primes" Version="4.0.4" />
|
||||||
|
<PackageReference Include="Plotly.NET" Version="3.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup Label="MLModel1">
|
||||||
|
<None Include="MLModel1.mlnet">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// This file was auto-generated by ML.NET Model Builder.
|
||||||
|
using Microsoft.ML;
|
||||||
|
using Microsoft.ML.Data;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
namespace EvenPerfectBitScanner
|
||||||
|
{
|
||||||
|
public partial class MLModel1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// model input class for MLModel1.
|
||||||
|
/// </summary>
|
||||||
|
#region model input class
|
||||||
|
public class ModelInput
|
||||||
|
{
|
||||||
|
[LoadColumn(0)]
|
||||||
|
[ColumnName(@"p")]
|
||||||
|
public float P { get; set; }
|
||||||
|
|
||||||
|
[LoadColumn(1)]
|
||||||
|
[ColumnName(@"divisor")]
|
||||||
|
public float Divisor { get; set; }
|
||||||
|
|
||||||
|
[LoadColumn(2)]
|
||||||
|
[ColumnName(@"lastDigit")]
|
||||||
|
public float LastDigit { get; set; }
|
||||||
|
|
||||||
|
[LoadColumn(3)]
|
||||||
|
[ColumnName(@"k")]
|
||||||
|
public float K { get; set; }
|
||||||
|
|
||||||
|
[LoadColumn(4)]
|
||||||
|
[ColumnName(@"lastMersenneDigit")]
|
||||||
|
public float LastMersenneDigit { get; set; }
|
||||||
|
|
||||||
|
[LoadColumn(5)]
|
||||||
|
[ColumnName(@"isNextKHigher")]
|
||||||
|
public float IsNextKHigher { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// model output class for MLModel1.
|
||||||
|
/// </summary>
|
||||||
|
#region model output class
|
||||||
|
public class ModelOutput
|
||||||
|
{
|
||||||
|
[ColumnName(@"p")]
|
||||||
|
public float P { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"divisor")]
|
||||||
|
public float Divisor { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"lastDigit")]
|
||||||
|
public float LastDigit { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"k")]
|
||||||
|
public float K { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"lastMersenneDigit")]
|
||||||
|
public float LastMersenneDigit { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"isNextKHigher")]
|
||||||
|
public float IsNextKHigher { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"Features")]
|
||||||
|
public float[] Features { get; set; }
|
||||||
|
|
||||||
|
[ColumnName(@"Score")]
|
||||||
|
public float Score { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static string MLNetModelPath = Path.GetFullPath("MLModel1.mlnet");
|
||||||
|
|
||||||
|
public static readonly Lazy<PredictionEngine<ModelInput, ModelOutput>> PredictEngine = new Lazy<PredictionEngine<ModelInput, ModelOutput>>(() => CreatePredictEngine(), true);
|
||||||
|
|
||||||
|
|
||||||
|
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>
|
||||||
|
/// Use this method to predict on <see cref="ModelInput"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">model input.</param>
|
||||||
|
/// <returns><seealso cref=" ModelOutput"/></returns>
|
||||||
|
public static ModelOutput Predict(ModelInput input)
|
||||||
|
{
|
||||||
|
var predEngine = PredictEngine.Value;
|
||||||
|
return predEngine.Predict(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
// This file was auto-generated by ML.NET Model Builder.
|
||||||
|
|
||||||
|
using Microsoft.ML.Data;
|
||||||
|
using Microsoft.ML;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Plotly.NET;
|
||||||
|
using Plotly.NET.LayoutObjects;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner
|
||||||
|
{
|
||||||
|
public partial class MLModel1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Permutation feature importance (PFI) is a technique to determine the importance
|
||||||
|
/// of features in a trained machine learning model. PFI works by taking a labeled dataset,
|
||||||
|
/// choosing a feature, and permuting the values for that feature across all the examples,
|
||||||
|
/// so that each example now has a random value for the feature and the original values for all other features.
|
||||||
|
/// The evaluation metric (e.g. R-squared) is then calculated for this modified dataset,
|
||||||
|
/// and the change in the evaluation metric from the original dataset is computed.
|
||||||
|
/// The larger the change in the evaluation metric, the more important the feature is to the model.
|
||||||
|
///
|
||||||
|
/// PFI typically takes a long time to compute, as the evaluation metric is calculated
|
||||||
|
/// many times to determine the importance of each feature.
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mlContext">The common context for all ML.NET operations.</param>
|
||||||
|
/// <param name="trainData">IDataView used to evaluate the model.</param>
|
||||||
|
/// <param name="model">Model to evaluate.</param>
|
||||||
|
/// <param name="labelColumnName">Label column being predicted.</param>
|
||||||
|
/// <returns>A list of each feature and its importance.</returns>
|
||||||
|
public static List<Tuple<string, double>> CalculatePFI(MLContext mlContext, IDataView trainData, ITransformer model, string labelColumnName)
|
||||||
|
{
|
||||||
|
var preprocessedTrainData = model.Transform(trainData);
|
||||||
|
|
||||||
|
var permutationFeatureImportance =
|
||||||
|
mlContext.Regression
|
||||||
|
.PermutationFeatureImportance(
|
||||||
|
model,
|
||||||
|
preprocessedTrainData,
|
||||||
|
labelColumnName: labelColumnName);
|
||||||
|
|
||||||
|
var featureImportanceMetrics =
|
||||||
|
permutationFeatureImportance
|
||||||
|
.Select((kvp) => new { kvp.Key, kvp.Value.RSquared })
|
||||||
|
.OrderByDescending(myFeatures => Math.Abs(myFeatures.RSquared.Mean));
|
||||||
|
|
||||||
|
var featurePFI = new List<Tuple<string, double>>();
|
||||||
|
foreach (var feature in featureImportanceMetrics)
|
||||||
|
{
|
||||||
|
var pfiValue = Math.Abs(feature.RSquared.Mean);
|
||||||
|
featurePFI.Add(new Tuple<string, double>(feature.Key, pfiValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
return featurePFI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// R Squared is a measure of variation between the values predicted by the model and the true values.
|
||||||
|
/// In a "perfect" model, there would be no variation between predictions and true values.
|
||||||
|
///
|
||||||
|
/// Here we will plot the predicted values vs the true values for the trained model. This RegressionChart.html
|
||||||
|
/// is then saved to the location specified by <param name="folderPath"></param>.
|
||||||
|
///
|
||||||
|
/// See more information on R Squared at https://en.wikipedia.org/wiki/Coefficient_of_determination.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="trainData">IDataView used to train the model.</param>
|
||||||
|
/// <param name="model">Model used for predictions.</param>
|
||||||
|
/// <param name="labelColumnName">Name of the predicted label column.</param>
|
||||||
|
/// <param name="folderPath">Folder path to save the RegressionChart.html file into.</param>
|
||||||
|
public static void PlotRSquaredValues(IDataView trainData, ITransformer model, string labelColumnName, string folderPath)
|
||||||
|
{
|
||||||
|
// Number of rows to display in charts.
|
||||||
|
int numberOfRows = 1000;
|
||||||
|
// Use the model to make batch predictions on training data
|
||||||
|
var testResults = model.Transform(trainData);
|
||||||
|
|
||||||
|
// Get the actual values from the dataset
|
||||||
|
var trueValues = testResults.GetColumn<float>(labelColumnName).Take(numberOfRows); ;
|
||||||
|
|
||||||
|
// Get the predicted values from the test results
|
||||||
|
var predictedValues = testResults.GetColumn<float>("Score").Take(numberOfRows);
|
||||||
|
|
||||||
|
// Setup what the graph looks like
|
||||||
|
var title = Title.init(Text: "R-Squared Plot");
|
||||||
|
var layout = Layout.init<IConvertible>(Title: title, PlotBGColor: Plotly.NET.Color.fromString("#e5ecf6"));
|
||||||
|
var xAxis = LinearAxis.init<IConvertible, IConvertible, IConvertible, IConvertible, IConvertible, IConvertible>(
|
||||||
|
Title: Title.init("True Values"),
|
||||||
|
ZeroLineColor: Plotly.NET.Color.fromString("#ffff"),
|
||||||
|
GridColor: Plotly.NET.Color.fromString("#ffff"),
|
||||||
|
ZeroLineWidth: 2);
|
||||||
|
var yAxis = LinearAxis.init<IConvertible, IConvertible, IConvertible, IConvertible, IConvertible, IConvertible>(
|
||||||
|
Title: Title.init("Predicted Values"),
|
||||||
|
ZeroLineColor: Plotly.NET.Color.fromString("#ffff"),
|
||||||
|
GridColor: Plotly.NET.Color.fromString("#ffff"),
|
||||||
|
ZeroLineWidth: 2);
|
||||||
|
|
||||||
|
// We will plot the line that shows the perfect result. Setup that line here.
|
||||||
|
var maximumValue = Math.Max(trueValues.Max(), predictedValues.Max());
|
||||||
|
var perfectX = new[] { 0, maximumValue };
|
||||||
|
var perfectY = new[] { 0, maximumValue };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Create the scatterplot that shows the true values vs the predicted values
|
||||||
|
var trueAndPredictedValues = Chart2D.Chart.Scatter<float, float, string>(x: trueValues, y: predictedValues, mode: StyleParam.Mode.Markers)
|
||||||
|
.WithLayout(layout)
|
||||||
|
.WithXAxis(xAxis)
|
||||||
|
.WithYAxis(yAxis);
|
||||||
|
|
||||||
|
// Setup the line that shows what a perfect prediction would look like
|
||||||
|
var perfectLineGraph = Chart2D.Chart.Line<float, float, string>(x: perfectX, y: perfectY)
|
||||||
|
.WithLayout(layout)
|
||||||
|
.WithLine(Line.init(Width: 1.5));
|
||||||
|
|
||||||
|
var chartWithValuesAndIdealLine = Chart.Combine(new[] { trueAndPredictedValues, perfectLineGraph });
|
||||||
|
var chartFilePath = folderPath + "\\RegressionChart.html";
|
||||||
|
|
||||||
|
chartWithValuesAndIdealLine.SaveHtml(chartFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
{
|
||||||
|
"Scenario": "Regression",
|
||||||
|
"DataSource": {
|
||||||
|
"Version": 3,
|
||||||
|
"EscapeCharacter": "\"",
|
||||||
|
"ReadMultiLines": false,
|
||||||
|
"KeepDiacritics": false,
|
||||||
|
"KeepPunctuations": false,
|
||||||
|
"AllowQuoting": false,
|
||||||
|
"Type": "TabularFile",
|
||||||
|
"FilePath": "C:\\Users\\marek\\source\\repos\\even-perfect-numbers-scanner\\BuildDivisorTransitions\\bin\\Release\\net8.0\\NextKForecastTraning.csv",
|
||||||
|
"Delimiter": ",",
|
||||||
|
"DecimalMarker": ".",
|
||||||
|
"HasHeader": true,
|
||||||
|
"ColumnProperties": [
|
||||||
|
{
|
||||||
|
"ColumnName": "p",
|
||||||
|
"ColumnPurpose": "Feature",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": false,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ColumnName": "divisor",
|
||||||
|
"ColumnPurpose": "Feature",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": false,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ColumnName": "lastDigit",
|
||||||
|
"ColumnPurpose": "Feature",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": true,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ColumnName": "k",
|
||||||
|
"ColumnPurpose": "Feature",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": false,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ColumnName": "lastMersenneDigit",
|
||||||
|
"ColumnPurpose": "Feature",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": true,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ColumnName": "isNextKHigher",
|
||||||
|
"ColumnPurpose": "Label",
|
||||||
|
"ColumnDataFormat": "Single",
|
||||||
|
"IsCategorical": true,
|
||||||
|
"Type": "Column",
|
||||||
|
"Version": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Environment": {
|
||||||
|
"Type": "LocalCPU",
|
||||||
|
"Version": 1
|
||||||
|
},
|
||||||
|
"RunHistory": {
|
||||||
|
"Version": 3,
|
||||||
|
"Type": "Result",
|
||||||
|
"Trials": [
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"Type": "Trial",
|
||||||
|
"TrainerName": "FastTreeRegression",
|
||||||
|
"Score": 0.30006118613190746,
|
||||||
|
"RuntimeInSeconds": 1.489,
|
||||||
|
"Parameter": {
|
||||||
|
"_SCHEMA_": "e0 * e1 * e2",
|
||||||
|
"e0": {
|
||||||
|
"OutputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e1": {
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"OutputColumnName": "Features"
|
||||||
|
},
|
||||||
|
"e2": {
|
||||||
|
"NumberOfLeaves": 4,
|
||||||
|
"MinimumExampleCountPerLeaf": 9,
|
||||||
|
"NumberOfTrees": 8,
|
||||||
|
"MaximumBinCountPerFeature": 317,
|
||||||
|
"FeatureFraction": 0.98434331463123226,
|
||||||
|
"LearningRate": 0.3857390791447961,
|
||||||
|
"LabelColumnName": "isNextKHigher",
|
||||||
|
"FeatureColumnName": "Features",
|
||||||
|
"DiskTranspose": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"Type": "Trial",
|
||||||
|
"TrainerName": "FastTreeRegression",
|
||||||
|
"Score": 0.299969238277351,
|
||||||
|
"RuntimeInSeconds": 1.496,
|
||||||
|
"Parameter": {
|
||||||
|
"_SCHEMA_": "e0 * e1 * e2",
|
||||||
|
"e0": {
|
||||||
|
"OutputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e1": {
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"OutputColumnName": "Features"
|
||||||
|
},
|
||||||
|
"e2": {
|
||||||
|
"NumberOfLeaves": 4,
|
||||||
|
"MinimumExampleCountPerLeaf": 9,
|
||||||
|
"NumberOfTrees": 8,
|
||||||
|
"MaximumBinCountPerFeature": 317,
|
||||||
|
"FeatureFraction": 0.98444606904931908,
|
||||||
|
"LearningRate": 0.38567641892007121,
|
||||||
|
"LabelColumnName": "isNextKHigher",
|
||||||
|
"FeatureColumnName": "Features",
|
||||||
|
"DiskTranspose": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"Type": "Trial",
|
||||||
|
"TrainerName": "FastTreeRegression",
|
||||||
|
"Score": 0.29992424440705012,
|
||||||
|
"RuntimeInSeconds": 0.993,
|
||||||
|
"Parameter": {
|
||||||
|
"_SCHEMA_": "e0 * e1 * e2",
|
||||||
|
"e0": {
|
||||||
|
"OutputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e1": {
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"OutputColumnName": "Features"
|
||||||
|
},
|
||||||
|
"e2": {
|
||||||
|
"NumberOfLeaves": 4,
|
||||||
|
"MinimumExampleCountPerLeaf": 9,
|
||||||
|
"NumberOfTrees": 8,
|
||||||
|
"MaximumBinCountPerFeature": 317,
|
||||||
|
"FeatureFraction": 0.98445819026817927,
|
||||||
|
"LearningRate": 0.38613186537816252,
|
||||||
|
"LabelColumnName": "isNextKHigher",
|
||||||
|
"FeatureColumnName": "Features",
|
||||||
|
"DiskTranspose": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"Type": "Trial",
|
||||||
|
"TrainerName": "FastTreeRegression",
|
||||||
|
"Score": 0.29992046748552242,
|
||||||
|
"RuntimeInSeconds": 1.389,
|
||||||
|
"Parameter": {
|
||||||
|
"_SCHEMA_": "e0 * e1 * e2",
|
||||||
|
"e0": {
|
||||||
|
"OutputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e1": {
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"OutputColumnName": "Features"
|
||||||
|
},
|
||||||
|
"e2": {
|
||||||
|
"NumberOfLeaves": 4,
|
||||||
|
"MinimumExampleCountPerLeaf": 9,
|
||||||
|
"NumberOfTrees": 8,
|
||||||
|
"MaximumBinCountPerFeature": 317,
|
||||||
|
"FeatureFraction": 0.984395476164661,
|
||||||
|
"LearningRate": 0.3858463322510558,
|
||||||
|
"LabelColumnName": "isNextKHigher",
|
||||||
|
"FeatureColumnName": "Features",
|
||||||
|
"DiskTranspose": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"Type": "Trial",
|
||||||
|
"TrainerName": "FastTreeRegression",
|
||||||
|
"Score": 0.29984566377505206,
|
||||||
|
"RuntimeInSeconds": 1.512,
|
||||||
|
"Parameter": {
|
||||||
|
"_SCHEMA_": "e0 * e1 * e2",
|
||||||
|
"e0": {
|
||||||
|
"OutputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e1": {
|
||||||
|
"InputColumnNames": [
|
||||||
|
"p",
|
||||||
|
"divisor",
|
||||||
|
"lastDigit",
|
||||||
|
"k",
|
||||||
|
"lastMersenneDigit"
|
||||||
|
],
|
||||||
|
"OutputColumnName": "Features"
|
||||||
|
},
|
||||||
|
"e2": {
|
||||||
|
"NumberOfLeaves": 4,
|
||||||
|
"MinimumExampleCountPerLeaf": 8,
|
||||||
|
"NumberOfTrees": 8,
|
||||||
|
"MaximumBinCountPerFeature": 317,
|
||||||
|
"FeatureFraction": 0.98439134546037266,
|
||||||
|
"LearningRate": 0.38521733136295422,
|
||||||
|
"LabelColumnName": "isNextKHigher",
|
||||||
|
"FeatureColumnName": "Features",
|
||||||
|
"DiskTranspose": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Estimators": {
|
||||||
|
"e0": "ReplaceMissingValues",
|
||||||
|
"e1": "Concatenate",
|
||||||
|
"e2": "FastTreeRegression",
|
||||||
|
"e3": "FastForestRegression",
|
||||||
|
"e4": "LightGbmRegression",
|
||||||
|
"e5": "LbfgsPoissonRegressionRegression",
|
||||||
|
"e6": "SdcaRegression"
|
||||||
|
},
|
||||||
|
"Schema": "e0 * e1 * (e2 + e3 + e4 + e5 + e6)",
|
||||||
|
"MetricName": "RSquared",
|
||||||
|
"ModelFilePath": "C:\\Users\\marek\\source\\repos\\even-perfect-numbers-scanner\\EvenPerfectBitScanner\\MLModel1.mlnet"
|
||||||
|
},
|
||||||
|
"Type": "TrainingConfig",
|
||||||
|
"Version": 5,
|
||||||
|
"TrainingOption": {
|
||||||
|
"Version": 2,
|
||||||
|
"Subsampling": false,
|
||||||
|
"Type": "RegressionTrainingOption",
|
||||||
|
"TrainingTime": 3600,
|
||||||
|
"LabelColumn": "isNextKHigher",
|
||||||
|
"ValidationOption": {
|
||||||
|
"Version": 0,
|
||||||
|
"Type": "CrossValidationValidationOption",
|
||||||
|
"NumberOfFolds": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,100 @@
|
|||||||
|
// This file was auto-generated by ML.NET Model Builder.
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.ML;
|
||||||
|
using Microsoft.ML.Data;
|
||||||
|
using Microsoft.ML.Trainers;
|
||||||
|
using Microsoft.ML.Trainers.FastTree;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner
|
||||||
|
{
|
||||||
|
public partial class MLModel1
|
||||||
|
{
|
||||||
|
public const string RetrainFilePath = @"C:\Users\marek\source\repos\even-perfect-numbers-scanner\BuildDivisorTransitions\bin\Release\net8.0\NextKForecastTraning.csv";
|
||||||
|
public const char RetrainSeparatorChar = ',';
|
||||||
|
public const bool RetrainHasHeader = true;
|
||||||
|
public const bool RetrainAllowQuoting = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Train a new model with the provided dataset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="outputModelPath">File path for saving the model. Should be similar to "C:\YourPath\ModelName.mlnet"</param>
|
||||||
|
/// <param name="inputDataFilePath">Path to the data file for training.</param>
|
||||||
|
/// <param name="separatorChar">Separator character for delimited training file.</param>
|
||||||
|
/// <param name="hasHeader">Boolean if training file has a header.</param>
|
||||||
|
public static void Train(string outputModelPath, string inputDataFilePath = RetrainFilePath, char separatorChar = RetrainSeparatorChar, bool hasHeader = RetrainHasHeader, bool allowQuoting = RetrainAllowQuoting)
|
||||||
|
{
|
||||||
|
var mlContext = new MLContext();
|
||||||
|
|
||||||
|
var data = LoadIDataViewFromFile(mlContext, inputDataFilePath, separatorChar, hasHeader, allowQuoting);
|
||||||
|
var model = RetrainModel(mlContext, data);
|
||||||
|
SaveModel(mlContext, model, data, outputModelPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load an IDataView from a file path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mlContext">The common context for all ML.NET operations.</param>
|
||||||
|
/// <param name="inputDataFilePath">Path to the data file for training.</param>
|
||||||
|
/// <param name="separatorChar">Separator character for delimited training file.</param>
|
||||||
|
/// <param name="hasHeader">Boolean if training file has a header.</param>
|
||||||
|
/// <returns>IDataView with loaded training data.</returns>
|
||||||
|
public static IDataView LoadIDataViewFromFile(MLContext mlContext, string inputDataFilePath, char separatorChar, bool hasHeader, bool allowQuoting)
|
||||||
|
{
|
||||||
|
return mlContext.Data.LoadFromTextFile<ModelInput>(inputDataFilePath, separatorChar, hasHeader, allowQuoting: allowQuoting);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save a model at the specified path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mlContext">The common context for all ML.NET operations.</param>
|
||||||
|
/// <param name="model">Model to save.</param>
|
||||||
|
/// <param name="data">IDataView used to train the model.</param>
|
||||||
|
/// <param name="modelSavePath">File path for saving the model. Should be similar to "C:\YourPath\ModelName.mlnet.</param>
|
||||||
|
public static void SaveModel(MLContext mlContext, ITransformer model, IDataView data, string modelSavePath)
|
||||||
|
{
|
||||||
|
// Pull the data schema from the IDataView used for training the model
|
||||||
|
DataViewSchema dataViewSchema = data.Schema;
|
||||||
|
|
||||||
|
using (var fs = File.Create(modelSavePath))
|
||||||
|
{
|
||||||
|
mlContext.Model.Save(model, dataViewSchema, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrain model using the pipeline generated as part of the training process.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mlContext"></param>
|
||||||
|
/// <param name="trainData"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ITransformer RetrainModel(MLContext mlContext, IDataView trainData)
|
||||||
|
{
|
||||||
|
var pipeline = BuildPipeline(mlContext);
|
||||||
|
var model = pipeline.Fit(trainData);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// build the pipeline that is used from model builder. Use this function to retrain model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mlContext"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEstimator<ITransformer> BuildPipeline(MLContext mlContext)
|
||||||
|
{
|
||||||
|
// Data process configuration with pipeline data transformations
|
||||||
|
var pipeline = mlContext.Transforms.ReplaceMissingValues(new []{new InputOutputColumnPair(@"p", @"p"),new InputOutputColumnPair(@"divisor", @"divisor"),new InputOutputColumnPair(@"lastDigit", @"lastDigit"),new InputOutputColumnPair(@"k", @"k"),new InputOutputColumnPair(@"lastMersenneDigit", @"lastMersenneDigit")})
|
||||||
|
.Append(mlContext.Transforms.Concatenate(@"Features", new []{@"p",@"divisor",@"lastDigit",@"k",@"lastMersenneDigit"}))
|
||||||
|
.Append(mlContext.Regression.Trainers.FastTree(new FastTreeRegressionTrainer.Options(){NumberOfLeaves=4,MinimumExampleCountPerLeaf=9,NumberOfTrees=8,MaximumBinCountPerFeature=317,FeatureFraction=0.9843433146312323,LearningRate=0.3857390791447961,LabelColumnName=@"isNextKHigher",FeatureColumnName=@"Features",DiskTranspose=false}));
|
||||||
|
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Resul
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Benchmarks", "EvenPerfectBitScanner.Benchmarks\EvenPerfectBitScanner.Benchmarks.csproj", "{83551FCC-41FA-4162-B541-AFCB5666A29F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Benchmarks", "EvenPerfectBitScanner.Benchmarks\EvenPerfectBitScanner.Benchmarks.csproj", "{83551FCC-41FA-4162-B541-AFCB5666A29F}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildDivisorTransitions", "BuildDivisorTransitions\BuildDivisorTransitions.csproj", "{0A936837-5082-4C0B-AC3B-840AD2E11057}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -47,5 +49,9 @@ Global
|
|||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0A936837-5082-4C0B-AC3B-840AD2E11057}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
Reference in new issue
Block a user