From c8e75201e4717e47407c86e1c171dfb05291459d Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 27 Aug 2026 10:55:09 +0200 Subject: [PATCH 1/3] Stabilize SDCA logistic regression test Make strict quality assertions deterministic and retain explicit coverage of multithreaded SDCA training. Fixes #7343. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cf5862a0-24ff-48b6-bd23-a5fa8d0053f7 --- .../TrainerEstimators/SdcaTests.cs | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs index 159f341071..29370c7426 100644 --- a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs +++ b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs @@ -72,7 +72,14 @@ public void SdcaLogisticRegression() // Step 2: Create a binary classifier. // We set the "Label" column as the label of the dataset, and the "Features" column as the features column. - var pipeline = mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features", l2Regularization: 0.001f); + var pipeline = mlContext.BinaryClassification.Trainers.SdcaLogisticRegression( + new SdcaLogisticRegressionBinaryTrainer.Options + { + LabelColumnName = "Label", + FeatureColumnName = "Features", + L2Regularization = 0.001f, + NumberOfThreads = 1 + }); // Step 3: Train the pipeline created. var model = pipeline.Fit(data); @@ -97,6 +104,37 @@ public void SdcaLogisticRegression() Assert.InRange(first.Probability, 0.8, 1); } + [Fact] + public void SdcaLogisticRegressionMultithreaded() + { + // Keep coverage of the nondeterministic parallel path while the quality test above remains deterministic. + // See https://github.com/dotnet/machinelearning/blob/240a849becda954f3e17d39f7606328be3a7f0de/src/Microsoft.ML.StandardTrainers/Standard/SdcaBinary.cs#L180-L188. + var rawData = SamplesUtils.DatasetUtils.GenerateBinaryLabelFloatFeatureVectorFloatWeightSamples(100); + var mlContext = new MLContext(1); + var data = mlContext.Data.Cache(mlContext.Data.LoadFromEnumerable(rawData)); + var pipeline = mlContext.BinaryClassification.Trainers.SdcaLogisticRegression( + new SdcaLogisticRegressionBinaryTrainer.Options + { + LabelColumnName = "Label", + FeatureColumnName = "Features", + L2Regularization = 0.001f, + NumberOfThreads = 4 + }); + + var transformedData = pipeline.Fit(data).Transform(data); + var predictions = mlContext.Data.CreateEnumerable(transformedData, false).ToArray(); + + Assert.Equal(100, predictions.Length); + Assert.All(predictions, prediction => + { + Assert.False(float.IsNaN(prediction.Score)); + Assert.False(float.IsInfinity(prediction.Score)); + Assert.InRange(prediction.Probability, 0, 1); + }); + Assert.True(predictions.Where(prediction => prediction.Label).Average(prediction => prediction.Score) > + predictions.Where(prediction => !prediction.Label).Average(prediction => prediction.Score)); + } + [Fact] public void SdcaLogisticRegressionWithWeight() { From 7ee0e5fd23dbca13ae375de8fd3ecec803429e6a Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 27 Aug 2026 13:06:54 +0200 Subject: [PATCH 2/3] Strengthen multithreaded SDCA validation Require the four-thread trainer to preserve the original AUC quality and outperform a featureless prior model on LogLoss. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cf5862a0-24ff-48b6-bd23-a5fa8d0053f7 --- .../TrainerEstimators/SdcaTests.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs index 29370c7426..26ddb3f624 100644 --- a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs +++ b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs @@ -122,17 +122,12 @@ public void SdcaLogisticRegressionMultithreaded() }); var transformedData = pipeline.Fit(data).Transform(data); - var predictions = mlContext.Data.CreateEnumerable(transformedData, false).ToArray(); + var metrics = mlContext.BinaryClassification.Evaluate(transformedData); + var priorModel = mlContext.BinaryClassification.Trainers.Prior().Fit(data); + var priorMetrics = mlContext.BinaryClassification.Evaluate(priorModel.Transform(data)); - Assert.Equal(100, predictions.Length); - Assert.All(predictions, prediction => - { - Assert.False(float.IsNaN(prediction.Score)); - Assert.False(float.IsInfinity(prediction.Score)); - Assert.InRange(prediction.Probability, 0, 1); - }); - Assert.True(predictions.Where(prediction => prediction.Label).Average(prediction => prediction.Score) > - predictions.Where(prediction => !prediction.Label).Average(prediction => prediction.Score)); + Assert.InRange(metrics.AreaUnderRocCurve, 0.9, 1); + Assert.True(metrics.LogLoss < priorMetrics.LogLoss); } [Fact] From 6b91e62e9813d4ae046fd810d94670596a473ef0 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 27 Aug 2026 15:27:26 +0200 Subject: [PATCH 3/3] Document multithreaded SDCA test flow Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cf5862a0-24ff-48b6-bd23-a5fa8d0053f7 --- .../TrainerEstimators/SdcaTests.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs index 26ddb3f624..9e5585b766 100644 --- a/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs +++ b/test/Microsoft.ML.Tests/TrainerEstimators/SdcaTests.cs @@ -109,9 +109,17 @@ public void SdcaLogisticRegressionMultithreaded() { // Keep coverage of the nondeterministic parallel path while the quality test above remains deterministic. // See https://github.com/dotnet/machinelearning/blob/240a849becda954f3e17d39f7606328be3a7f0de/src/Microsoft.ML.StandardTrainers/Standard/SdcaBinary.cs#L180-L188. + + // Generate C# objects as training examples. var rawData = SamplesUtils.DatasetUtils.GenerateBinaryLabelFloatFeatureVectorFloatWeightSamples(100); + + // Create a new context for ML.NET operations. var mlContext = new MLContext(1); + + // Step 1: Read and cache the data as an IDataView. var data = mlContext.Data.Cache(mlContext.Data.LoadFromEnumerable(rawData)); + + // Step 2: Create a binary classifier that exercises the parallel training path. var pipeline = mlContext.BinaryClassification.Trainers.SdcaLogisticRegression( new SdcaLogisticRegressionBinaryTrainer.Options { @@ -121,11 +129,15 @@ public void SdcaLogisticRegressionMultithreaded() NumberOfThreads = 4 }); + // Step 3: Train and evaluate the classifier on the training data. var transformedData = pipeline.Fit(data).Transform(data); var metrics = mlContext.BinaryClassification.Evaluate(transformedData); + + // Step 4: Evaluate a featureless classifier as a quality baseline. var priorModel = mlContext.BinaryClassification.Trainers.Prior().Fit(data); var priorMetrics = mlContext.BinaryClassification.Evaluate(priorModel.Transform(data)); + // Verify the multithreaded classifier learns the signal in the generated data. Assert.InRange(metrics.AreaUnderRocCurve, 0.9, 1); Assert.True(metrics.LogLoss < priorMetrics.LogLoss); }