Skip to content

SDCA Regression and BinaryClassification Pigsty extensions #837

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 6, 2018

Conversation

TomFinley
Copy link
Contributor

Related to the closed #632 and the API overall. In here I introduce extensions for SDCA regression and binary classification. (No multiclass until I also write extensions for term.)

This also includes a sort of general purpose utilities for writing reconcilers for trainers, though, again, only regression, binary classification, and binary classification without probabilities so far.

Also a minor change to the linear classification trainer, as it was not identifying that it was producing probabilities sometimes.

/// Constructor for the base class.
/// </summary>
/// <param name="inputs">The set of inputs</param>
/// <param name="outputNames">The names of the outputs, which we assume cannot be changed</param>
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

real question: do we put a period in the sentences of the

section, but not in the sentences in ? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having complete sentences in the summary is essential. About params, I'm less sure about that, but I think I prefer to have them, I'll try to add them.


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

namespace Microsoft.ML.Data.StaticPipe.Runtime
{
/// <summary>
/// General purpose reconciler for a typical case with trainers, where they accept some generally
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

reconciler [](start = 24, length = 10)

I am still fuzzy on the purpose of reconcilers. Is it a bridge from estimators to trainers? #Closed

Copy link
Contributor Author

@TomFinley TomFinley Sep 5, 2018

Choose a reason for hiding this comment

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

Hi @sfilipi thanks for the question -- I covered this somewhat in #632, in particular, if you check out the section "one or two implementation details," paragraphs 2 through 4 of that section deal with the role of reconcilers. (As does I suppose the XML docs for reconcilers.)

The idea is that, the user has declaratively defined their delegate where they define what they want done, and the analyzer that calls that delegate does a lot of work to determine what should go where, but at the final last step there has to be something responsible for actually creating those IEstimator (or, in some cases, IDataReaderEstimator) objects. That thing is the reconciler.

It's not a great name. #Resolved

/// <summary>
/// Produces the estimator. Note that this is made out of <see cref="ReconcileCore(IHostEnvironment, string[])"/>'s
/// return value, plus whatever usages of <see cref="CopyColumnsEstimator"/> are necessary to avoid collisions with
/// the output names fed to the constructor. This class provides the implementation, and subclassses should instead
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

subclassses [](start = 97, length = 11)

typo #Closed

return rec.Output;
}

private sealed class TrivialFactory : ISupportSdcaClassificationLossFactory
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

TrivialFactory [](start = 29, length = 14)

would 'BaseLossFactory' be a better name? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the idea is that this 'factory' will always return an existing object, so it's more 'trivial' than it is 'base'


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I agree with @Zruty0. I also do not like putting "base" in since we tend to reserve that word for abstract classes.


In reply to: 215369185 [](ancestors = 215369185,215330387)

int? maxIterations = null,
bool shuffle = true,
float biasLearningRate = 0,
Action<LinearBinaryPredictor, ParameterMixingCalibratedPredictor> onFit = null)
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

onFit [](start = 82, length = 5)

is this so we can pass different types of calibrators? #Closed

Copy link
Contributor Author

@TomFinley TomFinley Sep 5, 2018

Choose a reason for hiding this comment

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

No, this is so the user of this method can be informed about the calibrator, so they know the slope, etc. I have added some XML docs for this, that will attempt to explain what onFit is.


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

}

public static (Scalar<float> score, Scalar<bool> predictedLabel)
PredictSdcaBinaryClassificationCustomLoss(this Scalar<bool> label, Vector<float> features, Scalar<float> weights = null,
Copy link
Member

@sfilipi sfilipi Sep 5, 2018

Choose a reason for hiding this comment

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

PredictSdcaBinaryClassificationCustomLoss [](start = 12, length = 41)

Are we going to test those methods through the samples code we're doing later? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess so. But I wanted to test them now.


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

/// <param name="features">The features column name</param>
/// <param name="weights">The weights column name, or <c>null</c> if the reconciler was constructed with <c>null</c> weights</param>
/// <returns>Some sort of estimator producing columns with the fixed name <see cref="DefaultColumnNames.Score"/></returns>
public delegate IEstimator<ITransformer> EstimatorMaker(IHostEnvironment env, string label, string features, string weights);
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

Maker [](start = 62, length = 5)

Either 'builder' or 'factory' seems a bit more common for a factory method like this #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's do factory I guess.


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

/// </summary>
public static class SdcaStatic
{
public static Scalar<float> PredictSdcaRegression(this Scalar<float> label, Vector<float> features, Scalar<float> weights = null,
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

PredictSdcaRegression [](start = 36, length = 21)

Let's get into habit of writing extensive summary comments for these, since this is our public API now #Pending

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if you like my documentation.


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

Copy link
Contributor

Choose a reason for hiding this comment

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

I do


In reply to: 215430305 [](ancestors = 215430305,215367489)

var rec = new TrainerEstimatorReconciler.Regression(
(env, labelName, featuresName, weightsName) =>
{
var trainer = new SdcaRegressionTrainer(env, args, featuresName, labelName, weightsName);
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

args [](start = 65, length = 4)

Yuck, args! In transforms, I was trying to get rid of them. I think we should do the same for trainers? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

asking for a friend :)
That is, not insisting that you do so now.


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

Copy link
Contributor Author

@TomFinley TomFinley Sep 5, 2018

Choose a reason for hiding this comment

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

Hi @Zruty0 , I agree with you. I can make an issue on this subject. This will of course not be resolved in this PR, but it is important we begin to think about it.


In reply to: 215368265 [](ancestors = 215368265,215368077)


public ISupportSdcaClassificationLoss CreateComponent(IHostEnvironment env)
{
// REVIEW: We are ignoring env?
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

REVIEW: We are ignoring env? [](start = 19, length = 28)

well, in this case the loss has been given to us, so no need to use env to manufacture anything, right? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's fair I suppose.


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

}

/// <summary>
/// A reconciler for regression capable of handling the most common cases for binary classification
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

regression [](start = 29, length = 10)

binary classification? #Closed

}

/// <summary>
/// A reconciler for regression capable of handling the most common cases for binary classifier with calibrated outputs.
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

regression [](start = 29, length = 10)

seems like a copypasta error #Closed

/// </summary>
public (Scalar<float> score, Scalar<bool> predictedLabel) Output { get; }

protected override IEnumerable<PipelineColumn> Outputs { get; }
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

I'm not sure I fully grasp the difference between Output and Outputs... #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add a comment. They only really differ in content in this one class, due to the fact that are compile time we can only be sure two are present, while at runtime we also have to be sensitive as to whether we are in fact producing that extra probability column.


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


namespace Microsoft.ML.StaticPipelineTesting
{
public sealed class Training : MakeConsoleWork
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

MakeConsoleWork [](start = 35, length = 15)

can we rename this to something that indicates that it's a base class for tests?
Like BaseTestClassWithConsole ? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:D


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

}

public static (Scalar<float> score, Scalar<bool> predictedLabel)
PredictSdcaBinaryClassificationCustomLoss(this Scalar<bool> label, Vector<float> features, Scalar<float> weights = null,
Copy link
Contributor

@Zruty0 Zruty0 Sep 5, 2018

Choose a reason for hiding this comment

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

PredictSdcaBinaryClassificationCustomLoss [](start = 12, length = 41)

Maybe make this an overload instead of a method with a different name? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. In order to encourage "early" resolution I will also move the loss argument to be right after the delegate, and make it a non-default argument to encourage people to actually set it.


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ooo... hmmm. Maybe it has to go after features, but before weights. Hmmm. Hmmm.


In reply to: 215414897 [](ancestors = 215414897,215378059)

/// </summary>
internal Estimator<TTupleShape, TTupleShape, ITransformer> MakeNewEstimator()
/// <returns>An empty estimator with the same shape as the object on which it was created</returns>
public Estimator<TTupleShape, TTupleShape, ITransformer> MakeNewEstimator()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

public [](start = 8, length = 6)

As discussed here I believe the POR for right now until we change our minds again is for the method to create new estimator pipes to exist directly on these schema bearing objects (whatever they may be).

/// <param name="onFit">A delegate that is called every time the
/// <see cref="Estimator{TTupleInShape, TTupleOutShape, TTransformer}.Fit(DataView{TTupleInShape})"/> method is called on the
/// <see cref="Estimator{TTupleInShape, TTupleOutShape, TTransformer}"/> instance created out of this. This delegate will receive
/// the linear model that was learnt. Note that this action cannot change the result in any way; it is only a way for the caller to
Copy link
Contributor

Choose a reason for hiding this comment

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

learnt [](start = 38, length = 6)

maybe 'trained'? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I think the first instance can be trained, but I feel like the trailing word has to be learnt or something.

Copy link
Contributor

@Zruty0 Zruty0 left a comment

Choose a reason for hiding this comment

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

:shipit:

Copy link
Member

@sfilipi sfilipi left a comment

Choose a reason for hiding this comment

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

:shipit:

@TomFinley TomFinley merged commit 5654d72 into dotnet:master Sep 6, 2018
@TomFinley TomFinley deleted the tfinley/Pigsty branch September 6, 2018 01:39
@ghost ghost locked as resolved and limited conversation to collaborators Mar 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Direct API: Static Typing of Data Pipelines
3 participants