From 3f3c18f7750aa389fa3b2332d96078ae2756cce6 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Tue, 5 Mar 2019 16:25:25 -0800 Subject: [PATCH 1/7] Modular tensorflow public design review. --- rfcs/20190305-modular-tensorflow.md | 519 ++++++++++++++++++ .../api_picture.png | Bin 0 -> 24565 bytes .../big_picture.png | Bin 0 -> 19995 bytes .../cpp_module.png | Bin 0 -> 32864 bytes .../initial_tf_deps.png | Bin 0 -> 11226 bytes .../py_modules.png | Bin 0 -> 29365 bytes rfcs/20190305-modular-tensorflow/releases.png | Bin 0 -> 25061 bytes .../simple_package_deps.png | Bin 0 -> 6051 bytes 8 files changed, 519 insertions(+) create mode 100644 rfcs/20190305-modular-tensorflow.md create mode 100644 rfcs/20190305-modular-tensorflow/api_picture.png create mode 100644 rfcs/20190305-modular-tensorflow/big_picture.png create mode 100644 rfcs/20190305-modular-tensorflow/cpp_module.png create mode 100644 rfcs/20190305-modular-tensorflow/initial_tf_deps.png create mode 100644 rfcs/20190305-modular-tensorflow/py_modules.png create mode 100644 rfcs/20190305-modular-tensorflow/releases.png create mode 100644 rfcs/20190305-modular-tensorflow/simple_package_deps.png diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md new file mode 100644 index 000000000..e8b1d0781 --- /dev/null +++ b/rfcs/20190305-modular-tensorflow.md @@ -0,0 +1,519 @@ +# Modular TensorFlow + +| Status | (Proposed / Accepted / Implemented / Obsolete) | +:-------------- |:---------------------------------------------------- | +| **Author(s)** | Gunhan Gulsoy (gunan@google.com) | +| **Sponsor** | Martin Wicke (wicke@google.com) | +| **Updated** | 2019-03-06 | + + +## Motivation + +TensorFlow is a very successful open source project. Since it has been open sourced, [1800+ contributors](https://github.com/tensorflow/tensorflow) have submitted code into TF from outside Google. However, as more and more developers contribute, it becomes more and more difficult to manage contributions in the single repository. + +This project aims to split the TensorFlow codebase into** smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to the module APIs, these modules are now **managed/owned/released independently.** + +### Problems + + +#### Spaghetti dependencies + +Everything being in a single repository encourages everyone to freely use all other code in the repository, even when this does not make sense. This ensures the library is very difficult to modify later. One example we have for this is the current size of TF, and tf-lite. TF-mobile used to be our initial offering for ml for apps. However, tf mobile required 30+ MBs added to each app, where android apps on the average are [11.5 MBs](https://www.google.com/search?source=hp&ei=82Q-XPfsN5Pj9AORiKmoAw&q=android+average+app+size&btnK=Google+Search&oq=wombat&gs_l=psy-ab.3..0l10.876.1495..3702...0.0..0.76.466.7......0....1..gws-wiz.....0..0i131j0i3.Ij8iLyUMFbE). Thus the TF lite project was born. However, due to the nature of the core TF runtime, TF lite team decided that it is easier to write an entirely new runtime for mobile. + + +#### Long OSS build times + +Having a single repository works great for google. This is in part because it is backed by great infrastructure such as distributed source management tools and massively distributed build system. However, in the open source world these tools do not exist. While Google has efforts to make these available, they do not work as well as internal solutions, and they are too costly for many open source contributors. + +Therefore, building open source tensorflow becomes a painful experience. Many volunteers and developers outside google use their laptops for development. On such systems, TF development cycles require building all of tensorflow that takes around 2 hours. While there is an argument to be made that bazel caching should ensure that they build all of TF only once, without forge, bazel caching is not working as [well as expected](https://docs.bazel.build/versions/master/remote-caching.html#known-issues). + +This also impacts the TF development team, too. Our Kokoro builds are usually our longest running builds, and we have to disable windows and macos presubmits due to concerns about build times. As soon as the presubmits were disabled, average greenness have plunged for windows and macos builds from over 90% to below 50%. + + +#### Adding support for new hardware is very difficult and not scalable + +The ML ecosystem is constantly expanding. New hardware for accelerating ML applications is being worked on by many teams inside and outside Google. As the most popular machine learning framework, TF is expected to add support for many of these hardware as quickly as possible. + +Currently, this means that all such hardware developers need to check in their code into the [main tensorflow repository](http://github.com/tensorflow/tensorflow). This means that all the changes are required to go through TF team's review. This can make merging support for new hardware very very difficult. One glaring example is that AMD has a [fork of tensorflow that can run on AMD GPUs](https://github.com/ROCmSoftwarePlatform/tensorflow-upstream). However, [despite their efforts it has been more than 8 months](https://github.com/tensorflow/tensorflow/pulls?utf8=%E2%9C%93&q=is%3Apr++ROCM) and we still do not have AMD GPU support upstreamed into main TF repo. + + +#### Long PR review queue + +TensorFlow is a very successful opensource project. It is the [4th most forked](https://github.com/search?o=desc&q=stars:%3E1&s=forks&type=Repositories) and [5th most starred](https://github.com/search?q=stars%3A%3E0&s=stars&type=Repositories) project on github. This also means that TF receives quite a lot of opensource contributions. The TensorFlow team has to review all contributions to TensorFlow itself. This creates a bottleneck for merging the changes to the main repository. Currently, we have 296 open PRs, 173 of which had no updates in the last week, and even worse, 87 had no updates in the last 2 weeks as of the end of January. + +Modularizing TensorFlow means that: + + + +* We will enable contributors to own code that we will never use inside of google3. They will be able to host their own code, and work seamlessly with TensorFlow. +* We will have smaller repositories with owners having more control over their repositories. Currently, there is no single reviewer who has the full knowledge to confidently review every single change in TF main repository. Smaller repositories will mean that we will have clearer code owners defined with each repository, who will have more expertise about the code they own. +* We will avoid giant pull requests. In the past, [we have had 1500+ lines of changes](https://github.com/tensorflow/tensorflow/pull/20277) in single pull requests, which required 10 different reviewers to be able to review and merge the code. With smaller repositories, such changes will be split up into smaller and more manageable changes. + + +#### Flexibility for Collaborators/partners + +Currently, any partner or contributor that would like to work with us are subject to all the rules within our repository. Such rules are: + + + +* All code has to be reviewed by a member of TensorFlow team +* They have to use bazel +* They have to sign Google CLA. +* They have to open source their code as a part of our repository +* They have to wait for our release schedules to make use of their features +* They have to rewrite their code based on google style guides. + +With modularization, we would like to remove all of these constraints on our partners, at the cost of these plugins being required to use the C APIs we plan to offer. + + +#### Large TF support matrix + +TF support story is a unique beast. TF support matrix has a lot of orthogonal dimensions. Below are some of the more prominent dimensions: + +* Environment (google3, opensource) +* Operating system (Linux, windows, macos, mobile) +* Architecture (x86, arm, ppc64, …) +* Accelerator (CPU, GPU, TPU) +* Compiler (GCC, Clang, MSVC) +* Python version (2, 3.4, 3.5, 3.6, 3.7) + +More can be added to this list where we have to rebuild tensorflow to support different network architectures, CUDA versions, SIMD instruction sets, etc. + +Having a monolithic repository means we need to rebuild all of our code for all of these different combinations. However, it makes no sense to rebuild all of our C++ code if the only difference is the python version. Or rebuild all of our CPU kernels for different CUDA versions. Modularizing our code means we only need to rebuild and test the modules that are directly impacted by the dimensions we are changing in the support matrix. + + +## Overview + +This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to these APIs, these modules will be **managed/owned/released independently**. There will be different strategies to break apart pieces based on the languages, but below summarizes the approach for C++ and python: + + +![alt_text](20190305-modular-tensorflow/big_picture.png "Overview of modular TensorFlow") + +A summary of the above is: + + + +* Core TF functionality will be implemented in C++ +* Core TF functionality can be extended using shared objects. +* On top of the core C++ libraries, we will have the language bindings (Using the C API) +* There can be more functionality built on top of the core TF bindings in different languages, which can be maintained and distributed separately. +* All different pieces need to use Stable public APIs with backwards compatibility guarantees. + + +### Definitions + +This section will briefly describe the terms we will use in the rest of this design. + +**Modules:** These are the components of core TF library that will "accept" plugins to expand their capabilities. Examples of modules are networking, filesystem, (graph) optimizers. + +**Plugins:** Plugins are extensions to different modules. For example, filesystem module can have a GCP plugin, an S3 plugin, an HDFS plugin. + +**Shared objects:** These are dll/so/dylib files that can house **one or more** plugins for **one or more **modules. + +**Packages: **Python pip packages which may include python files and/or shared objects. + + +### C++ + +This project aims to implement similar plugin architectures for multiple components of TF code. While these will be listed separately, **there will be a lot of shared pieces between these components**. The modules we would like to handle are: + + + +1. Networking module, with verbs, gdr plugins initially +1. Filesystems module, with GCP, AWS and HDFS support +1. Kernels module, +1. Optimizers/Graph rewrite module, +1. Accelerator backends module + +The above is not an exhaustive list of modules we would like to introduce. These are just initial ideas for good candidates for modules. + +In the initial plan, we will keep XLA as a part of core TF, because of the large API surface. Once the initial work for the above modules are complete, we can reevaluate this decision with XLA team. + +Each of these aspects require unique special treatment in addition to the common strategy defined below. These unique nuances will be discussed in separate documents. Next, we detail the module/plugin architecture we would like to implement abstracting out the specific components listed above. + +This is a high level description of a single module and multiple plugins for this module: + + + +![alt_text](20190305-modular-tensorflow/cpp_module.png "C++ module example") + + +The big pieces of this design are: + + + +1. Modules: Well defined components within tensorflow that need multiple implementations, and select different code paths at runtime +1. Plugins: These will be implementations of each module. Each plug-in will implement an "interface" (i.e., the API defined as C functions rather than a pure virtual class in C++). These will be loaded dynamically at runtime, +1. TF framework/platform APIs: Shared functionality needed for implementing the plugins. Main purpose is to pass data/state between plugins and core. + + +### Python + +Below diagram provides a summary of the proposed tensorflow pip package ecosystem. + + +![alt_text](20190305-modular-tensorflow/py_modules.png "Python module example") + + + +1. Tensorflow Base pip package: This provides the core tensorflow functionality all of TF will share. While estimator and keras provide high level neural network primitives, base will provide basic matrix operations these two packages will use to build the high level APIs. +1. Required tensorflow addons: These are pieces of tensorflow that has to be included in all TF distributions. Examples to this are Estimator, keras, tensorboard and base. These are pieces of the public API that are promised to exist by our compatibility guarantees. +1. TensorFlow Metapackage: This will be a thin package that only defines the composition of tensorflow. Please see the detailed design section for more details on this package. +1. Optional TF packages: These packages will include the optional TF features users may choose to load and enable after they have TF working. Without these, TF will work just fine. Example features we will have as optional packages are GPU support, MKL support, or cloud filesystem support. These will use the C++ modules to load the functions they provide at runtime. + + +## Detailed Design + +We will describe each key design element here in detail. To make the points clearer, trivial examples will be created. + + +### Modularity in C/C++ + +This section will describe the key design points for C++ modularity. + + +#### Modules + +Each module's main pieces will be a module interface in C, and a registry for plugins implementing this module. As a supporting piece, each module will also need to provide a mechanism for plugins to add themselves to the registry at runtime. Below is a toy example for the described design: + + +``` +// A simple toy module called "M" +typedef struct M_context; + +// The summary of the interface plugins need to implement +typedef struct MInterface { + void (*M_Init)(M_context*, string); + void (*M_Execute)(M_context*); +}; + +// The plugin registry for module M +// The registry here implemented uses C++ class std::map +// This is OK as it is not exposed in our example here. +// As far as module implementations are concerned, they only +// need to see and use M_RegisterPlugin method, and that method takes // care of their addition into this registry. +std::map m_plugin_registry; + +// Function to call for each plugin at load time +// to add themselves to the registry +void M_RegisterPlugin( + string plugin, + void (*M_Init)(M_context*, string), + void (*M_Execute)(M_context*)) { + // Omitting error handling. + m_plugin_registry.insert(plugin, + MInterface(M_Init, M_Execute)); +} + +// Implementation of the interface is just a thin layer to +// get the correct plugin and call it. +// Here we assume that plugin explicitly gets selected by +// the init function. Some modules can go with implicit selection, +// Such as deducing the filesystem from the file path. +void M_Init(M_context* ctx, string id) { + // Just a quick hacky way to select the plugin here + ctx->interface = m_plugin_registry[id]; + ctx->interface.M_Init(ctx, id); +} + +void M_Execute(M_context* ctx) { + ctx->interface.M_Execute(ctx); +} +``` + + +**Please note that the above is a toy example to explain the abstract ideas described above. Exact implementation can vary across different modules.** + +Interface has to be pure C at the ABI level. We can have C++ header-only libraries built on top of these C ABI/APIs. + + +#### Plugins + +Plugins need to include implementation of the interfaces declared by one module. If the module interface requires Init and Compute methods, it will need to implement these two functions, plus a TF_InitPlugin function which will be called at load time. This function will also need to register the plugin as prescribed by the module. + + +``` +// A simple plugin implementation A, for module M. +typedef struct M_context; + +// Here is the meat of the plugin: +void A_Init(M_context* ctx, string id) { + // id can be thrown away, in this example. + // Or can encode different ways plugin can be initialized. + ...... + // initialize the plugin + // Modify the context using functions exposed by core + TF_SetFooInContext(ctx, foo); + TF_InitBarInContext(ctx); +} + +void A_Execute(M_context* ctx) { + .......... +} + +void TF_InitPlugin() { + M_RegisterPlugin("A", A_Init, A_Execute); +} +``` + + +When this plugin is loaded by TF at runtime, `TF_InitPlugin` method will be called. This method will register the plugin as prescribed by the module, and exit. + +Plugin shared objects will need to follow some standards: + + + +1. These cannot export any symbols into global namespace to avoid symbol collisions. +1. They need to communicate to TF through any provided C APIs. +1. They can link anything they like, anyway they like in addition to TF. +1. They can be built and distributed separately + + +#### How plugins are loaded + +TensorFlow will look for and load plugins in two different ways: + + + +1. Default TF plugin directories, such as `...python_dir.../site-packages/tensorflow-plugins` +1. User calls `tf.LoadLibrary` + +Both of these will go through the tf.LoadLibrary method, which does the following: + + + +1. Check the directory for plugins. +1. For each plugin, check if they are loadable using platform string, as defined in: [tensorflow/core/platform/platform_strings.h](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/platform/platform_strings.h) +1. dlopen the library +1. dlsym `TF_InitPlugin symbol`, and call it +1. exit. + +To ensure that correct platform strings are generated in each shared object, each plugin library is required to include the following code snippet: + + +``` +#include "tensorflow/core/platform/platform_strings.h" +TF_PLATFORM_STRINGS() +``` + + + +#### TF Framework/platform API + +While all the above components require a lot of careful planning, this piece of this design will require close to half of the total coding load. Currently, all planned components treat the union of all headers under TF as their API. More than 90% of these headers define C++ APIs. + +Our work here will cumulatively build a large API surface in C. While we can compartmentalize work for each module, with more modules implemented there will be a lot of shared API endpoints in core framework between these modules. + +Below is a 10K ft view of how the "different" APIs may look like in a simple set representation, with varying sizes, varying levels of intersection. + + +![alt_text](20190305-modular-tensorflow/api_picture.png "A simple representation of the API.") + +We expect all of this work to be cumulative and finally defining a large coherent API surface for TF. + +Once this API is ready, header only C++ APIs can be defined using this API. + + +### Modularity in Python + +This section will describe the key design points for modular python packages for TF. + + +### TensorFlow base pip package + +Contains the base Python API, and "Core TF" C++ shared objects + +This package will be a subset of the current "tensorflow" pip package. It will include all of the core TF API except the high level API modules we will split up. It will define a public API for everything except for the required add on packages. This API is required to have backwards compatibility guarantees for minor version changes. With this guarantee, we expect the following: + + + _"Given that the combination of these packages work: TF-base 1.n, and addon package 1.m work together, TF-base 1.(n+k) and add on package 1.m should always work together."_ + +If we discover a violation of this guarantee, that will be treated as a P1 bug, and it will require a patch release for the base package 1.(n+k) + + +### Required tensorflow addons + +These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full python code of TF, except for top level API wiring. + +These packages have two constraints: + + + +1. They are only allowed to use public APIs exposed by their dependencies. +1. They are required to provide backwards compatible public APIs. + +With the backwards compatible public APIs, we expect addons to be able to release independently as long as features they depend on are released in their dependencies. + +These packages will have full control over the versions of their dependencies. We recommend they only set a minimum version for their dependencies. When they need new features, they will bump their minimum requirement to include the new API changes. + + +### TensorFlow Metapackage + +This package will reconstruct the TF public API from the base and other requirements + +Just a simple setup.py file that defines dependencies on specific versions of all required packages and base package, plus an `__init__.py` file that defines the top level tensorflow API. + +The python code for tensorflow metapackage will be a single `__init__.py` file that will look like this: + + +``` +from tensorflow_base import * +import tensorflow_estimator as estimator +import tensorflow_keras as keras +<………… more packages as needed > +``` + + +A new tensorflow release will mean we will pick combinations of dependencies, run all our integration tests, and then release the above python file with these dependencies in its setup.py file: + + +``` +TENSORFLOW_DEPENDENCIES= [ + "tensorflow_base == 1.x.y", + "tensorflow_estimator == 1.a.b", + "tensorboard == 1.c.d", + "tensorflow_keras == 1.e.f" +] +``` + + + +### TF Public APIs + +As a part of the modularization, to be able to decouple development and releases for each of these packages, each package is required to expose a **public API with backwards compatibility guarantees**. What this means is, no API symbols in the public API cannot be changed in a backwards incompatible way, syntactically or semantically, between any minor versions. Below is a toy example of two packages explaining the guarantees we expect: + + +![alt_text](20190305-modular-tensorflow/simple_package_deps.png "Just two example packages.") + + + +* P1 depends on P2 +* P2 is expected to provide a public API +* All API symbols exposed by P2 version M.N is expected to work at version M.(N+K) for any non-negative integer K. +* P2 is allowed to make breaking changes to its API between major releases (M to M+1) +* If P1 version X.Y works with P2 version M.N, it should also work the same way with P2 version M.(N+K) However, there are no guarantees for it to work with P2 version (M+K).L +* When P1 is releasing a new version, it should check which API symbols it needs from P2, and fix the minimum version requirement in its pip package for P2 accordingly. + + +### Optional TF packages + +Mostly expected to contain the C++ plugins defined in the previous section. These will be simple pip packages that will deploy the shared objects under "site-packages/tensorflow-plugins" + +These shared objects will be automatically loaded by TF core if: + + + +* They correctly define the compatibility strings using `TF_PLATFORM_STRINGS` +* They are compatible with the system tf core is running on +* They have been properly built and signed (unless running in developer mode) + + +## Alternatives / Potential Issues + + + +* **Why do we not use C++ APIs instead of C**: Compilers have no guarantees for ABIs generated for C++ code. Any C++ API used will require each shared object to be compiled with the same compiler, using the same version of the compiler, with the same compiler flags ([See github issue 23561](https://github.com/tensorflow/tensorflow/issues/23561)). +* **Why do not we statically link everything**: Single shared object for everything: Anywhere except google does not have access to the massively parallel build system we use here at google. This causes prohibitive build times, causing major developer pain for open source developers. There are many more issues, but the summary is while this is a great solution for google, outside google this is simply infeasible. +* **TF will become a suite of multiple packages, built by multiple authorities. What if the bugs get blamed on TF team**: With the modular model, we expect testing of 3rd party code to become easier. This can also be mitigated if the error messages are better, and if they can clearly point out which module the issue stems from. Finally, we can create an apple-swift like testing model, where we run a jenkins setup that people can donate their machines to, and we can run continuous integration tests on their plugins. +* **Why not have APIs but still have a monolithic repository: **When everything is in a single repository, this enables developers to bypass the APIs, and depend on internals. Moreover, we cannot grant full control over different folders on our repository to our partners in a single repository. As long as they are in a single repository, they are still constrained by our build system and license. Finally, in a single repository we do not provide the option of closed source plugins for contributors. +* **Why not go with the OSS federation solutions?** OSS federation requires all dependencies to be in the federation before adding a repository. This is simply not possible for tensorflow, as eigen, llvm and many other dependencies will never be a part of the federation. +* **Documentation, how/where do we document everything?** With multiple repositories, structure of the documentation will need to be rethought, based on what is a part of "TensorFlow proper" and what is an optional feature. + + +## Testing Plan + +We propose the following principles to be followed for testing in a modular world: + +* Each plugin tested separately. +* Modules can plan their own integration tests. +* Cut combinatorial explosion by divide and conquer. +* Fuzzing at the core-module interface level if possible, in the case we need data marshalling between layers. +* With this proposal, we aim to also simplify testing of tensorflow code. The biggest gain we expect in the modular world will be, we will be able to "divide and conquer" the TensorFlow support matrix. +* Following describes an early modularized tensorflow package structure: + + +![alt_text](20190305-modular-tensorflow/initial_tf_deps.png "Initial package structure") + +In the current setup, we need to test all of the above packages for different python versions, operating systems, accelerators(CPU, GPU), compilers, and more variants combined. In the modularized world, each of these packages only need to be unit tested for the following: + + +* tensorflow-base: Operating systems, compiler versions and python versions only with CPU +* tf-gpu: With GPU only, for different operating systems. +* tf-estimator: Only for different python versions + +When testing a package that has dependencies, such as tf-estimator, or tf-gpu, tensorflow-base will be installed with its latest stable release, to ensure to avoid any flakes by this package. + +We know that with the current release cadence this is too slow to support TF's rapid development. But with modules, we expect to be able to release much more frequently. + +On top of the proposed unit testing plan above, we will need package level integration tests. We propose these to be run every night at head. We propose the following to act as the TF integration tests: + + + +* Miscellaneous pip utility tests. Build the nightly pip packages, install them. Then make sure you can import TF, run the command line utilities distributed with TF. +* Tutorials/notebook tests. Build the "nightly" pip packages for all above components. Then install this package. Finally extract the python code from notebooks and run them as graphs +* Models tests: Build and install the nightly pip packages, then run curated models under tensorflow/models for a small amount of steps. + +The above will simply check the sanity of TF, just will check if TF can run without crashing. However, TF requires much more testing. We propose expansion and adoption of the following regression tests to nightly TF test suites: + +* Convergence tests: Run a curated set of small models until convergence. measure the time to converge, and steps to converge +* Performance tests: Run a curated set of models for a pre-selected number of steps. Measure steps per second, and for image models images per second. + + +## Releases + +In the multi package environment, we aim to have the following with the releases: + +1. Smaller packages: We expect to release multiple small packages, instead of the giant package we are building and releasing right now. +1. Faster releases: We would like the smaller packages to be able to release much faster. With the ability to pin each dependency to a known good version, we would like to be able to compartmentalize issues, and only hold certain components back when only certain code in TF has issues. +1. Independent releases: With compatibility checks, we would like to be able to independently release different packages + +Below summarizes a timeline of releases for three packages, A, B and C, where B depends on A and C depends on B. + + +![alt_text](20190305-modular-tensorflow/releases.png "Release plans") + + +To summarize the above timeline: + +* Different packages set their own release cadences +* Each package will set version boundaries for each of their dependencies. +* Each package is responsible for ensuring that all of their public APIs are working without any changes until the next major release +* Packages do not need to modify the minimum version requirements unless they start using newly introduced public API symbols. +* TF metapackage releases may choose to hold back individual packages in favor of faster releases. But dependency requirements have to be respected when doing so. +* Major releases still need to be coordinated. + + +## Packaging Issue Scenarios + + +We will now go over a few failure modes in the proposed environment, and propose how things need to be resolved. We will use a simple example, where we have three packages, A, B and C, where C depends on B and A, and B depends on A. + + +#### Scenario 1: B does not work with a new release of A + +Potential issues: + +* B uses non-public symbols from A: + * B has to release a new version avoiding non-public APIs +* A changed public APIs: + * A has to revert changes to its public APIs and release a patch version replacing the bad version + + +#### Scenario 2: New release of B does not work with A + +Potential issues: + +* B depends on unreleased APIs A exposed in a newer version + * B needs to release a patch version, with just a change in the minimum required version of A + + +#### Scenario 3: C and B depend on different minimum versions of A + +As both C and B have to define a range of versions they require from A, the max version should satisfy both constraints. + + +#### Scenario 4: User installs C first, but then uninstalls A + +This is a pip issue. To help diagnose the problem, B and C should print that A is missing, and user needs to install that to use B or C. + + diff --git a/rfcs/20190305-modular-tensorflow/api_picture.png b/rfcs/20190305-modular-tensorflow/api_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3b6e1dc54d7a607b4fcb83f5cbc238954e3ec4 GIT binary patch literal 24565 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 DyFw>k literal 0 HcmV?d00001 diff --git a/rfcs/20190305-modular-tensorflow/big_picture.png b/rfcs/20190305-modular-tensorflow/big_picture.png new file mode 100644 index 0000000000000000000000000000000000000000..f4e47875a6b6bbf4e2945be2e088f87b4b0d38c4 GIT binary patch literal 19995 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 literal 0 HcmV?d00001 diff --git a/rfcs/20190305-modular-tensorflow/cpp_module.png b/rfcs/20190305-modular-tensorflow/cpp_module.png new file mode 100644 index 0000000000000000000000000000000000000000..566cc23259adf5fa941990241807b2d1ab4e9e00 GIT binary patch literal 32864 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 literal 0 HcmV?d00001 diff --git a/rfcs/20190305-modular-tensorflow/initial_tf_deps.png b/rfcs/20190305-modular-tensorflow/initial_tf_deps.png new file mode 100644 index 0000000000000000000000000000000000000000..aa23bd62e02f5f3651a2548984fed3816b939d71 GIT binary patch literal 11226 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 _1z2w6+AFzwhLPtMxe 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 J&AFd{`){UYrT72< literal 0 HcmV?d00001 diff --git a/rfcs/20190305-modular-tensorflow/py_modules.png b/rfcs/20190305-modular-tensorflow/py_modules.png new file mode 100644 index 0000000000000000000000000000000000000000..0f8fe9c8ddb01b8dd1d987049c753e8f13bd3d69 GIT binary patch literal 29365 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 literal 0 HcmV?d00001 diff --git a/rfcs/20190305-modular-tensorflow/simple_package_deps.png b/rfcs/20190305-modular-tensorflow/simple_package_deps.png new file mode 100644 index 0000000000000000000000000000000000000000..dacaa9a2e2a88c8b412e8b06d8d99c4960d07ad3 GIT binary patch literal 6051 zcmeAS@N?(olHy`uVBq!ia0y~yU~)xf|UvrBvql z!|8W(H!q81)pgcdqIA&1W0HZ62=`(qt4T^F2e=pOEo#j>)y*-DOUWQYplgDThnCr* z=8`3?ykb*0cvu&APcTwae*N$5-@kVy%Vg8bUMD@TEuY6;7xJzr{Qlk-hh;YL04*K` zqaiRF0;3@?8UmvsKw=0)JkZ-&ay0&^eUbV9?Ikxq+3Reue&y_4xAEY+nEL;f$8`mO z20jb_clUh#ZoNAp0ter{l>>?hIJF48x%Z9{$W(OUzz}rcD0J$$YrUHtB!7fcvF!aD zkggU1^_ClZH&+ujfFaO{V`Fvtcc4mz77N8A@8;fRW?*O#c+?`WyS$7aDD2cB?1aY! zNX|mBb&f#N_j4e3qc{gW#9mchA6f8xHe6bwy6)?S9SJQP0IP#vh(ftRIBJ$ zKM{0#Q@3vS{taQL*T-+SlfP?!?bDp}_#2bg?|C)rS#o$xnd`0npdevb%C9JBBv<`v z=Cijqe!A2>-+TMhuM3a9d@h^#_~^yj%Krx%7(7(V_rJPjYFxJe?Znuh)7E}p{zKNj zzVdyv?!w>4cxMNR^v}P$<>R(5>HT(gIiMhS*y((N_jSJA^YeUua^8Xld7pl~KWjhV zqROZ~!k;zwOJTrfQN!iVWnw-)i&+rPzkO*a-&cSC&t~7~cV6o!b=CJj2kMP13oMlGmR@n{ zoi*!$)!}RX`e(j9ZTIfxzk<{6+d-k@@P1VcLr=Kr(dP?~uAYC(Hl876*6%Ls&^wKf z%+k}75}q<8)EtX9`&wB)_g~+!=+?)f8^DPxC6!O{6GN|evsTJ{e8SY-uCay{QYO+dj942XII?$vi&%B127mB7^WEs znZ!Lc|NDqrK#67F$A9Uv^WTd$_-tOdoag}Z4qFcFz^1~dd`OP`!|`}s_*-d{OHBW zOULaY8PtVg$@6mi>kL1RK9s+FyY97f_vPq@$G110-}g~j9qbSRhE{>y>ysE{?%5i> zHkWf}*#b`0QxsM1-LlwK|EAvFex7uFJA=p7GW+ZKA8J20ufO!zI(CoO1#klJs>!?I zWCP5_^eH=lCDNcOJ0QgrN`XUsnK)x|)ZTyRul%2|yK*0Q*4E2nH)NZeyZvq^l&@RA z{=GRj3oxOLg3%Bd4S~@R7!85Z5Eu=C;T!@#w%b}LfO=g5U;dZcJAnotN5Nzopr04|!ie*gdg literal 0 HcmV?d00001 From 6526e3059de1062cfe435a687898f9707df2dac8 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Tue, 5 Mar 2019 22:32:54 -0800 Subject: [PATCH 2/7] Update the proposal status. --- rfcs/20190305-modular-tensorflow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index e8b1d0781..4b1d1807a 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -1,6 +1,6 @@ # Modular TensorFlow -| Status | (Proposed / Accepted / Implemented / Obsolete) | +| Status | Proposed | :-------------- |:---------------------------------------------------- | | **Author(s)** | Gunhan Gulsoy (gunan@google.com) | | **Sponsor** | Martin Wicke (wicke@google.com) | From 709c3a43c2ae9a13e4a08a04e975463eb9be31c9 Mon Sep 17 00:00:00 2001 From: Edd Wilder-James Date: Tue, 12 Mar 2019 10:51:07 -0700 Subject: [PATCH 3/7] Update 20190305-modular-tensorflow.md Here are my proposed changes, to streamline the introduction and correct a few typos. --- rfcs/20190305-modular-tensorflow.md | 88 ++++++++--------------------- 1 file changed, 25 insertions(+), 63 deletions(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index 4b1d1807a..d78dd1fcf 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -11,64 +11,35 @@ TensorFlow is a very successful open source project. Since it has been open sourced, [1800+ contributors](https://github.com/tensorflow/tensorflow) have submitted code into TF from outside Google. However, as more and more developers contribute, it becomes more and more difficult to manage contributions in the single repository. -This project aims to split the TensorFlow codebase into** smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to the module APIs, these modules are now **managed/owned/released independently.** - -### Problems +This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to the module APIs, these modules are now **managed/owned/released independently.** +### Problems addressed #### Spaghetti dependencies -Everything being in a single repository encourages everyone to freely use all other code in the repository, even when this does not make sense. This ensures the library is very difficult to modify later. One example we have for this is the current size of TF, and tf-lite. TF-mobile used to be our initial offering for ml for apps. However, tf mobile required 30+ MBs added to each app, where android apps on the average are [11.5 MBs](https://www.google.com/search?source=hp&ei=82Q-XPfsN5Pj9AORiKmoAw&q=android+average+app+size&btnK=Google+Search&oq=wombat&gs_l=psy-ab.3..0l10.876.1495..3702...0.0..0.76.466.7......0....1..gws-wiz.....0..0i131j0i3.Ij8iLyUMFbE). Thus the TF lite project was born. However, due to the nature of the core TF runtime, TF lite team decided that it is easier to write an entirely new runtime for mobile. - - -#### Long OSS build times - -Having a single repository works great for google. This is in part because it is backed by great infrastructure such as distributed source management tools and massively distributed build system. However, in the open source world these tools do not exist. While Google has efforts to make these available, they do not work as well as internal solutions, and they are too costly for many open source contributors. +Everything being in a single repository encourages everyone to freely use all other code in the repository, even when this does not make sense. This ensures the library is very difficult to modify later. -Therefore, building open source tensorflow becomes a painful experience. Many volunteers and developers outside google use their laptops for development. On such systems, TF development cycles require building all of tensorflow that takes around 2 hours. While there is an argument to be made that bazel caching should ensure that they build all of TF only once, without forge, bazel caching is not working as [well as expected](https://docs.bazel.build/versions/master/remote-caching.html#known-issues). - -This also impacts the TF development team, too. Our Kokoro builds are usually our longest running builds, and we have to disable windows and macos presubmits due to concerns about build times. As soon as the presubmits were disabled, average greenness have plunged for windows and macos builds from over 90% to below 50%. +#### Long build times +Many volunteers and developers outside Google use their laptops for development. On such systems, TF development cycles require building all of tensorflow that takes around 2 hours. While there is an argument to be made that bazel caching should ensure that they build all of TF only once, without forge, bazel caching is not working as [well as expected](https://docs.bazel.build/versions/master/remote-caching.html#known-issues). #### Adding support for new hardware is very difficult and not scalable The ML ecosystem is constantly expanding. New hardware for accelerating ML applications is being worked on by many teams inside and outside Google. As the most popular machine learning framework, TF is expected to add support for many of these hardware as quickly as possible. -Currently, this means that all such hardware developers need to check in their code into the [main tensorflow repository](http://github.com/tensorflow/tensorflow). This means that all the changes are required to go through TF team's review. This can make merging support for new hardware very very difficult. One glaring example is that AMD has a [fork of tensorflow that can run on AMD GPUs](https://github.com/ROCmSoftwarePlatform/tensorflow-upstream). However, [despite their efforts it has been more than 8 months](https://github.com/tensorflow/tensorflow/pulls?utf8=%E2%9C%93&q=is%3Apr++ROCM) and we still do not have AMD GPU support upstreamed into main TF repo. - +Currently, this means that all such hardware developers need to check in their code into the [main tensorflow repository](http://github.com/tensorflow/tensorflow). This means that all the changes are required to go through TF team's review. This can make merging support for new hardware very very difficult. #### Long PR review queue -TensorFlow is a very successful opensource project. It is the [4th most forked](https://github.com/search?o=desc&q=stars:%3E1&s=forks&type=Repositories) and [5th most starred](https://github.com/search?q=stars%3A%3E0&s=stars&type=Repositories) project on github. This also means that TF receives quite a lot of opensource contributions. The TensorFlow team has to review all contributions to TensorFlow itself. This creates a bottleneck for merging the changes to the main repository. Currently, we have 296 open PRs, 173 of which had no updates in the last week, and even worse, 87 had no updates in the last 2 weeks as of the end of January. - -Modularizing TensorFlow means that: - - - -* We will enable contributors to own code that we will never use inside of google3. They will be able to host their own code, and work seamlessly with TensorFlow. -* We will have smaller repositories with owners having more control over their repositories. Currently, there is no single reviewer who has the full knowledge to confidently review every single change in TF main repository. Smaller repositories will mean that we will have clearer code owners defined with each repository, who will have more expertise about the code they own. -* We will avoid giant pull requests. In the past, [we have had 1500+ lines of changes](https://github.com/tensorflow/tensorflow/pull/20277) in single pull requests, which required 10 different reviewers to be able to review and merge the code. With smaller repositories, such changes will be split up into smaller and more manageable changes. - - -#### Flexibility for Collaborators/partners - -Currently, any partner or contributor that would like to work with us are subject to all the rules within our repository. Such rules are: +TensorFlow is a very successful opensource project. It is the [4th most forked](https://github.com/search?o=desc&q=stars:%3E1&s=forks&type=Repositories) and [5th most starred](https://github.com/search?q=stars%3A%3E0&s=stars&type=Repositories) project on github. This also means that TF receives quite a lot of opensource contributions. The TensorFlow team has to review all contributions to TensorFlow itself. This creates a bottleneck for merging the changes to the main repository. +#### Flexibility for collaborators - -* All code has to be reviewed by a member of TensorFlow team -* They have to use bazel -* They have to sign Google CLA. -* They have to open source their code as a part of our repository -* They have to wait for our release schedules to make use of their features -* They have to rewrite their code based on google style guides. - -With modularization, we would like to remove all of these constraints on our partners, at the cost of these plugins being required to use the C APIs we plan to offer. - +Currently, any partner or contributor that would like to work with us are subject to all the rules within of the main repository. Some of these can be relaxed through modularization, where work can happen in a separate repository. #### Large TF support matrix -TF support story is a unique beast. TF support matrix has a lot of orthogonal dimensions. Below are some of the more prominent dimensions: +The TF support story is a unique beast. Our support matrix has a lot of orthogonal dimensions. Below are some of the more prominent dimensions: * Environment (google3, opensource) * Operating system (Linux, windows, macos, mobile) @@ -77,14 +48,14 @@ TF support story is a unique beast. TF support matrix has a lot of orthogonal di * Compiler (GCC, Clang, MSVC) * Python version (2, 3.4, 3.5, 3.6, 3.7) -More can be added to this list where we have to rebuild tensorflow to support different network architectures, CUDA versions, SIMD instruction sets, etc. +More can be added to this list where we have to rebuild TensorFlow to support different network architectures, CUDA versions, SIMD instruction sets, etc. -Having a monolithic repository means we need to rebuild all of our code for all of these different combinations. However, it makes no sense to rebuild all of our C++ code if the only difference is the python version. Or rebuild all of our CPU kernels for different CUDA versions. Modularizing our code means we only need to rebuild and test the modules that are directly impacted by the dimensions we are changing in the support matrix. +Having a monolithic repository means we need to rebuild all of our code for all of these different combinations. However, it makes no sense to rebuild all of our C++ code if the only difference is the Python version. Or rebuild all of our CPU kernels for different CUDA versions. Modularizing our code means we only need to rebuild and test the modules that are directly impacted by the dimensions we are changing in the support matrix. ## Overview -This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to these APIs, these modules will be **managed/owned/released independently**. There will be different strategies to break apart pieces based on the languages, but below summarizes the approach for C++ and python: +This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to these APIs, these modules will be **managed/owned/released independently**. There will be different strategies to break apart pieces based on the languages, but below summarizes the approach for C++ and Python: ![alt_text](20190305-modular-tensorflow/big_picture.png "Overview of modular TensorFlow") @@ -110,15 +81,13 @@ This section will briefly describe the terms we will use in the rest of this des **Shared objects:** These are dll/so/dylib files that can house **one or more** plugins for **one or more **modules. -**Packages: **Python pip packages which may include python files and/or shared objects. +**Packages: **Python pip packages which may include Python files and/or shared objects. ### C++ This project aims to implement similar plugin architectures for multiple components of TF code. While these will be listed separately, **there will be a lot of shared pieces between these components**. The modules we would like to handle are: - - 1. Networking module, with verbs, gdr plugins initially 1. Filesystems module, with GCP, AWS and HDFS support 1. Kernels module, @@ -133,15 +102,10 @@ Each of these aspects require unique special treatment in addition to the common This is a high level description of a single module and multiple plugins for this module: - - ![alt_text](20190305-modular-tensorflow/cpp_module.png "C++ module example") - The big pieces of this design are: - - 1. Modules: Well defined components within tensorflow that need multiple implementations, and select different code paths at runtime 1. Plugins: These will be implementations of each module. Each plug-in will implement an "interface" (i.e., the API defined as C functions rather than a pure virtual class in C++). These will be loaded dynamically at runtime, 1. TF framework/platform APIs: Shared functionality needed for implementing the plugins. Main purpose is to pass data/state between plugins and core. @@ -149,16 +113,16 @@ The big pieces of this design are: ### Python -Below diagram provides a summary of the proposed tensorflow pip package ecosystem. +Below diagram provides a summary of the proposed TensorFlow pip package ecosystem. ![alt_text](20190305-modular-tensorflow/py_modules.png "Python module example") -1. Tensorflow Base pip package: This provides the core tensorflow functionality all of TF will share. While estimator and keras provide high level neural network primitives, base will provide basic matrix operations these two packages will use to build the high level APIs. -1. Required tensorflow addons: These are pieces of tensorflow that has to be included in all TF distributions. Examples to this are Estimator, keras, tensorboard and base. These are pieces of the public API that are promised to exist by our compatibility guarantees. -1. TensorFlow Metapackage: This will be a thin package that only defines the composition of tensorflow. Please see the detailed design section for more details on this package. +1. TensorFlow Base pip package: This provides the core TensorFlow functionality all of TF will share. While estimator and keras provide high level neural network primitives, base will provide basic matrix operations these two packages will use to build the high level APIs. +1. Required TensorFlow addons: These are pieces of TensorFlow that has to be included in all TF distributions. Examples to this are Estimator, Keras, TensorBoard and base. These are pieces of the public API that are promised to exist by our compatibility guarantees. +1. TensorFlow Metapackage: This will be a thin package that only defines the composition of TensorFlow. Please see the detailed design section for more details on this package. 1. Optional TF packages: These packages will include the optional TF features users may choose to load and enable after they have TF working. Without these, TF will work just fine. Example features we will have as optional packages are GPU support, MKL support, or cloud filesystem support. These will use the C++ modules to load the functions they provide at runtime. @@ -166,12 +130,10 @@ Below diagram provides a summary of the proposed tensorflow pip package ecosyste We will describe each key design element here in detail. To make the points clearer, trivial examples will be created. - ### Modularity in C/C++ This section will describe the key design points for C++ modularity. - #### Modules Each module's main pieces will be a module interface in C, and a registry for plugins implementing this module. As a supporting piece, each module will also need to provide a mechanism for plugins to add themselves to the registry at runtime. Below is a toy example for the described design: @@ -316,7 +278,7 @@ Once this API is ready, header only C++ APIs can be defined using this API. ### Modularity in Python -This section will describe the key design points for modular python packages for TF. +This section will describe the key design points for modular Python packages for TF. ### TensorFlow base pip package @@ -333,7 +295,7 @@ If we discover a violation of this guarantee, that will be treated as a P1 bug, ### Required tensorflow addons -These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full python code of TF, except for top level API wiring. +These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full Python code of TF, except for top level API wiring. These packages have two constraints: @@ -353,7 +315,7 @@ This package will reconstruct the TF public API from the base and other requirem Just a simple setup.py file that defines dependencies on specific versions of all required packages and base package, plus an `__init__.py` file that defines the top level tensorflow API. -The python code for tensorflow metapackage will be a single `__init__.py` file that will look like this: +The Python code for tensorflow metapackage will be a single `__init__.py` file that will look like this: ``` @@ -414,7 +376,7 @@ These shared objects will be automatically loaded by TF core if: * **Why do we not use C++ APIs instead of C**: Compilers have no guarantees for ABIs generated for C++ code. Any C++ API used will require each shared object to be compiled with the same compiler, using the same version of the compiler, with the same compiler flags ([See github issue 23561](https://github.com/tensorflow/tensorflow/issues/23561)). * **Why do not we statically link everything**: Single shared object for everything: Anywhere except google does not have access to the massively parallel build system we use here at google. This causes prohibitive build times, causing major developer pain for open source developers. There are many more issues, but the summary is while this is a great solution for google, outside google this is simply infeasible. -* **TF will become a suite of multiple packages, built by multiple authorities. What if the bugs get blamed on TF team**: With the modular model, we expect testing of 3rd party code to become easier. This can also be mitigated if the error messages are better, and if they can clearly point out which module the issue stems from. Finally, we can create an apple-swift like testing model, where we run a jenkins setup that people can donate their machines to, and we can run continuous integration tests on their plugins. +* **TF will become a suite of multiple packages, built by multiple authorities. What if the bugs get blamed on TF team**: With the modular model, we expect testing of 3rd party code to become easier. This can also be mitigated if the error messages are better, and if they can clearly point out which module the issue stems from. Finally, we can create an apple-swift like testing model, where we run a Jenkins setup that people can donate their machines to, and we can run continuous integration tests on their plugins. * **Why not have APIs but still have a monolithic repository: **When everything is in a single repository, this enables developers to bypass the APIs, and depend on internals. Moreover, we cannot grant full control over different folders on our repository to our partners in a single repository. As long as they are in a single repository, they are still constrained by our build system and license. Finally, in a single repository we do not provide the option of closed source plugins for contributors. * **Why not go with the OSS federation solutions?** OSS federation requires all dependencies to be in the federation before adding a repository. This is simply not possible for tensorflow, as eigen, llvm and many other dependencies will never be a part of the federation. * **Documentation, how/where do we document everything?** With multiple repositories, structure of the documentation will need to be rethought, based on what is a part of "TensorFlow proper" and what is an optional feature. @@ -434,7 +396,7 @@ We propose the following principles to be followed for testing in a modular worl ![alt_text](20190305-modular-tensorflow/initial_tf_deps.png "Initial package structure") -In the current setup, we need to test all of the above packages for different python versions, operating systems, accelerators(CPU, GPU), compilers, and more variants combined. In the modularized world, each of these packages only need to be unit tested for the following: +In the current setup, we need to test all of the above packages for different Python versions, operating systems, accelerators (CPU, GPU), compilers, and more variants combined. In the modularized world, each of these packages only need to be unit tested for the following: * tensorflow-base: Operating systems, compiler versions and python versions only with CPU @@ -450,12 +412,12 @@ On top of the proposed unit testing plan above, we will need package level integ * Miscellaneous pip utility tests. Build the nightly pip packages, install them. Then make sure you can import TF, run the command line utilities distributed with TF. -* Tutorials/notebook tests. Build the "nightly" pip packages for all above components. Then install this package. Finally extract the python code from notebooks and run them as graphs +* Tutorials/notebook tests. Build the "nightly" pip packages for all above components. Then install this package. Finally extract the Python code from notebooks and run them as graphs * Models tests: Build and install the nightly pip packages, then run curated models under tensorflow/models for a small amount of steps. The above will simply check the sanity of TF, just will check if TF can run without crashing. However, TF requires much more testing. We propose expansion and adoption of the following regression tests to nightly TF test suites: -* Convergence tests: Run a curated set of small models until convergence. measure the time to converge, and steps to converge +* Convergence tests: Run a curated set of small models until convergence. Measure the time to converge, and steps to converge * Performance tests: Run a curated set of models for a pre-selected number of steps. Measure steps per second, and for image models images per second. From b42798f11d59dc9818bce4bd2cf6a276b4889518 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Tue, 12 Mar 2019 20:57:28 -0700 Subject: [PATCH 4/7] Fix markdown typos. --- rfcs/20190305-modular-tensorflow.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index d78dd1fcf..2291d5b02 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -79,9 +79,9 @@ This section will briefly describe the terms we will use in the rest of this des **Plugins:** Plugins are extensions to different modules. For example, filesystem module can have a GCP plugin, an S3 plugin, an HDFS plugin. -**Shared objects:** These are dll/so/dylib files that can house **one or more** plugins for **one or more **modules. +**Shared objects:** These are dll/so/dylib files that can house **one or more** plugins for **one or more** modules. -**Packages: **Python pip packages which may include Python files and/or shared objects. +**Packages:** Python pip packages which may include Python files and/or shared objects. ### C++ From 6faac9b8e76f03acd2a87edb774b1bfc51c26f9b Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Mon, 25 Nov 2019 14:18:11 -0800 Subject: [PATCH 5/7] Relax API requirements. --- rfcs/20190305-modular-tensorflow.md | 58 +++++++++-------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index 2291d5b02..9e3cdbdc5 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -11,7 +11,7 @@ TensorFlow is a very successful open source project. Since it has been open sourced, [1800+ contributors](https://github.com/tensorflow/tensorflow) have submitted code into TF from outside Google. However, as more and more developers contribute, it becomes more and more difficult to manage contributions in the single repository. -This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to the module APIs, these modules are now **managed/owned/released independently.** +This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs**. Thanks to the module APIs, these modules are now **managed/owned/released independently.** ### Problems addressed @@ -55,20 +55,27 @@ Having a monolithic repository means we need to rebuild all of our code for all ## Overview -This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that guarantee backwards compatibility. Thanks to these APIs, these modules will be **managed/owned/released independently**. There will be different strategies to break apart pieces based on the languages, but below summarizes the approach for C++ and Python: +This project aims to split the TensorFlow codebase into **smaller, more focused**, repositories that can be released and managed separately. These modules will talk to each other using **well defined APIs** that will evolve over time. Thanks to these APIs, these modules will be **managed/owned/released independently**. There will be different strategies to break apart pieces based on the languages, but below summarizes the approach for C++ and Python: ![alt_text](20190305-modular-tensorflow/big_picture.png "Overview of modular TensorFlow") A summary of the above is: - - * Core TF functionality will be implemented in C++ * Core TF functionality can be extended using shared objects. * On top of the core C++ libraries, we will have the language bindings (Using the C API) * There can be more functionality built on top of the core TF bindings in different languages, which can be maintained and distributed separately. -* All different pieces need to use Stable public APIs with backwards compatibility guarantees. +* All different pieces need to use well defined public APIs. + +A few important points to clarify above are: + +* We will try our best to make sure the APIs will stay as close as possible to + the current APIs. +* We are aiming to avoid needing to change most existing custom op and kernel + code. +* The APIs will evolve over time. We will modify the APIs based on our and + user's needs. These modifications are expected to reduce in frequency. ### Definitions @@ -90,7 +97,7 @@ This project aims to implement similar plugin architectures for multiple compone 1. Networking module, with verbs, gdr plugins initially 1. Filesystems module, with GCP, AWS and HDFS support -1. Kernels module, +1. Kernels module, 1. Optimizers/Graph rewrite module, 1. Accelerator backends module @@ -285,26 +292,11 @@ This section will describe the key design points for modular Python packages for Contains the base Python API, and "Core TF" C++ shared objects -This package will be a subset of the current "tensorflow" pip package. It will include all of the core TF API except the high level API modules we will split up. It will define a public API for everything except for the required add on packages. This API is required to have backwards compatibility guarantees for minor version changes. With this guarantee, we expect the following: - - - _"Given that the combination of these packages work: TF-base 1.n, and addon package 1.m work together, TF-base 1.(n+k) and add on package 1.m should always work together."_ - -If we discover a violation of this guarantee, that will be treated as a P1 bug, and it will require a patch release for the base package 1.(n+k) - +This package will be a subset of the current "tensorflow" pip package. It will include all of the core TF API except the high level API modules we will split up. It will define a public API for everything except for the required add on packages. ### Required tensorflow addons -These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full Python code of TF, except for top level API wiring. - -These packages have two constraints: - - - -1. They are only allowed to use public APIs exposed by their dependencies. -1. They are required to provide backwards compatible public APIs. - -With the backwards compatible public APIs, we expect addons to be able to release independently as long as features they depend on are released in their dependencies. +These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full Python code of TF, except for top level API wiring. As like any addons, these are only allowed to use public APIs exposed by their dependencies. These packages will have full control over the versions of their dependencies. We recommend they only set a minimum version for their dependencies. When they need new features, they will bump their minimum requirement to include the new API changes. @@ -342,19 +334,7 @@ TENSORFLOW_DEPENDENCIES= [ ### TF Public APIs -As a part of the modularization, to be able to decouple development and releases for each of these packages, each package is required to expose a **public API with backwards compatibility guarantees**. What this means is, no API symbols in the public API cannot be changed in a backwards incompatible way, syntactically or semantically, between any minor versions. Below is a toy example of two packages explaining the guarantees we expect: - - -![alt_text](20190305-modular-tensorflow/simple_package_deps.png "Just two example packages.") - - - -* P1 depends on P2 -* P2 is expected to provide a public API -* All API symbols exposed by P2 version M.N is expected to work at version M.(N+K) for any non-negative integer K. -* P2 is allowed to make breaking changes to its API between major releases (M to M+1) -* If P1 version X.Y works with P2 version M.N, it should also work the same way with P2 version M.(N+K) However, there are no guarantees for it to work with P2 version (M+K).L -* When P1 is releasing a new version, it should check which API symbols it needs from P2, and fix the minimum version requirement in its pip package for P2 accordingly. +As a part of the modularization, to be able to decouple development and releases for each of these packages, each package is required to expose a **well defined, well documented public API**. ### Optional TF packages @@ -363,8 +343,6 @@ Mostly expected to contain the C++ plugins defined in the previous section. Thes These shared objects will be automatically loaded by TF core if: - - * They correctly define the compatibility strings using `TF_PLATFORM_STRINGS` * They are compatible with the system tf core is running on * They have been properly built and signed (unless running in developer mode) @@ -372,8 +350,6 @@ These shared objects will be automatically loaded by TF core if: ## Alternatives / Potential Issues - - * **Why do we not use C++ APIs instead of C**: Compilers have no guarantees for ABIs generated for C++ code. Any C++ API used will require each shared object to be compiled with the same compiler, using the same version of the compiler, with the same compiler flags ([See github issue 23561](https://github.com/tensorflow/tensorflow/issues/23561)). * **Why do not we statically link everything**: Single shared object for everything: Anywhere except google does not have access to the massively parallel build system we use here at google. This causes prohibitive build times, causing major developer pain for open source developers. There are many more issues, but the summary is while this is a great solution for google, outside google this is simply infeasible. * **TF will become a suite of multiple packages, built by multiple authorities. What if the bugs get blamed on TF team**: With the modular model, we expect testing of 3rd party code to become easier. This can also be mitigated if the error messages are better, and if they can clearly point out which module the issue stems from. Finally, we can create an apple-swift like testing model, where we run a Jenkins setup that people can donate their machines to, and we can run continuous integration tests on their plugins. @@ -439,7 +415,7 @@ To summarize the above timeline: * Different packages set their own release cadences * Each package will set version boundaries for each of their dependencies. -* Each package is responsible for ensuring that all of their public APIs are working without any changes until the next major release +* Each package is responsible for ensuring that all of their public APIs are working as promised. * Packages do not need to modify the minimum version requirements unless they start using newly introduced public API symbols. * TF metapackage releases may choose to hold back individual packages in favor of faster releases. But dependency requirements have to be respected when doing so. * Major releases still need to be coordinated. From 4e3443a512794c45e75c4a7cc8128e2019685aad Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Mon, 25 Nov 2019 15:45:56 -0800 Subject: [PATCH 6/7] Further edits. --- rfcs/20190305-modular-tensorflow.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index 9e3cdbdc5..f7b0c3bab 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -75,7 +75,10 @@ A few important points to clarify above are: * We are aiming to avoid needing to change most existing custom op and kernel code. * The APIs will evolve over time. We will modify the APIs based on our and - user's needs. These modifications are expected to reduce in frequency. + user's needs. These modifications are expected to follow versioning guidelines + [described + here](https://github.com/tensorflow/community/blob/592221e839eb9629a9ff4c73d46ee44ccb832d97/rfcs/20190816-tf-project-versioning.md). + ### Definitions @@ -296,7 +299,12 @@ This package will be a subset of the current "tensorflow" pip package. It will i ### Required tensorflow addons -These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full Python code of TF, except for top level API wiring. As like any addons, these are only allowed to use public APIs exposed by their dependencies. +These packages are planned to contain high level TF functionality that can be safely split up from TF. Examples for these are tensorboard, estimator and keras. Together with the base TF package, these packages will contain the full Python code of TF, except for top level API wiring. As like any addons, these are only allowed to use public APIs exposed by their dependencies. These packages have two constraints + +1. They are only allowed to use public APIs exposed by their dependencies. +1. They are required to provide backwards compatible public APIs. + +With the backwards compatible public APIs, we expect addons to be able to release independently as long as features they depend on are released in their dependencies. These packages will have full control over the versions of their dependencies. We recommend they only set a minimum version for their dependencies. When they need new features, they will bump their minimum requirement to include the new API changes. @@ -353,7 +361,7 @@ These shared objects will be automatically loaded by TF core if: * **Why do we not use C++ APIs instead of C**: Compilers have no guarantees for ABIs generated for C++ code. Any C++ API used will require each shared object to be compiled with the same compiler, using the same version of the compiler, with the same compiler flags ([See github issue 23561](https://github.com/tensorflow/tensorflow/issues/23561)). * **Why do not we statically link everything**: Single shared object for everything: Anywhere except google does not have access to the massively parallel build system we use here at google. This causes prohibitive build times, causing major developer pain for open source developers. There are many more issues, but the summary is while this is a great solution for google, outside google this is simply infeasible. * **TF will become a suite of multiple packages, built by multiple authorities. What if the bugs get blamed on TF team**: With the modular model, we expect testing of 3rd party code to become easier. This can also be mitigated if the error messages are better, and if they can clearly point out which module the issue stems from. Finally, we can create an apple-swift like testing model, where we run a Jenkins setup that people can donate their machines to, and we can run continuous integration tests on their plugins. -* **Why not have APIs but still have a monolithic repository: **When everything is in a single repository, this enables developers to bypass the APIs, and depend on internals. Moreover, we cannot grant full control over different folders on our repository to our partners in a single repository. As long as they are in a single repository, they are still constrained by our build system and license. Finally, in a single repository we do not provide the option of closed source plugins for contributors. +* **Why not have APIs but still have a monolithic repository** When everything is in a single repository, this enables developers to bypass the APIs, and depend on internals. Moreover, we cannot grant full control over different folders on our repository to our partners in a single repository. As long as they are in a single repository, they are still constrained by our build system and license. Finally, in a single repository we do not provide the option of closed source plugins for contributors. * **Why not go with the OSS federation solutions?** OSS federation requires all dependencies to be in the federation before adding a repository. This is simply not possible for tensorflow, as eigen, llvm and many other dependencies will never be a part of the federation. * **Documentation, how/where do we document everything?** With multiple repositories, structure of the documentation will need to be rethought, based on what is a part of "TensorFlow proper" and what is an optional feature. @@ -375,7 +383,7 @@ We propose the following principles to be followed for testing in a modular worl In the current setup, we need to test all of the above packages for different Python versions, operating systems, accelerators (CPU, GPU), compilers, and more variants combined. In the modularized world, each of these packages only need to be unit tested for the following: -* tensorflow-base: Operating systems, compiler versions and python versions only with CPU +* tensorflow-base: Operating systems, compiler versions and python versions only with CPU * tf-gpu: With GPU only, for different operating systems. * tf-estimator: Only for different python versions From 1d07d97512b939e9f07830e3d86c769810a690f3 Mon Sep 17 00:00:00 2001 From: Gunhan Gulsoy Date: Mon, 25 Nov 2019 15:46:36 -0800 Subject: [PATCH 7/7] Update last updated time. --- rfcs/20190305-modular-tensorflow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/20190305-modular-tensorflow.md b/rfcs/20190305-modular-tensorflow.md index f7b0c3bab..afe645f91 100644 --- a/rfcs/20190305-modular-tensorflow.md +++ b/rfcs/20190305-modular-tensorflow.md @@ -4,7 +4,7 @@ :-------------- |:---------------------------------------------------- | | **Author(s)** | Gunhan Gulsoy (gunan@google.com) | | **Sponsor** | Martin Wicke (wicke@google.com) | -| **Updated** | 2019-03-06 | +| **Updated** | 2019-11-25 | ## Motivation