From 300a4b9321b118ee0721eebee7331736135a7a4c Mon Sep 17 00:00:00 2001 From: Faizan Muhammad Date: Thu, 25 Aug 2022 11:09:07 -0700 Subject: [PATCH 1/2] RFC: FunctionType for tf.function --- rfcs/20220824-tf-function-type.md | 492 +++++++++++++++++++++ rfcs/20220824-tf-function-type/diagram.png | Bin 0 -> 44665 bytes 2 files changed, 492 insertions(+) create mode 100644 rfcs/20220824-tf-function-type.md create mode 100644 rfcs/20220824-tf-function-type/diagram.png diff --git a/rfcs/20220824-tf-function-type.md b/rfcs/20220824-tf-function-type.md new file mode 100644 index 000000000..4e49cb1c7 --- /dev/null +++ b/rfcs/20220824-tf-function-type.md @@ -0,0 +1,492 @@ + +# FunctionType for tf.function + +| Status | Proposed | +:-------------- |:---------------------------------------------------- | +| **RFC #** | [TODO](https://github.com/tensorflow/community/pull/NNN) | +| **Author(s)** | Faizan Muhammad (fmuham@google.com)| +| **Sponsor** | Yanhua Sun (yanhuasun@google.com) | +| **Updated** | 2022-08-24 | + + + +## Objective + +This document details the introduction of a new `FunctionType` to represent the type of tf.function and ConcreteFunction instances. + + +## Motivation + +### Goals +* Build a practical, fundamental concept for a TensorFlow function’s “type” + +* Reduce tf.function “magic” by simplifying its mental model (and implementation) + * Be able to provide users with a simple, predictable story of what is going on + * Easier to eventually replicate/lower the logic in C++ + +* Greatly simplify argument-handling code for tf.function: + * Remove tech debt and pursue engineering excellence + * Speed up development velocity + +* Resolve/unblock ~14 relevant existing `tf.function` bugs (b/hotlists/4425735) + +* Open up the path for further `tf.function` and `ConcreteFunction` layering + +* Have minimal change in user-facing behavior (except for error messages, undetected contract violations etc.) + + +### Vision + +This diagram should be the **comprehensive** mental model for both users and developers about `tf.function `without **any** unpredictable exceptions. + +![alt_text](20220824-tf-function-type/diagram.png "Mental Model") + \ +(See the *Example Run Through* section for sample code as called in practice) + +Some examples of ways things currently do not hold up to this model: + + +* **Tech Debt:** Concepts like BoundArguments and FunctionType already exist implicitly and are emulated through code that can be made much simpler by their actualization + +* **Layering Violations:** Tracing logic should only use placeholder values derived from the FunctionType and be completely unaware of the actual values + +* **Serialization Inconsistency:** tf.function deserialized from SavedModel does not currently share the dispatch system of this model. + +* **Contract Violations:** ConcreteFunction lets through certain arguments that it should not support. + + + +### Problems + +* ConcreteFunction is unaware of the exact monomorphic type it actually is: + * `FullArgSpec` and Graph’s `structured_input_signature` is used instead + * Type information is lost during serialization so SavedModel has a hacky dispatch + * Root cause of several inconsistencies and user frustration + +* Extremely convoluted and redundant logic to manually do things like: + * **Type Validation**: Since `FunctionSpec` does not use `TraceType` + * **Argument Parsing**: Since `FunctionSpec `does not use inspect.Signature + * **Argument Conversions**: Original `*args` and `**kwargs` pass through multiple small mutating/validating/type casting functions + +* For the C++ API, we also need a clear notion of function types so that we can do things like dispatch without having to worry about all the intricacies and tech debt above + +* inspect.FullArgSpec that we use for inspection has been [replaced](https://docs.python.org/3/library/inspect.html#inspect.getfullargspec) by inspect.Signature in Python 3 + + +## Background + + +### The TF Function Zoo + +**Polymorphic vs Monomorphic:** A polymorphic function accepts multiple different types for a particular argument. In the tf.function world, TraceType denotes argument types and therefore if two (or more) mutually non-subtype types can be accepted by a function, then it is polymorphic. Otherwise it is monomorphic. + +**Differentiable vs Non-Differentiable:** A function that has an associated gradient function is considered differentiable otherwise it is non-differentiable. Not having a “gradient function” does not mean that mathematically one does not exist, it means that one has simply not been generated/registered for this particular instance. + +Given these definitions, the hierarchy of different “function”s in TF ecosystem can be described as: + +`tf.function` -> Polymorphic, Differentiable Function + +`ConcreteFunction` -> Monomorphic, Differentiable Function + +`_EagerDefinedFunction/FuncGraph` -> Monomorphic, Non-Differentiable Function + +A `tf.function` enables its polymorphism by using multiple monomorphic `ConcreteFunction `under the hood. `ConcreteFunction` enables its differentiability by associating a forward pass with a backward pass that computes the gradient. If higher-order gradients are needed, it associates a higher order backward pass with the lower order backward pass recursively. This trick is enabled by the fact that a backward pass inside a `ConcreteFunction `is actually another `ConcreteFunction`. The “gradient” functions are simply `ConcreteFunction `whose forward pass is the backward pass of another `ConcreteFunction`. + +`FunctionType` will describe the input contract of all these kinds of functions including arguments, keyword-arguments with default values and captures. + + +### Current Implementation + +The notion of “signature” for the polymorphic tf.function and the monomorphic ConcreteFunction is handled entirely by `FunctionSpec:` + +* Automatically derived from the python function using inspect.fullargspec +* Defined for every `tf.function `annotated Python function +* Used to perform input validation +* Used to transform tf.function/ConcreteFunction arguments to graph inputs +* Optionally also has the `input_signature` + * Constrains the types accepted by `tf.function/ConcreteFunction` + * Generalizes the traced concrete function to be as generic as the `input_signature` +* Inherited by `ConcreteFunction` from its parent tf.function with slight modifications + + +## Design Proposal + +### Introduce FunctionType (inspect.Signature + TraceType) + +All functions will use `FunctionType` to represent their input contract which is composed of a bunch of `Parameters`: + + +``` +CAPTURED_DEFAULT_VALUE = object() + +class Parameter(inspect.Parameter): + """Represents a parameter to a function.""" + + def __init__(self, name: str, kind: Any, optional: bool, + type_constraint: Optional[trace.TraceType]): + super().__init__( + name, + kind, + default=CAPTURED_DEFAULT_VALUE if optional else self.empty, + annotation=type_constraint + if type_constraint is not None else self.empty) + + @property + def optional(self) -> bool: + """If this parameter might not be supplied for a call.""" + return self.default is not self.empty + + @property + def type_constraint(self) -> Optional[trace.TraceType]: + """A supertype that the parameter's type must subtype for validity.""" + return self.annotation if self.annotation is not self.empty else None + + +class FunctionType(inspect.Signature): + """Represents the parameters of a polymorphic function.""" + + @classmethod + def from_callable(cls, obj, *, follow_wrapped=True) -> "FunctionType": + """Generate FunctionType from a python Callable.""" + signature = super().from_callable(obj, follow_wrapped=follow_wrapped) + + parameters = [ + Parameter(p.name, p.kind, p.default is not p.empty, None) + for p in signature.parameters.values() + ] + + return FunctionType(parameters) +``` + + +Key takeaways: + +* Directly extends the [canonical](https://docs.python.org/3/library/inspect.html#inspect.Signature) Python function signature representation, except: + * Default values are not stored in `FunctionType`, only that a parameter is optional + * Type annotations are strictly TraceTypes associated with that particular parameter + +* Automatically inherited [FunctionType.bind](https://docs.python.org/3/library/inspect.html#inspect.Signature.bind) makes 100s of lines of manual argument validation/canonicalization redundant + +* [BoundArguments](https://docs.python.org/3/library/inspect.html#inspect.BoundArguments) will be used to enforce a strict immutability of user args, kwargs except for functions that explicitly transform BoundArguments to another set of BoundArguments under a well-defined contract + +* Direct integration of `TraceType` will make 100s of lines of recurrent, manual and insufficient `isinstance`-based type checking redundant + +* `FunctionType` is trivially ready for lossless serialization. TraceType is already serializable and the rest of the structure is pretty simple. + + +### Why are Default Values not in FunctionType? + +Similar to how the TraceType of a particular argument instance is enough to describe it for the purposes of a `ConcreteFunction`, we only need to compute the TraceType of the default value and keep that in our FunctionType instead of the actual value. + +For example: + + +``` +@tf.function +def foo_int(x=1): + # FunctionType maps kwarg x to type Literal(1) + +@tf.function +def foo_tensor(x=tf.constant([1])): + # FunctionType maps kwarg x to type TensorSpec(shape=[1], dtype=tf.int32) + # Note how the default tensor value is not stored. +``` + + +In the above cases, the typing makes sense because `foo_int` needs to retrace for `foo_int(x=2)` after calling `foo_int()` but `foo_tensor(x=tf.constant([2])) `can re-use the trace of `foo_tensor()`. + +Currently, `get_concrete_function` does not produce a `ConcreteFunction` that remembers default values for either example: + + +``` +@tf.function +def foo(x, y=tf.constant([1.0])): + return x + y + +f1 = foo.get_concrete_function(tf.TensorSpec(None)) + +f1(tf.constant([1.0])) +# Raises 'TypeError: foo(x, y) missing required arguments: y.' + +f1(tf.constant([1.0]), tf.constant([3.0])) +# Returns 4 (overriding default value of y) +``` + + +That being said, the actual default values still need to be stored _somewhere_. Normally, we can just refer to the python function’s arg spec to access it but that will be lost during serialization. The solution is that **default values are actually a special type of captures**. + +Similar to how for captures, we retain their type in `CaptureSnapshot`, we only retain the type of default value in FunctionType. And we can maintain the actual values separately outside it as part of the set of captures of the function. The reasons are: + +* We use the same serialization/deserialization process for default values that we use for captures + * FunctionType should not need to concern itself with how to serialize a “value” (e.g. Tensor) + * Have parity between supported serializable default values and captures + * Reuse code + +* The actual graphs traced don't actually depend on the value so it shouldn’t be part of the type + * Imagine if you swap a default value of `tf.constant([1.0]) `with` tf.constant([2.0]), `everything still works as expected since they have the same type + +We can extract the default values as a dictionary mapping parameter names to values using the inspect library: + + +``` +def get_default_values(obj, follow_wrapped=True): + signature = inspect.Signature.from_callable(obj, follow_wrapped) + default_values = {} + for p in signature.parameters.values(): + if p.default is not p.empty: + default_values[p.name] = p.default + return default_values +``` + + + +### Deprecate experimental\_follow\_type\_hints + +There are only [24 usages](https://source.corp.google.com/search?q=experimental_follow_type_hints%3DTrue) (including tests) so it is not a heavily used feature. It also does not align with the notion of parameter type that we have established through TraceType and implicitly exists through the input\_signature API. \ + \ +For example, for a function that takes in an arbitrary Tensor, the parameter type is not `tf.Tensor` but rather `tf.TensorSpec(shape=None)`. `tf.Tensor` is simply the python class for representing the value. Therefore, the type annotations (if in future, we want to support) should be TraceType rather than Python classes. + +This proposal does not add a public TraceType annotations feature, but since FunctionType uses inspect.Signature’s annotation field for TraceType, we can no longer use it for Python classes. + + +### Integrate FunctionType inside FunctionSpec + +Currently, the constructor for FunctionSpec accepts a `fullargspec` and an `input_signature` but it will be updated to take FunctionType and default values instead (might be possible to remove `is_method` field as well): + + +``` +def __init__(self, + function_type, + default_values, + is_method, + is_pure=False, + experimental_follow_type_hints=False, + name=None, + jit_compile=None): +``` + + +However, we do this without any change to FunctionSpec serialization or current methods by having a converter function that can transform FunctionType into a FullArgSpec if needed: + + +``` +def get_fullargspec(function_type, default_values): + """Generate a FullArgSpec from FunctionType.""" + names = list(function_type.parameters.keys()) + + ordered_default_values = [] + for name in names: + if name in default_values: + ordered_default_values.append(default_values[name]) + + defaults = None if not ordered_default_values else tuple( + ordered_default_values) + return tf_inspect.FullArgSpec( + args=names, + varargs=None, + varkw=None, + defaults=defaults, + kwonlyargs=[], + kwonlydefaults=None, + annotations={}) + +``` + + +Now that FunctionSpec has FunctionType, we can replace all usages of FullArgSpec with FunctionType and simplify the code everywhere. + +Finally, we can replace the Python inspection code to use inspect.signature directly as well instead of producing a FullArgSpec. + +In the future, we can swap out the fullargspec in the proto file as well with FunctionType but until then if TraceType annotations are needed they can be serialized in as part of the FullArgSpec as well and recovered properly. \ + + + +### Example Run Through + +Say you have a tf.function of the form: + + +``` +@tf.function(input_signature= [tf.TensorSpec(shape=None)]) +def foo(x, y=1): + return x + y +``` + + + \ +As part of the tf.function declaration, we generate the `FunctionType` for the polymorphic function `foo`: + + +``` +foo._function_spec.function_type = FunctionType.from_callable(foo) +assert foo._function_spec.function_type == FunctionType( +    Parameter(name="x", optional=False, type_constraint=tf.TensorSpec(shape=None)),     +    Parameter(name="y", optional=True,type_constraint=None) +  ) +``` + + +Now the user calls `foo`: + + +``` +x = foo(2.0) +``` + + + \ +We first produce `BoundArguments` using `FunctionType` of tf.function: \ +(Note how the Python float was transformed to a Tensor due to the `type_constraint`) + + +``` +bound_args = function_type_lib.bind_type_constrain((2.0,), {}, + foo._function_spec.function_type) +assert bound_args == + BoundArguments( + Argument(name="x", value = tf.constant(2.0))), + Argument(name="y", value = CAPTURED_DEFAULT_VALUE) + ) + +bound_args = insert_default_values(bound_args, function_spec.default_values) + +assert bound_args == + BoundArguments( + Argument(name="x", value = tf.constant(2.0))), + Argument(name="y", value = 1) + ) +``` + + +And now we use `bound_args` to generate the `FunctionType` of `ConcreteFunction` we need: + + +``` +concrete_function_type = function_type_lib.from_args(bound_args, + foo._function_spec.function_type) + +assert concrete_function_type == FunctionType( + Parameter(name="x", optional=False, type_constraint=tf.TensorSpec(shape=None)), + Parameter(name="y", optional=False, type_constraint=Literal(1)) + ) +``` + + +Then we use that type to trace a new `ConcreteFunction` (or re-use a cached one): + + +``` +matching_concrete_function = foo._lookup_or_trace(concrete_function_type) +``` + + + \ +Finally, we can now call the `ConcreteFunction` with the arguments and return the result: + + +``` +return matching_concrete_function(*bound_args.args, **bound_args.kwargs) +``` + + +** \ + + +## Future Possibilities + +### Use TraceType for SavedModel Dispatch + +Now that we have a way to pass type information of a ConcreteFunction through SavedModel, we can recover it and use it to build a dispatch table at loading time, resolving b/203440205. + + +### TraceType-based Python Type Annotations + +We can deprecate/discourage `input_signature` in favor of a more Pythonic approach: + + +``` +# Old: +@tf.function(input_signature=[tf.TensorSpec(shape=None),tf.TensorSpec(shape=None)]) +def foo(x, y): + ... + +# New: +@tf.function +def foo(x: tf.TensorSpec(shape=None), y: tf.TensorSpec(shape=None)): + ... + +``` + + + +### Include Side Inputs (Captures) in FunctionType + +Long term, side input types should also be represented in `FunctionType` but support for side inputs is still underway and the topic can be revisited once that work is completed. + + +### Serialize FunctionType Directly (Instead of as FullArgSpec) + +For a C++ API to provide similar levels of functionality such as TraceType-based dispatch, having `FunctionType` information would be critical. While a `FunctionType` could theoretically be generated in C++ from the current FullArgSpec serialization, the extra effort can be eliminated by just serializing `FunctionType` directly. It would also allow for more advanced features that are currently not supported such as representing side input types. + + +### Expose FunctionType to Users for Debugging and Explainability + +As described above, the mental model that we want to move towards is very FunctionType-centric, as a result, exposing it to users would allow them to intuitively understand why certain behaviors are occurring. + +Since FunctionType is a canonical Python Signature as well, we can also return it through the `__signature__` dunder as well, which will allow for a tighter integration of tf.function within the Python landscape. \ + + + +# Alternatives Considered + +* Replace FunctionSpec entirely by FunctionType + * Too big of a scope + * Can’t get rid of FunctionSpec proto since current SavedModels use it + +* Include default values in FunctionType + * Makes serialization complex and raises some layering issues + +* Don’t support all the [5 canonical parameter kinds](https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind) + * Not possible since current behavior can not be emulated by a subset + +* Have a different class for tf.function and ConcreteFunction FunctionTypes + * FunctionSpec is already used commonly by both + * The extra invariants don’t need to be enforced by the representing data structure but could be in the generating code + +# User & Engineering Impact + +This would mostly be an internal layering effort. + +Any code that is broken due to subtle changes in API semantics will be fixed by the TensorFlow team unless the users were relying on non-guaranteed aspects such as private functions. + +The proposed code will be implemented and maintained by the TensorFlow Team. + + +# Performance Implications + +There are no significant performance implications expected. + + +# Compatibility + +This design doc is focused entirely on pure ayering changes with no behavioral changes. It does unblock a lot of possibilities to make tf.function more consistent and simple at the cost of some breaking changes but they are not a part of this doc. + + +# Dependencies + +No new library dependencies are added. + + +# Platforms and Environments + +No implications for platforms and environments. + + +# Tutorials/Examples and Documentation + +No user-facing implications, the newly written code will be supplemented with test suites and comments as appropriate. + + +# Third Parties + +No particular third-party implications. \ No newline at end of file diff --git a/rfcs/20220824-tf-function-type/diagram.png b/rfcs/20220824-tf-function-type/diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..09f814c9f2a7f533dd5cfd03b9ac5f031c803b58 GIT binary patch literal 44665 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�vw9Yzg&4XaD!wGt$I%^%OoOL-(gi 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 literal 0 HcmV?d00001 From 3d4700423f44e566ac621aa0b7e2d8f0598da9cf Mon Sep 17 00:00:00 2001 From: Faizan Muhammad Date: Thu, 25 Aug 2022 11:11:14 -0700 Subject: [PATCH 2/2] update request number --- rfcs/20220824-tf-function-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/20220824-tf-function-type.md b/rfcs/20220824-tf-function-type.md index 4e49cb1c7..8d479556f 100644 --- a/rfcs/20220824-tf-function-type.md +++ b/rfcs/20220824-tf-function-type.md @@ -3,7 +3,7 @@ | Status | Proposed | :-------------- |:---------------------------------------------------- | -| **RFC #** | [TODO](https://github.com/tensorflow/community/pull/NNN) | +| **RFC #** | [424](https://github.com/tensorflow/community/pull/424) | | **Author(s)** | Faizan Muhammad (fmuham@google.com)| | **Sponsor** | Yanhua Sun (yanhuasun@google.com) | | **Updated** | 2022-08-24 |