Skip to content

Final push to clean our overwritten arguments #1353

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

Closed
wants to merge 2 commits into from
Closed

Final push to clean our overwritten arguments #1353

wants to merge 2 commits into from

Conversation

qcolombet
Copy link
Contributor

The quantization profile node was the last use (aside from save nodes) of the overwritten attribute and thus, was also sensible to the same kind of scheduling bugs that was exposed in #1283.

There are several ways we could have fixed/worked around that:

  1. Teach the scheduler how to handle the implicit memory dependencies for that node too
  2. Check in the verifier that the overwritten inputs of the quantization profile nodes are not used anywhere else
  3. Model quantization profile with producing two outputs

I don't like #1 because it pushes more hacks in the scheduler (eventually I'd like we model the memory dependencies period.). #2 is really just a check that the situation does not happen, but if it does, we're back to square 1.
Therefore, I gave a quick stab at #3 with this PR.

The nice thing I was pursuing and that PR achieves is that we would have the invariant that only save nodes write to variable.

Quentin Colombet added 2 commits July 27, 2018 12:51
Prior to this commit, it was impossible to describe more than one
inplace property. This would limit our ability to set the inplace
property on instruction with more than one result.

With this patch, it is now possible to define one inplace property
list for each output of an instruction. To use this feature
simply invoke inplaceOperand method for each output on the
declaration of the instruction.
The QuantizationProfile node suffers the same problem as the save
node: it has implicit memory dependencies and the scheduler could
be tricker to generate invalid code because of that.

Unlike the save node, the problem is less likely to happen because
this node only deals with its only created variables. Yet, as soon
as those variables are created, it is possible to temper with them
to create invalid schedules.

Unlike the save node, where we taught the scheduler how to deal
with the implicit memory dependencies, this patch fixes the
representation of the QuantizationProfile node (and its underlying
QuantizationProfileInstr) by removing the implicit memory
dependencies. After this patch, the save node is the only node
with implicit memory dependencies.

Test Plan:
$ ninja check

$ ./bin/image-classifier tests/images/imagenet/*.png -image_mode=0to1 -m=resnet50 -dump_profile=resnet50_prof_async.yaml

$ ./bin/image-classifier tests/images/imagenet/*.png -image_mode=0to1 -m=resnet50 -dump_profile=resnet50_prof_async2.yaml

$ diff -q resnet50_prof_async2.yaml resnet50_prof_async.yaml

$ ./bin/image-classifier tests/images/imagenet/*.png -image_mode=0to1 -m=resnet50 -dump_profile=resnet50_prof_async2.yaml

$ diff -q resnet50_prof_async2.yaml resnet50_prof_async.yaml

Results:
Everything passed, no diffs.
@nadavrot
Copy link
Contributor

@qcolombet Yes, the quantize-profile node is the last node with overwritten attributes in our tree, but there are other nodes that we don't currently support. One important node is embedding tables. Embedding tables are (potentially huge) lookup tables. When training the lookup tables we need to update a small number of nodes in each iteration. Implementing the embedding tables using the method that nodes produce new values is impractical. Yes, the optimizer can save us in some cases, but I don't think that we should rely on the optimizer to save us. Is there a problem with enforcing a rule that operators that update some variables 'own' the variables?

@jfix71
Copy link
Contributor

jfix71 commented Jul 27, 2018

Is there a problem with enforcing a rule that operators that update some variables 'own' the variables?

@nadavrot By own, do you mean only the owner node can read from or write to the variable?

@qcolombet
Copy link
Contributor Author

Implementing the embedding tables using the method that nodes produce new values is impractical

I agree and I don't think we should expose them as variables (at least not how it is done right now).

Is there a problem with enforcing a rule that operators that update some variables 'own' the variables?

I think that would be the way to go, but then I believe it should be some special kind of variables. One thing that we need to enforce is that "owned" variables don't have any other reads (which is where we introduce the problematic memory dependencies). The best way to do that would be to not expose these variables for other to grab, and we miss that today. Indeed, variables are available at a module level and this cannot be changed easily because of how we use the Module at runtime #1334.

@nadavrot
Copy link
Contributor

@qcolombet Do you know how XLA handles variable mutability?

@qcolombet @jfix71 How would you feel if we split variable into 3 categories:

  1. StorageVariable: this storage kind will be used by ProfileQuantize, EmbeddingTable and other nodes that need database-like access pattern where you can't just copy the whole thing every time.
  2. Constant: this variable kind will store weights.
  3. IO: This kind of variables will be linked to actual thread-local buffers at runtime.

What do you think?

@qcolombet
Copy link
Contributor Author

Do you know how XLA handles variable mutability?

No, looking is still on my todolist :).

How would you feel if we split variable into 3 categories:
StorageVariable [...]

As long as those are not "gettable" to form other links that would work. The thing I want to be sure is that we don't create patterns that could lead into bugs into the scheduler.

@qcolombet
Copy link
Contributor Author

I wonder if we could have the variable being own (I mean litterally in the code) by the node itself.

@qcolombet
Copy link
Contributor Author

Note: I am happy to just trash this PR and go with the verifier check for now, until we land a better designed for the variables. I just hacked this this morning to see how difficult it would be to finally clean-up the overwritten problem and turned out it was easy and not too hacky, so I figured I shared :).

@qcolombet
Copy link
Contributor Author

It does prevent us for running into memory dependencies issues as of today though, which is nice IMHO.

@qcolombet
Copy link
Contributor Author

Abandoning this PR in favor of checks in the verifier.

@qcolombet
Copy link
Contributor Author

@nadavrot regarding mutability in XLA (hlo_instruction.h):
// HLO is pure (mostly). It has no concept of mutable state. Instead, data
// values are produced by one HLO and flow into consumers across dependency
// edges.

I was incidentally going in that direction :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants