PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

PipelineSweeperMacro for Multi-Class Classification - #539

Merged
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy
Jul 19, 2018
Merged

PipelineSweeperMacro for Multi-Class Classification#539
abgoswam merged 5 commits into
dotnet:masterfrom
abgoswam:agoswami/micro_accuracy

Conversation

@abgoswam

@abgoswamabgoswam commented Jul 16, 2018

Copy link
Copy Markdown
Member

Fixes#538

  • The PipelineSweeper currently only supports AUC as the optimization metric. Trying to optimize on any other metric throws an exception.
  • Need to fix the way metrics are handled by the PipelineSweeper Macro.
  • Added a test case for MultiClass classification using the PipelineSweeper.

"sep=, col=age:R4:0 col=workclass:TX:1 col=fnlwgt:R4:2 col=education:TX:3 col=education_num:R4:4 col=marital_status:TX:5 col=occupation:TX:6 " +
"col=relationship:TX:7 col=ethnicity:TX:8 col=sex:TX:9 col=Features:R4:10-12 col=native_country:TX:13 col=IsOver50K_:R4:14 header=+";
var inputFileTrain = new SimpleFileHandle(Env, pathData, false, false);
#pragma warning disable 0618

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this necessary? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disables warning generated because of using ImportText (obsolete) instead of Textloader.

Perhaps in a future PR, we can update all the unit tests to use TextLoader. I can create a separate bug to track that.


In reply to: 202746784 [](ancestors = 202746784)

var runner = new GraphRunner(Env, catalog, graphJson[FieldNames.Nodes] as JArray);
runner.SetInput("TrainingData", datasetTrain);
runner.SetInput("TestingData", datasetTest);
runner.RunAll();

@sfilipisfilipiJul 16, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner.RunAll(); [](start = 12, length = 16)

do you think the test should have a check on the results, make sure they are the same all the time, at least. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the unit test.


In reply to: 202747140 [](ancestors = 202747140)

… MultiClassClassification; refactored out unit tests for the PipelineSweeper
@dnfclas

dnfclas commented Jul 17, 2018

Copy link
Copy Markdown

CLA assistant check
All CLA requirements met. #Resolved

@abgoswamabgoswam changed the title WIP . Fixes PipelineSweeperMacro for Multi-Class ClassificationFixes PipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
@abgoswamabgoswam changed the title Fixes PipelineSweeperMacro for Multi-Class ClassificationPipelineSweeperMacro for Multi-Class ClassificationJul 17, 2018
AutoInference.AutoMlMlState amlsOut = (AutoInference.AutoMlMlState)exp.GetOutput(output.State);
Assert.NotNull(amlsOut);
Assert.Equal(amlsOut.GetAllEvaluatedPipelines().Length, numIterations);
Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1);

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.True(amlsOut.GetBestPipeline().PerformanceSummary.MetricValue > 0.1); [](start = 15, length = 77)

does it make more sense to compare against a fixed number? that might be a stronger test.. #Resolved

ThreshAtNumPos = 25,
Nmi = 26,
AvgMinScore = 27,
Dbi = 28

@sfilipisfilipiJul 17, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= 28 [](start = 16, length = 4)

the numbers are implied, if they are just sequential. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they are auto generated by the CSharp API generator. We did not specify the numbers in the Enum.


In reply to: 203217022 [](ancestors = 203217022)

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we serialize the enum, I think we'd want a fixed number. This could be serialized as a state object for the sweep so that the user can resume the sweep w/ the history of the sweep stored on disk. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a general comment , or something that needs to be addressed ?

Btw, this is is auto generated file . The Enum you see here is defined in PipelineSweeperSupportedMetrics.cs


In reply to: 203267499 [](ancestors = 203267499)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a topic to consider for the future.
When we serialize the enum, we'll either have to serialize the numeric form or the text form. A numeric form will be more stable, and for that we'd have to assign the numbers in the primary definition of the enum.

/// <summary>
/// Mapp Enum Metrics to a SupportedMetric
/// </summary>
private static readonly Dictionary<string, SupportedMetric> _map = new Dictionary<string, SupportedMetric>

@sfilipisfilipiJul 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_map [](start = 67, length = 5)

if the only usage for this is to contain a list of known metrics, the enum might be enough.
Take a look at Enum.Parse. You can move the construction of new SupportedMetric in the GetSupportedMetric, if the conversion succeeds. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To specify the metric argument in the Macro we are using an Enum. That's the list of metrics you see in he CSharpApi.cs file. However, for parsing the results from the train test macro we need to use the metric names used by the ML.NET evaluators.

e.g. AcuracyMicro (Enum Argument) v/s 'Accuracy(micro-avg)' (Evaluator metric). This dictionary maps the two. Does that clarify why we need this mapping?


In reply to: 203217600 [](ancestors = 203217600)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Senja meant that the conversion from the enum to a string is not needed (see my comment below on the GetSupportedMetric method).


In reply to: 203220227 [](ancestors = 203220227,203217600)


using (var ch = _host.Start("Suggested Pipeline"))
{
ch.Info($"PipelineSweeper Pipeline Id : {pipeline.UniqueId}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also print an increasing pipeline number? This lets the user see the progress of the sweeping. #Resolved

}
ch.Info($"PipelineSweeper Learner : {pipeline.Learner}");
ch.Info($"PipelineSweeper Train Metric Value: {pipeline.PerformanceSummary.TrainingMetricValue}");
ch.Info($"PipelineSweeper Test Metric Value: {pipeline.PerformanceSummary.MetricValue}");

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're printing the primary sweeping metric here. How much work would it be to print all of the pipeline's metrics?

Generally when hand sweeping over a dataset, I'm watching multiple metrics. This is important as one metric often increases at the detriment of others.

For instance, micro & macro accuracy often trade-off as some models end-up better at smaller classes or the majority classes. The best models improve the metrics in unison. #Pending

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I need to explore how we can expose this functionality for the PipelineSweeper. One thing to note is that the other metrics would depend on the TrainerKind.

I have created a separate task (269949) for this. Would not want to block this PR on this feature ask.


In reply to: 203264334 [](ancestors = 203264334)

public abstract class AutoMlStateBase : ComponentKind {}

public enum AutoInferenceAutoMlMlStateArgumentsMetrics
public enum PipelineSweeperSupportedMetricsMetrics

@justinormontjustinormontJul 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't MetricsMetrics a bit odd sounding? #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the auto generated file (the CSharpAPI translation layer) .

The name here results from concatenating the following from PipelineSweeperSupportedMetrics.cs

public sealed class PipelineSweeperSupportedMetrics { public enum Metrics {

The name used for the class / enum look fine to me. Any alternate suggestions ?


In reply to: 203265071 [](ancestors = 203265071)

@shauheen

shauheen commented Jul 18, 2018

Copy link
Copy Markdown
Contributor

@abgoswam why do you have fixes issue number in quotes? That fails to make it actually associate this with #538 #Resolved

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env [](start = 74, length = 3)

Is this argument needed? If it's just used for the one check below, we can either have an IExceptionContext instead, or simply use Contracts.CheckNonEmpty(). #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the argument. Is there a suitable Contracts.Check* API that is used for an Enum argument?

For now, I just removed the Checks since the default for the switch/case will throw a NotSupportedException anyway


In reply to: 203461762 [](ancestors = 203461762)

{ Metrics.Dbi.ToString(), new SupportedMetric(FieldNames.PipelineSweeperSupportedMetrics.Dbi, false)}
};

public static SupportedMetric GetSupportedMetric(IHostEnvironment env, string metricName)

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string [](start = 79, length = 6)

You can pass a Metric here instead of a string, this way you won't need the dictionary, and instead just do a switch statement on the parameter. #Resolved

@abgoswamabgoswamJul 18, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Modified to using switch case as suggested.

In general, regarding usage of switch-case v.s. a dictionary mapping - is there some concrete benefit of using switch-case here or is it mostly a matter of personal preferance ?


In reply to: 203462492 [](ancestors = 203462492)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to avoid the dictionary & switch statement, you can just keep a whitelist of the maximizing metrics. In the GetSupportedMetric, you can retrieve the boolean from looking up the whitelist.


In reply to: 203543398 [](ancestors = 203543398,203462492)

@abgoswamabgoswamJul 19, 2018

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Senja. I intend to re-factor this code (task 267452).
I have added the metrics issue as part of the same task.

I want to unblock the benchmarking efforts . Is it fine if i keep it as switch-case for now?


In reply to: 203780367 [](ancestors = 203780367,203543398,203462492)

public AutoMlMlState(IHostEnvironment env, Arguments args)
: this(env, SupportedMetric.ByName(Enum.GetName(typeof(Arguments.Metrics), args.Metric)), args.Engine.CreateComponent(env),
: this(env,
PipelineSweeperSupportedMetrics.GetSupportedMetric(env, Enum.GetName(typeof(PipelineSweeperSupportedMetrics.Metrics), args.Metric)),

@yaeldekelyaeldekelJul 18, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum.GetName [](start = 78, length = 12)

If you change the GetSupportedMetric method to take the Metrics value, then you won't need this, you can just pass args.Metric. #Resolved

@abgoswam

Copy link
Copy Markdown
MemberAuthor

Thanks . I didn't realize the description had quotes till you pointed it out


In reply to: 405928784 [](ancestors = 405928784)

@sfilipisfilipi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@yaeldekelyaeldekel left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@abgoswam
abgoswam merged commit 8ce2a23 into dotnet:masterJul 19, 2018
@abgoswam

Copy link
Copy Markdown
MemberAuthor

thanks for the review comments. This PR is now merged.

eerhardt pushed a commit to eerhardt/machinelearning that referenced this pull request Jul 27, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
codemzs pushed a commit to codemzs/machinelearning that referenced this pull request Aug 1, 2018
* failing test case for multiclass
* Refactored PipelineSweeperSupportedMetrics Class; added unit test for MultiClassClassification; refactored out unit tests for the PipelineSweeper
* take care of review comments; display transforms/learners + metrics in pipeline
* taking care of PR comments + refactor PipelineSweeperRunSummary
* taking care of review comments
@ghostghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PipelineSweeping fails for MultiClass classification

6 participants

@abgoswam@dnfclas@shauheen@justinormont@yaeldekel@sfilipi