Skip to content

Commit 924ae7a

Browse files
authored
Add AutoML Interactive Extension (#6243)
* Initial check-in of AutoML Interactive Extension * Remove warning disable code * clean up warnings * Add chart header and work around Plotly.NET issue. * Fix chart title. * Improve styling and add header to Table. * Update comments and remove some items from NoWarn. * Remove trailing semicolon * Resolve PR feedback * Move _updatePending = false outside of if check. * Resolve PR Feedback * Pull out ActionThrottler into class and fix delay bug.
1 parent 10f68a3 commit 924ae7a

File tree

7 files changed

+295
-3
lines changed

7 files changed

+295
-3
lines changed

Microsoft.ML.sln

+12-1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.AutoML", "src\
121121
EndProject
122122
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}"
123123
EndProject
124+
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}"
125+
EndProject
124126
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}"
125127
EndProject
126128
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
155157
EndProject
156158
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}"
157159
EndProject
158-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ML.TorchSharp", "src\Microsoft.ML.TorchSharp\Microsoft.ML.TorchSharp.csproj", "{FF0BD187-4451-4A3B-934B-2AE3454896E2}"
160+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.TorchSharp", "src\Microsoft.ML.TorchSharp\Microsoft.ML.TorchSharp.csproj", "{FF0BD187-4451-4A3B-934B-2AE3454896E2}"
159161
EndProject
160162
Global
161163
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -597,6 +599,14 @@ Global
597599
{A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|Any CPU.Build.0 = Release|Any CPU
598600
{A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|x64.ActiveCfg = Release|Any CPU
599601
{A6924919-9E37-4023-8B7F-E85C8E3CC9B3}.Release|x64.Build.0 = Release|Any CPU
602+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
603+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|Any CPU.Build.0 = Debug|Any CPU
604+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|x64.ActiveCfg = Debug|Any CPU
605+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Debug|x64.Build.0 = Debug|Any CPU
606+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|Any CPU.ActiveCfg = Release|Any CPU
607+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|Any CPU.Build.0 = Release|Any CPU
608+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|x64.ActiveCfg = Release|Any CPU
609+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394}.Release|x64.Build.0 = Release|Any CPU
600610
{3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
601611
{3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU
602612
{3C8F910B-7F23-4D25-B521-6D5AC9570ADD}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -796,6 +806,7 @@ Global
796806
{C2652287-CD6D-40FB-B042-95FB56D09DB8} = {AED9C836-31E3-4F3F-8ABC-929555D3F3C4}
797807
{E48285BF-F49A-4EA3-AED0-1BDDBF77EB80} = {09EADF06-BE25-4228-AB53-95AE3E15B530}
798808
{A6924919-9E37-4023-8B7F-E85C8E3CC9B3} = {DA452A53-2E94-4433-B08C-041EDEC729E6}
809+
{3B00090A-B5E4-4570-BCD0-B4CD5D499394} = {09EADF06-BE25-4228-AB53-95AE3E15B530}
799810
{3C8F910B-7F23-4D25-B521-6D5AC9570ADD} = {DA452A53-2E94-4433-B08C-041EDEC729E6}
800811
{E2DD0721-5B0F-4606-8182-4C7EFB834518} = {09EADF06-BE25-4228-AB53-95AE3E15B530}
801812
{56CB0850-7341-4D71-9AE4-9EFC472D93DD} = {09EADF06-BE25-4228-AB53-95AE3E15B530}

eng/Versions.props

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,16 @@
3535
<LightGBMVersion>2.3.1</LightGBMVersion>
3636
<MicrosoftCodeAnalysisAnalyzersVersion>3.3.0</MicrosoftCodeAnalysisAnalyzersVersion>
3737
<MicrosoftCodeAnalysisCSharpVersion>3.9.0</MicrosoftCodeAnalysisCSharpVersion>
38-
<MicrosoftDotNetInteractiveFormattingVersion>1.0.0-beta.22103.1</MicrosoftDotNetInteractiveFormattingVersion>
39-
<MicrosoftDotNetInteractiveVersion>1.0.0-beta.22103.1</MicrosoftDotNetInteractiveVersion>
38+
<MicrosoftDotNetInteractiveFormattingVersion>1.0.0-beta.22314.1</MicrosoftDotNetInteractiveFormattingVersion>
39+
<MicrosoftDotNetInteractiveVersion>1.0.0-beta.22314.1</MicrosoftDotNetInteractiveVersion>
4040
<MicrosoftMLFeaturizersVersion>0.4.1</MicrosoftMLFeaturizersVersion>
4141
<MicrosoftMLOnnxRuntimeVersion>1.10.0</MicrosoftMLOnnxRuntimeVersion>
4242
<MlNetMklDepsVersion>0.0.0.12</MlNetMklDepsVersion>
4343
<MSTestTestAdapterVersion>2.1.0</MSTestTestAdapterVersion>
4444
<MSTestTestFrameworkVersion>2.1.0</MSTestTestFrameworkVersion>
4545
<NewtonsoftJsonVersion>10.0.3</NewtonsoftJsonVersion>
4646
<ParquetDotNetVersion>2.1.3</ParquetDotNetVersion>
47+
<PlotlyNETCSharpVersion>0.0.1</PlotlyNETCSharpVersion>
4748
<SharpZipLibVersion>1.3.3</SharpZipLibVersion>
4849
<TensorflowDotNETVersion>0.20.1</TensorflowDotNETVersion>
4950
<TensorFlowMajorVersion>2</TensorFlowMajorVersion>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
12+
namespace Microsoft.ML.AutoML
13+
{
14+
internal class ActionThrottler
15+
{
16+
private readonly Action _action;
17+
private readonly TimeSpan _minDelay;
18+
19+
private DateTime _nextUpdateTime = DateTime.MinValue;
20+
private int _updatePending = 0;
21+
22+
/// <summary>
23+
/// This constructor initializes an ActionThrottler that ensures <paramref name="action"/> runs no more than once per <paramref name="minDelay"/>.
24+
/// </summary>
25+
/// <param name="action">The action to thorttle.</param>
26+
/// <param name="minDelay">Timespan to indicate the minimum delay between each time action is executed.</param>
27+
public ActionThrottler(Action action, TimeSpan minDelay)
28+
{
29+
_minDelay = minDelay;
30+
_action = action;
31+
}
32+
33+
34+
public async Task ExecuteAsync()
35+
{
36+
if (Interlocked.CompareExchange(ref _updatePending, 1, 0) == 0) // _updatePending is int initialized with 0
37+
{
38+
DateTime currentTime = DateTime.UtcNow;
39+
40+
if (_nextUpdateTime > currentTime)
41+
{
42+
await Task.Delay(_nextUpdateTime - currentTime);
43+
}
44+
_action();
45+
_nextUpdateTime = DateTime.UtcNow + _minDelay;
46+
_updatePending = 0;
47+
}
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.AspNetCore.Html;
6+
using Microsoft.Data.Analysis;
7+
using Microsoft.DotNet.Interactive;
8+
using Microsoft.DotNet.Interactive.Commands;
9+
using Microsoft.DotNet.Interactive.Formatting;
10+
using System.Collections.Generic;
11+
using System.IO;
12+
using System.Linq;
13+
using System.Text.Json;
14+
using System.Threading.Tasks;
15+
using Plotly.NET.CSharp;
16+
using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags;
17+
18+
19+
namespace Microsoft.ML.AutoML
20+
{
21+
public class AutoMLMonitorKernelExtension : IKernelExtension
22+
{
23+
public async Task OnLoadAsync(Kernel kernel)
24+
{
25+
Formatter.Register<NotebookMonitor>((monitor, writer) =>
26+
{
27+
WriteSummary(monitor, writer);
28+
WriteChart(monitor, writer);
29+
WriteTable(monitor, writer);
30+
}, "text/html");
31+
32+
if (Kernel.Root?.FindKernel("csharp") is { } csKernel)
33+
{
34+
await LoadExtensionApiAsync(csKernel);
35+
}
36+
}
37+
38+
private static async Task LoadExtensionApiAsync(Kernel cSharpKernel)
39+
{
40+
await cSharpKernel.SendAsync(new SubmitCode($@"#r ""{typeof(AutoMLMonitorKernelExtension).Assembly.Location}""
41+
using {typeof(NotebookMonitor).Namespace};"));
42+
}
43+
44+
private static void WriteSummary(NotebookMonitor monitor, TextWriter writer)
45+
{
46+
47+
var summary = new List<IHtmlContent>();
48+
49+
if (monitor.BestTrial != null)
50+
{
51+
var bestTrialParam = JsonSerializer.Serialize(monitor.BestTrial.TrialSettings.Parameter, new JsonSerializerOptions() { WriteIndented = true, });
52+
summary.Add(h3("Best Trial"));
53+
summary.Add(p($"Id: {monitor.BestTrial.TrialSettings.TrialId}"));
54+
summary.Add(p($"Trainer: {monitor.BestTrial.TrialSettings.Pipeline}".Replace("Unknown=>", "")));
55+
summary.Add(p($"Parameters: {bestTrialParam}"));
56+
}
57+
if (monitor.ActiveTrial != null)
58+
{
59+
60+
var activeTrialParam = JsonSerializer.Serialize(monitor.ActiveTrial.Parameter, new JsonSerializerOptions() { WriteIndented = true, });
61+
62+
summary.Add(h3("Active Trial"));
63+
summary.Add(p($"Id: {monitor.ActiveTrial.TrialId}"));
64+
summary.Add(p($"Trainer: {monitor.ActiveTrial.Pipeline}".Replace("Unknown=>", "")));
65+
summary.Add(p($"Parameters: {activeTrialParam}"));
66+
}
67+
68+
writer.Write(div(summary));
69+
}
70+
71+
private static void WriteChart(NotebookMonitor monitor, TextWriter writer)
72+
{
73+
var x = monitor.CompletedTrials.Select(x => x.TrialSettings.TrialId);
74+
var y = monitor.CompletedTrials.Select(x => x.Metric);
75+
76+
var chart = Chart.Point<int, double, string>(x, y, "Plot Metrics over Trials.")
77+
.WithTraceInfo(ShowLegend: false)
78+
.WithXAxisStyle<double, double, string>(TitleText: "Trial", ShowGrid: false)
79+
.WithYAxisStyle<double, double, string>(TitleText: "Metric", ShowGrid: false);
80+
81+
var chartHeader = new List<IHtmlContent>();
82+
chartHeader.Add(h3("Plot Metrics over Trials"));
83+
writer.Write(div(chartHeader));
84+
85+
86+
Formatter.GetPreferredFormatterFor(typeof(Plotly.NET.GenericChart.GenericChart), "text/html").Format(chart, writer);
87+
88+
// Works around issue with earlier versions of Plotly.NET - https://github.com/plotly/Plotly.NET/pull/305
89+
if (writer.ToString().EndsWith("</div \r\n"))
90+
{
91+
writer.Write(">");
92+
}
93+
}
94+
95+
private static void WriteTable(NotebookMonitor notebookMonitor, TextWriter writer)
96+
{
97+
var tableHeader = new List<IHtmlContent>();
98+
tableHeader.Add(h3("All Trials Table"));
99+
writer.Write(div(tableHeader));
100+
Formatter.GetPreferredFormatterFor(typeof(DataFrame), "text/html").Format(notebookMonitor.TrialData, writer);
101+
}
102+
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<IsPackable>false</IsPackable>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.DotNet.Interactive" Version="$(MicrosoftDotNetInteractiveVersion)" />
10+
<PackageReference Include="Microsoft.DotNet.Interactive.Formatting" Version="$(MicrosoftDotNetInteractiveFormattingVersion)" />
11+
<PackageReference Include="Plotly.NET.CSharp" Version="$(PlotlyNETCSharpVersion)" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\Microsoft.ML.SearchSpace\Microsoft.ML.SearchSpace.csproj" />
16+
<ProjectReference Include="..\Microsoft.Data.Analysis\Microsoft.Data.Analysis.csproj" />
17+
<ProjectReference Include="..\Microsoft.ML.AutoML\Microsoft.ML.AutoML.csproj" />
18+
</ItemGroup>
19+
20+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.DotNet.Interactive;
6+
using System.Collections.Generic;
7+
using Microsoft.Data.Analysis;
8+
using System;
9+
using System.Threading.Tasks;
10+
using System.Text.Json;
11+
using System.Threading;
12+
13+
namespace Microsoft.ML.AutoML
14+
{
15+
public class NotebookMonitor : IMonitor
16+
{
17+
private readonly ActionThrottler _updateThrottler;
18+
private DisplayedValue _valueToUpdate;
19+
20+
public TrialResult BestTrial { get; set; }
21+
public TrialResult MostRecentTrial { get; set; }
22+
public TrialSettings ActiveTrial { get; set; }
23+
public List<TrialResult> CompletedTrials { get; set; }
24+
public DataFrame TrialData { get; set; }
25+
26+
public NotebookMonitor()
27+
{
28+
CompletedTrials = new List<TrialResult>();
29+
TrialData = new DataFrame(new PrimitiveDataFrameColumn<int>("Trial"), new PrimitiveDataFrameColumn<float>("Metric"), new StringDataFrameColumn("Trainer"), new StringDataFrameColumn("Parameters"));
30+
_updateThrottler = new ActionThrottler(Update, TimeSpan.FromSeconds(5));
31+
}
32+
33+
public void ReportBestTrial(TrialResult result)
34+
{
35+
BestTrial = result;
36+
37+
ThrottledUpdate();
38+
}
39+
40+
public void ReportCompletedTrial(TrialResult result)
41+
{
42+
MostRecentTrial = result;
43+
CompletedTrials.Add(result);
44+
45+
var activeRunParam = JsonSerializer.Serialize(result.TrialSettings.Parameter, new JsonSerializerOptions() { WriteIndented = false, });
46+
47+
TrialData.Append(new List<KeyValuePair<string, object>>()
48+
{
49+
new KeyValuePair<string, object>("Trial",result.TrialSettings.TrialId),
50+
new KeyValuePair<string, object>("Metric", result.Metric),
51+
new KeyValuePair<string, object>("Trainer",result.TrialSettings.Pipeline.ToString().Replace("Unknown=>","")),
52+
new KeyValuePair<string, object>("Parameters",activeRunParam),
53+
}, true);
54+
55+
ThrottledUpdate();
56+
}
57+
58+
public void ReportFailTrial(TrialResult result)
59+
{
60+
// TODO figure out what to do with failed trials.
61+
ThrottledUpdate();
62+
}
63+
64+
public void ReportRunningTrial(TrialSettings setting)
65+
{
66+
ActiveTrial = setting;
67+
ThrottledUpdate();
68+
}
69+
70+
private void ThrottledUpdate()
71+
{
72+
Task.Run(async () => await _updateThrottler.ExecuteAsync());
73+
}
74+
75+
public void Update()
76+
{
77+
_valueToUpdate.Update(this);
78+
}
79+
80+
public void SetUpdate(DisplayedValue valueToUpdate)
81+
{
82+
_valueToUpdate = valueToUpdate;
83+
ThrottledUpdate();
84+
}
85+
}
86+
}

src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj

+21
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,29 @@
66
<IncludeInPackage>Microsoft.ML.AutoML</IncludeInPackage>
77
<PackageDescription>ML.NET AutoML: Optimizes an ML pipeline for your dataset, by automatically locating the best feature engineering, model, and hyperparameters</PackageDescription>
88
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
9+
10+
<!--
11+
1591: Documentation warnings
12+
NU5100: Warning that gets triggered because a .dll is not placed under lib folder on package. This is by design as we want AutoML Interactive to be under interactive-extensions folder.
13+
-->
14+
<NoWarn>$(NoWarn);1591;NU5100</NoWarn>
15+
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);AddAutoMLInteractiveToInteractiveExtensionsFolder</TargetsForTfmSpecificContentInPackage>
16+
917
</PropertyGroup>
1018

19+
<!-- The following properties are set to package AutoML Interactive with the AutoML nuget package. If AutoML Interactive undergoes TFM or dependency changes, we need to update the TargetFramework passed in below-->
20+
<Target Name="AddAutoMLInteractiveToInteractiveExtensionsFolder">
21+
<MSBuild Projects="./../Microsoft.ML.AutoML.Interactive/Microsoft.ML.AutoML.Interactive.csproj" Targets="_GetBuildOutputFilesWithTfm" Properties="TargetFramework=net6.0">
22+
<!-- Manually hardcoding the TargetFramework to net6.0 as that is the one that AutoML Interactive targets -->
23+
<Output TaskParameter="TargetOutputs" ItemName="_ItemsToIncludeForInteractive" />
24+
</MSBuild>
25+
26+
<ItemGroup>
27+
<_ItemsToIncludeForInteractive Update="@(_ItemsToIncludeForInteractive)" PackagePath="interactive-extensions/dotnet" />
28+
<TfmSpecificPackageFile Include="@(_ItemsToIncludeForInteractive)" />
29+
</ItemGroup>
30+
</Target>
31+
1132
<ItemGroup>
1233
<ProjectReference Include="..\..\tools-local\Microsoft.ML.AutoML.SourceGenerator\Microsoft.ML.AutoML.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
1334
<ProjectReference Include="..\Microsoft.ML.Core\Microsoft.ML.Core.csproj">

0 commit comments

Comments
 (0)