From de6200e7f58b616d6169cc35946e85323da66053 Mon Sep 17 00:00:00 2001 From: eqy Date: Sun, 15 Apr 2018 23:52:04 -0700 Subject: [PATCH 001/540] fix command line example package path --- tensorflow/contrib/lite/toco/g3doc/cmdline_examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/contrib/lite/toco/g3doc/cmdline_examples.md b/tensorflow/contrib/lite/toco/g3doc/cmdline_examples.md index 495014c6fc..f8327daa08 100644 --- a/tensorflow/contrib/lite/toco/g3doc/cmdline_examples.md +++ b/tensorflow/contrib/lite/toco/g3doc/cmdline_examples.md @@ -41,7 +41,7 @@ FlatBuffer to perform floating-point inference. ``` bazel run --config=opt \ - third_party/tensorflow/contrib/lite/toco:toco -- \ + //tensorflow/contrib/lite/toco:toco -- \ --savedmodel_directory=/tmp/saved_model \ --output_file=/tmp/foo.tflite ``` -- GitLab From cd2ba0c063ffd89f0310a6ab6482a5607e590cb1 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sun, 18 Mar 2018 18:50:34 -0700 Subject: [PATCH 002/540] Document additional argument --- tensorflow/python/ops/image_ops_impl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 8524c08f81..cee948fe43 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -984,6 +984,7 @@ def resize_image_aspect_with_pad(image, target_height, target_width, 3-D Tensor of shape `[height, width, channels]`. target_height: Target height. target_width: Target width. + method: Method to use for resizing image. See `resize_images()` Raises: ValueError: if `target_height` or `target_width` are zero or negative. -- GitLab From 96dc82647d0eb5d1903242c2dde1cf9dd5bb36f0 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sat, 28 Apr 2018 08:28:33 -0700 Subject: [PATCH 003/540] Rename API method --- tensorflow/python/ops/image_ops.py | 2 +- tensorflow/python/ops/image_ops_impl.py | 6 +++--- tensorflow/python/ops/image_ops_test.py | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/ops/image_ops.py b/tensorflow/python/ops/image_ops.py index f11b6dcea6..091ec61b1f 100644 --- a/tensorflow/python/ops/image_ops.py +++ b/tensorflow/python/ops/image_ops.py @@ -36,7 +36,7 @@ See the @{$python/image} guide. @@resize_bilinear @@resize_nearest_neighbor @@resize_image_with_crop_or_pad -@@resize_image_aspect_with_pad +@@resize_image_with_pad @@central_crop @@pad_to_bounding_box @@crop_to_bounding_box diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index cee948fe43..5fe0b7a251 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -969,8 +969,8 @@ def resize_images(images, return images -@tf_export('image.resize_image_aspect_with_pad') -def resize_image_aspect_with_pad(image, target_height, target_width, +@tf_export('image.resize_image_with_pad') +def resize_image_with_pad(image, target_height, target_width, method=ResizeMethod.BILINEAR): """ Resizes and pads an image to a target width and height. @@ -996,7 +996,7 @@ def resize_image_aspect_with_pad(image, target_height, target_width, If `images` was 3-D, a 3-D float Tensor of shape `[new_height, new_width, channels]`. """ - with ops.name_scope(None, 'resize_image_aspect_with_pad', [image]): + with ops.name_scope(None, 'resize_image_with_pad', [image]): image = ops.convert_to_tensor(image, name='image') image_shape = image.get_shape() is_batch = True diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 40a4d175ac..22d9ce4289 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -2458,9 +2458,9 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): self.assertTrue(y.op.name.startswith("resize_images")) -class ResizeImageAspectWithPadTest(test_util.TensorFlowTestCase): +class ResizeImageWithPadTest(test_util.TensorFlowTestCase): - def _ResizeImageAspectWithPad(self, x, target_height, target_width, + def _ResizeImageWithPad(self, x, target_height, target_width, use_tensor_inputs): if use_tensor_inputs: target_height = ops.convert_to_tensor(target_height) @@ -2471,7 +2471,7 @@ class ResizeImageAspectWithPadTest(test_util.TensorFlowTestCase): x_tensor = x feed_dict = {} - y = image_ops.resize_image_aspect_with_pad(x_tensor, target_height, + y = image_ops.resize_image_with_pad(x_tensor, target_height, target_width) if not use_tensor_inputs: self.assertTrue(y.get_shape().is_fully_defined()) @@ -2491,7 +2491,7 @@ class ResizeImageAspectWithPadTest(test_util.TensorFlowTestCase): y = np.array(y).reshape(y_shape) for use_tensor_inputs in use_tensor_inputs_options: - y_tf = self._ResizeImageAspectWithPad(x, target_height, target_width, + y_tf = self._ResizeImageWithPad(x, target_height, target_width, use_tensor_inputs) self.assertAllClose(y, y_tf) @@ -2507,7 +2507,7 @@ class ResizeImageAspectWithPadTest(test_util.TensorFlowTestCase): for use_tensor_inputs in use_tensor_inputs_options: try: - self._ResizeImageAspectWithPad(x, target_height, target_width, + self._ResizeImageWithPad(x, target_height, target_width, use_tensor_inputs) except Exception as e: if err_msg not in str(e): @@ -2517,7 +2517,7 @@ class ResizeImageAspectWithPadTest(test_util.TensorFlowTestCase): def _assertShapeInference(self, pre_shape, height, width, post_shape): image = array_ops.placeholder(dtypes.float32, shape=pre_shape) - y = image_ops.resize_image_aspect_with_pad(image, height, width) + y = image_ops.resize_image_with_pad(image, height, width) self.assertEqual(y.get_shape().as_list(), post_shape) def testNoOp(self): -- GitLab From 533cb5caa4c88d3f76e1994e8f039ea04d342482 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sat, 28 Apr 2018 08:30:56 -0700 Subject: [PATCH 004/540] Remove assertions --- tensorflow/python/ops/image_ops_impl.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 5fe0b7a251..e174feedb5 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1066,16 +1066,6 @@ def resize_image_with_pad(image, target_height, target_width, _, resized_height, resized_width, _ = _ImageDimensions(resized, rank=4) - assert_ops = [] - assert_ops += _assert( - equal_(resized_height, target_height), ValueError, - 'resized height is not correct.') - assert_ops += _assert( - equal_(resized_width, target_width), ValueError, - 'resized width is not correct.') - - resized = control_flow_ops.with_dependencies(assert_ops, resized) - if not is_batch: resized = array_ops.squeeze(resized, squeeze_dims=[0]) -- GitLab From 764ea231d9b649ad167fd1ffd4f4c5c4e79642c7 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sat, 28 Apr 2018 08:32:36 -0700 Subject: [PATCH 005/540] Update docstring --- tensorflow/python/ops/image_ops_impl.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index e174feedb5..d5ac72bac6 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -976,8 +976,9 @@ def resize_image_with_pad(image, target_height, target_width, Resizes and pads an image to a target width and height. Resizes an image to a target width and height by keeping - the aspect ratio the same without distortion and padding - it evenly with zeros. + the aspect ratio the same without distortion. If the target + dimensions don't match the image dimensions, the image + is padded with zeroes prior to resizing. Args: image: 4-D Tensor of shape `[batch, height, width, channels]` or -- GitLab From 74171d402a52074806bc5f0d1a3ddae92212214f Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Tue, 8 May 2018 14:24:32 -0700 Subject: [PATCH 006/540] Fix bad merge --- tensorflow/python/ops/image_ops.py | 61 ------------------------------ 1 file changed, 61 deletions(-) diff --git a/tensorflow/python/ops/image_ops.py b/tensorflow/python/ops/image_ops.py index 091ec61b1f..343531ac55 100644 --- a/tensorflow/python/ops/image_ops.py +++ b/tensorflow/python/ops/image_ops.py @@ -17,67 +17,6 @@ """Image processing and decoding ops. See the @{$python/image} guide. -<<<<<<< HEAD -======= - -@@decode_bmp -@@decode_gif -@@decode_jpeg -@@decode_and_crop_jpeg -@@encode_jpeg -@@extract_jpeg_shape -@@decode_png -@@encode_png -@@is_jpeg -@@decode_image -@@resize_images -@@resize_area -@@resize_bicubic -@@resize_bilinear -@@resize_nearest_neighbor -@@resize_image_with_crop_or_pad -@@resize_image_with_pad -@@central_crop -@@pad_to_bounding_box -@@crop_to_bounding_box -@@extract_glimpse -@@crop_and_resize -@@flip_up_down -@@random_flip_up_down -@@flip_left_right -@@random_flip_left_right -@@transpose_image -@@rot90 - -@@rgb_to_grayscale -@@grayscale_to_rgb -@@hsv_to_rgb -@@rgb_to_hsv -@@rgb_to_yiq -@@yiq_to_rgb -@@rgb_to_yuv -@@yuv_to_rgb -@@convert_image_dtype -@@adjust_brightness -@@random_brightness -@@adjust_contrast -@@random_contrast -@@adjust_hue -@@random_hue -@@adjust_gamma -@@adjust_saturation -@@random_saturation -@@per_image_standardization -@@draw_bounding_boxes -@@non_max_suppression -@@sample_distorted_bounding_box -@@total_variation -@@psnr -@@ssim -@@ssim_multiscale -@@image_gradients -@@sobel_edges ->>>>>>> 88687fa... Add resize_image_aspect_with_pad method """ from __future__ import absolute_import from __future__ import division -- GitLab From 5e6b20e53720e8d00619d851ce983f8da77c5cf4 Mon Sep 17 00:00:00 2001 From: Soila Kavulya Date: Tue, 8 May 2018 14:54:53 -0700 Subject: [PATCH 007/540] Deploy TensorFlow ecosystem jars --- tensorflow/java/maven/pom.xml | 10 +- tensorflow/java/maven/release.sh | 1 + tensorflow/java/maven/run_inside_container.sh | 42 ++++- .../pom-spark.xml.template | 19 +++ .../spark-tensorflow-connector/update.py | 152 ++++++++++++++++++ .../tensorflow-hadoop/pom-hadoop.xml.template | 18 +++ .../java/maven/tensorflow-hadoop/update.py | 114 +++++++++++++ 7 files changed, 352 insertions(+), 4 deletions(-) create mode 100644 tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template create mode 100644 tensorflow/java/maven/spark-tensorflow-connector/update.py create mode 100644 tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template create mode 100644 tensorflow/java/maven/tensorflow-hadoop/update.py diff --git a/tensorflow/java/maven/pom.xml b/tensorflow/java/maven/pom.xml index 0a09a5ea7c..21fed5a419 100644 --- a/tensorflow/java/maven/pom.xml +++ b/tensorflow/java/maven/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.tensorflow parentpom - 1.8.0 + 1.8.0-SNAPSHOT pom https://www.tensorflow.org @@ -32,6 +32,8 @@ libtensorflow_jni_gpu tensorflow proto + tensorflow-hadoop + spark-tensorflow-connector ossrh - https://oss.sonatype.org/content/repositories/snapshots + https://tap.jfrog.io/tap/public-snapshots + ossrh @@ -74,6 +77,7 @@ + diff --git a/tensorflow/java/maven/release.sh b/tensorflow/java/maven/release.sh index 9012ea14ea..6c51029198 100755 --- a/tensorflow/java/maven/release.sh +++ b/tensorflow/java/maven/release.sh @@ -48,6 +48,7 @@ fi set -ex docker run \ + $DOCKER_PROXY_RUN_ARGS \ -e TF_VERSION="${TF_VERSION}" \ -e DEPLOY_OSSRH="${DEPLOY_OSSRH:-true}" \ -e DEPLOY_BINTRAY="${DEPLOY_BINTRAY:-true}" \ diff --git a/tensorflow/java/maven/run_inside_container.sh b/tensorflow/java/maven/run_inside_container.sh index 6136ccfdfb..73f7ee94a0 100644 --- a/tensorflow/java/maven/run_inside_container.sh +++ b/tensorflow/java/maven/run_inside_container.sh @@ -32,11 +32,15 @@ if [[ "${TF_VERSION}" == *"-SNAPSHOT" ]]; then DEPLOY_BINTRAY="false" fi PROTOC_RELEASE_URL="https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip" +TF_ECOSYSTEM_URL="https://github.com/tensorflow/ecosystem.git" + if [[ "${DEPLOY_BINTRAY}" != "true" && "${DEPLOY_OSSRH}" != "true" ]]; then echo "Must deploy to at least one of Bintray or OSSRH" >&2 exit 2 fi +IS_SNAPSHOT="true" + set -ex clean() { @@ -183,6 +187,41 @@ generate_java_protos() { rm -rf "${DIR}/proto/tmp" } + +download_tf_ecosystem() { + ECOSYSTEM_DIR="/tmp/tensorflow-ecosystem" + HADOOP_DIR="${DIR}/tensorflow-hadoop" + SPARK_DIR="${DIR}/spark-tensorflow-connector" + + # Clean any previous attempts + rm -rf "${ECOSYSTEM_DIR}" + + # Clone the TensorFlow ecosystem project + mkdir -p "${ECOSYSTEM_DIR}" + cd "${ECOSYSTEM_DIR}" + git clone "${TF_ECOSYSTEM_URL}" + + # Copy the TensorFlow Hadoop source + cp -r "${ECOSYSTEM_DIR}/ecosystem/hadoop/src" "${HADOOP_DIR}" + python ${HADOOP_DIR}/update.py --template ${HADOOP_DIR}/pom-hadoop.xml.template \ + --input_pom ${ECOSYSTEM_DIR}/ecosystem/hadoop/pom.xml \ + --output_pom ${HADOOP_DIR}/pom.xml \ + --version ${TF_VERSION} + + # Copy the TensorFlow Spark connector source + cp -r "${ECOSYSTEM_DIR}/ecosystem/spark/spark-tensorflow-connector/src" "${SPARK_DIR}" + python ${SPARK_DIR}/update.py --template ${SPARK_DIR}/pom-spark.xml.template \ + --input_pom ${ECOSYSTEM_DIR}/ecosystem/spark/spark-tensorflow-connector/pom.xml \ + --output_pom ${SPARK_DIR}/pom.xml \ + --version ${TF_VERSION} \ + --scala_version 2.11 + + # Cleanup + rm -rf "${ECOSYSTEM_DIR}" + + cd "${DIR}" +} + # Deploy artifacts using a specific profile. # Arguments: # profile - name of selected profile. @@ -240,7 +279,7 @@ cd "${DIR}" # Comment lines out appropriately if debugging/tinkering with the release # process. # gnupg2 is required for signing -apt-get -qq update && apt-get -qqq install -y gnupg2 +apt-get -qq update && apt-get -qqq install -y gnupg2 && apt-get -qqq install -y git clean update_version_in_pom download_libtensorflow @@ -248,6 +287,7 @@ download_libtensorflow_jni download_libtensorflow_jni_gpu update_tensorflow_android generate_java_protos +download_tf_ecosystem # Build the release artifacts mvn verify # Push artifacts to repository diff --git a/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template b/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template new file mode 100644 index 0000000000..d8a3d559be --- /dev/null +++ b/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template @@ -0,0 +1,19 @@ + + 4.0.0 + TensorFlow TFRecord connector for Apache Spark DataFrames + spark-tensorflow-connector_${scala_version} + ${version} + jar + + https://github.com/tensorflow/ecosystem/ + + org.tensorflow + parentpom + ${version} + ../ + + + diff --git a/tensorflow/java/maven/spark-tensorflow-connector/update.py b/tensorflow/java/maven/spark-tensorflow-connector/update.py new file mode 100644 index 0000000000..6185ccbb00 --- /dev/null +++ b/tensorflow/java/maven/spark-tensorflow-connector/update.py @@ -0,0 +1,152 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Merge TensorFlow Spark connector pom from with deployment template. + +The TensorFlow Spark connector pom is here: https://github.com/tensorflow/ecosystem/tree/master/spark/spark-tensorflow-connector +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse +import sys +import string +import xml.etree.ElementTree as ET + +POM_NAMESPACE = "http://maven.apache.org/POM/4.0.0" +SCALA_VERSION_TAG = "scala.binary.version" + + +def get_args(): + """Parse command line args.""" + parser = argparse.ArgumentParser() + parser.add_argument( + '--version', + required=True, + help='Version for the artifact.') + parser.add_argument( + '--scala_version', + required=True, + choices=['2.10', '2.11'], + help='Scala version for the artifact.') + parser.add_argument( + '--template', + required=True, + help='Path to the pom file template.') + parser.add_argument( + '--input_pom', + required=True, + help='Path to input pom file to merge with template.') + parser.add_argument( + '--output_pom', + required=True, + help='Path to output pom file.') + return parser.parse_args() + + +def load_pom(input_path): + """ Loads POM file to XML tree""" + ET.register_namespace("", POM_NAMESPACE) + tree = ET.parse(input_path) + return tree + + +def update_scala_version(tree, version, is_template=False): + """ Updates scala version in XML tree""" + + if is_template: + tag = "{%s}artifactId" % POM_NAMESPACE + nodes = tree.findall(tag) + + if nodes is None: + raise ValueError("Missing artifactId in template pom") + + for node in nodes: + template = string.Template(node.text) + + text = template.substitute({"scala_version": version}) + node.text = text + else: + # Update scala version property in pom + tag = "{%s}%s" % (POM_NAMESPACE, SCALA_VERSION_TAG) + nodes = nodes = list(tree.iter(tag)) + + if len(nodes) == 0: + raise ValueError("Missing %s property in Spark connector pom") + + for node in nodes: + node.text = version + + return tree + + +def update_version(tree, version): + """ Updates version tags in XML tree """ + version_tag = "{%s}version" % POM_NAMESPACE + nodes = list(tree.iter(version_tag)) + + if len(nodes) == 0: + raise ValueError("Missing version in template pom") + + for node in nodes: + node.text = version + + return tree + + +def merge_tags(template_root, pom_root): + """ Merge pom file from TensorFlow Spark connector with deployment template. + + Modify the TensorFlow Spark connector pom to inherit parent pom and version info and + other tags provided by deployment template. + + TODO: Figure out if there is a cleaner way of doing this. Inheritance is needed + for propagating the deployment profile. + + Args: + template_root: Root XML element for template file. + pom_root: Root XML element for TensorFlow Spark connector pom file. + + Return: + template_root: Root XML element with merged tree. + """ + template_tags = [child.tag for child in template_root] + template_tags.append("{%s}groupId" % POM_NAMESPACE) # skip groupId since it is inherited from parent + + for child in pom_root: + if child.tag not in template_tags: + template_root.append(child) + + return template_root + + +def main(): + args = get_args() + template_tree = load_pom(args.template) + pom_tree = load_pom(args.input_pom) + + template_tree = update_version(template_tree, args.version) + template_tree = update_scala_version(template_tree, args.scala_version, is_template=True) + pom_tree = update_scala_version(pom_tree, args.scala_version, is_template=False) + template_root = merge_tags(template_tree.getroot(), pom_tree.getroot()) + + with open(args.output_pom, "w") as f: + f.write(ET.tostring(template_root)) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template b/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template new file mode 100644 index 0000000000..6a82c56cc7 --- /dev/null +++ b/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template @@ -0,0 +1,18 @@ + + 4.0.0 + TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop + tensorflow-hadoop + ${version} + jar + + https://github.com/tensorflow/ecosystem/ + + org.tensorflow + parentpom + ${version} + ../ + + diff --git a/tensorflow/java/maven/tensorflow-hadoop/update.py b/tensorflow/java/maven/tensorflow-hadoop/update.py new file mode 100644 index 0000000000..503062608d --- /dev/null +++ b/tensorflow/java/maven/tensorflow-hadoop/update.py @@ -0,0 +1,114 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Merge TensorFlow Hadoop pom from with deployment template. + +The TensorFlow Hadoop pom is here: https://github.com/tensorflow/ecosystem/tree/master/hadoop +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse +import sys +import xml.etree.ElementTree as ET + +POM_NAMESPACE = "http://maven.apache.org/POM/4.0.0" + + +def get_args(): + """Parse command line args.""" + parser = argparse.ArgumentParser() + parser.add_argument( + '--version', + required=True, + help='Version for the artifact.') + parser.add_argument( + '--template', + required=True, + help='Path to the pom file template.') + parser.add_argument( + '--input_pom', + required=True, + help='Path to input pom file to merge with template.') + parser.add_argument( + '--output_pom', + required=True, + help='Path to output pom file.') + return parser.parse_args() + + +def load_pom(input_path): + """ Loads POM file to XML tree""" + ET.register_namespace("", POM_NAMESPACE) + tree = ET.parse(input_path) + return tree + + +def update_version(tree, version): + """ Updates version tags in XML tree """ + version_tag = "{%s}version" % POM_NAMESPACE + nodes = list(tree.iter(version_tag)) + + if len(nodes) == 0: + raise ValueError("Missing version in template pom") + + for node in nodes: + node.text = version + + return tree + + +def merge_tags(template_root, pom_root): + """ Merge pom file from TensorFlow Hadoop with deployment template. + + Modify the TensorFlow Hadoop pom to inherit parent pom and version info and + other tags provided by deployment template. + + TODO: Figure out if there is a cleaner way of doing this. Inheritance is needed + for propagating the deployment profile. + + Args: + template_root: Root XML element for template file. + pom_root: Root XML element for TensorFlow Hadoop pom file. + + Return: + template_root: Root XML element with merged tree. + """ + template_tags = [child.tag for child in template_root] + template_tags.append("{%s}groupId" % POM_NAMESPACE) # skip groupId since it is inherited from parent + + for child in pom_root: + if child.tag not in template_tags: + template_root.append(child) + + return template_root + + +def main(): + args = get_args() + template_tree = load_pom(args.template) + pom_tree = load_pom(args.input_pom) + + template_tree = update_version(template_tree, args.version) + template_root = merge_tags(template_tree.getroot(), pom_tree.getroot()) + + with open(args.output_pom, "w") as f: + f.write(ET.tostring(template_root)) + + +if __name__ == '__main__': + sys.exit(main()) -- GitLab From f957cfbc4d27a57bf08d128b41042a16f1155ab0 Mon Sep 17 00:00:00 2001 From: Soila Kavulya Date: Tue, 8 May 2018 18:40:20 -0700 Subject: [PATCH 008/540] Add TensorFlow ecosystem Spark and Hadoop jars to Maven deployment --- tensorflow/java/maven/README.md | 6 +++++ tensorflow/java/maven/pom.xml | 8 +++--- tensorflow/java/maven/release.sh | 1 - tensorflow/java/maven/run_inside_container.sh | 26 ++++++++++--------- .../maven/spark-tensorflow-connector/pom.xml | 24 +++++++++++++++++ .../java/maven/tensorflow-hadoop/pom.xml | 24 +++++++++++++++++ 6 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 tensorflow/java/maven/spark-tensorflow-connector/pom.xml create mode 100644 tensorflow/java/maven/tensorflow-hadoop/pom.xml diff --git a/tensorflow/java/maven/README.md b/tensorflow/java/maven/README.md index c7e8f03806..fa756815a9 100644 --- a/tensorflow/java/maven/README.md +++ b/tensorflow/java/maven/README.md @@ -53,6 +53,12 @@ There are seven artifacts and thus `pom.xml`s involved in this release: 7. [`parentpom`](https://maven.apache.org/pom/index.html): Common settings shared by all of the above. +8. `tensorflow-hadoop`: The TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop. + The source code for this package is available in the [TensorFlow Ecosystem](https://github.com/tensorflow/ecosystem/tree/master/hadoop) + +9. `spark-tensorflow-connector`: A Scala library for loading and storing TensorFlow TFRecord + using Apache Spark DataFrames. The source code for this package is available + in the [TensorFlow Ecosystem](https://github.com/tensorflow/ecosystem/tree/master/spark/spark-tensorflow-connector) ## Updating the release diff --git a/tensorflow/java/maven/pom.xml b/tensorflow/java/maven/pom.xml index 21fed5a419..7a95fb2556 100644 --- a/tensorflow/java/maven/pom.xml +++ b/tensorflow/java/maven/pom.xml @@ -6,7 +6,7 @@ 4.0.0 org.tensorflow parentpom - 1.8.0-SNAPSHOT + 1.8.0 pom https://www.tensorflow.org @@ -46,8 +46,7 @@ ossrh - https://tap.jfrog.io/tap/public-snapshots - + https://oss.sonatype.org/content/repositories/snapshots ossrh @@ -77,7 +76,6 @@ - + diff --git a/tensorflow/java/maven/release.sh b/tensorflow/java/maven/release.sh index 6c51029198..9012ea14ea 100755 --- a/tensorflow/java/maven/release.sh +++ b/tensorflow/java/maven/release.sh @@ -48,7 +48,6 @@ fi set -ex docker run \ - $DOCKER_PROXY_RUN_ARGS \ -e TF_VERSION="${TF_VERSION}" \ -e DEPLOY_OSSRH="${DEPLOY_OSSRH:-true}" \ -e DEPLOY_BINTRAY="${DEPLOY_BINTRAY:-true}" \ diff --git a/tensorflow/java/maven/run_inside_container.sh b/tensorflow/java/maven/run_inside_container.sh index 73f7ee94a0..3808104bc1 100644 --- a/tensorflow/java/maven/run_inside_container.sh +++ b/tensorflow/java/maven/run_inside_container.sh @@ -39,8 +39,6 @@ if [[ "${DEPLOY_BINTRAY}" != "true" && "${DEPLOY_OSSRH}" != "true" ]]; then exit 2 fi -IS_SNAPSHOT="true" - set -ex clean() { @@ -48,7 +46,9 @@ clean() { # (though if run inside a clean docker container, there won't be any dirty # artifacts lying around) mvn -q clean - rm -rf libtensorflow_jni/src libtensorflow_jni/target libtensorflow_jni_gpu/src libtensorflow_jni_gpu/target libtensorflow/src libtensorflow/target tensorflow-android/target + rm -rf libtensorflow_jni/src libtensorflow_jni/target libtensorflow_jni_gpu/src libtensorflow_jni_gpu/target \ + libtensorflow/src libtensorflow/target tensorflow-android/target \ + tensorflow-hadoop/src spark-tensorflow-connector/src } update_version_in_pom() { @@ -188,6 +188,9 @@ generate_java_protos() { } +# Download the TensorFlow ecosystem source from git. +# The pom files from this repo do not inherit from the parent pom so the maven version +# is updated for each module. download_tf_ecosystem() { ECOSYSTEM_DIR="/tmp/tensorflow-ecosystem" HADOOP_DIR="${DIR}/tensorflow-hadoop" @@ -203,18 +206,15 @@ download_tf_ecosystem() { # Copy the TensorFlow Hadoop source cp -r "${ECOSYSTEM_DIR}/ecosystem/hadoop/src" "${HADOOP_DIR}" - python ${HADOOP_DIR}/update.py --template ${HADOOP_DIR}/pom-hadoop.xml.template \ - --input_pom ${ECOSYSTEM_DIR}/ecosystem/hadoop/pom.xml \ - --output_pom ${HADOOP_DIR}/pom.xml \ - --version ${TF_VERSION} + cp "${ECOSYSTEM_DIR}/ecosystem/hadoop/pom.xml" "${HADOOP_DIR}" + cd "${HADOOP_DIR}" + update_version_in_pom # Copy the TensorFlow Spark connector source cp -r "${ECOSYSTEM_DIR}/ecosystem/spark/spark-tensorflow-connector/src" "${SPARK_DIR}" - python ${SPARK_DIR}/update.py --template ${SPARK_DIR}/pom-spark.xml.template \ - --input_pom ${ECOSYSTEM_DIR}/ecosystem/spark/spark-tensorflow-connector/pom.xml \ - --output_pom ${SPARK_DIR}/pom.xml \ - --version ${TF_VERSION} \ - --scala_version 2.11 + cp "${ECOSYSTEM_DIR}/ecosystem/spark/spark-tensorflow-connector/pom.xml" "${SPARK_DIR}" + cd "${SPARK_DIR}" + update_version_in_pom # Cleanup rm -rf "${ECOSYSTEM_DIR}" @@ -280,6 +280,7 @@ cd "${DIR}" # process. # gnupg2 is required for signing apt-get -qq update && apt-get -qqq install -y gnupg2 && apt-get -qqq install -y git + clean update_version_in_pom download_libtensorflow @@ -288,6 +289,7 @@ download_libtensorflow_jni_gpu update_tensorflow_android generate_java_protos download_tf_ecosystem + # Build the release artifacts mvn verify # Push artifacts to repository diff --git a/tensorflow/java/maven/spark-tensorflow-connector/pom.xml b/tensorflow/java/maven/spark-tensorflow-connector/pom.xml new file mode 100644 index 0000000000..8c962d111f --- /dev/null +++ b/tensorflow/java/maven/spark-tensorflow-connector/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + TensorFlow TFRecord connector for Apache Spark DataFrames + spark-tensorflow-connector + jar + + + https://github.com/tensorflow/ecosystem.git + git@github.com:tensorflow/ecosystem.git + scm:git:https://github.com/tensorflow/ecosystem.git + + + https://github.com/tensorflow/ecosystem/ + + org.tensorflow + parentpom + 1.8.0 + ../ + + diff --git a/tensorflow/java/maven/tensorflow-hadoop/pom.xml b/tensorflow/java/maven/tensorflow-hadoop/pom.xml new file mode 100644 index 0000000000..ee90d8c92b --- /dev/null +++ b/tensorflow/java/maven/tensorflow-hadoop/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop + tensorflow-hadoop + jar + + + https://github.com/tensorflow/ecosystem.git + git@github.com:tensorflow/ecosystem.git + scm:git:https://github.com/tensorflow/ecosystem.git + + + https://github.com/tensorflow/ecosystem/ + + org.tensorflow + parentpom + 1.8.0 + ../ + + -- GitLab From 90b01f238d83d833ce9a843845dd96bb816a6c76 Mon Sep 17 00:00:00 2001 From: Soila Kavulya Date: Tue, 8 May 2018 18:46:35 -0700 Subject: [PATCH 009/540] Delete templating approach for deploying TensorFlow ecosystem jars --- .../pom-spark.xml.template | 19 --- .../spark-tensorflow-connector/update.py | 152 ------------------ .../tensorflow-hadoop/pom-hadoop.xml.template | 18 --- .../java/maven/tensorflow-hadoop/update.py | 114 ------------- 4 files changed, 303 deletions(-) delete mode 100644 tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template delete mode 100644 tensorflow/java/maven/spark-tensorflow-connector/update.py delete mode 100644 tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template delete mode 100644 tensorflow/java/maven/tensorflow-hadoop/update.py diff --git a/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template b/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template deleted file mode 100644 index d8a3d559be..0000000000 --- a/tensorflow/java/maven/spark-tensorflow-connector/pom-spark.xml.template +++ /dev/null @@ -1,19 +0,0 @@ - - 4.0.0 - TensorFlow TFRecord connector for Apache Spark DataFrames - spark-tensorflow-connector_${scala_version} - ${version} - jar - - https://github.com/tensorflow/ecosystem/ - - org.tensorflow - parentpom - ${version} - ../ - - - diff --git a/tensorflow/java/maven/spark-tensorflow-connector/update.py b/tensorflow/java/maven/spark-tensorflow-connector/update.py deleted file mode 100644 index 6185ccbb00..0000000000 --- a/tensorflow/java/maven/spark-tensorflow-connector/update.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Merge TensorFlow Spark connector pom from with deployment template. - -The TensorFlow Spark connector pom is here: https://github.com/tensorflow/ecosystem/tree/master/spark/spark-tensorflow-connector -""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import argparse -import sys -import string -import xml.etree.ElementTree as ET - -POM_NAMESPACE = "http://maven.apache.org/POM/4.0.0" -SCALA_VERSION_TAG = "scala.binary.version" - - -def get_args(): - """Parse command line args.""" - parser = argparse.ArgumentParser() - parser.add_argument( - '--version', - required=True, - help='Version for the artifact.') - parser.add_argument( - '--scala_version', - required=True, - choices=['2.10', '2.11'], - help='Scala version for the artifact.') - parser.add_argument( - '--template', - required=True, - help='Path to the pom file template.') - parser.add_argument( - '--input_pom', - required=True, - help='Path to input pom file to merge with template.') - parser.add_argument( - '--output_pom', - required=True, - help='Path to output pom file.') - return parser.parse_args() - - -def load_pom(input_path): - """ Loads POM file to XML tree""" - ET.register_namespace("", POM_NAMESPACE) - tree = ET.parse(input_path) - return tree - - -def update_scala_version(tree, version, is_template=False): - """ Updates scala version in XML tree""" - - if is_template: - tag = "{%s}artifactId" % POM_NAMESPACE - nodes = tree.findall(tag) - - if nodes is None: - raise ValueError("Missing artifactId in template pom") - - for node in nodes: - template = string.Template(node.text) - - text = template.substitute({"scala_version": version}) - node.text = text - else: - # Update scala version property in pom - tag = "{%s}%s" % (POM_NAMESPACE, SCALA_VERSION_TAG) - nodes = nodes = list(tree.iter(tag)) - - if len(nodes) == 0: - raise ValueError("Missing %s property in Spark connector pom") - - for node in nodes: - node.text = version - - return tree - - -def update_version(tree, version): - """ Updates version tags in XML tree """ - version_tag = "{%s}version" % POM_NAMESPACE - nodes = list(tree.iter(version_tag)) - - if len(nodes) == 0: - raise ValueError("Missing version in template pom") - - for node in nodes: - node.text = version - - return tree - - -def merge_tags(template_root, pom_root): - """ Merge pom file from TensorFlow Spark connector with deployment template. - - Modify the TensorFlow Spark connector pom to inherit parent pom and version info and - other tags provided by deployment template. - - TODO: Figure out if there is a cleaner way of doing this. Inheritance is needed - for propagating the deployment profile. - - Args: - template_root: Root XML element for template file. - pom_root: Root XML element for TensorFlow Spark connector pom file. - - Return: - template_root: Root XML element with merged tree. - """ - template_tags = [child.tag for child in template_root] - template_tags.append("{%s}groupId" % POM_NAMESPACE) # skip groupId since it is inherited from parent - - for child in pom_root: - if child.tag not in template_tags: - template_root.append(child) - - return template_root - - -def main(): - args = get_args() - template_tree = load_pom(args.template) - pom_tree = load_pom(args.input_pom) - - template_tree = update_version(template_tree, args.version) - template_tree = update_scala_version(template_tree, args.scala_version, is_template=True) - pom_tree = update_scala_version(pom_tree, args.scala_version, is_template=False) - template_root = merge_tags(template_tree.getroot(), pom_tree.getroot()) - - with open(args.output_pom, "w") as f: - f.write(ET.tostring(template_root)) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template b/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template deleted file mode 100644 index 6a82c56cc7..0000000000 --- a/tensorflow/java/maven/tensorflow-hadoop/pom-hadoop.xml.template +++ /dev/null @@ -1,18 +0,0 @@ - - 4.0.0 - TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop - tensorflow-hadoop - ${version} - jar - - https://github.com/tensorflow/ecosystem/ - - org.tensorflow - parentpom - ${version} - ../ - - diff --git a/tensorflow/java/maven/tensorflow-hadoop/update.py b/tensorflow/java/maven/tensorflow-hadoop/update.py deleted file mode 100644 index 503062608d..0000000000 --- a/tensorflow/java/maven/tensorflow-hadoop/update.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2017 The TensorFlow Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Merge TensorFlow Hadoop pom from with deployment template. - -The TensorFlow Hadoop pom is here: https://github.com/tensorflow/ecosystem/tree/master/hadoop -""" - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import argparse -import sys -import xml.etree.ElementTree as ET - -POM_NAMESPACE = "http://maven.apache.org/POM/4.0.0" - - -def get_args(): - """Parse command line args.""" - parser = argparse.ArgumentParser() - parser.add_argument( - '--version', - required=True, - help='Version for the artifact.') - parser.add_argument( - '--template', - required=True, - help='Path to the pom file template.') - parser.add_argument( - '--input_pom', - required=True, - help='Path to input pom file to merge with template.') - parser.add_argument( - '--output_pom', - required=True, - help='Path to output pom file.') - return parser.parse_args() - - -def load_pom(input_path): - """ Loads POM file to XML tree""" - ET.register_namespace("", POM_NAMESPACE) - tree = ET.parse(input_path) - return tree - - -def update_version(tree, version): - """ Updates version tags in XML tree """ - version_tag = "{%s}version" % POM_NAMESPACE - nodes = list(tree.iter(version_tag)) - - if len(nodes) == 0: - raise ValueError("Missing version in template pom") - - for node in nodes: - node.text = version - - return tree - - -def merge_tags(template_root, pom_root): - """ Merge pom file from TensorFlow Hadoop with deployment template. - - Modify the TensorFlow Hadoop pom to inherit parent pom and version info and - other tags provided by deployment template. - - TODO: Figure out if there is a cleaner way of doing this. Inheritance is needed - for propagating the deployment profile. - - Args: - template_root: Root XML element for template file. - pom_root: Root XML element for TensorFlow Hadoop pom file. - - Return: - template_root: Root XML element with merged tree. - """ - template_tags = [child.tag for child in template_root] - template_tags.append("{%s}groupId" % POM_NAMESPACE) # skip groupId since it is inherited from parent - - for child in pom_root: - if child.tag not in template_tags: - template_root.append(child) - - return template_root - - -def main(): - args = get_args() - template_tree = load_pom(args.template) - pom_tree = load_pom(args.input_pom) - - template_tree = update_version(template_tree, args.version) - template_root = merge_tags(template_tree.getroot(), pom_tree.getroot()) - - with open(args.output_pom, "w") as f: - f.write(ET.tostring(template_root)) - - -if __name__ == '__main__': - sys.exit(main()) -- GitLab From b7c333dc75041b05ef4b0023db5dbbda4a817283 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Wed, 16 May 2018 16:42:47 -0700 Subject: [PATCH 010/540] Resize first, pad second --- tensorflow/python/ops/image_ops_impl.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index d5ac72bac6..a070a4699f 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1048,19 +1048,19 @@ def resize_image_with_pad(image, target_height, target_width, # Find the ratio by which the image must be adjusted # to fit within the target ratio = max_(f_width / f_target_width, f_height / f_target_height) - p_height_float = max_((f_target_height - (f_height / ratio)) * ratio / 2, 0) - p_width_float = max_((f_target_width - (f_width / ratio)) * ratio / 2, 0) - p_height = math_ops.cast(math_ops.ceil(p_height_float), dtype=dtypes.int32) - p_width = math_ops.cast(math_ops.ceil(p_width_float), dtype=dtypes.int32) + resized_height_float = f_height / ratio + resized_width_float = f_width / ratio + resized_height = math_ops.cast(math_ops.floor(p_height_float), dtype=dtypes.int32) + resized_width = math_ops.cast(math_ops.floor(p_width_float), dtype=dtypes.int32) - padded_height = height + (p_height * 2) - padded_width = width + (p_width * 2) + p_height = target_height - resized_height + p_weight = target_width - resized_width - # Pad first, then resize to meet requested dimensions + # Resize first, then pad to meet requested dimensions + resized = resize_images(image, [resized_height, resized_width], method) + padded = pad_to_bounding_box(image, p_height, p_width, - padded_height, padded_width) - - resized = resize_images(padded, [target_height, target_width], method) + target_height, target_width) if resized.get_shape().ndims is None: raise ValueError('resized contains no shape.') -- GitLab From 416bac50aaa684049bb3270d379316efc5b960c2 Mon Sep 17 00:00:00 2001 From: Lukas Geiger Date: Fri, 25 May 2018 01:06:33 +0200 Subject: [PATCH 011/540] [tfgan] Add possibility to export GANEstimator saved model --- tensorflow/contrib/gan/python/estimator/python/head_impl.py | 6 +++++- tensorflow/contrib/gan/python/estimator/python/head_test.py | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/gan/python/estimator/python/head_impl.py b/tensorflow/contrib/gan/python/estimator/python/head_impl.py index ff903a78cc..5b5557bd8f 100644 --- a/tensorflow/contrib/gan/python/estimator/python/head_impl.py +++ b/tensorflow/contrib/gan/python/estimator/python/head_impl.py @@ -24,6 +24,7 @@ from tensorflow.contrib.gan.python import namedtuples as tfgan_tuples from tensorflow.contrib.gan.python import train as tfgan_train from tensorflow.python.estimator import model_fn as model_fn_lib from tensorflow.python.estimator.canned import head +from tensorflow.python.estimator.export import export_output from tensorflow.python.framework import ops from tensorflow.python.ops import metrics as metrics_lib @@ -182,7 +183,10 @@ class GANHead(head._Head): # pylint: disable=protected-access if mode == model_fn_lib.ModeKeys.PREDICT: return model_fn_lib.EstimatorSpec( mode=model_fn_lib.ModeKeys.PREDICT, - predictions=gan_model.generated_data) + predictions=gan_model.generated_data, + export_outputs={ + 'predict': export_output.PredictOutput(gan_model.generated_data) + }) elif mode == model_fn_lib.ModeKeys.EVAL: gan_loss = self.create_loss( features=None, mode=mode, logits=gan_model, labels=None) diff --git a/tensorflow/contrib/gan/python/estimator/python/head_test.py b/tensorflow/contrib/gan/python/estimator/python/head_test.py index 6587f1fc60..c121f322b5 100644 --- a/tensorflow/contrib/gan/python/estimator/python/head_test.py +++ b/tensorflow/contrib/gan/python/estimator/python/head_test.py @@ -71,13 +71,14 @@ class GANHeadTest(test.TestCase): return {} def _test_modes_helper(self, mode): - self.gan_head.create_estimator_spec( + return self.gan_head.create_estimator_spec( features=None, mode=mode, logits=get_gan_model()) def test_modes_predict(self): - self._test_modes_helper(model_fn_lib.ModeKeys.PREDICT) + spec = self._test_modes_helper(model_fn_lib.ModeKeys.PREDICT) + self.assertItemsEqual(('predict',), spec.export_outputs.keys()) def test_modes_eval(self): self._test_modes_helper(model_fn_lib.ModeKeys.EVAL) -- GitLab From 06ba7827cb4e781ab36e6bbc46cf34e3ea587335 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sun, 27 May 2018 10:33:27 -0700 Subject: [PATCH 012/540] Remove unused function --- tensorflow/python/ops/image_ops_impl.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index a070a4699f..6e72ebd634 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1031,12 +1031,6 @@ def resize_image_with_pad(image, target_height, target_width, else: return max(x, y) - def equal_(x, y): - if _is_tensor(x) or _is_tensor(y): - return math_ops.equal(x, y) - else: - return x == y - _, height, width, _ = _ImageDimensions(image, rank=4) # convert values to float, to ease divisions -- GitLab From b0ec8d2c467173ce5a43c13631bc51fd89f072e5 Mon Sep 17 00:00:00 2001 From: Soila Kavulya Date: Wed, 30 May 2018 19:23:08 -0700 Subject: [PATCH 013/540] Update artifactId for TensorFlow Hadoop and spark-connector jars --- tensorflow/java/maven/README.md | 4 ++-- .../java/maven/{tensorflow-hadoop => hadoop}/pom.xml | 4 ++-- tensorflow/java/maven/pom.xml | 4 ++-- tensorflow/java/maven/run_inside_container.sh | 10 ++++++---- .../pom.xml | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) rename tensorflow/java/maven/{tensorflow-hadoop => hadoop}/pom.xml (94%) rename tensorflow/java/maven/{spark-tensorflow-connector => spark-connector}/pom.xml (93%) diff --git a/tensorflow/java/maven/README.md b/tensorflow/java/maven/README.md index fa756815a9..3e030dcd09 100644 --- a/tensorflow/java/maven/README.md +++ b/tensorflow/java/maven/README.md @@ -53,10 +53,10 @@ There are seven artifacts and thus `pom.xml`s involved in this release: 7. [`parentpom`](https://maven.apache.org/pom/index.html): Common settings shared by all of the above. -8. `tensorflow-hadoop`: The TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop. +8. `hadoop`: The TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop. The source code for this package is available in the [TensorFlow Ecosystem](https://github.com/tensorflow/ecosystem/tree/master/hadoop) -9. `spark-tensorflow-connector`: A Scala library for loading and storing TensorFlow TFRecord +9. `spark-connector`: A Scala library for loading and storing TensorFlow TFRecord using Apache Spark DataFrames. The source code for this package is available in the [TensorFlow Ecosystem](https://github.com/tensorflow/ecosystem/tree/master/spark/spark-tensorflow-connector) diff --git a/tensorflow/java/maven/tensorflow-hadoop/pom.xml b/tensorflow/java/maven/hadoop/pom.xml similarity index 94% rename from tensorflow/java/maven/tensorflow-hadoop/pom.xml rename to tensorflow/java/maven/hadoop/pom.xml index ee90d8c92b..a872c20d3b 100644 --- a/tensorflow/java/maven/tensorflow-hadoop/pom.xml +++ b/tensorflow/java/maven/hadoop/pom.xml @@ -5,7 +5,7 @@ 4.0.0 TensorFlow TFRecord InputFormat/OutputFormat for Apache Hadoop - tensorflow-hadoop + hadoop jar @@ -21,4 +21,4 @@ 1.8.0 ../ - + \ No newline at end of file diff --git a/tensorflow/java/maven/pom.xml b/tensorflow/java/maven/pom.xml index 7a95fb2556..19287f8245 100644 --- a/tensorflow/java/maven/pom.xml +++ b/tensorflow/java/maven/pom.xml @@ -32,8 +32,8 @@ libtensorflow_jni_gpu tensorflow proto - tensorflow-hadoop - spark-tensorflow-connector + hadoop + spark-connector 4.0.0 TensorFlow TFRecord connector for Apache Spark DataFrames - spark-tensorflow-connector + spark-connector jar @@ -21,4 +21,4 @@ 1.8.0 ../ - + \ No newline at end of file -- GitLab From 13ceff2d4096554f195a3c865c1391500e172485 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 2 Jun 2018 22:11:20 +0000 Subject: [PATCH 014/540] Fix warning in constrained_optimization test In constrained_optimization test, keep_dims was used for reduce_sum. Since keep_dims has been deprecated it generates unnecessary warning. This fix updates keep_dims -> keepdims to disable the warning. Signed-off-by: Yong Tang --- .../constrained_optimization/python/swap_regret_optimizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py b/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py index 04014ab4ae..91b2486393 100644 --- a/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py +++ b/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py @@ -169,8 +169,8 @@ def _project_stochastic_matrix_wrt_euclidean_norm(matrix): del old_inactive # Needed by the condition, but not the body. iteration += 1 scale = (1.0 - standard_ops.reduce_sum( - matrix, axis=0, keep_dims=True)) / standard_ops.maximum( - 1.0, standard_ops.reduce_sum(inactive, axis=0, keep_dims=True)) + matrix, axis=0, keepdims=True)) / standard_ops.maximum( + 1.0, standard_ops.reduce_sum(inactive, axis=0, keepdims=True)) matrix += scale * inactive new_inactive = standard_ops.to_float(matrix > 0) matrix *= new_inactive -- GitLab From b7150cffc5e36fe736e648c624cfb8b0cb411f1f Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 2 Jun 2018 22:13:21 +0000 Subject: [PATCH 015/540] Update keep_dims for reduce_max Signed-off-by: Yong Tang --- .../constrained_optimization/python/swap_regret_optimizer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py b/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py index 91b2486393..3791dae8d7 100644 --- a/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py +++ b/tensorflow/contrib/constrained_optimization/python/swap_regret_optimizer.py @@ -206,10 +206,10 @@ def _project_log_stochastic_matrix_wrt_kl_divergence(log_matrix): # For numerical reasons, make sure that the largest matrix element is zero # before exponentiating. - log_matrix -= standard_ops.reduce_max(log_matrix, axis=0, keep_dims=True) + log_matrix -= standard_ops.reduce_max(log_matrix, axis=0, keepdims=True) log_matrix -= standard_ops.log( standard_ops.reduce_sum( - standard_ops.exp(log_matrix), axis=0, keep_dims=True)) + standard_ops.exp(log_matrix), axis=0, keepdims=True)) return log_matrix -- GitLab From 2d60c046ebbeac964efdc94e988fc86003f6fc9c Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Sun, 3 Jun 2018 18:37:29 -0700 Subject: [PATCH 016/540] Fix bugs --- tensorflow/python/ops/image_ops_impl.py | 24 +++++++++++++----------- tensorflow/python/ops/image_ops_test.py | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 6e72ebd634..073c0d62b7 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -871,7 +871,7 @@ def resize_images(images, Resized images will be distorted if their original aspect ratio is not the same as `size`. To avoid distortions see - @{tf.image.resize_image_with_crop_or_pad}. + @{tf.image.resize_image_with_pad}. `method` can be one of: @@ -1044,27 +1044,29 @@ def resize_image_with_pad(image, target_height, target_width, ratio = max_(f_width / f_target_width, f_height / f_target_height) resized_height_float = f_height / ratio resized_width_float = f_width / ratio - resized_height = math_ops.cast(math_ops.floor(p_height_float), dtype=dtypes.int32) - resized_width = math_ops.cast(math_ops.floor(p_width_float), dtype=dtypes.int32) + resized_height = math_ops.cast(math_ops.floor(resized_height_float), dtype=dtypes.int32) + resized_width = math_ops.cast(math_ops.floor(resized_width_float), dtype=dtypes.int32) - p_height = target_height - resized_height - p_weight = target_width - resized_width + f_padding_height = math_ops.floor((f_target_height - resized_height_float) / 2) + f_padding_width = math_ops.floor((f_target_width - resized_width_float) / 2) + p_height = max_(0, math_ops.cast(f_padding_height, dtype=dtypes.int32)) + p_width = max_(0, math_ops.cast(f_padding_width, dtype=dtypes.int32)) # Resize first, then pad to meet requested dimensions resized = resize_images(image, [resized_height, resized_width], method) - padded = pad_to_bounding_box(image, p_height, p_width, + padded = pad_to_bounding_box(resized, p_height, p_width, target_height, target_width) - if resized.get_shape().ndims is None: - raise ValueError('resized contains no shape.') + if padded.get_shape().ndims is None: + raise ValueError('padded contains no shape.') - _, resized_height, resized_width, _ = _ImageDimensions(resized, rank=4) + _, padded_height, padded_width, _ = _ImageDimensions(padded, rank=4) if not is_batch: - resized = array_ops.squeeze(resized, squeeze_dims=[0]) + padded = array_ops.squeeze(padded, squeeze_dims=[0]) - return resized + return padded @tf_export('image.per_image_standardization') diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index 22d9ce4289..e98d16e6d3 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -2540,7 +2540,7 @@ class ResizeImageWithPadTest(test_util.TensorFlowTestCase): x = [1, 2, 3, 4, 5, 6, 7, 8] x_shape = [2, 4, 1] - y = [0, 0, 5, 7] + y = [1, 3, 0, 0] y_shape = [2, 2, 1] self._assertReturns(x, x_shape, y, y_shape) -- GitLab From 7eaef86f7766e7c0577614e646dc8d6a972b91f9 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Mon, 4 Jun 2018 09:55:17 -0700 Subject: [PATCH 017/540] Remove unnecessary assertions --- tensorflow/python/ops/image_ops_impl.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 073c0d62b7..f3f9a02f01 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1018,12 +1018,6 @@ def resize_image_with_pad(image, target_height, target_width, 'target_height must be > 0.') image = control_flow_ops.with_dependencies(assert_ops, image) - if _is_tensor(target_height): - target_height = control_flow_ops.with_dependencies( - assert_ops, target_height) - if _is_tensor(target_width): - target_width = control_flow_ops.with_dependencies(assert_ops, - target_width) def max_(x, y): if _is_tensor(x) or _is_tensor(y): -- GitLab From 7edb417cd05fe438d587372fcf07e7c45e1dd8f8 Mon Sep 17 00:00:00 2001 From: Dan Osipov Date: Tue, 5 Jun 2018 16:39:47 -0700 Subject: [PATCH 018/540] Fix lint errors --- tensorflow/python/ops/image_ops_impl.py | 18 +++++++++++------- tensorflow/python/ops/image_ops_test.py | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index f3f9a02f01..231b49fbf5 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -971,7 +971,7 @@ def resize_images(images, @tf_export('image.resize_image_with_pad') def resize_image_with_pad(image, target_height, target_width, - method=ResizeMethod.BILINEAR): + method=ResizeMethod.BILINEAR): """ Resizes and pads an image to a target width and height. @@ -1038,17 +1038,21 @@ def resize_image_with_pad(image, target_height, target_width, ratio = max_(f_width / f_target_width, f_height / f_target_height) resized_height_float = f_height / ratio resized_width_float = f_width / ratio - resized_height = math_ops.cast(math_ops.floor(resized_height_float), dtype=dtypes.int32) - resized_width = math_ops.cast(math_ops.floor(resized_width_float), dtype=dtypes.int32) - - f_padding_height = math_ops.floor((f_target_height - resized_height_float) / 2) - f_padding_width = math_ops.floor((f_target_width - resized_width_float) / 2) + resized_height = math_ops.cast(math_ops.floor(resized_height_float), + dtype=dtypes.int32) + resized_width = math_ops.cast(math_ops.floor(resized_width_float), + dtype=dtypes.int32) + + padding_height = (f_target_height - resized_height_float) / 2 + padding_width = (f_target_width - resized_width_float) / 2 + f_padding_height = math_ops.floor(padding_height) + f_padding_width = math_ops.floor(padding_width) p_height = max_(0, math_ops.cast(f_padding_height, dtype=dtypes.int32)) p_width = max_(0, math_ops.cast(f_padding_width, dtype=dtypes.int32)) # Resize first, then pad to meet requested dimensions resized = resize_images(image, [resized_height, resized_width], method) - + padded = pad_to_bounding_box(resized, p_height, p_width, target_height, target_width) diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py index e98d16e6d3..ce46a4e59e 100644 --- a/tensorflow/python/ops/image_ops_test.py +++ b/tensorflow/python/ops/image_ops_test.py @@ -2461,7 +2461,7 @@ class ResizeImagesTest(test_util.TensorFlowTestCase): class ResizeImageWithPadTest(test_util.TensorFlowTestCase): def _ResizeImageWithPad(self, x, target_height, target_width, - use_tensor_inputs): + use_tensor_inputs): if use_tensor_inputs: target_height = ops.convert_to_tensor(target_height) target_width = ops.convert_to_tensor(target_width) @@ -2472,7 +2472,7 @@ class ResizeImageWithPadTest(test_util.TensorFlowTestCase): feed_dict = {} y = image_ops.resize_image_with_pad(x_tensor, target_height, - target_width) + target_width) if not use_tensor_inputs: self.assertTrue(y.get_shape().is_fully_defined()) @@ -2492,7 +2492,7 @@ class ResizeImageWithPadTest(test_util.TensorFlowTestCase): for use_tensor_inputs in use_tensor_inputs_options: y_tf = self._ResizeImageWithPad(x, target_height, target_width, - use_tensor_inputs) + use_tensor_inputs) self.assertAllClose(y, y_tf) def _assertRaises(self, @@ -2508,7 +2508,7 @@ class ResizeImageWithPadTest(test_util.TensorFlowTestCase): for use_tensor_inputs in use_tensor_inputs_options: try: self._ResizeImageWithPad(x, target_height, target_width, - use_tensor_inputs) + use_tensor_inputs) except Exception as e: if err_msg not in str(e): raise -- GitLab From 3216ba10048efede648054b4a9627ce194aec1d1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 14:55:15 -0700 Subject: [PATCH 019/540] While the DNN is training use that as the logit for evaluation. PiperOrigin-RevId: 200117729 --- .../estimator_batch/dnn_tree_combined_estimator.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tensorflow/contrib/boosted_trees/estimator_batch/dnn_tree_combined_estimator.py b/tensorflow/contrib/boosted_trees/estimator_batch/dnn_tree_combined_estimator.py index 758754feac..911d87fa10 100644 --- a/tensorflow/contrib/boosted_trees/estimator_batch/dnn_tree_combined_estimator.py +++ b/tensorflow/contrib/boosted_trees/estimator_batch/dnn_tree_combined_estimator.py @@ -232,7 +232,13 @@ def _dnn_tree_combined_model_fn(features, return update_op if predict_with_tree_only: - tree_train_logits = tree_logits + if mode == model_fn.ModeKeys.TRAIN or mode == model_fn.ModeKeys.PREDICT: + tree_train_logits = tree_logits + else: + tree_train_logits = control_flow_ops.cond( + global_step > dnn_steps_to_train, + lambda: tree_logits, + lambda: dnn_logits) else: tree_train_logits = dnn_logits + tree_logits -- GitLab From f4f92acbcd0994299882260fe4f4896385e6bff9 Mon Sep 17 00:00:00 2001 From: Suharsh Sivakumar Date: Mon, 11 Jun 2018 14:59:42 -0700 Subject: [PATCH 020/540] SpaceToBatchND supports quantization, so make the transformation know that. #19735 PiperOrigin-RevId: 200118450 --- tensorflow/contrib/lite/toco/graph_transformations/quantize.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc index ab24c4f996..d4b5920760 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc @@ -51,6 +51,7 @@ bool SupportsQuantization(const Operator& op) { type == OperatorType::kPadV2 || type == OperatorType::kTensorFlowReshape || type == OperatorType::kTanh || type == OperatorType::kMul || + type == OperatorType::kSpaceToBatchND || type == OperatorType::kSpaceToDepth || type == OperatorType::kStridedSlice || type == OperatorType::kDepthToSpace || -- GitLab From dfc2a6bad7d6f8b71bc4fbb65c0373c69f56b7b0 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 15:06:49 -0700 Subject: [PATCH 021/540] Make test_locallyconnected_2d_channels_first run in graph and eager modes. PiperOrigin-RevId: 200119934 --- tensorflow/python/keras/layers/local_test.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tensorflow/python/keras/layers/local_test.py b/tensorflow/python/keras/layers/local_test.py index 9123d449af..8df3f6b7bd 100644 --- a/tensorflow/python/keras/layers/local_test.py +++ b/tensorflow/python/keras/layers/local_test.py @@ -118,6 +118,7 @@ class LocallyConnectedLayersTest(test.TestCase): }, input_shape=(num_samples, num_row, num_col, stack_size)) + @tf_test_util.run_in_graph_and_eager_modes() def test_locallyconnected_2d_channels_first(self): num_samples = 8 filters = 3 @@ -125,15 +126,14 @@ class LocallyConnectedLayersTest(test.TestCase): num_row = 6 num_col = 10 - with self.test_session(): - testing_utils.layer_test( - keras.layers.LocallyConnected2D, - kwargs={ - 'filters': filters, - 'kernel_size': 3, - 'data_format': 'channels_first' - }, - input_shape=(num_samples, num_row, num_col, stack_size)) + testing_utils.layer_test( + keras.layers.LocallyConnected2D, + kwargs={ + 'filters': filters, + 'kernel_size': 3, + 'data_format': 'channels_first' + }, + input_shape=(num_samples, num_row, num_col, stack_size)) def test_locallyconnected_2d_regularization(self): num_samples = 8 -- GitLab From 0472c89ed62a46a2e86d608a30e4e57c09c40da1 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 15:18:36 -0700 Subject: [PATCH 022/540] Update ops-related pbtxt files. PiperOrigin-RevId: 200122052 --- .../core/ops/compat/ops_history.v1.pbtxt | 38 +++++++++++++++++++ tensorflow/core/ops/ops.pbtxt | 1 - 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tensorflow/core/ops/compat/ops_history.v1.pbtxt b/tensorflow/core/ops/compat/ops_history.v1.pbtxt index 8f8c90ee97..b48686d9a3 100644 --- a/tensorflow/core/ops/compat/ops_history.v1.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v1.pbtxt @@ -25468,6 +25468,44 @@ op { type: "func" } } +op { + name: "If" + input_arg { + name: "cond" + type_attr: "Tcond" + } + input_arg { + name: "input" + type_list_attr: "Tin" + } + output_arg { + name: "output" + type_list_attr: "Tout" + } + attr { + name: "Tcond" + type: "type" + } + attr { + name: "Tin" + type: "list(type)" + has_minimum: true + } + attr { + name: "Tout" + type: "list(type)" + has_minimum: true + minimum: 1 + } + attr { + name: "then_branch" + type: "func" + } + attr { + name: "else_branch" + type: "func" + } +} op { name: "Igamma" input_arg { diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index d3f3e87dfd..dd3a6cd22c 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -12358,7 +12358,6 @@ op { name: "Tin" type: "list(type)" has_minimum: true - minimum: 1 } attr { name: "Tout" -- GitLab From b12f58cfcf37cf8f20d3b6c0c7e9fdfb5ec54614 Mon Sep 17 00:00:00 2001 From: Derek Murray Date: Mon, 11 Jun 2018 15:30:58 -0700 Subject: [PATCH 023/540] [tf.data] Improve the error messages for `Dataset.from_generator()`. In particular: * Improve the error message when the generator yields something with the wrong structure. * Improve the error message when the generator yields something with the wrong element type. PiperOrigin-RevId: 200124096 --- .../dataset_from_generator_op_test.py | 32 +++++++++++++++++-- tensorflow/python/data/ops/dataset_ops.py | 24 ++++++++++---- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py b/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py index 296a76ec88..fb55ae1400 100644 --- a/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py +++ b/tensorflow/python/data/kernel_tests/dataset_from_generator_op_test.py @@ -259,9 +259,7 @@ class DatasetConstructorTest(test.TestCase): sess.run(init_op) self.assertAllEqual([1, 2, 3], sess.run(get_next)) self.assertAllEqual([4, 5, 6], sess.run(get_next)) - # NOTE(mrry): Type name in message differs between Python 2 (`long`) and - # 3 (`int`). - with self.assertRaisesOpError(r"invalid literal for"): + with self.assertRaisesOpError("The expected type was int64"): sess.run(get_next) self.assertAllEqual([7, 8, 9], sess.run(get_next)) with self.assertRaises(errors.OutOfRangeError): @@ -290,6 +288,34 @@ class DatasetConstructorTest(test.TestCase): with self.assertRaises(errors.OutOfRangeError): sess.run(get_next) + def testFromGeneratorStructureError(self): + def generator(): + yield 1, 2 + yield 3, 4 + yield 5 + yield 6, 7, 8 + yield 9, 10 + + iterator = (dataset_ops.Dataset.from_generator( + generator, output_types=(dtypes.int64, dtypes.int64)) + .make_initializable_iterator()) + init_op = iterator.initializer + get_next = iterator.get_next() + + with self.test_session() as sess: + sess.run(init_op) + self.assertEqual((1, 2), sess.run(get_next)) + self.assertEqual((3, 4), sess.run(get_next)) + with self.assertRaisesOpError( + r"The expected structure was \(tf\.int64, tf\.int64\)"): + sess.run(get_next) + with self.assertRaisesOpError( + r"The expected structure was \(tf\.int64, tf\.int64\)"): + sess.run(get_next) + self.assertEqual((9, 10), sess.run(get_next)) + with self.assertRaises(errors.OutOfRangeError): + sess.run(get_next) + def testFromGeneratorHeterogeneous(self): def generator(): yield 1 diff --git a/tensorflow/python/data/ops/dataset_ops.py b/tensorflow/python/data/ops/dataset_ops.py index 672ce014f6..597f92048e 100644 --- a/tensorflow/python/data/ops/dataset_ops.py +++ b/tensorflow/python/data/ops/dataset_ops.py @@ -409,13 +409,23 @@ class Dataset(object): # Use the same _convert function from the py_func() implementation to # convert the returned values to arrays early, so that we can inspect # their values. - # pylint: disable=protected-access - ret_arrays = [ - script_ops.FuncRegistry._convert(ret, dtype=dtype.as_numpy_dtype) - for ret, dtype in zip( - nest.flatten_up_to(output_types, values), flattened_types) - ] - # pylint: enable=protected-access + try: + flattened_values = nest.flatten_up_to(output_types, values) + except (TypeError, ValueError): + raise TypeError( + "`generator` yielded an element that did not match the expected " + "structure. The expected structure was %s, but the yielded " + "element was %s." % (output_types, values)) + ret_arrays = [] + for ret, dtype in zip(flattened_values, flattened_types): + try: + ret_arrays.append(script_ops.FuncRegistry._convert( # pylint: disable=protected-access + ret, dtype=dtype.as_numpy_dtype)) + except (TypeError, ValueError): + raise TypeError( + "`generator` yielded an element that could not be converted to " + "the expected type. The expected type was %s, but the yielded " + "element was %s." % (dtype.name, ret)) # Additional type and shape checking to ensure that the components # of the generated element match the `output_types` and `output_shapes` -- GitLab From 49ed096fb3f89855dbdccf183d10d8068324f1c2 Mon Sep 17 00:00:00 2001 From: Shanqing Cai Date: Mon, 11 Jun 2018 15:57:39 -0700 Subject: [PATCH 024/540] Improve tfdbg's handling of runtime errors * In some cases the RuntimeError object (tf_error in cli_shared.py) doesn't have the op or its name available. Handle that situation properly. * Previously, we used client graphs in the debugger CLI whenever it's available. This has caused issues in which the device names (e.g., "/device:GPU:0" vs "/job:localhost/replica:0/task:0/device:CPU:0"). This CL fixes that by favoring the runtime graph on the disk over the client graph. The former has the actual device names. Use the latter only if the former isn't available for some reason (e.g., writing graph to the disk failed.) PiperOrigin-RevId: 200128582 --- tensorflow/python/debug/cli/cli_shared.py | 44 +++++++++++-------- .../python/debug/cli/cli_shared_test.py | 5 +++ .../python/debug/examples/examples_test.sh | 6 +++ tensorflow/python/debug/lib/debug_data.py | 43 +++++++++--------- 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/tensorflow/python/debug/cli/cli_shared.py b/tensorflow/python/debug/cli/cli_shared.py index dea019fef5..6a368682de 100644 --- a/tensorflow/python/debug/cli/cli_shared.py +++ b/tensorflow/python/debug/cli/cli_shared.py @@ -451,42 +451,48 @@ def get_error_intro(tf_error): sample commands for debugging. """ - op_name = tf_error.op.name + if hasattr(tf_error, "op") and hasattr(tf_error.op, "name"): + op_name = tf_error.op.name + else: + op_name = None intro_lines = [ "--------------------------------------", RL("!!! An error occurred during the run !!!", "blink"), "", - "You may use the following commands to debug:", ] out = debugger_cli_common.rich_text_lines_from_rich_line_list(intro_lines) - out.extend( - _recommend_command("ni -a -d -t %s" % op_name, - "Inspect information about the failing op.", - create_link=True)) - out.extend( - _recommend_command("li -r %s" % op_name, - "List inputs to the failing op, recursively.", - create_link=True)) - - out.extend( - _recommend_command( - "lt", - "List all tensors dumped during the failing run() call.", - create_link=True)) + if op_name is not None: + out.extend(debugger_cli_common.RichTextLines( + ["You may use the following commands to debug:"])) + out.extend( + _recommend_command("ni -a -d -t %s" % op_name, + "Inspect information about the failing op.", + create_link=True)) + out.extend( + _recommend_command("li -r %s" % op_name, + "List inputs to the failing op, recursively.", + create_link=True)) + + out.extend( + _recommend_command( + "lt", + "List all tensors dumped during the failing run() call.", + create_link=True)) + else: + out.extend(debugger_cli_common.RichTextLines([ + "WARNING: Cannot determine the name of the op that caused the error."])) more_lines = [ "", - "Op name: " + op_name, + "Op name: %s" % op_name, "Error type: " + str(type(tf_error)), "", "Details:", str(tf_error), "", - "WARNING: Using client GraphDef due to the error, instead of " - "executor GraphDefs.", "--------------------------------------", "", ] diff --git a/tensorflow/python/debug/cli/cli_shared_test.py b/tensorflow/python/debug/cli/cli_shared_test.py index 3d7939490d..07b364db9f 100644 --- a/tensorflow/python/debug/cli/cli_shared_test.py +++ b/tensorflow/python/debug/cli/cli_shared_test.py @@ -372,6 +372,11 @@ class GetErrorIntroTest(test_util.TensorFlowTestCase): self.assertEqual("Details:", error_intro.lines[14]) self.assertStartsWith(error_intro.lines[15], "foo description") + def testGetErrorIntroForNoOpName(self): + tf_error = errors.OpError(None, None, "Fake OpError", -1) + error_intro = cli_shared.get_error_intro(tf_error) + self.assertIn("Cannot determine the name of the op", error_intro.lines[3]) + if __name__ == "__main__": googletest.main() diff --git a/tensorflow/python/debug/examples/examples_test.sh b/tensorflow/python/debug/examples/examples_test.sh index 2df6c0b6a2..e9c45a7e6e 100755 --- a/tensorflow/python/debug/examples/examples_test.sh +++ b/tensorflow/python/debug/examples/examples_test.sh @@ -69,6 +69,12 @@ run exit EOF +cat << EOF | ${DEBUG_ERRORS_BIN} --error=uninitialized_variable --debug --ui_type=readline +run +ni -a -d -t v/read +exit +EOF + cat << EOF | ${DEBUG_MNIST_BIN} --debug --max_steps=1 --fake_data --ui_type=readline run -t 1 run --node_name_filter hidden --op_type_filter MatMul diff --git a/tensorflow/python/debug/lib/debug_data.py b/tensorflow/python/debug/lib/debug_data.py index 8a65ad087b..7c96c2878c 100644 --- a/tensorflow/python/debug/lib/debug_data.py +++ b/tensorflow/python/debug/lib/debug_data.py @@ -748,7 +748,7 @@ class DebugDumpDir(object): return sum(len(self._dump_tensor_data[device_name]) for device_name in self._dump_tensor_data) - def _load_partition_graphs(self, partition_graphs, validate): + def _load_partition_graphs(self, client_partition_graphs, validate): """Load and process partition graphs. Load the graphs; parse the input and control input structure; obtain the @@ -757,8 +757,10 @@ class DebugDumpDir(object): tensor dumps. Args: - partition_graphs: A repeated field of GraphDefs representing the - partition graphs executed by the TensorFlow runtime. + client_partition_graphs: A repeated field of GraphDefs representing the + partition graphs executed by the TensorFlow runtime, from the Python + client. These partition graphs are used only if partition graphs + cannot be loaded from the dump directory on the file system. validate: (`bool`) Whether the dump files are to be validated against the partition graphs. @@ -769,24 +771,23 @@ class DebugDumpDir(object): self._debug_graphs = {} self._node_devices = {} - if partition_graphs: - partition_graphs_and_device_names = [ - (partition_graph, None) for partition_graph in partition_graphs] - else: - partition_graphs_and_device_names = [] - for device_name in self._device_names: - partition_graph = None - if device_name in self._dump_graph_file_paths: - partition_graph = _load_graph_def_from_event_file( - self._dump_graph_file_paths[device_name]) - else: - partition_graph = self._find_partition_graph(partition_graphs, - device_name) - if partition_graph: - partition_graphs_and_device_names.append((partition_graph, - device_name)) - else: - logging.warn("Failed to load partition graphs from disk.") + partition_graphs_and_device_names = [] + for device_name in self._device_names: + partition_graph = None + if device_name in self._dump_graph_file_paths: + partition_graph = _load_graph_def_from_event_file( + self._dump_graph_file_paths[device_name]) + else: + logging.warn( + "Failed to load partition graphs for device %s from disk. " + "As a fallback, the client graphs will be used. This " + "may cause mismatches in device names." % device_name) + partition_graph = self._find_partition_graph(client_partition_graphs, + device_name) + + if partition_graph: + partition_graphs_and_device_names.append((partition_graph, + device_name)) for partition_graph, maybe_device_name in partition_graphs_and_device_names: debug_graph = debug_graphs.DebugGraph(partition_graph, -- GitLab From a1244d61b1bf9db586ad12fb12b65d2db3913e45 Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Mon, 11 Jun 2018 16:04:33 -0700 Subject: [PATCH 025/540] Allow silent copies during remote execution. This is required to do anything useful from python. PiperOrigin-RevId: 200129777 --- tensorflow/c/eager/c_api_test.cc | 81 +++++++- .../core/common_runtime/eager/execute.cc | 191 ++++++++++-------- 2 files changed, 184 insertions(+), 88 deletions(-) diff --git a/tensorflow/c/eager/c_api_test.cc b/tensorflow/c/eager/c_api_test.cc index 27ff5f7211..992d1afd5f 100644 --- a/tensorflow/c/eager/c_api_test.cc +++ b/tensorflow/c/eager/c_api_test.cc @@ -142,8 +142,10 @@ void TestRemoteExecute(bool async) { TFE_ContextOptions* opts = TFE_NewContextOptions(); TFE_ContextOptionsSetServerDef(opts, serialized.data(), serialized.size(), status); - TFE_ContextOptionsSetAsync(opts, static_cast(1)); EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_ContextOptionsSetAsync(opts, static_cast(1)); + TFE_ContextOptionsSetDevicePlacementPolicy(opts, + TFE_DEVICE_PLACEMENT_EXPLICIT); TFE_Context* ctx = TFE_NewContext(opts, status); EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); TFE_DeleteContextOptions(opts); @@ -205,6 +207,83 @@ void TestRemoteExecute(bool async) { TEST(CAPI, RemoteExecute) { TestRemoteExecute(false); } TEST(CAPI, RemoteExecuteAsync) { TestRemoteExecute(true); } +void TestRemoteExecuteSilentCopies(bool async) { + tensorflow::ServerDef server_def = GetServerDef(2); + + // This server def has the task index set to 0. + string serialized = server_def.SerializeAsString(); + + server_def.set_task_index(1); + + std::unique_ptr worker_server; + ASSERT_TRUE( + tensorflow::eager::EagerGrpcServer::Create(server_def, &worker_server) + .ok()); + ASSERT_TRUE(worker_server->Start().ok()); + + TF_Status* status = TF_NewStatus(); + TFE_ContextOptions* opts = TFE_NewContextOptions(); + TFE_ContextOptionsSetServerDef(opts, serialized.data(), serialized.size(), + status); + EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_ContextOptionsSetAsync(opts, static_cast(1)); + TFE_ContextOptionsSetDevicePlacementPolicy(opts, TFE_DEVICE_PLACEMENT_SILENT); + TFE_Context* ctx = TFE_NewContext(opts, status); + EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_DeleteContextOptions(opts); + + TFE_TensorHandle* h0_task0 = TestMatrixTensorHandle(); + TFE_TensorHandle* h1_task0 = TestMatrixTensorHandle(); + const char remote_device_name[] = + "/job:localhost/replica:0/task:1/device:CPU:0"; + + // Handles are on task0, but op is on remote (task1). + TFE_Op* matmul = MatMulOp(ctx, h0_task0, h1_task0); + TFE_OpSetDevice(matmul, remote_device_name, status); + EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TFE_TensorHandle* retvals[1]; + int num_retvals = 1; + TFE_Execute(matmul, &retvals[0], &num_retvals, status); + EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + auto* retval_task0 = TFE_TensorHandleCopyToDevice( + retvals[0], ctx, "/job:localhost/replica:0/task:0/device:CPU:0", status); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TF_Tensor* t = TFE_TensorHandleResolve(retval_task0, status); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + TFE_DeleteTensorHandle(retval_task0); + 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_DeleteTensorHandle(h0_task0); + TFE_DeleteTensorHandle(h1_task0); + TFE_DeleteTensorHandle(retvals[0]); + + TFE_DeleteOp(matmul); + + TFE_ContextAsyncWait(ctx, status); + TFE_DeleteContext(ctx, status); + EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TF_DeleteStatus(status); + + // TODO(nareshmodi): Figure out how to correctly shut the server down. + worker_server.release(); +} + +TEST(CAPI, RemoteExecuteSilentCopies) { TestRemoteExecuteSilentCopies(false); } +TEST(CAPI, RemoteExecuteSilentCopiesAsync) { + TestRemoteExecuteSilentCopies(true); +} + TEST(CAPI, TensorHandle) { TFE_TensorHandle* h = TestMatrixTensorHandle(); EXPECT_EQ(TF_FLOAT, TFE_TensorHandleDataType(h)); diff --git a/tensorflow/core/common_runtime/eager/execute.cc b/tensorflow/core/common_runtime/eager/execute.cc index ce989f4b4e..c619857b78 100644 --- a/tensorflow/core/common_runtime/eager/execute.cc +++ b/tensorflow/core/common_runtime/eager/execute.cc @@ -66,6 +66,88 @@ int StepStatsDeviceIndex(StepStats* step_stats, EagerContext* ctx, return 0; } +// This function expects *handle to point to an existing tensor handle. The +// function will (maybe) update the *handle to be pointed to the newly copied +// tensor handle. +// +// The passed in *handle will be Unreffed if it is replaced. +Status MaybeCopyInputToExpectedDevice(EagerOperation* op, int i, + const Device* expected_device, + RunMetadata* run_metadata, + TensorHandle** handle) { + EagerContext* ctx = op->EagerContext(); + Device* handle_device = nullptr; + TF_RETURN_IF_ERROR((*handle)->Device(&handle_device)); + const Device* actual_device = + handle_device == nullptr ? ctx->HostCPU() : handle_device; + + if (expected_device != actual_device) { + switch (ctx->GetDevicePlacementPolicy()) { + case DEVICE_PLACEMENT_SILENT_FOR_INT32: + // TODO(xpan): See if we could bubble python related error up + // to python level. + if ((*handle)->dtype == DT_INT32) { + // Note: enabling silent copies of int32 tensors to match behavior + // of graph mode. + break; + } + TF_FALLTHROUGH_INTENDED; + case DEVICE_PLACEMENT_EXPLICIT: + return errors::InvalidArgument( + "Tensors on conflicting devices:" + " cannot compute ", + op->Name(), " as input #", i, " was expected to be on ", + expected_device->name(), " but is actually on ", + actual_device->name(), " (operation running on ", + op->Device()->name(), ")", + " Tensors can be copied explicitly using .gpu() or .cpu() " + "methods," + " or transparently copied by using tf.enable_eager_execution(" + "device_policy=tfe.DEVICE_PLACEMENT_SILENT). Copying tensors " + "between devices" + " may slow down your model"); + case DEVICE_PLACEMENT_WARN: + LOG(WARNING) << "before computing " << op->Name() << " input #" << i + << " was expected to be on " << expected_device->name() + << " but is actually on " << actual_device->name() + << " (operation running on " << op->Device()->name() + << "). This triggers a copy which can be a performance " + "bottleneck."; + break; + case DEVICE_PLACEMENT_SILENT: // Do nothing. + break; + } + // We are only here if the policy is warn or silent copies, so we should + // trigger a copy. + auto pre_time = Env::Default()->NowMicros(); + TensorHandle* result_handle; + Status status = EagerCopyToDevice( + *handle, ctx, expected_device->name().c_str(), &result_handle); + if (run_metadata != nullptr) { + auto* step_stats = run_metadata->mutable_step_stats(); + MaybeInitializeStepStats(step_stats, ctx); + // Record the sending on the source device for now. + int device_idx = StepStatsDeviceIndex(step_stats, ctx, handle_device); + auto* dev_stats = step_stats->mutable_dev_stats(device_idx); + auto* node_stats = dev_stats->add_node_stats(); + node_stats->set_node_name("_Send"); + node_stats->set_all_start_micros(pre_time); + node_stats->set_op_end_rel_micros(Env::Default()->NowMicros() - pre_time); + } + if (!status.ok()) { + if (result_handle != nullptr) result_handle->Unref(); + return errors::Internal("Failed copying input tensor from ", + actual_device->name(), " to ", + expected_device->name(), " in order to run ", + op->Name(), ": ", status.error_message()); + } + + (*handle)->Unref(); + *handle = result_handle; + } + return Status::OK(); +} + Status ValidateInputTypeAndPlacement(EagerContext* ctx, Device* op_device, EagerOperation* op, const OpKernel* kernel, RunMetadata* run_metadata) { @@ -78,76 +160,9 @@ Status ValidateInputTypeAndPlacement(EagerContext* ctx, Device* op_device, for (int i = 0; i < op->Inputs().size(); ++i) { const Device* expected_device = memtypes[i] == HOST_MEMORY ? host_device : op_device; - TensorHandle* handle = op->Inputs()[i]; - Device* handle_device = nullptr; - TF_RETURN_IF_ERROR(handle->Device(&handle_device)); - const Device* actual_device = - handle_device == nullptr ? host_device : handle_device; - if (expected_device != actual_device) { - switch (ctx->GetDevicePlacementPolicy()) { - case DEVICE_PLACEMENT_SILENT_FOR_INT32: - // TODO(xpan): See if we could bubble python related error up - // to python level. - if (handle->dtype == DT_INT32) { - // Note: enabling silent copies of int32 tensors to match behavior - // of graph mode. - break; - } - TF_FALLTHROUGH_INTENDED; - case DEVICE_PLACEMENT_EXPLICIT: - return errors::InvalidArgument( - "Tensors on conflicting devices:" - " cannot compute ", - op->Name(), " as input #", i, " was expected to be on ", - expected_device->name(), " but is actually on ", - actual_device->name(), " (operation running on ", - op_device->name(), ")", - " Tensors can be copied explicitly using .gpu() or .cpu() " - "methods," - " or transparently copied by using tf.enable_eager_execution(" - "device_policy=tfe.DEVICE_PLACEMENT_SILENT). Copying tensors " - "between devices" - " may slow down your model"); - case DEVICE_PLACEMENT_WARN: - LOG(WARNING) << "before computing " << op->Name() << " input #" << i - << " was expected to be on " << expected_device->name() - << " but is actually on " << actual_device->name() - << " (operation running on " << op_device->name() - << "). This triggers a copy which can be a performance " - "bottleneck."; - break; - case DEVICE_PLACEMENT_SILENT: // Do nothing. - break; - } - // We are only here if the policy is warn or silent copies, so we should - // trigger a copy. - auto pre_time = Env::Default()->NowMicros(); - TensorHandle* copied_tensor = nullptr; - Status status = EagerCopyToDevice( - handle, ctx, expected_device->name().c_str(), &copied_tensor); - if (run_metadata != nullptr) { - auto* step_stats = run_metadata->mutable_step_stats(); - MaybeInitializeStepStats(step_stats, ctx); - // Record the sending on the source device for now. - int device_idx = StepStatsDeviceIndex(step_stats, ctx, handle_device); - auto* dev_stats = step_stats->mutable_dev_stats(device_idx); - auto* node_stats = dev_stats->add_node_stats(); - node_stats->set_node_name("_Send"); - node_stats->set_all_start_micros(pre_time); - node_stats->set_op_end_rel_micros(Env::Default()->NowMicros() - - pre_time); - } - if (!status.ok()) { - if (copied_tensor != nullptr) copied_tensor->Unref(); - return errors::Internal("Failed copying input tensor from ", - actual_device->name(), " to ", - expected_device->name(), " in order to run ", - op->Name(), ": ", status.error_message()); - } - handle->Unref(); - handle = copied_tensor; - (*op->MutableInputs())[i] = copied_tensor; - } + TF_RETURN_IF_ERROR(MaybeCopyInputToExpectedDevice( + op, i, expected_device, run_metadata, &((*op->MutableInputs())[i]))); + tensorflow::TensorHandle* handle = op->Inputs()[i]; if (handle->dtype != kernel->input_type(i)) { return errors::InvalidArgument( "cannot compute ", op->Name(), " as input #", i, @@ -192,8 +207,8 @@ Status SelectDevice(const NodeDef& ndef, EagerContext* ctx, Device** device) { // Resource4> as the input params to the synthesized function. // // It populates `const_input_types`, `arg_input_types` and -// `op_input_to_func_input` based on the reordering results, that the caller can -// use them to build an XlaLaunch. On error, it returns NULL, and sets +// `op_input_to_func_input` based on the reordering results, that the caller +// can use them to build an XlaLaunch. On error, it returns NULL, and sets // `status` accordingly. const FunctionDef* OpToFunction(TFE_Op* op, std::vector* const_input_types, @@ -221,8 +236,8 @@ const FunctionDef* OpToFunction(TFE_Op* op, const std::unordered_set const_inputs( *XlaOpRegistry::CompileTimeConstantInputs(op->operation.Name())); - // First add place holders for the input args, so that we can refer to them by - // position in the next loop. Also tally up the resource inputs. + // First add place holders for the input args, so that we can refer to them + // by position in the next loop. Also tally up the resource inputs. int num_resource_inputs = 0; for (int i = 0; i < op_def.input_arg_size(); ++i) { if (op_def.input_arg(i).type() == DT_RESOURCE) { @@ -336,8 +351,9 @@ std::unique_ptr BuildXlaLaunch(TFE_Op* op, TF_Status* status) { &op_input_to_func_input, status); if (!status.ok()) return nullptr; } else { - // TODO(hongm): XlaOpRegistry::CompileTimeConstantInputs() does not work for - // functions, so we need to find another way to handle constant inputs. + // TODO(hongm): XlaOpRegistry::CompileTimeConstantInputs() does not work + // for functions, so we need to find another way to handle constant + // inputs. for (int i = const_input_types.size(); i < fdef->signature().input_arg_size(); ++i) { VLOG(1) << "Adding Targs from input arg " << i; @@ -348,8 +364,9 @@ std::unique_ptr BuildXlaLaunch(TFE_Op* op, TF_Status* status) { DCHECK(fdef != nullptr); // Copy inputs and their devices. - // Since input param reordering may have occurred between `op` and `launch_op` - // via `op_input_to_func_input`, adjust the actual inputs accordingly. + // Since input param reordering may have occurred between `op` and + // `launch_op` via `op_input_to_func_input`, adjust the actual inputs + // accordingly. *launch_op->operation.MutableInputs() = op->operation.Inputs(); for (TensorHandle* h : launch_op->operation.Inputs()) { h->Ref(); @@ -545,24 +562,24 @@ Status EagerLocalExecute(EagerOperation* op, Status EagerRemoteExecute(EagerOperation* op, eager::EagerClient* eager_client, uint64 context_id, TensorHandle** retvals, int* num_retvals) { - // All tensors must be on the same device. - // TODO(nareshmodi): handle silent copies eager::EnqueueRequest request; eager::EnqueueResponse response; auto* remote_op = request.add_queue()->mutable_operation(); - for (auto* input : op->Inputs()) { + for (int i = 0; i < op->Inputs().size(); i++) { tensorflow::Device* input_device; - TF_RETURN_IF_ERROR(input->Device(&input_device)); + TF_RETURN_IF_ERROR(op->Inputs()[i]->Device(&input_device)); if (op->Device() != input_device) { - return tensorflow::errors::InvalidArgument( - "Ops and inputs are not on the same device. Use " - "TFE_TensorHandleCopyToDevice to get ops on the same " - "device. Expected device: ", - op->Device()->name(), ", Actual device: ", input_device->name()); + // TODO(b/110044833): It's possible the same tensor gets copied to the + // remote device repeatedly. + TF_RETURN_IF_ERROR(MaybeCopyInputToExpectedDevice( + op, i, op->Device(), /* run_metadata= */ nullptr, + &(*op->MutableInputs())[i])); } + tensorflow::TensorHandle* input = op->Inputs()[i]; + tensorflow::uint64 op_id; int32 output_num; TF_RETURN_IF_ERROR(input->RemoteAddress(&op_id, &output_num)); -- GitLab From 8bf62f8530ed395110dad325b076fd923895fcba Mon Sep 17 00:00:00 2001 From: Akshay Modi Date: Mon, 11 Jun 2018 16:27:12 -0700 Subject: [PATCH 026/540] Remove memory leak in read variable call, and record gradient call. Fix #19385 PiperOrigin-RevId: 200132949 --- tensorflow/python/eager/pywrap_tfe_src.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tensorflow/python/eager/pywrap_tfe_src.cc b/tensorflow/python/eager/pywrap_tfe_src.cc index 52b3268903..6c9481c3af 100644 --- a/tensorflow/python/eager/pywrap_tfe_src.cc +++ b/tensorflow/python/eager/pywrap_tfe_src.cc @@ -1873,6 +1873,8 @@ PyObject* RecordGradient(PyObject* op_name, PyObject* inputs, PyObject* attrs, delete backward_function; }); + Py_DECREF(num_inputs); + Py_RETURN_NONE; } @@ -1931,8 +1933,10 @@ bool ReadVariableOp(const FastPathOpExecInfo& parent_op_exec_info, Py_INCREF(output->get()); // stay alive after since tuple steals. PyTuple_SET_ITEM(outputs.get(), 0, output->get()); - if (!RecordGradient(GetPythonObjectFromString("ReadVariableOp"), - inputs.get(), Py_None, outputs.get(), Py_None)) { + tensorflow::Safe_PyObjectPtr op_string( + GetPythonObjectFromString("ReadVariableOp")); + if (!RecordGradient(op_string.get(), inputs.get(), Py_None, outputs.get(), + Py_None)) { return false; } } -- GitLab From 95345968a2445c75eaeaa22659b7e574aafe25a7 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 16:41:25 -0700 Subject: [PATCH 027/540] Correct generator path PiperOrigin-RevId: 200135189 --- tensorflow/contrib/lite/builtin_ops.h | 2 +- tensorflow/contrib/lite/schema/builtin_ops_header/generator.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/lite/builtin_ops.h b/tensorflow/contrib/lite/builtin_ops.h index f3b2ac77fb..aef9a92883 100644 --- a/tensorflow/contrib/lite/builtin_ops.h +++ b/tensorflow/contrib/lite/builtin_ops.h @@ -17,7 +17,7 @@ limitations under the License. #define TENSORFLOW_CONTRIB_LITE_BUILTIN_OPS_H_ // DO NOT EDIT MANUALLY: This file is automatically generated by -// `schema_builtin_ops_header_generator.py`. +// `schema/builtin_ops_header/generator.cc`. #ifdef __cplusplus extern "C" { diff --git a/tensorflow/contrib/lite/schema/builtin_ops_header/generator.cc b/tensorflow/contrib/lite/schema/builtin_ops_header/generator.cc index 64ab0a9fe2..9dc8daa227 100644 --- a/tensorflow/contrib/lite/schema/builtin_ops_header/generator.cc +++ b/tensorflow/contrib/lite/schema/builtin_ops_header/generator.cc @@ -39,7 +39,7 @@ limitations under the License. #define TENSORFLOW_CONTRIB_LITE_BUILTIN_OPS_H_ // DO NOT EDIT MANUALLY: This file is automatically generated by -// `schema_builtin_ops_header_generator.py`. +// `schema/builtin_ops_header/generator.cc`. #ifdef __cplusplus extern "C" { -- GitLab From 734ce1d8e5991c8e7b243b0bab37c074864c0eea Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 16:44:29 -0700 Subject: [PATCH 028/540] Split out HloConstantInstruction and HloTraceInstruction as subclasses from HloInstruction. PiperOrigin-RevId: 200135616 --- tensorflow/compiler/xla/service/BUILD | 1 + .../compiler/xla/service/hlo_graph_dumper.cc | 20 +-- .../compiler/xla/service/hlo_instruction.cc | 141 +++++------------- .../compiler/xla/service/hlo_instruction.h | 40 ++--- .../compiler/xla/service/hlo_instructions.cc | 102 +++++++++++++ .../compiler/xla/service/hlo_instructions.h | 56 +++++++ 6 files changed, 224 insertions(+), 136 deletions(-) diff --git a/tensorflow/compiler/xla/service/BUILD b/tensorflow/compiler/xla/service/BUILD index 6f34703fec..6801012cc9 100644 --- a/tensorflow/compiler/xla/service/BUILD +++ b/tensorflow/compiler/xla/service/BUILD @@ -2574,6 +2574,7 @@ cc_library( hdrs = ["hlo_graph_dumper.h"], deps = [ ":hlo", + ":hlo_casting_utils", ":hlo_execution_profile", ":hlo_tfgraph_builder", "//tensorflow/compiler/xla:literal_util", diff --git a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc index 05aab9a2cd..28fc6c4209 100644 --- a/tensorflow/compiler/xla/service/hlo_graph_dumper.cc +++ b/tensorflow/compiler/xla/service/hlo_graph_dumper.cc @@ -28,6 +28,8 @@ limitations under the License. #include "tensorflow/compiler/xla/layout_util.h" #include "tensorflow/compiler/xla/literal_util.h" +#include "tensorflow/compiler/xla/service/hlo_casting_utils.h" +#include "tensorflow/compiler/xla/service/hlo_instructions.h" #include "tensorflow/compiler/xla/service/hlo_module.h" #include "tensorflow/compiler/xla/service/hlo_tfgraph_builder.h" #include "tensorflow/compiler/xla/shape_util.h" @@ -723,17 +725,14 @@ string HloDotDumper::DumpRootTag() { to_id, node_body, node_shape, NodeColorAttributes(color)); } -static const HloInstruction* TryGetFusionParameterConstant( +static const HloConstantInstruction* TryGetFusionParameterConstant( const HloInstruction* instr) { if (instr->opcode() != HloOpcode::kParameter || !instr->IsFused()) { return nullptr; } const HloInstruction* fusion = instr->parent()->FusionInstruction(); const HloInstruction* operand = fusion->operand(instr->parameter_number()); - if (operand->opcode() == HloOpcode::kConstant) { - return operand; - } - return nullptr; + return DynCast(operand); } bool HloDotDumper::ShouldMergeIntoUsers(const HloInstruction* instr) const { @@ -826,7 +825,7 @@ string HloDotDumper::DumpInstruction(const HloInstruction* instr) { string HloDotDumper::GetInstructionNodeInlinedOperands( const HloInstruction* instr) { - auto stringify_constant = [](const HloInstruction* constant) { + auto stringify_constant = [](const HloConstantInstruction* constant) { const auto& shape = constant->shape(); // If the shape has a dimension of size zero, print it as e.g. @@ -845,7 +844,7 @@ string HloDotDumper::GetInstructionNodeInlinedOperands( *elem_count *= dim; } } - if (elem_count.has_value() && *elem_count <= 8 && constant->HasLiteral()) { + if (elem_count.has_value() && *elem_count <= 8) { return Printf("%s (%s)", constant->literal().ToString(), ShapeUtil::HumanString(constant->shape())); } @@ -864,9 +863,10 @@ string HloDotDumper::GetInstructionNodeInlinedOperands( std::vector lines; for (int64 i = 0; i < instr->operand_count(); ++i) { const HloInstruction* operand = instr->operand(i); + const auto* constant_operand = DynCast(operand); optional operand_str; - if (operand->opcode() == HloOpcode::kConstant) { - operand_str = stringify_constant(operand); + if (constant_operand != nullptr) { + operand_str = stringify_constant(constant_operand); } else if (ShouldMergeIntoUsers(operand)) { // Special case: If the operand is a parameter to a fusion node and it // always has a constant value, display it like a regular constant. @@ -874,7 +874,7 @@ string HloDotDumper::GetInstructionNodeInlinedOperands( // For other parameters, use the parameter number rather than the proper // name, because that's generally how people think of the node. if (operand->opcode() == HloOpcode::kParameter) { - if (const HloInstruction* constant = + if (const HloConstantInstruction* constant = TryGetFusionParameterConstant(operand)) { operand_str = stringify_constant(constant); } else { diff --git a/tensorflow/compiler/xla/service/hlo_instruction.cc b/tensorflow/compiler/xla/service/hlo_instruction.cc index c89d836888..9e9bf6361d 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.cc +++ b/tensorflow/compiler/xla/service/hlo_instruction.cc @@ -178,6 +178,23 @@ StatusOr> HloInstruction::CreateFromProto( slice_limits, slice_strides); break; } + case HloOpcode::kConstant: { + CHECK(proto.has_literal()); + TF_ASSIGN_OR_RETURN(auto literal, + Literal::CreateFromProto(proto.literal())); + instruction = CreateConstant(std::move(literal)); + break; + } + case HloOpcode::kTrace: { + TF_RET_CHECK(proto.operand_ids_size() == 1) + << "Trace instruction should have 1 operand but sees " + << proto.operand_ids_size(); + CHECK(proto.has_literal()); + TF_ASSIGN_OR_RETURN(auto literal, + Literal::CreateFromProto(proto.literal())); + instruction = CreateTrace(literal->GetR1U8AsString(), operands(0)); + break; + } default: { instruction = WrapUnique(new HloInstruction(opcode, proto.shape())); for (const int64 operand_id : proto.operand_ids()) { @@ -223,22 +240,11 @@ StatusOr> HloInstruction::CreateFromProto( instruction->called_computations_.push_back(fused_computation); } - if (instruction->opcode() == HloOpcode::kTrace) { - TF_RET_CHECK(instruction->operands().size() == 1) - << "Trace instruction should have 1 operand but sees " - << instruction->operands().size(); - instruction->mutable_operand(0)->set_tracing(instruction.get()); - } - TF_RET_CHECK(!proto.name().empty()); instruction->SetAndSanitizeName(proto.name()); instruction->metadata_ = proto.metadata(); instruction->backend_config_ = proto.backend_config(); - if (proto.has_literal()) { - TF_ASSIGN_OR_RETURN(instruction->literal_, - Literal::CreateFromProto(proto.literal())); - } instruction->parameter_number_ = proto.parameter_number(); instruction->tuple_index_ = proto.tuple_index(); @@ -301,20 +307,12 @@ StatusOr> HloInstruction::CreateFromProto( /* static */ std::unique_ptr HloInstruction::CreateTrace( const string& tag, HloInstruction* operand) { - auto instruction = - WrapUnique(new HloInstruction(HloOpcode::kTrace, ShapeUtil::MakeNil())); - instruction->operands_.push_back(operand); - instruction->literal_ = Literal::CreateR1U8(tag); - operand->set_tracing(instruction.get()); - return instruction; + return MakeUnique(tag, operand); } /* static */ std::unique_ptr HloInstruction::CreateConstant( std::unique_ptr literal) { - auto instruction = - WrapUnique(new HloInstruction(HloOpcode::kConstant, literal->shape())); - instruction->literal_ = std::move(literal); - return instruction; + return MakeUnique(std::move(literal)); } /* static */ std::unique_ptr @@ -1321,6 +1319,8 @@ std::unique_ptr HloInstruction::CloneWithNewOperands( case HloOpcode::kBroadcast: case HloOpcode::kMap: case HloOpcode::kSlice: + case HloOpcode::kConstant: + case HloOpcode::kTrace: clone = CloneWithNewOperandsImpl(shape, new_operands, context); break; // Unary ops. @@ -1470,9 +1470,6 @@ std::unique_ptr HloInstruction::CloneWithNewOperands( clone = CreateWhile(shape, while_condition(), while_body(), new_operands[0]); break; - case HloOpcode::kConstant: - clone = CreateConstant(literal_->CloneToUnique()); - break; case HloOpcode::kFusion: { HloModule* module = context != nullptr ? context->module() : GetModule(); HloComputation* new_fused_computation = nullptr; @@ -1520,8 +1517,6 @@ std::unique_ptr HloInstruction::CloneWithNewOperands( case HloOpcode::kGenerateToken: clone = CreateGenerateToken(new_operands); break; - case HloOpcode::kTrace: - LOG(FATAL) << "Not yet implemented, clone: " << HloOpcodeString(opcode_); } SetupDerivedInstruction(clone.get()); clone->set_parent(parent_); @@ -1602,13 +1597,6 @@ const HloInstruction* HloInstruction::LatestNonGteAncestor() const { return hlo; } -const Literal& HloInstruction::literal() const { - CHECK_EQ(HloOpcode::kConstant, opcode_); - return *literal_; -} - -bool HloInstruction::HasLiteral() const { return literal_ != nullptr; } - int64 HloInstruction::tuple_index() const { CHECK_EQ(HloOpcode::kGetTupleElement, opcode_); return tuple_index_; @@ -1702,10 +1690,6 @@ void HloInstruction::AddUser(HloInstruction* user) { } } -bool HloInstruction::IsConstant() const { - return opcode_ == HloOpcode::kConstant; -} - bool HloInstruction::HasConstantOperand() const { for (const HloInstruction* operand : operands_) { if (operand->IsConstant()) { @@ -1782,7 +1766,6 @@ bool HloInstruction::IdenticalSlowPath( // These opcodes have complex or special behavior so just return false. case HloOpcode::kDomain: case HloOpcode::kRng: - case HloOpcode::kTrace: case HloOpcode::kWhile: case HloOpcode::kGenerateToken: return false; @@ -1790,10 +1773,6 @@ bool HloInstruction::IdenticalSlowPath( case HloOpcode::kParameter: return parameter_number() == other.parameter_number(); - // A constant is defined by the value in the literal. - case HloOpcode::kConstant: - return literal() == other.literal(); - // A reduce-precision operation is determined by the bit sizes. case HloOpcode::kReducePrecision: return exponent_bits() == other.exponent_bits() && @@ -1878,6 +1857,8 @@ bool HloInstruction::IdenticalSlowPath( case HloOpcode::kBroadcast: case HloOpcode::kMap: case HloOpcode::kSlice: + case HloOpcode::kConstant: + case HloOpcode::kTrace: LOG(FATAL) << "Base class impl called for opcode with subclass: " << opcode(); } @@ -2172,34 +2153,7 @@ string HloInstruction::OperandsToStringWithCanonicalNameMap( const HloPrintOptions& options, CanonicalNameMap* canonical_name_map) const { string operands; - if (opcode() == HloOpcode::kConstant) { - // For constants, show the actual value in place of an empty operand list. - // - // In HloInstruction, sometimes a constant literal is not constructed due - // to its size. Skip the printing in this case. - if (HasLiteral() && ((!ShapeUtil::IsTuple(shape()) && - ShapeUtil::ElementsIn(shape()) <= 10) || - options.print_large_constants())) { - // Literal::ToString emits multidimensional arrays over multiple - // lines. Compact this into one line by stripping out white space. - string tmp = literal().ToString(); - std::replace(tmp.begin(), tmp.end(), '\n', ' '); - std::vector v = tensorflow::str_util::Split(tmp, ' '); - bool first = true; - // Concatenate elements in "v" with spaces separating them, but ignoring - // empty entries. - for (const auto& s : v) { - if (s.empty()) { - continue; - } - StrAppend(&operands, (first ? "" : " "), s); - first = false; - } - } else { - // Do not show large constants or tuples. - operands = "{...}"; - } - } else if (opcode() == HloOpcode::kParameter) { + if (opcode() == HloOpcode::kParameter) { StrAppend(&operands, parameter_number_); } else { tensorflow::gtl::ArraySlice slice(operands_); @@ -2410,9 +2364,6 @@ HloInstructionProto HloInstruction::ToProto() const { *proto.mutable_metadata() = metadata_; proto.set_backend_config(backend_config_); - if (literal_ != nullptr) { - *proto.mutable_literal() = literal_->ToProto(); - } proto.set_parameter_number(parameter_number_); if (opcode() == HloOpcode::kFusion) { proto.set_fusion_kind(xla::ToString(fusion_kind())); @@ -2518,12 +2469,6 @@ void HloInstruction::set_tracing(HloInstruction* trace_instruction) { trace_instruction_ = trace_instruction; } -string HloInstruction::TracingTag() const { - CHECK_EQ(HloOpcode::kTrace, opcode()); - CHECK(literal_ != nullptr); - return literal_->GetR1U8AsString(); -} - bool HloInstruction::IsFused() const { return parent_->IsFusionComputation(); } bool HloInstruction::IsFusable() const { @@ -3035,10 +2980,6 @@ bool HloInstruction::IsElementwiseBinary() const { bool HloInstruction::IsElementwise() const { switch (opcode_) { - // Nullary elementwise operations. - case HloOpcode::kConstant: - return true; - // Unary elementwise operations. case HloOpcode::kAbs: case HloOpcode::kRoundNearestAfz: @@ -3500,23 +3441,6 @@ void HloInstruction::set_outer_dimension_partitions( outer_dimension_partitions_ = outer_dimension_partitions; } -void HloInstruction::RelayoutConstant(const Layout& new_layout, - const ShapeIndex& shape_index) { - CHECK_EQ(opcode(), HloOpcode::kConstant); - Shape* mutable_array_subshape = - ShapeUtil::GetMutableSubshape(mutable_shape(), shape_index); - CHECK(ShapeUtil::IsArray(*mutable_array_subshape)); - - // Normally array_subshape will always have a layout, but this invariant is - // temporarily broken in LayoutAssignment::AssignLayouts. - - if (!mutable_array_subshape->has_layout() || - !LayoutUtil::Equal(mutable_array_subshape->layout(), new_layout)) { - literal_ = literal_->Relayout(new_layout, shape_index); - *mutable_array_subshape->mutable_layout() = new_layout; - } -} - // TODO(b/80131774): Remove these temporary methods after transition. int64 HloInstruction::feature_index() const { return Cast(this)->feature_index(); @@ -3574,4 +3498,21 @@ const std::vector& HloInstruction::slice_strides() const { bool HloInstruction::IsInPlaceSlice() const { return Cast(this)->IsInPlaceSlice(); } + +const Literal& HloInstruction::literal() const { + return Cast(this)->literal(); +} + +bool HloInstruction::IsConstant() const { + return DynCast(this) != nullptr; +} + +void HloInstruction::RelayoutConstant(const Layout& new_layout, + const ShapeIndex& shape_index) { + Cast(this)->RelayoutConstant(new_layout, shape_index); +} + +string HloInstruction::TracingTag() const { + return Cast(this)->TracingTag(); +} } // namespace xla diff --git a/tensorflow/compiler/xla/service/hlo_instruction.h b/tensorflow/compiler/xla/service/hlo_instruction.h index ae1c563b56..05662ef01b 100644 --- a/tensorflow/compiler/xla/service/hlo_instruction.h +++ b/tensorflow/compiler/xla/service/hlo_instruction.h @@ -875,14 +875,6 @@ class HloInstruction { template Status Visit(DfsHloVisitorBase* visitor); - // Returns the literal associated with this instruction. - // - // Note: only constant and parameter opcodes have an associated literal. - const Literal& literal() const; - - // Returns whether there is literal associated with this instruction. - bool HasLiteral() const; - // Returns the parameter number associated with this instruction. // // Note: only parameter opcodes have an associated parameter number. @@ -1014,14 +1006,6 @@ class HloInstruction { string infeed_config() const { return infeed_config_; } void set_infeed_config(const string& config) { infeed_config_ = config; } - // Returns a tag to be used in tracing. - // - // Precondition: opcode() == HloOpcode::kTrace - string TracingTag() const; - - // Returns whether the instruction is a constant. - bool IsConstant() const; - // Returns true if this instruction is fused, ie contained within a fusion // instruction. bool IsFused() const; @@ -1452,12 +1436,6 @@ class HloInstruction { void set_outer_dimension_partitions( const std::vector& outer_dimension_partitions); - // Change the layout for an Constant Hlo instruction to match new_layout. For - // tuple shaped constants shape_index is the path to the internal array - // subshape whose layout needs to be changed. - void RelayoutConstant(const Layout& new_layout, - const ShapeIndex& shape_index = {}); - // Old methods kept for smooth subclassing transition BEGIN. // TODO(b/80131774): Remove this code. @@ -1504,6 +1482,19 @@ class HloInstruction { // Delegates to HloSliceInstruction::IsInPlaceSlice. bool IsInPlaceSlice() const; + + // Returns the literal associated with this instruction. + const Literal& literal() const; + + // Returns whether the instruction is a constant. + bool IsConstant() const; + + // Delegate to HloConstantInstruction::RelayoutConstant. + void RelayoutConstant(const Layout& new_layout, + const ShapeIndex& shape_index = {}); + + // Delegates to HloTraceInstruction::TracingTag. + string TracingTag() const; // Old methods kept for smooth subclassing transition END. protected: @@ -1544,7 +1535,7 @@ class HloInstruction { CanonicalNameMap* canonical_name_map) const; // Prints an operand to a string. - string OperandsToStringWithCanonicalNameMap( + virtual string OperandsToStringWithCanonicalNameMap( const HloPrintOptions& options, CanonicalNameMap* canonical_name_map) const; @@ -1639,9 +1630,6 @@ class HloInstruction { // Result shape of this instruction. Shape shape_; - // Literal, only present for kConstant. - std::unique_ptr literal_; - // Constant index, only present for kGetTupleElement. int64 tuple_index_ = -1; diff --git a/tensorflow/compiler/xla/service/hlo_instructions.cc b/tensorflow/compiler/xla/service/hlo_instructions.cc index 56792f8b1b..1815bf1b16 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.cc +++ b/tensorflow/compiler/xla/service/hlo_instructions.cc @@ -20,6 +20,7 @@ limitations under the License. namespace xla { using ::tensorflow::str_util::Join; +using ::tensorflow::strings::StrAppend; using ::tensorflow::strings::StrCat; HloBatchNormInstruction::HloBatchNormInstruction( @@ -586,4 +587,105 @@ std::unique_ptr HloSliceInstruction::CloneWithNewOperandsImpl( return MakeUnique(shape, new_operands[0], slice_starts_, slice_limits_, slice_strides_); } + +HloConstantInstruction::HloConstantInstruction(std::unique_ptr literal) + : HloInstruction(HloOpcode::kConstant, CHECK_NOTNULL(literal)->shape()), + literal_(std::move(literal)) {} + +HloInstructionProto HloConstantInstruction::ToProto() const { + HloInstructionProto proto = HloInstruction::ToProto(); + *proto.mutable_literal() = literal_->ToProto(); + return proto; +} + +bool HloConstantInstruction::IsElementwise() const { return true; } + +void HloConstantInstruction::RelayoutConstant(const Layout& new_layout, + const ShapeIndex& shape_index) { + Shape* mutable_array_subshape = + ShapeUtil::GetMutableSubshape(mutable_shape(), shape_index); + CHECK(ShapeUtil::IsArray(*mutable_array_subshape)); + + // Normally array_subshape will always have a layout, but this invariant is + // temporarily broken in LayoutAssignment::AssignLayouts. + + if (!mutable_array_subshape->has_layout() || + !LayoutUtil::Equal(mutable_array_subshape->layout(), new_layout)) { + literal_ = literal_->Relayout(new_layout, shape_index); + *mutable_array_subshape->mutable_layout() = new_layout; + } +} + +bool HloConstantInstruction::IdenticalSlowPath( + const HloInstruction& other, + const std::function& + eq_computations) const { + const auto& other_slice = static_cast(other); + return literal() == other_slice.literal(); +} + +std::unique_ptr +HloConstantInstruction::CloneWithNewOperandsImpl( + const Shape& shape, + tensorflow::gtl::ArraySlice new_operands, + HloCloneContext* context) const { + return MakeUnique(literal_->CloneToUnique()); +} + +string HloConstantInstruction::OperandsToStringWithCanonicalNameMap( + const HloPrintOptions& options, + CanonicalNameMap* canonical_name_map) const { + string operands; + // For constants, show the actual value in place of an empty operand list. + if ((!ShapeUtil::IsTuple(shape()) && ShapeUtil::ElementsIn(shape()) <= 10) || + options.print_large_constants()) { + // Literal::ToString emits multidimensional arrays over multiple + // lines. Compact this into one line by stripping out white space. + string tmp = literal().ToString(); + std::replace(tmp.begin(), tmp.end(), '\n', ' '); + std::vector v = tensorflow::str_util::Split(tmp, ' '); + bool first = true; + // Concatenate elements in "v" with spaces separating them, but ignoring + // empty entries. + for (const auto& s : v) { + if (s.empty()) { + continue; + } + StrAppend(&operands, (first ? "" : " "), s); + first = false; + } + } else { + // Do not show large constants or tuples. + operands = "{...}"; + } + return operands; +} + +HloTraceInstruction::HloTraceInstruction(const string& tag, + HloInstruction* operand) + : HloInstruction(HloOpcode::kTrace, ShapeUtil::MakeNil()), + literal_(Literal::CreateR1U8(tag)) { + AppendOperand(operand); + operand->set_tracing(this); +} + +HloInstructionProto HloTraceInstruction::ToProto() const { + HloInstructionProto proto = HloInstruction::ToProto(); + *proto.mutable_literal() = literal_->ToProto(); + return proto; +} + +bool HloTraceInstruction::IdenticalSlowPath( + const HloInstruction& other, + const std::function& + eq_computations) const { + return false; +} + +std::unique_ptr HloTraceInstruction::CloneWithNewOperandsImpl( + const Shape& shape, + tensorflow::gtl::ArraySlice new_operands, + HloCloneContext* context) const { + LOG(FATAL) << "Not yet implemented, clone: " << HloOpcodeString(opcode()); +} } // namespace xla diff --git a/tensorflow/compiler/xla/service/hlo_instructions.h b/tensorflow/compiler/xla/service/hlo_instructions.h index 18e786d8b6..ecd4a31912 100644 --- a/tensorflow/compiler/xla/service/hlo_instructions.h +++ b/tensorflow/compiler/xla/service/hlo_instructions.h @@ -433,6 +433,62 @@ class HloSliceInstruction : public HloInstruction { // Describes whether the slice can be lowered to an offset into the operand. bool is_in_place_slice_ = false; }; + +class HloConstantInstruction : public HloInstruction { + public: + explicit HloConstantInstruction(std::unique_ptr literal); + // Returns the literal associated with this instruction. + const Literal& literal() const { return *literal_; } + // Returns a serialized representation of this instruction. + HloInstructionProto ToProto() const override; + // Returns true if this instruction is elementwise on all its operands. + bool IsElementwise() const override; + + // Change the layout for an Constant Hlo instruction to match new_layout. For + // tuple shaped constants shape_index is the path to the internal array + // subshape whose layout needs to be changed. + void RelayoutConstant(const Layout& new_layout, + const ShapeIndex& shape_index = {}); + + private: + bool IdenticalSlowPath( + const HloInstruction& other, + const std::function& + eq_computations) const override; + string OperandsToStringWithCanonicalNameMap( + const HloPrintOptions& options, + CanonicalNameMap* canonical_name_map) const override; + // Implementation for non-common logic of CloneWithNewOperands. + std::unique_ptr CloneWithNewOperandsImpl( + const Shape& shape, + tensorflow::gtl::ArraySlice new_operands, + HloCloneContext* context) const override; + // TODO(b/36360764): Remove unique_ptr wrapping. + std::unique_ptr literal_; +}; + +class HloTraceInstruction : public HloInstruction { + public: + explicit HloTraceInstruction(const string& tag, HloInstruction* operand); + // Returns a tag to be used in tracing. + string TracingTag() const { return literal_->GetR1U8AsString(); } + // Returns a serialized representation of this instruction. + HloInstructionProto ToProto() const override; + + private: + bool IdenticalSlowPath( + const HloInstruction& other, + const std::function& + eq_computations) const override; + // Implementation for non-common logic of CloneWithNewOperands. + std::unique_ptr CloneWithNewOperandsImpl( + const Shape& shape, + tensorflow::gtl::ArraySlice new_operands, + HloCloneContext* context) const override; + // TODO(b/36360764): Remove unique_ptr wrapping. + std::unique_ptr literal_; +}; + } // namespace xla #endif // TENSORFLOW_COMPILER_XLA_SERVICE_HLO_INSTRUCTIONS_H_ -- GitLab From 4f912021b04f5f82b0d1a6bba5b32a24d7cb9fca Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 16:53:28 -0700 Subject: [PATCH 029/540] Add support for 8bit ResizeBilinear and Slice op to tflite and toco PiperOrigin-RevId: 200136934 --- .../contrib/lite/kernels/internal/BUILD | 5 +- .../internal/optimized/optimized_ops.h | 84 +++++++ .../internal/reference/reference_ops.h | 37 ++- ..._float_test.cc => resize_bilinear_test.cc} | 60 ++++- .../contrib/lite/kernels/resize_bilinear.cc | 23 +- .../lite/kernels/resize_bilinear_test.cc | 235 ++++++++++++++---- .../graph_transformations/hardcode_min_max.cc | 2 + .../toco/graph_transformations/quantize.cc | 3 +- 8 files changed, 358 insertions(+), 91 deletions(-) rename tensorflow/contrib/lite/kernels/internal/{resize_bilinear_float_test.cc => resize_bilinear_test.cc} (60%) diff --git a/tensorflow/contrib/lite/kernels/internal/BUILD b/tensorflow/contrib/lite/kernels/internal/BUILD index 0a5223b235..75298b995d 100644 --- a/tensorflow/contrib/lite/kernels/internal/BUILD +++ b/tensorflow/contrib/lite/kernels/internal/BUILD @@ -474,8 +474,9 @@ cc_test( ) cc_test( - name = "resize_bilinear_float_test", - srcs = ["resize_bilinear_float_test.cc"], + name = "resize_bilinear_test", + srcs = ["resize_bilinear_test.cc"], + tags = ["tflite_not_portable"], deps = [ ":optimized_base", ":reference_base", diff --git a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h index d2bee2cd70..8115a072d5 100644 --- a/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h @@ -5722,6 +5722,46 @@ inline void ResizeBilinearGeneric(const float* input_data, } } +template +inline void ResizeBilinearGenericSmallChannel( + const T* input_data, const Dims<4>& input_dims, T* output_data, + const Dims<4>& output_dims, int32 batches, int32 input_height, + int32 input_width, int32 depth, int32 output_height, int32 output_width, + float height_scale, float width_scale) { + memset(output_data, 0, + batches * output_height * output_width * depth * sizeof(T)); + + T* output_ptr = &output_data[0]; + for (int b = 0; b < batches; ++b) { + for (int y = 0; y < output_height; ++y) { + float input_y = y * height_scale; + int32 y0 = static_cast(std::floor(input_y)); + int32 y1 = std::min(y0 + 1, input_height - 1); + for (int x = 0; x < output_width; ++x) { + float input_x = x * width_scale; + int32 x0 = static_cast(input_x); + int32 x1 = std::min(x0 + 1, input_width - 1); + + int32 input_offset[4] = { + Offset(input_dims, 0, x0, y0, b), Offset(input_dims, 0, x1, y0, b), + Offset(input_dims, 0, x0, y1, b), Offset(input_dims, 0, x1, y1, b)}; + float scale[4] = {(1 - (input_y - y0)) * (1 - (input_x - x0)), + (1 - (input_y - y0)) * (input_x - x0), + (input_y - y0) * (1 - (input_x - x0)), + (input_y - y0) * (input_x - x0)}; + + for (int d = 0; d < depth; d++) { + const T* input_ptr = &input_data[d]; + *output_ptr++ = static_cast(input_ptr[input_offset[0]] * scale[0] + + input_ptr[input_offset[1]] * scale[1] + + input_ptr[input_offset[2]] * scale[2] + + input_ptr[input_offset[3]] * scale[3]); + } + } + } + } +} + inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, const int32* output_size_data, const Dims<4>& output_size_dims, float* output_data, @@ -5762,6 +5802,41 @@ inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, } } +// TODO(prabhumk): This is not a real quantized bilinear. It does not use int8 +// or int16 arithmetic. +inline void ResizeBilinear(const uint8* input_data, const Dims<4>& input_dims, + const int32* output_size_data, + const Dims<4>& output_size_dims, uint8* output_data, + const Dims<4>& output_dims, bool align_corners) { + gemmlowp::ScopedProfilingLabel label("ResizeBilinear"); + int32 batches = MatchingArraySize(input_dims, 3, output_dims, 3); + int32 input_height = ArraySize(input_dims, 2); + int32 input_width = ArraySize(input_dims, 1); + int32 depth = MatchingArraySize(input_dims, 0, output_dims, 0); + + TFLITE_DCHECK_EQ(ArraySize(output_size_dims, 3), 1); + TFLITE_DCHECK_EQ(ArraySize(output_size_dims, 2), 1); + TFLITE_DCHECK_EQ(ArraySize(output_size_dims, 1), 1); + TFLITE_DCHECK_EQ(ArraySize(output_size_dims, 0), 2); + int32 output_height = output_size_data[Offset(output_size_dims, 0, 0, 0, 0)]; + int32 output_width = output_size_data[Offset(output_size_dims, 1, 0, 0, 0)]; + + float height_scale = + (align_corners && output_height > 1) + ? (static_cast(input_height - 1) / (output_height - 1)) + : (static_cast(input_height) / output_height); + + float width_scale = + (align_corners && output_width > 1) + ? (static_cast(input_width - 1) / (output_width - 1)) + : (static_cast(input_width) / output_width); + + ResizeBilinearGenericSmallChannel( + input_data, input_dims, output_data, output_dims, batches, input_height, + input_width, depth, output_height, output_width, height_scale, + width_scale); +} + // legacy, for compatibility with old checked-in code inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, const int32* output_size_data, @@ -5771,6 +5846,15 @@ inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, output_data, output_dims, /*align_corners=*/false); } +// legacy, for compatibility with old checked-in code +inline void ResizeBilinear(const uint8* input_data, const Dims<4>& input_dims, + const int32* output_size_data, + const Dims<4>& output_size_dims, uint8* output_data, + const Dims<4>& output_dims) { + ResizeBilinear(input_data, input_dims, output_size_data, output_size_dims, + output_data, output_dims, /*align_corners=*/false); +} + template inline void SpaceToBatchND(const T* input_data, const Dims<4>& input_dims, const int32* block_shape_data, diff --git a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h index c3f645bdf1..9a3dae5cde 100644 --- a/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h @@ -3202,9 +3202,10 @@ inline void Gather(const T* input_data, const Dims<4>& input_dims, } } -inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, +template +inline void ResizeBilinear(const T* input_data, const Dims<4>& input_dims, const int32* output_size_data, - const Dims<4>& output_size_dims, float* output_data, + const Dims<4>& output_size_dims, T* output_data, const Dims<4>& output_dims, bool align_corners) { int32 batches = MatchingArraySize(input_dims, 3, output_dims, 3); int32 input_height = ArraySize(input_dims, 2); @@ -3236,15 +3237,15 @@ inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, int32 x0 = static_cast(std::floor(input_x)); int32 x1 = std::min(x0 + 1, input_width - 1); for (int c = 0; c < depth; ++c) { - float interpolation = input_data[Offset(input_dims, c, x0, y0, b)] * - (1 - (input_y - y0)) * - (1 - (input_x - x0)) + - input_data[Offset(input_dims, c, x0, y1, b)] * - (input_y - y0) * (1 - (input_x - x0)) + - input_data[Offset(input_dims, c, x1, y0, b)] * - (1 - (input_y - y0)) * (input_x - x0) + - input_data[Offset(input_dims, c, x1, y1, b)] * - (input_y - y0) * (input_x - x0); + T interpolation = + static_cast(input_data[Offset(input_dims, c, x0, y0, b)] * + (1 - (input_y - y0)) * (1 - (input_x - x0)) + + input_data[Offset(input_dims, c, x0, y1, b)] * + (input_y - y0) * (1 - (input_x - x0)) + + input_data[Offset(input_dims, c, x1, y0, b)] * + (1 - (input_y - y0)) * (input_x - x0) + + input_data[Offset(input_dims, c, x1, y1, b)] * + (input_y - y0) * (input_x - x0)); output_data[Offset(output_dims, c, x, y, b)] = interpolation; } } @@ -3257,8 +3258,18 @@ inline void ResizeBilinear(const float* input_data, const Dims<4>& input_dims, const int32* output_size_data, const Dims<4>& output_size_dims, float* output_data, const Dims<4>& output_dims) { - ResizeBilinear(input_data, input_dims, output_size_data, output_size_dims, - output_data, output_dims, /*align_corners=*/false); + ResizeBilinear(input_data, input_dims, output_size_data, + output_size_dims, output_data, output_dims, + /*align_corners=*/false); +} + +inline void ResizeBilinear(const uint8* input_data, const Dims<4>& input_dims, + const int32* output_size_data, + const Dims<4>& output_size_dims, uint8* output_data, + const Dims<4>& output_dims) { + ResizeBilinear(input_data, input_dims, output_size_data, + output_size_dims, output_data, output_dims, + /*align_corners=*/false); } template diff --git a/tensorflow/contrib/lite/kernels/internal/resize_bilinear_float_test.cc b/tensorflow/contrib/lite/kernels/internal/resize_bilinear_test.cc similarity index 60% rename from tensorflow/contrib/lite/kernels/internal/resize_bilinear_float_test.cc rename to tensorflow/contrib/lite/kernels/internal/resize_bilinear_test.cc index c1c50dff4d..3d8765f11b 100644 --- a/tensorflow/contrib/lite/kernels/internal/resize_bilinear_float_test.cc +++ b/tensorflow/contrib/lite/kernels/internal/resize_bilinear_test.cc @@ -24,9 +24,10 @@ limitations under the License. namespace tflite { namespace { +template void TestOneResizeBilinear(int batch, int depth, int input_width, int input_height, int output_width, - int output_height) { + int output_height, float error_threshold) { Dims<4> input_dims_inference = MakeDimsForInference(depth, input_width, input_height, batch); Dims<4> output_dims_inference = @@ -36,14 +37,15 @@ void TestOneResizeBilinear(int batch, int depth, int input_width, const int output_buffer_size = RequiredBufferSizeForDims(output_dims_inference); - std::vector input_data(input_buffer_size, 0); - std::vector reference_output_data(output_buffer_size, 0); + std::vector input_data(input_buffer_size, 0); + std::vector reference_output_data(output_buffer_size, 0); // Initialize the output data with something other than zero, so we can catch // issue with kernels failing to initialize the output. - std::vector output_data(output_buffer_size, 3.1415); + std::vector output_data(output_buffer_size, 3); - const float input_amplitude = 1.f; - FillRandom(&input_data, -input_amplitude, input_amplitude); + const T min_amplitude = static_cast(0); + const T max_amplitude = static_cast(255); + FillRandom(&input_data, min_amplitude, max_amplitude); Dims<4> output_size_dims = MakeDimsForInference(2, 1, 1, 1); std::vector output_size_data = {output_height, output_width}; @@ -58,14 +60,46 @@ void TestOneResizeBilinear(int batch, int depth, int input_width, double sum_diff = 0; float max_abs_val = 0; for (int i = 0; i < output_buffer_size; i++) { - sum_diff += std::abs(output_data[i] - reference_output_data[i]); - max_abs_val = std::max(max_abs_val, std::abs(reference_output_data[i])); + sum_diff += std::abs(static_cast(output_data[i]) - + static_cast(reference_output_data[i])); + max_abs_val = std::max( + max_abs_val, std::abs(static_cast(reference_output_data[i]))); } if (sum_diff != 0.f) { const float mean_diff = static_cast(sum_diff / output_buffer_size); const float relative_error = std::abs(mean_diff) / max_abs_val; - ASSERT_LT(relative_error, 1e-5f); + ASSERT_LT(relative_error, error_threshold); + } +} + +TEST(ResizeBilinear, TestResizeBilinear8Bit) { + const int kTestsToRun = 100 * 1000; + for (int i = 0; i < kTestsToRun; i++) { + const int batch = ExponentialRandomPositiveInt(0.9f, 3, 20); + const int depth = ExponentialRandomPositiveInt(0.9f, 6, 50); + const int input_width = ExponentialRandomPositiveInt(0.9f, 20, 200); + const int input_height = ExponentialRandomPositiveInt(0.9f, 20, 200); + const int output_width = ExponentialRandomPositiveInt(0.9f, 20, 200); + const int output_height = ExponentialRandomPositiveInt(0.9f, 20, 200); + + TestOneResizeBilinear(batch, depth, input_width, input_height, + output_width, output_height, 0.025); + } +} + +TEST(ResizeBilinear2x2, TestResizeBilinear8Bit) { + const int kTestsToRun = 100 * 1000; + for (int i = 0; i < kTestsToRun; i++) { + const int batch = ExponentialRandomPositiveInt(0.9f, 3, 20); + const int depth = ExponentialRandomPositiveInt(0.9f, 6, 50); + const int input_width = ExponentialRandomPositiveInt(0.9f, 20, 200); + const int input_height = ExponentialRandomPositiveInt(0.9f, 20, 200); + const int output_width = input_width * 2; + const int output_height = input_height * 2; + + TestOneResizeBilinear(batch, depth, input_width, input_height, + output_width, output_height, 1e-5); } } @@ -79,8 +113,8 @@ TEST(ResizeBilinear, TestResizeBilinear) { const int output_width = ExponentialRandomPositiveInt(0.9f, 20, 200); const int output_height = ExponentialRandomPositiveInt(0.9f, 20, 200); - TestOneResizeBilinear(batch, depth, input_width, input_height, output_width, - output_height); + TestOneResizeBilinear(batch, depth, input_width, input_height, + output_width, output_height, 1e-5); } } @@ -94,8 +128,8 @@ TEST(ResizeBilinear2x2, TestResizeBilinear) { const int output_width = input_width * 2; const int output_height = input_height * 2; - TestOneResizeBilinear(batch, depth, input_width, input_height, output_width, - output_height); + TestOneResizeBilinear(batch, depth, input_width, input_height, + output_width, output_height, 1e-5); } } } // namespace diff --git a/tensorflow/contrib/lite/kernels/resize_bilinear.cc b/tensorflow/contrib/lite/kernels/resize_bilinear.cc index f2092eaa36..86c4cd3ee8 100644 --- a/tensorflow/contrib/lite/kernels/resize_bilinear.cc +++ b/tensorflow/contrib/lite/kernels/resize_bilinear.cc @@ -61,12 +61,10 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); TF_LITE_ENSURE_EQ(context, NumDimensions(size), 1); - // TODO(ahentz): Our current implementations only support float32. - TF_LITE_ENSURE_EQ(context, input->type, kTfLiteFloat32); TF_LITE_ENSURE_EQ(context, size->type, kTfLiteInt32); // ResizeBilinear creates a float tensor even when the input is made of // integers. - output->type = kTfLiteFloat32; + output->type = input->type; if (!IsConstantTensor(size)) { SetTensorToDynamic(output); @@ -90,17 +88,24 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { } if (output->type == kTfLiteFloat32) { -#define TF_LITE_RESIZE_BILINEAR(type) \ - type::ResizeBilinear(GetTensorData(input), GetTensorDims(input), \ - GetTensorData(size), GetTensorDims(size), \ - GetTensorData(output), GetTensorDims(output), \ +#define TF_LITE_RESIZE_BILINEAR(type, datatype) \ + type::ResizeBilinear(GetTensorData(input), GetTensorDims(input), \ + GetTensorData(size), GetTensorDims(size), \ + GetTensorData(output), GetTensorDims(output), \ params->align_corners) if (kernel_type == kReference) { - TF_LITE_RESIZE_BILINEAR(reference_ops); + TF_LITE_RESIZE_BILINEAR(reference_ops, float); } if (kernel_type == kGenericOptimized || kernel_type == kNeonOptimized) { - TF_LITE_RESIZE_BILINEAR(optimized_ops); + TF_LITE_RESIZE_BILINEAR(optimized_ops, float); + } + } else if (output->type == kTfLiteUInt8) { + if (kernel_type == kReference) { + TF_LITE_RESIZE_BILINEAR(reference_ops, uint8_t); + } + if (kernel_type == kGenericOptimized || kernel_type == kNeonOptimized) { + TF_LITE_RESIZE_BILINEAR(optimized_ops, uint8_t); } #undef TF_LITE_RESIZE_BILINEAR } else { diff --git a/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc b/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc index 4e03f3820a..10caffea03 100644 --- a/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc +++ b/tensorflow/contrib/lite/kernels/resize_bilinear_test.cc @@ -22,6 +22,7 @@ namespace tflite { namespace { using ::testing::ElementsAreArray; +using uint8 = std::uint8_t; class ResizeBilinearOpModel : public SingleOpModel { public: @@ -34,7 +35,7 @@ class ResizeBilinearOpModel : public SingleOpModel { } else { size_ = AddInput({TensorType_INT32, {2}}); } - output_ = AddOutput(TensorType_FLOAT32); // Always float. + output_ = AddOutput(input.type); SetBuiltinOp(BuiltinOperator_RESIZE_BILINEAR, BuiltinOptions_ResizeBilinearOptions, CreateResizeBilinearOptions(builder_).Union()); @@ -45,12 +46,16 @@ class ResizeBilinearOpModel : public SingleOpModel { } } - void SetInput(std::initializer_list data) { + template + void SetInput(std::initializer_list data) { PopulateTensor(input_, data); } void SetSize(std::initializer_list data) { PopulateTensor(size_, data); } - std::vector GetOutput() { return ExtractVector(output_); } + template + std::vector GetOutput() { + return ExtractVector(output_); + } private: int input_; @@ -60,60 +65,121 @@ class ResizeBilinearOpModel : public SingleOpModel { TEST(ResizeBilinearOpTest, HorizontalResize) { ResizeBilinearOpModel m({TensorType_FLOAT32, {1, 1, 2, 1}}); - m.SetInput({3, 6}); + m.SetInput({3, 6}); m.SetSize({1, 3}); m.Invoke(); - EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 5, 6}))); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 5, 6}))); ResizeBilinearOpModel const_m({TensorType_FLOAT32, {1, 1, 2, 1}}, {1, 3}); - const_m.SetInput({3, 6}); + const_m.SetInput({3, 6}); + const_m.Invoke(); + EXPECT_THAT(const_m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 5, 6}))); +} + +TEST(ResizeBilinearOpTest, HorizontalResize8Bit) { + ResizeBilinearOpModel m({TensorType_UINT8, {1, 1, 2, 1}}); + m.SetInput({3, 6}); + m.SetSize({1, 3}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 5, 6}))); + + ResizeBilinearOpModel const_m({TensorType_UINT8, {1, 1, 2, 1}}, {1, 3}); + const_m.SetInput({3, 6}); const_m.Invoke(); - EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 5, 6}))); + EXPECT_THAT(const_m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 5, 6}))); } TEST(ResizeBilinearOpTest, VerticalResize) { ResizeBilinearOpModel m({TensorType_FLOAT32, {1, 2, 1, 1}}); - m.SetInput({3, 9}); + m.SetInput({3, 9}); m.SetSize({3, 1}); m.Invoke(); - EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 7, 9}))); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 7, 9}))); ResizeBilinearOpModel const_m({TensorType_FLOAT32, {1, 2, 1, 1}}, {3, 1}); - const_m.SetInput({3, 9}); + const_m.SetInput({3, 9}); + const_m.Invoke(); + EXPECT_THAT(const_m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 7, 9}))); +} + +TEST(ResizeBilinearOpTest, VerticalResize8Bit) { + ResizeBilinearOpModel m({TensorType_UINT8, {1, 2, 1, 1}}); + m.SetInput({3, 9}); + m.SetSize({3, 1}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 7, 9}))); + + ResizeBilinearOpModel const_m({TensorType_UINT8, {1, 2, 1, 1}}, {3, 1}); + const_m.SetInput({3, 9}); const_m.Invoke(); - EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 7, 9}))); + EXPECT_THAT(const_m.GetOutput(), + ElementsAreArray(ArrayFloatNear({3, 7, 9}))); } TEST(ResizeBilinearOpTest, TwoDimensionalResize) { ResizeBilinearOpModel m({TensorType_FLOAT32, {1, 2, 2, 1}}); - m.SetInput({ + m.SetInput({ 3, 6, // 9, 12 // }); m.SetSize({3, 3}); m.Invoke(); - EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 5, 6, // - 7, 9, 10, // - 9, 11, 12, // - }))); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + }))); ResizeBilinearOpModel const_m({TensorType_FLOAT32, {1, 2, 2, 1}}, {3, 3}); - const_m.SetInput({ + const_m.SetInput({ 3, 6, // 9, 12 // }); const_m.Invoke(); - EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 5, 6, // - 7, 9, 10, // - 9, 11, 12, // - }))); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + }))); +} + +TEST(ResizeBilinearOpTest, TwoDimensionalResize8Bit) { + ResizeBilinearOpModel m({TensorType_UINT8, {1, 2, 2, 1}}); + m.SetInput({ + 3, 6, // + 9, 12 // + }); + m.SetSize({3, 3}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + }))); + + ResizeBilinearOpModel const_m({TensorType_UINT8, {1, 2, 2, 1}}, {3, 3}); + const_m.SetInput({ + 3, 6, // + 9, 12 // + }); + const_m.Invoke(); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + }))); } TEST(ResizeBilinearOpTest, TwoDimensionalResizeWithTwoBatches) { ResizeBilinearOpModel m({TensorType_FLOAT32, {2, 2, 2, 1}}); - m.SetInput({ + m.SetInput({ 3, 6, // 9, 12, // 4, 10, // @@ -121,60 +187,123 @@ TEST(ResizeBilinearOpTest, TwoDimensionalResizeWithTwoBatches) { }); m.SetSize({3, 3}); m.Invoke(); - EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 5, 6, // - 7, 9, 10, // - 9, 11, 12, // - 4, 8, 10, // - 8, 12, 14, // - 10, 14, 16, // - }))); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + 4, 8, 10, // + 8, 12, 14, // + 10, 14, 16, // + }))); ResizeBilinearOpModel const_m({TensorType_FLOAT32, {2, 2, 2, 1}}, {3, 3}); - const_m.SetInput({ + const_m.SetInput({ 3, 6, // 9, 12, // 4, 10, // 10, 16 // }); const_m.Invoke(); - EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 5, 6, // - 7, 9, 10, // - 9, 11, 12, // - 4, 8, 10, // - 8, 12, 14, // - 10, 14, 16, // - }))); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + 4, 8, 10, // + 8, 12, 14, // + 10, 14, 16, // + }))); } TEST(ResizeBilinearOpTest, ThreeDimensionalResize) { ResizeBilinearOpModel m({TensorType_FLOAT32, {1, 2, 2, 2}}); - m.SetInput({ + m.SetInput({ 3, 4, 6, 10, // 9, 10, 12, 16, // }); m.SetSize({3, 3}); m.Invoke(); - EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 4, 5, 8, 6, 10, // - 7, 8, 9, 12, 10, 14, // - 9, 10, 11, 14, 12, 16, // - }))); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 4, 5, 8, 6, 10, // + 7, 8, 9, 12, 10, 14, // + 9, 10, 11, 14, 12, 16, // + }))); ResizeBilinearOpModel const_m({TensorType_FLOAT32, {1, 2, 2, 2}}, {3, 3}); - const_m.SetInput({ + const_m.SetInput({ 3, 4, 6, 10, // 9, 10, 12, 16, // }); const_m.Invoke(); - EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ - 3, 4, 5, 8, 6, 10, // - 7, 8, 9, 12, 10, 14, // - 9, 10, 11, 14, 12, 16, // - }))); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 4, 5, 8, 6, 10, // + 7, 8, 9, 12, 10, 14, // + 9, 10, 11, 14, 12, 16, // + }))); +} + +TEST(ResizeBilinearOpTest, TwoDimensionalResizeWithTwoBatches8Bit) { + ResizeBilinearOpModel m({TensorType_UINT8, {2, 2, 2, 1}}); + m.SetInput({ + 3, 6, // + 9, 12, // + 4, 10, // + 10, 16 // + }); + m.SetSize({3, 3}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + 4, 8, 10, // + 8, 12, 14, // + 10, 13, 16, // + }))); + + ResizeBilinearOpModel const_m({TensorType_UINT8, {2, 2, 2, 1}}, {3, 3}); + const_m.SetInput({ + 3, 6, // + 9, 12, // + 4, 10, // + 10, 16 // + }); + const_m.Invoke(); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 5, 6, // + 7, 9, 10, // + 9, 11, 12, // + 4, 8, 10, // + 8, 12, 14, // + 10, 13, 16, // + }))); } +TEST(ResizeBilinearOpTest, ThreeDimensionalResize8Bit) { + ResizeBilinearOpModel m({TensorType_UINT8, {1, 2, 2, 2}}); + m.SetInput({ + 3, 4, 6, 10, // + 9, 10, 12, 16, // + }); + m.SetSize({3, 3}); + m.Invoke(); + EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 4, 5, 8, 6, 10, // + 7, 8, 9, 12, 10, 14, // + 9, 10, 11, 13, 12, 16, // + }))); + + ResizeBilinearOpModel const_m({TensorType_UINT8, {1, 2, 2, 2}}, {3, 3}); + const_m.SetInput({ + 3, 4, 6, 10, // + 9, 10, 12, 16, // + }); + const_m.Invoke(); + EXPECT_THAT(const_m.GetOutput(), ElementsAreArray(ArrayFloatNear({ + 3, 4, 5, 8, 6, 10, // + 7, 8, 9, 12, 10, 14, // + 9, 10, 11, 13, 12, 16, // + }))); +} } // namespace } // namespace tflite diff --git a/tensorflow/contrib/lite/toco/graph_transformations/hardcode_min_max.cc b/tensorflow/contrib/lite/toco/graph_transformations/hardcode_min_max.cc index d63ee7c951..bda6dce22b 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/hardcode_min_max.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/hardcode_min_max.cc @@ -362,6 +362,8 @@ bool HardcodeMinMax::Run(Model* model, std::size_t op_index) { changed = HardcodeMinMaxForAverageOrMaxPool(model, op); break; + case OperatorType::kResizeBilinear: + case OperatorType::kSlice: case OperatorType::kStridedSlice: case OperatorType::kSqueeze: case OperatorType::kTensorFlowReshape: diff --git a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc index d4b5920760..eca2c701f8 100644 --- a/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc +++ b/tensorflow/contrib/lite/toco/graph_transformations/quantize.cc @@ -45,7 +45,8 @@ bool SupportsQuantization(const Operator& op) { type == OperatorType::kTensorFlowMinimum || type == OperatorType::kTensorFlowMaximum || type == OperatorType::kLogistic || type == OperatorType::kSoftmax || - type == OperatorType::kLogSoftmax || + type == OperatorType::kLogSoftmax || type == OperatorType::kSlice || + type == OperatorType::kResizeBilinear || type == OperatorType::kTensorFlowSplit || type == OperatorType::kSub || type == OperatorType::kSqueeze || type == OperatorType::kPad || type == OperatorType::kPadV2 || -- GitLab From c8980fd1b4d3a74de0214690f810d0c93da2558f Mon Sep 17 00:00:00 2001 From: Yu-Cheng Ling Date: Mon, 11 Jun 2018 17:12:31 -0700 Subject: [PATCH 030/540] Minor refactoring - Put together the ops with no option structs. PiperOrigin-RevId: 200139790 --- tensorflow/contrib/lite/model.cc | 96 +++++++++++++------------------- 1 file changed, 38 insertions(+), 58 deletions(-) diff --git a/tensorflow/contrib/lite/model.cc b/tensorflow/contrib/lite/model.cc index 4fb1ada9fd..039f32b38e 100644 --- a/tensorflow/contrib/lite/model.cc +++ b/tensorflow/contrib/lite/model.cc @@ -322,12 +322,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = nullptr; switch (op_type) { - case BuiltinOperator_CALL: - // TODO(aselle): Implement call in BuiltinOptions, but nullptrs are - // ok for now, since there is no call implementation either. - break; - case BuiltinOperator_CUSTOM: - break; case BuiltinOperator_CONV_2D: { TfLiteConvParams* params = MallocPOD(); if (auto* conv_params = op->builtin_options_as_Conv2DOptions()) { @@ -343,22 +337,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_TANH: - case BuiltinOperator_LOGISTIC: - case BuiltinOperator_RELU: - case BuiltinOperator_RELU_N1_TO_1: - case BuiltinOperator_RELU6: - case BuiltinOperator_CONCAT_EMBEDDINGS: - case BuiltinOperator_EXP: - case BuiltinOperator_TOPK_V2: - case BuiltinOperator_LOG_SOFTMAX: - case BuiltinOperator_DEQUANTIZE: - case BuiltinOperator_PRELU: - case BuiltinOperator_FLOOR: - case BuiltinOperator_NEG: - case BuiltinOperator_SIN: - case BuiltinOperator_LOG: - break; case BuiltinOperator_CAST: { TfLiteCastParams* params = MallocPOD(); if (auto* schema_params = op->builtin_options_as_CastOptions()) { @@ -446,9 +424,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_EMBEDDING_LOOKUP: - // no-op. - break; case BuiltinOperator_EMBEDDING_LOOKUP_SPARSE: { TfLiteEmbeddingLookupSparseParams* params = MallocPOD(); @@ -580,12 +555,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_PAD: { - break; - } - case BuiltinOperator_PADV2: { - break; - } case BuiltinOperator_RESHAPE: { auto* params = MallocPOD(); if (auto* schema_params = op->builtin_options_as_ReshapeOptions()) { @@ -625,15 +594,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_SPACE_TO_BATCH_ND: { - break; - } - case BuiltinOperator_BATCH_TO_SPACE_ND: { - break; - } - case BuiltinOperator_TRANSPOSE: { - break; - } case BuiltinOperator_MEAN: { auto* params = MallocPOD(); if (auto* schema_params = op->builtin_options_as_MeanOptions()) { @@ -673,10 +633,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_MAXIMUM: - case BuiltinOperator_MINIMUM: { - break; - } case BuiltinOperator_ARG_MAX: { auto* params = MallocPOD(); if (auto* schema_params = op->builtin_options_as_ArgMaxOptions()) { @@ -686,18 +642,6 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, *builtin_data = reinterpret_cast(params); break; } - case BuiltinOperator_GREATER: - case BuiltinOperator_GREATER_EQUAL: - case BuiltinOperator_LESS: - case BuiltinOperator_LESS_EQUAL: - case BuiltinOperator_EQUAL: - case BuiltinOperator_NOT_EQUAL: - case BuiltinOperator_SELECT: { - break; - } - case BuiltinOperator_SLICE: { - break; - } case BuiltinOperator_TRANSPOSE_CONV: { TfLiteTransposeConvParams* params = MallocPOD(); @@ -725,10 +669,46 @@ TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, error_reporter->Report("DELEGATE op shouldn't exist in model."); return kTfLiteError; } + + // Below are the ops with no builtin_data strcture. + case BuiltinOperator_BATCH_TO_SPACE_ND: + // TODO(aselle): Implement call in BuiltinOptions, but nullptrs are + // ok for now, since there is no call implementation either. + case BuiltinOperator_CALL: + case BuiltinOperator_CONCAT_EMBEDDINGS: + case BuiltinOperator_CUSTOM: + case BuiltinOperator_DEQUANTIZE: + case BuiltinOperator_EMBEDDING_LOOKUP: + case BuiltinOperator_EQUAL: + case BuiltinOperator_EXP: case BuiltinOperator_EXPAND_DIMS: - case BuiltinOperator_TILE: { + case BuiltinOperator_FLOOR: + case BuiltinOperator_GREATER: + case BuiltinOperator_GREATER_EQUAL: + case BuiltinOperator_LESS: + case BuiltinOperator_LESS_EQUAL: + case BuiltinOperator_LOG: + case BuiltinOperator_LOGISTIC: + case BuiltinOperator_LOG_SOFTMAX: + case BuiltinOperator_MAXIMUM: + case BuiltinOperator_MINIMUM: + case BuiltinOperator_NEG: + case BuiltinOperator_NOT_EQUAL: + case BuiltinOperator_PAD: + case BuiltinOperator_PADV2: + case BuiltinOperator_PRELU: + case BuiltinOperator_RELU: + case BuiltinOperator_RELU6: + case BuiltinOperator_RELU_N1_TO_1: + case BuiltinOperator_SELECT: + case BuiltinOperator_SIN: + case BuiltinOperator_SLICE: + case BuiltinOperator_SPACE_TO_BATCH_ND: + case BuiltinOperator_TANH: + case BuiltinOperator_TILE: + case BuiltinOperator_TOPK_V2: + case BuiltinOperator_TRANSPOSE: break; - } } return kTfLiteOk; } -- GitLab From bbee0c4c26d94aa7f0115f984116167052afa11e Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 17:13:19 -0700 Subject: [PATCH 031/540] Checking that TPUEstimator model function features have static shapes. PiperOrigin-RevId: 200139880 --- .../contrib/tpu/python/tpu/tpu_estimator.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 64ae35dfc5..2521522752 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -1343,8 +1343,55 @@ class _ModelFnWrapper(object): key, tensor)) return predictions + def _validate_model_features_and_labels(self, + features, + labels, + is_export_mode): + """Validates that the features and labels for the model function are valid. + + A valid features/labels object is the one with: + - Type: Tensor or a dictionary of Tensors + - Static shape if is_export_mode is False. + + Args: + features: the features that would be input to the model function. + labels: the labels that would be input to the model function. + is_export_mode: boolean value specifying if in export mode. + + Raises: + TypeError: If features/labels are not of the correct type. + ValueError: If features/labels have dynamic shape. + """ + + def validate(obj, obj_name): + """Helper validate function.""" + if not isinstance(obj, ops.Tensor) and not isinstance(obj, dict): + raise TypeError( + 'The {} to the model returned by input_fn must be either a Tensor ' + 'or a dictionary of Tensors. {}: {}'.format(obj_name, obj_name, + obj)) + if is_export_mode: + return + if isinstance(obj, ops.Tensor): + if not obj.get_shape().is_fully_defined(): + raise ValueError( + 'The {} to the model returned by input_fn must have static shape.' + ' Tensor: {}'.format(obj_name, obj)) + else: + for (key, tensor) in obj.items(): + if not tensor.get_shape().is_fully_defined(): + raise ValueError( + 'The {} to the model returned by input_fn must have static ' + 'shape. Key: \'{}\', Tensor: {}'.format( + obj_name, key, tensor)) + + validate(features, 'features') + if labels is not None: + validate(labels, 'labels') + def _call_model_fn(self, features, labels, is_export_mode=False): """Calls the model_fn with required parameters.""" + self._validate_model_features_and_labels(features, labels, is_export_mode) model_fn_args = function_utils.fn_args(self._model_fn) kwargs = {} -- GitLab From 5ebfc750447fd100e1b1c3bd747b87f460b50a81 Mon Sep 17 00:00:00 2001 From: Anna R Date: Mon, 11 Jun 2018 17:21:06 -0700 Subject: [PATCH 032/540] Add module docstrings that have been missing since new API generation was added. PiperOrigin-RevId: 200140810 --- tensorflow/tools/api/generator/BUILD | 24 ++++++ .../tools/api/generator/create_python_api.py | 52 ++++++++++-- tensorflow/tools/api/generator/doc_srcs.py | 65 +++++++++++++++ .../tools/api/generator/doc_srcs_test.py | 80 +++++++++++++++++++ 4 files changed, 215 insertions(+), 6 deletions(-) create mode 100644 tensorflow/tools/api/generator/doc_srcs.py create mode 100644 tensorflow/tools/api/generator/doc_srcs_test.py diff --git a/tensorflow/tools/api/generator/BUILD b/tensorflow/tools/api/generator/BUILD index f0c5877a90..3a28153e52 100644 --- a/tensorflow/tools/api/generator/BUILD +++ b/tensorflow/tools/api/generator/BUILD @@ -5,12 +5,21 @@ licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) +load("//tensorflow/tools/api/generator:api_gen.bzl", "TENSORFLOW_API_INIT_FILES") + +py_library( + name = "doc_srcs", + srcs = ["doc_srcs.py"], + srcs_version = "PY2AND3", +) + py_binary( name = "create_python_api", srcs = ["create_python_api.py"], srcs_version = "PY2AND3", visibility = ["//visibility:public"], deps = [ + ":doc_srcs", "//tensorflow/python:no_contrib", ], ) @@ -24,3 +33,18 @@ py_test( "//tensorflow/python:client_testlib", ], ) + +py_test( + name = "tensorflow_doc_srcs_test", + srcs = ["doc_srcs_test.py"], + args = [ + "--package=tensorflow.python", + ] + TENSORFLOW_API_INIT_FILES, + main = "doc_srcs_test.py", + srcs_version = "PY2AND3", + deps = [ + ":doc_srcs", + "//tensorflow/python:client_testlib", + "//tensorflow/python:no_contrib", + ], +) diff --git a/tensorflow/tools/api/generator/create_python_api.py b/tensorflow/tools/api/generator/create_python_api.py index 972bdc84ae..24e3c784d5 100644 --- a/tensorflow/tools/api/generator/create_python_api.py +++ b/tensorflow/tools/api/generator/create_python_api.py @@ -26,6 +26,7 @@ import sys from tensorflow.python.util import tf_decorator from tensorflow.python.util import tf_export +from tensorflow.tools.api.generator import doc_srcs API_ATTRS = tf_export.API_ATTRS @@ -36,10 +37,9 @@ _SYMBOLS_TO_SKIP_EXPLICITLY = { # would have side effects. 'tensorflow.python.platform.flags.FLAGS' } -_GENERATED_FILE_HEADER = """\"\"\"Imports for Python API. - -This file is MACHINE GENERATED! Do not edit. -Generated by: tensorflow/tools/api/generator/create_python_api.py script. +_GENERATED_FILE_HEADER = """# This file is MACHINE GENERATED! Do not edit. +# Generated by: tensorflow/tools/api/generator/create_python_api.py script. +\"\"\"%s \"\"\" """ @@ -247,6 +247,44 @@ def get_module(dir_path, relative_to_dir): return dir_path.replace('/', '.').strip('.') +def get_module_docstring(module_name, package): + """Get docstring for the given module. + + This method looks for docstring in the following order: + 1. Checks if module has a docstring specified in doc_srcs. + 2. Checks if module has a docstring source module specified + in doc_srcs. If it does, gets docstring from that module. + 3. Checks if module with module_name exists under base package. + If it does, gets docstring from that module. + 4. Returns a default docstring. + + Args: + module_name: module name relative to tensorflow + (excluding 'tensorflow.' prefix) to get a docstring for. + package: Base python package containing python with target tf_export + decorators. + + Returns: + One-line docstring to describe the module. + """ + # Module under base package to get a docstring from. + docstring_module_name = module_name + + if module_name in doc_srcs.TENSORFLOW_DOC_SOURCES: + docsrc = doc_srcs.TENSORFLOW_DOC_SOURCES[module_name] + if docsrc.docstring: + return docsrc.docstring + if docsrc.docstring_module_name: + docstring_module_name = docsrc.docstring_module_name + + docstring_module_name = package + '.' + docstring_module_name + if (docstring_module_name in sys.modules and + sys.modules[docstring_module_name].__doc__): + return sys.modules[docstring_module_name].__doc__ + + return 'Public API for tf.%s namespace.' % module_name + + def create_api_files( output_files, package, root_init_template, output_dir, api_name): """Creates __init__.py files for the Python API. @@ -290,7 +328,9 @@ def create_api_files( continue contents = '' if module or not root_init_template: - contents = _GENERATED_FILE_HEADER + text + contents = ( + _GENERATED_FILE_HEADER % + get_module_docstring(module, package) + text) else: # Read base init file with open(root_init_template, 'r') as root_init_template_file: @@ -303,7 +343,7 @@ def create_api_files( raise ValueError( 'Missing outputs for python_api_gen genrule:\n%s.' 'Make sure all required outputs are in the ' - 'tensorflow/tools/api/generator/BUILD file.' % + 'tensorflow/tools/api/generator/api_gen.bzl file.' % ',\n'.join(sorted(missing_output_files))) diff --git a/tensorflow/tools/api/generator/doc_srcs.py b/tensorflow/tools/api/generator/doc_srcs.py new file mode 100644 index 0000000000..74f6db98fd --- /dev/null +++ b/tensorflow/tools/api/generator/doc_srcs.py @@ -0,0 +1,65 @@ +# Copyright 2018 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Specifies sources of doc strings for API modules.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections + + +# Specifies docstring source for a module. +# Only one of docstring or docstring_module_name should be set. +# * If docstring is set, then we will use this docstring when +# for the module. +# * If docstring_module_name is set, then we will copy the docstring +# from docstring source module. +DocSource = collections.namedtuple( + 'DocSource', ['docstring', 'docstring_module_name']) +# Each attribute of DocSource is optional. +DocSource.__new__.__defaults__ = (None,) * len(DocSource._fields) + +TENSORFLOW_DOC_SOURCES = { + 'app': DocSource(docstring_module_name='platform.app'), + 'compat': DocSource(docstring_module_name='util.compat'), + 'distributions': DocSource( + docstring_module_name='ops.distributions.distributions'), + 'bitwise': DocSource(docstring_module_name='ops.bitwise_ops'), + 'errors': DocSource(docstring_module_name='framework.errors'), + 'gfile': DocSource(docstring_module_name='platform.gfile'), + 'graph_util': DocSource(docstring_module_name='framework.graph_util'), + 'image': DocSource(docstring_module_name='ops.image_ops'), + 'keras.estimator': DocSource(docstring_module_name='estimator.keras'), + 'linalg': DocSource(docstring_module_name='ops.linalg_ops'), + 'logging': DocSource(docstring_module_name='ops.logging_ops'), + 'losses': DocSource(docstring_module_name='ops.losses.losses'), + 'manip': DocSource(docstring_module_name='ops.manip_ops'), + 'math': DocSource(docstring_module_name='ops.math_ops'), + 'metrics': DocSource(docstring_module_name='ops.metrics'), + 'nn': DocSource(docstring_module_name='ops.nn_ops'), + 'nn.rnn_cell': DocSource(docstring_module_name='ops.rnn_cell'), + 'python_io': DocSource(docstring_module_name='lib.io.python_io'), + 'resource_loader': DocSource( + docstring_module_name='platform.resource_loader'), + 'sets': DocSource(docstring_module_name='ops.sets'), + 'sparse': DocSource(docstring_module_name='ops.sparse_ops'), + 'spectral': DocSource(docstring_module_name='ops.spectral_ops'), + 'strings': DocSource(docstring_module_name='ops.string_ops'), + 'sysconfig': DocSource(docstring_module_name='platform.sysconfig'), + 'test': DocSource(docstring_module_name='platform.test'), + 'train': DocSource(docstring_module_name='training.training'), + 'train.queue_runner': DocSource( + docstring_module_name='training.queue_runner'), +} diff --git a/tensorflow/tools/api/generator/doc_srcs_test.py b/tensorflow/tools/api/generator/doc_srcs_test.py new file mode 100644 index 0000000000..9ba95a3439 --- /dev/null +++ b/tensorflow/tools/api/generator/doc_srcs_test.py @@ -0,0 +1,80 @@ +# Copyright 2018 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================= +"""Tests for tensorflow.tools.api.generator.doc_srcs.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import argparse +import importlib +import sys + +from tensorflow.python.platform import test +from tensorflow.tools.api.generator import doc_srcs + + +FLAGS = None + + +class DocSrcsTest(test.TestCase): + + def testModulesAreValidAPIModules(self): + for module_name in doc_srcs.TENSORFLOW_DOC_SOURCES: + # Convert module_name to corresponding __init__.py file path. + file_path = module_name.replace('.', '/') + if file_path: + file_path += '/' + file_path += '__init__.py' + + if file_path not in FLAGS.outputs: + self.assertFalse('%s is not a valid API module' % module_name) + + def testHaveDocstringOrDocstringModule(self): + for module_name, docsrc in doc_srcs.TENSORFLOW_DOC_SOURCES.items(): + if docsrc.docstring and docsrc.docstring_module_name: + self.assertFalse( + '%s contains DocSource has both a docstring and a ' + 'docstring_module_name. ' + 'Only one of "docstring" or "docstring_module_name" should be set.' + % (module_name)) + + def testDocstringModulesAreValidModules(self): + for _, docsrc in doc_srcs.TENSORFLOW_DOC_SOURCES.items(): + if docsrc.docstring_module_name: + doc_module_name = '.'.join([ + FLAGS.package, docsrc.docstring_module_name]) + if doc_module_name not in sys.modules: + sys.assertFalse( + 'docsources_module %s is not a valid module under %s.' % + (docsrc.docstring_module_name, FLAGS.package)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + 'outputs', metavar='O', type=str, nargs='+', + help='create_python_api output files.') + parser.add_argument( + '--package', type=str, + help='Base package that imports modules containing the target tf_export ' + 'decorators.') + FLAGS, unparsed = parser.parse_known_args() + + importlib.import_module(FLAGS.package) + + # Now update argv, so that unittest library does not get confused. + sys.argv = [sys.argv[0]] + unparsed + test.main() -- GitLab From 8c5d37c3b96cdbcb8a3b657144d4fb63fb3dc100 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 17:24:32 -0700 Subject: [PATCH 033/540] Add `move_dimension` utility to move a single dimension within a Tensor. PiperOrigin-RevId: 200141207 --- .../kernel_tests/distribution_util_test.py | 48 +++++++++++ .../python/ops/distribution_util.py | 79 +++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/tensorflow/contrib/distributions/python/kernel_tests/distribution_util_test.py b/tensorflow/contrib/distributions/python/kernel_tests/distribution_util_test.py index 31d24aa9ea..bbbec2103a 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/distribution_util_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/distribution_util_test.py @@ -29,7 +29,9 @@ from tensorflow.contrib.distributions.python.ops import mvn_diag from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops +from tensorflow.python.ops import random_ops from tensorflow.python.ops.distributions import categorical from tensorflow.python.ops.distributions import normal from tensorflow.python.ops.linalg import linear_operator_diag @@ -540,5 +542,51 @@ class PadDynamicTest(_PadTest, test.TestCase): return False +class TestMoveDimension(test.TestCase): + + @test_util.run_in_graph_and_eager_modes() + def test_move_dimension_static_shape(self): + + x = random_ops.random_normal(shape=[200, 30, 4, 1, 6]) + + x_perm = distribution_util.move_dimension(x, 1, 1) + self.assertAllEqual(x_perm.shape.as_list(), [200, 30, 4, 1, 6]) + + x_perm = distribution_util.move_dimension(x, 0, 3) + self.assertAllEqual(x_perm.shape.as_list(), [30, 4, 1, 200, 6]) + + x_perm = distribution_util.move_dimension(x, 0, -2) + self.assertAllEqual(x_perm.shape.as_list(), [30, 4, 1, 200, 6]) + + x_perm = distribution_util.move_dimension(x, 4, 2) + self.assertAllEqual(x_perm.shape.as_list(), [200, 30, 6, 4, 1]) + + @test_util.run_in_graph_and_eager_modes() + def test_move_dimension_dynamic_shape(self): + + x_ = random_ops.random_normal(shape=[200, 30, 4, 1, 6]) + x = array_ops.placeholder_with_default(input=x_, shape=None) + + x_perm = distribution_util.move_dimension(x, 1, 1) + self.assertAllEqual(self.evaluate(array_ops.shape(x_perm)), + [200, 30, 4, 1, 6]) + + x_perm = distribution_util.move_dimension(x, 0, 3) + self.assertAllEqual(self.evaluate(array_ops.shape(x_perm)), + [30, 4, 1, 200, 6]) + + x_perm = distribution_util.move_dimension(x, 0, -2) + self.assertAllEqual(self.evaluate(array_ops.shape(x_perm)), + [30, 4, 1, 200, 6]) + + x_perm = distribution_util.move_dimension(x, 4, 2) + self.assertAllEqual(self.evaluate(array_ops.shape(x_perm)), + [200, 30, 6, 4, 1]) + + x_perm = distribution_util.move_dimension(x, -1, 2) + self.assertAllEqual(self.evaluate(array_ops.shape(x_perm)), + [200, 30, 6, 4, 1]) + + if __name__ == "__main__": test.main() diff --git a/tensorflow/contrib/distributions/python/ops/distribution_util.py b/tensorflow/contrib/distributions/python/ops/distribution_util.py index 289e1d50e1..6959b3e877 100644 --- a/tensorflow/contrib/distributions/python/ops/distribution_util.py +++ b/tensorflow/contrib/distributions/python/ops/distribution_util.py @@ -21,12 +21,19 @@ from __future__ import print_function from tensorflow.contrib import linalg from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops +from tensorflow.python.framework import smart_cond from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops.distributions import distribution as distribution_lib + +# The following two lines are redundant, in a sense. The first enables +# good coding practice *within* this file (`util.prefer_static_value` +# rather than `prefer_static_value`). The second ensures that users +# also get the core utils when they import this file. +from tensorflow.python.ops.distributions import util from tensorflow.python.ops.distributions.util import * # pylint: disable=wildcard-import @@ -484,3 +491,75 @@ def pad_mixture_dimensions(x, mixture_distribution, categorical_distribution, def static_value(x): """Returns the static value of a `Tensor` or `None`.""" return tensor_util.constant_value(ops.convert_to_tensor(x)) + + +def move_dimension(x, source_idx, dest_idx): + """Move a single tensor dimension within its shape. + + This is a special case of `tf.transpose()`, which applies + arbitrary permutations to tensor dimensions. + + Args: + x: Tensor of rank `ndims`. + source_idx: Integer index into `x.shape` (negative indexing is + supported). + dest_idx: Integer index into `x.shape` (negative indexing is + supported). + + Returns: + x_perm: Tensor of rank `ndims`, in which the dimension at original + index `source_idx` has been moved to new index `dest_idx`, with + all other dimensions retained in their original order. + + Example: + + ```python + x = tf.placeholder(shape=[200, 30, 4, 1, 6]) + x_perm = _move_dimension(x, 1, 1) # no-op + x_perm = _move_dimension(x, 0, 3) # result shape [30, 4, 1, 200, 6] + x_perm = _move_dimension(x, 0, -2) # equivalent to previous + x_perm = _move_dimension(x, 4, 2) # result shape [200, 30, 6, 4, 1] + ``` + """ + ndims = util.prefer_static_rank(x) + if isinstance(source_idx, int): + dtype = dtypes.int32 + else: + dtype = dtypes.as_dtype(source_idx.dtype) + + # Handle negative indexing. Since ndims might be dynamic, this makes + # source_idx and dest_idx also possibly dynamic. + if source_idx < 0: + source_idx = ndims + source_idx + if dest_idx < 0: + dest_idx = ndims + dest_idx + + # Construct the appropriate permutation of dimensions, depending + # whether the source is before or after the destination. + def move_left_permutation(): + return util.prefer_static_value( + array_ops.concat([ + math_ops.range(0, dest_idx, dtype=dtype), + [source_idx], + math_ops.range(dest_idx, source_idx, dtype=dtype), + math_ops.range(source_idx+1, ndims, dtype=dtype)], axis=0)) + + def move_right_permutation(): + return util.prefer_static_value( + array_ops.concat([ + math_ops.range(0, source_idx, dtype=dtype), + math_ops.range(source_idx+1, dest_idx+1, dtype=dtype), + [source_idx], + math_ops.range(dest_idx+1, ndims, dtype=dtype)], axis=0)) + + def x_permuted(): + return array_ops.transpose( + x, perm=smart_cond.smart_cond(source_idx < dest_idx, + move_right_permutation, + move_left_permutation)) + + # One final conditional to handle the special case where source + # and destination indices are equal. + return smart_cond.smart_cond(math_ops.equal(source_idx, dest_idx), + lambda: x, + x_permuted) -- GitLab From b5fa781337ad8becaab893d001b04f2b995575b5 Mon Sep 17 00:00:00 2001 From: Suharsh Sivakumar Date: Mon, 11 Jun 2018 18:41:48 -0700 Subject: [PATCH 034/540] TFLite should allow values of 0 for default_ranges_{min,max}. PiperOrigin-RevId: 200149066 --- tensorflow/contrib/lite/python/tflite_convert.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tensorflow/contrib/lite/python/tflite_convert.py b/tensorflow/contrib/lite/python/tflite_convert.py index 32ad84ec3c..f497533bed 100644 --- a/tensorflow/contrib/lite/python/tflite_convert.py +++ b/tensorflow/contrib/lite/python/tflite_convert.py @@ -116,7 +116,8 @@ def _convert_model(flags): "tensors in order to map between names and " "values.".format(",".join(input_arrays))) converter.quantized_input_stats = dict(zip(input_arrays, quant_stats)) - if flags.default_ranges_min and flags.default_ranges_max: + if (flags.default_ranges_min is not None) and (flags.default_ranges_max is + not None): converter.default_ranges_stats = (flags.default_ranges_min, flags.default_ranges_max) @@ -195,7 +196,7 @@ def _check_flags(flags, unparsed): raise ValueError("--std_dev_values, --mean_values must have the same " "number of items") - if bool(flags.default_ranges_min) != bool(flags.default_ranges_max): + if (flags.default_ranges_min is None) != (flags.default_ranges_max is None): raise ValueError("--default_ranges_min and --default_ranges_max must be " "used together") -- GitLab From 5f4be37bebe0343736e800884387cc2147bc55cb Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 19:09:42 -0700 Subject: [PATCH 035/540] Re-enable trainer TPU test. PiperOrigin-RevId: 200151330 --- .../compiler/xla/service/hlo_module_group_metadata.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/service/hlo_module_group_metadata.cc b/tensorflow/compiler/xla/service/hlo_module_group_metadata.cc index 4f1715e4ca..bf33640db1 100644 --- a/tensorflow/compiler/xla/service/hlo_module_group_metadata.cc +++ b/tensorflow/compiler/xla/service/hlo_module_group_metadata.cc @@ -127,9 +127,14 @@ Status HloModuleGroupMetadata::VerifyCompanionSets() const { for (HloInstruction* instruction : *companions) { // Go through all the communicating instructions (send, recv) of the given // companion, and record their device. + auto it = tracked_instructions_comms_.find(instruction); + if (it == tracked_instructions_comms_.end()) { + // Companions can be added even if they have no communicating + // instructions, if they are parent of companions. + continue; + } std::unordered_set comm_devices; - for (HloInstruction* comm_instruction : - tracked_instructions_comms_.at(instruction)) { + for (HloInstruction* comm_instruction : it->second) { auto device = GetInstructionDevice(*comm_instruction); TF_RET_CHECK(device) << "Instruction " << comm_instruction->ToString() << " does not have a device"; -- GitLab From 39c18ead40f4b998b857d07629317675fbf5d035 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 19:45:19 -0700 Subject: [PATCH 036/540] Use activation in MUL and ADD operations PiperOrigin-RevId: 200153612 --- tensorflow/contrib/lite/nnapi_delegate.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tensorflow/contrib/lite/nnapi_delegate.cc b/tensorflow/contrib/lite/nnapi_delegate.cc index 99cb40e967..999c31d4bf 100644 --- a/tensorflow/contrib/lite/nnapi_delegate.cc +++ b/tensorflow/contrib/lite/nnapi_delegate.cc @@ -234,7 +234,10 @@ void AddOpsAndParams(tflite::Interpreter* interpreter, next_id++; }; - auto add_add_params = [&add_scalar_int32]() { add_scalar_int32(0); }; + auto add_add_params = [&add_scalar_int32](void* data) { + auto* builtin = reinterpret_cast(data); + add_scalar_int32(builtin->activation); + }; auto add_pooling_params = [&add_scalar_int32](void* data) { auto builtin = reinterpret_cast(data); @@ -345,11 +348,11 @@ void AddOpsAndParams(tflite::Interpreter* interpreter, switch (builtin) { case tflite::BuiltinOperator_ADD: nn_op_type = ANEURALNETWORKS_ADD; - add_add_params(); + add_add_params(node.builtin_data); break; case tflite::BuiltinOperator_MUL: nn_op_type = ANEURALNETWORKS_MUL; - add_add_params(); + add_add_params(node.builtin_data); break; case tflite::BuiltinOperator_AVERAGE_POOL_2D: add_pooling_params(node.builtin_data); -- GitLab From 5357d13d2bdca2fcd3779d0e8ea4aab5d2e73c21 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 20:06:25 -0700 Subject: [PATCH 037/540] Rollback of changelist checking for static shapes for model function. END_PUBLIC BEGIN_PUBLIC Automated g4 rollback of changelist 200139880 PiperOrigin-RevId: 200155130 --- .../contrib/tpu/python/tpu/tpu_estimator.py | 47 ------------------- 1 file changed, 47 deletions(-) diff --git a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py index 2521522752..64ae35dfc5 100644 --- a/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py +++ b/tensorflow/contrib/tpu/python/tpu/tpu_estimator.py @@ -1343,55 +1343,8 @@ class _ModelFnWrapper(object): key, tensor)) return predictions - def _validate_model_features_and_labels(self, - features, - labels, - is_export_mode): - """Validates that the features and labels for the model function are valid. - - A valid features/labels object is the one with: - - Type: Tensor or a dictionary of Tensors - - Static shape if is_export_mode is False. - - Args: - features: the features that would be input to the model function. - labels: the labels that would be input to the model function. - is_export_mode: boolean value specifying if in export mode. - - Raises: - TypeError: If features/labels are not of the correct type. - ValueError: If features/labels have dynamic shape. - """ - - def validate(obj, obj_name): - """Helper validate function.""" - if not isinstance(obj, ops.Tensor) and not isinstance(obj, dict): - raise TypeError( - 'The {} to the model returned by input_fn must be either a Tensor ' - 'or a dictionary of Tensors. {}: {}'.format(obj_name, obj_name, - obj)) - if is_export_mode: - return - if isinstance(obj, ops.Tensor): - if not obj.get_shape().is_fully_defined(): - raise ValueError( - 'The {} to the model returned by input_fn must have static shape.' - ' Tensor: {}'.format(obj_name, obj)) - else: - for (key, tensor) in obj.items(): - if not tensor.get_shape().is_fully_defined(): - raise ValueError( - 'The {} to the model returned by input_fn must have static ' - 'shape. Key: \'{}\', Tensor: {}'.format( - obj_name, key, tensor)) - - validate(features, 'features') - if labels is not None: - validate(labels, 'labels') - def _call_model_fn(self, features, labels, is_export_mode=False): """Calls the model_fn with required parameters.""" - self._validate_model_features_and_labels(features, labels, is_export_mode) model_fn_args = function_utils.fn_args(self._model_fn) kwargs = {} -- GitLab From 51f2b9e2867dd3ddb736a093f36b786cec3217c5 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Mon, 11 Jun 2018 20:11:36 -0700 Subject: [PATCH 038/540] Exposes toco_flags and model_flags as optional parameters to allow fine grained control of conversion. PiperOrigin-RevId: 200155520 --- tensorflow/contrib/lite/python/convert.py | 72 +++++++++++++++-------- tensorflow/contrib/lite/python/lite.py | 1 + 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/tensorflow/contrib/lite/python/convert.py b/tensorflow/contrib/lite/python/convert.py index fce8ffb54a..c038c88945 100644 --- a/tensorflow/contrib/lite/python/convert.py +++ b/tensorflow/contrib/lite/python/convert.py @@ -111,29 +111,27 @@ def tensor_name(x): return x.name.split(":")[0] -def toco_convert(input_data, - input_tensors, - output_tensors, - inference_type=lite_constants.FLOAT, - inference_input_type=None, - input_format=lite_constants.TENSORFLOW_GRAPHDEF, - output_format=lite_constants.TFLITE, - quantized_input_stats=None, - default_ranges_stats=None, - drop_control_dependency=True, - reorder_across_fake_quant=False, - allow_custom_ops=False, - change_concat_input_ranges=False, - quantize_weights=False, - dump_graphviz_dir=None, - dump_graphviz_video=False): - """Convert a model using TOCO from `input_format` to `output_format`. +def build_toco_convert_protos(input_tensors, + output_tensors, + inference_type=lite_constants.FLOAT, + inference_input_type=None, + input_format=lite_constants.TENSORFLOW_GRAPHDEF, + output_format=lite_constants.TFLITE, + quantized_input_stats=None, + default_ranges_stats=None, + drop_control_dependency=True, + reorder_across_fake_quant=False, + allow_custom_ops=False, + change_concat_input_ranges=False, + quantize_weights=False, + dump_graphviz_dir=None, + dump_graphviz_video=False): + """Builds protocol buffers describing a conversion of a model using TOCO. Typically this is to convert from TensorFlow GraphDef to TFLite, in which case the default `input_format` and `output_format` are sufficient. Args: - input_data: Input data (i.e. often `sess.graph_def`). input_tensors: List of input tensors. Type and shape are computed using `foo.get_shape()` and `foo.dtype`. output_tensors: List of output tensors (only .name is used from this). @@ -180,8 +178,8 @@ def toco_convert(input_data, every graph transformation. (default False) Returns: - The converted data. For example if TFLite was the destination, then - this will be a tflite flatbuffer in a bytes array. + model_flags, toco_flags: two protocol buffers describing the conversion + process. Raises: ValueError: If the input tensor type is unknown @@ -204,7 +202,6 @@ def toco_convert(input_data, if dump_graphviz_dir: toco.dump_graphviz_dir = dump_graphviz_dir toco.dump_graphviz_include_video = dump_graphviz_video - model = _model_flags_pb2.ModelFlags() model.change_concat_input_ranges = change_concat_input_ranges for idx, input_tensor in enumerate(input_tensors): @@ -233,10 +230,35 @@ def toco_convert(input_data, for output_tensor in output_tensors: model.output_arrays.append(tensor_name(output_tensor)) + return model, toco + + +def toco_convert(input_data, input_tensors, output_tensors, *args, **kwargs): + """"Convert a model using TOCO. - # TODO(aselle): Consider handling the case of allowing quantized - # inputs to be converted to float (via the toco.inference_input_type field). - data = toco_convert_protos(model.SerializeToString(), - toco.SerializeToString(), + Typically this function is used to convert from TensorFlow GraphDef to TFLite. + Conversion can be customized by providing arguments that are forwarded to + `build_toco_convert_protos` (see documentation for details). + + Args: + input_data: Input data (i.e. often `sess.graph_def`), + input_tensors: List of input tensors. Type and shape are computed using + `foo.get_shape()` and `foo.dtype`. + output_tensors: List of output tensors (only .name is used from this). + *args: See `build_toco_convert_protos`, + **kwargs: See `build_toco_convert_protos`. + + Returns: + The converted data. For example if TFLite was the destination, then + this will be a tflite flatbuffer in a bytes array. + + Raises: + Defined in `build_toco_convert_protos`. + """ + model_flags, toco_flags = build_toco_convert_protos(input_tensors, + output_tensors, + *args, **kwargs) + data = toco_convert_protos(model_flags.SerializeToString(), + toco_flags.SerializeToString(), input_data.SerializeToString()) return data diff --git a/tensorflow/contrib/lite/python/lite.py b/tensorflow/contrib/lite/python/lite.py index 4fb88c1ad6..6b63c0ccef 100644 --- a/tensorflow/contrib/lite/python/lite.py +++ b/tensorflow/contrib/lite/python/lite.py @@ -36,6 +36,7 @@ from __future__ import print_function from google.protobuf import text_format as _text_format from google.protobuf.message import DecodeError from tensorflow.contrib.lite.python import lite_constants as constants +from tensorflow.contrib.lite.python.convert import build_toco_convert_protos # pylint: disable=unused-import from tensorflow.contrib.lite.python.convert import tensor_name from tensorflow.contrib.lite.python.convert import toco_convert from tensorflow.contrib.lite.python.convert import toco_convert_protos # pylint: disable=unused-import -- GitLab From f9ae897fdcba9d1f7aa4ed8e0514022f8e5e70f3 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 12 Jun 2018 01:34:20 -0700 Subject: [PATCH 039/540] [XLA:GPU] Check the reduce input shape when multi-output fusing reduces Otherwise we can end up in a situation where incompatible reduces that happen to have the same output shape are fused. PiperOrigin-RevId: 200180013 --- .../xla/service/gpu/multi_output_fusion.cc | 8 +++-- .../service/gpu/multi_output_fusion_test.cc | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc b/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc index 86c5c4fb6f..942c254533 100644 --- a/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc +++ b/tensorflow/compiler/xla/service/gpu/multi_output_fusion.cc @@ -47,12 +47,16 @@ bool GpuMultiOutputFusion::ShapesCompatibleForFusion(HloInstruction* instr1, element_instr = fused_expression_root; } } + // Special handling of kReduce instructions -- the fusion + // applies to the first operand. + if (element_instr->opcode() == HloOpcode::kReduce) { + return element_instr->operand(0)->shape(); + } return element_instr->shape(); }; // The elementwise output shapes must be the same (including layout) - return ShapeUtil::ShapeUtil::Equal(get_element_shape(instr1), - get_element_shape(instr2)); + return ShapeUtil::Equal(get_element_shape(instr1), get_element_shape(instr2)); } bool GpuMultiOutputFusion::IsProfitableOperand(HloInstruction* instr) { diff --git a/tensorflow/compiler/xla/service/gpu/multi_output_fusion_test.cc b/tensorflow/compiler/xla/service/gpu/multi_output_fusion_test.cc index d0b4c88487..5170cbc7e3 100644 --- a/tensorflow/compiler/xla/service/gpu/multi_output_fusion_test.cc +++ b/tensorflow/compiler/xla/service/gpu/multi_output_fusion_test.cc @@ -36,6 +36,11 @@ const char kModulePrefix[] = R"( scalar_lhs = f32[] parameter(0) scalar_rhs = f32[] parameter(1) ROOT add = f32[] add(scalar_lhs, scalar_rhs) + } + scalar_mul_computation { + scalar_lhs = f32[] parameter(0) + scalar_rhs = f32[] parameter(1) + ROOT mul = f32[] add(scalar_lhs, scalar_rhs) })"; TEST_F(InstructionFusionTest, MultiOutputFusionSiblingReduceAndReduceFusion) { @@ -67,6 +72,34 @@ TEST_F(InstructionFusionTest, MultiOutputFusionSiblingReduceAndReduceFusion) { op::Tuple(op::Reduce(), op::Reduce())); } +TEST_F(InstructionFusionTest, MultiOutputFusionDifferentReduceInputShapes) { + auto module = ParseHloString(tensorflow::strings::StrCat(kModulePrefix, R"( + fused_computation_1 { + p1.1 = f32[6400]{0} parameter(1) + mul = f32[6400]{0} multiply(p1.1, p1.1) + const.1 = f32[] parameter(0) + ROOT reduce.1 = f32[] reduce(p1.1, const.1), dimensions={0}, to_apply=scalar_add_computation + } + + fused_computation_2 { + p1.2 = f32[6400]{0} parameter(1) + r1 = f32[64,100]{0,1} reshape(p1.2) + const.2 = f32[] parameter(0) + ROOT reduce.2 = f32[] reduce(r1, const.2), dimensions={1,0}, to_apply=scalar_mul_computation + } + + ENTRY entry { + p0 = f32[] parameter(0) + p1 = f32[6400]{0} parameter(1) + const.2 = f32[] constant(1) + fusion.1 = f32[] fusion(p0, p1), kind=kInput, calls=fused_computation_1 + fusion.2 = f32[] fusion(p0, p1), kind=kInput, calls=fused_computation_2 + ROOT root = (f32[], f32[]) tuple(fusion.1, fusion.2) + })")) + .ValueOrDie(); + ASSERT_FALSE(GpuMultiOutputFusion().Run(module.get()).ValueOrDie()); +} + TEST_F(InstructionFusionTest, MultiOutputFusionSiblingReduceFusions) { // Two sibling fusions with reduce instruction roots sharing the same input // param. -- GitLab From da88bfa02f6fb7071a41ff065ec9a918b1e0b1d6 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 12 Jun 2018 01:52:52 -0700 Subject: [PATCH 040/540] Fixes documentation of multi_label_head to render accepted labels as markdown list PiperOrigin-RevId: 200181836 --- tensorflow/contrib/estimator/python/estimator/head.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/contrib/estimator/python/estimator/head.py b/tensorflow/contrib/estimator/python/estimator/head.py index b798769d2c..9594e5132f 100644 --- a/tensorflow/contrib/estimator/python/estimator/head.py +++ b/tensorflow/contrib/estimator/python/estimator/head.py @@ -529,6 +529,7 @@ def multi_label_head(n_classes, applications, the shape is `[batch_size, n_classes]`. Labels can be: + * A multi-hot tensor of shape `[D0, D1, ... DN, n_classes]` * An integer `SparseTensor` of class indices. The `dense_shape` must be `[D0, D1, ... DN, ?]` and the values within `[0, n_classes)`. -- GitLab From 433ac81400c788557001789f0a0c5a76a9b7e29c Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 12 Jun 2018 02:33:46 -0700 Subject: [PATCH 041/540] Modified Bessel functions of order zero and one. The functions are tf.math.bessel_i0(x), tf.math.bessel_i0e(x), tf.math.bessel_i1(x) and tf.math.bessel_i1e(x). The exponentially scaled versions tf.math.bessel_i0e(x) and tf.math.bessel_i1e(x) are more numerically stable. This code wraps the implementation that was recently added to Eigen. PiperOrigin-RevId: 200186968 --- .../api_def/base_api/api_def_BesselI0e.pbtxt | 10 +++ .../api_def/base_api/api_def_BesselI1e.pbtxt | 10 +++ .../python_api/api_def_BesselI0e.pbtxt | 4 ++ .../python_api/api_def_BesselI1e.pbtxt | 4 ++ tensorflow/core/kernels/cwise_op_bessel.cc | 29 +++++++++ tensorflow/core/kernels/cwise_op_bessel.cu.cc | 27 ++++++++ tensorflow/core/kernels/cwise_ops.h | 6 ++ tensorflow/core/ops/math_ops.cc | 4 ++ .../python/kernel_tests/cwise_ops_test.py | 24 ++++++++ tensorflow/python/ops/math_grad.py | 29 +++++++++ tensorflow/python/ops/math_ops.py | 61 +++++++++++++++++++ tensorflow/python/ops/special_math_ops.py | 48 +++++++++++++++ .../python/ops/special_math_ops_test.py | 28 +++++++++ .../tools/api/golden/tensorflow.math.pbtxt | 16 +++++ 14 files changed, 300 insertions(+) create mode 100644 tensorflow/core/api_def/base_api/api_def_BesselI0e.pbtxt create mode 100644 tensorflow/core/api_def/base_api/api_def_BesselI1e.pbtxt create mode 100644 tensorflow/core/api_def/python_api/api_def_BesselI0e.pbtxt create mode 100644 tensorflow/core/api_def/python_api/api_def_BesselI1e.pbtxt create mode 100644 tensorflow/core/kernels/cwise_op_bessel.cc create mode 100644 tensorflow/core/kernels/cwise_op_bessel.cu.cc diff --git a/tensorflow/core/api_def/base_api/api_def_BesselI0e.pbtxt b/tensorflow/core/api_def/base_api/api_def_BesselI0e.pbtxt new file mode 100644 index 0000000000..08313cebb9 --- /dev/null +++ b/tensorflow/core/api_def/base_api/api_def_BesselI0e.pbtxt @@ -0,0 +1,10 @@ +op { + graph_op_name: "BesselI0e" + summary: "Computes the Bessel i0e function of `x` element-wise." + description: <