diff --git a/.github/ISSUE_TEMPLATE/40-tflite-op-request.md b/.github/ISSUE_TEMPLATE/40-tflite-op-request.md
new file mode 100644
index 0000000000000000000000000000000000000000..7b391279e479ade4ed5327728f19be8752e11507
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/40-tflite-op-request.md
@@ -0,0 +1,24 @@
+---
+name: TensorFlow Lite Op Request
+about: Use this template for reporting ops you are using or missing.
+
+---
+
+
+**System information**
+- OS Platform and Distribution (e.g., Linux Ubuntu 16.04):
+- TensorFlow installed from (source or binary):
+- TensorFlow version (or github SHA if from source):
+
+
+**Provide the text output from tflite_convert**
+
+```
+# Copy and paste here
+```
+
+Also, please include a link to a GraphDef or the model if possible.
+
+**Any other info / logs**
+
+Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached.
diff --git a/README.md b/README.md
index 8af5370befbb090966a8b3af54d80c84a969aaa5..044174947a094d43a51f7140dd40ec0f17801d40 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,14 @@
|-----------------|
| [](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
+**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 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](https://www.tensorflow.org/guide/summaries_and_tensorboard), a data visualization toolkit.
+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](https://github.com/tensorflow/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
@@ -111,22 +113,24 @@ The TensorFlow project strives to abide by generally accepted best practices in
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
+**IBM ppc64le CPU** | [](http://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Build/) | TBA
**IBM ppc64le GPU** Nightly | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/) | [Nightly](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/)
**IBM ppc64le GPU** Stable Release | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/) | [Release](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/)
**Linux CPU with Intel® MKL-DNN** Nightly | [](https://tensorflow-ci.intel.com/job/tensorflow-mkl-linux-cpu/) | [Nightly](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-whl-nightly/)
**Linux CPU with Intel® MKL-DNN** Python 2.7
**Linux CPU with Intel® MKL-DNN** Python 3.4
**Linux CPU with Intel® MKL-DNN** Python 3.5
**Linux CPU with Intel® MKL-DNN** Python 3.6 | [](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-release-whl/lastStableBuild) | [1.11.0 py2.7](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp27-cp27mu-linux_x86_64.whl)
[1.11.0 py3.4](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp34-cp34m-linux_x86_64.whl)
[1.11.0 py3.5](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp35-cp35m-linux_x86_64.whl)
[1.11.0 py3.6](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp36-cp36m-linux_x86_64.whl)
## For more information
-* [TensorFlow Website](https://www.tensorflow.org)
-* [TensorFlow Tutorials](https://www.tensorflow.org/tutorials/)
-* [TensorFlow Model Zoo](https://github.com/tensorflow/models)
-* [TensorFlow Twitter](https://twitter.com/tensorflow)
-* [TensorFlow Blog](https://medium.com/tensorflow)
-* [TensorFlow Course at Stanford](https://web.stanford.edu/class/cs20si)
-* [TensorFlow Roadmap](https://www.tensorflow.org/community/roadmap)
-* [TensorFlow White Papers](https://www.tensorflow.org/about/bib)
-* [TensorFlow YouTube Channel](https://www.youtube.com/channel/UC0rqucBdTuFTjJiefW5t-IQ)
+
+* [TensorFlow Website](https://www.tensorflow.org)
+* [TensorFlow Tutorials](https://www.tensorflow.org/tutorials/)
+* [TensorFlow Model Zoo](https://github.com/tensorflow/models)
+* [TensorFlow Twitter](https://twitter.com/tensorflow)
+* [TensorFlow Blog](https://medium.com/tensorflow)
+* [TensorFlow Course at Stanford](https://web.stanford.edu/class/cs20si)
+* [TensorFlow Roadmap](https://www.tensorflow.org/community/roadmap)
+* [TensorFlow White Papers](https://www.tensorflow.org/about/bib)
+* [TensorFlow YouTube Channel](https://www.youtube.com/channel/UC0rqucBdTuFTjJiefW5t-IQ)
+* [TensorFlow Visualization Toolkit](https://github.com/tensorflow/tensorboard)
Learn more about the TensorFlow community at the [community page of tensorflow.org](https://www.tensorflow.org/community) for a few ways to participate.
diff --git a/WORKSPACE b/WORKSPACE
index 0c7bc085b512b084b9470abe17326d7c119aa327..7cc08e0164a202581ad7ebbe107a9e19410e70e4 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,5 +1,7 @@
workspace(name = "org_tensorflow")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
http_archive(
name = "io_bazel_rules_closure",
sha256 = "a38539c5b5c358548e75b44141b4ab637bba7c4dc02b46b1f62a96d6433f56ae",
@@ -57,9 +59,9 @@ android_workspace()
# Please add all new TensorFlow dependencies in workspace.bzl.
tf_workspace()
-new_http_archive(
+http_archive(
name = "inception_v1",
- build_file = "models.BUILD",
+ build_file = "//:models.BUILD",
sha256 = "7efe12a8363f09bc24d7b7a450304a15655a57a7751929b2c1593a71183bb105",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/inception_v1.zip",
@@ -67,9 +69,9 @@ new_http_archive(
],
)
-new_http_archive(
+http_archive(
name = "mobile_ssd",
- build_file = "models.BUILD",
+ build_file = "//:models.BUILD",
sha256 = "bddd81ea5c80a97adfac1c9f770e6f55cbafd7cce4d3bbe15fbeb041e6b8f3e8",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_android_export.zip",
@@ -77,9 +79,9 @@ new_http_archive(
],
)
-new_http_archive(
+http_archive(
name = "mobile_multibox",
- build_file = "models.BUILD",
+ build_file = "//:models.BUILD",
sha256 = "859edcddf84dddb974c36c36cfc1f74555148e9c9213dedacf1d6b613ad52b96",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip",
@@ -87,9 +89,9 @@ new_http_archive(
],
)
-new_http_archive(
+http_archive(
name = "stylize",
- build_file = "models.BUILD",
+ build_file = "//:models.BUILD",
sha256 = "3d374a730aef330424a356a8d4f04d8a54277c425e274ecb7d9c83aa912c6bfa",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/stylize_v1.zip",
@@ -97,9 +99,9 @@ new_http_archive(
],
)
-new_http_archive(
+http_archive(
name = "speech_commands",
- build_file = "models.BUILD",
+ build_file = "//:models.BUILD",
sha256 = "c3ec4fea3158eb111f1d932336351edfe8bd515bb6e87aad4f25dbad0a600d0c",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/speech_commands_v0.01.zip",
diff --git a/configure.py b/configure.py
index 234561d94a46f57c4de5ca487360e2d5a3dfdb2f..57a03bd17fac1a3a9942bdacf4661d021a62bbaa 100644
--- a/configure.py
+++ b/configure.py
@@ -238,6 +238,13 @@ def setup_python(environ_cp):
write_to_bazelrc('build --python_path=\"%s"' % python_bin_path)
environ_cp['PYTHON_BIN_PATH'] = python_bin_path
+ # If choosen python_lib_path is from a path specified in the PYTHONPATH
+ # variable, need to tell bazel to include PYTHONPATH
+ if environ_cp.get('PYTHONPATH'):
+ python_paths = environ_cp.get('PYTHONPATH').split(':')
+ if python_lib_path in python_paths:
+ write_action_env_to_bazelrc('PYTHONPATH', environ_cp.get('PYTHONPATH'))
+
# Write tools/python_bin_path.sh
with open(
os.path.join(_TF_WORKSPACE_ROOT, 'tools', 'python_bin_path.sh'),
@@ -445,11 +452,12 @@ def convert_version_to_int(version):
return int(version_str)
-def check_bazel_version(min_version):
- """Check installed bazel version is at least min_version.
+def check_bazel_version(min_version, max_version):
+ """Check installed bazel version is between min_version and max_version.
Args:
min_version: string for minimum bazel version.
+ max_version: string for maximum bazel version.
Returns:
The bazel version detected.
@@ -467,6 +475,7 @@ def check_bazel_version(min_version):
min_version_int = convert_version_to_int(min_version)
curr_version_int = convert_version_to_int(curr_version)
+ max_version_int = convert_version_to_int(max_version)
# Check if current bazel version can be detected properly.
if not curr_version_int:
@@ -480,6 +489,10 @@ def check_bazel_version(min_version):
print('Please upgrade your bazel installation to version %s or higher to '
'build TensorFlow!' % min_version)
sys.exit(0)
+ if curr_version_int > max_version_int:
+ print('Please downgrade your bazel installation to version %s or lower to '
+ 'build TensorFlow!' % min_version)
+ sys.exit(0)
return curr_version
@@ -859,7 +872,7 @@ def set_tf_cuda_version(environ_cp):
cuda_toolkit_paths_full = [
os.path.join(cuda_toolkit_path, x) for x in cuda_rt_lib_paths
]
- if any([os.path.exists(x) for x in cuda_toolkit_paths_full]):
+ if any(os.path.exists(x) for x in cuda_toolkit_paths_full):
break
# Reset and retry
@@ -1552,7 +1565,7 @@ def main():
# environment variables.
environ_cp = dict(os.environ)
- check_bazel_version('0.15.0')
+ check_bazel_version('0.15.0', '0.19.2')
reset_tf_configure_bazelrc()
# Explicitly import tools/bazel.rc, this is needed for Bazel 0.19.0 or later
@@ -1694,6 +1707,7 @@ def main():
config_info_line('nohdfs', 'Disable HDFS support.')
config_info_line('noignite', 'Disable Apacha Ignite support.')
config_info_line('nokafka', 'Disable Apache Kafka support.')
+ config_info_line('nonccl', 'Disable NVIDIA NCCL support.')
if __name__ == '__main__':
diff --git a/tensorflow/BUILD b/tensorflow/BUILD
index 17577afecb74b7008db5a282255278b35ed138a6..fd4b94202aad24a82abef8abd16431f61a8326f0 100644
--- a/tensorflow/BUILD
+++ b/tensorflow/BUILD
@@ -246,6 +246,12 @@ config_setting(
visibility = ["//visibility:public"],
)
+config_setting(
+ name = "no_nccl_support",
+ define_values = {"no_nccl_support": "true"},
+ visibility = ["//visibility:public"],
+)
+
# Crosses between platforms and file system libraries not supported on those
# platforms due to limitations in nested select() statements.
config_setting(
diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py
index 2efb8846c6837a3935e0a8439a18838cb2bea804..d81cf067eb07e88e2b8a86cf5643674235eb3f3b 100644
--- a/tensorflow/api_template.__init__.py
+++ b/tensorflow/api_template.__init__.py
@@ -21,8 +21,6 @@ from __future__ import print_function as _print_function
import os as _os
# pylint: disable=g-bad-import-order
-from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
-
from tensorflow.python.tools import component_api_helper as _component_api_helper
_component_api_helper.package_hook(
parent_package_str=__name__,
@@ -30,8 +28,6 @@ _component_api_helper.package_hook(
# API IMPORTS PLACEHOLDER
-from tensorflow.python.platform import flags # pylint: disable=g-import-not-at-top
-
# Make sure directory containing top level submodules is in
# the __path__ so that "from tensorflow.foo import bar" works.
# We're using bitwise, but there's nothing special about that.
@@ -39,8 +35,9 @@ _tf_api_dir = _os.path.dirname(_os.path.dirname(bitwise.__file__)) # pylint: di
if _tf_api_dir not in __path__:
__path__.append(_tf_api_dir)
-# Calls to enable and disable features.
-enable_eager_execution() # pylint: disable=undefined-variable
+# Enable TF2 behaviors
+from tensorflow.python.compat import compat as _compat # pylint: disable=g-import-not-at-top
+_compat.enable_v2_behavior()
# These symbols appear because we import the python package which
# in turn imports from tensorflow.core and tensorflow.python. They
diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD
index 84238ffc1f2b73c59055461fbeba33687d756208..f653e581bf3beda9fdbf8fb7905a4f9fe170e7fb 100644
--- a/tensorflow/c/BUILD
+++ b/tensorflow/c/BUILD
@@ -121,6 +121,7 @@ tf_cuda_library(
":c_api",
":c_api_internal",
"//tensorflow/c/eager:c_api",
+ "//tensorflow/c/eager:c_api_internal",
"//tensorflow/compiler/jit:flags",
"//tensorflow/contrib/tpu:all_ops",
"//tensorflow/core:core_cpu",
@@ -263,7 +264,7 @@ tf_cuda_cc_test(
tf_cc_test(
name = "c_api_experimental_test",
- size = "small",
+ size = "medium",
srcs = ["c_api_experimental_test.cc"],
data = ["testdata/tf_record"],
linkopts = select({
@@ -274,8 +275,11 @@ tf_cc_test(
# the shared library must be able to use core:framework.
# linkstatic = tf_kernel_tests_linkstatic(),
deps = [
+ ":c_api",
":c_api_experimental",
":c_test_util",
+ "//tensorflow/c/eager:c_api",
+ "//tensorflow/c/eager:c_api_test_util",
"//tensorflow/core:lib",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core:test",
diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc
index f160f204dec50b6495ed11c12c48918611206b01..3693cc85996365360253c8a94c29272a16e11e9a 100644
--- a/tensorflow/c/c_api_experimental.cc
+++ b/tensorflow/c/c_api_experimental.cc
@@ -15,7 +15,10 @@ limitations under the License.
#include "tensorflow/c/c_api_experimental.h"
+#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
+#include "tensorflow/c/eager/c_api.h"
+#include "tensorflow/c/eager/c_api_internal.h"
#include "tensorflow/compiler/jit/flags.h"
#include "tensorflow/core/common_runtime/eager/attr_builder.h"
#include "tensorflow/core/framework/tensor.pb.h"
@@ -23,6 +26,7 @@ limitations under the License.
#include "tensorflow/core/graph/node_builder.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/init_main.h"
+#include "tensorflow/core/platform/net.h"
#include "tensorflow/core/platform/platform.h"
#include "tensorflow/core/protobuf/config.pb.h"
#include "tensorflow/core/protobuf/tensorflow_server.pb.h"
@@ -8740,14 +8744,65 @@ void TFE_TensorHandlePrintDebugString(TFE_TensorHandle* handle) {
TF_DeleteStatus(status);
}
-TF_CAPI_EXPORT extern void TF_MakeInternalErrorStatus(TF_Status* status,
- const char* errMsg) {
+struct TFE_ExecuteOpNotification {
+ TFE_ExecuteOpNotification() : status(TF_NewStatus(), TF_DeleteStatus) {}
+ tensorflow::Notification n;
+ std::unique_ptr thread;
+ std::unique_ptr status;
+};
+
+TFE_ExecuteOpNotification* TFE_ExecuteOpInNewThread(TFE_Op* op,
+ TFE_TensorHandle** retvals,
+ int* num_retvals,
+ TF_Status* status) {
+ TFE_ExecuteOpNotification* n = new TFE_ExecuteOpNotification;
+
+ n->thread.reset(op->operation.EagerContext()->TFEnv()->StartThread(
+ tensorflow::ThreadOptions(), "ExecuteOpThread",
+ [op, retvals, num_retvals, n]() {
+ TFE_Execute(op, retvals, num_retvals, n->status.get());
+ n->n.Notify();
+ }));
+
+ return n;
+}
+
+void TFE_ExecuteOpNotificationWaitAndDelete(
+ TFE_ExecuteOpNotification* notification, TF_Status* status) {
+ if (notification == nullptr) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Passed in notification is a nullptr.");
+
+ return;
+ }
+ if (notification->thread == nullptr) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Passed in notification didn't start a thread correctly. Cleaning up "
+ "this notification. Please re-execute the operation to get a new "
+ "notification.");
+
+ delete notification;
+ return;
+ }
+
+ notification->n.WaitForNotification();
+
+ status->status = notification->status->status;
+
+ delete notification;
+}
+
+void TF_MakeInternalErrorStatus(TF_Status* status, const char* errMsg) {
status->status = tensorflow::errors::Internal(errMsg);
}
// This builder is used in the eager API to build a NodeDef.
struct TF_AttrBuilder : public tensorflow::AttrBuilder {
using tensorflow::AttrBuilder::AttrBuilder;
+ // The string buffers to make sure that any `attr_name` we pass into
+ // `builder->Set()` will outlive the subsequent
+ // `TF_AttrBuilderCheckCanRunOnDevice()` call(s) on the same `builder`.
+ std::set attr_names;
};
TF_AttrBuilder* TF_NewAttrBuilder(const char* op_name) {
@@ -8758,13 +8813,15 @@ void TF_DeleteAttrBuilder(TF_AttrBuilder* builder) { delete builder; }
void TF_AttrBuilderSetType(TF_AttrBuilder* builder, const char* attr_name,
TF_DataType value) {
- builder->Set(attr_name, static_cast(value));
+ auto iter = builder->attr_names.insert(attr_name).first;
+ builder->Set((*iter).c_str(), static_cast(value));
}
void TF_AttrBuilderSetTypeList(TF_AttrBuilder* builder, const char* attr_name,
const TF_DataType* values, int num_values) {
+ auto iter = builder->attr_names.insert(attr_name).first;
builder->Set(
- attr_name,
+ (*iter).c_str(),
tensorflow::gtl::ArraySlice(
reinterpret_cast(values), num_values));
}
@@ -8815,3 +8872,17 @@ int TF_OpIsStateful(const char* op_type, TF_Status* status) {
void TF_InitMain(const char* usage, int* argc, char*** argv) {
tensorflow::port::InitMain(usage, argc, argv);
}
+
+int TF_PickUnusedPortOrDie() {
+ return tensorflow::internal::PickUnusedPortOrDie();
+}
+
+TFE_TensorHandle* TFE_NewTensorHandleFromScalar(TF_DataType dtype_arg,
+ void* data, size_t len) {
+ auto dtype = static_cast(dtype_arg);
+ DCHECK(tensorflow::DataTypeCanUseMemcpy(dtype));
+
+ tensorflow::Tensor tensor(dtype, tensorflow::TensorShape({}));
+ std::memcpy(tensorflow::TensorCApi::Buffer(tensor)->data(), data, len);
+ return new TFE_TensorHandle(tensor, nullptr, nullptr);
+}
diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h
index 25c03df51890a6a599528645aad6ed9ff5b49ff0..80c8bfe594c4c89606efd01bec7f50e7a86b5bda 100644
--- a/tensorflow/c/c_api_experimental.h
+++ b/tensorflow/c/c_api_experimental.h
@@ -180,6 +180,25 @@ TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_DequeueVariantTensor(
TF_CAPI_EXPORT extern void TFE_TensorHandlePrintDebugString(
TFE_TensorHandle* handle);
+typedef struct TFE_ExecuteOpNotification TFE_ExecuteOpNotification;
+
+// Allows invoking a kernel asynchronously, and explicitly returns a
+// notification that can be waited upon. This always executes the kernel in a
+// new thread.
+// 1. `retvals` and `num_retvals` can only be consumed after
+// `TFE_ExecuteOp` returns successfully. They shouldn't be used
+// if the return is unsuccessful
+// 2. These new APIs cannot be used together with the TFE context level async
+// support.
+TF_CAPI_EXPORT extern TFE_ExecuteOpNotification* TFE_ExecuteOpInNewThread(
+ TFE_Op* op, TFE_TensorHandle** retvals, int* num_retvals,
+ TF_Status* status);
+
+// Waits to complete the op execution, and cleans up the notification.
+// Errors reported by op execution are set in `status`.
+TF_CAPI_EXPORT extern void TFE_ExecuteOpNotificationWaitAndDelete(
+ TFE_ExecuteOpNotification* notification, TF_Status* status);
+
TF_CAPI_EXPORT extern void TF_MakeInternalErrorStatus(TF_Status* status,
const char* errMsg);
@@ -218,6 +237,15 @@ TF_CAPI_EXPORT extern int TF_OpIsStateful(const char* op_type,
// this to be called.
TF_CAPI_EXPORT void TF_InitMain(const char* usage, int* argc, char*** argv);
+// Platform-specific implementation to return an unused port. (This should used
+// in tests only.)
+TF_CAPI_EXPORT int TF_PickUnusedPortOrDie();
+
+// Fast path method that makes constructing a single scalar tensor require less
+// overhead and copies.
+TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_NewTensorHandleFromScalar(
+ TF_DataType dtype, void* scalar, size_t len);
+
#ifdef __cplusplus
} /* end extern "C" */
#endif
diff --git a/tensorflow/c/c_api_experimental_test.cc b/tensorflow/c/c_api_experimental_test.cc
index 881dbaf35a5ec470a7e359312e33c4a27752a727..daa7701b7fe7e8ce757b6504329cf6434ad39778 100644
--- a/tensorflow/c/c_api_experimental_test.cc
+++ b/tensorflow/c/c_api_experimental_test.cc
@@ -15,6 +15,8 @@ limitations under the License.
#include "tensorflow/c/c_api_experimental.h"
#include "tensorflow/c/c_test_util.h"
+#include "tensorflow/c/eager/c_api.h"
+#include "tensorflow/c/eager/c_api_test_util.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/logging.h"
@@ -173,5 +175,126 @@ TEST(CAPI_EXPERIMENTAL, IsStateful) {
EXPECT_EQ(id, 0);
}
+TEST(CAPI_EXPERIMENTAL, TFE_ExecuteOpInNewThreadTest_Simple) {
+ TF_Status* status = TF_NewStatus();
+ TFE_ContextOptions* opts = TFE_NewContextOptions();
+ TFE_Context* ctx = TFE_NewContext(opts, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_DeleteContextOptions(opts);
+
+ TFE_TensorHandle* m = TestMatrixTensorHandle();
+
+ TFE_Op* matmul_op = MatMulOp(ctx, m, m);
+
+ TFE_TensorHandle* retvals[1] = {nullptr};
+ int num_retvals = 1;
+
+ auto* r =
+ TFE_ExecuteOpInNewThread(matmul_op, &retvals[0], &num_retvals, status);
+
+ TFE_ExecuteOpNotificationWaitAndDelete(r, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TF_Tensor* t = TFE_TensorHandleResolve(retvals[0], status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ float product[4] = {0};
+ EXPECT_EQ(sizeof(product), TF_TensorByteSize(t));
+ memcpy(&product[0], TF_TensorData(t), TF_TensorByteSize(t));
+ TF_DeleteTensor(t);
+ EXPECT_EQ(7, product[0]);
+ EXPECT_EQ(10, product[1]);
+ EXPECT_EQ(15, product[2]);
+ EXPECT_EQ(22, product[3]);
+
+ TFE_DeleteOp(matmul_op);
+ TFE_DeleteTensorHandle(m);
+
+ TFE_DeleteTensorHandle(retvals[0]);
+ TFE_DeleteContext(ctx);
+ TF_DeleteStatus(status);
+}
+
+// Perform a send/recv test. Recv blocks, so they need to be executed
+// asynchronously.
+TEST(CAPI_EXPERIMENTAL, TFE_ExecuteOpInNewThreadTest_Blocking) {
+ TF_Status* status = TF_NewStatus();
+ TFE_ContextOptions* opts = TFE_NewContextOptions();
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_Context* ctx = TFE_NewContext(opts, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_DeleteContextOptions(opts);
+
+ // Returns a 2x2 float32 Tensor on the CPU, with data 1., 2., 3., 4.
+ TFE_TensorHandle* m = TestMatrixTensorHandle();
+
+ // Build a send op.
+ TFE_Op* send_op = TFE_NewOp(ctx, "_Send", status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(send_op, m, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ string tensor_name = "Tensor";
+ TFE_OpSetAttrType(send_op, "T", TF_FLOAT);
+ TFE_OpSetAttrString(send_op, "tensor_name", tensor_name.c_str(),
+ tensor_name.size());
+ string send_device = "/job:localhost/replica:0/task:0/device:CPU:0";
+ TFE_OpSetAttrString(send_op, "send_device", send_device.c_str(),
+ send_device.size());
+ TFE_OpSetAttrInt(send_op, "send_device_incarnation", 1234);
+ string recv_device = "/job:localhost/replica:0/task:0/device:CPU:0";
+ TFE_OpSetAttrString(send_op, "recv_device", recv_device.c_str(),
+ recv_device.size());
+ TFE_OpSetAttrBool(send_op, "client_terminated", true);
+
+ // Build a recv op.
+ TFE_Op* recv_op = TFE_NewOp(ctx, "_Recv", status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TFE_OpSetAttrType(recv_op, "tensor_type", TF_FLOAT);
+ TFE_OpSetAttrString(recv_op, "tensor_name", tensor_name.c_str(),
+ tensor_name.size());
+ TFE_OpSetAttrString(recv_op, "send_device", send_device.c_str(),
+ send_device.size());
+ TFE_OpSetAttrInt(recv_op, "send_device_incarnation", 1234);
+ TFE_OpSetAttrString(recv_op, "recv_device", recv_device.c_str(),
+ recv_device.size());
+ TFE_OpSetAttrBool(recv_op, "client_terminated", true);
+
+ TFE_TensorHandle* send_retvals;
+ int send_num_retvals = 0;
+ auto* send_result = TFE_ExecuteOpInNewThread(send_op, &send_retvals,
+ &send_num_retvals, status);
+
+ TFE_TensorHandle* recv_retvals[1] = {nullptr};
+ int recv_num_retvals = 1;
+ auto* recv_result = TFE_ExecuteOpInNewThread(recv_op, &recv_retvals[0],
+ &recv_num_retvals, status);
+
+ TFE_ExecuteOpNotificationWaitAndDelete(send_result, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_ExecuteOpNotificationWaitAndDelete(recv_result, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TF_Tensor* t = TFE_TensorHandleResolve(recv_retvals[0], status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ float product[4] = {0};
+ EXPECT_EQ(sizeof(product), TF_TensorByteSize(t));
+ memcpy(&product[0], TF_TensorData(t), TF_TensorByteSize(t));
+ TF_DeleteTensor(t);
+ EXPECT_EQ(1, product[0]);
+ EXPECT_EQ(2, product[1]);
+ EXPECT_EQ(3, product[2]);
+ EXPECT_EQ(4, product[3]);
+
+ TFE_DeleteOp(send_op);
+ TFE_DeleteOp(recv_op);
+ TFE_DeleteTensorHandle(m);
+
+ TFE_DeleteTensorHandle(recv_retvals[0]);
+ TFE_DeleteContext(ctx);
+ TF_DeleteStatus(status);
+}
+
} // namespace
} // namespace tensorflow
diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD
index ba3d8533db7623b8fa7fdf35093abcd1450776b1..c34a84fcfee9b6ba9a7be86ae16e2856a2d343c7 100644
--- a/tensorflow/c/eager/BUILD
+++ b/tensorflow/c/eager/BUILD
@@ -50,6 +50,7 @@ tf_cuda_library(
],
"//conditions:default": [],
}) + [
+ "@com_google_absl//absl/memory",
"//tensorflow/core/common_runtime/eager:eager_operation",
"//tensorflow/core/distributed_runtime/eager:eager_client",
"//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client",
@@ -143,6 +144,7 @@ tf_cuda_cc_test(
"//tensorflow/core:test",
"//tensorflow/core:test_main",
"//tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
+ "@com_google_absl//absl/strings",
],
)
diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc
index 192044915f06e3644aebb200a229cce5f220752b..027d752f420238da867cb9d8c116640e1730caaa 100755
--- a/tensorflow/c/eager/c_api.cc
+++ b/tensorflow/c/eager/c_api.cc
@@ -21,6 +21,7 @@ limitations under the License.
#include
#include
+#include "absl/memory/memory.h"
#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/c/eager/c_api_internal.h"
@@ -80,7 +81,7 @@ tensorflow::Status GetAllRemoteDevices(
const std::vector& remote_workers,
tensorflow::WorkerCacheInterface* worker_cache,
std::unique_ptr* device_mgr) {
- std::vector remote_devices;
+ std::vector> remote_devices;
tensorflow::Status status;
// TODO(nareshmodi) do this in parallel instead of serially.
for (const string& remote_worker : remote_workers) {
@@ -93,7 +94,7 @@ tensorflow::Status GetAllRemoteDevices(
status = s;
if (s.ok()) {
for (tensorflow::Device* d : *devices) {
- remote_devices.push_back(d);
+ remote_devices.emplace_back(d);
}
}
n.Notify();
@@ -101,7 +102,7 @@ tensorflow::Status GetAllRemoteDevices(
n.WaitForNotification();
}
std::unique_ptr remote_device_mgr(
- new tensorflow::DeviceMgr(remote_devices));
+ new tensorflow::DeviceMgr(std::move(remote_devices)));
TF_RETURN_IF_ERROR(status);
@@ -262,13 +263,13 @@ TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx,
void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; }
TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) {
- std::vector devices;
+ 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));
+ new tensorflow::DeviceMgr(std::move(devices)));
tensorflow::Rendezvous* r =
new tensorflow::IntraProcessRendezvous(device_mgr.get());
@@ -410,6 +411,18 @@ const char* TFE_TensorHandleDeviceName(TFE_TensorHandle* h, TF_Status* status) {
: d->name().c_str();
}
+const char* TFE_TensorHandleBackingDeviceName(TFE_TensorHandle* h,
+ TF_Status* status) {
+ if (h == nullptr || h->handle == nullptr) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "The passed in handle is a nullptr");
+ return nullptr;
+ }
+ tensorflow::Device* d = h->handle->device();
+ return (d == nullptr) ? "/job:localhost/replica:0/task:0/device:CPU:0"
+ : d->name().c_str();
+}
+
TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopySharingTensor(
TFE_TensorHandle* h, TF_Status* status) {
if (h == nullptr || h->handle == nullptr) {
diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h
index b2454d872207e26feb3764671474a5d87c01f84d..8d6c8d958d5961fce817156a14eb2b2940c1f2f0 100755
--- a/tensorflow/c/eager/c_api.h
+++ b/tensorflow/c/eager/c_api.h
@@ -169,10 +169,33 @@ TF_CAPI_EXPORT extern int64_t TFE_TensorHandleNumElements(TFE_TensorHandle* h,
TF_CAPI_EXPORT extern int64_t TFE_TensorHandleDim(TFE_TensorHandle* h,
int dim_index,
TF_Status* status);
+
+// Returns the device of the operation that produced `h`.
+// If `h` was produced by a copy, returns the destination device of
+// the copy. Note that returned device name is not always the device
+// holding the tensor handle's memory. If you want the latter, use
+// TFE_TensorHandleBackingDeviceName.
+// This function will block till the operation that produces `h` has completed.
+//
+// Device on which the kernel of the operation that produced `h` ran.
+//
+// If `h` was produced by a copy, returns the destination device of
+// the copy.
+//
+// Note that returned device name is not always the device that owns the memory
+// that backs the tensor handle. For the latter see
+// TFE_TensorHandleBackingDeviceName.
+//
// This function will block till the operation that produces `h` has completed.
TF_CAPI_EXPORT extern const char* TFE_TensorHandleDeviceName(
TFE_TensorHandle* h, TF_Status* status);
+// Returns the name of the device in whose memory `h` resides.
+//
+// This function will block till the operation that produces `h` has completed.
+TF_CAPI_EXPORT extern const char* TFE_TensorHandleBackingDeviceName(
+ TFE_TensorHandle* h, TF_Status* status);
+
// Return a pointer to a new TFE_TensorHandle that shares the underlying tensor
// with `h`. On success, `status` is set to OK. On failure, `status` reflects
// the error and a nullptr is returned.
diff --git a/tensorflow/c/eager/c_api_test.cc b/tensorflow/c/eager/c_api_test.cc
index 0045bb5622647974a3c9f2cdf35bc21e126b4f52..6b39b79ee82f9c7baaf856e573a42b7da65691e5 100644
--- a/tensorflow/c/eager/c_api_test.cc
+++ b/tensorflow/c/eager/c_api_test.cc
@@ -16,6 +16,7 @@ limitations under the License.
#include "tensorflow/c/eager/c_api.h"
#include
+#include "absl/strings/match.h"
#include "tensorflow/c/eager/c_api_test_util.h"
#include "tensorflow/core/distributed_runtime/rpc/grpc_server_lib.h"
#include "tensorflow/core/framework/function.pb.h"
@@ -794,6 +795,14 @@ TEST(CAPI, TensorHandleNullptr) {
TF_SetStatus(status.get(), TF_OK, "");
+ device_name = TFE_TensorHandleBackingDeviceName(h, status.get());
+ ASSERT_EQ(TF_INVALID_ARGUMENT, TF_GetCode(status.get()));
+ ASSERT_EQ(device_name, nullptr);
+ ASSERT_EQ("The passed in handle is a nullptr",
+ string(TF_Message(status.get())));
+
+ TF_SetStatus(status.get(), TF_OK, "");
+
int num_dims = TFE_TensorHandleNumDims(h, status.get());
ASSERT_EQ(TF_INVALID_ARGUMENT, TF_GetCode(status.get()));
ASSERT_EQ(num_dims, -1);
@@ -809,6 +818,62 @@ TEST(CAPI, TensorHandleNullptr) {
string(TF_Message(status.get())));
}
+TEST(CAPI, TensorHandleDevices) {
+ std::unique_ptr status(
+ TF_NewStatus(), TF_DeleteStatus);
+ TFE_ContextOptions* opts = TFE_NewContextOptions();
+ TFE_Context* ctx = TFE_NewContext(opts, status.get());
+ TFE_DeleteContextOptions(opts);
+ ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+
+ TFE_TensorHandle* hcpu = TestMatrixTensorHandle();
+ const char* device_name = TFE_TensorHandleDeviceName(hcpu, status.get());
+ ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+ ASSERT_TRUE(absl::StrContains(device_name, "CPU:0")) << device_name;
+ const char* backing_device_name =
+ TFE_TensorHandleBackingDeviceName(hcpu, status.get());
+ ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+ ASSERT_TRUE(absl::StrContains(backing_device_name, "CPU:0"))
+ << backing_device_name;
+
+ // Disable the test if no GPU is present.
+ string gpu_device_name;
+ if (GetDeviceName(ctx, &gpu_device_name, "GPU")) {
+ TFE_TensorHandle* hgpu = TFE_TensorHandleCopyToDevice(
+ hcpu, ctx, gpu_device_name.c_str(), status.get());
+ ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get());
+
+ TFE_Op* shape_op = ShapeOp(ctx, hgpu);
+ TFE_OpSetDevice(shape_op, gpu_device_name.c_str(), status.get());
+ ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get());
+ TFE_TensorHandle* retvals[1];
+ int num_retvals = 1;
+ TFE_Execute(shape_op, &retvals[0], &num_retvals, status.get());
+ ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get());
+
+ // .device of shape is GPU since the op is executed on GPU
+ device_name = TFE_TensorHandleDeviceName(retvals[0], status.get());
+ ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+ ASSERT_TRUE(absl::StrContains(device_name, "GPU:0")) << device_name;
+
+ // .backing_device of shape is CPU since the tensor is backed by CPU
+ backing_device_name =
+ TFE_TensorHandleBackingDeviceName(retvals[0], status.get());
+ ASSERT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+ ASSERT_TRUE(absl::StrContains(backing_device_name, "CPU:0"))
+ << backing_device_name;
+
+ TFE_DeleteOp(shape_op);
+ TFE_DeleteTensorHandle(retvals[0]);
+ TFE_DeleteTensorHandle(hgpu);
+ }
+
+ TFE_DeleteTensorHandle(hcpu);
+ TFE_ContextAsyncWait(ctx, status.get());
+ EXPECT_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+ TFE_DeleteContext(ctx);
+}
+
void Execute_MatMul_CPU(bool async) {
TF_Status* status = TF_NewStatus();
TFE_ContextOptions* opts = TFE_NewContextOptions();
diff --git a/tensorflow/c/eager/c_api_test_util.cc b/tensorflow/c/eager/c_api_test_util.cc
index 008f088c2dcdd7d9114103516a4702e47a55c6de..bd38127d50c171af801dd1b937acefdba491b4a6 100644
--- a/tensorflow/c/eager/c_api_test_util.cc
+++ b/tensorflow/c/eager/c_api_test_util.cc
@@ -104,6 +104,19 @@ TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b) {
return op;
}
+TFE_Op* ShapeOp(TFE_Context* ctx, TFE_TensorHandle* a) {
+ TF_Status* status = TF_NewStatus();
+
+ TFE_Op* op = TFE_NewOp(ctx, "Shape", status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(op, a, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteStatus(status);
+ TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(a));
+
+ return op;
+}
+
TFE_TensorHandle* TestAxisTensorHandle() {
int64_t dims[] = {1};
int data[] = {1};
diff --git a/tensorflow/c/eager/c_api_test_util.h b/tensorflow/c/eager/c_api_test_util.h
index 474cae67c89249af3a62707f0db00ba458ca8f31..75ef9459e93b4f2ed471c423a34565594efc1714 100644
--- a/tensorflow/c/eager/c_api_test_util.h
+++ b/tensorflow/c/eager/c_api_test_util.h
@@ -37,6 +37,9 @@ TFE_TensorHandle* TestMatrixTensorHandle3X2();
// Return a matmul op multiplying `a` by `b`.
TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b);
+// Return a shape op fetching the shape of `a`.
+TFE_Op* ShapeOp(TFE_Context* ctx, TFE_TensorHandle* a);
+
// Return an 1-D INT32 tensor containing a single value 1.
TFE_TensorHandle* TestAxisTensorHandle();
diff --git a/tensorflow/cc/BUILD b/tensorflow/cc/BUILD
index 83353b79f722f0a95f508b32d4a49b14b35624fb..a09becc49b10d2c58f98fbcc11df5190f794c1d4 100644
--- a/tensorflow/cc/BUILD
+++ b/tensorflow/cc/BUILD
@@ -489,6 +489,7 @@ tf_gen_op_wrappers_cc(
"image_ops",
"io_ops",
"linalg_ops",
+ "list_ops",
"logging_ops",
"lookup_ops",
"manip_ops",
diff --git a/tensorflow/cc/saved_model/BUILD b/tensorflow/cc/saved_model/BUILD
index 3d3895c8fa82c3c0e2974228e9cad767d0e00df4..52345a376cc29ee47ccb9888c9bb26292468b5a9 100644
--- a/tensorflow/cc/saved_model/BUILD
+++ b/tensorflow/cc/saved_model/BUILD
@@ -133,5 +133,6 @@ filegroup(
"testdata/half_plus_two_pbtxt/**",
"testdata/half_plus_two_main_op/**",
"testdata/half_plus_two/**",
+ "testdata/half_plus_two_v2/**",
]),
)
diff --git a/tensorflow/cc/saved_model/constants.h b/tensorflow/cc/saved_model/constants.h
index 645a3f101d1ae7dda88ec4ca622c694dc5a7a919..6f00dc324bd7054b28de2c35023581e1666bfa01 100644
--- a/tensorflow/cc/saved_model/constants.h
+++ b/tensorflow/cc/saved_model/constants.h
@@ -33,10 +33,10 @@ constexpr char kSavedModelFilenamePb[] = "saved_model.pb";
/// SavedModel text format proto filename.
constexpr char kSavedModelFilenamePbTxt[] = "saved_model.pbtxt";
-/// SavedModel legacy init op key.
+/// SavedModel legacy init op collection key. Used in v1 SavedModels.
constexpr char kSavedModelLegacyInitOpKey[] = "legacy_init_op";
-/// SavedModel main op key.
+/// SavedModel main op collection key. Used in v1 SavedModels.
constexpr char kSavedModelMainOpKey[] = "saved_model_main_op";
/// Directory in which to save the SavedModel variables.
@@ -45,6 +45,11 @@ constexpr char kSavedModelVariablesDirectory[] = "variables";
/// SavedModel variables filename.
constexpr char kSavedModelVariablesFilename[] = "variables";
+/// SavedModel SignatureDef keys for the initialization and train ops. Used in
+/// V2 SavedModels.
+constexpr char kSavedModelInitOpSignatureKey[] = "__saved_model_init_op";
+constexpr char kSavedModelTrainOpSignatureKey[] = "__saved_model_train_op";
+
} // namespace tensorflow
#endif // TENSORFLOW_CC_SAVED_MODEL_CONSTANTS_H_
diff --git a/tensorflow/cc/saved_model/loader.cc b/tensorflow/cc/saved_model/loader.cc
index ec116f68cf4b61c9b2d15065916ad9169017b659..85d3dd01fa51b3c3ba6fcbf5faac03f1ff5630e2 100644
--- a/tensorflow/cc/saved_model/loader.cc
+++ b/tensorflow/cc/saved_model/loader.cc
@@ -122,34 +122,54 @@ Status RunOnce(const RunOptions& run_options,
return run_status;
}
-bool HasMainOp(const MetaGraphDef& meta_graph_def) {
+// RunInitOp will return OK if the initialization op was run successfully.
+// An empty init_op_name indicates that there are no init ops to run.
+Status RunInitOp(const RunOptions& run_options, const string& export_dir,
+ const MetaGraphDef& meta_graph_def,
+ const std::vector& asset_file_defs,
+ Session* session, const string& init_op_name) {
+ if (!init_op_name.empty()) {
+ LOG(INFO) << "Running initialization op on SavedModel bundle.";
+ std::vector> inputs;
+ AddAssetsTensorsToInputs(export_dir, asset_file_defs, &inputs);
+ RunMetadata run_metadata;
+ return RunOnce(run_options, inputs, {}, {init_op_name},
+ nullptr /* outputs */, &run_metadata, session);
+ }
+ return Status::OK();
+}
+
+// A SavedModel may store the name of the initialization op to run in the
+// in the SignatureDef (v2) or a collection (v1). If an init_op collection
+// exists, then the collection must contain exactly one op.
+Status GetInitOp(const string& export_dir, const MetaGraphDef& meta_graph_def,
+ string* init_op_name) {
+ const auto& sig_def_map = meta_graph_def.signature_def();
+ const auto& init_op_sig_it =
+ meta_graph_def.signature_def().find(kSavedModelInitOpSignatureKey);
+ if (init_op_sig_it != sig_def_map.end()) {
+ *init_op_name = init_op_sig_it->second.outputs()
+ .find(kSavedModelInitOpSignatureKey)
+ ->second.name();
+ return Status::OK();
+ }
+
const auto& collection_def_map = meta_graph_def.collection_def();
+ string init_op_collection_key;
if (collection_def_map.find(kSavedModelMainOpKey) !=
collection_def_map.end()) {
- return true;
+ init_op_collection_key = kSavedModelMainOpKey;
+ } else {
+ init_op_collection_key = kSavedModelLegacyInitOpKey;
}
- return false;
-}
-Status RunMainOp(const RunOptions& run_options, const string& export_dir,
- const MetaGraphDef& meta_graph_def,
- const std::vector& asset_file_defs,
- Session* session, const string& main_op_key) {
- LOG(INFO) << "Running MainOp with key " << main_op_key
- << " on SavedModel bundle.";
- const auto& collection_def_map = meta_graph_def.collection_def();
- const auto main_op_it = collection_def_map.find(main_op_key);
- if (main_op_it != collection_def_map.end()) {
- if (main_op_it->second.node_list().value_size() != 1) {
+ const auto init_op_it = collection_def_map.find(init_op_collection_key);
+ if (init_op_it != collection_def_map.end()) {
+ if (init_op_it->second.node_list().value_size() != 1) {
return errors::FailedPrecondition(
strings::StrCat("Expected exactly one main op in : ", export_dir));
}
- std::vector> inputs;
- AddAssetsTensorsToInputs(export_dir, asset_file_defs, &inputs);
- RunMetadata run_metadata;
- const StringPiece main_op_name = main_op_it->second.node_list().value(0);
- return RunOnce(run_options, inputs, {}, {string(main_op_name)},
- nullptr /* outputs */, &run_metadata, session);
+ *init_op_name = init_op_it->second.node_list().value(0);
}
return Status::OK();
}
@@ -236,15 +256,12 @@ Status LoadSavedModelInternal(const SessionOptions& session_options,
bundle->meta_graph_def.saver_def().restore_op_name(),
bundle->meta_graph_def.saver_def().filename_tensor_name(),
asset_file_defs, bundle->session.get()));
- if (HasMainOp(bundle->meta_graph_def)) {
- TF_RETURN_IF_ERROR(RunMainOp(run_options, export_dir,
- bundle->meta_graph_def, asset_file_defs,
- bundle->session.get(), kSavedModelMainOpKey));
- } else {
- TF_RETURN_IF_ERROR(RunMainOp(
- run_options, export_dir, bundle->meta_graph_def, asset_file_defs,
- bundle->session.get(), kSavedModelLegacyInitOpKey));
- }
+ string init_op_name;
+ TF_RETURN_IF_ERROR(
+ GetInitOp(export_dir, bundle->meta_graph_def, &init_op_name));
+ TF_RETURN_IF_ERROR(RunInitOp(run_options, export_dir, bundle->meta_graph_def,
+ asset_file_defs, bundle->session.get(),
+ init_op_name));
return Status::OK();
}
diff --git a/tensorflow/cc/saved_model/loader_test.cc b/tensorflow/cc/saved_model/loader_test.cc
index 72b8bc18710b0ee77cb01ed3ad0c2abb5183efb2..597e42bb65ab5536664089f7e65ec52d77fc8f23 100644
--- a/tensorflow/cc/saved_model/loader_test.cc
+++ b/tensorflow/cc/saved_model/loader_test.cc
@@ -36,6 +36,8 @@ constexpr char kTestDataMainOp[] =
"cc/saved_model/testdata/half_plus_two_main_op/00000123";
constexpr char kTestDataSharded[] =
"cc/saved_model/testdata/half_plus_two/00000123";
+constexpr char kTestDataInitOpV2[] =
+ "cc/saved_model/testdata/half_plus_two_v2/00000123";
class LoaderTest : public ::testing::Test {
protected:
@@ -227,5 +229,17 @@ TEST_F(LoaderTest, MaybeSavedModelDirectory) {
EXPECT_FALSE(MaybeSavedModelDirectory(invalid_export_dir));
}
+TEST_F(LoaderTest, SavedModelInitOpV2Format) {
+ SavedModelBundle bundle;
+ SessionOptions session_options;
+ RunOptions run_options;
+
+ const string export_dir =
+ io::JoinPath(testing::TensorFlowSrcRoot(), kTestDataInitOpV2);
+ TF_ASSERT_OK(LoadSavedModel(session_options, run_options, export_dir,
+ {kSavedModelTagServe}, &bundle));
+ CheckSavedModelBundle(export_dir, bundle);
+}
+
} // namespace
} // namespace tensorflow
diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f9ff036688007836524129e23f5cf82edd1e8910
--- /dev/null
+++ b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/assets/foo.txt
@@ -0,0 +1 @@
+asset-file-contents
\ No newline at end of file
diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb
new file mode 100644
index 0000000000000000000000000000000000000000..a10bbf8fb6bca0fcee6414b2927d2f706de85ebc
Binary files /dev/null and b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/saved_model.pb differ
diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.data-00000-of-00001 b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.data-00000-of-00001
new file mode 100644
index 0000000000000000000000000000000000000000..15b75d6ef6bffc336d138d923badb3928b8c4c13
Binary files /dev/null and b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.data-00000-of-00001 differ
diff --git a/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.index b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.index
new file mode 100644
index 0000000000000000000000000000000000000000..7ec9fb4fe2dd21d0a6c324aecd7658fc37cf2326
Binary files /dev/null and b/tensorflow/cc/saved_model/testdata/half_plus_two_v2/00000123/variables/variables.index differ
diff --git a/tensorflow/compiler/aot/codegen.cc b/tensorflow/compiler/aot/codegen.cc
index b17bc658fa06b9feb7edb292bd89ef31e6309169..e0ac7130a64d3928c39440c0e10a2d2e1990b9cd 100644
--- a/tensorflow/compiler/aot/codegen.cc
+++ b/tensorflow/compiler/aot/codegen.cc
@@ -164,7 +164,8 @@ string RewriteWithName(const string& name, string code,
}
// Generate methods for args (inputs).
-Status GenArgMethods(const tf2xla::Config& config, const xla::ProgramShape& ps,
+Status GenArgMethods(const tf2xla::Config& config,
+ const xla::ProgramShapeProto& ps,
const CompileResult& compile_result, string* methods) {
size_t num_args = ps.parameters_size();
if (config.feed_size() != num_args) {
@@ -174,7 +175,8 @@ Status GenArgMethods(const tf2xla::Config& config, const xla::ProgramShape& ps,
}
for (int i = 0; i < num_args; ++i) {
std::vector> rewrites;
- TF_RETURN_IF_ERROR(AddRewritesForShape(i, ps.parameters(i), &rewrites));
+ TF_RETURN_IF_ERROR(
+ AddRewritesForShape(i, xla::Shape(ps.parameters(i)), &rewrites));
const string code = R"(
void set_arg{{NAME}}_data(void* data) {
set_arg_data({{I}}, data);
@@ -204,7 +206,7 @@ Status GenArgMethods(const tf2xla::Config& config, const xla::ProgramShape& ps,
// Generate methods for results (outputs).
Status GenResultMethods(const tf2xla::Config& config,
- const xla::ProgramShape& ps, string* methods) {
+ const xla::ProgramShapeProto& ps, string* methods) {
if (ps.result().element_type() != xla::TUPLE) {
// The XlaCompiler we use to build the xla computation always generates a
// tuple result, and we rely on this to simplify code generation.
@@ -217,8 +219,8 @@ Status GenResultMethods(const tf2xla::Config& config,
}
for (int i = 0; i < ps.result().tuple_shapes_size(); ++i) {
std::vector> rewrites;
- TF_RETURN_IF_ERROR(
- AddRewritesForShape(i, ps.result().tuple_shapes(i), &rewrites));
+ TF_RETURN_IF_ERROR(AddRewritesForShape(
+ i, xla::Shape(ps.result().tuple_shapes(i)), &rewrites));
string code = R"(
{{TYPE}}* result{{NAME}}_data() {
return static_cast<{{TYPE}}*>(result_data({{I}}));
@@ -336,7 +338,7 @@ Status GenerateHeader(const CodegenOpts& opts, const tf2xla::Config& config,
ExtractEntryParamBufferInfos(buffer_infos);
std::vector buffer_infos_for_temps =
ExtractTempBufferInfos(buffer_infos);
- const xla::ProgramShape& ps = compile_result.program_shape;
+ const xla::ProgramShapeProto& ps = compile_result.program_shape;
string methods_arg, methods_result;
TF_RETURN_IF_ERROR(GenArgMethods(config, ps, compile_result, &methods_arg));
TF_RETURN_IF_ERROR(GenResultMethods(config, ps, &methods_result));
@@ -548,8 +550,8 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction {
static const char** StaticResultNames() {{RESULT_NAMES_CODE}}
// Shape of the args and results.
- static const xla::ProgramShape* StaticProgramShape() {
- static const xla::ProgramShape* kShape = {{PROGRAM_SHAPE_SHIM_EXPRESSION}};
+ static const xla::ProgramShapeProto* StaticProgramShape() {
+ static const xla::ProgramShapeProto* kShape = {{PROGRAM_SHAPE_SHIM_EXPRESSION}};
return kShape;
}
@@ -587,7 +589,7 @@ class {{CLASS}} : public tensorflow::XlaCompiledCpuFunction {
{"{{METHODS_RESULT}}\n", methods_result},
{"{{NS_END}}\n", ns_end},
{"{{NS_START}}\n", ns_start},
- {"{{PROGRAM_SHAPE}}", xla::ShapeUtil::HumanString(ps)},
+ {"{{PROGRAM_SHAPE}}", xla::ShapeUtil::HumanString(xla::ProgramShape(ps))},
{"{{PROGRAM_SHAPE_SHIM_EXPRESSION}}",
metadata_result.program_shape_access_shim},
{"{{RESULT_INDEX}}", absl::StrCat(result_index)},
@@ -615,11 +617,11 @@ static string CreateUniqueIdentifier(const CodegenOpts& opts,
Status GenerateMetadata(const CodegenOpts& opts,
const CompileResult& compile_result,
MetadataResult* metadata_result) {
- std::unique_ptr program_shape;
+ std::unique_ptr program_shape;
if (opts.gen_program_shape) {
program_shape =
- absl::make_unique(compile_result.program_shape);
+ absl::make_unique(compile_result.program_shape);
// The parameter names are currently meaningless, and redundant with the
// rest of our metadata, so clear them out to avoid confusion and save
@@ -631,8 +633,8 @@ Status GenerateMetadata(const CodegenOpts& opts,
// a shim that evaluates to nullptr, which is what we want.
ProtobufToEmbed program_shape_protobuf{
- CreateUniqueIdentifier(opts, "ProgramShape"), "xla::ProgramShape",
- program_shape.get()};
+ CreateUniqueIdentifier(opts, "ProgramShapeProto"),
+ "xla::ProgramShapeProto", program_shape.get()};
ProtobufToEmbed hlo_profile_printer_data_protobuf{
CreateUniqueIdentifier(opts, "HloProfilePrinterData"),
diff --git a/tensorflow/compiler/aot/codegen.h b/tensorflow/compiler/aot/codegen.h
index 90410c46a8e36e44454f1219ad76d0fb0937070d..9485e86b10e225a3c9c12eafd9905bdf7c15c9fa 100644
--- a/tensorflow/compiler/aot/codegen.h
+++ b/tensorflow/compiler/aot/codegen.h
@@ -57,7 +57,7 @@ struct MetadataResult {
std::vector header_variable_decls;
// program_shape_access_shim is a C++ expression that constructs the
- // xla::ProgramShape instance for the CompileResult passed to
+ // xla::ProgramShapeProto instance for the CompileResult passed to
// GenerateMetadata.
string program_shape_access_shim;
diff --git a/tensorflow/compiler/aot/codegen_test.cc b/tensorflow/compiler/aot/codegen_test.cc
index bb288d23000527be74f01630d20bbf82e50007ce..c1788ca32a1d099284eeb870f9513891051fd29e 100644
--- a/tensorflow/compiler/aot/codegen_test.cc
+++ b/tensorflow/compiler/aot/codegen_test.cc
@@ -181,13 +181,15 @@ TEST(CodegenTest, Golden) {
BufferInfo::MakeEntryParameter(/*size=*/96, /*param_number=*/1),
BufferInfo::MakeTempBuffer(3), BufferInfo::MakeTempBuffer(120)},
5, {}));
- compile_result.program_shape = xla::ShapeUtil::MakeProgramShape(
- {
- xla::ShapeUtil::MakeShape(xla::F32, {1, 2}),
- xla::ShapeUtil::MakeShape(xla::S64, {3, 4}),
- },
- xla::ShapeUtil::MakeTupleShape(
- {xla::ShapeUtil::MakeShape(xla::U32, {5, 6})}));
+ compile_result.program_shape =
+ xla::ShapeUtil::MakeProgramShape(
+ {
+ xla::ShapeUtil::MakeShape(xla::F32, {1, 2}),
+ xla::ShapeUtil::MakeShape(xla::S64, {3, 4}),
+ },
+ xla::ShapeUtil::MakeTupleShape(
+ {xla::ShapeUtil::MakeShape(xla::U32, {5, 6})}))
+ .ToProto();
compile_result.entry_point = "entry_point";
compile_result.pointer_size = 8;
diff --git a/tensorflow/compiler/aot/codegen_test_h.golden b/tensorflow/compiler/aot/codegen_test_h.golden
index e4d8a02877c75fa72c5747650ab9c7ac229955b3..a2cdab5d1a8e72504ca11b789287d4efd07a59e9 100644
--- a/tensorflow/compiler/aot/codegen_test_h.golden
+++ b/tensorflow/compiler/aot/codegen_test_h.golden
@@ -22,7 +22,7 @@ extern "C" void entry_point(
void* result, const xla::ExecutableRunOptions* run_options,
const void** args, void** temps, tensorflow::int64* profile_counters);
-extern "C" char __tfcompile_foo_bar_MyClass_ProgramShape_protobuf_array_contents[];
+extern "C" char __tfcompile_foo_bar_MyClass_ProgramShapeProto_protobuf_array_contents[];
namespace foo {
@@ -253,10 +253,10 @@ class MyClass : public tensorflow::XlaCompiledCpuFunction {
}
// Shape of the args and results.
- static const xla::ProgramShape* StaticProgramShape() {
- static const xla::ProgramShape* kShape = []() {
- xla::ProgramShape* proto = new xla::ProgramShape;
- proto->ParseFromArray(&__tfcompile_foo_bar_MyClass_ProgramShape_protobuf_array_contents[0], 52);
+ static const xla::ProgramShapeProto* StaticProgramShape() {
+ static const xla::ProgramShapeProto* kShape = []() {
+ xla::ProgramShapeProto* proto = new xla::ProgramShapeProto;
+ proto->ParseFromArray(&__tfcompile_foo_bar_MyClass_ProgramShapeProto_protobuf_array_contents[0], 52);
return proto;
}();
return kShape;
diff --git a/tensorflow/compiler/aot/codegen_test_o.golden b/tensorflow/compiler/aot/codegen_test_o.golden
index eb001c5d45bdfefc76629d7303d89f5480432235..ce8e5ec8c96a2c3696f14b8eea206d648182ecb5 100644
Binary files a/tensorflow/compiler/aot/codegen_test_o.golden and b/tensorflow/compiler/aot/codegen_test_o.golden differ
diff --git a/tensorflow/compiler/aot/compile.cc b/tensorflow/compiler/aot/compile.cc
index 2b5f97b34cd928d32eb220536342c715d91d45bb..9fc223bdc7c0e207ce2005cb86250aa77e709df8 100644
--- a/tensorflow/compiler/aot/compile.cc
+++ b/tensorflow/compiler/aot/compile.cc
@@ -56,17 +56,23 @@ Status CompileXla(xla::CompileOnlyClient* client,
return errors::Unknown("Couldn't get XLA program shape: ",
pshape_or.status().error_message());
}
- compile_result->program_shape = *pshape_or.ValueOrDie();
- xla::ProgramShape* pshape = &compile_result->program_shape;
- std::vector arg_layouts;
- arg_layouts.reserve(pshape->parameters_size());
+ compile_result->program_shape = pshape_or.ValueOrDie()->ToProto();
+ xla::ProgramShapeProto* pshape = &compile_result->program_shape;
+
+ // AotXlaComputationInstance::argument_layouts is a vector of Shape
+ // pointers. Accumulate the Shape objects themselves in a separate vector
+ // while building the vector of pointers.
+ std::vector arg_layout_ptrs(pshape->parameters_size());
+ std::vector arg_layouts(pshape->parameters_size());
for (int i = 0; i < pshape->parameters_size(); ++i) {
- arg_layouts.push_back(pshape->mutable_parameters(i));
+ arg_layouts[i] = xla::Shape(*pshape->mutable_parameters(i));
+ arg_layout_ptrs[i] = &arg_layouts[i];
}
xla::CompileOnlyClient::AotXlaComputationInstance instance;
instance.computation = &computation;
- instance.argument_layouts = std::move(arg_layouts);
- instance.result_layout = &pshape->result();
+ instance.argument_layouts = std::move(arg_layout_ptrs);
+ xla::Shape result_shape(pshape->result());
+ instance.result_layout = &result_shape;
xla::StatusOr>>
aot_or = client->CompileAheadOfTime({instance}, aot_opts);
if (!aot_or.ok()) {
diff --git a/tensorflow/compiler/aot/compile.h b/tensorflow/compiler/aot/compile.h
index e03c5b1aa77c1262ed903aae3072ef65f34d80a2..ee7bb26fabd2d897b85b62f38778ecbfe2238eb6 100644
--- a/tensorflow/compiler/aot/compile.h
+++ b/tensorflow/compiler/aot/compile.h
@@ -33,9 +33,9 @@ namespace tfcompile {
struct CompileResult {
// Contains object file and meta-info.
std::unique_ptr aot;
- xla::ProgramShape program_shape; // Static shape of args and results.
- string entry_point; // Name of generated function.
- int pointer_size = 0; // Size of a pointer in bytes.
+ xla::ProgramShapeProto program_shape; // Static shape of args and results.
+ string entry_point; // Name of generated function.
+ int pointer_size = 0; // Size of a pointer in bytes.
};
// CompileGraph compiles the graph_def into an object file containing a function
diff --git a/tensorflow/compiler/aot/tests/tfcompile_test.cc b/tensorflow/compiler/aot/tests/tfcompile_test.cc
index f10852c7850f61bfd8b99fa9f1648202d182085e..4dd79e5882d7da61be029735ef2b165908c599f9 100644
--- a/tensorflow/compiler/aot/tests/tfcompile_test.cc
+++ b/tensorflow/compiler/aot/tests/tfcompile_test.cc
@@ -526,13 +526,15 @@ TEST(TFCompileTest, ProgramShape) {
// muladd has the program shape defined.
MatMulAndAddComp muladd;
- const xla::ProgramShape* muladd_shape = muladd.ProgramShape();
+ const xla::ProgramShapeProto* muladd_shape = muladd.ProgramShape();
ASSERT_TRUE(muladd_shape != nullptr);
ASSERT_EQ(muladd_shape->parameters_size(), 2);
- EXPECT_TRUE(ShapeUtil::Compatible(muladd_shape->parameters(0), f32_2x2));
- EXPECT_TRUE(ShapeUtil::Compatible(muladd_shape->parameters(1), f32_2x2));
+ EXPECT_TRUE(
+ ShapeUtil::Compatible(xla::Shape(muladd_shape->parameters(0)), f32_2x2));
+ EXPECT_TRUE(
+ ShapeUtil::Compatible(xla::Shape(muladd_shape->parameters(1)), f32_2x2));
- const xla::Shape& muladd_result = muladd_shape->result();
+ const xla::Shape muladd_result(muladd_shape->result());
ASSERT_EQ(muladd_result.element_type(), xla::TUPLE);
ASSERT_EQ(ShapeUtil::TupleElementCount(muladd_result), 2);
const xla::Shape& muladd_result0 =
diff --git a/tensorflow/compiler/jit/BUILD b/tensorflow/compiler/jit/BUILD
index 682c0f0cb05c8c83acac28c8f3abf4f5e355e7c0..be91ed4f432b1890c22900f293fd4196e5c9d970 100644
--- a/tensorflow/compiler/jit/BUILD
+++ b/tensorflow/compiler/jit/BUILD
@@ -23,7 +23,6 @@ package(
load("//tensorflow:tensorflow.bzl", "cc_header_only_library")
load("//tensorflow:tensorflow.bzl", "tf_cc_test")
load("@local_config_cuda//cuda:build_defs.bzl", "if_cuda")
-load("@local_config_cuda//cuda:build_defs.bzl", "if_cuda_is_configured")
load("//tensorflow:tensorflow.bzl", "tf_cuda_cc_test")
load("//tensorflow:tensorflow.bzl", "tf_custom_op_py_library")
@@ -38,7 +37,7 @@ cc_library(
":xla_cpu_device",
":xla_cpu_jit",
"//tensorflow/compiler/plugin",
- ] + if_cuda_is_configured([
+ ] + if_cuda([
":xla_gpu_device",
":xla_gpu_jit",
]),
@@ -51,6 +50,7 @@ cc_library(
deps = [
":jit_compilation_passes",
"//tensorflow/compiler/jit/kernels:xla_ops",
+ "//tensorflow/compiler/tf2xla/kernels:xla_cpu_only_ops",
"//tensorflow/compiler/tf2xla/kernels:xla_dummy_ops",
"//tensorflow/compiler/tf2xla/kernels:xla_ops",
"//tensorflow/compiler/xla/service:cpu_plugin",
@@ -268,6 +268,7 @@ cc_library(
"//tensorflow/compiler/tf2xla:common",
"//tensorflow/compiler/tf2xla:dump_graph",
"//tensorflow/compiler/tf2xla:xla_compiler",
+ "//tensorflow/compiler/xla:debug_options_flags",
"//tensorflow/compiler/xla:statusor",
"//tensorflow/compiler/xla/client:client_library",
"//tensorflow/compiler/xla/client:local_client",
@@ -736,7 +737,10 @@ tf_custom_op_py_library(
visibility = [
":friends",
],
- deps = ["//tensorflow/compiler/jit/ops:xla_ops_wrapper_py"],
+ deps = [
+ "//tensorflow/compiler/jit/ops:xla_ops_grad",
+ "//tensorflow/compiler/jit/ops:xla_ops_wrapper_py",
+ ],
)
# This target can be used by XLA device plugins to prevent circular dependencies, and provides access to all of the required headers for building a device library.
diff --git a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc
index 11df946cc186660242574c2644463a26ead44f1f..48a23a4c1711ac88a329723c46559112d5a39dbd 100644
--- a/tensorflow/compiler/jit/build_xla_ops_pass_test.cc
+++ b/tensorflow/compiler/jit/build_xla_ops_pass_test.cc
@@ -42,14 +42,8 @@ class BuildXlaOpsTest : public ::testing::Test {
.ok());
}
- void TearDown() override {
- for (Device* device : devices_) {
- delete device;
- }
- }
-
private:
- std::vector devices_;
+ std::vector> devices_;
};
using ::tensorflow::testing::FindNodeByName;
diff --git a/tensorflow/compiler/jit/create_xla_launch_op_test.cc b/tensorflow/compiler/jit/create_xla_launch_op_test.cc
index 73866607621cd745f6e640a14405daebf0dd9985..0f872a480f4d4843217f1df3452c4dc62531264e 100644
--- a/tensorflow/compiler/jit/create_xla_launch_op_test.cc
+++ b/tensorflow/compiler/jit/create_xla_launch_op_test.cc
@@ -59,8 +59,9 @@ class CreateXlaLaunchOpTest : public ::testing::Test {
SessionOptions options;
auto* device_count = options.config.mutable_device_count();
device_count->insert({"CPU", 1});
+ std::vector> devices;
TF_CHECK_OK(DeviceFactory::AddDevices(
- options, "/job:localhost/replica:0/task:0", &devices_));
+ options, "/job:localhost/replica:0/task:0", &devices));
FunctionDefLibrary proto;
for (const auto& fdef : flib) {
@@ -69,7 +70,7 @@ class CreateXlaLaunchOpTest : public ::testing::Test {
lib_def_ = absl::make_unique(
OpRegistry::Global(), proto);
OptimizerOptions opts;
- device_mgr_ = absl::make_unique(devices_);
+ device_mgr_ = absl::make_unique(std::move(devices));
pflr_ = absl::make_unique(
device_mgr_.get(), Env::Default(), TF_GRAPH_DEF_VERSION, lib_def_.get(),
opts, /*default_thread_pool=*/nullptr, /*cluster_flr=*/nullptr);
@@ -77,7 +78,6 @@ class CreateXlaLaunchOpTest : public ::testing::Test {
}
FunctionLibraryRuntime* flr_;
- std::vector devices_;
std::unique_ptr device_mgr_;
std::unique_ptr lib_def_;
std::unique_ptr pflr_;
diff --git a/tensorflow/compiler/jit/encapsulate_util.cc b/tensorflow/compiler/jit/encapsulate_util.cc
index 28ec37b1b9c8a1a306b5e778bac5b6ba01c2c997..1f4b9c90a4ff0b1166cdb7b5942771b350740ef3 100644
--- a/tensorflow/compiler/jit/encapsulate_util.cc
+++ b/tensorflow/compiler/jit/encapsulate_util.cc
@@ -86,7 +86,7 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name,
continue;
} else if (src_xla_computation && !dst_xla_computation) {
if (src_outside_compilation) {
- // Case 1d: outside compilation to host computation control edge.
+ // Case 1c: outside compilation to host computation control edge.
edges_to_remove.push_back(e);
TF_RETURN_IF_ERROR(AppendToListAttr(
@@ -94,7 +94,7 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name,
}
} else if (!src_xla_computation && dst_xla_computation) {
if (dst_outside_compilation) {
- // Case 1d: host computation control to outside compilation edge.
+ // Case 1c: host computation control to outside compilation edge.
edges_to_remove.push_back(e);
TF_RETURN_IF_ERROR(AppendToListAttr(
@@ -103,40 +103,24 @@ Status ProcessControlEdges(Graph* g, const string& xla_computation_attr_name,
} else { // src_xla_computation && dst_xla_computation
if (*src_xla_computation != *dst_xla_computation) {
if (src_outside_compilation && dst_outside_compilation) {
- // Case 1c: outside compilation to outside compilation control edge.
+ // Case 1b: outside compilation to outside compilation control edge.
edges_to_remove.push_back(e);
TF_RETURN_IF_ERROR(AppendToListAttr(
e->dst(), kXlaControlDependenciesAttrName, e->src()->name()));
} else if (src_outside_compilation && !dst_outside_compilation) {
- // Case 1b: outside compilation to another XLA computaition control
+ // Case 1a: outside compilation to another XLA computaition control
// edge.
TF_RETURN_IF_ERROR(AppendToListAttr(
e->src(), kXlaConnectedToOtherXlaComputationAttrName,
*dst_xla_computation));
} else if (!src_outside_compilation && dst_outside_compilation) {
- // Case 1b: another XLA computaition to outside compilation control
+ // Case 1a: another XLA computaition to outside compilation control
// edge.
TF_RETURN_IF_ERROR(AppendToListAttr(
e->dst(), kXlaConnectedFromOtherXlaComputationAttrName,
*src_xla_computation));
}
- } else { // *src_xla_computation == *dst_xla_computation
- if (src_outside_compilation && dst_outside_compilation) {
- if (*src_outside_compilation != *dst_outside_compilation) {
- // Case 1c: outside compilation to outside compilation control edge.
- edges_to_remove.push_back(e);
-
- TF_RETURN_IF_ERROR(AppendToListAttr(
- e->dst(), kXlaControlDependenciesAttrName, e->src()->name()));
- }
- } else if (src_outside_compilation && !dst_outside_compilation) {
- // Case 1a: outside compilation to its XLA computation control edge.
- ReplaceAttr(e->src(), kXlaConnectedToXlaComputationAttrName, true);
- } else if (!src_outside_compilation && dst_outside_compilation) {
- // Case 1a: XLA computation to outside compilation in it control edge.
- ReplaceAttr(e->dst(), kXlaConnectedFromXlaComputationAttrName, true);
- }
}
}
}
@@ -181,12 +165,6 @@ Status ProcessXlaToXlaDataEdges(Graph* g,
edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()});
VLOG(4) << "XLA -> XLA edge: " << e->DebugString();
}
- } else { // *src_xla_computation == *dst_xla_computation
- if (src_outside_compilation && dst_outside_compilation &&
- *src_outside_compilation != *dst_outside_compilation) {
- edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()});
- VLOG(4) << "XLA -> XLA edge: " << e->DebugString();
- }
}
}
@@ -263,7 +241,7 @@ Status ProcessDataEdgeBetweenOutsideCompilationAndHostComputation(
// Remove the edge from host to outside compilation. Add a placeholder as
// outside compilation node input.
- std::map placeholders;
+ std::map, Node*> placeholders;
for (int i = 0; i < edges.size(); i++) {
Node* dst = g->FindNodeId(edges[i].dst_node_id);
const Edge* e;
@@ -275,9 +253,10 @@ Status ProcessDataEdgeBetweenOutsideCompilationAndHostComputation(
// Find or create placeholder node.
string new_name =
edges[i].is_host_to_outside_compilation
- ? absl::StrCat(src->name(), "_host_to_oc_placeholder")
- : absl::StrCat(src->name(), "_oc_to_host_placeholder");
- auto iter = placeholders.find(new_name);
+ ? absl::StrCat(src->name(), "_host_to_oc_placeholder_", src_output)
+ : absl::StrCat(src->name(), "_oc_to_host_placeholder_", src_output);
+ auto placeholder_index = std::make_pair(src->name(), src_output);
+ auto iter = placeholders.find(placeholder_index);
Node* placeholder_node;
if (iter == placeholders.end()) {
NodeDefBuilder placeholder_builder(new_name, "Placeholder");
@@ -310,7 +289,7 @@ Status ProcessDataEdgeBetweenOutsideCompilationAndHostComputation(
Status s;
placeholder_node = g->AddNode(placeholder_def, &s);
TF_RETURN_IF_ERROR(s);
- placeholders[new_name] = placeholder_node;
+ placeholders[placeholder_index] = placeholder_node;
} else {
placeholder_node = iter->second;
}
@@ -594,14 +573,244 @@ Status AddControlDependencies(
return Status::OK();
}
+// Step 1 for `PreprocessEdgesBetweenOutsideCompilations`. See comments of
+// `PreprocessEdgesBetweenOutsideCompilations` for details.
+Status PreprocessControlEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ // Gather edges to remove. We should not remove the edge while iterating.
+ std::vector edges_to_remove;
+ for (const Edge* e : g->edges()) {
+ if (!e->IsControlEdge()) {
+ continue;
+ }
+
+ auto src_outside_compilation =
+ GetStringAttr(*e->src(), outside_compilation_attr_name);
+ auto dst_outside_compilation =
+ GetStringAttr(*e->dst(), outside_compilation_attr_name);
+
+ if (src_outside_compilation && dst_outside_compilation) {
+ if (*src_outside_compilation != *dst_outside_compilation) {
+ // Case 1a: outside compilation to outside compilation control edge.
+ edges_to_remove.push_back(e);
+
+ TF_RETURN_IF_ERROR(AppendToListAttr(
+ e->dst(), kXlaControlDependenciesWithinXlaClusterAttrName,
+ e->src()->name()));
+ }
+ } else if (src_outside_compilation && !dst_outside_compilation) {
+ // Case 1b: outside compilation to its XLA computation control edge.
+ ReplaceAttr(e->src(), kXlaConnectedToXlaComputationAttrName, true);
+ } else if (!src_outside_compilation && dst_outside_compilation) {
+ // Case 1b: XLA computation to outside compilation in it control edge.
+ ReplaceAttr(e->dst(), kXlaConnectedFromXlaComputationAttrName, true);
+ }
+ }
+
+ for (auto e : edges_to_remove) {
+ g->RemoveEdge(e);
+ }
+ return Status::OK();
+}
+
+// Step 2 for `PreprocessEdgesBetweenOutsideCompilations`. See comments of
+// `PreprocessEdgesBetweenOutsideCompilations` for details.
+Status PreprocessDataEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ // Gather edges between outside compilation and host computation. Notice that
+ // we do not store `Edge*` directly because we remove some nodes while adding
+ // Identity nodes, and those Edge pointers might be invalidated.
+ struct EdgeInfo {
+ int dst_input, dst_node_id;
+ };
+ std::vector edges;
+ for (const Edge* e : g->edges()) {
+ if (e->IsControlEdge()) {
+ continue;
+ }
+
+ auto src_outside_compilation =
+ GetStringAttr(*e->src(), outside_compilation_attr_name);
+ auto dst_outside_compilation =
+ GetStringAttr(*e->dst(), outside_compilation_attr_name);
+
+ if (src_outside_compilation && dst_outside_compilation &&
+ *src_outside_compilation != *dst_outside_compilation) {
+ edges.push_back(EdgeInfo{e->dst_input(), e->dst()->id()});
+ VLOG(4) << "Oc -> oc edge: " << e->DebugString();
+ }
+ }
+
+ // Remove the edge from host to outside compilation. Add a placeholder as
+ // outside compilation node input.
+ std::map, Node*> placeholders;
+ for (int i = 0; i < edges.size(); i++) {
+ Node* dst = g->FindNodeId(edges[i].dst_node_id);
+ const Edge* e;
+ TF_RETURN_IF_ERROR(dst->input_edge(edges[i].dst_input, &e));
+ Node* src = e->src();
+ int src_output = e->src_output(), dst_input = e->dst_input();
+ g->RemoveEdge(e);
+
+ // Find or create placeholder node.
+ string new_name =
+ absl::StrCat(src->name(), "_oc_to_oc_placeholder_", src_output);
+ auto placeholder_index = std::make_pair(src->name(), src_output);
+ auto iter = placeholders.find(placeholder_index);
+ Node* placeholder_node;
+ if (iter == placeholders.end()) {
+ NodeDefBuilder placeholder_builder(new_name, "Placeholder");
+ placeholder_builder.Attr("dtype", src->output_type(src_output));
+ string outside_compilation_attr;
+ TF_RETURN_IF_ERROR(GetNodeAttr(dst->attrs(),
+ outside_compilation_attr_name,
+ &outside_compilation_attr));
+ placeholder_builder.Attr(outside_compilation_attr_name,
+ outside_compilation_attr);
+ placeholder_builder.Attr(kOutsideCompilationOriginalNodeAttrName,
+ src->name());
+ placeholder_builder.Attr(kOutsideCompilationSrcOutputAttrName,
+ src_output);
+ NodeDef placeholder_def;
+ TF_RETURN_IF_ERROR(placeholder_builder.Finalize(&placeholder_def));
+ Status s;
+ placeholder_node = g->AddNode(placeholder_def, &s);
+ TF_RETURN_IF_ERROR(s);
+ placeholders[placeholder_index] = placeholder_node;
+ } else {
+ placeholder_node = iter->second;
+ }
+ g->AddEdge(placeholder_node, 0, dst, dst_input);
+
+ // Replace `e->dst()` because its input node changed.
+ NodeDef new_def = dst->def();
+ *new_def.mutable_input(dst_input) = placeholder_node->name();
+ TF_ASSIGN_OR_RETURN(Node * dst_replace_node, ReplaceNode(g, dst, new_def));
+
+ // Other edge in `edges` might have `e->dst()` as src or dst
+ // node. Before removing `e->dst()`, replace those edges with
+ // corresponding edges for `dst_replace_node`.
+ for (int j = i + 1; j < edges.size(); j++) {
+ if (edges[j].dst_node_id == edges[i].dst_node_id) {
+ edges[j].dst_node_id = dst_replace_node->id();
+ }
+ }
+ }
+ return Status::OK();
+}
+
+// Step 1 for `PostprocessEdgesBetweenOutsideCompilations`. See comments of
+// `PostprocessEdgesBetweenOutsideCompilations` for details.
+Status PostprocessDataEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ // Gather all outside compilation to outside compilation nodes.
+ std::vector placeholder_nodes;
+ for (Node* n : g->nodes()) {
+ if (n->type_string() == "Placeholder" &&
+ HasNodeAttr(n->def(), kOutsideCompilationOriginalNodeAttrName)) {
+ placeholder_nodes.push_back(n);
+ }
+ }
+
+ // Remove the placeholder nodes, and reconnect original edge.
+ auto node_name_index = g->BuildNodeNameIndex();
+ for (auto n : placeholder_nodes) {
+ string node_name;
+ int node_src_output;
+ TF_RETURN_IF_ERROR(GetNodeAttr(
+ n->attrs(), kOutsideCompilationOriginalNodeAttrName, &node_name));
+ TF_RETURN_IF_ERROR(GetNodeAttr(
+ n->attrs(), kOutsideCompilationSrcOutputAttrName, &node_src_output));
+ auto iter = node_name_index.find(node_name);
+ if (iter == node_name_index.end()) {
+ return errors::Internal(
+ "Cannot find original node for oc -> host placeholder node ",
+ node_name);
+ }
+
+ // Change all usage node to use the original node instead.
+ Node* original_node = iter->second;
+ std::vector control_edges;
+ std::vector data_edges;
+ for (auto e : n->out_edges()) {
+ if (e->IsControlEdge()) {
+ control_edges.push_back(e);
+ } else {
+ data_edges.push_back({e->dst(), e->src_output(), e->dst_input()});
+ }
+ }
+ for (const Edge* e : control_edges) {
+ g->AddControlEdge(original_node, e->dst());
+ g->RemoveEdge(e);
+ }
+ for (int i = 0; i < data_edges.size(); i++) {
+ Node* dst = data_edges[i].dst;
+ NodeDef new_def = dst->def();
+ int dst_input = data_edges[i].dst_input;
+ *new_def.mutable_input(dst_input) =
+ absl::StrCat(original_node->name(), ":", node_src_output);
+ TF_ASSIGN_OR_RETURN(Node * replace_node, ReplaceNode(g, dst, new_def));
+
+ const Edge* edge_to_replace = nullptr;
+ TF_RETURN_IF_ERROR(replace_node->input_edge(dst_input, &edge_to_replace));
+ g->RemoveEdge(edge_to_replace);
+ g->AddEdge(original_node, node_src_output, replace_node, dst_input);
+
+ // Other edges might have `dst` as dst node. Update those edges with
+ // `replace_node`.
+ for (int j = i + 1; j < data_edges.size(); j++) {
+ if (data_edges[j].dst == dst) {
+ data_edges[j].dst = replace_node;
+ }
+ }
+
+ // Other placeholder node might have `dst` as original node. Update
+ // `node_name_index` with `replace_node`.
+ node_name_index[replace_node->name()] = replace_node;
+ }
+
+ // Remove placeholder node.
+ g->RemoveNode(n);
+ }
+ return Status::OK();
+}
+
+// Step 2 for `PostprocessEdgesBetweenOutsideCompilations`. See comments of
+// `PostprocessEdgesBetweenOutsideCompilations` for details.
+Status PostprocessControlEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ auto node_name_index = g->BuildNodeNameIndex();
+
+ // Reconnect outside compilation to outside compilation control edge.
+ for (Node* n : g->nodes()) {
+ std::vector control_deps;
+ Status s =
+ GetNodeAttr(n->attrs(), kXlaControlDependenciesWithinXlaClusterAttrName,
+ &control_deps);
+ if (!s.ok()) {
+ if (s.code() != error::NOT_FOUND) {
+ return s;
+ } else {
+ continue;
+ }
+ } else {
+ n->ClearAttr(kXlaControlDependenciesWithinXlaClusterAttrName);
+ for (const string& control_input : control_deps) {
+ auto iter = node_name_index.find(control_input);
+ if (iter == node_name_index.end()) {
+ return errors::Internal("Cannot find original node for ",
+ control_input);
+ }
+ g->AddControlEdge(iter->second, n);
+ }
+ }
+ }
+ return Status::OK();
+}
} // namespace
const char kXlaInferredShapesAttrName[] = "_xla_inferred_shapes";
-const char kXlaConnectedToXlaComputationAttrName[] =
- "_xla_connected_to_xla_computation";
-const char kXlaConnectedFromXlaComputationAttrName[] =
- "_xla_connected_from_xla_computation";
const char kXlaConnectedToOtherXlaComputationAttrName[] =
"_xla_connected_to_other_xla_computation";
const char kXlaConnectedFromOtherXlaComputationAttrName[] =
@@ -616,6 +825,15 @@ const char kHostToOutsideCompilationOriginalNodeAttrName[] =
"_xla_host_to_oc_node_name";
const char kHostToOutsideCompilationSrcOutputAttrName[] =
"_xla_host_to_oc_src_output";
+const char kXlaConnectedToXlaComputationAttrName[] =
+ "_xla_connected_to_xla_computation";
+const char kXlaConnectedFromXlaComputationAttrName[] =
+ "_xla_connected_from_xla_computation";
+const char kOutsideCompilationOriginalNodeAttrName[] =
+ "_xla_oc_to_oc_node_name";
+const char kOutsideCompilationSrcOutputAttrName[] = "_xla_oc_to_oc_src_output";
+const char kXlaControlDependenciesWithinXlaClusterAttrName[] =
+ "_xla_control_dependencies_within_xla_cluster";
Status PerformStaticShapeInferenceBeforeEncapsulation(
Graph* g, const string& xla_computation_attr_name,
@@ -699,4 +917,39 @@ Status PostprocessForEncapsulation(
return Status::OK();
}
+Status PreprocessEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ // Remove edges from source node to outside compilation nodes, and edges
+ // from outside compilation nodes to sink node.
+ std::vector edges_to_remove;
+ for (const Edge* e : g->source_node()->out_edges()) {
+ if (HasNodeAttr(e->dst()->def(), outside_compilation_attr_name)) {
+ edges_to_remove.push_back(e);
+ }
+ }
+ for (const Edge* e : g->sink_node()->in_edges()) {
+ if (HasNodeAttr(e->src()->def(), outside_compilation_attr_name)) {
+ edges_to_remove.push_back(e);
+ }
+ }
+ for (auto e : edges_to_remove) {
+ g->RemoveEdge(e);
+ }
+
+ TF_RETURN_IF_ERROR(PreprocessControlEdgesBetweenOutsideCompilations(
+ g, outside_compilation_attr_name));
+ TF_RETURN_IF_ERROR(PreprocessDataEdgesBetweenOutsideCompilations(
+ g, outside_compilation_attr_name));
+ return Status::OK();
+}
+
+Status PostprocessEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name) {
+ TF_RETURN_IF_ERROR(PostprocessDataEdgesBetweenOutsideCompilations(
+ g, outside_compilation_attr_name));
+ TF_RETURN_IF_ERROR(PostprocessControlEdgesBetweenOutsideCompilations(
+ g, outside_compilation_attr_name));
+ return Status::OK();
+}
+
} // namespace tensorflow
diff --git a/tensorflow/compiler/jit/encapsulate_util.h b/tensorflow/compiler/jit/encapsulate_util.h
index 5e0c4bf6a0cc92d69209595e257989665404db6b..e363bc5754ac395bae262dc67a780a0173efaf5e 100644
--- a/tensorflow/compiler/jit/encapsulate_util.h
+++ b/tensorflow/compiler/jit/encapsulate_util.h
@@ -44,14 +44,6 @@ Status PerformStaticShapeInferenceBeforeEncapsulation(
Graph* g, const string& xla_computation_attr_name,
const string& outside_compilation_attr_name);
-// Attribute indicating that some ops in this node's XLA computation has control
-// dependency on this node. Attribute value will always be "true".
-extern const char kXlaConnectedToXlaComputationAttrName[];
-
-// Attribute indicating that this node has control dependency on some ops in
-// this node's XLA computation. Attribute value will always be "true".
-extern const char kXlaConnectedFromXlaComputationAttrName[];
-
// Attribute indicating that some ops in other XLA computation has control
// dependency on this node. Attribute value will be a list of string (XLA
// computation names).
@@ -81,6 +73,14 @@ extern const char kOutsideCompilationToHostOriginalNodeAttrName[];
// int (src_output for original edge).
extern const char kOutsideCompilationToHostSrcOutputAttrName[];
+// Attribute indicating that some ops in this node's XLA computation has control
+// dependency on this node. Attribute value will always be "true".
+extern const char kXlaConnectedToXlaComputationAttrName[];
+
+// Attribute indicating that this node has control dependency on some ops in
+// this node's XLA computation. Attribute value will always be "true".
+extern const char kXlaConnectedFromXlaComputationAttrName[];
+
// Attribute indicating that this is an Placeholder node added to act as a
// temporary input node for an host node. Attribute value will be string
// (original input node name).
@@ -91,19 +91,31 @@ extern const char kHostToOutsideCompilationOriginalNodeAttrName[];
// for original edge).
extern const char kHostToOutsideCompilationSrcOutputAttrName[];
-// Preprocesses the graph for encapsulation. It will perform the following
-// operations in order:
+// Attribute indicating that this is an Placeholder node added to act as a
+// temporary input node for an outside compilation node. Attribute value will be
+// string (original input node name).
+extern const char kOutsideCompilationOriginalNodeAttrName[];
+
+// Attribute indicating that this is an Placeholder node added to act as a
+// temporary input node for an outside compilation node. Attribute value will be
+// int (src_output for original edge).
+extern const char kOutsideCompilationSrcOutputAttrName[];
+
+// Attribute indicating that this node has control dependencies on some other
+// nodes within the same XLA cluster. Attribute value will be a list of string
+// (node names).
+extern const char kXlaControlDependenciesWithinXlaClusterAttrName[];
+
+// Preprocesses edges between different XLA clusters for encapsulation. It will
+// perform the following operations in order:
//
-// 1a. For control edges between outside compilation and its XLA computation,
-// add attr "kXlaConnected{From, To}XlaComputationAttrName = true" to the
-// outside compilation node.
-// 1b. For control edges between outside compilation and another XLA
+// 1a. For control edges between outside compilation and another XLA
// computation, add attr "kXlaConnected{From, To}OtherXlaComputationAttrName
// = XLA computation node name" to the outside compilation node.
-// 1c. For control edges between different outside compilations, remove the edge
-// and add attr "kXlaControlDependenciesAttrName = src node name" to dst
-// node.
-// 1d. For control edges between outside compilation and host computation,
+// 1b. For control edges between different outside compilations (in different
+// XLA computations), remove the edge and add attr
+// "kXlaControlDependenciesAttrName = src node name" to dst node.
+// 1c. For control edges between outside compilation and host computation,
// remove the edge and add attr "kXlaControlDependenciesAttrName = src node
// name" to dst node.
// 2. For data edges between different XLA computations, if either src or dst
@@ -146,26 +158,53 @@ struct XlaClusterInfo {
const std::map host_compute_core;
};
-// Postprocesses the graph for encapsulation. This function reverts what
-// `PreprocessForEncapsulation` did. It will perform the following operations in
-// order:
+// Postprocesses edges between different XLA clusters for encapsulation. This
+// function reverts what `PreprocessForEncapsulation` did. It will perform the
+// following operations in order:
//
// 1. Remove Placeholder nodes between outside compilation and host computation
// (created in `PreprocessForEncapsulation` step 3).
// 2. Remove Identity nodes created in `PreprocessForEncapsulation` step 2.
-// 3a. Reconnect control edges between different outside compilations (marked by
-// `PreprocessForEncapsulation` step 1c) and control edges between outside
-// compilation and host computation (marked by `PreprocessForEncapsulation`
-// step 1d).
-// 3b. Reconnect control edges between outside compilation and another XLA
-// computation (marked by `PreprocessForEncapsulation` step 1b).
-// Notice that control edges marked by `PreprocessForEncapsulation` step 1a are
-// not handled here. They are handled in `RewriteOutsideCompilationSubgraphFn`.
+// 3a. Reconnect control edges between outside compilation and another XLA
+// computation (marked by `PreprocessForEncapsulation` step 1a).
+// 3b. Reconnect control edges between different outside compilations (marked by
+// `PreprocessForEncapsulation` step 1b).
+// 3c. Reconnect control edges between outside compilation and host computation
+// (marked by `PreprocessForEncapsulation` step 1c).
Status PostprocessForEncapsulation(
Graph* g, const string& xla_computation_attr_name,
const string& outside_compilation_attr_name,
const std::unordered_map& clusters);
+// Preprocesses edges within the same XLA cluster. It will perform the following
+// operations in order:
+//
+// 0. Remove edges from source node to outside compilation nodes, and edges
+// from outside compilation nodes to sink node.
+// 1a. For edges between different outside compilation clusters, remove the edge
+// and add attr "kXlaControlDependenciesWithinXlaClusterAttrName = src node
+// name" to dst node.
+// 1b. For control edges between outside compilation and its XLA computation,
+// add attr "kXlaConnected{From, To}XlaComputationAttrName = true" to the
+// outside compilation node.
+// 2. For data edges between different outside compilations, remove the edge
+// and create a Placeholder node as dst node's input.
+Status PreprocessEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name);
+
+// Postprocesses edges within the same XLA cluster. This function reverts what
+// `PreprocessEdgesBetweenOutsideCompilations` did. It will perform the
+// following operations in order:
+//
+// 1. Remove Placeholder nodes between different outside compilations (created
+// in `PreprocessEdgesBetweenOutsideCompilations` step 2).
+// 2a. Reconnect control edges between different outside compilations (marked by
+// `PreprocessEdgesBetweenOutsideCompilations` step 1a).
+// Notice that control edges marked by
+// `PreprocessEdgesBetweenOutsideCompilations` step 1b are not handled here.
+// They are handled in `RewriteOutsideCompilationSubgraphFn`.
+Status PostprocessEdgesBetweenOutsideCompilations(
+ Graph* g, const string& outside_compilation_attr_name);
} // namespace tensorflow
#endif // TENSORFLOW_COMPILER_JIT_ENCAPSULATE_UTIL_H_
diff --git a/tensorflow/compiler/jit/encapsulate_util_test.cc b/tensorflow/compiler/jit/encapsulate_util_test.cc
index 7255df3112916b7abcc98ff8204efc8c02209b13..3b8b49cb92f3e453883a8e64e12ce3748a5173f6 100644
--- a/tensorflow/compiler/jit/encapsulate_util_test.cc
+++ b/tensorflow/compiler/jit/encapsulate_util_test.cc
@@ -107,28 +107,19 @@ TEST(PreprocessForEncapsulationTest, ControlEdges) {
identity4_node->AddAttr("_xla", "1");
identity4_node->AddAttr("_oc", "0");
identity5_node->AddAttr("_xla", "1");
- // Case 1a: control edges between outside compilation and its XLA computation.
- g.AddControlEdge(add_node, identity0_node);
- g.AddControlEdge(identity0_node, identity1_node);
- // Case 1b: control edges between outside compilation and another XLA
+ // Case 1a: control edges between outside compilation and another XLA
// computation.
g.AddControlEdge(identity0_node, identity3_node);
g.AddControlEdge(identity1_node, identity4_node);
- // Case 1c: control edges between different outside compilations.
+ // Case 1b: control edges between different outside compilations.
g.AddControlEdge(identity0_node, identity4_node);
- // Case 1d: control edges between outside compilation and host computation.
+ // Case 1c: control edges between outside compilation and host computation.
g.AddControlEdge(const0_node, identity0_node);
g.AddControlEdge(identity0_node, identity2_node);
TF_CHECK_OK(PreprocessForEncapsulation(&g, "_xla", "_oc"));
- // Case 1a: add attr "_xla_connected_{from/to}_xla_computation = true" to the
- // outside compilation node.
- EXPECT_TRUE(HasNodeAttr(identity0_node->def(),
- kXlaConnectedFromXlaComputationAttrName));
- EXPECT_TRUE(HasNodeAttr(identity0_node->def(),
- kXlaConnectedToXlaComputationAttrName));
- // Case 1b: add attr "_xla_control_deps_{from/to} = XLA computation node name"
+ // Case 1a: add attr "_xla_control_deps_{from/to} = XLA computation node name"
// to the outside compilation node.
std::vector attr;
TF_CHECK_OK(GetNodeAttr(identity0_node->def(),
@@ -140,13 +131,13 @@ TEST(PreprocessForEncapsulationTest, ControlEdges) {
kXlaConnectedFromOtherXlaComputationAttrName, &attr));
EXPECT_EQ(attr.size(), 1);
EXPECT_EQ(attr[0], "0");
- // Case 1c: add attr "_xla_control_deps = src node name" to dst node.
+ // Case 1b: add attr "_xla_control_deps = src node name" to dst node.
attr.clear();
TF_CHECK_OK(GetNodeAttr(identity4_node->def(),
kXlaControlDependenciesAttrName, &attr));
EXPECT_EQ(attr.size(), 1);
EXPECT_EQ(attr[0], "identity0");
- // Case 1d: add attr "_xla_control_deps = src node name" to dst node.
+ // Case 1c: add attr "_xla_control_deps = src node name" to dst node.
attr.clear();
TF_CHECK_OK(GetNodeAttr(identity0_node->def(),
kXlaControlDependenciesAttrName, &attr));
@@ -162,23 +153,33 @@ TEST(PreprocessForEncapsulationTest, ControlEdges) {
TEST(PreprocessForEncapsulationTest, DataEdges) {
// Build the graph:
// "const_0" and "const_1" in host computation
+ // "identityn0" = ("const_0", "const_1") in host computation 0
// "add0" = "const_0" + "const_1" in XLA computation 0
// "add1" = "add0" + "const_0" in XLA computation 0 & outside compilation 0
// "identity0" = "add1" in XLA computation 0
// "add2" = "add1" + "identity0" in host computation
// "add3" = "add1" + "add2" in XLA computation 1
- // "add4" = "identity0" + "add2" in XLA computation 1 & outside compilation 1
+ // "add4" = "identity0" + "add2" in XLA computation 1 & outside compilation 0
+ // "add5" = "identityn0"[0] + "identityn0"[1] in XLA computation 1 &
+ // outside compilation 0
+ // "identityn1" = ("identityn0"[0], "identityn0"[1]) in XLA computation 1 &
+ // outside compilation 0
// "identity1" = "add4" in XLA computation 1
// "identity2" = "identity1" in host computation
tensorflow::Scope s = tensorflow::Scope::NewRootScope();
Output const_0 = ops::Const(s.WithOpName("const_0"), 1, {});
Output const_1 = ops::Const(s.WithOpName("const_1"), 2, {});
+ auto identityn0 =
+ ops::IdentityN(s.WithOpName("identityn_0"), {const_0, const_1});
Output add0 = ops::Add(s.WithOpName("add0"), const_0, const_1);
Output add1 = ops::Add(s.WithOpName("add1"), add0, const_0);
Output identity0 = ops::Identity(s.WithOpName("identity0"), add1);
Output add2 = ops::Add(s.WithOpName("add2"), add1, identity0);
Output add3 = ops::Add(s.WithOpName("add3"), add1, add2);
Output add4 = ops::Add(s.WithOpName("add4"), identity0, add2);
+ Output add5 = ops::Add(s.WithOpName("add5"), identityn0[0], identityn0[1]);
+ auto identityn1 = ops::IdentityN(s.WithOpName("identityn_1"),
+ {identityn0[0], identityn0[1]});
Output identity1 = ops::Identity(s.WithOpName("identity1"), add4);
Output identity2 = ops::Identity(s.WithOpName("identity2"), add4);
Graph g(OpRegistry::Global());
@@ -189,6 +190,8 @@ TEST(PreprocessForEncapsulationTest, DataEdges) {
Node *add0_node = node_index["add0"], *add1_node = node_index["add1"],
*identity0_node = node_index["identity0"],
*add3_node = node_index["add3"], *add4_node = node_index["add4"],
+ *add5_node = node_index["add5"],
+ *identityn1_node = node_index["identityn_1"],
*identity1_node = node_index["identity1"];
add0_node->AddAttr("_xla", "0");
add1_node->AddAttr("_xla", "0");
@@ -197,6 +200,10 @@ TEST(PreprocessForEncapsulationTest, DataEdges) {
add3_node->AddAttr("_xla", "1");
add4_node->AddAttr("_xla", "1");
add4_node->AddAttr("_oc", "0");
+ add5_node->AddAttr("_xla", "1");
+ add5_node->AddAttr("_oc", "0");
+ identityn1_node->AddAttr("_xla", "1");
+ identityn1_node->AddAttr("_oc", "0");
identity1_node->AddAttr("_xla", "1");
TF_CHECK_OK(PreprocessForEncapsulation(&g, "_xla", "_oc"));
@@ -214,8 +221,9 @@ TEST(PreprocessForEncapsulationTest, DataEdges) {
EXPECT_NE(bridge_identity0_add4, nullptr);
// Step 3: add placeholder for edges between host computation and outside
// compilation.
- EXPECT_EQ(bridge_add1_add3->def().input(0), "add1_oc_to_host_placeholder");
- Node *add1_oc_to_host_placeholder = node_index["add1_oc_to_host_placeholder"];
+ EXPECT_EQ(bridge_add1_add3->def().input(0), "add1_oc_to_host_placeholder_0");
+ Node *add1_oc_to_host_placeholder =
+ node_index["add1_oc_to_host_placeholder_0"];
TF_CHECK_OK(GetNodeAttr(add1_oc_to_host_placeholder->attrs(),
kOutsideCompilationToHostOriginalNodeAttrName, &str));
EXPECT_EQ(str, "add1");
@@ -226,15 +234,34 @@ TEST(PreprocessForEncapsulationTest, DataEdges) {
add4_node = node_index["add4"];
ASSERT_NE(add4_node, nullptr);
EXPECT_EQ(add4_node->def().input(0),
- "bridge_identity0_add4_host_to_oc_placeholder");
+ "bridge_identity0_add4_host_to_oc_placeholder_0");
Node *identity0_host_to_oc_placeholder =
- node_index["bridge_identity0_add4_host_to_oc_placeholder"];
+ node_index["bridge_identity0_add4_host_to_oc_placeholder_0"];
TF_CHECK_OK(GetNodeAttr(identity0_host_to_oc_placeholder->attrs(),
kHostToOutsideCompilationOriginalNodeAttrName, &str));
EXPECT_EQ(str, "bridge_identity0_add4");
TF_CHECK_OK(GetNodeAttr(identity0_host_to_oc_placeholder->attrs(),
kHostToOutsideCompilationSrcOutputAttrName, &i));
EXPECT_EQ(i, 0);
+
+ // Check different placeholder nodes are created for different src_output.
+ Node *placeholder0 = node_index["identityn_0_host_to_oc_placeholder_0"],
+ *placeholder1 = node_index["identityn_0_host_to_oc_placeholder_1"];
+ EXPECT_NE(placeholder0, nullptr);
+ EXPECT_NE(placeholder1, nullptr);
+ // Check we only have 2 placeholder nodes created for "identityn_0".
+ int placeholder_count = 0;
+ for (Node *n : g.nodes()) {
+ if (HasNodeAttr(n->def(), kHostToOutsideCompilationOriginalNodeAttrName)) {
+ string attr;
+ TF_CHECK_OK(GetNodeAttr(
+ n->attrs(), kHostToOutsideCompilationOriginalNodeAttrName, &attr));
+ if (attr == "identityn_0") {
+ ++placeholder_count;
+ }
+ }
+ }
+ EXPECT_EQ(placeholder_count, 2);
}
TEST(PostprocessForEncapsulationTest, ControlEdges) {
diff --git a/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc b/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc
index 2ce6fa73fc448ca83fa392aa909cb385453eb8b6..d334100aa4a915a87fb05d371e0e3379a7ee05f2 100644
--- a/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc
+++ b/tensorflow/compiler/jit/encapsulate_xla_computations_pass.cc
@@ -195,8 +195,11 @@ Status RewriteSubgraph(const std::vector& arg_source_tensors,
e->dst()->attrs().Find(kXlaClusterAttr) == nullptr &&
e->dst()->type_string() != kXlaClusterOutput) {
return errors::InvalidArgument(
- "Undeclared output of XLA computation. A common cause of this error "
- "is variable initializers that depend on the XLA computation. Edge: ",
+ "Undeclared output of XLA computation. Some common causes of this "
+ "error are: 1) variable initializers that depend on the XLA "
+ "computation; 2) gradient computations that depend on the XLA "
+ "computation, which can be mitigated by moving gradient computations "
+ "inside XLA computation. Offending edge: ",
e->src()->name(), ":", e->src_output(), " -> ", e->dst()->name(), ":",
e->dst_input());
}
diff --git a/tensorflow/compiler/jit/extract_outside_compilation_pass.cc b/tensorflow/compiler/jit/extract_outside_compilation_pass.cc
index 8b3587c5087a0651c466f53f3709ba21e75dd273..e3c7e2f89be9b37b51a633dabb099969c181013f 100644
--- a/tensorflow/compiler/jit/extract_outside_compilation_pass.cc
+++ b/tensorflow/compiler/jit/extract_outside_compilation_pass.cc
@@ -366,7 +366,7 @@ Status ReplaceOrRemoveOutsideCompilationCallNode(
// replace this node with compilation result node.
// 3) all outside compilation graphs.
Status ConstructHostGraph(
- const string& xla_cluster_name,
+ const string& xla_cluster_name, const string& outside_compilation_attr_name,
const std::vector& outside_compilation_host_graphs,
FunctionLibraryDefinition* fld, std::unique_ptr* host_graph) {
host_graph->reset(new Graph(fld));
@@ -476,6 +476,10 @@ Status ConstructHostGraph(
host_graph->get(),
std::unordered_set{(*host_graph)->sink_node()});
+ // Postprocess edges between different outside compilations.
+ TF_RETURN_IF_ERROR(PostprocessEdgesBetweenOutsideCompilations(
+ host_graph->get(), outside_compilation_attr_name));
+
if (VLOG_IS_ON(4)) {
dump_graph::DumpGraphToFile(
absl::StrCat("extract_outside_compilation_host_graph_for_",
@@ -801,6 +805,11 @@ Status ExtractOutsideCompilationForFunction(
},
&fbody));
std::unique_ptr fbody_deleter(fbody);
+
+ // Preprocess edges between different outside compilations. They will be
+ // restored in `ConstructHostGraph()`.
+ TF_RETURN_IF_ERROR(PreprocessEdgesBetweenOutsideCompilations(
+ fbody->graph, outside_compilation_attr_name));
if (VLOG_IS_ON(4)) {
dump_graph::DumpGraphToFile(
absl::StrCat("extract_outside_compilation_for_func_before_", func_name),
@@ -860,8 +869,9 @@ Status ExtractOutsideCompilationForFunction(
// Construct host graph.
if (!outside_compilation_host_graphs.empty()) {
- TF_RETURN_IF_ERROR(ConstructHostGraph(
- xla_cluster_name, outside_compilation_host_graphs, fld, host_graph));
+ TF_RETURN_IF_ERROR(
+ ConstructHostGraph(xla_cluster_name, outside_compilation_attr_name,
+ outside_compilation_host_graphs, fld, host_graph));
}
// Remove the outside compilation graphs from function library.
diff --git a/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc b/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc
index c5bd64f004ef98853955372680277e04c16bdc9e..bff956100da661b679b4557fce53671e6cef88c5 100644
--- a/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc
+++ b/tensorflow/compiler/jit/extract_outside_compilation_pass_test.cc
@@ -290,21 +290,18 @@ TEST(ExtractOutsideCompilationForFunctionTest, Basic) {
TF_CHECK_OK(GetNodeAttr(host_compute_1->attrs(), "shapes", &shapes));
EXPECT_EQ(shapes.size(), 1);
EXPECT_EQ(shapes[0].dim_size(), 1);
- // Check XlaHostCompute nodes' "shape_inference_graph" attr. "0" should have a
- // non-empty value, and "1" should have an empty value.
+ // Check XlaHostCompute nodes' "shape_inference_graph" attr. Both should have
+ // empty values.
string shape_inference_graph;
TF_CHECK_OK(GetNodeAttr(host_compute_0->attrs(), "shape_inference_graph",
&shape_inference_graph));
- EXPECT_EQ(shape_inference_graph,
- "_outside_compilation_shape_inference_cluster_0");
+ EXPECT_EQ(shape_inference_graph, "");
TF_CHECK_OK(GetNodeAttr(host_compute_1->attrs(), "shape_inference_graph",
&shape_inference_graph));
EXPECT_EQ(shape_inference_graph, "");
// Check `shape_inference_graphs`.
- EXPECT_EQ(shape_inference_graphs.size(), 1);
- EXPECT_EQ(shape_inference_graphs[0],
- "_outside_compilation_shape_inference_cluster_0");
+ EXPECT_EQ(shape_inference_graphs.size(), 0);
// Check `host_graph`: verify we have key placeholder and sequencer.
Node *key_placeholder = nullptr, *sequencer = nullptr;
@@ -333,8 +330,8 @@ TEST(ExtractOutsideCompilationForFunctionTest, Basic) {
send_recv_nodes.push_back(n);
}
}
- EXPECT_EQ(num_send_from_host, 2);
- EXPECT_EQ(num_recv_at_host, 2);
+ EXPECT_EQ(num_send_from_host, 1);
+ EXPECT_EQ(num_recv_at_host, 1);
for (Node *n : send_recv_nodes) {
Node *input_node;
TF_CHECK_OK(n->input_node(n->num_inputs() - 1, &input_node));
diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass.cc b/tensorflow/compiler/jit/mark_for_compilation_pass.cc
index 60b962d2e8889c287c103078be8a96c2aa32278d..6618e3a58ab7b6374ed775cd6e4e18a6a4975588 100644
--- a/tensorflow/compiler/jit/mark_for_compilation_pass.cc
+++ b/tensorflow/compiler/jit/mark_for_compilation_pass.cc
@@ -72,6 +72,11 @@ struct OperationFilter {
// to resort to a dummy implementation. Currently Assert and CheckNumerics ops
// have dummy XLA implementations.
bool allow_dummy_ops;
+
+ // Whether ops that produce or consume DT_VARIANT values are allowed. We
+ // don't auto-cluster these ops because we don't yet support live-in or
+ // live-out DT_VARIANT values.
+ bool allow_ops_producing_or_consuming_variant;
};
bool IsDummyImplOp(absl::string_view op_name) {
@@ -81,7 +86,13 @@ bool IsDummyImplOp(absl::string_view op_name) {
bool IsStatefulRandomOp(absl::string_view op_name) {
return op_name == "RandomUniform" || op_name == "RandomShuffle" ||
op_name == "RandomUniformInt" || op_name == "RandomStandardNormal" ||
- op_name == "TruncatedNormal";
+ op_name == "TruncatedNormal" || op_name == "Multinomial";
+}
+
+bool OpProducesOrConsumesVariant(const Node& node) {
+ auto is_variant = [](DataType dtype) { return dtype == DT_VARIANT; };
+ return absl::c_any_of(node.input_types(), is_variant) ||
+ absl::c_any_of(node.output_types(), is_variant);
}
bool HasXLAKernel(const Node& node, const DeviceType& jit_device_type) {
@@ -246,6 +257,10 @@ bool IsCompilableCall(const NodeDef& call_def,
if (!op_filter.allow_dummy_ops && IsDummyImplOp(node->type_string())) {
return false;
}
+ if (!op_filter.allow_ops_producing_or_consuming_variant &&
+ OpProducesOrConsumesVariant(*node)) {
+ return false;
+ }
if (!HasXLAKernel(*node, jit_device_type) &&
!IsCompilableCall(node->def(), jit_device_type, op_filter, depth + 1,
lib_runtime)) {
@@ -470,16 +485,15 @@ Status FindCompilationCandidates(
XlaOpRegistry::GetCompilationDevice(device_type.type(), ®istration));
DeviceType jit_device_type(registration->compilation_device_name);
+ bool always_auto_cluster = registration->autoclustering_policy ==
+ XlaOpRegistry::AutoclusteringPolicy::kAlways;
+
OperationFilter op_filter;
op_filter.allow_resource_ops = registration->compile_resource_ops;
- op_filter.allow_stateful_rng_ops =
- (registration->autoclustering_policy ==
- XlaOpRegistry::AutoclusteringPolicy::kAlways);
- op_filter.allow_control_trigger =
- (registration->autoclustering_policy ==
- XlaOpRegistry::AutoclusteringPolicy::kAlways);
- op_filter.allow_dummy_ops = (registration->autoclustering_policy ==
- XlaOpRegistry::AutoclusteringPolicy::kAlways);
+ op_filter.allow_stateful_rng_ops = always_auto_cluster;
+ op_filter.allow_control_trigger = always_auto_cluster;
+ op_filter.allow_dummy_ops = always_auto_cluster;
+ op_filter.allow_ops_producing_or_consuming_variant = always_auto_cluster;
if (!HasXLAKernel(*node, jit_device_type) &&
!IsCompilableCall(node->def(), jit_device_type, op_filter, 0,
@@ -503,6 +517,12 @@ Status FindCompilationCandidates(
<< node->type_string() << ")";
continue;
}
+ if (!op_filter.allow_ops_producing_or_consuming_variant &&
+ OpProducesOrConsumesVariant(*node)) {
+ VLOG(2) << "Rejecting " << node->name()
+ << ": produces or consumes DT_VARIANT";
+ continue;
+ }
if (!op_filter.allow_resource_ops &&
(HasResourceOutput(*node) || IsNonResourceVarResourceOp(*node))) {
@@ -639,6 +659,7 @@ bool IsCompilable(FunctionLibraryRuntime* flr, const NodeDef& ndef) {
op_filter.allow_stateful_rng_ops = true;
op_filter.allow_control_trigger = true;
op_filter.allow_dummy_ops = true;
+ op_filter.allow_ops_producing_or_consuming_variant = true;
return IsCompilableCall(ndef, jit_device_type, op_filter, 0, flr);
}
diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc
index 24d78c077268f83cebbdafddc1a658ae8dc6b8d8..bf2c5508ea9e987e80093f4c2e15d3ff5191126f 100644
--- a/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc
+++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test.cc
@@ -22,6 +22,7 @@ limitations under the License.
#include "tensorflow/cc/ops/array_ops.h"
#include "tensorflow/cc/ops/control_flow_ops_internal.h"
#include "tensorflow/cc/ops/function_ops.h"
+#include "tensorflow/cc/ops/list_ops.h"
#include "tensorflow/cc/ops/resource_variable_ops.h"
#include "tensorflow/cc/ops/sendrecv_ops.h"
#include "tensorflow/cc/ops/standard_ops.h"
@@ -1147,5 +1148,80 @@ TEST(XlaCompilationTest, DontAutoClusterDummyOps) {
EXPECT_EQ(clusters["test/check"], "");
}
+TEST(XlaCompilationTest, DontAutoClusterOpsProducingVariant) {
+ Scope root = Scope::NewRootScope().ExitOnError();
+ Output a = ops::Placeholder(root.WithOpName("test/a"), DT_INT64);
+ Output b = ops::Placeholder(root.WithOpName("test/b"), DT_INT64);
+
+ Output cast_a = ops::Cast(root.WithOpName("test/cast_a"), a, DT_INT32);
+ Output cast_b = ops::Cast(root.WithOpName("test/cast_b"), b, DT_INT32);
+
+ Output tensor_list_reserve = ops::TensorListReserve(
+ root.WithOpName("test/tensor_list_reserve"), cast_a, cast_b, DT_FLOAT);
+
+ std::unique_ptr graph(new Graph(OpRegistry::Global()));
+ TF_ASSERT_OK(root.ToGraph(graph.get()));
+
+ TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph));
+
+ std::unordered_map clusters = GetClusters(*graph);
+ EXPECT_EQ(clusters["test/tensor_list_reserve"], "");
+}
+
+TEST(XlaCompilationTest, DontAutoClusterOpsConsumingVariant) {
+ Scope root = Scope::NewRootScope().ExitOnError();
+ Output dummy_input =
+ ops::Placeholder(root.WithOpName("test/dummy_input"), DT_INT64);
+ Output variant_input =
+ ops::Placeholder(root.WithOpName("test/variant_input"), DT_VARIANT);
+
+ // Create one more node so that we don't avoid creating a cluster solely
+ // because it would be trivial.
+ Output dummy_cast =
+ ops::Cast(root.WithOpName("test/dummy_cast"), dummy_input, DT_INT32);
+
+ Output tensor_list_element_shape = ops::TensorListElementShape(
+ root.WithOpName("test/tensor_list_element_shape"), variant_input,
+ DT_INT32);
+
+ root.graph()->AddControlEdge(dummy_cast.node(),
+ tensor_list_element_shape.node());
+
+ std::unique_ptr graph(new Graph(OpRegistry::Global()));
+ TF_ASSERT_OK(root.ToGraph(graph.get()));
+
+ TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph));
+
+ std::unordered_map clusters = GetClusters(*graph);
+ EXPECT_EQ(clusters["test/tensor_list_element_shape"], "");
+}
+
+TEST(XlaCompilationTest, ClusterOpsProducingVariantIfOnXlaDevice) {
+ Scope root = Scope::NewRootScope().ExitOnError();
+ Output a = ops::Placeholder(root.WithOpName("test/a"), DT_INT64);
+ Output b = ops::Placeholder(root.WithOpName("test/b"), DT_INT64);
+
+ Output cast_a = ops::Cast(root.WithOpName("test/cast_a"), a, DT_INT32);
+ Output cast_b = ops::Cast(root.WithOpName("test/cast_b"), b, DT_INT32);
+
+ Output tensor_list_reserve = ops::TensorListReserve(
+ root.WithOpName("test/tensor_list_reserve"), cast_a, cast_b, DT_FLOAT);
+
+ std::unique_ptr graph(new Graph(OpRegistry::Global()));
+ TF_ASSERT_OK(root.ToGraph(graph.get()));
+
+ string xla_cpu_device = "/job:worker/replica:0/task:0/device:XLA_CPU:0";
+ for (Node* n : graph->nodes()) {
+ if (absl::StartsWith(n->name(), /*prefix=*/"test/")) {
+ n->set_assigned_device_name(xla_cpu_device);
+ }
+ }
+
+ TF_ASSERT_OK(MarkForCompilationPassTestHelper::MarkForCompilation(&graph));
+
+ std::unordered_map clusters = GetClusters(*graph);
+ EXPECT_NE(clusters["test/tensor_list_reserve"], "");
+}
+
} // namespace
} // namespace tensorflow
diff --git a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc
index d56d0f8ccfcdab40003be38059228cb255921b64..64a3301745790132fe3149bf8fb52d6c45ecc3c1 100644
--- a/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc
+++ b/tensorflow/compiler/jit/mark_for_compilation_pass_test_helper.cc
@@ -34,15 +34,9 @@ namespace tensorflow {
//
// It may be worth refactoring out XlaOpRegistry::RegisterCompilationDevice to
// make this more direct, but probably not worth it solely for this test.
- std::vector devices;
+ std::vector> devices;
TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(*session_options, "", &devices));
- auto delete_devices = gtl::MakeCleanup([&] {
- for (Device* d : devices) {
- delete d;
- }
- });
-
GraphOptimizationPassOptions opt_options;
opt_options.graph = graph;
opt_options.session_options = session_options;
diff --git a/tensorflow/compiler/jit/ops/BUILD b/tensorflow/compiler/jit/ops/BUILD
index f72224545b25bc7100e0b6788e6fbf0a7ca63dad..64409d9334751e0edfce9091a4e5697dd2c712c5 100644
--- a/tensorflow/compiler/jit/ops/BUILD
+++ b/tensorflow/compiler/jit/ops/BUILD
@@ -18,3 +18,9 @@ tf_gen_op_wrapper_py(
out = "xla_ops.py",
deps = ["//tensorflow/compiler/jit/ops:xla_ops"],
)
+
+py_library(
+ name = "xla_ops_grad",
+ srcs = ["xla_ops_grad.py"],
+ deps = ["//tensorflow/python:framework_ops"],
+)
diff --git a/tensorflow/contrib/estimator/python/estimator/linear.py b/tensorflow/compiler/jit/ops/xla_ops_grad.py
similarity index 61%
rename from tensorflow/contrib/estimator/python/estimator/linear.py
rename to tensorflow/compiler/jit/ops/xla_ops_grad.py
index b6a4444f66c2dd9ce104053613997af1f9c543eb..2d31d8dc714307a48932d061fb1af643940a0872 100644
--- a/tensorflow/contrib/estimator/python/estimator/linear.py
+++ b/tensorflow/compiler/jit/ops/xla_ops_grad.py
@@ -1,3 +1,4 @@
+"""Gradients for XLA ops."""
# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,21 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""linear python module.
-
-Importing from tensorflow.python.estimator is unsupported
-and will soon break!
-"""
-# pylint: disable=unused-import,g-bad-import-order,g-import-not-at-top,wildcard-import
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-from tensorflow_estimator.contrib.estimator.python.estimator import linear
+from tensorflow.python.framework import ops
-# Include attrs that start with single underscore.
-_HAS_DYNAMIC_ATTRIBUTES = True
-linear.__all__ = [s for s in dir(linear) if not s.startswith('__')]
-from tensorflow_estimator.contrib.estimator.python.estimator.linear import *
+@ops.RegisterGradient("XlaClusterOutput")
+def _XlaClusterOutputGrad(_, grad):
+ del grad # unused
+ raise RuntimeError("Gradient computation of graph in xla.compile() is "
+ "prohibited because it can cause performance degradation."
+ "Please move gradient computation inside xla.compile().")
diff --git a/tensorflow/compiler/jit/partially_decluster_pass_test.cc b/tensorflow/compiler/jit/partially_decluster_pass_test.cc
index 1fc5da5071f7aa6f6dd6636aacd60e33c12431a6..38a54cc5efae35ad77b6dc8039c653e920cfc071 100644
--- a/tensorflow/compiler/jit/partially_decluster_pass_test.cc
+++ b/tensorflow/compiler/jit/partially_decluster_pass_test.cc
@@ -386,7 +386,7 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) {
TF_ASSERT_OK(s.ToGraph(graph.get()));
// This is needed to register the XLA_GPU device.
- std::vector devices;
+ std::vector> devices;
TF_ASSERT_OK(DeviceFactory::AddDevices(
SessionOptions(), "/job:localhost/replica:0/task:0", &devices));
@@ -400,10 +400,6 @@ TEST(PartiallyDeclusterPassTest, DontDeclusterXlaDeviceOps) {
TF_ASSERT_OK(PartiallyDecluster(&graph));
EXPECT_EQ(GetXlaClusterForNode(*n), "cluster_0");
-
- for (Device* d : devices) {
- delete d;
- }
}
TEST(PartiallyDeclusterPassTest, DontDeclusterNonTensorFlowOps) {
diff --git a/tensorflow/compiler/jit/xla_cpu_device.cc b/tensorflow/compiler/jit/xla_cpu_device.cc
index 9006dd514b166ad8291d2d437305e53de2a093a4..7df898ad12a15345f45fc96e0ec3d42b6e51731b 100644
--- a/tensorflow/compiler/jit/xla_cpu_device.cc
+++ b/tensorflow/compiler/jit/xla_cpu_device.cc
@@ -31,12 +31,12 @@ namespace tensorflow {
class XlaCpuDeviceFactory : public DeviceFactory {
public:
Status CreateDevices(const SessionOptions& options, const string& name_prefix,
- std::vector* devices) override;
+ std::vector>* devices) override;
};
-Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options,
- const string& name_prefix,
- std::vector* devices) {
+Status XlaCpuDeviceFactory::CreateDevices(
+ const SessionOptions& session_options, const string& name_prefix,
+ std::vector>* devices) {
XlaDeviceFlags* flags = GetXlaDeviceFlags();
bool compile_on_demand = flags->tf_xla_compile_on_demand;
@@ -63,8 +63,7 @@ Status XlaCpuDeviceFactory::CreateDevices(const SessionOptions& session_options,
options.device_ordinal = 0;
options.compilation_device_name = DEVICE_CPU_XLA_JIT;
options.use_multiple_streams = false;
- auto device = absl::make_unique(session_options, options);
- devices->push_back(device.release());
+ devices->push_back(absl::make_unique(session_options, options));
return Status::OK();
}
diff --git a/tensorflow/compiler/jit/xla_device.cc b/tensorflow/compiler/jit/xla_device.cc
index 738bac54cca450857b506681a6d8fe54fbffb86c..4201ff91a89b1bee370e6a43337c51abe3bf974a 100644
--- a/tensorflow/compiler/jit/xla_device.cc
+++ b/tensorflow/compiler/jit/xla_device.cc
@@ -410,6 +410,31 @@ Status XlaDevice::Sync() {
return Status::OK();
}
+void XlaDevice::Sync(const DoneCallback& done) {
+ VLOG(1) << "XlaDevice::Sync (asynchronous)";
+ std::shared_ptr stream;
+ {
+ mutex_lock lock(mu_);
+ stream = stream_;
+ }
+ if (!stream) {
+ done(Status::OK());
+ return;
+ }
+
+ stream->ThenEnqueueOnBackgroundThread(
+ [this, stream, done](se::StreamExecutor*) {
+ tracing::ScopedActivity activity("XlaDevice::Sync::Callback",
+ /*is_expensive=*/true);
+ mutex_lock lock(mu_);
+ while (outstanding_asynchronous_operations_ > 0) {
+ outstanding_asynchronous_operations_cv_.wait(lock);
+ }
+ done(stream->ok() ? Status::OK()
+ : errors::Internal("XlaDevice::Sync() failed."));
+ });
+}
+
Status XlaDevice::MakeTensorFromProto(const TensorProto& tensor_proto,
const AllocatorAttributes alloc_attrs,
Tensor* tensor) {
diff --git a/tensorflow/compiler/jit/xla_device.h b/tensorflow/compiler/jit/xla_device.h
index dc8f49a9c975a25cbae0e980749db5a1daf039e4..c8bb276cdb9673fdcba4cc15a9f33ecd3ae96dbb 100644
--- a/tensorflow/compiler/jit/xla_device.h
+++ b/tensorflow/compiler/jit/xla_device.h
@@ -135,6 +135,7 @@ class XlaDevice : public LocalDevice {
void ComputeAsync(AsyncOpKernel* op_kernel, OpKernelContext* context,
AsyncOpKernel::DoneCallback done) override;
Status Sync() override;
+ void Sync(const DoneCallback& done) override;
Status FillContextMap(const Graph* graph,
DeviceContextMap* device_context_map) override
diff --git a/tensorflow/compiler/jit/xla_gpu_device.cc b/tensorflow/compiler/jit/xla_gpu_device.cc
index 441970169581d53e0d8683b98d26712445b170ea..944f732b99c0924a08932eda0aedd8c815cc51d0 100644
--- a/tensorflow/compiler/jit/xla_gpu_device.cc
+++ b/tensorflow/compiler/jit/xla_gpu_device.cc
@@ -29,12 +29,12 @@ namespace tensorflow {
class XlaGpuDeviceFactory : public DeviceFactory {
public:
Status CreateDevices(const SessionOptions& options, const string& name_prefix,
- std::vector* devices) override;
+ std::vector>* devices) override;
};
-Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options,
- const string& name_prefix,
- std::vector* devices) {
+Status XlaGpuDeviceFactory::CreateDevices(
+ const SessionOptions& session_options, const string& name_prefix,
+ std::vector>* devices) {
XlaOpRegistry::DeviceRegistration registration;
registration.compilation_device_name = DEVICE_GPU_XLA_JIT;
registration.autoclustering_policy =
@@ -70,7 +70,7 @@ Status XlaGpuDeviceFactory::CreateDevices(const SessionOptions& session_options,
return status;
}
- devices->push_back(device.release());
+ devices->push_back(std::move(device));
}
return Status::OK();
}
diff --git a/tensorflow/compiler/jit/xla_interpreter_device.cc b/tensorflow/compiler/jit/xla_interpreter_device.cc
index e828bae865d630bd40f227943cdabb2d8d95ca48..4007309ed1c57b663dca5bac0df11260bf1327f3 100644
--- a/tensorflow/compiler/jit/xla_interpreter_device.cc
+++ b/tensorflow/compiler/jit/xla_interpreter_device.cc
@@ -33,12 +33,12 @@ constexpr std::array kExecAllTypes = {
class XlaInterpreterDeviceFactory : public DeviceFactory {
public:
Status CreateDevices(const SessionOptions& options, const string& name_prefix,
- std::vector* devices) override;
+ std::vector>* devices) override;
};
Status XlaInterpreterDeviceFactory::CreateDevices(
const SessionOptions& session_options, const string& name_prefix,
- std::vector* devices) {
+ std::vector>* devices) {
static XlaDeviceOpRegistrations* registrations = RegisterXlaDeviceKernels(
DEVICE_XLA_INTERPRETER, DEVICE_INTERPRETER_XLA_JIT);
(void)registrations;
@@ -61,8 +61,7 @@ Status XlaInterpreterDeviceFactory::CreateDevices(
options.device_ordinal = 0;
options.compilation_device_name = DEVICE_INTERPRETER_XLA_JIT;
options.use_multiple_streams = false;
- auto device = absl::make_unique(session_options, options);
- devices->push_back(device.release());
+ devices->push_back(absl::make_unique(session_options, options));
return Status::OK();
}
diff --git a/tensorflow/compiler/tests/BUILD b/tensorflow/compiler/tests/BUILD
index 2b88a64fed322f662b3ff1d6bf706a813c52c758..bc3d60b90e58b4018f1c52b09941dedba7ef348a 100644
--- a/tensorflow/compiler/tests/BUILD
+++ b/tensorflow/compiler/tests/BUILD
@@ -375,27 +375,6 @@ tf_xla_py_test(
],
)
-tf_xla_py_test(
- name = "resampler_ops_test",
- size = "small",
- srcs = ["resampler_ops_test.py"],
- disabled_backends = [
- # TODO(b/74459949) Support BatchDot in CPU backend.
- "cpu",
- "cpu_ondemand",
- ],
- # TODO(b/112295522): figure out how to make OSS build pass.
- tags = ["no_oss"],
- deps = [
- ":xla_test",
- "//tensorflow/contrib/resampler:resampler_ops",
- "//tensorflow/contrib/resampler:resampler_py",
- "//tensorflow/python:array_ops",
- "//tensorflow/python:client_testlib",
- "//tensorflow/python:platform_test",
- ],
-)
-
tf_xla_py_test(
name = "dynamic_stitch_test",
size = "small",
diff --git a/tensorflow/compiler/tests/binary_ops_test.py b/tensorflow/compiler/tests/binary_ops_test.py
index 332381c59eed06d5697e58efb1d8fa2b6ef604d2..9a5423c1b2a5df7880453cbb328f6a8174066255 100644
--- a/tensorflow/compiler/tests/binary_ops_test.py
+++ b/tensorflow/compiler/tests/binary_ops_test.py
@@ -218,6 +218,21 @@ class BinaryOpsTest(xla_test.XLATestCase):
],
equality_test=self.ListsAreClose)
+ # TF doesn't define these for bf16.
+ if dtype != dtypes.bfloat16.as_numpy_dtype:
+ self._testBinary(
+ gen_math_ops.xdivy,
+ np.array([0, 4, 3, 2, 1, 0], dtype=dtype),
+ np.array([0, 5, 6, 7, 8, float("NaN")], dtype=dtype),
+ expected=np.array([0, 0.8, 0.5, 0.285714, 0.125, 0], dtype=dtype))
+
+ self._testBinary(
+ gen_math_ops.xlogy,
+ np.array([0, 4, 3, 2, 1, 0], dtype=dtype),
+ np.array([0, 5, 6, 7, 8, float("NaN")], dtype=dtype),
+ expected=np.array([0, 6.437752, 5.375278, 3.89182, 2.079442, 0],
+ dtype=dtype))
+
def testIntOps(self):
for dtype in self.signed_int_types:
self._testBinary(
diff --git a/tensorflow/compiler/tests/categorical_op_test.py b/tensorflow/compiler/tests/categorical_op_test.py
index 532e2b57484bc85aef196c16eb804b94f6ee3384..5d5e486f616937601214aa169a4c329ab78932c8 100644
--- a/tensorflow/compiler/tests/categorical_op_test.py
+++ b/tensorflow/compiler/tests/categorical_op_test.py
@@ -27,6 +27,7 @@ from tensorflow.python.framework import dtypes
from tensorflow.python.framework import random_seed
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import random_ops
+from tensorflow.python.ops import stateless_random_ops
from tensorflow.python.platform import googletest
@@ -56,7 +57,7 @@ class CategoricalTest(xla_test.XLATestCase):
Returns:
Frequencies from sampled classes; shape [batch_size, num_classes].
"""
- with self.cached_session() as sess, self.test_scope():
+ with self.cached_session(), self.test_scope():
random_seed.set_random_seed(1618)
op = random_ops.multinomial(logits, num_samples,
output_dtype=dtypes.int32)
@@ -79,7 +80,7 @@ class CategoricalTest(xla_test.XLATestCase):
def _testRngIsNotConstant(self, rng, dtype, output_dtype):
# Tests that 'rng' does not always return the same value.
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
x = rng(dtype, output_dtype)
@@ -107,7 +108,7 @@ class CategoricalTest(xla_test.XLATestCase):
def testCategoricalIsInRange(self):
for dtype in self.float_types:
for output_dtype in self.output_dtypes():
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
x = random_ops.multinomial(
array_ops.ones(shape=[1, 20], dtype=dtype), 1000,
@@ -138,6 +139,57 @@ class CategoricalTest(xla_test.XLATestCase):
chi2 = self._chi2(probs, freqs)
self.assertLess(chi2, 1e-3)
+ def testStatelessMultinomialIsInRange(self):
+ for dtype in self.float_types:
+ for output_dtype in self.output_dtypes():
+ with self.cached_session() as sess:
+ with self.test_scope():
+ seed_t = array_ops.placeholder(dtypes.int32, shape=[2])
+ x = stateless_random_ops.stateless_multinomial(
+ array_ops.ones(shape=[1, 20], dtype=dtype),
+ 1000,
+ seed_t,
+ output_dtype=output_dtype)
+ y = sess.run(x, {seed_t: [0x12345678, 0xabcdef12]})
+ self.assertTrue((y >= 0).sum() == 1000)
+ self.assertTrue((y < 20).sum() == 1000)
+
+ def testDeterminismMultinomial(self):
+ # Stateless values should be equal iff the seeds are equal (roughly)
+ num_samples = 10
+ with self.cached_session(), self.test_scope():
+ seed_t = array_ops.placeholder(dtypes.int32, shape=[2])
+ seeds = [(x, y) for x in range(5) for y in range(5)] * 3
+ for logits in ([[0.1, 0.25, 0.5, 0.15]], [[0.5, 0.5], [0.8, 0.2],
+ [0.25, 0.75]]):
+ pure = stateless_random_ops.stateless_multinomial(
+ logits, num_samples, seed=seed_t)
+ values = [(seed, pure.eval(feed_dict={seed_t: seed})) for seed in seeds]
+ for s0, v0 in values:
+ for s1, v1 in values:
+ self.assertEqual(s0 == s1, np.all(v0 == v1))
+
+ def testEmpty(self):
+ with self.cached_session():
+ with self.test_scope():
+ x = random_ops.multinomial(
+ array_ops.zeros([42, 40]), 0, output_dtype=dtypes.int32)
+ y = self.evaluate(x)
+ self.assertEqual(y.shape, (42, 0))
+
+ def testEmptyStateless(self):
+ with self.cached_session() as sess:
+ with self.test_scope():
+ seed_t = array_ops.placeholder(dtypes.int32, shape=[2])
+ x = stateless_random_ops.stateless_multinomial(
+ array_ops.zeros([42, 40]),
+ 0,
+ seed=seed_t,
+ output_dtype=dtypes.int32)
+ y = sess.run(x, {seed_t: [0x12345678, 0xabcdef12]})
+ self.assertEqual(y.shape, (42, 0))
+
+
if __name__ == '__main__':
googletest.main()
diff --git a/tensorflow/compiler/tests/concat_ops_test.py b/tensorflow/compiler/tests/concat_ops_test.py
index deb9ac186e63a520054993cb56375f152c8c6587..2187f57960f80300d631bdc7eb8fe5e9c8dddeea 100644
--- a/tensorflow/compiler/tests/concat_ops_test.py
+++ b/tensorflow/compiler/tests/concat_ops_test.py
@@ -254,7 +254,7 @@ class ConcatTest(xla_test.XLATestCase):
def DISABLED_testZeroSize(self):
# Verify that concat doesn't crash and burn for zero size inputs
np.random.seed(7)
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
for shape0 in (), (2,):
axis = len(shape0)
@@ -270,7 +270,7 @@ class ConcatTest(xla_test.XLATestCase):
self.assertAllEqual(c.eval(), correct)
# Check gradients
dc = np.random.randn(*c.get_shape().as_list())
- dxs = sess.run(gradients_impl.gradients(c, xs, dc))
+ dxs = self.evaluate(gradients_impl.gradients(c, xs, dc))
self.assertAllEqual(dc, np.concatenate(dxs, axis=axis))
def testConcatTuple(self):
@@ -330,7 +330,7 @@ class ConcatTest(xla_test.XLATestCase):
class ConcatOffsetTest(xla_test.XLATestCase):
def testBasic(self):
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
cdim = constant_op.constant(1, dtypes.int32)
s0 = constant_op.constant([2, 3, 5], dtypes.int32)
@@ -344,7 +344,7 @@ class ConcatOffsetTest(xla_test.XLATestCase):
class PackTest(xla_test.XLATestCase):
def testBasic(self):
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
s0 = constant_op.constant([2, 3, 5], dtypes.int32)
s1 = constant_op.constant([2, 7, 5], dtypes.int32)
@@ -354,7 +354,7 @@ class PackTest(xla_test.XLATestCase):
self.assertAllEqual(ans, [[2, 3, 5], [2, 7, 5], [2, 20, 5]])
def testScalars(self):
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
s0 = constant_op.constant(2, dtypes.int32)
s1 = constant_op.constant(3, dtypes.int32)
@@ -364,7 +364,7 @@ class PackTest(xla_test.XLATestCase):
self.assertAllEqual(ans, [2, 3, 5])
def testEmpty(self):
- with self.cached_session() as sess:
+ with self.cached_session():
with self.test_scope():
s0 = constant_op.constant([[]], dtypes.int32)
s1 = constant_op.constant([[]], dtypes.int32)
diff --git a/tensorflow/compiler/tests/dense_layer_test.py b/tensorflow/compiler/tests/dense_layer_test.py
index d1b90f098d7d6574999ba0af44b285f5ad5e4f8d..bf5ea7b1fb6fb3c774c4db20d059f131990d20d3 100644
--- a/tensorflow/compiler/tests/dense_layer_test.py
+++ b/tensorflow/compiler/tests/dense_layer_test.py
@@ -42,7 +42,7 @@ def GetRunMetadataLabels(run_metadata):
def InLabels(labels, substr):
"""Returns true iff one of the labels contains substr."""
- return any([substr in x for x in labels])
+ return any(substr in x for x in labels)
class DenseLayerTest(test.TestCase):
@@ -72,7 +72,7 @@ class DenseLayerTest(test.TestCase):
x = array_ops.placeholder(shape=[None, None, 3], dtype=np.float32)
y = layers.dense(x, 3)
- sess.run(variables.initialize_all_variables())
+ self.evaluate(variables.initialize_all_variables())
run_metadata = config_pb2.RunMetadata()
test_utils.RunWithWarmup(
sess,
@@ -97,7 +97,7 @@ class DenseLayerTest(test.TestCase):
with jit_scope():
y = layers.dense(x, 3)
- sess.run(variables.initialize_all_variables())
+ self.evaluate(variables.initialize_all_variables())
run_metadata = config_pb2.RunMetadata()
test_utils.RunWithWarmup(
sess,
@@ -126,7 +126,7 @@ class DenseLayerTest(test.TestCase):
with jit_scope():
y = layers.dense(x, 3)
- sess.run(variables.initialize_all_variables())
+ self.evaluate(variables.initialize_all_variables())
run_metadata = config_pb2.RunMetadata()
test_utils.RunWithWarmup(
sess,
diff --git a/tensorflow/compiler/tests/dynamic_stitch_test.py b/tensorflow/compiler/tests/dynamic_stitch_test.py
index 50b04daa6b9f4159a3c4bdeecaf900a5b35a833c..e89cf975f5d889091ce92a35165aef55ee5ad4b0 100644
--- a/tensorflow/compiler/tests/dynamic_stitch_test.py
+++ b/tensorflow/compiler/tests/dynamic_stitch_test.py
@@ -58,6 +58,15 @@ class DynamicStitchTest(xla_test.XLATestCase):
[idx1, idx2], [val1, val2],
expected=np.array([[], [], [], []], np.int32))
+ def testEmptyIndex(self):
+ idx1 = np.array([], dtype=np.int32)
+ idx2 = np.array([[], []], dtype=np.int32)
+ val1 = np.ndarray(shape=(0, 9), dtype=np.int32)
+ val2 = np.ndarray(shape=(2, 0, 9), dtype=np.int32)
+ self._AssertDynamicStitchResultIs([idx1, idx2], [val1, val2],
+ expected=np.ndarray(
+ shape=(0, 9), dtype=np.int32))
+
def testSimple1D(self):
val1 = np.array([0, 4, 7], dtype=np.int32)
val2 = np.array([1, 6, 2, 3, 5], dtype=np.int32)
diff --git a/tensorflow/compiler/tests/eager_test.py b/tensorflow/compiler/tests/eager_test.py
index 76706ad40a0f0e9d033196d2e32e9b6c154268f0..2af32b537ba53723370faf81aebf308a465718c7 100644
--- a/tensorflow/compiler/tests/eager_test.py
+++ b/tensorflow/compiler/tests/eager_test.py
@@ -101,7 +101,7 @@ class EagerTest(xla_test.XLATestCase):
self.assertAllEqual(15, product)
# Run some ops graphly
- with context.graph_mode(), self.cached_session() as sess:
+ with context.graph_mode(), self.cached_session():
with self.test_scope():
three = constant_op.constant(3)
five = constant_op.constant(5)
diff --git a/tensorflow/compiler/tests/fft_test.py b/tensorflow/compiler/tests/fft_test.py
index 61abf9c9c045b835b3a2e92fc588cd31f3da76ff..0edd0c35aa2d417a3ed24decbaa0b5d62d35bb62 100644
--- a/tensorflow/compiler/tests/fft_test.py
+++ b/tensorflow/compiler/tests/fft_test.py
@@ -158,6 +158,23 @@ class FFTTest(xla_test.XLATestCase):
self._VerifyFftMethod(INNER_DIMS_3D, np.real, _to_expected, _tf_fn)
+ def testRFFT3DMismatchedSize(self):
+
+ def _to_expected(x):
+ return np.fft.rfftn(
+ x,
+ axes=(-3, -2, -1),
+ s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2])
+
+ def _tf_fn(x):
+ return signal.rfft3d(
+ x,
+ fft_length=[
+ x.shape[-3].value // 2, x.shape[-2].value, x.shape[-1].value * 2
+ ])
+
+ self._VerifyFftMethod(INNER_DIMS_3D, np.real, _to_expected, _tf_fn)
+
def testIRFFT(self):
def _tf_fn(x):
@@ -202,6 +219,30 @@ class FFTTest(xla_test.XLATestCase):
self._VerifyFftMethod(INNER_DIMS_3D, _to_input, _to_expected, _tf_fn)
+ def testIRFFT3DMismatchedSize(self):
+
+ def _to_input(x):
+ return np.fft.rfftn(
+ np.real(x),
+ axes=(-3, -2, -1),
+ s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2])
+
+ def _to_expected(x):
+ return np.fft.irfftn(
+ x,
+ axes=(-3, -2, -1),
+ s=[x.shape[-3] // 2, x.shape[-2], x.shape[-1] * 2])
+
+ def _tf_fn(x):
+ return signal.irfft3d(
+ x,
+ fft_length=[
+ x.shape[-3].value // 2, x.shape[-2].value, x.shape[-1].value * 2
+ ])
+
+ self._VerifyFftMethod(INNER_DIMS_3D, _to_input, _to_expected, _tf_fn)
+
+
if __name__ == "__main__":
googletest.main()
diff --git a/tensorflow/compiler/tests/function_test.py b/tensorflow/compiler/tests/function_test.py
index dd9b7f30efedaa45c96e60290b14a42d7f969b34..a61827c2ae44de117abad5b7db5c6bcd78fa171e 100644
--- a/tensorflow/compiler/tests/function_test.py
+++ b/tensorflow/compiler/tests/function_test.py
@@ -40,7 +40,7 @@ class FunctionTest(xla_test.XLATestCase):
bval = np.array([5, 6, 7, 8]).reshape([2, 2]).astype(np.float32)
expected = APlus2B(aval, bval)
- with self.cached_session() as sess:
+ with self.cached_session():
@function.Defun(dtypes.float32, dtypes.float32)
def Foo(a, b):
@@ -66,7 +66,7 @@ class FunctionTest(xla_test.XLATestCase):
bval = np.array([4, 3, 2, 1]).reshape([2, 2]).astype(np.float32)
expected = APlus2B(aval, bval)
- with self.cached_session() as sess:
+ with self.cached_session():
@function.Defun(dtypes.float32, dtypes.float32)
def Foo(a, b):
@@ -90,7 +90,7 @@ class FunctionTest(xla_test.XLATestCase):
bval = np.array([5, 6, 7, 8]).reshape([2, 2]).astype(np.float32)
expected = Func(aval, bval)
- with self.cached_session() as sess:
+ with self.cached_session():
@function.Defun(dtypes.float32, dtypes.float32)
def Foo(a, b):
diff --git a/tensorflow/compiler/tests/jit_test.py b/tensorflow/compiler/tests/jit_test.py
index 6f51ae33a1b0fc8670ddf0cacb03a3b5a9176a91..dbea9849e217519874352b789588a2af62f1c826 100644
--- a/tensorflow/compiler/tests/jit_test.py
+++ b/tensorflow/compiler/tests/jit_test.py
@@ -75,7 +75,7 @@ def RunMetadataLabels(run_metadata):
def InLabels(labels, substr):
"""Returns true iff one of the labels contains substr."""
- return any([substr in x for x in labels])
+ return any(substr in x for x in labels)
def MetadataHasXlaRunOp(run_metadata):
diff --git a/tensorflow/compiler/tests/listdiff_op_test.py b/tensorflow/compiler/tests/listdiff_op_test.py
index 58622114e4f552fb71db9b040a39b57d7da0037c..0210201fa71a6e790e94667073ab4dba542537a5 100644
--- a/tensorflow/compiler/tests/listdiff_op_test.py
+++ b/tensorflow/compiler/tests/listdiff_op_test.py
@@ -33,13 +33,13 @@ class ListDiffTest(xla_test.XLATestCase):
def _testListDiff(self, x, y, out, idx):
for dtype in [dtypes.int32, dtypes.int64]:
for index_dtype in [dtypes.int32, dtypes.int64]:
- with self.cached_session() as sess:
+ with self.cached_session():
x_tensor = ops.convert_to_tensor(x, dtype=dtype)
y_tensor = ops.convert_to_tensor(y, dtype=dtype)
with self.test_scope():
out_tensor, idx_tensor = array_ops.listdiff(
x_tensor, y_tensor, out_idx=index_dtype)
- tf_out, tf_idx = sess.run([out_tensor, idx_tensor])
+ tf_out, tf_idx = self.evaluate([out_tensor, idx_tensor])
self.assertAllEqual(out, tf_out)
self.assertAllEqual(idx, tf_idx)
self.assertEqual(1, out_tensor.get_shape().ndims)
diff --git a/tensorflow/compiler/tests/lstm_test.py b/tensorflow/compiler/tests/lstm_test.py
index fd02a50aff94d2bd2e180a092a27c8195178c5e5..776ed899e68ddd3893b8bb30b7c8034297aa6515 100644
--- a/tensorflow/compiler/tests/lstm_test.py
+++ b/tensorflow/compiler/tests/lstm_test.py
@@ -89,7 +89,7 @@ class LSTMTest(test.TestCase):
# Initialize variables and run the unrolled LSTM step.
self.evaluate(variables.global_variables_initializer())
- return sess.run([m, c])
+ return self.evaluate([m, c])
def testLSTMCell(self):
# Run with all-0 weights, no padding.
@@ -174,7 +174,7 @@ class LSTMTest(test.TestCase):
# Initialize variables and run the unrolled LSTM layer.
self.evaluate(variables.global_variables_initializer())
- return sess.run(out_seq)
+ return self.evaluate(out_seq)
def testLSTMLayer(self):
# Run with all-0 weights, no padding.
diff --git a/tensorflow/compiler/tests/random_ops_test.py b/tensorflow/compiler/tests/random_ops_test.py
index 1e913909452d54ed59f33bb0d313fd062570d459..97ffad34c00b8ec16eb1ec109ba5d980e0ce673d 100644
--- a/tensorflow/compiler/tests/random_ops_test.py
+++ b/tensorflow/compiler/tests/random_ops_test.py
@@ -111,7 +111,7 @@ class RandomOpsTest(xla_test.XLATestCase):
return math.exp(-(x**2) / 2.) / math.sqrt(2 * math.pi)
def probit(x, sess=sess):
- return sess.run(special_math.ndtri(x))
+ return self.evaluate(special_math.ndtri(x))
a = -2.
b = 2.
diff --git a/tensorflow/compiler/tests/randomized_tests.cc b/tensorflow/compiler/tests/randomized_tests.cc
index a6b58020126a3297944f199e99b0801387615564..d23fd125163d1afe8c7fd5e008d4b617ff4b2874 100644
--- a/tensorflow/compiler/tests/randomized_tests.cc
+++ b/tensorflow/compiler/tests/randomized_tests.cc
@@ -3382,10 +3382,10 @@ int main(int argc, char** argv) {
}
// XLA devices register kernels at construction time; create all known devices
// to make sure the kernels are registered.
- std::vector devices;
+ std::vector> devices;
TF_CHECK_OK(tensorflow::DeviceFactory::AddDevices(
tensorflow::SessionOptions(), "", &devices));
- tensorflow::DeviceMgr device_mgr(devices);
+ tensorflow::DeviceMgr device_mgr(std::move(devices));
tensorflow::Device* ignored;
TF_QCHECK_OK(
diff --git a/tensorflow/compiler/tests/reduce_ops_test.py b/tensorflow/compiler/tests/reduce_ops_test.py
index 132c59c32c9db0c8759bdbb31f8613c3ef88b485..e8fc81bbb5472669c408b8bbdbcdfcdcf461131f 100644
--- a/tensorflow/compiler/tests/reduce_ops_test.py
+++ b/tensorflow/compiler/tests/reduce_ops_test.py
@@ -91,6 +91,7 @@ class ReduceOpsTest(xla_test.XLATestCase, parameterized.TestCase):
np.array([], dtype=np.bool).reshape(0, 3),
np.array([[False, True, False], [True, True, False]]),
]
+ ONES = [np.ones([34000, 2])]
def testReduceSumF32(self, index_dtype):
self._testReduction(math_ops.reduce_sum, np.sum, np.float32, self.REAL_DATA,
@@ -149,6 +150,11 @@ class ReduceOpsTest(xla_test.XLATestCase, parameterized.TestCase):
self._testReduction(math_ops.reduce_mean, np.mean, np.float32,
self.NONEMPTY_REAL_DATA, index_dtype)
+ def testReduceMeanF16(self, index_dtype):
+ if np.float16 in self.all_types:
+ self._testReduction(math_ops.reduce_mean, np.mean, np.float16, self.ONES,
+ index_dtype)
+
def testReduceMeanC64(self, index_dtype):
self._testReduction(math_ops.reduce_mean, np.mean, np.complex64,
self.NONEMPTY_COMPLEX_DATA, index_dtype)
diff --git a/tensorflow/compiler/tests/rmsprop_test.py b/tensorflow/compiler/tests/rmsprop_test.py
index 5138a4a2a9f0a5abd797ad9655fd75d1f60d5bbd..dc3e90b4afa41c08d899ee195d42fb91678bad1c 100644
--- a/tensorflow/compiler/tests/rmsprop_test.py
+++ b/tensorflow/compiler/tests/rmsprop_test.py
@@ -76,7 +76,7 @@ class RmspropTest(xla_test.XLATestCase):
rms_opt = rmsprop.RMSPropOptimizer(learning_rate, centered=centered)
rms_update = rms_opt.apply_gradients(
zip([grads0, grads1], [var0, var1]))
- variables.global_variables_initializer().run()
+ self.evaluate(variables.global_variables_initializer())
mg0 = rms_opt.get_slot(var0, "mg")
self.assertEqual(mg0 is not None, centered)
@@ -97,7 +97,7 @@ class RmspropTest(xla_test.XLATestCase):
# Run 3 steps of RMSProp
for _ in range(3):
- rms_update.run()
+ self.evaluate(rms_update)
var0_np, mg0_np, rms0_np, mom0_np = self._rmsprop_update_numpy(
var0_np,
diff --git a/tensorflow/compiler/tests/scan_ops_test.py b/tensorflow/compiler/tests/scan_ops_test.py
index 897db384b7e8067b0460b5f344201f101a4d8479..17639bd8a755b9e9f5acc77979ac7a4149f112db 100644
--- a/tensorflow/compiler/tests/scan_ops_test.py
+++ b/tensorflow/compiler/tests/scan_ops_test.py
@@ -71,7 +71,7 @@ def handle_options(func, x, axis, exclusive, reverse):
class CumsumTest(xla_test.XLATestCase):
- valid_dtypes = [np.float32]
+ valid_dtypes = [np.float32, np.int32]
def axis_dtypes(self):
return set(self.int_types).intersection([np.int32, np.int64])
@@ -149,7 +149,7 @@ class CumsumTest(xla_test.XLATestCase):
class CumprodTest(xla_test.XLATestCase):
- valid_dtypes = [np.float32]
+ valid_dtypes = [np.float32, np.int32]
def axis_dtypes(self):
return set(self.int_types).intersection([np.int32, np.int64])
diff --git a/tensorflow/compiler/tests/stateless_random_ops_test.py b/tensorflow/compiler/tests/stateless_random_ops_test.py
index 21708aa15877647e2a979a5a2674dfb734700df3..ee7ca7e6f196e114ff18e2597145e5c198980b08 100644
--- a/tensorflow/compiler/tests/stateless_random_ops_test.py
+++ b/tensorflow/compiler/tests/stateless_random_ops_test.py
@@ -156,7 +156,7 @@ class StatelessRandomOpsTest(xla_test.XLATestCase):
return math.exp(-(x**2) / 2.) / math.sqrt(2 * math.pi)
def probit(x, sess=sess):
- return sess.run(special_math.ndtri(x))
+ return self.evaluate(special_math.ndtri(x))
a = -2.
b = 2.
diff --git a/tensorflow/compiler/tests/unary_ops_test.py b/tensorflow/compiler/tests/unary_ops_test.py
index d612d3b32dd6b0893508413b337ea9ad95ef6dd7..95c9e7ffd4651642781143c2c1940b0e51e1e470 100644
--- a/tensorflow/compiler/tests/unary_ops_test.py
+++ b/tensorflow/compiler/tests/unary_ops_test.py
@@ -481,6 +481,72 @@ class UnaryOpsTest(xla_test.XLATestCase):
np.array([-1, -0.5, 0, 0.3], dtype=dtype),
expected=np.array([-1., -0.5, 0., 0.296875], dtype=dtype))
+ def quantize_and_dequantize_v2_round_half_up(x):
+ return array_ops.quantize_and_dequantize_v2(
+ x,
+ -1,
+ 1.0,
+ signed_input=True,
+ num_bits=8,
+ range_given=True,
+ round_mode="HALF_UP")
+
+ self._assertOpOutputMatchesExpected(
+ quantize_and_dequantize_v2_round_half_up,
+ np.array([-0.8, -0.5, 0, 0.3, 0.8, -2, 33], dtype=dtype),
+ expected=np.array([
+ -102.0 / 127,
+ -63.0 / 127,
+ 0,
+ 38.0 / 127,
+ 102.0 / 127,
+ -128.0 / 127,
+ 1,
+ ],
+ dtype=dtype))
+
+ def quantize_and_dequantize_v2_round_half_to_even(x):
+ return array_ops.quantize_and_dequantize_v2(
+ x,
+ -1.0,
+ 1.0,
+ signed_input=True,
+ num_bits=8,
+ range_given=True,
+ round_mode="HALF_TO_EVEN")
+
+ self._assertOpOutputMatchesExpected(
+ quantize_and_dequantize_v2_round_half_to_even,
+ np.array(
+ [
+ -0.8,
+ # The -0.5 should become -63.5 after scaling and with
+ # rounding this should become -64. But with the test
+ # unary_ops_test_cpu_ondemand, this fails as the result
+ # before scaling becomes -63.499996 and gets rounded to -63.
+ # TODO(sreenik): Some one more familiar with this test needs
+ # to take a look and resolve this. This works on all other
+ # variations of the platform like cpu, and gpu.
+ # -0.5,
+ 0,
+ 0.3,
+ 0.8,
+ -2,
+ 33
+ ],
+ dtype=dtype),
+ expected=np.array(
+ [
+ -102.0 / 127,
+ # -64.0 / 127,
+ 0,
+ 38.0 / 127,
+ 102.0 / 127,
+ -128.0 / 127,
+ 1,
+ ],
+ dtype=dtype))
+
def quantize_and_dequantize_v3(x):
return array_ops.quantize_and_dequantize_v3(
x, -127, 127, num_bits=8, signed_input=True, range_given=False)
diff --git a/tensorflow/compiler/tests/variable_ops_test.py b/tensorflow/compiler/tests/variable_ops_test.py
index e776c8a951c7ac24c65408a67007b03ae07e8be0..fcd7ac5ba1ca5049246e93e6f5f76746fb28c6b8 100644
--- a/tensorflow/compiler/tests/variable_ops_test.py
+++ b/tensorflow/compiler/tests/variable_ops_test.py
@@ -77,7 +77,7 @@ class VariableOpsTest(xla_test.XLATestCase):
sess.run(variables.variables_initializer([v]))
x = v.sparse_read(2)
self.assertAllClose(
- np.array([8j, 9, 10, 11]).astype(dtype), sess.run(x))
+ np.array([8j, 9, 10, 11]).astype(dtype), self.evaluate(x))
def testSparseRead1DIndices(self):
for dtype in self.numeric_types:
@@ -89,7 +89,7 @@ class VariableOpsTest(xla_test.XLATestCase):
x = v.sparse_read([2, 1])
self.assertAllClose(
np.array([[8, 9, 10, 11], [4, 5, 6j, 7]]).astype(dtype),
- sess.run(x))
+ self.evaluate(x))
def testSparseRead2DIndices(self):
for dtype in self.numeric_types:
@@ -102,7 +102,7 @@ class VariableOpsTest(xla_test.XLATestCase):
self.assertAllClose(
np.array([[[8, 9, 10, 11], [4, 5, 6, 7]],
[[0, 1, 2j, 3], [8, 9, 10, 11]]]).astype(dtype),
- sess.run(x))
+ self.evaluate(x))
def testSparseRead2DIndices3DTensor(self):
for dtype in self.numeric_types:
@@ -115,9 +115,9 @@ class VariableOpsTest(xla_test.XLATestCase):
x = v.sparse_read([[2, 1], [3, 0]])
self.assertAllClose(
np.array(
- [[[[20, 21, 22], [23, 24j, 25]], [[10, 11, 12], [13, 14, 15]]
- ], [[[30, 31, 32], [33, 34, 35]], [[0, 1, 2], [3, 4, 5]]]
- ],).astype(dtype), sess.run(x))
+ [[[[20, 21, 22], [23, 24j, 25]], [[10, 11, 12], [13, 14, 15]]],
+ [[[30, 31, 32], [33, 34, 35]], [[0, 1, 2], [3, 4, 5]]]
+ ],).astype(dtype), self.evaluate(x))
def testShape(self):
for dtype in self.numeric_types:
diff --git a/tensorflow/compiler/tests/xla_device_test.py b/tensorflow/compiler/tests/xla_device_test.py
index 28d61fb07dcb665fa0dbe3f3e566e291e24fa662..ef55292b1be91a731ec556d7efa9cdf1a696e5cc 100644
--- a/tensorflow/compiler/tests/xla_device_test.py
+++ b/tensorflow/compiler/tests/xla_device_test.py
@@ -81,7 +81,7 @@ class XlaDeviceTest(xla_test.XLATestCase):
with self.cached_session() as sess:
with self.test_scope():
x = gen_control_flow_ops.control_trigger()
- sess.run(x)
+ self.evaluate(x)
if __name__ == "__main__":
diff --git a/tensorflow/compiler/tf2xla/BUILD b/tensorflow/compiler/tf2xla/BUILD
index 486b4d8a8c35097c0ad333b6fd87d34e5bf5b1e4..25a84fb1b6609106213231db1ca1ce54da8bd960 100644
--- a/tensorflow/compiler/tf2xla/BUILD
+++ b/tensorflow/compiler/tf2xla/BUILD
@@ -9,6 +9,7 @@ package_group(
"//tensorflow/compiler/jit/...",
"//tensorflow/compiler/tests/...",
"//tensorflow/compiler/tf2xla/...",
+ "//tensorflow/contrib/compiler/...",
],
)
@@ -211,7 +212,6 @@ cc_library(
"//tensorflow/compiler/xla/client:xla_computation",
"//tensorflow/compiler/xla/client/lib:arithmetic",
"//tensorflow/compiler/xla/client/lib:constants",
- "//tensorflow/compiler/xla/client/lib:numeric",
"//tensorflow/core:core_cpu",
"//tensorflow/core:core_cpu_internal",
"//tensorflow/core:framework",
diff --git a/tensorflow/compiler/tf2xla/kernels/arg_op.cc b/tensorflow/compiler/tf2xla/kernels/arg_op.cc
index 2db2514397deca39e6874cf994532a20d2186316..795ea09831e183a26fb3498b9bbaf9c3adaef9ed 100644
--- a/tensorflow/compiler/tf2xla/kernels/arg_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/arg_op.cc
@@ -50,7 +50,7 @@ class XlaArgOp : public XlaOpKernel {
return;
}
- const XlaExpression& arg = XlaContext::Get(ctx).args()[index_];
+ const XlaExpression& arg = ctx->xla_context()->args()[index_];
OP_REQUIRES(ctx, arg.kind() != XlaExpression::Kind::kInvalid,
errors::InvalidArgument("Invalid/missing argument expression"));
ctx->SetOutputExpression(0, arg);
diff --git a/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc b/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc
index a267c0c72fce67d7c22c55a57f8d5ac4ffd2b7e2..0e2f335f3354e3ae6008bdc0ac0b80683fe479c1 100644
--- a/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/batch_norm_op.cc
@@ -115,9 +115,9 @@ class FusedBatchNormGradOp : public XlaOpKernel {
// operators. For now, cast everything to the statistics type (which
// may be more precise than the input type).
auto grad_backprop =
- XlaHelpers::ConvertElementType(b, ctx->Input(0), scale_dtype);
+ XlaHelpers::ConvertElementType(ctx->Input(0), scale_dtype);
auto activations =
- XlaHelpers::ConvertElementType(b, ctx->Input(1), scale_dtype);
+ XlaHelpers::ConvertElementType(ctx->Input(1), scale_dtype);
auto scale = ctx->Input(2);
auto mean = ctx->Input(3);
auto var = ctx->Input(4);
@@ -151,11 +151,11 @@ class FusedBatchNormGradOp : public XlaOpKernel {
const DataType accumulation_type =
XlaHelpers::SumAccumulationType(scale_dtype);
auto converted =
- XlaHelpers::ConvertElementType(b, grad_backprop, accumulation_type);
+ XlaHelpers::ConvertElementType(grad_backprop, accumulation_type);
auto reduce =
xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), reduction_dims);
- offset_backprop = XlaHelpers::ConvertElementType(b, reduce, scale_dtype);
+ offset_backprop = XlaHelpers::ConvertElementType(reduce, scale_dtype);
// scratch1 = rsqrt(pop_var + epsilon)
auto neg_half = XlaHelpers::FloatLiteral(b, scale_dtype, -0.5);
@@ -165,19 +165,18 @@ class FusedBatchNormGradOp : public XlaOpKernel {
// scratch2 = sum(y_backprop * (x - mean))
auto mul =
xla::Mul(grad_backprop, xla::Sub(activations, mean, {feature_index}));
- converted = XlaHelpers::ConvertElementType(b, mul, accumulation_type);
+ converted = XlaHelpers::ConvertElementType(mul, accumulation_type);
reduce =
xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), reduction_dims);
- auto scratch2 = XlaHelpers::ConvertElementType(b, reduce, scale_dtype);
+ auto scratch2 = XlaHelpers::ConvertElementType(reduce, scale_dtype);
x_backprop =
xla::Mul(grad_backprop, xla::Mul(scratch1, scale), {feature_index});
scale_backprop = xla::Mul(scratch1, scratch2);
}
- ctx->SetOutput(0,
- XlaHelpers::ConvertElementType(b, x_backprop, input_dtype));
+ ctx->SetOutput(0, XlaHelpers::ConvertElementType(x_backprop, input_dtype));
ctx->SetOutput(1, scale_backprop);
ctx->SetOutput(2, offset_backprop);
ctx->SetConstantOutput(3, Tensor());
diff --git a/tensorflow/compiler/tf2xla/kernels/bias_ops.cc b/tensorflow/compiler/tf2xla/kernels/bias_ops.cc
index 41f540506ba41fbe7f91393e7b8e26a89e72ef0a..e7f369b761f36a717ea5fb536780af91a8955b1e 100644
--- a/tensorflow/compiler/tf2xla/kernels/bias_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/bias_ops.cc
@@ -107,11 +107,11 @@ class BiasAddGradOp : public XlaOpKernel {
const DataType accumulation_type =
XlaHelpers::SumAccumulationType(input_type(0));
auto converted =
- XlaHelpers::ConvertElementType(b, ctx->Input(0), accumulation_type);
+ XlaHelpers::ConvertElementType(ctx->Input(0), accumulation_type);
auto reduce =
xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), reduce_dims);
- ctx->SetOutput(0, XlaHelpers::ConvertElementType(b, reduce, input_type(0)));
+ ctx->SetOutput(0, XlaHelpers::ConvertElementType(reduce, input_type(0)));
}
private:
diff --git a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc
index 47e517a6576d3a848bc41ceb703df2bd778c4a35..5e9280c1fe692037b0a842a92ef5a8c28b854a54 100644
--- a/tensorflow/compiler/tf2xla/kernels/binary_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/binary_ops.cc
@@ -43,6 +43,9 @@ namespace {
const std::vector& extend_dimensions) override { \
xla::XlaBuilder* b = ctx->builder(); \
(void)b; \
+ (void)lhs_shape; \
+ (void)rhs_shape; \
+ (void)extend_dimensions; \
return HLO; \
} \
}; \
@@ -103,23 +106,23 @@ static xla::XlaOp FloorDivImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x,
XLA_MAKE_BINARY(FloorDiv,
FloorDivImpl(b, input_type(0), lhs, rhs, broadcast_helper));
-static xla::XlaOp XlogyImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x,
- xla::XlaOp y, const BCast& broadcast_helper) {
+xla::XlaOp XlogyImpl(xla::XlaOp x, xla::XlaOp y,
+ const BCast& broadcast_helper) {
std::tie(x, y) = XlaBinaryOp::Broadcast(x, y, broadcast_helper);
- auto zero = XlaHelpers::Zero(b, dtype);
+ auto zero = xla::ZerosLike(x);
auto is_zero = xla::Eq(x, zero);
return xla::Select(is_zero, zero, xla::Mul(x, xla::Log(y)));
}
-XLA_MAKE_BINARY(Xlogy, XlogyImpl(b, input_type(0), lhs, rhs, broadcast_helper));
+XLA_MAKE_BINARY(Xlogy, XlogyImpl(lhs, rhs, broadcast_helper));
-static xla::XlaOp XdivyImpl(xla::XlaBuilder* b, DataType dtype, xla::XlaOp x,
- xla::XlaOp y, const BCast& broadcast_helper) {
+xla::XlaOp XdivyImpl(xla::XlaOp x, xla::XlaOp y,
+ const BCast& broadcast_helper) {
std::tie(x, y) = XlaBinaryOp::Broadcast(x, y, broadcast_helper);
- auto zero = XlaHelpers::Zero(b, dtype);
+ auto zero = xla::ZerosLike(x);
auto is_zero = xla::Eq(x, zero);
return xla::Select(is_zero, zero, xla::Div(x, y));
}
-XLA_MAKE_BINARY(Xdivy, XdivyImpl(b, input_type(0), lhs, rhs, broadcast_helper));
+XLA_MAKE_BINARY(Xdivy, XdivyImpl(lhs, rhs, broadcast_helper));
// Implementation of FloorMod. Pseudo-code:
// T trunc_mod = std::fmod(x, y);
diff --git a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc
index ad85940920ebb82e72331516e3fe46c79f853892..7199b9b6feb36dd45ef51f4c38463bc715fcc38a 100644
--- a/tensorflow/compiler/tf2xla/kernels/categorical_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/categorical_op.cc
@@ -21,10 +21,13 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/lib/arithmetic.h"
+#include "tensorflow/compiler/xla/client/lib/prng.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
+#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_shape.h"
+#include "tensorflow/core/framework/types.pb.h"
namespace tensorflow {
namespace {
@@ -57,11 +60,9 @@ class CategoricalOp : public XlaOpKernel {
const int64 batch_size = logits_shape.dim_size(0);
const int64 num_classes = logits_shape.dim_size(1);
- xla::XlaBuilder* builder = ctx->builder();
-
xla::Shape uniform_shape;
int class_dimension;
- if (num_samples > 1) {
+ if (num_samples != 1) {
std::array uniform_shape_array = {
{batch_size, num_samples, num_classes}};
xla::PrimitiveType uniform_xla_type;
@@ -83,16 +84,16 @@ class CategoricalOp : public XlaOpKernel {
xla::ShapeUtil::MakeShape(uniform_xla_type, uniform_shape_array);
class_dimension = 1;
}
- xla::XlaOp uniforms =
- xla::RngUniform(XlaHelpers::Zero(builder, input_type(0)),
- XlaHelpers::One(builder, input_type(0)), uniform_shape);
+ xla::PrimitiveType type;
+ OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(input_type(0), &type));
+ xla::XlaOp log_uniforms = GetLogUniforms(uniform_shape, type, ctx);
// Use Gumbel softmax trick to generate categorical samples.
// See:
// https://hips.seas.harvard.edu/blog/2013/04/06/the-gumbel-max-trick-for-discrete-distributions/
// TODO(b/68769470): Switch to using a cumulative sum approach.
auto softmax_entries =
- xla::Sub(logits, xla::Log(-xla::Log(uniforms)),
+ xla::Sub(logits, log_uniforms,
/*broadcast_dimensions=*/{0, class_dimension});
xla::PrimitiveType xla_output_type;
@@ -107,6 +108,16 @@ class CategoricalOp : public XlaOpKernel {
ctx->SetOutput(0, argmax);
}
+ virtual xla::XlaOp GetLogUniforms(xla::Shape uniform_shape,
+ xla::PrimitiveType type,
+ XlaOpKernelContext* ctx) {
+ xla::XlaBuilder* builder = ctx->builder();
+ auto uniforms =
+ xla::RngUniform(XlaHelpers::Zero(builder, input_type(0)),
+ XlaHelpers::One(builder, input_type(0)), uniform_shape);
+ return xla::Log(-xla::Log(uniforms));
+ }
+
private:
TF_DISALLOW_COPY_AND_ASSIGN(CategoricalOp);
};
@@ -115,5 +126,48 @@ class CategoricalOp : public XlaOpKernel {
REGISTER_XLA_OP(Name("Multinomial").CompileTimeConstantInput("num_samples"),
CategoricalOp);
+class StatelessCategoricalOp : public CategoricalOp {
+ public:
+ explicit StatelessCategoricalOp(OpKernelConstruction* ctx)
+ : CategoricalOp(ctx) {
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_));
+ }
+
+ xla::XlaOp GetLogUniforms(xla::Shape uniform_shape, xla::PrimitiveType type,
+ XlaOpKernelContext* ctx) override {
+ xla::XlaOp seed = ctx->Input(2);
+ auto seed0 = xla::Reshape(xla::Slice(seed, {0}, {1}, {1}), {});
+ auto seed1 = xla::Reshape(xla::Slice(seed, {1}, {2}, {1}), {});
+
+ xla::XlaBuilder* builder = ctx->builder();
+ if (uniform_shape.element_type() == xla::BF16) {
+ uniform_shape.set_element_type(xla::F32);
+ }
+ auto uniforms = xla::StatelessRngUniform(
+ {seed0, seed1}, uniform_shape, XlaHelpers::Zero(builder, DT_FLOAT),
+ XlaHelpers::One(builder, DT_FLOAT));
+ return xla::ConvertElementType(xla::Log(-xla::Log(uniforms)), type);
+ }
+
+ void Compile(XlaOpKernelContext* ctx) override {
+ TensorShape seed_shape = ctx->InputShape(2);
+ OP_REQUIRES(ctx, seed_shape.dims() == 1 && seed_shape.dim_size(0) == 2,
+ errors::InvalidArgument("seed must have shape [2], not ",
+ seed_shape.DebugString()));
+ CategoricalOp::Compile(ctx);
+ }
+
+ private:
+ DataType dtype_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(StatelessCategoricalOp);
+};
+
+REGISTER_XLA_OP(Name("StatelessMultinomial")
+ .CompileTimeConstantInput("num_samples")
+ .TypeConstraint("T", {DT_FLOAT, DT_BFLOAT16})
+ .TypeConstraint("Tseed", DT_INT32),
+ StatelessCategoricalOp);
+
} // anonymous namespace
} // namespace tensorflow
diff --git a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc
index c9a1be494066e4f935a1d818bc86c86333e34fae..641fefafb357f6ad10483c454600f3dadd4f8cb7 100644
--- a/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc
+++ b/tensorflow/compiler/tf2xla/kernels/conv_op_helpers.cc
@@ -24,7 +24,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/lib/arithmetic.h"
#include "tensorflow/compiler/xla/client/lib/constants.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/literal_util.h"
#include "tensorflow/core/framework/node_def_util.h"
@@ -65,60 +64,63 @@ xla::Shape ExpandedFilterShapeForDepthwiseConvolution(const xla::Shape& shape) {
// 0 0 1 1 0 0 0 0 1 1 0 0
// 0 0 0 0 1 1 0 0 0 0 1 1
//
-// The first step is to create a one tensor, A, that is [3]
-// 0 1 2
+// The first step is to create a iota A with iota_dimension = 2
+// 0 0 0 0 0 0 0 0 0 0 0 0
+// 1 1 1 1 1 1 1 1 1 1 1 1
+// 2 2 2 2 2 2 2 2 2 2 2 2
//
-// and another tensor, B, that is [3 * 2]
-// 0 1 2 3 4 5
+// 0 0 0 0 0 0 0 0 0 0 0 0
+// 1 1 1 1 1 1 1 1 1 1 1 1
+// 2 2 2 2 2 2 2 2 2 2 2 2
//
-// and divide B it by 2 to get
-// 0 0 1 1 2 2
+// and another iota B with iota_dimension = 3
+// 0 1 2 3 4 5 0 1 2 3 4 5
+// 0 1 2 3 4 5 0 1 2 3 4 5
+// 0 1 2 3 4 5 0 1 2 3 4 5
//
-// then we broadcast the B to [2, 2, 3, 3 * 2]
-// 0 0 1 1 2 2 0 0 1 1 2 2
-// 0 0 1 1 2 2 0 0 1 1 2 2
-// 0 0 1 1 2 2 0 0 1 1 2 2
+// 0 1 2 3 4 5 0 1 2 3 4 5
+// 0 1 2 3 4 5 0 1 2 3 4 5
+// 0 1 2 3 4 5 0 1 2 3 4 5
//
-// 0 0 1 1 2 2 0 0 1 1 2 2
-// 0 0 1 1 2 2 0 0 1 1 2 2
-// 0 0 1 1 2 2 0 0 1 1 2 2
+// and divide B by 2 to get
+// 0 0 1 1 2 2 0 0 1 1 2 2
+// 0 0 1 1 2 2 0 0 1 1 2 2
+// 0 0 1 1 2 2 0 0 1 1 2 2
//
-// Finally compare A and broadcasted B in dimension 2 amd return the result at
-// the beginning of the comment.
+// 0 0 1 1 2 2 0 0 1 1 2 2
+// 0 0 1 1 2 2 0 0 1 1 2 2
+// 0 0 1 1 2 2 0 0 1 1 2 2
+//
+// Finally compare A and B and return the result at the beginning of the
+// comment.
xla::XlaOp CreateExpandedFilterMask(const xla::Shape& filter_shape,
xla::XlaBuilder* builder) {
xla::Shape expanded_filter_shape =
ExpandedFilterShapeForDepthwiseConvolution(filter_shape);
int64 depthwise_multiplier =
filter_shape.dimensions(filter_shape.dimensions_size() - 1);
- int64 input_feature =
- filter_shape.dimensions(filter_shape.dimensions_size() - 2);
-
- // Create a M sized linspace and an M*N sized linspace that will be
- // broadcasted into perpendicular dimensions and compared.
- xla::XlaOp input_feature_iota = xla::Iota(builder, xla::S32, input_feature);
- xla::XlaOp expanded_feature_iota =
- xla::Iota(builder, xla::S32, input_feature * depthwise_multiplier);
- // Divide the M*N sized linspace by the depthwise_multiplier to create
- // [0 0 1 1 2 2] in the example in the function comment.
+ // Create two iotas with the shape of the expanded filter, one of them with
+ // the iota dimension chosen as the feature dimension, and the other a iota
+ // with the iota dimension chosen as the expanded output feature dimension.
+ std::vector iota_dimensions(expanded_filter_shape.dimensions().begin(),
+ expanded_filter_shape.dimensions().end());
+ xla::Shape iota_shape = xla::ShapeUtil::MakeShape(xla::S32, iota_dimensions);
+ xla::XlaOp input_feature_iota = xla::Iota(
+ builder, iota_shape, /*iota_dimension=*/iota_dimensions.size() - 2);
+ xla::XlaOp expanded_feature_iota = xla::Iota(
+ builder, iota_shape, /*iota_dimension=*/iota_dimensions.size() - 1);
+
+ // Divide 'expanded_feature_iota' by the depthwise_multiplier to create
+ // [0 0 1 1 2 2] ... in the example in the function comment.
expanded_feature_iota =
xla::Div(expanded_feature_iota,
XlaHelpers::IntegerLiteral(builder, DataType::DT_INT32,
depthwise_multiplier));
- // Broadcast the N*M linspace to [H, W, ..., M, M*N].
- std::vector expanded_feature_broadcast_dims(
- expanded_filter_shape.dimensions().begin(),
- expanded_filter_shape.dimensions().end());
- expanded_feature_broadcast_dims.pop_back();
- auto broadcasted_expanded_feature_iota =
- xla::Broadcast(expanded_feature_iota, expanded_feature_broadcast_dims);
-
- // Compare the broadcasted linspace to the input feature linspace in the
- // input feature dimension to create a diagonal predicate.
- return xla::Eq(broadcasted_expanded_feature_iota, input_feature_iota,
- {expanded_filter_shape.dimensions_size() - 2});
+ // Compare 'input_feature_iota' with 'expanded_feature_iota' to create a
+ // diagonal predicate.
+ return xla::Eq(expanded_feature_iota, input_feature_iota);
}
// Reshapes a filter of shape [H, W, ..., M, N] to [H, W, ..., 1, M*N]. Used to
diff --git a/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc b/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc
index b2f6ef43fa9765b0d6da8e3215cbea5b56b4fe05..6e6ba21daf5bf3eab5bfc15378e77b6dd253da7c 100644
--- a/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/dynamic_stitch_op.cc
@@ -113,8 +113,20 @@ class DynamicStitchOp : public XlaOpKernel {
}
}
int number_of_indices = max_index + 1;
- OP_REQUIRES(ctx, number_of_indices > 0,
- errors::InvalidArgument("no indices supplied"));
+ int64 result_rank = 1 + data0_shape.dims() - indices0_shape.dims();
+ if (number_of_indices == 0) {
+ std::vector result_shape(result_rank);
+ for (int d = indices0_shape.dims(); d < data0_shape.dims(); d++) {
+ result_shape[d - indices0_shape.dims() + 1] = data0_shape.dim_size(d);
+ }
+ xla::PrimitiveType element_type =
+ ctx->input_xla_type(ctx->num_inputs() - 1);
+ xla::Literal empty_literal = xla::Literal::CreateFromShape(
+ xla::ShapeUtil::MakeShape(element_type, result_shape));
+ ctx->SetOutput(0, xla::ConstantLiteral(ctx->builder(), empty_literal));
+ return;
+ }
+
// Construct the reverse mapping, for each index, of which slice of which
// input it comes from.
std::vector src_input_vector(number_of_indices);
@@ -157,12 +169,9 @@ class DynamicStitchOp : public XlaOpKernel {
// Set up the vectors for slicing: the first dimension will vary
// slice by slice, and the rest take the full common extra shape.
- std::vector slice_start(1 + data0_shape.dims() -
- indices0_shape.dims());
- std::vector slice_limit(1 + data0_shape.dims() -
- indices0_shape.dims());
- std::vector stride(1 + data0_shape.dims() - indices0_shape.dims(),
- 1);
+ std::vector slice_start(result_rank);
+ std::vector slice_limit(result_rank);
+ std::vector stride(result_rank, 1);
for (int d = indices0_shape.dims(); d < data0_shape.dims(); d++) {
slice_limit[1 + d - indices0_shape.dims()] = data0_shape.dim_size(d);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc b/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc
index c68b0bfd7961892294c2931e5c4c44de534a7740..29687c7b82f92d9f336854c4575746589c63b64f 100644
--- a/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/extract_image_patches_op.cc
@@ -17,7 +17,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_helpers.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/core/util/tensor_format.h"
diff --git a/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc b/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc
index cdba6680dee3fade5bdf0c453ed672b653072b0d..142be030f737f105980ab9c80a5a849e1ca6eb47 100644
--- a/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/fake_quantize_ops.cc
@@ -260,19 +260,19 @@ class FakeQuantWithMinMaxVarsGradOp : public XlaOpKernel {
xla::XlaOp below_min = xla::Lt(input, nudged_input_min);
xla::XlaOp select1 = xla::Select(below_min, gradient, zeroes);
xla::XlaOp reduce1 = xla::ReduceAll(
- XlaHelpers::ConvertElementType(b, select1, accumulation_type),
+ XlaHelpers::ConvertElementType(select1, accumulation_type),
XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type));
- xla::XlaOp output1 = XlaHelpers::ConvertElementType(b, reduce1, data_type);
+ xla::XlaOp output1 = XlaHelpers::ConvertElementType(reduce1, data_type);
ctx->SetOutput(1, output1);
xla::XlaOp above_max = xla::Gt(input, nudged_input_max);
xla::XlaOp select2 = xla::Select(above_max, gradient, zeroes);
xla::XlaOp reduce2 = xla::ReduceAll(
- XlaHelpers::ConvertElementType(b, select2, accumulation_type),
+ XlaHelpers::ConvertElementType(select2, accumulation_type),
XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type));
- xla::XlaOp output2 = XlaHelpers::ConvertElementType(b, reduce2, data_type);
+ xla::XlaOp output2 = XlaHelpers::ConvertElementType(reduce2, data_type);
ctx->SetOutput(2, output2);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/fft_ops.cc b/tensorflow/compiler/tf2xla/kernels/fft_ops.cc
index 9b06357d9b78be6d7b64e88a97f45f6c19176fc8..6df8b5367d2390e65995beb1583b225755e6ee9f 100644
--- a/tensorflow/compiler/tf2xla/kernels/fft_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/fft_ops.cc
@@ -20,6 +20,7 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/literal_util.h"
+#include "tensorflow/compiler/xla/util.h"
#include "tensorflow/core/framework/numeric_op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/tensor.h"
@@ -50,11 +51,36 @@ class GenericFftOp : public XlaOpKernel {
errors::InvalidArgument("input must be at least 1 dimensional"));
std::vector fft_length;
+ xla::XlaOp input = ctx->Input(0);
if (fft_type_ == FftType::RFFT || fft_type_ == FftType::IRFFT) {
OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntVector(1, &fft_length));
OP_REQUIRES(ctx, fft_length.size() == fft_rank_,
errors::InvalidArgument("fft_length must be length ",
fft_rank_, " vector"));
+
+ // Zero pad or truncate the axes we're doing FFT on.
+ absl::InlinedVector slice_sizes = input_shape.dim_sizes();
+ std::vector> padding_sizes(slice_sizes.size());
+ std::vector expected_sizes = fft_length;
+ // IRFFT wants the innermost axis to be n / 2 + 1.
+ if (fft_type_ == FftType::IRFFT) {
+ expected_sizes[fft_rank_ - 1] = fft_length[fft_rank_ - 1] / 2 + 1;
+ }
+ for (int i = 0; i < fft_rank_; i++) {
+ int index = input_shape.dims() - fft_rank_ + i;
+ if (input_shape.dim_size(index) > expected_sizes[i]) {
+ slice_sizes[index] = expected_sizes[i];
+ } else {
+ padding_sizes[index].second =
+ expected_sizes[i] - input_shape.dim_size(index);
+ }
+ }
+
+ std::vector start_indices(input_shape.dims(), 0);
+ std::vector strides(input_shape.dims(), 1);
+ input = xla::Pad(xla::Slice(input, start_indices, slice_sizes, strides),
+ XlaHelpers::Zero(ctx->builder(), ctx->input_type(0)),
+ xla::MakeEdgePaddingConfig(padding_sizes));
} else {
// Innermost axis provides the FFT length.
for (int i = 0; i < fft_rank_; i++) {
@@ -63,7 +89,7 @@ class GenericFftOp : public XlaOpKernel {
}
}
- xla::XlaOp fft = xla::Fft(ctx->Input(0), fft_type_, fft_length);
+ xla::XlaOp fft = xla::Fft(input, fft_type_, fft_length);
ctx->SetOutput(0, fft);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/if_op.cc b/tensorflow/compiler/tf2xla/kernels/if_op.cc
index 56da50f140893c68c8a1556853884720b21c7229..b5e083912555c865b5eadc7697075c9ca4451ca9 100644
--- a/tensorflow/compiler/tf2xla/kernels/if_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/if_op.cc
@@ -72,7 +72,7 @@ void XlaIfOp::Compile(XlaOpKernelContext* ctx) {
arg.shape = resource->shape();
OP_REQUIRES(ctx, arg.initialized,
errors::Unimplemented("Uninitialized arguments: ", arg.name));
- arg.tensor_array_size = resource->tensor_array_size();
+ arg.max_array_size = resource->max_array_size();
for (const auto& gradient : resource->tensor_array_gradients()) {
arg.tensor_array_gradients.insert(gradient.first);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/image_ops.cc b/tensorflow/compiler/tf2xla/kernels/image_ops.cc
index b49b2516d8b829a550071bc7580d350328833f32..e9bb0a77e99d144863b027bd214081316d61c314 100644
--- a/tensorflow/compiler/tf2xla/kernels/image_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/image_ops.cc
@@ -191,12 +191,11 @@ class AdjustContrastOpV2 : public XlaOpKernel {
DataType type = context->input_type(0);
const DataType accumulation_type = XlaHelpers::SumAccumulationType(type);
- auto converted =
- XlaHelpers::ConvertElementType(b, input, accumulation_type);
+ auto converted = XlaHelpers::ConvertElementType(input, accumulation_type);
auto reduce = xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type),
*context->GetOrCreateAdd(accumulation_type),
{height_dim, width_dim});
- auto output = XlaHelpers::ConvertElementType(b, reduce, type);
+ auto output = XlaHelpers::ConvertElementType(reduce, type);
output =
xla::Div(output, XlaHelpers::FloatLiteral(b, type, height * width));
diff --git a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc
index e310db2162da0997204f85bc3ca42e7b0460e1e3..e2c05b648bb194b1b452c527ddb1a2c5995b1217 100644
--- a/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc
+++ b/tensorflow/compiler/tf2xla/kernels/index_ops_cpu.cc
@@ -30,7 +30,9 @@ limitations under the License.
namespace tensorflow {
namespace {
-// The logic below uses a custom-call to implement argmax.
+// The logic below uses a custom-call to implement argmax when possible. When
+// custom-call is not allowed or input shapes are not supported, this kernel
+// falls back to using XLA HLO native ArgMax.
//
// Also see b/29507024 for first-class XLA support for indexing ops.
class ArgMaxCustomCallOp : public XlaOpKernel {
@@ -50,27 +52,40 @@ class ArgMaxCustomCallOp : public XlaOpKernel {
// overhead, when compiling ahead-of-time.
int64 dim;
OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(1, &dim));
- OP_REQUIRES(ctx, dim >= 0, errors::InvalidArgument("dim must be >= 0"));
- OP_REQUIRES(
- ctx, dim < input_shape.dims(),
- errors::InvalidArgument("dim must be < input rank (",
- input_shape.dims(), "), but got: ", dim));
- const int64 dim_size = input_shape.dim_size(dim);
- OP_REQUIRES(ctx, dim_size > 0,
+
+ const int input_dims = input_shape.dims();
+ const int axis = dim < 0 ? dim + input_dims : dim;
+ OP_REQUIRES(ctx, axis >= 0 && axis < input_dims,
+ errors::InvalidArgument("Expected dimension in the range [",
+ -input_dims, ", ", input_dims,
+ "), but got ", dim));
+
+ const int64 axis_size = input_shape.dim_size(axis);
+ OP_REQUIRES(ctx, axis_size > 0,
errors::InvalidArgument(
"Reduction axis ", dim,
" is empty in shape: ", input_shape.DebugString()));
- // The output shape is the input shape contracted along dim.
+ const DataType dtype = output_type(0);
+ xla::PrimitiveType output_type;
+ OP_REQUIRES_OK(ctx, DataTypeToPrimitiveType(dtype, &output_type));
+
+ // Fall back to XLA ArgMax HLO when CustomCall is not allowed or when input
+ // shape isn't supported.
+ if (!ctx->compiler()->options().allow_cpu_custom_calls ||
+ (input_dims != 1 && input_dims != 2)) {
+ xla::XlaOp output = XlaHelpers::ArgMax(ctx->Input(0), output_type, axis);
+ ctx->SetOutput(0, output);
+ return;
+ }
+
+ xla::XlaOp output;
+ // The output shape is the input shape contracted along axis.
TensorShape output_shape;
for (int d = 0; d < input_shape.dims() - 1; ++d) {
- output_shape.AddDim(input_shape.dim_size((d < dim) ? d : d + 1));
+ output_shape.AddDim(input_shape.dim_size((d < axis) ? d : d + 1));
}
- // For now we use a custom-call, only for the 1d and 2d cases.
- OP_REQUIRES(ctx, XlaContext::Get(ctx).allow_cpu_custom_calls(),
- errors::InvalidArgument(
- "ArgMax implementation requires a CustomCall on CPU"));
xla::XlaBuilder& b = *ctx->builder();
// XLA passes to the function, so it is not included here.
@@ -84,7 +99,7 @@ class ArgMaxCustomCallOp : public XlaOpKernel {
args.push_back(xla::ConstantLiteral(
&b, xla::LiteralUtil::CreateR1(output_shape.dim_sizes())));
args.push_back(
- xla::ConstantLiteral(&b, xla::LiteralUtil::CreateR0(dim)));
+ xla::ConstantLiteral(&b, xla::LiteralUtil::CreateR0(axis)));
}
// The argmax function expects row-major layout.
@@ -101,24 +116,15 @@ class ArgMaxCustomCallOp : public XlaOpKernel {
}
// Tell XLA to call the custom code, defined in
- // index_ops_kernel_argmax_float_1d.cc.
- xla::XlaOp output;
- switch (input_shape.dims()) {
- case 1:
- output = xla::CustomCallWithLayout(&b, "argmax_float_1d_xla_impl", args,
- xla_shape, arg_shapes);
- break;
- case 2:
- output = xla::CustomCallWithLayout(&b, "argmax_float_2d_xla_impl", args,
- xla_shape, arg_shapes);
- break;
- default:
- OP_REQUIRES(ctx, false,
- errors::Unimplemented(
- "Argmax is only implemented for 1d and 2d tensors"
- ", but got shape: ",
- input_shape.DebugString()));
+ // index_ops_kernel_argmax_float_{1, 2}d.cc.
+ if (input_dims == 1) {
+ output = xla::CustomCallWithLayout(&b, "argmax_float_1d_xla_impl", args,
+ xla_shape, arg_shapes);
+ } else {
+ output = xla::CustomCallWithLayout(&b, "argmax_float_2d_xla_impl", args,
+ xla_shape, arg_shapes);
}
+ output = xla::ConvertElementType(output, output_type);
ctx->SetOutput(0, output);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc b/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc
index f028e361bccd51de0bd69a1d2227c7afaed53455..93f029731c34e84000a3dc00df8af05654cccf2d 100644
--- a/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/l2loss_op.cc
@@ -37,12 +37,11 @@ class L2LossOp : public XlaOpKernel {
// output = sum(t ** 2) / 2
const DataType accumulation_type = XlaHelpers::SumAccumulationType(dtype);
- auto t =
- XlaHelpers::ConvertElementType(b, ctx->Input(0), accumulation_type);
+ auto t = XlaHelpers::ConvertElementType(ctx->Input(0), accumulation_type);
auto square = xla::Mul(t, t);
auto reduce = xla::Reduce(square, XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), dims);
- auto deconverted = XlaHelpers::ConvertElementType(b, reduce, dtype);
+ auto deconverted = XlaHelpers::ConvertElementType(reduce, dtype);
auto two = XlaHelpers::IntegerLiteral(b, dtype, 2);
ctx->SetOutput(0, xla::Div(deconverted, two));
}
diff --git a/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc b/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc
index 87ee2d3aede50eb24e65570f106d49030e1d4236..987901d82b3f3798dd52f18ef2497b8f0cf80b11 100644
--- a/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/lrn_ops.cc
@@ -49,16 +49,14 @@ class LRNOp : public XlaOpKernel {
// We use a window of depth_radius_ * 2 + 1, to account for the current
// element and a depth_radius_ on either side.
auto accumulation_type = XlaHelpers::SumAccumulationType(input_type(0));
- auto converted =
- XlaHelpers::ConvertElementType(builder, input, accumulation_type);
+ auto converted = XlaHelpers::ConvertElementType(input, accumulation_type);
auto squared = xla::Mul(converted, converted);
auto reduce = xla::ReduceWindow(
squared, XlaHelpers::Zero(builder, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type),
/* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1},
/* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame);
- auto sqr_sum =
- XlaHelpers::ConvertElementType(builder, reduce, input_type(0));
+ auto sqr_sum = XlaHelpers::ConvertElementType(reduce, input_type(0));
auto scale = xla::Pow(
xla::Add(xla::ConstantR0(builder, bias_),
@@ -138,15 +136,14 @@ class LRNGradOp : public XlaOpKernel {
auto accumulation_type = XlaHelpers::SumAccumulationType(input_type(0));
auto converted =
- XlaHelpers::ConvertElementType(builder, in_image, accumulation_type);
+ XlaHelpers::ConvertElementType(in_image, accumulation_type);
auto squared = xla::Mul(converted, converted);
auto reduce = xla::ReduceWindow(
squared, XlaHelpers::Zero(builder, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type),
/* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1},
/* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame);
- auto sqr_sum =
- XlaHelpers::ConvertElementType(builder, reduce, input_type(0));
+ auto sqr_sum = XlaHelpers::ConvertElementType(reduce, input_type(0));
auto norm =
xla::Add(xla::ConstantR0(builder, bias_),
@@ -157,15 +154,13 @@ class LRNGradOp : public XlaOpKernel {
xla::Div(out_image, norm)),
in_grads);
- auto converted_dy =
- XlaHelpers::ConvertElementType(builder, dy, accumulation_type);
+ auto converted_dy = XlaHelpers::ConvertElementType(dy, accumulation_type);
auto dy_reduce = xla::ReduceWindow(
converted_dy, XlaHelpers::Zero(builder, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type),
/* window_dimensions = */ {1, 1, 1, depth_radius_ * 2 + 1},
/* window_strides = */ {1, 1, 1, 1}, xla::Padding::kSame);
- auto dy_reduced =
- XlaHelpers::ConvertElementType(builder, dy_reduce, input_type(0));
+ auto dy_reduced = XlaHelpers::ConvertElementType(dy_reduce, input_type(0));
xla::XlaOp gradients = xla::Add(
xla::Mul(in_image, dy_reduced),
diff --git a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc
index 8dfd7de591c4a3c4768dd60b41e03d294ad49397..2dd0a710e47ec8cad6153402fdb3be59f5868205 100644
--- a/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/matrix_band_part_op.cc
@@ -16,8 +16,8 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_helpers.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
+#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/framework/tensor_shape.h"
namespace tensorflow {
@@ -61,11 +61,11 @@ class MatrixBandPartOp : public XlaOpKernel {
// Compute 'offset', which is how many diagonals we are above/below the
// diagonal.
- xla::XlaOp iota_m = xla::Iota(builder, index_xla_type, m);
- xla::XlaOp iota_n = xla::Iota(builder, index_xla_type, n);
+ xla::Shape iota_shape = xla::ShapeUtil::MakeShape(index_xla_type, {m, n});
+ xla::XlaOp iota_m = xla::Iota(builder, iota_shape, /*iota_dimension=*/0);
+ xla::XlaOp iota_n = xla::Iota(builder, iota_shape, /*iota_dimension=*/1);
- auto offset = xla::Sub(xla::Broadcast(iota_n, {m}), iota_m,
- /*broadcast_dimensions=*/{0});
+ auto offset = xla::Sub(iota_n, iota_m);
// If num_lower or num_upper are negative, include all lower/upper
// diagonals.
diff --git a/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc b/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc
index c0ca881ff82cee04e0c5e35f9a2d5732fabdd8a6..4f980b6d14ed667bdf4756ed740894098cae5919 100644
--- a/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/matrix_set_diag_op.cc
@@ -16,7 +16,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_helpers.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
namespace tensorflow {
diff --git a/tensorflow/compiler/tf2xla/kernels/permute_op.cc b/tensorflow/compiler/tf2xla/kernels/permute_op.cc
index 94b51e1a586c6cf623c181abf200b91851c7ba05..71920bf5c1e6aa5981aafa8b611cc01c0917e02b 100644
--- a/tensorflow/compiler/tf2xla/kernels/permute_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/permute_op.cc
@@ -75,8 +75,7 @@ class DataFormatVecPermuteOp : public XlaOpKernel {
}
auto keys = xla::ConstantR1(builder, absl::Span(dst_indices));
if (input_rank == 2) {
- keys = xla::BroadcastInDim(
- keys, xla::ShapeUtil::MakeShape(xla::S32, {4, 2}), {0});
+ keys = xla::BroadcastInDim(keys, {4, 2}, {0});
}
auto sorted = xla::Sort(keys, {ctx->Input(0)}, 0);
auto output = xla::GetTupleElement(sorted, 1);
diff --git a/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc b/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc
index 6f4ed496a1774dde68dd9d5fbd37995d615b678c..7fe102428db1cc5ce16037f56fa301d1941da8e3 100644
--- a/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/quantize_and_dequantize_op.cc
@@ -19,6 +19,7 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/lib/arithmetic.h"
#include "tensorflow/compiler/xla/client/lib/constants.h"
+#include "tensorflow/compiler/xla/client/lib/math.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/client/xla_computation.h"
#include "tensorflow/core/platform/macros.h"
@@ -26,12 +27,26 @@ limitations under the License.
namespace tensorflow {
namespace {
+enum QuantizerRoundMode {
+ // Round half up: if the fraction of y is exactly 0.5, then
+ // round(y) = y + 0.5
+ // E.g., -5.5 gets rounded to -5, -5.4 goes to -5,
+ // 5.4 goes to 5, and 5.5 goes to 6.
+ ROUND_HALF_UP,
+ // Round half to even: if the fraction of y is exactly 0.5, then round(y) is
+ // the nearest even integer to y.
+ // E.g., 23.5 gets rounded to 24, 24.5 gets rounded to 24, while -23.5 becomes
+ // -24, and -24.5 gets rounded to 24.
+ ROUND_HALF_TO_EVEN,
+};
+
class QuantizeAndDequantizeOp : public XlaOpKernel {
public:
explicit QuantizeAndDequantizeOp(OpKernelConstruction* ctx)
: XlaOpKernel(ctx) {
OP_REQUIRES_OK(ctx, ctx->GetAttr("signed_input", &signed_input_));
OP_REQUIRES_OK(ctx, ctx->GetAttr("range_given", &range_given_));
+ round_mode_ = ROUND_HALF_TO_EVEN;
}
void Compile(XlaOpKernelContext* ctx) override {
@@ -117,8 +132,17 @@ class QuantizeAndDequantizeOp : public XlaOpKernel {
// in that case they were measured from the tensor.
input = Clamp(min_range, input, max_range);
}
- xla::XlaOp result =
- Floor((input - min_range) * scale + half) * inverse_scale + min_range;
+ xla::XlaOp result;
+ switch (round_mode_) {
+ case ROUND_HALF_TO_EVEN: {
+ result = xla::RoundToEven(input * scale) * inverse_scale;
+ break;
+ }
+ case ROUND_HALF_UP: {
+ result = Floor(input * scale + half) * inverse_scale;
+ break;
+ }
+ }
ctx->SetOutput(0, result);
}
@@ -126,6 +150,7 @@ class QuantizeAndDequantizeOp : public XlaOpKernel {
int64 num_bits_ = -1;
bool signed_input_;
bool range_given_;
+ QuantizerRoundMode round_mode_;
};
class QuantizeAndDequantizeV2Op : public QuantizeAndDequantizeOp {
@@ -136,6 +161,20 @@ class QuantizeAndDequantizeV2Op : public QuantizeAndDequantizeOp {
OP_REQUIRES(ctx, num_bits_ > 0 && num_bits_ < (signed_input_ ? 62 : 63),
errors::InvalidArgument("num_bits is out of range: ", num_bits_,
" with signed_input_ ", signed_input_));
+ string round_mode_string;
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("round_mode", &round_mode_string));
+ OP_REQUIRES(
+ ctx,
+ (round_mode_string == "HALF_UP" || round_mode_string == "HALF_TO_EVEN"),
+ errors::InvalidArgument("Round mode string must be "
+ "'HALF_UP' or "
+ "'HALF_TO_EVEN', is '" +
+ round_mode_string + "'"));
+ if (round_mode_string == "HALF_UP") {
+ round_mode_ = ROUND_HALF_UP;
+ } else if (round_mode_string == "HALF_TO_EVEN") {
+ round_mode_ = ROUND_HALF_TO_EVEN;
+ }
}
};
diff --git a/tensorflow/compiler/tf2xla/kernels/random_ops.cc b/tensorflow/compiler/tf2xla/kernels/random_ops.cc
index 415ce9b77ffeac8a6a5f3c23537afb16c1d3567c..8822e29f7e77b1cbc6fa6ca61d0062d9b1b0c36e 100644
--- a/tensorflow/compiler/tf2xla/kernels/random_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/random_ops.cc
@@ -26,7 +26,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/lib/arithmetic.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/tensor.h"
diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc b/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc
index 132160de707911f26389034e16236985bb18e6ad..65e158d64fdd7df62d50b81c9e488b2d03476fb7 100644
--- a/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops.cc
@@ -125,10 +125,9 @@ class MeanOp : public XlaReductionOp {
auto size = xla::GetDimensionSize(input, dimensions_to_reduce[i]);
divisor = xla::Mul(divisor, size);
}
- xla::PrimitiveType type;
- TF_CHECK_OK(DataTypeToPrimitiveType(input_type(0), &type));
- divisor = xla::ConvertElementType(divisor, type);
- return reduce_output / divisor;
+ divisor = xla::ConvertElementType(divisor, xla_reduction_type_);
+ return XlaHelpers::ConvertElementType(reduce_output / divisor,
+ input_type(0));
}
};
diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops.h b/tensorflow/compiler/tf2xla/kernels/reduction_ops.h
index 8f1667df5b72e9ecf97e5771670ef209dee287a3..af716eab79886791e8507a84984b7ca60865d00e 100644
--- a/tensorflow/compiler/tf2xla/kernels/reduction_ops.h
+++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops.h
@@ -50,8 +50,8 @@ class XlaReductionOp : public XlaOpKernel {
// Applies a transformation to the output of the reduction. The desired
// computation should be added to 'builder'. Argument 'input' is the original
// input of the reduction; 'reduce_output' is the output of the reduction.
- // Returns the transformed reduction output, Defaults to returning
- // 'reduce_output' unchanged.
+ // Returns the transformed reduction output. Defaults to returning
+ // 'reduce_output' converted to the input type.
virtual xla::XlaOp BuildFinalizer(
xla::XlaBuilder* builder, const xla::XlaOp& input,
const xla::XlaOp& reduce_output,
diff --git a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc
index e96cabbb853be744dbba7f19fbbd227bb52ebb06..2ca2a85244b4edfe75db3d4fff6c2058adc2bf71 100644
--- a/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc
+++ b/tensorflow/compiler/tf2xla/kernels/reduction_ops_common.cc
@@ -35,13 +35,13 @@ XlaReductionOp::XlaReductionOp(OpKernelConstruction* ctx,
ctx, DataTypeToPrimitiveType(reduction_type_, &xla_reduction_type_));
}
-// Unless BuildFinalizer is overridden the reduction has no
-// finalizer.
+// The default finalizer converts the results back into the input type. This can
+// be overridden.
xla::XlaOp XlaReductionOp::BuildFinalizer(
xla::XlaBuilder* /*builder*/, const xla::XlaOp& /*input*/,
const xla::XlaOp& reduce_output,
const std::vector& /*dimensions_to_reduce*/) {
- return reduce_output;
+ return XlaHelpers::ConvertElementType(reduce_output, input_type(0));
}
void XlaReductionOp::Compile(XlaOpKernelContext* ctx) {
@@ -117,8 +117,7 @@ void XlaReductionOp::Compile(XlaOpKernelContext* ctx) {
xla::XlaComputation reduction_computation = r.Build().ConsumeValueOrDie();
auto reduce = xla::Reduce(data, initial, reduction_computation, xla_axes);
- auto deconverted = XlaHelpers::ConvertElementType(b, reduce, input_type(0));
- auto finalized = BuildFinalizer(b, data, deconverted, xla_axes);
+ auto finalized = BuildFinalizer(b, data, reduce, xla_axes);
auto result = keep_dims_ ? xla::Reshape(finalized, final_shape) : finalized;
ctx->SetOutput(0, result);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc
index 847704608fb32b43ffb61f87556d5231b9e39cde..769e0cd1409dd7e8099178c8d80b5a9adb0b20b3 100644
--- a/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/resampler_ops.cc
@@ -44,9 +44,6 @@ namespace {
using xla::XlaOp;
-// TODO(b/112295522): note that sampling from image boundary is not currently
-// being handled properly.
-
// Calculates the bilinear weight tensor, given basis ratio (px, py) of the
// sampling position:
// W = [(1-px)*(1-py), px*(1-py), (1-px)*py, px*py]
@@ -70,11 +67,8 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio,
std::vector last_two_dims_indices = {(broadcast_dims_size - 2),
(broadcast_dims_size - 1)};
- xla::Shape broadcast_shape =
- xla::ShapeUtil::MakeShape(xla_type, broadcast_dims);
-
auto broadcast_first_term =
- xla::BroadcastInDim(first_term, broadcast_shape, last_two_dims_indices);
+ xla::BroadcastInDim(first_term, broadcast_dims, last_two_dims_indices);
// Ratio is of the same dimension as warp, which is [batch, dim_0,... dim_n,
// 2], we broadcast ratio tensor to 'broadcast_dim' by keeping the
@@ -85,7 +79,7 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio,
ratio_broadcast_indices.erase(ratio_broadcast_indices.end() - 2);
auto broadcast_ratio =
- xla::BroadcastInDim(ratio, broadcast_shape, ratio_broadcast_indices);
+ xla::BroadcastInDim(ratio, broadcast_dims, ratio_broadcast_indices);
auto first_term_subtract_weights = broadcast_first_term - broadcast_ratio;
@@ -96,7 +90,7 @@ XlaOp BilinearWeights(XlaOpKernelContext* ctx, XlaOp ratio,
sign_change = xla::ConvertElementType(sign_change, xla_type);
auto broadcast_sign_change =
- xla::BroadcastInDim(sign_change, broadcast_shape, last_two_dims_indices);
+ xla::BroadcastInDim(sign_change, broadcast_dims, last_two_dims_indices);
auto flipped = first_term_subtract_weights * broadcast_sign_change;
@@ -232,21 +226,19 @@ XlaOp CalculateGradData(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
std::vector weights_with_channels_dims = reshaped_weights_dims;
weights_with_channels_dims.push_back(data_channels);
- auto weights_with_channels_shape =
- xla::ShapeUtil::MakeShape(warp_type, weights_with_channels_dims);
std::vector reshaped_weights_indices(reshaped_weights_dims.size());
std::iota(reshaped_weights_indices.begin(), reshaped_weights_indices.end(),
0);
// The dimension is [batch, dim_0, ..., dim_n, 2, 2, data_channel].
auto broadcast_reshaped_weights = xla::BroadcastInDim(
- reshaped_weights, weights_with_channels_shape, reshaped_weights_indices);
+ reshaped_weights, weights_with_channels_dims, reshaped_weights_indices);
std::vector grad_output_indices(warp_dims_without_last_dims.size());
std::iota(grad_output_indices.begin(), grad_output_indices.end(), 0);
grad_output_indices.push_back(weights_with_channels_dims.size() - 1);
XlaOp broadcast_grad_output = xla::BroadcastInDim(
- grad_output, weights_with_channels_shape, grad_output_indices);
+ grad_output, weights_with_channels_dims, grad_output_indices);
auto grad_output_multiply_weights =
broadcast_grad_output * broadcast_reshaped_weights;
@@ -294,13 +286,10 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
std::vector warp_dims_without_last_dims(warp_dims.begin(),
warp_dims.end() - 1);
+ // With dimension [batch, dim_0, ...dim_n, 4]
std::vector neighbor_broadcast_dims = warp_dims_without_last_dims;
neighbor_broadcast_dims.push_back(4);
- // With dimension [batch, dim_0, ...dim_n, 4]
- auto neighbor_broadcast_shape =
- xla::ShapeUtil::MakeShape(data_type, neighbor_broadcast_dims);
-
// The dimension is [batch, dim_0, ... dim_n, 4, data_channels]
auto neighbors_data = Gather2by2Neighbors(
ctx->builder(), data, gather_indices, data_channels, warp_shape.dims());
@@ -326,7 +315,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
xla::BroadcastInDim(
xla::ConvertElementType(
xla::ConstantR1(ctx->builder(), {0, 0, -1, 1}), data_type),
- neighbor_broadcast_shape, {last_warp_dim}),
+ neighbor_broadcast_dims, {last_warp_dim}),
neighbors_data, dot_dims, /*precision_config=*/nullptr);
// img_cxfy - img_fxfy
@@ -334,7 +323,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
xla::BroadcastInDim(
xla::ConvertElementType(
xla::ConstantR1(ctx->builder(), {-1, 1, 0, 0}), data_type),
- neighbor_broadcast_shape, {last_warp_dim}),
+ neighbor_broadcast_dims, {last_warp_dim}),
neighbors_data, dot_dims, /*precision_config=*/nullptr);
// img_cxcy - img_cxfy
@@ -342,7 +331,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
xla::BroadcastInDim(
xla::ConvertElementType(
xla::ConstantR1(ctx->builder(), {0, -1, 0, 1}), data_type),
- neighbor_broadcast_shape, {last_warp_dim}),
+ neighbor_broadcast_dims, {last_warp_dim}),
neighbors_data, dot_dims, /*precision_config=*/nullptr);
// img_fxcy - img_fxfy
@@ -350,7 +339,7 @@ XlaOp CalculateGradWarp(XlaOpKernelContext* ctx, XlaOp grad_output, XlaOp ratio,
xla::BroadcastInDim(
xla::ConvertElementType(
xla::ConstantR1(ctx->builder(), {-1, 0, 1, 0}), data_type),
- neighbor_broadcast_shape, {last_warp_dim}),
+ neighbor_broadcast_dims, {last_warp_dim}),
neighbors_data, dot_dims, /*precision_config=*/nullptr);
// Slice out x and y.
@@ -421,12 +410,13 @@ class ResamplerOp : public XlaOpKernel {
OP_REQUIRES(ctx, warp_shape.dim_size(last_warp_dim) == 2,
errors::InvalidArgument(
"the last dimension of warp must be exactly size 2."));
+ xla::PrimitiveType warp_type = ctx->input_xla_type(1);
XlaOp data = ctx->Input("data");
XlaOp warp = ctx->Input("warp");
// Find the coordinates of the top left corner for the 2x2 region to be
- // sampled from. The dimensions are (batch, dim_0, ... dim_n, 2) where the
+ // sampled from. The dimensions are [batch, dim_0, ... dim_n, 2] where the
// last dimension of size 2 in turn is [x, y].
XlaOp top_left = xla::ConvertElementType(warp, xla::U32);
@@ -457,10 +447,54 @@ class ResamplerOp : public XlaOpKernel {
dot_dims.add_lhs_contracting_dimensions(warp_shape.dims() - 1);
dot_dims.add_rhs_contracting_dimensions(warp_shape.dims() - 1);
+ // The dimension is [batch, dim_0, ...dim_n, data_channels].
auto blended_pixels = xla::DotGeneral(weights, neighbors_data, dot_dims,
/*precision_config=*/nullptr);
- ctx->SetOutput(0, blended_pixels);
+ // Handle out of boundary cases by constructing a predicate mask array based
+ // on the in-bound condition, and output 0 for the blended pixel value if
+ // out-bound. The dimension is the same as top_left: [batch, dim_0,
+ // ...dim_n, 2] where the last dimension of size 2 is the [x, y] coordinate.
+
+ auto is_ge_zero = xla::Ge(warp, xla::ZerosLike(warp));
+
+ auto is_lt_image_size = xla::Lt(
+ warp,
+ xla::ConvertElementType(
+ xla::ConstantR1(
+ ctx->builder(),
+ {/*width=*/static_cast(data_shape.dim_size(2) - 1),
+ /*height=*/static_cast(data_shape.dim_size(1) - 1)}),
+ warp_type),
+ /*broadcast_dimensions=*/{warp_shape.dims() - 1});
+
+ auto is_in_bound_x_y = xla::And(is_ge_zero, is_lt_image_size);
+ // Reduce along last dimension. The resulting dimension is:
+ // [batch, dim_0, ...dim_n].
+ auto is_in_bound = xla::Reduce(
+ is_in_bound_x_y, xla::ConstantR0(ctx->builder(), true),
+ xla::CreateScalarAndComputation(xla::PrimitiveType::PRED,
+ ctx->builder()),
+ {last_warp_dim});
+
+ // Broadcast 'is_in_bound' to the same dimension as 'blended_pixels', which
+ // is the dimension of the result:
+ // [batch, dim_0, ...dim_n, data_channels].
+ auto warp_dims = warp_shape.dim_sizes();
+ std::vector result_dims(warp_dims.begin(), warp_dims.end() - 1);
+ result_dims.push_back(data_channels);
+
+ std::vector broadcasted_dims(warp_dims.size() - 1);
+ std::iota(broadcasted_dims.begin(), broadcasted_dims.end(), 0);
+ auto broadcasted_is_in_bound =
+ xla::BroadcastInDim(is_in_bound, result_dims, broadcasted_dims);
+
+ // Set out of bound samples to zero.
+ auto zeros =
+ xla::Broadcast(xla::Zero(ctx->builder(), data_type), result_dims);
+ auto result = xla::Select(broadcasted_is_in_bound, blended_pixels, zeros);
+
+ ctx->SetOutput(0, result);
}
};
@@ -473,6 +507,8 @@ class ResamplerGradOp : public XlaOpKernel {
OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &output_dtype));
}
+ // TODO(b/112295522): note that sampling from image boundary is not currently
+ // being handled properly.
void Compile(XlaOpKernelContext* ctx) override {
TensorShape data_shape_tf = ctx->InputShape("data");
OP_REQUIRES(ctx, data_shape_tf.dims() == 4,
diff --git a/tensorflow/compiler/tf2xla/kernels/retval_op.cc b/tensorflow/compiler/tf2xla/kernels/retval_op.cc
index 6970dd0a00641c9f88571561501fb3454fb3eab3..e4046c795577983bff1a8053743bf4d3a258e583 100644
--- a/tensorflow/compiler/tf2xla/kernels/retval_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/retval_op.cc
@@ -47,8 +47,7 @@ class RetvalOp : public XlaOpKernel {
// compilation.
OP_REQUIRES_OK(ctx, frame->SetRetval(index_, input));
} else {
- XlaContext& xla_context = XlaContext::Get(ctx);
- xla_context.SetRetval(index_, ctx->InputExpression(0));
+ ctx->xla_context()->SetRetval(index_, ctx->InputExpression(0));
}
}
diff --git a/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc b/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc
index 7ff3e9163811434e8d621795c22bf8304ba7a1ed..d7b38e86cc985d608116488f9e76756a8e904f9c 100644
--- a/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/reverse_sequence_op.cc
@@ -18,7 +18,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#include "tensorflow/compiler/xla/client/lib/constants.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/framework/tensor_shape.h"
diff --git a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc
index b5fd7850bfca01868273c40cbf86188bd815be5b..4b9e1a578be2445091228953df7e5c5e82b42c28 100644
--- a/tensorflow/compiler/tf2xla/kernels/scan_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/scan_ops.cc
@@ -39,8 +39,8 @@ namespace {
// TODO(phawkins): implement double-sized windowed reductions in XLA and remove
// the type constraint.
-constexpr std::array kScanOpTypes = {
- {DT_HALF, DT_BFLOAT16, DT_FLOAT}};
+constexpr std::array kScanOpTypes = {
+ {DT_HALF, DT_BFLOAT16, DT_FLOAT, DT_INT32}};
class ScanOp : public XlaOpKernel {
public:
@@ -103,11 +103,10 @@ class ScanOp : public XlaOpKernel {
reducer = ctx->GetOrCreateMul(dtype);
}
auto output = xla::ReduceWindowWithGeneralPadding(
- XlaHelpers::ConvertElementType(builder, ctx->Input(0), dtype), init,
- *reducer, window_dims, window_strides,
+ XlaHelpers::ConvertElementType(ctx->Input(0), dtype), init, *reducer,
+ window_dims, window_strides,
/*base_dilations=*/{}, /*window_dilations=*/{}, padding);
- output =
- XlaHelpers::ConvertElementType(builder, output, ctx->input_type(0));
+ output = XlaHelpers::ConvertElementType(output, ctx->input_type(0));
// In exclusive mode, we have computed an extra element containing the sum
// of all the input elements. Slice off this extra "last" element.
diff --git a/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc b/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc
index a7f5a8f1698b9d02560de427d356e9e6be5caa7c..84470b230d421658e0d79dcecb175a24155f49b7 100644
--- a/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/sendrecv_ops.cc
@@ -42,7 +42,7 @@ SendOp::SendOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {
}
void SendOp::Compile(XlaOpKernelContext* ctx) {
- XlaCompiler* compiler = XlaContext::Get(ctx).compiler();
+ XlaCompiler* compiler = ctx->compiler();
xla::ChannelHandle channel;
OP_REQUIRES_OK(ctx, compiler->GetChannelHandle(tensor_name_, &channel));
xla::Send(ctx->Input(0), channel);
@@ -73,7 +73,7 @@ RecvOp::RecvOp(OpKernelConstruction* ctx) : XlaOpKernel(ctx) {
}
void RecvOp::Compile(XlaOpKernelContext* ctx) {
- XlaCompiler* compiler = XlaContext::Get(ctx).compiler();
+ XlaCompiler* compiler = ctx->compiler();
xla::ChannelHandle channel;
OP_REQUIRES_OK(ctx, compiler->GetChannelHandle(tensor_name_, &channel));
ctx->SetOutput(0, xla::Recv(ctx->builder(), shape_, channel));
diff --git a/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc b/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc
index 60b011ba6d9b64a89e4228ba2a213f72b67a462d..b1fa2915d59e4e5e2f2523e20e9a37898d087117 100644
--- a/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/sequence_ops.cc
@@ -18,7 +18,7 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_helpers.h"
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
+#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/primitive_util.h"
#include "tensorflow/core/framework/op_kernel.h"
diff --git a/tensorflow/compiler/tf2xla/kernels/softmax_op.cc b/tensorflow/compiler/tf2xla/kernels/softmax_op.cc
index d6bd927135c013ac1ec3f6547aef358dc2741896..20da8033536e3af3da0fcb216db45f808cacc1d5 100644
--- a/tensorflow/compiler/tf2xla/kernels/softmax_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/softmax_op.cc
@@ -71,7 +71,7 @@ class SoftmaxOp : public XlaOpKernel {
auto reduce =
xla::Reduce(converted, xla::Zero(b, xla_accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), {kClassDim});
- auto sum = XlaHelpers::ConvertElementType(b, reduce, type);
+ auto sum = XlaHelpers::ConvertElementType(reduce, type);
auto softmax =
log_
// softmax = shifted_logits - log(sum(exp(shifted_logits)))
@@ -111,11 +111,11 @@ std::pair CrossEntropyWithLogits(
// sum_{class} (exp(logits - max_logits))
const DataType accumulation_type = XlaHelpers::SumAccumulationType(type);
auto converted =
- XlaHelpers::ConvertElementType(b, exp_shifted_logits, accumulation_type);
+ XlaHelpers::ConvertElementType(exp_shifted_logits, accumulation_type);
auto reduce =
xla::Reduce(converted, XlaHelpers::Zero(b, accumulation_type),
*ctx->GetOrCreateAdd(accumulation_type), {kClassDim});
- auto sum_exp = XlaHelpers::ConvertElementType(b, reduce, type);
+ auto sum_exp = XlaHelpers::ConvertElementType(reduce, type);
// log(sum(exp(logits - max_logits)))
auto log_sum_exp = xla::Log(sum_exp);
@@ -126,11 +126,10 @@ std::pair CrossEntropyWithLogits(
// (The subtraction broadcasts along the batch dimension.)
auto sub = xla::Sub(shifted_logits, log_sum_exp, {kBatchDim});
auto mul = xla::Mul(xla::Neg(labels), sub);
- auto sum =
- xla::Reduce(XlaHelpers::ConvertElementType(b, mul, accumulation_type),
- XlaHelpers::Zero(b, accumulation_type),
- *ctx->GetOrCreateAdd(accumulation_type), {kClassDim});
- auto loss = XlaHelpers::ConvertElementType(b, sum, type);
+ auto sum = xla::Reduce(XlaHelpers::ConvertElementType(mul, accumulation_type),
+ XlaHelpers::Zero(b, accumulation_type),
+ *ctx->GetOrCreateAdd(accumulation_type), {kClassDim});
+ auto loss = XlaHelpers::ConvertElementType(sum, type);
// backprop: prob - labels, where
// prob = exp(logits - max_logits) / sum(exp(logits - max_logits))
diff --git a/tensorflow/compiler/tf2xla/kernels/stack_ops.cc b/tensorflow/compiler/tf2xla/kernels/stack_ops.cc
index 7b96b43ad834c28aa0283c5ef4ac516618ca5134..8e9e4daf99d3dd3b8e149e3f3e5f6c27665c0fcb 100644
--- a/tensorflow/compiler/tf2xla/kernels/stack_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/stack_ops.cc
@@ -69,7 +69,7 @@ Status MaybeInitializeStack(xla::XlaBuilder* builder, XlaResource* resource,
}
TensorShape stack_shape;
- stack_shape.AddDim(resource->tensor_array_size());
+ stack_shape.AddDim(resource->max_array_size());
stack_shape.AppendShape(elem_shape);
if (!resource->initialized()) {
@@ -97,10 +97,10 @@ class StackOp : public XlaOpKernel {
}
void Compile(XlaOpKernelContext* ctx) override {
- int64 size;
- OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(0, &size));
+ int64 max_size;
+ OP_REQUIRES_OK(ctx, ctx->ConstantInputAsIntScalar(0, &max_size));
OP_REQUIRES(
- ctx, size >= 0,
+ ctx, max_size >= 0,
errors::InvalidArgument(
"XLA compilation requires a fixed stack size upper bound. If "
"you are using tf.while_loop, set the maximum_iterations parameter "
@@ -108,14 +108,9 @@ class StackOp : public XlaOpKernel {
// We defer initializing the Stack resource until we see the first push.
// Otherwise we do not know the shape of the stack elements.
- xla::XlaOp value;
- XlaContext& xc = XlaContext::Get(ctx);
- XlaResource* resource;
- string name = absl::StrCat("Stack: ", stack_name_);
- OP_REQUIRES_OK(
- ctx, xc.CreateResource(XlaResource::kStack, -1, std::move(name), dtype_,
- TensorShape(), value, /*tensor_array_size=*/size,
- /*tensor_array_gradients=*/{}, &resource));
+ XlaResource* resource =
+ ctx->xla_context()->AddResource(XlaResource::CreateStack(
+ /*name=*/absl::StrCat("Stack: ", stack_name_), dtype_, max_size));
ctx->SetResourceOutput(0, resource);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc b/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc
index 252967a74649f5089f0cb0a9166b1d2b6e094f27..939d7e19515a1cb41e3e23e9d1fa957ae09ecab7 100644
--- a/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/tensor_array_ops.cc
@@ -61,8 +61,8 @@ Status MaybeInitializeTensorArray(xla::XlaBuilder* builder,
" but op has dtype ", DataTypeString(dtype), ".");
}
- TF_RET_CHECK(resource->tensor_array_size() >= 0)
- << resource->name() << " size " << resource->tensor_array_size();
+ TF_RET_CHECK(resource->max_array_size() >= 0)
+ << resource->name() << " size " << resource->max_array_size();
if (!resource->initialized()) {
TF_RETURN_IF_ERROR(resource->SetTypeAndShape(dtype, elem_shape));
@@ -78,7 +78,7 @@ Status MaybeInitializeTensorArray(xla::XlaBuilder* builder,
XLAShapeToTensorShape(shape_or_status.ValueOrDie(), &shape));
TensorShape ta_shape;
- ta_shape.AddDim(resource->tensor_array_size());
+ ta_shape.AddDim(resource->max_array_size());
ta_shape.AppendShape(elem_shape);
if (ta_shape != shape) {
return errors::InvalidArgument(
@@ -114,7 +114,7 @@ Status CheckTensorArrayIsInitialized(const string& op_name,
Status GetTensorArrayShape(const XlaResource* resource,
xla::XlaBuilder* builder, TensorShape* shape) {
*shape = resource->shape();
- shape->InsertDim(0, resource->tensor_array_size());
+ shape->InsertDim(0, resource->max_array_size());
return Status::OK();
}
@@ -166,13 +166,10 @@ class TensorArrayOp : public XlaOpKernel {
value = xla::Broadcast(zero, ta_shape.dim_sizes());
}
- XlaContext& xc = XlaContext::Get(ctx);
- XlaResource* var;
- string name = absl::StrCat("TensorArray: ", tensor_array_name_);
- OP_REQUIRES_OK(
- ctx, xc.CreateResource(XlaResource::kTensorArray, -1, std::move(name),
- dtype_, shape, value, /*tensor_array_size=*/size,
- /*tensor_array_gradients=*/{}, &var));
+ XlaResource* var =
+ ctx->xla_context()->AddResource(XlaResource::CreateTensorArray(
+ /*name=*/absl::StrCat("TensorArray: ", tensor_array_name_), dtype_,
+ shape, /*initial_value=*/value, /*max_array_size=*/size));
ctx->SetResourceOutput(0, var);
Tensor flow(DT_FLOAT, TensorShape({}));
@@ -517,14 +514,13 @@ class TensorArraySplitOp : public XlaOpKernel {
xla::XlaOp ta = resource->value();
TensorShape ta_shape;
- ta_shape.AddDim(resource->tensor_array_size());
+ ta_shape.AddDim(resource->max_array_size());
ta_shape.AppendShape(elem_shape);
- OP_REQUIRES(
- ctx, lengths.size() == resource->tensor_array_size(),
- errors::InvalidArgument(
- "TensorArray's size is not equal to the size of lengths (",
- lengths.size(), " vs. ", resource->tensor_array_size(), ")"));
+ OP_REQUIRES(ctx, lengths.size() == resource->max_array_size(),
+ errors::InvalidArgument(
+ "TensorArray's size is not equal to the size of lengths (",
+ lengths.size(), " vs. ", resource->max_array_size(), ")"));
const xla::XlaOp value = ctx->Input(1);
const xla::XlaOp flow = ctx->Input(3);
@@ -562,8 +558,7 @@ class TensorArraySizeOp : public XlaOpKernel {
XlaResource* var;
OP_REQUIRES_OK(ctx, ctx->GetResourceInput(0, &var));
Tensor size_tensor(DT_INT32, {});
- size_tensor.scalar()() =
- static_cast(var->tensor_array_size());
+ size_tensor.scalar()() = static_cast(var->max_array_size());
ctx->SetConstantOutput(0, size_tensor);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/training_ops.cc b/tensorflow/compiler/tf2xla/kernels/training_ops.cc
index 7077c2e3a546e198bdb4ff944ea531f3158810f2..960c1462ceb8c00a2d6c96564f6c985fd1caef0f 100644
--- a/tensorflow/compiler/tf2xla/kernels/training_ops.cc
+++ b/tensorflow/compiler/tf2xla/kernels/training_ops.cc
@@ -320,9 +320,8 @@ class ResourceApplyAdagradDA : public XlaOpKernel {
xla::XlaOp lr = ctx->Input(4);
xla::XlaOp l1 = ctx->Input(5);
xla::XlaOp l2 = ctx->Input(6);
- xla::XlaBuilder* const b = ctx->builder();
xla::XlaOp global_step =
- XlaHelpers::ConvertElementType(b, ctx->Input(7), dtype_);
+ XlaHelpers::ConvertElementType(ctx->Input(7), dtype_);
accum = accum + grad;
squared_accum = squared_accum + xla::Square(grad);
diff --git a/tensorflow/compiler/tf2xla/kernels/while_op.cc b/tensorflow/compiler/tf2xla/kernels/while_op.cc
index 559414eeaa5fec75e5a9d1866baaf738c024cd15..ce007fc04a818869686b9936a1607cee42665e87 100644
--- a/tensorflow/compiler/tf2xla/kernels/while_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/while_op.cc
@@ -64,7 +64,7 @@ Status MakeXlaCompilerArgumentsFromInputs(
if (!arg.initialized) {
*has_uninitialized_vars = true;
}
- arg.tensor_array_size = resource->tensor_array_size();
+ arg.max_array_size = resource->max_array_size();
for (const auto& gradient : resource->tensor_array_gradients()) {
arg.tensor_array_gradients.insert(gradient.first);
}
diff --git a/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc b/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc
index a9f88a6df2539b06ff44fb0aa49c2f2ae1389100..ad8e707e1116d01d492575986a7ab9586022f6b3 100644
--- a/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc
+++ b/tensorflow/compiler/tf2xla/kernels/xla_broadcast_helper_op.cc
@@ -89,13 +89,10 @@ class XlaBroadcastHelperOp : public XlaOpKernel {
lhs_shape.DebugString(), " and ", rhs_shape.DebugString()));
broadcast_shape[dim] = min_rank_shape->dim_size(i);
}
- xla::PrimitiveType type = context->input_xla_type(0);
- xla::Shape broadcast_xla_shape =
- xla::ShapeUtil::MakeShape(type, broadcast_shape);
if (broadcast_lhs) {
- lhs = xla::BroadcastInDim(lhs, broadcast_xla_shape, broadcast_dims);
+ lhs = xla::BroadcastInDim(lhs, broadcast_shape, broadcast_dims);
} else {
- rhs = xla::BroadcastInDim(rhs, broadcast_xla_shape, broadcast_dims);
+ rhs = xla::BroadcastInDim(rhs, broadcast_shape, broadcast_dims);
}
context->SetOutput(0, lhs);
context->SetOutput(1, rhs);
diff --git a/tensorflow/compiler/tf2xla/lib/broadcast.cc b/tensorflow/compiler/tf2xla/lib/broadcast.cc
index 3e402ef855cd7c114332d84032bc869232404fc8..be31f116686a2e302ece730e9d03312a45888a61 100644
--- a/tensorflow/compiler/tf2xla/lib/broadcast.cc
+++ b/tensorflow/compiler/tf2xla/lib/broadcast.cc
@@ -80,10 +80,8 @@ xla::StatusOr BroadcastTo(xla::XlaOp input,
broadcast_dim = broadcast_shape_size - broadcast_dim - 1;
}
absl::c_reverse(broadcast_shape);
- xla::XlaOp output = xla::BroadcastInDim(
- input,
- xla::ShapeUtil::MakeShape(input_shape.element_type(), broadcast_shape),
- broadcast_dims);
+ xla::XlaOp output =
+ xla::BroadcastInDim(input, broadcast_shape, broadcast_dims);
if (broadcast_shape != output_dims) {
output = xla::Reshape(output, output_dims);
}
diff --git a/tensorflow/compiler/tf2xla/python/BUILD b/tensorflow/compiler/tf2xla/python/BUILD
index c9f486edc8d30954619db0967c988fe8e26938de..fef97b98c376d9df8bbfd9cb6651216895e46bf4 100644
--- a/tensorflow/compiler/tf2xla/python/BUILD
+++ b/tensorflow/compiler/tf2xla/python/BUILD
@@ -1,11 +1,13 @@
licenses(["notice"]) # Apache 2.0
+package_group(
+ name = "friends",
+ includes = ["//tensorflow:internal"],
+)
+
package(
default_visibility = [
- "//learning/deepmind/public/wavenet/python:__subpackages__",
- "//learning/deepmind/research/alphastar:__subpackages__",
- "//learning/tfx:__subpackages__",
- "//tensorflow:internal",
+ ":friends",
],
)
diff --git a/tensorflow/compiler/tf2xla/shape_util.h b/tensorflow/compiler/tf2xla/shape_util.h
index f7e34a5b40c2f9244c029ed325a76322b8cf54dd..0b231ea8e7a2d8e303e91911e2e0a36fc83e78b4 100644
--- a/tensorflow/compiler/tf2xla/shape_util.h
+++ b/tensorflow/compiler/tf2xla/shape_util.h
@@ -18,6 +18,7 @@ limitations under the License.
#ifndef TENSORFLOW_COMPILER_TF2XLA_SHAPE_UTIL_H_
#define TENSORFLOW_COMPILER_TF2XLA_SHAPE_UTIL_H_
+#include "tensorflow/compiler/xla/shape.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/types.pb.h"
diff --git a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
index 66206909a92fddbac4e77e5d2d8164fcbb46f317..a1d359e97c4fad3ca74d44a358cba0e8190cdc22 100644
--- a/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
+++ b/tensorflow/compiler/tf2xla/xla_compiled_cpu_function.h
@@ -26,7 +26,7 @@ limitations under the License.
// Forward-declare, rather than include, to reduce code size for users that
// never use this functionality.
namespace xla {
-class ProgramShape;
+class ProgramShapeProto;
class HloProfilePrinterData;
}
@@ -84,7 +84,7 @@ class XlaCompiledCpuFunction {
void set_result_names(const char** result_names) {
result_names_ = result_names;
}
- void set_program_shape(const xla::ProgramShape* program_shape) {
+ void set_program_shape(const xla::ProgramShapeProto* program_shape) {
program_shape_ = program_shape;
}
const xla::HloProfilePrinterData* hlo_profile_printer_data() const {
@@ -122,7 +122,7 @@ class XlaCompiledCpuFunction {
const char** result_names_ = nullptr;
// [Optional] Arg and result shapes.
- const xla::ProgramShape* program_shape_ = nullptr;
+ const xla::ProgramShapeProto* program_shape_ = nullptr;
// [Optional] Profile printer data. Null if profiling is disabled.
const xla::HloProfilePrinterData* hlo_profile_printer_data_ = nullptr;
@@ -264,7 +264,7 @@ class XlaCompiledCpuFunction {
// Returns the shape of the args and results. May return nullptr if the
// program shape isn't available.
- const xla::ProgramShape* ProgramShape() const { return program_shape_; }
+ const xla::ProgramShapeProto* ProgramShape() const { return program_shape_; }
bool hlo_profiling_enabled() const {
return hlo_profile_printer_data_ != nullptr;
@@ -305,7 +305,7 @@ class XlaCompiledCpuFunction {
// Optional metadata.
const char** arg_names_ = nullptr;
const char** result_names_ = nullptr;
- const xla::ProgramShape* program_shape_ = nullptr;
+ const xla::ProgramShapeProto* program_shape_ = nullptr;
const xla::HloProfilePrinterData* hlo_profile_printer_data_ = nullptr;
};
diff --git a/tensorflow/compiler/tf2xla/xla_compiler.cc b/tensorflow/compiler/tf2xla/xla_compiler.cc
index 8036bc684401ff31c07ac381098e05fb8b7ee76a..ee461a3c07d4db514c7697e005a9371be4b54dd0 100644
--- a/tensorflow/compiler/tf2xla/xla_compiler.cc
+++ b/tensorflow/compiler/tf2xla/xla_compiler.cc
@@ -326,10 +326,10 @@ Status BuildComputation(
bool XlaCompiler::Argument::operator==(
const XlaCompiler::Argument& other) const {
- if (std::tie(kind, resource_kind, type, name, initialized, tensor_array_size,
+ if (std::tie(kind, resource_kind, type, name, initialized, max_array_size,
tensor_array_gradients) !=
std::tie(other.kind, other.resource_kind, other.type, other.name,
- other.initialized, other.tensor_array_size,
+ other.initialized, other.max_array_size,
other.tensor_array_gradients)) {
return false;
}
@@ -359,8 +359,8 @@ string XlaCompiler::Argument::HumanString() const {
string output = absl::StrCat("kind=resource", common, " resource_kind=",
XlaResource::KindToString(resource_kind),
" initialized=", initialized);
- if (tensor_array_size >= 0) {
- absl::StrAppend(&output, " tensor_array_size=", tensor_array_size);
+ if (max_array_size >= 0) {
+ absl::StrAppend(&output, " max_array_size=", max_array_size);
}
if (!tensor_array_gradients.empty()) {
absl::StrAppend(&output, " tensor_array_gradients=",
@@ -380,7 +380,7 @@ XlaCompiler::XlaCompiler(XlaCompiler::Options options)
initialization_status_(Status::OK()),
next_step_id_(1),
device_(new XlaCompilationDevice(SessionOptions(), options_.device_type)),
- device_mgr_({device_}) {
+ device_mgr_(absl::WrapUnique(device_)) {
CHECK(!options_.device_type.type_string().empty());
if (options_.populate_resource_manager) {
initialization_status_ =
@@ -567,12 +567,12 @@ Status XlaCompiler::XLAShapeForArgument(const XlaCompiler::Argument& arg,
return Status::OK();
}
case XlaResource::kTensorArray: {
- if (arg.tensor_array_size < 0) {
+ if (arg.max_array_size < 0) {
return errors::InvalidArgument(
- "Negative tensor_array_size in XLAShapeForArgument");
+ "Negative max_array_size in XLAShapeForArgument");
}
TensorShape shape;
- shape.AddDim(arg.tensor_array_size);
+ shape.AddDim(arg.max_array_size);
shape.AppendShape(arg.shape);
TF_RETURN_IF_ERROR(TensorShapeToXLAShape(arg.type, shape, xla_shape));
@@ -584,12 +584,12 @@ Status XlaCompiler::XLAShapeForArgument(const XlaCompiler::Argument& arg,
return Status::OK();
}
case XlaResource::kStack: {
- if (arg.tensor_array_size < 0) {
+ if (arg.max_array_size < 0) {
return errors::InvalidArgument(
- "Negative tensor_array_size in XLAShapeForArgument");
+ "Negative max_array_size in XLAShapeForArgument");
}
TensorShape shape;
- shape.AddDim(arg.tensor_array_size);
+ shape.AddDim(arg.max_array_size);
shape.AppendShape(arg.shape);
xla::Shape buffer_shape;
TF_RETURN_IF_ERROR(
@@ -635,21 +635,23 @@ Status XlaCompiler::BuildArguments(
const XlaCompiler::Argument& arg = args[i];
XlaExpression& arg_expression = (*arg_expressions)[i];
switch (arg.kind) {
- case XlaCompiler::Argument::kResource:
+ case XlaCompiler::Argument::kResource: {
TF_RET_CHECK(arg.resource_kind != XlaResource::kInvalid);
// TODO(phawkins): this code assumes that resource arguments do not
// alias.
- XlaResource* resource;
- TF_RETURN_IF_ERROR(context->CreateResource(
- arg.resource_kind, i, arg.name, arg.type, arg.shape, xla::XlaOp(),
- /*tensor_array_size=*/arg.tensor_array_size,
- /*tensor_array_gradients=*/arg.tensor_array_gradients, &resource));
+ XlaResource* resource =
+ context->AddResource(absl::make_unique(
+ arg.resource_kind, i, arg.name, arg.type, arg.shape,
+ xla::XlaOp(),
+ /*max_array_size=*/arg.max_array_size,
+ /*tensor_array_gradients=*/arg.tensor_array_gradients,
+ /*tensor_array_multiple_writes_aggregate=*/true));
arg_expression = XlaExpression::Resource(resource);
if (arg.initialized) {
input_mapping->push_back(i);
}
-
break;
+ }
case XlaCompiler::Argument::kParameter:
case XlaCompiler::Argument::kToken: {
input_mapping->push_back(i);
@@ -923,9 +925,7 @@ Status XlaCompiler::CompileGraph(const XlaCompiler::CompileOptions& options,
options_.device_type, name));
xla::XlaBuilder builder(name);
- XlaContext* context =
- new XlaContext(this, &builder, options_.allow_cpu_custom_calls,
- &options_.shape_representation_fn);
+ XlaContext* context = new XlaContext(this, &builder);
core::ScopedUnref context_unref(context);
std::vector real_args(args.begin(), args.end());
diff --git a/tensorflow/compiler/tf2xla/xla_compiler.h b/tensorflow/compiler/tf2xla/xla_compiler.h
index 63426124686e1b92a3534b7e365b8282008b8455..0d801b73a8c2651305328384377751254ecaa41d 100644
--- a/tensorflow/compiler/tf2xla/xla_compiler.h
+++ b/tensorflow/compiler/tf2xla/xla_compiler.h
@@ -150,7 +150,7 @@ class XlaCompiler {
// For a TensorArray or Stack resource, what is the array's declared size?
// (Used for lazy initialization.)
- int64 tensor_array_size = -1;
+ int64 max_array_size = -1;
// TensorArray resource parameters are passed as (array, gradient array 0,
// ..., gradient array k), where the gradient arrays are in the same order
diff --git a/tensorflow/compiler/tf2xla/xla_compiler_test.cc b/tensorflow/compiler/tf2xla/xla_compiler_test.cc
index eba5d77efabd752f8476c27e95610343c54ea460..fe2a5f5b0c9ea6b5f2bb71df836fdcabf9a0cf23 100644
--- a/tensorflow/compiler/tf2xla/xla_compiler_test.cc
+++ b/tensorflow/compiler/tf2xla/xla_compiler_test.cc
@@ -650,7 +650,7 @@ TEST_F(XlaCompilerTest, CanPassTensorArraysToAndFromComputation) {
args[0].initialized = true;
args[0].type = DT_INT32;
args[0].shape = TensorShape({});
- args[0].tensor_array_size = 2;
+ args[0].max_array_size = 2;
args[0].tensor_array_gradients = {"grad2"};
// Compiles the graph.
@@ -709,7 +709,7 @@ TEST_F(XlaCompilerTest, UnwrittenTensorArrayGradientsAreNotComputationOutputs) {
args[0].initialized = true;
args[0].type = DT_INT32;
args[0].shape = TensorShape({});
- args[0].tensor_array_size = 2;
+ args[0].max_array_size = 2;
args[0].tensor_array_gradients = {"grad1"};
// Compiles the graph.
@@ -741,7 +741,7 @@ TEST_F(XlaCompilerTest, NewTensorArrayGradientsAreComputationOutputs) {
args[0].initialized = true;
args[0].type = DT_INT32;
args[0].shape = TensorShape({});
- args[0].tensor_array_size = 2;
+ args[0].max_array_size = 2;
args[0].tensor_array_gradients = {"grad1"};
// Compiles the graph.
diff --git a/tensorflow/compiler/tf2xla/xla_context.cc b/tensorflow/compiler/tf2xla/xla_context.cc
index 43095fbb47351617a0de12a088c947106ccaa641..a69af70503376b6c0905deb8980abdc3254a6e47 100644
--- a/tensorflow/compiler/tf2xla/xla_context.cc
+++ b/tensorflow/compiler/tf2xla/xla_context.cc
@@ -54,25 +54,14 @@ const char XlaContext::kXlaContextResourceName[] = "_xla_context";
return *context;
}
-/* static */ XlaContext& XlaContext::Get(const XlaOpKernelContext* ctx) {
- return Get(ctx->op_kernel_context());
-}
-
void XlaContext::set_args(std::vector args) {
args_ = std::move(args);
}
-XlaContext::XlaContext(
- XlaCompiler* compiler, xla::XlaBuilder* builder,
- bool allow_cpu_custom_calls,
- const std::function(
- const TensorShape&, DataType)>* shape_representation_fn)
- : compiler_(compiler),
- builder_(builder),
- allow_cpu_custom_calls_(allow_cpu_custom_calls),
- shape_representation_fn_(shape_representation_fn) {}
+XlaContext::XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder)
+ : compiler_(compiler), builder_(builder) {}
-string XlaContext::DebugString() { return "TLA JIT context"; }
+string XlaContext::DebugString() { return "XLA JIT context"; }
void XlaContext::SetRetval(int index, const XlaExpression& expression) {
if (retvals_.size() <= index) {
@@ -81,21 +70,9 @@ void XlaContext::SetRetval(int index, const XlaExpression& expression) {
retvals_[index] = expression;
}
-Status XlaContext::CreateResource(
- XlaResource::Kind kind, int arg_num, string name, DataType type,
- TensorShape shape, const xla::XlaOp& handle, int64 tensor_array_size,
- const std::set& tensor_array_gradients, XlaResource** resource) {
- resources_.emplace_back(
- new XlaResource(kind, arg_num, std::move(name), type, std::move(shape),
- handle, tensor_array_size, tensor_array_gradients,
- /*tensor_array_multiple_writes_aggregate=*/false));
- *resource = resources_.back().get();
- return Status::OK();
-}
-
-xla::StatusOr XlaContext::RepresentationShape(
- const TensorShape& shape, DataType type) const {
- return (*shape_representation_fn_)(shape, type);
+XlaResource* XlaContext::AddResource(std::unique_ptr resource) {
+ resources_.push_back(std::move(resource));
+ return resources_.back().get();
}
const xla::XlaComputation* XlaContext::GetOrCreateMax(const DataType type) {
diff --git a/tensorflow/compiler/tf2xla/xla_context.h b/tensorflow/compiler/tf2xla/xla_context.h
index dbfd344c9bad8a5d05abb6a3b902ed3baebbe02a..0767d1faac14cedb8666f6cc37175eb7b55f6158 100644
--- a/tensorflow/compiler/tf2xla/xla_context.h
+++ b/tensorflow/compiler/tf2xla/xla_context.h
@@ -41,14 +41,10 @@ class XlaContext : public ResourceBase {
public:
// Retrieves the XlaContext of the current compilation.
static XlaContext& Get(const OpKernelContext* ctx);
- static XlaContext& Get(const XlaOpKernelContext* ctx);
// Creates a new XlaContext. See the documentation on the class data fields
// for descriptions of the arguments.
- XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder,
- bool allow_cpu_custom_calls,
- const std::function(
- const TensorShape&, DataType)>* shape_representation_fn);
+ XlaContext(XlaCompiler* compiler, xla::XlaBuilder* builder);
// Virtual method defined by ResourceBase.
string DebugString() override;
@@ -58,8 +54,6 @@ class XlaContext : public ResourceBase {
// Returns the XlaBuilder that Ops use for compiling new expressions.
xla::XlaBuilder* builder() { return builder_; }
- bool allow_cpu_custom_calls() const { return allow_cpu_custom_calls_; }
-
const std::vector& args() const { return args_; }
void set_args(std::vector args);
@@ -70,25 +64,13 @@ class XlaContext : public ResourceBase {
// grows the return values vector to size index+1 if it is smaller.
void SetRetval(int index, const XlaExpression& expression);
- // Creates a resource with resource `kind` and initial value `handle`. `name`
- // is a descriptive name for use in error messages. See the `XlaResource`
- // constructor for a description of the remaining arguments.
- // Fails if the resource already exists.
- Status CreateResource(XlaResource::Kind kind, int arg_num, string name,
- DataType type, TensorShape shape,
- const xla::XlaOp& handle, int64 tensor_array_size,
- const std::set& tensor_array_gradients,
- XlaResource** resource);
+ // Adds 'resource' to the set of resources owned by the context.
+ XlaResource* AddResource(std::unique_ptr resource);
const std::vector>& resources() {
return resources_;
}
- // Returns the XLA shape to be used to represent a variable of TF `shape`
- // and `type`, or of an argument or return value of a top-level computation.
- xla::StatusOr RepresentationShape(const TensorShape& shape,
- DataType type) const;
-
// Get an XLA lambda to compute Max. This is cached in the
// XlaContext since it may be used by multiple Ops. There is a
// separate specialization of the computation for each DataType.
@@ -118,9 +100,6 @@ class XlaContext : public ResourceBase {
// The XlaBuilder used to construct the subgraph's compiled representation.
xla::XlaBuilder* builder_;
- // Allow ops to emit CustomCall operations for CPU.
- const bool allow_cpu_custom_calls_;
-
// Arguments to the Tensorflow graph, indexed by _Arg index.
// Includes both compile-time constant arguments and runtime parameters.
std::vector args_;
@@ -131,11 +110,6 @@ class XlaContext : public ResourceBase {
// Holds ownership of resources. The resources are not ordered.
std::vector> resources_;
- // Describes the on-host shapes of parameters and return values. Also see:
- // XlaDevice::Options::shape_representation_fn.
- const std::function(const TensorShape&, DataType)>*
- shape_representation_fn_;
-
// Cache of prebuilt computations indexed by their type.
using ComputationMap = std::map;
diff --git a/tensorflow/compiler/tf2xla/xla_helpers.cc b/tensorflow/compiler/tf2xla/xla_helpers.cc
index 9a34cd8c6ae2dc6d52a3cc69168df96f5322c6da..c2c0751211180c3715a19d6c78e34659fd18914e 100644
--- a/tensorflow/compiler/tf2xla/xla_helpers.cc
+++ b/tensorflow/compiler/tf2xla/xla_helpers.cc
@@ -26,7 +26,6 @@ limitations under the License.
#include "tensorflow/compiler/tf2xla/xla_op_kernel.h"
#include "tensorflow/compiler/xla/client/lib/arithmetic.h"
#include "tensorflow/compiler/xla/client/lib/constants.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/client/xla_computation.h"
#include "tensorflow/compiler/xla/types.h"
@@ -216,8 +215,7 @@ DataType XlaHelpers::SumAccumulationType(const DataType& dtype) {
return dtype;
}
-xla::XlaOp XlaHelpers::ConvertElementType(xla::XlaBuilder* const builder,
- const xla::XlaOp& operand,
+xla::XlaOp XlaHelpers::ConvertElementType(const xla::XlaOp& operand,
const DataType new_element_type) {
xla::PrimitiveType convert_to;
TF_CHECK_OK(DataTypeToPrimitiveType(new_element_type, &convert_to));
diff --git a/tensorflow/compiler/tf2xla/xla_helpers.h b/tensorflow/compiler/tf2xla/xla_helpers.h
index 39578144caaadf293d24ea91aa874e56e27ecc01..4858dfee55a393d04cd2af83916eeb40820ee368 100644
--- a/tensorflow/compiler/tf2xla/xla_helpers.h
+++ b/tensorflow/compiler/tf2xla/xla_helpers.h
@@ -80,8 +80,7 @@ class XlaHelpers {
// A helper for creating a ConvertElementType xla op given a DataType rather
// than the xla::PrimitiveType.
- static xla::XlaOp ConvertElementType(xla::XlaBuilder* const builder,
- const xla::XlaOp& operand,
+ static xla::XlaOp ConvertElementType(const xla::XlaOp& operand,
const DataType new_element_type);
};
diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
index 86a78ee429e8913edb4a948727fa692083c472f4..fabbcd04fed96ad814d04c2df9394f43bfe0cf99 100644
--- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
+++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.cc
@@ -133,7 +133,8 @@ XlaJitCompiledCpuFunction::Compile(
jit->executable_ = std::move(executable);
jit->buffer_infos_ = std::move(buffer_infos);
jit->arg_index_table_ = std::move(arg_index_table);
- jit->program_shape_ = std::move(program_shape);
+ jit->program_shape_ =
+ absl::make_unique(program_shape->ToProto());
jit->static_data_.set_raw_function(raw_function);
jit->static_data_.set_buffer_infos(jit->buffer_infos_.data());
jit->static_data_.set_num_buffers(jit->buffer_infos_.size());
diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h
index d3c8f22a8078d03d15447ed200c914390f40b04f..a5392057177e983e11787c31bb496a8947add1e6 100644
--- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h
+++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function.h
@@ -80,8 +80,10 @@ class XlaJitCompiledCpuFunction {
std::vector arg_names_;
std::vector result_names_;
- // The backing data for the program shape.
- std::unique_ptr program_shape_;
+ // The backing data for the program shape. The proto form of program shape is
+ // used because the program shape is serialized and embedded in the object
+ // file.
+ std::unique_ptr program_shape_;
};
} // namespace tensorflow
diff --git a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc
index 6d49298a6f3e8a726695fafc42f3c5341fe98b5f..8846088678b53f6b9ecff0de732d6b5c82392b5a 100644
--- a/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc
+++ b/tensorflow/compiler/tf2xla/xla_jit_compiled_cpu_function_test.cc
@@ -116,13 +116,13 @@ TEST(XlaJitCompiledCpuFunction, Sum) {
// Check program shape.
using xla::ShapeUtil;
const xla::Shape s32 = ShapeUtil::MakeShape(xla::S32, {});
- const xla::ProgramShape* program_shape = function.ProgramShape();
- ASSERT_TRUE(program_shape != nullptr);
- ASSERT_EQ(program_shape->parameters_size(), 2);
- EXPECT_TRUE(ShapeUtil::Compatible(program_shape->parameters(0), s32));
- EXPECT_TRUE(ShapeUtil::Compatible(program_shape->parameters(1), s32));
+ ASSERT_TRUE(function.ProgramShape() != nullptr);
+ const xla::ProgramShape program_shape(*function.ProgramShape());
+ ASSERT_EQ(program_shape.parameters_size(), 2);
+ EXPECT_TRUE(ShapeUtil::Compatible(program_shape.parameters(0), s32));
+ EXPECT_TRUE(ShapeUtil::Compatible(program_shape.parameters(1), s32));
- const xla::Shape& result = program_shape->result();
+ const xla::Shape& result = program_shape.result();
ASSERT_EQ(result.element_type(), xla::TUPLE);
ASSERT_EQ(ShapeUtil::TupleElementCount(result), 1);
const xla::Shape& result0 = ShapeUtil::GetTupleElementShape(result, 0);
diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.cc b/tensorflow/compiler/tf2xla/xla_op_kernel.cc
index 8dd8def0549f2b39d4c9863bb535f19703c3ef22..58808c76de6330a6b28e21dbdead03dea25847f6 100644
--- a/tensorflow/compiler/tf2xla/xla_op_kernel.cc
+++ b/tensorflow/compiler/tf2xla/xla_op_kernel.cc
@@ -36,8 +36,16 @@ bool XlaOpKernelContext::ValidateInputsAreSameShape(OpKernel* op) {
return context_->ValidateInputsAreSameShape(op);
}
+XlaContext* XlaOpKernelContext::xla_context() const {
+ return &XlaContext::Get(context_);
+}
+
xla::XlaBuilder* XlaOpKernelContext::builder() const {
- return XlaContext::Get(this).builder();
+ return xla_context()->builder();
+}
+
+XlaCompiler* XlaOpKernelContext::compiler() const {
+ return xla_context()->compiler();
}
// Retrieves an XlaExpression that was allocated by a previous Op.
@@ -338,8 +346,8 @@ Status XlaOpKernelContext::ConstantInputList(
namespace {
Status ReadVariableInputTensor(const Tensor& tensor, DataType type,
- const OpKernelContext* ctx, TensorShape* shape,
- xla::XlaOp* value) {
+ const XlaOpKernelContext* ctx,
+ TensorShape* shape, xla::XlaOp* value) {
const XlaExpression* expression = CastExpressionFromTensor(tensor);
XlaResource* variable = expression->resource();
TF_RET_CHECK(variable != nullptr);
@@ -357,10 +365,9 @@ Status ReadVariableInputTensor(const Tensor& tensor, DataType type,
*shape = variable->shape();
}
- XlaContext& xla_context = XlaContext::Get(ctx);
- TF_ASSIGN_OR_RETURN(
- xla::Shape representation_shape,
- xla_context.RepresentationShape(variable->shape(), variable->type()));
+ TF_ASSIGN_OR_RETURN(xla::Shape representation_shape,
+ ctx->compiler()->options().shape_representation_fn(
+ variable->shape(), variable->type()));
xla::Shape xla_shape;
TF_RETURN_IF_ERROR(
TensorShapeToXLAShape(variable->type(), variable->shape(), &xla_shape));
@@ -377,15 +384,15 @@ Status ReadVariableInputTensor(const Tensor& tensor, DataType type,
Status XlaOpKernelContext::ReadVariableInput(int index, DataType type,
TensorShape* shape,
xla::XlaOp* value) {
- return ReadVariableInputTensor(context_->input(index), type, context_, shape,
+ return ReadVariableInputTensor(context_->input(index), type, this, shape,
value);
}
Status XlaOpKernelContext::ReadVariableInput(absl::string_view name,
DataType type, TensorShape* shape,
xla::XlaOp* value) {
- return ReadVariableInputTensor(GetInputTensorByName(name), type, context_,
- shape, value);
+ return ReadVariableInputTensor(GetInputTensorByName(name), type, this, shape,
+ value);
}
Status XlaOpKernelContext::GetVariableTypeAndShape(int index, DataType* type,
@@ -464,7 +471,7 @@ Status XlaOpKernelContext::GetResourceInput(int index, XlaResource** resource) {
namespace {
Status AssignVariableTensor(const Tensor& tensor, DataType type,
- const OpKernelContext* ctx, xla::XlaOp handle,
+ const XlaOpKernelContext* ctx, xla::XlaOp handle,
xla::XlaBuilder* builder) {
const XlaExpression* expression = CastExpressionFromTensor(tensor);
XlaResource* variable = expression->resource();
@@ -481,9 +488,9 @@ Status AssignVariableTensor(const Tensor& tensor, DataType type,
TF_RETURN_IF_ERROR(variable->SetTypeAndShape(type, shape));
- XlaContext& xla_context = XlaContext::Get(ctx);
- TF_ASSIGN_OR_RETURN(xla::Shape representation_shape,
- xla_context.RepresentationShape(shape, type));
+ TF_ASSIGN_OR_RETURN(
+ xla::Shape representation_shape,
+ ctx->compiler()->options().shape_representation_fn(shape, type));
xla::Shape xla_shape;
TF_RETURN_IF_ERROR(TensorShapeToXLAShape(type, shape, &xla_shape));
if (!xla::ShapeUtil::Compatible(xla_shape, representation_shape)) {
@@ -498,19 +505,15 @@ Status AssignVariableTensor(const Tensor& tensor, DataType type,
Status XlaOpKernelContext::AssignVariable(int input_index, DataType type,
xla::XlaOp handle) {
TF_RET_CHECK(handle.valid());
- return AssignVariableTensor(context_->input(input_index), type, context_,
- handle, builder());
+ return AssignVariableTensor(context_->input(input_index), type, this, handle,
+ builder());
}
Status XlaOpKernelContext::AssignVariable(absl::string_view name, DataType type,
xla::XlaOp handle) {
TF_RET_CHECK(handle.valid());
- return AssignVariableTensor(GetInputTensorByName(name), type, context_,
- handle, builder());
-}
-
-XlaCompiler* XlaOpKernelContext::compiler() const {
- return XlaContext::Get(context_).compiler();
+ return AssignVariableTensor(GetInputTensorByName(name), type, this, handle,
+ builder());
}
void XlaOpKernelContext::CtxFailure(const Status& s) {
@@ -530,22 +533,22 @@ void XlaOpKernelContext::CtxFailureWithWarning(const char* file, int line,
const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMax(
const DataType type) {
- return XlaContext::Get(context_).GetOrCreateMax(type);
+ return xla_context()->GetOrCreateMax(type);
}
const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMin(
const DataType type) {
- return XlaContext::Get(context_).GetOrCreateMin(type);
+ return xla_context()->GetOrCreateMin(type);
}
const xla::XlaComputation* XlaOpKernelContext::GetOrCreateAdd(
const DataType type) {
- return XlaContext::Get(context_).GetOrCreateAdd(type);
+ return xla_context()->GetOrCreateAdd(type);
}
const xla::XlaComputation* XlaOpKernelContext::GetOrCreateMul(
const DataType type) {
- return XlaContext::Get(context_).GetOrCreateMul(type);
+ return xla_context()->GetOrCreateMul(type);
}
const Tensor& XlaOpKernelContext::GetInputTensorByName(absl::string_view name) {
diff --git a/tensorflow/compiler/tf2xla/xla_op_kernel.h b/tensorflow/compiler/tf2xla/xla_op_kernel.h
index c06efa2c474c5ec3cb5d75d94ba15d4096faa085..1858844bc05a6e12abbf07af83cad816590ddd03 100644
--- a/tensorflow/compiler/tf2xla/xla_op_kernel.h
+++ b/tensorflow/compiler/tf2xla/xla_op_kernel.h
@@ -60,6 +60,8 @@ class XlaOpKernelContext {
public:
explicit XlaOpKernelContext(OpKernelContext* context);
+ XlaContext* xla_context() const;
+
// Returns the XLA XlaBuilder containing the output of compilation.
xla::XlaBuilder* builder() const;
diff --git a/tensorflow/compiler/tf2xla/xla_resource.cc b/tensorflow/compiler/tf2xla/xla_resource.cc
index a322eb9015e829fd468133f3de6c12aad7e4ff74..48a3c012727acd8472d3d5d4072ae700f5497d96 100644
--- a/tensorflow/compiler/tf2xla/xla_resource.cc
+++ b/tensorflow/compiler/tf2xla/xla_resource.cc
@@ -18,6 +18,7 @@ limitations under the License.
#include
#include
+#include "absl/memory/memory.h"
#include "tensorflow/compiler/tf2xla/shape_util.h"
#include "tensorflow/compiler/tf2xla/sharding_util.h"
#include "tensorflow/compiler/tf2xla/xla_context.h"
@@ -39,9 +40,29 @@ namespace tensorflow {
}
}
+/*static*/ std::unique_ptr XlaResource::CreateStack(
+ string name, DataType type, int64 max_size) {
+ return absl::make_unique(
+ XlaResource::kStack, /*arg_num=*/-1, std::move(name), type, TensorShape(),
+ /*initial_value=*/xla::XlaOp(),
+ /*max_array_size=*/max_size,
+ /*tensor_array_gradients=*/std::set{},
+ /*tensor_array_multiple_writes_aggregate=*/false);
+}
+
+/*static*/ std::unique_ptr XlaResource::CreateTensorArray(
+ string name, DataType type, TensorShape shape, xla::XlaOp initial_value,
+ int64 max_array_size) {
+ return absl::make_unique(
+ XlaResource::kTensorArray, /*arg_num=*/-1, std::move(name), type, shape,
+ initial_value, max_array_size,
+ /*tensor_array_gradients=*/std::set{},
+ /*tensor_array_multiple_writes_aggregate=*/false);
+}
+
XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type,
TensorShape shape, const xla::XlaOp& initial_value,
- int64 tensor_array_size,
+ int64 max_array_size,
const std::set& tensor_array_gradients,
bool tensor_array_multiple_writes_aggregate)
: kind_(kind),
@@ -51,7 +72,7 @@ XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type,
shape_(std::move(shape)),
value_(initial_value),
initial_value_(initial_value),
- tensor_array_size_(tensor_array_size),
+ max_array_size_(max_array_size),
tensor_array_multiple_writes_aggregate_(
tensor_array_multiple_writes_aggregate) {
CHECK(kind_ != kInvalid);
@@ -60,7 +81,7 @@ XlaResource::XlaResource(Kind kind, int arg_num, string name, DataType type,
tensor_array_gradients_[gradient].reset(new XlaResource(
/*kind=*/kTensorArray, /*arg_num=*/-1,
/*name=*/absl::StrCat("TensorArrayGrad: ", name_), type_, shape_,
- xla::XlaOp(), tensor_array_size_, /*tensor_array_gradients=*/{},
+ xla::XlaOp(), max_array_size_, /*tensor_array_gradients=*/{},
/*tensor_array_multiple_writes_aggregate=*/true));
}
}
@@ -113,7 +134,7 @@ Status XlaResource::SetZeroValue(xla::XlaBuilder* builder) {
}
case kTensorArray: {
TensorShape ta_shape;
- ta_shape.AddDim(tensor_array_size_);
+ ta_shape.AddDim(max_array_size_);
ta_shape.AppendShape(shape_);
value_ = xla::Broadcast(XlaHelpers::Zero(builder, type_),
ta_shape.dim_sizes());
@@ -121,7 +142,7 @@ Status XlaResource::SetZeroValue(xla::XlaBuilder* builder) {
}
case kStack: {
TensorShape ta_shape;
- ta_shape.AddDim(tensor_array_size_);
+ ta_shape.AddDim(max_array_size_);
ta_shape.AppendShape(shape_);
value_ =
xla::Tuple(builder, {xla::Broadcast(XlaHelpers::Zero(builder, type_),
@@ -146,14 +167,14 @@ Status XlaResource::GetOrCreateTensorArrayGradient(const string& source,
std::unique_ptr& gradient = tensor_array_gradients_[source];
if (!gradient) {
TensorShape ta_shape;
- ta_shape.AddDim(tensor_array_size_);
+ ta_shape.AddDim(max_array_size_);
ta_shape.AppendShape(shape_);
xla::XlaOp gradient_value =
xla::Broadcast(XlaHelpers::Zero(builder, type_), ta_shape.dim_sizes());
gradient.reset(
new XlaResource(/*kind=*/kTensorArray, /*arg_num=*/-1,
/*name=*/absl::StrCat("TensorArrayGrad: ", name_),
- type_, shape_, gradient_value, tensor_array_size_,
+ type_, shape_, gradient_value, max_array_size_,
/*tensor_array_gradients=*/{},
/*tensor_array_multiple_writes_aggregate=*/true));
}
diff --git a/tensorflow/compiler/tf2xla/xla_resource.h b/tensorflow/compiler/tf2xla/xla_resource.h
index 857b9a928bb824656f637b2b1ca2fc02a1bef139..736588bb8b89ba756cdce77eeebff8d1fcf4774c 100644
--- a/tensorflow/compiler/tf2xla/xla_resource.h
+++ b/tensorflow/compiler/tf2xla/xla_resource.h
@@ -38,9 +38,18 @@ class XlaResource {
};
static absl::string_view KindToString(Kind kind);
+ // Creates a new Stack resource.
+ static std::unique_ptr CreateStack(string name, DataType type,
+ int64 max_size);
+
+ // Creates a new TensorArray resource.
+ static std::unique_ptr CreateTensorArray(
+ string name, DataType type, TensorShape shape, xla::XlaOp initial_value,
+ int64 max_array_size);
+
XlaResource(Kind kind, int arg_num, string name, DataType type,
TensorShape shape, const xla::XlaOp& initial_value,
- int64 tensor_array_size,
+ int64 max_array_size,
const std::set& tensor_array_gradients,
bool tensor_array_multiple_writes_aggregate);
@@ -119,12 +128,12 @@ class XlaResource {
// TODO(phawkins): refactor this code to use subclasses, rather than putting
// kind-specific fields in XlaResource.
- // 'tensor_array_size' stores the expected size of the TensorArray or Stack.
+ // 'max_array_size' stores the expected size of the TensorArray or Stack.
// We need to store this since sometimes TensorArrays must be initialized
// lazily since we do not know the element shape at construction time.
// Used by both TensorArrays and Stacks.
- int64 tensor_array_size() const { return tensor_array_size_; }
- void set_tensor_array_size(int64 size) { tensor_array_size_ = size; }
+ int64 max_array_size() const { return max_array_size_; }
+ void set_max_array_size(int64 size) { max_array_size_ = size; }
bool tensor_array_multiple_writes_aggregate() const {
return tensor_array_multiple_writes_aggregate_;
@@ -151,7 +160,7 @@ class XlaResource {
xla::XlaOp value_;
xla::XlaOp initial_value_;
- int64 tensor_array_size_ = -1;
+ int64 max_array_size_ = -1;
bool tensor_array_multiple_writes_aggregate_ = false;
std::map> tensor_array_gradients_;
diff --git a/tensorflow/compiler/xla/BUILD b/tensorflow/compiler/xla/BUILD
index d914e97b6bd4506251dc4be504d6ab427590e615..4360e0857964b0ac63fc887e269b04a4b00d854a 100644
--- a/tensorflow/compiler/xla/BUILD
+++ b/tensorflow/compiler/xla/BUILD
@@ -226,12 +226,14 @@ cc_library(
"index_util.cc",
"layout_util.cc",
"primitive_util.cc",
+ "shape.cc",
"shape_util.cc",
],
hdrs = [
"index_util.h",
"layout_util.h",
"primitive_util.h",
+ "shape.h",
"shape_util.h",
],
visibility = ["//visibility:public"],
@@ -254,6 +256,23 @@ cc_library(
],
)
+tf_cc_test(
+ name = "shape_test",
+ srcs = ["shape_test.cc"],
+ deps = [
+ ":shape_util",
+ ":status_macros",
+ ":test",
+ ":test_helpers",
+ ":types",
+ ":util",
+ ":xla_data_proto",
+ "//tensorflow/core:lib",
+ "//tensorflow/core:test_main",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
tf_cc_test(
name = "shape_util_test",
srcs = ["shape_util_test.cc"],
diff --git a/tensorflow/compiler/xla/client/BUILD b/tensorflow/compiler/xla/client/BUILD
index 42da0ebf4992884187bbe21701a44d8ba2fccd64..fe99564d3c671cd7890e1fa26fcd2e3384972983 100644
--- a/tensorflow/compiler/xla/client/BUILD
+++ b/tensorflow/compiler/xla/client/BUILD
@@ -81,6 +81,7 @@ cc_library(
"//tensorflow/core:lib",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
+ "@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:span",
],
)
@@ -90,11 +91,12 @@ cc_library(
srcs = ["executable_build_options.cc"],
hdrs = ["executable_build_options.h"],
deps = [
+ "//tensorflow/compiler/xla:debug_options_flags",
"//tensorflow/compiler/xla:shape_util",
"//tensorflow/compiler/xla:util",
"//tensorflow/compiler/xla:xla_data_proto",
+ "//tensorflow/compiler/xla:xla_proto",
"//tensorflow/compiler/xla/service:device_memory_allocator",
- "//tensorflow/core:lib",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/types:optional",
@@ -191,6 +193,7 @@ cc_library(
hdrs = ["xla_computation.h"],
visibility = ["//visibility:public"],
deps = [
+ "//tensorflow/compiler/xla:shape_util",
"//tensorflow/compiler/xla:status_macros",
"//tensorflow/compiler/xla:util",
"//tensorflow/compiler/xla:xla_data_proto",
diff --git a/tensorflow/compiler/xla/client/client.cc b/tensorflow/compiler/xla/client/client.cc
index eef2844e0df6aaf509881535f41493673fbeeee5..74b76f929949d3300a5d0ff45d5fa4cd9f162642 100644
--- a/tensorflow/compiler/xla/client/client.cc
+++ b/tensorflow/compiler/xla/client/client.cc
@@ -20,6 +20,7 @@ limitations under the License.
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
+#include "absl/types/optional.h"
#include "tensorflow/compiler/xla/client/xla_computation.h"
#include "tensorflow/compiler/xla/debug_options_flags.h"
#include "tensorflow/compiler/xla/execution_options_util.h"
@@ -42,7 +43,7 @@ StatusOr Client::Transfer(const GlobalData& data,
TransferToClientRequest request;
*request.mutable_data() = data.handle();
if (shape_with_layout != nullptr) {
- *request.mutable_shape_with_layout() = *shape_with_layout;
+ *request.mutable_shape_with_layout() = shape_with_layout->ToProto();
}
TransferToClientResponse response;
@@ -123,7 +124,7 @@ StatusOr Client::TransferFromOutfeed(
}
request.set_replica_id(replica_id);
if (shape_with_layout != nullptr) {
- *request.mutable_shape_with_layout() = *shape_with_layout;
+ *request.mutable_shape_with_layout() = shape_with_layout->ToProto();
}
TransferFromOutfeedResponse response;
@@ -170,11 +171,14 @@ StatusOr Client::ExecuteAndTransfer(
std::unique_ptr data,
Execute(computation, arguments, execution_options, execution_profile));
- const Shape* shape_with_output_layout = nullptr;
+ absl::optional shape_with_output_layout;
if (execution_options && execution_options->has_shape_with_output_layout()) {
- shape_with_output_layout = &execution_options->shape_with_output_layout();
+ shape_with_output_layout =
+ Shape(execution_options->shape_with_output_layout());
}
- return Transfer(*data, shape_with_output_layout);
+ return Transfer(*data, shape_with_output_layout.has_value()
+ ? &(*shape_with_output_layout)
+ : nullptr);
}
StatusOr Client::ComputeConstant(const XlaComputation& computation,
@@ -229,7 +233,7 @@ StatusOr Client::Compile(
// The argument shapes affect how the computation is compiled.
for (const auto& arg_shape : argument_shapes) {
- *request.add_input_shape_with_layout() = arg_shape;
+ *request.add_input_shape_with_layout() = arg_shape.ToProto();
}
CompileResponse response;
@@ -458,7 +462,7 @@ StatusOr Client::GetShape(const GlobalData& data) {
return s;
}
- return response.shape();
+ return Shape(response.shape());
}
StatusOr Client::ExecutionStatsAsString(
diff --git a/tensorflow/compiler/xla/client/executable_build_options.cc b/tensorflow/compiler/xla/client/executable_build_options.cc
index 0f1745366b7c33e573aff2e66d85431b01488c49..1f594e551af381d7537e947892cbf7e0b5b3b861 100644
--- a/tensorflow/compiler/xla/client/executable_build_options.cc
+++ b/tensorflow/compiler/xla/client/executable_build_options.cc
@@ -16,6 +16,7 @@ limitations under the License.
#include "tensorflow/compiler/xla/client/executable_build_options.h"
#include "absl/strings/str_format.h"
+#include "tensorflow/compiler/xla/debug_options_flags.h"
#include "tensorflow/compiler/xla/shape_util.h"
namespace xla {
@@ -39,6 +40,13 @@ ExecutableBuildOptions& ExecutableBuildOptions::set_device_ordinal(
int ExecutableBuildOptions::device_ordinal() const { return device_ordinal_; }
+DebugOptions* ExecutableBuildOptions::mutable_debug_options() {
+ if (!has_debug_options()) {
+ debug_options_ = GetDebugOptionsFromFlags();
+ }
+ return &debug_options_.value();
+}
+
ExecutableBuildOptions& ExecutableBuildOptions::set_result_layout(
const Shape& shape_with_layout) {
result_layout_set_ = true;
@@ -55,68 +63,10 @@ string ExecutableBuildOptions::ToString() const {
if (result_layout_set_) {
result_layout = ShapeUtil::HumanStringWithLayout(result_layout_);
}
- string generate_hlo_graph = "nullopt";
- if (generate_hlo_graph_.has_value()) {
- generate_hlo_graph = generate_hlo_graph_.value();
- }
return absl::StrFormat(
"ExecutableBuildOptions{device_ordinal=%d, result_layout=%s, "
"generate_hlo_graph=%s}",
- device_ordinal_, result_layout, generate_hlo_graph);
-}
-
-ExecutableBuildOptions& ExecutableBuildOptions::set_generate_hlo_graph(
- string regex) {
- generate_hlo_graph_ = std::move(regex);
- return *this;
-}
-
-const absl::optional& ExecutableBuildOptions::generate_hlo_graph()
- const {
- return generate_hlo_graph_;
-}
-
-ExecutableBuildOptions& ExecutableBuildOptions::set_dump_optimized_hlo_proto_to(
- absl::string_view dirpath) {
- dump_optimized_hlo_proto_to_ = string(dirpath);
- return *this;
-}
-
-const absl::optional&
-ExecutableBuildOptions::dump_optimized_hlo_proto_to() const {
- return dump_optimized_hlo_proto_to_;
-}
-
-ExecutableBuildOptions&
-ExecutableBuildOptions::set_dump_unoptimized_hlo_proto_to(
- absl::string_view dirpath) {
- dump_unoptimized_hlo_proto_to_ = string(dirpath);
- return *this;
-}
-
-const absl::optional&
-ExecutableBuildOptions::dump_unoptimized_hlo_proto_to() const {
- return dump_unoptimized_hlo_proto_to_;
-}
-
-ExecutableBuildOptions& ExecutableBuildOptions::set_dump_per_pass_hlo_proto_to(
- absl::string_view dirpath) {
- dump_per_pass_hlo_proto_to_ = string(dirpath);
- return *this;
-}
-
-const absl::optional&
-ExecutableBuildOptions::dump_per_pass_hlo_proto_to() const {
- return dump_per_pass_hlo_proto_to_;
-}
-
-ExecutableBuildOptions& ExecutableBuildOptions::set_hlo_profile(bool enabled) {
- hlo_profile_ = enabled;
- return *this;
-}
-
-absl::optional ExecutableBuildOptions::hlo_profile() const {
- return hlo_profile_;
+ device_ordinal_, result_layout, debug_options().xla_generate_hlo_graph());
}
} // namespace xla
diff --git a/tensorflow/compiler/xla/client/executable_build_options.h b/tensorflow/compiler/xla/client/executable_build_options.h
index 93334db88bc24f2ffbf3c7a57ee45ef238286739..a58090253bfac7779e4b61bc7231a0f0d945cc00 100644
--- a/tensorflow/compiler/xla/client/executable_build_options.h
+++ b/tensorflow/compiler/xla/client/executable_build_options.h
@@ -19,7 +19,9 @@ limitations under the License.
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tensorflow/compiler/xla/service/device_memory_allocator.h"
+#include "tensorflow/compiler/xla/shape.h"
#include "tensorflow/compiler/xla/util.h"
+#include "tensorflow/compiler/xla/xla.pb.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
namespace xla {
@@ -44,6 +46,12 @@ class ExecutableBuildOptions {
ExecutableBuildOptions& set_result_layout(const Shape& shape_with_layout);
const Shape* result_layout() const;
+ // Expose access to the XLA debug options which will be passed to the
+ // compilation process.
+ bool has_debug_options() const { return debug_options_.has_value(); }
+ const DebugOptions& debug_options() const { return *debug_options_; }
+ DebugOptions* mutable_debug_options();
+
// If set, this specifies an allocator that can be used to allocate temporary
// space on the device during compilation. For example, the compiler might
// want to run various algorithms on the device and pick the fastest one -- it
@@ -55,56 +63,16 @@ class ExecutableBuildOptions {
DeviceMemoryAllocator* allocator);
DeviceMemoryAllocator* device_allocator() const;
- // If set, specifies a regexp of HLO graphs to dump (as in DebugOptions).
- ExecutableBuildOptions& set_generate_hlo_graph(string regex);
- const absl::optional& generate_hlo_graph() const;
-
- // If set, specifies a dirpath to dump the end-of-optimization-pipeline HLO
- // protobuf to (as in DebugOptions).
- ExecutableBuildOptions& set_dump_optimized_hlo_proto_to(
- absl::string_view dirpath);
- const absl::optional& dump_optimized_hlo_proto_to() const;
-
- // If set, specifies a dirpath to dump the start-of-optimization-pipeline HLO
- // protobuf to (as in DebugOptions).
- ExecutableBuildOptions& set_dump_unoptimized_hlo_proto_to(
- absl::string_view dirpath);
- const absl::optional& dump_unoptimized_hlo_proto_to() const;
-
- // If set, specifies a dirpath to dump the per-pass-in-pipeline HLO protobufs
- // to (as in DebugOptions).
- ExecutableBuildOptions& set_dump_per_pass_hlo_proto_to(
- absl::string_view dirpath);
- const absl::optional& dump_per_pass_hlo_proto_to() const;
-
- // If true, specifies that we should record an HLO profile during execution
- // and log it after execution (as in DebugOptions). If nullopt the default is
- // used.
- ExecutableBuildOptions& set_hlo_profile(bool enabled);
- absl::optional hlo_profile() const;
-
- void add_disabled_hlo_pass(absl::string_view pass_name) {
- disabled_hlo_passes_.push_back(std::string(pass_name));
- }
- const absl::Span disabled_hlo_passes() const {
- return disabled_hlo_passes_;
- }
-
// Returns a string representation of the build options, suitable for
// debugging.
string ToString() const;
private:
- absl::optional hlo_profile_;
int device_ordinal_ = -1;
Shape result_layout_;
bool result_layout_set_ = false;
- absl::optional generate_hlo_graph_;
- absl::optional dump_optimized_hlo_proto_to_;
- absl::optional dump_unoptimized_hlo_proto_to_;
- absl::optional dump_per_pass_hlo_proto_to_;
+ absl::optional debug_options_;
DeviceMemoryAllocator* device_allocator_ = nullptr;
- std::vector disabled_hlo_passes_;
};
} // namespace xla
diff --git a/tensorflow/compiler/xla/client/lib/BUILD b/tensorflow/compiler/xla/client/lib/BUILD
index f833ddcd3235e08e2d0d3c0b9921e96ef871c89e..c5733bc66deb8d55a9186ad1893abaf17ed6909e 100644
--- a/tensorflow/compiler/xla/client/lib/BUILD
+++ b/tensorflow/compiler/xla/client/lib/BUILD
@@ -164,7 +164,6 @@ cc_library(
deps = [
":constants",
":math",
- ":numeric",
"//tensorflow/compiler/xla:util",
"//tensorflow/compiler/xla:xla_data_proto",
"//tensorflow/compiler/xla/client:xla_builder",
@@ -178,8 +177,9 @@ cc_library(
srcs = ["sorting.cc"],
hdrs = ["sorting.h"],
deps = [
- ":numeric",
+ "//tensorflow/compiler/xla:shape_util",
"//tensorflow/compiler/xla:types",
+ "//tensorflow/compiler/xla:util",
"//tensorflow/compiler/xla:xla_data_proto",
"//tensorflow/compiler/xla/client:xla_builder",
],
@@ -188,10 +188,6 @@ cc_library(
xla_test(
name = "sorting_test",
srcs = ["sorting_test.cc"],
- blacklisted_backends = [
- "cpu",
- "gpu",
- ],
tags = ["enable_for_xla_interpreter"],
deps = [
":sorting",
diff --git a/tensorflow/compiler/xla/client/lib/numeric.h b/tensorflow/compiler/xla/client/lib/numeric.h
index efd8cdc25724198633e0bf1c48c4e7d9e4b4c9e1..f62fdab4b0e5e84347cfaa1424a8c2e5c58dd3ce 100644
--- a/tensorflow/compiler/xla/client/lib/numeric.h
+++ b/tensorflow/compiler/xla/client/lib/numeric.h
@@ -22,9 +22,6 @@ limitations under the License.
namespace xla {
-// Returns a rank 1 tensor of `type` containing values [0, 1, 2, ...].
-XlaOp Iota(XlaBuilder* builder, PrimitiveType type, int64 size);
-
// Returns an m x n matrix with 1s on the diagonal elements, zeros everywhere
// else.
XlaOp IdentityMatrix(XlaBuilder* builder, PrimitiveType type, int64 m, int64 n);
diff --git a/tensorflow/compiler/xla/client/lib/prng.cc b/tensorflow/compiler/xla/client/lib/prng.cc
index c6f68c8ee2f5198017c37abeb9551478f52a99f4..85b9e1827dcef5ed907d893277deb5a52f8f30e9 100644
--- a/tensorflow/compiler/xla/client/lib/prng.cc
+++ b/tensorflow/compiler/xla/client/lib/prng.cc
@@ -18,7 +18,6 @@ limitations under the License.
#include "absl/base/casts.h"
#include "tensorflow/compiler/xla/client/lib/constants.h"
#include "tensorflow/compiler/xla/client/lib/math.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/util.h"
diff --git a/tensorflow/compiler/xla/client/lib/sorting.cc b/tensorflow/compiler/xla/client/lib/sorting.cc
index 0475fd9c94f6e390b5169cfe2cbba8eae28ddc18..e8553a08bb014e790822a14e128686b60b8d6b7c 100644
--- a/tensorflow/compiler/xla/client/lib/sorting.cc
+++ b/tensorflow/compiler/xla/client/lib/sorting.cc
@@ -14,7 +14,9 @@ limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/xla/client/lib/sorting.h"
-#include "tensorflow/compiler/xla/client/lib/numeric.h"
+#include "tensorflow/compiler/xla/client/xla_builder.h"
+#include "tensorflow/compiler/xla/shape_util.h"
+#include "tensorflow/compiler/xla/util.h"
namespace xla {
@@ -23,13 +25,12 @@ XlaOp TopK(XlaOp input, int64 k) {
return builder->ReportErrorOrReturn([&]() -> StatusOr {
TF_ASSIGN_OR_RETURN(Shape input_shape, builder->GetShape(input));
int last_dim = input_shape.dimensions_size() - 1;
- int last_dim_size = input_shape.dimensions(last_dim);
- XlaOp iota_s32 = Iota(builder, S32, last_dim_size);
+ Shape iota_shape =
+ ShapeUtil::MakeShape(S32, AsInt64Slice(input_shape.dimensions()));
+ XlaOp iota_s32 = Iota(builder, iota_shape, last_dim);
auto input_dims = input_shape.dimensions();
- std::vector broadcast_dims(input_dims.begin(), input_dims.end() - 1);
- XlaOp broadcast_s32 = Broadcast(iota_s32, broadcast_dims);
- XlaOp sort_result = Sort(Neg(input), {broadcast_s32});
+ XlaOp sort_result = Sort(Neg(input), {iota_s32});
std::vector start_indices(input_shape.dimensions_size(), 0);
std::vector limit_indices(input_dims.begin(), input_dims.end());
limit_indices[last_dim] = k;
diff --git a/tensorflow/compiler/xla/client/lib/sorting_test.cc b/tensorflow/compiler/xla/client/lib/sorting_test.cc
index fef98c9923096e21a755c6d730de2c7c10852b2d..27ff36c7491ab8397d46f3a49493ff2b904deb2d 100644
--- a/tensorflow/compiler/xla/client/lib/sorting_test.cc
+++ b/tensorflow/compiler/xla/client/lib/sorting_test.cc
@@ -14,6 +14,9 @@ limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/xla/client/lib/sorting.h"
+
+#include
+
#include "tensorflow/compiler/xla/client/xla_builder.h"
#include "tensorflow/compiler/xla/test.h"
#include "tensorflow/compiler/xla/tests/client_library_test_base.h"
@@ -41,6 +44,28 @@ XLA_TEST_F(SortingTest, TopK3From8Indices) {
ComputeAndCompareR1(&builder, {0, 1, 2}, {});
}
+// TODO(b/119930279): enable this test.
+XLA_TEST_F(SortingTest, DISABLED_TopKFullSortMinInt) {
+ XlaBuilder builder(TestName());
+ auto x_rev = ConstantR1(&builder, {std::numeric_limits::min(),
+ std::numeric_limits::min() + 1,
+ std::numeric_limits::max()});
+ xla::GetTupleElement(xla::TopK(x_rev, 3), 1);
+ ComputeAndCompareR1(&builder, {2, 1, 0}, {});
+}
+
+XLA_TEST_F(SortingTest, NOT_TopKFullSortMinInt) {
+ XlaBuilder builder(TestName());
+ auto x_rev = ConstantR1(&builder, {std::numeric_limits::min(),
+ std::numeric_limits::min() + 1,
+ std::numeric_limits::max()});
+ xla::GetTupleElement(xla::TopK(x_rev, 3), 1);
+ // TopK currently negates the keys, which doesn't work correctly for
+ // std::numeric_limits::min(). Therefore, it will sort this key to the
+ // front instead of to the back.
+ ComputeAndCompareR1(&builder, {0, 2, 1}, {});
+}
+
XLA_TEST_F(SortingTest, TopKFullSort) {
XlaBuilder builder(TestName());
const int kSize = 16;
@@ -56,5 +81,13 @@ XLA_TEST_F(SortingTest, TopKFullSort) {
ComputeAndCompareR1(&builder, inputs, {});
}
+XLA_TEST_F(SortingTest, TopKFullSortWithDuplicates) {
+ XlaBuilder builder(TestName());
+ XlaOp a;
+ auto a_data = CreateR1Parameter({1, 1, 2, 2, 1}, 0, "a", &builder, &a);
+ xla::GetTupleElement(xla::TopK(a, 5), 1);
+ ComputeAndCompareR1(&builder, {2, 3, 0, 1, 4}, {a_data.get()});
+}
+
} // namespace
} // namespace xla
diff --git a/tensorflow/compiler/xla/client/lib/testing.cc b/tensorflow/compiler/xla/client/lib/testing.cc
index a44681f586278bf03f3fb2b8c812936cbf3ad47b..a95bbf2c8c860914877d3195b97342097dafc725 100644
--- a/tensorflow/compiler/xla/client/lib/testing.cc
+++ b/tensorflow/compiler/xla/client/lib/testing.cc
@@ -66,7 +66,7 @@ std::unique_ptr MakeFakeDataViaDeviceOrDie(const Shape& shape,
XlaComputation computation = b.Build().ConsumeValueOrDie();
auto execution_options = CreateDefaultExecutionOptions();
- *execution_options.mutable_shape_with_output_layout() = shape;
+ *execution_options.mutable_shape_with_output_layout() = shape.ToProto();
return client->Execute(computation, /*arguments=*/{}, &execution_options)
.ConsumeValueOrDie();
}
@@ -98,8 +98,8 @@ std::vector> MakeFakeArgumentsOrDie(
auto program_shape = computation.proto().host_program_shape();
std::vector> results;
- for (const Shape& shape : program_shape.parameters()) {
- results.push_back(MakeFakeDataOrDie(shape, client));
+ for (const ShapeProto& shape : program_shape.parameters()) {
+ results.push_back(MakeFakeDataOrDie(Shape(shape), client));
}
return results;
}
diff --git a/tensorflow/compiler/xla/client/sharding_builder.cc b/tensorflow/compiler/xla/client/sharding_builder.cc
index 176802b33ef824a1f898255a19e44def3c1fc982..fb9ea6ec3fc41d5e04ca125798a8199350470a44 100644
--- a/tensorflow/compiler/xla/client/sharding_builder.cc
+++ b/tensorflow/compiler/xla/client/sharding_builder.cc
@@ -36,7 +36,7 @@ OpSharding Tile(const Shape& tile_shape,
const TileAssignment& tile_assignment) {
OpSharding result;
result.set_type(OpSharding::Type::OpSharding_Type_OTHER);
- *result.mutable_tile_shape() = tile_shape;
+ *result.mutable_tile_shape() = tile_shape.ToProto();
for (int64 dim : tile_assignment.dimensions()) {
result.add_tile_assignment_dimensions(dim);
}
@@ -52,7 +52,7 @@ OpSharding Tile1D(const Shape& tile_shape, int64 num_tiles) {
CHECK_EQ(ShapeUtil::Rank(tile_shape), 1);
std::vector dimensions(1, num_tiles);
- *result.mutable_tile_shape() = tile_shape;
+ *result.mutable_tile_shape() = tile_shape.ToProto();
auto& tile_dimension =
(*result.mutable_tile_shape()->mutable_dimensions())[0];
tile_dimension = CeilOfRatio(static_cast(tile_dimension), num_tiles);
diff --git a/tensorflow/compiler/xla/client/xla_builder.cc b/tensorflow/compiler/xla/client/xla_builder.cc
index f508ffb9c958ecfae7aea2c232e04001bd826a19..60df2ec3959216b0564846ad47c21c5bcc01ea57 100644
--- a/tensorflow/compiler/xla/client/xla_builder.cc
+++ b/tensorflow/compiler/xla/client/xla_builder.cc
@@ -102,7 +102,7 @@ StatusOr XlaBuilder::GetShape(const XlaOp& op) const {
TF_RETURN_IF_ERROR(first_error_);
TF_ASSIGN_OR_RETURN(auto instr, LookUpInstruction(op));
- return instr->shape();
+ return Shape(instr->shape());
}
StatusOr> XlaBuilder::GetOperandShapes(
@@ -155,7 +155,7 @@ StatusOr XlaBuilder::GetProgramShape(int64 root_id) const {
ProgramShape program_shape;
- *program_shape.mutable_result() = root_proto->shape();
+ *program_shape.mutable_result() = Shape(root_proto->shape());
// Check that the parameter numbers are continuous from 0, and add parameter
// shapes and names to the program shape.
@@ -172,7 +172,7 @@ StatusOr XlaBuilder::GetProgramShape(int64 root_id) const {
const int64 index = instr.parameter_number();
TF_RET_CHECK(index >= 0 && index < param_count)
<< "invalid parameter number: " << index;
- *program_shape.mutable_parameters(index) = instr.shape();
+ *program_shape.mutable_parameters(index) = Shape(instr.shape());
*program_shape.mutable_parameter_names(index) = instr.name();
}
}
@@ -288,7 +288,8 @@ StatusOr XlaBuilder::Build(int64 root_id) {
HloComputationProto entry;
SetProtoIdAndName(&entry, name_, kNameSeparator, GetNextId());
- TF_ASSIGN_OR_RETURN(*entry.mutable_program_shape(), GetProgramShape(root_id));
+ TF_ASSIGN_OR_RETURN(ProgramShape program_shape, GetProgramShape(root_id));
+ *entry.mutable_program_shape() = program_shape.ToProto();
entry.set_root_id(root_id);
for (auto& instruction : instructions_) {
@@ -328,7 +329,7 @@ StatusOr XlaBuilder::InDimBroadcast(
TF_RETURN_IF_ERROR(first_error_);
HloInstructionProto instr;
- *instr.mutable_shape() = shape;
+ *instr.mutable_shape() = shape.ToProto();
for (int64 dim : broadcast_dimensions) {
instr.add_dimensions(dim);
}
@@ -379,8 +380,9 @@ XlaOp XlaBuilder::UnaryOp(HloOpcode unop, const XlaOp& operand) {
return ReportErrorOrReturn([&]() -> StatusOr {
HloInstructionProto instr;
TF_ASSIGN_OR_RETURN(const Shape& operand_shape, GetShape(operand));
- TF_ASSIGN_OR_RETURN(*instr.mutable_shape(),
+ TF_ASSIGN_OR_RETURN(Shape shape,
ShapeInference::InferUnaryOpShape(unop, operand_shape));
+ *instr.mutable_shape() = shape.ToProto();
return AddInstruction(std::move(instr), unop, {operand});
});
}
@@ -391,9 +393,10 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs,
HloInstructionProto instr;
TF_ASSIGN_OR_RETURN(const Shape& lhs_shape, GetShape(lhs));
TF_ASSIGN_OR_RETURN(const Shape& rhs_shape, GetShape(rhs));
- TF_ASSIGN_OR_RETURN(*instr.mutable_shape(),
+ TF_ASSIGN_OR_RETURN(Shape shape,
ShapeInference::InferBinaryOpShape(
binop, lhs_shape, rhs_shape, broadcast_dimensions));
+ *instr.mutable_shape() = shape.ToProto();
const int64 lhs_rank = ShapeUtil::Rank(lhs_shape);
const int64 rhs_rank = ShapeUtil::Rank(rhs_shape);
@@ -407,7 +410,7 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs,
const Shape& from_shape = should_broadcast_lhs ? lhs_shape : rhs_shape;
std::vector to_size;
- for (int64 size : instr.shape().dimensions()) {
+ for (int64 size : shape.dimensions()) {
to_size.push_back(size);
}
for (int64 from_dim = 0; from_dim < ShapeUtil::Rank(from_shape);
@@ -427,14 +430,14 @@ XlaOp XlaBuilder::BinaryOp(HloOpcode binop, const XlaOp& lhs, const XlaOp& rhs,
}
TF_ASSIGN_OR_RETURN(Shape updated_lhs_shape, GetShape(updated_lhs));
- if (!ShapeUtil::SameDimensions(instr.shape(), updated_lhs_shape)) {
+ if (!ShapeUtil::SameDimensions(shape, updated_lhs_shape)) {
TF_ASSIGN_OR_RETURN(updated_lhs,
- AddBroadcastSequence(instr.shape(), updated_lhs));
+ AddBroadcastSequence(shape, updated_lhs));
}
TF_ASSIGN_OR_RETURN(Shape updated_rhs_shape, GetShape(updated_rhs));
- if (!ShapeUtil::SameDimensions(instr.shape(), updated_rhs_shape)) {
+ if (!ShapeUtil::SameDimensions(shape, updated_rhs_shape)) {
TF_ASSIGN_OR_RETURN(updated_rhs,
- AddBroadcastSequence(instr.shape(), updated_rhs));
+ AddBroadcastSequence(shape, updated_rhs));
}
return AddInstruction(std::move(instr), binop, {updated_lhs, updated_rhs});
@@ -448,30 +451,28 @@ XlaOp XlaBuilder::TernaryOp(HloOpcode triop, const XlaOp& lhs, const XlaOp& rhs,
TF_ASSIGN_OR_RETURN(const Shape& lhs_shape, GetShape(lhs));
TF_ASSIGN_OR_RETURN(const Shape& rhs_shape, GetShape(rhs));
TF_ASSIGN_OR_RETURN(const Shape& ehs_shape, GetShape(ehs));
- TF_ASSIGN_OR_RETURN(*instr.mutable_shape(),
- ShapeInference::InferTernaryOpShape(
- triop, lhs_shape, rhs_shape, ehs_shape));
+ TF_ASSIGN_OR_RETURN(
+ Shape shape, ShapeInference::InferTernaryOpShape(triop, lhs_shape,
+ rhs_shape, ehs_shape));
+ *instr.mutable_shape() = shape.ToProto();
XlaOp updated_lhs = lhs;
XlaOp updated_rhs = rhs;
XlaOp updated_ehs = ehs;
- if (!ShapeUtil::IsTuple(instr.shape())) {
+ if (!ShapeUtil::IsTuple(shape)) {
if (!ShapeUtil::IsTuple(lhs_shape) &&
- !ShapeUtil::SameDimensions(instr.shape(), lhs_shape)) {
+ !ShapeUtil::SameDimensions(shape, lhs_shape)) {
// lhs is being implicitly broadcasted. Change to explicit.
- TF_ASSIGN_OR_RETURN(updated_lhs,
- AddBroadcastSequence(instr.shape(), lhs));
+ TF_ASSIGN_OR_RETURN(updated_lhs, AddBroadcastSequence(shape, lhs));
}
if (!ShapeUtil::IsTuple(rhs_shape) &&
- !ShapeUtil::SameDimensions(instr.shape(), rhs_shape)) {
+ !ShapeUtil::SameDimensions(shape, rhs_shape)) {
// rhs is being implicitly broadcasted. Change to explicit.
- TF_ASSIGN_OR_RETURN(updated_rhs,
- AddBroadcastSequence(instr.shape(), rhs));
+ TF_ASSIGN_OR_RETURN(updated_rhs, AddBroadcastSequence(shape, rhs));
}
if (!ShapeUtil::IsTuple(ehs_shape) &&
- !ShapeUtil::SameDimensions(instr.shape(), ehs_shape)) {
+ !ShapeUtil::SameDimensions(shape, ehs_shape)) {
// ehs is being implicitly broadcasted. Change to explicit.
- TF_ASSIGN_OR_RETURN(updated_ehs,
- AddBroadcastSequence(instr.shape(), ehs));
+ TF_ASSIGN_OR_RETURN(updated_ehs, AddBroadcastSequence(shape, ehs));
}
}
return AddInstruction(std::move(instr), triop,
@@ -492,7 +493,7 @@ XlaOp XlaBuilder::Mul(const XlaOp& lhs, const XlaOp& rhs,
XlaOp XlaBuilder::ConstantLiteral(const LiteralSlice& literal) {
return ReportErrorOrReturn([&]() -> StatusOr {
HloInstructionProto instr;
- *instr.mutable_shape() = literal.shape();
+ *instr.mutable_shape() = literal.shape().ToProto();
*instr.mutable_literal() = literal.ToProto();
return AddInstruction(std::move(instr), HloOpcode::kConstant);
});
@@ -501,7 +502,7 @@ XlaOp XlaBuilder::ConstantLiteral(const LiteralSlice& literal) {
XlaOp XlaBuilder::Iota(const Shape& shape, int64 iota_dimension) {
return ReportErrorOrReturn([&]() -> StatusOr {
HloInstructionProto instr;
- *instr.mutable_shape() = shape;
+ *instr.mutable_shape() = shape.ToProto();
instr.add_dimensions(iota_dimension);
return AddInstruction(std::move(instr), HloOpcode::kIota);
});
@@ -521,10 +522,10 @@ XlaOp XlaBuilder::Call(const XlaComputation& computation,
[](const Shape& shape) { return &shape; });
TF_ASSIGN_OR_RETURN(const ProgramShape& called_program_shape,
computation.GetProgramShape());
- TF_ASSIGN_OR_RETURN(
- *instr.mutable_shape(),
- ShapeInference::InferCallShape(operand_shape_ptrs,
- /*to_apply=*/called_program_shape));
+ TF_ASSIGN_OR_RETURN(Shape shape, ShapeInference::InferCallShape(
+ operand_shape_ptrs,
+ /*to_apply=*/called_program_shape));
+ *instr.mutable_shape() = shape.ToProto();
AddCalledComputation(computation, &instr);
@@ -542,7 +543,7 @@ XlaOp XlaBuilder::Parameter(int64 parameter_number, const Shape& shape,
}
instr.set_parameter_number(parameter_number);
instr.set_name(name);
- *instr.mutable_shape() = shape;
+ *instr.mutable_shape() = shape.ToProto();
return AddInstruction(std::move(instr), HloOpcode::kParameter);
});
}
@@ -572,27 +573,35 @@ XlaOp XlaBuilder::Broadcast(const XlaOp& operand,
}
XlaOp XlaBuilder::BroadcastInDim(
- const XlaOp& operand, const Shape& shape,
+ const XlaOp& operand, const absl::Span out_dim_size,
const absl::Span