-
Notifications
You must be signed in to change notification settings - Fork 0
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
[WIP] Create a minimal TF binding #4
Conversation
With ce3925f I've trimmed down TF based on what we actually use. Here's the diff between what TF# had and what we have: https://gist.github.com/ericstj/ada86e95c9178a58d2e1d038a14f4f31 Here's the diff between what we have and what we could further trim. I took a guess at what we might use in the future and left that stuff in: |
This now has a trimmed down version of TF# internal to MS.ML.Transforms. We can further refactor if folks wish but this should illustrate the rough size of the support cost of owning the portion of TF# we depend on. #Resolved |
This is just a stub to begin iterating on. To follow: 1. Pull over a copy of TF# source 2. Tree-shake unused code. 3. Rewrite / Rename TF# API as appropriate. 4. Come up with a strategy for providing TF bins (using TF#'s copy now, merely as a starting point).
*NOT BUILDING*
/// <summary> | ||
/// Creates a constant tensor with a single dimension from a float value. | ||
/// </summary> | ||
public unsafe TFTensor (float value) |
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.
public unsafe TFTensor (float value) [](start = 2, length = 36)
Can we have a templated versions of creating TFTensor from type ?
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.
We can have generic factory method that does that. It'll need to handle T's specifically via switch. What Ts do you expect it to handle? Scalars, Arrays of scalars, both?
In reply to: 210351058 [](ancestors = 210351058)
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.
For scalar only right now. Looks like SetupTensor method can work for arrays as it's already being used for arrays underneath every constructor.
In reply to: 210355494 [](ancestors = 210355494,210351058)
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.
Yes, SetupTensor can handle arrays and does the right thing pinning the managed array to avoid a copy. Note that will only work if the caller knows they have an array, if the caller doesn't and itself is a generic on T that might be an array we'll need to make the factory method handle it to.
I'll add a method to do this, it's very similar to those we have in System.Numerics.Vectors and System.Numerics.Tensors. It doesn't seem to difficult to do the same for an array.
In reply to: 210356670 [](ancestors = 210356670,210355494,210351058)
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 can use this method directly. This method takes TFDataType as input and I have that information from model. I can use this method for arrays. For scalar there is no such method so I needed a templated one.
In reply to: 210360411 [](ancestors = 210360411,210356670,210355494,210351058)
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.
Yeah, I'll make something, you may want to use it in both scenarios. Stay tuned.
In reply to: 210360411 [](ancestors = 210360411,210356670,210355494,210351058)
I've fixed some minor rule issues and disabled the naming analyzers since those churn the source too much.
For now it is BYOTF (bring your own TensorFlow) so the tests are grabbing the TF bits for TF#.
/// Creates a 1 dimensional tensor from an array of booleans. | ||
/// </summary> | ||
/// <param name="data">Data.</param> | ||
public TFTensor (bool [] data) : base (SetupTensor (TFDataType.Bool, data, size: 1)) { } |
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.
SetupTensor [](start = 41, length = 11)
I think I need this method exposed so that I can use it in the transform.
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's effectively exposed now that I have moved this code into the same assembly and its internal. I need to understand the use case to determine if calling directly is the right thing to do.
In reply to: 210351552 [](ancestors = 210351552)
|
||
// extern void TF_SessionRun (TF_Session *session, const TF_Buffer *run_options, const TF_Output *inputs, TF_Tensor *const *input_values, int ninputs, const TF_Output *outputs, TF_Tensor **output_values, int noutputs, const TF_Operation *const *target_opers, int ntargets, TF_Buffer *run_metadata, TF_Status *); | ||
[DllImport (NativeBinding.TensorFlowLibrary)] | ||
private static extern unsafe void TF_SessionRun (TF_Session session, LLBuffer* run_options, TFOutput [] inputs, TF_Tensor [] input_values, int ninputs, TFOutput [] outputs, TF_Tensor [] output_values, int noutputs, TF_Operation [] target_opers, int ntargets, LLBuffer* run_metadata, TF_Status status); |
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.
TF_SessionRun [](start = 36, length = 13)
I looked at the TF C-API and it states that the following about the outputs which indicates that we don't need to copy data out of TF. It transfers ownership to caller. Let me know if I get it correctly.
// On success, the tensors corresponding to outputs[0,noutputs-1] are placed in
// output_values[]. Ownership of the elements of output_values[] is transferred
// to the caller, which must eventually call TF_DeleteTensor on 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.
Right. We have to wrap the TFTensor in an ML.NET type and avoid the copy. It won't be exposed as a managed array, but as some other type that can be accessed like an array. That wrapping type would need to be disposable. Is there a type in ML.NET that's a good fit? I have an appropriate type in S.N.Tensors but we probably want to use whatever type ML.NET standardizes for this. Looked at VBuffer and it won't work since its a struct that exposes the managed array, it doesn't have a "pointer" / "IReadOnlyList" mode. I don't think IDV is correct either.
I looked into C-API to see if we could get TF to directly allocate the resulting tensor as a managed array and it doesn't look like they provide a hook for the allocator, so we'll need to either wrap their memory (and manage its liftime) or copy it.
Let me know your thoughts about a wrapping type for TFTensor or a native pointer.
In reply to: 210361853 [](ancestors = 210361853)
This method will accept a .NET type and produce a tensor. In the case of a scalar it allocates a single element on the managed heap to back the tensor. In the case of single or multi-dimensional array it pins the array on the managed heap and wraps it in a tensor, allowing TF to directly interact with the managed array. In all other cases we throw. To produce this method I used T4 templates, which autogenerate the CS source when you edit the tt file. See https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates#creating-a-design-time-t4-text-template for more details. We use the same approach in CoreFx and other repos for dealing with type-specific functionality breakout from a generic method.
OK, I've rebased this on your latest and added to it the generic method we discussed. Please have a look and merge at will. I can work in your branch from now on. |
This replaces usage of TF# with a locally built copy of the same types.
It's a work in progress as I plan to further trim the source, change names and namespaces, refactor, etc.
Best reviewed commit-by-commit.
/cc @zeahmed @Zruty0