Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka
, '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

Replace SubComponent with IComponentFactory in ML.Ensemble - #681

Merged
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent
Aug 17, 2018
Merged

Replace SubComponent with IComponentFactory in ML.Ensemble#681
eerhardt merged 8 commits into
dotnet:masterfrom
eerhardt:EnsembleSubComponent

Conversation

@eerhardt

Copy link
Copy Markdown
Member

The next round of SubComponent removal. Now the ML.Ensemble project is SubComponent free.

Working towards #585

Note: I had to move the Argument class's fields down to the concrete class because of the way we handle SignatureType. You can use a generic type in an attribute. However, this allowed me to remove the TSig type on the base classes, which is nice since the signature Type shouldn't be in the public API.

<ProjectReference Include="..\Microsoft.ML.Data\Microsoft.ML.Data.csproj" />
<ProjectReference Include="..\Microsoft.ML.StandardLearners\Microsoft.ML.StandardLearners.csproj" />
<ProjectReference Include="..\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj" />
<ProjectReference Include="..\Microsoft.ML.FastTree\Microsoft.ML.FastTree.csproj" />

@TomFinleyTomFinleyAug 15, 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.

[](start = 4, length = 84)

We need this due to the usage of FastTree as the default traniner for some ensemble classes. This could be fine, but I wonder if using something from StandardLearners might make a bit more sense, if we envision that someday FastTree will be factored into a separate nuget package. (Maybe we don't want that though, in which case this dependency is probably fine.) #Resolved

@eerhardteerhardtAug 15, 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.

One advantage to this change is that it brings to light these dependencies. Before we had a weakly-typed dependency using strings and DI. So if we ever did refactor FastTree to be separate, we could have easily broken this dependency.

I've logged #682 for this issue. #Resolved

@TomFinleyTomFinleyAug 16, 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.

Thanks @eerhardt ... yes I expect we'll see some more of this "hidden dependency" becoming exposed as we move away from direct usage of subcomponents and dependency injection. I recall a similar issue in #446 with the normalizers being defined in Microsoft.ML.Transforms and used in Microsoft.ML.Data, despite the former project depending on the latter. 😄 #Resolved

{
using TScalarPredictor = IPredictorProducing<Single>;

public sealed class RegressionStacking : BaseScalarStacking<SignatureRegressorTrainer>, IRegressionOutputCombiner, ICanSaveModel

@TomFinleyTomFinleyAug 15, 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.

SignatureRegressorTrainer [](start = 64, length = 25)

What are we going to do about this sort of restriction? I had suggested previously using something like ITrainer<IRegressionPredictor> or something like this, but I'm not sure what you thought of that idea. #Resolved

@eerhardteerhardtAug 16, 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.

Which restriction are you referring to? The Signature Type restriction, where we can't use typeof(TSig) in an attribute?

My hope is that some day we remove signature types all together. I haven't thought of/discovered a good replacement for them yet. Maybe an approach similar to ComponentKind which is just a string "Kind".

However, that still wouldn't help in this case, because we need a different signature/kind/etc for each concrete class, but we want to define the argument on the base class. #Resolved

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.

I meant just restricting the DI and API usage to only consider actual, in this case, regression trainers, which is one of the functions of the signatures. Currently this is done in a fairly half-hearted fashion using this IPredictorProducing<float> and IPredictorProducing<VBuffer<float>>, but if we got rid of this and replaced it with, say, IRegressionPredictor and IBinaryClassificationPredictor and IMulticlassPredictor (or something like that), then we could just have this be c omponent factory producing ITrainer<IRegressionPredictor> in this case. I think MEF should work well with that restriction as well, from a DI perspective.


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

{
get { return BasePredictorType; }
set { BasePredictorType = value; }
}

@TomFinleyTomFinleyAug 15, 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.

Hmmm. It seems like this boilerplate is necessarily only because ArgumentAttribute cannot be applied to properties, so we have to declare this backing field, which is then exposed through the property. If that is so, maybe we ought to just allow it to be applied to properties and change the command line parsing code to handle properties as well as fields, so we can avoid this awkwardness. #Resolved

@eerhardteerhardtAug 16, 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.

As we discussed offline, I changed this to internal, since Stacking doesn't allow external inheritors anyway. I also changed it to a method, since the base class only needs to retrieve the component factories. #Resolved

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

This can be sealed I hope? #Closed

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.

fixed.


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

/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>
{
private Func<IHostEnvironment, TComponent> _factory;

@TomFinleyTomFinleyAug 15, 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.

private Func<IHostEnvironment, TComponent> _factory; [](start = 8, length = 52)

readonly? #Closed

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.

fixed.


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

/// A class for creating a component with no extra parameters (other than an <see cref="IHostEnvironment"/>)
/// that simply wraps a delegate which creates the component.
/// </summary>
public class SimpleComponentFactory<TComponent> : IComponentFactory<TComponent>

@TomFinleyTomFinleyAug 15, 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.

public class SimpleComponentFactory [](start = 4, length = 35)

I'm somewhat reluctant to expose more public types in addition to IComponentFactory -- maybe if we just had something simple like a static creation class that returned IComponentFactory, with things like:

publicstaticclassComponentFactoryUtils{publicstaticIComponentFactory<TComponent>CreateFromFunction(Func<IHostEnvironment,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TComponent>factory){ ...}publicstaticIComponentFactory<TArg1,TArg2,TComponent>CreateFromFunction(Func<IHostEnvironment,TArg1,TArg2,TComponent>factory){ ...}}

Then we could hide the actual implementations of these.
#Closed

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 a good idea. It also simplifies the call sites, in some cases, since the types can be inferred. Fixed.


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

@TomFinley

TomFinley commented Aug 15, 2018

Copy link
Copy Markdown
Contributor
{

As a side effect to my earlier comment, we could then get rid of this funny little thing. #Closed


Refers to: src/Microsoft.ML.Core/EntryPoints/ComponentFactory.cs:65 in 84119d3. [](commit_id = 84119d3, deletion_comment = False)


public SimpleComponentFactory(Func<IHostEnvironment, TArg1, TComponent> factory)
/// <summary>
/// A utility class for creating IComponentFactory instances.

@TomFinleyTomFinleyAug 16, 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.

IComponentFactory [](start = 37, length = 17)

Might prefer this to be in <see tag or something. #Resolved

@TomFinleyTomFinley left a comment

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.

:shipit:

@@ -83,10 +83,9 @@ public virtual void CalculateMetrics(FeatureSubsetModel<IPredictorProducing<TOut
IDataScorerTransform scorePipe = ScoreUtils.GetScorer(model.Predictor, testData, Host, testData.Schema);
// REVIEW: Should we somehow allow the user to customize the evaluator?
// By what mechanism should we allow that?

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.

I think this comment need to be moved to few line below

using Microsoft.ML.Ensemble.EntryPoints;
using Microsoft.ML.Runtime.Internal.Internallearn;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.Learners;

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.

need some sorting

@Ivanidzo4kaIvanidzo4ka left a comment

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.

:shipit:

@eerhardt
eerhardt merged commit 94401d5 into dotnet:masterAug 17, 2018
@eerhardt
eerhardt deleted the EnsembleSubComponent branch August 17, 2018 22:03
@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.

3 participants

@eerhardt@TomFinley@Ivanidzo4ka