Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ML.NET is a cross-platform, open-source machine learning framework for .NET. It

- .NET SDK version selected by `global.json`
- Build system: Microsoft Arcade SDK (`eng/common/`)
- Test framework: xUnit (with `AwesomeAssertions`, `Xunit.Combinatorial`)
- Test framework: xUnit (with `Xunit.Combinatorial`)
- Native dependencies: MKL, OpenMP, libmf, oneDNN
- Major dependencies: TorchSharp, ONNX Runtime, TensorFlow, LightGBM
- Central package management: `Directory.Packages.props`
Expand Down Expand Up @@ -136,7 +136,7 @@ public class MyFeatureTests : TestDataPipeBase

Name test classes as `{Feature}Tests`, test methods as PascalCase descriptive names (e.g., `RandomizedPcaTrainerBaselineTest`). Do not use `Test_` prefixes or `_Should_` patterns.

Use `Assert.*` (xUnit) or `AwesomeAssertions` for fluent assertions. Do not use `Assert.That` (NUnit style).
Use the built-in `Assert.*` (xUnit) assertions. Do not use `Assert.That` (NUnit style) or additional assertion libraries.

Test data: use `Microsoft.ML.TestDatabases` package or files in `test/data/`, referenced via `GetDataPath("filename")` from the base class. Baseline output comparison uses files in `test/BaselineOutput/`. Update baselines carefully since they are the source of truth for output format stability.

Expand Down
1 change: 0 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@

<!-- Test-only dependencies -->
<PackageVersion Include="ApprovalTests" Version="$(ApprovalTestsVersion)" />
<PackageVersion Include="AwesomeAssertions" Version="$(AwesomeAssertionsVersion)" />
<PackageVersion Include="BenchmarkDotNet" Version="$(BenchmarkDotNetVersion)" />
<PackageVersion Include="BenchmarkDotNet.Diagnostics.Windows" Version="$(BenchmarkDotNetVersion)" />
<PackageVersion Include="coverlet.collector" Version="$(CoverletCollectorVersion)" />
Expand Down
24 changes: 14 additions & 10 deletions docs/specs/ML.Net Sweepable API.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Search space defines a range of hyper-parameter for tuner to search from. Sweepa

via attribute
```csharp
using Xunit;

public class Option
{
[Range(2, 32768, init: 2, logBase: true)]
Expand All @@ -31,17 +33,19 @@ var ss = new SearchSpace<Option>();
var parameter = ss.SampleFromFeatureSpace(new []{0,0,0,0,0,0});

// auto-binding
parameter.WindowSize.Should().Be(2);
parameter.SeriesLength.Should().Be(2);
parameter.UseSoftmax.Should().BeTrue();
parameter.AnotherOption.WindowSize.Should().Be(2);
Assert.Equal(2, parameter.WindowSize);
Assert.Equal(2, parameter.SeriesLength);
Assert.True(parameter.UseSoftmax);
Assert.Equal(2, parameter.AnotherOption.WindowSize);

// search space can also map parameter back to feature space
ss.MappingToFeatureSpace(parameter).Should().BeEquivalantTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
Assert.Equivalent(new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, ss.MappingToFeatureSpace(parameter), strict: true);
```

or correspondingly, via scratch
``` csharp
using Xunit;

var ss = new SearchSpace();
ss.Add("WindowSize", new UniformIntOption(2, 32768, true, 2));
ss.Add("SeriesLength", new ChoiceOption(2,3,4));
Expand All @@ -51,13 +55,13 @@ ss.Add("AnotherOption", ss.Clone());
var parameter = ss.SampleFromFeatureSpace(new []{0,0,0,0,0,0});

// auto-binding doesn't exist for scratch api
parameter["WindowSize"].AsType<int>.Should().Be(2);
parameter["SeriesLength"].AsType<int>.Should().Be(2);
parameter["UseSoftmax"].AsType<bool>.Should().BeTrue();
parameter["AnotherOption"]["WindowSize"].AsType<int>.Should().Be(2);
Assert.Equal(2, parameter["WindowSize"].AsType<int>());
Assert.Equal(2, parameter["SeriesLength"].AsType<int>());
Assert.True(parameter["UseSoftmax"].AsType<bool>());
Assert.Equal(2, parameter["AnotherOption"]["WindowSize"].AsType<int>());

// search space can also map parameter back to feature space
ss.MappingToFeatureSpace(parameter).Should().BeEquivalantTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
Assert.Equivalent(new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, ss.MappingToFeatureSpace(parameter), strict: true);
```

Currently, in order to make auto-binding work, there's a limitation on the parameter type that can be added to search space, which has to be either a Json primitive type or a nested search space.
Expand Down
1 change: 0 additions & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
<BenchmarkDotNetVersion>0.13.12</BenchmarkDotNetVersion>
<DotNetRuntime60Version>6.0.36</DotNetRuntime60Version>
<DotNetRuntime80Version>8.0.16</DotNetRuntime80Version>
<AwesomeAssertionsVersion>8.1.0</AwesomeAssertionsVersion>
<MicrosoftCodeAnalysisTestingVersion>1.1.2</MicrosoftCodeAnalysisTestingVersion>
<MicrosoftDotNetBuildTasksTemplatingVersion>9.0.0-beta.24212.4</MicrosoftDotNetBuildTasksTemplatingVersion>
<MicrosoftDotNetPlatformAbstractionsVersion>5.0.0-preview.5.20278.1</MicrosoftDotNetPlatformAbstractionsVersion>
Expand Down
12 changes: 7 additions & 5 deletions src/Microsoft.ML.SearchSpace/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Provides some basic tuning algoritions (GridSearch, etc..)
## Examples

``` csharp
using Xunit;

private class BasicSearchSpace
{
[Range(-1000, 1000, init: 0)]
Expand Down Expand Up @@ -55,17 +57,17 @@ var tuner = new DefaultValueTuner(ss);

// Get one sampling result from tuner
BasicSearchSpace param = tuner.Propose();
// param.UniformInt.Should().Be(0);
// param.ChoiceStr.Should().Be("a"); // no default value designate for ChoiceStr, so the first value will be used.
// param.NestSS.UniformInt.Should().Be(0);
// Assert.Equal(0, param.UniformInt);
// Assert.Equal("a", param.ChoiceStr); // no default value designate for ChoiceStr, so the first value will be used.
// Assert.Equal(0, param.NestSS.UniformInt);

// Or you can also sample from scratch
// The feature of ss is a 4-d [0, 1) vector.
BasicSearchSpace param2 = ss.SampleFromFeatureSpace(new[] {0.5, 0, 0.5, 0});
// (param == param2).Should().BeTrue();
// Assert.True(param == param2);

// You can also map param back to feature space
ss.MappingToFeatureSpace(param).Should().BeEquivalentTo(0.5, 0, 0.5, 0);
Assert.Equivalent(new[] { 0.5, 0, 0.5, 0 }, ss.MappingToFeatureSpace(param), strict: true);
```


9 changes: 4 additions & 5 deletions test/Microsoft.ML.AutoML.Tests/AutoFitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Globalization;
using System.Linq;
using System.Threading;
using FluentAssertions;
using Microsoft.ML.Data;
using Microsoft.ML.Runtime;
using Microsoft.ML.TestFramework;
Expand Down Expand Up @@ -85,7 +84,7 @@ public void AutoFit_UCI_Adult_AutoZero_Test()
var result = context.Auto()
.CreateBinaryClassificationExperiment(settings)
.Execute(trainData, new ColumnInformation() { LabelColumnName = DatasetUtil.UciAdultLabel });
result.BestRun.ValidationMetrics.Accuracy.Should().BeGreaterThanOrEqualTo(0.7);
Assert.True(result.BestRun.ValidationMetrics.Accuracy >= 0.7);
Assert.NotNull(result.BestRun.Estimator);
Assert.NotNull(result.BestRun.Model);
Assert.NotNull(result.BestRun.TrainerName);
Expand Down Expand Up @@ -285,7 +284,7 @@ public void AutoFitMultiTest(bool useNumberOfCVFolds)
.CreateMulticlassClassificationExperiment(settings)
.Execute(trainData, numberOfCVFolds, DatasetUtil.TrivialMulticlassDatasetLabel);

result.BestRun.Results.First().ValidationMetrics.MicroAccuracy.Should().BeGreaterThan(0.7);
Assert.True(result.BestRun.Results.First().ValidationMetrics.MicroAccuracy > 0.7);
var scoredData = result.BestRun.Results.First().Model.Transform(trainData);
Assert.Equal(NumberDataViewType.Single, scoredData.Schema[DefaultColumnNames.PredictedLabel].Type);

Expand Down Expand Up @@ -347,7 +346,7 @@ public void AutoFitMultiClassification_Image_TrainTest()
.CreateMulticlassClassificationExperiment(settings)
.Execute(trainDataset, testDataset, columnInference.ColumnInformation);

result.BestRun.ValidationMetrics.MicroAccuracy.Should().BeGreaterThan(0.1);
Assert.True(result.BestRun.ValidationMetrics.MicroAccuracy > 0.1);

var scoredData = result.BestRun.Model.Transform(trainData);
Assert.Equal(TextDataViewType.Instance, scoredData.Schema[DefaultColumnNames.PredictedLabel].Type);
Expand All @@ -370,7 +369,7 @@ public void AutoFitMultiClassification_Image_CV()
.CreateMulticlassClassificationExperiment(settings)
.Execute(trainData, 5, columnInference.ColumnInformation);

result.BestRun.Results.Select(x => x.ValidationMetrics.MicroAccuracy).Max().Should().BeGreaterThan(0.1);
Assert.True(result.BestRun.Results.Select(x => x.ValidationMetrics.MicroAccuracy).Max() > 0.1);

var scoredData = result.BestRun.Results.First().Model.Transform(trainData);
Assert.Equal(TextDataViewType.Instance, scoredData.Schema[DefaultColumnNames.PredictedLabel].Type);
Expand Down
51 changes: 23 additions & 28 deletions test/Microsoft.ML.AutoML.Tests/AutoMLExperimentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Data.Analysis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ML.AutoML.CodeGen;
Expand Down Expand Up @@ -54,9 +53,7 @@ public async Task AutoMLExperiment_throw_timeout_exception_when_ct_is_canceled_a
}
};

var runExperimentAction = async () => await experiment.RunAsync(cts.Token);

await runExperimentAction.Should().ThrowExactlyAsync<TimeoutException>();
await Assert.ThrowsAsync<TimeoutException>(() => experiment.RunAsync(cts.Token));
}

[Fact]
Expand Down Expand Up @@ -84,8 +81,7 @@ public async Task AutoMLExperiment_cancel_trial_when_exceeds_memory_limit_Async(
.SetTuner<RandomSearchTuner>()
.SetMaximumMemoryUsageInMegaByte(0.01);

var runExperimentAction = async () => await experiment.RunAsync();
await runExperimentAction.Should().ThrowExactlyAsync<TimeoutException>();
await Assert.ThrowsAsync<TimeoutException>(() => experiment.RunAsync());
}

[LightGBMFact]
Expand All @@ -111,8 +107,7 @@ public async Task AutoMLExperiment_lgbm_cancel_trial_when_exceeds_memory_limit_A
.SetTrainingTimeInSeconds(10)
.SetMaximumMemoryUsageInMegaByte(10);

var runExperimentAction = async () => await experiment.RunAsync();
await runExperimentAction.Should().ThrowExactlyAsync<TimeoutException>();
await Assert.ThrowsAsync<TimeoutException>(() => experiment.RunAsync());
}

[Fact]
Expand Down Expand Up @@ -143,9 +138,9 @@ public async Task AutoMLExperiment_return_current_best_trial_when_ct_is_canceled
var res = await experiment.RunAsync(cts.Token);

stopWatch.Stop();
stopWatch.ElapsedMilliseconds.Should().BeLessThanOrEqualTo(5000);
cts.IsCancellationRequested.Should().BeTrue();
res.Metric.Should().BeGreaterThan(0);
Assert.True(stopWatch.ElapsedMilliseconds <= 5000);
Assert.True(cts.IsCancellationRequested);
Assert.True(res.Metric > 0);
}

[Fact]
Expand Down Expand Up @@ -174,8 +169,8 @@ public async Task AutoMLExperiment_finish_training_when_time_is_up_Async()
cts.CancelAfter(100 * 1000);

var res = await experiment.RunAsync(cts.Token);
res.Metric.Should().BeGreaterThan(0);
cts.IsCancellationRequested.Should().BeFalse();
Assert.True(res.Metric > 0);
Assert.False(cts.IsCancellationRequested);
cts.Dispose();
}

Expand All @@ -202,7 +197,7 @@ public async Task AutoMLExperiment_finish_training_when_reach_to_max_model_async
}
};
await experiment.RunAsync();
runModelCounts.Should().Be(5);
Assert.Equal(5, runModelCounts);
}


Expand All @@ -228,7 +223,7 @@ public async Task AutoMLExperiment_UCI_Adult_Train_Test_Split_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.8);
Assert.True(result.Metric > 0.8);
}

[Fact(Skip = "skip in CI build")]
Expand All @@ -253,7 +248,7 @@ public async Task AutoMLExperiment_UCI_Adult_Fairlearn_Test()
.SetMaxModelToExplore(100);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.8);
Assert.True(result.Metric > 0.8);
}

[Fact]
Expand All @@ -278,7 +273,7 @@ public async Task AutoMLExperiment_UCI_Adult_CV_5_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.8);
Assert.True(result.Metric > 0.8);
}

[Fact]
Expand All @@ -305,7 +300,7 @@ public async Task AutoMLExperiment_Iris_CV_5_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.8);
Assert.True(result.Metric > 0.8);
}

[Fact]
Expand All @@ -332,7 +327,7 @@ public async Task AutoMLExperiment_Iris_Train_Test_Split_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.8);
Assert.True(result.Metric > 0.8);
}

[Fact]
Expand All @@ -359,7 +354,7 @@ public async Task AutoMLExperiment_Taxi_Fare_Train_Test_Split_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.5);
Assert.True(result.Metric > 0.5);

// test subsamping
experiment = context.Auto().CreateExperiment();
Expand All @@ -368,9 +363,9 @@ public async Task AutoMLExperiment_Taxi_Fare_Train_Test_Split_Test()
.SetPipeline(pipeline)
.SetMaxModelToExplore(1);
result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.5);
result.TrialSettings.Parameter[nameof(TrainValidateDatasetManager)]["TrainValidateDatasetSubsamplingKey"]
.AsType<float>().Should().Be(0.1f);
Assert.True(result.Metric > 0.5);
Assert.Equal(0.1f, result.TrialSettings.Parameter[nameof(TrainValidateDatasetManager)]["TrainValidateDatasetSubsamplingKey"]
.AsType<float>());
}

[Fact]
Expand All @@ -389,7 +384,7 @@ public async Task AutoMLExperiment_Taxi_Fare_CV_5_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.5);
Assert.True(result.Metric > 0.5);
}

[Fact]
Expand All @@ -408,8 +403,8 @@ public async Task AutoMLExperiment_Taxi_Fare_CV_5_SamplingKey_Test()
.SetMaxModelToExplore(1);

var result = await experiment.RunAsync();
result.Metric.Should().BeGreaterThan(0.2);
result.Metric.Should().BeLessThan(0.5);
Assert.True(result.Metric > 0.2);
Assert.True(result.Metric < 0.5);
}

[Fact]
Expand All @@ -418,12 +413,12 @@ public void AutoMLExperiment_should_use_seed_from_context_if_provided()
var context = new MLContext();
var experiment = context.Auto().CreateExperiment();
var settings = experiment.ServiceCollection.BuildServiceProvider().GetRequiredService<AutoMLExperiment.AutoMLExperimentSettings>();
settings.Seed.Should().BeNull();
Assert.Null(settings.Seed);

context = new MLContext(1);
experiment = context.Auto().CreateExperiment();
settings = experiment.ServiceCollection.BuildServiceProvider().GetRequiredService<AutoMLExperiment.AutoMLExperimentSettings>();
settings.Seed.Should().Be(1);
Assert.Equal(1, settings.Seed);
}
}

Expand Down
7 changes: 3 additions & 4 deletions test/Microsoft.ML.AutoML.Tests/ColumnInferenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using ApprovalTests;
using ApprovalTests.Namers;
using ApprovalTests.Reporters;
using FluentAssertions;
using Microsoft.ML.Data;
using Microsoft.ML.TestFramework;
using Newtonsoft.Json;
Expand Down Expand Up @@ -205,9 +204,9 @@ public void TrySplitColumns_should_split_on_dataset_with_newline_between_double_
var sample = TextFileSample.CreateFromFullFile(dataset);
var result = TextFileContents.TrySplitColumns(context, sample, TextFileContents.DefaultSeparators);

result.ColumnCount.Should().Be(4);
result.Separator.Should().Be(',');
result.IsSuccess.Should().BeTrue();
Assert.Equal(4, result.ColumnCount);
Assert.Equal(',', result.Separator);
Assert.True(result.IsSuccess);
}

[Fact]
Expand Down
Loading