diff --git a/RELEASE.md b/RELEASE.md index d8db1f72004b5d..76ec6bc7d348ab 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1,15 @@ +# Release 1.4.2 + +## Bug Fixes and Other Changes +* Fixes a potential security vulnerability where on-the-fly changes to the dtype + of a tensor reference may lead to undefined behavior. +* Fix an incompatibility with new Bazel versions. + +# Release 1.4.1 + +## Bug Fixes and Other Changes +* `LinearClassifier` fix for CloudML Engine. + # Release 1.4.0 ## Major Features And Improvements diff --git a/tensorflow/contrib/data/README.md b/tensorflow/contrib/data/README.md index 30e909111f460b..848782e8d89b86 100644 --- a/tensorflow/contrib/data/README.md +++ b/tensorflow/contrib/data/README.md @@ -18,7 +18,7 @@ The arguments accepted by the `Dataset.map()` transformation have changed: * `dataset.map(..., num_threads=T)` is now `dataset.map(num_parallel_calls=T)`. * `dataset.map(..., output_buffer_size=B)` is now - `dataset.map(...).prefetch(B). + `dataset.map(...).prefetch(B)`. Some transformations have been removed from `tf.data.Dataset`, and you must instead apply them using `Dataset.apply()` transformation. The full list of diff --git a/tensorflow/core/common_runtime/executor.cc b/tensorflow/core/common_runtime/executor.cc index b1537eab013843..67a42964427679 100644 --- a/tensorflow/core/common_runtime/executor.cc +++ b/tensorflow/core/common_runtime/executor.cc @@ -1764,6 +1764,19 @@ Status ExecutorState::PrepareInputs(const NodeItem& item, Entry* first_input, entry->ref_mu = nullptr; inp->tensor = entry->val.get(); + // The dtype of entry->ref could have been changed by another operation + // that ran after the operation that "produced" it executed, so + // re-validate that the type of the dereferenced tensor matches the + // expected input type. + if (item.input_type(i) != inp->tensor->dtype()) { + return AttachDef( + errors::InvalidArgument( + i, "-th input expects type ", + DataTypeString(item.input_type(i)), + " but automatically dereferenced input tensor has type ", + DataTypeString(inp->tensor->dtype())), + item.kernel->def()); + } } } } diff --git a/tensorflow/core/kernels/strided_slice_op.cc b/tensorflow/core/kernels/strided_slice_op.cc index 8fc40db3cc2206..c9bf6de96e9efd 100644 --- a/tensorflow/core/kernels/strided_slice_op.cc +++ b/tensorflow/core/kernels/strided_slice_op.cc @@ -294,6 +294,11 @@ class StridedSliceAssignOp : public OpKernel { OP_REQUIRES_OK(context, LookupResource(context, HandleFromInput(context, 0), &v)); old_lhs = *v->tensor(); + OP_REQUIRES(context, old_lhs.dtype() == DataTypeToEnum::value, + errors::InvalidArgument( + "l-value dtype ", DataTypeString(old_lhs.dtype()), + " does not match r-value dtype ", + DataTypeString(DataTypeToEnum::value))); } else { context->forward_ref_input_to_ref_output(0, 0); old_lhs = context->mutable_input(0, true); diff --git a/tensorflow/core/platform/default/build_config_root.bzl b/tensorflow/core/platform/default/build_config_root.bzl index caeed0aa4a3221..6e98f12114ec6b 100644 --- a/tensorflow/core/platform/default/build_config_root.bzl +++ b/tensorflow/core/platform/default/build_config_root.bzl @@ -10,7 +10,9 @@ def tf_sycl_tests_tags(): def tf_additional_plugin_deps(): return select({ - "//tensorflow:with_xla_support": ["//tensorflow/compiler/jit"], + str(Label("//tensorflow:with_xla_support")): [ + str(Label("//tensorflow/compiler/jit")) + ], "//conditions:default": [], }) @@ -19,37 +21,37 @@ def tf_additional_xla_deps_py(): def tf_additional_license_deps(): return select({ - "//tensorflow:with_xla_support": ["@llvm//:LICENSE.TXT"], + str(Label("//tensorflow:with_xla_support")): ["@llvm//:LICENSE.TXT"], "//conditions:default": [], }) def tf_additional_verbs_deps(): return select({ - "//tensorflow:with_verbs_support": [ - "//tensorflow/contrib/verbs:verbs_server_lib", - "//tensorflow/contrib/verbs:grpc_verbs_client", - ], + str(Label("//tensorflow:with_verbs_support")): [ + str(Label("//tensorflow/contrib/verbs:verbs_server_lib")), + str(Label("//tensorflow/contrib/verbs:grpc_verbs_client")), + ], "//conditions:default": [], }) def tf_additional_mpi_deps(): return select({ - "//tensorflow:with_mpi_support": [ - "//tensorflow/contrib/mpi:mpi_server_lib", + str(Label("//tensorflow:with_mpi_support")): [ + str(Label("//tensorflow/contrib/mpi:mpi_server_lib")), ], "//conditions:default": [], }) def tf_additional_gdr_deps(): return select({ - "//tensorflow:with_gdr_support": [ - "//tensorflow/contrib/gdr:gdr_server_lib", + str(Label("//tensorflow:with_gdr_support")): [ + str(Label("//tensorflow/contrib/gdr:gdr_server_lib")), ], "//conditions:default": [], }) def if_static(extra_deps, otherwise=[]): return select({ - "//tensorflow:framework_shared_object": otherwise, + str(Label("//tensorflow:framework_shared_object")): otherwise, "//conditions:default": extra_deps, }) diff --git a/tensorflow/core/public/version.h b/tensorflow/core/public/version.h index 02359949a9972f..b58ea2c4118a52 100644 --- a/tensorflow/core/public/version.h +++ b/tensorflow/core/public/version.h @@ -20,7 +20,7 @@ limitations under the License. #define TF_MAJOR_VERSION 1 #define TF_MINOR_VERSION 4 -#define TF_PATCH_VERSION 0 +#define TF_PATCH_VERSION 2 // TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1", // "-beta", "-rc", "-rc.1") diff --git a/tensorflow/docs_src/install/index.md b/tensorflow/docs_src/install/index.md index eddbfe9e31e6a3..c4fc882ddd43ee 100644 --- a/tensorflow/docs_src/install/index.md +++ b/tensorflow/docs_src/install/index.md @@ -2,9 +2,11 @@ We've built and tested TensorFlow on the following 64-bit laptop/desktop operating systems: + * MacOS X 10.11 (El Capitan) or later. * Ubuntu 14.04 or later * Windows 7 or later. + Although you might be able to install TensorFlow on other laptop or desktop systems, we only support (and only fix issues in) the preceding configurations. diff --git a/tensorflow/docs_src/install/install_c.md b/tensorflow/docs_src/install/install_c.md index 53e784ca7a563e..b2e992527cfe2d 100644 --- a/tensorflow/docs_src/install/install_c.md +++ b/tensorflow/docs_src/install/install_c.md @@ -35,7 +35,7 @@ enable TensorFlow for C: OS="linux" # Change to "darwin" for Mac OS TARGET_DIRECTORY="/usr/local" curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-${OS}-x86_64-1.4.0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-${OS}-x86_64-1.4.2.tar.gz" | sudo tar -C $TARGET_DIRECTORY -xz The `tar` command extracts the TensorFlow C library into the `lib` diff --git a/tensorflow/docs_src/install/install_go.md b/tensorflow/docs_src/install/install_go.md index bf56f9102bbad6..a6e9881bc40d3b 100644 --- a/tensorflow/docs_src/install/install_go.md +++ b/tensorflow/docs_src/install/install_go.md @@ -35,7 +35,7 @@ steps to install this library and enable TensorFlow for Go: TF_TYPE="cpu" # Change to "gpu" for GPU support TARGET_DIRECTORY='/usr/local' curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-1.4.0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-${TF_TYPE}-$(go env GOOS)-x86_64-1.4.2.tar.gz" | sudo tar -C $TARGET_DIRECTORY -xz The `tar` command extracts the TensorFlow C library into the `lib` diff --git a/tensorflow/docs_src/install/install_java.md b/tensorflow/docs_src/install/install_java.md index d5f5769890f85e..ec689ab0d67ce9 100644 --- a/tensorflow/docs_src/install/install_java.md +++ b/tensorflow/docs_src/install/install_java.md @@ -34,7 +34,7 @@ following to the project's `pom.xml` to use the TensorFlow Java APIs: org.tensorflow tensorflow - 1.4.0 + 1.4.2 ``` @@ -63,7 +63,7 @@ As an example, these steps will create a Maven project that uses TensorFlow: org.tensorflow tensorflow - 1.4.0 + 1.4.2 @@ -122,7 +122,7 @@ refer to the simpler instructions above instead. Take the following steps to install TensorFlow for Java on Linux or Mac OS: 1. Download - [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.4.0.jar), + [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.4.2.jar), which is the TensorFlow Java Archive (JAR). 2. Decide whether you will run TensorFlow for Java on CPU(s) only or with @@ -141,7 +141,7 @@ Take the following steps to install TensorFlow for Java on Linux or Mac OS: OS=$(uname -s | tr '[:upper:]' '[:lower:]') mkdir -p ./jni curl -L \ - "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-${TF_TYPE}-${OS}-x86_64-1.4.0.tar.gz" | + "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-${TF_TYPE}-${OS}-x86_64-1.4.2.tar.gz" | tar -xz -C ./jni ### Install on Windows @@ -149,10 +149,10 @@ Take the following steps to install TensorFlow for Java on Linux or Mac OS: Take the following steps to install TensorFlow for Java on Windows: 1. Download - [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.4.0.jar), + [libtensorflow.jar](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-1.4.2.jar), which is the TensorFlow Java Archive (JAR). 2. Download the following Java Native Interface (JNI) file appropriate for - [TensorFlow for Java on Windows](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-windows-x86_64-1.4.0.zip). + [TensorFlow for Java on Windows](https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-windows-x86_64-1.4.2.zip). 3. Extract this .zip file. @@ -200,7 +200,7 @@ must be part of your `classpath`. For example, you can include the downloaded `.jar` in your `classpath` by using the `-cp` compilation flag as follows: -
javac -cp libtensorflow-1.4.0.jar HelloTF.java
+
javac -cp libtensorflow-1.4.2.jar HelloTF.java
### Running @@ -214,11 +214,11 @@ two files are available to the JVM: For example, the following command line executes the `HelloTF` program on Linux and Mac OS X: -
java -cp libtensorflow-1.4.0.jar:. -Djava.library.path=./jni HelloTF
+
java -cp libtensorflow-1.4.2.jar:. -Djava.library.path=./jni HelloTF
And the following command line executes the `HelloTF` program on Windows: -
java -cp libtensorflow-1.4.0.jar;. -Djava.library.path=jni HelloTF
+
java -cp libtensorflow-1.4.2.jar;. -Djava.library.path=jni HelloTF
If the program prints Hello from version, you've successfully installed TensorFlow for Java and are ready to use the API. If the program diff --git a/tensorflow/docs_src/install/install_linux.md b/tensorflow/docs_src/install/install_linux.md index 41d8af78342d0a..2382e090a79afb 100644 --- a/tensorflow/docs_src/install/install_linux.md +++ b/tensorflow/docs_src/install/install_linux.md @@ -172,7 +172,7 @@ Take the following steps to install TensorFlow with Virtualenv: virtualenv environment:
(tensorflow)$ pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp34-cp34m-linux_x86_64.whl
+ https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp34-cp34m-linux_x86_64.whl If you encounter installation problems, see [Common Installation Problems](#common_installation_problems). @@ -277,7 +277,7 @@ take the following steps:
      $ sudo pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp34-cp34m-linux_x86_64.whl
+     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp34-cp34m-linux_x86_64.whl
      
If this step fails, see @@ -464,7 +464,7 @@ Take the following steps to install TensorFlow in an Anaconda environment:
      (tensorflow)$ pip install --ignore-installed --upgrade \
-     https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp34-cp34m-linux_x86_64.whl
+ https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp34-cp34m-linux_x86_64.whl @@ -632,14 +632,14 @@ This section documents the relevant values for Linux installations. CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp27-none-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp27-none-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.0-cp27-none-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.2-cp27-none-linux_x86_64.whl
 
Note that GPU support requires the NVIDIA hardware and software described in @@ -651,14 +651,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp34-cp34m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp34-cp34m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.0-cp34-cp34m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.2-cp34-cp34m-linux_x86_64.whl
 
Note that GPU support requires the NVIDIA hardware and software described in @@ -670,14 +670,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp35-cp35m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp35-cp35m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.0-cp35-cp35m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.2-cp35-cp35m-linux_x86_64.whl
 
@@ -689,14 +689,14 @@ Note that GPU support requires the NVIDIA hardware and software described in CPU only:
-https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.0-cp36-cp36m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.4.2-cp36-cp36m-linux_x86_64.whl
 
GPU support:
-https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.0-cp36-cp36m-linux_x86_64.whl
+https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.4.2-cp36-cp36m-linux_x86_64.whl
 
diff --git a/tensorflow/docs_src/install/install_mac.md b/tensorflow/docs_src/install/install_mac.md index 21f0a65c36c43b..f81fd320aa8212 100644 --- a/tensorflow/docs_src/install/install_mac.md +++ b/tensorflow/docs_src/install/install_mac.md @@ -109,7 +109,7 @@ Take the following steps to install TensorFlow with Virtualenv: TensorFlow in the active Virtualenv is as follows:
 $ pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.whl
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.2-py2-none-any.whl If you encounter installation problems, see [Common Installation Problems](#common-installation-problems). @@ -230,7 +230,7 @@ take the following steps: issue the following command:
 $ sudo pip3 install --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.whl 
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.2-py2-none-any.whl If the preceding command fails, see [installation problems](#common-installation-problems). @@ -339,7 +339,7 @@ Take the following steps to install TensorFlow in an Anaconda environment: TensorFlow for Python 2.7:
 (tensorflow)$ pip install --ignore-installed --upgrade \
-     https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.whl
+ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.2-py2-none-any.whl @@ -512,7 +512,7 @@ This section documents the relevant values for Mac OS installations.
-https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.whl
+https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.2-py2-none-any.whl
 
@@ -520,7 +520,7 @@ https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py2-none-any.
-https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.0-py3-none-any.whl
+https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.4.2-py3-none-any.whl
 
diff --git a/tensorflow/docs_src/install/install_sources.md b/tensorflow/docs_src/install/install_sources.md index 1d46f0a9a73ae0..ff8bbae552a726 100644 --- a/tensorflow/docs_src/install/install_sources.md +++ b/tensorflow/docs_src/install/install_sources.md @@ -132,7 +132,7 @@ The following NVIDIA software must be installed on your system: `LD_LIBRARY_PATH` environment variable as described in the NVIDIA documentation. * The NVIDIA drivers associated with NVIDIA's Cuda Toolkit. - * cuDNN (>= v3). We recommend version 5.1. For details, see + * cuDNN (>= v3). We recommend version 6.0. For details, see [NVIDIA's documentation](https://developer.nvidia.com/cudnn), particularly the description of appending the appropriate pathname to your `LD_LIBRARY_PATH` environment variable. @@ -342,10 +342,10 @@ Invoke `pip install` to install that pip package. The filename of the `.whl` file depends on your platform. For example, the following command will install the pip package -for TensorFlow 1.4.0 on Linux: +for TensorFlow 1.4.2 on Linux:
-$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.4.0-py2-none-any.whl
+$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.4.2-py2-none-any.whl
 
## Validate your installation @@ -434,8 +434,8 @@ Stack Overflow and specify the `tensorflow` tag. **Linux** - - + + @@ -449,7 +449,7 @@ Stack Overflow and specify the `tensorflow` tag. **Mac**
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.4.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
tensorflow_gpu-1.4.0GPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.568
tensorflow-1.4.2CPU2.7, 3.3-3.6GCC 4.8Bazel 0.5.4N/AN/A
tensorflow_gpu-1.4.2GPU2.7, 3.3-3.6GCC 4.8Bazel 0.5.468
tensorflow-1.3.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
tensorflow_gpu-1.3.0GPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.568
tensorflow-1.2.0CPU2.7, 3.3-3.6GCC 4.8Bazel 0.4.5N/AN/A
- + @@ -461,8 +461,8 @@ Stack Overflow and specify the `tensorflow` tag. **Windows**
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.4.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.4.2CPU2.7, 3.3-3.6Clang from xcodeBazel 0.5.4N/AN/A
tensorflow-1.3.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.2.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.5N/AN/A
tensorflow-1.1.0CPU2.7, 3.3-3.6Clang from xcodeBazel 0.4.2N/AN/A
- - + + diff --git a/tensorflow/docs_src/install/install_windows.md b/tensorflow/docs_src/install/install_windows.md index ae8749c2313d2c..960ed464c8ce6c 100644 --- a/tensorflow/docs_src/install/install_windows.md +++ b/tensorflow/docs_src/install/install_windows.md @@ -29,7 +29,7 @@ installed on your system: Ensure that you append the relevant Cuda pathnames to the `%PATH%` environment variable as described in the NVIDIA documentation. * The NVIDIA drivers associated with CUDA Toolkit 8.0. - * cuDNN v6.1. For details, see + * cuDNN v6.0. For details, see [NVIDIA's documentation](https://developer.nvidia.com/cudnn). Note that cuDNN is typically installed in a different location from the other CUDA DLLs. Ensure that you add the directory where you installed diff --git a/tensorflow/docs_src/mobile/index.md b/tensorflow/docs_src/mobile/index.md index a6f1422f6f170f..3c50fc6fa8a822 100644 --- a/tensorflow/docs_src/mobile/index.md +++ b/tensorflow/docs_src/mobile/index.md @@ -1,238 +1,36 @@ -# Building Mobile Apps with TensorFlow - -TensorFlow was designed from the ground up to be a good deep learning solution -for mobile platforms like Android and iOS. This guide is to help you understand -how to integrate TensorFlow into your mobile apps effectively and efficiently. - -## About this Guide - -This guide is aimed at developers who have a TensorFlow model that’s -successfully working in a desktop environment, and who want to integrate it into -a mobile application. Here are the main challenges you’ll face during that -process: - -- Understanding how to use Tensorflow for mobile. -- Building TensorFlow for your platform. -- Integrating the TensorFlow library into your application. -- Preparing your model file for mobile deployment. -- Optimizing for latency, RAM usage, model file size, and binary size. - -## Why run TensorFlow on mobile? - -Traditionally, deep learning has been associated with data centers and giant -clusters of high-powered GPU machines. However, it can be very expensive and -time-consuming to send all of the data a device has access to across a network -connection. Running on mobile makes it possible to deliver very interactive -applications in a way that’s not possible when you have to wait for a network -round trip. - -Here are some common use cases for on-device deep learning: - -### Speech Recognition - -There are a lot of interesting applications that can be built with a -speech-driven interface, and many of these require on-device processing. Most of -the time a user isn’t giving commands, and so streaming audio continuously to a -remote server would be a waste of bandwidth, since it would mostly be silence or -background noises. To solve this problem it’s common to have a small neural -network running on-device @{$tutorials/audio_recognition$listening out for a -particular keyword}. Once that keyword has been spotted, the rest of the -conversation can be transmitted over to the server for further processing if -more computing power is needed. - -### Image Recognition - -It can be very useful for a mobile app to be able to make sense of a camera -image. If your users are taking photos, recognizing what’s in them can help your -camera apps apply appropriate filters, or label the photos so they’re easily -findable. It’s important for embedded applications too, since you can use image -sensors to detect all sorts of interesting conditions, whether it’s spotting -endangered animals in the wild -or -[reporting how late your train is running](https://svds.com/tensorflow-image-recognition-raspberry-pi/). - -TensorFlow comes with several examples of recognizing the types of objects -inside images along with a variety of different pre-trained models, and they can -all be run on mobile devices. You can try out -our -[Tensorflow for Poets](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets/index.html#0) and -[Tensorflow for Poets 2: Optimize for Mobile](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets-2/index.html#0) codelabs to -see how to take a pretrained model and run some very fast and lightweight -training to teach it to recognize specific objects, and then optimize it to -run on mobile. - -### Object Localization - -Sometimes it’s important to know where objects are in an image as well as what -they are. There are lots of augmented reality use cases that could benefit a -mobile app, such as guiding users to the right component when offering them -help fixing their wireless network or providing informative overlays on top of -landscape features. Embedded applications often need to count objects that are -passing by them, whether it’s pests in a field of crops, or people, cars and -bikes going past a street lamp. - -TensorFlow offers a pretrained model for drawing bounding boxes around people -detected in images, together with tracking code to follow them over time. The -tracking is especially important for applications where you’re trying to count -how many objects are present over time, since it gives you a good idea when a -new object enters or leaves the scene. We have some sample code for this -available for Android [on -Github](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android), -and also a [more general object detection -model](https://github.com/tensorflow/models/tree/master/object_detection/README.md) -available as well. - -### Gesture Recognition - -It can be useful to be able to control applications with hand or other -gestures, either recognized from images or through analyzing accelerometer -sensor data. Creating those models is beyond the scope of this guide, but -TensorFlow is an effective way of deploying them. - -### Optical Character Recognition - -Google Translate’s live camera view is a great example of how effective -interactive on-device detection of text can be. - -
- -
- -There are multiple steps involved in recognizing text in images. You first have -to identify the areas where the text is present, which is a variation on the -object localization problem, and can be solved with similar techniques. Once you -have an area of text, you then need to interpret it as letters, and then use a -language model to help guess what words they represent. The simplest way to -estimate what letters are present is to segment the line of text into individual -letters, and then apply a simple neural network to the bounding box of each. You -can get good results with the kind of models used for MNIST, which you can find -in TensorFlow’s tutorials, though you may want a higher-resolution input. A -more advanced alternative is to use an LSTM model to process a whole line of -text at once, with the model itself handling the segmentation into different -characters. - -### Translation - -Translating from one language to another quickly and accurately, even if you -don’t have a network connection, is an important use case. Deep networks are -very effective at this sort of task, and you can find descriptions of a lot of -different models in the literature. Often these are sequence-to-sequence -recurrent models where you’re able to run a single graph to do the whole -translation, without needing to run separate parsing stages. - -### Text Classification - -If you want to suggest relevant prompts to users based on what they’re typing or -reading, it can be very useful to understand the meaning of the text. This is -where text classification comes in. Text classification is an umbrella term -that covers everything from sentiment analysis to topic discovery. You’re likely -to have your own categories or labels that you want to apply, so the best place -to start is with an example -like -[Skip-Thoughts](https://github.com/tensorflow/models/tree/master/skip_thoughts/), -and then train on your own examples. - -### Voice Synthesis - -A synthesized voice can be a great way of giving users feedback or aiding -accessibility, and recent advances such as -[WaveNet](https://deepmind.com/blog/wavenet-generative-model-raw-audio/) show -that deep learning can offer very natural-sounding speech. - -## How does it fit with the cloud? - -These examples of use cases give an idea of how on-device networks can -complement cloud services. Cloud has a great deal of computing power in a -controlled environment, but running on devices can offer higher interactivity. -In situations where the cloud is unavailable, or your cloud capacity is limited, -you can provide an offline experience, or reduce cloud workload by processing -easy cases on device. - -Doing on-device computation can also signal when it's time to switch to working -on the cloud. A good example of this is hotword detection in speech. Since -devices are able to constantly listen out for the keywords, this then triggers a -lot of traffic to cloud-based speech recognition once one is recognised. Without -the on-device component, the whole application wouldn’t be feasible, and this -pattern exists across several other applications as well. Recognizing that some -sensor input is interesting enough for further processing makes a lot of -interesting products possible. - -## What hardware and software should you have? - -TensorFlow runs on Ubuntu Linux, Windows 10, and OS X. For a list of all -supported operating systems and instructions to install TensorFlow, see -@{$install$Installing Tensorflow}. - -Some of the scripts in this guide require you to compile TensorFlow from source, -so you’ll need more than just `pip install` to work through all the sample code. - -To try out the mobile examples, you’ll need a device set up for development, -using -either [Android Studio](https://developer.android.com/studio/install.html), -or [XCode](https://developer.apple.com/xcode/) if you're developing for iOS. - -## What should you do before you get started? - -Before thinking about how to get your solution on mobile: - -1. Determine whether your problem is solvable by mobile machine learning -2. Create a labelled dataset to define your problem -3. Pick an effective model for the problem - -We'll discuss these in more detail below. - -### Is your problem solvable by mobile machine learning? - -Once you have an idea of the problem you want to solve, you need to make a plan -of how to build your solution. The most important first step is making sure that -your problem is actually solvable, and the best way to do that is to mock it up -using humans in the loop. - -For example, if you want to drive a robot toy car using voice commands, try -recording some audio from the device and listen back to it to see if you can -make sense of what’s being said. Often you’ll find there are problems in the -capture process, such as the motor drowning out speech or not being able to hear -at a distance, and you should tackle these problems before investing in the -modeling process. - -Another example would be giving photos taken from your app to people see if they -can classify what’s in them, in the way you’re looking for. If they can’t do -that (for example, trying to estimate calories in food from photos may be -impossible because all white soups look the same), then you’ll need to redesign -your experience to cope with that. A good rule of thumb is that if a human can’t -handle the task then it will be difficult to train a computer to do better. - -### Create a labelled dataset - -After you’ve solved any fundamental issues with your use case, you need to -create a labeled dataset to define what problem you’re trying to solve. This -step is extremely important, moreso than picking which model to use. You want it -to be as representative as possible of your actual use case, since the model -will only be effective at the task you teach it. It’s also worth investing in -tools to make labeling the data as efficient and accurate as possible. For -example, if you’re able to switch from having to click a button on a web -interface to simple keyboard shortcuts, you may be able to speed up the -generation process a lot. You should also start by doing the initial labeling -yourself, so you can learn about the difficulties and likely errors, and -possibly change your labeling or data capture process to avoid them. Once you -and your team are able to consistently label examples (that is once you -generally agree on the same labels for most examples), you can then try and -capture your knowledge in a manual and teach external raters how to run the same -process. - -### Pick an effective model - -The next step is to pick an effective model to use. You might be able to avoid -training a model from scratch if someone else has already implemented a model -similar to what you need; we have a repository of models implemented in -TensorFlow [on Github](https://github.com/tensorflow/models) that you can look -through. Lean towards the simplest model you can find, and try to get started as -soon as you have even a small amount of labelled data, since you’ll get the best -results when you’re able to iterate quickly. The shorter the time it takes to -try training a model and running it in s real application, the better overall -results you’ll see. It’s common for an algorithm to get great training accuracy -numbers but then fail to be useful within a real application because there’s a -mismatch between the dataset and real usage. Prototype end-to-end usage as soon -as possible to create a consistent user experience. +# Overview + +TensorFlow was designed to be a good deep learning solution for mobile +platforms. Currently we have two solutions for deploying machine learning +applications on mobile and embedded devices: @{$mobile/mobile_intro$TensorFlow +for Mobile} and @{$mobile/tflite$TensorFlow Lite}. + +## TensorFlow Lite versus TensorFlow Mobile + +Here are a few of the differences between the two: + +- TensorFlow Lite is an evolution of TensorFlow Mobile. In most cases, apps + developed with TensorFlow Lite will have a smaller binary size, fewer + dependencies, and better performance. + +- TensorFlow Lite is in developer preview, so not all use cases are covered yet. + We expect you to use TensorFlow Mobile to cover production cases. + +- TensorFlow Lite supports only a limited set of operators, so not all models + will work on it by default. TensorFlow for Mobile has a fuller set of + supported functionality. + +TensorFlow Lite provides better performance and a small binary size on mobile +platforms as well as the ability to leverage hardware acceleration if available +on their platforms. In addition, it has many fewer dependencies so it can be +built and hosted on simpler, more constrained device scenarios. TensorFlow Lite +also allows targeting accelerators through the [Neural Networks +API](https://developer.android.com/ndk/guides/neuralnetworks/index.html). + +TensorFlow Lite currently has coverage for a limited set of operators. While +TensorFlow for Mobile supports only a constrained set of ops by default, in +principle if you use an arbitrary operator in TensorFlow, it can be customized +to build that kernel. Thus use cases which are not currently supported by +TensorFlow Lite should continue to use TensorFlow for Mobile. As TensorFlow Lite +evolves, it will gain additional operators, and the decision will be easier to +make. \ No newline at end of file diff --git a/tensorflow/docs_src/mobile/leftnav_files b/tensorflow/docs_src/mobile/leftnav_files index 347c07d2330fb0..4d2c3b62341717 100644 --- a/tensorflow/docs_src/mobile/leftnav_files +++ b/tensorflow/docs_src/mobile/leftnav_files @@ -1,8 +1,11 @@ -### TensorFlow for Mobile index.md +### TensorFlow Lite +tflite/index.md +>>> +### TensorFlow Mobile +mobile_intro.md android_build.md ios_build.md -#raspi_build.md until this section gets rewritten, or TFLite takes over linking_libs.md prepare_models.md optimizing.md diff --git a/tensorflow/docs_src/mobile/mobile_intro.md b/tensorflow/docs_src/mobile/mobile_intro.md new file mode 100644 index 00000000000000..948563292a5fa2 --- /dev/null +++ b/tensorflow/docs_src/mobile/mobile_intro.md @@ -0,0 +1,247 @@ +# Introduction to TensorFlow Mobile + +TensorFlow was designed from the ground up to be a good deep learning solution +for mobile platforms like Android and iOS. This mobile guide should help you +understand how machine learning can work on mobile platforms and how to +integrate TensorFlow into your mobile apps effectively and efficiently. + +## About this Guide + +This guide is aimed at developers who have a TensorFlow model that’s +successfully working in a desktop environment, who want to integrate it into +a mobile application, and cannot use TensorFlow Lite. Here are the +main challenges you’ll face during that process: + +- Understanding how to use Tensorflow for mobile. +- Building TensorFlow for your platform. +- Integrating the TensorFlow library into your application. +- Preparing your model file for mobile deployment. +- Optimizing for latency, RAM usage, model file size, and binary size. + +## Common use cases for mobile machine learning + +**Why run TensorFlow on mobile?** + +Traditionally, deep learning has been associated with data centers and giant +clusters of high-powered GPU machines. However, it can be very expensive and +time-consuming to send all of the data a device has access to across a network +connection. Running on mobile makes it possible to deliver very interactive +applications in a way that’s not possible when you have to wait for a network +round trip. + +Here are some common use cases for on-device deep learning: + +### Speech Recognition + +There are a lot of interesting applications that can be built with a +speech-driven interface, and many of these require on-device processing. Most of +the time a user isn’t giving commands, and so streaming audio continuously to a +remote server would be a waste of bandwidth, since it would mostly be silence or +background noises. To solve this problem it’s common to have a small neural +network running on-device @{$tutorials/audio_recognition$listening out for a particular keyword}. +Once that keyword has been spotted, the rest of the +conversation can be transmitted over to the server for further processing if +more computing power is needed. + +### Image Recognition + +It can be very useful for a mobile app to be able to make sense of a camera +image. If your users are taking photos, recognizing what’s in them can help your +camera apps apply appropriate filters, or label the photos so they’re easily +findable. It’s important for embedded applications too, since you can use image +sensors to detect all sorts of interesting conditions, whether it’s spotting +endangered animals in the wild +or +[reporting how late your train is running](https://svds.com/tensorflow-image-recognition-raspberry-pi/). + +TensorFlow comes with several examples of recognizing the types of objects +inside images along with a variety of different pre-trained models, and they can +all be run on mobile devices. You can try out +our +[Tensorflow for Poets](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets/index.html#0) and +[Tensorflow for Poets 2: Optimize for Mobile](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets-2/index.html#0) codelabs to +see how to take a pretrained model and run some very fast and lightweight +training to teach it to recognize specific objects, and then optimize it to +run on mobile. + +### Object Localization + +Sometimes it’s important to know where objects are in an image as well as what +they are. There are lots of augmented reality use cases that could benefit a +mobile app, such as guiding users to the right component when offering them +help fixing their wireless network or providing informative overlays on top of +landscape features. Embedded applications often need to count objects that are +passing by them, whether it’s pests in a field of crops, or people, cars and +bikes going past a street lamp. + +TensorFlow offers a pretrained model for drawing bounding boxes around people +detected in images, together with tracking code to follow them over time. The +tracking is especially important for applications where you’re trying to count +how many objects are present over time, since it gives you a good idea when a +new object enters or leaves the scene. We have some sample code for this +available for Android [on +Github](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android), +and also a [more general object detection +model](https://github.com/tensorflow/models/tree/master/object_detection/README.md) +available as well. + +### Gesture Recognition + +It can be useful to be able to control applications with hand or other +gestures, either recognized from images or through analyzing accelerometer +sensor data. Creating those models is beyond the scope of this guide, but +TensorFlow is an effective way of deploying them. + +### Optical Character Recognition + +Google Translate’s live camera view is a great example of how effective +interactive on-device detection of text can be. + +
+ +
+ +There are multiple steps involved in recognizing text in images. You first have +to identify the areas where the text is present, which is a variation on the +object localization problem, and can be solved with similar techniques. Once you +have an area of text, you then need to interpret it as letters, and then use a +language model to help guess what words they represent. The simplest way to +estimate what letters are present is to segment the line of text into individual +letters, and then apply a simple neural network to the bounding box of each. You +can get good results with the kind of models used for MNIST, which you can find +in TensorFlow’s tutorials, though you may want a higher-resolution input. A +more advanced alternative is to use an LSTM model to process a whole line of +text at once, with the model itself handling the segmentation into different +characters. + +### Translation + +Translating from one language to another quickly and accurately, even if you +don’t have a network connection, is an important use case. Deep networks are +very effective at this sort of task, and you can find descriptions of a lot of +different models in the literature. Often these are sequence-to-sequence +recurrent models where you’re able to run a single graph to do the whole +translation, without needing to run separate parsing stages. + +### Text Classification + +If you want to suggest relevant prompts to users based on what they’re typing or +reading, it can be very useful to understand the meaning of the text. This is +where text classification comes in. Text classification is an umbrella term +that covers everything from sentiment analysis to topic discovery. You’re likely +to have your own categories or labels that you want to apply, so the best place +to start is with an example +like +[Skip-Thoughts](https://github.com/tensorflow/models/tree/master/skip_thoughts/), +and then train on your own examples. + +### Voice Synthesis + +A synthesized voice can be a great way of giving users feedback or aiding +accessibility, and recent advances such as +[WaveNet](https://deepmind.com/blog/wavenet-generative-model-raw-audio/) show +that deep learning can offer very natural-sounding speech. + +## Mobile machine learning and the cloud + +These examples of use cases give an idea of how on-device networks can +complement cloud services. Cloud has a great deal of computing power in a +controlled environment, but running on devices can offer higher interactivity. +In situations where the cloud is unavailable, or your cloud capacity is limited, +you can provide an offline experience, or reduce cloud workload by processing +easy cases on device. + +Doing on-device computation can also signal when it's time to switch to working +on the cloud. A good example of this is hotword detection in speech. Since +devices are able to constantly listen out for the keywords, this then triggers a +lot of traffic to cloud-based speech recognition once one is recognised. Without +the on-device component, the whole application wouldn’t be feasible, and this +pattern exists across several other applications as well. Recognizing that some +sensor input is interesting enough for further processing makes a lot of +interesting products possible. + +## What hardware and software should you have? + +TensorFlow runs on Ubuntu Linux, Windows 10, and OS X. For a list of all +supported operating systems and instructions to install TensorFlow, see +@{$install$Installing Tensorflow}. + +Note that some of the sample code we provide for mobile TensorFlow requires you +to compile TensorFlow from source, so you’ll need more than just `pip install` +to work through all the sample code. + +To try out the mobile examples, you’ll need a device set up for development, +using +either [Android Studio](https://developer.android.com/studio/install.html), +or [XCode](https://developer.apple.com/xcode/) if you're developing for iOS. + +## What should you do before you get started? + +Before thinking about how to get your solution on mobile: + +1. Determine whether your problem is solvable by mobile machine learning +2. Create a labelled dataset to define your problem +3. Pick an effective model for the problem + +We'll discuss these in more detail below. + +### Is your problem solvable by mobile machine learning? + +Once you have an idea of the problem you want to solve, you need to make a plan +of how to build your solution. The most important first step is making sure that +your problem is actually solvable, and the best way to do that is to mock it up +using humans in the loop. + +For example, if you want to drive a robot toy car using voice commands, try +recording some audio from the device and listen back to it to see if you can +make sense of what’s being said. Often you’ll find there are problems in the +capture process, such as the motor drowning out speech or not being able to hear +at a distance, and you should tackle these problems before investing in the +modeling process. + +Another example would be giving photos taken from your app to people see if they +can classify what’s in them, in the way you’re looking for. If they can’t do +that (for example, trying to estimate calories in food from photos may be +impossible because all white soups look the same), then you’ll need to redesign +your experience to cope with that. A good rule of thumb is that if a human can’t +handle the task then it will be difficult to train a computer to do better. + +### Create a labelled dataset + +After you’ve solved any fundamental issues with your use case, you need to +create a labeled dataset to define what problem you’re trying to solve. This +step is extremely important, moreso than picking which model to use. You want it +to be as representative as possible of your actual use case, since the model +will only be effective at the task you teach it. It’s also worth investing in +tools to make labeling the data as efficient and accurate as possible. For +example, if you’re able to switch from having to click a button on a web +interface to simple keyboard shortcuts, you may be able to speed up the +generation process a lot. You should also start by doing the initial labeling +yourself, so you can learn about the difficulties and likely errors, and +possibly change your labeling or data capture process to avoid them. Once you +and your team are able to consistently label examples (that is once you +generally agree on the same labels for most examples), you can then try and +capture your knowledge in a manual and teach external raters how to run the same +process. + +### Pick an effective model + +The next step is to pick an effective model to use. You might be able to avoid +training a model from scratch if someone else has already implemented a model +similar to what you need; we have a repository of models implemented in +TensorFlow [on Github](https://github.com/tensorflow/models) that you can look +through. Lean towards the simplest model you can find, and try to get started as +soon as you have even a small amount of labelled data, since you’ll get the best +results when you’re able to iterate quickly. The shorter the time it takes to +try training a model and running it in s real application, the better overall +results you’ll see. It’s common for an algorithm to get great training accuracy +numbers but then fail to be useful within a real application because there’s a +mismatch between the dataset and real usage. Prototype end-to-end usage as soon +as possible to create a consistent user experience. + +## Next Steps + +We suggest you get started by building one of our demos for +@{$mobile/android_build$Android} or @{$mobile/ios_build$iOS}. diff --git a/tensorflow/docs_src/mobile/tflite/index.md b/tensorflow/docs_src/mobile/tflite/index.md new file mode 100644 index 00000000000000..59daa2fe250905 --- /dev/null +++ b/tensorflow/docs_src/mobile/tflite/index.md @@ -0,0 +1,202 @@ +# Introduction to TensorFlow Lite + +TensorFlow Lite is TensorFlow’s lightweight solution for mobile and embedded +devices. It enables on-device machine learning inference with low latency and a +small binary size. TensorFlow Lite also supports hardware acceleration with the +[Android Neural Networks +API](https://developer.android.com/ndk/guides/neuralnetworks/index.html). + +TensorFlow Lite uses many techniques for achieving low latency such as +optimizing the kernels for mobile apps, pre-fused activations, and quantized +kernels that allow smaller and faster (fixed-point math) models. + +Most of our TensorFlow Lite documentation is [on +Github](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/lite) +for the time being. + +## What does TensorFlow Lite contain? + +TensorFlow Lite supports a set of core operators, both quantized and +float, which have been tuned for mobile platforms. They incorporate pre-fused +activations and biases to further enhance performance and quantized +accuracy. Additionally, TensorFlow Lite also supports using custom operations in +models. + +TensorFlow Lite defines a new model file format, based on +[FlatBuffers](https://google.github.io/flatbuffers/). FlatBuffers is an +open-sourced, efficient cross platform serialization library. It is similar to +[protocol buffers](https://developers.google.com/protocol-buffers/?hl=en), but +the primary difference is that FlatBuffers does not need a parsing/unpacking +step to a secondary representation before you can access data, often coupled +with per-object memory allocation. Also, the code footprint of FlatBuffers is an +order of magnitude smaller than protocol buffers. + +TensorFlow Lite has a new mobile-optimized interpreter, which has the key goals +of keeping apps lean and fast. The interpreter uses a static graph ordering and +a custom (less-dynamic) memory allocator to ensure minimal load, initialization, +and execution latency. + +TensorFlow Lite provides an interface to leverage hardware acceleration, if +available on the device. It does so via the Android Neural Networks library, +released as part of Android O-MR1. + +## Why do we need a new mobile-specific library? + +Machine Learning is changing the computing paradigm, and we see an emerging +trend of new use cases on mobile and embedded devices. Consumer expectations are +also trending toward natural, human-like interactions with their devices, driven +by the camera and voice interaction models. + +There are several factors which are fueling interest in this domain: + +- Innovation at the silicon layer is enabling new possibilities for hardware + acceleration, and frameworks such as the Android Neural Networks API make it + easy to leverage these. + +- Recent advances in real-time computer-vision and spoken language understanding + have led to mobile-optimized benchmark models being open sourced + (e.g. MobileNets, SqueezeNet). + +- Widely-available smart appliances create new possibilities for + on-device intelligence. + +- Interest in stronger user data privacy paradigms where user data does not need + to leave the mobile device. + +- Ability to serve ‘offline’ use cases, where the device does not need to be + connected to a network. + +We believe the next wave of machine learning applications will have significant +processing on mobile and embedded devices. + +## TensorFlow Lite developer preview highlights + +TensorFlow Lite is available as a developer preview and includes the +following: + +- A set of core operators, both quantized and float, many of which have been + tuned for mobile platforms. These can be used to create and run custom + models. Developers can also write their own custom operators and use them in + models. + +- A new [FlatBuffers](https://google.github.io/flatbuffers/)-based + model file format. + +- On-device interpreter with kernels optimized for faster execution on mobile. + +- TensorFlow converter to convert TensorFlow-trained models to the TensorFlow + Lite format. + +- Smaller in size: TensorFlow Lite is smaller than 300KB when all supported + operators are linked and less than 200KB when using only the operators needed + for supporting InceptionV3 and Mobilenet. + +- **Pre-tested models:** + + All of the following models are guaranteed to work out of the box: + + - Inception V3, a popular model for detecting the the dominant objects + present in an image. + + - [MobileNets](https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md), + a family of mobile-first computer vision models designed to effectively + maximize accuracy while being mindful of the restricted resources for an + on-device or embedded application. They are small, low-latency, low-power + models parameterized to meet the resource constraints of a variety of use + cases. They can be built upon for classification, detection, embeddings + and segmentation. MobileNet models are smaller but [lower in + accuracy](https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html) + than Inception V3. + + - On Device Smart Reply, an on-device model which provides one-touch + replies for an incoming text message by suggesting contextually relevant + messages. The model was built specifically for memory constrained devices + such as watches & phones and it has been successfully used to surface + [Smart Replies on Android + Wear](https://research.googleblog.com/2017/02/on-device-machine-intelligence.html) + to all first-party and third-party apps. + +- Quantized versions of the MobileNet model, which runs faster than the + non-quantized (float) version on CPU. + +- New Android demo app to illustrate the use of TensorFlow Lite with a quantized + MobileNet model for object classification. + +- Java and C++ API support + +Note: This is a developer release, and it’s likely that there will be changes in +the API in upcoming versions. We do not guarantee backward or forward +compatibility with this release. + +## Getting Started + +We recommend you try out TensorFlow Lite with the pre-tested models indicated +above. If you have an existing mode, you will need to test whether your model is +compatible with both the converter and the supported operator set. To test your +model, see the [documentation on +GitHub](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/lite). + +### Retrain Inception-V3 or MobileNet for a custom data set + +The pre-trained models mentioned above have been trained on the ImageNet data +set, which consists of 1000 predefined classes. If those classes are not +relevant or useful for your use case, you will need to retrain those +models. This technique is called transfer learning, which starts with a model +that has been already trained on a problem and will then be retrained on a +similar problem. Deep learning from scratch can take days, but transfer learning +can be done fairly quickly. In order to do this, you'll need to generate your +custom data set labeled with the relevant classes. + +The [TensorFlow for Poets](https://codelabs.developers.google.com/codelabs/tensorflow-for-poets/) +codelab walks through this process step-by-step. The retraining code supports +retraining for both floating point and quantized inference. + +## TensorFlow Lite Architecture + +The following diagram shows the architectural design of TensorFlow Lite: + + + +Starting with a trained TensorFlow model on disk, you'll convert that model to +the TensorFlow Lite file format (`.tflite`) using the TensorFlow Lite +Converter. Then you can use that converted file in your mobile application. + +Deploying the TensorFlow Lite model file uses: + +- Java API: A convenience wrapper around the C++ API on Android. + +- C++ API: Loads the TensorFlow Lite Model File and invokes the Interpreter. The + same library is available on both Android and iOS. + +- Interpreter: Executes the model using a set of kernels. The interpreter + supports selective kernel loading; without kernels it is only 100KB, and 300KB + with all the kernels loaded. This is a significant reduction from the 1.5M + required by TensorFlow Mobile. + +- On select Android devices, the Interpreter will use the Android Neural + Networks API for hardware acceleration, or default to CPU execution if none + are available. + +You can also implement custom kernels using the C++ API that can be used by the +Interpreter. + +## Future Work + +In future releases, TensorFlow Lite will support more models and built-in +operators, contain performance improvements for both fixed point and floating +point models, improvements to the tools to enable easier developer workflows and +support for other smaller devices and more. As we continue development, we hope +that TensorFlow Lite will greatly simplify the developer experience of targeting +a model for small devices. + +Future plans include using specialized machine learning hardware to get the best +possible performance for a particular model on a particular device. + +## Next Steps + +For the developer preview, most of our documentation is on GitHub. Please take a +look at the [TensorFlow Lite +repository](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/lite) +on GitHub for more information and for code samples, demo applications, and +more. + diff --git a/tensorflow/docs_src/tutorials/recurrent.md b/tensorflow/docs_src/tutorials/recurrent.md index 73d40575d79e07..3bae9bb457a069 100644 --- a/tensorflow/docs_src/tutorials/recurrent.md +++ b/tensorflow/docs_src/tutorials/recurrent.md @@ -51,10 +51,10 @@ The core of the model consists of an LSTM cell that processes one word at a time and computes probabilities of the possible values for the next word in the sentence. The memory state of the network is initialized with a vector of zeros and gets updated after reading each word. For computational reasons, we will -process data in mini-batches of size `batch_size`. In this example, it is important -to note that `current_batch_of_words` does not correspond to a "sentence" of words. -Every word in a batch should correspond to time t. Tensorflow will automatically sum -the gradients of each batch for you. +process data in mini-batches of size `batch_size`. In this example, it is +important to note that `current_batch_of_words` does not correspond to a +"sentence" of words. Every word in a batch should correspond to a time t. +TensorFlow will automatically sum the gradients of each batch for you. For example: ``` @@ -63,16 +63,17 @@ For example: [The, red, fox, jumped, high] words_in_dataset[0] = [The, The] -words_in_dataset[1] = [fox, fox] -words_in_dataset[2] = [is, jumped] -words_in_dataset[3] = [quick, high] -num_batches = 4, batch_size = 2, time_steps = 5 +words_in_dataset[1] = [brown, red] +words_in_dataset[2] = [fox, fox] +words_in_dataset[3] = [is, jumped] +words_in_dataset[4] = [quick, high] +batch_size = 2, time_steps = 5 ``` The basic pseudocode is as follows: ```python -words_in_dataset = tf.placeholder(tf.float32, [num_batches, batch_size, num_features]) +words_in_dataset = tf.placeholder(tf.float32, [time_steps, batch_size, num_features]) lstm = tf.contrib.rnn.BasicLSTMCell(lstm_size) # Initial state of the LSTM memory. hidden_state = tf.zeros([batch_size, lstm.state_size]) diff --git a/tensorflow/docs_src/tutorials/wide.md b/tensorflow/docs_src/tutorials/wide.md index ba16e12a723938..68dda1f2222b41 100644 --- a/tensorflow/docs_src/tutorials/wide.md +++ b/tensorflow/docs_src/tutorials/wide.md @@ -2,9 +2,9 @@ In this tutorial, we will use the tf.estimator API in TensorFlow to solve a binary classification problem: Given census data about a person such as age, -gender, education and occupation (the features), we will try to predict whether -or not the person earns more than 50,000 dollars a year (the target label). We -will train a **logistic regression** model, and given an individual's +education, marital status, and occupation (the features), we will try to predict +whether or not the person earns more than 50,000 dollars a year (the target +label). We will train a **logistic regression** model, and given an individual's information our model will output a number between 0 and 1, which can be interpreted as the probability that the individual has an annual income of over 50,000 dollars. @@ -15,31 +15,16 @@ To try the code for this tutorial: 1. @{$install$Install TensorFlow} if you haven't already. -2. Download [the tutorial code](https://www.tensorflow.org/code/tensorflow/examples/learn/wide_n_deep_tutorial.py). +2. Download [the tutorial code](https://github.com/tensorflow/models/tree/master/official/wide_deep/). -3. Install the pandas data analysis library. tf.estimator doesn't require pandas, but it does support it, and this tutorial uses pandas. To install pandas: +3. Execute the data download script we provide to you: - a. Get `pip`: - - # Ubuntu/Linux 64-bit - $ sudo apt-get install python-pip python-dev - - # macOS - $ sudo easy_install pip - $ sudo easy_install --upgrade six - - b. Use `pip` to install pandas: - - $ pip install -U pandas - - If you have trouble installing pandas, consult the - [instructions](https://pandas.pydata.org/pandas-docs/stable/install.html) - on the pandas site. + $ python data_download.py 4. Execute the tutorial code with the following command to train the linear model described in this tutorial: - $ python wide_n_deep_tutorial.py --model_type=wide + $ python wide_deep.py --model_type=wide Read on to find out how this code builds its linear model. @@ -47,51 +32,23 @@ Read on to find out how this code builds its linear model. The dataset we'll be using is the [Census Income Dataset](https://archive.ics.uci.edu/ml/datasets/Census+Income). -You can download the -[training data](https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data) -and [test data](https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test) -manually or use code like this: - -```python -import tempfile -import urllib -train_file = tempfile.NamedTemporaryFile() -test_file = tempfile.NamedTemporaryFile() -urllib.urlretrieve("https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data", train_file.name) -urllib.urlretrieve("https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test", test_file.name) -``` - -Once the CSV files are downloaded, let's read them into -[Pandas](https://pandas.pydata.org/) dataframes. - -```python -import pandas as pd -CSV_COLUMNS = [ - "age", "workclass", "fnlwgt", "education", "education_num", - "marital_status", "occupation", "relationship", "race", "gender", - "capital_gain", "capital_loss", "hours_per_week", "native_country", - "income_bracket"] -df_train = pd.read_csv(train_file.name, names=CSV_COLUMNS, skipinitialspace=True) -df_test = pd.read_csv(test_file.name, names=CSV_COLUMNS, skipinitialspace=True, skiprows=1) -``` +We have provided +[data_download.py](https://github.com/tensorflow/models/tree/master/official/wide_deep/data_download.py) +which downloads the code and performs some additional cleanup. Since the task is a binary classification problem, we'll construct a label column named "label" whose value is 1 if the income is over 50K, and 0 -otherwise. - -```python -train_labels = (df_train["income_bracket"].apply(lambda x: ">50K" in x)).astype(int) -test_labels = (df_test["income_bracket"].apply(lambda x: ">50K" in x)).astype(int) -``` +otherwise. For reference, see `input_fn` in +[wide_deep.py](https://github.com/tensorflow/models/tree/master/official/wide_deep/wide_deep.py). Next, let's take a look at the dataframe and see which columns we can use to predict the target label. The columns can be grouped into two types—categorical and continuous columns: * A column is called **categorical** if its value can only be one of the - categories in a finite set. For example, the native country of a person - (U.S., India, Japan, etc.) or the education level (high school, college, - etc.) are categorical columns. + categories in a finite set. For example, the relationship status of a person + (wife, husband, unmarried, etc.) or the education level (high school, + college, etc.) are categorical columns. * A column is called **continuous** if its value can be any numerical value in a continuous range. For example, the capital gain of a person (e.g. $14,084) is a continuous column. @@ -127,7 +84,7 @@ Here's a list of columns available in the Census Income dataset: : : : individual. : | income | Categorical | ">50K" or "<=50K", meaning | : : : whether the person makes more : -: : : than $50,000 annually. : +: : : than $50,000 annually. : ## Converting Data into Tensors @@ -136,50 +93,56 @@ Input Builder function. This builder function will not be called until it is later passed to tf.estimator.Estimator methods such as `train` and `evaluate`. The purpose of this function is to construct the input data, which is represented in the form of @{tf.Tensor}s or @{tf.SparseTensor}s. -In more detail, the Input Builder function returns the following as a pair: +In more detail, the input builder function returns the following as a pair: -1. `feature_cols`: A dict from feature column names to `Tensors` or +1. `features`: A dict from feature column names to `Tensors` or `SparseTensors`. -2. `label`: A `Tensor` containing the label column. +2. `labels`: A `Tensor` containing the label column. -The keys of the `feature_cols` will be used to construct columns in the -next section. Because we want to call the `train` and `evaluate` methods with +The keys of the `features` will be used to construct columns in the next +section. Because we want to call the `train` and `evaluate` methods with different data, we define a method that returns an input function based on the given data. Note that the returned input function will be called while constructing the TensorFlow graph, not while running the graph. What it is returning is a representation of the input data as the fundamental unit of TensorFlow computations, a `Tensor` (or `SparseTensor`). -We use the `tf.estimator.inputs.pandas_input_fn` method to create an input -function from pandas dataframes. -Each continuous column in the train or test dataframe -will be converted into a `Tensor`, which in general is a good format to -represent dense data. For categorical data, we must represent the data as a -`SparseTensor`. This data format is good for representing sparse data. -Another more advanced way to represent input data would be to -construct an @{$python/io_ops#inputs-and-readers$Inputs And Readers} -that represents a file or other data source, and iterates through the file as -TensorFlow runs the graph. +Each continuous column in the train or test data will be converted into a +`Tensor`, which in general is a good format to represent dense data. For +categorical data, we must represent the data as a `SparseTensor`. This data +format is good for representing sparse data. Our `input_fn` uses the `tf.data` +API, which makes it easy to apply transformations to our dataset: ```python -def input_fn(data_file, num_epochs, shuffle): - """Input builder function.""" - df_data = pd.read_csv( - tf.gfile.Open(data_file), - names=CSV_COLUMNS, - skipinitialspace=True, - engine="python", - skiprows=1) - # remove NaN elements - df_data = df_data.dropna(how="any", axis=0) - labels = df_data["income_bracket"].apply(lambda x: ">50K" in x).astype(int) - return tf.estimator.inputs.pandas_input_fn( - x=df_data, - y=labels, - batch_size=100, - num_epochs=num_epochs, - shuffle=shuffle, - num_threads=5) +def input_fn(data_file, num_epochs, shuffle, batch_size): + """Generate an input function for the Estimator.""" + assert tf.gfile.Exists(data_file), ( + '%s not found. Please make sure you have either run data_download.py or ' + 'set both arguments --train_data and --test_data.' % data_file) + + def parse_csv(value): + print('Parsing', data_file) + columns = tf.decode_csv(value, record_defaults=_CSV_COLUMN_DEFAULTS) + features = dict(zip(_CSV_COLUMNS, columns)) + labels = features.pop('income_bracket') + return features, tf.equal(labels, '>50K') + + # Extract lines from input files using the Dataset API. + dataset = tf.data.TextLineDataset(data_file) + + if shuffle: + dataset = dataset.shuffle(buffer_size=_SHUFFLE_BUFFER) + + dataset = dataset.map(parse_csv, num_parallel_calls=5) + + # We call repeat after shuffling, rather than before, to prevent separate + # epochs from blending together. + dataset = dataset.repeat(num_epochs) + dataset = dataset.batch(batch_size) + + iterator = dataset.make_one_shot_iterator() + features, labels = iterator.get_next() + return features, labels ``` ## Selecting and Engineering Features for the Model @@ -198,13 +161,15 @@ To define a feature column for a categorical feature, we can create a `CategoricalColumn` using the tf.feature_column API. If you know the set of all possible feature values of a column and there are only a few of them, you can use `categorical_column_with_vocabulary_list`. Each key in the list will get -assigned an auto-incremental ID starting from 0. For example, for the `gender` -column we can assign the feature string "Female" to an integer ID of 0 and -"Male" to 1 by doing: +assigned an auto-incremental ID starting from 0. For example, for the +`relationship` column we can assign the feature string "Husband" to an integer +ID of 0 and "Not-in-family" to 1, etc., by doing: ```python -gender = tf.feature_column.categorical_column_with_vocabulary_list( - "gender", ["Female", "Male"]) +relationship = tf.feature_column.categorical_column_with_vocabulary_list( + 'relationship', [ + 'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried', + 'Other-relative']) ``` What if we don't know the set of possible values in advance? Not a problem. We @@ -212,7 +177,7 @@ can use `categorical_column_with_hash_bucket` instead: ```python occupation = tf.feature_column.categorical_column_with_hash_bucket( - "occupation", hash_bucket_size=1000) + 'occupation', hash_bucket_size=1000) ``` What will happen is that each possible value in the feature column `occupation` @@ -241,29 +206,29 @@ We'll do the similar trick to define the other categorical features: ```python education = tf.feature_column.categorical_column_with_vocabulary_list( - "education", [ - "Bachelors", "HS-grad", "11th", "Masters", "9th", - "Some-college", "Assoc-acdm", "Assoc-voc", "7th-8th", - "Doctorate", "Prof-school", "5th-6th", "10th", "1st-4th", - "Preschool", "12th" - ]) + 'education', [ + 'Bachelors', 'HS-grad', '11th', 'Masters', '9th', 'Some-college', + 'Assoc-acdm', 'Assoc-voc', '7th-8th', 'Doctorate', 'Prof-school', + '5th-6th', '10th', '1st-4th', 'Preschool', '12th']) + marital_status = tf.feature_column.categorical_column_with_vocabulary_list( - "marital_status", [ - "Married-civ-spouse", "Divorced", "Married-spouse-absent", - "Never-married", "Separated", "Married-AF-spouse", "Widowed" - ]) + 'marital_status', [ + 'Married-civ-spouse', 'Divorced', 'Married-spouse-absent', + 'Never-married', 'Separated', 'Married-AF-spouse', 'Widowed']) + relationship = tf.feature_column.categorical_column_with_vocabulary_list( - "relationship", [ - "Husband", "Not-in-family", "Wife", "Own-child", "Unmarried", - "Other-relative" - ]) + 'relationship', [ + 'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried', + 'Other-relative']) + workclass = tf.feature_column.categorical_column_with_vocabulary_list( - "workclass", [ - "Self-emp-not-inc", "Private", "State-gov", "Federal-gov", - "Local-gov", "?", "Self-emp-inc", "Without-pay", "Never-worked" - ]) -native_country = tf.feature_column.categorical_column_with_hash_bucket( - "native_country", hash_bucket_size=1000) + 'workclass', [ + 'Self-emp-not-inc', 'Private', 'State-gov', 'Federal-gov', + 'Local-gov', '?', 'Self-emp-inc', 'Without-pay', 'Never-worked']) + +# To show an example of hashing: +occupation = tf.feature_column.categorical_column_with_hash_bucket( + 'occupation', hash_bucket_size=1000) ``` ### Base Continuous Feature Columns @@ -272,11 +237,11 @@ Similarly, we can define a `NumericColumn` for each continuous feature column that we want to use in the model: ```python -age = tf.feature_column.numeric_column("age") -education_num = tf.feature_column.numeric_column("education_num") -capital_gain = tf.feature_column.numeric_column("capital_gain") -capital_loss = tf.feature_column.numeric_column("capital_loss") -hours_per_week = tf.feature_column.numeric_column("hours_per_week") +age = tf.feature_column.numeric_column('age') +education_num = tf.feature_column.numeric_column('education_num') +capital_gain = tf.feature_column.numeric_column('capital_gain') +capital_loss = tf.feature_column.numeric_column('capital_loss') +hours_per_week = tf.feature_column.numeric_column('hours_per_week') ``` ### Making Continuous Features Categorical through Bucketization @@ -322,7 +287,7 @@ columns** to the model. ```python education_x_occupation = tf.feature_column.crossed_column( - ["education", "occupation"], hash_bucket_size=1000) + ['education', 'occupation'], hash_bucket_size=1000) ``` We can also create a `CrossedColumn` over more than two columns. Each @@ -332,7 +297,7 @@ or even another `CrossColumn`. Here's an example: ```python age_buckets_x_education_x_occupation = tf.feature_column.crossed_column( - [age_buckets, "education", "occupation"], hash_bucket_size=1000) + [age_buckets, 'education', 'occupation'], hash_bucket_size=1000) ``` ## Defining The Logistic Regression Model @@ -352,20 +317,18 @@ added to the `feature_columns` field of a model: ```python base_columns = [ - gender, native_country, education, occupation, workclass, relationship, + education, marital_status, relationship, workclass, occupation, age_buckets, ] crossed_columns = [ tf.feature_column.crossed_column( - ["education", "occupation"], hash_bucket_size=1000), + ['education', 'occupation'], hash_bucket_size=1000), tf.feature_column.crossed_column( - [age_buckets, "education", "occupation"], hash_bucket_size=1000), - tf.feature_column.crossed_column( - ["native_country", "occupation"], hash_bucket_size=1000) + [age_buckets, 'education', 'occupation'], hash_bucket_size=1000), ] model_dir = tempfile.mkdtemp() -m = tf.estimator.LinearClassifier( +model = tf.estimator.LinearClassifier( model_dir=model_dir, feature_columns=base_columns + crossed_columns) ``` @@ -377,34 +340,29 @@ in `model_dir`. ## Training and Evaluating Our Model After adding all the features to the model, now let's look at how to actually -train the model. Training a model is just a one-liner using the tf.estimator -API: +train the model. Training a model is just a single command using the +tf.estimator API: ```python -# set num_epochs to None to get infinite stream of data. -m.train( - input_fn=input_fn(train_file.name, num_epochs=None, shuffle=True), - steps=train_steps) +model.train(input_fn=lambda: input_fn(train_data, num_epochs, True, batch_size)) ``` After the model is trained, we can evaluate how good our model is at predicting the labels of the holdout data: ```python -results = m.evaluate( - input_fn=input_fn(test_file.name, num_epochs=1, shuffle=False), - steps=None) -print("model directory = %s" % model_dir) +results = model.evaluate(input_fn=lambda: input_fn( + test_data, 1, False, batch_size)) for key in sorted(results): - print("%s: %s" % (key, results[key])) + print('%s: %s' % (key, results[key])) ``` -The first line of the output should be something like `accuracy: 0.83557522`, -which means the accuracy is 83.6%. Feel free to try more features and -transformations and see if you can do even better! +The first line of the final output should be something like +`accuracy: 0.83557522`, which means the accuracy is 83.6%. Feel free to try more +features and transformations and see if you can do even better! If you'd like to see a working end-to-end example, you can download our -[example code](https://www.tensorflow.org/code/tensorflow/examples/learn/wide_n_deep_tutorial.py). +[example code](https://github.com/tensorflow/models/tree/master/official/wide_deep/wide_deep.py) and set the `model_type` flag to `wide`. ## Adding Regularization to Prevent Overfitting @@ -421,12 +379,12 @@ In the Linear Model library, you can add L1 and L2 regularizations to the model as: ``` -m = tf.estimator.LinearClassifier( +model = tf.estimator.LinearClassifier( model_dir=model_dir, feature_columns=base_columns + crossed_columns, optimizer=tf.train.FtrlOptimizer( - learning_rate=0.1, - l1_regularization_strength=1.0, - l2_regularization_strength=1.0)) + learning_rate=0.1, + l1_regularization_strength=1.0, + l2_regularization_strength=1.0)) ``` One important difference between L1 and L2 regularization is that L1 @@ -447,17 +405,17 @@ you a desirable model size. Finally, let's take a minute to talk about what the Logistic Regression model actually looks like in case you're not already familiar with it. We'll denote the label as \\(Y\\), and the set of observed features as a feature vector -\\(\mathbf{x}=[x_1, x_2, ..., x_d]\\). We define \\(Y=1\\) if an individual earned > -50,000 dollars and \\(Y=0\\) otherwise. In Logistic Regression, the probability of -the label being positive (\\(Y=1\\)) given the features \\(\mathbf{x}\\) is given -as: +\\(\mathbf{x}=[x_1, x_2, ..., x_d]\\). We define \\(Y=1\\) if an individual +earned > 50,000 dollars and \\(Y=0\\) otherwise. In Logistic Regression, the +probability of the label being positive (\\(Y=1\\)) given the features +\\(\mathbf{x}\\) is given as: $$ P(Y=1|\mathbf{x}) = \frac{1}{1+\exp(-(\mathbf{w}^T\mathbf{x}+b))}$$ -where \\(\mathbf{w}=[w_1, w_2, ..., w_d]\\) are the model weights for the features -\\(\mathbf{x}=[x_1, x_2, ..., x_d]\\). \\(b\\) is a constant that is often called -the **bias** of the model. The equation consists of two parts—A linear model and -a logistic function: +where \\(\mathbf{w}=[w_1, w_2, ..., w_d]\\) are the model weights for the +features \\(\mathbf{x}=[x_1, x_2, ..., x_d]\\). \\(b\\) is a constant that is +often called the **bias** of the model. The equation consists of two parts—A +linear model and a logistic function: * **Linear Model**: First, we can see that \\(\mathbf{w}^T\mathbf{x}+b = b + w_1x_1 + ... +w_dx_d\\) is a linear model where the output is a linear @@ -465,16 +423,17 @@ a logistic function: prediction one would make without observing any features. The model weight \\(w_i\\) reflects how the feature \\(x_i\\) is correlated with the positive label. If \\(x_i\\) is positively correlated with the positive label, the - weight \\(w_i\\) increases, and the probability \\(P(Y=1|\mathbf{x})\\) will be - closer to 1. On the other hand, if \\(x_i\\) is negatively correlated with the - positive label, then the weight \\(w_i\\) decreases and the probability - \\(P(Y=1|\mathbf{x})\\) will be closer to 0. + weight \\(w_i\\) increases, and the probability \\(P(Y=1|\mathbf{x})\\) will + be closer to 1. On the other hand, if \\(x_i\\) is negatively correlated + with the positive label, then the weight \\(w_i\\) decreases and the + probability \\(P(Y=1|\mathbf{x})\\) will be closer to 0. * **Logistic Function**: Second, we can see that there's a logistic function - (also known as the sigmoid function) \\(S(t) = 1/(1+\exp(-t))\\) being applied - to the linear model. The logistic function is used to convert the output of - the linear model \\(\mathbf{w}^T\mathbf{x}+b\\) from any real number into the - range of \\([0, 1]\\), which can be interpreted as a probability. + (also known as the sigmoid function) \\(S(t) = 1/(1+\exp(-t))\\) being + applied to the linear model. The logistic function is used to convert the + output of the linear model \\(\mathbf{w}^T\mathbf{x}+b\\) from any real + number into the range of \\([0, 1]\\), which can be interpreted as a + probability. Model training is an optimization problem: The goal is to find a set of model weights (i.e. model parameters) to minimize a **loss function** defined over the diff --git a/tensorflow/docs_src/tutorials/wide_and_deep.md b/tensorflow/docs_src/tutorials/wide_and_deep.md index 16f7925e8dd546..44677a810bc5c2 100644 --- a/tensorflow/docs_src/tutorials/wide_and_deep.md +++ b/tensorflow/docs_src/tutorials/wide_and_deep.md @@ -1,13 +1,12 @@ # TensorFlow Wide & Deep Learning Tutorial -In the previous @{$wide$TensorFlow Linear Model Tutorial}, -we trained a logistic regression model to predict the probability that the -individual has an annual income of over 50,000 dollars using the +In the previous @{$wide$TensorFlow Linear Model Tutorial}, we trained a logistic +regression model to predict the probability that the individual has an annual +income of over 50,000 dollars using the [Census Income Dataset](https://archive.ics.uci.edu/ml/datasets/Census+Income). -TensorFlow is -great for training deep neural networks too, and you might be thinking which one -you should choose—Well, why not both? Would it be possible to combine the -strengths of both in one model? +TensorFlow is great for training deep neural networks too, and you might be +thinking which one you should choose—well, why not both? Would it be possible to +combine the strengths of both in one model? In this tutorial, we'll introduce how to use the tf.estimator API to jointly train a wide linear model and a deep feed-forward neural network. This approach @@ -40,33 +39,18 @@ To try the code for this tutorial: 1. @{$install$Install TensorFlow} if you haven't already. -2. Download [the tutorial code](https://www.tensorflow.org/code/tensorflow/examples/learn/wide_n_deep_tutorial.py). +2. Download [the tutorial code](https://github.com/tensorflow/models/tree/master/official/wide_deep/). -3. Install the pandas data analysis library. tf.estimator doesn't require pandas, but it does support it, and this tutorial uses pandas. To install pandas: +3. Execute the data download script we provide to you: - a. Get `pip`: + $ python data_download.py - # Ubuntu/Linux 64-bit - $ sudo apt-get install python-pip python-dev +4. Execute the tutorial code with the following command to train the wide and +deep model described in this tutorial: - # Mac OS X - $ sudo easy_install pip - $ sudo easy_install --upgrade six + $ python wide_deep.py - b. Use `pip` to install pandas: - - $ sudo pip install pandas - - If you have trouble installing pandas, consult the - [instructions](https://pandas.pydata.org/pandas-docs/stable/install.html) - on the pandas site. - -4. Execute the tutorial code with the following command to train the linear -model described in this tutorial: - - $ python wide_n_deep_tutorial.py --model_type=wide_n_deep - -Read on to find out how this code builds its linear model. +Read on to find out how this code builds its model. ## Define Base Feature Columns @@ -78,43 +62,37 @@ part and the deep part of the model. ```python import tensorflow as tf -gender = tf.feature_column.categorical_column_with_vocabulary_list( - "gender", ["Female", "Male"]) +# Continuous columns +age = tf.feature_column.numeric_column('age') +education_num = tf.feature_column.numeric_column('education_num') +capital_gain = tf.feature_column.numeric_column('capital_gain') +capital_loss = tf.feature_column.numeric_column('capital_loss') +hours_per_week = tf.feature_column.numeric_column('hours_per_week') + education = tf.feature_column.categorical_column_with_vocabulary_list( - "education", [ - "Bachelors", "HS-grad", "11th", "Masters", "9th", - "Some-college", "Assoc-acdm", "Assoc-voc", "7th-8th", - "Doctorate", "Prof-school", "5th-6th", "10th", "1st-4th", - "Preschool", "12th" - ]) + 'education', [ + 'Bachelors', 'HS-grad', '11th', 'Masters', '9th', 'Some-college', + 'Assoc-acdm', 'Assoc-voc', '7th-8th', 'Doctorate', 'Prof-school', + '5th-6th', '10th', '1st-4th', 'Preschool', '12th']) + marital_status = tf.feature_column.categorical_column_with_vocabulary_list( - "marital_status", [ - "Married-civ-spouse", "Divorced", "Married-spouse-absent", - "Never-married", "Separated", "Married-AF-spouse", "Widowed" - ]) + 'marital_status', [ + 'Married-civ-spouse', 'Divorced', 'Married-spouse-absent', + 'Never-married', 'Separated', 'Married-AF-spouse', 'Widowed']) + relationship = tf.feature_column.categorical_column_with_vocabulary_list( - "relationship", [ - "Husband", "Not-in-family", "Wife", "Own-child", "Unmarried", - "Other-relative" - ]) + 'relationship', [ + 'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried', + 'Other-relative']) + workclass = tf.feature_column.categorical_column_with_vocabulary_list( - "workclass", [ - "Self-emp-not-inc", "Private", "State-gov", "Federal-gov", - "Local-gov", "?", "Self-emp-inc", "Without-pay", "Never-worked" - ]) + 'workclass', [ + 'Self-emp-not-inc', 'Private', 'State-gov', 'Federal-gov', + 'Local-gov', '?', 'Self-emp-inc', 'Without-pay', 'Never-worked']) # To show an example of hashing: occupation = tf.feature_column.categorical_column_with_hash_bucket( - "occupation", hash_bucket_size=1000) -native_country = tf.feature_column.categorical_column_with_hash_bucket( - "native_country", hash_bucket_size=1000) - -# Continuous base columns. -age = tf.feature_column.numeric_column("age") -education_num = tf.feature_column.numeric_column("education_num") -capital_gain = tf.feature_column.numeric_column("capital_gain") -capital_loss = tf.feature_column.numeric_column("capital_loss") -hours_per_week = tf.feature_column.numeric_column("hours_per_week") + 'occupation', hash_bucket_size=1000) # Transformations. age_buckets = tf.feature_column.bucketized_column( @@ -128,20 +106,20 @@ columns: ```python base_columns = [ - gender, native_country, education, occupation, workclass, relationship, + education, marital_status, relationship, workclass, occupation, age_buckets, ] crossed_columns = [ tf.feature_column.crossed_column( - ["education", "occupation"], hash_bucket_size=1000), - tf.feature_column.crossed_column( - [age_buckets, "education", "occupation"], hash_bucket_size=1000), + ['education', 'occupation'], hash_bucket_size=1000), tf.feature_column.crossed_column( - ["native_country", "occupation"], hash_bucket_size=1000) + [age_buckets, 'education', 'occupation'], hash_bucket_size=1000), ] ``` +You can also see the @{$wide$TensorFlow Linear Model Tutorial} for more details. + Wide models with crossed feature columns can memorize sparse interactions between features effectively. That being said, one limitation of crossed feature columns is that they do not generalize to feature combinations that have not @@ -158,36 +136,35 @@ concatenated with the continuous features, and then fed into the hidden layers of a neural network in the forward pass. The embedding values are initialized randomly, and are trained along with all other model parameters to minimize the training loss. If you're interested in learning more about embeddings, check out -the TensorFlow tutorial on -[Vector Representations of Words](https://www.tensorflow.org/versions/r0.9/tutorials/word2vec/index.html), -or [Word Embedding](https://en.wikipedia.org/wiki/Word_embedding) on Wikipedia. +the TensorFlow tutorial on @{$word2vec$Vector Representations of Words} or +[Word embedding](https://en.wikipedia.org/wiki/Word_embedding) on Wikipedia. Another way to represent categorical columns to feed into a neural network is -via a multi-hot representation. This is often appropriate for categorical -columns with only a few possible values. E.g. for the gender column, `"Male"` -can be represented as `[1, 0]` and `"Female"` as `[0, 1]`. This is a fixed -representation, whereas embeddings are more flexible and calculated at training -time. +via a one-hot or multi-hot representation. This is often appropriate for +categorical columns with only a few possible values. As an example of a one-hot +representation, for the relationship column, `"Husband"` can be represented as +[1, 0, 0, 0, 0, 0], and `"Not-in-family"` as [0, 1, 0, 0, 0, 0], etc. This is a +fixed representation, whereas embeddings are more flexible and calculated at +training time. We'll configure the embeddings for the categorical columns using `embedding_column`, and concatenate them with the continuous columns. -We also use `indicator_column` to create multi-hot representation of some +We also use `indicator_column` to create multi-hot representations of some categorical columns. ```python deep_columns = [ - tf.feature_column.indicator_column(workclass), - tf.feature_column.indicator_column(education), - tf.feature_column.indicator_column(gender), - tf.feature_column.indicator_column(relationship), - # To show an example of embedding - tf.feature_column.embedding_column(native_country, dimension=8), - tf.feature_column.embedding_column(occupation, dimension=8), age, education_num, capital_gain, capital_loss, hours_per_week, + tf.feature_column.indicator_column(workclass), + tf.feature_column.indicator_column(education), + tf.feature_column.indicator_column(marital_status), + tf.feature_column.indicator_column(relationship), + # To show an example of embedding + tf.feature_column.embedding_column(occupation, dimension=8), ] ``` @@ -221,11 +198,9 @@ handled for you under the hood, so you simply need to create a `DNNLinearCombinedClassifier`: ```python -import tempfile -model_dir = tempfile.mkdtemp() -m = tf.estimator.DNNLinearCombinedClassifier( - model_dir=model_dir, - linear_feature_columns=crossed_columns, +model = tf.estimator.DNNLinearCombinedClassifier( + model_dir='/tmp/census_model', + linear_feature_columns=base_columns + crossed_columns, dnn_feature_columns=deep_columns, dnn_hidden_units=[100, 50]) ``` @@ -233,88 +208,32 @@ m = tf.estimator.DNNLinearCombinedClassifier( ## Training and Evaluating The Model Before we train the model, let's read in the Census dataset as we did in the -@{$wide$TensorFlow Linear Model tutorial}. The code for -input data processing is provided here again for your convenience: +@{$wide$TensorFlow Linear Model tutorial}. See `data_download.py` as well as +`input_fn` within +[`wide_deep.py`](https://github.com/tensorflow/models/tree/master/official/wide_deep/wide_deep.py). + +After reading in the data, you can train and evaluate the model: ```python -import pandas as pd -import urllib - -# Define the column names for the data sets. -CSV_COLUMNS = [ - "age", "workclass", "fnlwgt", "education", "education_num", - "marital_status", "occupation", "relationship", "race", "gender", - "capital_gain", "capital_loss", "hours_per_week", "native_country", - "income_bracket" -] +# Train and evaluate the model every `FLAGS.epochs_per_eval` epochs. +for n in range(FLAGS.train_epochs // FLAGS.epochs_per_eval): + model.train(input_fn=lambda: input_fn( + FLAGS.train_data, FLAGS.epochs_per_eval, True, FLAGS.batch_size)) -def maybe_download(train_data, test_data): - """Maybe downloads training data and returns train and test file names.""" - if train_data: - train_file_name = train_data - else: - train_file = tempfile.NamedTemporaryFile(delete=False) - urllib.request.urlretrieve( - "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data", - train_file.name) # pylint: disable=line-too-long - train_file_name = train_file.name - train_file.close() - print("Training data is downloaded to %s" % train_file_name) - - if test_data: - test_file_name = test_data - else: - test_file = tempfile.NamedTemporaryFile(delete=False) - urllib.request.urlretrieve( - "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test", - test_file.name) # pylint: disable=line-too-long - test_file_name = test_file.name - test_file.close() - print("Test data is downloaded to %s"% test_file_name) - - return train_file_name, test_file_name - -def input_fn(data_file, num_epochs, shuffle): - """Input builder function.""" - df_data = pd.read_csv( - tf.gfile.Open(data_file), - names=CSV_COLUMNS, - skipinitialspace=True, - engine="python", - skiprows=1) - # remove NaN elements - df_data = df_data.dropna(how="any", axis=0) - labels = df_data["income_bracket"].apply(lambda x: ">50K" in x).astype(int) - return tf.estimator.inputs.pandas_input_fn( - x=df_data, - y=labels, - batch_size=100, - num_epochs=num_epochs, - shuffle=shuffle, - num_threads=5) -``` + results = model.evaluate(input_fn=lambda: input_fn( + FLAGS.test_data, 1, False, FLAGS.batch_size)) -After reading in the data, you can train and evaluate the model: + # Display evaluation metrics + print('Results at epoch', (n + 1) * FLAGS.epochs_per_eval) + print('-' * 30) -```python -# set num_epochs to None to get infinite stream of data. -m.train( - input_fn=input_fn(train_file_name, num_epochs=None, shuffle=True), - steps=train_steps) -# set steps to None to run evaluation until all data consumed. -results = m.evaluate( - input_fn=input_fn(test_file_name, num_epochs=1, shuffle=False), - steps=None) -print("model directory = %s" % model_dir) -for key in sorted(results): - print("%s: %s" % (key, results[key])) + for key in sorted(results): + print('%s: %s' % (key, results[key])) ``` -The first line of the output should be something like `accuracy: 0.84429705`. We -can see that the accuracy was improved from about 83.6% using a wide-only linear -model to about 84.4% using a Wide & Deep model. If you'd like to see a working -end-to-end example, you can download our -[example code](https://www.tensorflow.org/code/tensorflow/examples/learn/wide_n_deep_tutorial.py). +The final output accuracy should be somewhere around 85.5%. If you'd like to +see a working end-to-end example, you can download our +[example code](https://github.com/tensorflow/models/tree/master/official/wide_deep/wide_deep.py). Note that this tutorial is just a quick example on a small dataset to get you familiar with the API. Wide & Deep Learning will be even more powerful if you diff --git a/tensorflow/python/estimator/run_config.py b/tensorflow/python/estimator/run_config.py index 372f01dc8267c7..0fee99ac7cff84 100644 --- a/tensorflow/python/estimator/run_config.py +++ b/tensorflow/python/estimator/run_config.py @@ -80,6 +80,13 @@ def _get_master(cluster_spec, task_type, task_id): '%s\n\n' 'Note that these values may be coming from the TF_CONFIG environment ' 'variable.' % (task_id, task_type, cluster_spec)) + + # If there is only one node in the cluster, do things locally by setting + # master to ''. If a service or user sets TF_CONFIG with a single node, it's + # more performant to use a direct master rather than an RPC service. + if len(jobs) == 1 and len(cluster_spec.job_tasks(jobs[0])) == 1: + return _LOCAL_MASTER + return _GRPC_SCHEME + addresses[task_id] diff --git a/tensorflow/python/estimator/run_config_test.py b/tensorflow/python/estimator/run_config_test.py index ecc850d5405837..6a62c061ff8305 100644 --- a/tensorflow/python/estimator/run_config_test.py +++ b/tensorflow/python/estimator/run_config_test.py @@ -344,7 +344,7 @@ def test_single_chief_node(self): expected_cluster_spec=tf_config['cluster'], expected_task_type=run_config_lib.TaskType.CHIEF, expected_task_id=0, - expected_master='grpc://host0:0', + expected_master='', expected_evaluation_master='', expected_is_chief=True, expected_num_worker_replicas=1, @@ -572,7 +572,7 @@ def test_single_master_node(self): expected_cluster_spec=tf_config['cluster'], expected_task_type=run_config_lib.TaskType.MASTER, expected_task_id=0, - expected_master='grpc://host0:0', + expected_master='', expected_evaluation_master='', expected_is_chief=True, expected_num_worker_replicas=1, diff --git a/tensorflow/python/estimator/training.py b/tensorflow/python/estimator/training.py index 64b014a6b52391..c31ad3d5c3b807 100644 --- a/tensorflow/python/estimator/training.py +++ b/tensorflow/python/estimator/training.py @@ -43,6 +43,8 @@ _TF_CONFIG_ENV = 'TF_CONFIG' _ENVIRONMENT_KEY = 'environment' _ENVIRONMENT_GOOGLE_VALUE = 'google' +_TRAINER_JOBS = (run_config_lib.TaskType.CHIEF, run_config_lib.TaskType.MASTER, + run_config_lib.TaskType.WORKER) def _validate_input_fn(input_fn): @@ -624,11 +626,28 @@ def _should_stop_local_train(global_step): def _start_std_server(self, config): """Creates, starts, and returns a server_lib.Server.""" - if (not config.cluster_spec or not config.task_type or not config.master or + if (not config.cluster_spec or not config.task_type or config.task_id is None): raise RuntimeError('Could not start server; be sure to specify ' - 'cluster_spec, task_type, master, and task in ' + 'cluster_spec, task_type, and task in ' 'RunConfig or set the TF_CONFIG environment variable.') + + if not config.master: + jobs = config.cluster_spec.jobs + if (len(jobs) == 1 and len(config.cluster_spec.job_tasks(jobs[0])) == 1 + and config.task_type in _TRAINER_JOBS): + # For distributed training, config.master is empty if and only if it has + # a single node in the cluster spec. In this case, we should not start + # the server. + logging.info('Skip starting Tensorflow server as there is only one ' + 'node in the cluster.') + return + else: + raise RuntimeError( + 'Could not start server; be sure to specify master in ' + 'RunConfig or set the TF_CONFIG environment variable.') + + logging.info('Start Tensorflow server.') server = server_lib.Server( config.cluster_spec, job_name=config.task_type, diff --git a/tensorflow/python/estimator/training_test.py b/tensorflow/python/estimator/training_test.py index 1862e325e2b65a..8fd50faf5c30bd 100644 --- a/tensorflow/python/estimator/training_test.py +++ b/tensorflow/python/estimator/training_test.py @@ -480,7 +480,7 @@ def test_invalid_task_type(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.Mock() - mock_est.config.cluster_spec = {'1': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'1': ['dummy']}) mock_est.config.task_type = '' with self.assertRaisesRegexp(ValueError, _INVALID_TASK_TYPE): @@ -598,7 +598,8 @@ def test_fail_with_empty_master(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec( + {'worker': ['dummy', 'dummy1']}) mock_est.config.master = '' mock_est.config.task_type = 'worker' mock_est.config.task_id = 2 @@ -608,13 +609,33 @@ def test_fail_with_empty_master(self): self._run_task(training._TrainingExecutor(mock_est, mock_train_spec, mock_eval_spec)) + @test.mock.patch.object(time, 'sleep') + @test.mock.patch.object(server_lib, 'Server') + def test_single_worker_node_with_empty_tf_master( + self, mock_server, unused_mock_sleep): + mock_est = test.mock.Mock(spec=estimator_lib.Estimator) + mock_train_spec = test.mock.Mock(spec=training.TrainSpec) + mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) + + mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) + # Single node cluster. + mock_est.config.cluster_spec = server_lib.ClusterSpec({'worker': ['dummy']}) + mock_est.config.master = '' + mock_est.config.task_type = 'worker' + mock_est.config.task_id = 2 + + self._run_task(training._TrainingExecutor(mock_est, mock_train_spec, + mock_eval_spec)) + # mock_est.train.assert_called() + mock_server.assert_not_called() + def test_fail_with_empty_task_type(self): mock_est = test.mock.Mock(spec=estimator_lib.Estimator) mock_train_spec = test.mock.Mock(spec=training.TrainSpec) mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'worker': ['dummy']}) mock_est.config.master = 'grpc://...' mock_est.config.task_type = '' mock_est.config.task_id = 2 @@ -630,7 +651,7 @@ def test_fail_with_none_task_id(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'worker': ['dummy']}) mock_est.config.master = 'grpc://...' mock_est.config.task_type = 'worker' mock_est.config.task_id = None @@ -768,7 +789,7 @@ def test_fail_with_empty_cluster_spec(self): mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) mock_est.config.cluster_spec = None mock_est.config.master = 'grpc://...' - mock_est.config.task_type = 'worker' + mock_est.config.task_type = 'master' mock_est.config.task_id = 2 with self.assertRaisesRegexp(RuntimeError, @@ -782,23 +803,48 @@ def test_fail_with_empty_master(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec( + {'master': ['dummy'], 'worker': ['dummy1']}) mock_est.config.master = '' - mock_est.config.task_type = 'worker' - mock_est.config.task_id = 2 + mock_est.config.task_type = 'master' + mock_est.config.task_id = 0 with self.assertRaisesRegexp(RuntimeError, _INVALID_CONFIG_FOR_STD_SERVER_MSG): training._TrainingExecutor( mock_est, mock_train_spec, mock_eval_spec).run_master() + @test.mock.patch.object(time, 'sleep') + @test.mock.patch.object(server_lib, 'Server') + def test_single_master_node_with_empty_tf_master( + self, mock_server, unused_mock_sleep): + mock_est = test.mock.Mock(spec=estimator_lib.Estimator) + mock_est.evaluate = lambda *args, **kw: {ops.GraphKeys.GLOBAL_STEP: 123} + + mock_train_spec = test.mock.Mock(spec=training.TrainSpec, max_steps=123) + mock_eval_spec = test.mock.Mock(spec=training.EvalSpec, exporters=[]) + + mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) + mock_est.config.cluster_spec = server_lib.ClusterSpec( + {'master': ['dummy']}) + mock_est.config.master = '' + mock_est.config.task_type = 'master' + mock_est.config.task_id = 0 + + executor = training._TrainingExecutor( + mock_est, mock_train_spec, mock_eval_spec) + executor.run_master() + + mock_server.assert_not_called() + # mock_est.train.assert_called() + def test_fail_with_empty_task_type(self): mock_est = test.mock.Mock(spec=estimator_lib.Estimator) mock_train_spec = test.mock.Mock(spec=training.TrainSpec) mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'master': ['dummy']}) mock_est.config.master = 'grpc://...' mock_est.config.task_type = '' mock_est.config.task_id = 2 @@ -814,9 +860,9 @@ def test_fail_with_none_task_id(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'worker': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'master': ['dummy']}) mock_est.config.master = 'grpc://...' - mock_est.config.task_type = 'worker' + mock_est.config.task_type = 'master' mock_est.config.task_id = None with self.assertRaisesRegexp(RuntimeError, @@ -1246,7 +1292,7 @@ def test_fail_with_empty_cluster_spec(self): mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) mock_est.config.cluster_spec = None mock_est.config.master = 'grpc://...' - mock_est.config.task_type = 'gs' + mock_est.config.task_type = 'ps' mock_est.config.task_id = 2 with self.assertRaisesRegexp(RuntimeError, @@ -1260,9 +1306,9 @@ def test_fail_with_empty_master(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'gs': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'ps': ['dummy']}) mock_est.config.master = '' - mock_est.config.task_type = 'gs' + mock_est.config.task_type = 'ps' mock_est.config.task_id = 2 with self.assertRaisesRegexp(RuntimeError, @@ -1276,7 +1322,7 @@ def test_fail_with_empty_task_type(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'gs': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'ps': ['dummy']}) mock_est.config.master = 'grpc://...' mock_est.config.task_type = '' mock_est.config.task_id = 2 @@ -1292,9 +1338,9 @@ def test_fail_with_none_task_id(self): mock_eval_spec = test.mock.Mock(spec=training.EvalSpec) mock_est.config = test.mock.PropertyMock(spec=run_config_lib.RunConfig) - mock_est.config.cluster_spec = {'gs': 'dummy'} + mock_est.config.cluster_spec = server_lib.ClusterSpec({'ps': ['dummy']}) mock_est.config.master = 'grpc://...' - mock_est.config.task_type = 'gs' + mock_est.config.task_type = 'ps' mock_est.config.task_id = None with self.assertRaisesRegexp(RuntimeError, diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py index 1792886417f90a..5d0a561b882ea3 100644 --- a/tensorflow/python/kernel_tests/array_ops_test.py +++ b/tensorflow/python/kernel_tests/array_ops_test.py @@ -907,6 +907,32 @@ def testUninitialized(self): v = variables.Variable([1, 2]) sess.run(v[:].assign([1, 2])) + def testTypeError(self): + init_val = constant_op.constant([1, 2], dtype=dtypes.int32) + too_small_val = constant_op.constant([3, 4], dtype=dtypes.int8) + too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64) + v = variables.Variable(init_val) + with self.assertRaises(TypeError): + v[:].assign(too_small_val) + with self.assertRaises(TypeError): + v[:].assign(too_large_val) + + def testTypeErrorResource(self): + init_val = constant_op.constant([1, 2], dtype=dtypes.int32) + too_small_val = constant_op.constant([3, 4], dtype=dtypes.int8) + too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64) + v = resource_variable_ops.ResourceVariable(init_val) + with self.test_session() as sess: + sess.run(v.initializer) + with self.assertRaisesRegexp( + errors.InvalidArgumentError, + "l-value dtype int32 does not match r-value dtype int64"): + sess.run(v[:].assign(too_large_val)) + with self.assertRaisesRegexp( + errors.InvalidArgumentError, + "l-value dtype int32 does not match r-value dtype int8"): + sess.run(v[:].assign(too_small_val)) + class ShapeSizeRankTest(test_util.TensorFlowTestCase): diff --git a/tensorflow/python/ops/image_ops_impl.py b/tensorflow/python/ops/image_ops_impl.py index 4aef6ca85f3f0a..41f4fe3cb419b3 100644 --- a/tensorflow/python/ops/image_ops_impl.py +++ b/tensorflow/python/ops/image_ops_impl.py @@ -1602,9 +1602,11 @@ def non_max_suppression(boxes, collection of bounding boxes representing the selected boxes. The bounding box coordinates corresponding to the selected indices can then be obtained using the `tf.gather operation`. For example: + ```python selected_indices = tf.image.non_max_suppression( boxes, scores, max_output_size, iou_threshold) selected_boxes = tf.gather(boxes, selected_indices) + ``` Args: boxes: A 2-D float `Tensor` of shape `[num_boxes, 4]`. diff --git a/tensorflow/tensorflow.bzl b/tensorflow/tensorflow.bzl index 846863717b55f8..d41228ad7353da 100644 --- a/tensorflow/tensorflow.bzl +++ b/tensorflow/tensorflow.bzl @@ -437,6 +437,8 @@ def tf_gen_op_wrappers_cc(name, # "name" arg) # op_whitelist: if not empty, only op names in this list will be wrapped. It # is invalid to specify both "hidden" and "op_whitelist". +## cc_linkopts: Optional linkopts to be added to tf_cc_binary that contains the +# specified ops. def tf_gen_op_wrapper_py(name, out=None, hidden=None, @@ -445,7 +447,8 @@ def tf_gen_op_wrapper_py(name, require_shape_functions=False, hidden_file=None, generated_target_name=None, - op_whitelist=[]): + op_whitelist=[], + cc_linkopts=[]): if (hidden or hidden_file) and op_whitelist: fail('Cannot pass specify both hidden and op_whitelist.') @@ -455,7 +458,7 @@ def tf_gen_op_wrapper_py(name, deps = [str(Label("//tensorflow/core:" + name + "_op_lib"))] tf_cc_binary( name=tool_name, - linkopts=["-lm"], + linkopts=["-lm"] + cc_linkopts, copts=tf_copts(), linkstatic=1, # Faster to link this one-time-use binary dynamically deps=([ @@ -1108,7 +1111,7 @@ check_deps = rule( # Helper to build a dynamic library (.so) from the sources containing # implementations of custom ops and kernels. -def tf_custom_op_library(name, srcs=[], gpu_srcs=[], deps=[]): +def tf_custom_op_library(name, srcs=[], gpu_srcs=[], deps=[], linkopts=[]): cuda_deps = [ clean_dep("//tensorflow/core:stream_executor_headers_lib"), "@local_config_cuda//cuda:cuda_headers", @@ -1137,7 +1140,7 @@ def tf_custom_op_library(name, srcs=[], gpu_srcs=[], deps=[]): deps=deps + if_cuda(cuda_deps), data=[name + "_check_deps"], copts=tf_copts(), - linkopts=select({ + linkopts=linkopts + select({ "//conditions:default": [ "-lm", ], diff --git a/tensorflow/tools/ci_build/builds/pip.sh b/tensorflow/tools/ci_build/builds/pip.sh index 552df1434eab8c..a37cf226f95456 100755 --- a/tensorflow/tools/ci_build/builds/pip.sh +++ b/tensorflow/tools/ci_build/builds/pip.sh @@ -296,15 +296,20 @@ create_activate_virtualenv_and_install_tensorflow() { die "FAILED to create virtualenv directory: ${VIRTUALENV_DIR}" fi - # Verify that virtualenv exists - if [[ -z $(which virtualenv) ]]; then - die "FAILED: virtualenv not available on path" + if [[ ${PYTHON_BIN_PATH} == *"python3.6"* ]]; then + "${PYTHON_BIN_PATH}" -m venv "${VIRTUALENV_FLAGS}" \ + "${VIRTUALENV_DIR}" || \ + die "FAILED: Unable to create virtualenv" + else + # Verify that virtualenv exists + if [[ -z $(which virtualenv) ]]; then + die "FAILED: virtualenv not available on path" + fi + virtualenv ${VIRTUALENV_FLAGS} \ + -p "${PYTHON_BIN_PATH}" "${VIRTUALENV_DIR}" || \ + die "FAILED: Unable to create virtualenv" fi - virtualenv ${VIRTUALENV_FLAGS} \ - -p "${PYTHON_BIN_PATH}" "${VIRTUALENV_DIR}" || \ - die "FAILED: Unable to create virtualenv" - source "${VIRTUALENV_DIR}/bin/activate" || \ die "FAILED: Unable to activate virtualenv in ${VIRTUALENV_DIR}" diff --git a/tensorflow/tools/ci_build/ci_parameterized_build.sh b/tensorflow/tools/ci_build/ci_parameterized_build.sh index 7a1479c150488d..15ff0daaade03f 100755 --- a/tensorflow/tools/ci_build/ci_parameterized_build.sh +++ b/tensorflow/tools/ci_build/ci_parameterized_build.sh @@ -201,13 +201,13 @@ function get_cuda_capability_version() { # Container type, e.g., CPU, GPU CTYPE=${TF_BUILD_CONTAINER_TYPE} -# Determine if Docker is available +# Determine if the machine is a Mac OPT_FLAG="" -if [[ -z "$(which docker)" ]]; then +if [[ "$(uname -s)" == "Darwin" ]]; then DO_DOCKER=0 - echo "It appears that Docker is not available on this system. "\ -"Will perform build without Docker." + echo "It appears this machine is a Mac. "\ +"We will perform this build without Docker." echo "Also, the additional option flags will be applied to the build:" echo " ${NO_DOCKER_OPT_FLAG}" MAIN_CMD="${NO_DOCKER_MAIN_CMD} ${CTYPE}" @@ -514,8 +514,9 @@ echo "" TMP_DIR="" DOCKERFILE_FLAG="" -if [[ "${TF_BUILD_PYTHON_VERSION}" == "python3.5" ]]; then - # Modify Dockerfile for Python3.5 build +if [[ "${TF_BUILD_PYTHON_VERSION}" == "python3.5" ]] || + [["${TF_BUILD_PYTHON_VERSION}" == "python3.6" ]]; then + # Modify Dockerfile for Python3.5 | Python3.6 build TMP_DIR=$(mktemp -d) echo "Docker build will occur in temporary directory: ${TMP_DIR}" @@ -531,10 +532,10 @@ if [[ "${TF_BUILD_PYTHON_VERSION}" == "python3.5" ]]; then # Replace a line in the Dockerfile if sed -i \ - 's/RUN \/install\/install_pip_packages.sh/RUN \/install\/install_python3.5_pip_packages.sh/g' \ + "s/RUN \/install\/install_pip_packages.sh/RUN \/install\/install_${TF_BUILD_PYTHON_VERSION}_pip_packages.sh/g" \ "${DOCKERFILE}" then - echo "Copied and modified Dockerfile for Python 3.5 build: ${DOCKERFILE}" + echo "Copied and modified Dockerfile for ${TF_BUILD_PYTHON_VERSION} build: ${DOCKERFILE}" else die "ERROR: Faild to copy and modify Dockerfile: ${DOCKERFILE}" fi diff --git a/tensorflow/tools/ci_build/install/install_python3.5_pip_packages.sh b/tensorflow/tools/ci_build/install/install_python3.5_pip_packages.sh index e452c50221bee4..78b7f276066a8d 100755 --- a/tensorflow/tools/ci_build/install/install_python3.5_pip_packages.sh +++ b/tensorflow/tools/ci_build/install/install_python3.5_pip_packages.sh @@ -18,33 +18,12 @@ # TODO(cais): Remove this file once we upgrade to ubuntu:16.04 docker images for # Python 3.5 builds. +# LINT.IfChange + # fkrull/deadsnakes is for Python3.5 add-apt-repository -y ppa:fkrull/deadsnakes apt-get update -set +e -# Upgrade swig to 3.0.8 -SWIG_VERSION="3.0.8" -swig_ver_flat=$(echo $SWIG_VERSION | sed 's/\.//g' | sed 's/^0*//g') -local_swig_ver=$(swig -version | grep -i version | awk '{print $3}') -local_swig_ver_flat=$(echo $local_swig_ver | sed 's/\.//g' | sed 's/^0*//g') -if [[ -z $local_swig_ver_flat ]]; then - local_swig_ver_flat=0 -fi -if (( $local_swig_ver_flat < $swig_ver_flat )); then - set -e - wget -q http://downloads.sourceforge.net/swig/swig-3.0.8.tar.gz - tar xzf swig-3.0.8.tar.gz - pushd swig-3.0.8 - apt-get install -y --no-install-recommends libpcre3-dev - ./configure - make - make install - rm -f /usr/bin/swig - ln -s /usr/local/bin/swig /usr/bin/swig - popd - rm -rf swig-3.0.8 swig-3.0.8.tar.gz -fi set -e # Install Python 3.5 and dev library apt-get install -y --no-install-recommends python3.5 libpython3.5-dev @@ -91,3 +70,5 @@ pip3.5 install portpicker pip3.5 install werkzeug pip3.5 install grpcio + +# LINT.ThenChange(//tensorflow/tools/ci_build/install/install_python3.6_pip_packages.sh) diff --git a/tensorflow/tools/ci_build/install/install_python3.6_pip_packages.sh b/tensorflow/tools/ci_build/install/install_python3.6_pip_packages.sh new file mode 100755 index 00000000000000..ec7d9bf195dfdf --- /dev/null +++ b/tensorflow/tools/ci_build/install/install_python3.6_pip_packages.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Copyright 2016 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. +# ============================================================================== +# Install packages required by Python3.6 build + +# TODO(amitpatankar): Remove this file once we upgrade to ubuntu:16.04 +# docker images for Python 3.6 builds. + +# LINT.IfChange + +# fkrull/deadsnakes is for Python3.6 +add-apt-repository -y ppa:fkrull/deadsnakes +apt-get update + +set -e +# Install Python 3.6 and dev library +wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tar.xz +tar xvf Python-3.6.1.tar.xz +cd Python-3.6.1 + +./configure +make altinstall +pip3.6 -V +which pip3.6 +ln -s /usr/local/bin/pip3.6 /usr/local/bin/pip3 + +set -e +# Install six. +pip3 install --upgrade absl-py +pip3 install --upgrade six==1.10.0 + +# Install protobuf. +pip3 install --upgrade protobuf==3.3.0 + +# Remove obsolete version of six, which can sometimes confuse virtualenv. +rm -rf /usr/lib/python3/dist-packages/six* + +# Install numpy, scipy and scikit-learn required by the builds + +# numpy needs to be installed from source to fix segfaults. See: +# https://github.com/tensorflow/tensorflow/issues/6968 +# This workaround isn't needed for Ubuntu 16.04 or later. +pip3 install --no-binary=:all: --upgrade numpy==1.12.0 + +pip3 install scipy==0.18.1 + +pip3 install scikit-learn==0.18.1 + +# pandas required by `inflow` +pip3 install pandas==0.19.2 + +# Install recent-enough version of wheel for Python 3.6 wheel builds +pip3 install wheel==0.29.0 + +pip3 install portpicker + +pip3 install werkzeug + +pip3 install grpcio + +# LINT.ThenChange(//tensorflow/tools/ci_build/install/install_python3.5_pip_packages.sh) diff --git a/tensorflow/tools/ci_build/windows/bazel/common_env.sh b/tensorflow/tools/ci_build/windows/bazel/common_env.sh index 4a653698a2d7c1..bf7bc0b0839175 100644 --- a/tensorflow/tools/ci_build/windows/bazel/common_env.sh +++ b/tensorflow/tools/ci_build/windows/bazel/common_env.sh @@ -32,9 +32,11 @@ mkdir -p "$TMPDIR" # Set bash path export BAZEL_SH=${BAZEL_SH:-"C:/tools/msys64/usr/bin/bash"} +export PYTHON_BASE_PATH="${PYTHON_DIRECTORY:-Program Files/Anaconda3}" + # Set Python path for ./configure -export PYTHON_BIN_PATH="C:/Program Files/Anaconda3/python.exe" -export PYTHON_LIB_PATH="C:/Program Files/Anaconda3/lib/site-packages" +export PYTHON_BIN_PATH="C:/${PYTHON_BASE_PATH}/python.exe" +export PYTHON_LIB_PATH="C:/${PYTHON_BASE_PATH}/lib/site-packages" # Set Python path for cc_configure.bzl export BAZEL_PYTHON="C:/Program Files/Anaconda3/python.exe" @@ -44,10 +46,10 @@ export BAZEL_VS="C:/Program Files (x86)/Microsoft Visual Studio 14.0" # Add python into PATH, it's needed because gen_git_source.py uses # '/usr/bin/env python' as a shebang -export PATH="/c/Program Files/Anaconda3:$PATH" +export PATH="/c/${PYTHON_BASE_PATH}:$PATH" # Make sure we have pip in PATH -export PATH="/c/Program Files/Anaconda3/Scripts:$PATH" +export PATH="/c/${PYTHON_BASE_PATH}/Scripts:$PATH" # Add Cuda and Cudnn dll directories into PATH export PATH="/c/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v8.0/bin:$PATH" diff --git a/tensorflow/tools/docker/Dockerfile.devel-gpu b/tensorflow/tools/docker/Dockerfile.devel-gpu index 991019faa34c37..b05d62844f65d6 100644 --- a/tensorflow/tools/docker/Dockerfile.devel-gpu +++ b/tensorflow/tools/docker/Dockerfile.devel-gpu @@ -78,15 +78,18 @@ WORKDIR /tensorflow # Configure the build for our CUDA configuration. ENV CI_BUILD_PYTHON python -ENV LD_LIBRARY_PATH /usr/local/cuda/lib64/stubs:/usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH +ENV LD_LIBRARY_PATH /usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH ENV TF_NEED_CUDA 1 ENV TF_CUDA_COMPUTE_CAPABILITIES=3.0,3.5,5.2,6.0,6.1 -RUN ln -s /usr/local/cuda/lib64/stubs/libcuda.so /usr/local/cuda/lib64/stubs/libcuda.so.1 -RUN tensorflow/tools/ci_build/builds/configured GPU \ - bazel build -c opt --config=cuda --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" \ +RUN ln -s /usr/local/cuda/lib64/stubs/libcuda.so /usr/local/cuda/lib64/stubs/libcuda.so.1 && \ + LD_LIBRARY_PATH=/usr/local/cuda/lib64/stubs:${LD_LIBRARY_PATH} \ + tensorflow/tools/ci_build/builds/configured GPU \ + bazel build -c opt --config=cuda \ + --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" \ tensorflow/tools/pip_package:build_pip_package && \ + rm /usr/local/cuda/lib64/stubs/libcuda.so.1 && \ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/pip && \ pip --no-cache-dir install --upgrade /tmp/pip/tensorflow-*.whl && \ rm -rf /tmp/pip && \ diff --git a/tensorflow/tools/docker/parameterized_docker_build.sh b/tensorflow/tools/docker/parameterized_docker_build.sh index 830e3dcd32ec37..ce0dd5ac7a4768 100755 --- a/tensorflow/tools/docker/parameterized_docker_build.sh +++ b/tensorflow/tools/docker/parameterized_docker_build.sh @@ -34,6 +34,11 @@ # If set to a non-empty string, will use it as the URL from which the # pip wheel file will be downloaded (instead of building the pip locally). # +# TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL +# (Optional) +# If set to a non-empty string, we will treat TF_DOCKER_BUILD_CENTRAL_PIP +# as a path rather than a url. +# # TF_DOCKER_BUILD_IMAGE_NAME: # (Optional) # If set to any non-empty value, will use it as the image of the @@ -58,6 +63,23 @@ # tagged image name with an argument, to push the image to a central repo # such as gcr.io or Docker Hub. # +# TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS +# (Optional) +# Do not set this along with TF_DOCKER_BUILD_PUSH_CMD. We will push with the +# direct commands as opposed to a script. +# +# TF_DOCKER_USERNAME +# (Optional) +# Dockerhub username for pushing a package. +# +# TF_DOCKER_EMAIL +# (Optional) +# Dockerhub email for pushing a package. +# +# TF_DOCKER_PASSWORD +# (Optional) +# Dockerhub password for pushing a package. +# # TF_DOCKER_BUILD_PYTHON_VERSION # (Optional) # Specifies the desired Python version. Defaults to PYTHON2. @@ -217,6 +239,32 @@ if [[ "${TF_DOCKER_BUILD_IS_DEVEL}" == "no" ]]; then "COPY ${PIP_WHL} /\n"\ "RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \ > "${DOCKERFILE}" + + # Build from a local whl file path rather than an URL + elif [[ ! -z "${TF_DOCKER_BUILD_CENTRAL_PIP_IS_LOCAL}" ]]; then + PIP_WHL="${TF_DOCKER_BUILD_CENTRAL_PIP}" + if [[ -z "${PIP_WHL}" ]]; then + die "ERROR: Cannot locate the specified pip whl file" + fi + echo "Specified PIP whl file is at: ${PIP_WHL}" + + # Copy the pip file to tmp directory + cp "${PIP_WHL}" "${TMP_DIR}/" || \ + die "ERROR: Failed to copy wheel file: ${PIP_WHL}" + + # Use string replacement to put the correct file name into the Dockerfile + PIP_WHL=$(basename "${PIP_WHL}") + + # Modify the non-devel Dockerfile to point to the correct pip whl file + # location + sed -e "/# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/,"\ +"/# --- ~ DO NOT EDIT OR DELETE BETWEEN THE LINES --- #/c"\ +"COPY ${PIP_WHL} /\n"\ +"RUN pip --no-cache-dir install /${PIP_WHL}" "${ORIG_DOCKERFILE}" \ + > "${DOCKERFILE}" + echo "Using local pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}" + echo + else echo "Downloading pip wheel from: ${TF_DOCKER_BUILD_CENTRAL_PIP}" echo @@ -378,7 +426,6 @@ fi echo "" echo "Successfully tagged docker image: ${FINAL_IMG}" - # Optional: call command specified by TF_DOCKER_BUILD_PUSH_CMD to push image if [[ ! -z "${TF_DOCKER_BUILD_PUSH_CMD}" ]]; then ${TF_DOCKER_BUILD_PUSH_CMD} ${FINAL_IMG} @@ -388,3 +435,22 @@ if [[ ! -z "${TF_DOCKER_BUILD_PUSH_CMD}" ]]; then die "FAIL: Failed to push Docker image ${FINAL_IMG}" fi fi + +# Optional: set TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS to push image +if [[ ! -z "${TF_DOCKER_BUILD_PUSH_WITH_CREDENTIALS}" ]]; then + + docker login -u "${TF_DOCKER_USERNAME}" \ + -p "${TF_DOCKER_PASSWORD}" + + if [[ $? != "0" ]]; then + die "FAIL: Unable to login. Invalid credentials." + fi + docker push "${FINAL_IMG}" + if [[ $? == "0" ]]; then + docker logout + echo "Successfully pushed Docker image ${FINAL_IMG}" + else + docker logout + die "FAIL: Failed to push Docker image ${FINAL_IMG}" + fi +fi diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py index fc2e3e64da574a..51e0c9c9af59c8 100644 --- a/tensorflow/tools/pip_package/setup.py +++ b/tensorflow/tools/pip_package/setup.py @@ -29,7 +29,7 @@ # This version string is semver compatible, but incompatible with pip. # For pip, we will remove all '-' characters from this string, and use the # result for pip. -_VERSION = '1.4.0' +_VERSION = '1.4.2' REQUIRED_PACKAGES = [ 'enum34 >= 1.1.6', diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index 53a75fda14f9d5..ee4a8e28c0e0be 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -24,37 +24,52 @@ def _get_env_var(repository_ctx, name): return None +def _extract_version_number(bazel_version): + """Extracts the semantic version number from a version string + + Args: + bazel_version: the version string that begins with the semantic version + e.g. "1.2.3rc1 abc1234" where "abc1234" is a commit hash. + + Returns: + The semantic version string, like "1.2.3". + """ + for i in range(len(bazel_version)): + c = bazel_version[i] + if not (c.isdigit() or c == "."): + return bazel_version[:i] + return bazel_version + # Parse the bazel version string from `native.bazel_version`. +# e.g. +# "0.10.0rc1 abc123d" => (0, 10, 0) +# "0.3.0" => (0, 3, 0) def _parse_bazel_version(bazel_version): - # Remove commit from version. - version = bazel_version.split(" ", 1)[0] + """Parses a version string into a 3-tuple of ints + + int tuples can be compared directly using binary operators (<, >). - # Split into (release, date) parts and only return the release - # as a tuple of integers. - parts = version.split("-", 1) + Args: + bazel_version: the Bazel version string - # Turn "release" into a tuple of strings - version_tuple = () - for number in parts[0].split("."): - version_tuple += (str(number),) - return version_tuple + Returns: + An int 3-tuple of a (major, minor, patch) version. + """ + version = _extract_version_number(bazel_version) + return tuple([int(n) for n in version.split(".")]) -# Check that a specific bazel version is being used. -def check_version(bazel_version): +def check_bazel_version_at_least(minimum_bazel_version): if "bazel_version" not in dir(native): - fail("\nCurrent Bazel version is lower than 0.2.1, expected at least %s\n" % - bazel_version) + fail("\nCurrent Bazel version is lower than 0.2.1, expected at least %s\n" % minimum_bazel_version) elif not native.bazel_version: - print("\nCurrent Bazel is not a release version, cannot check for " + - "compatibility.") - print("Make sure that you are running at least Bazel %s.\n" % bazel_version) - else: - current_bazel_version = _parse_bazel_version(native.bazel_version) - minimum_bazel_version = _parse_bazel_version(bazel_version) - if minimum_bazel_version > current_bazel_version: - fail("\nCurrent Bazel version is {}, expected at least {}\n".format( - native.bazel_version, bazel_version)) + print("\nCurrent Bazel is not a release version, cannot check for compatibility.") + print("Make sure that you are running at least Bazel %s.\n" % minimum_bazel_version) + return + + if _parse_bazel_version(native.bazel_version) < _parse_bazel_version(minimum_bazel_version): + fail("\nCurrent Bazel version is {}, expected at least {}\n".format( + native.bazel_version, minimum_bazel_version)) def _repos_are_siblings(): @@ -143,7 +158,7 @@ def tf_workspace(path_prefix="", tf_repo_name=""): # We must check the bazel version before trying to parse any other BUILD # files, in case the parsing of those build files depends on the bazel # version we require here. - check_version("0.5.4") + check_bazel_version_at_least("0.5.4") cuda_configure(name="local_config_cuda") sycl_configure(name="local_config_sycl") python_configure(name="local_config_python") diff --git a/third_party/mkl/build_defs.bzl b/third_party/mkl/build_defs.bzl index 533c0766c71a18..6574f250927e9c 100644 --- a/third_party/mkl/build_defs.bzl +++ b/third_party/mkl/build_defs.bzl @@ -20,7 +20,7 @@ def if_mkl(if_true, if_false = []): """ return select({ - "//third_party/mkl:using_mkl": if_true, + str(Label("//third_party/mkl:using_mkl")): if_true, "//conditions:default": if_false })
Version:CPU/GPU:Python Version:Compiler:Build Tools:cuDNN:CUDA:
tensorflow-1.4.0CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A
tensorflow_gpu-1.4.0GPU3.5-3.6MSVC 2015 update 3Cmake v3.6.368
tensorflow-1.4.2CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A
tensorflow_gpu-1.4.2GPU3.5-3.6MSVC 2015 update 3Cmake v3.6.368
tensorflow-1.3.0CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A
tensorflow_gpu-1.3.0GPU3.5-3.6MSVC 2015 update 3Cmake v3.6.368
tensorflow-1.2.0CPU3.5-3.6MSVC 2015 update 3Cmake v3.6.3N/AN/A