-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Making trainingOption updater/getter less rigid #141
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
Conversation
…g in the _ prefix. Also, made the operation a little less fragile by updating any options which are in the default object, rather than a specific list. Some exceptions are handled separately (e.g. activation and log). Same thing for the _getTrainOpts function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the changes. There are a few things that I commented on that I think we need to handle still. Let me know what you think.
* momentum: (number), | ||
* activation: ['sigmoid', 'relu', 'leaky-relu', 'tanh'] | ||
*/ | ||
updateTrainingOptions(opts) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally had this method as private (i.e. starting with _
) but then asked myself why. I think it is fine to be exposed to the user but I could see it going either way. Mostly if we don't have the _
it indicates to the user that they are safe calling it without having strange side effects.
I would vote for keeping it public but it isn't a big deal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They set these options implicitly via the constructor or the train
, do they need a third way to set the training options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no they don't need it, but if we have it already setup it is 0 cost to us letting it be explicitly exposed. I am ok keeping it private I just thought I would bring it up.
if (opts.timeout) { this.trainOpts.timeout = opts.timeout; } | ||
if (opts.activation) { this.activation = opts.activation; } | ||
_updateTrainingOptions(opts) { | ||
Object.keys(NeuralNetwork.trainDefaults).forEach(opt => this.trainOpts[opt] = opts[opt] || this.trainOpts[opt]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would create weird behavior in the instance of updating training options. For example:
net.train(data, { log: true });
net.train(data2, { logPeriod: 50 });
The second training would not print because the log would be reset to the default. The same problem would occur any time the update training options method is called.
I like the idea of iterating instead of static if's but maybe we need to iterate on the union of keys from defaults and the passed in objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm iterating over the keys of the static, not the static itself. I'm still setting the this.trainOpts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ideally this would throw an error, as the net is still training
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robertleeplummerjr , I think this is assuming synchronous training, so there shouldn't be any overlap with train timing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doh, that is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all the new tools easily confuse me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return results; | ||
return Object.keys(NeuralNetwork.trainDefaults) | ||
.reduce((opts, opt) => { | ||
if (this.trainOpts[opt]) opts[opt] = this.trainOpts[opt]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to add the json object of a callback to the results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should it be? If someone wants to output it via JSON.stringify
, the keys with functions in them will get omitted. This is a little awkward, but sending in some string representation of the function means we'd have to account for this on both converting to and from a JSON. If they instead are just using the JSON as a holder in-memory for their net's configuration (e.g. how the tests use it), it would actually provide meaningful data back with references to the actual functions used rather than a placeholder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another question would be why would we want to give the json of something someone else owns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Said differently: There are likely values we do want to retain as json, perhaps we could just be static in defining them, rather than including all of them. If it were, for example, just a list of the ones that matter, that'd give us both the small footprint of code, and logic for what actually affected the net, which may be important later for json exporting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nm, I see it now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought: using reduce
is overkill. Lets get a list of the items that should be specifically exported, then map
them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it isn't that I hate reduce
, it has it's place (dark side, unstructured data) and here we know the context and structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so are you proposing we have get exportableTrainingOptions()
which will give us a subset of get trainingDefaults
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial thought was that this concept interfered with the general output would somehow make the library too non-specific enough for the lib, but the more I think about this, the more it makes sense.
ty guys for thinking this through, and it does clean up the training area.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
options are now fat free!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the first comment (the private vs public) I can see going either way, and I am fine with it. I just thought I would mention it as it might be convenient for users.
The second (resetting training options) was my bad in reading it. When I read it I thought "that will lead to weird behavior" but I totally read it wrong. Sorry.
The third comment I think is the only thing left. I mentioned how I would vote to either ignore both or possibly restore log
with the console.log
method. Either way we do it lets make sure the doc's reflect it.
The last thing we don't address is validation. Do we want to? If we do lets do that in a different pr (unless you want to group it I am fine either way).
what kind of validation? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lookin' good, almost there
return results; | ||
return Object.keys(NeuralNetwork.trainDefaults) | ||
.reduce((opts, opt) => { | ||
if (this.trainOpts[opt]) opts[opt] = this.trainOpts[opt]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought: using reduce
is overkill. Lets get a list of the items that should be specifically exported, then map
them.
I think validation should be a new pr, I just brought it up (probably not the best place to do that but we are on the topic in lol). Mostly with the focus of helping a user find out why their network isn't training. |
just fix up conflicts and we're good to go |
Description
I removed a lot of the hardcoded handling in
_updateTrainingOptions
, and instead have it iterate over all thetrainingDefault
options and set them if they exist. I didn't want to use a spread operator, as this keeps it limited to the options we want passed. this isn't a big deal IMO, and it could make this very simple to implement if we don't care about extra options.Motivation and Context
This is in response to some comments not being submitted before #137 was merged
How Has This Been Tested?
yarn test
- all passedScreenshots (if appropriate):
Types of changes
Author's Checklist:
Reviewer's Checklist: