Skip to content

Optimizer package for Graph mode#28

Merged
karllessard merged 22 commits intotensorflow:masterfrom
Craigacp:ndarray-optimizers
Mar 2, 2020
Merged

Optimizer package for Graph mode#28
karllessard merged 22 commits intotensorflow:masterfrom
Craigacp:ndarray-optimizers

Conversation

@Craigacp
Copy link
Collaborator

@Craigacp Craigacp commented Feb 8, 2020

This adds a new subproject tensorflow-training which currently contains org.tensorflow.training.optimizers a package of gradient optimizers which apply the underlying gradient update ops to a TF Graph.

In addition to the optimizers it makes a few small changes in the tensorflow-core-api package: it adds a variables initialiser list to Graph, a method which constructs an initialiser node which initialises all the variables in the graph, plus a variableWithInit method which accepts an Operand which is used to provide the shape, type and initial value for the variable.

There's also an MNIST CNN test in there, which we can move out to wherever it needs to go, and be combined with the other ones.

Before this gets merged it needs better Javadoc in the Optimizer class, and the global variables used by some of the optimizers need wiring into the globals field in the base class. I'll fix those things next week.

@karllessard
Copy link
Collaborator

@Craigacp , just quickly like that, it looks like you'll need to rebase your PR to resolve a conflict

@dhruvrajan
Copy link
Contributor

@Craigacp cool stuff! Did you mean to commit the files under src/annotations/gen? (those get regenerated at build time, if I'm not mistaken?)

@Craigacp
Copy link
Collaborator Author

Craigacp commented Feb 8, 2020

I rebased the branch and the deterministic generation commits went away with the associated conflict, but I seem to have picked up the ci changes that got merged in earlier today.

Copy link
Collaborator

@karllessard karllessard left a comment

Choose a reason for hiding this comment

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

Thanks @Craigacp , this is a very great addition to TF Java. I didn't went through the logic behind the optimizers themselves yet but just dropped quickly a few suggestions you might want to review before applying your next changes.

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
Copy link
Collaborator

Choose a reason for hiding this comment

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

2020, also shouldn't it be copyright to The Tensorflow Authors like all other files in the project?

Copy link
Collaborator Author

@Craigacp Craigacp Feb 10, 2020

Choose a reason for hiding this comment

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

We don't have an authors file in this repo, plus this is the text that Oracle Legal requires on all outbound source contributions. I'm not sure if putting it in the AUTHORS file will be sufficient for them. It looks like the main TF repo has an AUTHORS, but then it says to look at CONTRIBUTORS which doesn't exist, so maybe someone at Google should figure out what they want it to look like for all the TF related repos.


private final float rho;

private final float epsilon;
Copy link
Collaborator

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 need to enforce it but just FYI, pretty much all TF classes declare their members in this order, including both fields and methods: public, protected, default, private

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you mean all the public methods & fields, then protected etc, or all the public methods, protected methods, ... then public fields, protected fields etc?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well in this format, things are grouped per scope, meaning:

  1. public fields
  2. public methods
  3. protected fields
  4. protected methods
  5. ... and so on

Again, I don't necessarily want to continue enforcing this in our new repo but maybe we can apply it at least in the core, so that all classes of a single artifact follows the same pattern?


protected Optimizer(Graph graph) {
this.graph = graph;
this.tf = Ops.create(graph).withName(getOptimizerName());
Copy link
Collaborator

Choose a reason for hiding this comment

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

would it be easy to allow the user override the name of the scope for the optimizer ops (instead of getOptimizerName())? Also, maybe a user would like to pass its own instance of Ops (which might already be a subscope of another block or contains control dependencies, etc.)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's locked off to Graph at the moment as I don't think any of this works in eager mode, so the type system enforces that. I can allow a hook for the name, and we could relax the Graph check to an instanceof check throwing IllegalArgumentException to supply an ops. Should I keep the Graph entry point as well?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes I think it is ok that to have an entry point that accept a Graph but maybe add another that accept an Ops as well, so the user has full control on the name and control dependencies of the optmizers? Or maybe just a String for the name

For instance, does it make sense that a user would want to create two different optimizers of the same type (but with different parameters) for handling different variables? If so, then he'll need to give them different names or he will endup with a name conflict.

I think you understand my questioning here, I'll let you decide what would be the best approach to handle those corner cases.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added an additional constructor which accepts a Graph and a String for the base name of the operations.

@Craigacp
Copy link
Collaborator Author

I've rebased on the latest master, fixed the style issues, put the try with resources in, and updated it to use the @Endpoint annotation for variableWithInit. I've also stubbed out using @Endpoint for the Adam optimizer, and I think it should work, but it would require the optimizers to be in the tensorflow-core-api project as otherwise there will be ugly circular dependencies. TODOs are update the optimizer constructor to allow an ops, rearrange the code so it's ordered like the other bits of the project, and check the behaviour of tf.assign in eager mode.

* and return one of them.
*/
@Operator
public abstract class CoreOps {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This class name is a bit misleading, as all other *Ops classes are generated and exposes tf.* endpoints. Here, we are dealing with the endpoint implementations.

I've never been a huge fan of the *Ops name for the generated classes neither (even if that was my idea if I recall correctly...) and we could rename them instead. Like TensorFlowApi, TensorFlowLinearApi, TensorFlowSparseApi, etc. would be better picks.

But if we don't want to do this breaking change then I think we need to come up with something else for this new class.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I renamed it to Helpers, but that's also not a great name.


private final float rho;

private final float epsilon;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Well in this format, things are grouped per scope, meaning:

  1. public fields
  2. public methods
  3. protected fields
  4. protected methods
  5. ... and so on

Again, I don't necessarily want to continue enforcing this in our new repo but maybe we can apply it at least in the core, so that all classes of a single artifact follows the same pattern?


protected Optimizer(Graph graph) {
this.graph = graph;
this.tf = Ops.create(graph).withName(getOptimizerName());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes I think it is ok that to have an entry point that accept a Graph but maybe add another that accept an Ops as well, so the user has full control on the name and control dependencies of the optmizers? Or maybe just a String for the name

For instance, does it make sense that a user would want to create two different optimizers of the same type (but with different parameters) for handling different variables? If so, then he'll need to give them different names or he will endup with a name conflict.

I think you understand my questioning here, I'll let you decide what would be the best approach to handle those corner cases.

List<Operation> variables = new ArrayList<>();
Iterator<Operation> opItr = graph.operations();
while (opItr.hasNext()) {
Operation op = opItr.next();
Copy link
Collaborator

Choose a reason for hiding this comment

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

graph.operations().forEachRemaining maybe?

Also, is it OK that an optimizer is always applied to all variables in the graph? Is this true for all kind of graphs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's how they work in Python. It's really hard to make it work any other way without a lot of ceremony.

@karllessard
Copy link
Collaborator

Please don’t forget to rebase your PR before pushing a new version as I just merged some other breaking changes (mainly renaming ˋtf.constant to ˋtf.val and adding ˋtf.array`), thanks

@karllessard karllessard merged commit 9107991 into tensorflow:master Mar 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants