diff --git a/Microsoft.ML.sln b/Microsoft.ML.sln index 8b6a05ffda..5b90ca306b 100644 --- a/Microsoft.ML.sln +++ b/Microsoft.ML.sln @@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.AutoML", "src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.AutoML.Samples", "docs\samples\Microsoft.ML.AutoML.Samples\Microsoft.ML.AutoML.Samples.csproj", "{A6924919-9E37-4023-8B7F-E85C8E3CC9B3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.AutoML.Interactive", "src\Microsoft.ML.AutoML.Interactive\Microsoft.ML.AutoML.Interactive.csproj", "{3B00090A-B5E4-4570-BCD0-B4CD5D499394}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.Samples.GPU", "docs\samples\Microsoft.ML.Samples.GPU\Microsoft.ML.Samples.GPU.csproj", "{3C8F910B-7F23-4D25-B521-6D5AC9570ADD}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.Featurizers", "src\Microsoft.ML.Featurizers\Microsoft.ML.Featurizers.csproj", "{E2DD0721-5B0F-4606-8182-4C7EFB834518}" @@ -155,7 +157,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.SearchSpace.Te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.AutoML.SourceGenerator", "tools-local\Microsoft.ML.AutoML.SourceGenerator\Microsoft.ML.AutoML.SourceGenerator.csproj", "{C804B990-390E-41D7-8FF1-6774495D70E2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ML.TorchSharp", "src\Microsoft.ML.TorchSharp\Microsoft.ML.TorchSharp.csproj", "{FF0BD187-4451-4A3B-934B-2AE3454896E2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.TorchSharp", "src\Microsoft.ML.TorchSharp\Microsoft.ML.TorchSharp.csproj", "{FF0BD187-4451-4A3B-934B-2AE3454896E2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -597,6 +599,14 @@ Global {A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|Any CPU.Build.0 = Release|Any CPU {A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|x64.ActiveCfg = Release|Any CPU {A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|x64.Build.0 = Release|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|x64.ActiveCfg = Debug|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|x64.Build.0 = Debug|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|Any CPU.Build.0 = Release|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|x64.ActiveCfg = Release|Any CPU + {3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|x64.Build.0 = Release|Any CPU {3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -796,6 +806,7 @@ Global {C2652287-CD6D-40FB-B042-95FB56D09DB8} = {AED9C836-31E3-4F3F-8ABC-929555D3F3C4} {E48285BF-F49A-4EA3-AED0-1BDDBF77EB80} = {09EADF06-BE25-4228-AB53-95AE3E15B530} {A6924919-9E37-4023-8B7F-E85C8E3CC9B3} = {DA452A53-2E94-4433-B08C-041EDEC729E6} + {3B00090A-B5E4-4570-BCD0-B4CD5D499394} = {09EADF06-BE25-4228-AB53-95AE3E15B530} {3C8F910B-7F23-4D25-B521-6D5AC9570ADD} = {DA452A53-2E94-4433-B08C-041EDEC729E6} {E2DD0721-5B0F-4606-8182-4C7EFB834518} = {09EADF06-BE25-4228-AB53-95AE3E15B530} {56CB0850-7341-4D71-9AE4-9EFC472D93DD} = {09EADF06-BE25-4228-AB53-95AE3E15B530} diff --git a/eng/Versions.props b/eng/Versions.props index da4fc00545..5178e7ece8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -35,8 +35,8 @@ 2.3.1 3.3.0 3.9.0 - 1.0.0-beta.22103.1 - 1.0.0-beta.22103.1 + 1.0.0-beta.22314.1 + 1.0.0-beta.22314.1 0.4.1 1.10.0 0.0.0.12 @@ -44,6 +44,7 @@ 2.1.0 10.0.3 2.1.3 + 0.0.1 1.3.3 0.20.1 2 diff --git a/src/Microsoft.ML.AutoML.Interactive/ActionThrottler.cs b/src/Microsoft.ML.AutoML.Interactive/ActionThrottler.cs new file mode 100644 index 0000000000..16c15b947a --- /dev/null +++ b/src/Microsoft.ML.AutoML.Interactive/ActionThrottler.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.ML.AutoML +{ + internal class ActionThrottler + { + private readonly Action _action; + private readonly TimeSpan _minDelay; + + private DateTime _nextUpdateTime = DateTime.MinValue; + private int _updatePending = 0; + + /// + /// This constructor initializes an ActionThrottler that ensures runs no more than once per . + /// + /// The action to thorttle. + /// Timespan to indicate the minimum delay between each time action is executed. + public ActionThrottler(Action action, TimeSpan minDelay) + { + _minDelay = minDelay; + _action = action; + } + + + public async Task ExecuteAsync() + { + if (Interlocked.CompareExchange(ref _updatePending, 1, 0) == 0) // _updatePending is int initialized with 0 + { + DateTime currentTime = DateTime.UtcNow; + + if (_nextUpdateTime > currentTime) + { + await Task.Delay(_nextUpdateTime - currentTime); + } + _action(); + _nextUpdateTime = DateTime.UtcNow + _minDelay; + _updatePending = 0; + } + } + } +} diff --git a/src/Microsoft.ML.AutoML.Interactive/AutoMLMonitorKernelExtension.cs b/src/Microsoft.ML.AutoML.Interactive/AutoMLMonitorKernelExtension.cs new file mode 100644 index 0000000000..7868a24b4c --- /dev/null +++ b/src/Microsoft.ML.AutoML.Interactive/AutoMLMonitorKernelExtension.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.AspNetCore.Html; +using Microsoft.Data.Analysis; +using Microsoft.DotNet.Interactive; +using Microsoft.DotNet.Interactive.Commands; +using Microsoft.DotNet.Interactive.Formatting; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using Plotly.NET.CSharp; +using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; + + +namespace Microsoft.ML.AutoML +{ + public class AutoMLMonitorKernelExtension : IKernelExtension + { + public async Task OnLoadAsync(Kernel kernel) + { + Formatter.Register((monitor, writer) => + { + WriteSummary(monitor, writer); + WriteChart(monitor, writer); + WriteTable(monitor, writer); + }, "text/html"); + + if (Kernel.Root?.FindKernel("csharp") is { } csKernel) + { + await LoadExtensionApiAsync(csKernel); + } + } + + private static async Task LoadExtensionApiAsync(Kernel cSharpKernel) + { + await cSharpKernel.SendAsync(new SubmitCode($@"#r ""{typeof(AutoMLMonitorKernelExtension).Assembly.Location}"" +using {typeof(NotebookMonitor).Namespace};")); + } + + private static void WriteSummary(NotebookMonitor monitor, TextWriter writer) + { + + var summary = new List(); + + if (monitor.BestTrial != null) + { + var bestTrialParam = JsonSerializer.Serialize(monitor.BestTrial.TrialSettings.Parameter, new JsonSerializerOptions() { WriteIndented = true, }); + summary.Add(h3("Best Trial")); + summary.Add(p($"Id: {monitor.BestTrial.TrialSettings.TrialId}")); + summary.Add(p($"Trainer: {monitor.BestTrial.TrialSettings.Pipeline}".Replace("Unknown=>", ""))); + summary.Add(p($"Parameters: {bestTrialParam}")); + } + if (monitor.ActiveTrial != null) + { + + var activeTrialParam = JsonSerializer.Serialize(monitor.ActiveTrial.Parameter, new JsonSerializerOptions() { WriteIndented = true, }); + + summary.Add(h3("Active Trial")); + summary.Add(p($"Id: {monitor.ActiveTrial.TrialId}")); + summary.Add(p($"Trainer: {monitor.ActiveTrial.Pipeline}".Replace("Unknown=>", ""))); + summary.Add(p($"Parameters: {activeTrialParam}")); + } + + writer.Write(div(summary)); + } + + private static void WriteChart(NotebookMonitor monitor, TextWriter writer) + { + var x = monitor.CompletedTrials.Select(x => x.TrialSettings.TrialId); + var y = monitor.CompletedTrials.Select(x => x.Metric); + + var chart = Chart.Point(x, y, "Plot Metrics over Trials.") + .WithTraceInfo(ShowLegend: false) + .WithXAxisStyle(TitleText: "Trial", ShowGrid: false) + .WithYAxisStyle(TitleText: "Metric", ShowGrid: false); + + var chartHeader = new List(); + chartHeader.Add(h3("Plot Metrics over Trials")); + writer.Write(div(chartHeader)); + + + Formatter.GetPreferredFormatterFor(typeof(Plotly.NET.GenericChart.GenericChart), "text/html").Format(chart, writer); + + // Works around issue with earlier versions of Plotly.NET - https://github.com/plotly/Plotly.NET/pull/305 + if (writer.ToString().EndsWith(""); + } + } + + private static void WriteTable(NotebookMonitor notebookMonitor, TextWriter writer) + { + var tableHeader = new List(); + tableHeader.Add(h3("All Trials Table")); + writer.Write(div(tableHeader)); + Formatter.GetPreferredFormatterFor(typeof(DataFrame), "text/html").Format(notebookMonitor.TrialData, writer); + } + } +} diff --git a/src/Microsoft.ML.AutoML.Interactive/Microsoft.ML.AutoML.Interactive.csproj b/src/Microsoft.ML.AutoML.Interactive/Microsoft.ML.AutoML.Interactive.csproj new file mode 100644 index 0000000000..15040401ee --- /dev/null +++ b/src/Microsoft.ML.AutoML.Interactive/Microsoft.ML.AutoML.Interactive.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + false + + + + + + + + + + + + + + + diff --git a/src/Microsoft.ML.AutoML.Interactive/NotebookMonitor.cs b/src/Microsoft.ML.AutoML.Interactive/NotebookMonitor.cs new file mode 100644 index 0000000000..6e401d87d7 --- /dev/null +++ b/src/Microsoft.ML.AutoML.Interactive/NotebookMonitor.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.DotNet.Interactive; +using System.Collections.Generic; +using Microsoft.Data.Analysis; +using System; +using System.Threading.Tasks; +using System.Text.Json; +using System.Threading; + +namespace Microsoft.ML.AutoML +{ + public class NotebookMonitor : IMonitor + { + private readonly ActionThrottler _updateThrottler; + private DisplayedValue _valueToUpdate; + + public TrialResult BestTrial { get; set; } + public TrialResult MostRecentTrial { get; set; } + public TrialSettings ActiveTrial { get; set; } + public List CompletedTrials { get; set; } + public DataFrame TrialData { get; set; } + + public NotebookMonitor() + { + CompletedTrials = new List(); + TrialData = new DataFrame(new PrimitiveDataFrameColumn("Trial"), new PrimitiveDataFrameColumn("Metric"), new StringDataFrameColumn("Trainer"), new StringDataFrameColumn("Parameters")); + _updateThrottler = new ActionThrottler(Update, TimeSpan.FromSeconds(5)); + } + + public void ReportBestTrial(TrialResult result) + { + BestTrial = result; + + ThrottledUpdate(); + } + + public void ReportCompletedTrial(TrialResult result) + { + MostRecentTrial = result; + CompletedTrials.Add(result); + + var activeRunParam = JsonSerializer.Serialize(result.TrialSettings.Parameter, new JsonSerializerOptions() { WriteIndented = false, }); + + TrialData.Append(new List>() + { + new KeyValuePair("Trial",result.TrialSettings.TrialId), + new KeyValuePair("Metric", result.Metric), + new KeyValuePair("Trainer",result.TrialSettings.Pipeline.ToString().Replace("Unknown=>","")), + new KeyValuePair("Parameters",activeRunParam), + }, true); + + ThrottledUpdate(); + } + + public void ReportFailTrial(TrialResult result) + { + // TODO figure out what to do with failed trials. + ThrottledUpdate(); + } + + public void ReportRunningTrial(TrialSettings setting) + { + ActiveTrial = setting; + ThrottledUpdate(); + } + + private void ThrottledUpdate() + { + Task.Run(async () => await _updateThrottler.ExecuteAsync()); + } + + public void Update() + { + _valueToUpdate.Update(this); + } + + public void SetUpdate(DisplayedValue valueToUpdate) + { + _valueToUpdate = valueToUpdate; + ThrottledUpdate(); + } + } +} diff --git a/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj b/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj index 36a14ec5ce..2a223df06f 100644 --- a/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj +++ b/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj @@ -6,8 +6,29 @@ Microsoft.ML.AutoML ML.NET AutoML: Optimizes an ML pipeline for your dataset, by automatically locating the best feature engineering, model, and hyperparameters $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage + + + $(NoWarn);1591;NU5100 + $(TargetsForTfmSpecificContentInPackage);AddAutoMLInteractiveToInteractiveExtensionsFolder + + + + + + + + + + <_ItemsToIncludeForInteractive Update="@(_ItemsToIncludeForInteractive)" PackagePath="interactive-extensions/dotnet" /> + + + +