-
Notifications
You must be signed in to change notification settings - Fork 214
Saving and loading models in Java with a functional API #101
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
Comments
Hi @Shajan , no worries at all for the meeting, I've created a new issue in GitHub to continue our discussion so it won't get lost in a PR that already has been merged. So the idea is that while we will continue to only support session-centric saved models (these models with a single graph and one or more signatures), we will present it as a function to the user so the API will remain the same as much as possible when we start supporting them for real. For the unit test, quick question, how do you build the Python model? Is it using one or more |
Yes, a model with a few tf.functions. Here is a colab notebook with example https://colab.research.google.com/drive/1NrFbhe6do2Hq0VF3hgEk4KsGhY9kkNfU?usp=sharing Copied the main parts here below.
|
These are great developments, looking forward to a unit test whenever it's ready. I merged some older code from @karllessard to save/load models, seems to work with preliminary testing: #100 (comment) Comments welcome! All my diffs, source, and outputs are posted. Happy to test new methods for model save/load, if that's helpful. My work's motivated by deadlines over here, need model save/load. Thanks for everything! |
karllessard@bdb0420 Further code discussion is at https://groups.google.com/a/tensorflow.org/forum/#!msg/jvm/gGKO-hVS4Pc/LF4rLJOdAQAJ This commit manually merges Karl's code to mainline tensorflow-java. However, Ops.java is unchanged here, because there were no functional changes in Ops.java. This commit fixes tensorflow#100 Later, model-saving may be expected to be function-based, not session-based. Function-based model saving is discussed in tensorflow#101
@Shajan , can you please take a look at this new implementation? It turns out that the actual model was working great for loading function definition but not for exporting them, so I've shuffle the classes a little bit. Also, like we discussed, even if in TF Java we continue to only support session-centric models, we expose each signatures as if they were real Right now the Please let me know what you think of it and see if we should still go in that direction or not, thank you! |
I woke up this morning and rethought about this, I think resource management concerns shared by @yzhuang should be addressed properly. I'll push a new version of this code once I'm done with my coffee... |
New PR draft available at #103 |
Hi @Shajan, I still think that we should have a unit test loading a model saved from Python using |
Hum, time to start doing some reference counting? :) |
@saudet, I certainly thought of it! I think we should attack reference counting as a whole rather that just by pieces though (i.e. using it for managing all native resources, not only a few of them). It is probably better to wait after the first alpha release and see this as a future improvement. My latest draft handles function resource management properly, at the extent of what we are able to do with |
Agree. For the unit test, here is my suggestion: What do you think? |
@Shajan : sounds good! Do you think you can take care of this part? I’ll merge my changes to the common branch probably today |
@karllessard yes, i will add the test. |
Ok thanks @Shajan , I've merged my changes, please let me know when you are done with your unit tests so we can make an official PR for the master branch |
Hi @karllessard , try-with-resource is potentially a worse user experience. Can't we simply add a |
Hi @yzhuang , thanks for you valuable feedbacks, The proposal is done wrt the actual memory management paradigm where only resources that are explicitly allocated by the user must be protected by try-with-resource. For example, if you are loading a saved model bundle, you don't need to protect the retrieved // Actual sessions
try (SavedModelBundle s = SavedModelBundler.load(...);
Tensor<TFloat32> in = TFloat32.tensorOf(...);
Tensor<TFloat32> out = s.session().feed("input1", in).fetch(out).run().get(0).expect(TFloat32.DTYPE)) {
System.out.println("Result is " + out.data().getFloat());
}
// New functions
try (SavedModelBundle s = SavedModelBundler.load(...);
Tensor<TFloat32> in = TFloat32.tensorOf(...);
Tensor<TFloat32> out = s.function("func1").call(in).expect(TFloat32.DTYPE)) {
System.out.println("Result is " + out.data().getFloat());
} On the other hand, if the user explicitly creates the function, he should then release it, the same way again we do with graphs and sessions. // Actual sessions
try (Graph g = new Graph()) {
// ... fill graph
try (Session s = new Session(g);
Tensor<TFloat32> in = TFloat32.tensorOf(...);
Tensor<TFloat32> out = s.session().feed("input1", in).fetch(out).run().get(0).expect(TFloat32.DTYPE)) {
System.out.println("Result is " + out.data().getFloat());
}
}
// New functions
try (ConcreteFunction f = ConcreteFunction.create(...)) {
try (Tensor<TFloat32> in = TFloat32.tensorOf(...);
Tensor<TFloat32> out = f.call(in).expect(TFloat32.DTYPE)) {
System.out.println("Result is " + out.data().getFloat());
}
} The only exceptional case is when a function is created from an existing session, in which case protecting it is not required and will have no effect, e.g. try (Graph g = new Graph()) {
// ... fill the graph
try (Session s = new Session(g)) {
try (ConcreteFunction f = ConcreteFunction.create(Signature.builder()..., s)) {
// this block was not required but won't break anything neither
}
ConcreteFunction f = ConcreteFunction.create(Signature.builder()..., s); // this is legit in this case
}
} We are already planning to improve in the future the user experience with memory management as a whole by using reference counting on the native resources themselves but this is not in the scope of this feature. I think following the actual rules is acceptable for now. Did you identified a case where the experience would be worsened by the introduction or the use of functions? And can you please provide an example where keeping track of the number of session owners would enhance it, providing that the |
@karllessard Hi Karl, the above usage patterns look good to me, thanks for the clarifications! |
Just to clarify, are these try-with-resource semantics required in Scala, e.g. #100 (comment) It seems the Scala code compiles without all the try-blocks, but is not using the try-blocks a resource-usage-related mistake? |
Unsure if i need additional permissions. Push to origin failed while trying to push the unit test. java [shared-saved-model] $ git push origin |
@Shajan , can you please try again? |
Thanks, merged. |
Great! I think I can now rebase that branch and make a PR out of it |
Yes, required, and mistake otherwise. Tensors and other AutoCloseable native resources must be So, for my Scala 2.11.8, I wrote a manager that maintains a list of AutoCloseable objects, and closes them properly. This may be worth doing properly if there is ever a Tensorflow Scala. Also, I've tested this new Functional API in Scala, and saving works for me, thanks for your hard work @karllessard @Shajan! With the older Session-based model saving code, I had some issues with loading a model that used padding operations -- haven't tested yet with this new API. |
Uh oh!
There was an error while loading. Please reload this page.
I take it that we go with the current branch (after addressing open comments) and adding unit tests.
For unit tests: Here is a proposal
Originally posted by @Shajan in #89 (comment)
The text was updated successfully, but these errors were encountered: