diff --git a/.gitignore b/.gitignore
index be75938ec401b1d72fa54773c85191aaac7d7f35..828bbe9bd3363853ae3f58f54a8d5f60cefad837 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@ Podfile.lock
/tensorflow/contrib/lite/examples/ios/simple/data/*.txt
/tensorflow/contrib/lite/examples/ios/simple/data/*.tflite
xcuserdata/**
+/api_init_files_list.txt
# Android
.gradle
diff --git a/CODEOWNERS b/CODEOWNERS
index 007a304c3e706ce968576ec8979c08f1a3bcc552..b9f0313cc6d59d3fbdcd014e1a528126d863075a 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -45,7 +45,7 @@
# /tensorflow/contrib/session_bundle/ @nfiedel @sukritiramesh
# /tensorflow/contrib/slim/ @sguada @thenbasilmanran
# /tensorflow/contrib/stateless/ @girving
-# /tensorflow/contrib/tensor_forest/ @gilberthendry @thomascolthurst
+# /tensorflow/contrib/tensor_forest/ @gilberthendry @thomascolthurst @yupbank
# /tensorflow/contrib/testing/ @dandelionmane
# /tensorflow/contrib/timeseries/ @allenlavoie
# /tensorflow/contrib/tpu/ @frankchn @saeta @jhseu
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3dad41a88c8212b7445c32f241d887306d3c19ad..db4b1581ae671b1e676e215c9a80dfaab832fa21 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,16 @@
# Contributing guidelines
+## Pull Request Checklist
+
+Before sending your pull requests, make sure you followed this list.
+
+- Read [contributing guidelines](CONTRIBUTING.md).
+- Read [Code of Conduct](CODE_OF_CONDUCT.md).
+- Ensure you have signed the [Contributor License Agreement (CLA)](https://cla.developers.google.com/).
+- Check if my changes are consistent with the [guidelines](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#general-guidelines-and-philosophy-for-contribution).
+- Changes are consistent with the [Coding Style](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#c-coding-style).
+- Run [Unit Tests](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#running-unit-tests).
+
## How to become a contributor and submit your own code
### Contributor License Agreements
@@ -79,7 +90,7 @@ Bazel BUILD files also need to include a license section, e.g.,
Changes to TensorFlow C++ code should conform to
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
-Use `clang-tidy` to check your C/C++ changes. To install clang-tidy on ubuntu:16.04, do:
+Use `clang-tidy` to check your C/C++ changes. To install `clang-tidy` on ubuntu:16.04, do:
```bash
apt-get install -y clang-tidy
diff --git a/README.md b/README.md
index ef5bdc66ef03131318e1dde627e0224cca9137fd..63853137cfd30b396f8c7d204811f3e4a1794c07 100644
--- a/README.md
+++ b/README.md
@@ -5,16 +5,16 @@
-----------------
-| **`Documentation`** | **`Linux CPU`** | **`Linux GPU`** | **`Mac OS CPU`** | **`Windows CPU`** | **`Android`** |
-|-----------------|---------------------|------------------|-------------------|---------------|---------------|
-| [](https://www.tensorflow.org/api_docs/) | [](https://ci.tensorflow.org/job/tensorflow-master-cpu) | [](https://ci.tensorflow.org/job/tensorflow-master-linux-gpu) | [](https://ci.tensorflow.org/job/tensorflow-master-mac) | [](https://ci.tensorflow.org/job/tensorflow-master-win-cmake-py) | [](https://ci.tensorflow.org/job/tensorflow-master-android) [  ](https://bintray.com/google/tensorflow/tensorflow/_latestVersion)
+| **`Documentation`** |
+|-----------------|
+| [](https://www.tensorflow.org/api_docs/) |
**TensorFlow** is an open source software library for numerical computation using
data flow graphs. The graph nodes represent mathematical operations, while
the graph edges represent the multidimensional data arrays (tensors) that flow
-between them. This flexible architecture lets you deploy computation to one
+between them. This flexible architecture enables you to deploy computation to one
or more CPUs or GPUs in a desktop, server, or mobile device without rewriting
-code. TensorFlow also includes TensorBoard, a data visualization toolkit.
+code. TensorFlow also includes [TensorBoard](https://www.tensorflow.org/programmers_guide/summaries_and_tensorboard), a data visualization toolkit.
TensorFlow was originally developed by researchers and engineers
working on the Google Brain team within Google's Machine Intelligence Research
@@ -22,6 +22,10 @@ organization for the purposes of conducting machine learning and deep neural
networks research. The system is general enough to be applicable in a wide
variety of other domains, as well.
+Keep up to date with release announcements and security updates by
+subscribing to
+[announce@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/announce).
+
## Installation
*See [Installing TensorFlow](https://www.tensorflow.org/get_started/os_setup.html) for instructions on how to install our release binaries or how to build from source.*
@@ -36,15 +40,6 @@ environment to install the nightly TensorFlow build. We support CPU and GPU
packages on Linux, Mac, and Windows.
-**Individual whl files**
-* Linux CPU-only: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/)) / [Python 3.4](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/)) / [Python 3.5](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=cpu-slave/)) / [Python 3.6](http://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp36-cp36m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=cpu-slave/))
-* Linux GPU: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/42/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/)) / [Python 3.6](http://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp36-cp36m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=gpu-linux/))
-* Mac CPU-only: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/)) / [Python 3](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/))
-* Windows CPU-only: [Python 3.5 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=35/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly-1.head-cp35-cp35m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=35/)) / [Python 3.6 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=36/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly-1.head-cp36-cp36m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=36/))
-* Windows GPU: [Python 3.5 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=35/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly_gpu-1.head-cp35-cp35m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=35/)) / [Python 3.6 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=36/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly_gpu-1.head-cp36-cp36m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=36/))
-* Android: [demo APK](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/tensorflow_demo.apk), [native libs](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/native/)
-([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-android/))
-
#### *Try your first TensorFlow program*
```shell
$ python
@@ -61,6 +56,7 @@ $ python
42
>>> sess.close()
```
+Learn more examples about how to do specific tasks in TensorFlow at the [tutorials page of tensorflow.org](https://www.tensorflow.org/tutorials/).
## Contribution guidelines
@@ -78,10 +74,35 @@ The TensorFlow project strives to abide by generally accepted best practices in
[](https://bestpractices.coreinfrastructure.org/projects/1486)
+
+## Continuous build status
+
+### Official Builds
+
+| Build Type | Status | Artifacts |
+| --- | --- | --- |
+| **Linux CPU** |  | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Linux GPU** |  | [pypi](https://pypi.org/project/tf-nightly-gpu/) |
+| **Linux XLA** | TBA | TBA |
+| **MacOS** |  | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Windows CPU** | [](https://ci.tensorflow.org/job/tensorflow-master-win-cmake-py) | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Windows GPU** | [](http://ci.tensorflow.org/job/tf-master-win-gpu-cmake/) | [pypi](https://pypi.org/project/tf-nightly-gpu/) |
+| **Android** | [](https://ci.tensorflow.org/job/tensorflow-master-android) | [](https://bintray.com/google/tensorflow/tensorflow/_latestVersion) [demo APK](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/tensorflow_demo.apk), [native libs](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/native/) [build history](https://ci.tensorflow.org/view/Nightly/job/nightly-android/) |
+
+
+### Community Supported Builds
+
+| Build Type | Status | Artifacts |
+| --- | --- | --- |
+| **IBM s390x** | [](http://ibmz-ci.osuosl.org/job/TensorFlow_IBMZ_CI/) | TBA |
+| **IBM ppc64le CPU** | [](http://powerci.osuosl.org/job/TensorFlow_Ubuntu_16.04_CPU/) | TBA |
+
+
## For more information
* [TensorFlow Website](https://www.tensorflow.org)
* [TensorFlow White Papers](https://www.tensorflow.org/about/bib)
+* [TensorFlow YouTube Channel](https://www.youtube.com/channel/UC0rqucBdTuFTjJiefW5t-IQ)
* [TensorFlow Model Zoo](https://github.com/tensorflow/models)
* [TensorFlow MOOC on Udacity](https://www.udacity.com/course/deep-learning--ud730)
* [TensorFlow Course at Stanford](https://web.stanford.edu/class/cs20si)
diff --git a/RELEASE.md b/RELEASE.md
index 6f54dee58f75c29a16545ba25de12fe059baf1eb..e09e9c6190f57adec67c2ae1d85848dabfd9c2a7 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,3 +1,192 @@
+# Release 1.9.0
+
+## Major Features And Improvements
+* Update tf.keras to the Keras 2.1.6 API.
+* `tfe.Network` is deprecated. Please inherit from `tf.keras.Model`.
+* Adding support of core feature columns and losses to gradient boosted trees estimators.
+* The distributions.Bijector API supports broadcasting for Bijectors with new API changes. See [here](https://www.tensorflow.org/versions/r1.9/api_docs/python/tf/distributions/bijectors/Bijector) for more details.
+* Layered variable names have changed in the following conditions:
+ * Using `tf.keras.layers` with custom variable scopes.
+ * Using `tf.layers` in a subclassed `tf.keras.Model` class. See [here](https://www.tensorflow.org/versions/r1.9/api_docs/python/tf/layers) for more details
+
+## Breaking Chances
+ * If you're opening empty variable scopes; replace `variable_scope`('', ...) by `variable_scope`(`tf.get_variable_scope()`, ...).
+
+## Bug Fixes and Other Changes
+* `tf.data`:
+ * The `DatasetBase::DebugString()` method is now `const`.
+ * Added the `tf.contrib.data.sample_from_datasets()` API for randomly sampling from multiple datasets.
+* Eager Execution:
+* `tf.keras`:
+ * Move Keras code out of _impl folder and remove API files.
+ * `tf.keras.Model.save_weights` now saves in TensorFlow format by default.
+ * Enable dataset iterators to be passed to `tf.keras.Model` training/eval methods.
+* Accelerated Linear Algebra (XLA):
+* TensorFlow Debugger (tfdbg): fix an issue in which the TensorBoard Debugger Plugin could not handle total source file size exceeding gRPC message size limit (4 MB).
+* `tf.contrib`:
+ * Add `tf.contrib.data.choose_from_datasets()`.
+ * `tf.contrib.data.make_csv_dataset()` now supports line breaks in quoted strings. Two arguments were removed from `make_csv_dataset`.
+ * `tf.contrib.framework.zero_initializer` supports ResourceVariable.
+ * Adding "constrained_optimization" to tensorflow/contrib.
+* Other:
+ * Add GCS Configuration Ops.
+ * Changing signature of `MakeIterator` to enable propagating error status.
+ * KL divergence for two Dirichlet distributions.
+ * More consistent GcsFileSystem behavior for certain reads past EOF.
+ * Update benchmark for tf.scan to match ranges across eager and graph modes.
+ * Fixed bug in `tf.reduce_prod gradient` for complex dtypes.
+ * Add optional `args` argument to `Dataset.from_generator()`.
+ * Allow the use of '.' in variables (e.g. "hparams.parse('a.b=1.0')"), which would previously raise an error. This will correspond to an attribute name with an embedded '.' symbol (e.g. 'a.b'), which can only be accessed indirectly (e.g. through getattr and setattr). To set this up the user will first need to explicitly add the variable to the hparam object (e.g. "hparams.add_hparam(name='a.b', value=0.0)").
+ * Benchmark for tf.scan in graph and eager modes.
+ * Added complex128 support to FFT, FFT2D, FFT3D, IFFT, IFFT2D, and IFFT3D.
+ * Making ids unique in `nn.embedding_lookup_sparse`. This helps to reduce RPC calls for looking up the embeddings when there are repeated ids in the batch.
+ * Support indicator column in boosted trees.
+ * Prevent `tf.gradients()` from backpropagating through integer tensors.
+ * LinearOperator[1D,2D,3D]Circulant added to `tensorflow.linalg`.
+ * Conv3D, Conv3DBackpropInput, Conv3DBackpropFilter now supports arbitrary.
+ * Added `tf.train.Checkpoint` for reading/writing object-based checkpoints.
+ * `Dataset.list_files()` now produces determinstic results when `shuffle=False` or a `seed` is passed.
+ * Added LinearOperatorKronecker, a dense-free implementation of the Kronecker Product.
+ * Allow LinearOperator to broadcast.
+ * SavedModelBuilder will now deduplicate asset names that point to files with the same basename and the same contents. Note that this may result in new asset files included in SavedModels in cases where assets with the same name but different contents were previously overwriting each other.
+
+
+## Thanks to our Contributors
+
+This release contains contributions from many people at Google, as well as:
+
+Abdullah Alrasheed, Achal Shah, Ad-530, ADiegoCAlonso, Aditya Yogi, Ag Ramesh, akindyakov, Andy Kernahan, Anya Petrova, Aurelien Geron, Ben, Ben Barsdell, Bhavani-Subramanian, braincodercn, Brett Koonce, Brian Nemsick, Brian Zier, Bryan Heden, candy.dc, cclauss, Clayne Robison, ctiijima, Dalmo Cirne, David Norman, David T.H. Kao, DosLin, ekelsen, Elson Rodriguez, Erik Smistad, Felix Abecassis, Fergal Cotter, fo40225, foo0x29a, Freedom" Koan-Sin Tan, FréDéRic Branchaud-Charron, gdh1995, Geoffrey Irving, Giuseppe, gracehoney, Guido Zuidhof, Guillaume Klein, Guozhong Zhuang, Haggai, Harald Husum, imsheridan, Ivan Zhang, Jan Zikes, Jayaram Bobba, Jesse Benson, Jesse Gumz, Jiajia Li, Jie, jinghuangintel, Jingwen, jjsjann123, Joe Yearsley, Joel Hestness, Joel Shor, josephyearsley, Junpeng Lao, Karol M. Langner, Kb Sriram, krantideep95, Krish Ravindranath, Letian Feng, Loo Rong Jie, Lukas Geiger, Maciej, Mahmoud Abuzaina, ManHyuk, Mark Ryan, mbhuiyan, Michal Turek, Mostafa Alaa, Myungsung Kwak, Nand Dalal, Nehal J Wani, Neil Tenenholtz, ngc92, Nicholas Nadeau, P.Eng., Avs, Niranjan Hasabnis, P-Hidringer, Paul Van Eck, Peng Yu, Qing Zhao, Qingying Chen, Quanlong, Rajendra Arora, Rholais Lii, rmanyari, Robin Richtsfeld, Russell Klopfer, Sagi, Sam Sendelbach, Sandeep N Gupta, Sandip Giri, Sarah Edkins, Scott Tseng, Sdalbsoo, Sergii Khomenko, Seungwoo Choi (Biggie), Seyed Majid Azimi, Shaoning Zeng, shengfuintel, Siu Kei, Muk, Smit Shilu, soonson, Stefan Schweter, Sukhwan Kim, Sunitha Kambhampati, Taehoon Lee, tamimaddari82, Tang, Wenyi, Ted Chang, u2takey, Utkarsh Upadhyay, Vadim Markovtsev, voegtlel, Wai Hon Law, wangsiyu, Wenhao Hu, wenhao.hu, William D. Irons, Yan Facai (颜发才), Yanbo Liang, Yihong Wang, Yilei (Dolee) Yang, Yong Tang, Yuan (Terry) Tang
+
+# Release 1.8.0
+
+## Major Features And Improvements
+* Can now pass `tf.contrib.distribute.MirroredStrategy()` to `tf.estimator.RunConfig()` to run an Estimator model on multiple GPUs on one machine.
+* Add `tf.contrib.data.prefetch_to_device()`, which supports prefetching to GPU memory.
+* Added Gradient Boosted Trees as pre-made Estimators: BoostedTreesClassifier, BoostedTreesRegressor.
+* Add 3rd generation pipeline config for Cloud TPUs which improves performance and usability.
+* `tf.contrib.bayesflow` is moving out to it's own repo.
+* Added `tf.contrib.{proto,rpc}` to allow generic proto parsing and RPC communication[1](#rpc-issue).
+
+## Bug Fixes and Other Changes
+* `tf.data`:
+ * Add `tf.contrib.data.prefetch_to_device`, which enables prefetching dataset elements to GPU memory.
+ * Add `tf.contrib.data.AUTOTUNE`, which allows the tf.data runtime to automatically tune the prefetch buffer sizes based on your system and environment.
+ * Add `tf.contrib.data.make_csv_dataset` for building datasets of CSV files.
+* Eager Execution:
+ * With eager execution Datasets can now be used as standard python iterators (`for batch in dataset:`). Both `Dataset.__iter__()` and `Dataset.make_one_shot_iterator()` can now be used to create iterators when eager execution is enabled.
+ * Automatic device placement has been enabled (i.e., use a GPU if available automatically, without requiring an explicit `with tf.device(“/gpu:0”)`) (Fixes #14133)
+ * `tf.GradientTape` has moved out of contrib.
+* `tf.keras`:
+ * Added the fashion mnist dataset.
+ * New data preprocessing functions: `image/random_brightness`, `sequence/TimeseriesGenerator`, and `text/hashing_trick`.
+* Accelerated Linear Algebra (XLA):
+ * Select and scatter in reference util and evaluator now use lexicographical order to break ties.
+* TensorFlow Debugger (tfdbg) CLI:
+ * During tensor-filter operations, allow exclusion of nodes by regular expressions.
+ * Fix spurious background colors in some text terminals.
+* `tf.contrib`:
+ * Add meta-distribution BatchReshape which reshapes batch dimensions.
+ * `tf.contrib.layers.recompute_grad` works for explicit gradient checkpointing on TPU.
+ * Add `tf.contrib.framework.argsort`.
+ * Allow `DNNBoostedTreeCombinedEstimator` to work with core versions of feature columns and losses.
+ * Add non-linear image warping ops: `tf.contrib.image.sparse_image_warp`, `tf.contrib.image.dense_image_warp`, and `tf.contrib.image.interpolate_spline`.
+ * Fix bug in `tf.contrib.opt.MultitaskOptimizerWrapper` where types of tensors were mismatched.
+* Other:
+ * Low-level graph construction now calls the TensorFlow C API. This change should be invisible to most users, but can be disabled by setting the environment variable `TF_C_API_GRAPH_CONSTRUCTION=0` in this release. Future releases will remove the ability to disable this change. Please [file a bug](https://github.com/tensorflow/tensorflow/issues/new) if you find yourself using this escape hatch.
+ * Add description of shapes and a pointer to tutorial notebook in `tf.distributions.Distribution`.
+ * Update scatter operations:
+ * Add `tf.scatter_min` and `tf.scatter_max`
+ * Extend scatter operations to work with a scalar update parameter.
+ * Move cuDNN RNN ops to core for use in TensorFlow codebase only.
+ * Add `float64` support for `Conv2d`, `Conv2dBackpropInput`, and `Conv2dBackpropFilter`.
+ * Add `float64` support for `AvgPool`/`AvgPoolGrad`.
+ * Make graph name scope thread local so that they work correctly in multi-threaded environments.
+ * Update nsync synchronization library to avoid slow primitives on Linux.
+ * Removed need to put nsync/public on C include path when building custom ops.
+ * Add `tf.image.psnr`, `tf.image.ssim`, `tf.image.ssim_multiscale`, `tf.image.image_gradients`, `tf.image.sobel_edges`.
+ * Add links to https://js.tensorflow.org.
+ * Fix non-uniformity of orthogonal matrices.
+ * Fix bug where multi-image Estimator eval summaries were not displayed correctly.
+
+1 The cancellation logic of the RPC op contains a concurrency error. A fix has been submitted to master and will be part of the next release.
+
+## Thanks to our Contributors
+
+This release contains contributions from many people at Google, as well as:
+
+4d55397500, Aghasy, Alan Du, Alan Lee, Alan Yee, Alex Wiltschko, Animesh Karnewar, Ankit Gupta, Anton Matosov, Aris L, Ben Barsdell, Brent Yi, Brett Koonce, Carl Thomé, cbockman, Chikanaga Tomoyuki, Chris Tava, CéDric Deltheil, Dahan Gong, Dalmo Cirne, Daniel Erenrich, David Norman, DavidNorman, Edd Wilder-James, Fanjin Zeng, Felix Abecassis, fo40225, George Sterpu, Giovanni Terlingen, Gor Baghdasaryan, Guillaume Klein, Hanchen Li, Ilya Polenov, Jakub Kolodziejczyk, Jason Sadler, Jayaram Bobba, Jerry Liu, jinghuangintel, Jiongyan Zhang (张炯衍), Joel Shor, Jong Wook Kim, Julian Eisenschlos, Karl Lessard, Krish Ravindranath, Loo Rong Jie, Lukas Geiger, Luke Iwanski, Mahmoud Abuzaina, ManHyuk, Marvin Richter, Maximilian Mitchell, Mohammad Ashraf Bhuiyan, msofka, Mustafa Kasap, Nathan Burnham, Nathan Luehr, Naveen Marri, ngc92, nio1814, Oleg Zabluda, Ou Changkun, Panos Ipeirotis, Paul Van Eck, Peter Lee, Piotr Czapla, qjivy, Rholais Lii, Rodrigo Formigone, Russell Klopfer, ryantimjohn, Sang Han, SebastiáN RamíRez, shengfuintel, Siby Jose Plathottam, Silver Chan, Stanislaw Antol, Taehoon Lee, Tarang Chugh, Ted Chang, Thomas Bastiani, Xian Xu, Xiaoming (Jason) Cui, Yan Facai (颜发才), yaox12, Yashal Shakti Kanungo, Yong Tang, Yuan (Terry) Tang, Yuxin Wu, Ziyue(Louis) Lu
+
+# Release 1.7.0
+
+## Major Features And Improvements
+* Eager mode is moving out of contrib, try `tf.enable_eager_execution()`.
+* Graph rewrites emulating fixed-point quantization compatible with TensorFlow Lite, supported by new `tf.contrib.quantize` package.
+* Easily customize gradient computation with `tf.custom_gradient`.
+* [TensorBoard Debugger Plugin](https://github.com/tensorflow/tensorboard/blob/master/tensorboard/plugins/debugger/README.md), the graphical user interface (GUI) of TensorFlow Debugger (tfdbg), is now in alpha.
+* Experimental support for reading a sqlite database as a `Dataset` with new `tf.contrib.data.SqlDataset`.
+* Distributed Mutex / CriticalSection added to `tf.contrib.framework.CriticalSection`.
+* Better text processing with `tf.regex_replace`.
+* Easy, efficient sequence input with `tf.contrib.data.bucket_by_sequence_length`
+* Initial support for `tf.contrib.tensorrt` that enables native TensorRT in
+ TensorFlow.
+
+## Bug Fixes and Other Changes
+* Accelerated Linear Algebra (XLA):
+ * Add `MaxPoolGradGrad` support for XLA
+ * CSE pass from Tensorflow is now disabled in XLA.
+* `tf.data`:
+ * `tf.data.Dataset`
+ * Add support for building C++ Dataset op kernels as external libraries, using the `tf.load_op_library()` mechanism.
+ * `Dataset.list_files()` now shuffles its output by default.
+ * `Dataset.shuffle(..., seed=tf.constant(0, dtype=tf.int64))` now yields the same sequence of elements as `Dataset.shuffle(..., seed=0)`.
+ * Add `num_parallel_reads` argument to `tf.data.TFRecordDataset`.
+* `tf.contrib`:
+ * `tf.contrib.bayesflow.halton_sequence` now supports randomization.
+ * Add support for scalars in `tf.contrib.all_reduce`.
+ * Add `effective_sample_size` to `tf.contrib.bayesflow.mcmc_diagnostics`.
+ * Add `potential_scale_reduction` to `tf.contrib.bayesflow.mcmc_diagnostics`.
+ * Add `BatchNormalization`, `Kumaraswamy` bijectors.
+ * Deprecate `tf.contrib.learn`. Please check contrib/learn/README.md for instructions on how to convert existing code.
+ * `tf.contrib.data`
+ * Remove deprecated `tf.contrib.data.Dataset`, `tf.contrib.data.Iterator`, `tf.contrib.data.FixedLengthRecordDataset`, `tf.contrib.data.TextLineDataset`, and `tf.contrib.data.TFRecordDataset` classes.
+ * Added `bucket_by_sequence_length`, `sliding_window_batch`, and `make_batched_features_dataset`
+ * Remove unmaintained `tf.contrib.ndlstm`. You can find it externally at https://github.com/tmbarchive/tfndlstm.
+ * Moved most of `tf.contrib.bayesflow` to its own repo: `tfp`
+* Other:
+ * tf.py_func now reports the full stack trace if an exception occurs.
+ * Integrate `TPUClusterResolver` with GKE's integration for Cloud TPUs.
+ * Add a library for statistical testing of samplers.
+ * Add Helpers to stream data from the GCE VM to a Cloud TPU.
+ * Integrate ClusterResolvers with TPUEstimator.
+ * Unify metropolis_hastings interface with HMC kernel.
+ * Move LIBXSMM convolutions to a separate --define flag so that they are disabled by default.
+ * Fix `MomentumOptimizer` lambda.
+ * Reduce `tfp.layers` boilerplate via programmable docstrings.
+ * Add `auc_with_confidence_intervals`, a method for computing the AUC and confidence interval with linearithmic time complexity.
+ * `regression_head` now accepts customized link function, to satisfy the usage that user can define their own link function if the `array_ops.identity` does not meet the requirement.
+ * Fix `initialized_value` and `initial_value` behaviors for `ResourceVariables` created from `VariableDef` protos.
+ * Add TensorSpec to represent the specification of Tensors.
+ * Constant folding pass is now deterministic.
+ * Support `float16` `dtype` in `tf.linalg.*`.
+ * Add `tf.estimator.export.TensorServingInputReceiver` that allows `tf.estimator.Estimator.export_savedmodel` to pass raw tensors to model functions.
+
+## Deprecations
+
+* TensorFlow 1.7 may be the last time we support Cuda versions below 8.0.
+ Starting with TensorFlow 1.8 release, 8.0 will be the minimum supported
+ version.
+* TensorFlow 1.7 may be the last time we support cuDNN versions below 6.0.
+ Starting with TensorFlow 1.8 release, 6.0 will be the minimum supported
+ version.
+
+## Thanks to our Contributors
+
+This release contains contributions from many people at Google, as well as:
+
+4d55397500, Abe, Alistair Low, Andy Kernahan, Appledore, Ben, Ben Barsdell, Boris Pfahringer, Brad Wannow, Brett Koonce, Carl Thomé, cclauss, Chengzhi Chen, Chris Drake, Christopher Yeh, Clayne Robison, Codrut Grosu, Daniel Trebbien, Danny Goodman, David Goodwin, David Norman, Deron Eriksson, Donggeon Lim, Donny Viszneki, DosLin, DylanDmitri, Francisco Guerrero, Fred Reiss, gdh1995, Giuseppe, Glenn Weidner, gracehoney, Guozhong Zhuang, Haichen "Hc" Li, Harald Husum, harumitsu.nobuta, Henry Spivey, hsm207, Jekyll Song, Jerome, Jiongyan Zhang, jjsjann123, John Sungjin Park, Johnson145, JoshVarty, Julian Wolff, Jun Wang, June-One, Kamil Sindi, Kb Sriram, Kdavis-Mozilla, Kenji, lazypanda1, Liang-Chi Hsieh, Loo Rong Jie, Mahesh Bhosale, MandarJKulkarni, ManHyuk, Marcus Ong, Marshal Hayes, Martin Pool, matthieudelaro, mdfaijul, mholzel, Michael Zhou, Ming Li, Minmin Sun, Myungjoo Ham, MyungsungKwak, Naman Kamra, Peng Yu, Penghao Cen, Phil, Raghuraman-K, resec, Rohin Mohanadas, Sandeep N Gupta, Scott Tseng, seaotterman, Seo Sanghyeon, Sergei Lebedev, Ted Chang, terrytangyuan, Tim H, tkunic, Tod, vihanjain, Yan Facai (颜发才), Yin Li, Yong Tang, Yukun Chen, Yusuke Yamada
+
+
+
# Release 1.6.0
## Breaking Changes
@@ -106,7 +295,7 @@ Yoni Tsafir, yordun, Yuan (Terry) Tang, Yuxin Wu, zhengdi, Zhengsheng Wei, 田
* Add `complex64` support to XLA compiler.
* `bfloat` support is now added to XLA infrastructure.
* Make `ClusterSpec` propagation work with XLA devices.
- * Use a determinisitic executor to generate XLA graph.
+ * Use a deterministic executor to generate XLA graph.
* `tf.contrib`:
* `tf.contrib.distributions`:
* Add `tf.contrib.distributions.Autoregressive`.
@@ -274,14 +463,6 @@ answered questions, and were part of inspiring discussions.
# Release 1.4.0
-## Major Features And Improvements
-* `tf.keras` is now part of the core TensorFlow API.
-* [`tf.data`](http://tensorflow.org/programmers_guide/datasets) is now part of
- the core TensorFlow API.
- * The API is now subject to backwards compatibility guarantees.
-
-# Release 1.4.0
-
## Major Features And Improvements
* `tf.keras` is now part of the core TensorFlow API.
* [`tf.data`](http://tensorflow.org/programmers_guide/datasets) is now part of
diff --git a/tensorflow/SECURITY.md b/SECURITY.md
similarity index 91%
rename from tensorflow/SECURITY.md
rename to SECURITY.md
index fea24b273920885ba8a1ae96aafbf7710df46e1f..e2f6ff353a3c04a6ec6b8ccbaeb75db59fa22d54 100644
--- a/tensorflow/SECURITY.md
+++ b/SECURITY.md
@@ -6,7 +6,7 @@ report vulnerabilities in TensorFlow.
## TensorFlow models are programs
-TensorFlow's runtime system interprets and executes programs. What machine
+TensorFlow's runtime system interprets and executes programs. What machine
learning practitioners term
[**models**](https://developers.google.com/machine-learning/glossary/#model) are
expressed as programs that TensorFlow executes. TensorFlow programs are encoded
@@ -28,12 +28,12 @@ data you supply to TensorFlow to train a model, or to use a model to run
inference on the data.
**TensorFlow models are programs, and need to be treated as such from a security
-perspective.**
+perspective.**
## Running untrusted models
As a general rule: **Always** execute untrusted models inside a sandbox (e.g.,
-[nsjail](https://github.com/google/nsjail)).
+[nsjail](https://github.com/google/nsjail)).
There are several ways in which a model could become untrusted. Obviously, if an
untrusted party supplies TensorFlow kernels, arbitrary code may be executed.
@@ -109,11 +109,11 @@ graphs known to the `ModelServer`. This means that an attacker may run
graphs using untrusted inputs as described above, but they would not be able to
execute arbitrary graphs. It is possible to safely expose a `ModelServer`
directly to an untrusted network, **but only if the graphs it is configured to
-use have been carefully audited to be safe**.
+use have been carefully audited to be safe**.
Similar to best practices for other servers, we recommend running any
`ModelServer` with appropriate privileges (i.e., using a separate user with
-reduced permisisons). In the spirit of defense in depth, we recommend
+reduced permissions). In the spirit of defense in depth, we recommend
authenticating requests to any TensorFlow server connected to an untrusted
network, as well as sandboxing the server to minimize the adverse effects of
any breach.
@@ -129,11 +129,11 @@ with specially crafted inputs.
### What is a vulnerability?
Given TensorFlow's flexibility, it is possible to specify computation graphs
-which exhibit unexpected or unwanted behaviors. The fact that TensorFlow models
+which exhibit unexpected or unwanted behavior. The fact that TensorFlow models
can perform arbitrary computations means that they may read and write files,
communicate via the network, produce deadlocks and infinite loops, or run out
of memory. It is only when these behaviors are outside the specifications of the
-operations involved that such behavior is a vulnerability.
+operations involved that such behavior is a vulnerability.
A `FileWriter` writing a file is not unexpected behavior and therefore is not a
vulnerability in TensorFlow. A `MatMul` allowing arbitrary binary code execution
@@ -168,7 +168,18 @@ below).
Please use a descriptive subject line for your report email. After the initial
reply to your report, the security team will endeavor to keep you informed of
-the progress being made towards a fix and announcement.
+the progress being made towards a fix and announcement.
+
+In addition, please include the following information along with your report:
+
+* Your name and affiliation (if any).
+* A description of the technical details of the vulnerabilities. It is very
+ important to let us know how we can reproduce your findings.
+* An explanation who can exploit this vulnerability, and what they gain when
+ doing so -- write an attack scenario. This will help us evaluate your report
+ quickly, especially if the issue is complex.
+* Whether this vulnerability public or known to third parties. If it is, please
+ provide details.
If you believe that an existing (public) issue is security-related, please send
an email to `security@tensorflow.org`. The email should include the issue ID and
@@ -231,9 +242,7 @@ v//Fw6ZeY+HmRDFdirjD7wXtIuER4vqCryIqR6Xe9X8oJXz9L/Jhslc=
-----END PGP PUBLIC KEY BLOCK-----
```
-### Known vulnerabilities
-
-| Type | Versions affected | Reported by | Additional Information |
-|-------------------|:-----------------:|--------------------|-----------------------------|
-| out of bounds read| <=1.4 | TenCent Blade Team | [issue report](https://github.com/tensorflow/tensorflow/issues/14959) |
+### Known Vulnerabilities
+For a list of known vulnerabilities and security advisories for TensorFlow,
+(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/security/index.md)[click here].
diff --git a/WORKSPACE b/WORKSPACE
index 1e38a9a8cd754886fc5232531816b875de0879a3..fd7570a80ae2ee0087f7d2fd771fcce5b9690028 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -2,11 +2,11 @@ workspace(name = "org_tensorflow")
http_archive(
name = "io_bazel_rules_closure",
- sha256 = "6691c58a2cd30a86776dd9bb34898b041e37136f2dc7e24cadaeaf599c95c657",
- strip_prefix = "rules_closure-08039ba8ca59f64248bb3b6ae016460fe9c9914f",
+ sha256 = "a38539c5b5c358548e75b44141b4ab637bba7c4dc02b46b1f62a96d6433f56ae",
+ strip_prefix = "rules_closure-dbb96841cc0a5fb2664c37822803b06dab20c7d1",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz",
- "https://github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz", # 2018-01-16
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/dbb96841cc0a5fb2664c37822803b06dab20c7d1.tar.gz",
+ "https://github.com/bazelbuild/rules_closure/archive/dbb96841cc0a5fb2664c37822803b06dab20c7d1.tar.gz", # 2018-04-13
],
)
@@ -14,28 +14,18 @@ load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
closure_repositories()
+# We must check the bazel version before trying to parse any other BUILD
+# files, in case the parsing of those build files depends on the bazel
+# version we require here.
+load("//tensorflow:version_check.bzl", "check_bazel_version_at_least")
+check_bazel_version_at_least("0.10.0")
+
load("//tensorflow:workspace.bzl", "tf_workspace")
-# Uncomment and update the paths in these entries to build the Android demo.
-#android_sdk_repository(
-# name = "androidsdk",
-# api_level = 23,
-# # Ensure that you have the build_tools_version below installed in the
-# # SDK manager as it updates periodically.
-# build_tools_version = "26.0.1",
-# # Replace with path to Android SDK on your system
-# path = "",
-#)
-#
-#android_ndk_repository(
-# name="androidndk",
-# path="",
-# # This needs to be 14 or higher to compile TensorFlow.
-# # Please specify API level to >= 21 to build for 64-bit
-# # archtectures or the Android NDK will automatically select biggest
-# # API level that it supports without notice.
-# # Note that the NDK version is not the API level.
-# api_level=14)
+load("//third_party/android:android_configure.bzl", "android_configure")
+android_configure(name="local_config_android")
+load("@local_config_android//:android.bzl", "android_workspace")
+android_workspace()
# Please add all new TensorFlow dependencies in workspace.bzl.
tf_workspace()
diff --git a/configure.py b/configure.py
index b5436dba20ad1aadeffe8057c0a85709914f603e..ada342a50ab5104509156d3e44e6435a308255a3 100644
--- a/configure.py
+++ b/configure.py
@@ -35,12 +35,13 @@ except ImportError:
_DEFAULT_CUDA_VERSION = '9.0'
_DEFAULT_CUDNN_VERSION = '7'
+_DEFAULT_NCCL_VERSION = '1.3'
_DEFAULT_CUDA_COMPUTE_CAPABILITIES = '3.5,5.2'
_DEFAULT_CUDA_PATH = '/usr/local/cuda'
_DEFAULT_CUDA_PATH_LINUX = '/opt/cuda'
_DEFAULT_CUDA_PATH_WIN = ('C:/Program Files/NVIDIA GPU Computing '
'Toolkit/CUDA/v%s' % _DEFAULT_CUDA_VERSION)
-_DEFAULT_TENSORRT_PATH_LINUX = '/usr/lib/x86_64-linux-gnu'
+_DEFAULT_TENSORRT_PATH_LINUX = '/usr/lib/%s-linux-gnu' % platform.machine()
_TF_OPENCL_VERSION = '1.2'
_DEFAULT_COMPUTECPP_TOOLKIT_PATH = '/usr/local/computecpp'
_DEFAULT_TRISYCL_INCLUDE_DIR = '/usr/local/triSYCL/include'
@@ -225,8 +226,6 @@ def setup_python(environ_cp):
# Set-up env variables used by python_configure.bzl
write_action_env_to_bazelrc('PYTHON_BIN_PATH', python_bin_path)
write_action_env_to_bazelrc('PYTHON_LIB_PATH', python_lib_path)
- write_to_bazelrc('build --force_python=py%s' % python_major_version)
- write_to_bazelrc('build --host_force_python=py%s' % python_major_version)
write_to_bazelrc('build --python_path=\"%s"' % python_bin_path)
environ_cp['PYTHON_BIN_PATH'] = python_bin_path
@@ -250,7 +249,11 @@ def reset_tf_configure_bazelrc(workspace_path):
if _TF_BAZELRC_FILENAME in l:
continue
f.write('%s\n' % l)
- f.write('import %s\n' % _TF_BAZELRC)
+ if is_windows():
+ tf_bazelrc_path = _TF_BAZELRC.replace("\\", "/")
+ else:
+ tf_bazelrc_path = _TF_BAZELRC
+ f.write('import %s\n' % tf_bazelrc_path)
def cleanup_makefile():
@@ -444,7 +447,7 @@ def check_bazel_version(min_version):
if which('bazel') is None:
print('Cannot find bazel. Please install bazel.')
sys.exit(0)
- curr_version = run_shell(['bazel', '--batch', 'version'])
+ curr_version = run_shell(['bazel', '--batch', '--bazelrc=/dev/null', 'version'])
for line in curr_version.split('\n'):
if 'Build label: ' in line:
@@ -480,6 +483,8 @@ def set_cc_opt_flags(environ_cp):
if is_ppc64le():
# gcc on ppc64le does not support -march, use mcpu instead
default_cc_opt_flags = '-mcpu=native'
+ elif is_windows():
+ default_cc_opt_flags = '/arch:AVX'
else:
default_cc_opt_flags = '-march=native'
question = ('Please specify optimization flags to use during compilation when'
@@ -490,14 +495,9 @@ def set_cc_opt_flags(environ_cp):
for opt in cc_opt_flags.split():
write_to_bazelrc('build:opt --copt=%s' % opt)
# It should be safe on the same build host.
- if not is_ppc64le():
+ if not is_ppc64le() and not is_windows():
write_to_bazelrc('build:opt --host_copt=-march=native')
write_to_bazelrc('build:opt --define with_default_optimizations=true')
- # TODO(mikecase): Remove these default defines once we are able to get
- # TF Lite targets building without them.
- write_to_bazelrc('build --copt=-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK')
- write_to_bazelrc('build --host_copt=-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK')
-
def set_tf_cuda_clang(environ_cp):
"""set TF_CUDA_CLANG action_env.
@@ -520,7 +520,7 @@ def set_tf_cuda_clang(environ_cp):
def set_tf_download_clang(environ_cp):
"""Set TF_DOWNLOAD_CLANG action_env."""
- question = 'Do you want to download a fresh release of clang? (Experimental)'
+ question = 'Do you wish to download a fresh release of clang? (Experimental)'
yes_reply = 'Clang will be downloaded and used to compile tensorflow.'
no_reply = 'Clang will not be downloaded.'
set_action_env_var(
@@ -670,8 +670,9 @@ def create_android_ndk_rule(environ_cp):
error_msg=('The path %s or its child file "source.properties" '
'does not exist.')
)
-
- write_android_ndk_workspace_rule(android_ndk_home_path)
+ write_action_env_to_bazelrc('ANDROID_NDK_HOME', android_ndk_home_path)
+ write_action_env_to_bazelrc('ANDROID_NDK_API_LEVEL',
+ check_ndk_level(android_ndk_home_path))
def create_android_sdk_rule(environ_cp):
@@ -733,41 +734,12 @@ def create_android_sdk_rule(environ_cp):
error_msg=('The selected SDK does not have build-tools version %s '
'available.'))
- write_android_sdk_workspace_rule(android_sdk_home_path,
- android_build_tools_version,
- android_api_level)
-
-
-def write_android_sdk_workspace_rule(android_sdk_home_path,
- android_build_tools_version,
- android_api_level):
- print('Writing android_sdk_workspace rule.\n')
- with open(_TF_WORKSPACE, 'a') as f:
- f.write("""
-android_sdk_repository(
- name="androidsdk",
- api_level=%s,
- path="%s",
- build_tools_version="%s")\n
-""" % (android_api_level, android_sdk_home_path, android_build_tools_version))
-
-
-def write_android_ndk_workspace_rule(android_ndk_home_path):
- print('Writing android_ndk_workspace rule.')
- ndk_api_level = check_ndk_level(android_ndk_home_path)
- if int(ndk_api_level) not in _SUPPORTED_ANDROID_NDK_VERSIONS:
- print('WARNING: The API level of the NDK in %s is %s, which is not '
- 'supported by Bazel (officially supported versions: %s). Please use '
- 'another version. Compiling Android targets may result in confusing '
- 'errors.\n' % (android_ndk_home_path, ndk_api_level,
- _SUPPORTED_ANDROID_NDK_VERSIONS))
- with open(_TF_WORKSPACE, 'a') as f:
- f.write("""
-android_ndk_repository(
- name="androidndk",
- path="%s",
- api_level=%s)\n
-""" % (android_ndk_home_path, ndk_api_level))
+ write_action_env_to_bazelrc('ANDROID_BUILD_TOOLS_VERSION',
+ android_build_tools_version)
+ write_action_env_to_bazelrc('ANDROID_SDK_API_LEVEL',
+ android_api_level)
+ write_action_env_to_bazelrc('ANDROID_SDK_HOME',
+ android_sdk_home_path)
def check_ndk_level(android_ndk_home_path):
@@ -780,18 +752,16 @@ def check_ndk_level(android_ndk_home_path):
revision = re.search(r'Pkg.Revision = (\d+)', filedata)
if revision:
- return revision.group(1)
- return None
-
-
-def workspace_has_any_android_rule():
- """Check the WORKSPACE for existing android_*_repository rules."""
- with open(_TF_WORKSPACE, 'r') as f:
- workspace = f.read()
- has_any_rule = re.search(r'^android_[ns]dk_repository',
- workspace,
- re.MULTILINE)
- return has_any_rule
+ ndk_api_level = revision.group(1)
+ else:
+ raise Exception('Unable to parse NDK revision.')
+ if int(ndk_api_level) not in _SUPPORTED_ANDROID_NDK_VERSIONS:
+ print('WARNING: The API level of the NDK in %s is %s, which is not '
+ 'supported by Bazel (officially supported versions: %s). Please use '
+ 'another version. Compiling Android targets may result in confusing '
+ 'errors.\n' % (android_ndk_home_path, ndk_api_level,
+ _SUPPORTED_ANDROID_NDK_VERSIONS))
+ return ndk_api_level
def set_gcc_host_compiler_path(environ_cp):
@@ -841,8 +811,8 @@ def reformat_version_sequence(version_str, sequence_count):
def set_tf_cuda_version(environ_cp):
"""Set CUDA_TOOLKIT_PATH and TF_CUDA_VERSION."""
ask_cuda_version = (
- 'Please specify the CUDA SDK version you want to use, '
- 'e.g. 7.0. [Leave empty to default to CUDA %s]: ') % _DEFAULT_CUDA_VERSION
+ 'Please specify the CUDA SDK version you want to use. '
+ '[Leave empty to default to CUDA %s]: ') % _DEFAULT_CUDA_VERSION
for _ in range(_DEFAULT_PROMPT_ASK_ATTEMPTS):
# Configure the Cuda SDK version to use.
@@ -1044,7 +1014,10 @@ def set_tf_tensorrt_install_path(environ_cp):
for lib_file in possible_files:
if is_compatible(lib_file, cuda_ver, cudnn_ver):
- ver_str = nvinfer_pattern.search(lib_file).group(1)
+ matches = nvinfer_pattern.search(lib_file)
+ if len(matches.groups()) == 0:
+ continue
+ ver_str = matches.group(1)
ver = convert_version_to_int(ver_str) if len(ver_str) else 0
if ver > highest_ver[0]:
highest_ver = [ver, ver_str, lib_file]
@@ -1067,7 +1040,7 @@ def set_tf_tensorrt_install_path(environ_cp):
break
# Reset and Retry
- if len(possible_files):
+ if possible_files:
print('TensorRT libraries found in one the following directories',
'are not compatible with selected cuda and cudnn installations')
print(trt_install_path)
@@ -1076,7 +1049,8 @@ def set_tf_tensorrt_install_path(environ_cp):
if search_result:
print(libnvinfer_path_from_ldconfig)
else:
- print('Invalid path to TensorRT. None of the following files can be found:')
+ print(
+ 'Invalid path to TensorRT. None of the following files can be found:')
print(trt_install_path)
print(os.path.join(trt_install_path, 'lib'))
print(os.path.join(trt_install_path, 'lib64'))
@@ -1095,6 +1069,81 @@ def set_tf_tensorrt_install_path(environ_cp):
write_action_env_to_bazelrc('TF_TENSORRT_VERSION', tf_tensorrt_version)
+def set_tf_nccl_install_path(environ_cp):
+ """Set NCCL_INSTALL_PATH and TF_NCCL_VERSION.
+
+ Args:
+ environ_cp: copy of the os.environ.
+
+ Raises:
+ ValueError: if this method was called under non-Linux platform.
+ UserInputError: if user has provided invalid input multiple times.
+ """
+ if not is_linux():
+ raise ValueError('Currently NCCL is only supported on Linux platforms.')
+
+ ask_nccl_version = (
+ 'Please specify the NCCL version you want to use. '
+ '[Leave empty to default to NCCL %s]: ') % _DEFAULT_NCCL_VERSION
+
+ for _ in range(_DEFAULT_PROMPT_ASK_ATTEMPTS):
+ tf_nccl_version = get_from_env_or_user_or_default(
+ environ_cp, 'TF_NCCL_VERSION', ask_nccl_version, _DEFAULT_NCCL_VERSION)
+ tf_nccl_version = reformat_version_sequence(str(tf_nccl_version), 1)
+
+ if tf_nccl_version == '1':
+ break # No need to get install path, NCCL 1 is a GitHub repo.
+
+ # TODO(csigg): Look with ldconfig first if we can find the library in paths
+ # like /usr/lib/x86_64-linux-gnu and the header file in the corresponding
+ # include directory. This is where the NCCL .deb packages install them.
+ # Then ask the user if we should use that. Instead of a single
+ # NCCL_INSTALL_PATH, pass separate NCCL_LIB_PATH and NCCL_HDR_PATH to
+ # nccl_configure.bzl
+ default_nccl_path = environ_cp.get('CUDA_TOOLKIT_PATH')
+ ask_nccl_path = (r'Please specify the location where NCCL %s library is '
+ 'installed. Refer to README.md for more details. [Default '
+ 'is %s]:') % (tf_nccl_version, default_nccl_path)
+ nccl_install_path = get_from_env_or_user_or_default(
+ environ_cp, 'NCCL_INSTALL_PATH', ask_nccl_path, default_nccl_path)
+
+ # Result returned from "read" will be used unexpanded. That make "~"
+ # unusable. Going through one more level of expansion to handle that.
+ nccl_install_path = os.path.realpath(os.path.expanduser(nccl_install_path))
+ if is_windows() or is_cygwin():
+ nccl_install_path = cygpath(nccl_install_path)
+
+ if is_windows():
+ nccl_lib_path = 'lib/x64/nccl.lib'
+ elif is_linux():
+ nccl_lib_path = 'lib/libnccl.so.%s' % tf_nccl_version
+ elif is_macos():
+ nccl_lib_path = 'lib/libnccl.%s.dylib' % tf_nccl_version
+
+ nccl_lib_path = os.path.join(nccl_install_path, nccl_lib_path)
+ nccl_hdr_path = os.path.join(nccl_install_path, 'include/nccl.h')
+ if os.path.exists(nccl_lib_path) and os.path.exists(nccl_hdr_path):
+ # Set NCCL_INSTALL_PATH
+ environ_cp['NCCL_INSTALL_PATH'] = nccl_install_path
+ write_action_env_to_bazelrc('NCCL_INSTALL_PATH', nccl_install_path)
+ break
+
+ # Reset and Retry
+ print('Invalid path to NCCL %s toolkit, %s or %s not found. Please use the '
+ 'O/S agnostic package of NCCL 2' % (tf_nccl_version, nccl_lib_path,
+ nccl_hdr_path))
+
+ environ_cp['TF_NCCL_VERSION'] = ''
+ else:
+ raise UserInputError('Invalid TF_NCCL setting was provided %d '
+ 'times in a row. Assuming to be a scripting mistake.' %
+ _DEFAULT_PROMPT_ASK_ATTEMPTS)
+
+ # Set TF_NCCL_VERSION
+ environ_cp['TF_NCCL_VERSION'] = tf_nccl_version
+ write_action_env_to_bazelrc('TF_NCCL_VERSION', tf_nccl_version)
+
+
def get_native_cuda_compute_capabilities(environ_cp):
"""Get native cuda compute capabilities.
@@ -1143,6 +1192,9 @@ def set_tf_cuda_compute_capabilities(environ_cp):
ask_cuda_compute_capabilities, default_cuda_compute_capabilities)
# Check whether all capabilities from the input is valid
all_valid = True
+ # Remove all whitespace characters before splitting the string
+ # that users may insert by accident, as this will result in error
+ tf_cuda_compute_capabilities = ''.join(tf_cuda_compute_capabilities.split())
for compute_capability in tf_cuda_compute_capabilities.split(','):
m = re.match('[0-9]+.[0-9]+', compute_capability)
if not m:
@@ -1345,6 +1397,10 @@ def set_grpc_build_flags():
write_to_bazelrc('build --define grpc_no_ares=true')
+def set_build_strip_flag():
+ write_to_bazelrc('build --strip=always')
+
+
def set_windows_build_flags():
if is_windows():
# The non-monolithic build is not supported yet
@@ -1372,7 +1428,7 @@ def main():
# environment variables.
environ_cp = dict(os.environ)
- check_bazel_version('0.5.4')
+ check_bazel_version('0.10.0')
reset_tf_configure_bazelrc(args.workspace)
cleanup_makefile()
@@ -1389,6 +1445,9 @@ def main():
environ_cp['TF_NEED_OPENCL'] = '0'
environ_cp['TF_CUDA_CLANG'] = '0'
environ_cp['TF_NEED_TENSORRT'] = '0'
+ # TODO(ibiryukov): Investigate using clang as a cpu or cuda compiler on
+ # Windows.
+ environ_cp['TF_DOWNLOAD_CLANG'] = '0'
if is_macos():
environ_cp['TF_NEED_JEMALLOC'] = '0'
@@ -1403,7 +1462,7 @@ def main():
set_build_var(environ_cp, 'TF_NEED_S3', 'Amazon S3 File System',
'with_s3_support', True, 's3')
set_build_var(environ_cp, 'TF_NEED_KAFKA', 'Apache Kafka Platform',
- 'with_kafka_support', False, 'kafka')
+ 'with_kafka_support', True, 'kafka')
set_build_var(environ_cp, 'TF_ENABLE_XLA', 'XLA JIT', 'with_xla_support',
False, 'xla')
set_build_var(environ_cp, 'TF_NEED_GDR', 'GDR', 'with_gdr_support',
@@ -1428,6 +1487,8 @@ def main():
set_tf_cudnn_version(environ_cp)
if is_linux():
set_tf_tensorrt_install_path(environ_cp)
+ set_tf_nccl_install_path(environ_cp)
+
set_tf_cuda_compute_capabilities(environ_cp)
if 'LD_LIBRARY_PATH' in environ_cp and environ_cp.get(
'LD_LIBRARY_PATH') != '1':
@@ -1436,16 +1497,8 @@ def main():
set_tf_cuda_clang(environ_cp)
if environ_cp.get('TF_CUDA_CLANG') == '1':
- if not is_windows():
- # Ask if we want to download clang release while building.
- set_tf_download_clang(environ_cp)
- else:
- # We use bazel's generated crosstool on Windows and there is no
- # way to provide downloaded toolchain for that yet.
- # TODO(ibiryukov): Investigate using clang as a cuda compiler on
- # Windows.
- environ_cp['TF_DOWNLOAD_CLANG'] = '0'
-
+ # Ask whether we should download the clang toolchain.
+ set_tf_download_clang(environ_cp)
if environ_cp.get('TF_DOWNLOAD_CLANG') != '1':
# Set up which clang we should use as the cuda / host compiler.
set_clang_cuda_compiler_path(environ_cp)
@@ -1455,6 +1508,13 @@ def main():
if not is_windows():
set_gcc_host_compiler_path(environ_cp)
set_other_cuda_vars(environ_cp)
+ else:
+ # CUDA not required. Ask whether we should download the clang toolchain and
+ # use it for the CPU build.
+ set_tf_download_clang(environ_cp)
+ if environ_cp.get('TF_DOWNLOAD_CLANG') == '1':
+ write_to_bazelrc('build --config=download_clang')
+ write_to_bazelrc('test --config=download_clang')
set_build_var(environ_cp, 'TF_NEED_MPI', 'MPI', 'with_mpi_support', False)
if environ_cp.get('TF_NEED_MPI') == '1':
@@ -1463,23 +1523,18 @@ def main():
set_grpc_build_flags()
set_cc_opt_flags(environ_cp)
+ set_build_strip_flag()
set_windows_build_flags()
- if workspace_has_any_android_rule():
- print('The WORKSPACE file has at least one of ["android_sdk_repository", '
- '"android_ndk_repository"] already set. Will not ask to help '
- 'configure the WORKSPACE. Please delete the existing rules to '
- 'activate the helper.\n')
- else:
- if get_var(
- environ_cp, 'TF_SET_ANDROID_WORKSPACE', 'android workspace',
- False,
- ('Would you like to interactively configure ./WORKSPACE for '
- 'Android builds?'),
- 'Searching for NDK and SDK installations.',
- 'Not configuring the WORKSPACE for Android builds.'):
- create_android_ndk_rule(environ_cp)
- create_android_sdk_rule(environ_cp)
+ if get_var(
+ environ_cp, 'TF_SET_ANDROID_WORKSPACE', 'android workspace',
+ False,
+ ('Would you like to interactively configure ./WORKSPACE for '
+ 'Android builds?'),
+ 'Searching for NDK and SDK installations.',
+ 'Not configuring the WORKSPACE for Android builds.'):
+ create_android_ndk_rule(environ_cp)
+ create_android_sdk_rule(environ_cp)
print('Preconfigured Bazel build configs. You can use any of the below by '
'adding "--config=<>" to your build command. See tools/bazel.rc for '
diff --git a/tensorflow/BUILD b/tensorflow/BUILD
index dc995d231d3e591771f801e28024a76610cdba26..6d134dbb80cb8c3dcf15b2ba20783870a67e9a62 100644
--- a/tensorflow/BUILD
+++ b/tensorflow/BUILD
@@ -19,6 +19,10 @@ load(
"//tensorflow/core:platform/default/build_config.bzl",
"tf_additional_binary_deps",
)
+load(
+ "//tensorflow/tools/api/generator:api_gen.bzl",
+ "gen_api_init_files", # @unused
+)
# Config setting for determining if we are building for Android.
config_setting(
@@ -240,6 +244,13 @@ config_setting(
visibility = ["//visibility:public"],
)
+config_setting(
+ name = "with_kafka_support_windows_override",
+ define_values = {"with_kafka_support": "true"},
+ values = {"cpu": "x64_windows"},
+ visibility = ["//visibility:public"],
+)
+
config_setting(
name = "with_gcp_support_android_override",
define_values = {"with_gcp_support": "true"},
@@ -394,309 +405,6 @@ package_group(
],
)
-filegroup(
- name = "all_files",
- srcs = glob(
- ["**/*"],
- exclude = [
- "**/METADATA",
- "**/OWNERS",
- "g3doc/sitemap.md",
- ],
- ),
- visibility = ["//tensorflow:__subpackages__"],
-)
-
-py_library(
- name = "tensorflow_py",
- srcs = ["__init__.py"],
- srcs_version = "PY2AND3",
- visibility = ["//visibility:public"],
- deps = ["//tensorflow/python"],
-)
-
-filegroup(
- name = "all_opensource_files",
- data = [
- ":all_files",
- "//tensorflow/c:all_files",
- "//tensorflow/cc:all_files",
- "//tensorflow/cc/saved_model:all_files",
- "//tensorflow/cc/saved_model/python:all_files",
- "//tensorflow/cc/tools:all_files",
- "//tensorflow/compiler/aot:all_files",
- "//tensorflow/compiler/aot/tests:all_files",
- "//tensorflow/compiler/jit:all_files",
- "//tensorflow/compiler/jit/graphcycles:all_files",
- "//tensorflow/compiler/jit/kernels:all_files",
- "//tensorflow/compiler/jit/legacy_flags:all_files",
- "//tensorflow/compiler/jit/ops:all_files",
- "//tensorflow/compiler/plugin:all_files",
- "//tensorflow/compiler/tests:all_files",
- "//tensorflow/compiler/tf2xla:all_files",
- "//tensorflow/compiler/tf2xla/cc:all_files",
- "//tensorflow/compiler/tf2xla/kernels:all_files",
- "//tensorflow/compiler/tf2xla/lib:all_files",
- "//tensorflow/compiler/tf2xla/ops:all_files",
- "//tensorflow/compiler/xla:all_files",
- "//tensorflow/compiler/xla/client:all_files",
- "//tensorflow/compiler/xla/client/lib:all_files",
- "//tensorflow/compiler/xla/legacy_flags:all_files",
- "//tensorflow/compiler/xla/python:all_files",
- "//tensorflow/compiler/xla/service:all_files",
- "//tensorflow/compiler/xla/service/cpu:all_files",
- "//tensorflow/compiler/xla/service/gpu:all_files",
- "//tensorflow/compiler/xla/service/gpu/llvm_gpu_backend:all_files",
- "//tensorflow/compiler/xla/service/interpreter:all_files",
- "//tensorflow/compiler/xla/service/llvm_ir:all_files",
- "//tensorflow/compiler/xla/tests:all_files",
- "//tensorflow/compiler/xla/tools:all_files",
- "//tensorflow/compiler/xla/tools/parser:all_files",
- "//tensorflow/contrib:all_files",
- "//tensorflow/contrib/all_reduce:all_files",
- "//tensorflow/contrib/android:all_files",
- "//tensorflow/contrib/batching:all_files",
- "//tensorflow/contrib/bayesflow:all_files",
- "//tensorflow/contrib/boosted_trees:all_files",
- "//tensorflow/contrib/boosted_trees/estimator_batch:all_files",
- "//tensorflow/contrib/boosted_trees/lib:all_files",
- "//tensorflow/contrib/boosted_trees/proto:all_files",
- "//tensorflow/contrib/boosted_trees/resources:all_files",
- "//tensorflow/contrib/cloud:all_files",
- "//tensorflow/contrib/cloud/kernels:all_files",
- "//tensorflow/contrib/cluster_resolver:all_files",
- "//tensorflow/contrib/coder:all_files",
- "//tensorflow/contrib/compiler:all_files",
- "//tensorflow/contrib/copy_graph:all_files",
- "//tensorflow/contrib/crf:all_files",
- "//tensorflow/contrib/cudnn_rnn:all_files",
- "//tensorflow/contrib/data:all_files",
- "//tensorflow/contrib/data/kernels:all_files",
- "//tensorflow/contrib/data/python/kernel_tests:all_files",
- "//tensorflow/contrib/data/python/ops:all_files",
- "//tensorflow/contrib/decision_trees/proto:all_files",
- "//tensorflow/contrib/deprecated:all_files",
- "//tensorflow/contrib/distributions:all_files",
- "//tensorflow/contrib/eager/proto:all_files",
- "//tensorflow/contrib/eager/python:all_files",
- "//tensorflow/contrib/estimator:all_files",
- "//tensorflow/contrib/factorization:all_files",
- "//tensorflow/contrib/factorization/examples:all_files",
- "//tensorflow/contrib/factorization/kernels:all_files",
- "//tensorflow/contrib/feature_column:all_files",
- "//tensorflow/contrib/ffmpeg:all_files",
- "//tensorflow/contrib/ffmpeg/default:all_files",
- "//tensorflow/contrib/framework:all_files",
- "//tensorflow/contrib/fused_conv:all_files",
- "//tensorflow/contrib/gan:all_files",
- "//tensorflow/contrib/gdr:all_files",
- "//tensorflow/contrib/graph_editor:all_files",
- "//tensorflow/contrib/grid_rnn:all_files",
- "//tensorflow/contrib/hooks:all_files",
- "//tensorflow/contrib/hvx/clock_cycle_profiling:all_files",
- "//tensorflow/contrib/hvx/hvx_ops_support_checker:all_files",
- "//tensorflow/contrib/image:all_files",
- "//tensorflow/contrib/input_pipeline:all_files",
- "//tensorflow/contrib/input_pipeline/kernels:all_files",
- "//tensorflow/contrib/integrate:all_files",
- "//tensorflow/contrib/keras:all_files",
- "//tensorflow/contrib/kernel_methods:all_files",
- "//tensorflow/contrib/kfac:all_files",
- "//tensorflow/contrib/kfac/examples:all_files",
- "//tensorflow/contrib/kfac/examples/tests:all_files",
- "//tensorflow/contrib/kfac/python/kernel_tests:all_files",
- "//tensorflow/contrib/kfac/python/ops:all_files",
- "//tensorflow/contrib/labeled_tensor:all_files",
- "//tensorflow/contrib/layers:all_files",
- "//tensorflow/contrib/layers/kernels:all_files",
- "//tensorflow/contrib/learn:all_files",
- "//tensorflow/contrib/learn/python/learn/datasets:all_files",
- "//tensorflow/contrib/legacy_seq2seq:all_files",
- "//tensorflow/contrib/libsvm:all_files",
- "//tensorflow/contrib/linalg:all_files",
- "//tensorflow/contrib/linear_optimizer:all_files",
- "//tensorflow/contrib/lite:all_files",
- "//tensorflow/contrib/lite/java:all_files",
- "//tensorflow/contrib/lite/java/demo/app/src/main:all_files",
- "//tensorflow/contrib/lite/java/demo/app/src/main/assets:all_files",
- "//tensorflow/contrib/lite/java/src/main/native:all_files",
- "//tensorflow/contrib/lite/java/src/testhelper/java/org/tensorflow/lite:all_files",
- "//tensorflow/contrib/lite/kernels:all_files",
- "//tensorflow/contrib/lite/kernels/internal:all_files",
- "//tensorflow/contrib/lite/models/smartreply:all_files",
- "//tensorflow/contrib/lite/nnapi:all_files",
- "//tensorflow/contrib/lite/python:all_files",
- "//tensorflow/contrib/lite/schema:all_files",
- "//tensorflow/contrib/lite/testing:all_files",
- "//tensorflow/contrib/lite/toco:all_files",
- "//tensorflow/contrib/lite/toco/graph_transformations/tests:all_files",
- "//tensorflow/contrib/lite/toco/python:all_files",
- "//tensorflow/contrib/lite/toco/tensorflow_graph_matching:all_files",
- "//tensorflow/contrib/lite/toco/tflite:all_files",
- "//tensorflow/contrib/lite/tools:all_files",
- "//tensorflow/contrib/lookup:all_files",
- "//tensorflow/contrib/losses:all_files",
- "//tensorflow/contrib/makefile:all_files",
- "//tensorflow/contrib/memory_stats:all_files",
- "//tensorflow/contrib/meta_graph_transform:all_files",
- "//tensorflow/contrib/metrics:all_files",
- "//tensorflow/contrib/model_pruning:all_files",
- "//tensorflow/contrib/model_pruning/examples/cifar10:all_files",
- "//tensorflow/contrib/nccl:all_files",
- "//tensorflow/contrib/nearest_neighbor:all_files",
- "//tensorflow/contrib/nn:all_files",
- "//tensorflow/contrib/opt:all_files",
- "//tensorflow/contrib/periodic_resample:all_files",
- "//tensorflow/contrib/predictor:all_files",
- "//tensorflow/contrib/py2tf:all_files",
- "//tensorflow/contrib/py2tf/converters:all_files",
- "//tensorflow/contrib/py2tf/impl:all_files",
- "//tensorflow/contrib/py2tf/pyct:all_files",
- "//tensorflow/contrib/py2tf/pyct/static_analysis:all_files",
- "//tensorflow/contrib/py2tf/utils:all_files",
- "//tensorflow/contrib/quantize:all_files",
- "//tensorflow/contrib/receptive_field:all_files",
- "//tensorflow/contrib/reduce_slice_ops:all_files",
- "//tensorflow/contrib/remote_fused_graph/pylib:all_files",
- "//tensorflow/contrib/resampler:all_files",
- "//tensorflow/contrib/rnn:all_files",
- "//tensorflow/contrib/saved_model:all_files",
- "//tensorflow/contrib/saved_model/cc/saved_model:all_files",
- "//tensorflow/contrib/seq2seq:all_files",
- "//tensorflow/contrib/session_bundle:all_files",
- "//tensorflow/contrib/session_bundle/example:all_files",
- "//tensorflow/contrib/signal:all_files",
- "//tensorflow/contrib/slim:all_files",
- "//tensorflow/contrib/slim/python/slim/data:all_files",
- "//tensorflow/contrib/slim/python/slim/nets:all_files",
- "//tensorflow/contrib/solvers:all_files",
- "//tensorflow/contrib/sparsemax:all_files",
- "//tensorflow/contrib/specs:all_files",
- "//tensorflow/contrib/staging:all_files",
- "//tensorflow/contrib/stat_summarizer:all_files",
- "//tensorflow/contrib/stateless:all_files",
- "//tensorflow/contrib/summary:all_files",
- "//tensorflow/contrib/tensor_forest:all_files",
- "//tensorflow/contrib/tensor_forest/hybrid:all_files",
- "//tensorflow/contrib/tensor_forest/kernels/v4:all_files",
- "//tensorflow/contrib/tensor_forest/proto:all_files",
- "//tensorflow/contrib/tensorboard:all_files",
- "//tensorflow/contrib/tensorboard/db:all_files",
- "//tensorflow/contrib/tensorrt:all_files",
- "//tensorflow/contrib/testing:all_files",
- "//tensorflow/contrib/text:all_files",
- "//tensorflow/contrib/tfprof:all_files",
- "//tensorflow/contrib/timeseries:all_files",
- "//tensorflow/contrib/timeseries/examples:all_files",
- "//tensorflow/contrib/timeseries/python/timeseries:all_files",
- "//tensorflow/contrib/timeseries/python/timeseries/state_space_models:all_files",
- "//tensorflow/contrib/tpu:all_files",
- "//tensorflow/contrib/tpu/profiler:all_files",
- "//tensorflow/contrib/tpu/proto:all_files",
- "//tensorflow/contrib/training:all_files",
- "//tensorflow/contrib/util:all_files",
- "//tensorflow/contrib/verbs:all_files",
- "//tensorflow/core:all_files",
- "//tensorflow/core/api_def:all_files",
- "//tensorflow/core/debug:all_files",
- "//tensorflow/core/distributed_runtime:all_files",
- "//tensorflow/core/distributed_runtime/rpc:all_files",
- "//tensorflow/core/grappler:all_files",
- "//tensorflow/core/grappler/clusters:all_files",
- "//tensorflow/core/grappler/costs:all_files",
- "//tensorflow/core/grappler/inputs:all_files",
- "//tensorflow/core/grappler/optimizers:all_files",
- "//tensorflow/core/grappler/utils:all_files",
- "//tensorflow/core/kernels:all_files",
- "//tensorflow/core/kernels/batching_util:all_files",
- "//tensorflow/core/kernels/data:all_files",
- "//tensorflow/core/kernels/data/sql:all_files",
- "//tensorflow/core/kernels/fuzzing:all_files",
- "//tensorflow/core/kernels/hexagon:all_files",
- "//tensorflow/core/kernels/neon:all_files",
- "//tensorflow/core/lib/db:all_files",
- "//tensorflow/core/ops/compat:all_files",
- "//tensorflow/core/platform/cloud:all_files",
- "//tensorflow/core/platform/default/build_config:all_files",
- "//tensorflow/core/platform/hadoop:all_files",
- "//tensorflow/core/platform/s3:all_files",
- "//tensorflow/core/profiler:all_files",
- "//tensorflow/core/profiler/internal:all_files",
- "//tensorflow/core/profiler/internal/advisor:all_files",
- "//tensorflow/core/util/ctc:all_files",
- "//tensorflow/core/util/tensor_bundle:all_files",
- "//tensorflow/examples/adding_an_op:all_files",
- "//tensorflow/examples/android:all_files",
- "//tensorflow/examples/benchmark:all_files",
- "//tensorflow/examples/get_started/regression:all_files",
- "//tensorflow/examples/how_tos/reading_data:all_files",
- "//tensorflow/examples/image_retraining:all_files",
- "//tensorflow/examples/label_image:all_files",
- "//tensorflow/examples/learn:all_files",
- "//tensorflow/examples/multibox_detector:all_files",
- "//tensorflow/examples/saved_model:all_files",
- "//tensorflow/examples/speech_commands:all_files",
- "//tensorflow/examples/tutorials/estimators:all_files",
- "//tensorflow/examples/tutorials/layers:all_files",
- "//tensorflow/examples/tutorials/mnist:all_files",
- "//tensorflow/examples/tutorials/monitors:all_files",
- "//tensorflow/examples/tutorials/word2vec:all_files",
- "//tensorflow/examples/wav_to_spectrogram:all_files",
- "//tensorflow/go:all_files",
- "//tensorflow/java:all_files",
- "//tensorflow/java/src/main/java/org/tensorflow/examples:all_files",
- "//tensorflow/java/src/main/native:all_files",
- "//tensorflow/python:all_files",
- "//tensorflow/python/data:all_files",
- "//tensorflow/python/data/kernel_tests:all_files",
- "//tensorflow/python/data/ops:all_files",
- "//tensorflow/python/data/util:all_files",
- "//tensorflow/python/debug:all_files",
- "//tensorflow/python/eager:all_files",
- "//tensorflow/python/estimator:all_files",
- "//tensorflow/python/feature_column:all_files",
- "//tensorflow/python/keras:all_files",
- "//tensorflow/python/kernel_tests:all_files",
- "//tensorflow/python/kernel_tests/distributions:all_files",
- "//tensorflow/python/kernel_tests/linalg:all_files",
- "//tensorflow/python/kernel_tests/random:all_files",
- "//tensorflow/python/ops/distributions:all_files",
- "//tensorflow/python/ops/linalg:all_files",
- "//tensorflow/python/ops/losses:all_files",
- "//tensorflow/python/profiler:all_files",
- "//tensorflow/python/profiler/internal:all_files",
- "//tensorflow/python/saved_model:all_files",
- "//tensorflow/python/tools:all_files",
- "//tensorflow/tools/api/generator:all_files",
- "//tensorflow/tools/api/golden:all_files",
- "//tensorflow/tools/api/lib:all_files",
- "//tensorflow/tools/api/tests:all_files",
- "//tensorflow/tools/benchmark:all_files",
- "//tensorflow/tools/build_info:all_files",
- "//tensorflow/tools/ci_build/gpu_build:all_files",
- "//tensorflow/tools/common:all_files",
- "//tensorflow/tools/compatibility:all_files",
- "//tensorflow/tools/dist_test/server:all_files",
- "//tensorflow/tools/docker:all_files",
- "//tensorflow/tools/docker/notebooks:all_files",
- "//tensorflow/tools/docs:all_files",
- "//tensorflow/tools/git:all_files",
- "//tensorflow/tools/graph_transforms:all_files",
- "//tensorflow/tools/mlpbtxt:all_files",
- "//tensorflow/tools/proto_text:all_files",
- "//tensorflow/tools/quantization:all_files",
- "//tensorflow/tools/test:all_files",
- "//tensorflow/user_ops:all_files",
- "//third_party/eigen3:all_files",
- "//third_party/fft2d:all_files",
- "//third_party/flatbuffers:all_files",
- "//third_party/hadoop:all_files",
- "//third_party/sycl:all_files",
- "//third_party/sycl/sycl:all_files",
- ],
- visibility = ["//visibility:public"],
-)
-
load(
"//third_party/mkl:build_defs.bzl",
"if_mkl",
@@ -746,11 +454,12 @@ tf_cc_shared_object(
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [
+ "//tensorflow/core:core_cpu_impl",
"//tensorflow/core:framework_internal_impl",
+ "//tensorflow/core:gpu_runtime_impl",
+ "//tensorflow/core/grappler/optimizers:custom_graph_optimizer_registry_impl",
"//tensorflow/core:lib_internal_impl",
- "//tensorflow/core:core_cpu_impl",
"//tensorflow/stream_executor:stream_executor_impl",
- "//tensorflow/core:gpu_runtime_impl",
] + tf_additional_binary_deps(),
)
@@ -766,27 +475,27 @@ tf_cc_shared_object(
# excludes all but a subset of function names.
# On MacOS, the linker does not support version_script, but has an
# an "-exported_symbols_list" command. -z defs disallows undefined
-# symbols in object files and -s strips the output.
+# symbols in object files.
tf_cc_shared_object(
name = "libtensorflow.so",
linkopts = select({
"//tensorflow:darwin": [
"-Wl,-exported_symbols_list", # This line must be directly followed by the exported_symbols.lds file
- "//tensorflow/c:exported_symbols.lds",
+ "$(location //tensorflow/c:exported_symbols.lds)",
"-Wl,-install_name,@rpath/libtensorflow.so",
],
"//tensorflow:windows": [],
"//tensorflow:windows_msvc": [],
"//conditions:default": [
"-z defs",
- "-s",
"-Wl,--version-script", # This line must be directly followed by the version_script.lds file
- "//tensorflow/c:version_script.lds",
+ "$(location //tensorflow/c:version_script.lds)",
],
}),
deps = [
"//tensorflow/c:c_api",
+ "//tensorflow/c:c_api_experimental",
"//tensorflow/c:exported_symbols.lds",
"//tensorflow/c:version_script.lds",
"//tensorflow/c/eager:c_api",
@@ -799,15 +508,14 @@ tf_cc_shared_object(
linkopts = select({
"//tensorflow:darwin": [
"-Wl,-exported_symbols_list", # This line must be directly followed by the exported_symbols.lds file
- "//tensorflow:tf_exported_symbols.lds",
+ "$(location //tensorflow:tf_exported_symbols.lds)",
],
"//tensorflow:windows": [],
"//tensorflow:windows_msvc": [],
"//conditions:default": [
"-z defs",
- "-s",
"-Wl,--version-script", # This line must be directly followed by the version_script.lds file
- "//tensorflow:tf_version_script.lds",
+ "$(location //tensorflow:tf_version_script.lds)",
],
}),
deps = [
@@ -829,3 +537,20 @@ exports_files(
"tf_exported_symbols.lds",
],
)
+
+gen_api_init_files(
+ name = "tensorflow_python_api_gen",
+ srcs = ["api_template.__init__.py"],
+ root_init_template = "api_template.__init__.py",
+)
+
+py_library(
+ name = "tensorflow_py",
+ srcs = [
+ ":tensorflow_python_api_gen",
+ "//tensorflow/python/estimator/api:estimator_python_api_gen",
+ ],
+ srcs_version = "PY2AND3",
+ visibility = ["//visibility:public"],
+ deps = ["//tensorflow/python"],
+)
diff --git a/tensorflow/__init__.py b/tensorflow/__init__.py
index 78ad6aec19f3bbbfcb389012ac1577573b3e4901..440e9f8dbd2f4b2a2ab78eaaf26408584e7c1446 100644
--- a/tensorflow/__init__.py
+++ b/tensorflow/__init__.py
@@ -20,14 +20,16 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-# pylint: disable=wildcard-import
-from tensorflow.python import * # pylint: disable=redefined-builtin
-# pylint: enable=wildcard-import
+# pylint: disable=g-bad-import-order
+from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
from tensorflow.python.util.lazy_loader import LazyLoader
contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')
del LazyLoader
+from tensorflow.python.platform import flags # pylint: disable=g-import-not-at-top
+app.flags = flags # pylint: disable=undefined-variable
+
del absolute_import
del division
del print_function
diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9662d7b478ba61c69edc20b0d47293f9939e7881
--- /dev/null
+++ b/tensorflow/api_template.__init__.py
@@ -0,0 +1,58 @@
+# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+"""Bring in all of the public TensorFlow interface into this module."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+# pylint: disable=g-bad-import-order
+from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
+# API IMPORTS PLACEHOLDER
+
+try:
+ import os # pylint: disable=g-import-not-at-top
+ # Add `estimator` attribute to allow access to estimator APIs via
+ # "tf.estimator..."
+ from tensorflow.python.estimator.api import estimator # pylint: disable=g-import-not-at-top
+
+ # Add `estimator` to the __path__ to allow "from tensorflow.estimator..."
+ # style imports.
+ from tensorflow.python.estimator import api as estimator_api # pylint: disable=g-import-not-at-top
+ __path__ += [os.path.dirname(estimator_api.__file__)]
+ del estimator_api
+ del os
+except (ImportError, AttributeError):
+ print('tf.estimator package not installed.')
+
+from tensorflow.python.util.lazy_loader import LazyLoader # pylint: disable=g-import-not-at-top
+contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')
+del LazyLoader
+
+from tensorflow.python.platform import flags # pylint: disable=g-import-not-at-top
+app.flags = flags # pylint: disable=undefined-variable
+
+del absolute_import
+del division
+del print_function
+
+# These symbols appear because we import the python package which
+# in turn imports from tensorflow.core and tensorflow.python. They
+# must come from this module. So python adds these symbols for the
+# resolution to succeed.
+# pylint: disable=undefined-variable
+del python
+del core
+# pylint: enable=undefined-variable
diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD
index 5dfb743681255d8c03e91ea43fd441d94fdee59d..8a9301d584775cff3ae315e6fd856b00d1734248 100644
--- a/tensorflow/c/BUILD
+++ b/tensorflow/c/BUILD
@@ -17,7 +17,10 @@ load(
filegroup(
name = "headers",
- srcs = ["c_api.h"],
+ srcs = [
+ "c_api.h",
+ "c_api_experimental.h",
+ ],
visibility = ["//tensorflow:__subpackages__"],
)
@@ -31,6 +34,8 @@ filegroup(
exclude = [
"c_api_experimental.cc",
"c_api_experimental.h",
+ "python_api.cc",
+ "python_api.h",
"*test*",
],
),
@@ -113,6 +118,11 @@ tf_cuda_library(
":c_api",
":c_api_internal",
"//tensorflow/compiler/jit/legacy_flags:mark_for_compilation_pass_flags",
+ "//tensorflow/contrib/tpu:all_ops",
+ "//tensorflow/core:core_cpu",
+ "//tensorflow/core:framework",
+ "//tensorflow/core:lib",
+ "//tensorflow/core:lib_platform",
"//tensorflow/core:protos_all_cc",
],
)
@@ -209,6 +219,27 @@ tf_cuda_cc_test(
],
)
+tf_cc_test(
+ name = "c_api_experimental_test",
+ size = "small",
+ srcs = ["c_api_experimental_test.cc"],
+ data = ["testdata/tf_record"],
+ linkopts = select({
+ "//tensorflow:darwin": ["-headerpad_max_install_names"],
+ "//conditions:default": [],
+ }),
+ # We must ensure that the dependencies can be dynamically linked since
+ # the shared library must be able to use core:framework.
+ # linkstatic = tf_kernel_tests_linkstatic(),
+ deps = [
+ ":c_api_experimental",
+ ":c_test_util",
+ "//tensorflow/core:lib",
+ "//tensorflow/core:test",
+ "//tensorflow/core:test_main",
+ ],
+)
+
tf_cc_test(
name = "c_api_function_test",
size = "small",
@@ -253,20 +284,7 @@ tf_cuda_library(
deps = [
":c_api",
":c_api_internal",
+ # TODO(b/74620627): remove when _USE_C_SHAPES is removed
+ "//tensorflow/python:cpp_shape_inference_proto_cc",
],
)
-
-# -----------------------------------------------------------------------------
-# Google-internal targets.
-
-filegroup(
- name = "all_files",
- srcs = glob(
- ["**/*"],
- exclude = [
- "**/METADATA",
- "**/OWNERS",
- ],
- ),
- visibility = ["//tensorflow:__subpackages__"],
-)
diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc
index 85f1d1639b4d09f2de77d326481a86ec246270d0..cb0b093ad260e000dcef9d1123e967a77cf1a041 100644
--- a/tensorflow/c/c_api.cc
+++ b/tensorflow/c/c_api.cc
@@ -30,6 +30,7 @@ limitations under the License.
#endif
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/core/common_runtime/device_mgr.h"
+#include "tensorflow/core/common_runtime/eval_const_tensor.h"
#include "tensorflow/core/common_runtime/shape_refiner.h"
#include "tensorflow/core/framework/allocation_description.pb.h"
#include "tensorflow/core/framework/log_memory.h"
@@ -62,6 +63,7 @@ limitations under the License.
// brain namespace because we are defining 'extern "C"' functions.
using tensorflow::AllocationDescription;
using tensorflow::DataType;
+using tensorflow::ExtendSessionGraphHelper;
using tensorflow::Graph;
using tensorflow::GraphDef;
using tensorflow::mutex_lock;
@@ -73,6 +75,7 @@ using tensorflow::NodeBuilder;
using tensorflow::NodeDef;
using tensorflow::OpDef;
using tensorflow::OpRegistry;
+using tensorflow::OutputTensor;
using tensorflow::PartialTensorShape;
using tensorflow::RunMetadata;
using tensorflow::RunOptions;
@@ -628,7 +631,22 @@ Status MessageToBuffer(const tensorflow::protobuf::Message& in,
"Failed to allocate memory to serialize message of type '",
in.GetTypeName(), "' and size ", proto_size);
}
- in.SerializeToArray(buf, proto_size);
+ // SerializeToArray takes size as an int.
+ // This next 'if' is a workaround till we update to depend on a version
+ // of protocol buffers that includes
+ // https://github.com/google/protobuf/pull/4739
+ if (proto_size > std::numeric_limits::max()) {
+ return InvalidArgument("Cannot serialize protocol buffer of type ",
+ in.GetTypeName(), " as the serialized size (",
+ proto_size,
+ "bytes) would be larger than the limit (",
+ std::numeric_limits::max(), " bytes)");
+ }
+ if (!in.SerializeToArray(buf, proto_size)) {
+ return InvalidArgument("Unable to serialize ", in.GetTypeName(),
+ " protocol buffer, perhaps the serialized size (",
+ proto_size, " bytes) is too large?");
+ }
out->data = buf;
out->length = proto_size;
out->data_deallocator = [](void* data, size_t length) {
@@ -638,17 +656,17 @@ Status MessageToBuffer(const tensorflow::protobuf::Message& in,
}
void RecordMutation(TF_Graph* graph, const TF_Operation& op,
- const char* mutation_type)
- EXCLUSIVE_LOCKS_REQUIRED(graph->mu) {
+ const char* mutation_type) {
// If any session has already run this node_id, mark this session as
// unrunnable.
for (auto it : graph->sessions) {
+ mutex_lock session_lock(it.first->mu);
if (it.first->last_num_graph_nodes > op.node.id()) {
- it.second = FailedPrecondition(
+ it.second = strings::StrCat(
"Operation '", op.node.DebugString(), "' was changed by ",
mutation_type,
- " after it was run by a session. Nodes can be mutated "
- "only before they are executed by a session. Either don't modify "
+ " after it was run by a session. This mutation will have no effect, "
+ "and will trigger an error in the future. Either don't modify "
"nodes after running them or create a new session.");
}
}
@@ -708,6 +726,61 @@ void TF_GraphSetOutputHandleShapesAndTypes(TF_Graph* graph, TF_Output output,
Status LoadLibrary(const char* library_filename, void** result,
const void** buf, size_t* len);
+// TODO(josh11b,mrry): Change Session to be able to use a Graph*
+// directly, instead of requiring us to serialize to a GraphDef and
+// call Session::Extend().
+bool ExtendSessionGraphHelper(TF_Session* session, TF_Status* status) {
+ if (session->graph != nullptr) {
+ // Take the graph lock before the session lock to avoid deadlock. This is
+ // safe since session->graph does not change.
+ session->graph->mu.lock();
+ mutex_lock session_lock(session->mu);
+ const Graph& graph = session->graph->graph;
+
+ const string& mutation_warning = session->graph->sessions[session];
+ if (!mutation_warning.empty()) {
+ // TODO(b/74949947): turn this back into an error status
+ LOG(WARNING) << mutation_warning;
+ session->graph->sessions[session].clear();
+ }
+
+ const auto num_nodes = graph.num_node_ids();
+ if (session->last_num_graph_nodes < num_nodes) {
+ status->status = tensorflow::ValidateNoCycles(session->graph->graph);
+ if (!status->status.ok()) {
+ session->graph->mu.unlock();
+ return false;
+ }
+
+ GraphDef graph_def;
+ *graph_def.mutable_versions() = graph.versions();
+ // Fill graph_def with nodes with ids in the range
+ // [session->last_num_graph_nodes, num_nodes), that is the nodes
+ // added since the last TF_SessionRun() call.
+ for (auto id = session->last_num_graph_nodes; id < num_nodes; ++id) {
+ Node* const node = graph.FindNodeId(id);
+ if (node != nullptr && node->IsOp()) {
+ NodeDef* const node_def = graph_def.add_node();
+ *node_def = node->def();
+ }
+ }
+ *graph_def.mutable_library() = graph.flib_def().ToProto();
+ session->graph->mu.unlock();
+ status->status = session->session->Extend(graph_def);
+ if (!status->status.ok()) {
+ // Contract is we always delete input_values[i].
+ return false;
+ }
+ // Note: session->session is not modified if Extend() fails, so
+ // we only set last_num_graph_nodes if it succeeds.
+ session->last_num_graph_nodes = num_nodes;
+ } else {
+ session->graph->mu.unlock();
+ }
+ }
+ return true;
+}
+
} // namespace tensorflow
static void TF_Run_Setup(int noutputs, TF_Tensor** c_outputs,
@@ -2039,7 +2112,7 @@ static void GraphImportGraphDefLocked(TF_Graph* graph, const GraphDef& def,
for (int i = 0; i < size; ++i) {
TensorId id = results.missing_unused_input_map_keys[i];
- tf_results->missing_unused_key_names_data.push_back(id.first.ToString());
+ tf_results->missing_unused_key_names_data.push_back(std::string(id.first));
tf_results->missing_unused_key_names[i] =
tf_results->missing_unused_key_names_data.back().c_str();
tf_results->missing_unused_key_indexes[i] = id.second;
@@ -2408,11 +2481,7 @@ void TF_AddGradients(TF_Graph* g, TF_Output* y, int ny, TF_Output* x, int nx,
// TF_Session functions ----------------------------------------------
TF_Session::TF_Session(tensorflow::Session* s, TF_Graph* g)
- : session(s), graph(g), last_num_graph_nodes(0), device_mgr(nullptr) {
- if (s->LocalDeviceManager(&device_mgr).ok()) {
- devices = device_mgr->ListDevices();
- }
-}
+ : session(s), graph(g), last_num_graph_nodes(0), extend_before_run(true) {}
TF_Session* TF_NewSession(TF_Graph* graph, const TF_SessionOptions* opt,
TF_Status* status) {
@@ -2422,7 +2491,7 @@ TF_Session* TF_NewSession(TF_Graph* graph, const TF_SessionOptions* opt,
TF_Session* new_session = new TF_Session(session, graph);
if (graph != nullptr) {
mutex_lock l(graph->mu);
- graph->sessions[new_session] = Status::OK();
+ graph->sessions[new_session] = "";
}
return new_session;
} else {
@@ -2488,7 +2557,7 @@ TF_Session* TF_LoadSessionFromSavedModel(
TF_Session* session = new TF_Session(bundle.session.release(), graph);
- graph->sessions[session] = Status::OK();
+ graph->sessions[session] = "";
session->last_num_graph_nodes = graph->graph.num_node_ids();
return session;
#endif // __ANDROID__
@@ -2512,58 +2581,6 @@ void TF_DeleteSession(TF_Session* s, TF_Status* status) {
delete s;
}
-// TODO(josh11b,mrry): Change Session to be able to use a Graph*
-// directly, instead of requiring us to serialize to a GraphDef and
-// call Session::Extend().
-static bool ExtendSessionGraphHelper(TF_Session* session, TF_Status* status) {
- if (session->graph != nullptr) {
- mutex_lock session_lock(session->mu);
- session->graph->mu.lock();
- const Graph& graph = session->graph->graph;
-
- status->status = session->graph->sessions[session];
- if (!status->status.ok()) {
- session->graph->mu.unlock();
- return false;
- }
-
- const auto num_nodes = graph.num_node_ids();
- if (session->last_num_graph_nodes < num_nodes) {
- status->status = tensorflow::ValidateNoCycles(session->graph->graph);
- if (!status->status.ok()) {
- session->graph->mu.unlock();
- return false;
- }
-
- GraphDef graph_def;
- *graph_def.mutable_versions() = graph.versions();
- // Fill graph_def with nodes with ids in the range
- // [session->last_num_graph_nodes, num_nodes), that is the nodes
- // added since the last TF_SessionRun() call.
- for (auto id = session->last_num_graph_nodes; id < num_nodes; ++id) {
- Node* const node = graph.FindNodeId(id);
- if (node != nullptr && node->IsOp()) {
- NodeDef* const node_def = graph_def.add_node();
- *node_def = node->def();
- }
- }
- *graph_def.mutable_library() = graph.flib_def().ToProto();
- session->graph->mu.unlock();
- status->status = session->session->Extend(graph_def);
- if (!status->status.ok()) {
- // Contract is we always delete input_values[i].
- return false;
- }
- // Note: session->session is not modified if Extend() fails, so
- // we only set last_num_graph_nodes if it succeeds.
- session->last_num_graph_nodes = num_nodes;
- } else {
- session->graph->mu.unlock();
- }
- }
- return true;
-}
-
void TF_SessionRun(TF_Session* session, const TF_Buffer* run_options,
const TF_Output* inputs, TF_Tensor* const* input_values,
int ninputs, const TF_Output* outputs,
@@ -2573,7 +2590,8 @@ void TF_SessionRun(TF_Session* session, const TF_Buffer* run_options,
// TODO(josh11b,mrry): Change Session to be able to use a Graph*
// directly, instead of requiring us to serialize to a GraphDef and
// call Session::Extend().
- if (!ExtendSessionGraphHelper(session, status)) {
+ if (session->extend_before_run &&
+ !ExtendSessionGraphHelper(session, status)) {
return;
}
@@ -2610,7 +2628,8 @@ void TF_SessionPRunSetup(TF_Session* session, const TF_Output* inputs,
const char** handle, TF_Status* status) {
*handle = nullptr;
- if (!ExtendSessionGraphHelper(session, status)) {
+ if (session->extend_before_run &&
+ !ExtendSessionGraphHelper(session, status)) {
return;
}
@@ -2653,7 +2672,8 @@ void TF_SessionPRun(TF_Session* session, const char* handle,
// TODO(josh11b,mrry): Change Session to be able to use a Graph*
// directly, instead of requiring us to serialize to a GraphDef and
// call Session::Extend().
- if (!ExtendSessionGraphHelper(session, status)) {
+ if (session->extend_before_run &&
+ !ExtendSessionGraphHelper(session, status)) {
return;
}
@@ -2682,6 +2702,24 @@ void TF_SessionPRun(TF_Session* session, const char* handle,
output_values, target_names, nullptr, status);
}
+unsigned char TF_TryEvaluateConstant(TF_Graph* graph, TF_Output output,
+ TF_Tensor** result, TF_Status* status) {
+ *result = nullptr;
+ mutex_lock l(graph->mu);
+ OutputTensor tensor(&output.oper->node, output.index);
+ bool evaluated;
+ Tensor result_tensor;
+ status->status = EvaluateConstantTensor(
+ tensor, graph->refiner, *graph->graph.op_registry(),
+ graph->graph.versions().producer(), &evaluated, &result_tensor);
+ if (evaluated) {
+ DCHECK(status->status.ok());
+ *result = TF_TensorFromTensor(result_tensor, status);
+ if (!status->status.ok()) evaluated = false;
+ }
+ return evaluated;
+}
+
TF_ApiDefMap* TF_NewApiDefMap(TF_Buffer* op_list_buffer, TF_Status* status) {
tensorflow::OpList op_list;
if (!op_list.ParseFromArray(op_list_buffer->data, op_list_buffer->length)) {
diff --git a/tensorflow/c/c_api.h b/tensorflow/c/c_api.h
index ad592ef70961ef427bfe9fd322a82bd64df7f9f1..c8594347451dffd465d7fa926cc53818dc9e38d4 100644
--- a/tensorflow/c/c_api.h
+++ b/tensorflow/c/c_api.h
@@ -72,7 +72,7 @@ limitations under the License.
#ifdef SWIG
#define TF_CAPI_EXPORT
#else
-#if defined(COMPILER_MSVC)
+#if defined(_WIN32)
#ifdef TF_COMPILE_LIBRARY
#define TF_CAPI_EXPORT __declspec(dllexport)
#else
@@ -80,7 +80,7 @@ limitations under the License.
#endif // TF_COMPILE_LIBRARY
#else
#define TF_CAPI_EXPORT __attribute__((visibility("default")))
-#endif // COMPILER_MSVC
+#endif // _WIN32
#endif // SWIG
#ifdef __cplusplus
@@ -1275,13 +1275,22 @@ TF_CAPI_EXPORT extern void TF_FunctionGetAttrValueProto(
// Deleting a function does not remove it from any graphs it was copied to.
TF_CAPI_EXPORT extern void TF_DeleteFunction(TF_Function* func);
+// Attempts to evaluate `output`. This will only be possible if `output` doesn't
+// depend on any graph inputs (this function is safe to call if this isn't the
+// case though).
+//
+// If the evaluation is successful, this function returns true and `output`s
+// value is returned in `result`. Otherwise returns false. An error status is
+// returned if something is wrong with the graph or input. Note that this may
+// return false even if no error status is set.
+TF_CAPI_EXPORT extern unsigned char TF_TryEvaluateConstant(TF_Graph* graph,
+ TF_Output output,
+ TF_Tensor** result,
+ TF_Status* status);
+
// TODO(josh11b): Register OpDef, available to all operations added
// to this graph.
-// The following two may both benefit from a subgraph-definition API
-// that re-uses most of the graph-definition API.
-// TODO(andydavis): Add functions to a graph.
-
// --------------------------------------------------------------------------
// API for driving Graph execution.
@@ -1487,7 +1496,8 @@ TF_CAPI_EXPORT extern int TF_DeviceListCount(const TF_DeviceList* list);
// If index is out of bounds, an error code will be set in the status object,
// and a null pointer will be returned.
TF_CAPI_EXPORT extern const char* TF_DeviceListName(const TF_DeviceList* list,
- int index, TF_Status*);
+ int index,
+ TF_Status* status);
// Retrieves the type of the device at the given index.
//
@@ -1497,14 +1507,15 @@ TF_CAPI_EXPORT extern const char* TF_DeviceListName(const TF_DeviceList* list,
// If index is out of bounds, an error code will be set in the status object,
// and a null pointer will be returned.
TF_CAPI_EXPORT extern const char* TF_DeviceListType(const TF_DeviceList* list,
- int index, TF_Status*);
+ int index,
+ TF_Status* status);
// Retrieve the amount of memory associated with a given device.
//
// If index is out of bounds, an error code will be set in the status object,
// and -1 will be returned.
TF_CAPI_EXPORT extern int64_t TF_DeviceListMemoryBytes(
- const TF_DeviceList* list, int index, TF_Status*);
+ const TF_DeviceList* list, int index, TF_Status* status);
// --------------------------------------------------------------------------
// Load plugins containing custom ops and kernels
diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc
index be7f85a5bb06dce84579b109d506ded049042b50..95b04f9058afdfaadbc24f0238860279fcd3e800 100644
--- a/tensorflow/c/c_api_experimental.cc
+++ b/tensorflow/c/c_api_experimental.cc
@@ -17,8 +17,27 @@ limitations under the License.
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/compiler/jit/legacy_flags/mark_for_compilation_pass_flags.h"
+#include "tensorflow/core/graph/graph.h"
+#include "tensorflow/core/graph/node_builder.h"
+#include "tensorflow/core/lib/strings/strcat.h"
+#include "tensorflow/core/platform/platform.h"
#include "tensorflow/core/protobuf/config.pb.h"
+using tensorflow::FunctionDef;
+using tensorflow::Node;
+using tensorflow::NodeBuilder;
+using tensorflow::Status;
+
+namespace {
+typedef std::unique_ptr
+ UniqueFuncPtr;
+}
+
+// struct TF_Operation { tensorflow::Node node; };
+static TF_Operation* ToTF_Operation(Node* node) {
+ return static_cast(static_cast(node));
+}
+
void TF_EnableXLACompilation(TF_SessionOptions* options, unsigned char enable) {
tensorflow::ConfigProto& config = options->options.config;
auto* optimizer_options =
@@ -37,3 +56,8402 @@ void TF_EnableXLACompilation(TF_SessionOptions* options, unsigned char enable) {
optimizer_options->set_global_jit_level(tensorflow::OptimizerOptions::OFF);
}
}
+
+const char* TF_GraphDebugString(TF_Graph* graph, size_t* len) {
+ tensorflow::mutex_lock c(graph->mu);
+ const auto& debug_str = graph->graph.ToGraphDefDebug().DebugString();
+ *len = debug_str.size();
+ char* ret = static_cast(malloc(*len + 1));
+ memcpy(ret, debug_str.c_str(), *len + 1);
+ return ret;
+}
+
+// On success, returns a set of TF_Function instances from `text_proto` of
+// GraphDef type. These functions must be deleted by calling TF_DeleteFunction.
+//
+// If `mutate_proto_func` is non-NULL, run it over each FunctionDef proto,
+// before creating a TF_Function out of the possibly mutated proto.
+static std::vector CreateFunctionsFromTextProto(
+ const char* text_proto,
+ std::function* mutate_proto_func, TF_Status* status) {
+ tensorflow::GraphDef gdef;
+ if (!tensorflow::protobuf::TextFormat::ParseFromString(text_proto, &gdef)) {
+ status->status = tensorflow::errors::Internal(
+ "Invalid text proto for GraphDef: ", text_proto);
+ return {};
+ }
+ const auto& fdef_lib = gdef.library();
+ if (fdef_lib.gradient_size() > 0) {
+ status->status = tensorflow::errors::Internal(
+ "GradientDef is not supported in reading Dataset related functions: ",
+ text_proto);
+ return {};
+ }
+ std::vector ret;
+ for (const FunctionDef& fdef : fdef_lib.function()) {
+ // Make a copy so that we can mutate it.
+ FunctionDef fdef_to_load = fdef;
+ if (mutate_proto_func) {
+ (*mutate_proto_func)(&fdef_to_load);
+ }
+ VLOG(1) << "Adding func to graph: " << fdef_to_load.DebugString();
+ std::vector binary_proto_buf(fdef_to_load.ByteSizeLong());
+ fdef_to_load.SerializeToArray(binary_proto_buf.data(),
+ binary_proto_buf.size());
+ TF_Function* func = TF_FunctionImportFunctionDef(
+ binary_proto_buf.data(), binary_proto_buf.size(), status);
+ if (!status->status.ok()) return {};
+ ret.push_back(UniqueFuncPtr(func, TF_DeleteFunction));
+ }
+ return ret;
+}
+
+// On success, returns a newly created TF_Function instance encoding a dataset
+// node stack that returns a sequence of 3 floats, and sets `dataset_name` to
+// the created dataset name. The returned function must be deleted by calling
+// TF_DeleteFunction.
+static UniqueFuncPtr CreateFakeDatasetFunction(std::string* dataset_name,
+ TF_Status* status) {
+ const char* func_def = R"PREFIX(
+library {
+ function {
+ signature {
+ name: "_make_dataset_d8de2712"
+ output_arg {
+ name: "TensorSliceDataset"
+ type: DT_VARIANT
+ }
+ is_stateful: true
+ }
+ node_def {
+ name: "TensorSliceDataset/tensors/component_0"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\000\000(B\000\000,B\000\0000B"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "TensorSliceDataset"
+ op: "TensorSliceDataset"
+ input: "TensorSliceDataset/tensors/component_0:output:0"
+ attr {
+ key: "Toutput_types"
+ value {
+ list {
+ type: DT_FLOAT
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ }
+ ret {
+ key: "TensorSliceDataset"
+ value: "TensorSliceDataset:handle:0"
+ }
+ }
+}
+)PREFIX";
+
+ *dataset_name = "_make_dataset_d8de2712";
+ auto functions = CreateFunctionsFromTextProto(
+ func_def, /*mutate_proto_func*/ nullptr, status);
+ DCHECK_EQ(functions.size(), 1);
+ return std::move(functions[0]);
+}
+
+#if not defined(PLATFORM_WINDOWS)
+// On success, returns a set of TF_Function instances encoding a dataset
+// node stack that reads a Imagenet TFRecordFile dataset from `file_path`, and
+// sets `dataset_name` to the created dataset name. The returned functions must
+// be deleted by calling TF_DeleteFunction.
+static std::vector CreateImagenetDatasetFunctions(
+ const char* file_path, std::string* dataset_name, TF_Status* status) {
+#if defined(PLATFORM_WINDOWS)
+ status->status = tensorflow::errors::Unimplemented(
+ "TF_MakeFileBasedIteratorGetNextWithDatasets in the experimental C API "
+ "is not implemented for Windows");
+ return std::vector();
+#else
+ const char* func_def = R"PREFIX(
+library {
+ function {
+ signature {
+ name: "tf_map_func_91295dea"
+ input_arg {
+ name: "arg0"
+ type: DT_STRING
+ }
+ output_arg {
+ name: "FlatMapDataset"
+ type: DT_VARIANT
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ is_stateful: true
+ }
+ node_def {
+ name: "flat_filenames/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: -1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "flat_filenames"
+ op: "Reshape"
+ input: "arg0"
+ input: "flat_filenames/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "TensorSliceDataset"
+ op: "TensorSliceDataset"
+ input: "flat_filenames:output:0"
+ attr {
+ key: "Toutput_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FlatMapDataset"
+ op: "FlatMapDataset"
+ input: "TensorSliceDataset:handle:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ }
+ }
+ }
+ attr {
+ key: "f"
+ value {
+ func {
+ name: "tf_map_func_0cc8c35b"
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ }
+ ret {
+ key: "FlatMapDataset"
+ value: "FlatMapDataset:handle:0"
+ }
+ }
+ function {
+ signature {
+ name: "tf_map_func_0cc8c35b"
+ input_arg {
+ name: "arg0"
+ type: DT_STRING
+ }
+ output_arg {
+ name: "TFRecordDataset"
+ type: DT_VARIANT
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ is_stateful: true
+ }
+ node_def {
+ name: "compression_type"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: ""
+ }
+ }
+ }
+ }
+ node_def {
+ name: "buffer_size"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 8388608
+ }
+ }
+ }
+ }
+ node_def {
+ name: "TFRecordDataset"
+ op: "TFRecordDataset"
+ input: "arg0"
+ input: "compression_type:output:0"
+ input: "buffer_size:output:0"
+ }
+ ret {
+ key: "TFRecordDataset"
+ value: "TFRecordDataset:handle:0"
+ }
+ }
+ function {
+ signature {
+ name: "tf_map_func_74b6b15c"
+ input_arg {
+ name: "arg0"
+ type: DT_STRING
+ }
+ output_arg {
+ name: "Reshape_1"
+ type: DT_FLOAT
+ }
+ output_arg {
+ name: "sub_1"
+ type: DT_INT32
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ is_stateful: true
+ }
+ node_def {
+ name: "ParseSingleExample/key_image/class/label"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: -1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape"
+ op: "Reshape"
+ input: "ParseSingleExample/key_image/class/label:output:0"
+ input: "ParseSingleExample/Reshape/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/key_image/class/text"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: ""
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_1/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_1"
+ op: "Reshape"
+ input: "ParseSingleExample/key_image/class/text:output:0"
+ input: "ParseSingleExample/Reshape_1/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/key_image/encoded"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: ""
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_2/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_2"
+ op: "Reshape"
+ input: "ParseSingleExample/key_image/encoded:output:0"
+ input: "ParseSingleExample/Reshape_2/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/key_image/format"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "jpeg"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_3/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/Reshape_3"
+ op: "Reshape"
+ input: "ParseSingleExample/key_image/format:output:0"
+ input: "ParseSingleExample/Reshape_3/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "ParseSingleExample/ParseSingleExample"
+ op: "ParseSingleExample"
+ input: "arg0"
+ input: "ParseSingleExample/Reshape:output:0"
+ input: "ParseSingleExample/Reshape_1:output:0"
+ input: "ParseSingleExample/Reshape_2:output:0"
+ input: "ParseSingleExample/Reshape_3:output:0"
+ attr {
+ key: "Tdense"
+ value {
+ list {
+ type: DT_INT64
+ type: DT_STRING
+ type: DT_STRING
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "dense_keys"
+ value {
+ list {
+ s: "image/class/label"
+ s: "image/class/text"
+ s: "image/encoded"
+ s: "image/format"
+ }
+ }
+ }
+ attr {
+ key: "dense_shapes"
+ value {
+ list {
+ shape {
+ }
+ shape {
+ }
+ shape {
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "num_sparse"
+ value {
+ i: 5
+ }
+ }
+ attr {
+ key: "sparse_keys"
+ value {
+ list {
+ s: "image/object/bbox/xmax"
+ s: "image/object/bbox/xmin"
+ s: "image/object/bbox/ymax"
+ s: "image/object/bbox/ymin"
+ s: "image/object/class/label"
+ }
+ }
+ }
+ attr {
+ key: "sparse_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_FLOAT
+ type: DT_FLOAT
+ type: DT_FLOAT
+ type: DT_INT64
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape"
+ op: "Reshape"
+ input: "ParseSingleExample/ParseSingleExample:dense_values:2"
+ input: "Reshape/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/Substr/pos"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/Substr/len"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/Substr"
+ op: "Substr"
+ input: "Reshape:output:0"
+ input: "decode_image/Substr/pos:output:0"
+ input: "decode_image/Substr/len:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/is_jpeg/Substr/pos"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/is_jpeg/Substr/len"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/is_jpeg/Substr"
+ op: "Substr"
+ input: "Reshape:output:0"
+ input: "decode_image/is_jpeg/Substr/pos:output:0"
+ input: "decode_image/is_jpeg/Substr/len:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/is_jpeg/Equal/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "\377\330\377"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/is_jpeg/Equal"
+ op: "Equal"
+ input: "decode_image/is_jpeg/Substr:output:0"
+ input: "decode_image/is_jpeg/Equal/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/Switch"
+ op: "Switch"
+ input: "decode_image/is_jpeg/Equal:z:0"
+ input: "decode_image/is_jpeg/Equal:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/switch_t"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/switch_f"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/pred_id"
+ op: "Identity"
+ input: "decode_image/is_jpeg/Equal:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/check_jpeg_channels/x"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/check_jpeg_channels/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 4
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/check_jpeg_channels"
+ op: "NotEqual"
+ input: "decode_image/cond_jpeg/check_jpeg_channels/x:output:0"
+ input: "decode_image/cond_jpeg/check_jpeg_channels/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/Assert/Const"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 1, 3) when decoding JPEG images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/Assert/Assert/data_0"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 1, 3) when decoding JPEG images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/Assert/Assert"
+ op: "Assert"
+ input: "decode_image/cond_jpeg/check_jpeg_channels:z:0"
+ input: "decode_image/cond_jpeg/Assert/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/DecodeJpeg"
+ op: "DecodeJpeg"
+ input: "decode_image/cond_jpeg/DecodeJpeg/Switch:output_true:0"
+ input: "^decode_image/cond_jpeg/Assert/Assert"
+ attr {
+ key: "acceptable_fraction"
+ value {
+ f: 1.0
+ }
+ }
+ attr {
+ key: "channels"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "dct_method"
+ value {
+ s: ""
+ }
+ }
+ attr {
+ key: "fancy_upscaling"
+ value {
+ b: true
+ }
+ }
+ attr {
+ key: "ratio"
+ value {
+ i: 1
+ }
+ }
+ attr {
+ key: "try_recover_truncated"
+ value {
+ b: false
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/DecodeJpeg/Switch"
+ op: "Switch"
+ input: "Reshape:output:0"
+ input: "decode_image/cond_jpeg/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/is_png/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "\211PN"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/is_png"
+ op: "Equal"
+ input: "decode_image/cond_jpeg/is_png/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/is_png/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/is_png/Switch"
+ op: "Switch"
+ input: "decode_image/Substr:output:0"
+ input: "decode_image/cond_jpeg/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@decode_image/Substr"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/Switch"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/is_png:z:0"
+ input: "decode_image/cond_jpeg/is_png:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/switch_t"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/cond_png/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/switch_f"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/cond_png/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/pred_id"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/is_png:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/DecodePng"
+ op: "DecodePng"
+ input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch_1:output_true:0"
+ attr {
+ key: "channels"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "dtype"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/DecodePng/Switch"
+ op: "Switch"
+ input: "Reshape:output:0"
+ input: "decode_image/cond_jpeg/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/DecodePng/Switch_1"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/is_gif/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "GIF"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/is_gif"
+ op: "Equal"
+ input: "decode_image/cond_jpeg/cond_png/is_gif/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/is_gif/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/is_gif/Switch"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/is_png/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@decode_image/Substr"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Switch"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+ input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id"
+ op: "Identity"
+ input: "decode_image/cond_jpeg/cond_png/is_gif:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/x"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels"
+ op: "NotEqual"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/x:output:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/x"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 4
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1"
+ op: "NotEqual"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/x:output:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/LogicalAnd"
+ op: "LogicalAnd"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels:z:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_gif_channels_1:z:0"
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Const"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 3) when decoding GIF images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert/data_0"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 3) when decoding GIF images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert"
+ op: "Assert"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/LogicalAnd:z:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif"
+ op: "DecodeGif"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch_1:output_true:0"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert/Assert"
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/cond_png/DecodePng/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch_1"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/pos"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/len"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr"
+ op: "Substr"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/pos:output:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/len:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch"
+ op: "Switch"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif/Switch:output_false:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@Reshape"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "BM"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp"
+ op: "Equal"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr:output:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Const"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Unable to decode bytes as JPEG, PNG, GIF, or BMP"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert/data_0"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Unable to decode bytes as JPEG, PNG, GIF, or BMP"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert"
+ op: "Assert"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/is_bmp:z:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/x"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/y"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels"
+ op: "NotEqual"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/x:output:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Const"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 3) when decoding BMP images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert/data_0"
+ op: "Const"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Channels must be in (None, 0, 3) when decoding BMP images"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert"
+ op: "Assert"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/check_channels:z:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeBmp"
+ op: "DecodeBmp"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Substr/Switch:output_false:0"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert_1/Assert"
+ input: "^decode_image/cond_jpeg/cond_png/cond_gif/Assert_2/Assert"
+ attr {
+ key: "channels"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/cond_gif/Merge"
+ op: "Merge"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeBmp:image:0"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/DecodeGif:image:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/cond_png/Merge"
+ op: "Merge"
+ input: "decode_image/cond_jpeg/cond_png/cond_gif/Merge:output:0"
+ input: "decode_image/cond_jpeg/cond_png/DecodePng:image:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "decode_image/cond_jpeg/Merge"
+ op: "Merge"
+ input: "decode_image/cond_jpeg/cond_png/Merge:output:0"
+ input: "decode_image/cond_jpeg/DecodeJpeg:image:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "convert_image/Cast"
+ op: "Cast"
+ input: "decode_image/cond_jpeg/Merge:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "convert_image/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 0.00392156885937
+ }
+ }
+ }
+ }
+ node_def {
+ name: "convert_image"
+ op: "Mul"
+ input: "convert_image/Cast:y:0"
+ input: "convert_image/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "Const"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 4
+ }
+ }
+ tensor_content: "\000\000\000\000\000\000\000\000\000\000\200?\000\000\200?"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "distorted_bounding_box_crop/Shape"
+ op: "Shape"
+ input: "convert_image:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2/min_object_covered"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 0.10000000149
+ }
+ }
+ }
+ }
+ node_def {
+ name: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2"
+ op: "SampleDistortedBoundingBoxV2"
+ input: "distorted_bounding_box_crop/Shape:output:0"
+ input: "Const:output:0"
+ input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2/min_object_covered:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "area_range"
+ value {
+ list {
+ f: 0.0799999982119
+ f: 1.0
+ }
+ }
+ }
+ attr {
+ key: "aspect_ratio_range"
+ value {
+ list {
+ f: 0.75
+ f: 1.33333337307
+ }
+ }
+ }
+ attr {
+ key: "max_attempts"
+ value {
+ i: 1
+ }
+ }
+ attr {
+ key: "seed"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "seed2"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "use_image_if_no_bounding_boxes"
+ value {
+ b: true
+ }
+ }
+ }
+ node_def {
+ name: "distorted_bounding_box_crop/Slice"
+ op: "Slice"
+ input: "convert_image:z:0"
+ input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2:begin:0"
+ input: "distorted_bounding_box_crop/sample_distorted_bounding_box/SampleDistortedBoundingBoxV2:size:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "Shape"
+ op: "Shape"
+ input: "convert_image:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "Shape_1"
+ op: "Shape"
+ input: "distorted_bounding_box_crop/Slice:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "Equal"
+ op: "Equal"
+ input: "Shape:output:0"
+ input: "Shape_1:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "Cast"
+ op: "Cast"
+ input: "Equal:z:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "Const_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Sum"
+ op: "Sum"
+ input: "Cast:y:0"
+ input: "Const_1:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "keep_dims"
+ value {
+ b: false
+ }
+ }
+ }
+ node_def {
+ name: "GreaterEqual/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "GreaterEqual"
+ op: "GreaterEqual"
+ input: "Sum:output:0"
+ input: "GreaterEqual/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/Switch"
+ op: "Switch"
+ input: "GreaterEqual:z:0"
+ input: "GreaterEqual:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/switch_t"
+ op: "Identity"
+ input: "cond/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/switch_f"
+ op: "Identity"
+ input: "cond/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/pred_id"
+ op: "Identity"
+ input: "GreaterEqual:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/Shape"
+ op: "Shape"
+ input: "cond/Shape/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/Shape/Switch"
+ op: "Switch"
+ input: "convert_image:z:0"
+ input: "cond/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@convert_image"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Cast"
+ op: "Cast"
+ input: "cond/Shape:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice"
+ op: "StridedSlice"
+ input: "cond/Cast:y:0"
+ input: "cond/strided_slice/stack:output:0"
+ input: "cond/strided_slice/stack_1:output:0"
+ input: "cond/strided_slice/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_1/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_1/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_1/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_1"
+ op: "StridedSlice"
+ input: "cond/Cast:y:0"
+ input: "cond/strided_slice_1/stack:output:0"
+ input: "cond/strided_slice_1/stack_1:output:0"
+ input: "cond/strided_slice_1/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/Greater"
+ op: "Greater"
+ input: "cond/strided_slice:output:0"
+ input: "cond/strided_slice_1:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Switch"
+ op: "Switch"
+ input: "cond/Greater:z:0"
+ input: "cond/Greater:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/switch_t"
+ op: "Identity"
+ input: "cond/cond/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/switch_f"
+ op: "Identity"
+ input: "cond/cond/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/pred_id"
+ op: "Identity"
+ input: "cond/Greater:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice/stack"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice/stack_1"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice/stack_2"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice"
+ op: "StridedSlice"
+ input: "cond/cond/strided_slice/Switch:output_true:0"
+ input: "cond/cond/strided_slice/stack:output:0"
+ input: "cond/cond/strided_slice/stack_1:output:0"
+ input: "cond/cond/strided_slice/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice/Switch"
+ op: "Switch"
+ input: "cond/Cast:y:0"
+ input: "cond/cond/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@cond/Cast"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_1/stack"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_1/stack_1"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_1/stack_2"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_1"
+ op: "StridedSlice"
+ input: "cond/cond/strided_slice/Switch:output_true:0"
+ input: "cond/cond/strided_slice_1/stack:output:0"
+ input: "cond/cond/strided_slice_1/stack_1:output:0"
+ input: "cond/cond/strided_slice_1/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/truediv"
+ op: "RealDiv"
+ input: "cond/cond/strided_slice:output:0"
+ input: "cond/cond/strided_slice_1:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/mul/y"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 224.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/mul"
+ op: "Mul"
+ input: "cond/cond/truediv:z:0"
+ input: "cond/cond/mul/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast/x/1"
+ op: "Const"
+ input: "^cond/cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 224.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast/x"
+ op: "Pack"
+ input: "cond/cond/mul:z:0"
+ input: "cond/cond/Cast/x/1:output:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast"
+ op: "Cast"
+ input: "cond/cond/Cast/x:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_2/stack"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_2/stack_1"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_2/stack_2"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_2"
+ op: "StridedSlice"
+ input: "cond/cond/strided_slice_2/Switch:output_false:0"
+ input: "cond/cond/strided_slice_2/stack:output:0"
+ input: "cond/cond/strided_slice_2/stack_1:output:0"
+ input: "cond/cond/strided_slice_2/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_2/Switch"
+ op: "Switch"
+ input: "cond/Cast:y:0"
+ input: "cond/cond/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@cond/Cast"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_3/stack"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_3/stack_1"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_3/stack_2"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/strided_slice_3"
+ op: "StridedSlice"
+ input: "cond/cond/strided_slice_2/Switch:output_false:0"
+ input: "cond/cond/strided_slice_3/stack:output:0"
+ input: "cond/cond/strided_slice_3/stack_1:output:0"
+ input: "cond/cond/strided_slice_3/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/truediv_1"
+ op: "RealDiv"
+ input: "cond/cond/strided_slice_2:output:0"
+ input: "cond/cond/strided_slice_3:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/mul_1/y"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 224.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/mul_1"
+ op: "Mul"
+ input: "cond/cond/truediv_1:z:0"
+ input: "cond/cond/mul_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast_1/x/0"
+ op: "Const"
+ input: "^cond/cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 224.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast_1/x"
+ op: "Pack"
+ input: "cond/cond/Cast_1/x/0:output:0"
+ input: "cond/cond/mul_1:z:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Cast_1"
+ op: "Cast"
+ input: "cond/cond/Cast_1/x:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/cond/Merge"
+ op: "Merge"
+ input: "cond/cond/Cast_1:y:0"
+ input: "cond/cond/Cast:y:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic/images"
+ op: "Pack"
+ input: "cond/Shape/Switch:output_true:0"
+ attr {
+ key: "N"
+ value {
+ i: 1
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic"
+ op: "ResizeBicubic"
+ input: "cond/ResizeBicubic/images:output:0"
+ input: "cond/cond/Merge:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "align_corners"
+ value {
+ b: false
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_2/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_2/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_2/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_2"
+ op: "StridedSlice"
+ input: "cond/ResizeBicubic:resized_images:0"
+ input: "cond/strided_slice_2/stack:output:0"
+ input: "cond/strided_slice_2/stack_1:output:0"
+ input: "cond/strided_slice_2/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/Shape_1"
+ op: "Shape"
+ input: "cond/strided_slice_2:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_3/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_3/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_3/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_3"
+ op: "StridedSlice"
+ input: "cond/Shape_1:output:0"
+ input: "cond/strided_slice_3/stack:output:0"
+ input: "cond/strided_slice_3/stack_1:output:0"
+ input: "cond/strided_slice_3/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/Shape_2"
+ op: "Shape"
+ input: "cond/strided_slice_2:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_4/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_4/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_4/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_4"
+ op: "StridedSlice"
+ input: "cond/Shape_2:output:0"
+ input: "cond/strided_slice_4/stack:output:0"
+ input: "cond/strided_slice_4/stack_1:output:0"
+ input: "cond/strided_slice_4/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/sub/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/sub"
+ op: "Sub"
+ input: "cond/strided_slice_3:output:0"
+ input: "cond/sub/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/add/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/add"
+ op: "Add"
+ input: "cond/sub:z:0"
+ input: "cond/add/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv/Cast"
+ op: "Cast"
+ input: "cond/add:z:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv/Cast_1"
+ op: "Cast"
+ input: "cond/truediv/y:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv"
+ op: "RealDiv"
+ input: "cond/truediv/Cast:y:0"
+ input: "cond/truediv/Cast_1:y:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ }
+ node_def {
+ name: "cond/sub_1/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/sub_1"
+ op: "Sub"
+ input: "cond/strided_slice_4:output:0"
+ input: "cond/sub_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/add_1/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/add_1"
+ op: "Add"
+ input: "cond/sub_1:z:0"
+ input: "cond/add_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv_1/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv_1/Cast"
+ op: "Cast"
+ input: "cond/add_1:z:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv_1/Cast_1"
+ op: "Cast"
+ input: "cond/truediv_1/y:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/truediv_1"
+ op: "RealDiv"
+ input: "cond/truediv_1/Cast:y:0"
+ input: "cond/truediv_1/Cast_1:y:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ }
+ node_def {
+ name: "cond/Shape_3"
+ op: "Shape"
+ input: "cond/strided_slice_2:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/Rank"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Equal/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Equal"
+ op: "Equal"
+ input: "cond/Rank:output:0"
+ input: "cond/Equal/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/Assert/Const"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Rank of image must be equal to 3."
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Assert/Assert/data_0"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Rank of image must be equal to 3."
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Assert/Assert"
+ op: "Assert"
+ input: "cond/Equal:z:0"
+ input: "cond/Assert/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_5/stack"
+ op: "Const"
+ input: "^cond/Assert/Assert"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_5/stack_1"
+ op: "Const"
+ input: "^cond/Assert/Assert"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 3
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_5/stack_2"
+ op: "Const"
+ input: "^cond/Assert/Assert"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_5"
+ op: "StridedSlice"
+ input: "cond/Shape_3:output:0"
+ input: "cond/strided_slice_5/stack:output:0"
+ input: "cond/strided_slice_5/stack_1:output:0"
+ input: "cond/strided_slice_5/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/stack/0"
+ op: "Const"
+ input: "^cond/Assert/Assert"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/stack/1"
+ op: "Const"
+ input: "^cond/Assert/Assert"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/stack"
+ op: "Pack"
+ input: "cond/stack/0:output:0"
+ input: "cond/stack/1:output:0"
+ input: "cond/strided_slice_5:output:0"
+ attr {
+ key: "N"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_6/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_6/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_6/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_6"
+ op: "StridedSlice"
+ input: "cond/Shape_3:output:0"
+ input: "cond/strided_slice_6/stack:output:0"
+ input: "cond/strided_slice_6/stack_1:output:0"
+ input: "cond/strided_slice_6/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/GreaterEqual/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/GreaterEqual"
+ op: "GreaterEqual"
+ input: "cond/strided_slice_6:output:0"
+ input: "cond/GreaterEqual/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_7/stack"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_7/stack_1"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_7/stack_2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_7"
+ op: "StridedSlice"
+ input: "cond/Shape_3:output:0"
+ input: "cond/strided_slice_7/stack:output:0"
+ input: "cond/strided_slice_7/stack_1:output:0"
+ input: "cond/strided_slice_7/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/GreaterEqual_1/y"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 224
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/GreaterEqual_1"
+ op: "GreaterEqual"
+ input: "cond/strided_slice_7:output:0"
+ input: "cond/GreaterEqual_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/LogicalAnd"
+ op: "LogicalAnd"
+ input: "cond/GreaterEqual:z:0"
+ input: "cond/GreaterEqual_1:z:0"
+ }
+ node_def {
+ name: "cond/Assert_1/Const"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Crop size greater than the image size."
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Assert_1/Assert/data_0"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "Crop size greater than the image size."
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/Assert_1/Assert"
+ op: "Assert"
+ input: "cond/LogicalAnd:z:0"
+ input: "cond/Assert_1/Assert/data_0:output:0"
+ attr {
+ key: "T"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "summarize"
+ value {
+ i: 3
+ }
+ }
+ }
+ node_def {
+ name: "cond/stack_1/2"
+ op: "Const"
+ input: "^cond/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_DOUBLE
+ tensor_shape {
+ }
+ double_val: 0.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/stack_1"
+ op: "Pack"
+ input: "cond/truediv:z:0"
+ input: "cond/truediv_1:z:0"
+ input: "cond/stack_1/2:output:0"
+ attr {
+ key: "N"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/ToInt32"
+ op: "Cast"
+ input: "cond/stack_1:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_DOUBLE
+ }
+ }
+ }
+ node_def {
+ name: "cond/Slice"
+ op: "Slice"
+ input: "cond/strided_slice_2:output:0"
+ input: "cond/ToInt32:y:0"
+ input: "cond/stack:output:0"
+ input: "^cond/Assert_1/Assert"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "cond/Reshape"
+ op: "Reshape"
+ input: "cond/Slice:output:0"
+ input: "cond/stack:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic_1/images"
+ op: "Pack"
+ input: "cond/ResizeBicubic_1/images/Switch:output_false:0"
+ attr {
+ key: "N"
+ value {
+ i: 1
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic_1/images/Switch"
+ op: "Switch"
+ input: "distorted_bounding_box_crop/Slice:output:0"
+ input: "cond/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@distorted_bounding_box_crop/Slice"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic_1/size"
+ op: "Const"
+ input: "^cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ }
+ tensor_content: "\340\000\000\000\340\000\000\000"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/ResizeBicubic_1"
+ op: "ResizeBicubic"
+ input: "cond/ResizeBicubic_1/images:output:0"
+ input: "cond/ResizeBicubic_1/size:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "align_corners"
+ value {
+ b: false
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_8/stack"
+ op: "Const"
+ input: "^cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_8/stack_1"
+ op: "Const"
+ input: "^cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_8/stack_2"
+ op: "Const"
+ input: "^cond/switch_f"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "cond/strided_slice_8"
+ op: "StridedSlice"
+ input: "cond/ResizeBicubic_1:resized_images:0"
+ input: "cond/strided_slice_8/stack:output:0"
+ input: "cond/strided_slice_8/stack_1:output:0"
+ input: "cond/strided_slice_8/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "cond/Merge"
+ op: "Merge"
+ input: "cond/strided_slice_8:output:0"
+ input: "cond/Reshape:output:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "Const_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\354Q\370>\325x\351>;\337\317>"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "sub"
+ op: "Sub"
+ input: "cond/Merge:output:0"
+ input: "Const_2:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "Const_3"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\372~j>B`e>fff>"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "truediv"
+ op: "RealDiv"
+ input: "sub:z:0"
+ input: "Const_3:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/control_dependency"
+ op: "Identity"
+ input: "truediv:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@truediv"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/min"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 0.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/max"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 1.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/RandomUniform"
+ op: "RandomUniform"
+ input: "random_flip_left_right/random_uniform/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "seed"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "seed2"
+ value {
+ i: 0
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/sub"
+ op: "Sub"
+ input: "random_flip_left_right/random_uniform/max:output:0"
+ input: "random_flip_left_right/random_uniform/min:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform/mul"
+ op: "Mul"
+ input: "random_flip_left_right/random_uniform/RandomUniform:output:0"
+ input: "random_flip_left_right/random_uniform/sub:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/random_uniform"
+ op: "Add"
+ input: "random_flip_left_right/random_uniform/mul:z:0"
+ input: "random_flip_left_right/random_uniform/min:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/Less/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 0.5
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/Less"
+ op: "Less"
+ input: "random_flip_left_right/random_uniform:z:0"
+ input: "random_flip_left_right/Less/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/Switch"
+ op: "Switch"
+ input: "random_flip_left_right/Less:z:0"
+ input: "random_flip_left_right/Less:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/switch_t"
+ op: "Identity"
+ input: "random_flip_left_right/Switch:output_true:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/switch_f"
+ op: "Identity"
+ input: "random_flip_left_right/Switch:output_false:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/pred_id"
+ op: "Identity"
+ input: "random_flip_left_right/Less:z:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_BOOL
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/ReverseV2/axis"
+ op: "Const"
+ input: "^random_flip_left_right/switch_t"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/ReverseV2"
+ op: "ReverseV2"
+ input: "random_flip_left_right/ReverseV2/Switch:output_true:0"
+ input: "random_flip_left_right/ReverseV2/axis:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/ReverseV2/Switch"
+ op: "Switch"
+ input: "random_flip_left_right/control_dependency:output:0"
+ input: "random_flip_left_right/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@truediv"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/Switch_1"
+ op: "Switch"
+ input: "random_flip_left_right/control_dependency:output:0"
+ input: "random_flip_left_right/pred_id:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "_class"
+ value {
+ list {
+ s: "loc:@truediv"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "random_flip_left_right/Merge"
+ op: "Merge"
+ input: "random_flip_left_right/Switch_1:output_false:0"
+ input: "random_flip_left_right/ReverseV2:output:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ node_def {
+ name: "Reshape_1/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\340\000\000\000\340\000\000\000\003\000\000\000"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape_1"
+ op: "Reshape"
+ input: "random_flip_left_right/Merge:output:0"
+ input: "Reshape_1/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "Reshape_2/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape_2"
+ op: "Reshape"
+ input: "ParseSingleExample/ParseSingleExample:dense_values:0"
+ input: "Reshape_2/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "Cast_1"
+ op: "Cast"
+ input: "Reshape_2:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ node_def {
+ name: "sub_1/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "sub_1"
+ op: "Sub"
+ input: "Cast_1:y:0"
+ input: "sub_1/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ ret {
+ key: "Reshape_1"
+ value: "Reshape_1:output:0"
+ }
+ ret {
+ key: "sub_1"
+ value: "sub_1:z:0"
+ }
+ }
+ function {
+ signature {
+ name: "tf_predicate_7089b845"
+ input_arg {
+ name: "arg0"
+ type: DT_FLOAT
+ }
+ input_arg {
+ name: "arg1"
+ type: DT_INT32
+ }
+ input_arg {
+ name: "Equal/Placeholder"
+ type: DT_INT64
+ }
+ output_arg {
+ name: "Equal"
+ type: DT_BOOL
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ }
+ node_def {
+ name: "Shape"
+ op: "Shape"
+ input: "arg0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice"
+ op: "StridedSlice"
+ input: "Shape:output:0"
+ input: "strided_slice/stack:output:0"
+ input: "strided_slice/stack_1:output:0"
+ input: "strided_slice/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "Equal"
+ op: "Equal"
+ input: "strided_slice:output:0"
+ input: "Equal/Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ ret {
+ key: "Equal"
+ value: "Equal:z:0"
+ }
+ }
+ function {
+ signature {
+ name: "_make_dataset_5fa5e1f4"
+ output_arg {
+ name: "PrefetchDataset_1"
+ type: DT_VARIANT
+ }
+ is_stateful: true
+ }
+ node_def {
+ name: "TensorSliceDataset/MatchingFiles/pattern"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "$(DATA_DIR)"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "TensorSliceDataset/MatchingFiles"
+ op: "MatchingFiles"
+ input: "TensorSliceDataset/MatchingFiles/pattern:output:0"
+ }
+ node_def {
+ name: "TensorSliceDataset"
+ op: "TensorSliceDataset"
+ input: "TensorSliceDataset/MatchingFiles:filenames:0"
+ attr {
+ key: "Toutput_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/MatchingFiles/pattern"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "$(DATA_DIR)"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/MatchingFiles"
+ op: "MatchingFiles"
+ input: "ShuffleDataset/MatchingFiles/pattern:output:0"
+ }
+ node_def {
+ name: "ShuffleDataset/Shape"
+ op: "Shape"
+ input: "ShuffleDataset/MatchingFiles:filenames:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/strided_slice/stack"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/strided_slice/stack_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/strided_slice/stack_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/strided_slice"
+ op: "StridedSlice"
+ input: "ShuffleDataset/Shape:output:0"
+ input: "ShuffleDataset/strided_slice/stack:output:0"
+ input: "ShuffleDataset/strided_slice/stack_1:output:0"
+ input: "ShuffleDataset/strided_slice/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/Maximum/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/Maximum"
+ op: "Maximum"
+ input: "ShuffleDataset/strided_slice:output:0"
+ input: "ShuffleDataset/Maximum/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/seed"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/seed2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset"
+ op: "ShuffleDataset"
+ input: "TensorSliceDataset:handle:0"
+ input: "ShuffleDataset/Maximum:z:0"
+ input: "ShuffleDataset/seed:output:0"
+ input: "ShuffleDataset/seed2:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "reshuffle_each_iteration"
+ value {
+ b: true
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_1/buffer_size"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 1024
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_1/seed_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_1/seed2_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_1"
+ op: "ShuffleDataset"
+ input: "ShuffleDataset:handle:0"
+ input: "ShuffleDataset_1/buffer_size:output:0"
+ input: "ShuffleDataset_1/seed_1:output:0"
+ input: "ShuffleDataset_1/seed2_1:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "reshuffle_each_iteration"
+ value {
+ b: true
+ }
+ }
+ }
+ node_def {
+ name: "RepeatDataset/count"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: -1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "RepeatDataset"
+ op: "RepeatDataset"
+ input: "ShuffleDataset_1:handle:0"
+ input: "RepeatDataset/count:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset/cycle_length"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 8
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset/block_length"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset/sloppy"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_BOOL
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_BOOL
+ tensor_shape {
+ }
+ bool_val: true
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset/buffer_output_elements"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset/prefetch_input_elements"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 16
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelInterleaveDataset"
+ op: "ParallelInterleaveDataset"
+ input: "RepeatDataset:handle:0"
+ input: "ParallelInterleaveDataset/cycle_length:output:0"
+ input: "ParallelInterleaveDataset/block_length:output:0"
+ input: "ParallelInterleaveDataset/sloppy:output:0"
+ input: "ParallelInterleaveDataset/buffer_output_elements:output:0"
+ input: "ParallelInterleaveDataset/prefetch_input_elements:output:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ }
+ }
+ }
+ attr {
+ key: "f"
+ value {
+ func {
+ name: "tf_map_func_91295dea"
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_2/buffer_size_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 1024
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_2/seed_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_2/seed2_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset_2"
+ op: "ShuffleDataset"
+ input: "ParallelInterleaveDataset:handle:0"
+ input: "ShuffleDataset_2/buffer_size_1:output:0"
+ input: "ShuffleDataset_2/seed_2:output:0"
+ input: "ShuffleDataset_2/seed2_2:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_STRING
+ }
+ }
+ }
+ attr {
+ key: "reshuffle_each_iteration"
+ value {
+ b: true
+ }
+ }
+ }
+ node_def {
+ name: "ParallelMapDataset/num_parallel_calls"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 64
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ParallelMapDataset"
+ op: "ParallelMapDataset"
+ input: "ShuffleDataset_2:handle:0"
+ input: "ParallelMapDataset/num_parallel_calls:output:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ }
+ }
+ }
+ attr {
+ key: "f"
+ value {
+ func {
+ name: "tf_map_func_74b6b15c"
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 224
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 3
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "PrefetchDataset/buffer_size_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 64
+ }
+ }
+ }
+ }
+ node_def {
+ name: "PrefetchDataset"
+ op: "PrefetchDataset"
+ input: "ParallelMapDataset:handle:0"
+ input: "PrefetchDataset/buffer_size_2:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 224
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 3
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "BatchDataset/batch_size"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 64
+ }
+ }
+ }
+ }
+ node_def {
+ name: "BatchDataset"
+ op: "BatchDataset"
+ input: "PrefetchDataset:handle:0"
+ input: "BatchDataset/batch_size:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: -1
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 3
+ }
+ }
+ shape {
+ dim {
+ size: -1
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FilterDataset/batch_size_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 64
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FilterDataset"
+ op: "FilterDataset"
+ input: "BatchDataset:handle:0"
+ input: "FilterDataset/batch_size_1:output:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ type: DT_INT64
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: -1
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 3
+ }
+ }
+ shape {
+ dim {
+ size: -1
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ attr {
+ key: "predicate"
+ value {
+ func {
+ name: "tf_predicate_7089b845"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "PrefetchDataset_1/buffer_size_3"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 2
+ }
+ }
+ }
+ }
+ node_def {
+ name: "PrefetchDataset_1"
+ op: "PrefetchDataset"
+ input: "FilterDataset:handle:0"
+ input: "PrefetchDataset_1/buffer_size_3:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 64
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 224
+ }
+ dim {
+ size: 3
+ }
+ }
+ shape {
+ dim {
+ size: 64
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ ret {
+ key: "PrefetchDataset_1"
+ value: "PrefetchDataset_1:handle:0"
+ }
+ }
+}
+)PREFIX";
+
+ *dataset_name = "_make_dataset_5fa5e1f4";
+ std::function mutate_proto_func =
+ [dataset_name, file_path](FunctionDef* fdef) {
+ VLOG(1) << "Processsing function " << fdef->DebugString();
+ if (std::string(fdef->signature().name()) != *dataset_name) return;
+ // Change the input file pattern to `file_path`.
+ bool found = false;
+ for (auto& node_def : *fdef->mutable_node_def()) {
+ if (node_def.name() != "TensorSliceDataset/MatchingFiles/pattern" &&
+ node_def.name() != "ShuffleDataset/MatchingFiles/pattern")
+ continue;
+ DCHECK_EQ(node_def.op(), "Const");
+ DCHECK_GT(node_def.attr().count("value"), 0);
+ found = true;
+ DCHECK_EQ(node_def.attr().at("value").tensor().string_val(0),
+ "$(DATA_DIR)");
+ VLOG(1) << "Setting the value of node_def "
+ "TensorSliceDataset/MatchingFiles/pattern to "
+ << file_path;
+ auto* tensor = (*node_def.mutable_attr())["value"].mutable_tensor();
+ tensor->clear_string_val();
+ tensor->add_string_val(file_path);
+ }
+ VLOG(1) << "Rewrote function to " << fdef->DebugString();
+ DCHECK(found);
+ };
+ return CreateFunctionsFromTextProto(func_def, &mutate_proto_func, status);
+#endif
+}
+#endif
+
+#if not defined(PLATFORM_WINDOWS)
+// On success, returns a set of TF_Function instances encoding a dataset
+// node stack that reads an MNIST file dataset from `file_path`, and
+// sets `dataset_name` to the created dataset name. The returned functions must
+// be deleted by calling TF_DeleteFunction.
+static std::vector CreateMNISTDatasetFunctions(
+ const char* file_path, int batch_size, std::string* dataset_name,
+ TF_Status* status) {
+#if defined(PLATFORM_WINDOWS)
+ status->status = tensorflow::errors::Unimplemented(
+ "TF_MakeFileBasedIteratorGetNextWithDatasets in the experimental C API "
+ "is not implemented for Windows");
+ return nullptr;
+#else
+ const char* func_def = R"PREFIX(
+library {
+ function {
+ signature {
+ name: "tf_map_func_521bfd08"
+ input_arg {
+ name: "arg0"
+ type: DT_STRING
+ }
+ output_arg {
+ name: "truediv"
+ type: DT_FLOAT
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ }
+ node_def {
+ name: "DecodeRaw"
+ op: "DecodeRaw"
+ input: "arg0"
+ attr {
+ key: "little_endian"
+ value {
+ b: true
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "Cast"
+ op: "Cast"
+ input: "DecodeRaw:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "Reshape/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 784
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape"
+ op: "Reshape"
+ input: "Cast:y:0"
+ input: "Reshape/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "truediv/y"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ }
+ float_val: 255.0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "truediv"
+ op: "RealDiv"
+ input: "Reshape:output:0"
+ input: "truediv/y:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ }
+ ret {
+ key: "truediv"
+ value: "truediv:z:0"
+ }
+ }
+ function {
+ signature {
+ name: "tf_map_func_9a08860d"
+ input_arg {
+ name: "arg0"
+ type: DT_STRING
+ }
+ output_arg {
+ name: "ToInt32"
+ type: DT_INT32
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ }
+ node_def {
+ name: "DecodeRaw"
+ op: "DecodeRaw"
+ input: "arg0"
+ attr {
+ key: "little_endian"
+ value {
+ b: true
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ node_def {
+ name: "Reshape/shape"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ }
+ }
+ }
+ }
+ }
+ }
+ node_def {
+ name: "Reshape"
+ op: "Reshape"
+ input: "DecodeRaw:output:0"
+ input: "Reshape/shape:output:0"
+ attr {
+ key: "T"
+ value {
+ type: DT_UINT8
+ }
+ }
+ attr {
+ key: "Tshape"
+ value {
+ type: DT_INT32
+ }
+ }
+ }
+ node_def {
+ name: "ToInt32"
+ op: "Cast"
+ input: "Reshape:output:0"
+ attr {
+ key: "DstT"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "SrcT"
+ value {
+ type: DT_UINT8
+ }
+ }
+ }
+ ret {
+ key: "ToInt32"
+ value: "ToInt32:y:0"
+ }
+ }
+ function {
+ signature {
+ name: "tf_predicate_7089b845"
+ input_arg {
+ name: "arg0"
+ type: DT_FLOAT
+ }
+ input_arg {
+ name: "arg1"
+ type: DT_INT32
+ }
+ input_arg {
+ name: "Equal/Placeholder"
+ type: DT_INT64
+ }
+ output_arg {
+ name: "Equal"
+ type: DT_BOOL
+ }
+ description: "A wrapper for Defun that facilitates shape inference."
+ }
+ node_def {
+ name: "Shape"
+ op: "Shape"
+ input: "arg0"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "out_type"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice/stack_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 1
+ }
+ }
+ int_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "strided_slice"
+ op: "StridedSlice"
+ input: "Shape:output:0"
+ input: "strided_slice/stack:output:0"
+ input: "strided_slice/stack_1:output:0"
+ input: "strided_slice/stack_2:output:0"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+ }
+ node_def {
+ name: "Equal"
+ op: "Equal"
+ input: "strided_slice:output:0"
+ input: "Equal/Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_INT64
+ }
+ }
+ }
+ ret {
+ key: "Equal"
+ value: "Equal:z:0"
+ }
+ }
+ function {
+ signature {
+ name: "_make_dataset_2451e43a"
+ output_arg {
+ name: "FilterDataset"
+ type: DT_VARIANT
+ }
+ is_stateful: true
+ }
+ node_def {
+ name: "FixedLengthRecordDataset/filenames"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "$(DATA_DIR)/train-images-idx3-ubyte"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset/header_bytes"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 16
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset/record_bytes"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 784
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset/footer_bytes"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset/buffer_size"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 262144
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset"
+ op: "FixedLengthRecordDataset"
+ input: "FixedLengthRecordDataset/filenames:output:0"
+ input: "FixedLengthRecordDataset/header_bytes:output:0"
+ input: "FixedLengthRecordDataset/record_bytes:output:0"
+ input: "FixedLengthRecordDataset/footer_bytes:output:0"
+ input: "FixedLengthRecordDataset/buffer_size:output:0"
+ }
+ node_def {
+ name: "MapDataset"
+ op: "MapDataset"
+ input: "FixedLengthRecordDataset:handle:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ }
+ }
+ }
+ attr {
+ key: "f"
+ value {
+ func {
+ name: "tf_map_func_521bfd08"
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 784
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1/filenames_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: "$(DATA_DIR)/train-labels-idx1-ubyte"
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1/header_bytes_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 8
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1/record_bytes_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1/footer_bytes_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1/buffer_size_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 262144
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FixedLengthRecordDataset_1"
+ op: "FixedLengthRecordDataset"
+ input: "FixedLengthRecordDataset_1/filenames_1:output:0"
+ input: "FixedLengthRecordDataset_1/header_bytes_1:output:0"
+ input: "FixedLengthRecordDataset_1/record_bytes_1:output:0"
+ input: "FixedLengthRecordDataset_1/footer_bytes_1:output:0"
+ input: "FixedLengthRecordDataset_1/buffer_size_1:output:0"
+ }
+ node_def {
+ name: "MapDataset_1"
+ op: "MapDataset"
+ input: "FixedLengthRecordDataset_1:handle:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ }
+ }
+ }
+ attr {
+ key: "f"
+ value {
+ func {
+ name: "tf_map_func_9a08860d"
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ZipDataset"
+ op: "ZipDataset"
+ input: "MapDataset:handle:0"
+ input: "MapDataset_1:handle:0"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "CacheDataset/filename"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_STRING
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_STRING
+ tensor_shape {
+ }
+ string_val: ""
+ }
+ }
+ }
+ }
+ node_def {
+ name: "CacheDataset"
+ op: "CacheDataset"
+ input: "ZipDataset:handle:0"
+ input: "CacheDataset/filename:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "RepeatDataset/count"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: -1
+ }
+ }
+ }
+ }
+ node_def {
+ name: "RepeatDataset"
+ op: "RepeatDataset"
+ input: "CacheDataset:handle:0"
+ input: "RepeatDataset/count:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/buffer_size_2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 50000
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/seed"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset/seed2"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: 0
+ }
+ }
+ }
+ }
+ node_def {
+ name: "ShuffleDataset"
+ op: "ShuffleDataset"
+ input: "RepeatDataset:handle:0"
+ input: "ShuffleDataset/buffer_size_2:output:0"
+ input: "ShuffleDataset/seed:output:0"
+ input: "ShuffleDataset/seed2:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ attr {
+ key: "reshuffle_each_iteration"
+ value {
+ b: true
+ }
+ }
+ }
+ node_def {
+ name: "BatchDataset/batch_size"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: -123
+ }
+ }
+ }
+ }
+ node_def {
+ name: "BatchDataset"
+ op: "BatchDataset"
+ input: "ShuffleDataset:handle:0"
+ input: "BatchDataset/batch_size:output:0"
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: -1
+ }
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ dim {
+ size: -1
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FilterDataset/batch_size_1"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT64
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT64
+ tensor_shape {
+ }
+ int64_val: -123
+ }
+ }
+ }
+ }
+ node_def {
+ name: "FilterDataset"
+ op: "FilterDataset"
+ input: "BatchDataset:handle:0"
+ input: "FilterDataset/batch_size_1:output:0"
+ attr {
+ key: "Targuments"
+ value {
+ list {
+ type: DT_INT64
+ }
+ }
+ }
+ attr {
+ key: "output_shapes"
+ value {
+ list {
+ shape {
+ dim {
+ size: -1
+ }
+ dim {
+ size: 784
+ }
+ }
+ shape {
+ dim {
+ size: -1
+ }
+ }
+ }
+ }
+ }
+ attr {
+ key: "output_types"
+ value {
+ list {
+ type: DT_FLOAT
+ type: DT_INT32
+ }
+ }
+ }
+ attr {
+ key: "predicate"
+ value {
+ func {
+ name: "tf_predicate_7089b845"
+ }
+ }
+ }
+ }
+ ret {
+ key: "FilterDataset"
+ value: "FilterDataset:handle:0"
+ }
+ }
+}
+)PREFIX";
+
+ *dataset_name = "_make_dataset_2451e43a";
+ std::function mutate_proto_func =
+ [dataset_name, file_path, batch_size](FunctionDef* fdef) {
+ VLOG(1) << "Processsing function " << fdef->DebugString();
+ if (std::string(fdef->signature().name()) != *dataset_name) return;
+ // Change the input file pattern to `file_path`.
+ bool found_file_path = false, found_batch_size = false;
+ // `node_def` may be mutated.
+ for (auto& node_def : *fdef->mutable_node_def()) {
+ if (node_def.name() == "FixedLengthRecordDataset/filenames" ||
+ node_def.name() == "FixedLengthRecordDataset_1/filenames_1") {
+ DCHECK_EQ(node_def.op(), "Const");
+ DCHECK_GT(node_def.attr().count("value"), 0);
+ found_file_path = true;
+ // Replace $(DATA_DIR)/foo with /foo
+ // TODO(hongm): Use StringPiece manipulation for better efficiency.
+ const std::string cur_value =
+ node_def.attr().at("value").tensor().string_val(0);
+ const std::string pattern = "$(DATA_DIR)";
+ DCHECK_EQ(cur_value.compare(0, pattern.length(), pattern), 0);
+ const std::string new_value =
+ file_path + cur_value.substr(pattern.length());
+ VLOG(1) << "Setting the value of node_def " << node_def.name()
+ << " to " << new_value;
+ auto* tensor = (*node_def.mutable_attr())["value"].mutable_tensor();
+ tensor->clear_string_val();
+ tensor->add_string_val(new_value);
+ } else if (node_def.name() == "BatchDataset/batch_size" ||
+ node_def.name() == "FilterDataset/batch_size_1") {
+ DCHECK_EQ(node_def.op(), "Const");
+ DCHECK_GT(node_def.attr().count("value"), 0);
+ found_batch_size = true;
+ // Replace $(BATCH_SIZE) with `batch_size`
+ DCHECK_EQ(node_def.attr().at("value").tensor().int64_val(0), -123);
+ VLOG(1) << "Setting the batch size attr value of node_def "
+ << node_def.name() << " to " << batch_size;
+ auto* tensor = (*node_def.mutable_attr())["value"].mutable_tensor();
+ tensor->clear_int64_val();
+ tensor->add_int64_val(batch_size);
+ }
+ }
+ VLOG(1) << "Rewrote function to " << fdef->DebugString();
+ DCHECK(found_file_path);
+ DCHECK(found_batch_size);
+ };
+ return CreateFunctionsFromTextProto(func_def, &mutate_proto_func, status);
+#endif
+}
+#endif
+
+// Adds the input functions to `graph`. On success, returns the created
+// IteratorGetNext node.
+static TF_Operation* AddDatasetFunctionAndIteratorNodesToGraph(
+ const std::vector& funcs, const std::string& dataset_name,
+ const std::vector& output_types,
+ const std::vector& output_shapes,
+ TF_Graph* graph, TF_Status* status) {
+ DCHECK(!dataset_name.empty());
+ for (auto& func : funcs) {
+ TF_GraphCopyFunction(graph, func.get(), /*gradient*/ nullptr, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ }
+
+ tensorflow::mutex_lock c(graph->mu);
+
+ tensorflow::NameAttrList func;
+ func.set_name(dataset_name);
+ // Run the iterator node on CPU.
+ Node* oneshot_iterator_node;
+ tensorflow::Status s = NodeBuilder("OneShotIterator", "OneShotIterator")
+ .Device("/device:CPU:0")
+ .Attr("container", "")
+ .Attr("dataset_factory", func)
+ .Attr("output_types", output_types)
+ .Attr("output_shapes", output_shapes)
+ .Attr("shared_name", "")
+ .Finalize(&graph->graph, &oneshot_iterator_node);
+ if (!s.ok()) {
+ status->status = s;
+ return nullptr;
+ }
+ // Run shape inference function for each newly added node, so that more
+ // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
+ s = graph->refiner.AddNode(oneshot_iterator_node);
+ if (!s.ok()) {
+ status->status = s;
+ return nullptr;
+ }
+
+ // Run the iterator node on CPU.
+ Node* getnext_node;
+ s = NodeBuilder("IteratorGetNext", "IteratorGetNext")
+ .Input(oneshot_iterator_node)
+ .Device("/device:CPU:0")
+ .Attr("output_types", output_types)
+ .Attr("output_shapes", output_shapes)
+ .Finalize(&graph->graph, &getnext_node);
+ if (!s.ok()) {
+ status->status = s;
+ return nullptr;
+ }
+ // Run shape inference function for each newly added node, so that more
+ // subsequent nodes can be added to the graph via C API (TF_NewOperation()).
+ s = graph->refiner.AddNode(getnext_node);
+ if (!s.ok()) {
+ status->status = s;
+ return nullptr;
+ }
+
+ VLOG(1) << "Output graph: " << graph->graph.ToGraphDefDebug().DebugString();
+ return ToTF_Operation(getnext_node);
+}
+
+TF_Operation* TF_MakeFakeIteratorGetNextWithDatasets(TF_Graph* graph,
+ TF_Status* status) {
+ tensorflow::Status s;
+
+ std::string dataset_name;
+ UniqueFuncPtr result_func = CreateFakeDatasetFunction(&dataset_name, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ std::vector funcs;
+ funcs.push_back(std::move(result_func));
+ std::vector output_shape_list;
+ output_shape_list.push_back(tensorflow::TensorShapeProto());
+ auto* getnext_node = AddDatasetFunctionAndIteratorNodesToGraph(
+ funcs, dataset_name, {tensorflow::DT_FLOAT}, output_shape_list, graph,
+ status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ return getnext_node;
+}
+
+TF_Operation* TF_MakeFileBasedIteratorGetNextWithDatasets(
+ TF_Graph* graph, const char* file_path, int batch_size,
+ unsigned char is_mnist, TF_Status* status) {
+#if defined(PLATFORM_WINDOWS)
+ // TODO(ashankar): get these functions working on Windows.
+ status->status = tensorflow::errors::Unimplemented(
+ "TF_MakeFileBasedIteratorGetNextWithDatasets in the experimental C API "
+ "is not implemented for Windows");
+ return nullptr;
+#else
+ tensorflow::Status s;
+
+ std::string dataset_name;
+ const auto& funcs =
+ is_mnist
+ ? CreateMNISTDatasetFunctions(file_path, batch_size, &dataset_name,
+ status)
+ : CreateImagenetDatasetFunctions(file_path, &dataset_name, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ std::vector output_shape_list;
+ // batch_size X 224 X 224 X 3
+ auto image_shape = tensorflow::TensorShapeProto();
+ image_shape.add_dim()->set_size(batch_size);
+ if (is_mnist) {
+ image_shape.add_dim()->set_size(784);
+ } else {
+ image_shape.add_dim()->set_size(224);
+ image_shape.add_dim()->set_size(224);
+ image_shape.add_dim()->set_size(3);
+ }
+ output_shape_list.push_back(image_shape);
+
+ // batch_size
+ auto label_shape = tensorflow::TensorShapeProto();
+ label_shape.add_dim()->set_size(batch_size);
+ output_shape_list.push_back(label_shape);
+ auto* getnext_node = AddDatasetFunctionAndIteratorNodesToGraph(
+ funcs, dataset_name, {tensorflow::DT_FLOAT, tensorflow::DT_INT32},
+ output_shape_list, graph, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ tensorflow::mutex_lock c(graph->mu);
+ VLOG(1) << "The extended graph: "
+ << graph->graph.ToGraphDefDebug().DebugString();
+
+ return getnext_node;
+#endif
+}
+
+TF_Tensor* TF_DequeueNamedTensor(TF_Session* session, int tensor_id,
+ TF_Status* status) {
+ assert(session);
+ {
+ tensorflow::mutex_lock c(session->graph->mu);
+ VLOG(1) << "Dequeuing named tensor with id " << tensor_id
+ << ", with input graph: "
+ << session->graph->graph.ToGraphDefDebug().DebugString();
+ }
+
+ TF_Operation* dequeue_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("fifo_queue_dequeue_", tensor_id).c_str());
+ if (dequeue_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the dequeue node in the TF graph.");
+ return nullptr;
+ }
+
+ VLOG(1) << "Running the dequeue op";
+ TF_Output output{dequeue_op, 0};
+ TF_Tensor* ret;
+ TF_SessionRun(session, /*run_options*/ nullptr,
+ // input related parameters
+ /*inputs*/ nullptr, /*input_values*/ nullptr, /*ninputs*/ 0,
+ // output related parameters
+ /*outputs*/ &output, /*output_values*/ &ret,
+ /*noutputs*/ 1,
+ /*targets*/ nullptr, /*ntargets*/ 0,
+ /*run_metadata*/ nullptr, status);
+ if (VLOG_IS_ON(1) && status->status.ok()) {
+ tensorflow::Tensor tensor;
+ if (tensorflow::TF_TensorToTensor(ret, &tensor).ok()) {
+ VLOG(1) << "Dequeued tensor content: " << tensor.DebugString();
+ }
+ }
+ return ret;
+}
+
+void TF_EnqueueNamedTensor(TF_Session* session, int tensor_id,
+ TF_Tensor* tensor, TF_Status* status) {
+ assert(session);
+ {
+ tensorflow::mutex_lock c(session->graph->mu);
+ if (VLOG_IS_ON(1)) {
+ VLOG(1) << "Enqueuing named tensor with id " << tensor_id
+ << ", with input graph: "
+ << session->graph->graph.ToGraphDefDebug().DebugString();
+ tensorflow::Tensor internal_tensor;
+ if (tensorflow::TF_TensorToTensor(tensor, &internal_tensor).ok()) {
+ VLOG(1) << "Enqueu'ing tensor content: "
+ << internal_tensor.DebugString();
+ }
+ }
+ }
+
+ TF_Operation* enqueue_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("fifo_queue_enqueue_", tensor_id).c_str());
+ if (enqueue_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the enqueue node in the TF graph.");
+ return;
+ }
+
+ TF_Operation* placeholder_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("arg_tensor_enqueue_", tensor_id).c_str());
+ if (placeholder_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the placeholder node as input to enqueue in the TF "
+ "graph.");
+ return;
+ }
+
+ VLOG(1) << "Running the enqueue op";
+ TF_Output input{placeholder_op, 0};
+ TF_SessionRun(session, /*run_options*/ nullptr,
+ // input related parameters
+ /*inputs*/ &input, /*input_values*/ &tensor, /*ninputs*/ 1,
+ // output related parameters
+ /*outputs*/ nullptr, /*output_values*/ nullptr, /*noutputs*/ 0,
+ /*targets*/ &enqueue_op, /*ntargets*/ 1,
+ /*run_metadata*/ nullptr, status);
+ VLOG(1) << "Enqueuing is done.";
+}
diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h
index 5a7b007e40aa199889b2d00b2bde5976c19e2966..20bdace40f1272ded06e710034053a7610326e7f 100644
--- a/tensorflow/c/c_api_experimental.h
+++ b/tensorflow/c/c_api_experimental.h
@@ -25,6 +25,7 @@ limitations under the License.
// Experimental C API for TensorFlow.
//
// The API here is subject to changes in the future.
+// --------------------------------------------------------------------------
// Macro to control visibility of exported symbols in the shared library (.so,
// .dylib, .dll).
@@ -34,7 +35,7 @@ limitations under the License.
#ifdef SWIG
#define TF_CAPI_EXPORT
#else
-#if defined(COMPILER_MSVC)
+#if defined(_WIN32)
#ifdef TF_COMPILE_LIBRARY
#define TF_CAPI_EXPORT __declspec(dllexport)
#else
@@ -42,7 +43,7 @@ limitations under the License.
#endif // TF_COMPILE_LIBRARY
#else
#define TF_CAPI_EXPORT __attribute__((visibility("default")))
-#endif // COMPILER_MSVC
+#endif // _WIN32
#endif // SWIG
#ifdef __cplusplus
@@ -59,6 +60,61 @@ extern "C" {
TF_CAPI_EXPORT extern void TF_EnableXLACompilation(TF_SessionOptions* options,
unsigned char enable);
+// Returns the graph content in a human-readable format, with length set in
+// `len`. The format is subject to change in the future.
+// The returned string is heap-allocated, and caller should call free() on it.
+TF_CAPI_EXPORT extern const char* TF_GraphDebugString(TF_Graph* graph,
+ size_t* len);
+
+// Creates a stack of data set + iterator nodes, currently hard-coded to return
+// a sequence of 3 float values <42.0, 43.0, 44.0> over 3 calls. On success,
+// returns the IteratorGetNext node, which caller can run or feed into an node.
+//
+// TODO(hongm): Extend the API to allow customization of the nodes created.
+TF_CAPI_EXPORT extern TF_Operation* TF_MakeFakeIteratorGetNextWithDatasets(
+ TF_Graph* graph, TF_Status* status);
+
+// Similar to the above API, except that the returned iterator reads the
+// file based dataset from `file_path`.
+// If `is_mnist` is 0, the dataset corresponds to ImageNet.
+// The iterators outputs 2 tensors:
+// - A float tensor of shape `batch_size` X 784 when `is_mnist` is non-zero, or
+// `batch_size` X 224 X 224 X 3 otherwise.
+// - An int32 tensor of shape `batch_size`
+// TODO(hongm): Extend the API to allow customization of the nodes created.
+TF_CAPI_EXPORT extern TF_Operation* TF_MakeFileBasedIteratorGetNextWithDatasets(
+ TF_Graph* graph, const char* file_path, int batch_size,
+ unsigned char is_mnist, TF_Status* status);
+
+// On success, dequeues a tensor from a TF-managed FifoQueue given by
+// `tensor_id`, associated with `session`. There must be a graph node named
+// "fifo_queue_dequeue_", to be executed by this API call.
+
+// Caller must call TF_DeleteTensor() over the returned tensor. If the queue is
+// empty, this call is blocked.
+//
+// Tensors are enqueued via the corresponding TF enqueue op.
+// TODO(hongm): Add support for `timeout_ms`.
+TF_CAPI_EXPORT extern TF_Tensor* TF_DequeueNamedTensor(TF_Session* session,
+ int tensor_id,
+ TF_Status* status);
+
+// On success, enqueues `tensor` into a TF-managed FifoQueue given by
+// `tensor_id`, associated with `session`. There must be a graph node named
+// "fifo_queue_enqueue_", to be executed by this API call. It reads
+// from a placeholder node "arg_tensor_enqueue_".
+//
+// `tensor` is still owned by the caller. This call will be blocked if the queue
+// has reached its capacity, and will be unblocked when the queued tensors again
+// drop below the capacity due to dequeuing.
+//
+// Tensors are dequeued via the corresponding TF dequeue op.
+// TODO(hongm): Add support for `timeout_ms`.
+TF_CAPI_EXPORT extern void TF_EnqueueNamedTensor(TF_Session* session,
+ int tensor_id,
+ TF_Tensor* tensor,
+ TF_Status* status);
+
#ifdef __cplusplus
} /* end extern "C" */
#endif
diff --git a/tensorflow/c/c_api_experimental_test.cc b/tensorflow/c/c_api_experimental_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..30fcfd401d9d634962d64aaa3bf348de91f2ecae
--- /dev/null
+++ b/tensorflow/c/c_api_experimental_test.cc
@@ -0,0 +1,120 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include "tensorflow/c/c_api_experimental.h"
+#include "tensorflow/c/c_test_util.h"
+#include "tensorflow/core/lib/io/path.h"
+#include "tensorflow/core/platform/logging.h"
+#include "tensorflow/core/platform/test.h"
+
+namespace tensorflow {
+namespace {
+
+void TestFakeIteratorStack() {
+ TF_Status* s = TF_NewStatus();
+ TF_Graph* graph = TF_NewGraph();
+
+ TF_Operation* get_next = TF_MakeFakeIteratorGetNextWithDatasets(graph, s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+ CSession csession(graph, s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+ // Run the graph.
+ const float base_value = 42.0;
+ for (int i = 0; i < 3; ++i) {
+ csession.SetOutputs({get_next});
+ csession.Run(s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+ TF_Tensor* out = csession.output_tensor(0);
+ ASSERT_TRUE(out != nullptr);
+ ASSERT_EQ(TF_FLOAT, TF_TensorType(out));
+ ASSERT_EQ(0, TF_NumDims(out)); // scalar
+ ASSERT_EQ(sizeof(float), TF_TensorByteSize(out));
+ float* output_contents = static_cast(TF_TensorData(out));
+ ASSERT_EQ(base_value + i, *output_contents);
+ }
+
+ // This should error out since we've exhausted the iterator.
+ csession.Run(s);
+ ASSERT_EQ(TF_OUT_OF_RANGE, TF_GetCode(s)) << TF_Message(s);
+
+ // Clean up
+ csession.CloseAndDelete(s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+ TF_DeleteGraph(graph);
+ TF_DeleteStatus(s);
+}
+
+TEST(CAPI_EXPERIMENTAL, FakeIteratorGetNext) { TestFakeIteratorStack(); }
+
+TEST(CAPI_EXPERIMENTAL, ImagenetIteratorGetNext) {
+ TF_Status* s = TF_NewStatus();
+ TF_Graph* graph = TF_NewGraph();
+
+ const string file_path = tensorflow::io::JoinPath(
+ tensorflow::testing::TensorFlowSrcRoot(), "c/testdata/tf_record");
+ VLOG(1) << "data file path is " << file_path;
+ const int batch_size = 64;
+ TF_Operation* get_next = TF_MakeFileBasedIteratorGetNextWithDatasets(
+ graph, file_path.c_str(), batch_size, /*is_mnist*/ false, s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+ CSession csession(graph, s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+ // Run the graph.
+ // The two output tensors should look like:
+ // Tensor("IteratorGetNext:0", shape=(batch_size, 224, 224, 3), dtype=float32)
+ // Tensor("IteratorGetNext:1", shape=(batch_size, ), dtype=int32)
+ for (int i = 0; i < 3; ++i) {
+ LOG(INFO) << "Running iter " << i;
+ csession.SetOutputs({{get_next, 0}, {get_next, 1}});
+ csession.Run(s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+
+ {
+ TF_Tensor* image = csession.output_tensor(0);
+ ASSERT_TRUE(image != nullptr);
+ ASSERT_EQ(TF_FLOAT, TF_TensorType(image));
+ // Confirm shape is 224 X 224 X 3
+ ASSERT_EQ(4, TF_NumDims(image));
+ ASSERT_EQ(batch_size, TF_Dim(image, 0));
+ ASSERT_EQ(224, TF_Dim(image, 1));
+ ASSERT_EQ(224, TF_Dim(image, 2));
+ ASSERT_EQ(3, TF_Dim(image, 3));
+ ASSERT_EQ(sizeof(float) * batch_size * 224 * 224 * 3,
+ TF_TensorByteSize(image));
+ }
+
+ {
+ TF_Tensor* label = csession.output_tensor(1);
+ ASSERT_TRUE(label != nullptr);
+ ASSERT_EQ(TF_INT32, TF_TensorType(label));
+ ASSERT_EQ(1, TF_NumDims(label));
+ ASSERT_EQ(batch_size, TF_Dim(label, 0));
+ ASSERT_EQ(sizeof(int32) * batch_size, TF_TensorByteSize(label));
+ }
+ }
+
+ // Clean up
+ csession.CloseAndDelete(s);
+ ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
+ TF_DeleteGraph(graph);
+ TF_DeleteStatus(s);
+}
+
+} // namespace
+} // namespace tensorflow
diff --git a/tensorflow/c/c_api_function_test.cc b/tensorflow/c/c_api_function_test.cc
index 7ca50119eafe299b307f06c555aec1388e7e82e2..610274696f5940c063e68f2310cfd9cc1e0bd964 100644
--- a/tensorflow/c/c_api_function_test.cc
+++ b/tensorflow/c/c_api_function_test.cc
@@ -20,6 +20,7 @@ limitations under the License.
#include "tensorflow/core/framework/op_def.pb.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/hash/hash.h"
+#include "tensorflow/core/lib/strings/proto_serialization.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/logging.h"
diff --git a/tensorflow/c/c_api_internal.h b/tensorflow/c/c_api_internal.h
index 91667056e0eeb224b4b8a034766f11a123cd1a03..95652a11378d6276b5ba6540a07baa15aa77cc1c 100644
--- a/tensorflow/c/c_api_internal.h
+++ b/tensorflow/c/c_api_internal.h
@@ -84,19 +84,20 @@ struct TF_Graph {
std::unordered_map name_map
GUARDED_BY(mu);
- // The keys of this map are all the active sessions using this graph.
- // Each value is the current "runnability" status of the corresponding
- // session. Under normal conditions all statuses are Status::OK(), but
- // if some operation is mutated after it was run by a session (this
- // is detected in RecordMutation function), that session is no longer
- // safe to run. Its status will contain the error that will be returned
- // to the user, should she try running this session.
+ // The keys of this map are all the active sessions using this graph. Each
+ // value records whether the graph has been mutated since the corresponding
+ // session has been run (this is detected in RecordMutation function). If the
+ // string is empty, no mutation has occurred. Otherwise the string is a
+ // description of the mutation suitable for returning to the user.
//
// Sessions are added to this map in TF_NewSession, and removed in
// TF_DeleteSession.
// TF_Graph may only / must be deleted when
// sessions.size() == 0 && delete_requested == true
- tensorflow::gtl::FlatMap sessions
+ //
+ // TODO(b/74949947): mutations currently trigger a warning instead of a bad
+ // status, this should be reverted when possible.
+ tensorflow::gtl::FlatMap sessions
GUARDED_BY(mu);
bool delete_requested GUARDED_BY(mu); // set true by TF_DeleteGraph
@@ -124,15 +125,16 @@ struct TF_Session {
TF_Session(tensorflow::Session* s, TF_Graph* g);
tensorflow::Session* session;
- TF_Graph* graph;
+ TF_Graph* const graph;
- tensorflow::mutex mu;
+ tensorflow::mutex mu ACQUIRED_AFTER(TF_Graph::mu);
int last_num_graph_nodes;
- // NOTE(ashankar): Experimental fields to help keep the
- // buffers of a TF_Tensor pinned in device memory.
- const tensorflow::DeviceMgr* device_mgr; // Owned by session.
- std::vector devices; // Owned by device_mgr.
+ // If true, TF_SessionRun and similar methods will call
+ // ExtendSessionGraphHelper before running the graph (this is the default
+ // public behavior). Can be set to false if the caller needs to call
+ // ExtendSessionGraphHelper manually.
+ std::atomic extend_before_run;
};
struct TF_ImportGraphDefOptions {
@@ -210,7 +212,11 @@ void TF_GraphSetOutputHandleShapesAndTypes(TF_Graph* graph, TF_Output output,
TF_Status* status);
void RecordMutation(TF_Graph* graph, const TF_Operation& op,
- const char* mutation_type);
+ const char* mutation_type)
+ EXCLUSIVE_LOCKS_REQUIRED(graph->mu);
+
+bool ExtendSessionGraphHelper(TF_Session* session, TF_Status* status)
+ LOCKS_EXCLUDED(session->graph->mu, session->mu);
} // end namespace tensorflow
diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc
index 028f146be31790b211e546978302e81afe26b231..577f10c5e69ea9ecbe8ce821c6bd5167e98bef25 100644
--- a/tensorflow/c/c_api_test.cc
+++ b/tensorflow/c/c_api_test.cc
@@ -53,7 +53,7 @@ Status TF_TensorToTensor(const TF_Tensor* src, Tensor* dst);
namespace {
static void ExpectHasSubstr(StringPiece s, StringPiece expected) {
- EXPECT_TRUE(StringPiece(s).contains(expected))
+ EXPECT_TRUE(str_util::StrContains(s, expected))
<< "'" << s << "' does not contain '" << expected << "'";
}
@@ -1368,7 +1368,7 @@ TEST(CAPI, SavedModel) {
}
const tensorflow::string input_op_name =
- tensorflow::ParseTensorName(input_name).first.ToString();
+ std::string(tensorflow::ParseTensorName(input_name).first);
TF_Operation* input_op =
TF_GraphOperationByName(graph, input_op_name.c_str());
ASSERT_TRUE(input_op != nullptr);
@@ -1376,7 +1376,7 @@ TEST(CAPI, SavedModel) {
ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
const tensorflow::string output_op_name =
- tensorflow::ParseTensorName(output_name).first.ToString();
+ std::string(tensorflow::ParseTensorName(output_name).first);
TF_Operation* output_op =
TF_GraphOperationByName(graph, output_op_name.c_str());
ASSERT_TRUE(output_op != nullptr);
@@ -1700,7 +1700,7 @@ TEST_F(CApiGradientsTest, OpWithNoGradientRegistered_NoGradInputs) {
TestGradientsError(false);
}
-// REGISTER_OP for CApiTestAttributesTest test cases.
+// REGISTER_OP for CApiAttributesTest test cases.
// Registers two ops, each with a single attribute called 'v'.
// The attribute in one op will have a type 'type', the other
// will have list(type).
diff --git a/tensorflow/c/c_test_util.cc b/tensorflow/c/c_test_util.cc
index 3db2852ce6560ba493d60ef54a110161c112d110..f3b28c1708129d39e451d927a89c0d10e2193b63 100644
--- a/tensorflow/c/c_test_util.cc
+++ b/tensorflow/c/c_test_util.cc
@@ -34,6 +34,10 @@ static void DoubleDeallocator(void* data, size_t, void* arg) {
delete[] static_cast(data);
}
+static void FloatDeallocator(void* data, size_t, void* arg) {
+ delete[] static_cast(data);
+}
+
TF_Tensor* Int8Tensor(const int64_t* dims, int num_dims, const char* values) {
int64_t num_values = 1;
for (int i = 0; i < num_dims; ++i) {
@@ -78,21 +82,34 @@ TF_Tensor* DoubleTensor(double v) {
&DoubleDeallocator, nullptr);
}
+TF_Tensor* FloatTensor(float v) {
+ const int num_bytes = sizeof(float);
+ float* values = new float[1];
+ values[0] = v;
+ return TF_NewTensor(TF_FLOAT, nullptr, 0, values, num_bytes,
+ &FloatDeallocator, nullptr);
+}
+
// All the *Helper methods are used as a workaround for the restrictions that
// one cannot call ASSERT_* methods in non-void-returning functions (when
// exceptions are disabled during compilation)
void PlaceholderHelper(TF_Graph* graph, TF_Status* s, const char* name,
+ TF_DataType dtype, const std::vector& dims,
TF_Operation** op) {
TF_OperationDescription* desc = TF_NewOperation(graph, "Placeholder", name);
- TF_SetAttrType(desc, "dtype", TF_INT32);
+ TF_SetAttrType(desc, "dtype", dtype);
+ if (!dims.empty()) {
+ TF_SetAttrShape(desc, "shape", dims.data(), dims.size());
+ }
*op = TF_FinishOperation(desc, s);
ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
ASSERT_NE(*op, nullptr);
}
-TF_Operation* Placeholder(TF_Graph* graph, TF_Status* s, const char* name) {
+TF_Operation* Placeholder(TF_Graph* graph, TF_Status* s, const char* name,
+ TF_DataType dtype, const std::vector& dims) {
TF_Operation* op;
- PlaceholderHelper(graph, s, name, &op);
+ PlaceholderHelper(graph, s, name, dtype, dims, &op);
return op;
}
@@ -126,6 +143,12 @@ TF_Operation* ScalarConst(double v, TF_Graph* graph, TF_Status* s,
return Const(tensor.get(), graph, s, name);
}
+TF_Operation* ScalarConst(float v, TF_Graph* graph, TF_Status* s,
+ const char* name) {
+ unique_tensor_ptr tensor(FloatTensor(v), TF_DeleteTensor);
+ return Const(tensor.get(), graph, s, name);
+}
+
void AddOpHelper(TF_Operation* l, TF_Operation* r, TF_Graph* graph,
TF_Status* s, const char* name, TF_Operation** op,
bool check) {
diff --git a/tensorflow/c/c_test_util.h b/tensorflow/c/c_test_util.h
index 2a70177c724c569844a5d8ad42b99bed20209946..c16aba666ee6974fed5351c2d9ac291dcbcdecab 100644
--- a/tensorflow/c/c_test_util.h
+++ b/tensorflow/c/c_test_util.h
@@ -20,6 +20,7 @@ limitations under the License.
#include
#include "tensorflow/core/framework/attr_value.pb.h"
+#include "tensorflow/core/framework/function.pb.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/types.pb.h"
@@ -44,8 +45,12 @@ TF_Tensor* Int32Tensor(int32_t v);
TF_Tensor* DoubleTensor(double v);
+TF_Tensor* FloatTensor(float v);
+
TF_Operation* Placeholder(TF_Graph* graph, TF_Status* s,
- const char* name = "feed");
+ const char* name = "feed",
+ TF_DataType dtype = TF_INT32,
+ const std::vector& dims = {});
TF_Operation* Const(TF_Tensor* t, TF_Graph* graph, TF_Status* s,
const char* name = "const");
@@ -56,6 +61,9 @@ TF_Operation* ScalarConst(int32_t v, TF_Graph* graph, TF_Status* s,
TF_Operation* ScalarConst(double v, TF_Graph* graph, TF_Status* s,
const char* name = "scalar");
+TF_Operation* ScalarConst(float v, TF_Graph* graph, TF_Status* s,
+ const char* name = "scalar");
+
TF_Operation* Add(TF_Operation* l, TF_Operation* r, TF_Graph* graph,
TF_Status* s, const char* name = "add");
diff --git a/tensorflow/c/checkpoint_reader.cc b/tensorflow/c/checkpoint_reader.cc
index b1f7bdaa5420a56386e6983052df20aa976aa867..74bc25a491ac01cb725d1c004197e48727c30230 100644
--- a/tensorflow/c/checkpoint_reader.cc
+++ b/tensorflow/c/checkpoint_reader.cc
@@ -125,7 +125,7 @@ CheckpointReader::BuildV2VarMaps() {
const auto& slice_proto = entry.slices(i);
CHECK(filtered_keys
.insert(EncodeTensorNameSlice(
- v2_reader_->key().ToString() /* full var's name */,
+ std::string(v2_reader_->key()) /* full var's name */,
TensorSlice(slice_proto)))
.second);
}
@@ -138,11 +138,11 @@ CheckpointReader::BuildV2VarMaps() {
new TensorSliceReader::VarToDataTypeMap);
v2_reader_->Seek(kHeaderEntryKey);
for (v2_reader_->Next(); v2_reader_->Valid(); v2_reader_->Next()) {
- if (filtered_keys.count(v2_reader_->key().ToString()) > 0) continue;
+ if (filtered_keys.count(std::string(v2_reader_->key())) > 0) continue;
CHECK(entry.ParseFromArray(v2_reader_->value().data(),
v2_reader_->value().size()))
<< entry.InitializationErrorString();
- string key = v2_reader_->key().ToString();
+ string key = std::string(v2_reader_->key());
(*var_to_shape_map)[key] = TensorShape(entry.shape());
(*var_to_data_type_map)[key] = DataType(entry.dtype());
}
diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD
index e55cb672e97e1403a3dd864c91c176426eb3f067..f265da2c2c89c0e9caf14f2213c606fcb69997e0 100644
--- a/tensorflow/c/eager/BUILD
+++ b/tensorflow/c/eager/BUILD
@@ -14,6 +14,7 @@ tf_cuda_library(
name = "c_api",
srcs = [
"c_api.cc",
+ "c_api_debug.cc",
"c_api_internal.h",
],
hdrs = ["c_api.h"],
@@ -24,9 +25,16 @@ tf_cuda_library(
"//tensorflow/core:android_tensorflow_lib_lite",
],
"//conditions:default": [
- ":runtime",
"//tensorflow/c:c_api",
"//tensorflow/c:c_api_internal",
+ "//tensorflow/core:core_cpu",
+ "//tensorflow/core/common_runtime/eager:attr_builder",
+ "//tensorflow/core/common_runtime/eager:context",
+ "//tensorflow/core/common_runtime/eager:eager_executor",
+ "//tensorflow/core/common_runtime/eager:execute",
+ "//tensorflow/core/common_runtime/eager:kernel_and_device",
+ "//tensorflow/core/common_runtime/eager:tensor_handle",
+ "//tensorflow/core/common_runtime/eager:copy_to_device_node",
"//tensorflow/core:core_cpu_internal",
"//tensorflow/core:framework",
"//tensorflow/core:framework_internal",
@@ -38,9 +46,22 @@ tf_cuda_library(
"//tensorflow:with_xla_support": [
"//tensorflow/compiler/tf2xla:xla_compiler",
"//tensorflow/compiler/jit",
+ "//tensorflow/compiler/jit:xla_device",
],
"//conditions:default": [],
}) + [
+ "//tensorflow/core/common_runtime/eager:eager_operation",
+ "//tensorflow/core/distributed_runtime/eager:eager_client",
+ "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_channel",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_cache",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_service",
+ "//tensorflow/core/distributed_runtime/rpc:rpc_rendezvous_mgr",
+ "//tensorflow/core/distributed_runtime:remote_device",
+ "//tensorflow/core/distributed_runtime:server_lib",
+ "//tensorflow/core/distributed_runtime:worker_env",
"//tensorflow/core:gpu_runtime",
],
)
@@ -51,72 +72,74 @@ tf_cuda_library(
visibility = ["//tensorflow:internal"],
deps = [
":c_api",
- ":runtime",
"//tensorflow/c:c_api",
"//tensorflow/c:c_api_internal",
+ "//tensorflow/core:core_cpu",
"//tensorflow/core:core_cpu_lib",
"//tensorflow/core:framework",
"//tensorflow/core:framework_internal",
"//tensorflow/core:framework_lite",
+ "//tensorflow/core:lib",
"//tensorflow/core:lib_internal",
+ "//tensorflow/core/common_runtime/eager:attr_builder",
+ "//tensorflow/core/common_runtime/eager:context",
+ "//tensorflow/core/common_runtime/eager:eager_executor",
+ "//tensorflow/core/common_runtime/eager:eager_operation",
+ "//tensorflow/core/common_runtime/eager:kernel_and_device",
+ "//tensorflow/core/common_runtime/eager:tensor_handle",
+ "//tensorflow/core/distributed_runtime:remote_device",
+ "//tensorflow/core/distributed_runtime:server_lib",
+ "//tensorflow/core/distributed_runtime:worker_env",
+ "//tensorflow/core/distributed_runtime/eager:eager_client",
+ "//tensorflow/core/distributed_runtime/eager:remote_tensor_handle",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_channel",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_cache",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_service",
+ "//tensorflow/core/distributed_runtime/rpc:rpc_rendezvous_mgr",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client",
],
)
-tf_cuda_cc_test(
- name = "c_api_test",
- srcs = ["c_api_test.cc"],
- extra_copts = tfe_xla_copts(),
- tags = [
- "guitar",
- "multi_gpu",
+tf_cuda_library(
+ name = "c_api_test_util",
+ testonly = 1,
+ srcs = ["c_api_test_util.cc"],
+ hdrs = ["c_api_test_util.h"],
+ visibility = [
+ "//learning/brain:__subpackages__",
+ "//tensorflow:__subpackages__",
],
deps = [
":c_api",
"//tensorflow/c:c_test_util",
+ "//tensorflow/core:framework",
"//tensorflow/core:lib",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core:test",
- "//tensorflow/core:test_main",
],
)
-tf_cuda_library(
- name = "runtime",
- srcs = ["runtime.cc"],
- hdrs = ["runtime.h"],
- copts = tf_copts(),
- visibility = ["//tensorflow:internal"],
- deps = select({
- "//tensorflow:android": [
- "//tensorflow/core:android_tensorflow_lib_lite",
- ],
- "//conditions:default": [
- "//tensorflow/c:c_api",
- "//tensorflow/core:core_cpu",
- "//tensorflow/core:core_cpu_internal",
- "//tensorflow/core:framework",
- "//tensorflow/core:framework_internal",
- "//tensorflow/core:lib",
- "//tensorflow/core:lib_internal",
- "//tensorflow/core:protos_all_cc",
- ],
- }),
-)
-
-tf_cc_test(
- name = "runtime_test",
- srcs = ["runtime_test.cc"],
+tf_cuda_cc_test(
+ name = "c_api_test",
+ srcs = [
+ "c_api_debug_test.cc",
+ "c_api_test.cc",
+ ],
+ extra_copts = tfe_xla_copts(),
+ tags = [
+ "guitar",
+ "multi_gpu",
+ ],
deps = [
- ":runtime",
- "//tensorflow/cc:cc_ops",
- "//tensorflow/cc:client_session",
- "//tensorflow/cc:ops",
- "//tensorflow/cc:scope",
- "//tensorflow/core:core_cpu_internal",
- "//tensorflow/core:framework",
+ ":c_api",
+ ":c_api_test_util",
+ "//tensorflow/c:c_test_util",
"//tensorflow/core:lib",
+ "//tensorflow/core:protos_all_cc",
"//tensorflow/core:test",
"//tensorflow/core:test_main",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
],
)
diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc
index 98ef6f0d0ab094eae3e2e21624c3a4ba30d1c3d3..81221c4078bec9820ee187efdf0314da378be62b 100644
--- a/tensorflow/c/eager/c_api.cc
+++ b/tensorflow/c/eager/c_api.cc
@@ -24,22 +24,33 @@ limitations under the License.
#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/c/eager/c_api_internal.h"
-#include "tensorflow/c/eager/runtime.h"
#ifdef TENSORFLOW_EAGER_USE_XLA
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#endif // TENSORFLOW_EAGER_USE_XLA
#include "tensorflow/core/common_runtime/copy_tensor.h"
#include "tensorflow/core/common_runtime/device_factory.h"
#include "tensorflow/core/common_runtime/device_mgr.h"
+#include "tensorflow/core/common_runtime/device_set.h"
+#include "tensorflow/core/common_runtime/eager/attr_builder.h"
+#include "tensorflow/core/common_runtime/eager/copy_to_device_node.h"
+#include "tensorflow/core/common_runtime/eager/execute.h"
#include "tensorflow/core/common_runtime/function.h"
#include "tensorflow/core/common_runtime/rendezvous_mgr.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/eager_grpc_server_lib.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/grpc_eager_client.h"
+#include "tensorflow/core/distributed_runtime/rpc/grpc_channel.h"
+#include "tensorflow/core/distributed_runtime/server_lib.h"
+#include "tensorflow/core/distributed_runtime/worker_env.h"
+#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/rendezvous.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/core/refcount.h"
+#include "tensorflow/core/lib/gtl/cleanup.h"
#include "tensorflow/core/lib/gtl/flatmap.h"
#include "tensorflow/core/lib/gtl/map_util.h"
#include "tensorflow/core/lib/gtl/stl_util.h"
+#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/thread_annotations.h"
#include "tensorflow/core/public/version.h"
@@ -62,9 +73,121 @@ string DeviceName(const tensorflow::Device* d) {
return (d == nullptr) ? "cpu:0" : d->name();
}
-#ifdef TENSORFLOW_EAGER_USE_XLA
-std::atomic_int_fast64_t func_id_generator(0);
-#endif // TENSORFLOW_EAGER_USE_XLA
+tensorflow::Status GetAllRemoteDevices(
+ const std::vector& remote_workers,
+ tensorflow::WorkerCacheInterface* worker_cache,
+ std::unique_ptr* device_mgr) {
+ std::vector remote_devices;
+ tensorflow::Status status;
+ // TODO(nareshmodi) do this in parallel instead of serially.
+ for (const string& remote_worker : remote_workers) {
+ tensorflow::Notification n;
+ tensorflow::NewRemoteDevices(
+ tensorflow::Env::Default(), worker_cache, remote_worker,
+ [&status, &n, &remote_devices](
+ const tensorflow::Status& s,
+ std::vector* devices) {
+ status = s;
+ if (s.ok()) {
+ for (tensorflow::Device* d : *devices) {
+ remote_devices.push_back(d);
+ }
+ }
+ n.Notify();
+ });
+ n.WaitForNotification();
+ }
+ std::unique_ptr remote_device_mgr(
+ new tensorflow::DeviceMgr(remote_devices));
+
+ TF_RETURN_IF_ERROR(status);
+
+ *device_mgr = std::move(remote_device_mgr);
+ return tensorflow::Status::OK();
+}
+
+tensorflow::Status CreateRemoteContexts(
+ const std::vector& remote_workers,
+ tensorflow::eager::EagerClientCache* remote_eager_workers, bool async,
+ tensorflow::gtl::FlatMap* remote_contexts) {
+ for (int i = 0; i < remote_workers.size(); i++) {
+ const string& remote_worker = remote_workers[i];
+
+ tensorflow::eager::CreateContextRequest request;
+ tensorflow::eager::CreateContextResponse response;
+ tensorflow::DeviceNameUtils::ParsedName parsed_name;
+ if (!tensorflow::DeviceNameUtils::ParseFullName(remote_worker,
+ &parsed_name)) {
+ return tensorflow::errors::InvalidArgument(
+ "Unable to parse ", remote_worker, " as a device name");
+ }
+ request.mutable_server_def()->set_job_name(parsed_name.job);
+ request.mutable_server_def()->set_task_index(parsed_name.task);
+ request.set_async(async);
+ auto* eager_client = remote_eager_workers->GetClient(remote_worker);
+ if (eager_client == nullptr) {
+ return tensorflow::errors::Internal(
+ "Cannot find a client for the given target:", remote_worker);
+ }
+ tensorflow::Notification n;
+ tensorflow::Status status;
+ // TODO(nareshmodi) do this in parallel instead of serially.
+ eager_client->CreateContextAsync(
+ &request, &response, [&status, &n](const tensorflow::Status& s) {
+ status = s;
+ n.Notify();
+ });
+ n.WaitForNotification();
+ TF_RETURN_IF_ERROR(status);
+
+ remote_contexts->emplace(remote_worker, response.context_id());
+ }
+ return tensorflow::Status::OK();
+}
+
+tensorflow::Status NewRemoteAwareTFE_Context(const TFE_ContextOptions* opts,
+ TFE_Context** ctx) {
+ string worker_name = tensorflow::strings::StrCat(
+ "/job:", opts->server_def.job_name(),
+ "/replica:0/task:", opts->server_def.task_index());
+ std::unique_ptr server;
+ TF_RETURN_IF_ERROR(
+ tensorflow::eager::EagerGrpcServer::Create(opts->server_def, &server));
+
+ TF_RETURN_IF_ERROR(server->Start());
+
+ std::vector remote_workers;
+ server->master_env()->worker_cache->ListWorkers(&remote_workers);
+ remote_workers.erase(
+ std::remove(remote_workers.begin(), remote_workers.end(), worker_name),
+ remote_workers.end());
+
+ std::unique_ptr remote_device_mgr;
+ TF_RETURN_IF_ERROR(GetAllRemoteDevices(
+ remote_workers, server->master_env()->worker_cache, &remote_device_mgr));
+
+ std::shared_ptr channel_cache =
+ server->channel_cache();
+ std::unique_ptr remote_eager_workers(
+ tensorflow::eager::NewGrpcEagerClientCache(channel_cache));
+
+ // Initialize remote eager workers.
+ tensorflow::gtl::FlatMap remote_contexts;
+ TF_RETURN_IF_ERROR(CreateRemoteContexts(remote_workers,
+ remote_eager_workers.get(),
+ opts->async, &remote_contexts));
+
+ tensorflow::RemoteRendezvous* r =
+ server->worker_env()->rendezvous_mgr->Find(0);
+
+ auto* device_mgr = server->worker_env()->device_mgr;
+ *ctx = new TFE_Context(opts->session_options.options, opts->policy,
+ opts->async, device_mgr, r, std::move(server),
+ std::move(remote_eager_workers),
+ std::move(remote_device_mgr), remote_contexts);
+
+ return tensorflow::Status::OK();
+}
} // namespace
extern "C" {
@@ -76,181 +199,158 @@ void TFE_ContextOptionsSetConfig(TFE_ContextOptions* options, const void* proto,
TF_SetConfig(&options->session_options, proto, proto_len, status);
}
+void TFE_ContextOptionsSetAsync(TFE_ContextOptions* options,
+ unsigned char async) {
+ options->async = async;
+}
void TFE_ContextOptionsSetDevicePlacementPolicy(
TFE_ContextOptions* options, TFE_ContextDevicePlacementPolicy policy) {
options->policy = policy;
}
+TF_CAPI_EXPORT extern void TFE_ContextOptionsSetServerDef(
+ TFE_ContextOptions* options, const void* proto, size_t proto_len,
+ TF_Status* status) {
+ if (!options->server_def.ParseFromArray(proto, proto_len)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Invalid tensorflow.ServerDef protocol buffer");
+ }
+}
+
+TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx,
+ unsigned char async,
+ TF_Status* status) {
+ status->status = ctx->context.SetAsyncForThread(async);
+}
+
void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; }
TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) {
- TF_Graph* graph = TF_NewGraph();
- TF_Session* session = TF_NewSession(graph, &opts->session_options, status);
- if (status->status.ok()) {
- if (session->device_mgr == nullptr || session->devices.empty()) {
- status->status = tensorflow::errors::InvalidArgument(
- "Provided TF_SessionOptions are not compatible with eager execution "
- "(perhaps the TF_SessionOptions alluded to session execution in a "
- "remote address space?)");
- }
- }
- if (!status->status.ok()) {
- TF_DeleteGraph(graph);
- return nullptr;
+ if (!opts->server_def.job_name().empty()) {
+ TFE_Context* ctx = nullptr;
+ status->status = NewRemoteAwareTFE_Context(opts, &ctx);
+ return ctx;
}
- return new TFE_Context(*opts, session);
-}
+ std::vector devices;
+ status->status = tensorflow::DeviceFactory::AddDevices(
+ opts->session_options.options, "/job:localhost/replica:0/task:0",
+ &devices);
+ if (!status->status.ok()) return nullptr;
+ std::unique_ptr device_mgr(
+ new tensorflow::DeviceMgr(devices));
-void TFE_DeleteContext(TFE_Context* ctx, TF_Status* status) {
- status->status = tensorflow::Status::OK();
- {
- tensorflow::mutex_lock ml(ctx->cache_mu);
- tensorflow::gtl::STLDeleteValues(&ctx->kernel_cache);
- }
- TF_Graph* graph = ctx->session->graph;
- TF_DeleteSession(ctx->session, status);
- TF_DeleteGraph(graph);
- ctx->rendezvous->Unref();
- delete ctx;
+ tensorflow::Rendezvous* r =
+ new tensorflow::IntraProcessRendezvous(device_mgr.get());
+
+ return new TFE_Context(opts->session_options.options, opts->policy,
+ opts->async, std::move(device_mgr), r);
}
+void TFE_DeleteContext(TFE_Context* ctx, TF_Status* status) { delete ctx; }
+
TF_DeviceList* TFE_ContextListDevices(TFE_Context* ctx, TF_Status* status) {
- return TF_SessionListDevices(ctx->session, status);
+ TF_DeviceList* list = new TF_DeviceList;
+ ctx->context.local_device_mgr()->ListDeviceAttributes(&list->response);
+ if (ctx->context.remote_device_mgr()) {
+ ctx->context.remote_device_mgr()->ListDeviceAttributes(&list->response);
+ }
+ return list;
}
-void TFE_ContextClearCaches(TFE_Context* ctx) {
- tensorflow::mutex_lock ml(ctx->cache_mu);
- tensorflow::gtl::STLDeleteValues(&ctx->kernel_cache);
-}
+void TFE_ContextClearCaches(TFE_Context* ctx) { ctx->context.ClearCaches(); }
void TFE_ContextSetThreadLocalDevicePlacementPolicy(
TFE_Context* ctx, TFE_ContextDevicePlacementPolicy policy) {
- tensorflow::mutex_lock ml(ctx->policy_map_mu);
- ctx->thread_local_policies[std::this_thread::get_id()] = policy;
+ ctx->context.SetThreadLocalDevicePlacementPolicy(
+ static_cast(policy));
}
+// Note: this function looks up a thread local policy. So it should be called in
+// the appropriate client thread. In particular, in async mode, it may not be
+// safe to call this function from the async EagerExecutor threads.
extern TFE_ContextDevicePlacementPolicy TFE_ContextGetDevicePlacementPolicy(
TFE_Context* ctx) {
- tensorflow::mutex_lock ml(ctx->policy_map_mu);
- auto policy_map_it =
- ctx->thread_local_policies.find(std::this_thread::get_id());
- if (policy_map_it != ctx->thread_local_policies.end()) {
- return policy_map_it->second;
- }
- return ctx->policy;
+ return static_cast(
+ ctx->context.GetDevicePlacementPolicy());
+}
+
+void TFE_ContextAsyncWait(TFE_Context* ctx, TF_Status* status) {
+ status->status = ctx->context.AsyncWait();
+}
+
+void TFE_ContextGetStatus(TFE_Context* ctx, TF_Status* status) {
+ status->status = ctx->context.GetStatus();
+}
+
+void TFE_ContextAsyncClearError(TFE_Context* ctx) {
+ ctx->context.ClearAsyncError();
}
TFE_TensorHandle* TFE_NewTensorHandle(TF_Tensor* t, TF_Status* status) {
tensorflow::Tensor tensor;
status->status = tensorflow::TF_TensorToTensor(t, &tensor);
if (!status->status.ok()) return nullptr;
- return new TFE_TensorHandle(tensor, nullptr);
+ return new TFE_TensorHandle(tensor, nullptr, nullptr);
}
-void TFE_DeleteTensorHandle(TFE_TensorHandle* h) { delete h; }
+void TFE_DeleteTensorHandle(TFE_TensorHandle* h) {
+ DCHECK(h);
+ if (h->handle) {
+ h->handle->Unref();
+ }
+ delete h;
+}
TF_DataType TFE_TensorHandleDataType(TFE_TensorHandle* h) {
- return static_cast(h->t.dtype());
+ return static_cast(h->handle->dtype);
}
-int TFE_TensorHandleNumDims(TFE_TensorHandle* h) { return h->t.dims(); }
-
-int64_t TFE_TensorHandleDim(TFE_TensorHandle* h, int dim_index) {
- return h->t.dim_size(dim_index);
+int TFE_TensorHandleNumDims(TFE_TensorHandle* h, TF_Status* status) {
+ const tensorflow::Tensor* t = nullptr;
+ status->status = h->handle->Tensor(&t);
+ return t == nullptr ? 0 : t->dims();
}
-const char* TFE_TensorHandleDeviceName(TFE_TensorHandle* h) {
- // TODO(apassos) this will be potentially incorrect in the distributed case as
- // our local device will have a name which depends on the ClusterSpec and
- // hence will require the context to resolve.
- return (h->d == nullptr) ? "/job:localhost/replica:0/task:0/device:CPU:0"
- : h->d->name().c_str();
+int64_t TFE_TensorHandleDim(TFE_TensorHandle* h, int dim_index,
+ TF_Status* status) {
+ const tensorflow::Tensor* t = nullptr;
+ status->status = h->handle->Tensor(&t);
+ return t == nullptr ? 0 : t->dim_size(dim_index);
}
-TF_Tensor* TFE_TensorHandleResolve(TFE_TensorHandle* h, TF_Status* status) {
- if (!IsCPU(h->d)) {
- TF_SetStatus(status, TF_UNIMPLEMENTED,
- tensorflow::strings::StrCat(
- "TFE_TensorHandle can be resolved iff it is on CPU (this "
- "handle is on ",
- h->d->name(),
- "). Consider using TFE_TensorHandleCopyToDevice to get a "
- "copy of the tensor on CPU")
- .c_str());
- return nullptr;
- }
- return tensorflow::TF_TensorFromTensor(h->t, status);
+const char* TFE_TensorHandleDeviceName(TFE_TensorHandle* h, TF_Status* status) {
+ tensorflow::Device* d = nullptr;
+ status->status = h->handle->OpDevice(&d);
+ return (d == nullptr) ? "/job:localhost/replica:0/task:0/device:CPU:0"
+ : d->name().c_str();
}
-TFE_TensorHandle* TFE_TensorHandleCopyToDevice(TFE_TensorHandle* h,
- TFE_Context* ctx,
- const char* device_name,
- TF_Status* status) {
- tensorflow::Device* dstd = ctx->devices()[0];
- if (device_name != nullptr && strlen(device_name) > 0) {
- status->status = ctx->session->device_mgr->LookupDevice(device_name, &dstd);
- if (!status->status.ok()) return nullptr;
- }
-
- tensorflow::Device* srcd = h->d == nullptr ? ctx->devices()[0] : h->d;
- bool is_same_device =
- (srcd == dstd) || (DeviceName(srcd) == DeviceName(dstd));
- const bool dst_cpu = IsCPU(dstd);
- const bool src_cpu = IsCPU(srcd);
- // both_on_cpu can be true and yet is_same_device is false, if one of src/dst
- // has device type XLA_CPU, and the other CPU.
- const bool both_on_cpu = src_cpu && dst_cpu;
- if (is_same_device || both_on_cpu) {
- return new TFE_TensorHandle(h->t, dst_cpu ? nullptr : dstd);
- }
- tensorflow::Tensor* src = &(h->t);
- if (!dst_cpu && (src->dtype() != tensorflow::DT_VARIANT &&
- !tensorflow::DataTypeCanUseMemcpy(src->dtype()))) {
- TF_SetStatus(
- status, TF_INVALID_ARGUMENT,
- tensorflow::strings::StrCat("Can't copy Tensor with type ",
- tensorflow::DataTypeString(src->dtype()),
- " to device ", DeviceName(dstd), ".")
- .c_str());
- return nullptr;
- }
- tensorflow::AllocatorAttributes attr;
- if (src->dtype() == tensorflow::DT_VARIANT) {
- attr.set_on_host(true);
- }
- tensorflow::Tensor dst(dstd->GetAllocator(attr), src->dtype(), src->shape());
- if (src->shape().num_elements() == 0) {
- return new TFE_TensorHandle(dst, dst_cpu ? nullptr : dstd);
- }
- tensorflow::DeviceContext* src_device_context = nullptr;
- if (!src_cpu) {
- src_device_context = srcd->tensorflow_gpu_device_info()->default_context;
+TF_Tensor* TFE_TensorHandleResolve(TFE_TensorHandle* h, TF_Status* status) {
+ // TODO(agarwal): move this implementation inside TFE_TensorHandle.
+ tensorflow::Device* d = nullptr;
+ tensorflow::Device* op_device = nullptr;
+ const tensorflow::Tensor* t = nullptr;
+ status->status = h->handle->TensorAndDevice(&t, &d, &op_device);
+ if (!status->status.ok()) return nullptr;
+ tensorflow::TensorHandle* h_cpu = nullptr;
+ if (!IsCPU(d)) {
+ status->status = h->handle->CopyToDevice(
+ h->handle->Context(), h->handle->Context()->HostCPU(), &h_cpu);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ status->status = h_cpu->TensorAndDevice(&t, &d, &op_device);
+ if (!status->status.ok()) {
+ h_cpu->Unref();
+ return nullptr;
+ }
}
- tensorflow::DeviceContext* dst_device_context = nullptr;
- if (!dst_cpu) {
- dst_device_context = dstd->tensorflow_gpu_device_info()->default_context;
+ TF_Tensor* retval = tensorflow::TF_TensorFromTensor(*t, status);
+ if (h_cpu != nullptr) {
+ h_cpu->Unref();
}
- // TODO(ashankar): The Sync() call below may be more aggressive than
- // necessary. It is based on knowledge of implementation details - that
- // GPU devices are implemented using 3 streams - one for host->device copies,
- // one for device->host copies and one for sending operations to the GPU.
- // With that setup, Sync()ing across all 3 streams should be sufficient
- // but more than necessary (since it waits for operations that might have
- // nothing to do with this tensor to complete).
- status->status = srcd->Sync();
- tensorflow::Notification n;
- tensorflow::CopyTensor::ViaDMA("copy", src_device_context, dst_device_context,
- srcd, dstd, tensorflow::AllocatorAttributes(),
- tensorflow::AllocatorAttributes(), src, &dst,
- [status, &n](const tensorflow::Status& s) {
- status->status = s;
- n.Notify();
- });
- n.WaitForNotification();
- return (TF_GetCode(status) == TF_OK)
- ? new TFE_TensorHandle(dst, dst_cpu ? nullptr : dstd)
- : nullptr;
+ return retval;
}
TFE_Op* TFE_NewOp(TFE_Context* ctx, const char* op_or_function_name,
@@ -260,8 +360,7 @@ TFE_Op* TFE_NewOp(TFE_Context* ctx, const char* op_or_function_name,
status->status = tensorflow::AttrTypeMapForOp(name, &types);
if (status->status.ok()) return new TFE_Op(ctx, name, types);
if (TF_GetCode(status) == TF_NOT_FOUND) {
- tensorflow::mutex_lock l(ctx->functions_mu);
- if (ctx->func_lib_def.Find(name) != nullptr) {
+ if (ctx->context.FindFunctionByName(name)) {
status->status = tensorflow::Status::OK();
return new TFE_Op(ctx, name, nullptr);
}
@@ -272,23 +371,18 @@ TFE_Op* TFE_NewOp(TFE_Context* ctx, const char* op_or_function_name,
void TFE_DeleteOp(TFE_Op* op) { delete op; }
void TFE_OpSetDevice(TFE_Op* op, const char* device_name, TF_Status* status) {
- tensorflow::Device* d = nullptr;
- if (device_name != nullptr && strlen(device_name) > 0) {
- status->status =
- op->ctx->session->device_mgr->LookupDevice(device_name, &d);
- if (!status->status.ok()) return;
- }
- op->device = d;
+ status->status = op->operation.SetDevice(device_name);
}
const char* TFE_OpGetDevice(TFE_Op* op, TF_Status* status) {
- tensorflow::Device* device =
- (op->device == nullptr) ? op->ctx->devices()[0] : op->device;
+ tensorflow::Device* device = (op->operation.Device() == nullptr)
+ ? op->operation.EagerContext()->HostCPU()
+ : op->operation.Device();
return device->name().c_str();
}
void TFE_OpSetXLACompilation(TFE_Op* op, unsigned char enable) {
- op->use_xla = enable;
+ op->operation.SetUseXla(enable);
#ifndef TENSORFLOW_EAGER_USE_XLA
LOG(WARNING) << "This call is a no-op, as the TensorFlow library is not "
"built with XLA support.";
@@ -296,31 +390,20 @@ void TFE_OpSetXLACompilation(TFE_Op* op, unsigned char enable) {
}
void TFE_OpAddInput(TFE_Op* op, TFE_TensorHandle* h, TF_Status* status) {
- // Questionable heuristic ...
- //
- // Motivation: After an 'op' is placed on GPU because some of its earlier
- // inputs are on GPU, we want to keep the 'op' there, even if some later
- // inputs of it are not on GPU.
- if (IsCPU(op->device) && !IsCPU(h->d)) {
- op->device = h->d;
- }
- if (!status->status.ok()) return;
- op->inputs.push_back(h->t);
- op->input_devices.push_back(h->d);
- op->attrs.NumInputs(op->inputs.size());
+ op->operation.AddInput(h->handle);
}
TF_AttrType TFE_OpGetAttrType(TFE_Op* op, const char* attr_name,
unsigned char* is_list, TF_Status* status) {
TF_AttrType ret;
- if (op->is_function()) {
+ if (op->operation.is_function()) {
status->status = tensorflow::errors::Unimplemented(
"TODO(apassos): Support for attributes for TensorFlow functions is not "
"ready yet.");
return TF_ATTR_INT; // The compiler requires that we return something.
}
- status->status =
- tensorflow::AttrTypeByName(*op->attr_types, attr_name, &ret, is_list);
+ status->status = tensorflow::AttrTypeByName(*op->operation.AttrTypes(),
+ attr_name, &ret, is_list);
return ret;
}
@@ -339,23 +422,24 @@ TF_AttrType TFE_OpNameGetAttrType(TFE_Context* ctx,
}
void TFE_OpSetAttrString(TFE_Op* op, const char* attr_name, const char* value) {
- op->attrs.Set(attr_name, value);
+ op->operation.MutableAttrs()->Set(attr_name, value);
}
void TFE_OpSetAttrInt(TFE_Op* op, const char* attr_name, int64_t value) {
- op->attrs.Set(attr_name, static_cast(value));
+ op->operation.MutableAttrs()->Set(attr_name, static_cast(value));
}
void TFE_OpSetAttrFloat(TFE_Op* op, const char* attr_name, float value) {
- op->attrs.Set(attr_name, value);
+ op->operation.MutableAttrs()->Set(attr_name, value);
}
void TFE_OpSetAttrBool(TFE_Op* op, const char* attr_name, unsigned char value) {
- op->attrs.Set(attr_name, (value == 0) ? false : true);
+ op->operation.MutableAttrs()->Set(attr_name, (value == 0) ? false : true);
}
void TFE_OpSetAttrType(TFE_Op* op, const char* attr_name, TF_DataType value) {
- op->attrs.Set(attr_name, static_cast(value));
+ op->operation.MutableAttrs()->Set(attr_name,
+ static_cast(value));
}
void TFE_OpSetAttrShape(TFE_Op* op, const char* attr_name, const int64_t* dims,
@@ -377,23 +461,24 @@ void TFE_OpSetAttrShape(TFE_Op* op, const char* attr_name, const int64_t* dims,
proto.add_dim()->set_size(dims[d]);
}
}
- op->attrs.Set(attr_name, proto);
+ op->operation.MutableAttrs()->Set(attr_name, proto);
}
void TFE_OpSetAttrFunction(TFE_Op* op, const char* attr_name,
const TFE_Op* value) {
tensorflow::AttrValue attr_value;
tensorflow::NameAttrList* func = attr_value.mutable_func();
- func->set_name(value->name);
- value->attrs.FillAttrValueMap(func->mutable_attr());
- op->attrs.Set(attr_name, attr_value);
+ func->set_name(value->operation.Name());
+ value->operation.Attrs().FillAttrValueMap(func->mutable_attr());
+ op->operation.MutableAttrs()->Set(attr_name, attr_value);
}
#define TFE_OP_SET_ATTR_LIST(fn, type) \
void fn(TFE_Op* op, const char* attr_name, const type* values, \
int num_values) { \
- op->attrs.Set(attr_name, tensorflow::gtl::ArraySlice( \
- values, num_values)); \
+ op->operation.MutableAttrs()->Set( \
+ attr_name, \
+ tensorflow::gtl::ArraySlice(values, num_values)); \
}
TFE_OP_SET_ATTR_LIST(TFE_OpSetAttrStringList, char*)
TFE_OP_SET_ATTR_LIST(TFE_OpSetAttrFloatList, float)
@@ -401,14 +486,14 @@ TFE_OP_SET_ATTR_LIST(TFE_OpSetAttrFloatList, float)
void TFE_OpSetAttrIntList(TFE_Op* op, const char* attr_name,
const int64_t* values, int num_values) {
- op->attrs.Set(attr_name,
- tensorflow::gtl::ArraySlice(
- reinterpret_cast(values), num_values));
+ op->operation.MutableAttrs()->Set(
+ attr_name, tensorflow::gtl::ArraySlice(
+ reinterpret_cast(values), num_values));
}
void TFE_OpSetAttrTypeList(TFE_Op* op, const char* attr_name,
const TF_DataType* values, int num_values) {
- op->attrs.Set(
+ op->operation.MutableAttrs()->Set(
attr_name,
tensorflow::gtl::ArraySlice(
reinterpret_cast(values), num_values));
@@ -420,8 +505,8 @@ void TFE_OpSetAttrBoolList(TFE_Op* op, const char* attr_name,
for (int i = 0; i < num_values; ++i) {
b[i] = values[i];
}
- op->attrs.Set(attr_name,
- tensorflow::gtl::ArraySlice(b.get(), num_values));
+ op->operation.MutableAttrs()->Set(
+ attr_name, tensorflow::gtl::ArraySlice(b.get(), num_values));
}
void TFE_OpSetAttrShapeList(TFE_Op* op, const char* attr_name,
@@ -451,9 +536,9 @@ void TFE_OpSetAttrShapeList(TFE_Op* op, const char* attr_name,
}
}
}
- op->attrs.Set(attr_name,
- tensorflow::gtl::ArraySlice(
- proto.get(), num_values));
+ op->operation.MutableAttrs()->Set(
+ attr_name, tensorflow::gtl::ArraySlice(
+ proto.get(), num_values));
}
void TFE_OpSetAttrFunctionList(TFE_Op* op, const char* attr_name,
@@ -461,432 +546,41 @@ void TFE_OpSetAttrFunctionList(TFE_Op* op, const char* attr_name,
std::unique_ptr funcs(
new tensorflow::NameAttrList[num_values]);
for (int i = 0; i < num_values; i++) {
- funcs[i].set_name(value[i]->name);
- value[i]->attrs.FillAttrValueMap(funcs[i].mutable_attr());
- }
- op->attrs.Set(attr_name,
- tensorflow::gtl::ArraySlice(
- funcs.get(), num_values));
-}
-
-namespace {
-
-tensorflow::Status ValidateInputTypeAndPlacement(
- TFE_Context* ctx, tensorflow::Device* host_device,
- tensorflow::Device* op_device, TFE_Op* op,
- const tensorflow::OpKernel* kernel,
- std::vector* copied_tensors) {
- const tensorflow::MemoryTypeVector& memtypes = kernel->input_memory_types();
- if (memtypes.size() != op->inputs.size()) {
- return tensorflow::errors::InvalidArgument(
- "expected ", memtypes.size(), " inputs, got ", op->inputs.size());
- }
- for (int i = 0; i < op->inputs.size(); ++i) {
- const tensorflow::Device* expected_device =
- memtypes[i] == tensorflow::HOST_MEMORY ? host_device : op_device;
- const tensorflow::Device* actual_device =
- op->input_devices[i] == nullptr ? host_device : op->input_devices[i];
- if (expected_device != actual_device) {
- switch (TFE_ContextGetDevicePlacementPolicy(ctx)) {
- case TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32:
- // TODO(xpan): See if we could bubble python related error up
- // to python level.
- if (op->inputs[i].dtype() == tensorflow::DT_INT32) {
- // Note: enabling silent copies of int32 tensors to match behavior
- // of graph mode.
- break;
- }
- TF_FALLTHROUGH_INTENDED;
- case TFE_DEVICE_PLACEMENT_EXPLICIT:
- return tensorflow::errors::InvalidArgument(
- "Tensors on conflicting devices:"
- " cannot compute ",
- op->name, " as input #", i, " was expected to be on ",
- expected_device->name(), " but is actually on ",
- actual_device->name(), " (operation running on ",
- op_device->name(), ")",
- " Tensors can be copied explicitly using .gpu() or .cpu(),"
- " or transparently copied by using tfe.enable_eager_execution("
- "tfe.DEVICE_PLACEMENT_SILENT). Copying tensors between devices"
- " may slow down your model");
- case TFE_DEVICE_PLACEMENT_WARN:
- LOG(WARNING) << "before computing " << op->name << " input #" << i
- << " was expected to be on " << expected_device->name()
- << " but is actually on " << actual_device->name()
- << " (operation running on " << op_device->name()
- << "). This triggers a copy which can be a performance "
- "bottleneck.";
- break;
- case TFE_DEVICE_PLACEMENT_SILENT: // Do nothing.
- break;
- }
- // We are only here if the policy is warn or silent copies, so we should
- // trigger a copy.
- TFE_TensorHandle original{op->inputs[i], op->input_devices[i]};
- TF_Status* s = TF_NewStatus();
- TFE_TensorHandle* copied_tensor = TFE_TensorHandleCopyToDevice(
- &original, ctx, expected_device->name().c_str(), s);
- if (!s->status.ok()) {
- tensorflow::Status status = s->status;
- delete s;
- return tensorflow::errors::Internal(
- "Failed copying input tensor from ", actual_device->name(), " to ",
- expected_device->name(), " in order to run ", op->name, ": ",
- status.error_message());
- }
- op->inputs[i] = copied_tensor->t;
- copied_tensors->push_back(copied_tensor);
- op->input_devices[i] = copied_tensor->d;
- delete s;
- }
- if (op->inputs[i].dtype() != kernel->input_type(i)) {
- return tensorflow::errors::InvalidArgument(
- "cannot compute ", op->name, " as input #", i,
- " was expected to be a ",
- tensorflow::DataTypeString(kernel->input_type(i)),
- " tensor but is a ",
- tensorflow::DataTypeString(op->inputs[i].dtype()), " tensor");
- }
- }
- return tensorflow::Status::OK();
-}
-
-#ifdef TENSORFLOW_EAGER_USE_XLA
-// Synthesizes and returns a wrapper function over `op`, which must be a
-// primitive op (e.g. matmul).
-//
-// The wrapper function conforms to the function signature expected by
-// _XlaLaunchOp, with input params ordered by . For example, if the op has input params , they will be reordered to as the input params to the synthesized function.
-//
-// It populates `const_input_types`, `arg_input_types` and
-// `op_input_to_func_input` based on the reordering results, that the caller can
-// use them to build an _XlaLaunchOp. On error, it returns NULL, and sets
-// `status` accordingly.
-const tensorflow::FunctionDef* OpToFunction(
- TFE_Op* op, std::vector* const_input_types,
- std::vector* arg_input_types,
- tensorflow::gtl::FlatMap* op_input_to_func_input,
- TF_Status* status) {
- DCHECK(!op->is_function());
-
- tensorflow::FunctionDef fdef;
-
- // Get the OpDef of the op we are trying to encapsulate.
- TFE_Context* ctx = op->ctx;
- const tensorflow::OpRegistrationData* op_data;
- {
- tensorflow::tf_shared_lock l(ctx->functions_mu);
- status->status = ctx->func_lib_def.LookUp(op->name, &op_data);
- if (!status->status.ok()) {
- return nullptr;
- }
- }
- const tensorflow::OpDef& op_def = op_data->op_def;
-
- tensorflow::OpDef* signature = fdef.mutable_signature();
-
- // Handle constant inputs.
- const std::unordered_set const_inputs(
- *tensorflow::XlaOpRegistry::CompileTimeConstantInputs(op->name));
-
- // First add place holders for the input args, so that we can refer to them by
- // position in the next loop. Also tally up the resource inputs.
- int num_resource_inputs = 0;
- for (int i = 0; i < op_def.input_arg_size(); ++i) {
- if (op_def.input_arg(i).type() == tensorflow::DT_RESOURCE) {
- ++num_resource_inputs;
- }
- signature->add_input_arg();
- }
-
- // Now we map the input params from `op_def` to `signature`, where the param
- // ordering for `signature` is: .
- int const_index = 0;
- int arg_index = const_inputs.size();
- int resource_index = op_def.input_arg_size() - num_resource_inputs;
- for (int i = 0; i < op_def.input_arg_size(); ++i) {
- const tensorflow::OpDef::ArgDef& op_input_arg = op_def.input_arg(i);
- tensorflow::OpDef::ArgDef* func_input_arg = nullptr;
- if (const_inputs.find(op_input_arg.name()) != const_inputs.end()) {
- VLOG(1) << "For const input, mapping op input " << i << " to func input "
- << const_index;
- (*op_input_to_func_input)[i] = const_index;
- func_input_arg = signature->mutable_input_arg(const_index++);
- const_input_types->push_back(
- static_cast(op->inputs[i].dtype()));
- } else if (op_input_arg.type() == tensorflow::DT_RESOURCE) {
- VLOG(1) << "For resource input, mapping op input " << i
- << " to func input " << resource_index;
- (*op_input_to_func_input)[i] = resource_index;
- func_input_arg = signature->mutable_input_arg(resource_index++);
- } else {
- VLOG(1) << "For arg input, mapping op input " << i << " to func input "
- << arg_index;
- (*op_input_to_func_input)[i] = arg_index;
- func_input_arg = signature->mutable_input_arg(arg_index++);
- arg_input_types->push_back(
- static_cast(op->inputs[i].dtype()));
- }
-
- func_input_arg->set_name(op_input_arg.name());
- func_input_arg->set_type(op->inputs[i].dtype());
- }
- VLOG(1) << "Added OpDef Inputs: " << fdef.DebugString();
-
- // Resources args are at the end of the function input params, and we should
- // have iterated over all of them.
- DCHECK_EQ(signature->input_arg_size(), resource_index);
-
- // Make the synthesized function's name unique.
- signature->set_name(tensorflow::strings::StrCat(
- op_def.name(), func_id_generator.fetch_add(1)));
-
- // Add the node def and set its input names to match op_def's names.
- const tensorflow::NodeDef& ndef = op->attrs.BuildNodeDef();
- DCHECK_EQ(signature->input_arg_size(), ndef.input_size());
- *fdef.add_node_def() = ndef;
- for (int i = 0; i < op_def.input_arg_size(); ++i) {
- fdef.mutable_node_def(0)->set_input(i, op_def.input_arg(i).name());
- }
- VLOG(1) << "Added NodeDef: " << fdef.DebugString();
-
- // Fix the output names and set output types.
- for (int i = 0; i < op_def.output_arg_size(); ++i) {
- tensorflow::OpDef::ArgDef* arg = signature->add_output_arg();
- const tensorflow::OpDef::ArgDef& op_def_arg = op_def.output_arg(i);
- const string& out_tensor_name = tensorflow::strings::StrCat(
- ndef.name(), ":", op_def_arg.name(), ":", 0);
- arg->set_name(op_def_arg.name());
- (*fdef.mutable_ret())[op_def_arg.name()] = out_tensor_name;
- const string& type_attr = op_def_arg.type_attr();
- if (!type_attr.empty()) {
- auto i = ndef.attr().find(type_attr);
- if (i == ndef.attr().end()) {
- status->status = tensorflow::errors::InvalidArgument(
- tensorflow::strings::StrCat("Could not find attr ", type_attr,
- " in NodeDef ", ndef.DebugString()));
- return nullptr;
- }
- arg->set_type(i->second.type());
- }
- }
- VLOG(1) << "Fixed Output names and all types: " << fdef.DebugString();
-
- tensorflow::mutex_lock l(ctx->functions_mu);
- status->status = ctx->func_lib_def.AddFunctionDef(fdef);
- if (!status->status.ok()) return nullptr;
- const auto ret = ctx->func_lib_def.Find(signature->name());
- DCHECK(ret != nullptr);
- return ret;
-}
-
-// Builds an _XLALaunchOp as a wrapper over 'op', so that 'op' can be executed
-// via XLA.
-std::unique_ptr BuildXlaLaunch(TFE_Op* op, TF_Status* status) {
- VLOG(1) << "Creating _XlaLaunchOp for TFE_Op " << op->name;
- auto launch_op =
- std::unique_ptr(TFE_NewOp(op->ctx, "_XlaLaunch", status));
- if (TF_GetCode(status) != TF_OK) return nullptr;
- if (op->device) {
- TFE_OpSetDevice(launch_op.get(), op->device->name().c_str(), status);
- if (TF_GetCode(status) != TF_OK) return nullptr;
- }
-
- const tensorflow::FunctionDef* fdef;
- {
- tensorflow::tf_shared_lock l(op->ctx->functions_mu);
- fdef = op->ctx->func_lib_def.Find(op->name);
- }
- std::vector const_input_types;
- std::vector arg_input_types;
- tensorflow::gtl::FlatMap op_input_to_func_input;
- if (fdef == nullptr) {
- // See if this is a primitive op, and if so create a function for it, so
- // that _XlaLaunchOp can access it.
- fdef = OpToFunction(op, &const_input_types, &arg_input_types,
- &op_input_to_func_input, status);
- if (!status->status.ok()) return nullptr;
- } else {
- // TODO(hongm): XlaOpRegistry::CompileTimeConstantInputs() does not work for
- // functions, so we need to find another way to handle constant inputs.
- for (int i = const_input_types.size();
- i < fdef->signature().input_arg_size(); ++i) {
- VLOG(1) << "Adding Targs from input arg " << i;
- const tensorflow::OpDef::ArgDef& arg = fdef->signature().input_arg(i);
- arg_input_types.push_back(static_cast(arg.type()));
- }
- }
- DCHECK(fdef != nullptr);
-
- // Copy inputs and their devices.
- // Since input param reordering may have occurred between `op` and `launch_op`
- // via `op_input_to_func_input`, adjust the actual inputs accordingly.
- launch_op->inputs = op->inputs;
- launch_op->input_devices = op->input_devices;
- if (!op_input_to_func_input.empty()) {
- DCHECK_EQ(op->inputs.size(), op_input_to_func_input.size());
- if (!op->input_devices.empty()) {
- DCHECK_EQ(op->input_devices.size(), op_input_to_func_input.size());
- }
- for (int i = 0; i < op_input_to_func_input.size(); ++i) {
- VLOG(1) << "mapping op input " << i << " to func input "
- << op_input_to_func_input[i];
-
- launch_op->inputs[op_input_to_func_input[i]] = op->inputs[i];
- if (!op->input_devices.empty()) {
- launch_op->input_devices[op_input_to_func_input[i]] =
- op->input_devices[i];
- }
- }
+ funcs[i].set_name(value[i]->operation.Name());
+ value[i]->operation.Attrs().FillAttrValueMap(funcs[i].mutable_attr());
}
- launch_op->attrs.NumInputs(op->inputs.size());
-
- TFE_OpSetAttrTypeList(launch_op.get(), "Tconstants", const_input_types.data(),
- const_input_types.size());
-
- // Set Targs and Nresources attrs.
- TFE_OpSetAttrTypeList(launch_op.get(), "Targs", arg_input_types.data(),
- arg_input_types.size());
- const int num_resource_inputs = fdef->signature().input_arg_size() -
- const_input_types.size() -
- arg_input_types.size();
- TFE_OpSetAttrInt(launch_op.get(), "Nresources", num_resource_inputs);
-
- // Set Tresults attr.
- std::vector tresults;
- for (const tensorflow::OpDef::ArgDef& arg : fdef->signature().output_arg()) {
- tresults.push_back(static_cast(arg.type()));
- }
- TFE_OpSetAttrTypeList(launch_op.get(), "Tresults", tresults.data(),
- tresults.size());
-
- // Set function attr.
- tensorflow::AttrValue attr_value;
- tensorflow::NameAttrList* func = attr_value.mutable_func();
- func->set_name(fdef->signature().name());
- launch_op->attrs.Set("function", attr_value);
-
- return launch_op;
+ op->operation.MutableAttrs()->Set(
+ attr_name, tensorflow::gtl::ArraySlice(
+ funcs.get(), num_values));
}
-#endif // TENSORFLOW_EAGER_USE_XLA
-} // namespace
void TFE_Execute(TFE_Op* op, TFE_TensorHandle** retvals, int* num_retvals,
TF_Status* status) {
- TFE_Context* ctx = op->ctx;
- // TODO(ashankar): ASSUMPTION: ctx->devices()[0] is always CPU
- tensorflow::Device* device =
- (op->device == nullptr) ? ctx->devices()[0] : op->device;
-
-#ifdef TENSORFLOW_EAGER_USE_XLA
- std::unique_ptr xla_launch_op;
- if (op->use_xla && op->name != "_XlaLaunch") {
- xla_launch_op = BuildXlaLaunch(op, status);
- if (!status->status.ok()) {
- return;
- }
- op = xla_launch_op.get();
- }
-#endif // TENSORFLOW_EAGER_USE_XLA
-
- std::vector outputs(1);
- const tensorflow::MemoryTypeVector* output_memory_types = nullptr;
- tensorflow::Fprint128 cache_key = op->attrs.CacheKey(device->name());
- tensorflow::KernelAndDevice* kernel;
- {
- tensorflow::tf_shared_lock l(ctx->cache_mu);
- kernel = tensorflow::gtl::FindPtrOrNull(ctx->kernel_cache, cache_key);
- }
- if (kernel == nullptr) {
- const tensorflow::NodeDef& ndef = op->attrs.BuildNodeDef();
- kernel = new tensorflow::KernelAndDevice(ctx->rendezvous);
- // Knowledge of the implementation of Init (and in-turn
- // FunctionLibraryRuntime::CreateKernel) tells us that ctx->func_lib_def
- // will be accessed, so grab on to the lock.
- // See WARNING comment below - would be nice to rework to avoid this
- // subtlety.
- tensorflow::tf_shared_lock l(ctx->functions_mu);
- status->status =
- tensorflow::KernelAndDevice::Init(ndef, ctx->func_lib(device), kernel);
- if (!status->status.ok()) {
- delete kernel;
- return;
- }
- tensorflow::mutex_lock ml(ctx->cache_mu);
- tensorflow::gtl::InsertOrUpdate(&(ctx->kernel_cache), cache_key, kernel);
- }
- std::vector copied_tensors;
- status->status = ValidateInputTypeAndPlacement(
- ctx, ctx->devices()[0], device, op, kernel->kernel(), &copied_tensors);
- output_memory_types = &kernel->kernel()->output_memory_types();
+ tensorflow::gtl::InlinedVector handle_retvals(
+ *num_retvals);
+ status->status =
+ tensorflow::EagerExecute(&op->operation, &handle_retvals, num_retvals);
if (!status->status.ok()) {
- for (auto* t : copied_tensors) {
- TFE_DeleteTensorHandle(t);
- }
return;
}
- std::unique_ptr maybe_stats;
- if (ctx->should_store_metadata.load()) {
- maybe_stats.reset(new tensorflow::NodeExecStats);
- maybe_stats->set_node_name(op->name);
- maybe_stats->set_all_start_micros(tensorflow::Env::Default()->NowMicros());
- maybe_stats->set_op_start_rel_micros(0);
- maybe_stats->set_scheduled_micros(tensorflow::Env::Default()->NowMicros());
- // TODO(apassos) track referenced tensors
- }
- // WARNING: kernel->Run utilizes the FunctionLibraryRuntime
- // (ctx->func_lib(device)), which in turn holds a pointer to func_lib_def,
- // which is GUARDED_BY(ctx->functions_mu). But knowledge of the implementation
- // of FunctionLibraryRuntime tells us that func_lib_def is not accessed by
- // FunctionLibraryRuntime::Run(), so there is no thread-safety concern here.
- // This is quite subtle. Re-work things to make this better? (Would it make
- // sense for FunctionLibraryRuntime to ensure thread-safe access to
- // FunctionLibraryDefinition?). TODO(apassos) figure out how to record stats
- // for ops which are a part of functions.
- status->status = kernel->Run(&op->inputs, &outputs, maybe_stats.get());
- for (auto* t : copied_tensors) {
- TFE_DeleteTensorHandle(t);
- }
- if (!status->status.ok()) return;
- if (maybe_stats != nullptr) {
- maybe_stats->set_op_end_rel_micros(tensorflow::Env::Default()->NowMicros() -
- maybe_stats->all_start_micros());
- tensorflow::mutex_lock ml(ctx->metadata_mu);
- if (ctx->should_store_metadata.load()) {
- auto* step_stats = ctx->run_metadata.mutable_step_stats();
- // Lazily initialize the RunMetadata with information about all devices if
- // this is the first call.
- while (step_stats->dev_stats_size() < ctx->devices().size()) {
- step_stats->add_dev_stats();
- }
- // Find the current device's index.
- int device_idx = 0;
- for (int i = 0; i < ctx->devices().size(); ++i) {
- if (ctx->devices()[i] == device) {
- device_idx = i;
- break;
- }
- }
- // Populate the device stats for this device.
- auto* dev_stats = step_stats->mutable_dev_stats(device_idx);
- dev_stats->set_device(device->name());
- *dev_stats->add_node_stats() = *maybe_stats;
- }
- }
- *num_retvals = std::min(*num_retvals, outputs.size());
for (int i = 0; i < *num_retvals; ++i) {
- tensorflow::Device* d = IsCPU(device) ? nullptr : device;
- if (d != nullptr && output_memory_types != nullptr &&
- (*output_memory_types)[i] == tensorflow::HOST_MEMORY) {
- d = nullptr;
- }
- retvals[i] = new TFE_TensorHandle(outputs[i], d);
+ retvals[i] = new TFE_TensorHandle(handle_retvals[i]);
}
}
+TFE_TensorHandle* TFE_TensorHandleCopyToDevice(TFE_TensorHandle* h,
+ TFE_Context* ctx,
+ const char* device_name,
+ TF_Status* status) {
+ tensorflow::TensorHandle* handle;
+ status->status = tensorflow::EagerCopyToDevice(h->handle, &ctx->context,
+ device_name, &handle);
+ if (status->status.ok()) {
+ return new TFE_TensorHandle(handle);
+ }
+ return nullptr;
+}
+
void TFE_ContextAddFunctionDef(TFE_Context* ctx,
const char* serialized_function_def, size_t size,
TF_Status* status) {
@@ -896,46 +590,120 @@ void TFE_ContextAddFunctionDef(TFE_Context* ctx,
tensorflow::errors::InvalidArgument("Invalid FunctionDef proto");
return;
}
- tensorflow::mutex_lock l(ctx->functions_mu);
- status->status = ctx->func_lib_def.AddFunctionDef(function_def);
+ status->status = ctx->context.AddFunctionDef(function_def);
}
void TFE_ContextAddFunction(TFE_Context* ctx, TF_Function* function,
TF_Status* status) {
- tensorflow::mutex_lock l(ctx->functions_mu);
- status->status = ctx->func_lib_def.AddFunctionDef(function->fdef);
+ status->status = ctx->context.AddFunctionDef(function->fdef);
+}
+
+void TFE_ContextEnableRunMetadata(TFE_Context* ctx) {
+ ctx->context.SetShouldStoreMetadata(true);
+}
+
+void TFE_ContextDisableRunMetadata(TFE_Context* ctx) {
+ ctx->context.SetShouldStoreMetadata(false);
}
} // extern "C"
TFE_TensorHandle* TFE_NewTensorHandle(const tensorflow::Tensor& t) {
- return new TFE_TensorHandle(t, nullptr);
+ return new TFE_TensorHandle(t, nullptr, nullptr);
}
const tensorflow::Tensor* TFE_TensorHandleUnderlyingTensorInHostMemory(
TFE_TensorHandle* h, TF_Status* status) {
- if (h->d != nullptr) {
+ tensorflow::Device* d = nullptr;
+ tensorflow::Device* op_device = nullptr;
+ const tensorflow::Tensor* t = nullptr;
+ status->status = h->handle->TensorAndDevice(&t, &d, &op_device);
+ if (!status->status.ok()) return nullptr;
+ if (d != nullptr) {
status->status = tensorflow::errors::FailedPrecondition(
"TFE_TensorHandle is placed in device (not host) memory. Cannot return "
"a tensorflow::Tensor");
return nullptr;
}
- return &h->t;
+ return t;
}
-void TFE_ContextEnableRunMetadata(TFE_Context* ctx) {
- ctx->should_store_metadata.store(true);
+void TFE_ContextExportRunMetadata(TFE_Context* ctx, TF_Buffer* buf,
+ TF_Status* status) {
+ TFE_ContextAsyncWait(ctx, status);
+ if (!status->status.ok()) return;
+ tensorflow::mutex_lock ml(*ctx->context.MetadataMu());
+ status->status = MessageToBuffer(*ctx->context.RunMetadataProto(), buf);
+ ctx->context.RunMetadataProto()->Clear();
}
-void TFE_ContextDisableRunMetadata(TFE_Context* ctx) {
- tensorflow::mutex_lock ml(ctx->metadata_mu);
- ctx->should_store_metadata.store(false);
- ctx->run_metadata.Clear();
+namespace {
+TFE_Op* GetFunc(TFE_Context* ctx, const tensorflow::NameAttrList& func,
+ TF_Status* status) {
+ TFE_Op* func_op = TFE_NewOp(ctx, func.name().data(), status);
+ for (const auto& attr : func.attr()) {
+ if (TF_GetCode(status) != TF_OK) return nullptr;
+ SetOpAttrValueScalar(ctx, func_op, attr.second, attr.first.data(), status);
+ if (TF_GetCode(status) != TF_OK) return nullptr;
+ }
+ return func_op;
}
+} // namespace
-void TFE_ContextExportRunMetadata(TFE_Context* ctx, TF_Buffer* buf,
- TF_Status* status) {
- tensorflow::mutex_lock ml(ctx->metadata_mu);
- status->status = MessageToBuffer(ctx->run_metadata, buf);
- ctx->run_metadata.Clear();
-}
+namespace tensorflow {
+void SetOpAttrValueScalar(TFE_Context* ctx, TFE_Op* op,
+ const tensorflow::AttrValue& default_value,
+ const char* attr_name, TF_Status* status) {
+ switch (default_value.value_case()) {
+ case tensorflow::AttrValue::kS:
+ TFE_OpSetAttrString(op, attr_name, default_value.s().data());
+ break;
+ case tensorflow::AttrValue::kI:
+ TFE_OpSetAttrInt(op, attr_name, static_cast(default_value.i()));
+ break;
+ case tensorflow::AttrValue::kF:
+ TFE_OpSetAttrFloat(op, attr_name, default_value.f());
+ break;
+ case tensorflow::AttrValue::kB:
+ TFE_OpSetAttrBool(op, attr_name, default_value.b());
+ break;
+ case tensorflow::AttrValue::kType:
+ TFE_OpSetAttrType(op, attr_name,
+ static_cast(default_value.type()));
+ break;
+ case tensorflow::AttrValue::kShape: {
+ const auto& tensor_shape = default_value.shape();
+ if (tensor_shape.unknown_rank()) {
+ TFE_OpSetAttrShape(op, attr_name, nullptr, -1, status);
+ } else {
+ const auto num_dims = tensor_shape.dim_size();
+ std::unique_ptr dims(new int64_t[num_dims]);
+ for (int i = 0; i < num_dims; ++i) {
+ dims[i] = tensor_shape.dim(i).size();
+ }
+ TFE_OpSetAttrShape(op, attr_name, dims.get(), num_dims, status);
+ }
+ } break;
+ case tensorflow::AttrValue::kFunc: {
+ const auto func_op = GetFunc(ctx, default_value.func(), status);
+ if (TF_GetCode(status) != TF_OK) return;
+ // TODO(nareshmodi): TFE_OpSetAttrFunction and TFE_OpSetAttrFunctionList
+ // require TFE_Op* and just convert it internally a NameAttrValue, so
+ // consider adding an overload to the C API to make this case easier.
+ TFE_OpSetAttrFunction(op, attr_name, func_op);
+ } break;
+ case tensorflow::AttrValue::kList:
+ TF_FALLTHROUGH_INTENDED;
+ case tensorflow::AttrValue::kTensor:
+ TF_FALLTHROUGH_INTENDED;
+ case tensorflow::AttrValue::kPlaceholder:
+ TF_FALLTHROUGH_INTENDED;
+ case tensorflow::AttrValue::VALUE_NOT_SET:
+ TF_SetStatus(
+ status, TF_UNIMPLEMENTED,
+ tensorflow::strings::StrCat("Unable to get setfor default value: ",
+ default_value.DebugString())
+ .data());
+ }
+}
+} // namespace tensorflow
diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h
index 7a321b54da343fd2b8912187bc620c1e7456db0c..1862af3ce2f505a6e83b4805417eaf335ed07bc0 100644
--- a/tensorflow/c/eager/c_api.h
+++ b/tensorflow/c/eager/c_api.h
@@ -30,7 +30,7 @@ limitations under the License.
#ifdef SWIG
#define TF_CAPI_EXPORT
#else
-#if defined(COMPILER_MSVC)
+#if defined(_WIN32)
#ifdef TF_COMPILE_LIBRARY
#define TF_CAPI_EXPORT __declspec(dllexport)
#else
@@ -38,7 +38,7 @@ limitations under the License.
#endif // TF_COMPILE_LIBRARY
#else
#define TF_CAPI_EXPORT __attribute__((visibility("default")))
-#endif // COMPILER_MSVC
+#endif // _WIN32
#endif // SWIG
#ifdef __cplusplus
@@ -65,17 +65,32 @@ typedef enum TFE_ContextDevicePlacementPolicy {
TFE_DEVICE_PLACEMENT_EXPLICIT = 0,
// Copy the tensor to the right device but log a warning.
TFE_DEVICE_PLACEMENT_WARN = 1,
- // Silently copy the tensor, which has a performance cost since the
- // operation will be blocked till the copy completes.
+ // Silently copy the tensor, which has a performance cost since the operation
+ // will be blocked till the copy completes. This is the default placement
+ // policy.
TFE_DEVICE_PLACEMENT_SILENT = 2,
- // Default placement policy which silently copies int32 tensors but not other
- // dtypes.
+ // Placement policy which silently copies int32 tensors but not other dtypes.
TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32 = 3,
} TFE_ContextDevicePlacementPolicy;
+// Sets the default execution mode (sync/async). Note that this can be
+// overridden per thread using TFE_ContextSetAsyncForThread.
+TF_CAPI_EXPORT extern void TFE_ContextOptionsSetAsync(TFE_ContextOptions*,
+ unsigned char async);
+
TF_CAPI_EXPORT extern void TFE_ContextOptionsSetDevicePlacementPolicy(
TFE_ContextOptions*, TFE_ContextDevicePlacementPolicy);
+// A tensorflow.ServerDef specifies remote workers (in addition to the current
+// workers name). Operations created on this context can then be executed on
+// any of these remote workers by setting an appropriate device.
+//
+// If the following is set, all servers identified by the
+// ServerDef must be up when the context is created.
+TF_CAPI_EXPORT extern void TFE_ContextOptionsSetServerDef(
+ TFE_ContextOptions* options, const void* proto, size_t proto_len,
+ TF_Status* status);
+
// Destroy an options object.
TF_CAPI_EXPORT extern void TFE_DeleteContextOptions(TFE_ContextOptions*);
@@ -108,6 +123,30 @@ TF_CAPI_EXPORT extern void TFE_ContextSetThreadLocalDevicePlacementPolicy(
TF_CAPI_EXPORT extern TFE_ContextDevicePlacementPolicy
TFE_ContextGetDevicePlacementPolicy(TFE_Context*);
+// Overrides the execution mode (sync/async) for the current thread.
+TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context*,
+ unsigned char async,
+ TF_Status* status);
+
+// Causes the calling thread to block till all ops dispatched in async mode
+// have been executed. Note that "execution" here refers to kernel execution /
+// scheduling of copies, etc. Similar to sync execution, it doesn't guarantee
+// that lower level device queues (like GPU streams) have been flushed.
+//
+// This call may not block for execution of ops enqueued concurrently with this
+// call.
+TF_CAPI_EXPORT extern void TFE_ContextAsyncWait(TFE_Context*,
+ TF_Status* status);
+
+// When an error happens, any pending operations are discarded and newly issued
+// ops return an error. This call clears the error state and re-enables
+// execution of newly issued ops.
+//
+// Note that outputs of discarded ops remain in a corrupt state and should not
+// be used for future calls.
+// TODO(agarwal): mark the affected handles and raise errors if they are used.
+TF_CAPI_EXPORT extern void TFE_ContextAsyncClearError(TFE_Context*);
+
// A handle to a tensor on a device.
//
// Like a TF_Tensor, a TFE_TensorHandle refers to a tensor with a value, shape,
@@ -117,13 +156,25 @@ typedef struct TFE_TensorHandle TFE_TensorHandle;
TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_NewTensorHandle(TF_Tensor* t,
TF_Status* status);
+// Indicates that the caller will not be using `h` any more.
TF_CAPI_EXPORT extern void TFE_DeleteTensorHandle(TFE_TensorHandle* h);
TF_CAPI_EXPORT extern TF_DataType TFE_TensorHandleDataType(TFE_TensorHandle* h);
-TF_CAPI_EXPORT extern int TFE_TensorHandleNumDims(TFE_TensorHandle* h);
+// This function will block till the operation that produces `h` has completed.
+TF_CAPI_EXPORT extern int TFE_TensorHandleNumDims(TFE_TensorHandle* h,
+ TF_Status* status);
+// This function will block till the operation that produces `h` has completed.
TF_CAPI_EXPORT extern int64_t TFE_TensorHandleDim(TFE_TensorHandle* h,
- int dim_index);
+ int dim_index,
+ TF_Status* status);
+// This function will block till the operation that produces `h` has completed.
TF_CAPI_EXPORT extern const char* TFE_TensorHandleDeviceName(
- TFE_TensorHandle* h);
+ TFE_TensorHandle* h, TF_Status* status);
+
+// This function will block till the operation that produces `h` has
+// completed. The memory returned might alias the internal memory used by
+// TensorFlow. Hence, callers should not mutate this memory (for example by
+// modifying the memory region pointed to by TF_TensorData() on the returned
+// TF_Tensor).
TF_CAPI_EXPORT extern TF_Tensor* TFE_TensorHandleResolve(TFE_TensorHandle* h,
TF_Status* status);
@@ -133,10 +184,52 @@ TF_CAPI_EXPORT extern TF_Tensor* TFE_TensorHandleResolve(TFE_TensorHandle* h,
// that shares the underlying buffer. Otherwise, it currently requires at least
// one of the source or destination devices to be CPU (i.e., for the source or
// destination tensor to be placed in host memory).
+// If async execution is enabled, the copy may be enqueued and the call will
+// return "non-ready" handle. Else, this function returns after the copy has
+// been done.
TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopyToDevice(
TFE_TensorHandle* h, TFE_Context* ctx, const char* device_name,
TF_Status* status);
+// Debugging/Profiling information for TFE_TensorHandle
+//
+// TFE_TensorDebugInfo contains information useful for debugging and
+// profiling tensors.
+typedef struct TFE_TensorDebugInfo TFE_TensorDebugInfo;
+
+// Retrieves TFE_TensorDebugInfo for `handle`.
+// If TFE_TensorHandleTensorDebugInfo succeeds, `status` is set to OK and caller
+// is responsible for deleting returned TFE_TensorDebugInfo.
+// If TFE_TensorHandleTensorDebugInfo fails, `status` is set to appropriate
+// error and nullptr is returned. This function can block till the operation
+// that produces `handle` has completed.
+TF_CAPI_EXPORT extern TFE_TensorDebugInfo* TFE_TensorHandleTensorDebugInfo(
+ TFE_TensorHandle* handle, TF_Status* status);
+
+// Deletes `debug_info`.
+TF_CAPI_EXPORT extern void TFE_DeleteTensorDebugInfo(
+ TFE_TensorDebugInfo* debug_info);
+
+// Returns the number of dimensions used to represent the tensor on its device.
+// The number of dimensions used to reprensent the tensor on device can be
+// different from the number returned by TFE_TensorHandleNumDims.
+// The return value was current at the time of TFE_TensorDebugInfo creation.
+TF_CAPI_EXPORT extern int TFE_TensorDebugInfoOnDeviceNumDims(
+ TFE_TensorDebugInfo* debug_info);
+
+// Returns the number of elements in dimension `dim_index`.
+// Tensor representation on device can be transposed from its representation
+// on host. The data contained in dimension `dim_index` on device
+// can correspond to the data contained in another dimension in on-host
+// representation. The dimensions are indexed using the standard TensorFlow
+// major-to-minor order (slowest varying dimension first),
+// not the XLA's minor-to-major order.
+// On-device dimensions can be padded. TFE_TensorDebugInfoOnDeviceDim returns
+// the number of elements in a dimension after padding.
+// The return value was current at the time of TFE_TensorDebugInfo creation.
+TF_CAPI_EXPORT extern int64_t TFE_TensorDebugInfoOnDeviceDim(
+ TFE_TensorDebugInfo* debug_info, int dim_index);
+
// Description of the TensorFlow op to execute.
//
// Assumes that the provided 'ctx' outlives the returned TFE_Op, i.e.,
@@ -153,6 +246,7 @@ typedef struct TFE_Op TFE_Op;
TF_CAPI_EXPORT extern TFE_Op* TFE_NewOp(TFE_Context* ctx,
const char* op_or_function_name,
TF_Status* status);
+
TF_CAPI_EXPORT extern void TFE_DeleteOp(TFE_Op* op);
TF_CAPI_EXPORT extern void TFE_OpSetDevice(TFE_Op* op, const char* device_name,
@@ -238,13 +332,21 @@ TF_CAPI_EXPORT extern void TFE_OpSetAttrFunctionList(TFE_Op* op,
int num_values);
// Execute the operation defined by 'op' and return handles to computed
-// tensors in 'retvals'.
+// tensors in `retvals`.
+//
+// 'retvals' must point to a pre-allocated array of TFE_TensorHandle* and
+// '*num_retvals' should be set to the size of this array. It is an error if
+// the size of 'retvals' is less than the number of outputs. This call sets
+// *num_retvals to the number of outputs.
//
-// 'retvals' must point to a pre-allocated array of TFE_TensorHandle*
-// and '*num_retvals' should be set to the size of this array.
+// If async execution is enabled, the call may simply enqueue the execution
+// and return "non-ready" handles in `retvals`. Note that any handles contained
+// in 'op' should not be mutated till the kernel execution actually finishes.
//
-// On return, 'num_retvals' will be set to the actual number of outputs
-// returned by the operation.
+// For sync execution, if any of the inputs to `op` are not ready, this call
+// will block till they become ready and then return when the kernel execution
+// is done.
+// TODO(agarwal): change num_retvals to int from int*.
TF_CAPI_EXPORT extern void TFE_Execute(TFE_Op* op, TFE_TensorHandle** retvals,
int* num_retvals, TF_Status* status);
@@ -270,6 +372,8 @@ TF_CAPI_EXPORT extern void TFE_ContextDisableRunMetadata(TFE_Context* ctx);
// Populates the passed-in buffer with a serialized RunMetadata protocol buffer
// containing any run metadata information accumulated so far and clears this
// information.
+// If async mode is enabled, this call blocks till all currently pending ops are
+// done.
TF_CAPI_EXPORT extern void TFE_ContextExportRunMetadata(TFE_Context* ctx,
TF_Buffer* buf,
TF_Status* status);
diff --git a/tensorflow/c/eager/c_api_debug.cc b/tensorflow/c/eager/c_api_debug.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5006b76f1981d068e99a2c081115ebb3a66d8c7f
--- /dev/null
+++ b/tensorflow/c/eager/c_api_debug.cc
@@ -0,0 +1,167 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include "tensorflow/c/eager/c_api.h"
+
+#include
+
+#include "tensorflow/c/c_api.h"
+#include "tensorflow/c/eager/c_api_internal.h"
+#ifdef TENSORFLOW_EAGER_USE_XLA
+#include "tensorflow/compiler/jit/xla_device.h"
+#endif // TENSORFLOW_EAGER_USE_XLA
+
+using tensorflow::int64;
+using tensorflow::string;
+
+namespace {
+
+std::vector TensorShapeAsVector(TFE_TensorHandle* handle,
+ TF_Status* status) {
+ std::vector shape;
+ int rank = TFE_TensorHandleNumDims(handle, status);
+ if (!status->status.ok()) {
+ return shape;
+ }
+ shape.reserve(rank);
+ for (int i = 0; i < rank; ++i) {
+ shape.push_back(TFE_TensorHandleDim(handle, i, status));
+ if (!status->status.ok()) {
+ return shape;
+ }
+ }
+ return shape;
+}
+
+} // namespace
+
+extern "C" {
+
+TF_CAPI_EXPORT extern TFE_TensorDebugInfo* TFE_TensorHandleTensorDebugInfo(
+ TFE_TensorHandle* handle, TF_Status* status) {
+ const tensorflow::Tensor* tensor;
+ status->status = handle->handle->Tensor(&tensor);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ tensorflow::Device* device;
+ status->status = handle->handle->Device(&device);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+#ifdef TENSORFLOW_EAGER_USE_XLA
+ // If tensor resides on an XLA device, use XLA device's PaddedShapeFn.
+ tensorflow::XlaDevice* xla_device =
+ dynamic_cast(device);
+ if (xla_device != nullptr) {
+ tensorflow::XlaDevice::PaddedShapeFn shape_fn =
+ xla_device->metadata().padded_shape_fn();
+ xla::Shape padded_shape;
+ status->status = shape_fn(*tensor, &padded_shape);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ if (VLOG_IS_ON(3)) {
+ std::vector shape_to_log = TensorShapeAsVector(handle, status);
+ if (!status->status.ok()) {
+ // Ignore the status here as we are simply logging.
+ status->status = tensorflow::Status::OK();
+ } else {
+ VLOG(3) << "Fully padded shape of ["
+ << tensorflow::str_util::Join(shape_to_log, ", ") << "] is "
+ << padded_shape.DebugString();
+ }
+ }
+
+ if (xla::ShapeUtil::IsTuple(padded_shape)) {
+ if (xla::ShapeUtil::TupleElementCount(padded_shape) != 2) {
+ // Currently, the only case of XlaTensor containing a tuple shape is to
+ // represent 64 bit ints, doubles, and complex numbers (we don't support
+ // 64bit complex numbers).
+ status->status = tensorflow::errors::InvalidArgument(
+ "XlaTensors should only contain tuples of size 2. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+
+ // shape0 is not a const& because we will assign it to padded_shape below.
+ // It is illegal to assign a part of a message to itself.
+ xla::Shape shape0 = xla::ShapeUtil::GetTupleElementShape(padded_shape, 0);
+ const xla::Shape& shape1 =
+ xla::ShapeUtil::GetTupleElementShape(padded_shape, 1);
+ if (xla::ShapeUtil::IsTuple(shape0) || xla::ShapeUtil::IsTuple(shape1)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "XlaTensors should not contain nested tuples. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+ if (!xla::ShapeUtil::Equal(shape0, shape1)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Subshapes of XlaTensors should be the same. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+
+ // Since the only case we handle here are two equal subshapes, we
+ // simply return one of them. The caller will interpret it as this
+ // shape directly storing the 64bit types. This approximation is good
+ // enough for this API's debugging use case.
+ padded_shape = shape0;
+ }
+
+ int rank = padded_shape.dimensions_size();
+ std::vector dev_dims;
+ dev_dims.reserve(rank);
+ if (rank == 1) {
+ // Rank 1 tensors might not have padded_shape.layout.minor_to_major set,
+ dev_dims.push_back(padded_shape.dimensions(0));
+ } else {
+ for (int i = rank - 1; i >= 0; --i) {
+ int64 dim_index = padded_shape.layout().minor_to_major(i);
+ dev_dims.push_back(padded_shape.dimensions(dim_index));
+ }
+ }
+ status->status = tensorflow::Status::OK();
+ return new TFE_TensorDebugInfo(dev_dims);
+ }
+#endif // TENSORFLOW_EAGER_USE_XLA
+
+ // If the tensor is not an XLA tensor, the device shape is
+ // the same as regular tensor shape.
+ std::vector dev_dims = TensorShapeAsVector(handle, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ return new TFE_TensorDebugInfo(dev_dims);
+}
+
+TF_CAPI_EXPORT extern void TFE_DeleteTensorDebugInfo(
+ TFE_TensorDebugInfo* debug_info) {
+ delete debug_info;
+}
+
+TF_CAPI_EXPORT extern int TFE_TensorDebugInfoOnDeviceNumDims(
+ TFE_TensorDebugInfo* debug_info) {
+ return debug_info->dev_dims.size();
+}
+
+TF_CAPI_EXPORT extern int64_t TFE_TensorDebugInfoOnDeviceDim(
+ TFE_TensorDebugInfo* debug_info, int dim_index) {
+ return debug_info->dev_dims[dim_index];
+}
+
+} // extern "C"
diff --git a/tensorflow/c/eager/c_api_debug_test.cc b/tensorflow/c/eager/c_api_debug_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cddb9f6e00e9d639026f4bbe061d58f76771c0a9
--- /dev/null
+++ b/tensorflow/c/eager/c_api_debug_test.cc
@@ -0,0 +1,50 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include "tensorflow/c/eager/c_api.h"
+
+#include
+#include "tensorflow/c/eager/c_api_test_util.h"
+#include "tensorflow/core/platform/logging.h"
+#include "tensorflow/core/platform/test.h"
+
+TEST(CApiDebug, ScalarCPU) {
+ TFE_TensorHandle* h = TestScalarTensorHandle();
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorDebugInfo* debug_info = TFE_TensorHandleTensorDebugInfo(h, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ ASSERT_EQ(0, TFE_TensorDebugInfoOnDeviceNumDims(debug_info));
+
+ TFE_DeleteTensorDebugInfo(debug_info);
+ TFE_DeleteTensorHandle(h);
+ TF_DeleteStatus(status);
+}
+
+TEST(CApiDebug, 2DCPU) {
+ TFE_TensorHandle* h = TestMatrixTensorHandle3X2();
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorDebugInfo* debug_info = TFE_TensorHandleTensorDebugInfo(h, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ ASSERT_EQ(2, TFE_TensorDebugInfoOnDeviceNumDims(debug_info));
+ // Shape is the same for CPU tensors.
+ EXPECT_EQ(3, TFE_TensorDebugInfoOnDeviceDim(debug_info, 0));
+ EXPECT_EQ(2, TFE_TensorDebugInfoOnDeviceDim(debug_info, 1));
+
+ TFE_DeleteTensorDebugInfo(debug_info);
+ TFE_DeleteTensorHandle(h);
+ TF_DeleteStatus(status);
+}
diff --git a/tensorflow/c/eager/c_api_internal.h b/tensorflow/c/eager/c_api_internal.h
index 7b9f1db02ed9c53a280c7bd1284165cac4fb6353..04a6efc47c5177c82b7e88168b67cc584587de7c 100644
--- a/tensorflow/c/eager/c_api_internal.h
+++ b/tensorflow/c/eager/c_api_internal.h
@@ -19,18 +19,35 @@ limitations under the License.
#include
#include
+#include