Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0
, '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

Trainer estimator cleanup for FastTrees and LightGBM - #1352

Merged
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup
Oct 27, 2018
Merged

Trainer estimator cleanup for FastTrees and LightGBM#1352
sfilipi merged 12 commits into
dotnet:masterfrom
sfilipi:trainerEstimatorCleanup

Conversation

@sfilipi

Copy link
Copy Markdown
Member

1- Adding the GroupId to the TrainerEstimatorBase class.
2- Adding the static xtensions for LightGM Multiclass and Ranking. Fixes#1314
3- Reorganizing the static and dynamic xtensions for FastTree and LightGBM

Addresses part of #1318

Adding tests, and refactoring catalog and pigsty statics
adding groupid to the trainer estimator base
refactoring the catalog and static extensions for trees
/// </summary>
/// <param name="weightColumn">name of the weight column</param>
public static SchemaShape.Column MakeR4ScalarWeightColumn(string weightColumn)
/// <param name="isExplicit">whether the column is implicitely, or explicitely defined</param>

@rauhsrauhsOct 24, 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.

Spelling: implicitly & explicitly #Closed

@sfilipisfilipi self-assigned this Oct 24, 2018
@sfilipisfilipi added the API Issues pertaining the friendly API label Oct 24, 2018
/// <summary>
/// The optional groupID column that the ranking trainers expects.
/// </summary>
public readonly SchemaShape.Column GroupIdColumn;

@Zruty0Zruty0Oct 24, 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.

GroupIdColumn [](start = 43, length = 13)

I am not sure I like the idea that every estimator will have the group ID column, but it only makes sense for ranking trainers. #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.

The alternative would be to modify the role mapped data after the estimator constructs it, and inject the groupId, and that feels error-prone. It's just one reference :)


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

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.

So we have a TrainerEstimatorBase, is there anything that prevents us from having another subclass, if we wanted to have additional roles? We may have to change something below to be a virtual method or have some other extension point, but I feel like this would be helpful anyway.

I am not really a fan of having a single utility base class handle everything, since if it is capable of doing everything I suspect it will become too unwieldly.


In reply to: 227895594 [](ancestors = 227895594,227866406)

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.

idk what i like less; the GroupId field here, or making MakeRoles protected virtual ... changing it anyways.


In reply to: 228312151 [](ancestors = 228312151,227895594,227866406)


internal static class LightGbmStaticsUtils {
/// <summary>
/// LightGbm <see cref="RankingContext"/> extension method.

@Zruty0Zruty0Oct 24, 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.

LightGbm extension method. [](start = 12, length = 55)

Change the summary to look like the below summary #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.

still here


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


if (advancedSettings != null)
CheckArgsAndAdvancedSettingMismatch(numLeaves, minDataPerLeaf, learningRate, numBoostRound, new LightGbmArguments(), Args);

@Zruty0Zruty0Oct 24, 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.

I think there has been a misconception.

It is OK to have the parameters (like numLeaves and learningRate) available in 2 places (inside Args and as a ctor argument.
The correct pattern is

varargs=newArguments();args.NumLeaves=numLeaves;args.LearningRate=learningRate;//...advancedSettings?.Invoke(args);

That is, we set the args' fields to the user-provided ctor arguments, and then let the user optionally change them again in the delegate: this is not a bug.

One exception is for column names: we are always ignoring the column names if they are set in the arguments. So I suggested to check (and throw) if the user sets something like FeatureColumn in the args to the value different to featureColumn ctor argument (as we will not respect that change).

Apparently, the latter is not yet done, and it's probably fine for now. But let's not check the other args. #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.

what I have been doing, is the exact opposite, and i do prefer that tbh because of two reasons:

1- We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so. I don;t think we should promote the buried arguments in favor of the ones that surfaced in the signature.

2- It keeps the behavior consistent with the column names.

cc @TomFinley for his opinion.


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

@TomFinleyTomFinleyOct 25, 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.

I am not a fan of enforcing a mismatch, since I could easily imagine situations where someone sets some reasonable arguments, but might thanks to some complicated logic decide to think better of it in the more complex setter.

However there is an addition point I wanted to address, since my first reaction is to disagree with it somewhat.

We do have parms in two places, and i think whenever we can deprecate those params from the arguments, we should do so.

I am strongly not in favor of this. I believe it is essential that the object with the advanced setting also continue to have the basic settings.

The reason is, a delegate for setting the object might be something used alongside the constructor, but in more programmatic, non-direct instantiation settings, especially in situations where several decisions have to be taken, it might be a real honest-to-god separate method living in a class somewhere. If the options argument has omitted the most common options, as suggested here, then we would force this scenario to spread its setting objects across two places, in a way that becomes suddenly rather more complex than just setting a bunch of properties in a single object.

A more minor consideration is that it seems more in-line with the idiom from ASP.NET, which is where @alexdegroot originally suggested we lift the idiom here.

My inclination therefore is to agree with @Zruty0 on this one, sorry @sfilipi. :)


In reply to: 227886248 [](ancestors = 227886248,227869641)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

thanks for the elaborate and convincing argument @tfinley@gmail.com. changing it everywhere.


In reply to: 228319239 [](ancestors = 228319239,227886248,227869641)

@Zruty0Zruty0 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.

🕐

/// <param name="columnName">name of the weight column</param>
public static SchemaShape.Column MakeU4ScalarColumn(string columnName)
{
if (columnName == null)

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this check needed? It looks like SchemaShape.Column constructor also checks the name for null or empty string. #Resolved

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yep, because the check inside the constructor will throw if we pass null.


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

/// </summary>
/// <param name="ctx">The <see cref="BinaryClassificationContext"/>.</param>
/// <param name="label">The label column.</param>
/// <param name="features">The features colum.</param>

@singlissinglisOct 24, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

column, same on the other function comments. #Resolved

bool enforceNoNegativity)
: this(env, ArgsInit(featureColumn, labelColumn, weightColumn, advancedSettings), labelColumn,
l1Weight, l2Weight, optimizationTolerance, memorySize, enforceNoNegativity)
: this(env, new TArgs(), labelColumn,

@sfilipisfilipiOct 26, 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.

TArgs() [](start = 27, length = 8)

this needs to get all the other parameters in #Resolved

if (Args.LearningRates != learningRate)
{
using (var ch = Host.Start($"Setting learning rate to: {learningRate} as supplied in the direct arguments."))
Args.LearningRates = learningRate;

@Zruty0Zruty0Oct 27, 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.

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

indenting #Resolved

@Zruty0Zruty0 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:

/// <param name="labelColumn">The name of the label column.</param>
/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor nit, the ordering of parameters, minDocumentsInLeafs and learningRate. #Resolved

/// <param name="featureColumn">The name of the feature column.</param>
/// <param name="groupIdColumn">The name for the column containing the group ID.</param>
/// <param name="weightColumn">The name for the column containing the initial weight.</param>
/// <param name="learningRate">The learning rate.</param>

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ordering of parameters here too. #Resolved


internal class FastTreeStaticsUtils
{
internal static void CheckUserValues(PipelineColumn label, Vector<float> features, Scalar<float> weights,

@singlissinglisOct 27, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here... #Resolved

/// The columns names, however need to be provided directly, not through the <paramref name="advancedSettings"/>.</param>
public LinearClassificationTrainer(IHostEnvironment env,
string featureColumn,
string featureColumn,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

indent is off here

@singlissinglis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - I have a few minor nit picks on formatting.

@sfilipi
sfilipi merged commit 5123aee into dotnet:masterOct 27, 2018
@sfilipi

Copy link
Copy Markdown
MemberAuthor

thank you for reviewing @singlis and @Zruty0

@sfilipi
sfilipi deleted the trainerEstimatorCleanup branch October 27, 2018 06:00
@ghostghost locked as resolved and limited conversation to collaborators Mar 27, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@sfilipi@TomFinley@rauhs@singlis@Zruty0