diff --git a/BUILD b/BUILD new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index f323d2397226820781bf55658f587d4b1099081a..af76188c2f4d2e1908f541918c8b680627a90cf9 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,4 +1,5 @@ -GitHub issues are for bugs / installation problems / feature requests. +NOTE: Only file GitHub issues for bugs and feature requests. All other topics will be closed. + For general support from the community, see [StackOverflow](https://stackoverflow.com/questions/tagged/tensorflow). To make bugs and feature requests more easy to find and organize, we close issues that are deemed out of scope for GitHub Issues and point people to StackOverflow. @@ -7,6 +8,8 @@ For bugs or installation issues, please provide the following information. The more information you provide, the more easily we will be able to offer help and advice. +### What related GitHub issues or StackOverflow threads have you found by searching the web for your problem? + ### Environment info Operating System: @@ -15,7 +18,7 @@ Installed version of CUDA and cuDNN: If installed from binary pip package, provide: -1. Which pip package you installed. +1. A link to the pip package you installed: 2. The output from `python -c "import tensorflow; print(tensorflow.__version__)"`. If installed from source, provide @@ -23,13 +26,11 @@ If installed from source, provide 1. The commit hash (`git rev-parse HEAD`) 2. The output of `bazel version` -### Steps to reproduce -1. -2. -3. +### If possible, provide a minimal reproducible example (We usually don't have time to read hundreds of lines of your code) + + +### What other attempted solutions have you tried? -### What have you tried? -1. ### Logs or other output that would be helpful -(If logs are large, please upload as attachment). +(If logs are large, please upload as attachment or provide link). diff --git a/README.md b/README.md index 3de86a21654abee2e072ba48c8dd1cc4b2fb2be9..e356ff931ce9a759e973a319276ca5b87954db79 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ and discussion.** People who are a little more adventurous can also try our nightly binaries: * Linux CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/)) -* Linux GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/140/artifact/pip_test/whl/tensorflow-0.8.0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/)) +* Linux GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/140/artifact/pip_test/whl/tensorflow-0.8.0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_CONTAINER_TYPE=GPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/)) * Mac CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_CONTAINER_TYPE=CPU,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/)) -* Mac GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nigntly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/)) +* Mac GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/)) * [Android](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/lastSuccessfulBuild/artifact/bazel-out/local_linux/bin/tensorflow/examples/android/tensorflow_demo.apk) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/)) #### *Try your first TensorFlow program* diff --git a/RELEASE.md b/RELEASE.md index f1a8859c356546358a863a96428a89f2b1256cd8..02cc73bf130fa35e4820215f657858402b137889 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -10,6 +10,11 @@ * Int32 elements of list(type) arguments are no longer placed in host memory by default. If necessary, a list(type) argument to a kernel can be placed in host memory using a HostMemory annotation. +* uniform_unit_scaling_initializer() no longer takes a full_shape arg, instead + relying on the partition info passed to the initializer function when it's + called. +* The NodeDef protocol message is now defined in its own file node_def.proto + instead of graph.proto. # Release 0.10.0 diff --git a/WORKSPACE b/WORKSPACE index b6dbc7463f287482bd9926ea2ece99be60564c7a..9ff57bf9eb0130eb4f40f7f53f21f2f528df02f2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -20,7 +20,7 @@ tf_workspace() # Specify the minimum required bazel version. load("//tensorflow:tensorflow.bzl", "check_version") -check_version("0.2.0") +check_version("0.3.0") # TENSORBOARD_BOWER_AUTOGENERATED_BELOW_THIS_LINE_DO_NOT_EDIT @@ -143,6 +143,13 @@ new_git_repository( tag = "v1.0.8", ) +new_git_repository( + name = "iron_icons", + build_file = "bower.BUILD", + remote = "https://github.com/polymerelements/iron-icons.git", + tag = "v1.1.3", +) + new_git_repository( name = "iron_iconset_svg", build_file = "bower.BUILD", diff --git a/bower.BUILD b/bower.BUILD index cb3309a36e26632e7f40852bf906f3537564d614..9f4994944fc0e1dca979a8ee8d09648e9e45be25 100644 --- a/bower.BUILD +++ b/bower.BUILD @@ -142,6 +142,24 @@ filegroup( ], ) +filegroup( + name = "iron_icons", + srcs = [ + "av-icons.html", + "communication-icons.html", + "device-icons.html", + "editor-icons.html", + "hardware-icons.html", + "image-icons.html", + "index.html", + "iron-icons.html", + "maps-icons.html", + "notification-icons.html", + "places-icons.html", + "social-icons.html", + ], +) + filegroup( name = "iron_iconset_svg", srcs = [ diff --git a/configure b/configure index bcef37bd26b34bd2e236824a57be21165d83332d..f4b772c55ef60deb9370aec202fccaa802596a21 100755 --- a/configure +++ b/configure @@ -98,7 +98,7 @@ while true; do fi fi if [ -e "$GCC_HOST_COMPILER_PATH" ]; then - export CC=$GCC_HOST_COMPILER_PATH + export GCC_HOST_COMPILER_PATH break fi echo "Invalid gcc path. ${GCC_HOST_COMPILER_PATH} cannot be found" 1>&2 @@ -142,7 +142,7 @@ while true; do if [ -e "${CUDA_TOOLKIT_PATH}/${CUDA_RT_LIB_PATH}" ]; then export CUDA_TOOLKIT_PATH - export CUDA_VERSION=$TF_CUDA_VERSION + export TF_CUDA_VERSION break fi echo "Invalid path to CUDA $TF_CUDA_VERSION toolkit. ${CUDA_TOOLKIT_PATH}/${CUDA_RT_LIB_PATH} cannot be found" @@ -203,7 +203,7 @@ while true; do fi if [ -e "$CUDNN_INSTALL_PATH/${CUDA_DNN_LIB_ALT_PATH}" -o -e "$CUDNN_INSTALL_PATH/${CUDA_DNN_LIB_PATH}" ]; then - export CUDNN_VERSION=$TF_CUDNN_VERSION + export TF_CUDNN_VERSION export CUDNN_INSTALL_PATH break fi @@ -211,7 +211,7 @@ while true; do if [ "$OSNAME" == "Linux" ]; then CUDNN_PATH_FROM_LDCONFIG="$(ldconfig -p | sed -n 's/.*libcudnn.so .* => \(.*\)/\1/p')" if [ -e "${CUDNN_PATH_FROM_LDCONFIG}${TF_CUDNN_EXT}" ]; then - export CUDNN_VERSION=$TF_CUDNN_VERSION + export TF_CUDNN_VERSION export CUDNN_INSTALL_PATH="$(dirname ${CUDNN_PATH_FROM_LDCONFIG})" break fi @@ -263,7 +263,7 @@ EOF exit 1 fi else - export CUDA_COMPUTE_CAPABILITIES=$TF_CUDA_COMPUTE_CAPABILITIES + export TF_CUDA_COMPUTE_CAPABILITIES break fi TF_CUDA_COMPUTE_CAPABILITIES="" diff --git a/gif.BUILD b/gif.BUILD index 8dbea9cc413b53be56fa5ad7c19bd2d42353c61c..cbdcc75f126d5e27fa1930f0ec86adfd438c7137 100644 --- a/gif.BUILD +++ b/gif.BUILD @@ -9,12 +9,18 @@ SOURCES = [ "quantize.c", ] +HEADERS = [ + "gif_hash.h", + "gif_lib.h", + "gif_lib_private.h", +] + prefix_dir = "giflib-5.1.4/lib" cc_library( name = "gif", srcs = [prefix_dir + "/" + source for source in SOURCES], - hdrs = [prefix_dir + "/gif_lib.h"], + hdrs = [prefix_dir + "/" + hdrs for hdrs in HEADERS], includes = [prefix_dir], defines = [ "HAVE_CONFIG_H", diff --git a/grpc.BUILD b/grpc.BUILD index f79cc8b61066fd2f4b4c72c3bca42e978b67db60..2579536b17a4574f574341d6d8198bea6d1169ca 100644 --- a/grpc.BUILD +++ b/grpc.BUILD @@ -1,6 +1,15 @@ # NOTE(mrry): This file is an edited version of the following file: -# https://raw.githubusercontent.com/grpc/grpc/release-0_14/BUILD -# ...with the unnecessary SSL dependencies removed. +# https://raw.githubusercontent.com/grpc/grpc/d7ff4ff40071d2b486a052183e3e9f9382afb745/BUILD +# ...with small modifications to fix the build rules for :grpc++_unsecure. +# +# TODO(mrry): Upstream these fixes back to the gRPC repository. + +# GRPC Bazel BUILD file. +# This currently builds C, C++ and Objective-C code. +# This file has been automatically generated from a template file. +# Please look at the templates directory instead. +# This file can be regenerated from the template by running +# tools/buildgen/generate_projects.sh # Copyright 2015, Google Inc. # All rights reserved. @@ -35,6 +44,10 @@ licenses(["notice"]) # 3-clause BSD package(default_visibility = ["//visibility:public"]) + + + + cc_library( name = "gpr", srcs = [ @@ -42,11 +55,10 @@ cc_library( "src/core/lib/support/backoff.h", "src/core/lib/support/block_annotate.h", "src/core/lib/support/env.h", - "src/core/lib/support/load_file.h", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.h", - "src/core/lib/support/string_win32.h", + "src/core/lib/support/string_windows.h", "src/core/lib/support/thd_internal.h", "src/core/lib/support/time_precise.h", "src/core/lib/support/tmpfile.h", @@ -62,39 +74,38 @@ cc_library( "src/core/lib/support/cpu_windows.c", "src/core/lib/support/env_linux.c", "src/core/lib/support/env_posix.c", - "src/core/lib/support/env_win32.c", + "src/core/lib/support/env_windows.c", "src/core/lib/support/histogram.c", "src/core/lib/support/host_port.c", - "src/core/lib/support/load_file.c", "src/core/lib/support/log.c", "src/core/lib/support/log_android.c", "src/core/lib/support/log_linux.c", "src/core/lib/support/log_posix.c", - "src/core/lib/support/log_win32.c", + "src/core/lib/support/log_windows.c", "src/core/lib/support/murmur_hash.c", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/string.c", "src/core/lib/support/string_posix.c", - "src/core/lib/support/string_util_win32.c", - "src/core/lib/support/string_win32.c", + "src/core/lib/support/string_util_windows.c", + "src/core/lib/support/string_windows.c", "src/core/lib/support/subprocess_posix.c", "src/core/lib/support/subprocess_windows.c", "src/core/lib/support/sync.c", "src/core/lib/support/sync_posix.c", - "src/core/lib/support/sync_win32.c", + "src/core/lib/support/sync_windows.c", "src/core/lib/support/thd.c", "src/core/lib/support/thd_posix.c", - "src/core/lib/support/thd_win32.c", + "src/core/lib/support/thd_windows.c", "src/core/lib/support/time.c", "src/core/lib/support/time_posix.c", "src/core/lib/support/time_precise.c", - "src/core/lib/support/time_win32.c", + "src/core/lib/support/time_windows.c", "src/core/lib/support/tls_pthread.c", "src/core/lib/support/tmpfile_msys.c", "src/core/lib/support/tmpfile_posix.c", - "src/core/lib/support/tmpfile_win32.c", + "src/core/lib/support/tmpfile_windows.c", "src/core/lib/support/wrap_memcpy.c", ], hdrs = [ @@ -102,14 +113,14 @@ cc_library( "include/grpc/support/atm.h", "include/grpc/support/atm_gcc_atomic.h", "include/grpc/support/atm_gcc_sync.h", - "include/grpc/support/atm_win32.h", + "include/grpc/support/atm_windows.h", "include/grpc/support/avl.h", "include/grpc/support/cmdline.h", "include/grpc/support/cpu.h", "include/grpc/support/histogram.h", "include/grpc/support/host_port.h", "include/grpc/support/log.h", - "include/grpc/support/log_win32.h", + "include/grpc/support/log_windows.h", "include/grpc/support/port_platform.h", "include/grpc/support/slice.h", "include/grpc/support/slice_buffer.h", @@ -118,7 +129,7 @@ cc_library( "include/grpc/support/sync.h", "include/grpc/support/sync_generic.h", "include/grpc/support/sync_posix.h", - "include/grpc/support/sync_win32.h", + "include/grpc/support/sync_windows.h", "include/grpc/support/thd.h", "include/grpc/support/time.h", "include/grpc/support/tls.h", @@ -130,7 +141,7 @@ cc_library( "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", "include/grpc/impl/codegen/atm_gcc_sync.h", - "include/grpc/impl/codegen/atm_win32.h", + "include/grpc/impl/codegen/atm_windows.h", "include/grpc/impl/codegen/log.h", "include/grpc/impl/codegen/port_platform.h", "include/grpc/impl/codegen/slice.h", @@ -138,23 +149,19 @@ cc_library( "include/grpc/impl/codegen/sync.h", "include/grpc/impl/codegen/sync_generic.h", "include/grpc/impl/codegen/sync_posix.h", - "include/grpc/impl/codegen/sync_win32.h", + "include/grpc/impl/codegen/sync_windows.h", "include/grpc/impl/codegen/time.h", ], includes = [ "include", ".", ], - defines = [ - "GPR_BACKWARDS_COMPATIBILITY_MODE", - ], - copts = [ - "-std=c99", - ], deps = [ ], ) + + cc_library( name = "grpc", srcs = [ @@ -175,7 +182,10 @@ cc_library( "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/ev_epoll_linux.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h", + "src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/exec_ctx.h", "src/core/lib/iomgr/executor.h", @@ -183,6 +193,9 @@ cc_library( "src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/load_file.h", + "src/core/lib/iomgr/network_status_tracker.h", + "src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set_windows.h", @@ -191,7 +204,7 @@ cc_library( "src/core/lib/iomgr/sockaddr.h", "src/core/lib/iomgr/sockaddr_posix.h", "src/core/lib/iomgr/sockaddr_utils.h", - "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/sockaddr_windows.h", "src/core/lib/iomgr/socket_utils_posix.h", "src/core/lib/iomgr/socket_windows.h", "src/core/lib/iomgr/tcp_client.h", @@ -223,7 +236,6 @@ cc_library( "src/core/lib/surface/init.h", "src/core/lib/surface/lame_client.h", "src/core/lib/surface/server.h", - "src/core/lib/surface/surface_trace.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", "src/core/lib/transport/metadata.h", @@ -231,6 +243,7 @@ cc_library( "src/core/lib/transport/static_metadata.h", "src/core/lib/transport/transport.h", "src/core/lib/transport/transport_impl.h", + "src/core/ext/transport/chttp2/transport/bin_decoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/frame.h", @@ -252,15 +265,25 @@ cc_library( "src/core/ext/transport/chttp2/transport/timeout_encoding.h", "src/core/ext/transport/chttp2/transport/varint.h", "src/core/ext/transport/chttp2/alpn/alpn.h", - "src/core/lib/security/auth_filters.h", - "src/core/lib/security/b64.h", - "src/core/lib/security/credentials.h", - "src/core/lib/security/handshake.h", - "src/core/lib/security/json_token.h", - "src/core/lib/security/jwt_verifier.h", - "src/core/lib/security/secure_endpoint.h", - "src/core/lib/security/security_connector.h", - "src/core/lib/security/security_context.h", + "src/core/lib/security/context/security_context.h", + "src/core/lib/security/credentials/composite/composite_credentials.h", + "src/core/lib/security/credentials/credentials.h", + "src/core/lib/security/credentials/fake/fake_credentials.h", + "src/core/lib/security/credentials/google_default/google_default_credentials.h", + "src/core/lib/security/credentials/iam/iam_credentials.h", + "src/core/lib/security/credentials/jwt/json_token.h", + "src/core/lib/security/credentials/jwt/jwt_credentials.h", + "src/core/lib/security/credentials/jwt/jwt_verifier.h", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.h", + "src/core/lib/security/credentials/plugin/plugin_credentials.h", + "src/core/lib/security/credentials/ssl/ssl_credentials.h", + "src/core/lib/security/transport/auth_filters.h", + "src/core/lib/security/transport/handshake.h", + "src/core/lib/security/transport/secure_endpoint.h", + "src/core/lib/security/transport/security_connector.h", + "src/core/lib/security/transport/tsi_error.h", + "src/core/lib/security/util/b64.h", + "src/core/lib/security/util/json_util.h", "src/core/lib/tsi/fake_transport_security.h", "src/core/lib/tsi/ssl_transport_security.h", "src/core/lib/tsi/ssl_types.h", @@ -283,10 +306,13 @@ cc_library( "src/core/ext/client_config/subchannel_index.h", "src/core/ext/client_config/uri_parser.h", "src/core/ext/lb_policy/grpclb/load_balancer_api.h", - "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h", + "src/core/ext/load_reporting/load_reporting.h", + "src/core/ext/load_reporting/load_reporting_filter.h", "src/core/ext/census/aggregation.h", "src/core/ext/census/census_interface.h", "src/core/ext/census/census_rpc_stats.h", + "src/core/ext/census/gen/census.pb.h", "src/core/ext/census/grpc_filter.h", "src/core/ext/census/mlog.h", "src/core/ext/census/rpc_metric_id.h", @@ -298,7 +324,7 @@ cc_library( "src/core/lib/channel/connected_channel.c", "src/core/lib/channel/http_client_filter.c", "src/core/lib/channel/http_server_filter.c", - "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/compression.c", "src/core/lib/compression/message_compress.c", "src/core/lib/debug/trace.c", "src/core/lib/http/format_request.c", @@ -308,7 +334,10 @@ cc_library( "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/error.c", + "src/core/lib/iomgr/ev_epoll_linux.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c", + "src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/exec_ctx.c", "src/core/lib/iomgr/executor.c", @@ -316,6 +345,9 @@ cc_library( "src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/load_file.c", + "src/core/lib/iomgr/network_status_tracker.c", + "src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/resolve_address_posix.c", @@ -373,6 +405,7 @@ cc_library( "src/core/lib/transport/transport.c", "src/core/lib/transport/transport_op_string.c", "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c", + "src/core/ext/transport/chttp2/transport/bin_decoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c", @@ -396,20 +429,29 @@ cc_library( "src/core/ext/transport/chttp2/transport/writing.c", "src/core/ext/transport/chttp2/alpn/alpn.c", "src/core/lib/http/httpcli_security_connector.c", - "src/core/lib/security/b64.c", - "src/core/lib/security/client_auth_filter.c", - "src/core/lib/security/credentials.c", - "src/core/lib/security/credentials_metadata.c", - "src/core/lib/security/credentials_posix.c", - "src/core/lib/security/credentials_win32.c", - "src/core/lib/security/google_default_credentials.c", - "src/core/lib/security/handshake.c", - "src/core/lib/security/json_token.c", - "src/core/lib/security/jwt_verifier.c", - "src/core/lib/security/secure_endpoint.c", - "src/core/lib/security/security_connector.c", - "src/core/lib/security/security_context.c", - "src/core/lib/security/server_auth_filter.c", + "src/core/lib/security/context/security_context.c", + "src/core/lib/security/credentials/composite/composite_credentials.c", + "src/core/lib/security/credentials/credentials.c", + "src/core/lib/security/credentials/credentials_metadata.c", + "src/core/lib/security/credentials/fake/fake_credentials.c", + "src/core/lib/security/credentials/google_default/credentials_posix.c", + "src/core/lib/security/credentials/google_default/credentials_windows.c", + "src/core/lib/security/credentials/google_default/google_default_credentials.c", + "src/core/lib/security/credentials/iam/iam_credentials.c", + "src/core/lib/security/credentials/jwt/json_token.c", + "src/core/lib/security/credentials/jwt/jwt_credentials.c", + "src/core/lib/security/credentials/jwt/jwt_verifier.c", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.c", + "src/core/lib/security/credentials/plugin/plugin_credentials.c", + "src/core/lib/security/credentials/ssl/ssl_credentials.c", + "src/core/lib/security/transport/client_auth_filter.c", + "src/core/lib/security/transport/handshake.c", + "src/core/lib/security/transport/secure_endpoint.c", + "src/core/lib/security/transport/security_connector.c", + "src/core/lib/security/transport/server_auth_filter.c", + "src/core/lib/security/transport/tsi_error.c", + "src/core/lib/security/util/b64.c", + "src/core/lib/security/util/json_util.c", "src/core/lib/surface/init_secure.c", "src/core/lib/tsi/fake_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c", @@ -435,14 +477,19 @@ cc_library( "src/core/ext/client_config/subchannel_index.c", "src/core/ext/client_config/uri_parser.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", + "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", "src/core/ext/transport/chttp2/client/insecure/channel_create.c", + "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c", "src/core/ext/lb_policy/grpclb/load_balancer_api.c", - "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", "src/core/ext/lb_policy/pick_first/pick_first.c", "src/core/ext/lb_policy/round_robin/round_robin.c", "src/core/ext/resolver/dns/native/dns_resolver.c", "src/core/ext/resolver/sockaddr/sockaddr_resolver.c", + "src/core/ext/load_reporting/load_reporting.c", + "src/core/ext/load_reporting/load_reporting_filter.c", "src/core/ext/census/context.c", + "src/core/ext/census/gen/census.pb.c", "src/core/ext/census/grpc_context.c", "src/core/ext/census/grpc_filter.c", "src/core/ext/census/grpc_plugin.c", @@ -458,6 +505,8 @@ cc_library( "include/grpc/byte_buffer_reader.h", "include/grpc/compression.h", "include/grpc/grpc.h", + "include/grpc/grpc_posix.h", + "include/grpc/grpc_security_constants.h", "include/grpc/status.h", "include/grpc/impl/codegen/byte_buffer.h", "include/grpc/impl/codegen/byte_buffer_reader.h", @@ -470,7 +519,7 @@ cc_library( "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", "include/grpc/impl/codegen/atm_gcc_sync.h", - "include/grpc/impl/codegen/atm_win32.h", + "include/grpc/impl/codegen/atm_windows.h", "include/grpc/impl/codegen/log.h", "include/grpc/impl/codegen/port_platform.h", "include/grpc/impl/codegen/slice.h", @@ -478,10 +527,9 @@ cc_library( "include/grpc/impl/codegen/sync.h", "include/grpc/impl/codegen/sync_generic.h", "include/grpc/impl/codegen/sync_posix.h", - "include/grpc/impl/codegen/sync_win32.h", + "include/grpc/impl/codegen/sync_windows.h", "include/grpc/impl/codegen/time.h", "include/grpc/grpc_security.h", - "include/grpc/grpc_security_constants.h", "include/grpc/census.h", ], includes = [ @@ -499,160 +547,10 @@ cc_library( ], ) -cc_library( - name = "grpc++", - srcs = [ - "src/cpp/client/secure_credentials.h", - "src/cpp/common/core_codegen.h", - "src/cpp/common/secure_auth_context.h", - "src/cpp/server/secure_server_credentials.h", - "src/cpp/client/create_channel_internal.h", - "src/cpp/server/dynamic_thread_pool.h", - "src/cpp/server/thread_pool_interface.h", - "src/cpp/client/secure_credentials.cc", - "src/cpp/common/auth_property_iterator.cc", - "src/cpp/common/secure_auth_context.cc", - "src/cpp/common/secure_channel_arguments.cc", - "src/cpp/common/secure_create_auth_context.cc", - "src/cpp/server/secure_server_credentials.cc", - "src/cpp/client/channel.cc", - "src/cpp/client/client_context.cc", - "src/cpp/client/create_channel.cc", - "src/cpp/client/create_channel_internal.cc", - "src/cpp/client/credentials.cc", - "src/cpp/client/generic_stub.cc", - "src/cpp/client/insecure_credentials.cc", - "src/cpp/common/channel_arguments.cc", - "src/cpp/common/completion_queue.cc", - "src/cpp/common/core_codegen.cc", - "src/cpp/common/rpc_method.cc", - "src/cpp/server/async_generic_service.cc", - "src/cpp/server/create_default_thread_pool.cc", - "src/cpp/server/dynamic_thread_pool.cc", - "src/cpp/server/insecure_server_credentials.cc", - "src/cpp/server/server.cc", - "src/cpp/server/server_builder.cc", - "src/cpp/server/server_context.cc", - "src/cpp/server/server_credentials.cc", - "src/cpp/util/byte_buffer.cc", - "src/cpp/util/slice.cc", - "src/cpp/util/status.cc", - "src/cpp/util/string_ref.cc", - "src/cpp/util/time.cc", - "src/cpp/codegen/codegen_init.cc", - ], - hdrs = [ - "include/grpc++/alarm.h", - "include/grpc++/channel.h", - "include/grpc++/client_context.h", - "include/grpc++/completion_queue.h", - "include/grpc++/create_channel.h", - "include/grpc++/generic/async_generic_service.h", - "include/grpc++/generic/generic_stub.h", - "include/grpc++/grpc++.h", - "include/grpc++/impl/call.h", - "include/grpc++/impl/client_unary_call.h", - "include/grpc++/impl/grpc_library.h", - "include/grpc++/impl/method_handler_impl.h", - "include/grpc++/impl/proto_utils.h", - "include/grpc++/impl/rpc_method.h", - "include/grpc++/impl/rpc_service_method.h", - "include/grpc++/impl/serialization_traits.h", - "include/grpc++/impl/server_builder_option.h", - "include/grpc++/impl/service_type.h", - "include/grpc++/impl/sync.h", - "include/grpc++/impl/sync_cxx11.h", - "include/grpc++/impl/sync_no_cxx11.h", - "include/grpc++/impl/thd.h", - "include/grpc++/impl/thd_cxx11.h", - "include/grpc++/impl/thd_no_cxx11.h", - "include/grpc++/security/auth_context.h", - "include/grpc++/security/auth_metadata_processor.h", - "include/grpc++/security/credentials.h", - "include/grpc++/security/server_credentials.h", - "include/grpc++/server.h", - "include/grpc++/server_builder.h", - "include/grpc++/server_context.h", - "include/grpc++/support/async_stream.h", - "include/grpc++/support/async_unary_call.h", - "include/grpc++/support/byte_buffer.h", - "include/grpc++/support/channel_arguments.h", - "include/grpc++/support/slice.h", - "include/grpc++/support/status.h", - "include/grpc++/support/status_code_enum.h", - "include/grpc++/support/string_ref.h", - "include/grpc++/support/stub_options.h", - "include/grpc++/support/sync_stream.h", - "include/grpc++/support/time.h", - "include/grpc++/impl/codegen/async_stream.h", - "include/grpc++/impl/codegen/async_unary_call.h", - "include/grpc++/impl/codegen/call.h", - "include/grpc++/impl/codegen/call_hook.h", - "include/grpc++/impl/codegen/channel_interface.h", - "include/grpc++/impl/codegen/client_context.h", - "include/grpc++/impl/codegen/client_unary_call.h", - "include/grpc++/impl/codegen/completion_queue.h", - "include/grpc++/impl/codegen/completion_queue_tag.h", - "include/grpc++/impl/codegen/core_codegen_interface.h", - "include/grpc++/impl/codegen/create_auth_context.h", - "include/grpc++/impl/codegen/grpc_library.h", - "include/grpc++/impl/codegen/method_handler_impl.h", - "include/grpc++/impl/codegen/proto_utils.h", - "include/grpc++/impl/codegen/rpc_method.h", - "include/grpc++/impl/codegen/rpc_service_method.h", - "include/grpc++/impl/codegen/security/auth_context.h", - "include/grpc++/impl/codegen/serialization_traits.h", - "include/grpc++/impl/codegen/server_context.h", - "include/grpc++/impl/codegen/server_interface.h", - "include/grpc++/impl/codegen/service_type.h", - "include/grpc++/impl/codegen/status.h", - "include/grpc++/impl/codegen/status_code_enum.h", - "include/grpc++/impl/codegen/string_ref.h", - "include/grpc++/impl/codegen/stub_options.h", - "include/grpc++/impl/codegen/sync.h", - "include/grpc++/impl/codegen/sync_cxx11.h", - "include/grpc++/impl/codegen/sync_no_cxx11.h", - "include/grpc++/impl/codegen/sync_stream.h", - "include/grpc++/impl/codegen/time.h", - "include/grpc/impl/codegen/byte_buffer.h", - "include/grpc/impl/codegen/byte_buffer_reader.h", - "include/grpc/impl/codegen/compression_types.h", - "include/grpc/impl/codegen/connectivity_state.h", - "include/grpc/impl/codegen/grpc_types.h", - "include/grpc/impl/codegen/propagation_bits.h", - "include/grpc/impl/codegen/status.h", - "include/grpc/impl/codegen/alloc.h", - "include/grpc/impl/codegen/atm.h", - "include/grpc/impl/codegen/atm_gcc_atomic.h", - "include/grpc/impl/codegen/atm_gcc_sync.h", - "include/grpc/impl/codegen/atm_win32.h", - "include/grpc/impl/codegen/log.h", - "include/grpc/impl/codegen/port_platform.h", - "include/grpc/impl/codegen/slice.h", - "include/grpc/impl/codegen/slice_buffer.h", - "include/grpc/impl/codegen/sync.h", - "include/grpc/impl/codegen/sync_generic.h", - "include/grpc/impl/codegen/sync_posix.h", - "include/grpc/impl/codegen/sync_win32.h", - "include/grpc/impl/codegen/time.h", - "include/grpc++/impl/codegen/config.h", - "include/grpc++/impl/codegen/config_protobuf.h", - "include/grpc++/support/config.h", - "include/grpc++/support/config_protobuf.h", - ], - includes = [ - "include", - ".", - ], - deps = [ - "//external:libssl", - "//external:protobuf_clib", - ":grpc", - ], -) + cc_library( - name = "grpc_unsecure", + name = "grpc_cronet", srcs = [ "src/core/lib/channel/channel_args.h", "src/core/lib/channel/channel_stack.h", @@ -671,7 +569,10 @@ cc_library( "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/ev_epoll_linux.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h", + "src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/exec_ctx.h", "src/core/lib/iomgr/executor.h", @@ -679,6 +580,9 @@ cc_library( "src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/load_file.h", + "src/core/lib/iomgr/network_status_tracker.h", + "src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set_windows.h", @@ -687,7 +591,7 @@ cc_library( "src/core/lib/iomgr/sockaddr.h", "src/core/lib/iomgr/sockaddr_posix.h", "src/core/lib/iomgr/sockaddr_utils.h", - "src/core/lib/iomgr/sockaddr_win32.h", + "src/core/lib/iomgr/sockaddr_windows.h", "src/core/lib/iomgr/socket_utils_posix.h", "src/core/lib/iomgr/socket_windows.h", "src/core/lib/iomgr/tcp_client.h", @@ -719,7 +623,6 @@ cc_library( "src/core/lib/surface/init.h", "src/core/lib/surface/lame_client.h", "src/core/lib/surface/server.h", - "src/core/lib/surface/surface_trace.h", "src/core/lib/transport/byte_stream.h", "src/core/lib/transport/connectivity_state.h", "src/core/lib/transport/metadata.h", @@ -727,6 +630,8 @@ cc_library( "src/core/lib/transport/static_metadata.h", "src/core/lib/transport/transport.h", "src/core/lib/transport/transport_impl.h", + "third_party/objective_c/Cronet/cronet_c_for_grpc.h", + "src/core/ext/transport/chttp2/transport/bin_decoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/frame.h", @@ -764,16 +669,31 @@ cc_library( "src/core/ext/client_config/subchannel_call_holder.h", "src/core/ext/client_config/subchannel_index.h", "src/core/ext/client_config/uri_parser.h", - "src/core/ext/lb_policy/grpclb/load_balancer_api.h", - "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.h", - "src/core/ext/census/aggregation.h", - "src/core/ext/census/census_interface.h", - "src/core/ext/census/census_rpc_stats.h", - "src/core/ext/census/grpc_filter.h", - "src/core/ext/census/mlog.h", - "src/core/ext/census/rpc_metric_id.h", + "src/core/lib/security/context/security_context.h", + "src/core/lib/security/credentials/composite/composite_credentials.h", + "src/core/lib/security/credentials/credentials.h", + "src/core/lib/security/credentials/fake/fake_credentials.h", + "src/core/lib/security/credentials/google_default/google_default_credentials.h", + "src/core/lib/security/credentials/iam/iam_credentials.h", + "src/core/lib/security/credentials/jwt/json_token.h", + "src/core/lib/security/credentials/jwt/jwt_credentials.h", + "src/core/lib/security/credentials/jwt/jwt_verifier.h", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.h", + "src/core/lib/security/credentials/plugin/plugin_credentials.h", + "src/core/lib/security/credentials/ssl/ssl_credentials.h", + "src/core/lib/security/transport/auth_filters.h", + "src/core/lib/security/transport/handshake.h", + "src/core/lib/security/transport/secure_endpoint.h", + "src/core/lib/security/transport/security_connector.h", + "src/core/lib/security/transport/tsi_error.h", + "src/core/lib/security/util/b64.h", + "src/core/lib/security/util/json_util.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", "src/core/lib/surface/init.c", - "src/core/lib/surface/init_unsecure.c", "src/core/lib/channel/channel_args.c", "src/core/lib/channel/channel_stack.c", "src/core/lib/channel/channel_stack_builder.c", @@ -781,7 +701,7 @@ cc_library( "src/core/lib/channel/connected_channel.c", "src/core/lib/channel/http_client_filter.c", "src/core/lib/channel/http_server_filter.c", - "src/core/lib/compression/compression_algorithm.c", + "src/core/lib/compression/compression.c", "src/core/lib/compression/message_compress.c", "src/core/lib/debug/trace.c", "src/core/lib/http/format_request.c", @@ -791,7 +711,10 @@ cc_library( "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/error.c", + "src/core/lib/iomgr/ev_epoll_linux.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c", + "src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/exec_ctx.c", "src/core/lib/iomgr/executor.c", @@ -799,6 +722,9 @@ cc_library( "src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/load_file.c", + "src/core/lib/iomgr/network_status_tracker.c", + "src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/resolve_address_posix.c", @@ -855,7 +781,11 @@ cc_library( "src/core/lib/transport/static_metadata.c", "src/core/lib/transport/transport.c", "src/core/lib/transport/transport_op_string.c", - "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", + "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c", + "src/core/ext/transport/cronet/transport/cronet_api_dummy.c", + "src/core/ext/transport/cronet/transport/cronet_transport.c", + "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", + "src/core/ext/transport/chttp2/transport/bin_decoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c", @@ -878,7 +808,6 @@ cc_library( "src/core/ext/transport/chttp2/transport/varint.c", "src/core/ext/transport/chttp2/transport/writing.c", "src/core/ext/transport/chttp2/alpn/alpn.c", - "src/core/ext/transport/chttp2/client/insecure/channel_create.c", "src/core/ext/client_config/channel_connectivity.c", "src/core/ext/client_config/client_channel.c", "src/core/ext/client_config/client_channel_factory.c", @@ -898,28 +827,43 @@ cc_library( "src/core/ext/client_config/subchannel_call_holder.c", "src/core/ext/client_config/subchannel_index.c", "src/core/ext/client_config/uri_parser.c", - "src/core/ext/resolver/dns/native/dns_resolver.c", - "src/core/ext/resolver/sockaddr/sockaddr_resolver.c", - "src/core/ext/lb_policy/grpclb/load_balancer_api.c", - "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v0/load_balancer.pb.c", - "src/core/ext/lb_policy/pick_first/pick_first.c", - "src/core/ext/lb_policy/round_robin/round_robin.c", - "src/core/ext/census/context.c", - "src/core/ext/census/grpc_context.c", - "src/core/ext/census/grpc_filter.c", - "src/core/ext/census/grpc_plugin.c", - "src/core/ext/census/initialize.c", - "src/core/ext/census/mlog.c", - "src/core/ext/census/operation.c", - "src/core/ext/census/placeholders.c", - "src/core/ext/census/tracing.c", - "src/core/plugin_registry/grpc_unsecure_plugin_registry.c", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/security/context/security_context.c", + "src/core/lib/security/credentials/composite/composite_credentials.c", + "src/core/lib/security/credentials/credentials.c", + "src/core/lib/security/credentials/credentials_metadata.c", + "src/core/lib/security/credentials/fake/fake_credentials.c", + "src/core/lib/security/credentials/google_default/credentials_posix.c", + "src/core/lib/security/credentials/google_default/credentials_windows.c", + "src/core/lib/security/credentials/google_default/google_default_credentials.c", + "src/core/lib/security/credentials/iam/iam_credentials.c", + "src/core/lib/security/credentials/jwt/json_token.c", + "src/core/lib/security/credentials/jwt/jwt_credentials.c", + "src/core/lib/security/credentials/jwt/jwt_verifier.c", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.c", + "src/core/lib/security/credentials/plugin/plugin_credentials.c", + "src/core/lib/security/credentials/ssl/ssl_credentials.c", + "src/core/lib/security/transport/client_auth_filter.c", + "src/core/lib/security/transport/handshake.c", + "src/core/lib/security/transport/secure_endpoint.c", + "src/core/lib/security/transport/security_connector.c", + "src/core/lib/security/transport/server_auth_filter.c", + "src/core/lib/security/transport/tsi_error.c", + "src/core/lib/security/util/b64.c", + "src/core/lib/security/util/json_util.c", + "src/core/lib/surface/init_secure.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/transport_security.c", + "src/core/plugin_registry/grpc_cronet_plugin_registry.c", ], hdrs = [ "include/grpc/byte_buffer.h", "include/grpc/byte_buffer_reader.h", "include/grpc/compression.h", "include/grpc/grpc.h", + "include/grpc/grpc_posix.h", + "include/grpc/grpc_security_constants.h", "include/grpc/status.h", "include/grpc/impl/codegen/byte_buffer.h", "include/grpc/impl/codegen/byte_buffer_reader.h", @@ -932,7 +876,7 @@ cc_library( "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", "include/grpc/impl/codegen/atm_gcc_sync.h", - "include/grpc/impl/codegen/atm_win32.h", + "include/grpc/impl/codegen/atm_windows.h", "include/grpc/impl/codegen/log.h", "include/grpc/impl/codegen/port_platform.h", "include/grpc/impl/codegen/slice.h", @@ -940,75 +884,818 @@ cc_library( "include/grpc/impl/codegen/sync.h", "include/grpc/impl/codegen/sync_generic.h", "include/grpc/impl/codegen/sync_posix.h", - "include/grpc/impl/codegen/sync_win32.h", + "include/grpc/impl/codegen/sync_windows.h", "include/grpc/impl/codegen/time.h", - "include/grpc/census.h", + "include/grpc/grpc_cronet.h", + "include/grpc/grpc_security.h", ], includes = [ "include", ".", ], deps = [ + "//external:libssl", ":gpr", - "//external:nanopb", - ], - copts = [ - "-std=gnu99", ], ) + + cc_library( - name = "grpc++_unsecure", + name = "grpc_unsecure", srcs = [ - "src/cpp/client/create_channel_internal.h", - "src/cpp/common/core_codegen.h", - "src/cpp/server/dynamic_thread_pool.h", - "src/cpp/server/thread_pool_interface.h", - "src/cpp/common/insecure_create_auth_context.cc", - "src/cpp/client/channel.cc", - "src/cpp/client/client_context.cc", - "src/cpp/client/create_channel.cc", - "src/cpp/client/create_channel_internal.cc", - "src/cpp/client/credentials.cc", - "src/cpp/client/generic_stub.cc", - "src/cpp/client/insecure_credentials.cc", - "src/cpp/common/channel_arguments.cc", - "src/cpp/common/completion_queue.cc", - "src/cpp/common/core_codegen.cc", - "src/cpp/common/rpc_method.cc", - "src/cpp/server/async_generic_service.cc", - "src/cpp/server/create_default_thread_pool.cc", - "src/cpp/server/dynamic_thread_pool.cc", - "src/cpp/server/insecure_server_credentials.cc", - "src/cpp/server/server.cc", - "src/cpp/server/server_builder.cc", - "src/cpp/server/server_context.cc", - "src/cpp/server/server_credentials.cc", - "src/cpp/util/byte_buffer.cc", - "src/cpp/util/slice.cc", - "src/cpp/util/status.cc", - "src/cpp/util/string_ref.cc", - "src/cpp/util/time.cc", - "src/cpp/codegen/codegen_init.cc", - ], - hdrs = [ - "include/grpc++/alarm.h", - "include/grpc++/channel.h", - "include/grpc++/client_context.h", - "include/grpc++/completion_queue.h", - "include/grpc++/create_channel.h", - "include/grpc++/generic/async_generic_service.h", - "include/grpc++/generic/generic_stub.h", - "include/grpc++/grpc++.h", - "include/grpc++/impl/call.h", - "include/grpc++/impl/client_unary_call.h", - "include/grpc++/impl/grpc_library.h", - "include/grpc++/impl/method_handler_impl.h", - "include/grpc++/impl/proto_utils.h", - "include/grpc++/impl/rpc_method.h", - "include/grpc++/impl/rpc_service_method.h", - "include/grpc++/impl/serialization_traits.h", - "include/grpc++/impl/server_builder_option.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/ev_epoll_linux.h", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.h", + "src/core/lib/iomgr/ev_poll_posix.h", + "src/core/lib/iomgr/ev_posix.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/load_file.h", + "src/core/lib/iomgr/network_status_tracker.h", + "src/core/lib/iomgr/polling_entity.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_windows.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/ext/transport/chttp2/transport/bin_decoder.h", + "src/core/ext/transport/chttp2/transport/bin_encoder.h", + "src/core/ext/transport/chttp2/transport/chttp2_transport.h", + "src/core/ext/transport/chttp2/transport/frame.h", + "src/core/ext/transport/chttp2/transport/frame_data.h", + "src/core/ext/transport/chttp2/transport/frame_goaway.h", + "src/core/ext/transport/chttp2/transport/frame_ping.h", + "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", + "src/core/ext/transport/chttp2/transport/frame_settings.h", + "src/core/ext/transport/chttp2/transport/frame_window_update.h", + "src/core/ext/transport/chttp2/transport/hpack_encoder.h", + "src/core/ext/transport/chttp2/transport/hpack_parser.h", + "src/core/ext/transport/chttp2/transport/hpack_table.h", + "src/core/ext/transport/chttp2/transport/http2_errors.h", + "src/core/ext/transport/chttp2/transport/huffsyms.h", + "src/core/ext/transport/chttp2/transport/incoming_metadata.h", + "src/core/ext/transport/chttp2/transport/internal.h", + "src/core/ext/transport/chttp2/transport/status_conversion.h", + "src/core/ext/transport/chttp2/transport/stream_map.h", + "src/core/ext/transport/chttp2/transport/timeout_encoding.h", + "src/core/ext/transport/chttp2/transport/varint.h", + "src/core/ext/transport/chttp2/alpn/alpn.h", + "src/core/ext/client_config/client_channel.h", + "src/core/ext/client_config/client_channel_factory.h", + "src/core/ext/client_config/client_config.h", + "src/core/ext/client_config/connector.h", + "src/core/ext/client_config/initial_connect_string.h", + "src/core/ext/client_config/lb_policy.h", + "src/core/ext/client_config/lb_policy_factory.h", + "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/parse_address.h", + "src/core/ext/client_config/resolver.h", + "src/core/ext/client_config/resolver_factory.h", + "src/core/ext/client_config/resolver_registry.h", + "src/core/ext/client_config/subchannel.h", + "src/core/ext/client_config/subchannel_call_holder.h", + "src/core/ext/client_config/subchannel_index.h", + "src/core/ext/client_config/uri_parser.h", + "src/core/ext/load_reporting/load_reporting.h", + "src/core/ext/load_reporting/load_reporting_filter.h", + "src/core/ext/lb_policy/grpclb/load_balancer_api.h", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h", + "src/core/ext/census/aggregation.h", + "src/core/ext/census/census_interface.h", + "src/core/ext/census/census_rpc_stats.h", + "src/core/ext/census/gen/census.pb.h", + "src/core/ext/census/grpc_filter.h", + "src/core/ext/census/mlog.h", + "src/core/ext/census/rpc_metric_id.h", + "src/core/lib/surface/init.c", + "src/core/lib/surface/init_unsecure.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/compression/compression.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/error.c", + "src/core/lib/iomgr/ev_epoll_linux.c", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.c", + "src/core/lib/iomgr/ev_poll_posix.c", + "src/core/lib/iomgr/ev_posix.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/load_file.c", + "src/core/lib/iomgr/network_status_tracker.c", + "src/core/lib/iomgr/polling_entity.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", + "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", + "src/core/ext/transport/chttp2/transport/bin_decoder.c", + "src/core/ext/transport/chttp2/transport/bin_encoder.c", + "src/core/ext/transport/chttp2/transport/chttp2_plugin.c", + "src/core/ext/transport/chttp2/transport/chttp2_transport.c", + "src/core/ext/transport/chttp2/transport/frame_data.c", + "src/core/ext/transport/chttp2/transport/frame_goaway.c", + "src/core/ext/transport/chttp2/transport/frame_ping.c", + "src/core/ext/transport/chttp2/transport/frame_rst_stream.c", + "src/core/ext/transport/chttp2/transport/frame_settings.c", + "src/core/ext/transport/chttp2/transport/frame_window_update.c", + "src/core/ext/transport/chttp2/transport/hpack_encoder.c", + "src/core/ext/transport/chttp2/transport/hpack_parser.c", + "src/core/ext/transport/chttp2/transport/hpack_table.c", + "src/core/ext/transport/chttp2/transport/huffsyms.c", + "src/core/ext/transport/chttp2/transport/incoming_metadata.c", + "src/core/ext/transport/chttp2/transport/parsing.c", + "src/core/ext/transport/chttp2/transport/status_conversion.c", + "src/core/ext/transport/chttp2/transport/stream_lists.c", + "src/core/ext/transport/chttp2/transport/stream_map.c", + "src/core/ext/transport/chttp2/transport/timeout_encoding.c", + "src/core/ext/transport/chttp2/transport/varint.c", + "src/core/ext/transport/chttp2/transport/writing.c", + "src/core/ext/transport/chttp2/alpn/alpn.c", + "src/core/ext/transport/chttp2/client/insecure/channel_create.c", + "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c", + "src/core/ext/client_config/channel_connectivity.c", + "src/core/ext/client_config/client_channel.c", + "src/core/ext/client_config/client_channel_factory.c", + "src/core/ext/client_config/client_config.c", + "src/core/ext/client_config/client_config_plugin.c", + "src/core/ext/client_config/connector.c", + "src/core/ext/client_config/default_initial_connect_string.c", + "src/core/ext/client_config/initial_connect_string.c", + "src/core/ext/client_config/lb_policy.c", + "src/core/ext/client_config/lb_policy_factory.c", + "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/parse_address.c", + "src/core/ext/client_config/resolver.c", + "src/core/ext/client_config/resolver_factory.c", + "src/core/ext/client_config/resolver_registry.c", + "src/core/ext/client_config/subchannel.c", + "src/core/ext/client_config/subchannel_call_holder.c", + "src/core/ext/client_config/subchannel_index.c", + "src/core/ext/client_config/uri_parser.c", + "src/core/ext/resolver/dns/native/dns_resolver.c", + "src/core/ext/resolver/sockaddr/sockaddr_resolver.c", + "src/core/ext/load_reporting/load_reporting.c", + "src/core/ext/load_reporting/load_reporting_filter.c", + "src/core/ext/lb_policy/grpclb/load_balancer_api.c", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", + "src/core/ext/lb_policy/pick_first/pick_first.c", + "src/core/ext/lb_policy/round_robin/round_robin.c", + "src/core/ext/census/context.c", + "src/core/ext/census/gen/census.pb.c", + "src/core/ext/census/grpc_context.c", + "src/core/ext/census/grpc_filter.c", + "src/core/ext/census/grpc_plugin.c", + "src/core/ext/census/initialize.c", + "src/core/ext/census/mlog.c", + "src/core/ext/census/operation.c", + "src/core/ext/census/placeholders.c", + "src/core/ext/census/tracing.c", + "src/core/plugin_registry/grpc_unsecure_plugin_registry.c", + ], + hdrs = [ + "include/grpc/byte_buffer.h", + "include/grpc/byte_buffer_reader.h", + "include/grpc/compression.h", + "include/grpc/grpc.h", + "include/grpc/grpc_posix.h", + "include/grpc/grpc_security_constants.h", + "include/grpc/status.h", + "include/grpc/impl/codegen/byte_buffer.h", + "include/grpc/impl/codegen/byte_buffer_reader.h", + "include/grpc/impl/codegen/compression_types.h", + "include/grpc/impl/codegen/connectivity_state.h", + "include/grpc/impl/codegen/grpc_types.h", + "include/grpc/impl/codegen/propagation_bits.h", + "include/grpc/impl/codegen/status.h", + "include/grpc/impl/codegen/alloc.h", + "include/grpc/impl/codegen/atm.h", + "include/grpc/impl/codegen/atm_gcc_atomic.h", + "include/grpc/impl/codegen/atm_gcc_sync.h", + "include/grpc/impl/codegen/atm_windows.h", + "include/grpc/impl/codegen/log.h", + "include/grpc/impl/codegen/port_platform.h", + "include/grpc/impl/codegen/slice.h", + "include/grpc/impl/codegen/slice_buffer.h", + "include/grpc/impl/codegen/sync.h", + "include/grpc/impl/codegen/sync_generic.h", + "include/grpc/impl/codegen/sync_posix.h", + "include/grpc/impl/codegen/sync_windows.h", + "include/grpc/impl/codegen/time.h", + "include/grpc/census.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + ":gpr", + "//external:nanopb", + ], + copts = [ + "-std=gnu99", + ], +) + + + +cc_library( + name = "grpc++", + srcs = [ + "include/grpc++/impl/codegen/core_codegen.h", + "src/cpp/client/secure_credentials.h", + "src/cpp/common/secure_auth_context.h", + "src/cpp/server/secure_server_credentials.h", + "src/cpp/client/create_channel_internal.h", + "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/thread_pool_interface.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/ev_epoll_linux.h", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.h", + "src/core/lib/iomgr/ev_poll_posix.h", + "src/core/lib/iomgr/ev_posix.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/load_file.h", + "src/core/lib/iomgr/network_status_tracker.h", + "src/core/lib/iomgr/polling_entity.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_windows.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/cpp/client/secure_credentials.cc", + "src/cpp/common/auth_property_iterator.cc", + "src/cpp/common/secure_auth_context.cc", + "src/cpp/common/secure_channel_arguments.cc", + "src/cpp/common/secure_create_auth_context.cc", + "src/cpp/server/secure_server_credentials.cc", + "src/cpp/client/channel.cc", + "src/cpp/client/client_context.cc", + "src/cpp/client/create_channel.cc", + "src/cpp/client/create_channel_internal.cc", + "src/cpp/client/create_channel_posix.cc", + "src/cpp/client/credentials.cc", + "src/cpp/client/generic_stub.cc", + "src/cpp/client/insecure_credentials.cc", + "src/cpp/common/channel_arguments.cc", + "src/cpp/common/completion_queue.cc", + "src/cpp/common/core_codegen.cc", + "src/cpp/common/rpc_method.cc", + "src/cpp/server/async_generic_service.cc", + "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", + "src/cpp/server/insecure_server_credentials.cc", + "src/cpp/server/server.cc", + "src/cpp/server/server_builder.cc", + "src/cpp/server/server_context.cc", + "src/cpp/server/server_credentials.cc", + "src/cpp/server/server_posix.cc", + "src/cpp/util/byte_buffer.cc", + "src/cpp/util/slice.cc", + "src/cpp/util/status.cc", + "src/cpp/util/string_ref.cc", + "src/cpp/util/time.cc", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/compression/compression.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/error.c", + "src/core/lib/iomgr/ev_epoll_linux.c", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.c", + "src/core/lib/iomgr/ev_poll_posix.c", + "src/core/lib/iomgr/ev_posix.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/load_file.c", + "src/core/lib/iomgr/network_status_tracker.c", + "src/core/lib/iomgr/polling_entity.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/cpp/codegen/codegen_init.cc", + ], + hdrs = [ + "include/grpc++/alarm.h", + "include/grpc++/channel.h", + "include/grpc++/client_context.h", + "include/grpc++/completion_queue.h", + "include/grpc++/create_channel.h", + "include/grpc++/create_channel_posix.h", + "include/grpc++/generic/async_generic_service.h", + "include/grpc++/generic/generic_stub.h", + "include/grpc++/grpc++.h", + "include/grpc++/impl/call.h", + "include/grpc++/impl/client_unary_call.h", + "include/grpc++/impl/codegen/core_codegen.h", + "include/grpc++/impl/grpc_library.h", + "include/grpc++/impl/method_handler_impl.h", + "include/grpc++/impl/rpc_method.h", + "include/grpc++/impl/rpc_service_method.h", + "include/grpc++/impl/serialization_traits.h", + "include/grpc++/impl/server_builder_option.h", + "include/grpc++/impl/server_builder_plugin.h", + "include/grpc++/impl/server_initializer.h", + "include/grpc++/impl/service_type.h", + "include/grpc++/impl/sync.h", + "include/grpc++/impl/sync_cxx11.h", + "include/grpc++/impl/sync_no_cxx11.h", + "include/grpc++/impl/thd.h", + "include/grpc++/impl/thd_cxx11.h", + "include/grpc++/impl/thd_no_cxx11.h", + "include/grpc++/security/auth_context.h", + "include/grpc++/security/auth_metadata_processor.h", + "include/grpc++/security/credentials.h", + "include/grpc++/security/server_credentials.h", + "include/grpc++/server.h", + "include/grpc++/server_builder.h", + "include/grpc++/server_context.h", + "include/grpc++/server_posix.h", + "include/grpc++/support/async_stream.h", + "include/grpc++/support/async_unary_call.h", + "include/grpc++/support/byte_buffer.h", + "include/grpc++/support/channel_arguments.h", + "include/grpc++/support/config.h", + "include/grpc++/support/slice.h", + "include/grpc++/support/status.h", + "include/grpc++/support/status_code_enum.h", + "include/grpc++/support/string_ref.h", + "include/grpc++/support/stub_options.h", + "include/grpc++/support/sync_stream.h", + "include/grpc++/support/time.h", + "include/grpc/byte_buffer.h", + "include/grpc/byte_buffer_reader.h", + "include/grpc/compression.h", + "include/grpc/grpc.h", + "include/grpc/grpc_posix.h", + "include/grpc/grpc_security_constants.h", + "include/grpc/status.h", + "include/grpc/impl/codegen/byte_buffer.h", + "include/grpc/impl/codegen/byte_buffer_reader.h", + "include/grpc/impl/codegen/compression_types.h", + "include/grpc/impl/codegen/connectivity_state.h", + "include/grpc/impl/codegen/grpc_types.h", + "include/grpc/impl/codegen/propagation_bits.h", + "include/grpc/impl/codegen/status.h", + "include/grpc/impl/codegen/alloc.h", + "include/grpc/impl/codegen/atm.h", + "include/grpc/impl/codegen/atm_gcc_atomic.h", + "include/grpc/impl/codegen/atm_gcc_sync.h", + "include/grpc/impl/codegen/atm_windows.h", + "include/grpc/impl/codegen/log.h", + "include/grpc/impl/codegen/port_platform.h", + "include/grpc/impl/codegen/slice.h", + "include/grpc/impl/codegen/slice_buffer.h", + "include/grpc/impl/codegen/sync.h", + "include/grpc/impl/codegen/sync_generic.h", + "include/grpc/impl/codegen/sync_posix.h", + "include/grpc/impl/codegen/sync_windows.h", + "include/grpc/impl/codegen/time.h", + "include/grpc++/impl/codegen/async_stream.h", + "include/grpc++/impl/codegen/async_unary_call.h", + "include/grpc++/impl/codegen/call.h", + "include/grpc++/impl/codegen/call_hook.h", + "include/grpc++/impl/codegen/channel_interface.h", + "include/grpc++/impl/codegen/client_context.h", + "include/grpc++/impl/codegen/client_unary_call.h", + "include/grpc++/impl/codegen/completion_queue.h", + "include/grpc++/impl/codegen/completion_queue_tag.h", + "include/grpc++/impl/codegen/config.h", + "include/grpc++/impl/codegen/core_codegen_interface.h", + "include/grpc++/impl/codegen/create_auth_context.h", + "include/grpc++/impl/codegen/grpc_library.h", + "include/grpc++/impl/codegen/method_handler_impl.h", + "include/grpc++/impl/codegen/rpc_method.h", + "include/grpc++/impl/codegen/rpc_service_method.h", + "include/grpc++/impl/codegen/security/auth_context.h", + "include/grpc++/impl/codegen/serialization_traits.h", + "include/grpc++/impl/codegen/server_context.h", + "include/grpc++/impl/codegen/server_interface.h", + "include/grpc++/impl/codegen/service_type.h", + "include/grpc++/impl/codegen/status.h", + "include/grpc++/impl/codegen/status_code_enum.h", + "include/grpc++/impl/codegen/string_ref.h", + "include/grpc++/impl/codegen/stub_options.h", + "include/grpc++/impl/codegen/sync.h", + "include/grpc++/impl/codegen/sync_cxx11.h", + "include/grpc++/impl/codegen/sync_no_cxx11.h", + "include/grpc++/impl/codegen/sync_stream.h", + "include/grpc++/impl/codegen/time.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + "//external:libssl", + "//external:protobuf_clib", + ":grpc", + ":gpr", + ], +) + + + +cc_library( + name = "grpc++_reflection", + srcs = [ + "src/cpp/ext/proto_server_reflection.h", + "src/cpp/ext/proto_server_reflection.cc", + "src/cpp/ext/proto_server_reflection_plugin.cc", + "src/cpp/ext/reflection.grpc.pb.cc", + "src/cpp/ext/reflection.pb.cc", + ], + hdrs = [ + "include/grpc++/ext/proto_server_reflection_plugin.h", + "include/grpc++/ext/reflection.grpc.pb.h", + "include/grpc++/ext/reflection.pb.h", + "include/grpc++/impl/codegen/proto_utils.h", + "include/grpc++/impl/codegen/async_stream.h", + "include/grpc++/impl/codegen/async_unary_call.h", + "include/grpc++/impl/codegen/call.h", + "include/grpc++/impl/codegen/call_hook.h", + "include/grpc++/impl/codegen/channel_interface.h", + "include/grpc++/impl/codegen/client_context.h", + "include/grpc++/impl/codegen/client_unary_call.h", + "include/grpc++/impl/codegen/completion_queue.h", + "include/grpc++/impl/codegen/completion_queue_tag.h", + "include/grpc++/impl/codegen/config.h", + "include/grpc++/impl/codegen/core_codegen_interface.h", + "include/grpc++/impl/codegen/create_auth_context.h", + "include/grpc++/impl/codegen/grpc_library.h", + "include/grpc++/impl/codegen/method_handler_impl.h", + "include/grpc++/impl/codegen/rpc_method.h", + "include/grpc++/impl/codegen/rpc_service_method.h", + "include/grpc++/impl/codegen/security/auth_context.h", + "include/grpc++/impl/codegen/serialization_traits.h", + "include/grpc++/impl/codegen/server_context.h", + "include/grpc++/impl/codegen/server_interface.h", + "include/grpc++/impl/codegen/service_type.h", + "include/grpc++/impl/codegen/status.h", + "include/grpc++/impl/codegen/status_code_enum.h", + "include/grpc++/impl/codegen/string_ref.h", + "include/grpc++/impl/codegen/stub_options.h", + "include/grpc++/impl/codegen/sync.h", + "include/grpc++/impl/codegen/sync_cxx11.h", + "include/grpc++/impl/codegen/sync_no_cxx11.h", + "include/grpc++/impl/codegen/sync_stream.h", + "include/grpc++/impl/codegen/time.h", + "include/grpc/impl/codegen/byte_buffer.h", + "include/grpc/impl/codegen/byte_buffer_reader.h", + "include/grpc/impl/codegen/compression_types.h", + "include/grpc/impl/codegen/connectivity_state.h", + "include/grpc/impl/codegen/grpc_types.h", + "include/grpc/impl/codegen/propagation_bits.h", + "include/grpc/impl/codegen/status.h", + "include/grpc/impl/codegen/alloc.h", + "include/grpc/impl/codegen/atm.h", + "include/grpc/impl/codegen/atm_gcc_atomic.h", + "include/grpc/impl/codegen/atm_gcc_sync.h", + "include/grpc/impl/codegen/atm_windows.h", + "include/grpc/impl/codegen/log.h", + "include/grpc/impl/codegen/port_platform.h", + "include/grpc/impl/codegen/slice.h", + "include/grpc/impl/codegen/slice_buffer.h", + "include/grpc/impl/codegen/sync.h", + "include/grpc/impl/codegen/sync_generic.h", + "include/grpc/impl/codegen/sync_posix.h", + "include/grpc/impl/codegen/sync_windows.h", + "include/grpc/impl/codegen/time.h", + "include/grpc++/impl/codegen/config_protobuf.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + ":grpc++", + ], +) + + + +cc_library( + name = "grpc++_unsecure", + srcs = [ + "src/cpp/client/create_channel_internal.h", + "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/thread_pool_interface.h", + "src/cpp/common/insecure_create_auth_context.cc", + "src/cpp/client/channel.cc", + "src/cpp/client/client_context.cc", + "src/cpp/client/create_channel.cc", + "src/cpp/client/create_channel_internal.cc", + "src/cpp/client/create_channel_posix.cc", + "src/cpp/client/credentials.cc", + "src/cpp/client/generic_stub.cc", + "src/cpp/client/insecure_credentials.cc", + "src/cpp/common/channel_arguments.cc", + "src/cpp/common/completion_queue.cc", + "src/cpp/common/core_codegen.cc", + "src/cpp/common/rpc_method.cc", + "src/cpp/server/async_generic_service.cc", + "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", + "src/cpp/server/insecure_server_credentials.cc", + "src/cpp/server/server.cc", + "src/cpp/server/server_builder.cc", + "src/cpp/server/server_context.cc", + "src/cpp/server/server_credentials.cc", + "src/cpp/server/server_posix.cc", + "src/cpp/util/byte_buffer.cc", + "src/cpp/util/slice.cc", + "src/cpp/util/status.cc", + "src/cpp/util/string_ref.cc", + "src/cpp/util/time.cc", + "src/cpp/codegen/codegen_init.cc", + ], + hdrs = [ + "include/grpc++/alarm.h", + "include/grpc++/channel.h", + "include/grpc++/client_context.h", + "include/grpc++/completion_queue.h", + "include/grpc++/create_channel.h", + "include/grpc++/create_channel_posix.h", + "include/grpc++/generic/async_generic_service.h", + "include/grpc++/generic/generic_stub.h", + "include/grpc++/grpc++.h", + "include/grpc++/impl/call.h", + "include/grpc++/impl/client_unary_call.h", + "include/grpc++/impl/codegen/core_codegen.h", + "include/grpc++/impl/grpc_library.h", + "include/grpc++/impl/method_handler_impl.h", + "include/grpc++/impl/rpc_method.h", + "include/grpc++/impl/rpc_service_method.h", + "include/grpc++/impl/serialization_traits.h", + "include/grpc++/impl/server_builder_option.h", + "include/grpc++/impl/server_builder_plugin.h", + "include/grpc++/impl/server_initializer.h", "include/grpc++/impl/service_type.h", "include/grpc++/impl/sync.h", "include/grpc++/impl/sync_cxx11.h", @@ -1023,10 +1710,12 @@ cc_library( "include/grpc++/server.h", "include/grpc++/server_builder.h", "include/grpc++/server_context.h", + "include/grpc++/server_posix.h", "include/grpc++/support/async_stream.h", "include/grpc++/support/async_unary_call.h", "include/grpc++/support/byte_buffer.h", "include/grpc++/support/channel_arguments.h", + "include/grpc++/support/config.h", "include/grpc++/support/slice.h", "include/grpc++/support/status.h", "include/grpc++/support/status_code_enum.h", @@ -1043,11 +1732,11 @@ cc_library( "include/grpc++/impl/codegen/client_unary_call.h", "include/grpc++/impl/codegen/completion_queue.h", "include/grpc++/impl/codegen/completion_queue_tag.h", + "include/grpc++/impl/codegen/config.h", "include/grpc++/impl/codegen/core_codegen_interface.h", "include/grpc++/impl/codegen/create_auth_context.h", "include/grpc++/impl/codegen/grpc_library.h", "include/grpc++/impl/codegen/method_handler_impl.h", - "include/grpc++/impl/codegen/proto_utils.h", "include/grpc++/impl/codegen/rpc_method.h", "include/grpc++/impl/codegen/rpc_service_method.h", "include/grpc++/impl/codegen/security/auth_context.h", @@ -1064,6 +1753,388 @@ cc_library( "include/grpc++/impl/codegen/sync_no_cxx11.h", "include/grpc++/impl/codegen/sync_stream.h", "include/grpc++/impl/codegen/time.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + "//external:protobuf_clib", + ":gpr", + ":grpc_unsecure", + ], +) + + + +cc_library( + name = "grpc_plugin_support", + srcs = [ + "src/compiler/config.h", + "src/compiler/cpp_generator.h", + "src/compiler/cpp_generator_helpers.h", + "src/compiler/csharp_generator.h", + "src/compiler/csharp_generator_helpers.h", + "src/compiler/generator_helpers.h", + "src/compiler/node_generator.h", + "src/compiler/node_generator_helpers.h", + "src/compiler/objective_c_generator.h", + "src/compiler/objective_c_generator_helpers.h", + "src/compiler/python_generator.h", + "src/compiler/ruby_generator.h", + "src/compiler/ruby_generator_helpers-inl.h", + "src/compiler/ruby_generator_map-inl.h", + "src/compiler/ruby_generator_string-inl.h", + "src/compiler/cpp_generator.cc", + "src/compiler/csharp_generator.cc", + "src/compiler/node_generator.cc", + "src/compiler/objective_c_generator.cc", + "src/compiler/python_generator.cc", + "src/compiler/ruby_generator.cc", + ], + hdrs = [ + "include/grpc++/impl/codegen/config_protobuf.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + "//external:protobuf_compiler", + ], +) + + + +cc_library( + name = "grpc_csharp_ext", + srcs = [ + "src/csharp/ext/grpc_csharp_ext.c", + ], + hdrs = [ + ], + includes = [ + "include", + ".", + ], + deps = [ + ":grpc", + ":gpr", + ], +) + + + + +objc_library( + name = "gpr_objc", + srcs = [ + "src/core/lib/profiling/basic_timers.c", + "src/core/lib/profiling/stap_timers.c", + "src/core/lib/support/alloc.c", + "src/core/lib/support/avl.c", + "src/core/lib/support/backoff.c", + "src/core/lib/support/cmdline.c", + "src/core/lib/support/cpu_iphone.c", + "src/core/lib/support/cpu_linux.c", + "src/core/lib/support/cpu_posix.c", + "src/core/lib/support/cpu_windows.c", + "src/core/lib/support/env_linux.c", + "src/core/lib/support/env_posix.c", + "src/core/lib/support/env_windows.c", + "src/core/lib/support/histogram.c", + "src/core/lib/support/host_port.c", + "src/core/lib/support/log.c", + "src/core/lib/support/log_android.c", + "src/core/lib/support/log_linux.c", + "src/core/lib/support/log_posix.c", + "src/core/lib/support/log_windows.c", + "src/core/lib/support/murmur_hash.c", + "src/core/lib/support/slice.c", + "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", + "src/core/lib/support/string.c", + "src/core/lib/support/string_posix.c", + "src/core/lib/support/string_util_windows.c", + "src/core/lib/support/string_windows.c", + "src/core/lib/support/subprocess_posix.c", + "src/core/lib/support/subprocess_windows.c", + "src/core/lib/support/sync.c", + "src/core/lib/support/sync_posix.c", + "src/core/lib/support/sync_windows.c", + "src/core/lib/support/thd.c", + "src/core/lib/support/thd_posix.c", + "src/core/lib/support/thd_windows.c", + "src/core/lib/support/time.c", + "src/core/lib/support/time_posix.c", + "src/core/lib/support/time_precise.c", + "src/core/lib/support/time_windows.c", + "src/core/lib/support/tls_pthread.c", + "src/core/lib/support/tmpfile_msys.c", + "src/core/lib/support/tmpfile_posix.c", + "src/core/lib/support/tmpfile_windows.c", + "src/core/lib/support/wrap_memcpy.c", + ], + hdrs = [ + "include/grpc/support/alloc.h", + "include/grpc/support/atm.h", + "include/grpc/support/atm_gcc_atomic.h", + "include/grpc/support/atm_gcc_sync.h", + "include/grpc/support/atm_windows.h", + "include/grpc/support/avl.h", + "include/grpc/support/cmdline.h", + "include/grpc/support/cpu.h", + "include/grpc/support/histogram.h", + "include/grpc/support/host_port.h", + "include/grpc/support/log.h", + "include/grpc/support/log_windows.h", + "include/grpc/support/port_platform.h", + "include/grpc/support/slice.h", + "include/grpc/support/slice_buffer.h", + "include/grpc/support/string_util.h", + "include/grpc/support/subprocess.h", + "include/grpc/support/sync.h", + "include/grpc/support/sync_generic.h", + "include/grpc/support/sync_posix.h", + "include/grpc/support/sync_windows.h", + "include/grpc/support/thd.h", + "include/grpc/support/time.h", + "include/grpc/support/tls.h", + "include/grpc/support/tls_gcc.h", + "include/grpc/support/tls_msvc.h", + "include/grpc/support/tls_pthread.h", + "include/grpc/support/useful.h", + "include/grpc/impl/codegen/alloc.h", + "include/grpc/impl/codegen/atm.h", + "include/grpc/impl/codegen/atm_gcc_atomic.h", + "include/grpc/impl/codegen/atm_gcc_sync.h", + "include/grpc/impl/codegen/atm_windows.h", + "include/grpc/impl/codegen/log.h", + "include/grpc/impl/codegen/port_platform.h", + "include/grpc/impl/codegen/slice.h", + "include/grpc/impl/codegen/slice_buffer.h", + "include/grpc/impl/codegen/sync.h", + "include/grpc/impl/codegen/sync_generic.h", + "include/grpc/impl/codegen/sync_posix.h", + "include/grpc/impl/codegen/sync_windows.h", + "include/grpc/impl/codegen/time.h", + "src/core/lib/profiling/timers.h", + "src/core/lib/support/backoff.h", + "src/core/lib/support/block_annotate.h", + "src/core/lib/support/env.h", + "src/core/lib/support/murmur_hash.h", + "src/core/lib/support/stack_lockfree.h", + "src/core/lib/support/string.h", + "src/core/lib/support/string_windows.h", + "src/core/lib/support/thd_internal.h", + "src/core/lib/support/time_precise.h", + "src/core/lib/support/tmpfile.h", + ], + includes = [ + "include", + ".", + ], + deps = [ + ], +) + + + +objc_library( + name = "grpc_objc", + srcs = [ + "src/core/lib/surface/init.c", + "src/core/lib/channel/channel_args.c", + "src/core/lib/channel/channel_stack.c", + "src/core/lib/channel/channel_stack_builder.c", + "src/core/lib/channel/compress_filter.c", + "src/core/lib/channel/connected_channel.c", + "src/core/lib/channel/http_client_filter.c", + "src/core/lib/channel/http_server_filter.c", + "src/core/lib/compression/compression.c", + "src/core/lib/compression/message_compress.c", + "src/core/lib/debug/trace.c", + "src/core/lib/http/format_request.c", + "src/core/lib/http/httpcli.c", + "src/core/lib/http/parser.c", + "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/endpoint.c", + "src/core/lib/iomgr/endpoint_pair_posix.c", + "src/core/lib/iomgr/endpoint_pair_windows.c", + "src/core/lib/iomgr/error.c", + "src/core/lib/iomgr/ev_epoll_linux.c", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.c", + "src/core/lib/iomgr/ev_poll_posix.c", + "src/core/lib/iomgr/ev_posix.c", + "src/core/lib/iomgr/exec_ctx.c", + "src/core/lib/iomgr/executor.c", + "src/core/lib/iomgr/iocp_windows.c", + "src/core/lib/iomgr/iomgr.c", + "src/core/lib/iomgr/iomgr_posix.c", + "src/core/lib/iomgr/iomgr_windows.c", + "src/core/lib/iomgr/load_file.c", + "src/core/lib/iomgr/network_status_tracker.c", + "src/core/lib/iomgr/polling_entity.c", + "src/core/lib/iomgr/pollset_set_windows.c", + "src/core/lib/iomgr/pollset_windows.c", + "src/core/lib/iomgr/resolve_address_posix.c", + "src/core/lib/iomgr/resolve_address_windows.c", + "src/core/lib/iomgr/sockaddr_utils.c", + "src/core/lib/iomgr/socket_utils_common_posix.c", + "src/core/lib/iomgr/socket_utils_linux.c", + "src/core/lib/iomgr/socket_utils_posix.c", + "src/core/lib/iomgr/socket_windows.c", + "src/core/lib/iomgr/tcp_client_posix.c", + "src/core/lib/iomgr/tcp_client_windows.c", + "src/core/lib/iomgr/tcp_posix.c", + "src/core/lib/iomgr/tcp_server_posix.c", + "src/core/lib/iomgr/tcp_server_windows.c", + "src/core/lib/iomgr/tcp_windows.c", + "src/core/lib/iomgr/time_averaged_stats.c", + "src/core/lib/iomgr/timer.c", + "src/core/lib/iomgr/timer_heap.c", + "src/core/lib/iomgr/udp_server.c", + "src/core/lib/iomgr/unix_sockets_posix.c", + "src/core/lib/iomgr/unix_sockets_posix_noop.c", + "src/core/lib/iomgr/wakeup_fd_eventfd.c", + "src/core/lib/iomgr/wakeup_fd_nospecial.c", + "src/core/lib/iomgr/wakeup_fd_pipe.c", + "src/core/lib/iomgr/wakeup_fd_posix.c", + "src/core/lib/iomgr/workqueue_posix.c", + "src/core/lib/iomgr/workqueue_windows.c", + "src/core/lib/json/json.c", + "src/core/lib/json/json_reader.c", + "src/core/lib/json/json_string.c", + "src/core/lib/json/json_writer.c", + "src/core/lib/surface/alarm.c", + "src/core/lib/surface/api_trace.c", + "src/core/lib/surface/byte_buffer.c", + "src/core/lib/surface/byte_buffer_reader.c", + "src/core/lib/surface/call.c", + "src/core/lib/surface/call_details.c", + "src/core/lib/surface/call_log_batch.c", + "src/core/lib/surface/channel.c", + "src/core/lib/surface/channel_init.c", + "src/core/lib/surface/channel_ping.c", + "src/core/lib/surface/channel_stack_type.c", + "src/core/lib/surface/completion_queue.c", + "src/core/lib/surface/event_string.c", + "src/core/lib/surface/lame_client.c", + "src/core/lib/surface/metadata_array.c", + "src/core/lib/surface/server.c", + "src/core/lib/surface/validate_metadata.c", + "src/core/lib/surface/version.c", + "src/core/lib/transport/byte_stream.c", + "src/core/lib/transport/connectivity_state.c", + "src/core/lib/transport/metadata.c", + "src/core/lib/transport/metadata_batch.c", + "src/core/lib/transport/static_metadata.c", + "src/core/lib/transport/transport.c", + "src/core/lib/transport/transport_op_string.c", + "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c", + "src/core/ext/transport/chttp2/transport/bin_decoder.c", + "src/core/ext/transport/chttp2/transport/bin_encoder.c", + "src/core/ext/transport/chttp2/transport/chttp2_plugin.c", + "src/core/ext/transport/chttp2/transport/chttp2_transport.c", + "src/core/ext/transport/chttp2/transport/frame_data.c", + "src/core/ext/transport/chttp2/transport/frame_goaway.c", + "src/core/ext/transport/chttp2/transport/frame_ping.c", + "src/core/ext/transport/chttp2/transport/frame_rst_stream.c", + "src/core/ext/transport/chttp2/transport/frame_settings.c", + "src/core/ext/transport/chttp2/transport/frame_window_update.c", + "src/core/ext/transport/chttp2/transport/hpack_encoder.c", + "src/core/ext/transport/chttp2/transport/hpack_parser.c", + "src/core/ext/transport/chttp2/transport/hpack_table.c", + "src/core/ext/transport/chttp2/transport/huffsyms.c", + "src/core/ext/transport/chttp2/transport/incoming_metadata.c", + "src/core/ext/transport/chttp2/transport/parsing.c", + "src/core/ext/transport/chttp2/transport/status_conversion.c", + "src/core/ext/transport/chttp2/transport/stream_lists.c", + "src/core/ext/transport/chttp2/transport/stream_map.c", + "src/core/ext/transport/chttp2/transport/timeout_encoding.c", + "src/core/ext/transport/chttp2/transport/varint.c", + "src/core/ext/transport/chttp2/transport/writing.c", + "src/core/ext/transport/chttp2/alpn/alpn.c", + "src/core/lib/http/httpcli_security_connector.c", + "src/core/lib/security/context/security_context.c", + "src/core/lib/security/credentials/composite/composite_credentials.c", + "src/core/lib/security/credentials/credentials.c", + "src/core/lib/security/credentials/credentials_metadata.c", + "src/core/lib/security/credentials/fake/fake_credentials.c", + "src/core/lib/security/credentials/google_default/credentials_posix.c", + "src/core/lib/security/credentials/google_default/credentials_windows.c", + "src/core/lib/security/credentials/google_default/google_default_credentials.c", + "src/core/lib/security/credentials/iam/iam_credentials.c", + "src/core/lib/security/credentials/jwt/json_token.c", + "src/core/lib/security/credentials/jwt/jwt_credentials.c", + "src/core/lib/security/credentials/jwt/jwt_verifier.c", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.c", + "src/core/lib/security/credentials/plugin/plugin_credentials.c", + "src/core/lib/security/credentials/ssl/ssl_credentials.c", + "src/core/lib/security/transport/client_auth_filter.c", + "src/core/lib/security/transport/handshake.c", + "src/core/lib/security/transport/secure_endpoint.c", + "src/core/lib/security/transport/security_connector.c", + "src/core/lib/security/transport/server_auth_filter.c", + "src/core/lib/security/transport/tsi_error.c", + "src/core/lib/security/util/b64.c", + "src/core/lib/security/util/json_util.c", + "src/core/lib/surface/init_secure.c", + "src/core/lib/tsi/fake_transport_security.c", + "src/core/lib/tsi/ssl_transport_security.c", + "src/core/lib/tsi/transport_security.c", + "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", + "src/core/ext/client_config/channel_connectivity.c", + "src/core/ext/client_config/client_channel.c", + "src/core/ext/client_config/client_channel_factory.c", + "src/core/ext/client_config/client_config.c", + "src/core/ext/client_config/client_config_plugin.c", + "src/core/ext/client_config/connector.c", + "src/core/ext/client_config/default_initial_connect_string.c", + "src/core/ext/client_config/initial_connect_string.c", + "src/core/ext/client_config/lb_policy.c", + "src/core/ext/client_config/lb_policy_factory.c", + "src/core/ext/client_config/lb_policy_registry.c", + "src/core/ext/client_config/parse_address.c", + "src/core/ext/client_config/resolver.c", + "src/core/ext/client_config/resolver_factory.c", + "src/core/ext/client_config/resolver_registry.c", + "src/core/ext/client_config/subchannel.c", + "src/core/ext/client_config/subchannel_call_holder.c", + "src/core/ext/client_config/subchannel_index.c", + "src/core/ext/client_config/uri_parser.c", + "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", + "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", + "src/core/ext/transport/chttp2/client/insecure/channel_create.c", + "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c", + "src/core/ext/lb_policy/grpclb/load_balancer_api.c", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", + "src/core/ext/lb_policy/pick_first/pick_first.c", + "src/core/ext/lb_policy/round_robin/round_robin.c", + "src/core/ext/resolver/dns/native/dns_resolver.c", + "src/core/ext/resolver/sockaddr/sockaddr_resolver.c", + "src/core/ext/load_reporting/load_reporting.c", + "src/core/ext/load_reporting/load_reporting_filter.c", + "src/core/ext/census/context.c", + "src/core/ext/census/gen/census.pb.c", + "src/core/ext/census/grpc_context.c", + "src/core/ext/census/grpc_filter.c", + "src/core/ext/census/grpc_plugin.c", + "src/core/ext/census/initialize.c", + "src/core/ext/census/mlog.c", + "src/core/ext/census/operation.c", + "src/core/ext/census/placeholders.c", + "src/core/ext/census/tracing.c", + "src/core/plugin_registry/grpc_plugin_registry.c", + ], + hdrs = [ + "include/grpc/byte_buffer.h", + "include/grpc/byte_buffer_reader.h", + "include/grpc/compression.h", + "include/grpc/grpc.h", + "include/grpc/grpc_posix.h", + "include/grpc/grpc_security_constants.h", + "include/grpc/status.h", "include/grpc/impl/codegen/byte_buffer.h", "include/grpc/impl/codegen/byte_buffer_reader.h", "include/grpc/impl/codegen/compression_types.h", @@ -1075,7 +2146,7 @@ cc_library( "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", "include/grpc/impl/codegen/atm_gcc_sync.h", - "include/grpc/impl/codegen/atm_win32.h", + "include/grpc/impl/codegen/atm_windows.h", "include/grpc/impl/codegen/log.h", "include/grpc/impl/codegen/port_platform.h", "include/grpc/impl/codegen/slice.h", @@ -1083,71 +2154,321 @@ cc_library( "include/grpc/impl/codegen/sync.h", "include/grpc/impl/codegen/sync_generic.h", "include/grpc/impl/codegen/sync_posix.h", - "include/grpc/impl/codegen/sync_win32.h", + "include/grpc/impl/codegen/sync_windows.h", "include/grpc/impl/codegen/time.h", - "include/grpc++/impl/codegen/config.h", - "include/grpc++/impl/codegen/config_protobuf.h", - "include/grpc++/support/config.h", - "include/grpc++/support/config_protobuf.h", + "include/grpc/grpc_security.h", + "include/grpc/census.h", + "src/core/lib/channel/channel_args.h", + "src/core/lib/channel/channel_stack.h", + "src/core/lib/channel/channel_stack_builder.h", + "src/core/lib/channel/compress_filter.h", + "src/core/lib/channel/connected_channel.h", + "src/core/lib/channel/context.h", + "src/core/lib/channel/http_client_filter.h", + "src/core/lib/channel/http_server_filter.h", + "src/core/lib/compression/algorithm_metadata.h", + "src/core/lib/compression/message_compress.h", + "src/core/lib/debug/trace.h", + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_pair.h", + "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/ev_epoll_linux.h", + "src/core/lib/iomgr/ev_poll_and_epoll_posix.h", + "src/core/lib/iomgr/ev_poll_posix.h", + "src/core/lib/iomgr/ev_posix.h", + "src/core/lib/iomgr/exec_ctx.h", + "src/core/lib/iomgr/executor.h", + "src/core/lib/iomgr/iocp_windows.h", + "src/core/lib/iomgr/iomgr.h", + "src/core/lib/iomgr/iomgr_internal.h", + "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/load_file.h", + "src/core/lib/iomgr/network_status_tracker.h", + "src/core/lib/iomgr/polling_entity.h", + "src/core/lib/iomgr/pollset.h", + "src/core/lib/iomgr/pollset_set.h", + "src/core/lib/iomgr/pollset_set_windows.h", + "src/core/lib/iomgr/pollset_windows.h", + "src/core/lib/iomgr/resolve_address.h", + "src/core/lib/iomgr/sockaddr.h", + "src/core/lib/iomgr/sockaddr_posix.h", + "src/core/lib/iomgr/sockaddr_utils.h", + "src/core/lib/iomgr/sockaddr_windows.h", + "src/core/lib/iomgr/socket_utils_posix.h", + "src/core/lib/iomgr/socket_windows.h", + "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_posix.h", + "src/core/lib/iomgr/tcp_server.h", + "src/core/lib/iomgr/tcp_windows.h", + "src/core/lib/iomgr/time_averaged_stats.h", + "src/core/lib/iomgr/timer.h", + "src/core/lib/iomgr/timer_heap.h", + "src/core/lib/iomgr/udp_server.h", + "src/core/lib/iomgr/unix_sockets_posix.h", + "src/core/lib/iomgr/wakeup_fd_pipe.h", + "src/core/lib/iomgr/wakeup_fd_posix.h", + "src/core/lib/iomgr/workqueue.h", + "src/core/lib/iomgr/workqueue_posix.h", + "src/core/lib/iomgr/workqueue_windows.h", + "src/core/lib/json/json.h", + "src/core/lib/json/json_common.h", + "src/core/lib/json/json_reader.h", + "src/core/lib/json/json_writer.h", + "src/core/lib/surface/api_trace.h", + "src/core/lib/surface/call.h", + "src/core/lib/surface/call_test_only.h", + "src/core/lib/surface/channel.h", + "src/core/lib/surface/channel_init.h", + "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/completion_queue.h", + "src/core/lib/surface/event_string.h", + "src/core/lib/surface/init.h", + "src/core/lib/surface/lame_client.h", + "src/core/lib/surface/server.h", + "src/core/lib/transport/byte_stream.h", + "src/core/lib/transport/connectivity_state.h", + "src/core/lib/transport/metadata.h", + "src/core/lib/transport/metadata_batch.h", + "src/core/lib/transport/static_metadata.h", + "src/core/lib/transport/transport.h", + "src/core/lib/transport/transport_impl.h", + "src/core/ext/transport/chttp2/transport/bin_decoder.h", + "src/core/ext/transport/chttp2/transport/bin_encoder.h", + "src/core/ext/transport/chttp2/transport/chttp2_transport.h", + "src/core/ext/transport/chttp2/transport/frame.h", + "src/core/ext/transport/chttp2/transport/frame_data.h", + "src/core/ext/transport/chttp2/transport/frame_goaway.h", + "src/core/ext/transport/chttp2/transport/frame_ping.h", + "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", + "src/core/ext/transport/chttp2/transport/frame_settings.h", + "src/core/ext/transport/chttp2/transport/frame_window_update.h", + "src/core/ext/transport/chttp2/transport/hpack_encoder.h", + "src/core/ext/transport/chttp2/transport/hpack_parser.h", + "src/core/ext/transport/chttp2/transport/hpack_table.h", + "src/core/ext/transport/chttp2/transport/http2_errors.h", + "src/core/ext/transport/chttp2/transport/huffsyms.h", + "src/core/ext/transport/chttp2/transport/incoming_metadata.h", + "src/core/ext/transport/chttp2/transport/internal.h", + "src/core/ext/transport/chttp2/transport/status_conversion.h", + "src/core/ext/transport/chttp2/transport/stream_map.h", + "src/core/ext/transport/chttp2/transport/timeout_encoding.h", + "src/core/ext/transport/chttp2/transport/varint.h", + "src/core/ext/transport/chttp2/alpn/alpn.h", + "src/core/lib/security/context/security_context.h", + "src/core/lib/security/credentials/composite/composite_credentials.h", + "src/core/lib/security/credentials/credentials.h", + "src/core/lib/security/credentials/fake/fake_credentials.h", + "src/core/lib/security/credentials/google_default/google_default_credentials.h", + "src/core/lib/security/credentials/iam/iam_credentials.h", + "src/core/lib/security/credentials/jwt/json_token.h", + "src/core/lib/security/credentials/jwt/jwt_credentials.h", + "src/core/lib/security/credentials/jwt/jwt_verifier.h", + "src/core/lib/security/credentials/oauth2/oauth2_credentials.h", + "src/core/lib/security/credentials/plugin/plugin_credentials.h", + "src/core/lib/security/credentials/ssl/ssl_credentials.h", + "src/core/lib/security/transport/auth_filters.h", + "src/core/lib/security/transport/handshake.h", + "src/core/lib/security/transport/secure_endpoint.h", + "src/core/lib/security/transport/security_connector.h", + "src/core/lib/security/transport/tsi_error.h", + "src/core/lib/security/util/b64.h", + "src/core/lib/security/util/json_util.h", + "src/core/lib/tsi/fake_transport_security.h", + "src/core/lib/tsi/ssl_transport_security.h", + "src/core/lib/tsi/ssl_types.h", + "src/core/lib/tsi/transport_security.h", + "src/core/lib/tsi/transport_security_interface.h", + "src/core/ext/client_config/client_channel.h", + "src/core/ext/client_config/client_channel_factory.h", + "src/core/ext/client_config/client_config.h", + "src/core/ext/client_config/connector.h", + "src/core/ext/client_config/initial_connect_string.h", + "src/core/ext/client_config/lb_policy.h", + "src/core/ext/client_config/lb_policy_factory.h", + "src/core/ext/client_config/lb_policy_registry.h", + "src/core/ext/client_config/parse_address.h", + "src/core/ext/client_config/resolver.h", + "src/core/ext/client_config/resolver_factory.h", + "src/core/ext/client_config/resolver_registry.h", + "src/core/ext/client_config/subchannel.h", + "src/core/ext/client_config/subchannel_call_holder.h", + "src/core/ext/client_config/subchannel_index.h", + "src/core/ext/client_config/uri_parser.h", + "src/core/ext/lb_policy/grpclb/load_balancer_api.h", + "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h", + "src/core/ext/load_reporting/load_reporting.h", + "src/core/ext/load_reporting/load_reporting_filter.h", + "src/core/ext/census/aggregation.h", + "src/core/ext/census/census_interface.h", + "src/core/ext/census/census_rpc_stats.h", + "src/core/ext/census/gen/census.pb.h", + "src/core/ext/census/grpc_filter.h", + "src/core/ext/census/mlog.h", + "src/core/ext/census/rpc_metric_id.h", ], includes = [ "include", ".", ], deps = [ - "//external:protobuf_clib", - ":gpr", - ":grpc_unsecure", + ":gpr_objc", + "//external:libssl_objc", + "//external:nanopb", ], + sdk_dylibs = ["libz"], ) -cc_library( - name = "grpc_plugin_support", + + +cc_binary( + name = "grpc_cpp_plugin", srcs = [ - "src/compiler/config.h", - "src/compiler/cpp_generator.h", - "src/compiler/cpp_generator_helpers.h", - "src/compiler/csharp_generator.h", - "src/compiler/csharp_generator_helpers.h", - "src/compiler/generator_helpers.h", - "src/compiler/node_generator.h", - "src/compiler/node_generator_helpers.h", - "src/compiler/objective_c_generator.h", - "src/compiler/objective_c_generator_helpers.h", - "src/compiler/python_generator.h", - "src/compiler/ruby_generator.h", - "src/compiler/ruby_generator_helpers-inl.h", - "src/compiler/ruby_generator_map-inl.h", - "src/compiler/ruby_generator_string-inl.h", - "src/compiler/cpp_generator.cc", - "src/compiler/csharp_generator.cc", - "src/compiler/node_generator.cc", - "src/compiler/objective_c_generator.cc", - "src/compiler/python_generator.cc", - "src/compiler/ruby_generator.cc", + "src/compiler/cpp_plugin.cc", ], - hdrs = [ - "include/grpc++/support/config.h", - "include/grpc++/support/config_protobuf.h", - "include/grpc++/impl/codegen/config.h", - "include/grpc++/impl/codegen/config_protobuf.h", + deps = [ + "//external:protobuf_compiler", + ":grpc_plugin_support", ], - includes = [ - "include", - ".", +) + + +cc_binary( + name = "grpc_csharp_plugin", + srcs = [ + "src/compiler/csharp_plugin.cc", ], deps = [ "//external:protobuf_compiler", + ":grpc_plugin_support", ], ) + cc_binary( - name = "grpc_cpp_plugin", + name = "grpc_node_plugin", srcs = [ - "src/compiler/cpp_plugin.cc", + "src/compiler/node_plugin.cc", + ], + deps = [ + "//external:protobuf_compiler", + ":grpc_plugin_support", + ], +) + + +cc_binary( + name = "grpc_objective_c_plugin", + srcs = [ + "src/compiler/objective_c_plugin.cc", + ], + deps = [ + "//external:protobuf_compiler", + ":grpc_plugin_support", + ], +) + + +cc_binary( + name = "grpc_python_plugin", + srcs = [ + "src/compiler/python_plugin.cc", + ], + deps = [ + "//external:protobuf_compiler", + ":grpc_plugin_support", + ], +) + + +cc_binary( + name = "grpc_ruby_plugin", + srcs = [ + "src/compiler/ruby_plugin.cc", ], deps = [ "//external:protobuf_compiler", ":grpc_plugin_support", ], ) + + + + + + + + +objc_path = "src/objective-c" + +rx_library_path = objc_path + "/RxLibrary" + +objc_library( + name = "rx_library", + hdrs = glob([ + rx_library_path + "/*.h", + rx_library_path + "/transformations/*.h", + ]), + srcs = glob([ + rx_library_path + "/*.m", + rx_library_path + "/transformations/*.m", + ]), + includes = [objc_path], + deps = [ + ":rx_library_private", + ], +) + +objc_library( + name = "rx_library_private", + hdrs = glob([rx_library_path + "/private/*.h"]), + srcs = glob([rx_library_path + "/private/*.m"]), + visibility = ["//visibility:private"], +) + +objc_client_path = objc_path + "/GRPCClient" + +objc_library( + name = "grpc_client", + hdrs = glob([ + objc_client_path + "/*.h", + objc_client_path + "/private/*.h", + ]), + srcs = glob([ + objc_client_path + "/*.m", + objc_client_path + "/private/*.m", + ]), + includes = [objc_path], + bundles = [":gRPCCertificates"], + deps = [ + ":grpc_objc", + ":rx_library", + ], +) + +objc_bundle_library( + # The choice of name is signicant here, since it determines the bundle name. + name = "gRPCCertificates", + resources = ["etc/roots.pem"], +) + +proto_objc_rpc_path = objc_path + "/ProtoRPC" + +objc_library( + name = "proto_objc_rpc", + hdrs = glob([ + proto_objc_rpc_path + "/*.h", + ]), + srcs = glob([ + proto_objc_rpc_path + "/*.m", + ]), + includes = [objc_path], + deps = [ + ":grpc_client", + ":rx_library", + "//external:protobuf_objc", + ], +) diff --git a/tensorflow/BUILD b/tensorflow/BUILD index a501a4f993fa051fb33f48b47904500219808bef..efd2adb3bd9995d69cff643fc6113f40d0ea82ed 100644 --- a/tensorflow/BUILD +++ b/tensorflow/BUILD @@ -109,6 +109,7 @@ filegroup( "//tensorflow/contrib/quantization/kernels:all_files", "//tensorflow/contrib/quantization/kernels/hexagon:all_files", "//tensorflow/contrib/quantization/tools:all_files", + "//tensorflow/contrib/rnn:all_files", "//tensorflow/contrib/session_bundle:all_files", "//tensorflow/contrib/session_bundle/example:all_files", "//tensorflow/contrib/slim:all_files", @@ -138,6 +139,7 @@ filegroup( "//tensorflow/examples/tutorials/word2vec:all_files", "//tensorflow/g3doc/how_tos/adding_an_op:all_files", "//tensorflow/g3doc/tutorials:all_files", + "//tensorflow/go:all_files", "//tensorflow/models/embedding:all_files", "//tensorflow/models/image/alexnet:all_files", "//tensorflow/models/image/cifar10:all_files", @@ -175,6 +177,16 @@ cc_binary( name = "libtensorflow.so", linkshared = 1, deps = [ + "//tensorflow/c:c_api", + "//tensorflow/core:tensorflow", + ], +) + +cc_binary( + name = "libtensorflow_c.so", + linkshared = 1, + deps = [ + "//tensorflow/c:c_api", "//tensorflow/core:tensorflow", ], ) @@ -183,6 +195,7 @@ cc_binary( name = "libtensorflow_cc.so", linkshared = 1, deps = [ + "//tensorflow/c:c_api", "//tensorflow/cc:cc_ops", "//tensorflow/core:tensorflow", ], diff --git a/tensorflow/__init__.py b/tensorflow/__init__.py index 4fc5d8e8168a8c99d900c6970846fbf701c46b75..ec7cd91e7e022b30b86515261df732e6f44281b0 100644 --- a/tensorflow/__init__.py +++ b/tensorflow/__init__.py @@ -21,3 +21,18 @@ from __future__ import division from __future__ import print_function from tensorflow.python import * + + +# Lazily import the `tf.contrib` module. This avoids loading all of the +# dependencies of `tf.contrib` at `import tensorflow` time. +class _LazyContribLoader(object): + + def __getattr__(self, item): + global contrib + # Replace the lazy loader with the imported module itself. + import importlib # pylint: disable=g-import-not-at-top + contrib = importlib.import_module('tensorflow.contrib') + return getattr(contrib, item) + + +contrib = _LazyContribLoader() diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc index f10e2a3ddd2305aa0d3e65f9a4e3a4500ddbf16f..3f10598fcceb4929b4c67c728b079a16436abd67 100644 --- a/tensorflow/c/c_api.cc +++ b/tensorflow/c/c_api.cc @@ -773,11 +773,12 @@ void TF_SetAttrBool(TF_OperationDescription* desc, const char* attr_name, void TF_SetAttrBoolList(TF_OperationDescription* desc, const char* attr_name, const unsigned char* values, int num_values) { - bool* b = new bool[num_values]; + std::unique_ptr b(new bool[num_values]); for (int i = 0; i < num_values; ++i) { b[i] = values[i]; } - desc->node_builder.Attr(attr_name, ArraySlice(b, num_values)); + desc->node_builder.Attr(attr_name, + ArraySlice(b.get(), num_values)); } void TF_SetAttrType(TF_OperationDescription* desc, const char* attr_name, @@ -823,7 +824,7 @@ void TF_SetAttrShapeList(TF_OperationDescription* desc, const char* attr_name, } void TF_SetAttrTensorShapeProto(TF_OperationDescription* desc, - const char* attr_name, void* proto, + const char* attr_name, const void* proto, int proto_len, TF_Status* status) { TensorShapeProto shape; if (shape.ParseFromArray(proto, proto_len)) { @@ -996,12 +997,13 @@ int TF_OperationInputListLength(TF_Operation* oper, const char* arg_name, } TF_Port TF_OperationInput(TF_Port oper_in) { - for (const auto* edge : oper_in.oper->node.in_edges()) { - if (edge->dst_input() == oper_in.index) { - return {ToOperation(edge->src()), edge->src_output()}; - } + const tensorflow::Edge* edge; + Status s = oper_in.oper->node.input_edge(oper_in.index, &edge); + if (!s.ok()) { + return {nullptr, -1}; } - return {nullptr, -1}; + + return {ToOperation(edge->src()), edge->src_output()}; } int TF_OperationOutputNumConsumers(TF_Port oper_out) { @@ -1029,13 +1031,7 @@ int TF_OperationOutputConsumers(TF_Port oper_out, TF_Port* consumers, } int TF_OperationNumControlInputs(TF_Operation* oper) { - int count = 0; - for (const auto* edge : oper->node.in_edges()) { - if (edge->IsControlEdge()) { - ++count; - } - } - return count; + return oper->node.in_edges().size() - oper->node.num_inputs(); } int TF_OperationGetControlInputs(TF_Operation* oper, diff --git a/tensorflow/c/c_api.h b/tensorflow/c/c_api.h index e02c2f1620533a51813594ff7852ce90baf83fce..c31b57f79f05cb94f4b28828bd68dd5399a3f979 100644 --- a/tensorflow/c/c_api.h +++ b/tensorflow/c/c_api.h @@ -369,7 +369,7 @@ extern void TF_SetAttrShapeList(TF_OperationDescription* desc, // `proto` must point to an array of `proto_len` bytes representing a // binary-serialized TensorShapeProto. extern void TF_SetAttrTensorShapeProto(TF_OperationDescription* desc, - const char* attr_name, void* proto, + const char* attr_name, const void* proto, int proto_len, TF_Status* status); // `protos` and `proto_lens` must point to arrays of length `num_shapes`. // `protos[i]` must point to an array of `proto_lens[i]` bytes diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc index b9c5256ec237d4edcd0decc811a9fd0ec6a6b10b..589f001b142d6f9b3e197afdb91632e669e5fa51 100644 --- a/tensorflow/c/c_api_test.cc +++ b/tensorflow/c/c_api_test.cc @@ -17,6 +17,7 @@ limitations under the License. #include #include "tensorflow/core/framework/graph.pb_text.h" +#include "tensorflow/core/framework/node_def.pb_text.h" #include "tensorflow/core/framework/tensor.h" #include "tensorflow/core/framework/types.pb.h" #include "tensorflow/core/lib/core/error_codes.pb.h" diff --git a/tensorflow/cc/BUILD b/tensorflow/cc/BUILD index ef1423dfedd43c2e2376748c522eea3946f98b7a..8f9ac466765ad4cc4ff45e2e64ed590dfda5549f 100644 --- a/tensorflow/cc/BUILD +++ b/tensorflow/cc/BUILD @@ -27,6 +27,7 @@ cc_library( "//tensorflow/core:core_cpu", "//tensorflow/core:framework", "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", ], ) @@ -239,6 +240,7 @@ cc_library( deps = [ "//tensorflow/core:framework", "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", "//tensorflow/core:proto_text", "//tensorflow/core:protos_all_cc", ], diff --git a/tensorflow/cc/framework/cc_op_gen.cc b/tensorflow/cc/framework/cc_op_gen.cc index 659fdfb153e076520197a65c364e5283580fa2f6..8ed53404f1ed29079d384f506356495060ca0f85 100644 --- a/tensorflow/cc/framework/cc_op_gen.cc +++ b/tensorflow/cc/framework/cc_op_gen.cc @@ -232,7 +232,7 @@ string PrintAttrValue(string op, const AttrValue& attr_value) { string ToCamelCase(const string& str) { string result; const char joiner = '_'; - int i = 0; + size_t i = 0; bool cap = true; while (i < str.size()) { const char c = str[i++]; diff --git a/tensorflow/contrib/bayesflow/BUILD b/tensorflow/contrib/bayesflow/BUILD index 354c2283e4fd717b3c03a7bc967bf59b84fe0bf2..cf88489e8a896213afbc96828ef8b2ee8dd214d9 100644 --- a/tensorflow/contrib/bayesflow/BUILD +++ b/tensorflow/contrib/bayesflow/BUILD @@ -1,5 +1,6 @@ # Description: -# Contains ops for statistical distributions (with pdf, cdf, sample, etc...). +# Contains ops for working with statistical distributions, +# particularly useful for Bayesian inference. # APIs here are meant to evolve over time. licenses(["notice"]) # Apache 2.0 @@ -16,6 +17,28 @@ py_library( srcs_version = "PY2AND3", ) +cuda_py_test( + name = "entropy_test", + size = "medium", + srcs = ["python/kernel_tests/entropy_test.py"], + additional_deps = [ + ":bayesflow_py", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + ], +) + +cuda_py_test( + name = "monte_carlo_test", + size = "small", + srcs = ["python/kernel_tests/monte_carlo_test.py"], + additional_deps = [ + ":bayesflow_py", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + ], +) + cuda_py_test( name = "stochastic_graph_test", size = "small", diff --git a/tensorflow/contrib/bayesflow/__init__.py b/tensorflow/contrib/bayesflow/__init__.py index 365ef42836d657b9f07b44cc2a394d05e28b7091..ee473d8d7f77f1daa1b3d367701a2048f08c281d 100644 --- a/tensorflow/contrib/bayesflow/__init__.py +++ b/tensorflow/contrib/bayesflow/__init__.py @@ -21,6 +21,8 @@ from __future__ import division from __future__ import print_function # pylint: disable=unused-import,wildcard-import,line-too-long +from tensorflow.contrib.bayesflow.python.ops import entropy +from tensorflow.contrib.bayesflow.python.ops import monte_carlo from tensorflow.contrib.bayesflow.python.ops import stochastic_gradient_estimators from tensorflow.contrib.bayesflow.python.ops import stochastic_graph from tensorflow.contrib.bayesflow.python.ops import variational_inference diff --git a/tensorflow/contrib/bayesflow/python/kernel_tests/entropy_test.py b/tensorflow/contrib/bayesflow/python/kernel_tests/entropy_test.py new file mode 100644 index 0000000000000000000000000000000000000000..b3f2f275c1c04acd2ef227c523fc67c94b01d534 --- /dev/null +++ b/tensorflow/contrib/bayesflow/python/kernel_tests/entropy_test.py @@ -0,0 +1,338 @@ +# 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. +# ============================================================================== +"""Tests for Monte Carlo Ops.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +import tensorflow as tf + +distributions = tf.contrib.distributions +layers = tf.contrib.layers +entropy = tf.contrib.bayesflow.entropy + + +class NormalNoEntropy(distributions.Normal): # pylint: disable=no-init + """Normal distribution without a `.entropy` method.""" + + def entropy(self): + return NotImplementedError('Entropy removed by gremlins') + + +def get_train_op(scalar_loss, optimizer='SGD', learning_rate=1.0, decay=0.0): + global_step = tf.Variable(0) + + def decay_fn(rate, t): + return rate * (1 + tf.to_float(t))**(-decay) + + train_op = layers.optimize_loss( + scalar_loss, + global_step, + learning_rate, + optimizer, + learning_rate_decay_fn=decay_fn) + return train_op + + +def _assert_monotonic_decreasing(array, atol=1e-5): + array = np.asarray(array) + _assert_monotonic_increasing(-array, atol=atol) + + +def _assert_monotonic_increasing(array, atol=1e-5): + array = np.asarray(array) + diff = np.diff(array.ravel()) + np.testing.assert_array_less(-1 * atol, diff) + + +class ElboRatioTest(tf.test.TestCase): + """Show sampling converges to true KL values.""" + + def setUp(self): + self._rng = np.random.RandomState(0) + + def test_convergence_to_kl_using_sample_form_on_3dim_normal(self): + # Test that the sample mean KL is the same as analytic when we use samples + # to estimate every part of the KL divergence ratio. + vector_shape = (2, 3) + n_samples = 5000 + + with self.test_session(): + q = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + p = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + + # In this case, the log_ratio is the KL. + sample_kl = -1 * entropy.elbo_ratio( + log_p=p.log_prob, + q=q, + n=n_samples, + form=entropy.ELBOForms.sample, + seed=42) + actual_kl = distributions.kl(q, p) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertEqual((2,), sample_kl.get_shape()) + self.assertAllClose(actual_kl.eval(), sample_kl.eval(), rtol=0.03) + + def test_convergence_to_kl_using_analytic_entropy_form_on_3dim_normal(self): + # Test that the sample mean KL is the same as analytic when we use an + # analytic entropy combined with sampled cross-entropy. + n_samples = 5000 + + vector_shape = (2, 3) + with self.test_session(): + q = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + p = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + + # In this case, the log_ratio is the KL. + sample_kl = -1 * entropy.elbo_ratio( + log_p=p.log_prob, + q=q, + n=n_samples, + form=entropy.ELBOForms.analytic_entropy, + seed=42) + actual_kl = distributions.kl(q, p) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertEqual((2,), sample_kl.get_shape()) + self.assertAllClose(actual_kl.eval(), sample_kl.eval(), rtol=0.05) + + def test_sample_kl_zero_when_p_and_q_are_the_same_distribution(self): + n_samples = 50 + + vector_shape = (2, 3) + with self.test_session(): + q = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + + # In this case, the log_ratio is the KL. + sample_kl = -1 * entropy.elbo_ratio( + log_p=q.log_prob, + q=q, + n=n_samples, + form=entropy.ELBOForms.sample, + seed=42) + + self.assertEqual((2,), sample_kl.get_shape()) + self.assertAllClose(np.zeros(2), sample_kl.eval()) + + +class EntropyShannonTest(tf.test.TestCase): + + def test_normal_entropy_default_form_uses_exact_entropy(self): + with self.test_session(): + dist = distributions.Normal(mu=1.11, sigma=2.22) + mc_entropy = entropy.entropy_shannon(dist, n=11) + exact_entropy = dist.entropy() + self.assertEqual(exact_entropy.get_shape(), mc_entropy.get_shape()) + self.assertAllClose(exact_entropy.eval(), mc_entropy.eval()) + + def test_normal_entropy_analytic_form_uses_exact_entropy(self): + with self.test_session(): + dist = distributions.Normal(mu=1.11, sigma=2.22) + mc_entropy = entropy.entropy_shannon( + dist, form=entropy.ELBOForms.analytic_entropy) + exact_entropy = dist.entropy() + self.assertEqual(exact_entropy.get_shape(), mc_entropy.get_shape()) + self.assertAllClose(exact_entropy.eval(), mc_entropy.eval()) + + def test_normal_entropy_sample_form_gets_approximate_answer(self): + # Tested by showing we get a good answer that is not exact. + with self.test_session(): + dist = distributions.Normal(mu=1.11, sigma=2.22) + mc_entropy = entropy.entropy_shannon( + dist, n=1000, form=entropy.ELBOForms.sample, seed=0) + exact_entropy = dist.entropy() + + self.assertEqual(exact_entropy.get_shape(), mc_entropy.get_shape()) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertAllClose(exact_entropy.eval(), mc_entropy.eval(), rtol=0.01) + + # Make sure there is some error, proving we used samples + self.assertLess(0.0001, tf.abs(exact_entropy - mc_entropy).eval()) + + def test_default_entropy_falls_back_on_sample_if_analytic_not_available(self): + # Tested by showing we get a good answer that is not exact. + with self.test_session(): + # NormalNoEntropy is like a Normal, but does not have .entropy method, so + # we are forced to fall back on sample entropy. + dist_no_entropy = NormalNoEntropy(mu=1.11, sigma=2.22) + dist_yes_entropy = distributions.Normal(mu=1.11, sigma=2.22) + + mc_entropy = entropy.entropy_shannon( + dist_no_entropy, n=1000, form=entropy.ELBOForms.sample, seed=0) + exact_entropy = dist_yes_entropy.entropy() + + self.assertEqual(exact_entropy.get_shape(), mc_entropy.get_shape()) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertAllClose(exact_entropy.eval(), mc_entropy.eval(), rtol=0.01) + + # Make sure there is some error, proving we used samples + self.assertLess(0.0001, tf.abs(exact_entropy - mc_entropy).eval()) + + +class RenyiRatioTest(tf.test.TestCase): + """Show renyi_ratio is minimized when the distributions match.""" + + def setUp(self): + self._rng = np.random.RandomState(0) + + def test_fitting_two_dimensional_normal_n_equals_1000(self): + # Minmizing Renyi divergence should allow us to make one normal match + # another one exactly. + n = 1000 + mu_true = np.array([1.0, -1.0], dtype=np.float64) + chol_true = np.array([[2.0, 0.0], [0.5, 1.0]], dtype=np.float64) + with self.test_session() as sess: + target = distributions.MultivariateNormalCholesky(mu_true, chol_true) + + # Set up q distribution by defining mean/covariance as Variables + mu = tf.Variable(np.zeros(mu_true.shape), dtype=mu_true.dtype, name='mu') + mat = tf.Variable( + np.zeros(chol_true.shape), dtype=chol_true.dtype, name='mat') + chol = distributions.batch_matrix_diag_transform( + mat, transform=tf.nn.softplus) + q = distributions.MultivariateNormalCholesky(mu, chol) + for alpha in [0.25, 0.75]: + + negative_renyi_divergence = entropy.renyi_ratio( + log_p=target.log_prob, q=q, n=n, alpha=alpha, seed=0) + train_op = get_train_op( + tf.reduce_mean(-negative_renyi_divergence), + optimizer='SGD', + learning_rate=0.5, + decay=0.1) + + tf.initialize_all_variables().run() + renyis = [] + for step in range(1000): + sess.run(train_op) + if step in [1, 5, 100]: + renyis.append(negative_renyi_divergence.eval()) + + # This optimization should maximize the renyi divergence. + _assert_monotonic_increasing(renyis, atol=0) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertAllClose(target.mu.eval(), q.mu.eval(), rtol=0.06) + self.assertAllClose(target.sigma.eval(), q.sigma.eval(), rtol=0.02) + + def test_divergence_between_identical_distributions_is_zero(self): + n = 1000 + vector_shape = (2, 3) + with self.test_session(): + q = distributions.MultivariateNormalDiag( + mu=self._rng.rand(*vector_shape), + diag_stdev=self._rng.rand(*vector_shape)) + for alpha in [0.25, 0.75]: + + negative_renyi_divergence = entropy.renyi_ratio( + log_p=q.log_prob, q=q, n=n, alpha=alpha, seed=0) + + self.assertEqual((2,), negative_renyi_divergence.get_shape()) + self.assertAllClose(np.zeros(2), negative_renyi_divergence.eval()) + + +class RenyiAlphaTest(tf.test.TestCase): + + def test_with_three_alphas(self): + with self.test_session(): + for dtype in (tf.float32, tf.float64): + alpha_min = tf.constant(0.0, dtype=dtype) + alpha_max = 0.5 + decay_time = 3 + + alpha_0 = entropy.renyi_alpha( + 0, decay_time, alpha_min=alpha_min, alpha_max=alpha_max) + alpha_1 = entropy.renyi_alpha( + 1, decay_time, alpha_min=alpha_min, alpha_max=alpha_max) + alpha_2 = entropy.renyi_alpha( + 2, decay_time, alpha_min=alpha_min, alpha_max=alpha_max) + alpha_3 = entropy.renyi_alpha( + 3, decay_time, alpha_min=alpha_min, alpha_max=alpha_max) + + # Alpha should start at alpha_max. + self.assertAllClose(alpha_max, alpha_0.eval(), atol=1e-5) + # Alpha should finish at alpha_min. + self.assertAllClose(alpha_min.eval(), alpha_3.eval(), atol=1e-5) + # In between, alpha should be monotonically decreasing. + _assert_monotonic_decreasing( + [alpha_0.eval(), alpha_1.eval(), alpha_2.eval(), alpha_3.eval()]) + + def test_non_scalar_input_raises(self): + with self.test_session(): + # Good values here + step = 0 + alpha_min = 0.0 + alpha_max = 0.5 + decay_time = 3 + + # Use one bad value inside each check. + # The "bad" value is always the non-scalar one. + with self.assertRaisesRegexp(ValueError, 'must be scalar'): + entropy.renyi_alpha( + [step], decay_time, alpha_min=alpha_min, alpha_max=alpha_max).eval() + + with self.assertRaisesRegexp(ValueError, 'must be scalar'): + entropy.renyi_alpha( + step, [decay_time], alpha_min=alpha_min, alpha_max=alpha_max).eval() + + with self.assertRaisesRegexp(ValueError, 'must be scalar'): + entropy.renyi_alpha( + step, decay_time, alpha_min=[alpha_min], alpha_max=alpha_max).eval() + + with self.assertRaisesRegexp(ValueError, 'must be scalar'): + entropy.renyi_alpha( + step, decay_time, alpha_min=alpha_min, alpha_max=[alpha_max]).eval() + + def test_input_with_wrong_sign_raises(self): + with self.test_session(): + # Good values here + step = 0 + alpha_min = 0.0 + alpha_max = 0.5 + decay_time = 3 + + # Use one bad value inside each check. + # The "bad" value is always the non-scalar one. + with self.assertRaisesOpError('decay_time must be positive'): + entropy.renyi_alpha( + step, 0.0, alpha_min=alpha_min, alpha_max=alpha_max).eval() + + with self.assertRaisesOpError('step must be non-negative'): + entropy.renyi_alpha( + -1, decay_time, alpha_min=alpha_min, alpha_max=alpha_max).eval() + + +if __name__ == '__main__': + tf.test.main() diff --git a/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py b/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py new file mode 100644 index 0000000000000000000000000000000000000000..2dd06d2d4be33da0e0d55b6893fed8904f37d8b0 --- /dev/null +++ b/tensorflow/contrib/bayesflow/python/kernel_tests/monte_carlo_test.py @@ -0,0 +1,179 @@ +# 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. +# ============================================================================== +"""Tests for Monte Carlo Ops.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import tensorflow as tf + +distributions = tf.contrib.distributions +layers = tf.contrib.layers +monte_carlo = tf.contrib.bayesflow.monte_carlo + + +class ExpectationImportanceSampleTest(tf.test.TestCase): + + def test_normal_integral_mean_and_var_correctly_estimated(self): + n = int(1e6) + with self.test_session(): + mu_p = tf.constant([-1.0, 1.0], dtype=tf.float64) + mu_q = tf.constant([0.0, 0.0], dtype=tf.float64) + sigma_p = tf.constant([0.5, 0.5], dtype=tf.float64) + sigma_q = tf.constant([1.0, 1.0], dtype=tf.float64) + p = distributions.Normal(mu=mu_p, sigma=sigma_p) + q = distributions.Normal(mu=mu_q, sigma=sigma_q) + + # Compute E_p[X]. + e_x = monte_carlo.expectation_importance_sampler( + f=lambda x: x, log_p=p.log_prob, sampling_dist_q=q, n=n, seed=42) + + # Compute E_p[X^2]. + e_x2 = monte_carlo.expectation_importance_sampler( + f=tf.square, + log_p=p.log_prob, + sampling_dist_q=q, + n=n, + seed=42) + + stdev = tf.sqrt(e_x2 - tf.square(e_x)) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + # Convergence of mean is +- 0.003 if n = 100M + # Convergence of std is +- 0.00001 if n = 100M + self.assertEqual(p.get_batch_shape(), e_x.get_shape()) + self.assertAllClose(p.mean().eval(), e_x.eval(), rtol=0.01) + self.assertAllClose(p.std().eval(), stdev.eval(), rtol=0.02) + + def test_multivariate_normal_prob_positive_product_of_components(self): + # Test that importance sampling can correctly estimate the probability that + # the product of components in a MultivariateNormal are > 0. + n = 1000 + with self.test_session(): + p = distributions.MultivariateNormalDiag( + mu=[0.0, 0.0], diag_stdev=[1.0, 1.0]) + q = distributions.MultivariateNormalDiag( + mu=[0.5, 0.5], diag_stdev=[3., 3.]) + + # Compute E_p[X_1 * X_2 > 0], with X_i the ith component of X ~ p(x). + # Should equal 1/2 because p is a spherical Gaussian centered at (0, 0). + def indicator(x): + x1_times_x2 = tf.reduce_prod(x, reduction_indices=[-1]) + return 0.5 * (tf.sign(x1_times_x2) + 1.0) + + prob = monte_carlo.expectation_importance_sampler( + f=indicator, log_p=p.log_prob, sampling_dist_q=q, n=n, seed=42) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + # Convergence is +- 0.004 if n = 100k. + self.assertEqual(p.get_batch_shape(), prob.get_shape()) + self.assertAllClose(0.5, prob.eval(), rtol=0.05) + + +class ExpectationImportanceSampleLogspaceTest(tf.test.TestCase): + + def test_normal_distribution_second_moment_estimated_correctly(self): + # Test the importance sampled estimate against an analytical result. + n = int(1e6) + with self.test_session(): + mu_p = tf.constant([0.0, 0.0], dtype=tf.float64) + mu_q = tf.constant([-1.0, 1.0], dtype=tf.float64) + sigma_p = tf.constant([1.0, 2 / 3.], dtype=tf.float64) + sigma_q = tf.constant([1.0, 1.0], dtype=tf.float64) + p = distributions.Normal(mu=mu_p, sigma=sigma_p) + q = distributions.Normal(mu=mu_q, sigma=sigma_q) + + # Compute E_p[X^2]. + # Should equal [1, (2/3)^2] + log_e_x2 = monte_carlo.expectation_importance_sampler_logspace( + log_f=lambda x: tf.log(tf.square(x)), + log_p=p.log_prob, + sampling_dist_q=q, + n=n, + seed=42) + e_x2 = tf.exp(log_e_x2) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertEqual(p.get_batch_shape(), e_x2.get_shape()) + self.assertAllClose([1., (2 / 3.)**2], e_x2.eval(), rtol=0.02) + + +class ExpectationTest(tf.test.TestCase): + + def test_mc_estimate_of_normal_mean_and_variance_is_correct_vs_analytic(self): + n = 10000 + with self.test_session(): + p = distributions.Normal(mu=[1.0, -1.0], sigma=[0.3, 0.5]) + # Compute E_p[X] and E_p[X^2]. + z = p.sample_n(n=n) + e_x = monte_carlo.expectation(lambda x: x, p, z=z, seed=42) + e_x2 = monte_carlo.expectation(tf.square, p, z=z, seed=0) + var = e_x2 - tf.square(e_x) + + self.assertEqual(p.get_batch_shape(), e_x.get_shape()) + self.assertEqual(p.get_batch_shape(), e_x2.get_shape()) + + # Relative tolerance (rtol) chosen 2 times as large as minimim needed to + # pass. + self.assertAllClose(p.mean().eval(), e_x.eval(), rtol=0.01) + self.assertAllClose(p.variance().eval(), var.eval(), rtol=0.02) + + +class GetSamplesTest(tf.test.TestCase): + """Test the private method 'get_samples'.""" + + def test_raises_if_both_z_and_n_are_none(self): + with self.test_session(): + dist = distributions.Normal(mu=0., sigma=1.) + z = None + n = None + seed = None + with self.assertRaisesRegexp(ValueError, 'exactly one'): + monte_carlo._get_samples(dist, z, n, seed) + + def test_raises_if_both_z_and_n_are_not_none(self): + with self.test_session(): + dist = distributions.Normal(mu=0., sigma=1.) + z = dist.sample_n(n=1) + n = 1 + seed = None + with self.assertRaisesRegexp(ValueError, 'exactly one'): + monte_carlo._get_samples(dist, z, n, seed) + + def test_returns_n_samples_if_n_provided(self): + with self.test_session(): + dist = distributions.Normal(mu=0., sigma=1.) + z = None + n = 10 + seed = None + z = monte_carlo._get_samples(dist, z, n, seed) + self.assertEqual((10,), z.get_shape()) + + def test_returns_z_if_z_provided(self): + with self.test_session(): + dist = distributions.Normal(mu=0., sigma=1.) + z = dist.sample_n(n=10) + n = None + seed = None + z = monte_carlo._get_samples(dist, z, n, seed) + self.assertEqual((10,), z.get_shape()) + + +if __name__ == '__main__': + tf.test.main() diff --git a/tensorflow/contrib/bayesflow/python/kernel_tests/stochastic_graph_test.py b/tensorflow/contrib/bayesflow/python/kernel_tests/stochastic_graph_test.py index 172c474d13a4260852f2c7c96c58af39a041812b..1c21b786f741b211850172ba5616db3de9109c5a 100644 --- a/tensorflow/contrib/bayesflow/python/kernel_tests/stochastic_graph_test.py +++ b/tensorflow/contrib/bayesflow/python/kernel_tests/stochastic_graph_test.py @@ -354,5 +354,47 @@ class TestSurrogateLosses(tf.test.TestCase): self.assertAllClose(*sess.run([sl_dt2, sum([loss, dt2_term])])) +class StochasticDependenciesMapTest(tf.test.TestCase): + + def testBuildsMapOfUpstreamNodes(self): + dt1 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + dt2 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + out1 = dt1.value() + 1. + out2 = dt2.value() + 2. + x = out1 + out2 + y = out2 * 3. + dep_map = sg._stochastic_dependencies_map([x, y]) + self.assertEqual(dep_map[dt1], set([x])) + self.assertEqual(dep_map[dt2], set([x, y])) + + def testHandlesStackedStochasticNodes(self): + dt1 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + out1 = dt1.value() + 1. + dt2 = sg.DistributionTensor(distributions.Normal, mu=out1, sigma=1.) + x = dt2.value() + 2. + dt3 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + y = dt3.value() * 3. + dep_map = sg._stochastic_dependencies_map([x, y]) + self.assertEqual(dep_map[dt1], set([x])) + self.assertEqual(dep_map[dt2], set([x])) + self.assertEqual(dep_map[dt3], set([y])) + + def testTraversesControlInputs(self): + dt1 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + logits = dt1.value() * 3. + dt2 = sg.DistributionTensor(distributions.Bernoulli, logits=logits) + dt3 = sg.DistributionTensor(distributions.Normal, mu=0., sigma=1.) + x = dt3.value() + y = tf.ones((2, 2)) * 4. + z = tf.ones((2, 2)) * 3. + out = tf.cond( + tf.cast(dt2, tf.bool), lambda: tf.add(x, y), lambda: tf.square(z)) + out += 5. + dep_map = sg._stochastic_dependencies_map([out]) + self.assertEqual(dep_map[dt1], set([out])) + self.assertEqual(dep_map[dt2], set([out])) + self.assertEqual(dep_map[dt3], set([out])) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/contrib/bayesflow/python/ops/entropy.py b/tensorflow/contrib/bayesflow/python/ops/entropy.py new file mode 100644 index 0000000000000000000000000000000000000000..209b269c00cf894bd55d0e6b728ba418e4d3e07f --- /dev/null +++ b/tensorflow/contrib/bayesflow/python/ops/entropy.py @@ -0,0 +1,422 @@ +# 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. +# ============================================================================== +r"""Entropy Ops. + +## Background + +Common Shannon entropy, the Evidence Lower BOund (ELBO), KL divergence, and more +all have information theoretic use and interpretations. They are also often +used in variational inference. This library brings together `Ops` for +estimating them, e.g. using Monte Carlo expectations. + +## Examples + +Example of fitting a variational posterior with the ELBO. + +``` +# We start by assuming knowledge of the log of a joint density p(z, x) over +# latent variable z and fixed measurement x. Since x is fixed, the Python +# function does not take x as an argument. +def log_joint(z): + theta = tf.Variable(0.) # Trainable variable that helps define log_joint. + ... + +# Next, define a Normal distribution with trainable parameters. +q = distributions.Normal(mu=tf.Variable(0.), sigma=tf.Variable(1.)) + +# Now, define a loss function (negative ELBO) that, when minimized, will adjust +# mu, sigma, and theta, increasing the ELBO, which we hope will both reduce the +# KL divergence between q(z) and p(z | x), and increase p(x). Note that we +# cannot guarantee both, but in general we expect both to happen. +elbo = entropy.elbo_ratio(log_p, q, n=10) +loss = -elbo + +# Minimize the loss +train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss) +tf.initialize_all_variables().run() +for step in range(100): + train_op.run() +``` + +## Ops + +@@elbo_ratio +@@entropy_shannon +@@renyi_ratio +@@renyi_alpha + +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import math + +from tensorflow.contrib.bayesflow.python.ops import monte_carlo +from tensorflow.contrib.bayesflow.python.ops import variational_inference +from tensorflow.python.framework import ops +from tensorflow.python.ops import check_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.platform import tf_logging as logging + +# Make utility functions from monte_carlo available. +# pylint: disable=protected-access +_get_samples = monte_carlo._get_samples +_logspace_mean = monte_carlo._logspace_mean +_sample_mean = monte_carlo._sample_mean + +# pylint: enable=protected-access + +__all__ = [ + 'elbo_ratio', + 'entropy_shannon', + 'renyi_ratio', + 'renyi_alpha', +] + + +ELBOForms = variational_inference.ELBOForms # pylint: disable=invalid-name + + +def elbo_ratio(log_p, + q, + z=None, + n=None, + seed=None, + form=None, + name='elbo_ratio'): + r"""Estimate of the ratio appearing in the `ELBO` and `KL` divergence. + + With `p(z) := exp{log_p(z)}`, this `Op` returns an approximation of + + ``` + E_q[ Log[p(Z) / q(Z)] ] + ``` + + The term `E_q[ Log[p(Z)] ]` is always computed as a sample mean. + The term `E_q[ Log[q(z)] ]` can be computed with samples, or an exact formula + if `q.entropy()` is defined. This is controlled with the kwarg `form`. + + This log-ratio appears in different contexts: + + #### `KL[q || p]` + + If `log_p(z) = Log[p(z)]` for distribution `p`, this `Op` approximates + the negative Kullback-Leibler divergence. + + ``` + elbo_ratio(log_p, q, n=100) = -1 * KL[q || p], + KL[q || p] = E[ Log[q(Z)] - Log[p(Z)] ] + ``` + + Note that if `p` is a `Distribution`, then `distributions.kl(q, p)` may be + defined and available as an exact result. + + #### ELBO + + If `log_p(z) = Log[p(z, x)]` is the log joint of a distribution `p`, this is + the Evidence Lower BOund (ELBO): + + ``` + ELBO ~= E[ Log[p(Z, x)] - Log[q(Z)] ] + = Log[p(x)] - KL[q || p] + <= Log[p(x)] + ``` + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + log_p: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. + q: `tf.contrib.distributions.BaseDistribution`. + z: `Tensor` of samples from `q`, produced by `q.sample_n`. + n: Integer `Tensor`. Number of samples to generate if `z` is not provided. + seed: Python integer to seed the random number generator. + form: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. + name: A name to give this `Op`. + + Returns: + Scalar `Tensor` holding sample mean KL divergence. `shape` is the batch + shape of `q`, and `dtype` is the same as `q`. + + Raises: + ValueError: If `form` is not handled by this function. + """ + form = ELBOForms.default if form is None else form + + with ops.name_scope(name, values=[n, z]): + z = _get_samples(q, z, n, seed) + + entropy = entropy_shannon(q, z=z, form=form) + + # If log_p(z) = Log[p(z)], cross entropy = -E_q[log(p(Z))] + negative_cross_entropy = _sample_mean(log_p(z)) + + return entropy + negative_cross_entropy + + +def entropy_shannon(p, + z=None, + n=None, + seed=None, + form=None, + name='entropy_shannon'): + r"""Monte Carlo or deterministic computation of Shannon's entropy. + + Depending on the kwarg `form`, this `Op` returns either the analytic entropy + of the distribution `p`, or the sampled entropy: + + ``` + -n^{-1} sum_{i=1}^n p.log_prob(z_i), where z_i ~ p, + \approx - E_p[ Log[p(Z)] ] + = Entropy[p] + ``` + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + p: `tf.contrib.distributions.BaseDistribution` + z: `Tensor` of samples from `p`, produced by `p.sample_n(n)` for some `n`. + n: Integer `Tensor`. Number of samples to generate if `z` is not provided. + seed: Python integer to seed the random number generator. + form: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. + name: A name to give this `Op`. + + Returns: + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + + Raises: + ValueError: If `form` not handled by this function. + ValueError: If `form` is `ELBOForms.analytic_entropy` and `n` was provided. + """ + form = ELBOForms.default if form is None else form + + if n is not None and form == ELBOForms.analytic_entropy: + raise ValueError('If form == ELBOForms.analytic_entropy, n must be None.') + + with ops.name_scope(name, values=[n, z]): + # Entropy: -E_p[log(p(Z))]. + entropy = None + + # Try analytic path + if form in [ELBOForms.default, ELBOForms.analytic_entropy]: + try: + entropy = p.entropy() + logging.info('Using analytic entropy(p:%s)', p) + except NotImplementedError as e: + if form == ELBOForms.analytic_entropy: + raise e + elif form != ELBOForms.sample: + raise ValueError('ELBOForm not handled by this function: %s' % form) + + # Sample path + if entropy is None: + logging.info('Using sampled entropy(p:%s)', p) + entropy = -1. * monte_carlo.expectation( + p.log_prob, p, z=z, n=n, seed=seed) + + return entropy + + +def renyi_ratio(log_p, q, alpha, z=None, n=None, seed=None, name='renyi_ratio'): + r"""Monte Carlo estimate of the ratio appearing in Renyi divergence. + + This can be used to compute the Renyi (alpha) divergence, or a log evidence + approximation based on Renyi divergence. + + #### Definition + + With `z_i` iid samples from `q`, and `exp{log_p(z)} = p(z)`, this `Op` returns + the (biased for finite `n`) estimate: + + ``` + (1 - alpha)^{-1} Log[ n^{-1} sum_{i=1}^n ( p(z_i) / q(z_i) )^{1 - alpha}, + \approx (1 - alpha)^{-1} Log[ E_q[ (p(Z) / q(Z))^{1 - alpha} ] ] + ``` + + This ratio appears in different contexts: + + #### Renyi divergence + + If `log_p(z) = Log[p(z)]` is the log prob of a distribution, and + `alpha > 0`, `alpha != 1`, this `Op` approximates `-1` times Renyi divergence: + + ``` + # Choose reasonably high n to limit bias, see below. + renyi_ratio(log_p, q, alpha, n=100) + \approx -1 * D_alpha[q || p], where + D_alpha[q || p] := (1 - alpha)^{-1} Log E_q[(p(Z) / q(Z))^{1 - alpha}] + ``` + + The Renyi (or "alpha") divergence is non-negative and equal to zero iff + `q = p`. Various limits of `alpha` lead to different special case results: + + ``` + alpha D_alpha[q || p] + ----- --------------- + --> 0 Log[ int_{q > 0} p(z) dz ] + = 0.5, -2 Log[1 - Hel^2[q || p]], (\propto squared Hellinger distance) + --> 1 KL[q || p] + = 2 Log[ 1 + chi^2[q || p] ], (\propto squared Chi-2 divergence) + --> infty Log[ max_z{q(z) / p(z)} ], (min description length principle). + ``` + + See "Renyi Divergence Variational Inference", by Li and Turner. + + #### Log evidence approximation + + If `log_p(z) = Log[p(z, x)]` is the log of the joint distribution `p`, this is + an alternative to the ELBO common in variational inference. + + ``` + L_alpha(q, p) = Log[p(x)] - D_alpha[q || p] + ``` + + If `q` and `p` have the same support, and `0 < a <= b < 1`, one can show + `ELBO <= D_b <= D_a <= Log[p(x)]`. Thus, this `Op` allows a smooth + interpolation between the ELBO and the true evidence. + + #### Stability notes + + Note that when `1 - alpha` is not small, the ratio `(p(z) / q(z))^{1 - alpha}` + is subject to underflow/overflow issues. For that reason, it is evaluated in + log-space after centering. Nonetheless, infinite/NaN results may occur. For + that reason, one may wish to shrink `alpha` gradually. See the `Op` + `renyi_alpha`. Using `float64` will also help. + + + #### Bias for finite sample size + + Due to nonlinearity of the logarithm, for random variables `{X_1,...,X_n}`, + `E[ Log[sum_{i=1}^n X_i] ] != Log[ E[sum_{i=1}^n X_i] ]`. As a result, this + estimate is biased for finite `n`. For `alpha < 1`, it is non-decreasing + with `n` (in expectation). For example, if `n = 1`, this estimator yields the + same result as `elbo_ratio`, and as `n` increases the expected value + of the estimator increases. + + #### Call signature + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + log_p: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. + q: `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. + alpha: `Tensor` with shape `q.batch_shape` and values not equal to 1. + z: `Tensor` of samples from `q`, produced by `q.sample_n`. + n: Integer `Tensor`. The number of samples to use if `z` is not provided. + Note that this can be highly biased for small `n`, see docstring. + seed: Python integer to seed the random number generator. + name: A name to give this `Op`. + + Returns: + renyi_result: The scaled log of sample mean. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + """ + with ops.name_scope(name, values=[alpha, n, z]): + z = _get_samples(q, z, n, seed) + + # Evaluate sample mean in logspace. Note that _logspace_mean will compute + # (among other things) the mean of q.log_prob(z), which could also be + # obtained with q.entropy(). However, DON'T use analytic entropy, because + # that increases variance, and could result in NaN/Inf values of a sensitive + # term. + + # log_values + # = (1 - alpha) * ( Log p - Log q ) + log_values = (1. - alpha) * (log_p(z) - q.log_prob(z)) + + # log_mean_values + # = Log[ E[ values ] ] + # = Log[ E[ (p / q)^{1-alpha} ] ] + log_mean_values = _logspace_mean(log_values) + + return log_mean_values / (1. - alpha) + + +def renyi_alpha(step, + decay_time, + alpha_min, + alpha_max=0.99999, + name='renyi_alpha'): + r"""Exponentially decaying `Tensor` appropriate for Renyi ratios. + + When minimizing the Renyi divergence for `0 <= alpha < 1` (or maximizing the + Renyi equivalent of elbo) in high dimensions, it is not uncommon to experience + `NaN` and `inf` values when `alpha` is far from `1`. + + For that reason, it is often desirable to start the optimization with `alpha` + very close to 1, and reduce it to a final `alpha_min` according to some + schedule. The user may even want to optimize using `elbo_ratio` for + some fixed time before switching to Renyi based methods. + + This `Op` returns an `alpha` decaying exponentially with step: + + ``` + s(step) = (exp{step / decay_time} - 1) / (e - 1) + t(s) = max(0, min(s, 1)), (smooth growth from 0 to 1) + alpha(t) = (1 - t) alpha_min + t alpha_max + ``` + + Args: + step: Non-negative scalar `Tensor`. Typically the global step or an + offset version thereof. + decay_time: Postive scalar `Tensor`. + alpha_min: `float` or `double` `Tensor`. + The minimal, final value of `alpha`, achieved when `step >= decay_time` + alpha_max: `Tensor` of same `dtype` as `alpha_min`. + The maximal, beginning value of `alpha`, achieved when `step == 0` + name: A name to give this `Op`. + + Returns: + alpha: A `Tensor` of same `dtype` as `alpha_min`. + """ + with ops.name_scope(name, values=[step, decay_time, alpha_min, alpha_max]): + alpha_min = ops.convert_to_tensor(alpha_min, name='alpha_min') + dtype = alpha_min.dtype + + alpha_max = ops.convert_to_tensor(alpha_max, dtype=dtype, name='alpha_max') + decay_time = math_ops.cast(decay_time, dtype) + step = math_ops.cast(step, dtype) + + check_scalars = [ + check_ops.assert_rank(step, 0, message='step must be scalar'), + check_ops.assert_rank( + decay_time, 0, message='decay_time must be scalar'), + check_ops.assert_rank(alpha_min, 0, message='alpha_min must be scalar'), + check_ops.assert_rank(alpha_max, 0, message='alpha_max must be scalar'), + ] + check_sign = [ + check_ops.assert_non_negative( + step, message='step must be non-negative'), + check_ops.assert_positive( + decay_time, message='decay_time must be positive'), + ] + + with ops.control_dependencies(check_scalars + check_sign): + theta = (math_ops.exp(step / decay_time) - 1.) / (math.e - 1.) + theta = math_ops.minimum(math_ops.maximum(theta, 0.), 1.) + return alpha_max * (1. - theta) + alpha_min * theta diff --git a/tensorflow/contrib/bayesflow/python/ops/monte_carlo.py b/tensorflow/contrib/bayesflow/python/ops/monte_carlo.py new file mode 100644 index 0000000000000000000000000000000000000000..ce58f82efa294e927e7ba6220917ae27f91fb97a --- /dev/null +++ b/tensorflow/contrib/bayesflow/python/ops/monte_carlo.py @@ -0,0 +1,292 @@ +# 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. +# ============================================================================== +r"""Monte Carlo integration and helpers. + +## Background + +Monte Carlo integration refers to the practice of estimating an expectation with +a sample mean. For example, given random variable `Z in R^k` with density `p`, +the expectation of function `f` can be approximated like: + +``` +E_p[f(Z)] = \int f(z) p(z) dz + ~ S_n + := n^{-1} \sum_{i=1}^n f(z_i), z_i iid samples from p. +``` + +If `E_p[|f(Z)|] < infinity`, then `S_n --> E_p[f(Z)]` by the strong law of large +numbers. If `E_p[f(Z)^2] < infinity`, then `S_n` is asymptotically normal with +variance `Var[f(Z)] / n`. + +Practicioners of Bayesian statistics often find themselves wanting to estimate +`E_p[f(Z)]` when the distribution `p` is known only up to a constant. For +example, the joint distribution `p(z, x)` may be known, but the evidence +`p(x) = \int p(z, x) dz` may be intractable. In that case, a parameterized +distribution family `q_lambda(z)` may be chosen, and the optimal `lambda` is the +one minimizing the KL divergence between `q_lambda(z)` and +`p(z | x)`. We only know `p(z, x)`, but that is sufficient to find `lambda`. + + +## Log-space evaluation and subtracting the maximum. + +Care must be taken when the random variable lives in a high dimensional space. +For example, the naive importance sample estimate `E_q[f(Z) p(Z) / q(Z)]` +involves the ratio of two terms `p(Z) / q(Z)`, each of which must have tails +dropping off faster than `O(|z|^{-(k + 1)})` in order to have finite integral. +This ratio would often be zero or infinity up to numerical precision. + +For that reason, we write + +``` +Log E_q[ f(Z) p(Z) / q(Z) ] + = Log E_q[ exp{Log[f(Z)] + Log[p(Z)] - Log[q(Z)] - C} ] + C, where +C := Max[ Log[f(Z)] + Log[p(Z)] - Log[q(Z)] ]. +``` + +The maximum value of the exponentiated term will be 0.0, and the the expecation +can be evaluated in a stable manner. + +## Ops + +@@expectation +@@expectation_importance_sampler +@@expectation_importance_sampler_logspace + +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import ops +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn + +__all__ = [ + 'expectation', + 'expectation_importance_sampler', + 'expectation_importance_sampler_logspace', +] + + +def expectation_importance_sampler(f, + log_p, + sampling_dist_q, + z=None, + n=None, + seed=None, + name='expectation_importance_sampler'): + r"""Monte Carlo estimate of `E_p[f(Z)] = E_q[f(Z) p(Z) / q(Z)]`. + + With `p(z) := exp{log_p(z)}`, this `Op` returns + + ``` + n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ], z_i ~ q, + \approx E_q[ f(Z) p(Z) / q(Z) ] + = E_p[f(Z)] + ``` + + This integral is done in log-space with max-subtraction to better handle the + often extreme values that `f(z) p(z) / q(z)` can take on. + + If `f >= 0`, it is up to 2x more efficient to exponentiate the result of + `expectation_importance_sampler_logspace` applied to `Log[f]`. + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + f: Callable mapping samples from `sampling_dist_q` to `Tensors` with shape + broadcastable to `q.batch_shape`. + For example, `f` works "just like" `q.log_prob`. + log_p: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `sampling_dist_q.log_prob`. + sampling_dist_q: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. + z: `Tensor` of samples from `q`, produced by `q.sample_n`. + n: Integer `Tensor`. Number of samples to generate if `z` is not provided. + seed: Python integer to seed the random number generator. + name: A name to give this `Op`. + + Returns: + The importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + """ + q = sampling_dist_q + with ops.name_scope(name, values=[z, n]): + z = _get_samples(q, z, n, seed) + + log_p_z = log_p(z) + q_log_prob_z = q.log_prob(z) + + def _importance_sampler_positive_f(log_f_z): + # Same as expectation_importance_sampler_logspace, but using Tensors + # rather than samples and functions. Allows us to sample once. + log_values = log_f_z + log_p_z - q_log_prob_z + return _logspace_mean(log_values) + + # With f_plus(z) = max(0, f(z)), f_minus(z) = max(0, -f(z)), + # E_p[f(Z)] = E_p[f_plus(Z)] - E_p[f_minus(Z)] + # = E_p[f_plus(Z) + 1] - E_p[f_minus(Z) + 1] + # Without incurring bias, 1 is added to each to prevent zeros in logspace. + # The logarithm is approximately linear around 1 + epsilon, so this is good + # for small values of 'z' as well. + f_z = f(z) + log_f_plus_z = math_ops.log(nn.relu(f_z) + 1.) + log_f_minus_z = math_ops.log(nn.relu(-1. * f_z) + 1.) + + log_f_plus_integral = _importance_sampler_positive_f(log_f_plus_z) + log_f_minus_integral = _importance_sampler_positive_f(log_f_minus_z) + + return math_ops.exp(log_f_plus_integral) - math_ops.exp(log_f_minus_integral) + + +def expectation_importance_sampler_logspace( + log_f, + log_p, + sampling_dist_q, + z=None, + n=None, + seed=None, + name='expectation_importance_sampler_logspace'): + r"""Importance sampling with a positive function, in log-space. + + With `p(z) := exp{log_p(z)}`, and `f(z) = exp{log_f(z)}`, this `Op` + returns + + ``` + Log[ n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ] ], z_i ~ q, + \approx Log[ E_q[ f(Z) p(Z) / q(Z) ] ] + = Log[E_p[f(Z)]] + ``` + + This integral is done in log-space with max-subtraction to better handle the + often extreme values that `f(z) p(z) / q(z)` can take on. + + In contrast to `expectation_importance_sampler`, this `Op` returns values in + log-space. + + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + log_f: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_f` works "just like" `sampling_dist_q.log_prob`. + log_p: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. + sampling_dist_q: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. + z: `Tensor` of samples from `q`, produced by `q.sample_n`. + n: Integer `Tensor`. Number of samples to generate if `z` is not provided. + seed: Python integer to seed the random number generator. + name: A name to give this `Op`. + + Returns: + Logarithm of the importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + """ + q = sampling_dist_q + with ops.name_scope(name, values=[z, n]): + z = _get_samples(q, z, n, seed) + log_values = log_f(z) + log_p(z) - q.log_prob(z) + return _logspace_mean(log_values) + + +def _logspace_mean(log_values): + """Evaluate `Log[E[values]]` in a stable manner. + + Args: + log_values: `Tensor` holding `Log[values]`. + + Returns: + `Tensor` of same `dtype` as `log_values`, reduced across dim 0. + `Log[Mean[values]]`. + """ + # center = Max[Log[values]], with stop-gradient + # The center hopefully keep the exponentiated term small. It is cancelled + # from the final result, so putting stop gradient on it will not change the + # final result. We put stop gradient on to eliminate unnecessary computation. + center = array_ops.stop_gradient(_sample_max(log_values)) + + # centered_values = exp{Log[values] - E[Log[values]]} + centered_values = math_ops.exp(log_values - center) + + # log_mean_of_values = Log[ E[centered_values] ] + center + # = Log[ E[exp{log_values - E[log_values]}] ] + center + # = Log[E[values]] - E[log_values] + center + # = Log[E[values]] + log_mean_of_values = math_ops.log(_sample_mean(centered_values)) + center + + return log_mean_of_values + + +def expectation(f, p, z=None, n=None, seed=None, name='expectation'): + r"""Monte Carlo estimate of an expectation: `E_p[f(Z)]` with sample mean. + + This `Op` returns + + ``` + n^{-1} sum_{i=1}^n f(z_i), where z_i ~ p + \approx E_p[f(Z)] + ``` + + User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + + Args: + f: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `f` works "just like" `sampling_dist_q.log_prob`. + p: `tf.contrib.distributions.BaseDistribution`. + z: `Tensor` of samples from `p`, produced by `p.sample_n`. + n: Integer `Tensor`. Number of samples to generate if `z` is not provided. + seed: Python integer to seed the random number generator. + name: A name to give this `Op`. + + Returns: + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + """ + with ops.name_scope(name, values=[n, z]): + z = _get_samples(p, z, n, seed) + return _sample_mean(f(z)) + + +def _sample_mean(values): + """Mean over sample indices. In this module this is always [0].""" + return math_ops.reduce_mean(values, reduction_indices=[0]) + + +def _sample_max(values): + """Max over sample indices. In this module this is always [0].""" + return math_ops.reduce_max(values, reduction_indices=[0]) + + +def _get_samples(dist, z, n, seed): + """Check args and return samples.""" + with ops.name_scope('get_samples', values=[z, n]): + if (n is None) == (z is None): + raise ValueError( + 'Must specify exactly one of arguments "n" and "z". Found: ' + 'n = %s, z = %s' % (n, z)) + if n is not None: + return dist.sample_n(n=n, seed=seed) + else: + return ops.convert_to_tensor(z, name='z') diff --git a/tensorflow/contrib/bayesflow/python/ops/stochastic_graph.py b/tensorflow/contrib/bayesflow/python/ops/stochastic_graph.py index 499c91ea6ffd0c1587f4ccd1bac11dd869ecb67b..7d29ae23d1944884d834d2a5734d510d59a87cf0 100644 --- a/tensorflow/contrib/bayesflow/python/ops/stochastic_graph.py +++ b/tensorflow/contrib/bayesflow/python/ops/stochastic_graph.py @@ -43,6 +43,7 @@ import threading import six +from tensorflow.contrib import distributions from tensorflow.contrib.bayesflow.python.ops import stochastic_gradient_estimators as sge from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape @@ -333,7 +334,7 @@ class DistributionTensor(StochasticTensor): `MeanValueType` or if `loss_fn=None`. Args: - dist_cls: a class deriving from `BaseDistribution`. + dist_cls: a `Distribution` class. name: a name for this `DistributionTensor` and its ops. dist_value_type: a `_StochasticValueType`, which will determine what the `value` of this `DistributionTensor` will be. If not provided, the @@ -346,7 +347,13 @@ class DistributionTensor(StochasticTensor): module for additional loss functions and baselines. **dist_args: keyword arguments to be passed through to `dist_cls` on construction. + + Raises: + TypeError: if `dist_cls` is not a `Distribution`. + TypeError: if `loss_fn` is not `callable`. """ + if not issubclass(dist_cls, distributions.Distribution): + raise TypeError("dist_cls must be a subclass of Distribution") self._dist_cls = dist_cls self._dist_args = dist_args if dist_value_type is None: @@ -395,12 +402,12 @@ class DistributionTensor(StochasticTensor): if isinstance(self._value_type, MeanValue): value_tensor = self._dist.mean() elif isinstance(self._value_type, SampleValue): - value_tensor = self._dist.sample_n(self._value_type.n) + value_tensor = self._dist.sample(self._value_type.n) elif isinstance(self._value_type, SampleAndReshapeValue): if self._value_type.n == 1: value_tensor = self._dist.sample() else: - samples = self._dist.sample_n(self._value_type.n) + samples = self._dist.sample(self._value_type.n) samples_shape = array_ops.shape(samples) samples_static_shape = samples.get_shape() new_batch_size = samples_shape[0] * samples_shape[1] diff --git a/tensorflow/contrib/bayesflow/python/ops/variational_inference.py b/tensorflow/contrib/bayesflow/python/ops/variational_inference.py index f276d8b82945dab9ef6c54f1338026bf12d026bd..784c79492ca655561495a73ba44d391eda5c9364 100644 --- a/tensorflow/contrib/bayesflow/python/ops/variational_inference.py +++ b/tensorflow/contrib/bayesflow/python/ops/variational_inference.py @@ -24,7 +24,7 @@ from __future__ import division from __future__ import print_function from tensorflow.contrib import distributions -from tensorflow.contrib.bayesflow import stochastic_graph as sg +from tensorflow.contrib.bayesflow.python.ops import stochastic_graph as sg from tensorflow.python.framework import ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import tf_logging as logging diff --git a/tensorflow/contrib/cmake/CMakeLists.txt b/tensorflow/contrib/cmake/CMakeLists.txt index e5a0790ff4ad848f65e9b7efe9d4c3af5f98826b..4fe5960d3b73992078807382c3080970a36fddac 100644 --- a/tensorflow/contrib/cmake/CMakeLists.txt +++ b/tensorflow/contrib/cmake/CMakeLists.txt @@ -51,7 +51,8 @@ include(highwayhash) # Let's get to work! include(tf_core_framework.cmake) -include(tf_stream_executor.cmake) +# NOTE: Disabled until issue #3996 is fixed. +# include(tf_stream_executor.cmake) include(tf_core_cpu.cmake) include(tf_models.cmake) include(tf_core_ops.cmake) diff --git a/tensorflow/contrib/cmake/tf_core_framework.cmake b/tensorflow/contrib/cmake/tf_core_framework.cmake index c4828823556ebddb6d78d0f29add90b01e72a5a9..0dbe3c194d98e97ac23d0d0e3639f435007d2658 100644 --- a/tensorflow/contrib/cmake/tf_core_framework.cmake +++ b/tensorflow/contrib/cmake/tf_core_framework.cmake @@ -95,6 +95,7 @@ set(tf_proto_text_srcs "tensorflow/core/framework/graph.proto" "tensorflow/core/framework/kernel_def.proto" "tensorflow/core/framework/log_memory.proto" + "tensorflow/core/framework/node_def.proto" "tensorflow/core/framework/op_def.proto" "tensorflow/core/framework/step_stats.proto" "tensorflow/core/framework/summary.proto" diff --git a/tensorflow/contrib/cmake/tf_core_kernels.cmake b/tensorflow/contrib/cmake/tf_core_kernels.cmake index 2fff5c2dd37a52dded6e7505135939c927f5d32b..8f911e3cb10a4ddede362dbdf10092dcf7d97863 100644 --- a/tensorflow/contrib/cmake/tf_core_kernels.cmake +++ b/tensorflow/contrib/cmake/tf_core_kernels.cmake @@ -13,6 +13,8 @@ file(GLOB_RECURSE tf_core_kernels_exclude_srcs "${tensorflow_source_dir}/tensorflow/core/kernels/*testutil.cc" "${tensorflow_source_dir}/tensorflow/core/kernels/*main.cc" "${tensorflow_source_dir}/tensorflow/core/kernels/*.cu.cc" + "${tensorflow_source_dir}/tensorflow/core/kernels/debug_ops.h" + "${tensorflow_source_dir}/tensorflow/core/kernels/debug_ops.cc" ) list(REMOVE_ITEM tf_core_kernels_srcs ${tf_core_kernels_exclude_srcs}) diff --git a/tensorflow/contrib/copy_graph/python/util/copy_elements.py b/tensorflow/contrib/copy_graph/python/util/copy_elements.py index 62a8d784eea0e9c8a3a1037367bcab0d03926857..3c80a17633957ec0a1c74d8dc23c8a974e98f21a 100644 --- a/tensorflow/contrib/copy_graph/python/util/copy_elements.py +++ b/tensorflow/contrib/copy_graph/python/util/copy_elements.py @@ -198,7 +198,7 @@ def copy_op_to_graph(org_instance, to_graph, variables, for x in op.inputs] #Make a new node_def based on that of the original. - #An instance of tensorflow.core.framework.graph_pb2.NodeDef, it + #An instance of tensorflow.core.framework.node_def_pb2.NodeDef, it #stores String-based info such as name, device and type of the op. #Unique to every Operation instance. new_node_def = deepcopy(op._node_def) diff --git a/tensorflow/contrib/distributions/python/kernel_tests/bernoulli_test.py b/tensorflow/contrib/distributions/python/kernel_tests/bernoulli_test.py index 82f77fbfd1e096f5ccb32acb85a2d50006f77331..ad1402de77f99a5528c3436a14cd408281b58992 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/bernoulli_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/bernoulli_test.py @@ -197,6 +197,25 @@ class BernoulliTest(tf.test.TestCase): # as well as n. self.assertAllClose(p, np.mean(sample_values, axis=0), atol=1e-2) self.assertEqual(set([0, 1]), set(sample_values.flatten())) + # In this test we're just interested in verifying there isn't a crash + # owing to mismatched types. b/30940152 + dist = tf.contrib.distributions.Bernoulli(np.log([.2, .4])) + self.assertAllEqual( + (1, 2), dist.sample_n(1, seed=42).get_shape().as_list()) + + def testSampleActsLikeSampleN(self): + with self.test_session() as sess: + p = [0.2, 0.6] + dist = tf.contrib.distributions.Bernoulli(p=p) + n = 1000 + seed = 42 + self.assertAllEqual(dist.sample(n, seed).eval(), + dist.sample_n(n, seed).eval()) + n = tf.placeholder(tf.int32) + sample, sample_n = sess.run([dist.sample(n, seed), + dist.sample_n(n, seed)], + feed_dict={n: 1000}) + self.assertAllEqual(sample, sample_n) def testMean(self): with self.test_session(): diff --git a/tensorflow/contrib/distributions/python/kernel_tests/categorical_test.py b/tensorflow/contrib/distributions/python/kernel_tests/categorical_test.py index f91f2c33ac8cfed07f7bb810e28db89c94f23841..4fbcc1d812f8945cead2e48e3900671d4476c1b5 100644 --- a/tensorflow/contrib/distributions/python/kernel_tests/categorical_test.py +++ b/tensorflow/contrib/distributions/python/kernel_tests/categorical_test.py @@ -70,8 +70,10 @@ class CategoricalTest(tf.test.TestCase): self.assertEqual(dist.dtype, dist.mode().dtype) self.assertEqual(dist.logits.dtype, tf.float32) self.assertEqual(dist.logits.dtype, dist.entropy().dtype) - self.assertEqual(dist.logits.dtype, dist.pmf(0).dtype) - self.assertEqual(dist.logits.dtype, dist.log_pmf(0).dtype) + self.assertEqual(dist.logits.dtype, dist.pmf( + np.array(0, dtype=np.int64)).dtype) + self.assertEqual(dist.logits.dtype, dist.log_pmf( + np.array(0, dtype=np.int64)).dtype) def testUnknownShape(self): with self.test_session(): diff --git a/tensorflow/contrib/distributions/python/ops/bernoulli.py b/tensorflow/contrib/distributions/python/ops/bernoulli.py index e4dbaba638c8b14d98ee4c9ce7458b6bea53cec2..60c1f3fa4c443af68e84fdeeb6afad3ebc00e619 100644 --- a/tensorflow/contrib/distributions/python/ops/bernoulli.py +++ b/tensorflow/contrib/distributions/python/ops/bernoulli.py @@ -24,7 +24,6 @@ from tensorflow.contrib.distributions.python.ops import kullback_leibler from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn @@ -67,55 +66,18 @@ class Bernoulli(distribution.Distribution): Raises: ValueError: If p and logits are passed, or if neither are passed. """ - self._allow_nan_stats = allow_nan_stats - self._name = name - self._dtype = dtype - self._validate_args = validate_args self._logits, self._p = distribution_util.get_logits_and_prob( name=name, logits=logits, p=p, validate_args=validate_args) with ops.name_scope(name): with ops.name_scope("q"): self._q = 1. - self._p - self._batch_shape = array_ops.shape(self._logits) - self._event_shape = array_ops.constant([], dtype=dtypes.int32) - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._dtype - - @property - def is_reparameterized(self): - return False - - def batch_shape(self, name="batch_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._batch_shape]): - return array_ops.identity(self._batch_shape) - - def get_batch_shape(self): - return self._logits.get_shape() - - def event_shape(self, name="event_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._batch_shape]): - return array_ops.constant([], dtype=self._batch_shape.dtype) - - def get_event_shape(self): - return tensor_shape.scalar() + super(Bernoulli, self).__init__( + dtype=dtype, + parameters={"p": self._p, "q": self._q, "logits": self._logits}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def logits(self): @@ -130,142 +92,69 @@ class Bernoulli(distribution.Distribution): """1-p.""" return self._q - def prob(self, event, name="prob"): - """Probability mass function. + def _batch_shape(self): + return array_ops.shape(self._logits) - Args: - event: `int32` or `int64` binary Tensor; must be broadcastable with `p`. - name: A name for this operation. + def _get_batch_shape(self): + return self._logits.get_shape() - Returns: - The probabilities of the events. - """ - return super(Bernoulli, self).prob(event, name) + def _event_shape(self): + return array_ops.constant([], dtype=dtypes.int32) - def log_prob(self, event, name="log_prob"): - """Log of the probability mass function. + def _get_event_shape(self): + return tensor_shape.scalar() - Args: - event: `int32` or `int64` binary Tensor. - name: A name for this operation (optional). + def _sample_n(self, n, seed=None): + new_shape = array_ops.concat(0, ([n], self.batch_shape())) + uniform = random_ops.random_uniform( + new_shape, seed=seed, dtype=self.p.dtype) + sample = math_ops.less(uniform, self.p) + return math_ops.cast(sample, self.dtype) - Returns: - The log-probabilities of the events. - """ + def _log_prob(self, event): # TODO(jaana): The current sigmoid_cross_entropy_with_logits has # inconsistent behavior for logits = inf/-inf. - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.logits, event]): - event = ops.convert_to_tensor(event, name="event") - event = math_ops.cast(event, self.logits.dtype) - logits = self.logits - # sigmoid_cross_entropy_with_logits doesn't broadcast shape, - # so we do this here. - # TODO(b/30637701): Check dynamic shape, and don't broadcast if the - # dynamic shapes are the same. - if (not event.get_shape().is_fully_defined() or - not logits.get_shape().is_fully_defined() or - event.get_shape() != logits.get_shape()): - logits = array_ops.ones_like(event) * logits - event = array_ops.ones_like(logits) * event - return -nn.sigmoid_cross_entropy_with_logits(logits, event) - - def sample_n(self, n, seed=None, name="sample_n"): - """Generate `n` samples. + event = ops.convert_to_tensor(event, name="event") + event = math_ops.cast(event, self.logits.dtype) + logits = self.logits + # sigmoid_cross_entropy_with_logits doesn't broadcast shape, + # so we do this here. + # TODO(b/30637701): Check dynamic shape, and don't broadcast if the + # dynamic shapes are the same. + if (not event.get_shape().is_fully_defined() or + not logits.get_shape().is_fully_defined() or + event.get_shape() != logits.get_shape()): + logits = array_ops.ones_like(event) * logits + event = array_ops.ones_like(logits) * event + return -nn.sigmoid_cross_entropy_with_logits(logits, event) - Args: - n: scalar. Number of samples to draw from each distribution. - seed: Python integer seed for RNG. - name: name to give to the op. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape` with values of type - `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.p, n]): - n = ops.convert_to_tensor(n, name="n") - new_shape = array_ops.concat(0, ([n], self.batch_shape())) - uniform = random_ops.random_uniform( - new_shape, seed=seed, dtype=dtypes.float32) - sample = math_ops.less(uniform, self.p) - sample.set_shape(tensor_shape.vector(tensor_util.constant_value(n)) - .concatenate(self.get_batch_shape())) - return math_ops.cast(sample, self.dtype) + def _prob(self, event): + return math_ops.exp(self._log_prob(event)) - def entropy(self, name="entropy"): - """Entropy of the distribution. + def _entropy(self): + # TODO(b/31086883): use tf.nn.softplus; fix inconsistent behavior between + # cpu and gpu at -inf/inf. + return (-self.logits * (math_ops.sigmoid(self.logits) - 1) + + math_ops.log(1. + math_ops.exp(-self.logits))) - Args: - name: Name for the op. + def _mean(self): + return array_ops.identity(self.p) - Returns: - entropy: `Tensor` of the same type and shape as `p`. - """ - # TODO(jaana): fix inconsistent behavior between cpu and gpu at -inf/inf. - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.logits]): - return (-self.logits * (math_ops.sigmoid( - self.logits) - 1) + math_ops.log( - math_ops.exp(-self.logits) + 1)) + def _variance(self): + return self.q * self.p - def mean(self, name="mean"): - """Mean of the distribution. + def _std(self): + return math_ops.sqrt(self._variance()) - Args: - name: Name for the op. + def _mode(self): + return math_ops.cast(self.p > self.q, self.dtype) - Returns: - mean: `Tensor` of the same type and shape as `p`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.p]): - return array_ops.identity(self.p) - def mode(self, name="mode"): - """Mode of the distribution. +distribution_util.append_class_fun_doc(Bernoulli.mode, doc_str=""" + Specific notes: 1 if p > 1-p. 0 otherwise. - - Args: - name: Name for the op. - - Returns: - mode: binary `Tensor` of type self.dtype. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.p, self.q]): - return math_ops.cast(self.p > self.q, self.dtype) - - def variance(self, name="variance"): - """Variance of the distribution. - - Args: - name: Name for the op. - - Returns: - variance: `Tensor` of the same type and shape as `p`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.p, self.q]): - return self.q * self.p - - def std(self, name="std"): - """Standard deviation of the distribution. - - Args: - name: Name for the op. - - Returns: - std: `Tensor` of the same type and shape as `p`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.sqrt(self.variance()) - - @property - def is_continuous(self): - return False +""") @kullback_leibler.RegisterKL(Bernoulli, Bernoulli) diff --git a/tensorflow/contrib/distributions/python/ops/beta.py b/tensorflow/contrib/distributions/python/ops/beta.py index 5b1bdcc5d6aec1ada2e84cd304d34a60e5aeb930..04f9d9acb9b27c019065766602df254a2531f5a0 100644 --- a/tensorflow/contrib/distributions/python/ops/beta.py +++ b/tensorflow/contrib/distributions/python/ops/beta.py @@ -18,22 +18,21 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -# pylint: disable=line-too-long +import numpy as np from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util +from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops -# pylint: enable=line-too-long - class Beta(distribution.Distribution): """Beta distribution. @@ -134,21 +133,19 @@ class Beta(distribution.Distribution): with ops.name_scope(name, values=[a, b]): with ops.control_dependencies([ check_ops.assert_positive(a), - check_ops.assert_positive(b)] if validate_args else []): - a = array_ops.identity(a, name="a") - b = array_ops.identity(b, name="b") - - self._a = a - self._b = b - self._name = name - - # Used for mean/mode/variance/entropy/sampling computations - self._a_b_sum = self._a + self._b - - self._get_batch_shape = self._a_b_sum.get_shape() - self._get_event_shape = tensor_shape.TensorShape([]) - self._validate_args = validate_args - self._allow_nan_stats = allow_nan_stats + check_ops.assert_positive(b), + ] if validate_args else []): + self._a = array_ops.identity(a, name="a") + self._b = array_ops.identity(b, name="b") + contrib_tensor_util.assert_same_float_dtype((self._a, self._b)) + # Used for mean/mode/variance/entropy/sampling computations + self._a_b_sum = self._a + self._b + super(Beta, self).__init__( + dtype=self._a_b_sum.dtype, + parameters={"a": self._a, "b": self._b, "a_b_sum": self._a_b_sum}, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def a(self): @@ -161,245 +158,109 @@ class Beta(distribution.Distribution): return self._b @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._a_b_sum.dtype - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a_b_sum]): - return array_ops.shape(self._a_b_sum) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. + def a_b_sum(self): + """Sum of parameters.""" + return self._a_b_sum + + def _batch_shape(self): + return array_ops.shape(self.a_b_sum) + + def _get_batch_shape(self): + return self.a_b_sum.get_shape() + + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) + + def _get_event_shape(self): + return tensor_shape.scalar() + + def _sample_n(self, n, seed=None): + a = array_ops.ones_like(self.a_b_sum, dtype=self.dtype) * self.a + b = array_ops.ones_like(self.a_b_sum, dtype=self.dtype) * self.b + gamma1_sample = random_ops.random_gamma( + [n,], a, dtype=self.dtype, seed=seed) + gamma2_sample = random_ops.random_gamma( + [n,], b, dtype=self.dtype, seed=seed) + beta_sample = gamma1_sample / (gamma1_sample + gamma2_sample) + return beta_sample + + def _log_prob(self, x): + x = self._assert_valid_sample(x) + log_unnormalized_prob = ((self.a - 1.) * math_ops.log(x) + + (self.b - 1.) * math_ops.log(1. - x)) + log_normalization = (math_ops.lgamma(self.a) + + math_ops.lgamma(self.b) - + math_ops.lgamma(self.a_b_sum)) + return log_unnormalized_prob - log_normalization + + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) + + def _entropy(self): + return (math_ops.lgamma(self.a) - + (self.a - 1.) * math_ops.digamma(self.a) + + math_ops.lgamma(self.b) - + (self.b - 1.) * math_ops.digamma(self.b) - + math_ops.lgamma(self.a_b_sum) + + (self.a_b_sum - 2.) * math_ops.digamma(self.a_b_sum)) + + def _mean(self): + return self.a / self.a_b_sum + + def _variance(self): + return (self.a * self.b) / (self.a_b_sum**2. * (self.a_b_sum + 1.)) + + def _std(self): + return math_ops.sqrt(self.variance()) + + def _mode(self): + mode = (self.a - 1.)/ (self.a_b_sum - 2.) + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + math_ops.logical_and( + math_ops.greater(self.a, 1.), + math_ops.greater(self.b, 1.)), + mode, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), dtype=self.dtype), self.a, + message="Mode not defined for components of a <= 1."), + check_ops.assert_less( + array_ops.ones((), dtype=self.dtype), self.b, + message="Mode not defined for components of b <= 1."), + ], mode) + + def _assert_valid_sample(self, x): + """Check x for proper shape, values, then return tensor version.""" + if not self.validate_args: return x + return control_flow_ops.with_dependencies([ + check_ops.assert_positive( + x, + message="Negative events lie outside Beta distribution support."), + check_ops.assert_less( + x, array_ops.ones((), self.dtype), + message="Event>=1 lies outside Beta distribution support."), + ], x) - Args: - name: name to give to the op - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], name=name, dtype=dtypes.int32) +_prob_note = """ - def get_event_shape(self): - """`TensorShape` available at graph construction time. + Note that the argument `x` must be a non-negative floating point tensor + whose shape can be broadcast with `self.a` and `self.b`. For fixed leading + dimensions, the last dimension represents counts for the corresponding Beta + distribution in `self.a` and `self.b`. `x` is only legal if `0 < x < 1`. +""" - Same meaning as `event_shape`. May be only partially defined. +distribution_util.append_class_fun_doc(Beta.log_prob, doc_str=_prob_note) +distribution_util.append_class_fun_doc(Beta.prob, doc_str=_prob_note) - Returns: - event shape - """ - return self._get_event_shape - - def mean(self, name="mean"): - """Mean of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._a_b_sum]): - return self._a / self._a_b_sum - - def variance(self, name="variance"): - """Variance of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._b, self._a_b_sum]): - return (self._a * self._b) / ( - self._a_b_sum **2 * (self._a_b_sum + 1)) - - def std(self, name="std"): - """Standard deviation of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.sqrt(self.variance()) - - def mode(self, name="mode"): - """Mode of the distribution. +distribution_util.append_class_fun_doc(Beta.mode, doc_str=""" Note that the mode for the Beta distribution is only defined when `a > 1`, `b > 1`. This returns the mode when `a > 1` and `b > 1`, - and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception + and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception will be raised rather than returning `NaN`. - - Args: - name: The name for this op. - - Returns: - Mode of the Beta distribution. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._b, self._a_b_sum]): - a = self._a - b = self._b - a_b_sum = self._a_b_sum - one = constant_op.constant(1, self.dtype) - mode = (a - 1)/ (a_b_sum - 2) - - if self.allow_nan_stats: - return math_ops.select( - math_ops.logical_and( - math_ops.greater(a, 1), math_ops.greater(b, 1)), - mode, - (constant_op.constant(float("NaN"), dtype=self.dtype) * - array_ops.ones_like(a_b_sum, dtype=self.dtype))) - else: - return control_flow_ops.with_dependencies([ - check_ops.assert_less( - one, a, - message="mode not defined for components of a <= 1" - ), - check_ops.assert_less( - one, b, - message="mode not defined for components of b <= 1" - )], mode) - - def entropy(self, name="entropy"): - """Entropy of the distribution in nats.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._b, self._a_b_sum]): - a = self._a - b = self._b - a_b_sum = self._a_b_sum - - entropy = math_ops.lgamma(a) - (a - 1) * math_ops.digamma(a) - entropy += math_ops.lgamma(b) - (b - 1) * math_ops.digamma(b) - entropy += -math_ops.lgamma(a_b_sum) + ( - a_b_sum - 2) * math_ops.digamma(a_b_sum) - return entropy - - def cdf(self, x, name="cdf"): - """Cumulative distribution function.""" - # TODO(srvasude): Implement this once betainc op is checked in. - raise NotImplementedError("Beta cdf not implemented.") - - def log_cdf(self, x, name="log_cdf"): - """Log CDF.""" - raise NotImplementedError("Beta cdf not implemented.") - - def log_prob(self, x, name="log_prob"): - """`Log(P[counts])`, computed for every batch member. - - Args: - x: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents counts for the corresponding - Beta distribution in `self.a` and `self.b`. `x` is only legal if - 0 < x < 1. - name: Name to give this Op, defaults to "log_prob". - - Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. - """ - a = self._a - b = self._b - with ops.name_scope(self.name): - with ops.name_scope(name, values=[a, x]): - x = self._check_x(x) - - unnorm_pdf = (a - 1) * math_ops.log(x) + ( - b - 1) * math_ops.log(1 - x) - normalization_factor = -(math_ops.lgamma(a) + math_ops.lgamma(b) - - math_ops.lgamma(a + b)) - log_prob = unnorm_pdf + normalization_factor - - return log_prob - - def prob(self, x, name="prob"): - """`P[x]`, computed for every batch member. - - Args: - x: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents x for the corresponding Beta - distribution in `self.a` and `self.b`. `x` is only legal if is - between 0 and 1. - name: Name to give this Op, defaults to "pdf". - - Returns: - Probabilities for each record, shape `[N1,...,Nm]`. - """ - return super(Beta, self).prob(x, name=name) - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Beta Distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, n]): - a = array_ops.ones_like(self._a_b_sum, dtype=self.dtype) * self.a - b = array_ops.ones_like(self._a_b_sum, dtype=self.dtype) * self.b - n = ops.convert_to_tensor(n) - - gamma1_sample = random_ops.random_gamma( - [n,], a, dtype=self.dtype, seed=seed) - gamma2_sample = random_ops.random_gamma( - [n,], b, dtype=self.dtype, seed=seed) - - beta_sample = gamma1_sample / (gamma1_sample + gamma2_sample) - - n_val = tensor_util.constant_value(n) - final_shape = tensor_shape.vector(n_val).concatenate( - self._a_b_sum.get_shape()) - - beta_sample.set_shape(final_shape) - return beta_sample - - @property - def is_continuous(self): - return True - - @property - def is_reparameterized(self): - return False - - def _check_x(self, x): - """Check x for proper shape, values, then return tensor version.""" - x = ops.convert_to_tensor(x, name="x_before_deps") - dependencies = [ - check_ops.assert_positive(x), - check_ops.assert_less(x, constant_op.constant( - 1, self.dtype))] if self.validate_args else [] - return control_flow_ops.with_dependencies(dependencies, x) +""") diff --git a/tensorflow/contrib/distributions/python/ops/binomial.py b/tensorflow/contrib/distributions/python/ops/binomial.py index 697fb02495e1f125c9a46b9fba9aecd0912dafd1..fc799d30b40b9bb9544e66850bea691c74e9cf9a 100644 --- a/tensorflow/contrib/distributions/python/ops/binomial.py +++ b/tensorflow/contrib/distributions/python/ops/binomial.py @@ -125,93 +125,23 @@ class Binomial(distribution.Distribution): ``` """ - self._logits, self._p = distribution_util.get_logits_and_prob( name=name, logits=logits, p=p, validate_args=validate_args) - with ops.name_scope(name, values=[n]): with ops.control_dependencies([ check_ops.assert_non_negative( n, message="n has negative components."), distribution_util.assert_integer_form( - n, message="n has non-integer components." - )] if validate_args else []): - self._n = array_ops.identity(n, name="convert_n") - - self._name = name - self._validate_args = validate_args - self._allow_nan_stats = allow_nan_stats - - self._get_batch_shape = common_shapes.broadcast_shape( - self._n.get_shape(), self._p.get_shape()) - self._get_event_shape = tensor_shape.TensorShape([]) - - @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._p.dtype - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - return array_ops.shape(self._n + self._p) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], name=name, dtype=dtypes.int32) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._get_event_shape + n, message="n has non-integer components."), + ] if validate_args else []): + self._n = array_ops.identity(n, name="n") + super(Binomial, self).__init__( + dtype=self._p.dtype, + parameters={"n": self._n, "p": self._p, "logits": self._logits}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def n(self): @@ -228,101 +158,43 @@ class Binomial(distribution.Distribution): """Probability of success.""" return self._p - def mean(self, name="mean"): - """Mean of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p]): - return self._n * self._p - - def variance(self, name="variance"): - """Variance of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p]): - return self._n * self._p * (1 - self._p) - - def std(self, name="std"): - """Standard deviation of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p]): - return math_ops.sqrt(self.variance()) - - def mode(self, name="mode"): - """Mode of the distribution. - - Note that when `(n + 1) * p` is an integer, there are actually two modes. - Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return - only the larger of the two modes. - - Args: - name: The name for this op. - - Returns: - The mode of the Binomial distribution. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p]): - return math_ops.floor((self._n + 1) * self._p) - - def log_prob(self, counts, name="log_prob"): - """`Log(P[counts])`, computed for every batch member. - - For each batch member of counts `k`, `P[counts]` is the probability that - after sampling `n` draws from this Binomial distribution, the number of - successes is `k`. Note that different sequences of draws can result in the - same counts, thus the probability includes a combinatorial coefficient. + def _batch_shape(self): + return array_ops.shape(self._n + self._p) - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. - name: Name to give this Op, defaults to "log_prob". - - Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. - """ - n = self._n - p = self._p - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p, counts]): - counts = self._check_counts(counts) + def _get_batch_shape(self): + return common_shapes.broadcast_shape(self.n.get_shape(), + self.p.get_shape()) - prob_prob = counts * math_ops.log(p) + ( - n - counts) * math_ops.log(1 - p) + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) - combinations = math_ops.lgamma(n + 1) - math_ops.lgamma( - counts + 1) - math_ops.lgamma(n - counts + 1) - log_prob = prob_prob + combinations - return log_prob + def _get_event_shape(self): + return tensor_shape.scalar() - def prob(self, counts, name="prob"): - """`P[counts]`, computed for every batch member. + def _log_prob(self, counts): + counts = self._check_counts(counts) + prob_prob = (counts * math_ops.log(self.p) + + (self.n - counts) * math_ops.log(1. - self.p)) + combinations = (math_ops.lgamma(self.n + 1) - + math_ops.lgamma(counts + 1) - + math_ops.lgamma(self.n - counts + 1)) + log_prob = prob_prob + combinations + return log_prob + def _prob(self, counts): + return math_ops.exp(self._log_prob(counts)) - For each batch member of counts `k`, `P[counts]` is the probability that - after sampling `n` draws from this Binomial distribution, the number of - successes is `k`. Note that different sequences of draws can result in the - same counts, thus the probability includes a combinatorial coefficient. + def _mean(self): + return self._n * self._p - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. - name: Name to give this Op, defaults to "prob". - - Returns: - Probabilities for each record, shape `[N1,...,Nm]`. - """ - return super(Binomial, self).prob(counts, name=name) + def _variance(self): + return self._n * self._p * (1 - self._p) - @property - def is_continuous(self): - return False + def _std(self): + return math_ops.sqrt(self._variance()) - @property - def is_reparameterized(self): - return False + def _mode(self): + return math_ops.floor((self._n + 1) * self._p) def _check_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" @@ -336,3 +208,26 @@ class Binomial(distribution.Distribution): counts, self._n, message="counts are not less than or equal to n."), distribution_util.assert_integer_form( counts, message="counts have non-integer components.")], counts) + + +_prob_note = """ + + For each batch member of counts `k`, `P[counts]` is the probability that + after sampling `n` draws from this Binomial distribution, the number of + successes is `k`. Note that different sequences of draws can result in the + same counts, thus the probability includes a combinatorial coefficient. + + counts: Non-negative tensor with dtype `dtype` and whose shape can be + broadcast with `self.p` and `self.n`. `counts` is only legal if it is + less than or equal to `n` and its components are equal to integer + values. +""" +distribution_util.append_class_fun_doc(Binomial.log_prob, doc_str=_prob_note) +distribution_util.append_class_fun_doc(Binomial.prob, doc_str=_prob_note) + +distribution_util.append_class_fun_doc(Binomial.mode, doc_str=""" + + Note that when `(n + 1) * p` is an integer, there are actually two modes. + Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return + only the larger of the two modes. +""") diff --git a/tensorflow/contrib/distributions/python/ops/categorical.py b/tensorflow/contrib/distributions/python/ops/categorical.py index 4380637d496b43069df532f379787a44c83ef191..a84c31d1049b4bb1717d8fd880dac71ee3ece337 100644 --- a/tensorflow/contrib/distributions/python/ops/categorical.py +++ b/tensorflow/contrib/distributions/python/ops/categorical.py @@ -19,10 +19,10 @@ from __future__ import division from __future__ import print_function from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import nn_ops @@ -58,66 +58,45 @@ class Categorical(distribution.Distribution): undefined statistics will return NaN for this statistic. name: A name for this distribution (optional). """ - self._allow_nan_stats = allow_nan_stats - self._name = name - self._dtype = dtype - self._validate_args = validate_args with ops.name_scope(name, values=[logits]): self._logits = ops.convert_to_tensor(logits, name="logits") - logits_shape = array_ops.shape(self._logits, name="logits_shape") - static_logits_shape = self._logits.get_shape().with_rank_at_least(1) - static_logits_rank = static_logits_shape.ndims - if static_logits_rank is not None: + + logits_shape_static = self._logits.get_shape().with_rank_at_least(1) + if logits_shape_static.ndims is not None: self._batch_rank = ops.convert_to_tensor( - static_logits_rank - 1, dtype=dtypes.int32, + logits_shape_static.ndims - 1, + dtype=dtypes.int32, name="batch_rank") else: - self._batch_rank = array_ops.rank(self._logits) - 1 + with ops.name_scope(name="batch_rank"): + self._batch_rank = array_ops.rank(self._logits) - 1 - if static_logits_shape[-1].value is not None: + logits_shape = array_ops.shape(self._logits, name="logits_shape") + if logits_shape_static[-1].value is not None: self._num_classes = ops.convert_to_tensor( - static_logits_shape[-1].value, - dtype=dtypes.int32, name="num_classes") + logits_shape_static[-1].value, + dtype=dtypes.int32, + name="num_classes") else: - self._num_classes = array_ops.gather(logits_shape, self._batch_rank) - - self._batch_shape = logits_shape[:-1] - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._dtype - - @property - def is_reparameterized(self): - return False - - def batch_shape(self, name="batch_shape"): - with ops.name_scope(self.name): - return array_ops.identity(self._batch_shape, name=name) - - def get_batch_shape(self): - return self.logits.get_shape()[:-1] - - def event_shape(self, name="event_shape"): - with ops.name_scope(self.name): - return array_ops.constant([], dtype=self._batch_shape.dtype, name=name) - - def get_event_shape(self): - return tensor_shape.scalar() + self._num_classes = array_ops.gather(logits_shape, + self._batch_rank, + name="num_classes") + + if logits_shape_static[:-1].is_fully_defined(): + self._batch_shape_val = constant_op.constant( + logits_shape_static[:-1].as_list(), + dtype=dtypes.int32, + name="batch_shape") + else: + with ops.name_scope(name="batch_shape"): + self._batch_shape_val = logits_shape[:-1] + super(Categorical, self).__init__( + dtype=dtype, + parameters={"logits": self._logits, "num_classes": self._num_classes}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def num_classes(self): @@ -128,89 +107,55 @@ class Categorical(distribution.Distribution): def logits(self): return self._logits - def log_prob(self, k, name="log_prob"): - """Log-probability of class `k`. - - Args: - k: `int32` or `int64` Tensor. Must be broadcastable with a `batch_shape` - `Tensor`. - name: A name for this operation (optional). - - Returns: - The log-probabilities of the classes indexed by `k` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[k, self.logits]): - k = ops.convert_to_tensor(k, name="k") - - logits = self.logits * array_ops.ones_like( - array_ops.expand_dims(k, -1), - dtype=self.logits.dtype) - k *= array_ops.ones( - array_ops.slice( - array_ops.shape(logits), [0], [array_ops.rank(logits) - 1]), - dtype=k.dtype) - k.set_shape(tensor_shape.TensorShape(logits.get_shape()[:-1])) - - return -nn_ops.sparse_softmax_cross_entropy_with_logits(logits, k) - - def prob(self, k, name="prob"): - """Probability of class `k`. + def _batch_shape(self): + # Use identity to inherit callers "name". + return array_ops.identity(self._batch_shape_val) - Args: - k: `int32` or `int64` Tensor. Must be broadcastable with logits. - name: A name for this operation (optional). - - Returns: - The probabilities of the classes indexed by `k` - """ - return super(Categorical, self).prob(k, name) + def _get_batch_shape(self): + return self.logits.get_shape()[:-1] - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Categorical distribution. + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) - Args: - n: 0-D. Number of independent samples to draw for each distribution. - seed: Random seed (optional). - name: A name for this operation (optional). - - Returns: - An `int64` `Tensor` with shape `[n, batch_shape, event_shape]` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.logits, n]): - n = ops.convert_to_tensor(n, name="n") - logits_2d = array_ops.reshape( - self.logits, array_ops.pack([-1, self.num_classes])) - samples = random_ops.multinomial(logits_2d, n, seed=seed) - samples = math_ops.cast(samples, self._dtype) - ret = array_ops.reshape( - array_ops.transpose(samples), - array_ops.concat(0, ([n], self.batch_shape()))) - ret.set_shape(tensor_shape.vector(tensor_util.constant_value(n)) - .concatenate(self.get_batch_shape())) - return ret - - def entropy(self, name="sample"): - with ops.name_scope(self.name): - with ops.name_scope(name): - logits_2d = array_ops.reshape( - self.logits, array_ops.pack([-1, self.num_classes])) - histogram_2d = nn_ops.softmax(logits_2d) - ret = array_ops.reshape( - nn_ops.softmax_cross_entropy_with_logits(logits_2d, histogram_2d), - self.batch_shape()) - ret.set_shape(self.get_batch_shape()) - return ret - - def mode(self, name="mode"): - with ops.name_scope(self.name): - with ops.name_scope(name): - ret = math_ops.argmax(self.logits, dimension=self._batch_rank) - ret = math_ops.cast(ret, self._dtype) - ret.set_shape(self.get_batch_shape()) - return ret + def _get_event_shape(self): + return tensor_shape.scalar() - @property - def is_continuous(self): - return False + def _sample_n(self, n, seed=None): + logits_2d = array_ops.reshape( + self.logits, array_ops.pack([-1, self.num_classes])) + samples = random_ops.multinomial(logits_2d, n, seed=seed) + samples = math_ops.cast(samples, self.dtype) + ret = array_ops.reshape( + array_ops.transpose(samples), + array_ops.concat(0, ([n], self.batch_shape()))) + return ret + + def _log_prob(self, k): + k = ops.convert_to_tensor(k, name="k") + logits = self.logits * array_ops.ones_like( + array_ops.expand_dims(k, -1), + dtype=self.logits.dtype) + shape = array_ops.slice(array_ops.shape(logits), [0], + [array_ops.rank(logits) - 1]) + k *= array_ops.ones(shape, dtype=k.dtype) + k.set_shape(tensor_shape.TensorShape(logits.get_shape()[:-1])) + return -nn_ops.sparse_softmax_cross_entropy_with_logits(logits, k) + + def _prob(self, k): + return math_ops.exp(self._log_prob(k)) + + def _entropy(self): + logits_2d = array_ops.reshape( + self.logits, array_ops.pack([-1, self.num_classes])) + histogram_2d = nn_ops.softmax(logits_2d) + ret = array_ops.reshape( + nn_ops.softmax_cross_entropy_with_logits(logits_2d, histogram_2d), + self.batch_shape()) + ret.set_shape(self.get_batch_shape()) + return ret + + def _mode(self): + ret = math_ops.argmax(self.logits, dimension=self._batch_rank) + ret = math_ops.cast(ret, self.dtype) + ret.set_shape(self.get_batch_shape()) + return ret diff --git a/tensorflow/contrib/distributions/python/ops/chi2.py b/tensorflow/contrib/distributions/python/ops/chi2.py index 8abb906c8d097de284a9ddd1fcc9084b9e0acfed..bb1771c39010c7b0e748bbf863492a09b0a01d95 100644 --- a/tensorflow/contrib/distributions/python/ops/chi2.py +++ b/tensorflow/contrib/distributions/python/ops/chi2.py @@ -58,9 +58,9 @@ class Chi2(gamma.Gamma): # allow_nan_stats=False # through to the parent class results in unnecessary asserts. with ops.name_scope(name, values=[df]): - df = ops.convert_to_tensor(df) + df = ops.convert_to_tensor(df, name="df") self._df = df - super(Chi2, self).__init__(alpha=df / 2, + super(Chi2, self).__init__(alpha=0.5 * df, beta=constant_op.constant(0.5, dtype=df.dtype), validate_args=validate_args, allow_nan_stats=allow_nan_stats) diff --git a/tensorflow/contrib/distributions/python/ops/dirichlet.py b/tensorflow/contrib/distributions/python/ops/dirichlet.py index 7081053db00e7a37a495b15209d251bfe6f3325f..899867fe7f5f9e2c167cfd6de6f9eff0547d3873 100644 --- a/tensorflow/contrib/distributions/python/ops/dirichlet.py +++ b/tensorflow/contrib/distributions/python/ops/dirichlet.py @@ -17,12 +17,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import numpy as np + from tensorflow.contrib.distributions.python.ops import distribution from tensorflow.contrib.distributions.python.ops import distribution_util -from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops @@ -129,25 +128,21 @@ class Dirichlet(distribution.Distribution): """ with ops.name_scope(name, values=[alpha]): - alpha = ops.convert_to_tensor(alpha, name="alpha_before_deps") + alpha = ops.convert_to_tensor(alpha, name="alpha") with ops.control_dependencies([ - check_ops.assert_positive(alpha), check_ops.assert_rank_at_least( - alpha, 1) + check_ops.assert_positive(alpha), + check_ops.assert_rank_at_least(alpha, 1) ] if validate_args else []): - alpha = array_ops.identity(alpha, name="alpha") - - self._alpha = alpha - self._name = name - - # Used for mean/mode/variance/entropy computations - self._alpha_0 = math_ops.reduce_sum(alpha, - reduction_indices=[-1], - keep_dims=False) - - self._get_batch_shape = self._alpha_0.get_shape() - self._get_event_shape = self._alpha.get_shape().with_rank_at_least(1)[-1:] - self._validate_args = validate_args - self._allow_nan_stats = allow_nan_stats + self._alpha = array_ops.identity(alpha, name="alpha") + self._alpha_sum = math_ops.reduce_sum(alpha, + reduction_indices=[-1], + keep_dims=False) + super(Dirichlet, self).__init__( + dtype=self._alpha.dtype, + parameters={"alpha": self._alpha, "alpha_sum": self._alpha_sum}, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def alpha(self): @@ -155,240 +150,108 @@ class Dirichlet(distribution.Distribution): return self._alpha @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._alpha.dtype - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha]): - return array_ops.shape(self._alpha_0) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha]): - return array_ops.gather(array_ops.shape(self._alpha), - [array_ops.rank(self._alpha) - 1]) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._get_event_shape - - def mean(self, name="mean"): - """Mean of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._alpha_0]): - return self._alpha / array_ops.expand_dims(self._alpha_0, -1) - - def variance(self, name="variance"): - """Variance of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._alpha_0]): - alpha = array_ops.expand_dims(self._alpha, -1) - alpha_0 = array_ops.expand_dims(self._alpha_0, -1) - - expanded_alpha_0 = array_ops.expand_dims(alpha_0, -1) - - variance = -math_ops.batch_matmul(alpha, alpha, adj_y=True) / ( - expanded_alpha_0 ** 2 * (expanded_alpha_0 + 1)) - diagonal = self._alpha / (alpha_0 * (alpha_0 + 1)) - variance += array_ops.batch_matrix_diag(diagonal) - return variance - - def std(self, name="std"): - """Standard deviation of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.sqrt(self.variance()) - - def mode(self, name="mode"): - """Mode of the distribution. - - Note that the mode for the Beta distribution is only defined - when `alpha > 1`. This returns the mode when `alpha > 1`, - and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception - will be raised rather than returning `NaN`. - - Args: - name: The name for this op. - - Returns: - Mode of the Dirichlet distribution. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._alpha_0]): - one = constant_op.constant(1, self.dtype) - mode = (self._alpha - 1)/ ( - array_ops.expand_dims(self._alpha_0, -1) - math_ops.cast( - self.event_shape()[0], self.dtype)) - - if self.allow_nan_stats: - return math_ops.select( - math_ops.greater(self._alpha, 1), - mode, - (constant_op.constant(float("NaN"), dtype=self.dtype) * - array_ops.ones_like(self._alpha, dtype=self.dtype))) - else: - return control_flow_ops.with_dependencies([ - check_ops.assert_less( - one, self._alpha, - message="mode not defined for components of alpha <= 1") - ], mode) - - def entropy(self, name="entropy"): - """Entropy of the distribution in nats.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._alpha_0]): - alpha = self._alpha - alpha_0 = self._alpha_0 - - entropy = special_math_ops.lbeta(alpha) - entropy += (alpha_0 - math_ops.cast( - self.event_shape()[0], self.dtype)) * math_ops.digamma( - alpha_0) - entropy += -math_ops.reduce_sum( - (alpha - 1) * math_ops.digamma(alpha), - reduction_indices=[-1], - keep_dims=False) - return entropy - - def cdf(self, x, name="cdf"): - """Cumulative distribution function.""" - raise NotImplementedError("Dirichlet does not have a well-defined cdf.") - - def log_cdf(self, x, name="log_cdf"): - """Log CDF.""" - raise NotImplementedError("Dirichlet does not have a well-defined cdf.") - - def log_prob(self, x, name="log_prob"): - """`Log(P[counts])`, computed for every batch member. - - Args: - x: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet distribution - in `self.alpha`. `x` is only legal if it sums up to one. - name: Name to give this Op, defaults to "log_prob". - - Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. - """ - alpha = self._alpha - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, x]): - x = self._check_x(x) - - unnorm_prob = (alpha - 1) * math_ops.log(x) - log_prob = math_ops.reduce_sum( - unnorm_prob, reduction_indices=[-1], - keep_dims=False) - special_math_ops.lbeta(alpha) - - return log_prob - - def prob(self, x, name="prob"): - """`P[x]`, computed for every batch member. - - Args: - x: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents x for the corresponding Dirichlet distribution in - `self.alpha` and `self.beta`. `x` is only legal if it sums up to one. - name: Name to give this Op, defaults to "prob". - - Returns: - Probabilities for each record, shape `[N1,...,Nm]`. - """ - return super(Dirichlet, self).prob(x, name=name) - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.alpha, n]): - gamma_sample = random_ops.random_gamma( - [n,], self.alpha, dtype=self.dtype, seed=seed) - n_val = tensor_util.constant_value(n) - final_shape = tensor_shape.vector(n_val).concatenate( - self.alpha.get_shape()) - - gamma_sample.set_shape(final_shape) - return gamma_sample / math_ops.reduce_sum( - gamma_sample, reduction_indices=[-1], keep_dims=True) - - @property - def is_continuous(self): - return True - - @property - def is_reparameterized(self): - return False - - def _check_x(self, x): - """Check x for proper shape, values, then return tensor version.""" - x = ops.convert_to_tensor(x, name="x_before_deps") - candidate_one = math_ops.reduce_sum(x, reduction_indices=[-1]) - one = constant_op.constant(1., self.dtype) - dependencies = [check_ops.assert_positive(x), check_ops.assert_less( - x, one, message="x has components greater than or equal to 1"), - distribution_util.assert_close(one, candidate_one) - ] if self.validate_args else [] - return control_flow_ops.with_dependencies(dependencies, x) + def alpha_sum(self): + """Sum of shape parameter.""" + return self._alpha_sum + + def _batch_shape(self): + return array_ops.shape(self.alpha_sum) + + def _get_batch_shape(self): + return self.alpha_sum.get_shape() + + def _event_shape(self): + return array_ops.gather(array_ops.shape(self.alpha), + [array_ops.rank(self.alpha) - 1]) + + def _get_event_shape(self): + return self.alpha.get_shape().with_rank_at_least(1)[-1:] + + def _sample_n(self, n, seed=None): + gamma_sample = random_ops.random_gamma( + [n,], self.alpha, dtype=self.dtype, seed=seed) + return gamma_sample / math_ops.reduce_sum( + gamma_sample, reduction_indices=[-1], keep_dims=True) + + def _log_prob(self, x): + x = ops.convert_to_tensor(x, name="x") + x = self._assert_valid_sample(x) + unnorm_prob = (self.alpha - 1.) * math_ops.log(x) + log_prob = math_ops.reduce_sum( + unnorm_prob, reduction_indices=[-1], + keep_dims=False) - special_math_ops.lbeta(self.alpha) + return log_prob + + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) + + def _entropy(self): + entropy = special_math_ops.lbeta(self.alpha) + entropy += math_ops.digamma(self.alpha_sum) * ( + self.alpha_sum - math_ops.cast(self.event_shape()[0], self.dtype)) + entropy += -math_ops.reduce_sum( + (self.alpha - 1.) * math_ops.digamma(self.alpha), + reduction_indices=[-1], + keep_dims=False) + return entropy + + def _mean(self): + return self.alpha / array_ops.expand_dims(self.alpha_sum, -1) + + def _variance(self): + scale = self.alpha_sum * math_ops.sqrt(1. + self.alpha_sum) + alpha = self.alpha / scale + outer_prod = -math_ops.batch_matmul( + array_ops.expand_dims(alpha, dim=-1), # column + array_ops.expand_dims(alpha, dim=-2)) # row + return array_ops.batch_matrix_set_diag( + outer_prod, alpha * (self.alpha_sum / scale - alpha)) + + def _std(self): + return math_ops.sqrt(self._variance()) + + def _mode(self): + mode = ((self.alpha - 1.) / + (array_ops.expand_dims(self.alpha_sum, dim=-1) - + math_ops.cast(self.event_shape()[0], self.dtype))) + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + shape = array_ops.concat(0, (self.batch_shape(), self.event_shape())) + return math_ops.select( + math_ops.greater(self.alpha, 1.), + mode, + array_ops.fill(shape, nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), dtype=self.dtype), self.alpha, + message="mode not defined for components of alpha <= 1") + ], mode) + + def _assert_valid_sample(self, x): + if not self.validate_args: return x + return control_flow_ops.with_dependencies([ + check_ops.assert_positive(x), + distribution_util.assert_close( + array_ops.ones((), dtype=self.dtype), + math_ops.reduce_sum(x, reduction_indices=[-1])), + ], x) + + +_prob_note = """ + + Note that the input must be a non-negative tensor with dtype `dtype` and whose + shape can be broadcast with `self.alpha`. For fixed leading dimensions, the + last dimension represents counts for the corresponding Dirichlet distribution + in `self.alpha`. `x` is only legal if it sums up to one. +""" +distribution_util.append_class_fun_doc(Dirichlet.log_prob, doc_str=_prob_note) +distribution_util.append_class_fun_doc(Dirichlet.prob, doc_str=_prob_note) + +distribution_util.append_class_fun_doc(Dirichlet.mode, doc_str=""" + + Note that the mode for the Dirichlet distribution is only defined + when `alpha > 1`. This returns the mode when `alpha > 1`, + and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception + will be raised rather than returning `NaN`. +""") diff --git a/tensorflow/contrib/distributions/python/ops/dirichlet_multinomial.py b/tensorflow/contrib/distributions/python/ops/dirichlet_multinomial.py index d6fc8522d09153c1110ffb9e7bfae913ac488613..45e31e5580b95f625153d7d07007c8ee98e24ea0 100644 --- a/tensorflow/contrib/distributions/python/ops/dirichlet_multinomial.py +++ b/tensorflow/contrib/distributions/python/ops/dirichlet_multinomial.py @@ -139,9 +139,6 @@ class DirichletMultinomial(distribution.Distribution): ``` """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - self._name = name with ops.name_scope(name, values=[n, alpha]): # Broadcasting works because: # * The broadcasting convention is to prepend dimensions of size [1], and @@ -152,16 +149,19 @@ class DirichletMultinomial(distribution.Distribution): # explicitivity. # * All calls involving `counts` eventually require a broadcast between # `counts` and alpha. - self._alpha = self._check_alpha(alpha) - self._n = self._check_n(n) - + self._alpha = self._assert_valid_alpha(alpha, validate_args) + self._n = self._assert_valid_n(n, validate_args) self._alpha_sum = math_ops.reduce_sum( self._alpha, reduction_indices=[-1], keep_dims=False) - - self._get_batch_shape = self._alpha_sum.get_shape() - - # event shape depends only on alpha, not "n". - self._get_event_shape = self._alpha.get_shape().with_rank_at_least(1)[-1:] + super(DirichletMultinomial, self).__init__( + dtype=self._alpha.dtype, + parameters={"alpha": self._alpha, + "alpha_sum": self._alpha_sum, + "n": self._n}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def n(self): @@ -174,195 +174,57 @@ class DirichletMultinomial(distribution.Distribution): return self._alpha @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._alpha.dtype - - def mean(self, name="mean"): - """Class means for every batch member.""" - alpha = self._alpha - alpha_sum = self._alpha_sum - n = self._n - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, alpha_sum, n]): - mean_no_n = alpha / array_ops.expand_dims(alpha_sum, -1) - return array_ops.expand_dims(n, -1) * mean_no_n - - def variance(self, name="mean"): - """Class variances for every batch member. - - The variance for each batch member is defined as the following: - - ``` - Var(X_j) = n * alpha_j / alpha_0 * (1 - alpha_j / alpha_0) * - (n + alpha_0) / (1 + alpha_0) - ``` - - where `alpha_0 = sum_j alpha_j`. - - The covariance between elements in a batch is defined as: - - ``` - Cov(X_i, X_j) = -n * alpha_i * alpha_j / alpha_0 ** 2 * - (n + alpha_0) / (1 + alpha_0) - ``` - - Args: - name: The name for this op. - - Returns: - A `Tensor` representing the variances for each batch member. - """ - alpha = self._alpha - alpha_sum = self._alpha_sum - n = self._n - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, alpha_sum, n]): - expanded_alpha_sum = array_ops.expand_dims(alpha_sum, -1) - shared_factor = n * (expanded_alpha_sum + n) / ( - expanded_alpha_sum + 1) * array_ops.ones_like(alpha) - - mean_no_n = alpha / expanded_alpha_sum - expanded_mean_no_n = array_ops.expand_dims(mean_no_n, -1) - variance = -math_ops.batch_matmul( - expanded_mean_no_n, expanded_mean_no_n, adj_y=True) - variance += array_ops.batch_matrix_diag(mean_no_n) - variance *= array_ops.expand_dims(shared_factor, -1) - return variance - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha_sum]): - return array_ops.shape(self._alpha_sum) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha]): - return array_ops.reverse(array_ops.shape(self._alpha), [True])[0] - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._get_event_shape - - def cdf(self, x, name="cdf"): - raise NotImplementedError( - "DirichletMultinomial does not have a well-defined cdf.") - - def log_cdf(self, x, name="log_cdf"): - raise NotImplementedError( - "DirichletMultinomial does not have a well-defined cdf.") - - def log_prob(self, counts, name="log_prob"): - """`Log(P[counts])`, computed for every batch member. - - For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability - that after sampling `n` draws from this Dirichlet Multinomial - distribution, the number of draws falling in class `j` is `n_j`. Note that - different sequences of draws can result in the same counts, thus the - probability includes a combinatorial coefficient. - - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. - name: Name to give this Op, defaults to "log_prob". - - Returns: - Log probabilities for each record, shape `[N1,...,Nn]`. - """ - n = self._n - alpha = self._alpha - with ops.name_scope(self.name): - with ops.name_scope(name, values=[n, alpha, counts]): - counts = self._check_counts(counts) - - ordered_prob = (special_math_ops.lbeta(alpha + counts) - - special_math_ops.lbeta(alpha)) - log_prob = ordered_prob + distribution_util.log_combinations( - n, counts) - return log_prob - - def prob(self, counts, name="prob"): - """`P[counts]`, computed for every batch member. - - For each batch of counts `[c_1,...,c_k]`, `P[counts]` is the probability - that after sampling `sum_j c_j` draws from this Dirichlet Multinomial - distribution, the number of draws falling in class `j` is `c_j`. Note that - different sequences of draws can result in the same counts, thus the - probability includes a combinatorial coefficient. - - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. - name: Name to give this Op, defaults to "prob". - - Returns: - Probabilities for each record, shape `[N1,...,Nn]`. - """ - return super(DirichletMultinomial, self).prob(counts, name=name) - - def _check_counts(self, counts): + def alpha_sum(self): + """Summation of alpha parameter.""" + return self._alpha_sum + + def _batch_shape(self): + return array_ops.shape(self.alpha_sum) + + def _get_batch_shape(self): + return self.alpha_sum.get_shape() + + def _event_shape(self): + return array_ops.reverse(array_ops.shape(self.alpha), [True])[0] + + def _get_event_shape(self): + # Event shape depends only on alpha, not "n". + return self.alpha.get_shape().with_rank_at_least(1)[-1:] + + def _log_prob(self, counts): + counts = self._assert_valid_counts(counts) + ordered_prob = (special_math_ops.lbeta(self.alpha + counts) - + special_math_ops.lbeta(self.alpha)) + log_prob = ordered_prob + distribution_util.log_combinations( + self.n, counts) + return log_prob + + def _prob(self, counts): + return math_ops.exp(self._log_prob(counts)) + + def _mean(self): + normalized_alpha = self.alpha / array_ops.expand_dims(self.alpha_sum, -1) + return array_ops.expand_dims(self.n, -1) * normalized_alpha + + def _variance(self): + alpha_sum = array_ops.expand_dims(self.alpha_sum, -1) + normalized_alpha = self.alpha / alpha_sum + variance = -math_ops.batch_matmul( + array_ops.expand_dims(normalized_alpha, -1), + array_ops.expand_dims(normalized_alpha, -2)) + variance = array_ops.batch_matrix_set_diag( + variance, normalized_alpha * (1. - normalized_alpha)) + shared_factor = (self.n * (alpha_sum + self.n) / + (alpha_sum + 1) * array_ops.ones_like(self.alpha)) + variance *= array_ops.expand_dims(shared_factor, -1) + return variance + + def _assert_valid_counts(self, counts): """Check counts for proper shape, values, then return tensor version.""" counts = ops.convert_to_tensor(counts, name="counts") if not self.validate_args: return counts candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) - return control_flow_ops.with_dependencies([ check_ops.assert_non_negative(counts), check_ops.assert_equal( @@ -370,26 +232,59 @@ class DirichletMultinomial(distribution.Distribution): message="counts do not sum to n"), distribution_util.assert_integer_form(counts)], counts) - def _check_alpha(self, alpha): + def _assert_valid_alpha(self, alpha, validate_args): alpha = ops.convert_to_tensor(alpha, name="alpha") - if not self.validate_args: + if not validate_args: return alpha return control_flow_ops.with_dependencies( [check_ops.assert_rank_at_least(alpha, 1), check_ops.assert_positive(alpha)], alpha) - def _check_n(self, n): + def _assert_valid_n(self, n, validate_args): n = ops.convert_to_tensor(n, name="n") - if not self.validate_args: + if not validate_args: return n return control_flow_ops.with_dependencies( [check_ops.assert_non_negative(n), distribution_util.assert_integer_form(n)], n) - @property - def is_continuous(self): - return False - @property - def is_reparameterized(self): - return False +_prob_note = """ + + For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability + that after sampling `n` draws from this Dirichlet Multinomial + distribution, the number of draws falling in class `j` is `n_j`. Note that + different sequences of draws can result in the same counts, thus the + probability includes a combinatorial coefficient. + + Note that input, "counts", must be a non-negative tensor with dtype `dtype` + and whose shape can be broadcast with `self.alpha`. For fixed leading + dimensions, the last dimension represents counts for the corresponding + Dirichlet Multinomial distribution in `self.alpha`. `counts` is only legal if + it sums up to `n` and its components are equal to integer values. +""" +distribution_util.append_class_fun_doc(DirichletMultinomial.log_prob, + doc_str=_prob_note) +distribution_util.append_class_fun_doc(DirichletMultinomial.prob, + doc_str=_prob_note) + +distribution_util.append_class_fun_doc(DirichletMultinomial.variance, + doc_str=""" + + The variance for each batch member is defined as the following: + + ``` + Var(X_j) = n * alpha_j / alpha_0 * (1 - alpha_j / alpha_0) * + (n + alpha_0) / (1 + alpha_0) + ``` + + where `alpha_0 = sum_j alpha_j`. + + The covariance between elements in a batch is defined as: + + ``` + Cov(X_i, X_j) = -n * alpha_i * alpha_j / alpha_0 ** 2 * + (n + alpha_0) / (1 + alpha_0) + ``` + +""") diff --git a/tensorflow/contrib/distributions/python/ops/distribution.py b/tensorflow/contrib/distributions/python/ops/distribution.py index 63be0ad79b45aa32daa41317109027f3dcb06c16..30c79bc75e60f6e18a034a19f7b3f02941fc5634 100644 --- a/tensorflow/contrib/distributions/python/ops/distribution.py +++ b/tensorflow/contrib/distributions/python/ops/distribution.py @@ -19,8 +19,11 @@ from __future__ import division from __future__ import print_function import abc +import contextlib +import numpy as np import six +from tensorflow.contrib.distributions.python.ops import distribution_util from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape @@ -38,88 +41,37 @@ class BaseDistribution(object): that want to fulfill a simpler distribution contract. """ - @abc.abstractproperty - def name(self): - """Name to prepend to all ops.""" - # return self._name. - pass - @abc.abstractmethod - def prob(self, value, name="prob"): - """Probability density/mass function.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[value]): - value = ops.convert_to_tensor(value) - return math_ops.exp(self.log_prob(value)) + def sample_n(self, n, seed=None, name="sample"): + # See `Distribution.sample_n` for docstring. + pass @abc.abstractmethod def log_prob(self, value, name="log_prob"): - """Log of the probability density/mass function.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[value]): - value = ops.convert_to_tensor(value) - return math_ops.log(self.prob(value)) - - def sample_n(self, n, seed=None, name="sample_n"): - """Generate `n` samples. - - Args: - n: scalar. Number of samples to draw. - seed: Python integer seed for RNG - name: name to give to the op. - - Returns: - samples: a `Tensor` with a prepended dimension (n,). - """ - raise NotImplementedError("sample_n not implemented") - - def sample(self, sample_shape=(), seed=None, name="sample"): - """Generate samples of the specified shape. - - Note that a call to `sample()` without arguments will generate a single - sample. - - Args: - sample_shape: Rank 1 `int32` `Tensor`. Shape of the generated samples. - seed: Python integer seed for RNG - name: name to give to the op. - - Returns: - samples: a `Tensor` with prepended dimensions `sample_shape`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[sample_shape]): - sample_shape = ops.convert_to_tensor(sample_shape, - dtype=dtypes.int32, - name="sample_shape") - total = math_ops.reduce_prod(sample_shape) - samples = self.sample_n(total, seed) - output_shape = array_ops.concat(0, [sample_shape, array_ops.slice( - array_ops.shape(samples), [1], [-1])]) - output = array_ops.reshape(samples, output_shape, name=name) - output.set_shape(tensor_util.constant_value_as_shape( - sample_shape).concatenate(samples.get_shape()[1:])) - return output + # See `Distribution.log_prob` for docstring. + pass -@six.add_metaclass(abc.ABCMeta) class Distribution(BaseDistribution): - """Fully-featured abstract base class for probability distributions. + """A generic probability distribution base class. + + `Distribution` is a base class for constructing and organizing properties + (e.g., mean, variance) of random variables (e.g, Bernoulli, Gaussian). - This class defines the API for probability distributions. Users will only ever - instantiate subclasses of `Distribution`. + ### Subclassing - ### API + Subclasess are expected to implement a leading-underscore version of the + same-named function. The argument signature should be identical except for + the omission of `name="..."`. For example, to enable `log_prob(value, + name="log_prob")` a subclass should implement `_log_prob(value)`. - The key methods for probability distributions are defined here. + Subclasses can rewrite/append to public-level docstrings. For example, - To keep ops generated by the distribution tied together by name, subclasses - should override `name` and use it to prepend names of ops in other methods - (see `cdf` for an example). + ```python + Subclass.prob.__func__.__doc__ += "Some other details." + ``` - Subclasses that wish to support `cdf` and `log_cdf` can override `log_cdf` - and use the base class's implementation for `cdf`, or vice versa. The same - goes for `log_prob` and `prob`. + would add the string "Some other details." to the `prob` function docstring. ### Broadcasting, batching, and shapes @@ -209,6 +161,42 @@ class Distribution(BaseDistribution): """ + def __init__(self, + dtype=None, + parameters=None, + is_continuous=True, + is_reparameterized=False, + validate_args=True, + allow_nan_stats=False, + name=None): + """Constructs the `Distribution`. + + Args: + dtype: The type of the event samples. `None` implies no type-enforcement. + parameters: Python dictionary of parameters used by this `Distribution`. + is_continuous: Python boolean, default `True`. If `True` this + `Distribution` is continuous over its supported domain. + is_reparameterized: Python boolean, default `False`. If `True` this + `Distribution` can be reparameterized in terms of some standard + distribution with a function whose Jacobian is constant for the support + of the standard distribution. + validate_args: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. + allow_nan_stats: Python boolean, default `False`. If `False`, raise an + exception if a statistic (e.g., mean, mode) is undefined for any batch + member. If True, batch members with valid parameters leading to + undefined statistics will return `NaN` for this statistic. + name: A name for this distribution (optional). + """ + self._name = name or type(self).__name__ + self._dtype = dtype + self._parameters = parameters or {} + self._is_continuous = is_continuous + self._is_reparameterized = is_reparameterized + self._allow_nan_stats = allow_nan_stats + self._validate_args = validate_args + @classmethod def param_shapes(cls, sample_shape, name="DistributionParamShapes"): """Shapes of parameters given the desired shape of a call to `sample()`. @@ -276,8 +264,8 @@ class Distribution(BaseDistribution): # shapes has a Tensor shape for mu and sigma # shapes == { - # 'mu': tf.constant([batch_size, 10]), - # 'sigma': tf.constant([batch_size, 10]), + # "mu": tf.constant([batch_size, 10]), + # "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -348,70 +336,54 @@ class Distribution(BaseDistribution): """ raise NotImplementedError("_safe_transforms is not implemented") - @abc.abstractproperty - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - # return self._allow_nan_stats - # Notes: - # - # When it makes sense, return +- infinity for statistics. E.g. the variance - # of a Cauchy distribution would be +infinity. However, sometimes the - # statistic is undefined (e.g. if a distribution's pdf does not achieve a - # maximum within the support of the distribution, mode is undefined). - # If the mean is undefined, then by definition the variance is undefined. - # E.g. the mean for Student's T for df = 1 is undefined (no clear way to say - # it is either + or - infinity), so the variance = E[(X - mean)^2] is also - # undefined. - # - # Distributions should be initialized with a kwarg "allow_nan_stats" with - # the following docstring (refer to above docstring note on undefined - # statistics for more detail). - # allow_nan_stats: Boolean, default False. If False, raise an exception if - # a statistic (e.g. mean/mode/etc...) is undefined for any batch member. - # If True, batch members with valid parameters leading to undefined - # statistics will return NaN for this statistic. - pass - - @abc.abstractproperty - def validate_args(self): - """Boolean describing behavior on invalid input.""" - # return self._validate_args. - pass + @property + def name(self): + """Name prepended to all ops created by this `Distribution`.""" + return self._name - @abc.abstractproperty + @property def dtype(self): - """dtype of samples from this distribution.""" - # return self._dtype - pass + """The `DType` of `Tensor`s handled by this `Distribution`.""" + return self._dtype - @abc.abstractmethod - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. + @property + def parameters(self): + """Dictionary of parameters used by this `Distribution`.""" + return self._parameters - Args: - name: name to give to the op + @property + def is_continuous(self): + return self._is_continuous - Returns: - `Tensor` `event_shape` - """ - # For scalar distributions, constant([], int32) - # with ops.name_scope(self.name): - # with ops.name_scope(name, values=[tensor_arguments]): - # Your code here - pass + @property + def is_reparameterized(self): + return self._is_reparameterized - @abc.abstractmethod - def get_event_shape(self): - """`TensorShape` available at graph construction time. + @property + def allow_nan_stats(self): + """Python boolean describing behavior when a stat is undefined. - Same meaning as `event_shape`. May be only partially defined. + Stats return +/- infinity when it makes sense. E.g., the variance + of a Cauchy distribution is infinity. However, sometimes the + statistic is undefined, e.g., if a distribution's pdf does not achieve a + maximum within the support of the distribution, the mode is undefined. + If the mean is undefined, then by definition the variance is undefined. + E.g. the mean for Student's T for df = 1 is undefined (no clear way to say + it is either + or - infinity), so the variance = E[(X - mean)^2] is also + undefined. + + Returns: + allow_nan_stats: Python boolean. """ - # return self._event_shape - pass + return self._allow_nan_stats + + @property + def validate_args(self): + """Python boolean indicated possibly expensive checks are enabled.""" + return self._validate_args - @abc.abstractmethod def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. + """Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -420,119 +392,327 @@ class Distribution(BaseDistribution): name: name to give to the op Returns: - `Tensor` `batch_shape` + batch_shape: `Tensor`. """ - # with ops.name_scope(self.name): - # with ops.name_scope(name, values=[tensor_arguments]): - # Your code here - pass + self._check_hasattr(self._batch_shape) + with self._name_scope(name): + return self._batch_shape() - @abc.abstractmethod def get_batch_shape(self): - """`TensorShape` available at graph construction time. + """Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. + + Returns: + batch_shape: `TensorShape`, possibly unknown. """ - pass + self._check_hasattr(self._get_batch_shape) + return self._get_batch_shape() - def sample_n(self, n, seed=None, name="sample_n"): - """Generate `n` samples. + def event_shape(self, name="event_shape"): + """Shape of a single sample from a single batch as a 1-D int32 `Tensor`. Args: - n: scalar. Number of samples to draw from each distribution. - seed: Python integer seed for RNG - name: name to give to the op. + name: name to give to the op + + Returns: + event_shape: `Tensor`. + """ + self._check_hasattr(self._event_shape) + with self._name_scope(name): + return self._event_shape() + + def get_event_shape(self): + """Shape of a single sample from a single batch as a `TensorShape`. + + Same meaning as `event_shape`. May be only partially defined. Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. + event_shape: `TensorShape`, possibly unknown. """ - return super(Distribution, self).sample_n(n, seed, name) + self._check_hasattr(self._get_event_shape) + return self._get_event_shape() def sample(self, sample_shape=(), seed=None, name="sample"): - """Generate samples of the specified shape for each batched distribution. + """Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single - sample per batched distribution. + sample. Args: - sample_shape: Rank 1 `int32` `Tensor`. Shape of the generated samples. + sample_shape: 0D or 1D `int32` `Tensor`. Shape of the generated samples. seed: Python integer seed for RNG name: name to give to the op. Returns: - samples: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. + samples: a `Tensor` with prepended dimensions `sample_shape`. """ - return super(Distribution, self).sample(sample_shape, seed, name) + with self._name_scope(name, values=[sample_shape]): + sample_shape = ops.convert_to_tensor( + sample_shape, dtype=dtypes.int32, name="sample_shape") + if sample_shape.get_shape().ndims == 0: + return self.sample_n(sample_shape, seed) + sample_shape, total = self._expand_sample_shape(sample_shape) + samples = self.sample_n(total, seed) + output_shape = array_ops.concat(0, [sample_shape, array_ops.slice( + array_ops.shape(samples), [1], [-1])]) + output = array_ops.reshape(samples, output_shape) + output.set_shape(tensor_util.constant_value_as_shape( + sample_shape).concatenate(samples.get_shape()[1:])) + return output - def cdf(self, value, name="cdf"): - """Cumulative distribution function.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[value]): - value = ops.convert_to_tensor(value) - return math_ops.exp(self.log_cdf(value)) + def sample_n(self, n, seed=None, name="sample_n"): + """Generate `n` samples. + + Args: + n: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. + seed: Python integer seed for RNG + name: name to give to the op. + + Returns: + samples: a `Tensor` with a prepended dimension (n,). + + Raises: + TypeError: if `n` is not an integer type. + """ + self._check_hasattr(self._sample_n) + with self._name_scope(name, values=[n]): + n = ops.convert_to_tensor(n, name="n") + if not n.dtype.is_integer: + raise TypeError("n.dtype=%s is not an integer type" % n.dtype) + x = self._sample_n(n, seed) + + # Set shape hints. + sample_shape = tensor_shape.TensorShape( + tensor_util.constant_value(n)) + batch_ndims = self.get_batch_shape().ndims + event_ndims = self.get_event_shape().ndims + if batch_ndims is not None and event_ndims is not None: + inferred_shape = sample_shape.concatenate( + self.get_batch_shape().concatenate( + self.get_event_shape())) + x.set_shape(inferred_shape) + elif x.get_shape().ndims is not None and x.get_shape().ndims > 0: + x.get_shape()[0].merge_with(sample_shape) + if batch_ndims is not None and batch_ndims > 0: + x.get_shape()[1:1+batch_ndims].merge_with(self.get_batch_shape()) + if event_ndims is not None and event_ndims > 0: + x.get_shape()[-event_ndims:].merge_with(self.get_event_shape()) + + return x + + def log_prob(self, value, name="log_prob"): + """Log probability density/mass function (depending on `is_continuous`). + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + log_prob: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + """ + self._check_hasattr(self._log_prob) + with self._name_scope(name, values=[value]): + value = ops.convert_to_tensor(value, name="value") + return self._log_prob(value) + + def prob(self, value, name="prob"): + """Probability density/mass function (depending on `is_continuous`). + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + prob: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + """ + self._check_hasattr(self._prob) + with self._name_scope(name, values=[value]): + value = ops.convert_to_tensor(value, name="value") + return self._prob(value) def log_cdf(self, value, name="log_cdf"): - """Log CDF.""" - raise NotImplementedError("log_cdf is not implemented") + """Log cumulative distribution function. + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + logcdf: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + """ + self._check_hasattr(self._log_cdf) + with self._name_scope(name, values=[value]): + value = ops.convert_to_tensor(value, name="value") + return self._log_cdf(value) + + def cdf(self, value, name="cdf"): + """Cumulative distribution function. + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + cdf: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + """ + self._check_hasattr(self._cdf) + with self._name_scope(name, values=[value]): + value = ops.convert_to_tensor(value, name="value") + return self._cdf(value) def entropy(self, name="entropy"): - """Entropy of the distribution in nats.""" - raise NotImplementedError("entropy not implemented") + """Shanon entropy in nats.""" + self._check_hasattr(self._entropy) + with self._name_scope(name): + return self._entropy() def mean(self, name="mean"): - """Mean of the distribution.""" - raise NotImplementedError("mean not implemented") + """Mean.""" + self._check_hasattr(self._mean) + with self._name_scope(name): + return self._mean() - def mode(self, name="mode"): - """Mode of the distribution.""" - raise NotImplementedError("mode not implemented") + def variance(self, name="variance"): + """Variance.""" + self._check_hasattr(self._variance) + with self._name_scope(name): + return self._variance() def std(self, name="std"): - """Standard deviation of the distribution.""" - raise NotImplementedError("std not implemented") + """Standard deviation.""" + self._check_hasattr(self._std) + with self._name_scope(name): + return self._std() - def variance(self, name="variance"): - """Variance of the distribution.""" - raise NotImplementedError("variance not implemented") + def mode(self, name="mode"): + """Mode.""" + self._check_hasattr(self._mode) + with self._name_scope(name): + return self._mode() - @abc.abstractproperty - def is_continuous(self): - pass + def log_pdf(self, value, name="log_pdf"): + """Log probability density function. - @abc.abstractproperty - def is_reparameterized(self): - pass + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. - def log_pdf(self, value, name="log_pdf"): - """Log of the probability density function.""" - if self.is_continuous: - return self.log_prob(value, name=name) - else: - raise NotImplementedError( - "log_pdf is not implemented for non-continuous distributions") + Returns: + log_prob: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + Raises: + AttributeError: if not `is_continuous`. + """ + if not self.is_continuous: + raise AttributeError( + "log_pdf is undefined for non-continuous distributions.") + return self.log_prob(value, name=name) def pdf(self, value, name="pdf"): - """The probability density function.""" - if self.is_continuous: - return self.prob(value, name=name) - else: - raise NotImplementedError( - "pdf is not implemented for non-continuous distributions") + """Probability density function. + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + prob: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + Raises: + AttributeError: if not `is_continuous`. + """ + if not self.is_continuous: + raise AttributeError("pdf is undefined for non-continuous distributions.") + return self.prob(value, name) def log_pmf(self, value, name="log_pmf"): - """Log of the probability mass function.""" + """Log probability mass function. + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + log_pmf: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + Raises: + AttributeError: if `is_continuous`. + """ if self.is_continuous: - raise NotImplementedError( - "log_pmf is not implemented for continuous distributions") - else: - return self.log_prob(value, name=name) + raise AttributeError("log_pmf is undefined for continuous distributions.") + return self.log_prob(value, name=name) def pmf(self, value, name="pmf"): - """The probability mass function.""" + """Probability mass function. + + Args: + value: `float` or `double` `Tensor`. + name: The name to give this op. + + Returns: + pmf: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + Raises: + AttributeError: if `is_continuous`. + """ if self.is_continuous: - raise NotImplementedError( - "pmf is not implemented for continuous distributions") + raise AttributeError("pmf is undefined for continuous distributions.") + return self.prob(value, name=name) + + @contextlib.contextmanager + def _name_scope(self, name=None, values=None): + """Helper function to standardize op scope.""" + with ops.name_scope(self.name): + with ops.name_scope(name, values=( + (values or []) + list(self.parameters.values()))) as scope: + yield scope + + def _check_hasattr(self, func): + if hasattr(self, func.__func__.__name__) and callable(func): return + raise NotImplementedError( + "Subclass %s does not implement %s" % + (type(self).__name__, func.__func__.__name__)) + + def _expand_sample_shape(self, sample_shape): + """Helper to `sample` which ensures sample_shape is 1D.""" + sample_shape_static_val = tensor_util.constant_value(sample_shape) + ndims = sample_shape.get_shape().ndims + if sample_shape_static_val is None: + if ndims is None or not sample_shape.get_shape().is_fully_defined(): + ndims = array_ops.rank(sample_shape) + expanded_shape = distribution_util.pick_vector( + math_ops.equal(ndims, 0), + np.array((1,), dtype=dtypes.int32.as_numpy_dtype()), + array_ops.shape(sample_shape)) + sample_shape = array_ops.reshape(sample_shape, expanded_shape) + total = math_ops.reduce_prod(sample_shape) # reduce_prod([]) == 1 else: - return self.prob(value, name=name) + if ndims is None: + raise ValueError( + "Shouldn't be here; ndims cannot be none when we have a " + "tf.constant shape.") + if ndims == 0: + sample_shape_static_val = np.reshape(sample_shape_static_val, [1]) + sample_shape = ops.convert_to_tensor( + sample_shape_static_val, + dtype=dtypes.int32, + name="sample_shape") + total = np.prod(sample_shape_static_val, + dtype=dtypes.int32.as_numpy_dtype()) + return sample_shape, total + + +distribution_util.append_class_fun_doc(BaseDistribution.sample_n, + doc_str=Distribution.sample_n.__doc__) +distribution_util.append_class_fun_doc(BaseDistribution.log_prob, + doc_str=Distribution.log_prob.__doc__) diff --git a/tensorflow/contrib/distributions/python/ops/distribution_util.py b/tensorflow/contrib/distributions/python/ops/distribution_util.py index c6386b905b6b12e6fd6d595a8b9d28b12409a879..a1ab35f1f0cad92fe8eb9c692c581efd33934a2a 100644 --- a/tensorflow/contrib/distributions/python/ops/distribution_util.py +++ b/tensorflow/contrib/distributions/python/ops/distribution_util.py @@ -18,6 +18,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import sys import numpy as np from tensorflow.python.framework import constant_op @@ -374,3 +375,27 @@ def pick_vector(cond, return array_ops.slice(array_ops.concat(0, (true_vector, false_vector)), [math_ops.select(cond, 0, n)], [math_ops.select(cond, n, -1)]) + + +def append_class_fun_doc(fn, doc_str): + """Appends the `doc_str` argument to `fn.__doc__`. + + This function is primarily needed because Python 3 changes how docstrings are + programmatically set. + + Args: + fn: Class function. + doc_str: String + """ + # TODO(b/31100586): Figure out why appending accumulates rather than resets + # for each subclass. + if sys.version_info.major < 3: + if fn.__func__.__doc__ is None: + fn.__func__.__doc__ = doc_str + # else: + # fn.__func__.__doc__ += doc_str + else: + if fn.__doc__ is None: + fn.__doc__ = doc_str + # else: + # fn.__doc__ += doc_str diff --git a/tensorflow/contrib/distributions/python/ops/exponential.py b/tensorflow/contrib/distributions/python/ops/exponential.py index e0d2dba7a00a426e9ee40942c95fb4d4775c276f..59ac2390606b71b33e8192b56aee55067ae27ce1 100644 --- a/tensorflow/contrib/distributions/python/ops/exponential.py +++ b/tensorflow/contrib/distributions/python/ops/exponential.py @@ -21,10 +21,7 @@ from __future__ import print_function import numpy as np from tensorflow.contrib.distributions.python.ops import gamma -from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import random_ops @@ -41,8 +38,11 @@ class Exponential(gamma.Gamma): distribution, with Exponential(lam) = Gamma(1, lam). """ - def __init__( - self, lam, validate_args=True, allow_nan_stats=False, name="Exponential"): + def __init__(self, + lam, + validate_args=True, + allow_nan_stats=False, + name="Exponential"): """Construct Exponential distribution with parameter `lam`. Args: @@ -62,50 +62,28 @@ class Exponential(gamma.Gamma): # allow_nan_stats=False # through to the parent class results in unnecessary asserts. with ops.name_scope(name, values=[lam]): - lam = ops.convert_to_tensor(lam) - self._lam = lam + self._lam = ops.convert_to_tensor(lam, name="lam") super(Exponential, self).__init__( - alpha=constant_op.constant(1.0, dtype=lam.dtype), - beta=lam, + alpha=array_ops.ones((), dtype=self._lam.dtype), + beta=self._lam, allow_nan_stats=allow_nan_stats, validate_args=validate_args) + # While the Gamma distribution is not reparameterizeable, the + # exponential distribution is. + self._is_reparameterized = True @property def lam(self): return self._lam - @property - def is_reparameterized(self): - # While the Gamma distribution is not reparameterizeable, the - # exponential distribution is. - return True - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Exponential Distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by the hyperparameters. - """ - broadcast_shape = self._lam.get_shape() - with ops.name_scope(name, "ExponentialSample", [self.lam, n]): - n = ops.convert_to_tensor(n, name="n") - shape = array_ops.concat(0, ([n], array_ops.shape(self._lam))) - # Sample uniformly-at-random from the open-interval (0, 1). - sampled = random_ops.random_uniform( - shape, minval=np.nextafter( - self.dtype.as_numpy_dtype(0.), self.dtype.as_numpy_dtype(1.)), - maxval=constant_op.constant(1.0, dtype=self.dtype), - seed=seed, - dtype=self.dtype) - - n_val = tensor_util.constant_value(n) - final_shape = tensor_shape.vector(n_val).concatenate(broadcast_shape) - sampled.set_shape(final_shape) - - return -math_ops.log(sampled) / self._lam + def _sample_n(self, n, seed=None): + shape = array_ops.concat(0, ([n], array_ops.shape(self._lam))) + # Sample uniformly-at-random from the open-interval (0, 1). + sampled = random_ops.random_uniform( + shape, + minval=np.nextafter(self.dtype.as_numpy_dtype(0.), + self.dtype.as_numpy_dtype(1.)), + maxval=array_ops.ones((), dtype=self.dtype), + seed=seed, + dtype=self.dtype) + return -math_ops.log(sampled) / self._lam diff --git a/tensorflow/contrib/distributions/python/ops/gamma.py b/tensorflow/contrib/distributions/python/ops/gamma.py index c9a6c286f0cd7eb3ee4ccb8bb3db8084e024da20..a02b21ce1036d9bea676415217b1593a69085459 100644 --- a/tensorflow/contrib/distributions/python/ops/gamma.py +++ b/tensorflow/contrib/distributions/python/ops/gamma.py @@ -20,8 +20,9 @@ from __future__ import print_function import numpy as np -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long -from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util # pylint: disable=line-too-long +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util +from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import common_shapes from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -88,41 +89,20 @@ class Gamma(distribution.Distribution): Raises: TypeError: if `alpha` and `beta` are different dtypes. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - with ops.name_scope(name, values=[alpha, beta]) as scope: - self._name = scope - with ops.control_dependencies([check_ops.assert_positive( - alpha), check_ops.assert_positive(beta)] if validate_args else []): - alpha = array_ops.identity(alpha, name="alpha") - beta = array_ops.identity(beta, name="beta") - - self._get_batch_shape = common_shapes.broadcast_shape( - alpha.get_shape(), beta.get_shape()) - self._get_event_shape = tensor_shape.TensorShape([]) - - self._alpha = alpha - self._beta = beta - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._alpha.dtype + with ops.name_scope(name, values=[alpha, beta]): + with ops.control_dependencies([ + check_ops.assert_positive(alpha), + check_ops.assert_positive(beta), + ] if validate_args else []): + self._alpha = array_ops.identity(alpha, name="alpha") + self._beta = array_ops.identity(beta, name="beta") + contrib_tensor_util.assert_same_float_dtype((self._alpha, self._beta)) + super(Gamma, self).__init__( + dtype=self._alpha.dtype, + parameters={"alpha": self._alpha, "beta": self._beta}, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def alpha(self): @@ -134,181 +114,88 @@ class Gamma(distribution.Distribution): """Inverse scale parameter.""" return self._beta - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return array_ops.shape(self._alpha + self._beta) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - `TensorShape` object. - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - `TensorShape` object. - """ - return self._get_event_shape - - def mean(self, name="mean"): - """Mean of each batch member.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return self._alpha / self._beta - - def mode(self, name="mode"): - """Mode of each batch member. - - The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, - and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception - will be raised rather than returning `NaN`. - - Args: - name: A name to give this op. - - Returns: - The mode for every batch member, a `Tensor` with same `dtype` as self. - """ - alpha = self._alpha - beta = self._beta - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, beta]): - mode_if_defined = (alpha - 1.0) / beta - if self.allow_nan_stats: - alpha_ge_1 = alpha >= 1.0 - nan = np.nan * self._ones() - return math_ops.select(alpha_ge_1, mode_if_defined, nan) - else: - one = constant_op.constant(1.0, dtype=self.dtype) - return control_flow_ops.with_dependencies( - [check_ops.assert_less( - one, alpha, - message="mode not defined for components of alpha <= 1" - )], mode_if_defined) - - def variance(self, name="variance"): - """Variance of each batch member.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return self._alpha / math_ops.square(self._beta) - - def std(self, name="std"): - """Standard deviation of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return math_ops.sqrt(self._alpha) / self._beta - - def log_prob(self, x, name="log_prob"): - """Log prob of observations in `x` under these Gamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - log_prob: tensor of dtype `dtype`, the log-PDFs of `x`. - - Raises: - TypeError: if `x` and `alpha` are different dtypes. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - alpha = self._alpha - beta = self._beta - x = ops.convert_to_tensor(x) - x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if - self.validate_args else [], x) - contrib_tensor_util.assert_same_float_dtype(tensors=[x,], - dtype=self.dtype) - - return (alpha * math_ops.log(beta) + (alpha - 1) * math_ops.log(x) - - beta * x - math_ops.lgamma(self._alpha)) - - def prob(self, x, name="prob"): - """Pdf of observations in `x` under these Gamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - prob: tensor of dtype `dtype`, the PDFs of `x` - - Raises: - TypeError: if `x` and `alpha` are different dtypes. - """ - return super(Gamma, self).prob(x, name) - - def log_cdf(self, x, name="log_cdf"): - """Log CDF of observations `x` under these Gamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - log_cdf: tensor of dtype `dtype`, the log-CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - x = ops.convert_to_tensor(x) - x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if - self.validate_args else [], x) - contrib_tensor_util.assert_same_float_dtype(tensors=[x,], - dtype=self.dtype) - # Note that igamma returns the regularized incomplete gamma function, - # which is what we want for the CDF. - return math_ops.log(math_ops.igamma(self._alpha, self._beta * x)) - - def cdf(self, x, name="cdf"): - """CDF of observations `x` under these Gamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - cdf: tensor of dtype `dtype`, the CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - return math_ops.igamma(self._alpha, self._beta * x) - - def entropy(self, name="entropy"): - """The entropy of Gamma distribution(s). + def _batch_shape(self): + return array_ops.shape(self.alpha + self.beta) + + def _get_batch_shape(self): + return common_shapes.broadcast_shape(self.alpha.get_shape(), + self.beta.get_shape()) + + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) + + def _get_event_shape(self): + return tensor_shape.scalar() + + def _sample_n(self, n, seed=None): + return random_ops.random_gamma([n], + self.alpha, + beta=self.beta, + dtype=self.dtype, + seed=seed) + + def _log_prob(self, x): + x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if + self.validate_args else [], x) + contrib_tensor_util.assert_same_float_dtype(tensors=[x], + dtype=self.dtype) + return (self.alpha * math_ops.log(self.beta) + + (self.alpha - 1.) * math_ops.log(x) - + self.beta * x - + math_ops.lgamma(self.alpha)) + + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) + + def _log_cdf(self, x): + x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if + self.validate_args else [], x) + contrib_tensor_util.assert_same_float_dtype(tensors=[x], dtype=self.dtype) + # Note that igamma returns the regularized incomplete gamma function, + # which is what we want for the CDF. + return math_ops.log(math_ops.igamma(self.alpha, self.beta * x)) + + def _cdf(self, x): + return math_ops.igamma(self.alpha, self.beta * x) + + def _entropy(self): + return (self.alpha - + math_ops.log(self.beta) + + math_ops.lgamma(self.alpha) + + (1. - self.alpha) * math_ops.digamma(self.alpha)) + + def _mean(self): + return self.alpha / self.beta + + def _variance(self): + return self.alpha / math_ops.square(self.beta) + + def _std(self): + return math_ops.sqrt(self.alpha) / self.beta + + def _mode(self): + mode = (self.alpha - 1.) / self.beta + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + self.alpha >= 1., + mode, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), self.dtype), + self.alpha, + message="mode not defined for components of alpha <= 1"), + ], mode) + + +distribution_util.append_class_fun_doc(Gamma.sample_n, doc_str=""" + + See the documentation for tf.random_gamma for more details. +""") + +distribution_util.append_class_fun_doc(Gamma.entropy, doc_str=""" This is defined to be @@ -318,50 +205,11 @@ class Gamma(distribution.Distribution): ``` where digamma(alpha) is the digamma function. +""") - Args: - name: The name to give this op. - - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.alpha, self._beta]): - alpha = self._alpha - beta = self._beta - return (alpha - math_ops.log(beta) + math_ops.lgamma(alpha) + - (1 - alpha) * math_ops.digamma(alpha)) - - def sample_n(self, n, seed=None, name="sample_n"): - """Draws `n` samples from the Gamma distribution(s). - - See the doc for tf.random_gamma for further detail. - - Args: - n: Python integer, the number of observations to sample from each - distribution. - seed: Python integer, the random seed for this operation. - name: Optional name for the operation. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - """ - with ops.name_scope(self.name, values=[n, self.alpha, self._beta]): - return random_ops.random_gamma([n], - self.alpha, - beta=self._beta, - dtype=self.dtype, - seed=seed, - name=name) - - @property - def is_reparameterized(self): - return False - - def _ones(self): - return array_ops.ones_like(self._alpha + self._beta, dtype=self.dtype) +distribution_util.append_class_fun_doc(Gamma.mode, doc_str=""" - @property - def is_continuous(self): - return True + The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, + and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception + will be raised rather than returning `NaN`. +""") diff --git a/tensorflow/contrib/distributions/python/ops/inverse_gamma.py b/tensorflow/contrib/distributions/python/ops/inverse_gamma.py index b0c1eb3c859a4cebf288702cca15920e1f3ccb15..58c92a9acae7f47f2044be8f15a0ff19dc0b2c1a 100644 --- a/tensorflow/contrib/distributions/python/ops/inverse_gamma.py +++ b/tensorflow/contrib/distributions/python/ops/inverse_gamma.py @@ -20,8 +20,8 @@ from __future__ import print_function import numpy as np -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long -from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util # pylint: disable=line-too-long +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util from tensorflow.python.framework import common_shapes from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes @@ -87,41 +87,19 @@ class InverseGamma(distribution.Distribution): Raises: TypeError: if `alpha` and `beta` are different dtypes. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - with ops.name_scope(name, values=[alpha, beta]) as scope: - self._name = scope - with ops.control_dependencies([check_ops.assert_positive( - alpha), check_ops.assert_positive(beta)] if validate_args else []): - alpha = array_ops.identity(alpha, name="alpha") - beta = array_ops.identity(beta, name="beta") - - self._get_batch_shape = common_shapes.broadcast_shape( - alpha.get_shape(), beta.get_shape()) - self._get_event_shape = tensor_shape.TensorShape([]) - - self._alpha = alpha - self._beta = beta - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._alpha.dtype + with ops.name_scope(name, values=[alpha, beta]): + with ops.control_dependencies([ + check_ops.assert_positive(alpha), + check_ops.assert_positive(beta), + ] if validate_args else []): + self._alpha = array_ops.identity(alpha, name="alpha") + self._beta = array_ops.identity(beta, name="beta") + super(InverseGamma, self).__init__( + dtype=self._alpha.dtype, + parameters={"alpha": self._alpha, "beta": self._beta}, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def alpha(self): @@ -133,210 +111,88 @@ class InverseGamma(distribution.Distribution): """Scale parameter.""" return self._beta - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return array_ops.shape(self._alpha + self._beta) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - `TensorShape` object. - """ - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - `TensorShape` object. - """ - return self._get_event_shape - - def mean(self, name="mean"): - """Mean of each batch member. - - The mean of an inverse gamma distribution is `beta / (alpha - 1)`, - when `alpha > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is - `False`, an exception will be raised rather than returning `NaN` - - Args: - name: A name to give this op. - - Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. - """ - alpha = self._alpha - beta = self._beta - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, beta]): - mean_if_defined = beta / (alpha - 1.0) - if self.allow_nan_stats: - alpha_gt_1 = alpha > 1.0 - nan = np.nan * self._ones() - return math_ops.select(alpha_gt_1, mean_if_defined, nan) - else: - one = constant_op.constant(1.0, dtype=self.dtype) - return control_flow_ops.with_dependencies( - [check_ops.assert_less( - one, alpha, - message="mean not defined for components of alpha <= 1")], - mean_if_defined) - - def mode(self, name="mode"): - """Mode of each batch member. - - The mode of an inverse gamma distribution is `beta / (alpha + 1)`. - - Args: - name: A name to give this op. - - Returns: - The mode for every batch member, a `Tensor` with same `dtype` as self. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - return self._beta / (self._alpha + 1.0) - - def variance(self, name="variance"): - """Variance of each batch member. - - Variance for inverse gamma is defined only for `alpha > 2`. If - `self.allow_nan_stats` is `False`, an exception will be raised rather - than returning `NaN`. - - Args: - name: A name to give this op. - - Returns: - The variance for every batch member, a `Tensor` with same `dtype` as self. - """ - alpha = self._alpha - beta = self._beta - with ops.name_scope(self.name): - with ops.name_scope(name, values=[alpha, beta]): - var_if_defined = (math_ops.square(self._beta) / - (math_ops.square(self._alpha - 1.0) * - (self._alpha - 2.0))) - if self.allow_nan_stats: - alpha_gt_2 = alpha > 2.0 - nan = np.nan * self._ones() - return math_ops.select(alpha_gt_2, var_if_defined, nan) - else: - two = constant_op.constant(2.0, dtype=self.dtype) - return control_flow_ops.with_dependencies( - [check_ops.assert_less( - two, alpha, - message="variance not defined for components of alpha <= 2")], - var_if_defined) - - def log_prob(self, x, name="log_prob"): - """Log prob of observations in `x` under these InverseGamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - log_prob: tensor of dtype `dtype`, the log-PDFs of `x`. - - Raises: - TypeError: if `x` and `alpha` are different dtypes. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - alpha = self._alpha - beta = self._beta - x = ops.convert_to_tensor(x) - x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if - self.validate_args else [], x) - contrib_tensor_util.assert_same_float_dtype(tensors=[x,], - dtype=self.dtype) - - return (alpha * math_ops.log(beta) - math_ops.lgamma(self._alpha) - - (alpha + 1) * math_ops.log(x) - beta / x) - - def prob(self, x, name="prob"): - """Pdf of observations in `x` under these Gamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - prob: tensor of dtype `dtype`, the PDFs of `x` - - Raises: - TypeError: if `x` and `alpha` are different dtypes. - """ - return super(InverseGamma, self).prob(x, name) - - def log_cdf(self, x, name="log_cdf"): - """Log CDF of observations `x` under these InverseGamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - log_cdf: tensor of dtype `dtype`, the log-CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - x = ops.convert_to_tensor(x) - x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if - self.validate_args else [], x) - contrib_tensor_util.assert_same_float_dtype(tensors=[x,], - dtype=self.dtype) - # Note that igammac returns the upper regularized incomplete gamma - # function Q(a, x), which is what we want for the CDF. - return math_ops.log(math_ops.igammac(self._alpha, self._beta / x)) - - def cdf(self, x, name="cdf"): - """CDF of observations `x` under these InverseGamma distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. - name: The name to give this op. - - Returns: - cdf: tensor of dtype `dtype`, the CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta, x]): - return math_ops.igammac(self._alpha, self._beta / x) - - def entropy(self, name="entropy"): - """The entropy of these InverseGamma distribution(s). + def _batch_shape(self): + return array_ops.shape(self.alpha + self.beta) + + def _get_batch_shape(self): + return common_shapes.broadcast_shape(self.alpha.get_shape(), + self.beta.get_shape()) + + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) + + def _get_event_shape(self): + return tensor_shape.scalar() + + def _sample_n(self, n, seed=None): + return 1. / random_ops.random_gamma([n], self.alpha, beta=self.beta, + dtype=self.dtype, seed=seed) + + def _log_prob(self, x): + x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if + self.validate_args else [], x) + return (self.alpha * math_ops.log(self.beta) - + math_ops.lgamma(self.alpha) - + (self.alpha + 1.) * math_ops.log(x) - self.beta / x) + + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) + + def _log_cdf(self, x): + return math_ops.log(self._cdf(x)) + + def _cdf(self, x): + x = control_flow_ops.with_dependencies([check_ops.assert_positive(x)] if + self.validate_args else [], x) + # Note that igammac returns the upper regularized incomplete gamma + # function Q(a, x), which is what we want for the CDF. + return math_ops.igammac(self.alpha, self.beta / x) + + def _entropy(self): + return (self.alpha + + math_ops.log(self.beta) + + math_ops.lgamma(self.alpha) - + (1. + self.alpha) * math_ops.digamma(self.alpha)) + + def _mean(self): + mean = self.beta / (self.alpha - 1.) + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + self.alpha > 1., mean, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), self.dtype), self.alpha, + message="mean not defined for components of self.alpha <= 1"), + ], mean) + + def _variance(self): + var = (math_ops.square(self.beta) / + (math_ops.square(self.alpha - 1.) * (self.alpha - 2.))) + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + self.alpha > 2., var, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + constant_op.constant(2., dtype=self.dtype), self.alpha, + message="variance not defined for components of alpha <= 2"), + ], var) + + def _mode(self): + return self.beta / (self.alpha + 1.) + + +distribution_util.append_class_fun_doc(InverseGamma.sample_n, doc_str=""" + + See the documentation for tf.random_gamma for more details. +""") + +distribution_util.append_class_fun_doc(InverseGamma.entropy, doc_str=""" This is defined to be @@ -346,51 +202,23 @@ class InverseGamma(distribution.Distribution): ``` where digamma(alpha) is the digamma function. +""") - Args: - name: The name to give this op. - - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._alpha, self._beta]): - alpha = self._alpha - beta = self._beta - return (alpha + math_ops.log(beta) + math_ops.lgamma(alpha) - - (1 + alpha) * math_ops.digamma(alpha)) +distribution_util.append_class_fun_doc(InverseGamma.mean, doc_str=""" - def sample_n(self, n, seed=None, name="sample_n"): - """Draws `n` samples from these InverseGamma distribution(s). - - See the doc for tf.random_gamma for further details on sampling strategy. + The mean of an inverse gamma distribution is `beta / (alpha - 1)`, + when `alpha > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is + `False`, an exception will be raised rather than returning `NaN` +""") - Args: - n: Python integer, the number of observations to sample from each - distribution. - seed: Python integer, the random seed for this operation. - name: Optional name for the operation. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[n, self._alpha, self._beta]): - one = constant_op.constant(1.0, dtype=self.dtype) - return one / random_ops.random_gamma([n], - self._alpha, - beta=self._beta, - dtype=self.dtype, - seed=seed) +distribution_util.append_class_fun_doc(InverseGamma.variance, doc_str=""" - @property - def is_reparameterized(self): - return False + Variance for inverse gamma is defined only for `alpha > 2`. If + `self.allow_nan_stats` is `False`, an exception will be raised rather + than returning `NaN`. +""") - def _ones(self): - return array_ops.ones_like(self._alpha + self._beta, dtype=self.dtype) +distribution_util.append_class_fun_doc(InverseGamma.mode, doc_str=""" - @property - def is_continuous(self): - return True + The mode of an inverse gamma distribution is `beta / (alpha + 1)`. +""") diff --git a/tensorflow/contrib/distributions/python/ops/laplace.py b/tensorflow/contrib/distributions/python/ops/laplace.py index 6f6980b5a203d4a9a0a634d18479f8a9d46b464c..59e96739df4daa2f04fd1b0534e5f3972899553a 100644 --- a/tensorflow/contrib/distributions/python/ops/laplace.py +++ b/tensorflow/contrib/distributions/python/ops/laplace.py @@ -29,7 +29,6 @@ from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import math_ops @@ -77,88 +76,19 @@ class Laplace(distribution.Distribution): Raises: TypeError: if `loc` and `scale` are of different dtype. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args with ops.name_scope(name, values=[loc, scale]): - loc = ops.convert_to_tensor(loc) - scale = ops.convert_to_tensor(scale) with ops.control_dependencies([check_ops.assert_positive(scale)] if validate_args else []): - self._name = name self._loc = array_ops.identity(loc, name="loc") self._scale = array_ops.identity(scale, name="scale") - self._batch_shape = common_shapes.broadcast_shape( - self._loc.get_shape(), self._scale.get_shape()) - self._event_shape = tensor_shape.TensorShape([]) - - contrib_tensor_util.assert_same_float_dtype((loc, scale)) - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._loc.dtype - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return array_ops.shape(self._loc + self._scale) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._event_shape + contrib_tensor_util.assert_same_float_dtype((self._loc, self._scale)) + super(Laplace, self).__init__( + dtype=self._loc.dtype, + parameters={"loc": self._loc, "scale": self._scale}, + is_reparameterized=True, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def loc(self): @@ -170,154 +100,64 @@ class Laplace(distribution.Distribution): """Distribution parameter for scale.""" return self._scale - def mean(self, name="mean"): - """Mean of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._scale, self._loc]): - return self._loc + array_ops.zeros_like(self._scale) - - def median(self, name="median"): - """Median of this distribution.""" - return self.mean(name="median") - - def mode(self, name="mode"): - """Mode of this distribution.""" - return self.mean(name="mode") - - def std(self, name="std"): - """Standard deviation of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._scale, self._loc]): - sqrt_2 = constant_op.constant(math.sqrt(2.), dtype=self.dtype) - return sqrt_2 * self._scale + array_ops.zeros_like(self._loc) + def _batch_shape(self): + return array_ops.shape(self.loc + self.scale) - def variance(self, name="variance"): - """Variance of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.square(self.std()) + def _get_batch_shape(self): + return common_shapes.broadcast_shape(self.loc.get_shape(), + self.scale.get_shape()) - def prob(self, x, name="pdf"): - """The prob of observations in `x` under the Laplace distribution(s). + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) - Args: - x: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. - name: The name to give this op. - - Returns: - pdf: tensor of dtype `dtype`, the pdf values of `x`. - """ - return 0.5 / self._scale * math_ops.exp( - -math_ops.abs(x - self._loc) / self._scale) + def _get_event_shape(self): + return tensor_shape.scalar() - def log_prob(self, x, name="log_prob"): - """Log prob of observations in `x` under these Laplace distribution(s). + def _sample_n(self, n, seed=None): + shape = array_ops.concat(0, ([n], self.batch_shape())) + # Sample uniformly-at-random from the open-interval (-1, 1). + uniform_samples = random_ops.random_uniform( + shape=shape, + minval=np.nextafter(self.dtype.as_numpy_dtype(-1.), + self.dtype.as_numpy_dtype(0.)), + maxval=1., + dtype=self.dtype, + seed=seed) + return (self.loc - self.scale * math_ops.sign(uniform_samples) * + math_ops.log(1. - math_ops.abs(uniform_samples))) - Args: - x: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. - name: The name to give this op. + def _log_prob(self, x): + return (-math.log(2.) - math_ops.log(self.scale) - + math_ops.abs(x - self.loc) / self.scale) - Returns: - log_prob: tensor of dtype `dtype`, the log-probability of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._loc, self._scale, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" - % (x.dtype, self.dtype)) - log_2 = constant_op.constant(math.log(2.), dtype=self.dtype) - return (-log_2 - math_ops.log(self._scale) - - math_ops.abs(x - self._loc) / self._scale) + def _prob(self, x): + return 0.5 / self.scale * math_ops.exp( + -math_ops.abs(x - self.loc) / self.scale) - def cdf(self, x, name="cdf"): - """CDF of observations in `x` under the Laplace distribution(s). + def _log_cdf(self, x): + return math_ops.log(self.cdf(x)) - Args: - x: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. - name: The name to give this op. + def _cdf(self, x): + y = x - self.loc + return (0.5 + 0.5 * math_ops.sign(y) * + (1. - math_ops.exp(-math_ops.abs(y) / self.scale))) - Returns: - cdf: tensor of dtype `dtype`, the CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._loc, self._scale, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" - % (x.dtype, self.dtype)) - y = x - self._loc - return 0.5 + 0.5 * math_ops.sign(y) * ( - 1. - math_ops.exp(-math_ops.abs(y) / self._scale)) + def _entropy(self): + # Use broadcasting rules to calculate the full broadcast scale. + scale = self.scale + array_ops.zeros_like(self.loc) + return math.log(2.) + 1. + math_ops.log(scale) - def log_cdf(self, x, name="log_cdf"): - """Log CDF of observations `x` under the Laplace distribution(s). + def _mean(self): + return self.loc + array_ops.zeros_like(self.scale) - Args: - x: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. - name: The name to give this op. + def _variance(self): + return math_ops.square(self._std()) - Returns: - log_cdf: tensor of dtype `dtype`, the log-CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._loc, self._scale, x]): - return math_ops.log(self.cdf(x)) + def _std(self): + return math.sqrt(2.) * self.scale + array_ops.zeros_like(self.loc) - def entropy(self, name="entropy"): - """The entropy of Laplace distribution(s). + def _median(self): + return self._mean() - Args: - name: The name to give this op. - - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._loc, self._scale]): - log_2_e = constant_op.constant(math.log(2.) + 1., dtype=self.dtype) - # Use broadcasting rules to calculate the full broadcast scale. - scale = self._scale + array_ops.zeros_like(self._loc) - return log_2_e + math_ops.log(scale) - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Laplace Distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the parameters. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._loc, self._scale, n]): - n = ops.convert_to_tensor(n) - n_val = tensor_util.constant_value(n) - shape = array_ops.concat(0, ([n], self.batch_shape())) - # Sample uniformly-at-random from the open-interval (-1, 1). - uniform_samples = random_ops.random_uniform( - shape=shape, - minval=np.nextafter(self.dtype.as_numpy_dtype(-1.), - self.dtype.as_numpy_dtype(0.)), - maxval=self.dtype.as_numpy_dtype(1.), - dtype=self.dtype, - seed=seed) - - # Provide some hints to shape inference - inferred_shape = tensor_shape.vector(n_val).concatenate( - self.get_batch_shape()) - uniform_samples.set_shape(inferred_shape) - - return (self._loc - self._scale * math_ops.sign(uniform_samples) * - math_ops.log(1. - math_ops.abs(uniform_samples))) - - @property - def is_reparameterized(self): - return True - - @property - def is_continuous(self): - return True + def _mode(self): + return self._mean() diff --git a/tensorflow/contrib/distributions/python/ops/multinomial.py b/tensorflow/contrib/distributions/python/ops/multinomial.py index 931daecc8648928240609b4dd243bc99603bdd66..bc79510e12972bc9baf9600c328f0cfe98ac5781 100644 --- a/tensorflow/contrib/distributions/python/ops/multinomial.py +++ b/tensorflow/contrib/distributions/python/ops/multinomial.py @@ -144,20 +144,20 @@ class Multinomial(distribution.Distribution): n, message="n has non-integer components.") ] if validate_args else []): self._n = array_ops.identity(n, name="convert_n") - self._name = name - - self._validate_args = validate_args - self._allow_nan_stats = allow_nan_stats - - self._mean = array_ops.expand_dims(n, -1) * self._p - # Only used for inferring shape. - self._broadcast_shape = math_ops.reduce_sum(self._mean, - reduction_indices=[-1], - keep_dims=False) - - self._get_batch_shape = self._broadcast_shape.get_shape() - self._get_event_shape = ( - self._mean.get_shape().with_rank_at_least(1)[-1:]) + self._mean_val = array_ops.expand_dims(n, -1) * self._p + self._broadcast_shape = math_ops.reduce_sum( + self._mean_val, reduction_indices=[-1], keep_dims=False) + super(Multinomial, self).__init__( + dtype=self._p.dtype, + parameters={"p": self._p, + "n": self._n, + "mean": self._mean, + "logits": self._logits, + "broadcast_shape": self._broadcast_shape}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def n(self): @@ -174,127 +174,55 @@ class Multinomial(distribution.Distribution): """Log-odds.""" return self._logits - @property - def name(self): - """Name to prepend to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self._p.dtype - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._broadcast_shape]): - return array_ops.shape(self._broadcast_shape) + def _batch_shape(self): + return array_ops.shape(self._broadcast_shape) - def get_batch_shape(self): - """`TensorShape` available at graph construction time. + def _get_batch_shape(self): + return self._broadcast_shape.get_shape() - Same meaning as `batch_shape`. May be only partially defined. + def _event_shape(self): + return array_ops.gather(array_ops.shape(self._mean_val), + [array_ops.rank(self._mean_val) - 1]) - Returns: - batch shape - """ - return self._get_batch_shape + def _get_event_shape(self): + return self._mean_val.get_shape().with_rank_at_least(1)[-1:] - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. + def _log_prob(self, counts): + counts = self._assert_valid_sample(counts) + log_unnormalized_prob = math_ops.reduce_sum( + counts * math_ops.log(self.p), + reduction_indices=[-1]) + log_normalizer = -distribution_util.log_combinations(self.n, counts) + return log_unnormalized_prob - log_normalizer - Args: - name: name to give to the op - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mean]): - return array_ops.gather(array_ops.shape(self._mean), - [array_ops.rank(self._mean) - 1]) + def _prob(self, counts): + return math_ops.exp(self._log_prob(counts)) - def get_event_shape(self): - """`TensorShape` available at graph construction time. + def _mean(self): + return array_ops.identity(self._mean_val) - Same meaning as `event_shape`. May be only partially defined. + def _variance(self): + p = self.p * array_ops.expand_dims(array_ops.ones_like(self.n), -1) + outer_prod = math_ops.batch_matmul( + array_ops.expand_dims(self._mean_val, -1), + array_ops.expand_dims(p, -2)) + return array_ops.batch_matrix_set_diag( + -outer_prod, self._mean_val - self._mean_val * p) - Returns: - event shape - """ - return self._get_event_shape - - def mean(self, name="mean"): - """Mean of the distribution.""" - with ops.name_scope(self.name): - return array_ops.identity(self._mean, name=name) - - def variance(self, name="variance"): - """Variance of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._n, self._p, self._mean]): - p = array_ops.expand_dims( - self._p * array_ops.expand_dims( - array_ops.ones_like(self._n), -1), -1) - variance = -math_ops.batch_matmul( - array_ops.expand_dims(self._mean, -1), p, adj_y=True) - variance += array_ops.batch_matrix_diag(self._mean) - return variance - - def log_prob(self, counts, name="log_prob"): - """`Log(P[counts])`, computed for every batch member. - - For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability - that after sampling `n` draws from this Multinomial distribution, the - number of draws falling in class `j` is `n_j`. Note that different - sequences of draws can result in the same counts, thus the probability - includes a combinatorial coefficient. - - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. - name: Name to give this Op, defaults to "log_prob". - - Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. - """ - n = self._n - p = self._p - with ops.name_scope(self.name): - with ops.name_scope(name, values=[n, p, counts]): - counts = self._check_counts(counts) - - prob_prob = math_ops.reduce_sum(counts * math_ops.log(self._p), - reduction_indices=[-1]) - log_prob = prob_prob + distribution_util.log_combinations( - n, counts) - return log_prob + def _assert_valid_sample(self, counts): + """Check counts for proper shape, values, then return tensor version.""" + if not self.validate_args: return counts + return control_flow_ops.with_dependencies([ + check_ops.assert_non_negative( + counts, message="counts has negative components."), + check_ops.assert_equal( + self.n, math_ops.reduce_sum(counts, reduction_indices=[-1]), + message="counts do not sum to n."), + distribution_util.assert_integer_form( + counts, message="counts have non-integer components.") + ], counts) - def prob(self, counts, name="prob"): - """`P[counts]`, computed for every batch member. +_prob_note = """ For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability that after sampling `n` draws from this Multinomial distribution, the @@ -302,38 +230,11 @@ class Multinomial(distribution.Distribution): sequences of draws can result in the same counts, thus the probability includes a combinatorial coefficient. - Args: - counts: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. - name: Name to give this Op, defaults to "prob". - - Returns: - Probabilities for each record, shape `[N1,...,Nm]`. - """ - return super(Multinomial, self).prob(counts, name=name) - - @property - def is_continuous(self): - return False - - @property - def is_reparameterized(self): - return False - - def _check_counts(self, counts): - """Check counts for proper shape, values, then return tensor version.""" - counts = ops.convert_to_tensor(counts, name="counts_before_deps") - candidate_n = math_ops.reduce_sum(counts, reduction_indices=[-1]) - if not self.validate_args: - return counts - - return control_flow_ops.with_dependencies([ - check_ops.assert_non_negative( - counts, message="counts has negative components."), - check_ops.assert_equal( - self._n, candidate_n, message="counts do not sum to n."), - distribution_util.assert_integer_form( - counts, message="counts have non-integer components.")], counts) + Note that input "counts" must be a non-negative tensor with dtype `dtype` + and whose shape can be broadcast with `self.p` and `self.n`. For fixed + leading dimensions, the last dimension represents counts for the + corresponding Multinomial distribution in `self.p`. `counts` is only legal + if it sums up to `n` and its components are equal to integer values. +""" +distribution_util.append_class_fun_doc(Multinomial.log_prob, doc_str=_prob_note) +distribution_util.append_class_fun_doc(Multinomial.prob, doc_str=_prob_note) diff --git a/tensorflow/contrib/distributions/python/ops/mvn.py b/tensorflow/contrib/distributions/python/ops/mvn.py index f957ad1c6ceb7bb3e7d6a82b85370bbd67535446..0f003c22e0839e34ed9679fdfdcd7db8330a59d4 100644 --- a/tensorflow/contrib/distributions/python/ops/mvn.py +++ b/tensorflow/contrib/distributions/python/ops/mvn.py @@ -21,6 +21,7 @@ from __future__ import print_function import math from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util from tensorflow.contrib.distributions.python.ops import kullback_leibler from tensorflow.contrib.distributions.python.ops import operator_pd_cholesky from tensorflow.contrib.distributions.python.ops import operator_pd_diag @@ -29,8 +30,6 @@ from tensorflow.contrib.distributions.python.ops import operator_pd_vdvt_update from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops @@ -120,24 +119,27 @@ class _MultivariateNormalOperatorPD(distribution.Distribution): Raises: TypeError: If `mu` and `cov` are different dtypes. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args with ops.name_scope(name): with ops.name_scope("init", values=[mu] + cov.inputs): + self._mu = array_ops.identity(mu, name="mu") self._cov = cov - self._mu = self._check_mu(mu) - self._name = name - - def _check_mu(self, mu): + self._validate_args = validate_args # Needed by _assert_valid_mu. + self._mu = self._assert_valid_mu(self._mu) + super(_MultivariateNormalOperatorPD, self).__init__( + dtype=self._mu.dtype, + parameters={"mu": self._mu, "cov": self._cov}, + is_reparameterized=True, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) + + def _assert_valid_mu(self, mu): """Return `mu` after validity checks and possibly with assertations.""" - mu = ops.convert_to_tensor(mu) cov = self._cov - if mu.dtype != cov.dtype: raise TypeError( "mu and cov must have the same dtype. Found mu.dtype = %s, " - "cov.dtype = %s" - % (mu.dtype, cov.dtype)) + "cov.dtype = %s" % (mu.dtype, cov.dtype)) # Try to validate with static checks. mu_shape = mu.get_shape() @@ -170,44 +172,6 @@ class _MultivariateNormalOperatorPD(distribution.Distribution): ) return control_flow_ops.with_dependencies([assert_same_shape], mu) - @property - def validate_args(self): - """`Boolean` describing behavior on invalid input.""" - return self._validate_args - - @property - def allow_nan_stats(self): - """`Boolean` describing behavior when stats are undefined.""" - return self._allow_nan_stats - - @property - def dtype(self): - return self._mu.dtype - - def get_event_shape(self): - """`TensorShape` available at graph construction time.""" - # Recall _check_mu ensures mu and self._cov have same batch shape. - return self._cov.get_shape()[-1:] - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`.""" - # Recall _check_mu ensures mu and self._cov have same batch shape. - with ops.name_scope(self.name): - with ops.name_scope(name, values=self._cov.inputs): - return array_ops.pack([self._cov.vector_space_dimension()]) - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`.""" - # Recall _check_mu ensures mu and self._cov have same batch shape. - with ops.name_scope(self.name): - with ops.name_scope(name, values=self._cov.inputs): - return self._cov.batch_shape() - - def get_batch_shape(self): - """`TensorShape` available at graph construction time.""" - # Recall _check_mu ensures mu and self._cov have same batch shape. - return self._cov.get_batch_shape() - @property def mu(self): return self._mu @@ -218,23 +182,6 @@ class _MultivariateNormalOperatorPD(distribution.Distribution): with ops.name_scope(self.name): return self._cov.to_dense() - def mean(self, name="mean"): - """Mean of each batch member.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu]): - return array_ops.identity(self._mu) - - def mode(self, name="mode"): - """Mode of each batch member.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu]): - return array_ops.identity(self._mu) - - def variance(self, name="variance"): - """Variance of each batch member.""" - with ops.name_scope(self.name): - return self.sigma - def log_sigma_det(self, name="log_sigma_det"): """Log of determinant of covariance matrix.""" with ops.name_scope(self.name): @@ -247,160 +194,111 @@ class _MultivariateNormalOperatorPD(distribution.Distribution): with ops.name_scope(name, values=self._cov.inputs): return math_ops.exp(self._cov.log_det()) - def log_prob(self, x, name="log_prob"): - """Log prob of observations `x` given these Multivariate Normals. + def _batch_shape(self): + return self._cov.batch_shape() - `x` is a batch vector with compatible shape if `x` is a `Tensor` whose - shape can be broadcast up to either: + def _get_batch_shape(self): + return self._cov.get_batch_shape() - ```` - self.batch_shape + self.event_shape - OR - [M1,...,Mm] + self.batch_shape + self.event_shape - ``` + def _event_shape(self): + return array_ops.pack([self._cov.vector_space_dimension()]) - Args: - x: Compatible batch vector with same `dtype` as this distribution. - name: The name to give this op. + def _get_event_shape(self): + return self._cov.get_shape()[-1:] - Returns: - log_prob: tensor of dtype `dtype`, the log-PDFs of `x`. - """ + def _sample_n(self, n, seed=None): + # Recall _assert_valid_mu ensures mu and self._cov have same batch shape. + shape = array_ops.concat(0, [self._cov.vector_shape(), [n]]) + white_samples = random_ops.random_normal(shape=shape, + mean=0, + stddev=1, + dtype=self.dtype, + seed=seed) + + correlated_samples = self._cov.sqrt_matmul(white_samples) + + # Move the last dimension to the front + perm = array_ops.concat(0, ( + array_ops.pack([array_ops.rank(correlated_samples) - 1]), + math_ops.range(0, array_ops.rank(correlated_samples) - 1))) + + # TODO(ebrevdo): Once we get a proper tensor contraction op, + # perform the inner product using that instead of batch_matmul + # and this slow transpose can go away! + correlated_samples = array_ops.transpose(correlated_samples, perm) + samples = correlated_samples + self.mu + return samples + + def _log_prob(self, x): # Q: Why are shape requirements as stated above? # A: The compatible shapes are precisely the ones that will broadcast to # a shape compatible with self._cov. # See Operator base class for notes about shapes compatible with self._cov. - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, x] + self._cov.inputs): - x = ops.convert_to_tensor(x) - contrib_tensor_util.assert_same_float_dtype((self._mu, x)) - - # _check_mu asserts that self.mu has same batch shape as self.cov. - # so batch shape of self.mu = that of self._cov and self, and the - # batch shape of x_centered is a broadcast version of these. If this - # broadcast results in a shape like - # [M1,...,Mm] + self.batch_shape + self.event_shape - # OR - # self.batch_shape + self.event_shape - # then subsequent operator calls are guaranteed to work. - x_centered = x - self.mu - - # Compute the term x^{-1} sigma^{-1} x which appears in the exponent of - # the pdf. - x_whitened_norm = self._cov.inv_quadratic_form_on_vectors(x_centered) - - log_sigma_det = self.log_sigma_det() - - log_two_pi = constant_op.constant( - math.log(2 * math.pi), dtype=self.dtype) - k = math_ops.cast(self._cov.vector_space_dimension(), self.dtype) - log_prob_value = -(log_sigma_det + k * log_two_pi + x_whitened_norm) / 2 - - output_static_shape = x_centered.get_shape()[:-1] - log_prob_value.set_shape(output_static_shape) - return log_prob_value - - def prob(self, x, name="prob"): - """The PDF of observations `x` under these Multivariate Normals. - - `x` is a batch vector with compatible shape if `x` is a `Tensor` whose - shape can be broadcast up to either: - - ```` - self.batch_shape + self.event_shape - OR - [M1,...,Mm] + self.batch_shape + self.event_shape - ``` - - Args: - x: Compatible batch vector with same `dtype` as this distribution. - name: The name to give this op. - - Returns: - prob: tensor of dtype `dtype`, the prob values of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, x] + self._cov.inputs): - return math_ops.exp(self.log_prob(x)) - - def entropy(self, name="entropy"): - """The entropies of these Multivariate Normals. - - Args: - name: The name to give this op. + x = ops.convert_to_tensor(x) + contrib_tensor_util.assert_same_float_dtype((self._mu, x)) - Returns: - entropy: tensor of dtype `dtype`, the entropies. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu] + self._cov.inputs): - log_sigma_det = self.log_sigma_det() - one_plus_log_two_pi = constant_op.constant(1 + math.log(2 * math.pi), - dtype=self.dtype) + # _assert_valid_mu asserts that self.mu has same batch shape as self.cov. + # so batch shape of self.mu = that of self._cov and self, and the + # batch shape of x_centered is a broadcast version of these. If this + # broadcast results in a shape like + # [M1,...,Mm] + self.batch_shape + self.event_shape + # OR + # self.batch_shape + self.event_shape + # then subsequent operator calls are guaranteed to work. + x_centered = x - self.mu - # Use broadcasting rules to calculate the full broadcast sigma. - k = math_ops.cast(self._cov.vector_space_dimension(), dtype=self.dtype) - entropy_value = (k * one_plus_log_two_pi + log_sigma_det) / 2 - entropy_value.set_shape(log_sigma_det.get_shape()) - return entropy_value + # Compute the term x^{-1} sigma^{-1} x which appears in the exponent of + # the pdf. + x_whitened_norm = self._cov.inv_quadratic_form_on_vectors(x_centered) - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Multivariate Normal Distributions. + k = math_ops.cast(self._cov.vector_space_dimension(), self.dtype) + log_prob_value = -0.5 * (self.log_sigma_det() + + k * math.log(2. * math.pi) + + x_whitened_norm) - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. + output_static_shape = x_centered.get_shape()[:-1] + log_prob_value.set_shape(output_static_shape) + return log_prob_value - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, n] + self._cov.inputs): - # Recall _check_mu ensures mu and self._cov have same batch shape. - broadcast_shape = self.mu.get_shape() - n = ops.convert_to_tensor(n) - - shape = array_ops.concat(0, [self._cov.vector_shape(), [n]]) - white_samples = random_ops.random_normal(shape=shape, - mean=0, - stddev=1, - dtype=self.dtype, - seed=seed) + def _prob(self, x): + return math_ops.exp(self.log_prob(x)) - correlated_samples = self._cov.sqrt_matmul(white_samples) + def _entropy(self): + log_sigma_det = self.log_sigma_det() + one_plus_log_two_pi = constant_op.constant(1 + math.log(2 * math.pi), + dtype=self.dtype) - # Move the last dimension to the front - perm = array_ops.concat(0, ( - array_ops.pack([array_ops.rank(correlated_samples) - 1]), - math_ops.range(0, array_ops.rank(correlated_samples) - 1))) + # Use broadcasting rules to calculate the full broadcast sigma. + k = math_ops.cast(self._cov.vector_space_dimension(), dtype=self.dtype) + entropy_value = (k * one_plus_log_two_pi + log_sigma_det) / 2 + entropy_value.set_shape(log_sigma_det.get_shape()) + return entropy_value - # TODO(ebrevdo): Once we get a proper tensor contraction op, - # perform the inner product using that instead of batch_matmul - # and this slow transpose can go away! - correlated_samples = array_ops.transpose(correlated_samples, perm) + def _mean(self): + return array_ops.identity(self._mu) - samples = correlated_samples + self.mu + def _variance(self): + return self.sigma - # Provide some hints to shape inference - n_val = tensor_util.constant_value(n) - final_shape = tensor_shape.vector(n_val).concatenate(broadcast_shape) - samples.set_shape(final_shape) + def _mode(self): + return array_ops.identity(self._mu) - return samples - @property - def is_reparameterized(self): - return True +_prob_note = """ + `x` is a batch vector with compatible shape if `x` is a `Tensor` whose + shape can be broadcast up to either: - @property - def name(self): - return self._name + ```` + self.batch_shape + self.event_shape + OR + [M1,...,Mm] + self.batch_shape + self.event_shape + ``` - @property - def is_continuous(self): - return True +""" +distribution_util.append_class_fun_doc(_MultivariateNormalOperatorPD.log_prob, + doc_str=_prob_note) +distribution_util.append_class_fun_doc(_MultivariateNormalOperatorPD.prob, + doc_str=_prob_note) class MultivariateNormalDiag(_MultivariateNormalOperatorPD): diff --git a/tensorflow/contrib/distributions/python/ops/normal.py b/tensorflow/contrib/distributions/python/ops/normal.py index 54813ad99098e609d64bfc19660147edc6db9a1b..2660f2970bcbd6c78118a73cf46a0ed2d9bdeaeb 100644 --- a/tensorflow/contrib/distributions/python/ops/normal.py +++ b/tensorflow/contrib/distributions/python/ops/normal.py @@ -20,15 +20,14 @@ from __future__ import print_function import math -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long -from tensorflow.contrib.distributions.python.ops import kullback_leibler # pylint: disable=line-too-long -from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util # pylint: disable=line-too-long +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import kullback_leibler +from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import common_shapes from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import math_ops @@ -108,21 +107,19 @@ class Normal(distribution.Distribution): Raises: TypeError: if mu and sigma are different dtypes. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args with ops.name_scope(name, values=[mu, sigma]): - mu = ops.convert_to_tensor(mu) - sigma = ops.convert_to_tensor(sigma) with ops.control_dependencies([check_ops.assert_positive(sigma)] if validate_args else []): - self._name = name self._mu = array_ops.identity(mu, name="mu") self._sigma = array_ops.identity(sigma, name="sigma") - self._batch_shape = common_shapes.broadcast_shape( - self._mu.get_shape(), self._sigma.get_shape()) - self._event_shape = tensor_shape.TensorShape([]) - - contrib_tensor_util.assert_same_float_dtype((mu, sigma)) + contrib_tensor_util.assert_same_float_dtype((self._mu, self._sigma)) + super(Normal, self).__init__( + dtype=self._sigma.dtype, + parameters={"mu": self._mu, "sigma": self._sigma}, + is_reparameterized=True, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @staticmethod def _param_shapes(sample_shape): @@ -141,73 +138,6 @@ class Normal(distribution.Distribution): """ return {"sigma": nn.softplus} - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._mu.dtype - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma]): - return array_ops.shape(self._mu + self._sigma) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._batch_shape - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._event_shape - @property def mu(self): """Distribution parameter for the mean.""" @@ -218,148 +148,58 @@ class Normal(distribution.Distribution): """Distribution parameter for standard deviation.""" return self._sigma - def mean(self, name="mean"): - """Mean of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._sigma, self._mu]): - return self._mu * array_ops.ones_like(self._sigma) - - def mode(self, name="mode"): - """Mode of this distribution.""" - return self.mean(name="mode") - - def std(self, name="std"): - """Standard deviation of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._sigma, self._mu]): - return self._sigma * array_ops.ones_like(self._mu) - - def variance(self, name="variance"): - """Variance of this distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.square(self.std()) - - def log_prob(self, x, name="log_prob"): - """Log prob of observations in `x` under these Normal distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. - name: The name to give this op. - - Returns: - log_prob: tensor of dtype `dtype`, the log-PDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" - % (x.dtype, self.dtype)) - log_2_pi = constant_op.constant(math.log(2 * math.pi), dtype=self.dtype) - return (-0.5*log_2_pi - math_ops.log(self._sigma) - -0.5*math_ops.square((x - self._mu) / self._sigma)) - - def cdf(self, x, name="cdf"): - """CDF of observations in `x` under these Normal distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. - name: The name to give this op. - - Returns: - cdf: tensor of dtype `dtype`, the CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" - % (x.dtype, self.dtype)) - # TODO(ebrevdo): wrap this in a Defun with a custom Defun - # gradient because the analytic gradient may be faster than - # automatic differentiation. - return (0.5 + 0.5*math_ops.erf( - 1.0/(math.sqrt(2.0) * self._sigma)*(x - self._mu))) - - def log_cdf(self, x, name="log_cdf"): - """Log CDF of observations `x` under these Normal distribution(s). + def _batch_shape(self): + return array_ops.shape(self.mu + self.sigma) - Args: - x: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. - name: The name to give this op. + def _get_batch_shape(self): + return common_shapes.broadcast_shape( + self._mu.get_shape(), self.sigma.get_shape()) - Returns: - log_cdf: tensor of dtype `dtype`, the log-CDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma, x]): - return math_ops.log(self.cdf(x)) + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) - def prob(self, x, name="prob"): - """The PDF of observations in `x` under these Normal distribution(s). + def _get_event_shape(self): + return tensor_shape.scalar() - Args: - x: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. - name: The name to give this op. + def _sample_n(self, n, seed=None): + shape = array_ops.concat(0, ([n], array_ops.shape(self.mean()))) + sampled = random_ops.random_normal( + shape=shape, mean=0, stddev=1, dtype=self.mu.dtype, seed=seed) + return sampled * self.sigma + self.mu - Returns: - prob: tensor of dtype `dtype`, the prob values of `x`. - """ - return super(Normal, self).prob(x, name=name) + def _log_prob(self, x): + return (-0.5 * math.log(2. * math.pi) - math_ops.log(self.sigma) + -0.5 * math_ops.square((x - self.mu) / self.sigma)) - def entropy(self, name="entropy"): - """The entropy of Normal distribution(s). + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) - Args: - name: The name to give this op. + def _log_cdf(self, x): + return math_ops.log(self._cdf(x)) - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma]): - two_pi_e1 = constant_op.constant( - 2 * math.pi * math.exp(1), dtype=self.dtype) - # Use broadcasting rules to calculate the full broadcast sigma. - sigma = self._sigma * array_ops.ones_like(self._mu) - return 0.5 * math_ops.log(two_pi_e1 * math_ops.square(sigma)) + def _cdf(self, x): + # TODO(ebrevdo): wrap this in a Defun with a custom Defun + # gradient because the analytic gradient may be faster than + # automatic differentiation. + return (0.5 + 0.5*math_ops.erf( + 1. / (math.sqrt(2.) * self.sigma) * (x - self.mu))) - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Normal Distributions. + def _entropy(self): + # Use broadcasting rules to calculate the full broadcast sigma. + sigma = self.sigma * array_ops.ones_like(self.mu) + return 0.5 * math.log(2. * math.pi * math.e) + math_ops.log(sigma) - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. + def _mean(self): + return self.mu * array_ops.ones_like(self.sigma) - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu, self._sigma, n]): - broadcast_shape = common_shapes.broadcast_shape( - self._mu.get_shape(), self._sigma.get_shape()) - n = ops.convert_to_tensor(n) - shape = array_ops.concat(0, ([n], array_ops.shape(self.mean()))) - sampled = random_ops.random_normal( - shape=shape, mean=0, stddev=1, dtype=self._mu.dtype, seed=seed) - - # Provide some hints to shape inference - n_val = tensor_util.constant_value(n) - final_shape = tensor_shape.vector(n_val).concatenate(broadcast_shape) - sampled.set_shape(final_shape) - - return sampled * self._sigma + self._mu + def _variance(self): + return math_ops.square(self.std()) - @property - def is_reparameterized(self): - return True + def _std(self): + return self.sigma * array_ops.ones_like(self.mu) - @property - def is_continuous(self): - return True + def _mode(self): + return self._mean() @kullback_leibler.RegisterKL(Normal, Normal) @@ -382,5 +222,5 @@ def _kl_normal_normal(n_a, n_b, name=None): s_a_squared = math_ops.square(n_a.sigma) s_b_squared = math_ops.square(n_b.sigma) ratio = s_a_squared / s_b_squared - return (math_ops.square(n_a.mu - n_b.mu) / (two * s_b_squared) - + half * (ratio - one - math_ops.log(ratio))) + return (math_ops.square(n_a.mu - n_b.mu) / (two * s_b_squared) + + half * (ratio - one - math_ops.log(ratio))) diff --git a/tensorflow/contrib/distributions/python/ops/poisson.py b/tensorflow/contrib/distributions/python/ops/poisson.py index 524dd13442f230362878cf417ad78039205a01db..778b6af33dac14bc0d598b59a544c574cfa94763 100644 --- a/tensorflow/contrib/distributions/python/ops/poisson.py +++ b/tensorflow/contrib/distributions/python/ops/poisson.py @@ -29,10 +29,6 @@ from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import math_ops -__all__ = [ - 'Poisson', -] - class Poisson(distribution.Distribution): """Poisson distribution. @@ -68,186 +64,83 @@ class Poisson(distribution.Distribution): undefined statistics will return NaN for this statistic. name: A name for this distribution. """ - with ops.name_scope(name, values=[lam]) as scope: - self._name = scope - with ops.control_dependencies( - [check_ops.assert_positive(lam)] if validate_args else []): + with ops.name_scope(name, values=[lam]): + with ops.control_dependencies([check_ops.assert_positive(lam)] if + validate_args else []): self._lam = array_ops.identity(lam, name="lam") - self._validate_args = validate_args - self._allow_nan_stats = allow_nan_stats - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._lam.dtype + super(Poisson, self).__init__( + dtype=self._lam.dtype, + parameters={"lam": self._lam}, + is_continuous=False, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def lam(self): """Rate parameter.""" return self._lam - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - def batch_shape(self, name="batch_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam]): - return array_ops.shape(self.lam) + def _batch_shape(self): + return array_ops.shape(self.lam) - def get_batch_shape(self): + def _get_batch_shape(self): return self.lam.get_shape() - def event_shape(self, name="event_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) - def get_event_shape(self): + def _get_event_shape(self): return tensor_shape.scalar() - def log_cdf(self, x, name="log_cdf"): - """Log cumulative density function. + def _log_prob(self, x): + x = self._assert_valid_sample(x, check_integer=True) + return x * math_ops.log(self.lam) - self.lam - math_ops.lgamma(x + 1) - Args: - x: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. - name: A name for this operation. + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) - Returns: - The Log CDF of the events. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[x]): - return math_ops.log(self.cdf(x)) + def _log_cdf(self, x): + return math_ops.log(self.cdf(x)) - def cdf(self, x, name="cdf"): - """Cumulative density function. + def _cdf(self, x): + x = self._assert_valid_sample(x, check_integer=False) + return math_ops.igammac(math_ops.floor(x + 1), self.lam) - Args: - x: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. - name: A name for this operation. - - Returns: - The CDF of the events. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam, x]): - x = self._check_x(x, check_integer=False) - return math_ops.igammac(math_ops.floor(x + 1), self.lam) + def _mean(self): + return array_ops.identity(self.lam) - def prob(self, x, name="prob"): - """Probability mass function. + def _variance(self): + return array_ops.identity(self.lam) - Args: - x: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. - name: A name for this operation. - - Returns: - The probabilities of the events. - """ - return super(Poisson, self).prob(x, name) - - def log_prob(self, x, name="log_prob"): - """Log probability mass function. - - Args: - x: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. - name: A name for this operation (optional). - - Returns: - The log-probabilities of the events. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam, x]): - x = self._check_x(x, check_integer=True) - return x * math_ops.log(self.lam) - self.lam - math_ops.lgamma(x + 1) - - def mean(self, name="mean"): - """Mean of the distribution. - - Args: - name: Name for the op. - - Returns: - mean: `Tensor` of the same type and shape as `lam`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam]): - return array_ops.identity(self.lam) + def _std(self): + return math_ops.sqrt(self.variance()) - def variance(self, name="variance"): - """Variance of the distribution. + def _mode(self): + return math_ops.floor(self.lam) - Args: - name: Name for the op. - - Returns: - variance: `Tensor` of the same type and shape as `lam`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam]): - return array_ops.identity(self.lam) + def _assert_valid_sample(self, x, check_integer=True): + if not self.validate_args: return x + with ops.name_scope('check_x', values=[x]): + dependencies = [check_ops.assert_non_negative(x)] + if check_integer: + dependencies += [distribution_util.assert_integer_form( + x, message="x has non-integer components.")] + return control_flow_ops.with_dependencies(dependencies, x) - def std(self, name="std"): - """Standard deviation of the distribution. - Args: - name: Name for the op. +_prob_note = """ - Returns: - std: `Tensor` of the same type and shape as `lam`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam]): - return math_ops.sqrt(self.variance()) + Note thet the input value must be a non-negative floating point tensor with + dtype `dtype` and whose shape can be broadcast with `self.lam`. `x` is only + legal if it is non-negative and its components are equal to integer values. +""" +distribution_util.append_class_fun_doc(Poisson.log_prob, doc_str=_prob_note) +distribution_util.append_class_fun_doc(Poisson.prob, doc_str=_prob_note) - def mode(self, name="mode"): - """Mode of the distribution. +distribution_util.append_class_fun_doc(Poisson.mode, doc_str=""" Note that when `lam` is an integer, there are actually two modes. Namely, `lam` and `lam - 1` are both modes. Here we return only the larger of the two modes. - - Args: - name: Name for the op. - - Returns: - mode: `Tensor` of the same type and shape as `lam`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.lam]): - return math_ops.floor(self.lam) - - @property - def is_continuous(self): - return False - - @property - def is_reparameterized(self): - return False - - def _check_x(self, x, check_integer=True): - with ops.name_scope('check_x', values=[x]): - x = ops.convert_to_tensor(x, name="x") - if not self.validate_args: - return x - dependencies = [check_ops.assert_non_negative(x)] - if check_integer: - dependencies += [distribution_util.assert_integer_form( - x, message="x has non-integer components.")] - return control_flow_ops.with_dependencies(dependencies, x) +""") diff --git a/tensorflow/contrib/distributions/python/ops/student_t.py b/tensorflow/contrib/distributions/python/ops/student_t.py index fd02e1d2ece1dc4ccc870ea97c64526aa18d56f1..7ed661e0cb5ab371cda82c87d1f45aab696e2a6a 100644 --- a/tensorflow/contrib/distributions/python/ops/student_t.py +++ b/tensorflow/contrib/distributions/python/ops/student_t.py @@ -19,16 +19,15 @@ from __future__ import division from __future__ import print_function import math - import numpy as np -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long -from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util # pylint: disable=line-too-long +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util +from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import common_shapes from tensorflow.python.framework import constant_op from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import control_flow_ops @@ -119,39 +118,23 @@ class StudentT(distribution.Distribution): Raises: TypeError: if mu and sigma are different dtypes. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - with ops.name_scope(name, values=[df, mu, sigma]) as scope: - with ops.control_dependencies([check_ops.assert_positive( - df), check_ops.assert_positive(sigma)] if validate_args else []): - self._df = ops.convert_to_tensor(df, name="df") - self._mu = ops.convert_to_tensor(mu, name="mu") - self._sigma = ops.convert_to_tensor(sigma, name="sigma") + with ops.name_scope(name, values=[df, mu, sigma]): + with ops.control_dependencies([ + check_ops.assert_positive(df), + check_ops.assert_positive(sigma), + ] if validate_args else []): + self._df = array_ops.identity(df, name="df") + self._mu = array_ops.identity(mu, name="mu") + self._sigma = array_ops.identity(sigma, name="sigma") contrib_tensor_util.assert_same_float_dtype( (self._df, self._mu, self._sigma)) - self._name = scope - self._get_batch_shape = common_shapes.broadcast_shape( - self._sigma.get_shape(), common_shapes.broadcast_shape( - self._df.get_shape(), self._mu.get_shape())) - self._get_event_shape = tensor_shape.TensorShape([]) - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._df.dtype + super(StudentT, self).__init__( + dtype=self._sigma.dtype, + parameters={"df": self._df, "mu": self._mu, "sigma": self._sigma}, + is_reparameterized=True, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def df(self): @@ -168,41 +151,125 @@ class StudentT(distribution.Distribution): """Scaling factors of these Student's t distribution(s).""" return self._sigma - def mean(self, name="mean"): - """Mean of the distribution. + def _batch_shape(self): + return array_ops.shape(self.df + self.mu + self.sigma) + + def _get_batch_shape(self): + return common_shapes.broadcast_shape( + self.sigma.get_shape(), + common_shapes.broadcast_shape( + self.df.get_shape(), + self.mu.get_shape())) + + def _event_shape(self): + return constant_op.constant([], dtype=math_ops.int32) + + def _get_event_shape(self): + return tensor_shape.scalar() + + def _sample_n(self, n, seed=None): + # We use 2 uniform random floats to generate polar random variates. + # http://dl.acm.org/citation.cfm?id=179631 + # Theorem 2. Let G, H be iid variates, uniformly distributed on [0,1]. + # Let theta = 2*pi*H, let R = sqrt(df*(G^(-2/df) - 1)) for df > 0. + # Let X = R*cos(theta), and let Y = R*sin(theta). + # Then X ~ t_df and Y ~ t_df. + # The variates X and Y are not independent. + shape = array_ops.concat(0, ([2, n], self.batch_shape())) + uniform = random_ops.random_uniform(shape=shape, + dtype=self.dtype, + seed=seed) + samples_g, samples_h = array_ops.unpack(uniform, num=2) + theta = (2. * math.pi) * samples_h + r = math_ops.sqrt(self.df * + (math_ops.pow(samples_g, -2 / self.df) - 1)) + samples = r * math_ops.cos(theta) + return samples * self.sigma + self.mu + + def _log_prob(self, x): + y = (x - self.mu) / self.sigma + half_df = 0.5 * self.df + return (math_ops.lgamma(0.5 + half_df) - + math_ops.lgamma(half_df) - + 0.5 * math_ops.log(self.df) - + 0.5 * math.log(math.pi) - + math_ops.log(self.sigma) - + (0.5 + half_df) * math_ops.log(1. + math_ops.square(y) / self.df)) + + def _prob(self, x): + y = (x - self.mu) / self.sigma + half_df = 0.5 * self.df + return (math_ops.exp(math_ops.lgamma(0.5 + half_df) - + math_ops.lgamma(half_df)) / + (math_ops.sqrt(self.df) * math.sqrt(math.pi) * self.sigma) * + math_ops.pow(1. + math_ops.square(y) / self.df, -(0.5 + half_df))) + + def _entropy(self): + u = array_ops.expand_dims(self.df * self._ones(), -1) + v = array_ops.expand_dims(self._ones(), -1) + beta_arg = array_ops.concat(len(u.get_shape()) - 1, [u, v]) / 2 + half_df = 0.5 * self.df + return ((0.5 + half_df) * (math_ops.digamma(0.5 + half_df) - + math_ops.digamma(half_df)) + + 0.5 * math_ops.log(self.df) + + special_math_ops.lbeta(beta_arg) + + math_ops.log(self.sigma)) + + def _mean(self): + mean = self.mu * self._ones() + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + math_ops.greater(self.df, self._ones()), mean, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), dtype=self.dtype), self.df, + message="mean not defined for components of df <= 1"), + ], mean) + + def _variance(self): + var = (self._ones() * + math_ops.square(self.sigma) * self.df / (self.df - 2)) + # When 1 < df <= 2, variance is infinite. + inf = np.array(np.inf, dtype=self.dtype.as_numpy_dtype()) + result_where_defined = math_ops.select( + math_ops.greater(self.df, array_ops.fill(self.batch_shape(), 2.)), + var, + array_ops.fill(self.batch_shape(), inf, name="inf")) + + if self.allow_nan_stats: + nan = np.array(np.nan, dtype=self.dtype.as_numpy_dtype()) + return math_ops.select( + math_ops.greater(self.df, self._ones()), + result_where_defined, + array_ops.fill(self.batch_shape(), nan, name="nan")) + else: + return control_flow_ops.with_dependencies([ + check_ops.assert_less( + array_ops.ones((), dtype=self.dtype), self.df, + message="variance not defined for components of df <= 1"), + ], result_where_defined) + + def _std(self): + return math_ops.sqrt(self.variance()) + + def _mode(self): + return array_ops.identity(self.mu) + + def _ones(self): + return array_ops.ones(self.batch_shape(), dtype=self.dtype) + + +distribution_util.append_class_fun_doc(StudentT.mean, doc_str=""" The mean of Student's T equals `mu` if `df > 1`, otherwise it is `NaN`. If `self.allow_nan_stats=False`, then an exception will be raised rather than returning `NaN`. +""") - Args: - name: A name to give this op. - - Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu]): - result_if_defined = self._mu * self._ones() - if self.allow_nan_stats: - df_gt_1 = self._df > self._ones() - nan = np.nan + self._zeros() - return math_ops.select(df_gt_1, result_if_defined, nan) - else: - one = constant_op.constant(1.0, dtype=self.dtype) - return control_flow_ops.with_dependencies( - [check_ops.assert_less( - one, self._df, - message="mean not defined for components of df <= 1" - )], result_if_defined) - - def mode(self, name="mode"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._mu]): - return array_ops.identity(self._mu) - - def variance(self, name="variance"): - """Variance of the distribution. +distribution_util.append_class_fun_doc(StudentT.variance, doc_str=""" Variance for Student's T equals @@ -212,179 +279,4 @@ class StudentT(distribution.Distribution): NaN, when df <= 1 ``` - The NaN state occurs because mean is undefined for `df <= 1`, and if - `self.allow_nan_stats` is `False`, an exception will be raised if any batch - members fall into this state. - - Args: - name: A name for this op. - - Returns: - The variance for every batch member, a `Tensor` with same `dtype` as self. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._df, self._sigma]): - result_where_finite = ( - self._zeros() - + math_ops.square(self._sigma) * self._df / (self._df - 2)) - # When 1 < df <= 2, variance is infinite. - result_where_defined = math_ops.select( - self._zeros() + self._df > 2, - result_where_finite, - self._zeros() + np.inf) - - if self.allow_nan_stats: - return math_ops.select( - (self._zeros() + self._df > 1), - result_where_defined, - self._zeros() + np.nan) - else: - one = constant_op.constant(1.0, dtype=self.dtype) - return control_flow_ops.with_dependencies( - [check_ops.assert_less( - one, self._df, - message="variance not defined for components of df <= 1" - )], result_where_defined) - - def std(self, name="std"): - with ops.name_scope(self.name): - with ops.name_scope(name): - return math_ops.sqrt(self.variance()) - - def batch_shape(self, name="batch_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name): - return array_ops.shape(self._ones()) - - def get_batch_shape(self): - return self._get_batch_shape - - def event_shape(self, name="event_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=math_ops.int32) - - def get_event_shape(self): - return self._event_shape - - def log_prob(self, x, name="log_prob"): - """Log prob of observations in `x` under these Student's t-distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `mu` and `df`. - name: The name to give this op. - - Returns: - log_prob: tensor of dtype `dtype`, the log-PDFs of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._df, self._mu, self._sigma, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" % - (x.dtype, self.dtype)) - df_2 = self._df / 2 - log_beta = (math_ops.lgamma(0.5) + math_ops.lgamma(df_2) - - math_ops.lgamma(0.5 + df_2)) - return (-math_ops.log(self._df) / 2 - log_beta - (self._df + 1) / 2 * - math_ops.log(1 + math_ops.square((x - self._mu) / self._sigma) / - self._df) - math_ops.log(self._sigma)) - - def prob(self, x, name="prob"): - """The PDF of observations in `x` under these Student's t distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `df`, `mu`, and - `sigma`. - name: The name to give this op. - - Returns: - prob: tensor of dtype `dtype`, the prob values of `x`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._df, self._mu, self._sigma, x]): - x = ops.convert_to_tensor(x) - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" % - (x.dtype, self.dtype)) - reloc_scaled = (x - self._mu) / self._sigma - return (math_ops.exp(math_ops.lgamma((self._df + 1) / 2) - - math_ops.lgamma(self._df / 2)) / - math_ops.sqrt(self._df) / math.sqrt(np.pi) * - math_ops.pow(1 + math_ops.square(reloc_scaled) / self._df, - -(self._df + 1) / 2) / self.sigma) - - def entropy(self, name="entropy"): - """The entropy of Student t distribution(s). - - Args: - name: The name to give this op. - - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._df, self._sigma]): - u = array_ops.expand_dims(self._df + self._zeros(), -1) - v = array_ops.expand_dims(self._ones(), -1) - beta_arg = array_ops.concat(len(u.get_shape()) - 1, [u, v]) / 2 - return ((self._df + 1) / 2 * (math_ops.digamma((self._df + 1) / 2) - - math_ops.digamma(self._df / 2)) + - math_ops.log(self._df) / 2 + - special_math_ops.lbeta(beta_arg) + - math_ops.log(self._sigma)) - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Student t Distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._df, self._mu, self._sigma, n]): - n = ops.convert_to_tensor(n, name="n") - n_val = tensor_util.constant_value(n) - - # We use 2 uniform random floats to generate polar random variates. - # http://dl.acm.org/citation.cfm?id=179631 - # Theorem 2. Let G, H be iid variates, uniformly distributed on [0,1]. - # Let theta = 2*pi*H, let R = sqrt(df*(G^(-2/df) - 1)) for df > 0. - # Let X = R*cos(theta), and let Y = R*sin(theta). - # Then X ~ t_df and Y ~ t_df. - # The variates X and Y are not independent. - shape = array_ops.concat(0, ([2, n], self.batch_shape())) - uniform = random_ops.random_uniform(shape=shape, - dtype=self.dtype, - seed=seed) - samples_g, samples_h = array_ops.unpack(uniform, num=2) - theta = (2 * np.pi) * samples_h - r = math_ops.sqrt(self._df * - (math_ops.pow(samples_g, -2 / self._df) - 1)) - samples = r * math_ops.cos(theta) - - # Provide some hints to shape inference - inferred_shape = tensor_shape.vector(n_val).concatenate( - self.get_batch_shape()) - samples.set_shape(inferred_shape) - - return samples * self._sigma + self._mu - - @property - def is_reparameterized(self): - return True - - def _ones(self): - return array_ops.ones_like(self._df + self._mu + self._sigma) - - def _zeros(self): - return array_ops.zeros_like(self._df + self._mu + self._sigma) - - @property - def is_continuous(self): - return True +""") diff --git a/tensorflow/contrib/distributions/python/ops/transformed_distribution.py b/tensorflow/contrib/distributions/python/ops/transformed_distribution.py index 24429332c08fe625daa5cb4b30ee57cb0d4030f7..68a19cd9ebc8a76416286f99706b46bb882ab643 100644 --- a/tensorflow/contrib/distributions/python/ops/transformed_distribution.py +++ b/tensorflow/contrib/distributions/python/ops/transformed_distribution.py @@ -17,8 +17,10 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.distributions.python.ops import distribution_util from tensorflow.python.framework import ops +from tensorflow.python.ops import math_ops class TransformedDistribution(distribution.Distribution): @@ -85,70 +87,18 @@ class TransformedDistribution(distribution.Distribution): TypeError: if `base_dist_cls` is not a subclass of `Distribution`. """ - if not issubclass(base_dist_cls, distribution.Distribution): - raise TypeError("base_dist_cls must be a subclass of Distribution.") - with ops.name_scope(name, values=base_dist_args.values()) as scope: - self._name = scope + with ops.name_scope(name, values=base_dist_args.values()): self._base_dist = base_dist_cls(**base_dist_args) - self._transform = transform - self._inverse = inverse - self._log_det_jacobian = log_det_jacobian - self._inverse_cache = {} - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self._base_dist.dtype - - def batch_shape(self, name="batch_shape"): - """Batch dimensions of this instance as a 1-D int32 `Tensor`. - - The product of the dimensions of the `batch_shape` is the number of - independent distributions of this kind the instance represents. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `batch_shape` - """ - with ops.name_scope(self.name): - return self._base_dist.batch_shape(name) - - def get_batch_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `batch_shape`. May be only partially defined. - - Returns: - batch shape - """ - return self._base_dist.get_batch_shape() - - def event_shape(self, name="event_shape"): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`. - - Args: - name: name to give to the op. - - Returns: - `Tensor` `event_shape` - """ - with ops.name_scope(self.name): - return self._base_dist.event_shape(name) - - def get_event_shape(self): - """`TensorShape` available at graph construction time. - - Same meaning as `event_shape`. May be only partially defined. - - Returns: - event shape - """ - return self._base_dist.get_event_shape() + self._transform = transform + self._inverse = inverse + self._log_det_jacobian = log_det_jacobian + self._inverse_cache = {} + super(TransformedDistribution, self).__init__( + dtype=self._base_dist.dtype, + is_reparameterized=self._base_dist.is_reparameterized, + validate_args=self._base_dist.validate_args, + allow_nan_stats=self._base_dist.allow_nan_stats, + name=name) @property def base_distribution(self): @@ -170,87 +120,74 @@ class TransformedDistribution(distribution.Distribution): """Function computing the log determinant of the Jacobian of transform.""" return self._log_det_jacobian - def log_prob(self, y, name="log_prob"): - """Log prob of observations in `y`. + def _batch_shape(self): + return self.base_distribution.batch_shape() - `log ( p(g(y)) / det|J(g(y))| )`, where `g` is the inverse of `transform`. + def _get_batch_shape(self): + return self.base_distribution.get_batch_shape() - Args: - y: tensor of dtype `dtype`. - name: The name to give this op. + def _event_shape(self): + return self.base_distribution.event_shape() - Returns: - log_pdf: tensor of dtype `dtype`, the log-PDFs of `y`. + def _get_event_shape(self): + return self.base_distribution.get_event_shape() - Raises: - ValueError: if `inverse` was not provided to the distribution and `y` was - not returned from `sample`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[y]): - y = ops.convert_to_tensor(y) - if y.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" % - (y.dtype, self.dtype)) - with ops.name_scope("inverse"): - if y in self._inverse_cache: - x = self._inverse_cache[y] - elif self._inverse: - x = self._inverse(y) - else: - raise ValueError("No inverse function exists and input `y` was not " - "returned from `sample`.") - with ops.name_scope("log_det_jacobian"): - log_det_jacobian = self._log_det_jacobian(x) - return self._base_dist.log_prob(x) - log_det_jacobian - - def prob(self, y, name="prob"): - """The prob of observations in `y`. - - `p(g(y)) / det|J(g(y))|`, where `g` is the inverse of `transform`. + def _sample_n(self, n, seed=None): + samples = self.base_distribution.sample_n(n=n, seed=seed) + with ops.name_scope("transform"): + transformed = self.transform(samples) + self._inverse_cache[transformed] = samples + return transformed - Args: - y: `Tensor` of dtype `dtype`. - name: The name to give this op. + def _log_prob(self, y): + y = ops.convert_to_tensor(y, name="y") + with ops.name_scope("inverse"): + if y in self._inverse_cache: + x = self._inverse_cache[y] + elif self.inverse: + x = self.inverse(y) + else: + raise ValueError("No inverse function exists and input `y` was not " + "returned from `sample`.") + with ops.name_scope("log_det_jacobian"): + log_det_jacobian = self.log_det_jacobian(x) + return self.base_distribution.log_prob(x) - log_det_jacobian - Returns: - pdf: `Tensor` of dtype `dtype`, the pdf values of `y`. - """ - return super(TransformedDistribution, self).prob(y, name=name) + def _prob(self, y): + return math_ops.exp(self._log_prob(y)) - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations. + +distribution_util.append_class_fun_doc(TransformedDistribution.batch_shape, + doc_str=""" + + The product of the dimensions of the `batch_shape` is the number of + independent distributions of this kind the instance represents. + +""") + +distribution_util.append_class_fun_doc(TransformedDistribution.sample_n, + doc_str=""" Samples from the base distribution and then passes through the transform. +""") - Args: - n: scalar, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. +distribution_util.append_class_fun_doc(TransformedDistribution.log_prob, + doc_str=""" - Returns: - samples: `[n, ...]`, a `Tensor` of `n` samples. - """ - with ops.name_scope(self.name): - with ops.name_scope(name): - samples = self._base_dist.sample_n(n=n, seed=seed) - with ops.name_scope("transform"): - transformed = self._transform(samples) - self._inverse_cache[transformed] = samples - return transformed + `(log o p o g)(y) - (log o det o J o g)(y)`, + where `g` is the inverse of `transform`. - @property - def is_reparameterized(self): - return self._base_dist.is_reparameterized + Raises: + ValueError: if `inverse` was not provided to the distribution and `y` was + not returned from `sample`. +""") - @property - def allow_nan_stats(self): - return self._base_dist.allow_nan_stats +distribution_util.append_class_fun_doc(TransformedDistribution.prob, + doc_str=""" - @property - def validate_args(self): - return self._base_dist.validate_args + `p(g(y)) / det|J(g(y))|`, where `g` is the inverse of `transform`. - @property - def is_continuous(self): - return True + Raises: + ValueError: if `inverse` was not provided to the distribution and `y` was + not returned from `sample`. +""") diff --git a/tensorflow/contrib/distributions/python/ops/uniform.py b/tensorflow/contrib/distributions/python/ops/uniform.py index 3174cf2549209c2631435b4c3ad709c9d81aa8d0..0df823315f08d645ea0d8eb2c9c1d8587e75103a 100644 --- a/tensorflow/contrib/distributions/python/ops/uniform.py +++ b/tensorflow/contrib/distributions/python/ops/uniform.py @@ -18,14 +18,15 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.contrib.distributions.python.ops import distribution # pylint: disable=line-too-long -from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util # pylint: disable=line-too-long +import math + +from tensorflow.contrib.distributions.python.ops import distribution +from tensorflow.contrib.framework.python.framework import tensor_util as contrib_tensor_util from tensorflow.python.framework import common_shapes from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.framework import tensor_shape -from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops from tensorflow.python.ops import math_ops @@ -39,8 +40,8 @@ class Uniform(distribution.Distribution): """ def __init__(self, - a=0.0, - b=1.0, + a=0., + b=1., validate_args=True, allow_nan_stats=False, name="Uniform"): @@ -81,57 +82,19 @@ class Uniform(distribution.Distribution): Raises: InvalidArgumentError: if `a >= b` and `validate_args=True`. """ - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - with ops.name_scope(name, values=[a, b]): - with ops.control_dependencies([check_ops.assert_less( - a, b, message="uniform not defined when a > b.")] if validate_args - else []): - a = array_ops.identity(a, name="a") - b = array_ops.identity(b, name="b") - - self._a = a - self._b = b - self._name = name - self._batch_shape = common_shapes.broadcast_shape( - self._a.get_shape(), self._b.get_shape()) - self._event_shape = tensor_shape.TensorShape([]) - - contrib_tensor_util.assert_same_float_dtype((a, b)) - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - return self._name - - @property - def dtype(self): - return self.a.dtype - - def batch_shape(self, name="batch_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._b]): - return array_ops.shape(self._a + self._b) - - def get_batch_shape(self): - return self._batch_shape - - def event_shape(self, name="event_shape"): - with ops.name_scope(self.name): - with ops.name_scope(name): - return constant_op.constant([], dtype=dtypes.int32) - - def get_event_shape(self): - return self._event_shape + with ops.control_dependencies([ + check_ops.assert_less(a, b, message="uniform not defined when a > b.") + ] if validate_args else []): + self._a = array_ops.identity(a, name="a") + self._b = array_ops.identity(b, name="b") + contrib_tensor_util.assert_same_float_dtype((self._a, self._b)) + super(Uniform, self).__init__( + dtype=self._a.dtype, + parameters={"a": self._a, "b": self._b}, + is_reparameterized=True, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def a(self): @@ -141,137 +104,65 @@ class Uniform(distribution.Distribution): def b(self): return self._b - def prob(self, x, name="prob"): - """The PDF of observations in `x` under these Uniform distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. - name: The name to give this op. - - Returns: - prob: tensor of dtype `dtype`, the prob values of `x`. If `x` is `nan`, - will return `nan`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, x]): - x = ops.convert_to_tensor(x, name="x") - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" % - (x.dtype, self.dtype)) - - broadcasted_x = x * self._ones() - return math_ops.select( - math_ops.is_nan(broadcasted_x), broadcasted_x, math_ops.select( - math_ops.logical_or(broadcasted_x < self.a, - broadcasted_x > self.b), - array_ops.zeros_like(broadcasted_x), - (1.0 / self.range()) * array_ops.ones_like(broadcasted_x))) - - def log_prob(self, x, name="log_prob"): - return super(Uniform, self).log_prob(x, name) - - def cdf(self, x, name="cdf"): - """CDF of observations in `x` under these Uniform distribution(s). - - Args: - x: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. - name: The name to give this op. - - Returns: - cdf: tensor of dtype `dtype`, the CDFs of `x`. If `x` is `nan`, will - return `nan`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, x]): - x = ops.convert_to_tensor(x, name="x") - if x.dtype != self.dtype: - raise TypeError("Input x dtype does not match dtype: %s vs. %s" % - (x.dtype, self.dtype)) - - broadcasted_x = x * self._ones() - zeros = array_ops.zeros_like(x + self.a + self.b, dtype=self.dtype) - ones = array_ops.ones_like(x + self.a + self.b, dtype=self.dtype) - result_if_not_big = math_ops.select( - x < self.a, zeros, (broadcasted_x - self.a) / self.range()) - return math_ops.select(x >= self.b, ones, result_if_not_big) - - def log_cdf(self, x, name="log_cdf"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, x]): - x = ops.convert_to_tensor(x, name="x") - return math_ops.log(self.cdf(x)) - - def entropy(self, name="entropy"): - """The entropy of Uniform distribution(s). - - Args: - name: The name to give this op. - - Returns: - entropy: tensor of dtype `dtype`, the entropy. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, self.range()]): - return math_ops.log(self.range()) - - def sample_n(self, n, seed=None, name="sample_n"): - """Sample `n` observations from the Uniform Distributions. - - Args: - n: `Scalar`, type int32, the number of observations to sample. - seed: Python integer, the random seed. - name: The name to give this op. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b, n]): - n = ops.convert_to_tensor(n, name="n") - n_val = tensor_util.constant_value(n) - - shape = array_ops.concat(0, ([n], self.batch_shape())) - samples = random_ops.random_uniform(shape=shape, - dtype=self.dtype, - seed=seed) - - # Provide some hints to shape inference - inferred_shape = tensor_shape.vector(n_val).concatenate( - self.get_batch_shape()) - samples.set_shape(inferred_shape) - - return (array_ops.expand_dims(self.a, 0) + array_ops.expand_dims( - self.range(), 0) * samples) - - def mean(self, name="mean"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self._a, self._b]): - return (self.a + self.b) / 2 - - def variance(self, name="variance"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.range()]): - return math_ops.square(self.range()) / 12. - - def std(self, name="std"): - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.range()]): - return self.range() / math_ops.sqrt(12.) - def range(self, name="range"): """`b - a`.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[self.a, self.b]): - return self.b - self.a + with self._name_scope(name): + return self.b - self.a - @property - def is_reparameterized(self): - return True + def _batch_shape(self): + return array_ops.shape(self._a + self._b) - def _ones(self): - return array_ops.ones_like(self.a + self.b) + def _get_batch_shape(self): + return common_shapes.broadcast_shape( + self._a.get_shape(), self._b.get_shape()) - @property - def is_continuous(self): - return True + def _event_shape(self): + return constant_op.constant([], dtype=dtypes.int32) + + def _get_event_shape(self): + return tensor_shape.scalar() + + def _sample_n(self, n, seed=None): + shape = array_ops.concat(0, ([n], self.batch_shape())) + samples = random_ops.random_uniform(shape=shape, + dtype=self.dtype, + seed=seed) + return (array_ops.expand_dims(self.a, 0) + + array_ops.expand_dims(self.range(), 0) * samples) + + def _log_prob(self, x): + return math_ops.log(self._prob(x)) + + def _prob(self, x): + broadcasted_x = x * array_ops.ones(self.batch_shape()) + return math_ops.select( + math_ops.is_nan(broadcasted_x), + broadcasted_x, + math_ops.select( + math_ops.logical_or(broadcasted_x < self.a, + broadcasted_x > self.b), + array_ops.zeros_like(broadcasted_x), + (1. / self.range()) * array_ops.ones_like(broadcasted_x))) + + def _log_cdf(self, x): + return math_ops.log(self.cdf(x)) + + def _cdf(self, x): + broadcasted_x = x * array_ops.ones(self.batch_shape()) + zeros = array_ops.zeros_like(x + self.a + self.b, dtype=self.dtype) + ones = array_ops.ones_like(x + self.a + self.b, dtype=self.dtype) + result_if_not_big = math_ops.select( + x < self.a, zeros, (broadcasted_x - self.a) / self.range()) + return math_ops.select(x >= self.b, ones, result_if_not_big) + + def _entropy(self): + return math_ops.log(self.range()) + + def _mean(self): + return (self.a + self.b) / 2. + + def _variance(self): + return math_ops.square(self.range()) / 12. + + def _std(self): + return self.range() / math.sqrt(12.) diff --git a/tensorflow/contrib/distributions/python/ops/wishart.py b/tensorflow/contrib/distributions/python/ops/wishart.py index 6fb61bcad9e52edf674cdfae61bba8ac69a7e474..3ffcf531e0b16167a299d41ed7065869c596f6bc 100644 --- a/tensorflow/contrib/distributions/python/ops/wishart.py +++ b/tensorflow/contrib/distributions/python/ops/wishart.py @@ -28,7 +28,6 @@ from tensorflow.contrib.framework.python.framework import tensor_util as contrib from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops -from tensorflow.python.framework import tensor_shape from tensorflow.python.framework import tensor_util from tensorflow.python.ops import array_ops from tensorflow.python.ops import check_ops @@ -72,9 +71,9 @@ class _WishartOperatorPD(distribution.Distribution): df, scale_operator_pd, cholesky_input_output_matrices=False, - allow_nan_stats=False, validate_args=True, - name='Wishart'): + allow_nan_stats=False, + name=None): """Construct Wishart distributions. Args: @@ -86,13 +85,13 @@ class _WishartOperatorPD(distribution.Distribution): Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. + validate_args: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. allow_nan_stats: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. - validate_args: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. name: The name to give Ops created by the initializer. Raises: @@ -100,31 +99,29 @@ class _WishartOperatorPD(distribution.Distribution): TypeError: if scale.dtype != df.dtype ValueError: if df < k, where scale operator event shape is `(k, k)` """ - self._scale_operator_pd = scale_operator_pd self._cholesky_input_output_matrices = cholesky_input_output_matrices - self._allow_nan_stats = allow_nan_stats - self._validate_args = validate_args - self._name = name with ops.name_scope(name): with ops.name_scope('init', values=[df, scale_operator_pd]): - if not self.dtype.is_floating: + if not scale_operator_pd.dtype.is_floating: raise TypeError( 'scale_operator_pd.dtype=%s is not a floating-point type' % - self.dtype) - self._df = ops.convert_to_tensor(df, dtype=self.dtype, name='df') + scale_operator_pd.dtype) + self._scale_operator_pd = scale_operator_pd + self._df = ops.convert_to_tensor( + df, dtype=scale_operator_pd.dtype, name='df') contrib_tensor_util.assert_same_float_dtype( - (self._df, self.scale_operator_pd)) - if (self.scale_operator_pd.get_shape().ndims is None or - self.scale_operator_pd.get_shape()[-1].value is None): + (self._df, self._scale_operator_pd)) + if (self._scale_operator_pd.get_shape().ndims is None or + self._scale_operator_pd.get_shape()[-1].value is None): self._dimension = math_ops.cast( - self.scale_operator_pd.vector_space_dimension(), - dtype=self.dtype, name='dimension') + self._scale_operator_pd.vector_space_dimension(), + dtype=self._scale_operator_pd.dtype, name='dimension') else: self._dimension = ops.convert_to_tensor( - self.scale_operator_pd.get_shape()[-1].value, - dtype=self.dtype, name='dimension') - df_val = tensor_util.constant_value(self.df) - dim_val = tensor_util.constant_value(self.dimension) + self._scale_operator_pd.get_shape()[-1].value, + dtype=self._scale_operator_pd.dtype, name='dimension') + df_val = tensor_util.constant_value(self._df) + dim_val = tensor_util.constant_value(self._dimension) if df_val is not None and dim_val is not None: df_val = np.asarray(df_val) if not df_val.shape: df_val = (df_val,) @@ -133,38 +130,21 @@ class _WishartOperatorPD(distribution.Distribution): 'Degrees of freedom (df = %s) cannot be less than dimension of ' 'scale matrix (scale.dimension = %s)' % (df_val, dim_val)) - elif self.validate_args: + elif validate_args: assertions = check_ops.assert_less_equal( - self.dimension, self.df, + self._dimension, self._df, message=('Degrees of freedom (df = %s) cannot be less than ' 'dimension of scale matrix (scale.dimension = %s)' % - (self.dimension, self.df))) + (self._dimension, self._df))) self._df = control_flow_ops.with_dependencies([assertions], self._df) - - @property - def inputs(self): - """Dictionary of inputs provided at initialization.""" - return {'scale_operator_pd': self.scale_operator_pd, 'df': self._df} - - @property - def allow_nan_stats(self): - """Boolean describing behavior when a stat is undefined for batch member.""" - return self._allow_nan_stats - - @property - def validate_args(self): - """Boolean describing behavior on invalid input.""" - return self._validate_args - - @property - def name(self): - """Name prepended to all ops.""" - return self._name - - @property - def dtype(self): - """dtype of samples from this distribution.""" - return self.scale_operator_pd.dtype + super(_WishartOperatorPD, self).__init__( + dtype=self._scale_operator_pd.dtype, + parameters={'df': self._df, + 'scale_operator_pd': self._scale_operator_pd, + 'dimension': self._dimension}, + validate_args=validate_args, + allow_nan_stats=allow_nan_stats, + name=name) @property def df(self): @@ -193,239 +173,165 @@ class _WishartOperatorPD(distribution.Distribution): """Dimension of underlying vector space. The `p` in `R^(p*p)`.""" return self._dimension - def is_continuous(self): - return True - - def is_reparameterized(self): - return True + def _event_shape(self): + s = self.scale_operator_pd.shape() + return array_ops.slice(s, array_ops.shape(s) - 2, [2]) - def event_shape(self, name='event_shape'): - """Shape of a sample from a single distribution as a 1-D int32 `Tensor`.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - s = self.scale_operator_pd.shape() - return array_ops.slice(s, array_ops.shape(s) - 2, [2]) - - def get_event_shape(self): - """`TensorShape` available at graph construction time.""" + def _get_event_shape(self): return self.scale_operator_pd.get_shape()[-2:] - def batch_shape(self, name='batch_shape'): - """Batch dimensions of this instance as a 1-D int32 `Tensor`.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - return self.scale_operator_pd.batch_shape() + def _batch_shape(self): + return self.scale_operator_pd.batch_shape() - def get_batch_shape(self): - """`TensorShape` available at graph construction time.""" + def _get_batch_shape(self): return self.scale_operator_pd.get_batch_shape() - def prob(self, value, name='prob'): - """Probability density/mass function.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[value]): - return math_ops.exp(self.log_prob(value)) - - def log_prob(self, x, name='log_prob'): - """Log of the probability density/mass function. - - Args: - x: `float` or `double` `Tensor`. - name: The name to give this op. - - Returns: - log_prob: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with - values of type `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[x] + list(self.inputs.values())): - x = ops.convert_to_tensor(x, name='x') - contrib_tensor_util.assert_same_float_dtype( - (self.scale_operator_pd, x)) - if self.cholesky_input_output_matrices: - x_sqrt = x - else: - # Complexity: O(nbk^3) - x_sqrt = linalg_ops.batch_cholesky(x) - - batch_shape = self.batch_shape() - event_shape = self.event_shape() - ndims = array_ops.rank(x_sqrt) - # sample_ndims = ndims - batch_ndims - event_ndims - sample_ndims = ndims - array_ops.shape(batch_shape)[0] - 2 - sample_shape = array_ops.slice( - array_ops.shape(x_sqrt), [0], [sample_ndims]) - - # We need to be able to pre-multiply each matrix by its corresponding - # batch scale matrix. Since a Distribution Tensor supports multiple - # samples per batch, this means we need to reshape the input matrix `x` - # so that the first b dimensions are batch dimensions and the last two - # are of shape [dimension, dimensions*number_of_samples]. Doing these - # gymnastics allows us to do a batch_solve. - # - # After we're done with sqrt_solve (the batch operation) we need to undo - # this reshaping so what we're left with is a Tensor partitionable by - # sample, batch, event dimensions. - - # Complexity: O(nbk^2) since transpose must access every element. - scale_sqrt_inv_x_sqrt = x_sqrt - perm = array_ops.concat(0, (math_ops.range(sample_ndims, ndims), - math_ops.range(0, sample_ndims))) - scale_sqrt_inv_x_sqrt = array_ops.transpose(scale_sqrt_inv_x_sqrt, perm) - shape = array_ops.concat( - 0, (batch_shape, - (math_ops.cast(self.dimension, dtype=dtypes.int32), -1))) - scale_sqrt_inv_x_sqrt = array_ops.reshape(scale_sqrt_inv_x_sqrt, shape) - - # Complexity: O(nbM*k) where M is the complexity of the operator solving - # a vector system. E.g., for OperatorPDDiag, each solve is O(k), so - # this complexity is O(nbk^2). For OperatorPDCholesky, each solve is - # O(k^2) so this step has complexity O(nbk^3). - scale_sqrt_inv_x_sqrt = self.scale_operator_pd.sqrt_solve( - scale_sqrt_inv_x_sqrt) - - # Undo make batch-op ready. - # Complexity: O(nbk^2) - shape = array_ops.concat(0, (batch_shape, event_shape, sample_shape)) - scale_sqrt_inv_x_sqrt = array_ops.reshape(scale_sqrt_inv_x_sqrt, shape) - perm = array_ops.concat(0, (math_ops.range(ndims - sample_ndims, ndims), - math_ops.range(0, ndims - sample_ndims))) - scale_sqrt_inv_x_sqrt = array_ops.transpose(scale_sqrt_inv_x_sqrt, perm) - - # Write V = SS', X = LL'. Then: - # tr[inv(V) X] = tr[inv(S)' inv(S) L L'] - # = tr[inv(S) L L' inv(S)'] - # = tr[(inv(S) L) (inv(S) L)'] - # = sum_{ik} (inv(S) L)_{ik}^2 - # The second equality follows from the cyclic permutation property. - # Complexity: O(nbk^2) - trace_scale_inv_x = math_ops.reduce_sum( - math_ops.square(scale_sqrt_inv_x_sqrt), - reduction_indices=[-2, -1]) - - # Complexity: O(nbk) - half_log_det_x = math_ops.reduce_sum( - math_ops.log(array_ops.batch_matrix_diag_part(x_sqrt)), - reduction_indices=[-1]) - - # Complexity: O(nbk^2) - log_prob = ((self.df - self.dimension - 1.) * half_log_det_x - - 0.5 * trace_scale_inv_x - - self.log_normalizing_constant()) - - # Set shape hints. - # Try to merge what we know from the input then what we know from the - # parameters of this distribution. - if x.get_shape().ndims is not None: - log_prob.set_shape(x.get_shape()[:-2]) - if (log_prob.get_shape().ndims is not None and - self.get_batch_shape().ndims is not None and - self.get_batch_shape().ndims > 0): - log_prob.get_shape()[-self.get_batch_shape().ndims:].merge_with( - self.get_batch_shape()) - - return log_prob - - def sample_n(self, n, seed=None, name='sample'): - # pylint: disable=line-too-long - """Generate `n` samples. - - Complexity: O(nbk^3) - - The sampling procedure is based on the [Bartlett decomposition]( - https://en.wikipedia.org/wiki/Wishart_distribution#Bartlett_decomposition) - and [using a Gamma distribution to generate Chi2 random variates]( - https://en.wikipedia.org/wiki/Chi-squared_distribution#Gamma.2C_exponential.2C_and_related_distributions). - - Args: - n: Scalar. Number of samples to draw from each distribution. - seed: Python integer; random number generator seed. - name: The name of this op. - - Returns: - samples: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=[n] + list(self.inputs.values())): - n = ops.convert_to_tensor(n, name='n') - if n.dtype != dtypes.int32: - raise TypeError('n.dtype=%s which is not int32' % n.dtype) - batch_shape = self.batch_shape() - event_shape = self.event_shape() - batch_ndims = array_ops.shape(batch_shape)[0] - - ndims = batch_ndims + 3 # sample_ndims=1, event_ndims=2 - shape = array_ops.concat(0, ((n,), batch_shape, event_shape)) - - # Complexity: O(nbk^2) - x = random_ops.random_normal(shape=shape, - mean=0., - stddev=1., - dtype=self.dtype, - seed=seed) - - # Complexity: O(nbk) - # This parametrization is equivalent to Chi2, i.e., - # ChiSquared(k) == Gamma(alpha=k/2, beta=1/2) - g = random_ops.random_gamma(shape=(n,), - alpha=self._multi_gamma_sequence( - 0.5 * self.df, self.dimension), - beta=0.5, - dtype=self.dtype, - seed=seed) - - # Complexity: O(nbk^2) - x = array_ops.batch_matrix_band_part(x, -1, 0) # Tri-lower. - - # Complexity: O(nbk) - x = array_ops.batch_matrix_set_diag(x, math_ops.sqrt(g)) - - # Make batch-op ready. - # Complexity: O(nbk^2) - perm = array_ops.concat(0, (math_ops.range(1, ndims), (0,))) - x = array_ops.transpose(x, perm) - shape = array_ops.concat(0, (batch_shape, (event_shape[0], -1))) - x = array_ops.reshape(x, shape) - - # Complexity: O(nbM) where M is the complexity of the operator solving a - # vector system. E.g., for OperatorPDDiag, each matmul is O(k^2), so - # this complexity is O(nbk^2). For OperatorPDCholesky, each matmul is - # O(k^3) so this step has complexity O(nbk^3). - x = self.scale_operator_pd.sqrt_matmul(x) - - # Undo make batch-op ready. - # Complexity: O(nbk^2) - shape = array_ops.concat(0, (batch_shape, event_shape, (n,))) - x = array_ops.reshape(x, shape) - perm = array_ops.concat(0, ((ndims-1,), math_ops.range(0, ndims-1))) - x = array_ops.transpose(x, perm) - - if not self.cholesky_input_output_matrices: - # Complexity: O(nbk^3) - x = math_ops.batch_matmul(x, x, adj_y=True) - - # Set shape hints. - if self.scale_operator_pd.get_shape().ndims is not None: - x.set_shape(tensor_shape.TensorShape( - [tensor_util.constant_value(n)] + - self.scale_operator_pd.get_shape().as_list())) - elif x.get_shape().ndims is not None: - x.get_shape()[0].merge_with( - tensor_shape.TensorDimension(tensor_util.constant_value(n))) - - return x - - def cdf(self, value, name='cdf'): - """Cumulative distribution function.""" - raise NotImplementedError('cdf is not implemented') - - def log_cdf(self, value, name='log_cdf'): - """Log CDF.""" - raise NotImplementedError('log_cdf is not implemented') - - def entropy(self, name='entropy'): - """Entropy of the distribution in nats.""" + def _sample_n(self, n, seed): + batch_shape = self.batch_shape() + event_shape = self.event_shape() + batch_ndims = array_ops.shape(batch_shape)[0] + + ndims = batch_ndims + 3 # sample_ndims=1, event_ndims=2 + shape = array_ops.concat(0, ((n,), batch_shape, event_shape)) + + # Complexity: O(nbk^2) + x = random_ops.random_normal(shape=shape, + mean=0., + stddev=1., + dtype=self.dtype, + seed=seed) + + # Complexity: O(nbk) + # This parametrization is equivalent to Chi2, i.e., + # ChiSquared(k) == Gamma(alpha=k/2, beta=1/2) + g = random_ops.random_gamma(shape=(n,), + alpha=self._multi_gamma_sequence( + 0.5 * self.df, self.dimension), + beta=0.5, + dtype=self.dtype, + seed=seed) + + # Complexity: O(nbk^2) + x = array_ops.batch_matrix_band_part(x, -1, 0) # Tri-lower. + + # Complexity: O(nbk) + x = array_ops.batch_matrix_set_diag(x, math_ops.sqrt(g)) + + # Make batch-op ready. + # Complexity: O(nbk^2) + perm = array_ops.concat(0, (math_ops.range(1, ndims), (0,))) + x = array_ops.transpose(x, perm) + shape = array_ops.concat(0, (batch_shape, (event_shape[0], -1))) + x = array_ops.reshape(x, shape) + + # Complexity: O(nbM) where M is the complexity of the operator solving a + # vector system. E.g., for OperatorPDDiag, each matmul is O(k^2), so + # this complexity is O(nbk^2). For OperatorPDCholesky, each matmul is + # O(k^3) so this step has complexity O(nbk^3). + x = self.scale_operator_pd.sqrt_matmul(x) + + # Undo make batch-op ready. + # Complexity: O(nbk^2) + shape = array_ops.concat(0, (batch_shape, event_shape, (n,))) + x = array_ops.reshape(x, shape) + perm = array_ops.concat(0, ((ndims-1,), math_ops.range(0, ndims-1))) + x = array_ops.transpose(x, perm) + + if not self.cholesky_input_output_matrices: + # Complexity: O(nbk^3) + x = math_ops.batch_matmul(x, x, adj_y=True) + + return x + + def _log_prob(self, x): + if self.cholesky_input_output_matrices: + x_sqrt = x + else: + # Complexity: O(nbk^3) + x_sqrt = linalg_ops.batch_cholesky(x) + + batch_shape = self.batch_shape() + event_shape = self.event_shape() + ndims = array_ops.rank(x_sqrt) + # sample_ndims = ndims - batch_ndims - event_ndims + sample_ndims = ndims - array_ops.shape(batch_shape)[0] - 2 + sample_shape = array_ops.slice( + array_ops.shape(x_sqrt), [0], [sample_ndims]) + + # We need to be able to pre-multiply each matrix by its corresponding + # batch scale matrix. Since a Distribution Tensor supports multiple + # samples per batch, this means we need to reshape the input matrix `x` + # so that the first b dimensions are batch dimensions and the last two + # are of shape [dimension, dimensions*number_of_samples]. Doing these + # gymnastics allows us to do a batch_solve. + # + # After we're done with sqrt_solve (the batch operation) we need to undo + # this reshaping so what we're left with is a Tensor partitionable by + # sample, batch, event dimensions. + + # Complexity: O(nbk^2) since transpose must access every element. + scale_sqrt_inv_x_sqrt = x_sqrt + perm = array_ops.concat(0, (math_ops.range(sample_ndims, ndims), + math_ops.range(0, sample_ndims))) + scale_sqrt_inv_x_sqrt = array_ops.transpose(scale_sqrt_inv_x_sqrt, perm) + shape = array_ops.concat( + 0, (batch_shape, + (math_ops.cast(self.dimension, dtype=dtypes.int32), -1))) + scale_sqrt_inv_x_sqrt = array_ops.reshape(scale_sqrt_inv_x_sqrt, shape) + + # Complexity: O(nbM*k) where M is the complexity of the operator solving + # a vector system. E.g., for OperatorPDDiag, each solve is O(k), so + # this complexity is O(nbk^2). For OperatorPDCholesky, each solve is + # O(k^2) so this step has complexity O(nbk^3). + scale_sqrt_inv_x_sqrt = self.scale_operator_pd.sqrt_solve( + scale_sqrt_inv_x_sqrt) + + # Undo make batch-op ready. + # Complexity: O(nbk^2) + shape = array_ops.concat(0, (batch_shape, event_shape, sample_shape)) + scale_sqrt_inv_x_sqrt = array_ops.reshape(scale_sqrt_inv_x_sqrt, shape) + perm = array_ops.concat(0, (math_ops.range(ndims - sample_ndims, ndims), + math_ops.range(0, ndims - sample_ndims))) + scale_sqrt_inv_x_sqrt = array_ops.transpose(scale_sqrt_inv_x_sqrt, perm) + + # Write V = SS', X = LL'. Then: + # tr[inv(V) X] = tr[inv(S)' inv(S) L L'] + # = tr[inv(S) L L' inv(S)'] + # = tr[(inv(S) L) (inv(S) L)'] + # = sum_{ik} (inv(S) L)_{ik}^2 + # The second equality follows from the cyclic permutation property. + # Complexity: O(nbk^2) + trace_scale_inv_x = math_ops.reduce_sum( + math_ops.square(scale_sqrt_inv_x_sqrt), + reduction_indices=[-2, -1]) + + # Complexity: O(nbk) + half_log_det_x = math_ops.reduce_sum( + math_ops.log(array_ops.batch_matrix_diag_part(x_sqrt)), + reduction_indices=[-1]) + + # Complexity: O(nbk^2) + log_prob = ((self.df - self.dimension - 1.) * half_log_det_x - + 0.5 * trace_scale_inv_x - + self.log_normalizing_constant()) + + # Set shape hints. + # Try to merge what we know from the input then what we know from the + # parameters of this distribution. + if x.get_shape().ndims is not None: + log_prob.set_shape(x.get_shape()[:-2]) + if (log_prob.get_shape().ndims is not None and + self.get_batch_shape().ndims is not None and + self.get_batch_shape().ndims > 0): + log_prob.get_shape()[-self.get_batch_shape().ndims:].merge_with( + self.get_batch_shape()) + + return log_prob + + def _prob(self, x): + return math_ops.exp(self._log_prob(x)) + + def _entropy(self): half_dp1 = 0.5 * self.dimension + 0.5 half_df = 0.5 * self.df return (self.dimension * (half_df + half_dp1 * math.log(2.)) + @@ -433,110 +339,74 @@ class _WishartOperatorPD(distribution.Distribution): self._multi_lgamma(half_df, self.dimension) + (half_dp1 - half_df) * self._multi_digamma(half_df, self.dimension)) - def mean(self, name='mean'): - """Mean of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - if self.cholesky_input_output_matrices: - return math_ops.sqrt(self.df) * self.scale_operator_pd.sqrt_to_dense() - else: - return self.df * self.scale_operator_pd.to_dense() - - def mode(self, name='mode'): - """Mode of the distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - s = self.df - self.dimension - 1. - s = math_ops.select( - math_ops.less(s, 0.), - constant_op.constant(float('NaN'), dtype=self.dtype, name='nan'), - s) - if self.cholesky_input_output_matrices: - return math_ops.sqrt(s) * self.scale_operator_pd.sqrt_to_dense() - else: - return s * self.scale_operator_pd.to_dense() - - def std(self, name='std'): - """Standard deviation of the Wishart distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - if self.cholesky_input_output_matrices: - raise ValueError( - 'Computing std. dev. when is cholesky_input_output_matrices=True ' - 'does not make sense.') - return linalg_ops.batch_cholesky(self.variance()) - - def variance(self, name='variance'): - """Variance of the Wishart distribution. - - This function should not be confused with the covariance of the Wishart. The - covariance matrix would have shape `q x q` where, - `q = dimension * (dimension+1) / 2` - and having elements corresponding to some mapping from a lower-triangular - matrix to a vector-space. - - This function returns the diagonal of the Covariance matrix but shaped - as a `dimension x dimension` matrix. - - Args: - name: The name of this op. - - Returns: - variance: `Tensor` of dtype `self.dtype`. - """ - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - x = math_ops.sqrt(self.df) * self.scale_operator_pd.to_dense() - d = array_ops.expand_dims(array_ops.batch_matrix_diag_part(x), -1) - v = math_ops.square(x) + math_ops.batch_matmul(d, d, adj_y=True) - if self.cholesky_input_output_matrices: - return linalg_ops.batch_cholesky(v) - else: - return v + def _mean(self): + if self.cholesky_input_output_matrices: + return math_ops.sqrt(self.df) * self.scale_operator_pd.sqrt_to_dense() + return self.df * self.scale_operator_pd.to_dense() + + def _variance(self): + x = math_ops.sqrt(self.df) * self.scale_operator_pd.to_dense() + d = array_ops.expand_dims(array_ops.batch_matrix_diag_part(x), -1) + v = math_ops.square(x) + math_ops.batch_matmul(d, d, adj_y=True) + if self.cholesky_input_output_matrices: + return linalg_ops.batch_cholesky(v) + return v + + def _std(self): + if self.cholesky_input_output_matrices: + raise ValueError( + 'Computing std. dev. when is cholesky_input_output_matrices=True ' + 'does not make sense.') + return linalg_ops.batch_cholesky(self.variance()) + + def _mode(self): + s = self.df - self.dimension - 1. + s = math_ops.select( + math_ops.less(s, 0.), + constant_op.constant(float('NaN'), dtype=self.dtype, name='nan'), + s) + if self.cholesky_input_output_matrices: + return math_ops.sqrt(s) * self.scale_operator_pd.sqrt_to_dense() + return s * self.scale_operator_pd.to_dense() def mean_log_det(self, name='mean_log_det'): """Computes E[log(det(X))] under this Wishart distribution.""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - return (self._multi_digamma(0.5 * self.df, self.dimension) + - self.dimension * math.log(2.) + - self.scale_operator_pd.log_det()) + with self._name_scope(name): + return (self._multi_digamma(0.5 * self.df, self.dimension) + + self.dimension * math.log(2.) + + self.scale_operator_pd.log_det()) def log_normalizing_constant(self, name='log_normalizing_constant'): """Computes the log normalizing constant, log(Z).""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=list(self.inputs.values())): - return (self.df * self.scale_operator_pd.sqrt_log_det() + - 0.5 * self.df * self.dimension * math.log(2.) + - self._multi_lgamma(0.5 * self.df, self.dimension)) + with self._name_scope(name): + return (self.df * self.scale_operator_pd.sqrt_log_det() + + 0.5 * self.df * self.dimension * math.log(2.) + + self._multi_lgamma(0.5 * self.df, self.dimension)) def _multi_gamma_sequence(self, a, p, name='multi_gamma_sequence'): """Creates sequence used in multivariate (di)gamma; shape = shape(a)+[p].""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[a, p]): - # Linspace only takes scalars, so we'll add in the offset afterwards. - seq = math_ops.linspace( - constant_op.constant(0., dtype=self.dtype), - 0.5 - 0.5 * p, - math_ops.cast(p, dtypes.int32)) - return seq + array_ops.expand_dims(a, [-1]) + with self._name_scope(name, values=[a, p]): + # Linspace only takes scalars, so we'll add in the offset afterwards. + seq = math_ops.linspace( + constant_op.constant(0., dtype=self.dtype), + 0.5 - 0.5 * p, + math_ops.cast(p, dtypes.int32)) + return seq + array_ops.expand_dims(a, [-1]) def _multi_lgamma(self, a, p, name='multi_lgamma'): """Computes the log multivariate gamma function; log(Gamma_p(a)).""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[a, p]): - seq = self._multi_gamma_sequence(a, p) - return (0.25 * p * (p - 1.) * math.log(math.pi) + - math_ops.reduce_sum(math_ops.lgamma(seq), - reduction_indices=(-1,))) + with self._name_scope(name, values=[a, p]): + seq = self._multi_gamma_sequence(a, p) + return (0.25 * p * (p - 1.) * math.log(math.pi) + + math_ops.reduce_sum(math_ops.lgamma(seq), + reduction_indices=(-1,))) def _multi_digamma(self, a, p, name='multi_digamma'): """Computes the multivariate digamma function; Psi_p(a).""" - with ops.name_scope(self.name): - with ops.name_scope(name, values=[a, p]): - seq = self._multi_gamma_sequence(a, p) - return math_ops.reduce_sum(math_ops.digamma(seq), - reduction_indices=(-1,)) + with self._name_scope(name, values=[a, p]): + seq = self._multi_gamma_sequence(a, p) + return math_ops.reduce_sum(math_ops.digamma(seq), + reduction_indices=(-1,)) class WishartCholesky(_WishartOperatorPD): @@ -606,9 +476,9 @@ class WishartCholesky(_WishartOperatorPD): df, scale, cholesky_input_output_matrices=False, - allow_nan_stats=False, validate_args=True, - name='Wishart'): + allow_nan_stats=False, + name='WishartCholesky'): """Construct Wishart distributions. Args: @@ -621,13 +491,13 @@ class WishartCholesky(_WishartOperatorPD): Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. + validate_args: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. allow_nan_stats: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. - validate_args: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. name: The name scope to give class member ops. """ super(WishartCholesky, self).__init__( @@ -635,8 +505,8 @@ class WishartCholesky(_WishartOperatorPD): scale_operator_pd=operator_pd_cholesky.OperatorPDCholesky( scale, verify_pd=validate_args), cholesky_input_output_matrices=cholesky_input_output_matrices, - allow_nan_stats=allow_nan_stats, validate_args=validate_args, + allow_nan_stats=allow_nan_stats, name=name) @@ -703,9 +573,9 @@ class WishartFull(_WishartOperatorPD): df, scale, cholesky_input_output_matrices=False, - allow_nan_stats=False, validate_args=True, - name='Wishart'): + allow_nan_stats=False, + name='WishartFull'): """Construct Wishart distributions. Args: @@ -718,13 +588,13 @@ class WishartFull(_WishartOperatorPD): Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. + validate_args: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. allow_nan_stats: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. - validate_args: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. name: The name scope to give class member ops. """ super(WishartFull, self).__init__( @@ -732,6 +602,6 @@ class WishartFull(_WishartOperatorPD): scale_operator_pd=operator_pd_full.OperatorPDFull( scale, verify_pd=validate_args), cholesky_input_output_matrices=cholesky_input_output_matrices, - allow_nan_stats=allow_nan_stats, validate_args=validate_args, + allow_nan_stats=allow_nan_stats, name=name) diff --git a/tensorflow/contrib/factorization/kernels/clustering_ops.cc b/tensorflow/contrib/factorization/kernels/clustering_ops.cc index 5f680ceadbc50f3ba9559d0945983fe0b36a7162..2ee366d922d4b7dd3d7ab2c627e651090dd1765f 100644 --- a/tensorflow/contrib/factorization/kernels/clustering_ops.cc +++ b/tensorflow/contrib/factorization/kernels/clustering_ops.cc @@ -31,7 +31,7 @@ #include "tensorflow/core/lib/gtl/top_n.h" #include "tensorflow/core/lib/random/philox_random.h" #include "tensorflow/core/lib/random/simple_philox.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" namespace tensorflow { diff --git a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc index 9db453f0dd2806fce311fe9b5d197baf97024aa5..a34c64d328cda069ddc52486453228098ee32970 100644 --- a/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc +++ b/tensorflow/contrib/ffmpeg/default/ffmpeg_lib.cc @@ -26,8 +26,8 @@ #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/strings/str_util.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/env.h" -#include "tensorflow/core/platform/host_info.h" using tensorflow::strings::StrCat; diff --git a/tensorflow/contrib/framework/BUILD b/tensorflow/contrib/framework/BUILD index b77fe259f842d470ce3f5a0e9256658bba777a65..133339d97865d0802da0d194f7942a51417f6738 100644 --- a/tensorflow/contrib/framework/BUILD +++ b/tensorflow/contrib/framework/BUILD @@ -22,7 +22,6 @@ py_library( "python/ops/embedding_ops.py", "python/ops/ops.py", "python/ops/prettyprint_ops.py", - "python/ops/sampling_ops.py", "python/ops/variables.py", ], srcs_version = "PY2AND3", @@ -83,23 +82,6 @@ py_test( deps = ["//tensorflow:tensorflow_py"], ) -py_test( - name = "sampling_ops_test", - size = "small", - srcs = ["python/ops/sampling_ops_test.py"], - srcs_version = "PY2AND3", - deps = ["//tensorflow:tensorflow_py"], -) - -py_test( - name = "sampling_ops_threading_test", - size = "small", - srcs = ["python/ops/sampling_ops_threading_test.py"], - srcs_version = "PY2AND3", - tags = ["notsan"], - deps = ["//tensorflow:tensorflow_py"], -) - filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/contrib/framework/python/ops/__init__.py b/tensorflow/contrib/framework/python/ops/__init__.py index e868989a73e698d9d0e3e5400997e264537e025a..b0b1935595de39b600cb59707f28a90fd5a46606 100644 --- a/tensorflow/contrib/framework/python/ops/__init__.py +++ b/tensorflow/contrib/framework/python/ops/__init__.py @@ -24,6 +24,5 @@ from tensorflow.contrib.framework.python.ops.arg_scope import * from tensorflow.contrib.framework.python.ops.embedding_ops import * from tensorflow.contrib.framework.python.ops.ops import * from tensorflow.contrib.framework.python.ops.prettyprint_ops import * -from tensorflow.contrib.framework.python.ops.sampling_ops import * from tensorflow.contrib.framework.python.ops.variables import * # pylint: enable=wildcard-import diff --git a/tensorflow/contrib/framework/python/ops/variables_test.py b/tensorflow/contrib/framework/python/ops/variables_test.py index 11bd723179840f8d904e22705a82896fed1394c0..d6e1d03a560c5e002634a5cc7818ddf12dad1f3e 100644 --- a/tensorflow/contrib/framework/python/ops/variables_test.py +++ b/tensorflow/contrib/framework/python/ops/variables_test.py @@ -472,7 +472,8 @@ class ModelVariablesTest(tf.test.TestCase): def testInitializedVariableValue(self): with self.test_session() as sess: - a = tf.contrib.framework.model_variable('a', [5], initializer=tf.ones) + a = tf.contrib.framework.model_variable( + 'a', [5], initializer=tf.ones_initializer) sess.run(tf.initialize_all_variables()) self.assertAllEqual(a.eval(), [1]*5) diff --git a/tensorflow/contrib/graph_editor/__init__.py b/tensorflow/contrib/graph_editor/__init__.py index dad4600b9a3e926841518b0d48e6ba32bc286364..71d89f192c3730c9ebd04bde92b69a9d8dac95d4 100644 --- a/tensorflow/contrib/graph_editor/__init__.py +++ b/tensorflow/contrib/graph_editor/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""# TensorFlow Graph Editor. +"""TensorFlow Graph Editor. The TensorFlow Graph Editor library allows for modification of an existing tf.Graph instance in-place. @@ -61,7 +61,7 @@ Note that this procedure is very costly because a new session must be created after any modifications. Among other things, it takes time because the entire graph state must be saved and restored again. -### Sub-graph +## Sub-graph Most of the functions in the Graph Editor library operate on *sub-graph*. More precisely, they take as input arguments instances of the SubGraphView class @@ -94,7 +94,7 @@ to avoid any confusion, the default graph is never used and the graph on which to operate must always be explicitely given. This is the reason why *graph=tf.get_default_graph()* is used in the code snippets above. -### Modules overview +## Modules overview * util: utility functions. * select: various selection methods of TensorFlow tensors and operations. @@ -109,7 +109,7 @@ which to operate must always be explicitely given. This is the reason why * transform: the Transformer class, which enables transforming (or simply copying) a subgraph into another one. -### Module: util +## Module: util @@make_list_of_op @@get_tensors @@ -121,7 +121,7 @@ which to operate must always be explicitely given. This is the reason why @@make_placeholder_from_tensor @@make_placeholder_from_dtype_and_shape -### Module: select +## Module: select @@filter_ts @@filter_ts_from_regex @@ -140,13 +140,13 @@ which to operate must always be explicitely given. This is the reason why @@select_ts @@select_ops_and_ts -### Module: subgraph +## Module: subgraph @@SubGraphView @@make_view @@make_view_from_scope -### Module: reroute +## Module: reroute @@swap_ts @@reroute_a2b_ts @@ -163,7 +163,7 @@ which to operate must always be explicitely given. This is the reason why @@remove_control_inputs @@add_control_inputs -### Module: edit +## Module: edit @@detach_control_inputs @@detach_control_outputs @@ -173,7 +173,7 @@ which to operate must always be explicitely given. This is the reason why @@connect @@bypass -### Module: transform +## Module: transform @@replace_t_with_placeholder_handler @@keep_t_if_possible_handler @@ -183,13 +183,15 @@ which to operate must always be explicitely given. This is the reason why @@transform_op_in_place @@Transformer @@copy +@@copy_with_input_replacements +@@graph_replace -### Module: match +## Module: match @@op_type @@OpMatcher -### Useful aliases +## Useful aliases @@ph @@sgv diff --git a/tensorflow/contrib/graph_editor/subgraph.py b/tensorflow/contrib/graph_editor/subgraph.py index 56eeeca10264d92048dc7debf8931d360ad7cbab..c5fa9614deb95822b9408a896b2a5e7d192897dc 100644 --- a/tensorflow/contrib/graph_editor/subgraph.py +++ b/tensorflow/contrib/graph_editor/subgraph.py @@ -440,7 +440,8 @@ class SubGraphView(object): def print_list(name, iterable, get_name): if iterable: print("** {}[{}]:".format(name, len(iterable)), file=res) - print("\n".join([get_name(elem) for elem in iterable]), file=res) + print("\n".join([" {}".format(get_name(elem)) for elem in iterable]), + file=res) else: print("** {}: empty".format(name), file=res) diff --git a/tensorflow/contrib/graph_editor/tests/transform_test.py b/tensorflow/contrib/graph_editor/tests/transform_test.py index e88f83e3f8032cbdc4d1a52252e2b56b8cd185fc..0b09584ec04756ae1212204ed8bd2a21af9ead0f 100644 --- a/tensorflow/contrib/graph_editor/tests/transform_test.py +++ b/tensorflow/contrib/graph_editor/tests/transform_test.py @@ -18,9 +18,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import numpy as np import tensorflow as tf from tensorflow.contrib import graph_editor as ge +# Precision tolerance for floating-point value tests. +ERROR_TOLERANCE = 1e-3 + class TransformTest(tf.test.TestCase): @@ -35,9 +39,23 @@ class TransformTest(tf.test.TestCase): def test_copy(self): graph = tf.Graph() - ge.copy(self.graph, graph) + _, info = ge.copy(self.graph, graph) self.assertEqual(set(op.name for op in self.graph.get_operations()), set(op.name for op in graph.get_operations())) + src_ops = self.graph.get_operations() + dst_ops = graph.get_operations() + for op in src_ops: + op_ = info.transformed(op) + self.assertTrue(op_ in dst_ops) + self.assertEqual(op.name, op_.name) + self.assertEqual(info.original(op_), op) + src_ts = ge.util.get_tensors(self.graph) + dst_ts = ge.util.get_tensors(graph) + for t in src_ts: + t_ = info.transformed(t) + self.assertTrue(t_ in dst_ts) + self.assertEqual(t.name, t_.name) + self.assertEqual(info.original(t_), t) def test_transform(self): transformer = ge.Transformer() @@ -93,5 +111,30 @@ class TransformTest(tf.test.TestCase): top = ge.select_ops("^AddNoise_2$", graph=self.graph)[0] self.assertTrue(matcher2(top)) + def test_copy_with_input_replacements(self): + with self.graph.as_default(): + ten = tf.constant(10.0, shape=[10], name="Input") + sgv, _ = ge.copy_with_input_replacements(self.o.op, + {self.o.op.inputs[1]: ten}) + with tf.Session() as sess: + val = sess.run(sgv.outputs[0]) + self.assertNear(np.linalg.norm(val - np.array([11])), + 0.0, ERROR_TOLERANCE) + + def test_graph_replace(self): + tf.reset_default_graph() + a = tf.constant(1.0, name="a") + b = tf.Variable(1.0, name="b") + eps = tf.constant(0.001, name="eps") + c = tf.identity(a + b + eps, name="c") + a_new = tf.constant(2.0, name="a_new") + c_new = ge.graph_replace(c, {a: a_new}) + with tf.Session() as sess: + sess.run(tf.initialize_all_variables()) + c_val, c_new_val = sess.run([c, c_new]) + self.assertNear(c_val, 2.001, ERROR_TOLERANCE) + self.assertNear(c_new_val, 3.001, ERROR_TOLERANCE) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/contrib/graph_editor/transform.py b/tensorflow/contrib/graph_editor/transform.py index 908631ebccc4209c1c7a65b4df42340af9680a72..584318891c14f3fa16c781193163c0b552132b00 100644 --- a/tensorflow/contrib/graph_editor/transform.py +++ b/tensorflow/contrib/graph_editor/transform.py @@ -22,9 +22,13 @@ from __future__ import print_function from copy import deepcopy from six import iteritems +from six import iterkeys +from six import string_types +from six import StringIO from tensorflow.contrib.graph_editor import edit from tensorflow.contrib.graph_editor import reroute +from tensorflow.contrib.graph_editor import select from tensorflow.contrib.graph_editor import subgraph from tensorflow.contrib.graph_editor import util from tensorflow.python.framework import ops as tf_ops @@ -39,6 +43,8 @@ __all__ = [ "transform_op_in_place", "Transformer", "copy", + "copy_with_input_replacements", + "graph_replace", ] @@ -232,9 +238,119 @@ class Transformer(object): self.transformed_ops = {} self.transformed_ts = {} - def create_ops_mapping(self): - """Return the mapping from original ops to transformed ops.""" - return {op.name: op_.name for op, op_ in iteritems(self.transformed_ops)} + class ResultInfo(object): + """"Contains information about the result of a transform operation.""" + + def __init__(self, info): + """Constructor. + + Args: + info: an instance of Transformer._Info containing various internal + information about the transform operation. + """ + self._graph = info.graph + self._scope = info.scope + self._graph_ = info.graph_ + self._scope_ = info.scope_ + self._transformed_ops = info.transformed_ops + self._transformed_ts = info.transformed_ts + + def _get_transformed_map(self, top): + """Return the correct container depending on the type of `top`.""" + if isinstance(top, tf_ops.Operation): + return self._transformed_ops + elif isinstance(top, tf_ops.Tensor): + return self._transformed_ts + else: + raise TypeError( + "Expected a tf.Tensor or a tf.Operation, got a {}".format( + type(top))) + + def _transformed_elem(self, original_top): + """Return the transformed op/tensor corresponding to the original one. + + Args: + original_top: the original tensor/operation. + Returns: + the transformed tensor/operation (or None if no match is found). + """ + transformed_map = self._get_transformed_map(original_top) + if isinstance(original_top, string_types): + for original, transformed in iteritems(transformed_map): + if original.name == original_top: + return transformed + return None + else: + if original_top not in transformed_map: + return None + return transformed_map[original_top] + + def _original_elem(self, transformed_top): + """Return the original op/tensor corresponding to the transformed one. + + Args: + transformed_top: the transformed tensor/operation. + Returns: + the original tensor/operation (or None if no match is found). + """ + transformed_map = self._get_transformed_map(transformed_top) + if isinstance(transformed_top, string_types): + finder = lambda transformed: transformed.name == transformed_top + else: + finder = lambda transformed: transformed == transformed_top + for original, transformed in iteritems(transformed_map): + if finder(transformed): + return original + return None + + def transformed(self, original): + """Return the transformed op/tensor corresponding to the original one. + + Note that the output of this function mimics the hierarchy + of its input argument `original`. + Given an iterable, it returns a list. Given an operation or a tensor, + it will return an operation or a tensor. + + Args: + original: the original tensor/operation. + Returns: + the transformed tensor/operation (or None if no match is found). + """ + return util.transform_tree(original, self._transformed_elem) + + def original(self, transformed): + """Return the original op/tensor corresponding to the transformed one. + + Note that the output of this function mimics the hierarchy + of its input argument `transformed`. + Given an iterable, it returns a list. Given an operation or a tensor, + it will return an operation or a tensor. + + Args: + transformed: the transformed tensor/operation. + Returns: + the original tensor/operation (or None if no match is found). + """ + return util.transform_tree(transformed, self._original_elem) + + def __str__(self): + res = StringIO() + print("Transform result info:", file=res) + if self._graph == self._graph_: + in_place_str = "" if self._scope_ else " IN-PLACE" + print(" Within graph[{}]{}".format( + id(self._graph), in_place_str), file=res) + else: + print(" graph[{}] => graph[{}]".format( + id(self._graph), id(self._graph_)), file=res) + if self._scope: + print(" Relative to source scope: {}".format(self._scope), file=res) + if self._scope_: + print(" Scope destination: {}".format(self._scope_), file=res) + print("Operations mapping:", file=res) + for op, op_ in iteritems(self._transformed_ops): + print(" {} => {}".format(op.name, op_.name), file=res) + return res.getvalue() def __init__(self): """Transformer constructor. @@ -287,12 +403,13 @@ class Transformer(object): relative path of x/y and will be transformed into b/x/y. reuse_dst_scope: if True the dst_scope is re-used if it already exists. Otherwise, the scope is given a unique name based on the one given - by postfixing an underscore followed by a digit (default). + by appending an underscore followed by a digit (default). Returns: - A tuple `(sgv, ops_mapping)` where: + A tuple `(sgv, info)` where: `sgv` is the transformed subgraph view; - `ops_mapping` is a dictionary mapping the name of the original ops - to the name of the transformed ops. + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. Raises: ValueError: if the argumens are invalid. """ @@ -330,9 +447,9 @@ class Transformer(object): sgv_ = self._transform_sgv(sgv) - ops_mapping = self._info.create_ops_mapping() + res_info = Transformer.ResultInfo(self._info) self._info = None - return sgv_, ops_mapping + return sgv_, res_info def _transform_sgv(self, sgv): """Transform a subgraph view. @@ -470,9 +587,13 @@ def copy(sgv, dst_graph=None, dst_scope="", src_scope="", src_scope: the source scope. reuse_dst_scope: if True the dst_scope is re-used if it already exists. Otherwise, the scope is given a unique name based on the one given - by postfixing an underscore followed by a digit (default). + by appending an underscore followed by a digit (default). Returns: - The subgraph view of the copied subgraph. + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. Raises: TypeError: if dst_graph is not a tf.Graph. StandardError: if sgv cannot be converted to a SubGraphView using @@ -487,3 +608,92 @@ def copy(sgv, dst_graph=None, dst_scope="", src_scope="", copier = Transformer() return copier( sgv, dst_graph, dst_scope, src_scope, reuse_dst_scope=reuse_dst_scope) + + +def copy_with_input_replacements(sgv, replacement_ts, + dst_graph=None, dst_scope="", src_scope="", + reuse_dst_scope=False): + """Copy a subgraph, replacing some of its inputs. + + Note a replacement only happens if the tensor to be replaced + is an input of the given subgraph. The inputs of a subgraph can + be queried using sgv.inputs. + + Args: + sgv: the source subgraph-view. This argument is converted to a subgraph + using the same rules as the function subgraph.make_view. + replacement_ts: dictionary mapping from original tensors to the + replaced one. + dst_graph: the destination graph. + dst_scope: the destination scope. + src_scope: the source scope. + reuse_dst_scope: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + Returns: + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. + Raises: + TypeError: if dst_graph is not a tf.Graph. + StandardError: if sgv cannot be converted to a SubGraphView using + the same rules as the function subgraph.make_view. + """ + sgv = subgraph.make_view(sgv) + if dst_graph is None: + dst_graph = sgv.graph + if not isinstance(dst_graph, tf_ops.Graph): + raise TypeError("Expected a tf.Graph, got: {}".format(type(dst_graph))) + + copier = Transformer() + # Replace tensor if possible. + def replace_t_with_replacement_handler(info, t): + if t in replacement_ts: + return replacement_ts[t] + else: + return keep_t_if_possible_handler(info, t) + copier.transform_external_input_handler = replace_t_with_replacement_handler + return copier( + sgv, dst_graph, dst_scope, src_scope, reuse_dst_scope=reuse_dst_scope) + + +def graph_replace(target_ts, replacement_ts, dst_scope="", + src_scope="", reuse_dst_scope=False): + """Create a new graph which compute the targets from the replaced Tensors. + + Args: + target_ts: a single tf.Tensor or an iterabble of tf.Tensor. + replacement_ts: dictionary mapping from original tensors to replaced tensors + dst_scope: the destination scope. + src_scope: the source scope. + reuse_dst_scope: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + Returns: + A single tf.Tensor or a list of target tf.Tensor, depending on + the type of the input argument `target_ts`. + The returned tensors are recomputed using the tensors from replacement_ts. + Raises: + ValueError: if the targets are not connected to replacement_ts. + """ + # Identify operations in the graph that will change. + # Start forward walk at Tensors that will be replaced, and + # backward walk at the target output Tensors. + flatten_target_ts = util.flatten_tree(target_ts) + # Construct the forward control dependencies edges so that + # the get_walks_intersection_ops can also traverse the + # control dependencies. + graph = util.get_unique_graph(flatten_target_ts, check_types=(tf_ops.Tensor)) + control_ios = util.ControlOutputs(graph) + ops = select.get_walks_intersection_ops(list(iterkeys(replacement_ts)), + flatten_target_ts, + control_ios=control_ios) + if not ops: + raise ValueError("Targets and replacements are not connected!") + # Create a copy of the relevant subgraph + _, info = copy_with_input_replacements( + ops, replacement_ts, None, dst_scope, src_scope, reuse_dst_scope) + # Return the transformed targets + return info.transformed(target_ts) diff --git a/tensorflow/contrib/graph_editor/util.py b/tensorflow/contrib/graph_editor/util.py index 506726580529d6c9463711014d5a6abfd6b5ebce..fd6c64d70b003a0021315f71657c7f128db22f40 100644 --- a/tensorflow/contrib/graph_editor/util.py +++ b/tensorflow/contrib/graph_editor/util.py @@ -19,6 +19,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from six import iteritems from tensorflow.python.framework import ops as tf_ops from tensorflow.python.ops import array_ops as tf_array_ops @@ -86,6 +87,54 @@ def is_iterable(obj): return True +def flatten_tree(tree, leaves=None): + """Flatten a tree into a list. + + Args: + tree: iterable or not. If iterable, its elements (child) can also be + iterable or not. + leaves: list to which the tree leaves are appended (None by default). + Returns: + A list of all the leaves in the tree. + """ + if leaves is None: + leaves = [] + if is_iterable(tree): + for child in tree: + flatten_tree(child, leaves) + else: + leaves.append(tree) + return leaves + + +def transform_tree(tree, fn, iterable_type=tuple): + """Transform all the nodes of a tree. + + Args: + tree: iterable or not. If iterable, its elements (child) can also be + iterable or not. + fn: function to apply to each leaves. + iterable_type: type use to construct the resulting tree for unknwon + iterable, typically `list` or `tuple`. + Returns: + A tree whose leaves has been transformed by `fn`. + The hierarchy of the output tree mimics the one of the input tree. + """ + if is_iterable(tree): + if isinstance(tree, list): + return [transform_tree(child, fn) for child in tree] + elif isinstance(tree, tuple): + # this works for named tupled as well: + return tree.__new__(type(tree), + (transform_tree(child, fn) for child in tree)) + elif isinstance(tree, dict): + return {k: transform_tree(child, fn) for k, child in iteritems(tree)} + else: + return iterable_type(transform_tree(child, fn) for child in tree) + else: + return fn(tree) + + def check_graphs(*args): """Check that all the element in args belong to the same graph. diff --git a/tensorflow/contrib/ios_examples/README.md b/tensorflow/contrib/ios_examples/README.md index 1c29c74e51e319eee55fd71ac87322e19169d97f..83b1d7868a0eca5350e8c33778124cae0dd8d98b 100644 --- a/tensorflow/contrib/ios_examples/README.md +++ b/tensorflow/contrib/ios_examples/README.md @@ -71,6 +71,9 @@ rundown: inside the library are not stripped out. To the linker, they can appear unused because no other code references the variables, but in fact their constructors have the important side effect of registering the class. + + - You'll need to include the Accelerate framework in the "Link Binary with + Libraries" build phase of your project. - C++11 support (or later) should be enabled by setting `C++ Language Dialect` to `GNU++11` (or `GNU++14`), and `C++ Standard Library` to `libc++`. diff --git a/tensorflow/contrib/ios_examples/benchmark/benchmark.xcodeproj/project.pbxproj b/tensorflow/contrib/ios_examples/benchmark/benchmark.xcodeproj/project.pbxproj index 934bafdeb94d953b7147fcfdd0c6995de68428ae..a726698747545a52cd37334e5c34e32730f03220 100644 --- a/tensorflow/contrib/ios_examples/benchmark/benchmark.xcodeproj/project.pbxproj +++ b/tensorflow/contrib/ios_examples/benchmark/benchmark.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 590E7D881D02091F00DF5523 /* libprotobuf-lite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */; }; 590E7D8A1D0209DD00DF5523 /* libprotobuf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 590E7D871D02091F00DF5523 /* libprotobuf.a */; }; + 5993C7701D5D4E7F0048CE6A /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5993C76F1D5D4E7F0048CE6A /* Accelerate.framework */; }; 59A3D0011CF4E68100C4259F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 59A3CFF21CF4E68100C4259F /* AppDelegate.mm */; }; 59A3D0031CF4E68100C4259F /* grace_hopper.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 59A3CFF51CF4E68100C4259F /* grace_hopper.jpg */; }; 59A3D0051CF4E68100C4259F /* imagenet_comp_graph_label_strings.txt in Resources */ = {isa = PBXBuildFile; fileRef = 59A3CFF71CF4E68100C4259F /* imagenet_comp_graph_label_strings.txt */; }; @@ -25,6 +26,7 @@ 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libprotobuf-lite.a"; path = "../../makefile/gen/protobuf_ios/lib/libprotobuf-lite.a"; sourceTree = ""; }; 590E7D871D02091F00DF5523 /* libprotobuf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libprotobuf.a; path = ../../makefile/gen/protobuf_ios/lib/libprotobuf.a; sourceTree = ""; }; 5911579B1CF4011C00C31E3A /* benchmark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = benchmark.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5993C76F1D5D4E7F0048CE6A /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 59A3CFF11CF4E68100C4259F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 59A3CFF21CF4E68100C4259F /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = ""; }; 59A3CFF41CF4E68100C4259F /* cropped_panda.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = cropped_panda.jpg; sourceTree = ""; }; @@ -50,6 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5993C7701D5D4E7F0048CE6A /* Accelerate.framework in Frameworks */, 590E7D8A1D0209DD00DF5523 /* libprotobuf.a in Frameworks */, 590E7D881D02091F00DF5523 /* libprotobuf-lite.a in Frameworks */, 59A3D0181CF4E86100C4259F /* UIKit.framework in Frameworks */, @@ -63,6 +66,7 @@ 591157921CF4011C00C31E3A = { isa = PBXGroup; children = ( + 5993C76F1D5D4E7F0048CE6A /* Accelerate.framework */, 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */, 590E7D871D02091F00DF5523 /* libprotobuf.a */, 59A3D0171CF4E86100C4259F /* UIKit.framework */, diff --git a/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj b/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj index 14785cc708ed02154d28a690ee8087d15c534e6c..451f536a7c4d905f00ce92f9cc792b647b7f9018 100644 --- a/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj +++ b/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 592FF90D18EDD0DA00C164F8 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 592FF90A18EDD0DA00C164F8 /* MainStoryboard_iPhone.storyboard */; }; 592FF92518EE240200C164F8 /* CameraExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 592FF92218EE240200C164F8 /* CameraExampleAppDelegate.m */; }; 592FF92618EE240200C164F8 /* CameraExampleViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 592FF92418EE240200C164F8 /* CameraExampleViewController.mm */; }; + 5993C7721D5D4E980048CE6A /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5993C7711D5D4E980048CE6A /* Accelerate.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -52,6 +53,7 @@ 592FF92218EE240200C164F8 /* CameraExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraExampleAppDelegate.m; sourceTree = SOURCE_ROOT; }; 592FF92318EE240200C164F8 /* CameraExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CameraExampleViewController.h; sourceTree = SOURCE_ROOT; }; 592FF92418EE240200C164F8 /* CameraExampleViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CameraExampleViewController.mm; sourceTree = SOURCE_ROOT; }; + 5993C7711D5D4E980048CE6A /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,6 +61,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5993C7721D5D4E980048CE6A /* Accelerate.framework in Frameworks */, 591D3EDF1CFFAD230059011C /* libprotobuf-lite.a in Frameworks */, 591D3EE01CFFAD230059011C /* libprotobuf.a in Frameworks */, 591D3ECF1CFF7FCE0059011C /* ImageIO.framework in Frameworks */, @@ -103,6 +106,7 @@ 592FF8B718ECBD7600C164F8 /* Frameworks */ = { isa = PBXGroup; children = ( + 5993C7711D5D4E980048CE6A /* Accelerate.framework */, 591D3EDD1CFFAD230059011C /* libprotobuf-lite.a */, 591D3EDE1CFFAD230059011C /* libprotobuf.a */, 591D3ECE1CFF7FCE0059011C /* ImageIO.framework */, diff --git a/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj b/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj index a81286a5b19f26b118e0539a9b1d12482feb5b7d..9e058be281438d15dc4a33d1aa132ea5fc5e1f6f 100644 --- a/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj +++ b/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 590E7D881D02091F00DF5523 /* libprotobuf-lite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */; }; 590E7D8A1D0209DD00DF5523 /* libprotobuf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 590E7D871D02091F00DF5523 /* libprotobuf.a */; }; + 5993C7741D5D4EAF0048CE6A /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5993C7731D5D4EAF0048CE6A /* Accelerate.framework */; }; 59A3D0011CF4E68100C4259F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 59A3CFF21CF4E68100C4259F /* AppDelegate.mm */; }; 59A3D0031CF4E68100C4259F /* grace_hopper.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 59A3CFF51CF4E68100C4259F /* grace_hopper.jpg */; }; 59A3D0051CF4E68100C4259F /* imagenet_comp_graph_label_strings.txt in Resources */ = {isa = PBXBuildFile; fileRef = 59A3CFF71CF4E68100C4259F /* imagenet_comp_graph_label_strings.txt */; }; @@ -25,6 +26,7 @@ 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libprotobuf-lite.a"; path = "../../makefile/gen/protobuf_ios/lib/libprotobuf-lite.a"; sourceTree = ""; }; 590E7D871D02091F00DF5523 /* libprotobuf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libprotobuf.a; path = ../../makefile/gen/protobuf_ios/lib/libprotobuf.a; sourceTree = ""; }; 5911579B1CF4011C00C31E3A /* tf_ios_makefile_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tf_ios_makefile_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5993C7731D5D4EAF0048CE6A /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 59A3CFF11CF4E68100C4259F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 59A3CFF21CF4E68100C4259F /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = ""; }; 59A3CFF41CF4E68100C4259F /* cropped_panda.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = cropped_panda.jpg; sourceTree = ""; }; @@ -50,6 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5993C7741D5D4EAF0048CE6A /* Accelerate.framework in Frameworks */, 590E7D8A1D0209DD00DF5523 /* libprotobuf.a in Frameworks */, 590E7D881D02091F00DF5523 /* libprotobuf-lite.a in Frameworks */, 59A3D0181CF4E86100C4259F /* UIKit.framework in Frameworks */, @@ -63,6 +66,7 @@ 591157921CF4011C00C31E3A = { isa = PBXGroup; children = ( + 5993C7731D5D4EAF0048CE6A /* Accelerate.framework */, 590E7D861D02091F00DF5523 /* libprotobuf-lite.a */, 590E7D871D02091F00DF5523 /* libprotobuf.a */, 59A3D0171CF4E86100C4259F /* UIKit.framework */, diff --git a/tensorflow/contrib/layers/__init__.py b/tensorflow/contrib/layers/__init__.py index 20a82a235e2ebfd4db43c3daa578786bfdfb24b6..4bec7c2661a154589e38f34ebe3e3308f1f717bf 100644 --- a/tensorflow/contrib/layers/__init__.py +++ b/tensorflow/contrib/layers/__init__.py @@ -27,6 +27,7 @@ common machine learning algorithms. @@convolution2d_transpose @@flatten @@fully_connected +@@layer_norm @@max_pool2d @@one_hot_encoding @@repeat diff --git a/tensorflow/contrib/layers/python/layers/feature_column.py b/tensorflow/contrib/layers/python/layers/feature_column.py index dbb6b30152356e739de3ca73fff93d52f4f0375b..35c6d1a2d773a787da04550059b6b6195ef70f16 100644 --- a/tensorflow/contrib/layers/python/layers/feature_column.py +++ b/tensorflow/contrib/layers/python/layers/feature_column.py @@ -76,6 +76,7 @@ import collections import math from tensorflow.contrib.framework.python.framework import checkpoint_utils +from tensorflow.contrib.framework.python.framework import deprecation from tensorflow.contrib.framework.python.ops import variables as contrib_variables from tensorflow.contrib.layers.python.layers import embedding_ops from tensorflow.contrib.layers.python.ops import bucketization_op @@ -90,6 +91,21 @@ from tensorflow.python.ops import parsing_ops from tensorflow.python.ops import string_ops from tensorflow.python.ops import variable_scope from tensorflow.python.ops import variables +from tensorflow.python.platform import tf_logging as logging + + +class _EmbeddingLookupArguments( + collections.namedtuple("_EmbeddingLookupArguments", + ["input_tensor", + "weight_tensor", + "vocab_size", + "initializer", + "combiner"])): + """Represents the information needed from a column for embedding lookup. + + Used to to compute DNN inputs and weighted sum. + """ + pass class _FeatureColumn(object): @@ -106,21 +122,33 @@ class _FeatureColumn(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty + @deprecation.deprecated( + "2016-09-25", + "Should be private.") def name(self): """Returns the name of column or transformed column.""" pass @abc.abstractproperty + @deprecation.deprecated( + "2016-09-25", + "Should be private.") def config(self): """Returns configuration of the base feature for `tf.parse_example`.""" pass @abc.abstractproperty + @deprecation.deprecated( + "2016-09-25", + "Should be private.") def key(self): """Returns a string which will be used as a key when we do sorting.""" pass @abc.abstractmethod + @deprecation.deprecated( + "2016-09-25", + "Should be private.") def insert_transformed_feature(self, columns_to_tensors): """Apply transformation and inserts it into columns_to_tensors. @@ -133,6 +161,9 @@ class _FeatureColumn(object): self)) @abc.abstractmethod + @deprecation.deprecated( + "2016-09-25", + "Use layers.input_from_feature_columns instead.") def to_dnn_input_layer(self, input_tensor, weight_collection=None, @@ -141,6 +172,9 @@ class _FeatureColumn(object): raise ValueError("Calling an abstract method.") @abc.abstractmethod + @deprecation.deprecated( + "2016-09-25", + "Use layers.weighted_sum_from_feature_columns instead.") def to_weighted_sum(self, input_tensor, num_outputs=1, @@ -149,6 +183,22 @@ class _FeatureColumn(object): """Returns a Tensor as linear predictions and a list of created Variable.""" raise ValueError("Calling an abstract method.") + # It is expected that classes implement either to_embedding_lookup_arguments + # or to_dense_tensor to be used in linear models. + # pylint: disable=unused-argument + def _to_embedding_lookup_arguments(self, input_tensor): + """Returns arguments to look up embeddings for this column.""" + raise NotImplementedError("Calling an abstract method.") + + # pylint: disable=unused-argument + def _to_dense_tensor(self, input_tensor): + """Returns a dense tensor representing this column's values.""" + raise NotImplementedError("Calling an abstract method.") + + def _checkpoint_path(self): + """Returns None, or a (path,tensor_name) to load a checkpoint from.""" + return None + def _key_without_properties(self, properties): """Helper method for self.key() that omits particular properties.""" fields_values = [] @@ -303,6 +353,26 @@ class _SparseColumn(_FeatureColumn, combiner=self.combiner, trainable=trainable) + def _to_embedding_lookup_arguments(self, input_tensor): + return _EmbeddingLookupArguments( + input_tensor=self.id_tensor(input_tensor), + weight_tensor=self.weight_tensor(input_tensor), + vocab_size=self.length, + initializer=init_ops.zeros_initializer, + combiner=self.combiner) + + def is_compatible(self, other_column): + """Check compatability of two sparse columns.""" + if self.lookup_config and other_column.lookup_config: + return self.lookup_config == other_column.lookup_config + compatible = (self.length == other_column.length and + (self.dtype == other_column.dtype or + (self.dtype.is_integer and other_column.dtype.is_integer))) + if compatible: + logging.warn("Column {} and {} may not have the same vocabulary.". + format(self.name, other_column.name)) + return compatible + class _SparseColumnIntegerized(_SparseColumn): """See `sparse_column_with_integerized_feature`.""" @@ -547,6 +617,14 @@ class _WeightedSparseColumn(_FeatureColumn, collections.namedtuple( combiner=self.sparse_id_column.combiner, trainable=trainable) + def _to_embedding_lookup_arguments(self, input_tensor): + return _EmbeddingLookupArguments( + input_tensor=self.id_tensor(input_tensor), + weight_tensor=self.weight_tensor(input_tensor), + vocab_size=self.length, + initializer=init_ops.zeros_initializer, + combiner=self.sparse_id_column.combiner) + def weighted_sparse_column(sparse_id_column, weight_column_name, @@ -554,8 +632,8 @@ def weighted_sparse_column(sparse_id_column, """Creates a _SparseColumn by combining sparse_id_column with a weight column. Args: - sparse_id_column: A _SparseColumn which is created by `sparse_column_with_*` - functions. + sparse_id_column: A `_SparseColumn` which is created by + `sparse_column_with_*` functions. weight_column_name: A string defining a sparse column name which represents weight or value of the corresponding sparse id feature. dtype: Type of weights, such as `tf.float32` @@ -592,12 +670,13 @@ def weighted_sparse_column(sparse_id_column, class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( "_EmbeddingColumn", ["sparse_id_column", "dimension", "combiner", "initializer", - "ckpt_to_load_from", "tensor_name_in_ckpt"])): + "ckpt_to_load_from", "tensor_name_in_ckpt", "shared_embedding_name", + "shared_vocab_size"])): """Represents an embedding column. Args: - sparse_id_column: A _SparseColumn which is created by `sparse_column_with_*` - or `weighted_sparse_column` functions. + sparse_id_column: A `_SparseColumn` which is created by + `sparse_column_with_*` or `weighted_sparse_column` functions. dimension: An integer specifying dimension of the embedding. combiner: A string specifying how to reduce if there are multiple entries in a single row. Currently "mean", "sqrtn" and "sum" are supported. Each @@ -616,6 +695,9 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( tensor_name_in_ckpt: (Optional). Name of the `Tensor` in the provided checkpoint from which to restore the column weights. Required if `ckpt_to_load_from` is not None. + shared_embedding_name: (Optional). The common name for shared embedding. + shared_vocab_size: (Optional). The common vocab_size used for shared + embedding space. Raises: ValueError: if `initializer` is specified and is not callable. Also, @@ -628,7 +710,9 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( combiner="mean", initializer=None, ckpt_to_load_from=None, - tensor_name_in_ckpt=None): + tensor_name_in_ckpt=None, + shared_embedding_name=None, + shared_vocab_size=None): if initializer is not None and not callable(initializer): raise ValueError("initializer must be callable if specified. " "Embedding of column_name: {}".format( @@ -645,16 +729,24 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( return super(_EmbeddingColumn, cls).__new__(cls, sparse_id_column, dimension, combiner, initializer, ckpt_to_load_from, - tensor_name_in_ckpt) + tensor_name_in_ckpt, + shared_embedding_name, + shared_vocab_size) @property def name(self): - return "{}_embedding".format(self.sparse_id_column.name) + if self.shared_embedding_name is None: + return "{}_embedding".format(self.sparse_id_column.name) + else: + return "{}_shared_embedding".format(self.sparse_id_column.name) @property def length(self): """Returns id size.""" - return self.sparse_id_column.length + if self.shared_vocab_size is None: + return self.sparse_id_column.length + else: + return self.shared_vocab_size @property def config(self): @@ -673,6 +765,7 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( input_tensor, weight_collections=None, trainable=True): + is_shared_embedding = self.shared_embedding_name is not None output, embedding_weights = _create_embedding_lookup( input_tensor=self.sparse_id_column.id_tensor(input_tensor), weight_tensor=self.sparse_id_column.weight_tensor(input_tensor), @@ -681,7 +774,10 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( weight_collections=_add_variable_collection(weight_collections), initializer=self.initializer, combiner=self.combiner, - trainable=trainable) + trainable=trainable, + name=self.shared_embedding_name, + is_shared_embedding=is_shared_embedding) + if self.ckpt_to_load_from is not None: weights_to_restore = embedding_weights if len(embedding_weights) == 1: @@ -691,6 +787,11 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( {self.tensor_name_in_ckpt: weights_to_restore}) return output + def _checkpoint_path(self): + if self.ckpt_to_load_from is not None: + return self.ckpt_to_load_from, self.tensor_name_in_ckpt + return None + # pylint: disable=unused-argument def to_weighted_sum(self, input_tensor, @@ -700,6 +801,11 @@ class _EmbeddingColumn(_FeatureColumn, collections.namedtuple( raise ValueError("EmbeddingColumn is not supported in linear models. " "Please use sparse_column. column: {}".format(self)) + # pylint: disable=unused-argument + def _to_embedding_lookup_arguments(self, input_tensor): + raise ValueError("Column {} is not supported in linear models. " + "Please use sparse_column.".format(self)) + def embedding_column(sparse_id_column, dimension, @@ -707,16 +813,16 @@ def embedding_column(sparse_id_column, initializer=None, ckpt_to_load_from=None, tensor_name_in_ckpt=None): - """Creates an _EmbeddingColumn. + """Creates an `_EmbeddingColumn`. Args: - sparse_id_column: A _SparseColumn which is created by `sparse_column_with_*` - or crossed_column functions. Note that `combiner` defined in - `sparse_id_column` is ignored. + sparse_id_column: A `_SparseColumn` which is created by for example + `sparse_column_with_*` or crossed_column functions. Note that `combiner` + defined in `sparse_id_column` is ignored. dimension: An integer specifying dimension of the embedding. combiner: A string specifying how to reduce if there are multiple entries in a single row. Currently "mean", "sqrtn" and "sum" are supported. Each - of this can be thought as example level normalizations on the column: + of this can be considered an example level normalization on the column: * "sum": do not normalize * "mean": do l1 normalization * "sqrtn": do l2 normalization @@ -733,12 +839,100 @@ def embedding_column(sparse_id_column, `ckpt_to_load_from` is not None. Returns: - An _EmbeddingColumn. + An `_EmbeddingColumn`. """ return _EmbeddingColumn(sparse_id_column, dimension, combiner, initializer, ckpt_to_load_from, tensor_name_in_ckpt) +def shared_embedding_columns(sparse_id_columns, + dimension, + combiner="mean", + shared_embedding_name=None, + initializer=None, + ckpt_to_load_from=None, + tensor_name_in_ckpt=None): + """Creates a list of `_EmbeddingColumn` sharing the same embedding. + + Args: + sparse_id_columns: An iterable of `_SparseColumn`, such as those created by + `sparse_column_with_*` or crossed_column functions. Note that `combiner` + defined in each sparse_id_column is ignored. + dimension: An integer specifying dimension of the embedding. + combiner: A string specifying how to reduce if there are multiple entries + in a single row. Currently "mean", "sqrtn" and "sum" are supported. Each + of this can be considered an example level normalization on the column: + * "sum": do not normalize + * "mean": do l1 normalization + * "sqrtn": do l2 normalization + For more information: `tf.embedding_lookup_sparse`. + shared_embedding_name: (Optional). A string specifying the name of shared + embedding weights. This will be needed if you want to reference the shared + embedding separately from the generated `_EmbeddingColumn`. + initializer: A variable initializer function to be used in embedding + variable initialization. If not specified, defaults to + `tf.truncated_normal_initializer` with mean 0.0 and standard deviation + 1/sqrt(sparse_id_columns[0].length). + ckpt_to_load_from: (Optional). String representing checkpoint name/pattern + to restore the column weights. Required if `tensor_name_in_ckpt` is not + None. + tensor_name_in_ckpt: (Optional). Name of the `Tensor` in the provided + checkpoint from which to restore the column weights. Required if + `ckpt_to_load_from` is not None. + + Returns: + A tuple of `_EmbeddingColumn` with shared embedding space. + + Raises: + ValueError: if sparse_id_columns is empty, or its elements are not + compatible with each other. + TypeError: if at least one element of sparse_id_columns is not a + `SparseTensor`. + """ + if len(sparse_id_columns) < 1: + raise ValueError("The input sparse_id_columns should have at least one " + "element.") + for sparse_id_column in sparse_id_columns: + if not isinstance(sparse_id_column, _SparseColumn): + raise TypeError("Elements of sparse_id_columns must be _SparseColumn, but" + "{} is not.".format(sparse_id_column)) + + if not isinstance(sparse_id_columns, list): + sparse_id_columns = list(sparse_id_columns) + if len(sparse_id_columns) == 1: + return [ + _EmbeddingColumn(sparse_id_columns[0], dimension, combiner, initializer, + ckpt_to_load_from, tensor_name_in_ckpt, + shared_embedding_name)] + else: + # check compatibility of sparse_id_columns + compatible = True + for column in sparse_id_columns[1:]: + compatible = compatible and column.is_compatible(sparse_id_columns[0]) + if not compatible: + raise ValueError("The input sparse id columns are not compatible.") + # Construct the shared name and size for shared embedding space. + if not shared_embedding_name: + if len(sparse_id_columns) <= 3: + shared_embedding_name = "_".join([column.name + for column in sparse_id_columns]) + else: + shared_embedding_name = "_".join([column.name + for column in sparse_id_columns[0:3]]) + shared_embedding_name += ( + "_plus_{}_others".format(len(sparse_id_columns)-3)) + shared_embedding_name += "_shared_embedding" + shared_vocab_size = sparse_id_columns[0].length + + embedded_columns = [] + for column in sparse_id_columns: + embedded_columns.append( + _EmbeddingColumn(column, dimension, combiner, initializer, + ckpt_to_load_from, tensor_name_in_ckpt, + shared_embedding_name, shared_vocab_size)) + return tuple(embedded_columns) + + class _HashedEmbeddingColumn(collections.namedtuple( "_HashedEmbeddingColumn", ["column_name", "size", "dimension", "combiner", "initializer"]), _EmbeddingColumn): @@ -929,6 +1123,9 @@ class _RealValuedColumn(_FeatureColumn, collections.namedtuple( transformed_input_tensor, weight, name="matmul") return log_odds_by_dim, [weight] + def _to_dense_tensor(self, input_tensor): + return input_tensor + def real_valued_column(column_name, dimension=1, @@ -1172,6 +1369,14 @@ class _BucketizedColumn(_FeatureColumn, collections.namedtuple( combiner="sum", trainable=trainable) + def _to_embedding_lookup_arguments(self, input_tensor): + return _EmbeddingLookupArguments( + input_tensor=self.to_sparse_tensor(input_tensor), + weight_tensor=None, + vocab_size=self.length * self.source_column.dimension, + initializer=init_ops.zeros_initializer, + combiner="sum") + def bucketized_column(source_column, boundaries): """Creates a _BucketizedColumn. @@ -1371,6 +1576,19 @@ class _CrossedColumn(_FeatureColumn, collections.namedtuple( {self.tensor_name_in_ckpt: weights_to_restore}) return output, embedding_weights + def _checkpoint_path(self): + if self.ckpt_to_load_from is not None: + return self.ckpt_to_load_from, self.tensor_name_in_ckpt + return None + + def _to_embedding_lookup_arguments(self, input_tensor): + return _EmbeddingLookupArguments( + input_tensor=input_tensor, + weight_tensor=None, + vocab_size=self.length, + initializer=init_ops.zeros_initializer, + combiner=self.combiner) + def crossed_column(columns, hash_bucket_size, combiner="sum", ckpt_to_load_from=None, @@ -1488,6 +1706,9 @@ class DataFrameColumn(_FeatureColumn, log_odds_by_dim = math_ops.matmul(input_tensor, weight, name="matmul") return log_odds_by_dim, [weight] + def _to_dense_tensor(self, input_tensor): + return self.to_dnn_input_layer(input_tensor) + def __eq__(self, other): if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ @@ -1621,7 +1842,7 @@ def _add_variable_collection(weight_collections): def _create_embeddings(shape, dtype, initializer, trainable, weight_collections, - name="weights"): + name=None): """Creates embedding variable. If called within the scope of a partitioner, will partition the variable and @@ -1646,6 +1867,8 @@ def _create_embeddings(shape, dtype, initializer, trainable, weight_collections, Raises: ValueError: If initializer is None or not callable. """ + if name is None: + name = "weights" if not initializer: raise ValueError("initializer must be defined.") if not callable(initializer): @@ -1662,9 +1885,76 @@ def _create_embeddings(shape, dtype, initializer, trainable, weight_collections, return embeddings._get_variable_list() # pylint: disable=protected-access +def _create_shared_embeddings(name, shape, dtype, initializer, trainable, + weight_collections): + """Creates or reuse shared embedding variable. + + If called within the scope of a partitioner, will partition the variable and + return a list of `tf.Variable`. If no partitioner is specified, returns a list + with just one variable. + + Args: + name: A string specifying the name of the embedding variable. + shape: shape of the embeddding. Note this is not the shape of partitioned + variables. + dtype: type of the embedding. Also the shape of each partitioned variable. + initializer: A variable initializer function to be used in embedding + variable initialization. + trainable: If `True` also add variables to the graph collection + `GraphKeys.TRAINABLE_VARIABLES` (see tf.Variable). + weight_collections: List of graph collections to which embedding variables + are added. + + Returns: + A list of `tf.Variable` containing the partitioned embeddings. + + Raises: + ValueError: If initializer is None or not callable, or shape of existing + embedding does not match required shape. + """ + if not initializer: + raise ValueError("initializer must be defined.") + if not callable(initializer): + raise ValueError("initializer must be callable.") + + shared_embedding_collection_name = ( + "SHARED_EMBEDDING_COLLECTION_" + name.upper()) + graph = ops.get_default_graph() + shared_embedding_collection = ( + graph.get_collection_ref(shared_embedding_collection_name)) + if shared_embedding_collection: + if len(shared_embedding_collection) > 1: + raise ValueError("Collection %s can only contain one " + "(partitioned) variable." + % shared_embedding_collection_name) + else: + embeddings = shared_embedding_collection[0] + if embeddings.get_shape() != shape: + raise ValueError("The embedding variable with name {} already exists, " + "but its shape does not match required embedding shape" + " here. Please make sure to use different " + "shared_embedding_name for different shared " + "embeddings.".format(name)) + else: + embeddings = contrib_variables.model_variable( + name=name, + shape=shape, + dtype=dtype, + initializer=initializer, + trainable=trainable, + collections=weight_collections) + graph.add_to_collection(shared_embedding_collection_name, embeddings) + + if isinstance(embeddings, variables.Variable): + return [embeddings] + else: # Else it should be of type `_PartitionedVariable`. + return embeddings._get_variable_list() # pylint: disable=protected-access + + def _create_embedding_lookup(input_tensor, weight_tensor, vocab_size, dimension, weight_collections, initializer, combiner, - trainable, name="weights"): + trainable, name="weights", + is_shared_embedding=False): """Creates embedding variable and does a lookup. Args: @@ -1686,17 +1976,28 @@ def _create_embedding_lookup(input_tensor, weight_tensor, vocab_size, dimension, trainable: If `True` also add variables to the graph collection `GraphKeys.TRAINABLE_VARIABLES` (see tf.Variable). name: A string specifying the name of the embedding variable. + is_shared_embedding: An bool indicating if this is creating shared embedding + variable. Returns: A Tensor with shape [batch_size, dimension] and embedding Variable. """ - embeddings = _create_embeddings(name=name, - shape=[vocab_size, dimension], - dtype=dtypes.float32, - initializer=initializer, - trainable=trainable, - weight_collections=weight_collections) + if is_shared_embedding: + embeddings = _create_shared_embeddings( + name=name, + shape=[vocab_size, dimension], + dtype=dtypes.float32, + initializer=initializer, + trainable=trainable, + weight_collections=weight_collections) + else: + embeddings = _create_embeddings(name=name, + shape=[vocab_size, dimension], + dtype=dtypes.float32, + initializer=initializer, + trainable=trainable, + weight_collections=weight_collections) return embedding_ops.safe_embedding_lookup_sparse( embeddings, input_tensor, diff --git a/tensorflow/contrib/layers/python/layers/feature_column_ops.py b/tensorflow/contrib/layers/python/layers/feature_column_ops.py index a676647d0446cad492eb972050de7ed251e252bb..fcad9bde1988a8597131efecb406e8edeb8aa0a8 100644 --- a/tensorflow/contrib/layers/python/layers/feature_column_ops.py +++ b/tensorflow/contrib/layers/python/layers/feature_column_ops.py @@ -18,8 +18,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +from tensorflow.contrib.framework.python.framework import checkpoint_utils from tensorflow.contrib.framework.python.ops import variables as contrib_variables +from tensorflow.contrib.layers.python.layers import embedding_ops from tensorflow.contrib.layers.python.layers import feature_column as fc +from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import init_ops @@ -111,6 +114,60 @@ def input_from_feature_columns(columns_to_tensors, return array_ops.concat(1, output_tensors) +def _create_embedding_lookup(column, + columns_to_tensors, + embedding_lookup_arguments, + num_outputs, + trainable, + weight_collections): + """Creates variables and returns predictions for linear weights in a model. + + Args: + column: the column we're working on. + columns_to_tensors: a map from column name to tensors. + embedding_lookup_arguments: arguments for embedding lookup. + num_outputs: how many outputs. + trainable: whether the variable we create is trainable. + weight_collections: weights will be placed here. + + Returns: + variables: the created embeddings. + predictions: the computed predictions. + """ + with variable_scope.variable_scope( + None, default_name=column.name, values=columns_to_tensors.values()): + variable = contrib_variables.model_variable( + name='weights', + shape=[embedding_lookup_arguments.vocab_size, num_outputs], + dtype=dtypes.float32, + initializer=embedding_lookup_arguments.initializer, + trainable=trainable, + collections=weight_collections) + if isinstance(variable, variables.Variable): + variable = [variable] + else: + variable = variable._get_variable_list() # pylint: disable=protected-access + predictions = embedding_ops.safe_embedding_lookup_sparse( + variable, + embedding_lookup_arguments.input_tensor, + sparse_weights=embedding_lookup_arguments.weight_tensor, + default_id=0, + combiner=embedding_lookup_arguments.combiner, + name=column.name + '_weights') + return variable, predictions + + +def _maybe_restore_from_checkpoint(checkpoint_path, variable): + if checkpoint_path is not None: + path, tensor_name = checkpoint_path + weights_to_restore = variable + if len(variable) == 1: + weights_to_restore = variable[0] + checkpoint_utils.init_from_checkpoint(path, + {tensor_name: weights_to_restore}) + + + def weighted_sum_from_feature_columns(columns_to_tensors, feature_columns, num_outputs, @@ -180,22 +237,36 @@ def weighted_sum_from_feature_columns(columns_to_tensors, column_to_variable = dict() transformer = _Transformer(columns_to_tensors) for column in sorted(set(feature_columns), key=lambda x: x.key): - with variable_scope.variable_scope( - None, - default_name=column.name, - values=columns_to_tensors.values()): - try: - transformed_tensor = transformer.transform(column) - predictions, variable = column.to_weighted_sum(transformed_tensor, - num_outputs, - weight_collections, - trainable) - except ValueError as e: - raise ValueError('Error creating weighted sum for column: {}.\n' - '{}'.format(column.name, e)) + transformed_tensor = transformer.transform(column) + try: + embedding_lookup_arguments = column._to_embedding_lookup_arguments( # pylint: disable=protected-access + transformed_tensor) + variable, predictions = _create_embedding_lookup( + column, + columns_to_tensors, + embedding_lookup_arguments, + num_outputs, + trainable, + weight_collections) + except NotImplementedError: + with variable_scope.variable_scope( + None, + default_name=column.name, + values=columns_to_tensors.values()): + tensor = column._to_dense_tensor(transformed_tensor) # pylint: disable=protected-access + variable = [contrib_variables.model_variable( + name='weight', + shape=[tensor.get_shape()[1], num_outputs], + initializer=array_ops.zeros_initializer, + collections=weight_collections)] + predictions = math_ops.matmul(tensor, variable[0], name='matmul') + except ValueError as ee: + raise ValueError('Error creating weighted sum for column: {}.\n' + '{}'.format(column.name, ee)) output_tensors.append(predictions) column_to_variable[column] = variable _log_variable(variable) + _maybe_restore_from_checkpoint(column._checkpoint_path(), variable) # pylint: disable=protected-access predictions_no_bias = math_ops.add_n(output_tensors) bias = contrib_variables.model_variable( diff --git a/tensorflow/contrib/layers/python/layers/feature_column_test.py b/tensorflow/contrib/layers/python/layers/feature_column_test.py index f8f098d41bc4fd8cfcf95be6e3d876a53c825b16..87aebb466ca1824113a43cf1fb83988d366ebdb9 100644 --- a/tensorflow/contrib/layers/python/layers/feature_column_test.py +++ b/tensorflow/contrib/layers/python/layers/feature_column_test.py @@ -52,6 +52,55 @@ class FeatureColumnTest(tf.test.TestCase): self.assertEqual(b.dimension, 4) self.assertEqual(b.combiner, "mean") + def testSharedEmbeddingColumn(self): + a1 = tf.contrib.layers.sparse_column_with_keys( + "a1", ["marlo", "omar", "stringer"]) + a2 = tf.contrib.layers.sparse_column_with_keys( + "a2", ["marlo", "omar", "stringer"]) + b = tf.contrib.layers.shared_embedding_columns( + [a1, a2], dimension=4, combiner="mean") + self.assertEqual(len(b), 2) + self.assertEqual(b[0].shared_embedding_name, "a1_a2_shared_embedding") + self.assertEqual(b[1].shared_embedding_name, "a1_a2_shared_embedding") + + # Create a sparse id tensor for a1. + input_tensor_c1 = tf.SparseTensor(indices=[[0, 0], [1, 1], [2, 2]], + values=[0, 1, 2], shape=[3, 3]) + # Create a sparse id tensor for a2. + input_tensor_c2 = tf.SparseTensor(indices=[[0, 0], [1, 1], [2, 2]], + values=[0, 1, 2], shape=[3, 3]) + with tf.variable_scope("run_1"): + b1 = b[0].to_dnn_input_layer(input_tensor_c1) + b2 = b[1].to_dnn_input_layer(input_tensor_c2) + with self.test_session() as sess: + sess.run(tf.initialize_all_variables()) + b1_value = b1.eval() + b2_value = b2.eval() + for i in range(len(b1_value)): + self.assertAllClose(b1_value[i], b2_value[i]) + + # Test the case when a shared_embedding_name is explictly specified. + d = tf.contrib.layers.shared_embedding_columns( + [a1, a2], dimension=4, combiner="mean", + shared_embedding_name="my_shared_embedding") + # a3 is a completely different sparse column with a1 and a2, but since the + # same shared_embedding_name is passed in, a3 will have the same embedding + # as a1 and a2 + a3 = tf.contrib.layers.sparse_column_with_keys( + "a3", ["cathy", "tom", "anderson"]) + e = tf.contrib.layers.shared_embedding_columns( + [a3], dimension=4, combiner="mean", + shared_embedding_name="my_shared_embedding") + with tf.variable_scope("run_2"): + d1 = d[0].to_dnn_input_layer(input_tensor_c1) + e1 = e[0].to_dnn_input_layer(input_tensor_c1) + with self.test_session() as sess: + sess.run(tf.initialize_all_variables()) + d1_value = d1.eval() + e1_value = e1.eval() + for i in range(len(d1_value)): + self.assertAllClose(d1_value[i], e1_value[i]) + def testRealValuedColumn(self): a = tf.contrib.layers.real_valued_column("aaa") self.assertEqual(a.name, "aaa") @@ -418,17 +467,22 @@ class FeatureColumnTest(tf.test.TestCase): values=[0, 1, 2, 3], shape=[4, 4]) - # Invoking 'crossed_col.to_weighted_sum' will create the crossed column - # weights variable. + # Invoking 'weighted_sum_from_feature_columns' will create the crossed + # column weights variable. with tf.variable_scope("run_1"): with tf.variable_scope(crossed_col.name): # Returns looked up column weights which is same as crossed column # weights as well as actual references to weights variables. - col_weights, weights = crossed_col.to_weighted_sum(input_tensor) + _, col_weights, _ = ( + tf.contrib.layers.weighted_sum_from_feature_columns( + {sparse_col_1.name: input_tensor, + sparse_col_2.name: input_tensor}, + [crossed_col], + 1)) # Update the weights since default initializer initializes all weights # to 0.0. - for weight in weights: - assign_op = tf.assign(weight, weight + 0.5) + for weight in col_weights.values(): + assign_op = tf.assign(weight[0], weight[0] + 0.5) save = tf.train.Saver() checkpoint_path = os.path.join(self.get_temp_dir(), "model.ckpt") @@ -436,21 +490,28 @@ class FeatureColumnTest(tf.test.TestCase): with self.test_session() as sess: sess.run(tf.initialize_all_variables()) sess.run(assign_op) - saved_col_weights = col_weights.eval() + saved_col_weights = col_weights[crossed_col][0].eval() save.save(sess, checkpoint_path) crossed_col_initialized = tf.contrib.layers.crossed_column( columns=[sparse_col_1, sparse_col_2], hash_bucket_size=4, ckpt_to_load_from=checkpoint_path, - tensor_name_in_ckpt="run_1/col_1_X_col_2/weights") + tensor_name_in_ckpt=("run_1/col_1_X_col_2/" + "weighted_sum_from_feature_columns/" + "col_1_X_col_2/weights")) with tf.variable_scope("run_2"): # This will initialize the crossed column weights from provided checkpoint # and return a [4, 1] tensor which is same as weights variable. Since we # won't modify weights, this should be same as 'saved_col_weights'. - col_weights_from_ckpt, _ = crossed_col_initialized.to_weighted_sum( - input_tensor) + _, col_weights, _ = ( + tf.contrib.layers.weighted_sum_from_feature_columns( + {sparse_col_1.name: input_tensor, + sparse_col_2.name: input_tensor}, + [crossed_col_initialized], + 1)) + col_weights_from_ckpt = col_weights[crossed_col_initialized][0] with self.test_session() as sess: sess.run(tf.initialize_all_variables()) diff --git a/tensorflow/contrib/layers/python/layers/initializers.py b/tensorflow/contrib/layers/python/layers/initializers.py index 1786b71dcf749730208ee6b304706714c9c446f9..fef925ca7e3e3c2e389745c3bc86992398bda796 100644 --- a/tensorflow/contrib/layers/python/layers/initializers.py +++ b/tensorflow/contrib/layers/python/layers/initializers.py @@ -105,7 +105,8 @@ def variance_scaling_initializer(factor=2.0, mode='FAN_IN', uniform=False, raise TypeError('Cannot create initializer for non-floating point type.') if mode not in ['FAN_IN', 'FAN_OUT', 'FAN_AVG']: raise TypeError('Unknow mode %s [FAN_IN, FAN_OUT, FAN_AVG]', mode) - def _initializer(shape, dtype=dtype): + + def _initializer(shape, dtype=dtype, partition_info=None): """Initializer function.""" if not dtype.is_floating: raise TypeError('Cannot create initializer for non-floating point type.') diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py index cf1e13b97eae463d380d075083fb463cb44f5007..0947480d7c33a5d373485fadbe16bc7ae0c62716 100644 --- a/tensorflow/contrib/layers/python/layers/layers.py +++ b/tensorflow/contrib/layers/python/layers/layers.py @@ -52,6 +52,7 @@ __all__ = ['avg_pool2d', 'dropout', 'flatten', 'fully_connected', + 'layer_norm', 'linear', 'max_pool2d', 'one_hot_encoding', @@ -128,6 +129,18 @@ def batch_norm(inputs, Can be used as a normalizer function for conv2d and fully_connected. + Note: When is_training is True the moving_mean and moving_variance need to be + updated, by default the update_ops are placed in tf.GraphKeys.UPDATE_OPS so + they need to be added as a dependency to the train_op, example: + + update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) + if update_ops: + updates = tf.group(update_ops) + total_loss = control_flow_ops.with_dependencies([updates], total_loss) + + One can set update_collections=None to force the updates in place, but that + can have speed penalty, specially in distributed settings. + Args: inputs: a tensor with 2 or more dimensions, where the first dimension has `batch_size`. The normalization is over all but the last dimension. @@ -139,8 +152,9 @@ def batch_norm(inputs, epsilon: small float added to variance to avoid dividing by zero. activation_fn: Optional activation function. updates_collections: collections to collect the update ops for computation. + The updates_ops need to be excuted with the train_op. If None, a control dependency would be added to make sure the updates are - computed. + computed in place. is_training: whether or not the layer is in training mode. In training mode it would accumulate the statistics of the moments into `moving_mean` and `moving_variance` using an exponential moving average with the given @@ -221,7 +235,9 @@ def batch_norm(inputs, need_moments = is_training_value is None or is_training_value if need_moments: # Calculate the moments based on the individual batch. - mean, variance = nn.moments(inputs, axis, shift=moving_mean) + # Use a copy of moving_mean as a shift to compute more reliable moments. + shift = math_ops.add(moving_mean, 0) + mean, variance = nn.moments(inputs, axis, shift=shift) moving_vars_fn = lambda: (moving_mean, moving_variance) if updates_collections is None: def _force_updates(): @@ -261,7 +277,8 @@ def batch_norm(inputs, outputs.set_shape(inputs_shape) if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope @@ -313,7 +330,8 @@ def bias_add(inputs, outputs = nn.bias_add(inputs, biases) if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope @@ -426,7 +444,8 @@ def convolution2d(inputs, outputs = nn.bias_add(outputs, biases) if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope @@ -526,7 +545,8 @@ def convolution2d_in_plane( if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope @@ -653,7 +673,8 @@ def convolution2d_transpose( if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope @@ -830,7 +851,95 @@ def fully_connected(inputs, # Reshape back outputs outputs = array_ops.reshape(outputs, array_ops.pack(out_shape)) outputs.set_shape(static_shape) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) + + +@add_arg_scope +def layer_norm(inputs, + center=True, + scale=True, + activation_fn=None, + reuse=None, + variables_collections=None, + outputs_collections=None, + trainable=True, + scope=None): + """Adds a Layer Normalization layer from https://arxiv.org/abs/1607.06450. + + "Layer Normalization" + + Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton + + Can be used as a normalizer function for conv2d and fully_connected. + + Args: + inputs: a tensor with 2 or more dimensions. The normalization + occurs over all but the first dimension. + center: If True, subtract `beta`. If False, `beta` is ignored. + scale: If True, multiply by `gamma`. If False, `gamma` is + not used. When the next layer is linear (also e.g. `nn.relu`), this can be + disabled since the scaling can be done by the next layer. + activation_fn: Optional activation function. + reuse: whether or not the layer and its variables should be reused. To be + able to reuse the layer scope must be given. + variables_collections: optional collections for the variables. + outputs_collections: collections to add the outputs. + trainable: If `True` also add variables to the graph collection + `GraphKeys.TRAINABLE_VARIABLES` (see tf.Variable). + scope: Optional scope for `variable_op_scope`. + + Returns: + A `Tensor` representing the output of the operation. + + Raises: + ValueError: if rank or last dimension of `inputs` is undefined. + """ + with variable_scope.variable_scope(scope, 'LayerNorm', [inputs], + reuse=reuse) as sc: + inputs = ops.convert_to_tensor(inputs) + inputs_shape = inputs.get_shape() + inputs_rank = inputs_shape.ndims + if inputs_rank is None: + raise ValueError('Inputs %s has undefined rank.' % inputs.name) + dtype = inputs.dtype.base_dtype + axis = list(range(1, inputs_rank)) + params_shape = inputs_shape[-1:] + if not params_shape.is_fully_defined(): + raise ValueError('Inputs %s has undefined last dimension %s.' % ( + inputs.name, params_shape)) + # Allocate parameters for the beta and gamma of the normalization. + beta, gamma = None, None + if center: + beta_collections = utils.get_variable_collections(variables_collections, + 'beta') + beta = variables.model_variable('beta', + shape=params_shape, + dtype=dtype, + initializer=init_ops.zeros_initializer, + collections=beta_collections, + trainable=trainable) + if scale: + gamma_collections = utils.get_variable_collections(variables_collections, + 'gamma') + gamma = variables.model_variable('gamma', + shape=params_shape, + dtype=dtype, + initializer=init_ops.ones_initializer, + collections=gamma_collections, + trainable=trainable) + # Calculate the moments on the last axis (layer activations). + mean, variance = nn.moments(inputs, axis, keep_dims=True) + # Compute layer normalization using the batch_normalization function. + variance_epsilon = 1E-12 + outputs = nn.batch_normalization( + inputs, mean, variance, beta, gamma, variance_epsilon) + outputs.set_shape(inputs_shape) + if activation_fn: + outputs = activation_fn(outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, + outputs) @add_arg_scope @@ -1079,7 +1188,8 @@ def separable_convolution2d( if activation_fn: outputs = activation_fn(outputs) - return utils.collect_named_outputs(outputs_collections, sc.name, outputs) + return utils.collect_named_outputs(outputs_collections, + sc.original_name_scope, outputs) @add_arg_scope diff --git a/tensorflow/contrib/layers/python/layers/layers_test.py b/tensorflow/contrib/layers/python/layers/layers_test.py index 4d8498940514c946efdea14deca2729d10b71485..4fc2e07b9bc712b8a2ca9c107cbed425b45a33ee 100644 --- a/tensorflow/contrib/layers/python/layers/layers_test.py +++ b/tensorflow/contrib/layers/python/layers/layers_test.py @@ -203,6 +203,16 @@ class Convolution2dTest(tf.test.TestCase): scope='conv1') self.assertEquals(output.op.name, 'conv1/Relu') + def testCreateConvWithCollection(self): + height, width = 3, 3 + images = tf.random_uniform((5, height, width, 3), seed=1) + with tf.name_scope('fe'): + conv = tf.contrib.layers.convolution2d( + images, 32, [3, 3], outputs_collections='outputs', + scope='Conv') + namedOutputs = tf.get_collection('outputs')[0] + self.assertEquals(namedOutputs.name, 'fe/Conv') + def testCreateConvWithoutActivation(self): height, width = 3, 3 with self.test_session(): @@ -989,6 +999,16 @@ class FCTest(tf.test.TestCase): output = tf.contrib.layers.fully_connected(inputs, 32, scope='fc1') self.assertEquals(output.op.name, 'fc1/Relu') + def testCreateFCWithCollection(self): + height, width = 3, 3 + inputs = tf.random_uniform((5, height * width * 3), seed=1) + with tf.name_scope('fe'): + fc = tf.contrib.layers.fully_connected( + inputs, 7, outputs_collections='outputs', + scope='fc') + namedOutputs = tf.get_collection('outputs')[0] + self.assertEquals(namedOutputs.name, 'fe/fc') + def testCreateFcCreatesWeightsAndBiasesVars(self): height, width = 3, 3 inputs = tf.random_uniform((5, height * width * 3), seed=1) @@ -1490,6 +1510,141 @@ class BatchNormTest(tf.test.TestCase): output_false = sess.run([output], {is_training: False}) self.assertTrue(np.allclose(output_true, output_false)) + def testTrainMovingVars(self): + """Test that the gradients are stable while the moving_mean is updated. + + Since the moving_mean is used as shift to compute the tf.momments, the + gradients could diverge, this test checks that gradients remains stable + while the moving_mean is updated. + """ + height, width = 7, 7 + num_channels = 32 + with self.test_session() as sess: + image_shape = (10, height, width, num_channels) + image_values = np.random.rand(*image_shape) + 2 + expected_mean = np.mean(image_values, axis=(0, 1, 2)) + expected_var = np.var(image_values, axis=(0, 1, 2)) + images = tf.constant(image_values, shape=image_shape, dtype=tf.float32) + output = tf.contrib.layers.batch_norm(images, + decay=0.2, + updates_collections=None, + is_training=True) + self.assertEquals(tf.get_collection(tf.GraphKeys.UPDATE_OPS), []) + + objective = tf.reduce_sum(output) + + [images_gradients] = tf.gradients(objective, images) + # Initialize all variables + sess.run(tf.initialize_all_variables()) + moving_mean = tf.contrib.framework.get_variables( + 'BatchNorm/moving_mean')[0] + moving_variance = tf.contrib.framework.get_variables( + 'BatchNorm/moving_variance')[0] + mean, variance = sess.run([moving_mean, moving_variance]) + # After initialization moving_mean == 0 and moving_variance == 1. + self.assertAllClose(mean, [0] * num_channels) + self.assertAllClose(variance, [1] * num_channels) + + # Initial input gradients. + images_gradients_value = sess.run(images_gradients) + for _ in range(10): + np_output, new_images_gradients = sess.run([output, images_gradients]) + # The outputs should be close to 0.0 mean and 1.0 variance + self.assertAllClose(np.mean(np_output, axis=(0, 1, 2)), + [0] * num_channels, rtol=0.1, atol=0.1) + self.assertAllClose(np.var(np_output, axis=(0, 1, 2)), + [1] * num_channels, rtol=0.1, atol=0.1) + # The gradients should change slowly while updating moving_mean. + max_diff = np.max(np.abs(images_gradients_value - new_images_gradients)) + self.assertGreater(max_diff, 0.0) + self.assertLess(max_diff, 5e-5) + self.assertAllClose(moving_mean.eval(), expected_mean) + self.assertAllClose(moving_variance.eval(), expected_var) + + +class LayerNormTest(tf.test.TestCase): + + def testUnknownShape(self): + with tf.Graph().as_default() as g, self.test_session(g): + inputs = tf.placeholder(dtype=tf.float32) + with self.assertRaisesRegexp(ValueError, 'undefined rank'): + tf.contrib.layers.layer_norm(inputs) + + def testUnknownLastDim(self): + with tf.Graph().as_default() as g, self.test_session(g): + inputs = tf.placeholder(dtype=tf.float32) + inputs.set_shape(tf.TensorShape((5, 3, 3, None))) + with self.assertRaisesRegexp(ValueError, 'undefined last dimension'): + tf.contrib.layers.layer_norm(inputs) + + def testCreateOp(self): + height, width = 3, 3 + with self.test_session(): + images = np.random.uniform(size=(5, height, width, 3)) + output = tf.contrib.layers.layer_norm(images) + self.assertTrue(output.op.name.startswith('LayerNorm/batchnorm')) + self.assertListEqual(output.get_shape().as_list(), [5, height, width, 3]) + + def testCreateVariables(self): + height, width = 3, 3 + with self.test_session(): + images = tf.random_uniform((5, height, width, 3), seed=1) + tf.contrib.layers.layer_norm(images) + beta = tf.contrib.framework.get_variables_by_name('beta')[0] + gamma = tf.contrib.framework.get_variables_by_name('gamma')[0] + self.assertEquals(beta.op.name, 'LayerNorm/beta') + self.assertEquals(gamma.op.name, 'LayerNorm/gamma') + + def testReuseVariables(self): + height, width = 3, 3 + with self.test_session(): + images = tf.random_uniform((5, height, width, 3), seed=1) + tf.contrib.layers.layer_norm(images, scope='ln') + tf.contrib.layers.layer_norm(images, scope='ln', reuse=True) + beta = tf.contrib.framework.get_variables_by_name('beta') + gamma = tf.contrib.framework.get_variables_by_name('gamma') + self.assertEquals(len(beta), 1) + self.assertEquals(len(gamma), 1) + + def testReuseVars(self): + height, width = 3, 3 + with self.test_session() as sess: + image_shape = (10, height, width, 3) + image_values = np.random.rand(*image_shape) + images = tf.constant(image_values, shape=image_shape, dtype=tf.float32) + output_train = tf.contrib.layers.layer_norm(images, scope='LN') + output_eval = tf.contrib.layers.layer_norm(images, + scope='LN', + reuse=True) + # Initialize all variables + sess.run(tf.initialize_all_variables()) + # output_train and output_eval should be the same. + self.assertAllClose(sess.run([output_train]), sess.run([output_eval])) + + def doOutputTest(self, input_shape): + with self.test_session() as sess: + input_values = np.random.rand(*input_shape) + inputs = tf.constant(input_values, shape=input_shape, dtype=tf.float32) + output_op = tf.contrib.layers.layer_norm(inputs, scope='LN') + # Initialize all variables + sess.run(tf.initialize_all_variables()) + # The mean and variance of the output should be close to 0 and 1 + # respectively. + moments_axis = tuple([i for i in range(1, len(input_shape))]) + outputs = sess.run(output_op) + expected_mean = np.zeros(input_shape[0]) + expected_var = np.ones(input_shape[0]) + mean = np.mean(outputs, axis=moments_axis) + var = np.var(outputs, axis=moments_axis) + tol = 1e-5 + self.assertAllClose(mean, expected_mean, rtol=tol, atol=tol) + self.assertAllClose(var, expected_var, rtol=tol, atol=tol) + + def testOutput2DInput(self): + self.doOutputTest((10, 300)) + + def testOutput4DInput(self): + self.doOutputTest((100, 10, 10, 3)) class MaxPool2DTest(tf.test.TestCase): diff --git a/tensorflow/contrib/layers/python/layers/target_column.py b/tensorflow/contrib/layers/python/layers/target_column.py index feef4e4a74c564710b813ea9add4324263a8518c..27f06ff099a9566aabfbc1b5a24758eca7a6085a 100644 --- a/tensorflow/contrib/layers/python/layers/target_column.py +++ b/tensorflow/contrib/layers/python/layers/target_column.py @@ -175,9 +175,51 @@ class _TargetColumn(object): def problem_type(self): return self._problem_type + def _weighted_loss(self, loss, weight_tensor): + """Returns cumulative weighted loss.""" + unweighted_loss = array_ops.reshape(loss, shape=(-1,)) + weighted_loss = math_ops.mul(unweighted_loss, + array_ops.reshape( + weight_tensor, shape=(-1,))) + return weighted_loss + + def training_loss(self, logits, target, features): + """Returns training loss tensor for this head. + + Training loss is different from the loss reported on the tensorboard as we + should respect the example weights when computing the gradient. + + L = sum_{i} w_{i} * l_{i} / B + + where B is the number of examples in the batch, l_{i}, w_{i} are individual + losses, and example weight. + + Args: + logits: logits, a float tensor. + target: either a tensor for labels or in multihead case, a dict of string + to target tensor. + features: features dict. + + Returns: + Loss tensor. + """ + target = target[self.name] if isinstance(target, dict) else target + loss_unweighted = self._loss_fn(logits, target) + + weight_tensor = self.get_weight_tensor(features) + if weight_tensor is None: + return math_ops.reduce_mean(loss_unweighted, name="loss") + else: + loss_weighted = self._weighted_loss(loss_unweighted, weight_tensor) + return math_ops.reduce_mean(loss_weighted, name="loss") + def loss(self, logits, target, features): """Returns loss tensor for this head. + The loss returned is the weighted average. + + L = sum_{i} w_{i} * l_{i} / sum_{i} w_{i} + Args: logits: logits, a float tensor. target: either a tensor for labels or in multihead case, a dict of string @@ -194,10 +236,7 @@ class _TargetColumn(object): if weight_tensor is None: return math_ops.reduce_mean(loss_unweighted, name="loss") else: - loss_unweighted = array_ops.reshape(loss_unweighted, shape=(-1,)) - loss_weighted = math_ops.mul( - loss_unweighted, - array_ops.reshape(weight_tensor, shape=(-1,))) + loss_weighted = self._weighted_loss(loss_unweighted, weight_tensor) return math_ops.div( math_ops.reduce_sum(loss_weighted), math_ops.to_float(math_ops.reduce_sum(weight_tensor)), diff --git a/tensorflow/contrib/layers/python/layers/target_column_test.py b/tensorflow/contrib/layers/python/layers/target_column_test.py index 65e8955d88226d672fb30b1d3a7762c86aed2050..11f0919d356da3b407f8ef97717db3535c8f8324 100644 --- a/tensorflow/contrib/layers/python/layers/target_column_test.py +++ b/tensorflow/contrib/layers/python/layers/target_column_test.py @@ -27,23 +27,29 @@ class RegressionTargetColumnTest(tf.test.TestCase): def testRegression(self): target_column = tf.contrib.layers.regression_target() with tf.Graph().as_default(), tf.Session() as sess: - logits = tf.constant([[1.], [1.], [3.]]) + prediction = tf.constant([[1.], [1.], [3.]]) targets = tf.constant([[0.], [1.], [1.]]) - self.assertAlmostEqual(5. / 3, - sess.run(target_column.loss(logits, targets, {}))) + self.assertAlmostEqual( + 5. / 3, sess.run(target_column.loss(prediction, targets, {}))) def testRegressionWithWeights(self): target_column = tf.contrib.layers.regression_target( weight_column_name="label_weight") with tf.Graph().as_default(), tf.Session() as sess: - features = {"label_weight": tf.constant([[1.], [0.], [0.]])} - logits = tf.constant([[1.], [1.], [3.]]) + features = {"label_weight": tf.constant([[2.], [5.], [0.]])} + prediction = tf.constant([[1.], [1.], [3.]]) targets = tf.constant([[0.], [1.], [1.]]) self.assertAlmostEqual( - 1., sess.run(target_column.loss(logits, targets, features))) + 2. / 7, + sess.run(target_column.loss(prediction, targets, features)), + places=3) + self.assertAlmostEqual( + 2. / 3, + sess.run(target_column.training_loss(prediction, targets, features)), + places=3) -class MulltiClassTargetColumnTest(tf.test.TestCase): +class MultiClassTargetColumnTest(tf.test.TestCase): def testBinaryClassification(self): target_column = tf.contrib.layers.multi_class_target(n_classes=2) @@ -126,9 +132,9 @@ class MulltiClassTargetColumnTest(tf.test.TestCase): def testBinarySVMDefaultWeights(self): target_column = tf.contrib.layers.binary_svm_target() - logits = tf.constant([[-0.5], [1.2]]) + predictions = tf.constant([[-0.5], [1.2]]) targets = tf.constant([0, 1]) - loss = target_column.loss(logits, targets, {}) + loss = target_column.loss(predictions, targets, {}) # Prediction for first example is in the right side of the hyperplane (i.e., # < 0) but it is within the [-1,1] margin. There is a 0.5 loss incurred by # this example. The 2nd prediction is outside the margin so it incurs no @@ -139,15 +145,17 @@ class MulltiClassTargetColumnTest(tf.test.TestCase): def testBinarySVMWithWeights(self): target_column = tf.contrib.layers.binary_svm_target( weight_column_name="weights") - logits = tf.constant([[-0.7], [0.2]]) + predictions = tf.constant([[-0.7], [0.2]]) targets = tf.constant([0, 1]) features = {"weights": tf.constant([2.0, 10.0])} - loss = target_column.loss(logits, targets, features) + loss = target_column.loss(predictions, targets, features) + training_loss = target_column.training_loss(predictions, targets, features) # Prediction for both examples are in the right side of the hyperplane but # within the margin. The (weighted) loss incurred is 2*0.3=0.6 and 10*0.8=8 # respectively. The overall (normalized) loss is therefore 8.6/12. with tf.Session() as sess: - self.assertAlmostEqual(8.6 / 12, sess.run(loss)) + self.assertAlmostEqual(8.6 / 12, sess.run(loss), places=3) + self.assertAlmostEqual(8.6 / 2, sess.run(training_loss), places=3) if __name__ == "__main__": diff --git a/tensorflow/contrib/learn/BUILD b/tensorflow/contrib/learn/BUILD index 057a80f1a661b9d230a510b32fdc4fe01d07e02a..ad1706a6f9d81e5dbe9cca756c4689a48422badb 100644 --- a/tensorflow/contrib/learn/BUILD +++ b/tensorflow/contrib/learn/BUILD @@ -359,6 +359,19 @@ py_test( ], ) +py_test( + name = "run_config_test", + size = "small", + srcs = [ + "python/learn/tests/run_config_test.py", + ], + srcs_version = "PY2AND3", + deps = [ + "//tensorflow:tensorflow_py", + "//tensorflow/python:framework_test_lib", + ], +) + py_test( name = "basic_session_run_hooks_test", size = "small", @@ -671,6 +684,9 @@ py_test( size = "small", srcs = ["python/learn/utils/export_test.py"], srcs_version = "PY2AND3", + tags = [ + "manual", # http://b/31032996 + ], deps = [ ":learn", "//tensorflow:tensorflow_py", diff --git a/tensorflow/contrib/learn/__init__.py b/tensorflow/contrib/learn/__init__.py index e2a0aab657951790184916e3d8cb1ee40ac37e90..84c5a35671098afa79cdf7c3f0dd1a3ececc5d9b 100644 --- a/tensorflow/contrib/learn/__init__.py +++ b/tensorflow/contrib/learn/__init__.py @@ -23,7 +23,6 @@ Train and evaluate TensorFlow models. @@BaseEstimator @@Estimator @@ModeKeys -@@TensorFlowClassifier @@DNNClassifier @@DNNRegressor @@TensorFlowDNNClassifier @@ -31,11 +30,8 @@ Train and evaluate TensorFlow models. @@TensorFlowEstimator @@LinearClassifier @@LinearRegressor -@@TensorFlowLinearClassifier -@@TensorFlowLinearRegressor @@TensorFlowRNNClassifier @@TensorFlowRNNRegressor -@@TensorFlowRegressor ## Graph actions diff --git a/tensorflow/contrib/learn/python/learn/dataframe/__init__.py b/tensorflow/contrib/learn/python/learn/dataframe/__init__.py index 8fba9b6513604a24ff464be9b7266b00a3c5e413..d65f246528571f2b1ba5b9e6d42816b86d4980e8 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/__init__.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/__init__.py @@ -25,6 +25,7 @@ from tensorflow.contrib.learn.python.learn.dataframe.series import Series from tensorflow.contrib.learn.python.learn.dataframe.series import TransformedSeries from tensorflow.contrib.learn.python.learn.dataframe.tensorflow_dataframe import TensorFlowDataFrame from tensorflow.contrib.learn.python.learn.dataframe.transform import parameter +from tensorflow.contrib.learn.python.learn.dataframe.transform import TensorFlowTransform from tensorflow.contrib.learn.python.learn.dataframe.transform import Transform # Transforms @@ -34,6 +35,9 @@ from tensorflow.contrib.learn.python.learn.dataframe.transforms.hashes import Ha from tensorflow.contrib.learn.python.learn.dataframe.transforms.in_memory_source import NumpySource from tensorflow.contrib.learn.python.learn.dataframe.transforms.in_memory_source import PandasSource from tensorflow.contrib.learn.python.learn.dataframe.transforms.reader_source import ReaderSource +# Coming soon; multichange client hassle due to no DIFFBASE in Cider +# from tensorflow.contrib.learn.python.learn.dataframe \ +# .transforms.split_mask import SplitMask from tensorflow.contrib.learn.python.learn.dataframe.transforms.sum import Sum @@ -50,4 +54,5 @@ for bt_def in _bt.BINARY_TRANSFORMS: _bt.register_binary_op(*bt_def) __all__ = ['DataFrame', 'Series', 'PredefinedSeries', 'TransformedSeries', - 'TensorFlowDataFrame', 'parameter', 'Transform'] + 'TensorFlowDataFrame', 'TensorFlowTransform', 'parameter', + 'Transform'] diff --git a/tensorflow/contrib/learn/python/learn/dataframe/dataframe.py b/tensorflow/contrib/learn/python/learn/dataframe/dataframe.py index 6e03f086425a9d5066e29df37d5f0caafd1bd123..dd836c1dec361dacfa03df7f8abce648bf438f8d 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/dataframe.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/dataframe.py @@ -59,21 +59,16 @@ class DataFrame(object): if not isinstance(k, str): raise TypeError("The only supported type for keys is string; got %s" % type(k)) - if isinstance(v, Series): - s = v + if v is None: + del self._columns[k] + elif isinstance(v, Series): + self._columns[k] = v elif isinstance(v, Transform) and v.input_valency() == 0: - s = v() - # TODO(jamieas): hook up these special cases again - # TODO(soergel): can these special cases be generalized? - # elif isinstance(v, pd.Series): - # s = series.NumpySeries(v.values) - # elif isinstance(v, np.ndarray): - # s = series.NumpySeries(v) + self._columns[k] = v() else: raise TypeError( - "Column in assignment must be an inflow.Series, pandas.Series or a" - " numpy array; got type '%s'." % type(v).__name__) - self._columns[k] = s + "Column in assignment must be an inflow.Series, inflow.Transform," + " or None; got type '%s'." % type(v).__name__) def select_columns(self, keys): """Returns a new DataFrame with a subset of columns. @@ -89,6 +84,21 @@ class DataFrame(object): result[key] = self._columns[key] return result + def exclude_columns(self, exclude_keys): + """Returns a new DataFrame with all columns not excluded via exclude_keys. + + Args: + exclude_keys: A list of strings. Each should be the name of a column in + the DataFrame. These columns will be excluded from the result. + Returns: + A new DataFrame containing all columns except those specified. + """ + result = type(self)() + for key, value in self._columns.items(): + if key not in exclude_keys: + result[key] = value + return result + def __getitem__(self, key): """Indexing functionality for DataFrames. @@ -117,6 +127,12 @@ class DataFrame(object): value = [value] self.assign(**dict(zip(key, value))) + def __delitem__(self, key): + if isinstance(key, str): + key = [key] + value = [None for _ in key] + self.assign(**dict(zip(key, value))) + def build(self, **kwargs): # We do not allow passing a cache here, because that would encourage # working around the rule that DataFrames cannot be expected to be diff --git a/tensorflow/contrib/learn/python/learn/dataframe/queues/feeding_functions.py b/tensorflow/contrib/learn/python/learn/dataframe/queues/feeding_functions.py index ae925b606dcfa75f9f63174685ed117623043557..d4f3c596340163d1d769a085c9a812456ce11109 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/queues/feeding_functions.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/queues/feeding_functions.py @@ -18,11 +18,13 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import collections import random import numpy as np from tensorflow.contrib.learn.python.learn.dataframe.queues import feeding_queue_runner as fqr from tensorflow.python.framework import dtypes +from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import data_flow_ops @@ -47,7 +49,8 @@ class _ArrayFeedFn(object): array, batch_size, random_start=False, - seed=None): + seed=None, + num_epochs=None): if len(placeholders) != 2: raise ValueError("_array_feed_fn expects 2 placeholders; got {}.".format( len(placeholders))) @@ -55,18 +58,80 @@ class _ArrayFeedFn(object): self._array = array self._max = len(array) self._batch_size = batch_size + self._num_epochs = num_epochs + self._epoch = 0 random.seed(seed) self._trav = random.randrange(self._max) if random_start else 0 + self._epoch_end = (self._trav - 1) % self._max def __call__(self): + if self._num_epochs and self._epoch >= self._num_epochs: + raise errors.OutOfRangeError(None, None, + "Already emitted %s epochs." % self._epoch) + integer_indexes = [j % self._max for j in range(self._trav, self._trav + self._batch_size) ] + + if self._epoch_end in integer_indexes: + # after this batch we will have processed self._epoch epochs, possibly + # overshooting a bit to fill out a batch. + self._epoch += 1 + self._trav = (integer_indexes[-1] + 1) % self._max return {self._placeholders[0]: integer_indexes, self._placeholders[1]: self._array[integer_indexes]} +class _OrderedDictNumpyFeedFn(object): + """Creates feed dictionaries from `OrderedDict`s of numpy arrays.""" + + def __init__(self, + placeholders, + ordered_dict_of_arrays, + batch_size, + random_start=False, + seed=None, + num_epochs=None): + if len(placeholders) != len(ordered_dict_of_arrays) + 1: + raise ValueError("Expected {} placeholders; got {}.".format( + len(ordered_dict_of_arrays), len(placeholders))) + self._index_placeholder = placeholders[0] + self._col_placeholders = placeholders[1:] + self._ordered_dict_of_arrays = ordered_dict_of_arrays + self._max = len(ordered_dict_of_arrays.values()[0]) + for _, v in ordered_dict_of_arrays.items(): + if len(v) != self._max: + raise ValueError("Array lengths must match.") + self._batch_size = batch_size + self._num_epochs = num_epochs + self._epoch = 0 + random.seed(seed) + self._trav = random.randrange(self._max) if random_start else 0 + self._epoch_end = (self._trav - 1) % self._max + + def __call__(self): + if self._num_epochs and self._epoch >= self._num_epochs: + raise errors.OutOfRangeError(None, None, + "Already emitted %s epochs." % self._epoch) + + integer_indexes = [j % self._max + for j in range(self._trav, self._trav + self._batch_size) + ] + + if self._epoch_end in integer_indexes: + # after this batch we will have processed self._epoch epochs, possibly + # overshooting a bit to fill out a batch. + self._epoch += 1 + + self._trav = (integer_indexes[-1] + 1) % self._max + feed_dict = {self._index_placeholder: integer_indexes} + cols = [column[integer_indexes] + for column in self._ordered_dict_of_arrays.values()] + feed_dict.update(dict(zip(self._col_placeholders, cols))) + return feed_dict + + class _PandasFeedFn(object): """Creates feed dictionaries from pandas `DataFrames`.""" @@ -75,7 +140,8 @@ class _PandasFeedFn(object): dataframe, batch_size, random_start=False, - seed=None): + seed=None, + num_epochs=None): if len(placeholders) != len(dataframe.columns) + 1: raise ValueError("Expected {} placeholders; got {}.".format( len(dataframe.columns), len(placeholders))) @@ -84,13 +150,30 @@ class _PandasFeedFn(object): self._dataframe = dataframe self._max = len(dataframe) self._batch_size = batch_size + self._num_epochs = num_epochs + self._epoch = 0 random.seed(seed) self._trav = random.randrange(self._max) if random_start else 0 + self._epoch_end = (self._trav - 1) % self._max def __call__(self): + if self._num_epochs and self._epoch >= self._num_epochs: + raise errors.OutOfRangeError(None, None, + "Already emitted %s epochs." % self._epoch) + integer_indexes = [j % self._max for j in range(self._trav, self._trav + self._batch_size) ] + + if self._epoch_end in integer_indexes: + # after this batch we will have processed self._epoch epochs, possibly + # overshooting a bit to fill out a batch. + self._epoch += 1 + if self._epoch == self._num_epochs: + # trim this batch, so as not to overshoot the last epoch. + batch_end_inclusive = integer_indexes.index(self._epoch_end) + integer_indexes = integer_indexes[:(batch_end_inclusive+1)] + self._trav = (integer_indexes[-1] + 1) % self._max result = self._dataframe.iloc[integer_indexes] cols = [result[col].values for col in result.columns] @@ -106,7 +189,8 @@ def enqueue_data(data, num_threads=1, seed=None, name="enqueue_input", - enqueue_size=1): + enqueue_size=1, + num_epochs=None): """Creates a queue filled from a numpy array or pandas `DataFrame`. Returns a queue filled with the rows of the given array or `DataFrame`. In @@ -126,6 +210,7 @@ def enqueue_data(data, seed: used to seed shuffling and reader starting points. name: a scope name identifying the data. enqueue_size: the number of rows to enqueue per step. + num_epochs: limit enqueuing to a specified number of epochs, if provided. Returns: A queue filled with the rows of the given array or `DataFrame`. @@ -138,6 +223,11 @@ def enqueue_data(data, types = [dtypes.int64, dtypes.as_dtype(data.dtype)] queue_shapes = [(), data.shape[1:]] get_feed_fn = _ArrayFeedFn + elif isinstance(data, collections.OrderedDict): + types = [dtypes.int64] + [dtypes.as_dtype(col.dtype) + for col in data.values()] + queue_shapes = [()] + [col.shape[1:] for col in data.values()] + get_feed_fn = _OrderedDictNumpyFeedFn elif HAS_PANDAS and isinstance(data, pd.DataFrame): types = [dtypes.as_dtype(dt) for dt in [data.index.dtype] + list(data.dtypes)] @@ -148,6 +238,29 @@ def enqueue_data(data, "data must be either a numpy array or pandas DataFrame if pandas is " "installed; got {}".format(type(data).__name__)) + # TODO(jamieas): TensorBoard warnings for all warnings below once available. + + if num_threads > 1 and num_epochs is not None: + logging.warning( + "enqueue_data was called with num_epochs and num_threads > 1. " + "num_epochs is applied per thread, so this will produce more " + "epochs than you probably intend. " + "If you want to limit epochs, use one thread.") + + if shuffle and num_threads > 1 and num_epochs is not None: + logging.warning( + "enqueue_data was called with shuffle=True, num_threads > 1, and " + "num_epochs. This will create multiple threads, all reading the " + "array/dataframe in order adding to the same shuffling queue; the " + "results will likely not be sufficiently shuffled.") + + if not shuffle and num_threads > 1: + logging.warning( + "enqueue_data was called with shuffle=False and num_threads > 1. " + "This will create multiple threads, all reading the " + "array/dataframe in order. If you want examples read in order, use" + " one thread; if you want multiple threads, enable shuffling.") + if shuffle: min_after_dequeue = int(capacity / 4 if min_after_dequeue is None else min_after_dequeue) @@ -157,13 +270,6 @@ def enqueue_data(data, shapes=queue_shapes, seed=seed) else: - if num_threads > 1: - # TODO(jamieas): Add TensorBoard warning here once available. - logging.warning( - "enqueue_data was called with shuffle=False and num_threads > 1. " - "This will create multiple threads, all reading the " - "array/dataframe in order. If you want examples read in order, use" - " one thread; if you want multiple threads, enable shuffling.") min_after_dequeue = 0 # just for the summary text queue = data_flow_ops.FIFOQueue(capacity, dtypes=types, @@ -183,7 +289,8 @@ def enqueue_data(data, data, enqueue_size, random_start=shuffle, - seed=seed_i)) + seed=seed_i, + num_epochs=num_epochs)) runner = fqr.FeedingQueueRunner(queue=queue, enqueue_ops=enqueue_ops, diff --git a/tensorflow/contrib/learn/python/learn/dataframe/tensorflow_dataframe.py b/tensorflow/contrib/learn/python/learn/dataframe/tensorflow_dataframe.py index ddd2b8bfb6e529d141de961e99b2e17e8f45bafe..70c3953133187ac63d9b1b48273e52b336445e73 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/tensorflow_dataframe.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/tensorflow_dataframe.py @@ -28,10 +28,10 @@ from tensorflow.contrib.learn.python.learn.dataframe import dataframe as df from tensorflow.contrib.learn.python.learn.dataframe.transforms import batch from tensorflow.contrib.learn.python.learn.dataframe.transforms import csv_parser from tensorflow.contrib.learn.python.learn.dataframe.transforms import example_parser -from tensorflow.contrib.learn.python.learn.dataframe.transforms import hashes from tensorflow.contrib.learn.python.learn.dataframe.transforms import in_memory_source from tensorflow.contrib.learn.python.learn.dataframe.transforms import reader_source from tensorflow.contrib.learn.python.learn.dataframe.transforms import sparsify +from tensorflow.contrib.learn.python.learn.dataframe.transforms import split_mask from tensorflow.python.client import session as sess from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors @@ -189,16 +189,12 @@ class TensorFlowDataFrame(df.DataFrame): Returns: Two `DataFrame`s containing the partitioned rows. """ - # TODO(soergel): allow seed? if isinstance(index_series, str): index_series = self[index_series] - num_buckets = 1000000 # close enough for simple splits - hashed_input, = hashes.HashFast(num_buckets)(index_series) - threshold = int(num_buckets * proportion) - left = hashed_input < threshold - right = ~left - left_rows = self.select_rows(left) - right_rows = self.select_rows(right) + left_mask, = split_mask.SplitMask(proportion)(index_series) + right_mask = ~left_mask + left_rows = self.select_rows(left_mask) + right_rows = self.select_rows(right_mask) if batch_size: left_rows = left_rows.batch(batch_size=batch_size, shuffle=False) @@ -206,7 +202,58 @@ class TensorFlowDataFrame(df.DataFrame): return left_rows, right_rows - def run_once(self): + def split_fast(self, index_series, proportion, batch_size, + base_batch_size=1000): + """Deterministically split a `DataFrame` into two `DataFrame`s. + + Note this split is only as deterministic as the underlying hash function; + see `tf.string_to_hash_bucket_fast`. The hash function is deterministic + for a given binary, but may change occasionally. The only way to achieve + an absolute guarantee that the split `DataFrame`s do not change across runs + is to materialize them. + + Note too that the allocation of a row to one partition or the + other is evaluated independently for each row, so the exact number of rows + in each partition is binomially distributed. + + Args: + index_series: a `Series` of unique strings, whose hash will determine the + partitioning; or the name in this `DataFrame` of such a `Series`. + (This `Series` must contain strings because TensorFlow provides hash + ops only for strings, and there are no number-to-string converter ops.) + proportion: The proportion of the rows to select for the 'left' + partition; the remaining (1 - proportion) rows form the 'right' + partition. + batch_size: the batch size to use when rebatching the left and right + `DataFrame`s. If None (default), the `DataFrame`s are not rebatched; + thus their batches will have variable sizes, according to which rows + are selected from each batch of the original `DataFrame`. + base_batch_size: the batch size to use for materialized data, prior to the + split. + + Returns: + Two `DataFrame`s containing the partitioned rows. + """ + if isinstance(index_series, str): + index_series = self[index_series] + left_mask, = split_mask.SplitMask(proportion)(index_series) + right_mask = ~left_mask + self["left_mask__"] = left_mask + self["right_mask__"] = right_mask + # TODO(soergel): instead of base_batch_size can we just do one big batch? + # avoid computing the hashes twice + m = self.materialize_to_memory(batch_size=base_batch_size) + left_rows_df = m.select_rows(m["left_mask__"]) + right_rows_df = m.select_rows(m["right_mask__"]) + del left_rows_df[["left_mask__", "right_mask__"]] + del right_rows_df[["left_mask__", "right_mask__"]] + + # avoid recomputing the split repeatedly + left_rows_df = left_rows_df.materialize_to_memory(batch_size=batch_size) + right_rows_df = right_rows_df.materialize_to_memory(batch_size=batch_size) + return left_rows_df, right_rows_df + + def run_one_batch(self): """Creates a new 'Graph` and `Session` and runs a single batch. Returns: @@ -215,6 +262,46 @@ class TensorFlowDataFrame(df.DataFrame): """ return list(self.run(num_batches=1))[0] + def run_one_epoch(self): + """Creates a new 'Graph` and `Session` and runs a single epoch. + + Naturally this makes sense only for DataFrames that fit in memory. + + Returns: + A dictionary mapping column names to numpy arrays that contain a single + epoch of the `DataFrame`. + """ + # batches is a list of dicts of numpy arrays + batches = [b for b in self.run(num_epochs=1)] + + # first invert that to make a dict of lists of numpy arrays + pivoted_batches = {} + for k in batches[0].keys(): + pivoted_batches[k] = [] + for b in batches: + for k, v in b.items(): + pivoted_batches[k].append(v) + + # then concat the arrays in each column + result = {k: np.concatenate(column_batches) + for k, column_batches in pivoted_batches.items()} + return result + + def materialize_to_memory(self, batch_size): + unordered_dict_of_arrays = self.run_one_epoch() + + # there may already be an 'index' column, in which case from_ordereddict) + # below will complain because it wants to generate a new one. + # for now, just remove it. + # TODO(soergel): preserve index history, potentially many levels deep + del unordered_dict_of_arrays["index"] + + # the order of the columns in this dict is arbitrary; we just need it to + # remain consistent. + ordered_dict_of_arrays = collections.OrderedDict(unordered_dict_of_arrays) + return TensorFlowDataFrame.from_ordereddict(ordered_dict_of_arrays, + batch_size=batch_size) + def batch(self, batch_size, shuffle=False, @@ -591,3 +678,51 @@ class TensorFlowDataFrame(df.DataFrame): dataframe = cls() dataframe.assign(**(numpy_source()._asdict())) return dataframe + + @classmethod + def from_ordereddict(cls, + ordered_dict_of_arrays, + num_threads=None, + enqueue_size=None, + batch_size=None, + queue_capacity=None, + min_after_dequeue=None, + shuffle=True, + seed=None, + data_name="numpy_data"): + """Creates a `tf.learn.DataFrame` from a `numpy.ndarray`. + + The returned `DataFrame` contains two columns: 'index' and 'value'. The + 'value' column contains a row from the array. The 'index' column contains + the corresponding row number. + + Args: + ordered_dict_of_arrays: `OrderedDict` of `numpy.ndarray` that serves as a + data source. + num_threads: the number of threads to use for enqueueing. + enqueue_size: the number of rows to enqueue per step. + batch_size: desired batch size. + queue_capacity: capacity of the queue that will store parsed `Example`s + min_after_dequeue: minimum number of elements that can be left by a + dequeue operation. Only used if `shuffle` is true. + shuffle: whether records should be shuffled. Defaults to true. + seed: passed to random shuffle operations. Only used if `shuffle` is true. + data_name: a scope name identifying the data. + + Returns: + A `tf.learn.DataFrame` that contains batches drawn from the given + array. + """ + numpy_source = in_memory_source.OrderedDictNumpySource( + ordered_dict_of_arrays, + num_threads=num_threads, + enqueue_size=enqueue_size, + batch_size=batch_size, + queue_capacity=queue_capacity, + shuffle=shuffle, + min_after_dequeue=min_after_dequeue, + seed=seed, + data_name=data_name) + dataframe = cls() + dataframe.assign(**(numpy_source()._asdict())) + return dataframe diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transform.py b/tensorflow/contrib/learn/python/learn/dataframe/transform.py index bbb97d2f290afacc500819cde0c7ae5beb2904db..c28da59ac76130d25bf330abb5d9ffa01fac1aca 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transform.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transform.py @@ -185,20 +185,15 @@ class Transform(object): self.output_names) return self._return_type - def _check_output_tensors(self, output_tensors): - """Helper for `build(...)`; verifies the output of `_build_transform`. + def __str__(self): + return self.name - Args: - output_tensors: value returned by a call to `_build_transform`. + def __repr__(self): + parameters_sorted = ["%s: %s" % (repr(k), repr(v)) + for k, v in sorted(self.parameters().items())] + parameters_joined = ", ".join(parameters_sorted) - Raises: - TypeError: `transform_output` is not a list. - ValueError: `transform_output` does not match `output_names`. - """ - if not isinstance(output_tensors, self.return_type): - raise TypeError( - "Expected a NamedTuple of Tensors with elements %s; got %s." % - (self.output_names, type(output_tensors).__name__)) + return "%s({%s})" % (self.name, parameters_joined) def __call__(self, input_series=None): """Apply this `Transform` to the provided `Series`, producing 'Series'. @@ -217,12 +212,62 @@ class Transform(object): if len(input_series) != self.input_valency: raise ValueError("Expected %s input Series but received %s." % (self.input_valency, len(input_series))) - output_series = [TransformedSeries(input_series, self, output_name) - for output_name in self.output_names] + output_series = self._produce_output_series(input_series) # pylint: disable=not-callable return self.return_type(*output_series) + @abstractmethod + def _produce_output_series(self, input_series): + """Applies the transformation to the `transform_input`. + + Args: + input_series: a list of Series representing the input to + the Transform. + + Returns: + A list of Series representing the transformed output, in order + corresponding to `_output_names`. + """ + raise NotImplementedError() + + +class TensorFlowTransform(Transform): + """A function from a list of `Series` to a namedtuple of `Series`. + + Transforms map zero or more Series of a DataFrame to new Series. + """ + + __metaclass__ = ABCMeta + + def _check_output_tensors(self, output_tensors): + """Helper for `build(...)`; verifies the output of `_build_transform`. + + Args: + output_tensors: value returned by a call to `_build_transform`. + + Raises: + TypeError: `transform_output` is not a list. + ValueError: `transform_output` does not match `output_names`. + """ + if not isinstance(output_tensors, self.return_type): + raise TypeError( + "Expected a NamedTuple of Tensors with elements %s; got %s." % + (self.output_names, type(output_tensors).__name__)) + + def _produce_output_series(self, input_series=None): + """Apply this `Transform` to the provided `Series`, producing `Series`. + + Args: + input_series: None, a `Series`, or a list of input `Series`, acting as + positional arguments. + + Returns: + A namedtuple of the output `Series`. + """ + return [TransformedSeries(input_series, self, output_name) + for output_name in self.output_names] + def build_transitive(self, input_series, cache=None, **kwargs): """Apply this `Transform` to the provided `Series`, producing 'Tensor's. @@ -277,13 +322,3 @@ class Transform(object): A namedtuple of Tensors representing the transformed output. """ raise NotImplementedError() - - def __str__(self): - return self.name - - def __repr__(self): - parameters_sorted = ["%s: %s" % (repr(k), repr(v)) - for k, v in sorted(self.parameters().items())] - parameters_joined = ", ".join(parameters_sorted) - - return "%s({%s})" % (self.name, parameters_joined) diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/batch.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/batch.py index cf1585634ca0813bd49c0cdba1520652998fc35a..7793e296e2151c93b6848825c63b21b5a0adc5ab 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/batch.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/batch.py @@ -23,7 +23,7 @@ from tensorflow.contrib.learn.python.learn.dataframe import transform from tensorflow.python.training import input as input_ops -class AbstractBatchTransform(transform.Transform): +class AbstractBatchTransform(transform.TensorFlowTransform): """Abstract parent class for batching Transforms.""" def __init__(self, diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/binary_transforms.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/binary_transforms.py index 78a21250c9c7e4d1dd493b83d12bfef507ebb257..b3e52254032ef97851285fbdfddfe5f91d28d406 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/binary_transforms.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/binary_transforms.py @@ -42,7 +42,7 @@ _DOC_FORMAT_STRING = ("A `Transform` that wraps `{0}`. " "Documentation for `{0}`: \n\n {1}") -class SeriesBinaryTransform(transform.Transform): +class SeriesBinaryTransform(transform.TensorFlowTransform): """Parent class for `Transform`s that operate on two `Series`.""" @property @@ -64,7 +64,7 @@ class SeriesBinaryTransform(transform.Transform): return self.return_type(self._apply_op(input_tensors[0], input_tensors[1])) -class ScalarBinaryTransform(transform.Transform): +class ScalarBinaryTransform(transform.TensorFlowTransform): """Parent class for `Transform`s that combine `Series` to a scalar.""" def __init__(self, scalar): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/boolean_mask.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/boolean_mask.py index cdb244744a0d979d9b3648ee69211832020ca884..880217f558a97d06617e772df9334fd488ac2536 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/boolean_mask.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/boolean_mask.py @@ -62,7 +62,7 @@ def sparse_boolean_mask(sparse_tensor, mask, name="sparse_boolean_mask"): @series.Series.register_binary_op("select_rows") -class BooleanMask(transform.Transform): +class BooleanMask(transform.TensorFlowTransform): """Apply a boolean mask to a `Series`.""" @property diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/csv_parser.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/csv_parser.py index d78b5652d6e61a262ccb4400da15880cfdb27856..08620ae62eddb2a6dda20eeedb68ae6c94fe9cf3 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/csv_parser.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/csv_parser.py @@ -23,7 +23,7 @@ from tensorflow.python.framework import constant_op from tensorflow.python.ops import parsing_ops -class CSVParser(transform.Transform): +class CSVParser(transform.TensorFlowTransform): """A Transform that parses lines from a CSV file.""" def __init__(self, column_names, default_values): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/densify.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/densify.py index 0f0c1a08911c910ae473780e6a3c04e94de31e60..d5b55ee359941ca16b05d373046420fabd56ae60 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/densify.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/densify.py @@ -23,7 +23,7 @@ from tensorflow.contrib.learn.python.learn.dataframe import transform from tensorflow.python.ops import sparse_ops -class Densify(transform.Transform): +class Densify(transform.TensorFlowTransform): """Transforms Sparse to Dense Tensor.""" def __init__(self, diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/difference.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/difference.py index b585fceeb63f6f552d86c4a199a9c768ae7388c6..f9cb0c9485516abedbb3847530755d5cb328287f 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/difference.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/difference.py @@ -32,7 +32,7 @@ def _negate_sparse(sparse_tensor): @series.Series.register_binary_op("__sub__") -class Difference(transform.Transform): +class Difference(transform.TensorFlowTransform): """Subtracts one 'Series` from another.""" def __init__(self): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/example_parser.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/example_parser.py index c2c5e0cbed5c92cc7b0ddfd40e390ceb418dfbf0..f0176600c36bea3174f295d07834ebf0c1a1795c 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/example_parser.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/example_parser.py @@ -24,7 +24,7 @@ from tensorflow.contrib.learn.python.learn.dataframe import transform from tensorflow.python.ops import parsing_ops -class ExampleParser(transform.Transform): +class ExampleParser(transform.TensorFlowTransform): """A Transform that parses serialized `tensorflow.Example` protos.""" def __init__(self, features): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/hashes.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/hashes.py index 325e7827ce2f35d0fddbfb5cddaf3a95d090b402..6462a6ff51cf370a1b8b2e4837b71347daa7ec68 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/hashes.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/hashes.py @@ -23,11 +23,11 @@ from tensorflow.contrib.learn.python.learn.dataframe import transform from tensorflow.python.ops import string_ops -class HashFast(transform.Transform): +class HashFast(transform.TensorFlowTransform): """Perform a fast hash of a `Series`.""" def __init__(self, num_buckets): - """Initialize `CSVParser`. + """Initialize `HashFast`. Args: num_buckets: The number of hash buckets to use. diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/in_memory_source.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/in_memory_source.py index d96d53468a56e94a372c118fd68e19b86f0feb1e..f7b58601b4a755b328b6b0bb8864f946b0fc8e50 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/in_memory_source.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/in_memory_source.py @@ -22,12 +22,12 @@ from tensorflow.contrib.learn.python.learn.dataframe import transform from tensorflow.contrib.learn.python.learn.dataframe.queues import feeding_functions -class BaseInMemorySource(transform.Transform): +class BaseInMemorySource(transform.TensorFlowTransform): """Abstract parent class for NumpySource and PandasSource.""" def __init__(self, data, - num_threads=1, + num_threads=None, enqueue_size=None, batch_size=None, queue_capacity=None, @@ -94,9 +94,11 @@ class BaseInMemorySource(transform.Transform): self.queue_capacity, self.shuffle, self.min_after_dequeue, + num_threads=self.num_threads, seed=self.seed, name=self.data_name, - enqueue_size=self.enqueue_size) + enqueue_size=self.enqueue_size, + num_epochs=kwargs.get("num_epochs")) dequeued = queue.dequeue_many(self.batch_size) @@ -121,6 +123,36 @@ class NumpySource(BaseInMemorySource): return ("index", "value") +class OrderedDictNumpySource(BaseInMemorySource): + """A zero-input Transform that produces Series from a dict of numpy arrays.""" + + def __init__(self, + ordered_dict_of_arrays, + num_threads=None, + enqueue_size=None, + batch_size=None, + queue_capacity=None, + shuffle=False, + min_after_dequeue=None, + seed=None, + data_name="pandas_data"): + if "index" in ordered_dict_of_arrays.keys(): + raise ValueError("Column name `index` is reserved.") + super(OrderedDictNumpySource, self).__init__(ordered_dict_of_arrays, + num_threads, enqueue_size, + batch_size, queue_capacity, + shuffle, min_after_dequeue, + seed, data_name) + + @property + def name(self): + return "OrderedDictNumpySource" + + @property + def _output_names(self): + return tuple(["index"] + self._data.keys()) + + class PandasSource(BaseInMemorySource): """A zero-input Transform that produces Series from a DataFrame.""" diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/reader_source.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/reader_source.py index ddb2d321d1c600da01baf185f8329d7a40816829..e8fa402bd604590dfc5dc27eaf1516f9be0d7b48 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/reader_source.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/reader_source.py @@ -23,7 +23,7 @@ from tensorflow.python.ops import io_ops from tensorflow.python.training import input as input_ops -class ReaderSource(transform.Transform): +class ReaderSource(transform.TensorFlowTransform): """Produces `Tensor`s of keys and values using a `tf.Reader`.""" def __init__(self, @@ -40,8 +40,8 @@ class ReaderSource(transform.Transform): """Initializes a ReaderSource. Args: - reader_cls: A subclass of `tesorflow.ReaderBase` that will be used to read - from `work_units`. + reader_cls: A subclass of `tensorflow.ReaderBase` that will be used to + read from `work_units`. work_units: A list that describes the source(s) of data to read. Typically, this is a list of filenames. reader_kwargs: A dictionary of kwargs to be passed to `reader_cls` when it diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/sparsify.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/sparsify.py index f3447c5d9408b622193d6cfa098fc16bd2ad3e23..05b66a683c0888b502777d2706fc857ad5d79e79 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/sparsify.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/sparsify.py @@ -29,7 +29,7 @@ from tensorflow.python.ops import array_ops from tensorflow.python.ops import math_ops -class Sparsify(transform.Transform): +class Sparsify(transform.TensorFlowTransform): """Transforms Dense to Sparse Tensor.""" def __init__(self, strip_value): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/split_mask.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/split_mask.py new file mode 100644 index 0000000000000000000000000000000000000000..953e74ba845e0a55468a43279c3ac5c42517534e --- /dev/null +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/split_mask.py @@ -0,0 +1,81 @@ +# 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. +# ============================================================================== + +"""Masks one `Series` based on the content of another `Series`.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.contrib.learn.python.learn.dataframe import transform +from tensorflow.contrib.learn.python.learn.dataframe.transforms import hashes + + +class SplitMask(transform.Transform): + """Provide a boolean mask based on a hash of a `Series`.""" + + def __init__(self, proportion): + """Initialize `SplitMask`. + + Args: + proportion: The proportion of the rows to select for the '1' + partition; the remaining (1 - proportion) rows form the '0' + partition. + """ + # TODO(soergel): allow seed? + super(SplitMask, self).__init__() + self._proportion = proportion + + @property + def name(self): + return "SplitMask" + + @property + def input_valency(self): + return 1 + + @property + def _output_names(self): + return "output", + + def _produce_output_series(self, input_series=None): + """Deterministically generate a boolean Series for partitioning rows. + + Note this split is only as deterministic as the underlying hash function; + see `tf.string_to_hash_bucket_fast`. The hash function is deterministic + for a given binary, but may change occasionally. The only way to achieve + an absolute guarantee that the split `DataFrame`s do not change across runs + is to materialize them. + + Note too that the allocation of a row to one partition or the + other is evaluated independently for each row, so the exact number of rows + in each partition is binomially distributed. + + Args: + input_series: a `Series` of unique strings, whose hash will determine the + partitioning. + (This `Series` must contain strings because TensorFlow provides hash + ops only for strings, and there are no number-to-string converter ops.) + + Returns: + Two `DataFrame`s containing the partitioned rows. + """ + # TODO(soergel): allow seed? + num_buckets = 1000000 # close enough for simple splits + hashed_input, = hashes.HashFast(num_buckets)(input_series[0]) + threshold = int(num_buckets * self._proportion) + left_mask = hashed_input < threshold + return [left_mask] + diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/sum.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/sum.py index 878b08f4b0ad56e706c842438b243644dd23aa44..212ac178f2814e043ac27119f5dcb606995084be 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/sum.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/sum.py @@ -26,7 +26,7 @@ from tensorflow.python.ops import sparse_ops @series.Series.register_binary_op("__add__") -class Sum(transform.Transform): +class Sum(transform.TensorFlowTransform): """Adds two `Series`.""" def __init__(self): diff --git a/tensorflow/contrib/learn/python/learn/dataframe/transforms/unary_transforms.py b/tensorflow/contrib/learn/python/learn/dataframe/transforms/unary_transforms.py index 7f9eb7ce1da5e066c61635cc1f16e3a447dbc469..eab476eb99e99f60db7f3d914719400f2e85ef2e 100644 --- a/tensorflow/contrib/learn/python/learn/dataframe/transforms/unary_transforms.py +++ b/tensorflow/contrib/learn/python/learn/dataframe/transforms/unary_transforms.py @@ -93,7 +93,7 @@ def register_unary_op(registered_name, operation, ignore_dtype=None): return self.return_type(result) cls = type(operation.__name__, - (transform.Transform,), + (transform.TensorFlowTransform,), {"name": name, "__doc__": doc, "input_valency": input_valency, diff --git a/tensorflow/contrib/learn/python/learn/estimators/__init__.py b/tensorflow/contrib/learn/python/learn/estimators/__init__.py index 87046218ee66d04a2d860e5cdfc0835faee19340..384f2ba53b259b8d2aa779bedba3fd92d67db194 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/__init__.py +++ b/tensorflow/contrib/learn/python/learn/estimators/__init__.py @@ -37,10 +37,6 @@ from tensorflow.contrib.learn.python.learn.estimators.estimator import infer_rea from tensorflow.contrib.learn.python.learn.estimators.estimator import ModeKeys from tensorflow.contrib.learn.python.learn.estimators.linear import LinearClassifier from tensorflow.contrib.learn.python.learn.estimators.linear import LinearRegressor -from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowClassifier -from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearClassifier -from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearRegressor -from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowRegressor from tensorflow.contrib.learn.python.learn.estimators.logistic_regressor import LogisticRegressor from tensorflow.contrib.learn.python.learn.estimators.random_forest import TensorForestEstimator from tensorflow.contrib.learn.python.learn.estimators.random_forest import TensorForestLossMonitor diff --git a/tensorflow/contrib/learn/python/learn/estimators/classifier.py b/tensorflow/contrib/learn/python/learn/estimators/classifier.py index 61b2c5e1812048dcad851f6214061162e587324a..d9d88bd15b734b42578ef171a7d2222429045e07 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/classifier.py +++ b/tensorflow/contrib/learn/python/learn/estimators/classifier.py @@ -42,7 +42,8 @@ class Classifier(estimator.Estimator): CLASS_OUTPUT = 'classes' PROBABILITY_OUTPUT = 'probabilities' - def __init__(self, model_fn, n_classes, model_dir=None, config=None): + def __init__(self, model_fn, n_classes, model_dir=None, config=None, + params=None): """Constructor for Classifier. Args: @@ -52,11 +53,17 @@ class Classifier(estimator.Estimator): also be used to load checkpoints from the directory into a estimator to continue training a previously saved model. config: Configuration object (optional) + params: `dict` of hyper parameters that will be passed into `model_fn`. """ self._n_classes = n_classes self._logits_fn = model_fn - super(Classifier, self).__init__(model_fn=self._classifier_model, - model_dir=model_dir, config=config) + if params: + model_fn = self._classifier_model_with_params + else: + model_fn = self._classifier_model + super(Classifier, self).__init__(model_fn=model_fn, + model_dir=model_dir, config=config, + params=params) def evaluate(self, x=None, @@ -161,7 +168,15 @@ class Classifier(estimator.Estimator): return predictions[self.PROBABILITY_OUTPUT] def _classifier_model(self, features, targets, mode): - logits, loss, train_op = self._logits_fn(features, targets, mode) + return self._convert_to_estimator_model_result( + self._logits_fn(features, targets, mode)) + + def _classifier_model_with_params(self, features, targets, mode, params): + return self._convert_to_estimator_model_result( + self._logits_fn(features, targets, mode, params)) + + def _convert_to_estimator_model_result(self, logits_fn_result): + logits, loss, train_op = logits_fn_result return { 'classes': math_ops.argmax(logits, len(logits.get_shape()) - 1), 'probabilities': nn.softmax(logits) diff --git a/tensorflow/contrib/learn/python/learn/estimators/classifier_test.py b/tensorflow/contrib/learn/python/learn/estimators/classifier_test.py index fd6618561ef074ee3732bf84617ee3a5d0398142..f14de75252cc8ad78b3e5873d25e89663292a316 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/classifier_test.py +++ b/tensorflow/contrib/learn/python/learn/estimators/classifier_test.py @@ -46,19 +46,27 @@ def logistic_model_fn(features, target, unused_mode): return prediction, loss, train_op +def logistic_model_params_fn(features, target, unused_mode, params): + target = tf.one_hot(target, 3, 1, 0) + prediction, loss = tf.contrib.learn.models.logistic_regression_zero_init( + features, target) + train_op = tf.contrib.layers.optimize_loss( + loss, tf.contrib.framework.get_global_step(), optimizer='Adagrad', + learning_rate=params['learning_rate']) + return prediction, loss, train_op + + class ClassifierTest(tf.test.TestCase): def testIrisAll(self): - iris = tf.contrib.learn.datasets.load_iris() est = tf.contrib.learn.Classifier(model_fn=logistic_model_fn, n_classes=3) - est.fit(iris.data, iris.target, steps=100) - scores = est.evaluate(x=iris.data, y=iris.target, name='eval') - predictions = est.predict(x=iris.data) - predictions_proba = est.predict_proba(x=iris.data) - self.assertEqual(predictions.shape[0], iris.target.shape[0]) - self.assertAllEqual(predictions, np.argmax(predictions_proba, axis=1)) - other_score = _sklearn.accuracy_score(iris.target, predictions) - self.assertAllClose(other_score, scores['accuracy']) + self._runIrisAll(est) + + def testIrisAllWithParams(self): + est = tf.contrib.learn.Classifier(model_fn=logistic_model_params_fn, + n_classes=3, + params={'learning_rate': 0.01}) + self._runIrisAll(est) def testIrisPredictAsIterable(self): iris = tf.contrib.learn.datasets.load_iris() @@ -89,6 +97,17 @@ class ClassifierTest(tf.test.TestCase): predictions = list(est.predict(input_fn=predict_input_fn, as_iterable=True)) self.assertEqual(len(predictions), iris.target.shape[0]) + def _runIrisAll(self, est): + iris = tf.contrib.learn.datasets.load_iris() + est.fit(iris.data, iris.target, steps=100) + scores = est.evaluate(x=iris.data, y=iris.target, name='eval') + predictions = est.predict(x=iris.data) + predictions_proba = est.predict_proba(x=iris.data) + self.assertEqual(predictions.shape[0], iris.target.shape[0]) + self.assertAllEqual(predictions, np.argmax(predictions_proba, axis=1)) + other_score = _sklearn.accuracy_score(iris.target, predictions) + self.assertAllClose(other_score, scores['accuracy']) + if __name__ == '__main__': tf.test.main() diff --git a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py index 963dcdc457ca8d84cf06234fbc1c0c1d95ecaaa8..bfd028deb4f07ffd78b06c153bfcddc4d26650ef 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py +++ b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined.py @@ -174,16 +174,20 @@ class _DNNLinearCombinedBaseEstimator(estimator.BaseEstimator): else: centered_bias_step = [] with ops.control_dependencies(centered_bias_step): - loss = self._target_column.loss(logits, targets, features) - logging_ops.scalar_summary("loss", loss) + training_loss = self._target_column.training_loss(logits, targets, + features) + weighted_average_loss = self._target_column.loss(logits, targets, + features) - linear_train_step = self._linear_model.get_train_step(loss) - dnn_train_step = (self._dnn_model.get_train_step(loss) - if self._dnn_model else []) + logging_ops.scalar_summary("loss", weighted_average_loss) + + linear_train_step = self._linear_model.get_train_step(training_loss) + dnn_train_step = (self._dnn_model.get_train_step(training_loss) if + self._dnn_model else []) with ops.control_dependencies(linear_train_step + dnn_train_step): with ops.get_default_graph().colocate_with(global_step): - return state_ops.assign_add(global_step, 1).op, loss + return state_ops.assign_add(global_step, 1).op, weighted_average_loss def _get_eval_ops(self, features, targets, metrics=None): """See base class.""" @@ -242,10 +246,11 @@ class _DNNLinearCombinedBaseEstimator(estimator.BaseEstimator): logits = array_ops.reshape( array_ops.tile(centered_bias[0], [batch_size]), [batch_size, self._target_column.num_label_columns]) - loss = self._target_column.loss(logits, targets, features) + training_loss = self._target_column.training_loss(logits, targets, features) # Learn central bias by an optimizer. 0.1 is a convervative lr for a single # variable. - return training.AdagradOptimizer(0.1).minimize(loss, var_list=centered_bias) + return training.AdagradOptimizer(0.1).minimize( + training_loss, var_list=centered_bias) def _logits(self, features, is_training=False): linear_feature_columns = self._get_linear_feature_columns() diff --git a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined_test.py b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined_test.py index f3706a312c4cd4e757e69d463b6bcb7e30e67e3c..9e3a6dfd7fb95a73d3dc26be7dbfefcc4e9cdb65 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined_test.py +++ b/tensorflow/contrib/learn/python/learn/estimators/dnn_linear_combined_test.py @@ -498,6 +498,7 @@ class DNNLinearCombinedClassifierTest(tf.test.TestCase): self.assertNotIn('dnn/logits/weights', classifier.get_variable_names()) self.assertEquals(1, len(classifier.linear_bias_)) self.assertEquals(2, len(classifier.linear_weights_)) + print(classifier.linear_weights_) self.assertEquals(1, len(classifier.linear_weights_['linear/age/weight'])) self.assertEquals( 100, len(classifier.linear_weights_['linear/language/weights'])) diff --git a/tensorflow/contrib/learn/python/learn/estimators/estimator.py b/tensorflow/contrib/learn/python/learn/estimators/estimator.py index b60c4e91e64d745d2339bc14b2527beca162dfc4..c8511b8c75fe3d54fcc3f142d0480c4a40f95315 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/estimator.py +++ b/tensorflow/contrib/learn/python/learn/estimators/estimator.py @@ -20,6 +20,7 @@ from __future__ import division from __future__ import print_function import abc +import copy import inspect import itertools import os @@ -224,6 +225,11 @@ class BaseEstimator( self._graph = None + @property + def config(self): + # TODO(wicke): make RunConfig immutable, and then return it without a copy. + return copy.deepcopy(self._config) + def fit(self, x=None, y=None, input_fn=None, steps=None, batch_size=None, monitors=None, max_steps=None): # pylint: disable=g-doc-args,g-doc-return-or-yield @@ -376,9 +382,8 @@ class BaseEstimator( def model_dir(self): return self._model_dir - def export(self, export_dir, signature_fn=None, - input_fn=export.default_input_fn, default_batch_size=1, - exports_to_keep=None): + def export(self, export_dir, signature_fn=None, input_fn=None, + default_batch_size=1, exports_to_keep=None): """Exports inference graph into given dir. Args: @@ -392,12 +397,14 @@ class BaseEstimator( default_batch_size: Default batch size of the `Example` placeholder. exports_to_keep: Number of exports to keep. """ - export.export_estimator(estimator=self, - export_dir=export_dir, - signature_fn=signature_fn, - input_fn=input_fn, - default_batch_size=default_batch_size, - exports_to_keep=exports_to_keep) + # pylint: disable=protected-access + export._export_estimator(estimator=self, + export_dir=export_dir, + signature_fn=signature_fn, + input_fn=input_fn, + default_batch_size=default_batch_size, + exports_to_keep=exports_to_keep) + # pylint: enable=protected-access @abc.abstractproperty def _get_train_ops(self, features, targets): diff --git a/tensorflow/contrib/learn/python/learn/estimators/linear.py b/tensorflow/contrib/learn/python/learn/estimators/linear.py index 197a4c2ea2aa5801525e11c4c50129fd31fc0de6..9e1c20c6712604d6a641dbaf7c38dc13d3753957 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/linear.py +++ b/tensorflow/contrib/learn/python/learn/estimators/linear.py @@ -21,9 +21,7 @@ from __future__ import print_function from tensorflow.contrib import layers from tensorflow.contrib.framework.python.ops import variables as contrib_variables -from tensorflow.contrib.learn.python.learn.estimators import _sklearn from tensorflow.contrib.learn.python.learn.estimators import dnn_linear_combined -from tensorflow.contrib.learn.python.learn.estimators.base import DeprecatedMixin from tensorflow.contrib.linear_optimizer.python import sdca_optimizer from tensorflow.python.framework import ops from tensorflow.python.ops import logging_ops @@ -315,18 +313,3 @@ class LinearRegressor(dnn_linear_combined.DNNLinearCombinedRegressor): @property def bias_(self): return self.linear_bias_ - - -# TensorFlowLinearRegressor and TensorFlowLinearClassifier are deprecated. -class TensorFlowLinearRegressor(DeprecatedMixin, LinearRegressor, - _sklearn.RegressorMixin): - pass - - -class TensorFlowLinearClassifier(DeprecatedMixin, LinearClassifier, - _sklearn.ClassifierMixin): - pass - - -TensorFlowRegressor = TensorFlowLinearRegressor -TensorFlowClassifier = TensorFlowLinearClassifier diff --git a/tensorflow/contrib/learn/python/learn/estimators/run_config.py b/tensorflow/contrib/learn/python/learn/estimators/run_config.py index d04b854ce6c8ca03bac5e065218e1f94efa1a402..8803127debe66b78614a83c26437116327c46fa6 100644 --- a/tensorflow/contrib/learn/python/learn/estimators/run_config.py +++ b/tensorflow/contrib/learn/python/learn/estimators/run_config.py @@ -12,15 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== - """Run Config.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function +import json +import os + from tensorflow.python import ConfigProto from tensorflow.python import GPUOptions +from tensorflow.python.training.server_lib import ClusterSpec class RunConfig(object): @@ -33,9 +36,9 @@ class RunConfig(object): # TODO(wicke): Move options out once functionality is covered by monitors def __init__(self, - master='', - task=0, - num_ps_replicas=0, + master=None, + task=None, + num_ps_replicas=None, num_cores=4, log_device_placement=False, gpu_memory_fraction=1, @@ -44,20 +47,59 @@ class RunConfig(object): save_summary_steps=100, save_checkpoints_secs=60, keep_checkpoint_max=5, - keep_checkpoint_every_n_hours=10000): + keep_checkpoint_every_n_hours=10000, + job_name=None, + is_chief=None): """Constructor. + If set to None, `master`, `task`, `num_ps_replicas`, `cluster_spec`, + `job_name`, and `is_chief` are set based on the TF_CONFIG environment + variable, if the pertinent information is present; otherwise, the defaults + listed in the Args section apply. + + The TF_CONFIG environment variable is a JSON object with two relevant + attributes: `task` and `cluster_spec`. `cluster_spec` is a JSON serialized + version of the Python dict described in server_lib.py. `task` has two + attributes: `type` and `index`, where `type` can be any of the task types + in the cluster_spec. When TF_CONFIG contains said information, the + following properties are set on this class: + + * `job_name` is set to [`task`][`type`] + * `task` is set to [`task`][`index`] + * `cluster_spec` is parsed from [`cluster`] + * 'master' is determined by looking up `job_name` and `task` in the + cluster_spec. + * `num_ps_replicas` is set by counting the number of nodes listed + in the `ps` job of `cluster_spec`. + * `is_chief`: true when `job_name` == "master" and `task` == 0. + + Example: + ``` + cluster = {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + os.environ['TF_CONFIG'] = json.dumps({ + {'cluster': cluster, + 'task': {'type': 'worker', 'index': 1}}}) + config = RunConfig() + assert config.master == 'host4:2222' + assert config.task == 1 + assert config.num_ps_replicas == 2 + assert config.cluster_spec == server_lib.ClusterSpec(cluster) + assert config.job_name == 'worker' + assert not config.is_chief + ``` + Args: - master: TensorFlow master. Empty string (the default) for local. + master: TensorFlow master. Defaults to empty string for local. task: Task id of the replica running the training (default: 0). num_ps_replicas: Number of parameter server tasks to use (default: 0). num_cores: Number of cores to be used (default: 4). log_device_placement: Log the op placement to devices (default: False). gpu_memory_fraction: Fraction of GPU memory used by the process on each GPU uniformly on the same machine. - cluster_spec: a tf.train.ClusterSpec object that describes the cluster in - the case of distributed computation. If missing, reasonable assumptions - are made for the addresses of jobs. + cluster_spec: a `tf.train.ClusterSpec` object that describes the cluster + in the case of distributed computation. If missing, reasonable + assumptions are made for the addresses of jobs. tf_random_seed: Random seed for TensorFlow initializers. Setting this value allows consistency between reruns. save_summary_steps: Save summaries every this many steps. @@ -69,19 +111,121 @@ class RunConfig(object): keep_checkpoint_every_n_hours: Number of hours between each checkpoint to be saved. The default value of 10,000 hours effectively disables the feature. + job_name: the type of task, e.g., 'ps', 'worker', etc. The `job_name` + must exist in the `cluster_spec.jobs`. + is_chief: whether or not this task (as identified by the other parameters) + should be the chief task. + + Raises: + ValueError: if num_ps_replicas and cluster_spec are set (cluster_spec + may fome from the TF_CONFIG environment variable). """ - self.master = master - self.task = task - self.num_ps_replicas = num_ps_replicas + # If not explicitly specified in the constructor and the TF_CONFIG + # environment variable is present, load cluster_spec from TF_CONFIG. + config = json.loads(os.environ.get('TF_CONFIG') or '{}') + if not cluster_spec and 'cluster' in config: + cluster_spec = ClusterSpec(config['cluster']) + self.cluster_spec = cluster_spec + + # Set job_name and task. If explicitly specified, use those values, + # otherwise, if the TF_CONFIG environment variable is present, use that. + # Otherwise, use the respective default (None / 0). + task_env = config.get('task', {}) + self._job_name = job_name or task_env.get('type') or None + self.task = task if task is not None else task_env.get('index') or 0 + + self.master = (master or _get_master(self.cluster_spec, self.job_name, + self.task) or '') + + if num_ps_replicas is not None and self.cluster_spec: + raise ValueError('Cannot specify both num_ps_replicas and cluster_spec. ' + 'Note: cluster_spec may have been set in the TF_CONFIG ' + 'environment variable.') + self.num_ps_replicas = num_ps_replicas or _count_ps(self.cluster_spec) or 0 + + # Set is_chief. + self._is_chief = is_chief + # When the TF_CONFIG environment variable is set, we can set the default + # of is_chief to 0 when job_name is "master" and task is 0. + if (self._is_chief is None) and config: + self._is_chief = (self._job_name == 'master' and self.task == 0) + + # Enforce that is_chief is only applicable to workers or masters + # (Cloud ML) with task == 0. + if self._is_chief: + if self.task != 0: + raise ValueError( + 'Task is %d, but only task 0 may be chief. Please check is_chief ' + 'and task, which may have been set in TF_CONFIG environment ' + 'variable.' % (self.task,)) + if self._job_name not in (None, 'master', 'worker'): + raise ValueError( + 'job_name is \'%s\', but only masters or workers may be chiefs. ' + 'Please check is_chief and job_name, which may have been set in ' + 'TF_CONFIG environment variable.' % (self._job_name,)) + elif (self._is_chief is False and self._job_name == 'master' and + self.task == 0): + raise ValueError( + 'Master task 0 must be chief. Please check is_chief, job_name, and ' + 'task, which may have been set in TF_CONFIG environment variable.') + gpu_options = GPUOptions( per_process_gpu_memory_fraction=gpu_memory_fraction) - self.tf_config = ConfigProto(log_device_placement=log_device_placement, - inter_op_parallelism_threads=num_cores, - intra_op_parallelism_threads=num_cores, - gpu_options=gpu_options) - self.cluster_spec = cluster_spec + self.tf_config = ConfigProto( + log_device_placement=log_device_placement, + inter_op_parallelism_threads=num_cores, + intra_op_parallelism_threads=num_cores, + gpu_options=gpu_options) + self.tf_random_seed = tf_random_seed self.save_summary_steps = save_summary_steps self.save_checkpoints_secs = save_checkpoints_secs self.keep_checkpoint_max = keep_checkpoint_max self.keep_checkpoint_every_n_hours = keep_checkpoint_every_n_hours + + @property + def is_chief(self): + return self._is_chief + + @property + def job_name(self): + return self._job_name + + +def _count_ps(cluster_spec): + """Counts the number of parameter servers in cluster_spec.""" + return len(cluster_spec.as_dict().get('ps', [])) if cluster_spec else 0 + + +def _get_master(cluster_spec, job_name, task_index): + """Returns the appropriate string for the TensorFlow master.""" + if not cluster_spec: + return '' + + # If there is only one node in the cluster, do things locally. + jobs = cluster_spec.jobs + if len(jobs) == 1 and len(cluster_spec.job_tasks(jobs[0])) == 1: + return '' + + # Lookup the master in cluster_spec using job_name and task_index, + # if possible. + if job_name: + if job_name not in jobs: + raise ValueError( + '%s is not a valid task in the cluster_spec:\n' + '%s\n\n' + 'Note that these values may be coming from the TF_CONFIG environment ' + 'variable.' % (job_name, cluster_spec)) + addresses = cluster_spec.job_tasks(job_name) + if task_index >= len(addresses) or task_index < 0: + raise ValueError( + '%d is not a valid task index for task type %s in the ' + 'cluster_spec:\n' + '%s\n\n' + 'Note that these value may be coming from the TF_CONFIG environment ' + 'variable.' % (task_index, job_name, cluster_spec)) + return addresses[task_index] + + # For backwards compatibility, we return empty string if job_name was + # not set (job_name did not previously exist). + return '' diff --git a/tensorflow/contrib/learn/python/learn/evaluable.py b/tensorflow/contrib/learn/python/learn/evaluable.py index 6a02d57a350f2ed3d1f96ed1650ada9a40fa1744..db76e3578d3e6585e57980b565889574f18a8998 100644 --- a/tensorflow/contrib/learn/python/learn/evaluable.py +++ b/tensorflow/contrib/learn/python/learn/evaluable.py @@ -39,7 +39,7 @@ class Evaluable(object): processed. - If `input_fn` is provided, and it raises an end-of-input exception (`OutOfRangeError` or `StopIteration`). - - If `x` is provided, and all items in `x` have ben processed. + - If `x` is provided, and all items in `x` have been processed. The return value is a dict containing the metrics specified in `metrics`, as well as an entry `global_step` which contains the value of the global step diff --git a/tensorflow/contrib/learn/python/learn/experiment.py b/tensorflow/contrib/learn/python/learn/experiment.py index 0f96b70fae1d6aac34a99f8d982669a936d2046b..b8c791ae79028d8d62a1e60962c609c32aa4439c 100644 --- a/tensorflow/contrib/learn/python/learn/experiment.py +++ b/tensorflow/contrib/learn/python/learn/experiment.py @@ -27,6 +27,7 @@ from tensorflow.contrib.learn.python.learn import trainable from tensorflow.contrib.learn.python.learn.estimators._sklearn import NotFittedError from tensorflow.python.platform import flags from tensorflow.python.platform import tf_logging as logging +from tensorflow.python.training import server_lib FLAGS = flags.FLAGS @@ -89,6 +90,10 @@ class Experiment(object): self._eval_delay_secs = eval_delay_secs self._continuous_eval_throttle_secs = continuous_eval_throttle_secs + @property + def estimator(self): + return self._estimator + def train(self, delay_secs=None): """Fit the estimator using the training data. @@ -101,14 +106,19 @@ class Experiment(object): Returns: The trained estimator. """ + start = time.time() if delay_secs is None: - task_id = 0 - if hasattr(FLAGS, "task"): - task_id = FLAGS.task - delay_secs = min(60, task_id*5) + task_id = self._estimator.config.task or 0 + delay_secs = min(60, task_id * 5) + + # Start the server, if needed. + if self._estimator.config.cluster_spec: + self._start_server() if delay_secs: - logging.info("Waiting %d secs before starting training.", delay_secs) + elapsed_secs = time.time() - start + remaining = delay_secs - elapsed_secs + logging.info("Waiting %d secs before starting training.", remaining) time.sleep(delay_secs) return self._estimator.fit(input_fn=self._train_input_fn, @@ -218,6 +228,17 @@ class Experiment(object): delay_secs=delay_secs, throttle_delay_secs=throttle_delay_secs) + def run_std_server(self): + """Starts a TensorFlow server and joins the serving thread. + + Typically used for parameter servers. + + Raises: + ValueError: if not enough information is available in the estimator's + config to create a server. + """ + self._start_server().join() + def test(self): """Tests training and evaluating the estimator both for a single step. @@ -232,3 +253,20 @@ class Experiment(object): steps=1, metrics=self._eval_metrics, name="one_pass") + + def _start_server(self): + """Creates, starts, and returns a server_lib.Server.""" + config = self._estimator.config + if (not config.cluster_spec or not config.job_name or not config.master or + config.task is None): + raise ValueError("Could not start server; be sure to specify " + "cluster_spec, job_name, master, and task in " + "RunConfig or set the TF_CONFIG environment variable.") + server = server_lib.Server( + config.cluster_spec, + job_name=config.job_name, + task_index=config.task, + config=config.tf_config, + start=False) + server.start() + return server diff --git a/tensorflow/contrib/learn/python/learn/graph_actions.py b/tensorflow/contrib/learn/python/learn/graph_actions.py index 05edc6dfae93f66205fb36730cc31e8addcf602e..4665caa2d45e67de480a843e5161370f4ce35305 100644 --- a/tensorflow/contrib/learn/python/learn/graph_actions.py +++ b/tensorflow/contrib/learn/python/learn/graph_actions.py @@ -234,8 +234,10 @@ def _monitored_train(graph, all_hooks.extend([ basic_session_run_hooks.NanTensorHook( loss_op, fail_on_nan_loss=fail_on_nan_loss), - basic_session_run_hooks.LoggingTensorHook( - {'loss': loss_op.name}, every_n_iter=log_every_steps), + basic_session_run_hooks.LoggingTensorHook({ + 'loss': loss_op.name, + 'step': global_step_tensor.name + }, every_n_iter=log_every_steps), ]) scaffold = monitored_session.Scaffold( diff --git a/tensorflow/contrib/learn/python/learn/learn_io/graph_io.py b/tensorflow/contrib/learn/python/learn/learn_io/graph_io.py index 5f502f0108c5cec8e08a7cb879d97ae1f8f38b72..9becd7b97bcd3734a8a1d083c09accd0d5e434ec 100644 --- a/tensorflow/contrib/learn/python/learn/learn_io/graph_io.py +++ b/tensorflow/contrib/learn/python/learn/learn_io/graph_io.py @@ -74,8 +74,7 @@ def read_batch_examples(file_pattern, batch_size, reader, name: Name of resulting op. Returns: - String `Tensor` of batched `Example` proto. If `keep_keys` is True, then - returns tuple of string `Tensor`s, where first value is the key. + String `Tensor` of batched `Example` proto. Raises: ValueError: for invalid inputs. @@ -127,8 +126,9 @@ def read_keyed_batch_examples( name: Name of resulting op. Returns: - String `Tensor` of batched `Example` proto. If `keep_keys` is True, then - returns tuple of string `Tensor`s, where first value is the key. + Returns tuple of: + - `Tensor` of string keys. + - String `Tensor` of batched `Example` proto. Raises: ValueError: for invalid inputs. @@ -272,8 +272,9 @@ def read_keyed_batch_features(file_pattern, name: Name of resulting op. Returns: - A dict of `Tensor` or `SparseTensor` objects for each in `features`. - If `keep_keys` is `True`, returns tuple of string `Tensor` and above dict. + Returns tuple of: + - `Tensor` of string keys. + - A dict of `Tensor` or `SparseTensor` objects for each in `features`. Raises: ValueError: for invalid inputs. @@ -392,7 +393,6 @@ def read_batch_features(file_pattern, batch_size, features, reader, Returns: A dict of `Tensor` or `SparseTensor` objects for each in `features`. - If `keep_keys` is `True`, returns tuple of string `Tensor` and above dict. Raises: ValueError: for invalid inputs. diff --git a/tensorflow/contrib/learn/python/learn/learn_io/graph_io_test.py b/tensorflow/contrib/learn/python/learn/learn_io/graph_io_test.py index e14048d04c325252c511ee2f6d975f2c458c0f17..c1b1c409454a1a3cb368d262386cc4098b52d0f3 100644 --- a/tensorflow/contrib/learn/python/learn/learn_io/graph_io_test.py +++ b/tensorflow/contrib/learn/python/learn/learn_io/graph_io_test.py @@ -121,9 +121,13 @@ class GraphIOTest(tf.test.TestCase): with tf.Graph().as_default() as g, self.test_session(graph=g) as sess: features = tf.contrib.learn.io.read_batch_record_features( - _VALID_FILE_PATTERN, batch_size, features, randomize_input=False, - queue_capacity=queue_capacity, reader_num_threads=2, - parser_num_threads=2, name=name) + _VALID_FILE_PATTERN, + batch_size, + features, + randomize_input=False, + queue_capacity=queue_capacity, + reader_num_threads=2, + name=name) self.assertEqual("%s/fifo_queue_1_Dequeue:0" % name, features["feature"].name) file_name_queue_name = "%s/file_name_queue" % name diff --git a/tensorflow/contrib/learn/python/learn/learn_runner.py b/tensorflow/contrib/learn/python/learn/learn_runner.py index 331ca8df935f16caadf8a1383c89c5589aa4094f..f9fc9838fa238519df0768d036dd9f33b4a294c0 100644 --- a/tensorflow/contrib/learn/python/learn/learn_runner.py +++ b/tensorflow/contrib/learn/python/learn/learn_runner.py @@ -22,12 +22,22 @@ from tensorflow.contrib.learn.python.learn.experiment import Experiment from tensorflow.python.platform import tf_logging as logging -def run(experiment_fn, output_dir, schedule): +def run(experiment_fn, output_dir, schedule=None): """Make and run an experiment. It creates an Experiment by calling `experiment_fn`. Then it calls the function named as `schedule` of the Experiment. + If schedule is not provided, then the default schedule for the current task + type is used. The defaults are as follows: + + * 'ps' maps to 'serve' + * 'worker' maps to 'train' + * 'master' maps to 'local_run' + + If the experiment's config does not include a task type, then an exception + is raised. + Example: ``` def _create_my_experiment(output_dir): @@ -53,14 +63,13 @@ def run(experiment_fn, output_dir, schedule): The return value of function `schedule`. Raises: - ValueError: If output_dir or schedule is empty, or if `schedule` doesn't - references a member of `Experiment`. + ValueError: If `output_dir` is empty, `schedule` is None but no task + type is set in the built experiment's config, the task type has no + default, or `schedule` doesn't reference a member of `Experiment`. TypeError: `schedule` references non-callable member. """ if not output_dir: raise ValueError('Must specify an output directory') - if not schedule: - raise ValueError('Must specify a schedule') if not callable(experiment_fn): raise TypeError('Experiment builder "%s" is not callable.' % experiment_fn) @@ -71,6 +80,12 @@ def run(experiment_fn, output_dir, schedule): raise TypeError('Experiment builder did not return an Experiment ' 'instance, got %s instead.' % type(experiment)) + # Get the schedule + config = experiment.estimator.config + schedule = schedule or _get_default_schedule(config) + if not schedule: + raise ValueError('Must specify a schedule') + # Execute the schedule if not hasattr(experiment, schedule): logging.error('Schedule references non-existent task %s', schedule) @@ -90,3 +105,21 @@ def run(experiment_fn, output_dir, schedule): raise TypeError('Schedule references non-callable member %s', schedule) return task() + + +def _get_default_schedule(config): + """Returns the default schedule for the provided RunConfig.""" + if not config or not config.job_name: + return None + + if not config.job_name or config.job_name == 'master': + # TODO(rhaertel): handle the case there are more + # than one masters or explicitly disallow. + return 'local_run' + elif config.job_name == 'ps': + return 'serve' + elif config.job_name == 'worker': + return 'train' + + return ValueError('No default schedule for task type: %s' % + (config.job_name,)) diff --git a/tensorflow/contrib/learn/python/learn/monitored_session.py b/tensorflow/contrib/learn/python/learn/monitored_session.py index c87633e97639546be20bb1147256b9195c32ac7c..6f9957f25e112d5df067eb5e81a5ed6c4df53cae 100644 --- a/tensorflow/contrib/learn/python/learn/monitored_session.py +++ b/tensorflow/contrib/learn/python/learn/monitored_session.py @@ -143,7 +143,7 @@ class Scaffold(object): self._saver = Scaffold._get_or_default( 'saver', ops.GraphKeys.SAVERS, - lambda: training_saver.Saver(sharded=True)) + lambda: training_saver.Saver(sharded=True, allow_empty=True)) # pylint: enable=g-long-lambda self._saver.build() @@ -240,7 +240,7 @@ class MonitoredSession(object): """ def __init__(self, - master, + master='', is_chief=True, checkpoint_dir=None, hooks=None, diff --git a/tensorflow/contrib/learn/python/learn/tests/base_test.py b/tensorflow/contrib/learn/python/learn/tests/base_test.py index 3e0f9df6d8db12214fef00ef4a0867e7b4763dbf..115f86aa7eb94122e0bae55909cddf76498b1c1f 100644 --- a/tensorflow/contrib/learn/python/learn/tests/base_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/base_test.py @@ -41,47 +41,36 @@ class BaseTest(tf.test.TestCase): x = np.random.rand(1000) y = 2 * x + 3 feature_columns = learn.infer_real_valued_columns_from_input(x) - regressor = learn.TensorFlowLinearRegressor(feature_columns=feature_columns) - regressor.fit(x, y) + regressor = learn.LinearRegressor(feature_columns=feature_columns) + regressor.fit(x, y, max_steps=100) score = mean_squared_error(y, regressor.predict(x)) self.assertLess(score, 1.0, "Failed with score = {0}".format(score)) def testIris(self): iris = datasets.load_iris() - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), n_classes=3) - classifier.fit(iris.data, [x for x in iris.target]) + classifier.fit(iris.data, [x for x in iris.target], max_steps=100) score = accuracy_score(iris.target, classifier.predict(iris.data)) self.assertGreater(score, 0.7, "Failed with score = {0}".format(score)) - def testIrisClassWeight(self): - iris = datasets.load_iris() - # Note, class_weight are not supported anymore :( Use weight_column. - with self.assertRaises(ValueError): - classifier = learn.TensorFlowLinearClassifier( - feature_columns=learn.infer_real_valued_columns_from_input(iris.data), - n_classes=3, class_weight=[0.1, 0.8, 0.1]) - classifier.fit(iris.data, iris.target) - score = accuracy_score(iris.target, classifier.predict(iris.data)) - self.assertLess(score, 0.7, "Failed with score = {0}".format(score)) - def testIrisAllVariables(self): iris = datasets.load_iris() - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), n_classes=3) - classifier.fit(iris.data, [x for x in iris.target]) + classifier.fit(iris.data, [x for x in iris.target], max_steps=100) self.assertEqual( classifier.get_variable_names(), ["centered_bias_weight", "centered_bias_weight/Adagrad", "global_step", # Double slashes appear because the column name is empty. If it was not - # empty, the variable names would be "linear/column_name/_weight" etc. - "linear//_weight", - "linear//_weight/Ftrl", - "linear//_weight/Ftrl_1", + # empty, the variable names would be "linear/column_name/weight" etc. + "linear//weight", + "linear//weight/Ftrl", + "linear//weight/Ftrl_1", "linear/bias_weight", "linear/bias_weight/Ftrl", "linear/bias_weight/Ftrl_1"]) @@ -89,23 +78,20 @@ class BaseTest(tf.test.TestCase): def testIrisSummaries(self): iris = datasets.load_iris() output_dir = tempfile.mkdtemp() + "learn_tests/" - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), n_classes=3, model_dir=output_dir) - classifier.fit(iris.data, iris.target) + classifier.fit(iris.data, iris.target, max_steps=100) score = accuracy_score(iris.target, classifier.predict(iris.data)) self.assertGreater(score, 0.5, "Failed with score = {0}".format(score)) # TODO(ipolosukhin): Check that summaries are correclty written. def testIrisContinueTraining(self): iris = datasets.load_iris() - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), - n_classes=3, - learning_rate=0.01, - continue_training=True, - steps=250) - classifier.fit(iris.data, iris.target) + n_classes=3) + classifier.fit(iris.data, iris.target, steps=100) score1 = accuracy_score(iris.target, classifier.predict(iris.data)) classifier.fit(iris.data, iris.target, steps=500) score2 = accuracy_score(iris.target, classifier.predict(iris.data)) @@ -130,10 +116,10 @@ class BaseTest(tf.test.TestCase): for y in iris.target: yield y - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), - n_classes=3, steps=100) - classifier.fit(iris_data(), iris_target()) + n_classes=3) + classifier.fit(iris_data(), iris_target(), max_steps=500) score1 = accuracy_score(iris.target, classifier.predict(iris.data)) score2 = accuracy_score(iris.target, classifier.predict(iris_predict_data())) @@ -147,22 +133,19 @@ class BaseTest(tf.test.TestCase): if log_loss: random.seed(42) iris = datasets.load_iris() - classifier = learn.TensorFlowClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(iris.data), - n_classes=3, steps=250) - classifier.fit(iris.data, iris.target) + n_classes=3) + classifier.fit(iris.data, iris.target, max_steps=250) score = log_loss(iris.target, classifier.predict_proba(iris.data)) self.assertLess(score, 0.8, "Failed with score = {0}".format(score)) def testBoston(self): random.seed(42) boston = datasets.load_boston() - regressor = learn.TensorFlowLinearRegressor( - feature_columns=learn.infer_real_valued_columns_from_input(boston.data), - batch_size=boston.data.shape[0], - steps=500, - learning_rate=0.001) - regressor.fit(boston.data, boston.target) + regressor = learn.LinearRegressor( + feature_columns=learn.infer_real_valued_columns_from_input(boston.data)) + regressor.fit(boston.data, boston.target, max_steps=500) score = mean_squared_error(boston.target, regressor.predict(boston.data)) self.assertLess(score, 150, "Failed with score = {0}".format(score)) diff --git a/tensorflow/contrib/learn/python/learn/tests/dataframe/arithmetic_transform_test.py b/tensorflow/contrib/learn/python/learn/tests/dataframe/arithmetic_transform_test.py index 045f84580f189d5a3929a6f2a2df8d077201637a..3682a6517de84fce2663ea7aa737b59f369aea87 100644 --- a/tensorflow/contrib/learn/python/learn/tests/dataframe/arithmetic_transform_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/dataframe/arithmetic_transform_test.py @@ -49,7 +49,7 @@ class SumTestCase(tf.test.TestCase): frame["a+b"] = frame["a"] + frame["b"] expected_sum = pandas_df["a"] + pandas_df["b"] - actual_sum = frame.run_once()["a+b"] + actual_sum = frame.run_one_batch()["a+b"] np.testing.assert_array_equal(expected_sum, actual_sum) @@ -70,7 +70,7 @@ class DifferenceTestCase(tf.test.TestCase): frame["a-b"] = frame["a"] - frame["b"] expected_diff = pandas_df["a"] - pandas_df["b"] - actual_diff = frame.run_once()["a-b"] + actual_diff = frame.run_one_batch()["a-b"] np.testing.assert_array_equal(expected_diff, actual_diff) diff --git a/tensorflow/contrib/learn/python/learn/tests/dataframe/dataframe_test.py b/tensorflow/contrib/learn/python/learn/tests/dataframe/dataframe_test.py index 780c8840781dfd67526e8ac191145b1949ade33f..c5da6244f42d5967b84b3d3468b124319e3a7497 100644 --- a/tensorflow/contrib/learn/python/learn/tests/dataframe/dataframe_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/dataframe/dataframe_test.py @@ -51,11 +51,23 @@ class DataFrameTest(tf.test.TestCase): df2 = df.select_columns(["a", "c"]) self.assertEqual(df2.columns(), frozenset(["a", "c"])) + def test_exclude_columns(self): + df = setup_test_df() + df2 = df.exclude_columns(["a", "c"]) + self.assertEqual(df2.columns(), frozenset(["b"])) + def test_get_item(self): df = setup_test_df() c1 = df["b"] self.assertEqual(mocks.MockTensor("Mock Tensor 2", tf.int32), c1.build()) + def test_del_item_column(self): + df = setup_test_df() + self.assertEqual(3, len(df)) + del df["b"] + self.assertEqual(2, len(df)) + self.assertEqual(df.columns(), frozenset(["a", "c"])) + def test_set_item_column(self): df = setup_test_df() self.assertEqual(3, len(df)) diff --git a/tensorflow/contrib/learn/python/learn/tests/dataframe/mocks.py b/tensorflow/contrib/learn/python/learn/tests/dataframe/mocks.py index 6e5f2b5ab8374b1599f42414bbc62aa058727575..0a64babb95638ae361f21448a2ee763ccae9abe6 100644 --- a/tensorflow/contrib/learn/python/learn/tests/dataframe/mocks.py +++ b/tensorflow/contrib/learn/python/learn/tests/dataframe/mocks.py @@ -110,7 +110,7 @@ class MockSeries(learn.Series): return self._cachekey -class MockTransform(learn.Transform): +class MockTransform(learn.TensorFlowTransform): """A mock transform for use in testing.""" __metaclass__ = ABCMeta diff --git a/tensorflow/contrib/learn/python/learn/tests/dataframe/tensorflow_dataframe_test.py b/tensorflow/contrib/learn/python/learn/tests/dataframe/tensorflow_dataframe_test.py index d7e2fe684b8750bdc4812038357b976b6c73d70e..98e7cf4a071ce2a50cf6c1723dc9652f5c745a5f 100644 --- a/tensorflow/contrib/learn/python/learn/tests/dataframe/tensorflow_dataframe_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/dataframe/tensorflow_dataframe_test.py @@ -131,7 +131,7 @@ class TensorFlowDataFrameTestCase(tf.test.TestCase): batch_size=10, shuffle=False) - batch = tensorflow_df.run_once() + batch = tensorflow_df.run_one_batch() np.testing.assert_array_equal(pandas_df.index.values, batch["index"], "Expected index {}; got {}".format( @@ -239,7 +239,7 @@ class TensorFlowDataFrameTestCase(tf.test.TestCase): s = pandas_df["string"] for i in range(0, len(s)): if isinstance(s[i], float) and math.isnan(s[i]): - s[i] = "" + pandas_df.set_value(i, "string", "") tensorflow_df = df.TensorFlowDataFrame.from_csv_with_feature_spec( [data_path], batch_size=batch_size, diff --git a/tensorflow/contrib/learn/python/learn/tests/experiment_test.py b/tensorflow/contrib/learn/python/learn/tests/experiment_test.py index 11feab7c487c7c24513777689b523d14890a84bb..56401558d23e0a30c7225eb5d399c7535219424b 100644 --- a/tensorflow/contrib/learn/python/learn/tests/experiment_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/experiment_test.py @@ -19,16 +19,20 @@ from __future__ import print_function import time import tensorflow as tf -# importing to get flags. -from tensorflow.contrib.learn.python.learn import learn_runner # pylint: disable=unused-import +from tensorflow.contrib.learn.python.learn import run_config class TestEstimator(tf.contrib.learn.Evaluable, tf.contrib.learn.Trainable): - def __init__(self): + def __init__(self, config=None): self.eval_count = 0 self.fit_count = 0 self.monitors = [] + self._config = config or run_config.RunConfig() + + @property + def config(self): + return self._config def evaluate(self, **kwargs): tf.logging.info('evaluate called with args: %s' % kwargs) @@ -72,18 +76,86 @@ class ExperimentTest(tf.test.TestCase): self.assertAlmostEqual(duration, delay, delta=0.5) def test_train_default_delay(self): - est = TestEstimator() + config = run_config.RunConfig() + est = TestEstimator(config) ex = tf.contrib.learn.Experiment(est, train_input_fn='train_input', eval_input_fn='eval_input') - tf.flags.DEFINE_integer('task', 0, 'task') for task in [0, 1, 3]: start = time.time() - tf.flags.FLAGS.task = task + config.task = task ex.train() duration = time.time() - start self.assertAlmostEqual(duration, task*5, delta=0.5) + @tf.test.mock.patch('tensorflow.python.training.server_lib.Server') # pylint: disable=line-too-long + def test_train_starts_server(self, mock_server): + # Arrange. + config = tf.contrib.learn.RunConfig( + master='host4:2222', + cluster_spec=tf.train.ClusterSpec( + {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + ), + job_name='worker', + task=1, + num_cores=15, + gpu_memory_fraction=0.314, + ) + + est = TestEstimator(config) + ex = tf.contrib.learn.Experiment(est, + train_input_fn='train_input', + eval_input_fn='eval_input') + + # Act. + # We want to make sure we discount the time it takes to start the server + # in our accounting of the delay, so we set a small delay here. + start = time.time() + ex.train(delay_secs=1) + duration = time.time() - start + + # Assert. + expected_config_proto = tf.ConfigProto() + expected_config_proto.inter_op_parallelism_threads = 15 + expected_config_proto.intra_op_parallelism_threads = 15 + expected_config_proto.gpu_options.per_process_gpu_memory_fraction = 0.314 + mock_server.assert_called_with( + config.cluster_spec, + job_name='worker', + task_index=1, + config=expected_config_proto, + start=False) + mock_server.assert_has_calls([tf.test.mock.call().start()]) + + # Ensure that the delay takes into account the time to start the server. + self.assertAlmostEqual(duration, 1.0, delta=0.5) + + @tf.test.mock.patch('tensorflow.python.training.server_lib.Server') # pylint: disable=line-too-long + def test_train_server_does_not_start_without_cluster_spec(self, mock_server): + config = tf.contrib.learn.RunConfig(master='host4:2222') + ex = tf.contrib.learn.Experiment(TestEstimator(config), + train_input_fn='train_input', + eval_input_fn='eval_input') + ex.train() + + # The server should not have started because there was no ClusterSpec. + self.assertFalse(mock_server.called) + + def test_train_raises_if_job_name_is_missing(self): + no_job_name = tf.contrib.learn.RunConfig( + cluster_spec=tf.train.ClusterSpec( + {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + ), + task=1, + ) + with self.assertRaises(ValueError): + ex = tf.contrib.learn.Experiment(TestEstimator(no_job_name), + train_input_fn='train_input', + eval_input_fn='eval_input') + ex.train() + def test_evaluate(self): est = TestEstimator() ex = tf.contrib.learn.Experiment(est, @@ -154,6 +226,41 @@ class ExperimentTest(tf.test.TestCase): self.assertTrue(isinstance(est.monitors[0], tf.contrib.learn.monitors.ValidationMonitor)) + @tf.test.mock.patch('tensorflow.python.training.server_lib.Server') # pylint: disable=line-too-long + def test_run_std_server(self, mock_server): + # Arrange. + config = tf.contrib.learn.RunConfig( + master='host2:2222', + cluster_spec=tf.train.ClusterSpec( + {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + ), + job_name='ps', + task=1, + num_cores=15, + gpu_memory_fraction=0.314, + ) + est = TestEstimator(config) + ex = tf.contrib.learn.Experiment(est, + train_input_fn='train_input', + eval_input_fn='eval_input') + + # Act. + ex.run_std_server() + + # Assert. + mock_server.assert_has_calls([tf.test.mock.call().start(), + tf.test.mock.call().join()]) + + @tf.test.mock.patch('tensorflow.python.training.server_lib.Server') # pylint: disable=line-too-long + def test_run_std_server_raises_without_cluster_spec(self, mock_server): + config = tf.contrib.learn.RunConfig(master='host4:2222') + with self.assertRaises(ValueError): + ex = tf.contrib.learn.Experiment(TestEstimator(config), + train_input_fn='train_input', + eval_input_fn='eval_input') + ex.run_std_server() + def test_test(self): est = TestEstimator() ex = tf.contrib.learn.Experiment(est, diff --git a/tensorflow/contrib/learn/python/learn/tests/io_test.py b/tensorflow/contrib/learn/python/learn/tests/io_test.py index 0806728e3d20cea3437ffabd36f778bfa96c6f48..80732337f979b18d8c88799ad1984ddaf091edfa 100644 --- a/tensorflow/contrib/learn/python/learn/tests/io_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/io_test.py @@ -41,10 +41,10 @@ class IOTest(tf.test.TestCase): iris = datasets.load_iris() data = pd.DataFrame(iris.data) labels = pd.DataFrame(iris.target) - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(data), n_classes=3) - classifier.fit(data, labels) + classifier.fit(data, labels, steps=100) score = accuracy_score(labels[0], classifier.predict(data)) self.assertGreater(score, 0.5, "Failed with score = {0}".format(score)) else: @@ -57,10 +57,10 @@ class IOTest(tf.test.TestCase): iris = datasets.load_iris() data = pd.DataFrame(iris.data) labels = pd.Series(iris.target) - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(data), n_classes=3) - classifier.fit(data, labels) + classifier.fit(data, labels, steps=100) score = accuracy_score(labels, classifier.predict(data)) self.assertGreater(score, 0.5, "Failed with score = {0}".format(score)) @@ -110,10 +110,10 @@ class IOTest(tf.test.TestCase): data = dd.from_pandas(data, npartitions=2) labels = pd.DataFrame(iris.target) labels = dd.from_pandas(labels, npartitions=2) - classifier = learn.TensorFlowLinearClassifier( + classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(data), n_classes=3) - classifier.fit(data, labels) + classifier.fit(data, labels, steps=100) predictions = data.map_partitions(classifier.predict).compute() score = accuracy_score(labels.compute(), predictions) self.assertGreater(score, 0.5, "Failed with score = {0}".format(score)) diff --git a/tensorflow/contrib/learn/python/learn/tests/learn_runner_test.py b/tensorflow/contrib/learn/python/learn/tests/learn_runner_test.py index d01d9685053d184ce126d8193b54257d575e8f27..a916fe54acb010fc7fba349b8c569a60c3296d93 100644 --- a/tensorflow/contrib/learn/python/learn/tests/learn_runner_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/learn_runner_test.py @@ -18,14 +18,34 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import json +import os + import tensorflow as tf from tensorflow.contrib.learn.python.learn import learn_runner +from tensorflow.contrib.learn.python.learn import run_config class TestExperiment(tf.contrib.learn.Experiment): - def __init__(self, default=None): + def __init__(self, default=None, config=None): self.default = default + self.config = config + + @property + def estimator(self): + class Estimator(object): + config = self.config + return Estimator() + + def local_run(self): + return "train_and_evaluate" + + def train(self): + return "train" + + def serve(self): + return "serve" def simple_task(self): return "simple_task, default=%s." % self.default @@ -44,20 +64,66 @@ def build_non_experiment(output_dir): class MainTest(tf.test.TestCase): - def test_run(self): + def setUp(self): + # Ensure the TF_CONFIG environment variable is unset for all tests. + os.environ.pop("TF_CONFIG", None) + + def test_run_with_explicit_args(self): self.assertEqual( "simple_task, default=None.", - learn_runner.run( - build_experiment, output_dir="/tmp", schedule="simple_task")) + learn_runner.run(build_experiment, + output_dir="/tmp", + schedule="simple_task")) + + def test_schedule_from_tf_config(self): + os.environ["TF_CONFIG"] = json.dumps({"task": {"type": "worker"}}) + # RunConfig constructuor will set job_name from TF_CONFIG. + config = run_config.RunConfig() + self.assertEqual( + "train", + learn_runner.run(lambda output_dir: TestExperiment(config=config), + output_dir="/tmp")) + + def test_schedule_from_manually_specified_job_name(self): + config = run_config.RunConfig(job_name="worker") + self.assertEqual( + "train", + learn_runner.run(lambda output_dir: TestExperiment(config=config), + output_dir="/tmp")) + + def test_schedule_from_config_runs_train_and_evaluate_on_master(self): + config = run_config.RunConfig(job_name="master") + self.assertEqual( + "train_and_evaluate", + learn_runner.run(lambda output_dir: TestExperiment(config=config), + output_dir="/tmp")) + + def test_schedule_from_config_runs_serve_on_ps(self): + config = run_config.RunConfig(job_name="ps") + self.assertEqual( + "serve", + learn_runner.run(lambda output_dir: TestExperiment(config=config), + output_dir="/tmp")) + + def test_schedule_from_config_runs_train_on_worker(self): + config = run_config.RunConfig(job_name="worker") + self.assertEqual( + "train", + learn_runner.run(lambda output_dir: TestExperiment(config=config), + output_dir="/tmp")) def test_fail_no_output_dir(self): self.assertRaisesRegexp(ValueError, "Must specify an output directory", learn_runner.run, build_experiment, "", "simple_task") - def test_fail_no_schedule(self): + def test_fail_no_schedule_and_no_config(self): + self.assertRaisesRegexp(ValueError, "Must specify a schedule", + learn_runner.run, build_experiment, "/tmp") + + def test_fail_job_name_with_no_default_schedule(self): self.assertRaisesRegexp(ValueError, "Must specify a schedule", - learn_runner.run, build_experiment, "/tmp", "") + learn_runner.run, build_experiment, "/tmp") def test_fail_non_callable(self): self.assertRaisesRegexp(TypeError, "Experiment builder .* is not callable", @@ -65,19 +131,30 @@ class MainTest(tf.test.TestCase): "simple_test") def test_fail_not_experiment(self): - self.assertRaisesRegexp( - TypeError, "Experiment builder did not return an Experiment", - learn_runner.run, build_non_experiment, "/tmp", "simple_test") + self.assertRaisesRegexp(TypeError, + "Experiment builder did not return an Experiment", + learn_runner.run, build_non_experiment, "/tmp", + "simple_test") def test_fail_non_existent_task(self): - self.assertRaisesRegexp( - ValueError, "Schedule references non-existent task", - learn_runner.run, build_experiment, "/tmp", "mirage") + self.assertRaisesRegexp(ValueError, "Schedule references non-existent task", + learn_runner.run, build_experiment, "/tmp", + "mirage") def test_fail_non_callable_task(self): + self.assertRaisesRegexp(TypeError, + "Schedule references non-callable member", + learn_runner.run, build_experiment, "/tmp", + "default") + + def test_fail_schedule_from_config_with_no_job_name(self): + config = run_config.RunConfig(job_name=None) self.assertRaisesRegexp( - TypeError, "Schedule references non-callable member", - learn_runner.run, build_experiment, "/tmp", "default") + ValueError, + "Must specify a schedule", + learn_runner.run, + lambda output_dir: TestExperiment(config=config), + output_dir="/tmp") if __name__ == "__main__": diff --git a/tensorflow/contrib/learn/python/learn/tests/monitored_session_test.py b/tensorflow/contrib/learn/python/learn/tests/monitored_session_test.py index 4011d158271c0394b196f117f86f829efe9132ee..af790f2a91ba75eceaa192fa9de1918698ffe7dc 100644 --- a/tensorflow/contrib/learn/python/learn/tests/monitored_session_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/monitored_session_test.py @@ -61,6 +61,18 @@ class ScaffoldTest(tf.test.TestCase): sess.run([scaffold.init_op, scaffold.local_init_op]) self.assertEquals(0, len(sess.run(scaffold.ready_op))) + def test_defaults_no_variables(self): + with tf.Graph().as_default(): + scaffold = monitored_session.Scaffold() + tf.constant(1, name='my_const') + scaffold.finalize() + self.assertTrue(isinstance(scaffold.init_op, tf.Operation)) + self.assertEqual(None, scaffold.init_feed_dict) + self.assertEqual(None, scaffold.init_fn) + self.assertTrue(isinstance(scaffold.ready_op, tf.Tensor)) + self.assertTrue(isinstance(scaffold.local_init_op, tf.Operation)) + self.assertTrue(isinstance(scaffold.saver, tf.train.Saver)) + def test_caches_values(self): with tf.Graph().as_default(): tf.Variable([1]) diff --git a/tensorflow/contrib/learn/python/learn/tests/multioutput_test.py b/tensorflow/contrib/learn/python/learn/tests/multioutput_test.py index d632b3735e958b07470feabd5d472d523728ac0a..a51f7468905d95e652a8e5c42684faeee0788f07 100644 --- a/tensorflow/contrib/learn/python/learn/tests/multioutput_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/multioutput_test.py @@ -35,10 +35,10 @@ class MultiOutputTest(tf.test.TestCase): rng = np.random.RandomState(1) x = np.sort(200 * rng.rand(100, 1) - 100, axis=0) y = np.array([np.pi * np.sin(x).ravel(), np.pi * np.cos(x).ravel()]).T - regressor = learn.TensorFlowLinearRegressor( + regressor = learn.LinearRegressor( feature_columns=learn.infer_real_valued_columns_from_input(x), - learning_rate=0.01, target_dimension=2) - regressor.fit(x, y) + target_dimension=2) + regressor.fit(x, y, steps=100) score = mean_squared_error(regressor.predict(x), y) self.assertLess(score, 10, "Failed with score = {0}".format(score)) diff --git a/tensorflow/contrib/learn/python/learn/tests/regression_test.py b/tensorflow/contrib/learn/python/learn/tests/regression_test.py index a1ee9a1a3114f272b593cea9d87371ee5c171ad6..252dd73e9eb28d7c3c3125b3530f1385d6a58c45 100644 --- a/tensorflow/contrib/learn/python/learn/tests/regression_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/regression_test.py @@ -37,7 +37,7 @@ class RegressionTest(tf.test.TestCase): weights = 10 * rng.randn(n_weights) y = np.dot(x, weights) y += rng.randn(len(x)) * 0.05 + rng.normal(bias, 0.01) - regressor = learn.TensorFlowLinearRegressor( + regressor = learn.LinearRegressor( feature_columns=learn.infer_real_valued_columns_from_input(x), optimizer="SGD") regressor.fit(x, y, steps=200) diff --git a/tensorflow/contrib/learn/python/learn/tests/run_config_test.py b/tensorflow/contrib/learn/python/learn/tests/run_config_test.py new file mode 100644 index 0000000000000000000000000000000000000000..d42123166730bb47e09e8bb997300f397092f890 --- /dev/null +++ b/tensorflow/contrib/learn/python/learn/tests/run_config_test.py @@ -0,0 +1,215 @@ +# 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. +# ============================================================================== +"""run_config.py tests.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import json + +import tensorflow as tf +from tensorflow.contrib.learn.python.learn import run_config + +patch = tf.test.mock.patch + + +class RunConfigTest(tf.test.TestCase): + + def test_defaults_with_no_tf_config(self): + config = run_config.RunConfig() + self.assertEquals(config.master, "") + self.assertEquals(config.task, 0) + self.assertEquals(config.num_ps_replicas, 0) + self.assertIsNone(config.cluster_spec) + self.assertIsNone(config.job_name) + self.assertIsNone(config.is_chief) + + def test_values_from_tf_config(self): + tf_config = {"cluster": {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}, + "task": {"type": "worker", + "index": 1}} + with patch.dict("os.environ", {"TF_CONFIG": json.dumps(tf_config)}): + config = run_config.RunConfig() + + self.assertEquals(config.master, "host4:4") + self.assertEquals(config.task, 1) + self.assertEquals(config.num_ps_replicas, 2) + self.assertEquals(config.cluster_spec.as_dict(), tf_config["cluster"]) + self.assertEquals(config.job_name, "worker") + self.assertFalse(config.is_chief) + + def test_explicitly_specified_values(self): + cluster_spec = tf.train.ClusterSpec({ + "ps": ["localhost:9990"], + "my_job_name": ["localhost:9991", "localhost:9992", "localhost:0"] + }) + config = run_config.RunConfig( + master="localhost:0", + task=2, + job_name="my_job_name", + cluster_spec=cluster_spec,) + + self.assertEquals(config.master, "localhost:0") + self.assertEquals(config.task, 2) + self.assertEquals(config.num_ps_replicas, 1) + self.assertEquals(config.cluster_spec, cluster_spec) + self.assertEquals(config.job_name, "my_job_name") + self.assertFalse(config.is_chief) + + def test_tf_config_with_overrides(self): + # Purpose: to test the case where TF_CONFIG is set, but then + # values are overridden by manually passing them to the constructor. + + # Setup the TF_CONFIG environment variable + tf_config = {"cluster": {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}, + "task": {"type": "worker", + "index": 1}} + with patch.dict("os.environ", {"TF_CONFIG": json.dumps(tf_config)}): + # Run, but override all of the values that would otherwise have been + # set by TF_CONFIG. + cluster_spec_override = tf.train.ClusterSpec({ + "ps": ["my_host1:314"], + "my_job_name": ["my_host2:314", "my_host4:314", "my_host5:314"], + "master": ["my_host6:313"] + }) + config = run_config.RunConfig( + master="my_master", + task=0, + job_name="master", + cluster_spec=cluster_spec_override, + is_chief=True) + + # To protect against changes to the test itself (either + # the TF_CONFIG variable or the manual overrides), we will assert + # that the overrides are in fact different than TF_CONFIG. + self.assertNotEquals(tf_config["cluster"], cluster_spec_override) + self.assertNotIn("my_job_name", tf_config["cluster"]) + + # Now we assert that the correct values were indeed returned. + self.assertEquals(config.master, "my_master") + self.assertEquals(config.task, 0) + self.assertEquals(config.num_ps_replicas, 1) + self.assertEquals(config.cluster_spec, cluster_spec_override) + self.assertEquals(config.job_name, "master") + self.assertTrue(config.is_chief) + + def test_explicitly_setting_task_to_0_overrides_tf_config(self): + # Setup the TF_CONFIG environment variable + tf_config = {"task": {"index": 1}} + with patch.dict("os.environ", {"TF_CONFIG": json.dumps(tf_config)}): + config = run_config.RunConfig(task=0) + self.assertEquals(config.task, 0) + + def test_num_ps_replicas_and_cluster_spec_are_mutually_exclusive(self): + cluster_spec = tf.train.ClusterSpec( + {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}) + expected_msg_regexp = "Cannot specify both num_ps_replicas and cluster_spec" + with self.assertRaisesRegexp(ValueError, expected_msg_regexp): + run_config.RunConfig( + num_ps_replicas=2, + cluster_spec=cluster_spec,) + + def test_num_ps_replicas_from_tf_config(self): + tf_config = {"cluster": {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}, + "task": {"type": "worker", + "index": 1}} + with patch.dict("os.environ", {"TF_CONFIG": json.dumps(tf_config)}): + expected_msg_regexp = ("Cannot specify both num_ps_replicas and " + "cluster_spec.*cluster_spec may have been set in " + "the TF_CONFIG environment variable") + with self.assertRaisesRegexp(ValueError, expected_msg_regexp): + run_config.RunConfig(num_ps_replicas=2) + + def test_no_cluster_spec_results_in_empty_master(self): + config = run_config.RunConfig() + self.assertEquals(config.master, "") + + def test_single_node_in_cluster_spec_produces_empty_master(self): + cluster_spec = tf.train.ClusterSpec({"worker": ["host1:1"]}) + config = run_config.RunConfig(cluster_spec=cluster_spec) + self.assertEquals(config.master, "") + + def test_no_job_name_produces_empty_master(self): + cluster_spec = tf.train.ClusterSpec( + {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}) + # NB: omitted job_name; better to omit than explictly set to None + # as this better mimics client behavior. + config = run_config.RunConfig(cluster_spec=cluster_spec) + self.assertEquals(config.master, "") + + def test_invalid_job_name_raises(self): + cluster_spec = tf.train.ClusterSpec( + {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}) + expected_msg_regexp = "not_in_cluster_spec is not a valid task" + with self.assertRaisesRegexp(ValueError, expected_msg_regexp): + run_config.RunConfig( + cluster_spec=cluster_spec, job_name="not_in_cluster_spec") + + def test_illegal_task_index_raises(self): + cluster_spec = tf.train.ClusterSpec( + {"ps": ["host1:1", "host2:2"], + "worker": ["host3:3", "host4:4", "host5:5"]}) + expected_msg_regexp = "3 is not a valid task index" + with self.assertRaisesRegexp(ValueError, expected_msg_regexp): + run_config.RunConfig( + cluster_spec=cluster_spec, job_name="worker", task=3) + + def test_empty_cluster_spec(self): + config = run_config.RunConfig(cluster_spec=tf.train.ClusterSpec({})) + self.assertEquals(config.cluster_spec.as_dict(), {}) + + def test_num_ps_replicas_can_be_set_if_cluster_spec_is_empty(self): + config = run_config.RunConfig( + num_ps_replicas=2, + cluster_spec=tf.train.ClusterSpec({})) + # Basically, just make sure no exception is being raised. + self.assertEquals(config.num_ps_replicas, 2) + + def test_is_chief_from_tf_config(self): + # is_chief should be true when ["task"]["type"] == "master" and + # index == 0. Note that test_values_from_tf_config covers the + # non-master case. + tf_config = {"cluster": {"ps": ["host1:1", "host2:2"], + "master": ["host3:3"], + "worker": ["host4:4", "host5:5", "host6:6"]}, + "task": {"type": "master", + "index": 0}} + with patch.dict("os.environ", {"TF_CONFIG": json.dumps(tf_config)}): + config = run_config.RunConfig() + + self.assertTrue(config.is_chief) + + def test_bad_is_chief_combinations_raise(self): + msg = "Task is 1, but only task 0 may be chief" + with self.assertRaisesRegexp(ValueError, msg): + run_config.RunConfig(is_chief=True, task=1) + + msg = "job_name is \'ps\', but only masters or workers may be chiefs" + with self.assertRaisesRegexp(ValueError, msg): + run_config.RunConfig(is_chief=True, task=0, job_name="ps") + + with self.assertRaisesRegexp(ValueError, "Master task 0 must be chief"): + run_config.RunConfig(is_chief=False, task=0, job_name="master") + + +if __name__ == "__main__": + tf.test.main() diff --git a/tensorflow/contrib/learn/python/learn/tests/saver_test.py b/tensorflow/contrib/learn/python/learn/tests/saver_test.py index 00c80935a77c22f13edcb7d29d3ea959c39b8e14..2c939712bbd8bd6a41537218c490af4a96875d30 100644 --- a/tensorflow/contrib/learn/python/learn/tests/saver_test.py +++ b/tensorflow/contrib/learn/python/learn/tests/saver_test.py @@ -35,10 +35,9 @@ class SaverTest(tf.test.TestCase): iris = datasets.load_iris() cont_features = [ tf.contrib.layers.real_valued_column('', dimension=4)] - classifier = learn.TensorFlowLinearClassifier( - feature_columns=cont_features, n_classes=3) - classifier.fit(iris.data, iris.target) - classifier.save(path) + classifier = learn.LinearClassifier( + feature_columns=cont_features, n_classes=3, model_dir=path) + classifier.fit(iris.data, iris.target, steps=200) # TODO(ipolosukhin): Remove or restore. # new_classifier = learn.TensorFlowEstimator.restore(path) # self.assertEqual(type(new_classifier), type(classifier)) diff --git a/tensorflow/contrib/learn/python/learn/utils/export.py b/tensorflow/contrib/learn/python/learn/utils/export.py index a67b6fca4a2c62d5a5686523330c34bd823d88af..88ba2a9bf90ba53410fd1d0b58b8f1ac1e512895 100644 --- a/tensorflow/contrib/learn/python/learn/utils/export.py +++ b/tensorflow/contrib/learn/python/learn/utils/export.py @@ -20,6 +20,7 @@ from __future__ import division from __future__ import print_function from tensorflow.contrib import layers +from tensorflow.contrib.framework import deprecated from tensorflow.contrib.framework.python.ops import variables as contrib_variables from tensorflow.contrib.session_bundle import exporter from tensorflow.contrib.session_bundle import gc @@ -167,18 +168,34 @@ def logistic_regression_signature_fn(examples, unused_features, predictions): # pylint: disable=protected-access -def default_input_fn(estimator, examples): +def _default_input_fn(estimator, examples): """Creates default input parsing using Estimator's feature signatures.""" return estimator._get_feature_ops_from_example(examples) +@deprecated('2016-09-23', 'Please use BaseEstimator.export') def export_estimator(estimator, export_dir, signature_fn=None, - input_fn=default_input_fn, + input_fn=_default_input_fn, default_batch_size=1, exports_to_keep=None): """Deprecated, please use BaseEstimator.export.""" + _export_estimator(estimator=estimator, + export_dir=export_dir, + signature_fn=signature_fn, + input_fn=input_fn, + default_batch_size=default_batch_size, + exports_to_keep=exports_to_keep) + + +def _export_estimator(estimator, + export_dir, + signature_fn, + input_fn, + default_batch_size, + exports_to_keep): + input_fn = input_fn or _default_input_fn checkpoint_path = tf_saver.latest_checkpoint(estimator._model_dir) with ops.Graph().as_default() as g: contrib_variables.create_global_step(g) diff --git a/tensorflow/contrib/linear_optimizer/kernels/sdca_ops.cc b/tensorflow/contrib/linear_optimizer/kernels/sdca_ops.cc index c83e37e814fb7f9a268b3d2be9d46955a26453a9..10c6d6478e5bbe71463ddb37ec56267ff4ebe1f5 100644 --- a/tensorflow/contrib/linear_optimizer/kernels/sdca_ops.cc +++ b/tensorflow/contrib/linear_optimizer/kernels/sdca_ops.cc @@ -64,7 +64,8 @@ using UnalignedInt64Vector = TTypes::UnalignedConstVec; struct ExampleStatistics { // feature_weights dot feature_values for the example. double wx = 0; - + // dot product using the previous weights + double prev_wx = 0; // sum of squared feature values occurring in the example divided by // L2 * sum(example_weights). double normalized_squared_norm = 0; @@ -279,7 +280,7 @@ const ExampleStatistics Example::ComputeWxAndWeightedExampleNorm( result.normalized_squared_norm = squared_norm_ / regularization.symmetric_l2(); - // Compute the w \dot x. + // Compute the w \dot x and prev_w \dot x. // Sparse features contribution. for (size_t j = 0; j < sparse_features_.size(); ++j) { @@ -294,6 +295,9 @@ const ExampleStatistics Example::ComputeWxAndWeightedExampleNorm( const double feature_weight = sparse_weights.nominals(feature_index) + sparse_weights.deltas(feature_index) * num_partitions; + result.prev_wx += + feature_value * + regularization.Shrink(sparse_weights.nominals(feature_index)); result.wx += feature_value * regularization.Shrink(feature_weight); } } @@ -306,9 +310,14 @@ const ExampleStatistics Example::ComputeWxAndWeightedExampleNorm( const Eigen::Tensor feature_weights = dense_weights.nominals + dense_weights.deltas * dense_weights.deltas.constant(num_partitions); + const Eigen::Tensor prev_prediction = + (dense_vector.row() * + regularization.EigenShrink(dense_weights.nominals)) + .sum(); const Eigen::Tensor prediction = (dense_vector.row() * regularization.EigenShrink(feature_weights)) .sum(); + result.prev_wx += prev_prediction(); result.wx += prediction(); } @@ -699,7 +708,7 @@ class DistributedSdcaLargeBatchSolver : public OpKernel { // Update example data. example_state_data(example_index, 0) = new_dual; example_state_data(example_index, 1) = loss_updater_->ComputePrimalLoss( - example_statistics.wx, example_label, example_weight); + example_statistics.prev_wx, example_label, example_weight); example_state_data(example_index, 2) = loss_updater_->ComputeDualLoss(dual, example_label, example_weight); example_state_data(example_index, 3) = example_weight; diff --git a/tensorflow/contrib/linear_optimizer/python/kernel_tests/sdca_ops_test.py b/tensorflow/contrib/linear_optimizer/python/kernel_tests/sdca_ops_test.py index 865ae9299ccfe75345c7593bb78a75804df277d9..e92af51ba12c512d7b3a8fa1c23c03063b0b98b0 100644 --- a/tensorflow/contrib/linear_optimizer/python/kernel_tests/sdca_ops_test.py +++ b/tensorflow/contrib/linear_optimizer/python/kernel_tests/sdca_ops_test.py @@ -982,7 +982,27 @@ class ShardedMutableHashTableTest(SdcaModelTest): result = output.eval() self.assertAllEqual([0, 1, -1], result) - self.assertAllEqual(3, table.values_reduce_sum().eval()) + def testExportSharded(self): + with self._single_threaded_test_session(): + default_val = -1 + num_shards = 2 + keys = tf.constant(['a1', 'b1', 'c2']) + values = tf.constant([0, 1, 2], tf.int64) + table = _ShardedMutableHashTable( + tf.string, tf.int64, default_val, num_shards=num_shards) + self.assertAllEqual(0, table.size().eval()) + + table.insert(keys, values).run() + self.assertAllEqual(3, table.size().eval()) + + keys_list, values_list = table.export_sharded() + self.assertAllEqual(num_shards, len(keys_list)) + self.assertAllEqual(num_shards, len(values_list)) + + self.assertAllEqual(set([b'b1', b'c2']), set(keys_list[0].eval())) + self.assertAllEqual([b'a1'], keys_list[1].eval()) + self.assertAllEqual(set([1, 2]), set(values_list[0].eval())) + self.assertAllEqual([0], values_list[1].eval()) if __name__ == '__main__': diff --git a/tensorflow/contrib/linear_optimizer/python/ops/sdca_ops.py b/tensorflow/contrib/linear_optimizer/python/ops/sdca_ops.py index 5d81b3af09397a48204c1fc5e56aea7c38d26a40..db8a2f91ee32daf1234b88e5c4f7a5cd4805d478 100644 --- a/tensorflow/contrib/linear_optimizer/python/ops/sdca_ops.py +++ b/tensorflow/contrib/linear_optimizer/python/ops/sdca_ops.py @@ -150,23 +150,20 @@ class _ShardedMutableHashTable(lookup_ops.LookupInterface): return control_flow_ops.group(*return_values) - def values_reduce_sum(self, name=None): - """Computes reduce_sum reducing dimension 0 across all values in all shards. - - Args: - name: A name for the operation (optional). + def export_sharded(self, name=None): + """Returns lists of the keys and values tensors in the sharded table. Returns: - A tensor with the sum across all values in the same shape as the table's - value shape. + A pair of lists with the first list containing the key tensors and the + second list containing the value tensors from each shard. """ - # TODO(andreasst): consider replacing with something like export_sharded - # and doing the sum in SdcaModel. - sums = [] + keys_list = [] + values_list = [] for table_shard in self._table_shards: - _, exported_values = table_shard.export(name=name) - sums.append(math_ops.reduce_sum(exported_values, 0)) - return math_ops.add_n(sums) + exported_keys, exported_values = table_shard.export(name=name) + keys_list.append(exported_keys) + values_list.append(exported_values) + return keys_list, values_list class SparseFeatureColumn(object): @@ -418,21 +415,29 @@ class SdcaModel(object): def _l1_loss(self): """Computes the (un-normalized) l1 loss of the model.""" - with name_scope('l1_loss'): - sum = 0.0 + with name_scope('sdca/l1_loss'): + sums = [] for name in ['sparse_features_weights', 'dense_features_weights']: for weights in self._convert_n_to_tensor(self._variables[name]): - sum += math_ops.reduce_sum(math_ops.abs(weights)) + with ops.device(weights.device): + sums.append( + math_ops.reduce_sum( + math_ops.abs(math_ops.cast(weights, dtypes.float64)))) + sum = math_ops.add_n(sums) # SDCA L1 regularization cost is: l1 * sum(|weights|) return self._options['symmetric_l1_regularization'] * sum def _l2_loss(self, l2): """Computes the (un-normalized) l2 loss of the model.""" - with name_scope('l2_loss'): - sum = 0.0 + with name_scope('sdca/l2_loss'): + sums = [] for name in ['sparse_features_weights', 'dense_features_weights']: for weights in self._convert_n_to_tensor(self._variables[name]): - sum += math_ops.reduce_sum(math_ops.square(weights)) + with ops.device(weights.device): + sums.append( + math_ops.reduce_sum( + math_ops.square(math_ops.cast(weights, dtypes.float64)))) + sum = math_ops.add_n(sums) # SDCA L2 regularization cost is: l2 * sum(weights^2) / 2 return l2 * sum / 2.0 @@ -588,16 +593,23 @@ class SdcaModel(object): An Operation that computes the approximate duality gap over all examples. """ - summed_values = self._hashtable.values_reduce_sum() - primal_loss = summed_values[1] - dual_loss = summed_values[2] - example_weights = summed_values[3] - # TODO(andreasst): what about handle examples_weights == 0? - return ( - primal_loss + dual_loss + math_ops.to_float(self._l1_loss()) + - (2.0 * - math_ops.to_float(self._l2_loss(self._symmetric_l2_regularization()))) - ) / example_weights + with name_scope('sdca/approximate_duality_gap'): + _, values_list = self._hashtable.export_sharded() + shard_sums = [] + for values in values_list: + with ops.device(values.device): + shard_sums.append( + math_ops.reduce_sum(math_ops.cast(values, dtypes.float64), 0)) + summed_values = math_ops.add_n(shard_sums) + + primal_loss = summed_values[1] + dual_loss = summed_values[2] + example_weights = summed_values[3] + # Note: we return NaN if there are no weights or all weights are 0, e.g. + # if no examples have been processed + return (primal_loss + dual_loss + self._l1_loss() + + (2.0 * self._l2_loss(self._symmetric_l2_regularization())) + ) / example_weights def unregularized_loss(self, examples): """Add operations to compute the loss (without the regularization loss). @@ -616,9 +628,12 @@ class SdcaModel(object): 'sparse_features', 'dense_features'], examples) self._assertList(['sparse_features', 'dense_features'], examples) with name_scope('sdca/unregularized_loss'): - predictions = self._linear_predictions(examples) - labels = convert_to_tensor(examples['example_labels']) - weights = convert_to_tensor(examples['example_weights']) + predictions = math_ops.cast( + self._linear_predictions(examples), dtypes.float64) + labels = math_ops.cast( + convert_to_tensor(examples['example_labels']), dtypes.float64) + weights = math_ops.cast( + convert_to_tensor(examples['example_weights']), dtypes.float64) if self._options['loss_type'] == 'logistic_loss': return math_ops.reduce_sum(math_ops.mul( @@ -669,4 +684,5 @@ class SdcaModel(object): # (as specified by the user) and *not* # self._symmetric_l2_regularization(). self._l2_loss(self._options['symmetric_l2_regularization'])) / - math_ops.reduce_sum(weights) + self.unregularized_loss(examples)) + math_ops.reduce_sum(math_ops.cast(weights, dtypes.float64)) + + self.unregularized_loss(examples)) diff --git a/tensorflow/contrib/lookup/lookup_ops.py b/tensorflow/contrib/lookup/lookup_ops.py index d90a6137b5a1af7e409c7caeb943b549ec7ae9bc..d330790c2d24dd72bb41095e4bf716d5bc8f8dc5 100644 --- a/tensorflow/contrib/lookup/lookup_ops.py +++ b/tensorflow/contrib/lookup/lookup_ops.py @@ -726,7 +726,8 @@ class MutableHashTable(LookupInterface): the given name across multiple sessions. name: A name for the operation (optional). checkpoint: if True, the contents of the table are saved to and restored - from checkpoints. + from checkpoints. If `shared_name` is empty, the table is shared using + the table node name. Returns: A `MutableHashTable` object. @@ -738,16 +739,21 @@ class MutableHashTable(LookupInterface): dtype=value_dtype) self._value_shape = self._default_value.get_shape() + # The table must be shared if checkpointing is requested. Use the node name + # if no shared_name has been explicitly specified. + use_node_name_sharing = checkpoint and shared_name is None # pylint: disable=protected-access if self._default_value.get_shape().ndims == 0: self._table_ref = gen_data_flow_ops._mutable_hash_table( shared_name=shared_name, + use_node_name_sharing=use_node_name_sharing, key_dtype=key_dtype, value_dtype=value_dtype, name=name) else: self._table_ref = gen_data_flow_ops._mutable_hash_table_of_tensors( shared_name=shared_name, + use_node_name_sharing=use_node_name_sharing, key_dtype=key_dtype, value_dtype=value_dtype, value_shape=self._default_value.get_shape(), diff --git a/tensorflow/contrib/lookup/lookup_ops_test.py b/tensorflow/contrib/lookup/lookup_ops_test.py index ff97fe7493a5b8894759f9f19d01d4e6cc9f67c9..9633d1004987d369fdce1a19a1414b97efa21bd9 100644 --- a/tensorflow/contrib/lookup/lookup_ops_test.py +++ b/tensorflow/contrib/lookup/lookup_ops_test.py @@ -235,6 +235,33 @@ class HashTableOpTest(tf.test.TestCase): tf.contrib.lookup.KeyValueTensorInitializer(keys, values), default_val) + def testMultipleSessions(self): + # Start a server + server = tf.train.Server( + {"local0": ["localhost:0"]}, protocol="grpc", start=True) + # Create two sessions sharing the same state + session1 = tf.Session(server.target) + session2 = tf.Session(server.target) + + default_val = -1 + keys = tf.constant(["brain", "salad", "surgery"]) + values = tf.constant([0, 1, 2], tf.int64) + table = tf.contrib.lookup.HashTable( + tf.contrib.lookup.KeyValueTensorInitializer(keys, values), + default_val, + name="t1") + + # Init the table in the first session. + with session1: + table.init.run() + self.assertAllEqual(3, table.size().eval()) + + # Init the table in the second session and verify that we do not get a + # "Table already initialized" error. + with session2: + table.init.run() + self.assertAllEqual(3, table.size().eval()) + class MutableHashTableOpTest(tf.test.TestCase): @@ -321,6 +348,36 @@ class MutableHashTableOpTest(tf.test.TestCase): output = table.lookup(input_string) self.assertAllEqual([-1, 0, 1, 2, -1], output.eval()) + def testSharing(self): + # Start a server to store the table state + server = tf.train.Server( + {"local0": ["localhost:0"]}, protocol="grpc", start=True) + # Create two sessions sharing the same state + session1 = tf.Session(server.target) + session2 = tf.Session(server.target) + + table = tf.contrib.lookup.MutableHashTable( + tf.int64, tf.string, "-", name="t1") + + # Populate the table in the first session + with session1: + self.assertAllEqual(0, table.size().eval()) + + keys = tf.constant([11, 12], tf.int64) + values = tf.constant(["a", "b"]) + table.insert(keys, values).run() + self.assertAllEqual(2, table.size().eval()) + + output = table.lookup(tf.constant([11, 12, 13], tf.int64)) + self.assertAllEqual([b"a", b"b", b"-"], output.eval()) + + # Verify that we can access the shared data from the second session + with session2: + self.assertAllEqual(2, table.size().eval()) + + output = table.lookup(tf.constant([10, 11, 12], tf.int64)) + self.assertAllEqual([b"-", b"a", b"b"], output.eval()) + def testMutableHashTableOfTensors(self): with self.test_session(): default_val = tf.constant([-1, -1], tf.int64) diff --git a/tensorflow/contrib/makefile/Makefile b/tensorflow/contrib/makefile/Makefile index e7c0488c2cdd7b829e9769743bd3d616df75973b..69cb84c2bb2c2d486596596ccbc72df18149cc0a 100644 --- a/tensorflow/contrib/makefile/Makefile +++ b/tensorflow/contrib/makefile/Makefile @@ -224,7 +224,7 @@ ifeq ($(TARGET),ANDROID) CXX := $(CC_PREFIX) $(NDK_ROOT)/toolchains/arm-linux-androideabi-4.9/prebuilt/$(OS_PATH)-x86_64/bin/arm-linux-androideabi-g++ CXXFLAGS +=\ --sysroot $(NDK_ROOT)/platforms/android-21/arch-arm \ --Wno-c++11-narrowing \ +-Wno-narrowing \ -march=armv7-a \ -fPIE @@ -264,6 +264,7 @@ ifeq ($(TARGET),ANDROID) INCLUDES += -I$(HEXAGON_INCLUDE) LIBS += -lgemm_wrapper LDFLAGS += -L$(HEXAGON_LIBS) + CXXFLAGS += -DUSE_HEXAGON_LIBS endif endif # ANDROID @@ -284,6 +285,7 @@ ifeq ($(TARGET),IOS) CXXFLAGS += -miphoneos-version-min=$(MIN_SDK_VERSION) \ -arch armv7 \ -D__thread= \ + -DUSE_GEMM_FOR_CONV \ -Wno-c++11-narrowing \ -mno-thumb \ -DTF_LEAN_BINARY \ @@ -294,6 +296,7 @@ ifeq ($(TARGET),IOS) ${IPHONEOS_SYSROOT} LDFLAGS := -arch armv7 \ -miphoneos-version-min=${MIN_SDK_VERSION} \ + -framework Accelerate \ -Xlinker -S \ -Xlinker -x \ -Xlinker -dead_strip \ @@ -305,6 +308,7 @@ ifeq ($(TARGET),IOS) CXXFLAGS += -miphoneos-version-min=$(MIN_SDK_VERSION) \ -arch armv7s \ -D__thread= \ + -DUSE_GEMM_FOR_CONV \ -Wno-c++11-narrowing \ -mno-thumb \ -DTF_LEAN_BINARY \ @@ -315,6 +319,7 @@ ifeq ($(TARGET),IOS) ${IPHONEOS_SYSROOT} LDFLAGS := -arch armv7s \ -miphoneos-version-min=${MIN_SDK_VERSION} \ + -framework Accelerate \ -Xlinker -S \ -Xlinker -x \ -Xlinker -dead_strip \ @@ -326,6 +331,7 @@ ifeq ($(TARGET),IOS) CXXFLAGS += -miphoneos-version-min=$(MIN_SDK_VERSION) \ -arch arm64 \ -D__thread= \ + -DUSE_GEMM_FOR_CONV \ -Wno-c++11-narrowing \ -DTF_LEAN_BINARY \ -D__ANDROID_TYPES_SLIM__ \ @@ -335,6 +341,7 @@ ifeq ($(TARGET),IOS) ${IPHONEOS_SYSROOT} LDFLAGS := -arch arm64 \ -miphoneos-version-min=${MIN_SDK_VERSION} \ + -framework Accelerate \ -Xlinker -S \ -Xlinker -x \ -Xlinker -dead_strip \ @@ -346,6 +353,7 @@ ifeq ($(TARGET),IOS) CXXFLAGS += -mios-simulator-version-min=$(MIN_SDK_VERSION) \ -arch i386 \ -D__thread= \ + -DUSE_GEMM_FOR_CONV \ -Wno-c++11-narrowing \ -DTF_LEAN_BINARY \ -D__ANDROID_TYPES_SLIM__ \ @@ -355,6 +363,7 @@ ifeq ($(TARGET),IOS) ${IPHONESIMULATOR_SYSROOT} LDFLAGS := -arch i386 \ -mios-simulator-version-min=${MIN_SDK_VERSION} \ + -framework Accelerate \ -Xlinker -S \ -Xlinker -x \ -Xlinker -dead_strip \ @@ -366,6 +375,7 @@ ifeq ($(TARGET),IOS) CXXFLAGS += -mios-simulator-version-min=$(MIN_SDK_VERSION) \ -arch x86_64 \ -D__thread= \ + -DUSE_GEMM_FOR_CONV \ -Wno-c++11-narrowing \ -DTF_LEAN_BINARY \ -D__ANDROID_TYPES_SLIM__ \ @@ -375,6 +385,7 @@ ifeq ($(TARGET),IOS) ${IPHONESIMULATOR_SYSROOT} LDFLAGS := -arch x86_64 \ -mios-simulator-version-min=${MIN_SDK_VERSION} \ + -framework Accelerate \ -Xlinker -S \ -Xlinker -x \ -Xlinker -dead_strip \ diff --git a/tensorflow/contrib/makefile/README.md b/tensorflow/contrib/makefile/README.md index acfcf8f220fdbc78d4cb45cff0dac5c2f01f3b7a..c0a68470ba99ad510f5b5589593f19eba5dc84c8 100644 --- a/tensorflow/contrib/makefile/README.md +++ b/tensorflow/contrib/makefile/README.md @@ -260,15 +260,17 @@ For other variations of valid optimization flags, see [clang optimization levels ## Raspberry Pi Building on the Raspberry Pi is similar to a normal Linux system. First -download the dependencies and build protobuf: +download the dependencies, install the required packages and build protobuf: ```bash tensorflow/contrib/makefile/download_dependencies.sh +sudo apt-get install autoconf automake libtool cd tensorflow/contrib/makefile/downloads/protobuf/ ./autogen.sh ./configure make sudo make install +sudo ldconfig # refresh shared library cache cd ../../../../.. ``` diff --git a/tensorflow/contrib/makefile/download_dependencies.sh b/tensorflow/contrib/makefile/download_dependencies.sh index 43cd9f4fbcd3aaca8350b22cdc599078019a424a..e14502106595a2cb3b4518b78cfc7703a22e9807 100755 --- a/tensorflow/contrib/makefile/download_dependencies.sh +++ b/tensorflow/contrib/makefile/download_dependencies.sh @@ -63,4 +63,8 @@ git clone https://github.com/google/gemmlowp.git gemmlowp git clone https://github.com/google/protobuf.git protobuf git clone https://github.com/google/googletest.git googletest +# TODO(satok): Remove this once protobuf/autogen.sh is fixed. +replace_by_sed 's#https://googlemock.googlecode.com/files/gmock-1.7.0.zip#http://download.tensorflow.org/deps/gmock-1.7.0.zip#' \ +protobuf/autogen.sh + echo "download_dependencies.sh completed successfully." diff --git a/tensorflow/contrib/makefile/proto_text_pb_cc_files.txt b/tensorflow/contrib/makefile/proto_text_pb_cc_files.txt index c680c0d04c640b7da0bbf7b114aa694060b9d0d8..2b2513e80fd8123faf1a66f7d3e4a5c42e387da2 100644 --- a/tensorflow/contrib/makefile/proto_text_pb_cc_files.txt +++ b/tensorflow/contrib/makefile/proto_text_pb_cc_files.txt @@ -19,6 +19,7 @@ tensorflow/core/framework/tensor.pb.cc tensorflow/core/framework/summary.pb.cc tensorflow/core/framework/step_stats.pb.cc tensorflow/core/framework/op_def.pb.cc +tensorflow/core/framework/node_def.pb.cc tensorflow/core/framework/log_memory.pb.cc tensorflow/core/framework/kernel_def.pb.cc tensorflow/core/framework/graph.pb.cc diff --git a/tensorflow/contrib/makefile/proto_text_pb_h_files.txt b/tensorflow/contrib/makefile/proto_text_pb_h_files.txt index 29aa8a8ef2cd8ea54a6a1be7557154dc9201d4d3..b6028734392008848b3e854718cff9ae161f02c8 100644 --- a/tensorflow/contrib/makefile/proto_text_pb_h_files.txt +++ b/tensorflow/contrib/makefile/proto_text_pb_h_files.txt @@ -19,6 +19,7 @@ tensorflow/core/framework/tensor.pb.h tensorflow/core/framework/summary.pb.h tensorflow/core/framework/step_stats.pb.h tensorflow/core/framework/op_def.pb.h +tensorflow/core/framework/node_def.pb.h tensorflow/core/framework/log_memory.pb.h tensorflow/core/framework/kernel_def.pb.h tensorflow/core/framework/graph.pb.h diff --git a/tensorflow/contrib/makefile/tf_op_files.txt b/tensorflow/contrib/makefile/tf_op_files.txt index 4a92a2f000409ae14d163727aa40a2ccd73eaaa4..4f5c3176dee7bd781c954f57e53412317511b168 100644 --- a/tensorflow/contrib/makefile/tf_op_files.txt +++ b/tensorflow/contrib/makefile/tf_op_files.txt @@ -12,6 +12,7 @@ tensorflow/core/kernels/tile_ops_cpu_impl_2.cc tensorflow/core/kernels/tile_ops_cpu_impl_3.cc tensorflow/core/kernels/tile_ops_cpu_impl_4.cc tensorflow/core/kernels/tile_ops_cpu_impl_5.cc +tensorflow/core/kernels/tile_ops_cpu_impl_6.cc tensorflow/core/kernels/strided_slice_op_inst_6.cc tensorflow/core/kernels/strided_slice_op_inst_5.cc tensorflow/core/kernels/strided_slice_op_inst_4.cc @@ -98,6 +99,7 @@ tensorflow/core/kernels/cwise_op_equal_to.cc tensorflow/core/kernels/cwise_op_div.cc tensorflow/core/kernels/cwise_op_add.cc tensorflow/core/kernels/ctc_decoder_ops.cc +tensorflow/core/kernels/conv_ops_using_gemm.cc tensorflow/core/kernels/conv_ops.cc tensorflow/core/kernels/conv_grad_ops.cc tensorflow/core/kernels/control_flow_ops.cc diff --git a/tensorflow/contrib/makefile/tf_pb_text_files.txt b/tensorflow/contrib/makefile/tf_pb_text_files.txt index ff400d16fa9d64271d999f3bbd29bbb3ee01faea..9db31e5d23509d9934a4c42c1f369be272c71109 100644 --- a/tensorflow/contrib/makefile/tf_pb_text_files.txt +++ b/tensorflow/contrib/makefile/tf_pb_text_files.txt @@ -12,6 +12,7 @@ tensorflow/core/framework/tensor.pb_text.cc tensorflow/core/framework/summary.pb_text.cc tensorflow/core/framework/step_stats.pb_text.cc tensorflow/core/framework/op_def.pb_text.cc +tensorflow/core/framework/node_def.pb_text.cc tensorflow/core/framework/log_memory.pb_text.cc tensorflow/core/framework/kernel_def.pb_text.cc tensorflow/core/framework/graph.pb_text.cc diff --git a/tensorflow/contrib/makefile/tf_proto_files.txt b/tensorflow/contrib/makefile/tf_proto_files.txt index 0490cebf1670237d83c80eae43c94d84414d84f1..1b85c50060dc8d6239c45c61a581f8d3ff2d0cf0 100644 --- a/tensorflow/contrib/makefile/tf_proto_files.txt +++ b/tensorflow/contrib/makefile/tf_proto_files.txt @@ -19,6 +19,7 @@ tensorflow/core/framework/tensor.proto tensorflow/core/framework/summary.proto tensorflow/core/framework/step_stats.proto tensorflow/core/framework/op_def.proto +tensorflow/core/framework/node_def.proto tensorflow/core/framework/log_memory.proto tensorflow/core/framework/kernel_def.proto tensorflow/core/framework/graph.proto diff --git a/tensorflow/contrib/metrics/ops/set_ops.cc b/tensorflow/contrib/metrics/ops/set_ops.cc index c68a1c964a60d3c9b82d2b60618b7e8ca25fc581..2e2bd913676cc7a5147676d4e10f040cd199222e 100644 --- a/tensorflow/contrib/metrics/ops/set_ops.cc +++ b/tensorflow/contrib/metrics/ops/set_ops.cc @@ -19,9 +19,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("SetSize") .Input("set_indices: int64") @@ -67,15 +67,15 @@ REGISTER_OP("DenseToDenseSetOperation") // python/ops/set_ops.py. // Dimension n contains the set values to be compared, so ranks and the // first n-1 dimensions of inputs and output must match. - const Dimension* output_rank; - const Shape* input0_shape = c->input(0); + DimensionHandle output_rank; + ShapeHandle input0_shape = c->input(0); if (c->RankKnown(input0_shape)) { const int32 input0_rank = c->Rank(input0_shape); if (input0_rank < 2) { return errors::InvalidArgument("Input 0, expected rank >= 2, got ", input0_rank, "."); } - const Shape* input1_shape = c->input(1); + ShapeHandle input1_shape = c->input(1); if (c->RankKnown(input1_shape)) { const int32 rank = c->Rank(input1_shape); if (input0_rank != rank) { @@ -83,19 +83,19 @@ REGISTER_OP("DenseToDenseSetOperation") input0_rank, ", input 1 ", rank, "."); } - const Shape* group0_shape; + ShapeHandle group0_shape; TF_RETURN_IF_ERROR( c->Subshape(input0_shape, 0, rank - 1, &group0_shape)); - const Shape* group1_shape; + ShapeHandle group1_shape; TF_RETURN_IF_ERROR( c->Subshape(input1_shape, 0, rank - 1, &group1_shape)); - const Shape* unused_shape; + ShapeHandle unused_shape; TF_RETURN_IF_ERROR( c->Merge(group0_shape, group1_shape, &unused_shape)); } output_rank = c->MakeDim(input0_rank); } else { - const Shape* input1_shape = c->input(1); + ShapeHandle input1_shape = c->input(1); if (c->RankKnown(input1_shape)) { const int32 input1_rank = c->Rank(input1_shape); if (input1_rank < 2) { @@ -107,9 +107,9 @@ REGISTER_OP("DenseToDenseSetOperation") output_rank = c->UnknownDim(); } } - const Dimension* output_num_elements = c->Dim(input0_shape, 0); + DimensionHandle output_num_elements = c->Dim(input0_shape, 0); if (!c->ValueKnown(output_num_elements)) { - const Shape* input1_shape = c->input(1); + ShapeHandle input1_shape = c->input(1); output_num_elements = c->Dim(input1_shape, 0); if (!c->ValueKnown(output_num_elements)) { output_num_elements = c->UnknownDim(); @@ -163,8 +163,8 @@ REGISTER_OP("DenseToSparseSetOperation") // python/ops/set_ops.py. // Dimension n contains the set values to be compared, so ranks and the // first n-1 dimensions of inputs and output must match. - const Dimension* output_rank; - const Shape* input0_shape = c->input(0); + DimensionHandle output_rank; + ShapeHandle input0_shape = c->input(0); if (c->RankKnown(input0_shape)) { const int32 input0_rank = c->Rank(input0_shape); if (input0_rank < 2) { @@ -177,7 +177,7 @@ REGISTER_OP("DenseToSparseSetOperation") } TF_RETURN_IF_ERROR( c->ValidateSparseTensor(c->input(1), c->input(2), c->input(3))); - const Dimension* output_num_elements = c->Dim(input0_shape, 0); + DimensionHandle output_num_elements = c->Dim(input0_shape, 0); if (!c->ValueKnown(output_num_elements)) { output_num_elements = c->UnknownDim(); } diff --git a/tensorflow/contrib/metrics/python/ops/confusion_matrix_ops.py b/tensorflow/contrib/metrics/python/ops/confusion_matrix_ops.py index cf000f06d3ac6a384764a958c5951ea16b51c27f..5620001f1a75096ddf62503aa51b1b80ad1118c4 100644 --- a/tensorflow/contrib/metrics/python/ops/confusion_matrix_ops.py +++ b/tensorflow/contrib/metrics/python/ops/confusion_matrix_ops.py @@ -59,7 +59,7 @@ def confusion_matrix(predictions, labels, num_classes=None, name: Scope name. Returns: - A l X l matrix represeting the confusion matrix, where l in the number of + A k X k matrix represeting the confusion matrix, where k is the number of possible labels in the classification task. Raises: diff --git a/tensorflow/contrib/metrics/python/ops/metric_ops.py b/tensorflow/contrib/metrics/python/ops/metric_ops.py index 249c25b072f78169764fca500faa8b1d6662a6df..c4d20e5db999a4b2cd06478952fb3a8d11c4b497 100644 --- a/tensorflow/contrib/metrics/python/ops/metric_ops.py +++ b/tensorflow/contrib/metrics/python/ops/metric_ops.py @@ -628,7 +628,7 @@ def streaming_recall(predictions, labels, ignore_mask=None, return recall, update_op -def _tp_fn_tn_fp(predictions, labels, thresholds, weights): +def _tp_fn_tn_fp(predictions, labels, thresholds, weights=None): """Computes true_positives, false_negatives, true_negatives, false_positives. The `_tp_fn_tn_fp` function creates four local variables, `true_positives`, diff --git a/tensorflow/contrib/opt/BUILD b/tensorflow/contrib/opt/BUILD index 0671cb3d809a7fbace68c26b626ca56f41a26683..55314613c2bf6682c676e857a19fc2cf06604327 100644 --- a/tensorflow/contrib/opt/BUILD +++ b/tensorflow/contrib/opt/BUILD @@ -12,6 +12,7 @@ py_library( srcs = [ "__init__.py", "python/training/external_optimizer.py", + "python/training/moving_average_optimizer.py", "python/training/variable_clipping_optimizer.py", ], srcs_version = "PY2AND3", @@ -28,6 +29,19 @@ py_test( ], ) +py_test( + name = "moving_average_optimizer_test", + srcs = ["python/training/moving_average_optimizer_test.py"], + srcs_version = "PY2AND3", + tags = [ + "notsan", # b/31055119 + ], + deps = [ + ":opt_py", + "//tensorflow:tensorflow_py", + ], +) + py_test( name = "variable_clipping_optimizer_test", srcs = ["python/training/variable_clipping_optimizer_test.py"], diff --git a/tensorflow/contrib/opt/__init__.py b/tensorflow/contrib/opt/__init__.py index 973d42cbd0dfae5286f28138ed1c0001938d0b9b..11e1eaea6708ed281f472491e6920b3edba11d2f 100644 --- a/tensorflow/contrib/opt/__init__.py +++ b/tensorflow/contrib/opt/__init__.py @@ -20,4 +20,5 @@ from __future__ import print_function # pylint: disable=wildcard-import from tensorflow.contrib.opt.python.training.external_optimizer import * +from tensorflow.contrib.opt.python.training.moving_average_optimizer import * from tensorflow.contrib.opt.python.training.variable_clipping_optimizer import * diff --git a/tensorflow/contrib/opt/python/training/moving_average_optimizer.py b/tensorflow/contrib/opt/python/training/moving_average_optimizer.py new file mode 100644 index 0000000000000000000000000000000000000000..6d37178a98f3ad37406ce844fe8558f5d316bd06 --- /dev/null +++ b/tensorflow/contrib/opt/python/training/moving_average_optimizer.py @@ -0,0 +1,130 @@ +# 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. +# ============================================================================== +"""Optimizer that computes a moving average of the variables. + +Empirically it has been found that using the moving average of the trained +parameters of a deep network is better than using its trained parameters +directly. This optimizer allows you to compute this moving average and swap the +variables at save time so that any code outside of the training loop will use by +default the averaged values instead of the original ones. + +Example of usage: + +```python + +// Encapsulate your favorite optimizer (here the momentum one) +// inside the MovingAverageOptimizer. +opt = tf.train.MomentumOptimizer(learning_rate, FLAGS.momentum) +opt = tf.contrib.opt.MovingAverageOptimizer(opt) +// Then create your model and all its variables. +model = build_model() +// Add the training op that optimizes using opt. +// This needs to be called before swapping_saver(). +opt.minimize(cost, var_list) +// Then create your saver like this: +saver = opt.swapping_saver() +// Pass it to your training loop. + slim.learning.train( + model, + ... + saver=saver) +``` + +Note that for evaluation, the normal saver should be used instead of +swapping_saver(). +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import six + +from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import variables +from tensorflow.python.training import moving_averages +from tensorflow.python.training import optimizer +from tensorflow.python.training import saver + + +class MovingAverageOptimizer(optimizer.Optimizer): + """Optimizer wrapper that maintains a moving average of parameters.""" + + def __init__(self, opt, average_decay=0.9999): + """Construct a new MovingAverageOptimizer. + + Args: + opt: A tf.Optimizer that will be used to compute and apply gradients. + average_decay: Float. Decay to use to maintain the moving averages + of trained variables. + See tf.train.ExponentialMovingAverage for details. + """ + self._optimizer = opt + self._ema = moving_averages.ExponentialMovingAverage(average_decay) + self._variable_map = None + + def apply_gradients(self, grads_and_vars, global_step=None, name=None): + train_op = self._optimizer.apply_gradients( + grads_and_vars, global_step=global_step, name=name) + var_list = [x[1] for x in grads_and_vars if x[0] is not None] + ma_op = self._ema.apply(var_list) + self._variable_map = {} + for v in var_list: + v_avg = self._ema.average(v) + self._variable_map[v.op.name] = v_avg + self._variable_map[v_avg.op.name] = v + return control_flow_ops.group(train_op, ma_op) + + def swapping_saver(self, var_list=None, name='swapping_saver', **kwargs): + """Create a saver swapping moving averages and variables. + + You should use this saver during training. It will save the moving averages + of the trained parameters under the original parameter names. For + evaluations or inference you should use a regular saver and it will + automatically use the moving averages for the trained variable. + + You must call this function after all variables have been created and after + you have called Optimizer.minimize(). + + Args: + var_list: List of variables to save, as per `Saver()`. + If set to None, will save all the variables that have been + created before this call. + name: The name of the saver. + **kwargs: Keyword arguments of `Saver()`. + + Returns: + A `tf.Saver` object. + + Raises: + RuntimeError: If apply_gradients or minimize has not been called before. + """ + + if self._variable_map is None: + raise RuntimeError('Must call apply_gradients or minimize before ' + 'creating the swapping_saver') + if var_list is None: + var_list = variables.all_variables() + if not isinstance(var_list, dict): + var_list = saver.BaseSaverBuilder.OpListToDict(var_list) + # Now swap variables and moving averages + swapped_var_list = {} + for k, v in six.iteritems(var_list): + v_swap = self._variable_map.get(v.op.name, None) + if v_swap: + swapped_var_list[k] = v_swap + else: + swapped_var_list[k] = v + # Build the swapping saver. + return saver.Saver(swapped_var_list, name=name, **kwargs) diff --git a/tensorflow/contrib/opt/python/training/moving_average_optimizer_test.py b/tensorflow/contrib/opt/python/training/moving_average_optimizer_test.py new file mode 100644 index 0000000000000000000000000000000000000000..5d1e1593743bb7c8c9f4f607307622fc2d5e1ac7 --- /dev/null +++ b/tensorflow/contrib/opt/python/training/moving_average_optimizer_test.py @@ -0,0 +1,88 @@ +# 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. +# ============================================================================== +"""Tests for moving_average_optimizer.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os.path + +import six +import tensorflow as tf + + +class MovingAverageOptimizerTest(tf.test.TestCase): + + def testRun(self): + for dtype in [tf.half, tf.float32, tf.float64]: + with self.test_session() as sess: + orig_val0 = [1.0, 2.0] + orig_val1 = [3.0, 4.0] + var0 = tf.Variable(orig_val0, name='var0', dtype=dtype) + var1 = tf.Variable(orig_val1, name='var1', dtype=dtype) + grads0 = tf.constant([0.1, 0.1], dtype=dtype) + grads1 = tf.constant([0.01, 0.01], dtype=dtype) + + opt = tf.contrib.opt.MovingAverageOptimizer( + tf.train.GradientDescentOptimizer(learning_rate=2.0), + average_decay=0.5) + save_path = os.path.join(self.get_temp_dir(), 'model') + var_list = [var0, var1] + update = opt.apply_gradients( + list(six.moves.zip([grads0, grads1], [var0, var1]))) + train_saver = opt.swapping_saver(var_list) + inference_saver = tf.train.Saver(var_list) + tf.initialize_all_variables().run() + # Fetch params to validate initial values + # Step 1: the momentum accumulators were. So we should see a normal + # update: v -= grad * learning_rate + update.run() + self.assertAllCloseAccordingToType([0.8, 1.8], var0.eval()) + self.assertAllCloseAccordingToType([2.98, 3.98], var1.eval()) + update.run() + # Test that the swapping saver save/restore operation is identity. + self.assertAllCloseAccordingToType([0.6, 1.6], var0.eval()) + self.assertAllCloseAccordingToType([2.96, 3.96], var1.eval()) + train_saver.save(sess, save_path) + train_saver.restore(sess, save_path) + val0 = var0.eval() + val1 = var1.eval() + self.assertAllCloseAccordingToType([0.6, 1.6], val0) + self.assertAllCloseAccordingToType([2.96, 3.96], val1) + # Test that the normal saver will have the averaged variables. + # We test that the average values are between the original value and the + # most recent variable values (since they are an average of the two). + inference_saver.restore(sess, save_path) + avg_val0 = var0.eval() + avg_val1 = var1.eval() + for i in six.moves.range(len(val0)): + self.assertLess(val0[i], avg_val0[i]) + self.assertLess(avg_val0[i], orig_val0[i]) + self.assertLess(val1[i], avg_val1[i]) + self.assertLess(avg_val1[i], orig_val1[i]) + + def testFailWhenSaverCreatedBeforeInitialized(self): + with self.test_session(): + var = tf.Variable([1.0], name='var', dtype=tf.float32) + opt = tf.contrib.opt.MovingAverageOptimizer( + tf.train.GradientDescentOptimizer(learning_rate=2.0)) + # We didn't call apply_gradients yet. + # This will raise an exception. + with self.assertRaises(RuntimeError): + _ = opt.swapping_saver([var]) + + +if __name__ == '__main__': + tf.test.main() diff --git a/tensorflow/contrib/quantization/Makefile.in b/tensorflow/contrib/quantization/Makefile.in index 656f1d00eac27d52caa39c95b82a83e4916e6155..563639e5d752c8ab4419d77f3643a570e400e5f7 100644 --- a/tensorflow/contrib/quantization/Makefile.in +++ b/tensorflow/contrib/quantization/Makefile.in @@ -39,6 +39,7 @@ tensorflow/contrib/quantization/kernels/quantize_op.cc \ tensorflow/contrib/quantization/kernels/quantized_conv_ops.cc \ tensorflow/contrib/quantization/kernels/quantized_matmul_op.cc \ tensorflow/contrib/quantization/kernels/quantized_matmul_op_test.cc \ +tensorflow/contrib/quantization/kernels/hexagon/quantized_matmul_op_for_hexagon_test.cc \ tensorflow/contrib/makefile/test/test_main.cc QUANTIZATION_TEST_OBJS := $(addprefix $(OBJDIR), $(QUANTIZATION_TEST_SRCS:.cc=.o)) diff --git a/tensorflow/contrib/quantization/kernels/hexagon/quantized_matmul_op_for_hexagon_test.cc b/tensorflow/contrib/quantization/kernels/hexagon/quantized_matmul_op_for_hexagon_test.cc index 1fa4ba0163e56749d81ecb74741fcbcd7feaa4c0..9c452fe39c7f0568129b7af8a0da5bd21cd546d7 100644 --- a/tensorflow/contrib/quantization/kernels/hexagon/quantized_matmul_op_for_hexagon_test.cc +++ b/tensorflow/contrib/quantization/kernels/hexagon/quantized_matmul_op_for_hexagon_test.cc @@ -30,7 +30,7 @@ limitations under the License. #include "tensorflow/core/platform/test.h" #ifdef USE_HEXAGON_LIBS -#include "gemm_wrapper.h" +#include "tensorflow/core/platform/hexagon/gemm_wrapper.h" #endif namespace tensorflow { @@ -39,8 +39,10 @@ class QuantizedMatMulOpForHexagonTest : public OpsTestBase { protected: void SetUp() final { #ifdef USE_HEXAGON_LIBS - LOG(INFO) << "Hexagon libs are linked (version = " - << hexagon_gemm_wrapper_GetVersion() << ")"; + LOG(INFO) << "Hexagon libs are linked (wrapper version = " + << hexagon_gemm_wrapper_GetWrapperVersion() + << ", hexagon binary version = " + << hexagon_gemm_wrapper_GetHexagonBinaryVersion() << ")"; #else LOG(WARNING) << "Hexagon libs are not linked."; #endif diff --git a/tensorflow/contrib/quantization/ops/array_ops.cc b/tensorflow/contrib/quantization/ops/array_ops.cc index 7dd64f82e00571950cb0488e01f183e386428ff1..ff636c79578024d7f6c7945e4f099b67c9768eb1 100644 --- a/tensorflow/contrib/quantization/ops/array_ops.cc +++ b/tensorflow/contrib/quantization/ops/array_ops.cc @@ -20,7 +20,7 @@ limitations under the License. namespace tensorflow { using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("QuantizeV2") .Input("input: float") @@ -33,7 +33,7 @@ REGISTER_OP("QuantizeV2") .Attr("mode: {'MIN_COMBINED', 'MIN_FIRST'} = 'MIN_COMBINED'") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -110,7 +110,7 @@ REGISTER_OP("Dequantize") .Attr("mode: {'MIN_COMBINED', 'MIN_FIRST'} = 'MIN_COMBINED'") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); return Status::OK(); @@ -168,7 +168,7 @@ REGISTER_OP("QuantizedConcat") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::ConcatShape(c)); - const Shape* unused; + ShapeHandle unused; for (int i = 2; i < c->num_inputs(); ++i) { TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 0, &unused)); } diff --git a/tensorflow/contrib/quantization/ops/math_ops.cc b/tensorflow/contrib/quantization/ops/math_ops.cc index ed0930c2d6425e352f3484161cce76fb3c1fbc53..93bb28363036f0ffcabdd74783e3d265a827acc5 100644 --- a/tensorflow/contrib/quantization/ops/math_ops.cc +++ b/tensorflow/contrib/quantization/ops/math_ops.cc @@ -21,7 +21,7 @@ limitations under the License. namespace tensorflow { using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("QuantizedMatMul") .Input("a: T1") @@ -40,7 +40,7 @@ REGISTER_OP("QuantizedMatMul") .Attr("transpose_b: bool = false") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::MatMulShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(4), 0, &unused)); @@ -82,7 +82,7 @@ REGISTER_OP("QuantizeDownAndShrinkRange") .Attr("out_type: quantizedtype") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); diff --git a/tensorflow/contrib/quantization/ops/nn_ops.cc b/tensorflow/contrib/quantization/ops/nn_ops.cc index c33f318c6e7ac229c3ed7410eb51d688c0e2106a..720377043ded97c56986651e6e4872ae2ebf8edf 100644 --- a/tensorflow/contrib/quantization/ops/nn_ops.cc +++ b/tensorflow/contrib/quantization/ops/nn_ops.cc @@ -21,9 +21,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("QuantizedAvgPool") .Input("input: T") @@ -38,7 +38,7 @@ REGISTER_OP("QuantizedAvgPool") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::AvgPoolShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -76,7 +76,7 @@ REGISTER_OP("QuantizedBiasAdd") .Attr("out_type: quantizedtype") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::BiasAddShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(4), 0, &unused)); @@ -117,7 +117,7 @@ REGISTER_OP("QuantizedConv2D") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::Conv2DShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(4), 0, &unused)); @@ -159,7 +159,7 @@ REGISTER_OP("QuantizedMaxPool") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::MaxPoolShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -193,7 +193,7 @@ REGISTER_OP("QuantizedRelu") .Attr("out_type: quantizedtype = DT_QUINT8") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -222,7 +222,7 @@ REGISTER_OP("QuantizedRelu6") .Attr("out_type: quantizedtype = DT_QUINT8") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -252,7 +252,7 @@ REGISTER_OP("QuantizedReluX") .Attr("out_type: quantizedtype = DT_QUINT8") .SetShapeFn([](InferenceContext* c) { TF_RETURN_IF_ERROR(shape_inference::UnchangedShape(c)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(1, c->Scalar()); @@ -294,17 +294,17 @@ REGISTER_OP("QuantizedBatchNormWithGlobalNormalization") .Attr("variance_epsilon: float") .Attr("scale_after_normalization: bool") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Dimension* last_dim = c->Dim(input, 3); + DimensionHandle last_dim = c->Dim(input, 3); for (int i = 1; i < 5; ++i) { // covers m, v, beta, gamma - const Shape* vec; + ShapeHandle vec; TF_RETURN_IF_ERROR(c->WithRank(c->input(i * 3), 1, &vec)); TF_RETURN_IF_ERROR(c->Merge(last_dim, c->Dim(vec, 0), &last_dim)); } - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->ReplaceDim(input, 3, last_dim, &out)); c->set_output(0, out); c->set_output(1, c->Scalar()); diff --git a/tensorflow/contrib/quantization/tools/quantize_graph.py b/tensorflow/contrib/quantization/tools/quantize_graph.py index 60cbca98347a90b52b525e3243f8d462887542ff..0a814dadaefece37f8f0498e5c72c4f5bfd2b5c4 100644 --- a/tensorflow/contrib/quantization/tools/quantize_graph.py +++ b/tensorflow/contrib/quantization/tools/quantize_graph.py @@ -66,12 +66,12 @@ flags.DEFINE_boolean("load_quantization_so", True, def print_input_nodes(current_node, nodes_map, indent, already_visited): print(" " * indent + current_node.op + ":" + current_node.name) + already_visited[current_node.name] = True for input_node_name in current_node.input: if input_node_name in already_visited: continue input_node = nodes_map[input_node_name] print_input_nodes(input_node, nodes_map, indent + 1, already_visited) - already_visited[current_node.name] = True def create_node(op, name, inputs): @@ -350,13 +350,13 @@ class GraphRewriter(object): def round_nodes_recursively(self, current_node): """The entry point for simple rounding quantization.""" + self.already_visited[current_node.name] = True for input_node_name in current_node.input: input_node_name = node_name_from_input(input_node_name) if input_node_name in self.already_visited: continue input_node = self.nodes_map[input_node_name] self.round_nodes_recursively(input_node) - self.already_visited[current_node.name] = True nodes_to_quantize = ["Conv2D", "BiasAdd", "MatMul"] if any(current_node.op in s for s in nodes_to_quantize): new_node = tf.NodeDef() @@ -381,13 +381,13 @@ class GraphRewriter(object): def quantize_nodes_recursively(self, current_node): """The entry point for quantizing nodes to eight bit and back.""" + self.already_visited[current_node.name] = True for input_node_name in current_node.input: input_node_name = node_name_from_input(input_node_name) if input_node_name in self.already_visited: continue input_node = self.nodes_map[input_node_name] self.quantize_nodes_recursively(input_node) - self.already_visited[current_node.name] = True nodes_to_quantize = ["Conv2D", "BiasAdd", "MatMul"] if any(current_node.op in s for s in nodes_to_quantize): for input_name in current_node.input: @@ -448,13 +448,13 @@ class GraphRewriter(object): def eightbitize_nodes_recursively(self, current_node): """The entry point for transforming a graph into full eight bit.""" + self.already_visited[current_node.name] = True for input_node_name in current_node.input: input_node_name = node_name_from_input(input_node_name) if input_node_name in self.already_visited: continue input_node = self.nodes_map[input_node_name] self.eightbitize_nodes_recursively(input_node) - self.already_visited[current_node.name] = True if current_node.op == "MatMul": self.eightbitize_mat_mul_node(current_node) elif current_node.op == "Conv2D": diff --git a/tensorflow/contrib/rnn/BUILD b/tensorflow/contrib/rnn/BUILD index f69c656c68b5545abba968645253881e07a4bf1a..92489033c85bf2287cf016d68a3319b6d28abc52 100644 --- a/tensorflow/contrib/rnn/BUILD +++ b/tensorflow/contrib/rnn/BUILD @@ -6,7 +6,7 @@ licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) -package(default_visibility = ["//tensorflow:__subpackages__"]) +package(default_visibility = ["//visibility:public"]) load("//tensorflow:tensorflow.bzl", "cuda_py_tests") load("//tensorflow:tensorflow.bzl", "tf_custom_op_library") @@ -15,6 +15,7 @@ py_library( name = "rnn_py", srcs = ["__init__.py"] + glob(["python/ops/*.py"]), data = [ + ":python/ops/_gru_ops.so", ":python/ops/_lstm_ops.so", ], srcs_version = "PY2AND3", @@ -59,6 +60,33 @@ tf_custom_op_library( ], ) +tf_custom_op_library( + name = "python/ops/_gru_ops.so", + srcs = [ + "kernels/gru_ops.cc", + "kernels/gru_ops.h", + "ops/gru_ops.cc", + ], + gpu_srcs = [ + "kernels/gru_ops_gpu.cu.cc", + "kernels/gru_ops.h", + ], + deps = [ + "//tensorflow/core/kernels:eigen_helpers", + ], +) + +cuda_py_tests( + name = "gru_ops_test", + size = "small", + srcs = ["python/kernel_tests/gru_ops_test.py"], + additional_deps = [ + ":rnn_py", + "//tensorflow/python:framework_test_lib", + "//tensorflow/python:platform_test", + ], +) + filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/contrib/rnn/__init__.py b/tensorflow/contrib/rnn/__init__.py index 9622b46ff5f8a0099160ac77a7507b1112886aa7..627310957afc495ea37c8a5ef66e0901b0bdec7f 100644 --- a/tensorflow/contrib/rnn/__init__.py +++ b/tensorflow/contrib/rnn/__init__.py @@ -18,6 +18,7 @@ ### Fused RNNCells @@LSTMBlockCell +@@GRUBlockCell ### LSTM-like cells @@CoupledInputForgetGateLSTMCell @@ -33,5 +34,6 @@ from __future__ import division from __future__ import print_function # pylint: disable=unused-import,wildcard-import, line-too-long +from tensorflow.contrib.rnn.python.ops.gru_ops import * from tensorflow.contrib.rnn.python.ops.lstm_ops import * from tensorflow.contrib.rnn.python.ops.rnn_cell import * diff --git a/tensorflow/contrib/rnn/kernels/gru_ops.cc b/tensorflow/contrib/rnn/kernels/gru_ops.cc new file mode 100644 index 0000000000000000000000000000000000000000..89a48171112dd285ebf6c5df9cac039f0640f5da --- /dev/null +++ b/tensorflow/contrib/rnn/kernels/gru_ops.cc @@ -0,0 +1,508 @@ +/* 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. +==============================================================================*/ + +#define EIGEN_USE_THREADS + +#if GOOGLE_CUDA +#include "tensorflow/core/platform/stream_executor.h" +#endif // GOOGLE_CUDA + +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/contrib/rnn/kernels/gru_ops.h" +#include "tensorflow/core/framework/op_kernel.h" + +namespace tensorflow { + +typedef Eigen::ThreadPoolDevice CPUDevice; +typedef Eigen::GpuDevice GPUDevice; + +#if GOOGLE_CUDA +namespace { +template +perftools::gputools::DeviceMemory AsDeviceMemory(const T* cuda_memory) { + perftools::gputools::DeviceMemoryBase wrapped(const_cast(cuda_memory)); + perftools::gputools::DeviceMemory typed(wrapped); + return typed; +} +} // namespace +#endif // GOOGLE_CUDA + +namespace functor { +template +// TODO(gitegaurav) : Refactor the matmul operation inside the kernel. Make +// similar changes in the LSTMBlockCell. Create a new file which contains matmul +// functionality. It should perform matmul operation using CuBlas when the Cuda +// support is present otherwise using eigentensors. +void TensorCuBlasGemm::operator()(OpKernelContext* ctx, + perftools::gputools::Stream* stream, + bool transa, bool transb, uint64 m, + uint64 n, uint64 k, T alpha, const T* a, + int lda, const T* b, int ldb, T beta, T* c, + int ldc) { +#if GOOGLE_CUDA + perftools::gputools::blas::Transpose trans[] = { + perftools::gputools::blas::Transpose::kNoTranspose, + perftools::gputools::blas::Transpose::kTranspose}; + + auto a_ptr = AsDeviceMemory(a); + auto b_ptr = AsDeviceMemory(b); + auto c_ptr = AsDeviceMemory(c); + + bool blas_launch_status = + stream + ->ThenBlasGemm(trans[transa], trans[transb], m, n, k, alpha, a_ptr, + lda, b_ptr, ldb, beta, &c_ptr, ldc) + .ok(); + OP_REQUIRES(ctx, blas_launch_status, errors::Aborted("CuBlasGemm failed!")); +#else + ctx->SetStatus(errors::InvalidArgument("CuBlasGemm needs CUDA.")); +#endif +} + +template struct TensorCuBlasGemm; +} // end namespace functor + +template +class GRUCellBlockOp : public OpKernel { + public: + explicit GRUCellBlockOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} + // TODO(gitegaurav) Replace the input checks with some smarter function. + void Compute(OpKernelContext* ctx) override { + // Grab the input tensors. + const Tensor* x_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("x", &x_tensor)); + + const Tensor* h_prev_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("h_prev", &h_prev_tensor)); + + const Tensor* w_ru_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("w_ru", &w_ru_tensor)); + + const Tensor* w_c_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("w_c", &w_c_tensor)); + + const Tensor* b_ru_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("b_ru", &b_ru_tensor)); + + const Tensor* b_c_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("b_c", &b_c_tensor)); + + const int64 batch_size = x_tensor->dim_size(0); + const int64 input_size = x_tensor->dim_size(1); + const int64 cell_size = h_prev_tensor->dim_size(1); + + // Sanity checks for input shapes. + + // Shape of 'h' must be [batch_size, cell_size] + OP_REQUIRES(ctx, h_prev_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("h_prev.dims(0) != batch_size: ", + h_prev_tensor->dim_size(0), " vs. ", + batch_size)); + OP_REQUIRES(ctx, h_prev_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("h_prev.dims(1) != cell_size: ", + h_prev_tensor->dim_size(1), " vs. ", + cell_size)); + + // Shape of 'w_ru' must be [input_size+cell_size, 2*cell_size] + OP_REQUIRES(ctx, w_ru_tensor->dim_size(0) == input_size + cell_size, + errors::InvalidArgument( + "w_ru.dim_size(0) != input_size + cell_size: ", + w_ru_tensor->dim_size(0), " vs. ", input_size + cell_size)); + + OP_REQUIRES(ctx, w_ru_tensor->dim_size(1) == cell_size * 2, + errors::InvalidArgument("w_ru.dim_size(1) != cell_size * 2: ", + w_ru_tensor->dim_size(1), " vs. ", + cell_size * 2)); + + // Shape of 'w_c' must be [input_size+cell_size, cell_size] + OP_REQUIRES(ctx, w_c_tensor->dim_size(0) == input_size + cell_size, + errors::InvalidArgument( + "w_c.dim_size(0) != input_size + cell_size: ", + w_c_tensor->dim_size(0), " vs. ", input_size + cell_size)); + + OP_REQUIRES( + ctx, w_c_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("w_c.dim_size(1) != cell_size: ", + w_c_tensor->dim_size(1), " vs. ", cell_size)); + + // Shape of 'b_ru' must be [2*cell_size] + OP_REQUIRES(ctx, b_ru_tensor->dim_size(0) == cell_size * 2, + errors::InvalidArgument("b_ru.dim_size(0) != cell_size * 2: ", + b_ru_tensor->dim_size(0), " vs. ", + cell_size * 2)); + + OP_REQUIRES(ctx, b_ru_tensor->dims() == 1, + errors::InvalidArgument("Rank of b_ru must be 1", + b_ru_tensor->dims(), " vs. 1", 1)); + // Shape of 'b_c' must be [cell_size] + OP_REQUIRES( + ctx, b_c_tensor->dim_size(0) == cell_size, + errors::InvalidArgument("b_c.dim_size(0) != cell_size: ", + b_c_tensor->dim_size(0), " vs. ", cell_size)); + OP_REQUIRES(ctx, b_c_tensor->dims() == 1, + errors::InvalidArgument("Rank of b_c must be 1", + b_c_tensor->dims(), " vs. 1")); + + // Create output tensors. + Tensor* r_tensor = nullptr; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("r", TensorShape({batch_size, cell_size}), + &r_tensor)); + + Tensor* u_tensor = nullptr; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("u", TensorShape({batch_size, cell_size}), + &u_tensor)); + + Tensor* c_tensor = nullptr; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("c", TensorShape({batch_size, cell_size}), + &c_tensor)); + + Tensor* h_tensor = nullptr; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("h", TensorShape({batch_size, cell_size}), + &h_tensor)); + + // Allocate temp tensors. + Tensor x_h_prev_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_temp( + DataTypeToEnum::v(), + TensorShape({batch_size, input_size + cell_size}), + &x_h_prev_tensor)); + + Tensor x_h_prevr_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_temp( + DataTypeToEnum::v(), + TensorShape({batch_size, input_size + cell_size}), + &x_h_prevr_tensor)); + + Tensor r_u_bar_tensor; + OP_REQUIRES_OK(ctx, + ctx->allocate_temp(DataTypeToEnum::v(), + TensorShape({batch_size, 2 * cell_size}), + &r_u_bar_tensor)); + + const Device& device = ctx->eigen_device(); + + perftools::gputools::Stream* stream = + std::is_same::value + ? ctx->op_device_context()->stream() + : nullptr; + + functor::GRUBlockCellFprop(batch_size, input_size, + cell_size)( + ctx, stream, device, x_tensor->matrix(), h_prev_tensor->matrix(), + w_ru_tensor->matrix(), w_c_tensor->matrix(), + b_ru_tensor->vec(), b_c_tensor->vec(), r_u_bar_tensor.matrix(), + r_tensor->matrix(), u_tensor->matrix(), c_tensor->matrix(), + h_tensor->matrix(), x_h_prev_tensor.matrix(), + x_h_prevr_tensor.matrix()); + } +}; + +// Register the Block GRU cell kernel for CPU. +#define REGISTER_KERNEL(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("GRUBlockCell").Device(DEVICE_CPU).TypeConstraint("T"), \ + GRUCellBlockOp); + +REGISTER_KERNEL(float); +#undef REGISTER_KERNEL + +template +class GRUBlockCellGradOp : public OpKernel { + public: + explicit GRUBlockCellGradOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} + + void Compute(OpKernelContext* ctx) override { + // Grab the input tensors. + const Tensor* x_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("x", &x_tensor)); + + const Tensor* h_prev_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("h_prev", &h_prev_tensor)); + + const Tensor* w_ru_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("w_ru", &w_ru_tensor)); + + const Tensor* w_c_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("w_c", &w_c_tensor)); + + const Tensor* b_ru_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("b_ru", &b_ru_tensor)); + + const Tensor* b_c_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("b_c", &b_c_tensor)); + + const Tensor* r_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("r", &r_tensor)); + + const Tensor* u_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("u", &u_tensor)); + + const Tensor* c_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("c", &c_tensor)); + + const Tensor* d_h_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->input("d_h", &d_h_tensor)); + + const int64 batch_size = x_tensor->dim_size(0); + const int64 input_size = x_tensor->dim_size(1); + const int64 cell_size = h_prev_tensor->dim_size(1); + + // Sanity checks for input shapes. + + // Shape of 'h_prev' must be [batch_size, cell_size] + OP_REQUIRES(ctx, h_prev_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("h_prev.dims(0) != batch_size: ", + h_prev_tensor->dim_size(0), " vs. ", + batch_size)); + OP_REQUIRES(ctx, h_prev_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("h_prev.dims(1) != cell_size: ", + h_prev_tensor->dim_size(1), " vs. ", + cell_size)); + + // Shape of 'w_ru' must be [input_size+cell_size, 2*cell_size] + OP_REQUIRES(ctx, w_ru_tensor->dim_size(0) == input_size + cell_size, + errors::InvalidArgument( + "w_ru.dim_size(0) != input_size + cell_size: ", + w_ru_tensor->dim_size(0), " vs. ", input_size + cell_size)); + + OP_REQUIRES(ctx, w_ru_tensor->dim_size(1) == cell_size * 2, + errors::InvalidArgument("w_ru.dim_size(1) != cell_size * 2: ", + w_ru_tensor->dim_size(1), " vs. ", + cell_size * 2)); + + // Shape of 'w_c' must be [input_size+cell_size, cell_size] + OP_REQUIRES(ctx, w_c_tensor->dim_size(0) == input_size + cell_size, + errors::InvalidArgument( + "w_c.dim_size(0) != input_size + cell_size: ", + w_c_tensor->dim_size(0), " vs. ", input_size + cell_size)); + + OP_REQUIRES( + ctx, w_c_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("w_c.dim_size(1) != cell_size: ", + w_c_tensor->dim_size(1), " vs. ", cell_size)); + + // Shape of 'b_ru' must be [2*cell_size] + OP_REQUIRES(ctx, b_ru_tensor->dim_size(0) == cell_size * 2, + errors::InvalidArgument("b_ru.dim_size(0) != cell_size * 2: ", + b_ru_tensor->dim_size(0), " vs. ", + cell_size * 2)); + + OP_REQUIRES(ctx, b_ru_tensor->dims() == 1, + errors::InvalidArgument("Rank of b_ru must be 1", + b_ru_tensor->dims(), " vs. 1")); + + // Shape of 'b_c' must be [cell_size] + OP_REQUIRES( + ctx, b_c_tensor->dim_size(0) == cell_size, + errors::InvalidArgument("b_c.dim_size(0) != cell_size: ", + b_c_tensor->dim_size(0), " vs. ", cell_size)); + + OP_REQUIRES(ctx, b_c_tensor->dims() == 1, + errors::InvalidArgument("Rank of b_c must be 1 ", + b_c_tensor->dims(), " vs. 1")); + + // Shape of 'r' must be [batch_size, cell_size] + OP_REQUIRES( + ctx, r_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("r.dims(0) != batch_size: ", + r_tensor->dim_size(0), " vs. ", batch_size)); + OP_REQUIRES( + ctx, r_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("r.dims(1) != cell_size: ", + r_tensor->dim_size(1), " vs. ", cell_size)); + + // Shape of 'u' must be [batch_size, cell_size] + OP_REQUIRES( + ctx, u_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("u.dims(0) != batch_size: ", + u_tensor->dim_size(0), " vs. ", batch_size)); + OP_REQUIRES( + ctx, u_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("u.dims(1) != cell_size: ", + u_tensor->dim_size(1), " vs. ", cell_size)); + + // Shape of 'c' must be [batch_size, cell_size] + OP_REQUIRES( + ctx, c_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("c.dims(0) != batch_size: ", + c_tensor->dim_size(0), " vs. ", batch_size)); + OP_REQUIRES( + ctx, c_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("c.dims(1) != cell_size: ", + c_tensor->dim_size(1), " vs. ", cell_size)); + + // Shape of 'd_h' must be [batch_size, cell_size] + OP_REQUIRES( + ctx, d_h_tensor->dim_size(0) == batch_size, + errors::InvalidArgument("d_h.dims(0) != batch_size: ", + d_h_tensor->dim_size(0), " vs. ", batch_size)); + OP_REQUIRES( + ctx, d_h_tensor->dim_size(1) == cell_size, + errors::InvalidArgument("d_h.dims(1) != cell_size: ", + d_h_tensor->dim_size(1), " vs. ", cell_size)); + + // Create output tensors. + Tensor* d_x_tensor = nullptr; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("d_x", TensorShape({batch_size, input_size}), + &d_x_tensor)); + + Tensor* d_h_prev_tensor = nullptr; + OP_REQUIRES_OK(ctx, ctx->allocate_output( + "d_h_prev", TensorShape({batch_size, cell_size}), + &d_h_prev_tensor)); + + Tensor* d_c_bar_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_output( + "d_c_bar", TensorShape({batch_size, cell_size}), + &d_c_bar_tensor)); + + Tensor* d_r_bar_u_bar_tensor; + OP_REQUIRES_OK( + ctx, ctx->allocate_output("d_r_bar_u_bar", + TensorShape({batch_size, 2 * cell_size}), + &d_r_bar_u_bar_tensor)); + + // Allocate temp tensors. + Tensor d_r_bar_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum::v(), + TensorShape({batch_size, cell_size}), + &d_r_bar_tensor)); + + Tensor d_u_bar_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum::v(), + TensorShape({batch_size, cell_size}), + &d_u_bar_tensor)); + + Tensor d_h_prevr_tensor; + OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum::v(), + TensorShape({batch_size, cell_size}), + &d_h_prevr_tensor)); + + Tensor d_x_component_1_h_prev_compenent_1; + OP_REQUIRES_OK(ctx, ctx->allocate_temp( + DataTypeToEnum::v(), + TensorShape({batch_size, input_size + cell_size}), + &d_x_component_1_h_prev_compenent_1)); + + Tensor d_x_component_2_h_prevr; + OP_REQUIRES_OK(ctx, ctx->allocate_temp( + DataTypeToEnum::v(), + TensorShape({batch_size, input_size + cell_size}), + &d_x_component_2_h_prevr)); + + const Device& device = ctx->eigen_device(); + perftools::gputools::Stream* stream = + std::is_same::value + ? ctx->op_device_context()->stream() + : nullptr; + + functor::GRUBlockCellBprop(batch_size, input_size, + cell_size)( + ctx, stream, device, x_tensor->matrix(), h_prev_tensor->matrix(), + w_ru_tensor->matrix(), w_c_tensor->matrix(), + b_ru_tensor->vec(), b_c_tensor->vec(), r_tensor->matrix(), + u_tensor->matrix(), c_tensor->matrix(), d_h_tensor->matrix(), + d_x_tensor->matrix(), d_h_prev_tensor->matrix(), + d_c_bar_tensor->matrix(), d_r_bar_u_bar_tensor->matrix(), + d_r_bar_tensor.matrix(), d_u_bar_tensor.matrix(), + d_h_prevr_tensor.matrix(), + d_x_component_1_h_prev_compenent_1.matrix(), + d_x_component_2_h_prevr.matrix()); + } +}; + +// Register the gradient kernel for CPU. +#define REGISTER_KERNEL(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("GRUBlockCellGrad").Device(DEVICE_CPU).TypeConstraint("T"), \ + GRUBlockCellGradOp); + +REGISTER_KERNEL(float); +#undef REGISTER_KERNEL + +// GPU support. +#if GOOGLE_CUDA +#define EIGEN_USE_GPU + +// Forward declare the GPU Fprop functor. +namespace functor { +#define DECLARE_GPU_SPEC(T) \ + template <> \ + void GRUBlockCellFprop::operator()( \ + OpKernelContext* ctx, perftools::gputools::Stream* stream, \ + const GPUDevice& d, typename TTypes::ConstMatrix x, \ + typename TTypes::ConstMatrix h_prev, \ + typename TTypes::ConstMatrix w_ru, \ + typename TTypes::ConstMatrix w_c, typename TTypes::ConstVec b_ru, \ + typename TTypes::ConstVec b_c, typename TTypes::Matrix r_u_bar, \ + typename TTypes::Matrix r, typename TTypes::Matrix u, \ + typename TTypes::Matrix c, typename TTypes::Matrix h, \ + typename TTypes::Matrix x_h_prev, \ + typename TTypes::Matrix x_h_prevr); \ + extern template struct GRUBlockCellFprop; + +DECLARE_GPU_SPEC(float); +#undef DECLARE_GPU_SPEC +} // end namespace functor + +// Register the Block GRU cell kernel for GPU. +#define REGISTER_GPU_KERNEL(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("GRUBlockCell").Device(DEVICE_GPU).TypeConstraint("T"), \ + GRUCellBlockOp); + +REGISTER_GPU_KERNEL(float); +#undef REGISTER_GPU_KERNEL + +// Forward declare the GPU Bprop functor. +namespace functor { +#define DECLARE_GPU_SPEC(T) \ + template <> \ + void GRUBlockCellBprop::operator()( \ + OpKernelContext* ctx, perftools::gputools::Stream* stream, \ + const GPUDevice& d, typename TTypes::ConstMatrix x, \ + typename TTypes::ConstMatrix h, typename TTypes::ConstMatrix w_ru, \ + typename TTypes::ConstMatrix w_c, typename TTypes::ConstVec b_ru, \ + typename TTypes::ConstVec b_c, typename TTypes::ConstMatrix r, \ + typename TTypes::ConstMatrix u, typename TTypes::ConstMatrix c, \ + typename TTypes::ConstMatrix d_h, typename TTypes::Matrix d_x, \ + typename TTypes::Matrix d_h_prev, typename TTypes::Matrix d_c_bar, \ + typename TTypes::Matrix d_r_bar_u_bar, \ + typename TTypes::Matrix d_r_bar, typename TTypes::Matrix d_u_bar, \ + typename TTypes::Matrix d_h_prevr, \ + typename TTypes::Matrix d_x_comp1_h_prev_comp1, \ + typename TTypes::Matrix d_x_comp2_and_h_prevr); \ + extern template struct GRUBlockCellBprop; + +DECLARE_GPU_SPEC(float); +#undef DECLARE_GPU_SPEC +} // end namespace functor + +// Register the gradient kernel for GPU. +#define REGISTER_GPU_KERNEL(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("GRUBlockCellGrad").Device(DEVICE_GPU).TypeConstraint("T"), \ + GRUBlockCellGradOp); + +REGISTER_GPU_KERNEL(float); +#undef REGISTER_GPU_KERNEL +#endif // GOOGLE_CUDA + +} // end namespace tensorflow diff --git a/tensorflow/contrib/rnn/kernels/gru_ops.h b/tensorflow/contrib/rnn/kernels/gru_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..b2ff859b8efd1ca6b7df3355e68b029dd4752bca --- /dev/null +++ b/tensorflow/contrib/rnn/kernels/gru_ops.h @@ -0,0 +1,243 @@ +/* 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. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ +#define THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ + +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/core/framework/tensor_types.h" +#include "tensorflow/core/platform/types.h" + +namespace perftools { +namespace gputools { +class Stream; +} // end namespace gputools +} // end namespace perftools + +namespace tensorflow { + +class OpKernelContext; + +namespace functor { + +template +struct TensorCuBlasGemm { + void operator()(OpKernelContext* ctx, perftools::gputools::Stream* stream, + bool transa, bool transb, uint64 m, uint64 n, uint64 k, + T alpha, const T* a, int lda, const T* b, int ldb, T beta, + T* c, int ldc); +}; + +template +struct TensorBlasGemm; + +template +struct TensorBlasGemm { + static void compute(OpKernelContext* ctx, perftools::gputools::Stream* stream, + const Device& d, bool transa, bool transb, T alpha, + typename TTypes::ConstMatrix a, + typename TTypes::ConstMatrix b, T beta, + typename TTypes::Matrix c) { + int64 m = c.dimensions()[0]; + int64 n = c.dimensions()[1]; + int64 k = transa ? a.dimensions()[0] : a.dimensions()[1]; + + TensorCuBlasGemm()(ctx, stream, transb, transa, n, m, k, alpha, b.data(), + transb ? k : n, a.data(), transa ? m : k, beta, + c.data(), n); + } +}; + +template +struct TensorBlasGemm { + static void compute(OpKernelContext* ctx, perftools::gputools::Stream* stream, + const Device& d, bool transa, bool transb, T alpha, + typename TTypes::ConstMatrix a, + typename TTypes::ConstMatrix b, T beta, + typename TTypes::Matrix c) { + Eigen::array, 1> contract_pairs; + contract_pairs[0] = + Eigen::IndexPair(transa == false, transb == true); + if (alpha == T(1) && beta == T(0)) { + c.device(d) = a.contract(b, contract_pairs); + } else if (alpha == T(1) && beta == T(1)) { + c.device(d) += a.contract(b, contract_pairs); + } else { + c.device(d) = c.constant(alpha) * a.contract(b, contract_pairs) + + c.constant(beta) * c; + } + } +}; + +struct GRUCell { + GRUCell(const int batch_size, const int input_size, const int cell_size) + : batch_size_(batch_size), + input_size_(input_size), + cell_size_(cell_size) {} + + inline Eigen::array x_offsets() const { return {0, 0}; } + + inline Eigen::array x_extends() const { + return {batch_size_, input_size_}; + } + + inline Eigen::array h_offsets() const { + return {0, input_size_}; + } + + inline Eigen::array h_extends() const { + return {batch_size_, cell_size_}; + } + + inline Eigen::array ru_r_offset() const { + return {0, 0}; + } + + inline Eigen::array ru_u_offset() const { + return {0, cell_size_}; + } + + inline Eigen::array cell_extents() const { + return {batch_size_, cell_size_}; + } + + protected: + const int batch_size_; + const int input_size_; + const int cell_size_; +}; + +template +struct GRUBlockCellFprop : public GRUCell { + GRUBlockCellFprop(const int batch_size, const int input_size, + const int cell_size) + : GRUCell(batch_size, input_size, cell_size) {} + + void operator()(OpKernelContext* ctx, perftools::gputools::Stream* stream, + const Device& d, typename TTypes::ConstMatrix x, + typename TTypes::ConstMatrix h_prev, + typename TTypes::ConstMatrix w_ru, + typename TTypes::ConstMatrix w_c, + typename TTypes::ConstVec b_ru, + typename TTypes::ConstVec b_c, + typename TTypes::Matrix r_u_bar, + typename TTypes::Matrix r, typename TTypes::Matrix u, + typename TTypes::Matrix c, typename TTypes::Matrix h, + typename TTypes::Matrix x_h_prev, + typename TTypes::Matrix x_h_prevr) { + // Concat x_h_prev = [x, h_prev]. + x_h_prev.slice(x_offsets(), x_extends()).device(d) = x; + x_h_prev.slice(h_offsets(), h_extends()).device(d) = h_prev; + + // r_u_bar = x_h_prev * w_ru + b_ru + typename TTypes::ConstMatrix const_x_h_prev(x_h_prev.data(), + x_h_prev.dimensions()); + TensorBlasGemm::compute(ctx, stream, d, false, false, + T(1), const_x_h_prev, w_ru, + T(0), r_u_bar); + + // Creating a bias matrix for adding by broadcasting 'b_ru' + Eigen::array broadcast_shape({batch_size_, 1}); + Eigen::array b_ru_shape({1, b_ru.dimensions()[0]}); + r_u_bar.device(d) += b_ru.reshape(b_ru_shape).broadcast(broadcast_shape); + + // Slice r_u_bar into r, u and apply the sigmoid. + r.device(d) = (r_u_bar.slice(ru_r_offset(), cell_extents())).sigmoid(); + u.device(d) = (r_u_bar.slice(ru_u_offset(), cell_extents())).sigmoid(); + + // Concat x_h_prevr = [x,h_prev*r] + x_h_prevr.slice(x_offsets(), x_extends()).device(d) = x; + x_h_prevr.slice(h_offsets(), h_extends()).device(d) = h_prev * r; + + // c = tanh(x_h_prevr*w_c+b_c), Note b_c is broadcasted before adding. + typename TTypes::ConstMatrix const_x_h_prevr(x_h_prevr.data(), + x_h_prevr.dimensions()); + TensorBlasGemm::compute( + ctx, stream, d, false, false, T(1), const_x_h_prevr, w_c, T(0), c); + + Eigen::array b_c_shape({1, b_c.dimensions()[0]}); + c.device(d) += (b_c.reshape(b_c_shape).broadcast(broadcast_shape)); + c.device(d) = c.tanh(); + + // h= u*h_prev + (1-u)*c + h.device(d) = u * (h_prev - c) + c; + } +}; + +template +struct GRUBlockCellBprop : public GRUCell { + GRUBlockCellBprop(const int batch_size, const int input_size, + const int cell_size) + : GRUCell(batch_size, input_size, cell_size) {} + + void operator()( + OpKernelContext* ctx, perftools::gputools::Stream* stream, + const Device& d, typename TTypes::ConstMatrix x, + typename TTypes::ConstMatrix h_prev, + typename TTypes::ConstMatrix w_ru, typename TTypes::ConstMatrix w_c, + typename TTypes::ConstVec b_ru, typename TTypes::ConstVec b_c, + typename TTypes::ConstMatrix r, typename TTypes::ConstMatrix u, + typename TTypes::ConstMatrix c, typename TTypes::ConstMatrix d_h, + typename TTypes::Matrix d_x, typename TTypes::Matrix d_h_prev, + typename TTypes::Matrix d_c_bar, + typename TTypes::Matrix d_r_bar_u_bar, + typename TTypes::Matrix d_r_bar, typename TTypes::Matrix d_u_bar, + typename TTypes::Matrix d_hr, + typename TTypes::Matrix d_x_comp1_and_h_prev_comp1, + typename TTypes::Matrix d_x_comp2_and_h_prevr) { + // d_c_bar = d_h*(1-u)*(1-(c*c)) + d_c_bar.device(d) = + ((d_h * (u.constant(T(1)) - u)) * (c.constant(T(1)) - c * c)); + + // d_u_bar = d_h*(h-c)*(u*(1-u)) + d_u_bar.device(d) = d_h * (h_prev - c) * u * (u.constant(T(1)) - u); + + // [2nd_component_of_d_x d_h_prevr] = d_c_bar X w_c^T + typename TTypes::ConstMatrix const_d_c_bar(d_c_bar.data(), + d_c_bar.dimensions()); + TensorBlasGemm::compute(ctx, stream, d, false, true, + T(1), const_d_c_bar, w_c, + T(0), d_x_comp2_and_h_prevr); + + d_hr.device(d) = d_x_comp2_and_h_prevr.slice(h_offsets(), h_extends()); + d_r_bar.device(d) = (d_hr * h_prev * r) * (r.constant(T(1)) - r); + + // d_r_bar_u_bar = concatenate(d_r_bar, d_u_bar) along axis = 1. + d_r_bar_u_bar.slice(ru_r_offset(), cell_extents()).device(d) = d_r_bar; + d_r_bar_u_bar.slice(ru_u_offset(), cell_extents()).device(d) = d_u_bar; + + // [1st_component_of_d_x 1st_component_of_d_h_prev] = [d_r_bar d_u_bar] X + // w_ru^T + typename TTypes::ConstMatrix const_d_r_bar_u_bar( + d_r_bar_u_bar.data(), d_r_bar_u_bar.dimensions()); + TensorBlasGemm::compute( + ctx, stream, d, false, true, T(1), const_d_r_bar_u_bar, w_ru, T(0), + d_x_comp1_and_h_prev_comp1); + + // d_x = d_x_comp1 + d_x_comp2 + d_x.device(d) = (d_x_comp1_and_h_prev_comp1 + d_x_comp2_and_h_prevr) + .slice(x_offsets(), x_extends()); + + // d_h_prev = d_h_comp1 + d_hr*r + d_h*u + d_h_prev.device(d) = + d_x_comp1_and_h_prev_comp1.slice(h_offsets(), h_extends()) + + (d_hr * r) + (d_h * u); + } +}; + +} // namespace functor +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_RNN_KERNELS_GRU_OPS_H_ diff --git a/tensorflow/contrib/rnn/kernels/gru_ops_gpu.cu.cc b/tensorflow/contrib/rnn/kernels/gru_ops_gpu.cu.cc new file mode 100644 index 0000000000000000000000000000000000000000..846c7f49e3633b28466ba3fa4cdda9c9964988ed --- /dev/null +++ b/tensorflow/contrib/rnn/kernels/gru_ops_gpu.cu.cc @@ -0,0 +1,35 @@ +/* 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU +#include "tensorflow/contrib/rnn/kernels/gru_ops.h" + +namespace tensorflow { +namespace functor { + +typedef Eigen::GpuDevice GPUDevice; + +#define DEFINE_GPU_SPECS(T) \ + template struct GRUBlockCellFprop; \ + template struct GRUBlockCellBprop; + +DEFINE_GPU_SPECS(float); +#undef DEFINE_GPU_SPECS + +} // end namespace functor +} // end namespace tensorflow +#endif // GOOGLE_CUDA diff --git a/tensorflow/contrib/rnn/ops/gru_ops.cc b/tensorflow/contrib/rnn/ops/gru_ops.cc new file mode 100644 index 0000000000000000000000000000000000000000..5accb4fb355a3b686f77c2c367236412477c1759 --- /dev/null +++ b/tensorflow/contrib/rnn/ops/gru_ops.cc @@ -0,0 +1,178 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/framework/op.h" + +REGISTER_OP("GRUBlockCell") + .Attr("T: {float}") + .Input("x: T") + .Input("h_prev: T") + .Input("w_ru: T") + .Input("w_c: T") + .Input("b_ru: T") + .Input("b_c: T") + .Output("r: T") + .Output("u: T") + .Output("c: T") + .Output("h: T") + .Doc(R"doc( +Computes the GRU cell forward propagation for 1 time step. + +Args + x: Input to the GRU cell. + h_prev: State input from the previous GRU cell. + w_ru: Weight matrix for the reset and update gate. + w_c: Weight matrix for the cell connection gate. + b_ru: Bias vector for the reset and update gate. + b_c: Bias vector for the cell connection gate. + +Returns + r: Output of the reset gate. + u: Output of the update gate. + c: Output of the cell connection gate. + h: Current state of the GRU cell. + +Note on notation of the variables: + +Concatenation of a and b is represented by a_b +Element-wise dot product of a and b is represented by ab +Element-wise dot product is represented by \circ +Matrix multiplication is represented by * + +Baises are initialized with : +`b_ru` - constant_initializer(1.0) +`b_c` - constant_initializer(0.0) + +This kernel op implements the following mathematical equations: + +``` +x_h_prev = [x, h_prev] + +[r_bar u_bar] = x_h_prev * w_ru + b_ru + +r = sigmoid(r_bar) +u = sigmoid(u_bar) + +h_prevr = h_prev \circ r + +x_h_prevr = [x h_prevr] + +c_bar = x_h_prevr * w_c + b_c +c = tanh(c_bar) + +h = (1-u) \circ c + u \circ h_prev +``` +)doc"); + +REGISTER_OP("GRUBlockCellGrad") + .Attr("T: {float}") + .Input("x: T") + .Input("h_prev: T") + .Input("w_ru: T") + .Input("w_c: T") + .Input("b_ru: T") + .Input("b_c: T") + .Input("r: T") + .Input("u: T") + .Input("c: T") + .Input("d_h: T") + .Output("d_x: T") + .Output("d_h_prev: T") + .Output("d_c_bar: T") + .Output("d_r_bar_u_bar: T") + .Doc(R"doc( +Computes the GRU cell back-propagation for 1 time step. + +Args + x: Input to the GRU cell. + h_prev: State input from the previous GRU cell. + w_ru: Weight matrix for the reset and update gate. + w_c: Weight matrix for the cell connection gate. + b_ru: Bias vector for the reset and update gate. + b_c: Bias vector for the cell connection gate. + r: Output of the reset gate. + u: Output of the update gate. + c: Output of the cell connection gate. + d_h: Gradients of the h_new wrt to objective function. + +Returns + d_x: Gradients of the x wrt to objective function. + d_h_prev: Gradients of the h wrt to objective function. + d_c_bar Gradients of the c_bar wrt to objective function. + d_r_bar_u_bar Gradients of the r_bar & u_bar wrt to objective function. + +This kernel op implements the following mathematical equations: + +Note on notation of the variables: + +Concatenation of a and b is represented by a_b +Element-wise dot product of a and b is represented by ab +Element-wise dot product is represented by \circ +Matrix multiplication is represented by * + +Additional notes for clarity: + +`w_ru` can be segmented into 4 different matrices. +``` +w_ru = [w_r_x w_u_x + w_r_h_prev w_u_h_prev] +``` +Similarly, `w_c` can be segmented into 2 different matrices. +``` +w_c = [w_c_x w_c_h_prevr] +``` +Same goes for biases. +``` +b_ru = [b_ru_x b_ru_h] +b_c = [b_c_x b_c_h] +``` +Another note on notation: +``` +d_x = d_x_component_1 + d_x_component_2 + +where d_x_component_1 = d_r_bar * w_r_x^T + d_u_bar * w_r_x^T +and d_x_component_2 = d_c_bar * w_c_x^T + +d_h_prev = d_h_prev_component_1 + d_h_prevr \circ r + d_h \circ u +where d_h_prev_componenet_1 = d_r_bar * w_r_h_prev^T + d_u_bar * w_r_h_prev^T +``` + +Mathematics behind the Gradients below: +``` +d_c_bar = d_h \circ (1-u) \circ (1-c \circ c) +d_u_bar = d_h \circ (h-c) \circ u \circ (1-u) + +d_r_bar_u_bar = [d_r_bar d_u_bar] + +[d_x_component_1 d_h_prev_component_1] = d_r_bar_u_bar * w_ru^T + +[d_x_component_2 d_h_prevr] = d_c_bar * w_c^T + +d_x = d_x_component_1 + d_x_component_2 + +d_h_prev = d_h_prev_component_1 + d_h_prevr \circ r + u +``` +Below calculation is performed in the python wrapper for the Gradients +(not in the gradient kernel.) +``` +d_w_ru = x_h_prevr^T * d_c_bar + +d_w_c = x_h_prev^T * d_r_bar_u_bar + +d_b_ru = sum of d_r_bar_u_bar along axis = 0 + +d_b_c = sum of d_c_bar along axis = 0 +``` +)doc"); diff --git a/tensorflow/contrib/rnn/python/kernel_tests/gru_ops_test.py b/tensorflow/contrib/rnn/python/kernel_tests/gru_ops_test.py new file mode 100644 index 0000000000000000000000000000000000000000..f2ed962ab98bd03224f9c1b17090fae3bf8ebf86 --- /dev/null +++ b/tensorflow/contrib/rnn/python/kernel_tests/gru_ops_test.py @@ -0,0 +1,579 @@ +# 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. +# ============================================================================== +"""Tests for Block GRU module.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time +import numpy as np +import tensorflow as tf +from tensorflow.contrib.rnn.python.ops import gru_ops +from tensorflow.python.ops import variable_scope as vs + + +class GRUBlockCellTest(tf.test.TestCase): + _use_gpu = False + + def testNoneDimsWithDynamicRNN(self): + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + batch_size = 4 + cell_size = 5 + input_size = 6 + num_steps = 7 + + cell = gru_ops.GRUBlockCell(cell_size) + + x = tf.placeholder(tf.float32, shape=(None, None, input_size)) + _, output = tf.nn.dynamic_rnn(cell, x, time_major=True, dtype=tf.float32) + sess.run(tf.initialize_all_variables()) + feed = {} + feed[x] = np.random.randn(num_steps, batch_size, input_size) + sess.run(output, feed) + + def testBlockGRUToGRUCellSingleStep(self): + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + batch_size = 4 + cell_size = 5 + input_size = 6 + + seed = 1994 + initializer = tf.random_uniform_initializer(-0.01, 0.01, seed=seed) + + # Inputs + x = tf.zeros([batch_size, input_size]) + h = tf.zeros([batch_size, cell_size]) + + # Values for the inputs. + x_value = np.random.rand(batch_size, input_size) + h_value = np.random.rand(batch_size, cell_size) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + output = tf.nn.rnn_cell.GRUCell(cell_size)(x, h) + sess.run([tf.initialize_all_variables()]) + basic_res = sess.run([output], {x: x_value, h: h_value}) + + # Output from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + output = gru_ops.GRUBlockCell(cell_size)(x, h) + sess.run([tf.initialize_all_variables()]) + block_res = sess.run([output], {x: x_value, h: h_value}) + + self.assertEqual(len(block_res), len(basic_res)) + for block, basic in zip(block_res, basic_res): + self.assertAllClose(block, basic) + + def testBlockGRUToGRUCellMultiStep(self): + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + batch_size = 2 + cell_size = 3 + input_size = 3 + time_steps = 4 + + # Random initializers. + seed = 1994 + initializer = tf.random_uniform_initializer(-0.01, 0.01, seed=seed) + np.random.seed(seed) + + # Inputs + concat_x = tf.placeholder( + tf.float32, shape=(time_steps, batch_size, input_size)) + h = tf.zeros([batch_size, cell_size]) + + # Values for the inputs. + x_values = np.random.rand(time_steps, batch_size, input_size) + h_value = np.random.rand(batch_size, cell_size) + + # Output from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + cell = gru_ops.GRUBlockCell(cell_size) + outputs_dynamic, state_dynamic = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + feeds = {concat_x: x_values, h: h_value} + sess.run([tf.initialize_all_variables()]) + block_res = sess.run([outputs_dynamic, state_dynamic], feeds) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + cell = tf.nn.rnn_cell.GRUCell(cell_size) + outputs_dynamic, state_dynamic = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + feeds = {concat_x: x_values, h: h_value} + sess.run([tf.initialize_all_variables()]) + basic_res = sess.run([outputs_dynamic, state_dynamic], feeds) + + # Check the lengths of the outputs_dynamic, and states. + self.assertEqual(len(block_res), len(basic_res)) + self.assertEqual(len(block_res[0]), len(basic_res[0])) + self.assertEqual(len(block_res[1]), len(basic_res[1])) + + # Check the outputs_dynamic values. + for block_output, basic_output in zip(block_res[0], basic_res[0]): + self.assertAllClose(block_output, basic_output) + + # Check the state_dynamic value. + self.assertAllClose(block_res[1], block_res[1]) + + def testDerivativeOfBlockGRUToGRUCellSingleStep(self): + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + batch_size = 2 + cell_size = 3 + input_size = 4 + + seed = 1994 + initializer = tf.random_uniform_initializer(-0.01, 0.01, seed=seed) + np.random.seed(seed) + + # Inputs + x = tf.zeros([batch_size, input_size]) + h = tf.zeros([batch_size, cell_size]) + + # Values for the inputs. + x_value = np.random.rand(batch_size, input_size) + h_value = np.random.rand(batch_size, cell_size) + + # Gradients from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + output = gru_ops.GRUBlockCell(cell_size)(x, h) + sess.run([tf.initialize_all_variables()]) + + all_variables = tf.all_variables()[0:4] + [w_ru, b_ru, w_c, b_c] = all_variables + + d_new_h_wrt_x = tf.gradients([output], x) + d_new_h_wrt_h = tf.gradients([output], h) + d_new_h_wrt_w_ru = tf.gradients([output], w_ru) + d_new_h_wrt_w_c = tf.gradients([output], w_c) + d_new_h_wrt_b_ru = tf.gradients([output], b_ru) + d_new_h_wrt_b_c = tf.gradients([output], b_c) + + d_block_res = sess.run([d_new_h_wrt_x, d_new_h_wrt_h, d_new_h_wrt_w_ru, + d_new_h_wrt_w_c, d_new_h_wrt_b_ru, + d_new_h_wrt_b_c], {x: x_value, + h: h_value}) + + # Gradients from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + output = tf.nn.rnn_cell.GRUCell(cell_size)(x, h) + sess.run([tf.initialize_all_variables()]) + + all_variables = tf.all_variables()[4:8] + [w_ru, b_ru, w_c, b_c] = all_variables + + d_new_h_wrt_x = tf.gradients([output], x) + d_new_h_wrt_h = tf.gradients([output], h) + d_new_h_wrt_w_ru = tf.gradients([output], w_ru) + d_new_h_wrt_w_c = tf.gradients([output], w_c) + d_new_h_wrt_b_ru = tf.gradients([output], b_ru) + d_new_h_wrt_b_c = tf.gradients([output], b_c) + + d_basic_res = sess.run([d_new_h_wrt_x, d_new_h_wrt_h, d_new_h_wrt_w_ru, + d_new_h_wrt_w_c, d_new_h_wrt_b_ru, + d_new_h_wrt_b_c], {x: x_value, + h: h_value}) + + # Check lengths of derivative results. + self.assertEqual(len(d_block_res), len(d_basic_res)) + # Check the value of every derivative result. + for block, basic in zip(d_block_res, d_basic_res): + self.assertAllClose(block, basic) + + def testDerivativeOfBlockGRUToGRUCellMultiSteps(self): + batch_size = 2 + cell_size = 3 + input_size = 4 + time_steps = 2 + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + # Random initializers. + seed = 1994 + initializer = tf.random_uniform_initializer(-0.01, 0.01, seed=seed) + np.random.seed(seed) + + # Inputs + concat_x = tf.placeholder( + tf.float32, shape=(time_steps, batch_size, input_size)) + h = tf.zeros([batch_size, cell_size]) + + # Values for the inputs. + x_values = np.random.rand(time_steps, batch_size, input_size) + h_value = np.random.rand(batch_size, cell_size) + feeds = {concat_x: x_values, h: h_value} + + # Gradients from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + cell = gru_ops.GRUBlockCell(cell_size) + + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + grad_output_wrt_x = tf.gradients([outputs_dynamic[0]], concat_x) + grad_output_wrt_h = tf.gradients([outputs_dynamic[0]], h) + + sess.run([tf.initialize_all_variables()]) + block_grad_res_x, block_grad_res_h = sess.run( + [grad_output_wrt_x, grad_output_wrt_h], feeds) + + # Gradients from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + cell = tf.nn.rnn_cell.GRUCell(cell_size) + + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + grad_output_wrt_x = tf.gradients([outputs_dynamic[0]], concat_x) + grad_output_wrt_h = tf.gradients([outputs_dynamic[0]], h) + + sess.run([tf.initialize_all_variables()]) + basic_grad_res_x, basic_grad_res_h = sess.run( + [grad_output_wrt_x, grad_output_wrt_h], feeds) + + # Check derivatives values of the outputs wrt to x. + self.assertEqual(len(block_grad_res_x), len(basic_grad_res_x)) + + # Check derivatives values of the outputs wrt to h. + for block, basic in zip(block_grad_res_x, basic_grad_res_x): + self.assertAllClose(block, basic) + + # Check derivatives values of the outputs wrt to x. + self.assertEqual(len(block_grad_res_h), len(basic_grad_res_h)) + + # Check derivatives values of the outputs wrt to h. + for block, basic in zip(block_grad_res_h, basic_grad_res_h): + self.assertAllClose(block, basic) + + def testGradient(self): + with self.test_session(use_gpu=self._use_gpu, graph=tf.Graph()) as sess: + batch_size = 1 + cell_size = 3 + input_size = 2 + + # Inputs + x = tf.zeros([batch_size, input_size]) + h = tf.zeros([batch_size, cell_size]) + output = gru_ops.GRUBlockCell(cell_size)(x, h) + + sess.run([tf.initialize_all_variables()]) + + all_variables = tf.all_variables() + + [w_ru, b_ru, w_c, b_c] = all_variables[:4] + + error_x = tf.test.compute_gradient_error(x, (batch_size, input_size), + output[0], + (batch_size, cell_size)) + error_h = tf.test.compute_gradient_error(h, (batch_size, cell_size), + output[0], + (batch_size, cell_size)) + error_w_ru = tf.test.compute_gradient_error(w_ru, (input_size + cell_size, + 2 * cell_size), + output[0], + (batch_size, cell_size)) + error_w_c = tf.test.compute_gradient_error(w_c, (input_size + cell_size, + cell_size), output[0], + (batch_size, cell_size)) + error_b_ru = tf.test.compute_gradient_error(b_ru, (2 * cell_size,), + output[0], + (batch_size, cell_size)) + error_b_c = tf.test.compute_gradient_error(b_c, (cell_size,), output[0], + (batch_size, cell_size)) + + eps = 1e-4 + self.assertLess(error_x, eps) + self.assertLess(error_h, eps) + self.assertLess(error_w_ru, eps) + self.assertLess(error_w_c, eps) + self.assertLess(error_b_ru, eps) + self.assertLess(error_b_c, eps) + + +class GRUBlockCellGpuTest(GRUBlockCellTest): + _use_gpu = True + +#### Benchmarking GRUBlockCell vs GRUCell. + + +def time_taken_by_op(op, sess, num_runs=50): + """Time taken by the Op.""" + for _ in range(2): + sess.run([op]) + + start_time = time.time() + for _ in range(num_runs): + sess.run([op]) + + end_time = time.time() + time_taken = end_time - start_time + return time_taken + + +def training_gru_block_vs_gru_cell(batch_size, + cell_size, + input_size, + time_steps, + use_gpu=False, + iters=30): + """Benchmark training speed between GRUBlockCell vs GRUCell.""" + tf.reset_default_graph() + with tf.Session(graph=tf.Graph()) as sess: + # Specify the device which is been used. + with tf.device("/cpu:0" if not use_gpu else "/gpu:0"): + + # Random initializers. + seed = 1994 + initializer = tf.random_uniform_initializer(-1, 1, seed=seed) + np.random.seed(seed) + + # Inputs + concat_x = vs.get_variable("concat_x", + [time_steps, batch_size, input_size]) + h = vs.get_variable("h", [batch_size, cell_size]) + y = vs.get_variable("y", [time_steps, batch_size, cell_size]) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + cell = tf.nn.rnn_cell.GRUCell(cell_size) + + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + sess.run([tf.initialize_all_variables()]) + cost = tf.reduce_mean(tf.square(outputs_dynamic - y)) + learning_rate = 0.01 + optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize( + cost) + + # time for a training step. + basic_time_training = time_taken_by_op(optimizer, sess, iters) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + cell = gru_ops.GRUBlockCell(cell_size) + + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + sess.run([tf.initialize_all_variables()]) + cost = tf.reduce_mean(tf.square(outputs_dynamic - y)) + learning_rate = 0.01 + optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize( + cost) + + # time for a training step. + block_time_training = time_taken_by_op(optimizer, sess, iters) + + performance_training = ( + basic_time_training - block_time_training) * 100 / basic_time_training + + print(",".join([str(batch_size), str(cell_size), str(input_size), str( + time_steps), str(use_gpu), str(basic_time_training), str( + block_time_training), str(performance_training)])) + + return basic_time_training, block_time_training + + +def inference_gru_block_vs_gru_cell(batch_size, + cell_size, + input_size, + time_steps, + use_gpu=False, + iters=30): + """Benchmark inference speed between GRUBlockCell vs GRUCell.""" + tf.reset_default_graph() + with tf.Session(graph=tf.Graph()) as sess: + with tf.device("/cpu:0" if not use_gpu else "/gpu:0"): + + # Random initializers. + seed = 1994 + initializer = tf.random_uniform_initializer(-1, 1, seed=seed) + np.random.seed(seed) + + # Inputs + concat_x = vs.get_variable("concat_x", + [time_steps, batch_size, input_size]) + h = vs.get_variable("h", [batch_size, cell_size]) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + cell = tf.nn.rnn_cell.GRUCell(cell_size) + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + sess.run([tf.initialize_all_variables()]) + basic_time_inference = time_taken_by_op(outputs_dynamic, sess, iters) + + # Output from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + cell = gru_ops.GRUBlockCell(cell_size) + outputs_dynamic, _ = tf.nn.dynamic_rnn( + cell, + inputs=concat_x, + initial_state=h, + time_major=True, + dtype=tf.float32) + sess.run([tf.initialize_all_variables()]) + block_time_inference = time_taken_by_op(outputs_dynamic, sess, iters) + + performance_inference = (basic_time_inference - block_time_inference + ) * 100 / basic_time_inference + print(",".join([str(batch_size), str(cell_size), str(input_size), str( + time_steps), str(use_gpu), str(basic_time_inference), str( + block_time_inference), str(performance_inference)])) + + return basic_time_inference, block_time_inference + + +def single_bprop_step_gru_block_vs_gru_cell(batch_size, + cell_size, + input_size, + use_gpu=False, + iters=30): + """Benchmark single bprop step speed between GRUBlockCell vs GRUCell.""" + tf.reset_default_graph() + with tf.Session(graph=tf.Graph()) as sess: + with tf.device("/cpu:0" if not use_gpu else "/gpu:0"): + initializer = tf.random_uniform_initializer(-1, 1, seed=1989) + # Inputs + x = vs.get_variable("x", [batch_size, input_size]) + h = vs.get_variable("h", [batch_size, cell_size]) + + # Output from the basic GRU cell implementation. + with tf.variable_scope("basic", initializer=initializer): + output = tf.nn.rnn_cell.GRUCell(cell_size)(tf.identity(x), + tf.identity(h)) + sess.run([tf.initialize_all_variables()]) + grad_output_wrt_input = tf.gradients([output], h) + basic_time_bprop = time_taken_by_op(grad_output_wrt_input, sess, iters) + + # Output from the block GRU cell implementation. + with tf.variable_scope("block", initializer=initializer): + output = gru_ops.GRUBlockCell(cell_size)(tf.identity(x), tf.identity(h)) + sess.run([tf.initialize_all_variables()]) + grad_output_wrt_input = tf.gradients([output], h) + block_time_bprop = time_taken_by_op(grad_output_wrt_input, sess, iters) + + performance_inference = ( + basic_time_bprop - block_time_bprop) * 100 / basic_time_bprop + + print(",".join([str(batch_size), str(cell_size), str(input_size), str( + use_gpu), str(basic_time_bprop), str(block_time_bprop), str( + performance_inference)])) + + return basic_time_bprop, block_time_bprop + + +class BenchmarkGRUBlock(tf.test.Benchmark): + + def benchmarkTrainingBlockGRUVsGRUCell(self): + print("Comparison GRUBlockCell vs GRUCell") + print("--------------------------------------------------------------") + print("Training speed GRUBlockCell vs GRUCell") + print("batch_size, cell_size, input_size, time_steps, GPU, " + "basic_time_training, block_time_training, performance_training[%]") + iters = 10 + for use_gpu in [True, False]: + for batch_size in [1, 32, 128]: + for cell_size in [128, 512]: + for input_size in [128, 512]: + for time_steps in [50]: + basic_time, block_time = training_gru_block_vs_gru_cell( + batch_size, cell_size, input_size, time_steps, use_gpu, iters) + self.report_benchmark( + name="GRUCell_training_time_BS%i_CS%i_IS%i_TS%i_gpu_%s" % + (batch_size, cell_size, input_size, time_steps, use_gpu), + iters=iters, + wall_time=basic_time) + self.report_benchmark( + name="GRUBlockCell_training_time_BS%i_CS%i_IS%i_TS%i_gpu_%s" % + (batch_size, cell_size, input_size, time_steps, use_gpu), + iters=iters, + wall_time=block_time) + + def benchmarkInferenceBlockGRUVsGRUCell(self): + print("--------------------------------------------------------------") + print("Inference speed GRUBlockCell vs GRUCell") + print( + "batch_size, cell_size, input_size, time_steps, GPU, " + "basic_time_inference, block_time_inference, performance_inference[%]") + iters = 10 + for use_gpu in [True, False]: + for batch_size in [1, 32, 128]: + for cell_size in [128, 512]: + for input_size in [128, 512]: + for time_steps in [50]: + basic_time, block_time = inference_gru_block_vs_gru_cell( + batch_size, cell_size, input_size, time_steps, use_gpu, iters) + self.report_benchmark( + name="GRUCell_inference_time_BS%i_CS%i_IS%i_TS%i_gpu_%s" % + (batch_size, cell_size, input_size, time_steps, use_gpu), + iters=iters, + wall_time=basic_time) + self.report_benchmark( + name="GRUBlockCell_inference_time_BS%i_CS%i_IS%i_TS%i_gpu_%s" + % (batch_size, cell_size, input_size, time_steps, use_gpu), + iters=iters, + wall_time=block_time) + + def benchmarkSingleBpropStepBlockGRUVsGRUCell(self): + print("--------------------------------------------------------------") + print("Single bprop step speed GRUBlockCell vs GRUCell") + print("batch_size, cell_size, input_size, GPU, basic_time, " + "block_time, performance_inference[%]") + iters = 10 + for use_gpu in [True, False]: + for batch_size in [1, 32, 128]: + for cell_size in [128, 512]: + for input_size in [128, 512]: + basic_time, block_time = single_bprop_step_gru_block_vs_gru_cell( + batch_size, cell_size, input_size, use_gpu, iters) + self.report_benchmark( + name="GRUCell_Bprop_single_step_time_BS%i_CS%i_IS%i_gpu_%s" % + (batch_size, cell_size, input_size, use_gpu), + iters=iters, + wall_time=basic_time) + self.report_benchmark( + name="GRUBlockCell_Bprop_single_step_time_BS%i_CS%i_IS%i_gpu_%s" + % (batch_size, cell_size, input_size, use_gpu), + iters=iters, + wall_time=block_time) + + print("--------------------------------------------------------------") + + +if __name__ == "__main__": + tf.test.main() diff --git a/tensorflow/contrib/rnn/python/ops/gru_ops.py b/tensorflow/contrib/rnn/python/ops/gru_ops.py new file mode 100644 index 0000000000000000000000000000000000000000..49faad9dd527d673fc38cac910a299e8073bdaae --- /dev/null +++ b/tensorflow/contrib/rnn/python/ops/gru_ops.py @@ -0,0 +1,202 @@ +# 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. +# ============================================================================== +"""Python wrapper for the Block GRU Op.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +from tensorflow.python.framework import load_library +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_shape +from tensorflow.python.ops import array_ops +from tensorflow.python.ops import init_ops +from tensorflow.python.ops import math_ops +from tensorflow.python.ops import nn_ops +from tensorflow.python.ops import rnn_cell +from tensorflow.python.ops import variable_scope as vs +from tensorflow.python.platform import resource_loader + +_gru_ops_so = load_library.load_op_library( + resource_loader.get_path_to_datafile("_gru_ops.so")) +assert _gru_ops_so, "Could not load _gru_ops.so." + + +@ops.RegisterShape("GRUBlockCellGrad") +def _GRUBlockCellGradShape(op): + batch_size = op.inputs[0].get_shape().with_rank(2)[0] + input_size = op.inputs[0].get_shape().with_rank(2)[1] + cell_size = op.inputs[1].get_shape().with_rank(2)[1] + twice_cell_size = op.inputs[2].get_shape().with_rank(2)[1] + + return [tensor_shape.TensorShape([batch_size, input_size]), + tensor_shape.TensorShape([batch_size, cell_size]), + tensor_shape.TensorShape([batch_size, cell_size]), + tensor_shape.TensorShape([batch_size, twice_cell_size])] + + +@ops.RegisterGradient("GRUBlockCell") +def _GRUBlockCellGrad(op, *grad): + r"""Gradient for GRUBlockCell. + + Args: + op: Op for which the gradient is defined. + *grad: Gradients of the optimization function wrt output + for the Op. + + Returns: + d_x: Gradients wrt to x + d_h: Gradients wrt to h + d_w_ru: Gradients wrt to w_ru + d_w_c: Gradients wrt to w_c + d_b_ru: Gradients wrt to b_ru + d_b_c: Gradients wrt to b_c + + Mathematics behind the Gradients below: + ``` + d_c_bar = d_h \circ (1-u) \circ (1-c \circ c) + d_u_bar = d_h \circ (h-c) \circ u \circ (1-u) + + d_r_bar_u_bar = [d_r_bar d_u_bar] + + [d_x_component_1 d_h_prev_component_1] = d_r_bar_u_bar * w_ru^T + + [d_x_component_2 d_h_prevr] = d_c_bar * w_c^T + + d_x = d_x_component_1 + d_x_component_2 + + d_h_prev = d_h_prev_component_1 + d_h_prevr \circ r + u + ``` + Below calculation is performed in the python wrapper for the Gradients + (not in the gradient kernel.) + ``` + d_w_ru = x_h_prevr^T * d_c_bar + + d_w_c = x_h_prev^T * d_r_bar_u_bar + + d_b_ru = sum of d_r_bar_u_bar along axis = 0 + + d_b_c = sum of d_c_bar along axis = 0 + ``` + """ + x, h_prev, w_ru, w_c, b_ru, b_c = op.inputs + r, u, c, _ = op.outputs + _, _, _, d_h = grad + + d_x, d_h_prev, d_c_bar, d_r_bar_u_bar = _gru_ops_so.gru_block_cell_grad( + x, h_prev, w_ru, w_c, b_ru, b_c, r, u, c, d_h) + + x_h_prev = array_ops.concat(1, [x, h_prev]) + d_w_ru = math_ops.matmul(x_h_prev, d_r_bar_u_bar, transpose_a=True) + d_b_ru = nn_ops.bias_add_grad(d_r_bar_u_bar) + + x_h_prevr = array_ops.concat(1, [x, h_prev * r]) + d_w_c = math_ops.matmul(x_h_prevr, d_c_bar, transpose_a=True) + d_b_c = nn_ops.bias_add_grad(d_c_bar) + + return d_x, d_h_prev, d_w_ru, d_w_c, d_b_ru, d_b_c + + +@ops.RegisterShape("GRUBlockCell") +def _GRUBlockCellShape(op): + batch_size = op.inputs[0].get_shape().with_rank(2)[0] + cell_size = op.inputs[1].get_shape().with_rank(2)[1] + + return (tensor_shape.TensorShape([batch_size, cell_size]), + tensor_shape.TensorShape([batch_size, cell_size]), + tensor_shape.TensorShape([batch_size, cell_size]), + tensor_shape.TensorShape([batch_size, cell_size])) + + +class GRUBlockCell(rnn_cell.RNNCell): + r"""Block GRU cell implementation. + + The implementation is based on: http://arxiv.org/abs/1406.1078 + Computes the LSTM cell forward propagation for 1 time step. + + This kernel op implements the following mathematical equations: + + Baises are initialized with : + `b_ru` - constant_initializer(1.0) + `b_c` - constant_initializer(0.0) + ``` + x_h_prev = [x, h_prev] + + [r_bar u_bar] = x_h_prev * w_ru + b_ru + + r = sigmoid(r_bar) + u = sigmoid(u_bar) + + h_prevr = h_prev \circ r + + x_h_prevr = [x h_prevr] + + c_bar = x_h_prevr * w_c + b_c + c = tanh(c_bar) + + h = (1-u) \circ c + u \circ h_prev + ``` + + """ + + def __init__(self, cell_size): + """Initialize the Block GRU cell. + + Args: + cell_size: int, GRU cell size. + """ + self._cell_size = cell_size + + @property + def state_size(self): + return self._cell_size + + @property + def output_size(self): + return self._cell_size + + def __call__(self, x, h_prev, scope=None): + """GRU cell.""" + with vs.variable_scope(scope or type(self).__name__): + input_size = x.get_shape().with_rank(2)[1] + + # Check if the input size exist. + if input_size is None: + raise ValueError("Expecting input_size to be set.") + + # Check cell_size == state_size from h_prev. + cell_size = h_prev.get_shape().with_rank(2)[1] + if cell_size != self._cell_size: + raise ValueError("Shape of h_prev[1] incorrect: cell_size %i vs %s" % + (self._cell_size, cell_size)) + + if cell_size is None: + raise ValueError("cell_size from `h_prev` should not be None.") + + w_ru = vs.get_variable("w_ru", [input_size + self._cell_size, + self._cell_size * 2]) + b_ru = vs.get_variable( + "b_ru", [self._cell_size * 2], + initializer=init_ops.constant_initializer(1.0)) + w_c = vs.get_variable("w_c", + [input_size + self._cell_size, self._cell_size]) + b_c = vs.get_variable( + "b_c", [self._cell_size], + initializer=init_ops.constant_initializer(0.0)) + + _gru_block_cell = _gru_ops_so.gru_block_cell # pylint: disable=invalid-name + _, _, _, new_h = _gru_block_cell( + x=x, h_prev=h_prev, w_ru=w_ru, w_c=w_c, b_ru=b_ru, b_c=b_c) + + return new_h, new_h diff --git a/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py b/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py index d768722cd8acb157bc77ebd31b2679a5ac50864f..5a5e3c8ce2fc561ea4302e3000d63fe05f8ac9fc 100644 --- a/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py +++ b/tensorflow/contrib/slim/python/slim/data/tfexample_decoder.py @@ -26,6 +26,7 @@ from __future__ import print_function import abc from tensorflow.contrib.slim.python.slim.data import data_decoder +from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops @@ -96,6 +97,50 @@ class ItemHandlerCallback(ItemHandler): return self._func(keys_to_tensors) +class BoundingBox(ItemHandler): + """An ItemHandler that concatenates a set of parsed Tensors to Bounding Boxes. + """ + + def __init__(self, keys=None, prefix=None): + """Initialize the bounding box handler. + + Args: + keys: A list of four key names representing the ymin, xmin, ymax, mmax + prefix: An optional prefix for each of the bounding box keys. + If provided, `prefix` is appended to each key in `keys`. + + Raises: + ValueError: if keys is not `None` and also not a list of exactly 4 keys + """ + if keys is None: + keys = ['ymin', 'xmin', 'ymax', 'xmax'] + elif len(keys) != 4: + raise ValueError('BoundingBox expects 4 keys but got {}'.format( + len(keys))) + self._prefix = prefix + self._keys = keys + self._full_keys = [prefix + k for k in keys] + super(BoundingBox, self).__init__(self._full_keys) + + def tensors_to_item(self, keys_to_tensors): + """Maps the given dictionary of tensors to a contatenated list of bboxes. + + Args: + keys_to_tensors: a mapping of TF-Example keys to parsed tensors. + + Returns: + [num_boxes, 4] tensor of bounding box coordinates, + i.e. 1 bounding box per row, in order [y_min, x_min, y_max, x_max]. + """ + sides = [] + for key in self._full_keys: + side = array_ops.expand_dims(keys_to_tensors[key].values, 0) + sides.append(side) + + bounding_box = array_ops.concat(0, sides) + return array_ops.transpose(bounding_box) + + class Tensor(ItemHandler): """An ItemHandler that returns a parsed Tensor.""" @@ -226,7 +271,7 @@ class Image(ItemHandler): Args: image_key: the name of the TF-Example feature in which the encoded image is stored. - format_key: the name of the TF-Example feature in which the encoded image + format_key: the name of the TF-Example feature in which the image format is stored. shape: the output shape of the image. If provided, the image is reshaped accordingly. If left as None, no reshaping is done. A shape should be @@ -266,15 +311,22 @@ class Image(ItemHandler): """ def decode_png(): return image_ops.decode_png(image_buffer, self._channels) + def decode_raw(): + return parsing_ops.decode_raw(image_buffer, dtypes.uint8) def decode_jpg(): return image_ops.decode_jpeg(image_buffer, self._channels) image = control_flow_ops.case({ - math_ops.equal(image_format, 'png'): decode_png, + math_ops.logical_or(math_ops.equal(image_format, 'png'), + math_ops.equal(image_format, 'PNG')): decode_png, + math_ops.logical_or(math_ops.equal(image_format, 'raw'), + math_ops.equal(image_format, 'RAW')): decode_raw, }, default=decode_jpg, exclusive=True) + image.set_shape([None, None, self._channels]) if self._shape is not None: image = array_ops.reshape(image, self._shape) + return image diff --git a/tensorflow/contrib/slim/python/slim/data/tfexample_decoder_test.py b/tensorflow/contrib/slim/python/slim/data/tfexample_decoder_test.py index 7f0dd30ed9fd1a201460087c91bccafb1beab085..cd75db8967bf67371099f8f07a2e907357f2b6a0 100644 --- a/tensorflow/contrib/slim/python/slim/data/tfexample_decoder_test.py +++ b/tensorflow/contrib/slim/python/slim/data/tfexample_decoder_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# 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. @@ -55,13 +55,15 @@ class TFExampleDecoderTest(tf.test.TestCase): return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def _Encoder(self, image, image_format): - assert image_format in ['jpeg', 'png'] - if image_format == 'jpeg': + assert image_format in ['jpeg', 'JPEG', 'png', 'PNG', 'raw', 'RAW'] + if image_format in ['jpeg', 'JPEG']: tf_image = tf.constant(image, dtype=tf.uint8) return tf.image.encode_jpeg(tf_image) - if image_format == 'png': + if image_format in ['png', 'PNG']: tf_image = tf.constant(image, dtype=tf.uint8) return tf.image.encode_png(tf_image) + if image_format in ['raw', 'RAW']: + return tf.constant(image.tostring(), dtype=tf.string) def GenerateImage(self, image_format, image_shape): """Generates an image and an example containing the encoded image. @@ -74,9 +76,11 @@ class TFExampleDecoderTest(tf.test.TestCase): image: the generated image. example: a TF-example with a feature key 'image/encoded' set to the serialized image and a feature key 'image/format' set to the image - encoding format ['jpeg', 'png']. + encoding format ['jpeg', 'JPEG', 'png', 'PNG', 'raw']. """ - image = np.linspace(0, 17, num=18).reshape(image_shape).astype(np.uint8) + num_pixels = image_shape[0] * image_shape[1] * image_shape[2] + image = np.linspace(0, num_pixels-1, num=num_pixels).reshape( + image_shape).astype(np.uint8) tf_encoded = self._Encoder(image, image_format) example = tf.train.Example(features=tf.train.Features(feature={ 'image/encoded': self._EncodedBytesFeature(tf_encoded), @@ -85,35 +89,39 @@ class TFExampleDecoderTest(tf.test.TestCase): return image, example.SerializeToString() - def DecodeExample(self, serialized_example, item_handler, image_shape, - image_format): + def DecodeExample(self, serialized_example, item_handler, image_format): """Decodes the given serialized example with the specified item handler. Args: serialized_example: a serialized TF example string. item_handler: the item handler used to decode the image. - image_shape: the shape of the image being decoded. image_format: the image format being decoded. Returns: the decoded image found in the serialized Example. """ + serialized_example = tf.reshape(serialized_example, shape=[]) + decoder = slim.tfexample_decoder.TFExampleDecoder( + keys_to_features={ + 'image/encoded': tf.FixedLenFeature( + (), tf.string, default_value=''), + 'image/format': tf.FixedLenFeature( + (), tf.string, default_value=image_format), + }, + items_to_handlers={'image': item_handler} + ) + [tf_image] = decoder.decode(serialized_example, ['image']) + return tf_image + + def RunDecodeExample(self, serialized_example, item_handler, image_format): + tf_image = self.DecodeExample(serialized_example, item_handler, + image_format) + with self.test_session(): - serialized_example = tf.reshape(serialized_example, shape=[]) - decoder = slim.tfexample_decoder.TFExampleDecoder( - keys_to_features={ - 'image/encoded': tf.FixedLenFeature( - (), tf.string, default_value=''), - 'image/format': tf.FixedLenFeature( - (), tf.string, default_value=image_format), - }, - items_to_handlers={'image': item_handler} - ) - [tf_image] = decoder.decode(serialized_example, ['image']) decoded_image = tf_image.eval() - # We need to recast them here to avoid some issues with uint8. - return decoded_image.astype(np.float32) + # We need to recast them here to avoid some issues with uint8. + return decoded_image.astype(np.float32) def testDecodeExampleWithJpegEncoding(self): image_shape = (2, 3, 3) @@ -121,26 +129,97 @@ class TFExampleDecoderTest(tf.test.TestCase): image_format='jpeg', image_shape=image_shape) - decoded_image = self.DecodeExample( + decoded_image = self.RunDecodeExample( serialized_example, slim.tfexample_decoder.Image(), - image_shape=image_shape, image_format='jpeg') # Need to use a tolerance of 1 because of noise in the jpeg encode/decode self.assertAllClose(image, decoded_image, atol=1.001) + def testDecodeExampleWithJPEGEncoding(self): + test_image_channels = [1, 3] + for channels in test_image_channels: + image_shape = (2, 3, channels) + image, serialized_example = self.GenerateImage( + image_format='JPEG', + image_shape=image_shape) + + decoded_image = self.RunDecodeExample( + serialized_example, + slim.tfexample_decoder.Image(channels=channels), + image_format='JPEG') + + # Need to use a tolerance of 1 because of noise in the jpeg encode/decode + self.assertAllClose(image, decoded_image, atol=1.001) + + def testDecodeExampleWithNoShapeInfo(self): + test_image_channels = [1, 3] + for channels in test_image_channels: + image_shape = (2, 3, channels) + _, serialized_example = self.GenerateImage( + image_format='jpeg', + image_shape=image_shape) + + tf_decoded_image = self.DecodeExample( + serialized_example, + slim.tfexample_decoder.Image(shape=None, channels=channels), + image_format='jpeg') + self.assertEqual(tf_decoded_image.get_shape().ndims, 3) + def testDecodeExampleWithPngEncoding(self): + test_image_channels = [1, 3] + for channels in test_image_channels: + image_shape = (2, 3, channels) + image, serialized_example = self.GenerateImage( + image_format='png', + image_shape=image_shape) + + decoded_image = self.RunDecodeExample( + serialized_example, + slim.tfexample_decoder.Image(channels=channels), + image_format='png') + + self.assertAllClose(image, decoded_image, atol=0) + + def testDecodeExampleWithPNGEncoding(self): + test_image_channels = [1, 3] + for channels in test_image_channels: + image_shape = (2, 3, channels) + image, serialized_example = self.GenerateImage( + image_format='PNG', + image_shape=image_shape) + + decoded_image = self.RunDecodeExample( + serialized_example, + slim.tfexample_decoder.Image(channels=channels), + image_format='PNG') + + self.assertAllClose(image, decoded_image, atol=0) + + def testDecodeExampleWithRawEncoding(self): image_shape = (2, 3, 3) image, serialized_example = self.GenerateImage( - image_format='png', + image_format='raw', image_shape=image_shape) - decoded_image = self.DecodeExample( + decoded_image = self.RunDecodeExample( serialized_example, - slim.tfexample_decoder.Image(), - image_shape=image_shape, - image_format='png') + slim.tfexample_decoder.Image(shape=image_shape), + image_format='raw') + + self.assertAllClose(image, decoded_image, atol=0) + + def testDecodeExampleWithRAWEncoding(self): + image_shape = (2, 3, 3) + image, serialized_example = self.GenerateImage( + image_format='RAW', + image_shape=image_shape) + + decoded_image = self.RunDecodeExample( + serialized_example, + slim.tfexample_decoder.Image(shape=image_shape), + image_format='RAW') self.assertAllClose(image, decoded_image, atol=0) @@ -594,5 +673,44 @@ class TFExampleDecoderTest(tf.test.TestCase): else: self.assertAllClose(image, decoded_image, atol=0) + def testDecodeExampleWithBoundingBox(self): + num_bboxes = 10 + np_ymin = np.random.rand(num_bboxes, 1) + np_xmin = np.random.rand(num_bboxes, 1) + np_ymax = np.random.rand(num_bboxes, 1) + np_xmax = np.random.rand(num_bboxes, 1) + np_bboxes = np.hstack([np_ymin, np_xmin, np_ymax, np_xmax]) + + example = tf.train.Example(features=tf.train.Features(feature={ + 'image/object/bbox/ymin': self._EncodedFloatFeature(np_ymin), + 'image/object/bbox/xmin': self._EncodedFloatFeature(np_xmin), + 'image/object/bbox/ymax': self._EncodedFloatFeature(np_ymax), + 'image/object/bbox/xmax': self._EncodedFloatFeature(np_xmax), + })) + serialized_example = example.SerializeToString() + + with self.test_session(): + serialized_example = tf.reshape(serialized_example, shape=[]) + + keys_to_features = { + 'image/object/bbox/ymin': tf.VarLenFeature(tf.float32), + 'image/object/bbox/xmin': tf.VarLenFeature(tf.float32), + 'image/object/bbox/ymax': tf.VarLenFeature(tf.float32), + 'image/object/bbox/xmax': tf.VarLenFeature(tf.float32), + } + + items_to_handlers = { + 'object/bbox': slim.tfexample_decoder.BoundingBox( + ['ymin', 'xmin', 'ymax', 'xmax'], 'image/object/bbox/'), + } + + decoder = slim.tfexample_decoder.TFExampleDecoder( + keys_to_features, + items_to_handlers) + [tf_bboxes] = decoder.decode(serialized_example, ['object/bbox']) + bboxes = tf_bboxes.eval() + + self.assertAllClose(np_bboxes, bboxes) + if __name__ == '__main__': tf.test.main() diff --git a/tensorflow/contrib/slim/python/slim/evaluation.py b/tensorflow/contrib/slim/python/slim/evaluation.py index 6c40f7743be28c52b72b9e634b936fdefc32a3e4..6f2fae800c589a7fb1faf0ce632cf490645437c9 100644 --- a/tensorflow/contrib/slim/python/slim/evaluation.py +++ b/tensorflow/contrib/slim/python/slim/evaluation.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# 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. @@ -136,7 +136,12 @@ from tensorflow.python.training import summary_io from tensorflow.python.training import supervisor from tensorflow.python.training import training_util -__all__ = ['evaluation', 'evaluation_loop', 'wait_for_new_checkpoint'] +__all__ = [ + 'evaluate_once', + 'evaluation', + 'evaluation_loop', + 'wait_for_new_checkpoint' +] def wait_for_new_checkpoint(checkpoint_dir, @@ -241,6 +246,88 @@ def evaluation(sess, _USE_DEFAULT = 0 +def evaluate_once(master, + checkpoint_path, + logdir, + num_evals=1, + eval_op=None, + eval_op_feed_dict=None, + final_op=None, + final_op_feed_dict=None, + summary_op=_USE_DEFAULT, + summary_op_feed_dict=None, + variables_to_restore=None, + session_config=None): + """Evaluates the model at the given checkpoint path. + + Args: + master: The BNS address of the TensorFlow master. + checkpoint_path: The path to a checkpoint to use for evaluation. + logdir: The directory where the TensorFlow summaries are written to. + num_evals: The number of times to run `eval_op`. + eval_op: A operation run `num_evals` times. + eval_op_feed_dict: The feed dictionary to use when executing the `eval_op`. + final_op: An operation to execute after all of the `eval_op` executions. The + value of `final_op` is returned. + final_op_feed_dict: A feed dictionary to use when executing `final_op`. + summary_op: The summary_op to evaluate after running TF-Slims metric ops. By + default the summary_op is set to tf.merge_all_summaries(). + summary_op_feed_dict: An optional feed dictionary to use when running the + `summary_op`. + variables_to_restore: A list of TensorFlow variables to restore during + evaluation. If the argument is left as `None` then + slim.variables.GetVariablesToRestore() is used. + session_config: An instance of `tf.ConfigProto` that will be used to + configure the `Session`. If left as `None`, the default will be used. + + Returns: + The value of `final_op` or `None` if `final_op` is `None`. + """ + if summary_op == _USE_DEFAULT: + summary_op = logging_ops.merge_all_summaries() + + global_step = variables.get_or_create_global_step() + + init_op = control_flow_ops.group(tf_variables.initialize_all_variables(), + tf_variables.initialize_local_variables(), + data_flow_ops.initialize_all_tables()) + + saver = tf_saver.Saver(variables_to_restore or + variables.get_variables_to_restore()) + + summary_writer = summary_io.SummaryWriter(logdir) + + sv = supervisor.Supervisor(graph=ops.get_default_graph(), + logdir=logdir, + init_op=init_op, + summary_op=None, + summary_writer=None, + global_step=None, + saver=None) + + logging.info('Starting evaluation at ' + time.strftime('%Y-%m-%d-%H:%M:%S', + time.gmtime())) + with sv.managed_session( + master, start_standard_services=False, config=session_config) as sess: + saver.restore(sess, checkpoint_path) + sv.start_queue_runners(sess) + final_op_value = evaluation(sess, + num_evals=num_evals, + eval_op=eval_op, + eval_op_feed_dict=eval_op_feed_dict, + final_op=final_op, + final_op_feed_dict=final_op_feed_dict, + summary_op=summary_op, + summary_op_feed_dict=summary_op_feed_dict, + summary_writer=summary_writer, + global_step=global_step) + + logging.info('Finished evaluation at ' + time.strftime('%Y-%m-%d-%H:%M:%S', + time.gmtime())) + + return final_op_value + + def evaluation_loop(master, checkpoint_dir, logdir, diff --git a/tensorflow/contrib/slim/python/slim/evaluation_test.py b/tensorflow/contrib/slim/python/slim/evaluation_test.py index 4e59f3efe2b09673141125cfd229363ab2a7079f..5c8e7bf6639dc7edc7949fcabda0e87983da95a9 100644 --- a/tensorflow/contrib/slim/python/slim/evaluation_test.py +++ b/tensorflow/contrib/slim/python/slim/evaluation_test.py @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. All Rights Reserved. +# 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. @@ -95,7 +95,7 @@ class EvaluationTest(tf.test.TestCase): self.assertAlmostEqual(accuracy_value, self._expected_accuracy) def testFinalOpsOnEvaluationLoop(self): - _, update_op = slim.metrics.streaming_accuracy( + value_op, update_op = slim.metrics.streaming_accuracy( self._predictions, self._labels) init_op = tf.group(tf.initialize_all_variables(), tf.initialize_local_variables()) @@ -104,15 +104,18 @@ class EvaluationTest(tf.test.TestCase): gfile.MakeDirs(chkpt_dir) logdir = os.path.join(self.get_temp_dir(), 'tmp_logs2/') gfile.MakeDirs(logdir) - saver = tf.train.Saver(tf.all_variables()) + + # Save initialized variables to checkpoint directory + saver = tf.train.Saver() with self.test_session() as sess: init_op.run() - # Save initialized variables to checkpoint directory saver.save(sess, os.path.join(chkpt_dir, 'chkpt')) - accuracy_value = slim.evaluation.evaluation_loop( - '', chkpt_dir, logdir, final_op=update_op, - max_number_of_evaluations=1) - self.assertAlmostEqual(accuracy_value, self._expected_accuracy) + + # Now, run the evaluation loop: + accuracy_value = slim.evaluation.evaluation_loop( + '', chkpt_dir, logdir, eval_op=update_op, final_op=value_op, + max_number_of_evaluations=1) + self.assertAlmostEqual(accuracy_value, self._expected_accuracy) def _create_names_to_metrics(self, predictions, labels): accuracy0, update_op0 = tf.contrib.metrics.streaming_accuracy( @@ -247,5 +250,54 @@ class EvaluationTest(tf.test.TestCase): # The timeout kicked in. self.assertLess(end, start + 1.1) + +class SingleEvaluationTest(tf.test.TestCase): + + def setUp(self): + super(SingleEvaluationTest, self).setUp() + + num_classes = 8 + batch_size = 16 + inputs, labels = GenerateTestData(num_classes, batch_size) + self._expected_accuracy = GroundTruthAccuracy(inputs, labels, batch_size) + + self._global_step = slim.get_or_create_global_step() + self._inputs = tf.constant(inputs, dtype=tf.float32) + self._labels = tf.constant(labels, dtype=tf.int64) + self._predictions, self._scale = TestModel(self._inputs) + + def testErrorRaisedIfCheckpointDoesntExist(self): + checkpoint_path = os.path.join(self.get_temp_dir(), + 'this_file_doesnt_exist') + log_dir = os.path.join(self.get_temp_dir(), 'error_raised') + with self.assertRaises(ValueError): + slim.evaluation.evaluate_once('', checkpoint_path, log_dir) + + def testRestoredModelPerformance(self): + checkpoint_path = os.path.join(self.get_temp_dir(), 'model.ckpt') + log_dir = os.path.join(self.get_temp_dir(), 'log_dir1/') + + # First, save out the current model to a checkpoint: + init_op = tf.group(tf.initialize_all_variables(), + tf.initialize_local_variables()) + saver = tf.train.Saver() + with self.test_session() as sess: + sess.run(init_op) + saver.save(sess, checkpoint_path) + + # Next, determine the metric to evaluate: + value_op, update_op = slim.metrics.streaming_accuracy( + self._predictions, self._labels) + + # Run the evaluation and verify the results: + accuracy_value = slim.evaluation.evaluate_once( + '', + checkpoint_path, + log_dir, + eval_op=update_op, + final_op=value_op) + self.assertAlmostEqual(accuracy_value, self._expected_accuracy) + + if __name__ == '__main__': tf.test.main() diff --git a/tensorflow/contrib/slim/python/slim/learning.py b/tensorflow/contrib/slim/python/slim/learning.py index c4374dc9a1276e7cd73b6bad6063a9feb43574a9..59fecea0c99059a9fd6655e9c5eb276045413cc7 100644 --- a/tensorflow/contrib/slim/python/slim/learning.py +++ b/tensorflow/contrib/slim/python/slim/learning.py @@ -448,24 +448,29 @@ def create_train_op( # Scale gradients. if gradient_multipliers: - grads = multiply_gradients(grads, gradient_multipliers) + with ops.name_scope('multiply_grads'): + grads = multiply_gradients(grads, gradient_multipliers) # Clip gradients. if clip_gradient_norm > 0: - grads = clip_gradient_norms(grads, clip_gradient_norm) + with ops.name_scope('clip_grads'): + grads = clip_gradient_norms(grads, clip_gradient_norm) # Summarize gradients. if summarize_gradients: - add_gradients_summaries(grads) + with ops.name_scope('summarize_grads'): + add_gradients_summaries(grads) # Create gradient updates. grad_updates = optimizer.apply_gradients(grads, global_step=global_step) - # Make sure total_loss is valid. - total_loss = array_ops.check_numerics(total_loss, 'LossTensor is inf or nan') + with ops.name_scope('train_op'): + # Make sure total_loss is valid. + total_loss = array_ops.check_numerics(total_loss, + 'LossTensor is inf or nan') - # Ensure the train_tensor computes grad_updates. - return control_flow_ops.with_dependencies([grad_updates], total_loss) + # Ensure the train_tensor computes grad_updates. + return control_flow_ops.with_dependencies([grad_updates], total_loss) def _wait_for_step(sess, global_step, step): @@ -529,7 +534,7 @@ def train_step(sess, train_op, global_step, train_step_kwargs): if 'should_log' in train_step_kwargs: if sess.run(train_step_kwargs['should_log']): - logging.info('global step %d: loss = %.4f (%.2f sec)', + logging.info('global step %d: loss = %.4f (%.2f sec/step)', np_global_step, total_loss, time_elapsed) # TODO(nsilberman): figure out why we can't put this into sess.run. The @@ -672,11 +677,17 @@ def train(train_op, global_step = variables.get_or_create_global_step() saver = saver or tf_saver.Saver() - if init_op == _USE_DEFAULT: - init_op = tf_variables.initialize_all_variables() + with ops.name_scope('init_ops'): + if init_op == _USE_DEFAULT: + init_op = tf_variables.initialize_all_variables() - if ready_op == _USE_DEFAULT: - ready_op = tf_variables.report_uninitialized_variables() + if ready_op == _USE_DEFAULT: + ready_op = tf_variables.report_uninitialized_variables() + + if local_init_op == _USE_DEFAULT: + local_init_op = control_flow_ops.group( + tf_variables.initialize_local_variables(), + data_flow_ops.initialize_all_tables()) if summary_op == _USE_DEFAULT: summary_op = logging_ops.merge_all_summaries() @@ -684,11 +695,6 @@ def train(train_op, if summary_writer == _USE_DEFAULT: summary_writer = supervisor.Supervisor.USE_DEFAULT - if local_init_op == _USE_DEFAULT: - local_init_op = control_flow_ops.group( - tf_variables.initialize_local_variables(), - data_flow_ops.initialize_all_tables()) - cleanup_op = None if is_chief and sync_optimizer: @@ -705,19 +711,20 @@ def train(train_op, cleanup_op = sync_optimizer.get_clean_up_op() if train_step_kwargs == _USE_DEFAULT: - train_step_kwargs = {} - - if number_of_steps: - should_stop_op = math_ops.greater_equal(global_step, number_of_steps) - else: - should_stop_op = constant_op.constant(False) - train_step_kwargs['should_stop'] = should_stop_op - train_step_kwargs['should_log'] = math_ops.equal( - math_ops.mod(global_step, log_every_n_steps), 0) - if is_chief and trace_every_n_steps is not None: - train_step_kwargs['should_trace'] = math_ops.equal( - math_ops.mod(global_step, trace_every_n_steps), 0) - train_step_kwargs['logdir'] = logdir + with ops.name_scope('train_step'): + train_step_kwargs = {} + + if number_of_steps: + should_stop_op = math_ops.greater_equal(global_step, number_of_steps) + else: + should_stop_op = constant_op.constant(False) + train_step_kwargs['should_stop'] = should_stop_op + train_step_kwargs['should_log'] = math_ops.equal( + math_ops.mod(global_step, log_every_n_steps), 0) + if is_chief and trace_every_n_steps is not None: + train_step_kwargs['should_trace'] = math_ops.equal( + math_ops.mod(global_step, trace_every_n_steps), 0) + train_step_kwargs['logdir'] = logdir sv = supervisor.Supervisor( graph=graph, diff --git a/tensorflow/contrib/slim/python/slim/nets/BUILD b/tensorflow/contrib/slim/python/slim/nets/BUILD index 94410c2967100f59e31d2ab2e4e4639098234c78..9d5b95c6b15dcaaf623a5e403ff4a89e69073e5d 100644 --- a/tensorflow/contrib/slim/python/slim/nets/BUILD +++ b/tensorflow/contrib/slim/python/slim/nets/BUILD @@ -6,7 +6,10 @@ licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) package( - default_visibility = ["//tensorflow:__subpackages__"], + default_visibility = [ + "//tensorflow:__subpackages__", + "//tensorflow_models:__subpackages__", + ], ) py_library( diff --git a/tensorflow/contrib/slim/python/slim/nets/alexnet.py b/tensorflow/contrib/slim/python/slim/nets/alexnet.py index f6fedf98887f688f3c0784e632d766d0de035bc5..7aca4875983932d2e694c36184062d0ac1b67dc5 100644 --- a/tensorflow/contrib/slim/python/slim/nets/alexnet.py +++ b/tensorflow/contrib/slim/python/slim/nets/alexnet.py @@ -54,8 +54,8 @@ def alexnet_v2_arg_scope(weight_decay=0.0005): def alexnet_v2(inputs, num_classes=1000, - dropout_keep_prob=0.5, is_training=True, + dropout_keep_prob=0.5, spatial_squeeze=True, scope='alexnet_v2'): """AlexNet version 2. @@ -74,9 +74,9 @@ def alexnet_v2(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. + is_training: whether or not the model is being trained. dropout_keep_prob: the probability that activations are kept in the dropout layers during training. - is_training: whether or not the model is being trained. spatial_squeeze: whether or not should squeeze the spatial dimensions of the outputs. Useful to remove unnecessary dimensions for classification. scope: Optional scope for the variables. diff --git a/tensorflow/contrib/slim/python/slim/nets/inception.py b/tensorflow/contrib/slim/python/slim/nets/inception.py index b6ec1b9da6c3ac893cd43c66e772b3ea6b8f20f2..6f50025644b1cca371130bf7bfb99c4e15da8f90 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception.py @@ -20,8 +20,10 @@ from __future__ import print_function # pylint: disable=unused-import from tensorflow.contrib.slim.python.slim.nets.inception_v1 import inception_v1 +from tensorflow.contrib.slim.python.slim.nets.inception_v1 import inception_v1_arg_scope from tensorflow.contrib.slim.python.slim.nets.inception_v1 import inception_v1_base from tensorflow.contrib.slim.python.slim.nets.inception_v2 import inception_v2 +from tensorflow.contrib.slim.python.slim.nets.inception_v2 import inception_v2_arg_scope from tensorflow.contrib.slim.python.slim.nets.inception_v2 import inception_v2_base from tensorflow.contrib.slim.python.slim.nets.inception_v3 import inception_v3 from tensorflow.contrib.slim.python.slim.nets.inception_v3 import inception_v3_arg_scope diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v1.py b/tensorflow/contrib/slim/python/slim/nets/inception_v1.py index ede5e300f512bdb0756a0a4ec6979dfdc5e7218b..8b9e3254a312c2f124fb180e3e60f34cc5e4baec 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v1.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v1.py @@ -245,8 +245,8 @@ def inception_v1_base(inputs, def inception_v1(inputs, num_classes=1000, - dropout_keep_prob=0.8, is_training=True, + dropout_keep_prob=0.8, prediction_fn=slim.softmax, spatial_squeeze=True, reuse=None, @@ -265,8 +265,8 @@ def inception_v1(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. - dropout_keep_prob: the percentage of activation values that are retained. is_training: whether is training or not. + dropout_keep_prob: the percentage of activation values that are retained. prediction_fn: a function to get predictions out of logits. spatial_squeeze: if True, logits is of shape is [B, C], if false logits is of shape [B, 1, 1, C], where B is batch_size and C is number of classes. @@ -299,3 +299,52 @@ def inception_v1(inputs, end_points['Predictions'] = prediction_fn(logits, scope='Predictions') return logits, end_points inception_v1.default_image_size = 224 + + +def inception_v1_arg_scope(weight_decay=0.00004, + use_batch_norm=True, + batch_norm_var_collection='moving_vars'): + """Defines the default InceptionV1 arg scope. + + Note: Althougth the original paper didn't use batch_norm we found it useful. + + Args: + weight_decay: The weight decay to use for regularizing the model. + use_batch_norm: "If `True`, batch_norm is applied after each convolution. + batch_norm_var_collection: The name of the collection for the batch norm + variables. + + Returns: + An `arg_scope` to use for the inception v3 model. + """ + batch_norm_params = { + # Decay for the moving averages. + 'decay': 0.9997, + # epsilon to prevent 0s in variance. + 'epsilon': 0.001, + # collection containing update_ops. + 'updates_collections': tf.GraphKeys.UPDATE_OPS, + # collection containing the moving mean and moving variance. + 'variables_collections': { + 'beta': None, + 'gamma': None, + 'moving_mean': [batch_norm_var_collection], + 'moving_variance': [batch_norm_var_collection], + } + } + if use_batch_norm: + normalizer_fn = slim.batch_norm + normalizer_params = batch_norm_params + else: + normalizer_fn = None + normalizer_params = {} + # Set weight_decay for weights in Conv and FC layers. + with slim.arg_scope([slim.conv2d, slim.fully_connected], + weights_regularizer=slim.l2_regularizer(weight_decay)): + with slim.arg_scope( + [slim.conv2d], + weights_initializer=slim.variance_scaling_initializer(), + activation_fn=tf.nn.relu, + normalizer_fn=normalizer_fn, + normalizer_params=normalizer_params) as sc: + return sc diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v1_test.py b/tensorflow/contrib/slim/python/slim/nets/inception_v1_test.py index 3be79f792e3f2cf2bafacb25e6c1026e0fed9024..aeae7cffe69632c41ca74a4b46040a3c733bf9fa 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v1_test.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v1_test.py @@ -110,8 +110,7 @@ class InceptionV1Test(tf.test.TestCase): batch_size = 5 height, width = 224, 224 inputs = tf.random_uniform((batch_size, height, width, 3)) - with slim.arg_scope([slim.conv2d, slim.separable_conv2d], - normalizer_fn=slim.batch_norm): + with slim.arg_scope(inception.inception_v1_arg_scope()): inception.inception_v1_base(inputs) total_params, _ = slim.model_analyzer.analyze_vars( slim.get_model_variables()) diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v2.py b/tensorflow/contrib/slim/python/slim/nets/inception_v2.py index 3e419742e225960284fd7669e2ffced5068e3f55..2e8ddbd133aab7cf5667efad820ff43e9f3888f8 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v2.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v2.py @@ -413,8 +413,8 @@ def inception_v2_base(inputs, def inception_v2(inputs, num_classes=1000, - dropout_keep_prob=0.8, is_training=True, + dropout_keep_prob=0.8, min_depth=16, depth_multiplier=1.0, prediction_fn=slim.softmax, @@ -431,8 +431,8 @@ def inception_v2(inputs, Args: inputs: a tensor of shape [batch_size, height, width, channels]. num_classes: number of predicted classes. - dropout_keep_prob: the percentage of activation values that are retained. is_training: whether is training or not. + dropout_keep_prob: the percentage of activation values that are retained. min_depth: Minimum depth value (number of channels) for all convolution ops. Enforced when depth_multiplier < 1, and not an active constraint when depth_multiplier >= 1. @@ -513,3 +513,43 @@ def _reduced_kernel_size_for_small_input(input_tensor, kernel_size): kernel_size_out = [min(shape[1], kernel_size[0]), min(shape[2], kernel_size[1])] return kernel_size_out + + +def inception_v2_arg_scope(weight_decay=0.00004, + batch_norm_var_collection='moving_vars'): + """Defines the default InceptionV2 arg scope. + + Args: + weight_decay: The weight decay to use for regularizing the model. + batch_norm_var_collection: The name of the collection for the batch norm + variables. + + Returns: + An `arg_scope` to use for the inception v3 model. + """ + batch_norm_params = { + # Decay for the moving averages. + 'decay': 0.9997, + # epsilon to prevent 0s in variance. + 'epsilon': 0.001, + # collection containing update_ops. + 'updates_collections': tf.GraphKeys.UPDATE_OPS, + # collection containing the moving mean and moving variance. + 'variables_collections': { + 'beta': None, + 'gamma': None, + 'moving_mean': [batch_norm_var_collection], + 'moving_variance': [batch_norm_var_collection], + } + } + + # Set weight_decay for weights in Conv and FC layers. + with slim.arg_scope([slim.conv2d, slim.fully_connected], + weights_regularizer=slim.l2_regularizer(weight_decay)): + with slim.arg_scope( + [slim.conv2d], + weights_initializer=slim.variance_scaling_initializer(), + activation_fn=tf.nn.relu, + normalizer_fn=slim.batch_norm, + normalizer_params=batch_norm_params) as sc: + return sc diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v2_test.py b/tensorflow/contrib/slim/python/slim/nets/inception_v2_test.py index 15ab355d64d4ccf10c34e9e36f0c3730d3fe3836..f9d26b9b4d34965714eb0d6a5f1fcb54f27e74b4 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v2_test.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v2_test.py @@ -107,12 +107,11 @@ class InceptionV2Test(tf.test.TestCase): batch_size = 5 height, width = 224, 224 inputs = tf.random_uniform((batch_size, height, width, 3)) - with slim.arg_scope([slim.conv2d, slim.separable_conv2d], - normalizer_fn=slim.batch_norm): + with slim.arg_scope(inception.inception_v2_arg_scope()): inception.inception_v2_base(inputs) total_params, _ = slim.model_analyzer.analyze_vars( slim.get_model_variables()) - self.assertAlmostEqual(10173240, total_params) + self.assertAlmostEqual(10173112, total_params) def testBuildEndPointsWithDepthMultiplierLessThanOne(self): batch_size = 5 diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v3.py b/tensorflow/contrib/slim/python/slim/nets/inception_v3.py index cba112f7039d0149823a85e472983a341cc4c9b8..0efd90135295eb82581ff207a04e31ba095b0d4d 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v3.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v3.py @@ -416,8 +416,8 @@ def inception_v3_base(inputs, def inception_v3(inputs, num_classes=1000, - dropout_keep_prob=0.8, is_training=True, + dropout_keep_prob=0.8, min_depth=16, depth_multiplier=1.0, prediction_fn=slim.softmax, @@ -441,8 +441,8 @@ def inception_v3(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. - dropout_keep_prob: the percentage of activation values that are retained. is_training: whether is training or not. + dropout_keep_prob: the percentage of activation values that are retained. min_depth: Minimum depth value (number of channels) for all convolution ops. Enforced when depth_multiplier < 1, and not an active constraint when depth_multiplier >= 1. @@ -555,14 +555,12 @@ def _reduced_kernel_size_for_small_input(input_tensor, kernel_size): return kernel_size_out -def inception_v3_arg_scope(is_training=True, - weight_decay=0.00004, +def inception_v3_arg_scope(weight_decay=0.00004, stddev=0.1, batch_norm_var_collection='moving_vars'): """Defines the default InceptionV3 arg scope. Args: - is_training: Whether or not we're training the model. weight_decay: The weight decay to use for regularizing the model. stddev: The standard deviation of the trunctated normal weight initializer. batch_norm_var_collection: The name of the collection for the batch norm @@ -572,11 +570,12 @@ def inception_v3_arg_scope(is_training=True, An `arg_scope` to use for the inception v3 model. """ batch_norm_params = { - 'is_training': is_training, # Decay for the moving averages. 'decay': 0.9997, # epsilon to prevent 0s in variance. 'epsilon': 0.001, + # collection containing update_ops. + 'updates_collections': tf.GraphKeys.UPDATE_OPS, # collection containing the moving mean and moving variance. 'variables_collections': { 'beta': None, diff --git a/tensorflow/contrib/slim/python/slim/nets/inception_v3_test.py b/tensorflow/contrib/slim/python/slim/nets/inception_v3_test.py index 786715f327eef531b0b0e7d6501aa65482a96253..ca978e30fec38e33de61e4ef8cd8ac3ddcf33461 100644 --- a/tensorflow/contrib/slim/python/slim/nets/inception_v3_test.py +++ b/tensorflow/contrib/slim/python/slim/nets/inception_v3_test.py @@ -113,8 +113,7 @@ class InceptionV3Test(tf.test.TestCase): batch_size = 5 height, width = 299, 299 inputs = tf.random_uniform((batch_size, height, width, 3)) - with slim.arg_scope([slim.conv2d], - normalizer_fn=slim.batch_norm): + with slim.arg_scope(inception.inception_v3_arg_scope()): inception.inception_v3_base(inputs) total_params, _ = slim.model_analyzer.analyze_vars( slim.get_model_variables()) diff --git a/tensorflow/contrib/slim/python/slim/nets/overfeat.py b/tensorflow/contrib/slim/python/slim/nets/overfeat.py index c60f21300a72a647bd3716e4f765eaf6f3fd36b3..807862469f674a600c747ba03f173784d122478b 100644 --- a/tensorflow/contrib/slim/python/slim/nets/overfeat.py +++ b/tensorflow/contrib/slim/python/slim/nets/overfeat.py @@ -49,8 +49,8 @@ def overfeat_arg_scope(weight_decay=0.0005): def overfeat(inputs, num_classes=1000, - dropout_keep_prob=0.5, is_training=True, + dropout_keep_prob=0.5, spatial_squeeze=True, scope='overfeat'): """Contains the model definition for the OverFeat network. @@ -69,9 +69,9 @@ def overfeat(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. + is_training: whether or not the model is being trained. dropout_keep_prob: the probability that activations are kept in the dropout layers during training. - is_training: whether or not the model is being trained. spatial_squeeze: whether or not should squeeze the spatial dimensions of the outputs. Useful to remove unnecessary dimensions for classification. scope: Optional scope for the variables. diff --git a/tensorflow/contrib/slim/python/slim/nets/resnet_utils.py b/tensorflow/contrib/slim/python/slim/nets/resnet_utils.py index b375488cb046082495ba49dc97fa60824ff1b47a..de8c2effc21772ae82943ab43ce9cef565876ba2 100644 --- a/tensorflow/contrib/slim/python/slim/nets/resnet_utils.py +++ b/tensorflow/contrib/slim/python/slim/nets/resnet_utils.py @@ -206,7 +206,7 @@ def stack_blocks_dense(net, blocks, output_stride=None, return net -def resnet_arg_scope(is_training=False, +def resnet_arg_scope(is_training=True, weight_decay=0.0001, batch_norm_decay=0.997, batch_norm_epsilon=1e-5, @@ -236,7 +236,8 @@ def resnet_arg_scope(is_training=False, 'is_training': is_training, 'decay': batch_norm_decay, 'epsilon': batch_norm_epsilon, - 'scale': batch_norm_scale + 'scale': batch_norm_scale, + 'updates_collections': tf.GraphKeys.UPDATE_OPS, } with slim.arg_scope( diff --git a/tensorflow/contrib/slim/python/slim/nets/resnet_v1.py b/tensorflow/contrib/slim/python/slim/nets/resnet_v1.py index 072033edbfad5077504b15ddf4965b85655db75a..221185620bccbab4cdbb2463ea1fbcc67fb7adfe 100644 --- a/tensorflow/contrib/slim/python/slim/nets/resnet_v1.py +++ b/tensorflow/contrib/slim/python/slim/nets/resnet_v1.py @@ -196,6 +196,7 @@ def resnet_v1(inputs, if num_classes is not None: end_points['predictions'] = slim.softmax(net, scope='predictions') return net, end_points +resnet_v1.default_image_size = 224 def resnet_v1_50(inputs, diff --git a/tensorflow/contrib/slim/python/slim/nets/resnet_v2.py b/tensorflow/contrib/slim/python/slim/nets/resnet_v2.py index d9ece105dc4914abafeb51777f554f0fbfeda8e9..3712692f47a9869ddd6da182a3432447777a138c 100644 --- a/tensorflow/contrib/slim/python/slim/nets/resnet_v2.py +++ b/tensorflow/contrib/slim/python/slim/nets/resnet_v2.py @@ -205,6 +205,7 @@ def resnet_v2(inputs, if num_classes is not None: end_points['predictions'] = slim.softmax(net, scope='predictions') return net, end_points +resnet_v2.default_image_size = 224 def resnet_v2_50(inputs, diff --git a/tensorflow/contrib/slim/python/slim/nets/vgg.py b/tensorflow/contrib/slim/python/slim/nets/vgg.py index 42c23faa1ca20430ae76fcc3c9e27bd12b69f186..8c1821e9eabf8d70aee0b2f63c85e49264161c27 100644 --- a/tensorflow/contrib/slim/python/slim/nets/vgg.py +++ b/tensorflow/contrib/slim/python/slim/nets/vgg.py @@ -35,6 +35,7 @@ Usage: @@vgg_a @@vgg_16 +@@vgg_19 """ from __future__ import absolute_import from __future__ import division @@ -64,8 +65,8 @@ def vgg_arg_scope(weight_decay=0.0005): def vgg_a(inputs, num_classes=1000, - dropout_keep_prob=0.5, is_training=True, + dropout_keep_prob=0.5, spatial_squeeze=True, scope='vgg_a'): """Oxford Net VGG 11-Layers version A Example. @@ -76,9 +77,9 @@ def vgg_a(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. + is_training: whether or not the model is being trained. dropout_keep_prob: the probability that activations are kept in the dropout layers during training. - is_training: whether or not the model is being trained. spatial_squeeze: whether or not should squeeze the spatial dimensions of the outputs. Useful to remove unnecessary dimensions for classification. scope: Optional scope for the variables. @@ -123,8 +124,8 @@ vgg_a.default_image_size = 224 def vgg_16(inputs, num_classes=1000, - dropout_keep_prob=0.5, is_training=True, + dropout_keep_prob=0.5, spatial_squeeze=True, scope='vgg_16'): """Oxford Net VGG 16-Layers version D Example. @@ -135,9 +136,9 @@ def vgg_16(inputs, Args: inputs: a tensor of size [batch_size, height, width, channels]. num_classes: number of predicted classes. + is_training: whether or not the model is being trained. dropout_keep_prob: the probability that activations are kept in the dropout layers during training. - is_training: whether or not the model is being trained. spatial_squeeze: whether or not should squeeze the spatial dimensions of the outputs. Useful to remove unnecessary dimensions for classification. scope: Optional scope for the variables. @@ -179,5 +180,65 @@ def vgg_16(inputs, return net, end_points vgg_16.default_image_size = 224 + +def vgg_19(inputs, + num_classes=1000, + is_training=True, + dropout_keep_prob=0.5, + spatial_squeeze=True, + scope='vgg_19'): + """Oxford Net VGG 19-Layers version E Example. + + Note: All the fully_connected layers have been transformed to conv2d layers. + To use in classification mode, resize input to 224x224. + + Args: + inputs: a tensor of size [batch_size, height, width, channels]. + num_classes: number of predicted classes. + is_training: whether or not the model is being trained. + dropout_keep_prob: the probability that activations are kept in the dropout + layers during training. + spatial_squeeze: whether or not should squeeze the spatial dimensions of the + outputs. Useful to remove unnecessary dimensions for classification. + scope: Optional scope for the variables. + + Returns: + the last op containing the log predictions and end_points dict. + """ + with tf.variable_scope(scope, 'vgg_19', [inputs]) as sc: + end_points_collection = sc.name + '_end_points' + # Collect outputs for conv2d, fully_connected and max_pool2d. + with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d], + outputs_collections=end_points_collection): + net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1') + net = slim.max_pool2d(net, [2, 2], scope='pool1') + net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2') + net = slim.max_pool2d(net, [2, 2], scope='pool2') + net = slim.repeat(net, 4, slim.conv2d, 256, [3, 3], scope='conv3') + net = slim.max_pool2d(net, [2, 2], scope='pool3') + net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv4') + net = slim.max_pool2d(net, [2, 2], scope='pool4') + net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv5') + net = slim.max_pool2d(net, [2, 2], scope='pool5') + # Use conv2d instead of fully_connected layers. + net = slim.conv2d(net, 4096, [7, 7], padding='VALID', scope='fc6') + net = slim.dropout(net, dropout_keep_prob, is_training=is_training, + scope='dropout6') + net = slim.conv2d(net, 4096, [1, 1], scope='fc7') + net = slim.dropout(net, dropout_keep_prob, is_training=is_training, + scope='dropout7') + net = slim.conv2d(net, num_classes, [1, 1], + activation_fn=None, + normalizer_fn=None, + scope='fc8') + # Convert end_points_collection into a end_point dict. + end_points = dict(tf.get_collection(end_points_collection)) + if spatial_squeeze: + net = tf.squeeze(net, [1, 2], name='fc8/squeezed') + end_points[sc.name + '/fc8'] = net + return net, end_points +vgg_19.default_image_size = 224 + # Alias vgg_d = vgg_16 +vgg_e = vgg_19 diff --git a/tensorflow/contrib/slim/python/slim/nets/vgg_test.py b/tensorflow/contrib/slim/python/slim/nets/vgg_test.py index 5bb6562fd04e283035d5ae9d6af972880146606a..53837d32165baa5bf4a911c517a015b011f7881f 100644 --- a/tensorflow/contrib/slim/python/slim/nets/vgg_test.py +++ b/tensorflow/contrib/slim/python/slim/nets/vgg_test.py @@ -206,7 +206,6 @@ class VGG16Test(tf.test.TestCase): 'vgg_16/fc7', 'vgg_16/fc8' ] - print(end_points.keys()) self.assertSetEqual(set(end_points.keys()), set(expected_names)) def testModelVariables(self): @@ -297,5 +296,160 @@ class VGG16Test(tf.test.TestCase): output = sess.run(logits) self.assertTrue(output.any()) + +class VGG19Test(tf.test.TestCase): + + def testBuild(self): + batch_size = 5 + height, width = 224, 224 + num_classes = 1000 + with self.test_session(): + inputs = tf.random_uniform((batch_size, height, width, 3)) + logits, _ = vgg.vgg_19(inputs, num_classes) + self.assertEquals(logits.op.name, 'vgg_19/fc8/squeezed') + self.assertListEqual(logits.get_shape().as_list(), + [batch_size, num_classes]) + + def testFullyConvolutional(self): + batch_size = 1 + height, width = 256, 256 + num_classes = 1000 + with self.test_session(): + inputs = tf.random_uniform((batch_size, height, width, 3)) + logits, _ = vgg.vgg_19(inputs, num_classes, spatial_squeeze=False) + self.assertEquals(logits.op.name, 'vgg_19/fc8/BiasAdd') + self.assertListEqual(logits.get_shape().as_list(), + [batch_size, 2, 2, num_classes]) + + def testEndPoints(self): + batch_size = 5 + height, width = 224, 224 + num_classes = 1000 + with self.test_session(): + inputs = tf.random_uniform((batch_size, height, width, 3)) + _, end_points = vgg.vgg_19(inputs, num_classes) + expected_names = [ + 'vgg_19/conv1/conv1_1', + 'vgg_19/conv1/conv1_2', + 'vgg_19/pool1', + 'vgg_19/conv2/conv2_1', + 'vgg_19/conv2/conv2_2', + 'vgg_19/pool2', + 'vgg_19/conv3/conv3_1', + 'vgg_19/conv3/conv3_2', + 'vgg_19/conv3/conv3_3', + 'vgg_19/conv3/conv3_4', + 'vgg_19/pool3', + 'vgg_19/conv4/conv4_1', + 'vgg_19/conv4/conv4_2', + 'vgg_19/conv4/conv4_3', + 'vgg_19/conv4/conv4_4', + 'vgg_19/pool4', + 'vgg_19/conv5/conv5_1', + 'vgg_19/conv5/conv5_2', + 'vgg_19/conv5/conv5_3', + 'vgg_19/conv5/conv5_4', + 'vgg_19/pool5', + 'vgg_19/fc6', + 'vgg_19/fc7', + 'vgg_19/fc8' + ] + self.assertSetEqual(set(end_points.keys()), set(expected_names)) + + def testModelVariables(self): + batch_size = 5 + height, width = 224, 224 + num_classes = 1000 + with self.test_session(): + inputs = tf.random_uniform((batch_size, height, width, 3)) + vgg.vgg_19(inputs, num_classes) + expected_names = [ + 'vgg_19/conv1/conv1_1/weights', + 'vgg_19/conv1/conv1_1/biases', + 'vgg_19/conv1/conv1_2/weights', + 'vgg_19/conv1/conv1_2/biases', + 'vgg_19/conv2/conv2_1/weights', + 'vgg_19/conv2/conv2_1/biases', + 'vgg_19/conv2/conv2_2/weights', + 'vgg_19/conv2/conv2_2/biases', + 'vgg_19/conv3/conv3_1/weights', + 'vgg_19/conv3/conv3_1/biases', + 'vgg_19/conv3/conv3_2/weights', + 'vgg_19/conv3/conv3_2/biases', + 'vgg_19/conv3/conv3_3/weights', + 'vgg_19/conv3/conv3_3/biases', + 'vgg_19/conv3/conv3_4/weights', + 'vgg_19/conv3/conv3_4/biases', + 'vgg_19/conv4/conv4_1/weights', + 'vgg_19/conv4/conv4_1/biases', + 'vgg_19/conv4/conv4_2/weights', + 'vgg_19/conv4/conv4_2/biases', + 'vgg_19/conv4/conv4_3/weights', + 'vgg_19/conv4/conv4_3/biases', + 'vgg_19/conv4/conv4_4/weights', + 'vgg_19/conv4/conv4_4/biases', + 'vgg_19/conv5/conv5_1/weights', + 'vgg_19/conv5/conv5_1/biases', + 'vgg_19/conv5/conv5_2/weights', + 'vgg_19/conv5/conv5_2/biases', + 'vgg_19/conv5/conv5_3/weights', + 'vgg_19/conv5/conv5_3/biases', + 'vgg_19/conv5/conv5_4/weights', + 'vgg_19/conv5/conv5_4/biases', + 'vgg_19/fc6/weights', + 'vgg_19/fc6/biases', + 'vgg_19/fc7/weights', + 'vgg_19/fc7/biases', + 'vgg_19/fc8/weights', + 'vgg_19/fc8/biases', + ] + model_variables = [v.op.name for v in slim.get_model_variables()] + self.assertSetEqual(set(model_variables), set(expected_names)) + + def testEvaluation(self): + batch_size = 2 + height, width = 224, 224 + num_classes = 1000 + with self.test_session(): + eval_inputs = tf.random_uniform((batch_size, height, width, 3)) + logits, _ = vgg.vgg_19(eval_inputs, is_training=False) + self.assertListEqual(logits.get_shape().as_list(), + [batch_size, num_classes]) + predictions = tf.argmax(logits, 1) + self.assertListEqual(predictions.get_shape().as_list(), [batch_size]) + + def testTrainEvalWithReuse(self): + train_batch_size = 2 + eval_batch_size = 1 + train_height, train_width = 224, 224 + eval_height, eval_width = 256, 256 + num_classes = 1000 + with self.test_session(): + train_inputs = tf.random_uniform( + (train_batch_size, train_height, train_width, 3)) + logits, _ = vgg.vgg_19(train_inputs) + self.assertListEqual(logits.get_shape().as_list(), + [train_batch_size, num_classes]) + tf.get_variable_scope().reuse_variables() + eval_inputs = tf.random_uniform( + (eval_batch_size, eval_height, eval_width, 3)) + logits, _ = vgg.vgg_19(eval_inputs, is_training=False, + spatial_squeeze=False) + self.assertListEqual(logits.get_shape().as_list(), + [eval_batch_size, 2, 2, num_classes]) + logits = tf.reduce_mean(logits, [1, 2]) + predictions = tf.argmax(logits, 1) + self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size]) + + def testForward(self): + batch_size = 1 + height, width = 224, 224 + with self.test_session() as sess: + inputs = tf.random_uniform((batch_size, height, width, 3)) + logits, _ = vgg.vgg_19(inputs) + sess.run(tf.initialize_all_variables()) + output = sess.run(logits) + self.assertTrue(output.any()) + if __name__ == '__main__': tf.test.main() diff --git a/tensorflow/contrib/tensor_forest/core/ops/best_splits_op.cc b/tensorflow/contrib/tensor_forest/core/ops/best_splits_op.cc index ecb856c2ffb4f31966e3f9e7a0c050fa2f7a63ed..421f371d9e50c36230b4f769ddc27b86326f2b59 100644 --- a/tensorflow/contrib/tensor_forest/core/ops/best_splits_op.cc +++ b/tensorflow/contrib/tensor_forest/core/ops/best_splits_op.cc @@ -26,9 +26,9 @@ namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; using std::placeholders::_1; using tensorforest::BestFeatureClassification; @@ -45,7 +45,7 @@ REGISTER_OP("BestSplits") .Input("accumulator_sqaures: float") .Output("split_indices: int32") .SetShapeFn([](InferenceContext* c) { - const Shape* finished_nodes; + ShapeHandle finished_nodes; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &finished_nodes)); c->set_output(0, c->Vector(c->Dim(finished_nodes, 0))); return Status::OK(); diff --git a/tensorflow/contrib/tensor_forest/core/ops/count_extremely_random_stats_op.cc b/tensorflow/contrib/tensor_forest/core/ops/count_extremely_random_stats_op.cc index cd224b0cb936e1e53813032f8a7ca95b6fb0cffe..f49afa025c061658cae7e32640bda3baec2de269 100644 --- a/tensorflow/contrib/tensor_forest/core/ops/count_extremely_random_stats_op.cc +++ b/tensorflow/contrib/tensor_forest/core/ops/count_extremely_random_stats_op.cc @@ -49,9 +49,9 @@ using tensorforest::Initialize; using tensorforest::IsAllInitialized; using tensorforest::FeatureSpec; -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; // A data structure to store the results of parallel tree traversal. struct InputDataResult { @@ -174,11 +174,11 @@ REGISTER_OP("CountExtremelyRandomStats") bool regression; TF_RETURN_IF_ERROR(c->GetAttr("regression", ®ression)); - const Dimension* num_points = c->Dim(c->input(0), 0); + DimensionHandle num_points = c->Dim(c->input(0), 0); if (c->RankKnown(c->input(3)) && c->Rank(c->input(3)) > 0) { num_points = c->UnknownDim(); } - const Dimension* num_nodes = c->Dim(c->input(7), 0); + DimensionHandle num_nodes = c->Dim(c->input(7), 0); // Node sums c->set_output(0, c->Matrix(num_nodes, num_classes)); diff --git a/tensorflow/contrib/tensor_forest/core/ops/sample_inputs_op.cc b/tensorflow/contrib/tensor_forest/core/ops/sample_inputs_op.cc index 01d3b30abc24e0965eb5cd90dec0210a2fab6329..565353bcf37959758f50f76a437ab11ed2880120 100644 --- a/tensorflow/contrib/tensor_forest/core/ops/sample_inputs_op.cc +++ b/tensorflow/contrib/tensor_forest/core/ops/sample_inputs_op.cc @@ -23,15 +23,16 @@ #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/shape_inference.h" #include "tensorflow/core/kernels/bounds_check.h" +#include "tensorflow/core/lib/random/distribution_sampler.h" #include "tensorflow/core/lib/random/philox_random.h" #include "tensorflow/core/lib/random/simple_philox.h" #include "tensorflow/core/platform/logging.h" namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; using tensorforest::CheckTensorBounds; using tensorforest::IsAllInitialized; @@ -43,6 +44,7 @@ REGISTER_OP("SampleInputs") .Input("sparse_input_indices: int64") .Input("sparse_input_values: float") .Input("sparse_input_shape: int64") + .Input("input_weights: float") .Input("node_to_accumulator: int32") .Input("leaves: int32") .Input("candidate_split_features: int32") @@ -51,10 +53,10 @@ REGISTER_OP("SampleInputs") .Output("new_split_feature_rows: int32") .Output("new_split_threshold_rows: float") .SetShapeFn([](InferenceContext* c) { - const Shape* candidate_split_features; + ShapeHandle candidate_split_features; TF_RETURN_IF_ERROR( - c->WithRank(c->input(6), 2, &candidate_split_features)); - const Dimension* split_dim = c->Dim(candidate_split_features, 1); + c->WithRank(c->input(7), 2, &candidate_split_features)); + DimensionHandle split_dim = c->Dim(candidate_split_features, 1); c->set_output(0, c->Vector(InferenceContext::kUnknownDim)); c->set_output(1, c->Matrix(InferenceContext::kUnknownDim, split_dim)); c->set_output(2, c->Matrix(InferenceContext::kUnknownDim, split_dim)); @@ -81,6 +83,12 @@ input_data: The features for the current batch of training data. sparse_input_indices: The indices tensor from the SparseTensor input. sparse_input_values: The values tensor from the SparseTensor input. sparse_input_shape: The shape tensor from the SparseTensor input. +input_weights: For a dense input, input_weights[i] is the weight associated + with input_data[i]. For sparse input, input_weights[i] is the weight + associated with sparse_input_values[i]. Or in either case, if all the + weights are 1, input_weights can be empty. SampleInputs will reject inputs + with weight less than Uniform([0,1)), so weights outside of that range may + not be what you want. node_to_accumulator: For a fertile node i, node_to_accumulator[i] is the associated accumulator slot. For non-fertile nodes, it is -1. leaves: `leaves[i]` is the leaf that the i-th input landed in, as @@ -166,18 +174,33 @@ class SampleInputs : public OpKernel { return false; } + // increment_input implements a "++" operation for the situation when + // you want to do something n times on an underlying iterator. + // In an ideal world, this would be a built-in iterator adaptor. + template + static void increment_input(const int n, T* it, int* count) { + *count += 1; + if (*count == n) { + *count = 0; + (*it)++; + } + } + void Compute(OpKernelContext* context) override { const Tensor& input_data = context->input(0); const Tensor& sparse_input_indices = context->input(1); const Tensor& sparse_input_values = context->input(2); const Tensor& sparse_input_shape = context->input(3); - const Tensor& node_to_accumulator = context->input(4); - const Tensor& leaves = context->input(5); - const Tensor& split_features = context->input(6); - const Tensor& split_thresholds = context->input(7); + const Tensor& input_weights = context->input(4); + const Tensor& node_to_accumulator = context->input(5); + const Tensor& leaves = context->input(6); + const Tensor& split_features = context->input(7); + const Tensor& split_thresholds = context->input(8); bool sparse_input = (sparse_input_indices.shape().dims() == 2); + bool have_weights = (input_weights.shape().dim_size(0) > 0); + if (sparse_input) { OP_REQUIRES(context, sparse_input_shape.shape().dims() == 1, errors::InvalidArgument( @@ -198,10 +221,24 @@ class SampleInputs : public OpKernel { errors::InvalidArgument( "sparse_input_indices and sparse_input_values should " "agree on the number of non-zero values")); + if (have_weights) { + OP_REQUIRES(context, sparse_input_values.shape().dim_size(0) == + input_weights.shape().dim_size(0), + errors::InvalidArgument( + "sparse_input_values and input_weights should agree " + "on the number of inputs")); + } } else { OP_REQUIRES(context, input_data.shape().dims() == 2, errors::InvalidArgument( "input_data should be two-dimensional")); + if (have_weights) { + OP_REQUIRES(context, input_data.shape().dim_size(0) == + input_weights.shape().dim_size(0), + errors::InvalidArgument( + "input_data and input_weights should agree on the " + "number of inputs")); + } } OP_REQUIRES(context, node_to_accumulator.shape().dims() == 1, @@ -228,6 +265,7 @@ class SampleInputs : public OpKernel { if (!CheckTensorBounds(context, sparse_input_indices)) return; if (!CheckTensorBounds(context, sparse_input_values)) return; if (!CheckTensorBounds(context, sparse_input_shape)) return; + if (!CheckTensorBounds(context, input_weights)) return; if (!CheckTensorBounds(context, node_to_accumulator)) return; if (!CheckTensorBounds(context, leaves)) return; if (!CheckTensorBounds(context, split_features)) return; @@ -260,6 +298,7 @@ class SampleInputs : public OpKernel { const auto node_map = node_to_accumulator.unaligned_flat(); const auto features = split_features.tensor(); const auto thresholds = split_thresholds.tensor(); + const auto weights = input_weights.tensor(); const int32 num_data = static_cast(leaves.shape().dim_size(0)); const int32 num_splits = static_cast( @@ -338,24 +377,41 @@ class SampleInputs : public OpKernel { thresholds(accumulator, split); } - for (const int32 i : inputs_for_accumulator) { - VLOG(2) << "Looking at data # " << i; - - int32 num_inits = split_initializations_per_input_; - for (int split = 0; split < num_splits && num_inits > 0; split++) { - if (new_split_feature_rows_flat(output_slot, split) < 0) { - VLOG(1) << "Over-writing @ " << output_slot << "," << split; - int32 index; - float val; - const bool success = get_random_feature(i, &index, &val); - if (success) { - new_split_feature_rows_flat(output_slot, split) = index; - new_split_threshold_rows_flat(output_slot, split) = val; - --num_inits; - } else { + auto it = inputs_for_accumulator.begin(); + int input_used_count = 0; + for (int split = 0; + split < num_splits && it != inputs_for_accumulator.end(); split++) { + if (new_split_feature_rows_flat(output_slot, split) < 0) { + if (have_weights) { + // If we have weights, we probabilistically reject inputs with + // low weight. Which means we might have to look at a bunch of + // inputs -- maybe even all of them -- to fill this slot. + while (it != inputs_for_accumulator.end()) { + float w = weights(*it); + if (rng_->RandFloat() <= w) { + break; + } + increment_input(split_initializations_per_input_, &it, + &input_used_count); + } + if (it == inputs_for_accumulator.end()) { break; } } + int32 index; + float val; + const bool success = get_random_feature(*it, &index, &val); + increment_input(split_initializations_per_input_, &it, + &input_used_count); + if (success) { + VLOG(1) << "Over-writing @ " << output_slot << "," << split; + new_split_feature_rows_flat(output_slot, split) = index; + new_split_threshold_rows_flat(output_slot, split) = val; + } else { + VLOG(1) << "get_random_feature failed, bailing on output for " + << "accumulator " << accumulator; + break; + } } } ++output_slot; diff --git a/tensorflow/contrib/tensor_forest/core/ops/training_ops_test.cc b/tensorflow/contrib/tensor_forest/core/ops/training_ops_test.cc index ba9a3a18c2780667327568b6b16291e873741c39..cbb899a3e9539d0ae19b8fec0be5032c202c9575 100644 --- a/tensorflow/contrib/tensor_forest/core/ops/training_ops_test.cc +++ b/tensorflow/contrib/tensor_forest/core/ops/training_ops_test.cc @@ -55,12 +55,12 @@ TEST(TrainingOpsTest, BestSplits_ShapeFn) { TEST(TrainingOpsTest, SampleInputs_ShapeFn) { ShapeInferenceTestOp op("SampleInputs"); - // input[6].dim(1) determines dims in the output. - INFER_OK(op, "?;?;?;?;?;?;?;?", "[?];[?,?];[?,?]"); - INFER_OK(op, "?;?;?;?;?;?;[?,?];?", "[?];[?,d6_1];[?,d6_1]"); - INFER_OK(op, "?;?;?;?;?;?;[1,2];?", "[?];[?,d6_1];[?,d6_1]"); + // input[7].dim(1) determines dims in the output. + INFER_OK(op, "?;?;?;?;?;?;?;?;?", "[?];[?,?];[?,?]"); + INFER_OK(op, "?;?;?;?;?;?;?;[?,?];?", "[?];[?,d7_1];[?,d7_1]"); + INFER_OK(op, "?;?;?;?;?;?;?;[1,2];?", "[?];[?,d7_1];[?,d7_1]"); INFER_ERROR("Shape must be rank 2 but is rank 3", op, - "?;?;?;?;?;?;[1,2,3];?"); + "?;?;?;?;?;?;?;[1,2,3];?"); } TEST(TrainingOpsTest, CountExtremelyRandomStats_ShapeFn) { diff --git a/tensorflow/contrib/tensor_forest/core/ops/tree_predictions_op.cc b/tensorflow/contrib/tensor_forest/core/ops/tree_predictions_op.cc index dab1aca99eb9a2d91c0caf2a59d34ed79a6682a8..4a81d6d6c67714e0e8d0aa7cf60da0c5e8b13e9f 100644 --- a/tensorflow/contrib/tensor_forest/core/ops/tree_predictions_op.cc +++ b/tensorflow/contrib/tensor_forest/core/ops/tree_predictions_op.cc @@ -35,9 +35,9 @@ using tensorforest::DataColumnTypes; using tensorforest::FeatureSpec; using tensorforest::Sum; -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("TreePredictions") .Attr("valid_leaf_threshold: float") @@ -55,8 +55,8 @@ REGISTER_OP("TreePredictions") .SetShapeFn([](InferenceContext* c) { // The output of TreePredictions is // [node_pcw(evaluate_tree(x), c) for c in classes for x in input_data]. - const Dimension* num_points = c->Dim(c->input(0), 0); - const Dimension* num_classes = c->Dim(c->input(7), 1); + DimensionHandle num_points = c->Dim(c->input(0), 0); + DimensionHandle num_classes = c->Dim(c->input(7), 1); if (c->RankKnown(c->input(3)) && c->Rank(c->input(3)) > 0) { num_points = c->UnknownDim(); diff --git a/tensorflow/contrib/tensor_forest/python/kernel_tests/sample_inputs_op_test.py b/tensorflow/contrib/tensor_forest/python/kernel_tests/sample_inputs_op_test.py index 9830651a5d0b25fa8d16166ac7d5ffa28b6bf5f7..58f3e898ae0b2be89cf37a8464f75e238e350e7a 100644 --- a/tensorflow/contrib/tensor_forest/python/kernel_tests/sample_inputs_op_test.py +++ b/tensorflow/contrib/tensor_forest/python/kernel_tests/sample_inputs_op_test.py @@ -39,12 +39,14 @@ class SampleInputsTest(test_util.TensorFlowTestCase): def testSimple(self): with self.test_session(): tf.initialize_all_variables().run() - indices, feature_updates, threshold_updates = ( - self.ops.sample_inputs( - self.input_data, [], [], [], - self.node_map, self.leaves, self.split_features, - self.split_thresholds, split_initializations_per_input=1, - split_sampling_random_seed=3)) + indices, feature_updates, threshold_updates = (self.ops.sample_inputs( + self.input_data, [], [], [], [], + self.node_map, + self.leaves, + self.split_features, + self.split_thresholds, + split_initializations_per_input=1, + split_sampling_random_seed=3)) self.assertAllEqual([1, 0], indices.eval()) self.assertAllEqual([[1, 0, 1], [0, 0, -1]], feature_updates.eval()) @@ -64,27 +66,49 @@ class SampleInputsTest(test_util.TensorFlowTestCase): with self.test_session(): tf.initialize_all_variables().run() - indices, feature_updates, threshold_updates = ( - self.ops.sample_inputs( - [], sparse_indices, sparse_values, sparse_shape, - self.node_map, self.leaves, self.split_features, - self.split_thresholds, split_initializations_per_input=1, - split_sampling_random_seed=3)) + indices, feature_updates, threshold_updates = (self.ops.sample_inputs( + [], + sparse_indices, + sparse_values, + sparse_shape, [], + self.node_map, + self.leaves, + self.split_features, + self.split_thresholds, + split_initializations_per_input=1, + split_sampling_random_seed=3)) self.assertAllEqual([1, 0], indices.eval()) self.assertAllEqual([[1, 0, 0], [4, 7, -1]], feature_updates.eval()) self.assertAllEqual([[5., -2., -2.], [-1., 6., 0.]], threshold_updates.eval()) + def testWeights(self): + with self.test_session(): + tf.initialize_all_variables().run() + indices, feature_updates, threshold_updates = (self.ops.sample_inputs( + self.input_data, [], [], [], [0.5, 0.1, 0.8, 0.7], + self.node_map, + self.leaves, + self.split_features, + self.split_thresholds, + split_initializations_per_input=1, + split_sampling_random_seed=3)) + self.assertAllEqual([1, 0], indices.eval()) + self.assertAllEqual([[1, 0, 0], [-1, -1, -1]], feature_updates.eval()) + self.assertAllEqual([[5., -2., 20.], [0., 0., 0.]], + threshold_updates.eval()) + def testNoAccumulators(self): with self.test_session(): tf.initialize_all_variables().run() - indices, feature_updates, threshold_updates = ( - self.ops.sample_inputs( - self.input_data, [], [], [], - [-1] * 3, self.leaves, self.split_features, - self.split_thresholds, split_initializations_per_input=1, - split_sampling_random_seed=3)) + indices, feature_updates, threshold_updates = (self.ops.sample_inputs( + self.input_data, [], [], [], [], [-1] * 3, + self.leaves, + self.split_features, + self.split_thresholds, + split_initializations_per_input=1, + split_sampling_random_seed=3)) self.assertAllEqual([], indices.eval()) self.assertAllEqual((0, 3), feature_updates.eval().shape) self.assertAllEqual((0, 3), threshold_updates.eval().shape) @@ -96,9 +120,12 @@ class SampleInputsTest(test_util.TensorFlowTestCase): with self.assertRaisesOpError( 'split_features and split_thresholds should be the same shape.'): indices, _, _ = self.ops.sample_inputs( - self.input_data, [], [], [], - self.node_map, self.leaves, self.split_features, - self.split_thresholds, split_initializations_per_input=1, + self.input_data, [], [], [], [], + self.node_map, + self.leaves, + self.split_features, + self.split_thresholds, + split_initializations_per_input=1, split_sampling_random_seed=3) self.assertAllEqual([], indices.eval()) diff --git a/tensorflow/contrib/tensor_forest/python/ops/training_ops.py b/tensorflow/contrib/tensor_forest/python/ops/training_ops.py index 399457107496ed7b5a14e585e9e26221b2cdabc5..b56ca58e07c80443cc6fca9bde7fe6e66de5c72f 100644 --- a/tensorflow/contrib/tensor_forest/python/ops/training_ops.py +++ b/tensorflow/contrib/tensor_forest/python/ops/training_ops.py @@ -69,7 +69,7 @@ def _CountExtremelyRandomStatsShape(op): @ops.RegisterShape('SampleInputs') def _SampleInputsShape(op): """Shape function for SampleInputs Op.""" - num_splits = op.inputs[6].get_shape()[1].value + num_splits = op.inputs[7].get_shape()[1].value return [[None], [None, num_splits], [None, num_splits]] diff --git a/tensorflow/contrib/tensor_forest/python/tensor_forest.py b/tensorflow/contrib/tensor_forest/python/tensor_forest.py index 3e7d13d72df7559ebd66801904e825ebc0e9d372..c28bd4ff41e792f5c5df0e8580c9c0d92cef2d63 100644 --- a/tensorflow/contrib/tensor_forest/python/tensor_forest.py +++ b/tensorflow/contrib/tensor_forest/python/tensor_forest.py @@ -610,9 +610,14 @@ class RandomTreeGraphs(object): # Sample inputs. update_indices, feature_updates, threshold_updates = ( self.training_ops.sample_inputs( - input_data, sparse_indices, sparse_values, sparse_shape, + input_data, + sparse_indices, + sparse_values, + sparse_shape, + input_weights, self.variables.node_to_accumulator_map, - input_leaves, self.variables.candidate_split_features, + input_leaves, + self.variables.candidate_split_features, self.variables.candidate_split_thresholds, split_initializations_per_input=( self.params.split_initializations_per_input), diff --git a/tensorflow/contrib/training/BUILD b/tensorflow/contrib/training/BUILD index 5b7046919e0c41f91909986dca0bb8a431ea1120..a44143ba4062f248f39dcd9a59f4eb358230c782 100644 --- a/tensorflow/contrib/training/BUILD +++ b/tensorflow/contrib/training/BUILD @@ -11,6 +11,7 @@ py_library( name = "training_py", srcs = [ "__init__.py", + "python/training/sampling_ops.py", "python/training/sequence_queueing_state_saver.py", ], srcs_version = "PY2AND3", @@ -41,6 +42,31 @@ py_test( ], ) +py_test( + name = "sampling_ops_test", + size = "small", + srcs = ["python/training/sampling_ops_test.py"], + srcs_version = "PY2AND3", + deps = [ + ":training_py", + "//tensorflow:tensorflow_py", + "//tensorflow/python:framework_test_lib", + ], +) + +py_test( + name = "sampling_ops_threading_test", + size = "small", + srcs = ["python/training/sampling_ops_threading_test.py"], + srcs_version = "PY2AND3", + tags = ["notsan"], + deps = [ + ":training_py", + "//tensorflow:tensorflow_py", + "//tensorflow/python:framework_test_lib", + ], +) + filegroup( name = "all_files", srcs = glob( diff --git a/tensorflow/contrib/training/__init__.py b/tensorflow/contrib/training/__init__.py index fcd4f4b6cc317d732b38b3b7c34f47feac6c5c64..d8cd9058008521f2657e449696f81e34358fd7f7 100644 --- a/tensorflow/contrib/training/__init__.py +++ b/tensorflow/contrib/training/__init__.py @@ -25,6 +25,19 @@ like to store state in the forward direction across segments of an example. @@batch_sequences_with_states @@NextQueuedSequenceBatch @@SequenceQueueingStateSaver + + +## Online data resampling + +Use ['stratified_sample'](#stratified_sample) or +['stratified_sample_unknown_dist'](#stratified_sample_unknown_dist) to resample +from the data and change the class proportions that the Tensorflow graph sees. +For instance, if you have a binary classification dataset that is 99.9% class +1, a common approach is to resample from the data so that the data is more +balanced. + +@@stratified_sample +@@stratified_sample_unknown_dist """ from __future__ import absolute_import @@ -32,6 +45,7 @@ from __future__ import division from __future__ import print_function # pylint: disable=unused-import,wildcard-import +from tensorflow.contrib.training.python.training.sampling_ops import * from tensorflow.contrib.training.python.training.sequence_queueing_state_saver import * from tensorflow.python.util.all_util import make_all diff --git a/tensorflow/contrib/framework/python/ops/sampling_ops.py b/tensorflow/contrib/training/python/training/sampling_ops.py similarity index 100% rename from tensorflow/contrib/framework/python/ops/sampling_ops.py rename to tensorflow/contrib/training/python/training/sampling_ops.py diff --git a/tensorflow/contrib/framework/python/ops/sampling_ops_test.py b/tensorflow/contrib/training/python/training/sampling_ops_test.py similarity index 89% rename from tensorflow/contrib/framework/python/ops/sampling_ops_test.py rename to tensorflow/contrib/training/python/training/sampling_ops_test.py index 5b974f58487d3a817fc0adaaf686ba4f0d6bced0..6f7c2eda0d0deafdaa0d462a480f2ba65c8e79c7 100644 --- a/tensorflow/contrib/framework/python/ops/sampling_ops_test.py +++ b/tensorflow/contrib/training/python/training/sampling_ops_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np import tensorflow as tf +from tensorflow.contrib.training.python.training import sampling_ops from tensorflow.python.platform import tf_logging as logging @@ -35,7 +36,7 @@ class SamplingOpsTest(tf.test.TestCase): # Curry the rejection sampler so we can easily run the same tests on both # stratified_sample and stratified_sample_unknown_dist. def curried_sampler(tensors, labels, probs, batch_size, enqueue_many=True): - return tf.contrib.framework.sampling_ops.stratified_sample( + return tf.contrib.training.stratified_sample( tensors=tensors, labels=labels, target_probs=probs, @@ -44,7 +45,7 @@ class SamplingOpsTest(tf.test.TestCase): enqueue_many=enqueue_many) samplers = [ - tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist, + tf.contrib.training.stratified_sample_unknown_dist, curried_sampler, ] @@ -85,18 +86,18 @@ class SamplingOpsTest(tf.test.TestCase): # In the rejection sampling case, make sure that probability lengths are # the same. with self.assertRaises(ValueError): - tf.contrib.framework.sampling_ops.stratified_sample( + tf.contrib.training.stratified_sample( val, label, [.1] * 10, batch_size, init_probs=[.2] * 5) # In the rejection sampling case, make sure that zero initial probability # classes also have zero target probability. with self.assertRaises(ValueError): - tf.contrib.framework.sampling_ops.stratified_sample( + tf.contrib.training.stratified_sample( val, label, [.2, .4, .4], batch_size, init_probs=[0, .5, .5]) # Probabilities must be 1D. with self.assertRaises(ValueError): - tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( + tf.contrib.training.stratified_sample_unknown_dist( val, label, np.array([[.25, .25], [.25, .25]]), batch_size) def testRuntimeAssertionFailures(self): @@ -118,7 +119,7 @@ class SamplingOpsTest(tf.test.TestCase): # Set up graph with illegal label vector. label_ph = tf.placeholder(tf.int32, shape=[None]) probs_ph = tf.placeholder(tf.float32, shape=[5]) # shape must be defined - val_tf, lbl_tf, prob_tf = tf.contrib.framework.sampling_ops._verify_input( + val_tf, lbl_tf, prob_tf = sampling_ops._verify_input( # pylint: disable=protected-access vals, label_ph, [probs_ph]) for illegal_label in illegal_labels: @@ -162,13 +163,13 @@ class SamplingOpsTest(tf.test.TestCase): val_input_batch = [tf.zeros([2, 3, 4])] lbl_input_batch = tf.ones([], dtype=tf.int32) probs = np.array([0, 1, 0, 0, 0]) - batches = tf.contrib.framework.sampling_ops.stratified_sample( + batches = tf.contrib.training.stratified_sample( val_input_batch, lbl_input_batch, probs, batch_size, init_probs=probs) - batches += tf.contrib.framework.sampling_ops.stratified_sample( + batches += tf.contrib.training.stratified_sample( val_input_batch, lbl_input_batch, probs, batch_size, init_probs=probs) - batches += tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( + batches += tf.contrib.training.stratified_sample_unknown_dist( val_input_batch, lbl_input_batch, probs, batch_size) - batches += tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( + batches += tf.contrib.training.stratified_sample_unknown_dist( val_input_batch, lbl_input_batch, probs, batch_size) summary_op = tf.merge_summary(tf.get_collection(tf.GraphKeys.SUMMARIES)) @@ -183,13 +184,13 @@ class SamplingOpsTest(tf.test.TestCase): def testBatchingBehavior(self): self.batchingBehaviorHelper( - tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist) + tf.contrib.training.stratified_sample_unknown_dist) def testRejectionBatchingBehavior(self): initial_p = [0, .3, 0, .7, 0] def curried_sampler(val, lbls, probs, batch, enqueue_many=True): - return tf.contrib.framework.sampling_ops.stratified_sample( + return tf.contrib.training.stratified_sample( val, lbls, probs, @@ -212,7 +213,7 @@ class SamplingOpsTest(tf.test.TestCase): probs = tf.placeholder(tf.float32, shape=[5]) batch_size = 2 - data_batch, labels = tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( # pylint: disable=line-too-long + data_batch, labels = tf.contrib.training.stratified_sample_unknown_dist( val, label, probs, batch_size) with self.test_session() as sess: @@ -252,7 +253,7 @@ class SamplingOpsTest(tf.test.TestCase): # Set up graph with placeholders. vals_ph = tf.placeholder(tf.float32) # completely undefined shape labels_ph = tf.placeholder(tf.int32) # completely undefined shape - val_tf, labels_tf, _ = tf.contrib.framework.sampling_ops._verify_input( + val_tf, labels_tf, _ = sampling_ops._verify_input( # pylint: disable=protected-access [vals_ph], labels_ph, [probs]) # Run graph to make sure there are no shape-related runtime errors. @@ -289,13 +290,13 @@ class SamplingOpsTest(tf.test.TestCase): def testDataListInput(self): self.dataListHelper( - tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist) + tf.contrib.training.stratified_sample_unknown_dist) def testRejectionDataListInput(self): initial_p = [0, 1, 0, 0, 0] def curried_sampler(val, lbls, probs, batch, enqueue_many=False): - return tf.contrib.framework.sampling_ops.stratified_sample( + return tf.contrib.training.stratified_sample( val, lbls, probs, @@ -358,13 +359,13 @@ class SamplingOpsTest(tf.test.TestCase): def testNormalBehavior(self): self.normalBehaviorHelper( - tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist) + tf.contrib.training.stratified_sample_unknown_dist) def testRejectionNormalBehavior(self): initial_p = [.7, 0, 0, .3, 0] def curried_sampler(val, lbls, probs, batch, enqueue_many=False): - return tf.contrib.framework.sampling_ops.stratified_sample( + return tf.contrib.training.stratified_sample( val, lbls, probs, @@ -377,7 +378,7 @@ class SamplingOpsTest(tf.test.TestCase): def testRejectionNormalBehaviorWithOnlineInitPEstimate(self): def curried_sampler(val, lbls, probs, batch, enqueue_many=False): - return tf.contrib.framework.sampling_ops.stratified_sample( + return tf.contrib.training.stratified_sample( val, lbls, probs, batch, init_probs=None, enqueue_many=enqueue_many) self.normalBehaviorHelper(curried_sampler) @@ -392,8 +393,7 @@ class SamplingOpsTest(tf.test.TestCase): batch_size = 4 # Set up the test graph. - [batch] = tf.contrib.framework.sampling_ops._conditional_batch( - [tensor], accept_prob, batch_size) + [batch] = sampling_ops._conditional_batch([tensor], accept_prob, batch_size) # pylint: disable=protected-access # Check conditional operation. with self.test_session(): @@ -415,9 +415,8 @@ class SamplingOpsTest(tf.test.TestCase): batch_size = 4 # Check that output types are the same for 1 and 2-length input lists. - output1 = tf.contrib.framework.sampling_ops._conditional_batch( - [tensor], accept_prob, batch_size) - output2 = tf.contrib.framework.sampling_ops._conditional_batch( + output1 = sampling_ops._conditional_batch([tensor], accept_prob, batch_size) # pylint: disable=protected-access + output2 = sampling_ops._conditional_batch( # pylint: disable=protected-access [tensor, tensor], accept_prob, batch_size) self.assertEqual(type(output1), type(output2)) diff --git a/tensorflow/contrib/framework/python/ops/sampling_ops_threading_test.py b/tensorflow/contrib/training/python/training/sampling_ops_threading_test.py similarity index 88% rename from tensorflow/contrib/framework/python/ops/sampling_ops_threading_test.py rename to tensorflow/contrib/training/python/training/sampling_ops_threading_test.py index 3812c3348c4aa04ba57c6661daf07eb693740f9d..b4dff881c3b7f79bbf03283f08d94b4c815b76da 100644 --- a/tensorflow/contrib/framework/python/ops/sampling_ops_threading_test.py +++ b/tensorflow/contrib/training/python/training/sampling_ops_threading_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function import tensorflow as tf +from tensorflow.contrib.training.python.training import sampling_ops class SamplingOpsThreadingTest(tf.test.TestCase): @@ -30,10 +31,10 @@ class SamplingOpsThreadingTest(tf.test.TestCase): tf.set_random_seed(1234) label = tf.cast(tf.round(tf.random_uniform([1]) * num_classes), tf.int32) - prob_estimate = tf.contrib.framework.sampling_ops._estimate_data_distribution( # pylint: disable=line-too-long + prob_estimate = sampling_ops._estimate_data_distribution( # pylint: disable=protected-access label, num_classes) # Check that prob_estimate is well-behaved in a multithreaded context. - _, _, [prob_estimate] = tf.contrib.framework.sampling_ops._verify_input( + _, _, [prob_estimate] = sampling_ops._verify_input( # pylint: disable=protected-access [], label, [prob_estimate]) # Use queues to run multiple threads over the graph, each of which diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD index 224badc7d3a2de064cb8b41965d93531bf9fe689..fedddac6713d109783cba2960506f71eea4dbc6e 100644 --- a/tensorflow/core/BUILD +++ b/tensorflow/core/BUILD @@ -143,9 +143,7 @@ cc_library( "lib/core/threadpool.h", "lib/gtl/array_slice.h", "lib/gtl/inlined_vector.h", - "lib/gtl/map_util.h", # TODO(josh11b): make internal "lib/gtl/priority_queue_util.h", - "lib/gtl/stl_util.h", # TODO(josh11b): make internal "lib/hash/crc32c.h", # TODO(josh11b): make internal "lib/histogram/histogram.h", "lib/io/inputbuffer.h", # TODO(josh11b): make internal @@ -169,16 +167,18 @@ cc_library( "lib/strings/str_util.h", # TODO(josh11b): make internal "lib/strings/strcat.h", "lib/strings/stringprintf.h", + "platform/cpu_info.h", "platform/env.h", "platform/file_system.h", "platform/fingerprint.h", - "platform/host_info.h", # TODO(josh11b): make internal + "platform/hexagon/profile_utils/cpu_utils.h", "platform/init_main.h", "platform/logging.h", "platform/macros.h", "platform/mem.h", "platform/net.h", "platform/mutex.h", + "platform/notification.h", "platform/protobuf.h", # TODO(josh11b): make internal "platform/regexp.h", "platform/strong_hash.h", @@ -266,6 +266,7 @@ tf_cuda_library( "util/cuda_kernel_helper.h", "util/device_name_utils.h", "util/events_writer.h", + "util/example_proto_fast_parsing.h", "util/example_proto_helper.h", "util/guarded_philox_random.h", "util/memmapped_file_system.h", @@ -427,6 +428,7 @@ tf_cuda_library( "graph/graph_constructor.h", "graph/graph_def_builder.h", "graph/node_builder.h", + "graph/shape_refiner.h", "graph/validate.h", "public/session.h", "public/session_options.h", @@ -529,6 +531,7 @@ cc_library( ":framework", ":framework_internal", ":lib", + ":lib_internal", ":proto_text", ":protos_all_cc", ":shape_inference_testutil", @@ -859,6 +862,8 @@ cc_library( "lib/**/*.cc", "platform/*.h", "platform/*.cc", + "platform/hexagon/**/*.h", + "platform/hexagon/**/*.cc", ] + tf_additional_lib_srcs(), exclude = [ "**/*test*", @@ -874,12 +879,17 @@ cc_library( "lib/gtl/int_type.h", "lib/gtl/iterator_range.h", "lib/gtl/manual_constructor.h", + "lib/gtl/map_util.h", + "lib/gtl/stl_util.h", "lib/gtl/top_n.h", "lib/hash/hash.h", + "lib/io/buffered_inputstream.h", "lib/io/inputstream_interface.h", "lib/io/iterator.h", "lib/io/match.h", "lib/io/random_inputstream.h", + "lib/io/snappy/snappy_inputbuffer.h", + "lib/io/snappy/snappy_outputbuffer.h", "lib/io/zlib_compression_options.h", "lib/io/zlib_inputbuffer.h", "lib/io/zlib_outputbuffer.h", @@ -896,6 +906,7 @@ cc_library( "lib/wav/wav_io.h", "platform/demangle.h", "platform/denormal.h", + "platform/host_info.h", "platform/platform.h", "platform/tensor_coding.h", "platform/tracing.h", @@ -1034,22 +1045,24 @@ filegroup( "lib/strings/numbers.h", "lib/strings/str_util.h", "lib/strings/strcat.h", + "platform/cpu_info.h", "platform/default/dynamic_annotations.h", "platform/default/integral_types.h", "platform/default/logging.h", "platform/default/mutex.h", + "platform/default/notification.h", "platform/default/protobuf.h", "platform/default/thread_annotations.h", "platform/env.h", "platform/file_statistics.h", "platform/file_system.h", "platform/fingerprint.h", - "platform/host_info.h", "platform/logging.h", "platform/macros.h", "platform/mem.h", "platform/mutex.h", "platform/net.h", + "platform/notification.h", "platform/platform.h", "platform/protobuf.h", "platform/strong_hash.h", @@ -1263,6 +1276,7 @@ cc_library( deps = [ ":framework", ":lib", + ":lib_internal", ":test", ], ) @@ -1306,6 +1320,7 @@ tf_cc_tests( "lib/hash/crc32c_test.cc", "lib/hash/hash_test.cc", "lib/histogram/histogram_test.cc", + "lib/io/buffered_inputstream_test.cc", "lib/io/inputbuffer_test.cc", "lib/io/inputstream_interface_test.cc", "lib/io/match_test.cc", @@ -1313,6 +1328,7 @@ tf_cc_tests( "lib/io/random_inputstream_test.cc", "lib/io/record_reader_writer_test.cc", "lib/io/recordio_test.cc", + "lib/io/snappy/snappy_buffers_test.cc", "lib/io/table_test.cc", "lib/io/zlib_buffers_test.cc", "lib/monitoring/collection_registry_test.cc", @@ -1331,6 +1347,7 @@ tf_cc_tests( "lib/strings/stringprintf_test.cc", "lib/wav/wav_io_test.cc", "platform/fingerprint_test.cc", + "platform/hexagon/profile_utils/cpu_utils_test.cc", "platform/integral_types_test.cc", "platform/logging_test.cc", "platform/net_test.cc", @@ -1452,6 +1469,7 @@ tf_cc_tests( "graph/node_builder_test.cc", "graph/optimizer_cse_test.cc", "graph/quantize_training_test.cc", + "graph/shape_refiner_test.cc", "graph/subgraph_test.cc", "graph/tensor_id_test.cc", "graph/validate_test.cc", @@ -1459,6 +1477,7 @@ tf_cc_tests( "util/command_line_flags_test.cc", "util/device_name_utils_test.cc", "util/events_writer_test.cc", + "util/example_proto_fast_parsing_test.cc", "util/example_proto_helper_test.cc", "util/memmapped_file_system_test.cc", "util/presized_cuckoo_map_test.cc", @@ -1486,6 +1505,7 @@ tf_cc_tests( ":test_main", ":testlib", "//tensorflow/cc:cc_ops", + "//tensorflow/cc:scope", "//tensorflow/cc:sendrecv_ops", "//tensorflow/core/kernels:ops_util", "//third_party/eigen3", diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index c8786c90d30aa54121e98cc27f8d84927fa5e2f9..6aedcf4e7e82114b4809e20addb1ce8a6dd5f770 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -52,7 +52,7 @@ limitations under the License. #include "tensorflow/core/lib/strings/numbers.h" #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/lib/strings/strcat.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/mutex.h" #include "tensorflow/core/platform/types.h" @@ -1031,9 +1031,9 @@ DirectSession::RunState::~RunState() { void DirectSession::WaitForNotification(RunState* run_state, int64 timeout_in_ms) { if (timeout_in_ms > 0) { - bool timed_out = - run_state->executors_done.WaitForNotificationWithTimeout(timeout_in_ms); - if (timed_out) { + bool notified = WaitForNotificationWithTimeout(&run_state->executors_done, + timeout_in_ms); + if (!notified) { { mutex_lock l(run_state->mu_); run_state->status.Update(Status(error::DEADLINE_EXCEEDED, diff --git a/tensorflow/core/common_runtime/function.cc b/tensorflow/core/common_runtime/function.cc index 9f76830f1f74e5e70ff84f8d81ac9a7ca2b50643..2b0a3b3c086134f1fb64c6bb90c4e08721558244 100644 --- a/tensorflow/core/common_runtime/function.cc +++ b/tensorflow/core/common_runtime/function.cc @@ -44,7 +44,11 @@ static const char* const kRetOp = "_Retval"; static const char* const kGradientOp = "SymbolicGradient"; static const char* const kNodeLabel = "Func"; static const char* const kFuncAttr = "f"; -static const char* const kNoinlineAttr = "noinline"; +// kNoinlineAttr must start with an "_" to avoid collisions with +// user-specified attrs. +static const char* const kNoinlineAttr = "_noinline"; +// Old graphs use no "_". +static const char* const kOldNoinlineAttr = "noinline"; // Represents the index-th output of a node. struct Endpoint { @@ -357,6 +361,8 @@ Status FunctionLibraryRuntimeImpl::InstantiateSymbolicGradient( func.name()); } FunctionDef grad_fdef; + // TODO(josh11b): Should filter out the attrs from func that aren't used + // by the gradient function. TF_RETURN_IF_ERROR(creator(AttrSlice(&func.attr()), &grad_fdef)); TF_RETURN_IF_ERROR(FunctionDefToBody(grad_fdef, func.attr(), g_body)); } else { @@ -867,12 +873,16 @@ static void InlineFunctionBody(Graph* g, Node* caller, } // Given a node's NodeDef, returns false iff the node explicitly -// specified noinline. This gives ExpandInlineFunctions a heuristic to +// specified _noinline. This gives ExpandInlineFunctions a heuristic to // decide whether to inline the function. -bool ShouldInline(const NodeDef& ndef) { +// `old` is true for GraphDef versions older than 12, when the +// `noinline` attr was renamed to `_noinline` to avoid conflicts with +// user-specified attrs. +bool ShouldInline(const NodeDef& ndef, bool old) { bool noinline = false; - if (GetNodeAttr(ndef, kNoinlineAttr, &noinline).ok()) { - // If the node specifies attribute 'noinlne', returns accordingly. + const char* const attr = old ? kOldNoinlineAttr : kNoinlineAttr; + if (GetNodeAttr(ndef, attr, &noinline).ok()) { + // If the node specifies attribute '_noinline', returns accordingly. return !noinline; } if (ndef.op() != kGradientOp) { @@ -881,7 +891,7 @@ bool ShouldInline(const NodeDef& ndef) { return true; } // If the node is a SymbolicGradient, we use the forward - // function's attribute 'noinline' instead. + // function's attribute '_noinline' instead. const NameAttrList* forward_func_attrs; Status s = GetNodeAttr(AttrSlice(&ndef.attr()), kFuncAttr, &forward_func_attrs); @@ -890,10 +900,9 @@ bool ShouldInline(const NodeDef& ndef) { // continue and the runtime will error out. return false; } - s = GetNodeAttr(AttrSlice(&forward_func_attrs->attr()), kNoinlineAttr, - &noinline); + s = GetNodeAttr(AttrSlice(&forward_func_attrs->attr()), attr, &noinline); if (!s.ok()) { - // The forward function doesn't specify 'noinline' attr, we should + // The forward function doesn't specify '_noinline' attr, we should // be free to decide. return true; } @@ -903,9 +912,11 @@ bool ShouldInline(const NodeDef& ndef) { bool ExpandInlineFunctions(FunctionLibraryRuntime* lib, Graph* graph) { std::vector> candidates; + // Identify old graphs before the 'noinline' attr was renamed '_noinline'. + const bool old_inline_attr = graph->versions().producer() < 12; for (Node* node : graph->nodes()) { VLOG(3) << "Expanding " << node->DebugString(); - if (!ShouldInline(node->def())) { + if (!ShouldInline(node->def(), old_inline_attr)) { VLOG(3) << "noinline: " << node->DebugString(); continue; } diff --git a/tensorflow/core/common_runtime/function_test.cc b/tensorflow/core/common_runtime/function_test.cc index c4d1bb59e8d4cd6a61b26dcfc46067f6d4445b2e..2f5507a0c555afa6aea7561a57940c5eb43091c9 100644 --- a/tensorflow/core/common_runtime/function_test.cc +++ b/tensorflow/core/common_runtime/function_test.cc @@ -257,7 +257,7 @@ TEST_F(FunctionLibraryRuntimeTest, ExpandInlineFunctions) { Init({test::function::XTimesTwo(), test::function::XTimesFour(), test::function::XTimes16()}); Graph* g = GetFuncBody("XTimes16", {{"T", DT_FLOAT}}); - CHECK(g); + ASSERT_TRUE(g != nullptr); const char* e0 = R"P( (n2:float) -> (n4:float) { n3 = XTimesFour[T=float](n2) @@ -342,7 +342,7 @@ TEST_F(FunctionLibraryRuntimeTest, OptimizeGraph) { Init({test::function::XTimesTwo(), test::function::XTimesFour(), test::function::XTimes16()}); Graph* g = GetFuncBody("XTimes16", {{"T", DT_FLOAT}}); - CHECK(g); + ASSERT_TRUE(g != nullptr); ExpandInlineFunctions(lib_, g); OptimizeGraph(lib_, &g); const char* e0 = R"P( @@ -358,8 +358,8 @@ TEST_F(FunctionLibraryRuntimeTest, OptimizeGraph) { delete g; } -TEST_F(FunctionLibraryRuntimeTest, ManySwaps) { - auto func = FDH::Define( +TEST_F(FunctionLibraryRuntimeTest, ManySwapsOld) { + auto func = FDH::Define( // Creates a FunctionDef using FunctionDef::Nodes // Name "ManySwapsFirst", // Args @@ -377,8 +377,41 @@ TEST_F(FunctionLibraryRuntimeTest, ManySwaps) { {{"a5", "b5"}, "Swap", {"a4", "b4"}, {{"T", DT_FLOAT}}}, {{"o"}, "Identity", {"a5"}, {{"T", DT_FLOAT}}}}); Init({test::function::Swap(), func}); - Graph* g = GetFuncBody("ManySwapsFirst", {{"T", DT_FLOAT}}); - CHECK(g); + Graph* g = GetFuncBody("ManySwapsFirst", {}); + ASSERT_TRUE(g != nullptr); + OptimizeGraph(lib_, &g); + const char* e0 = R"P( +(n3:float, n2:float) -> (n3:float) { +} +)P"; + EXPECT_EQ(e0, DebugString(g)); + delete g; +} + +// Like the above test, but using NodeDefs in the FunctionDef. +TEST_F(FunctionLibraryRuntimeTest, ManySwapsNodeDef) { + auto func = FDH::Create( // Creates a FunctionDef using NodeDefs + // Name + "ManySwapsNodeDef", + // Input + {"x: float", "y: float"}, + // Output + {"o: float"}, + // Attr + {}, + // Nodes + {{{"a"}, "Swap", {"x", "y"}, {{"T", DT_FLOAT}}}, + {{"b"}, "Swap", {"a:o0", "a:o1"}, {{"T", DT_FLOAT}}}, + {{"c"}, "Swap", {"b:o0", "b:o1"}, {{"T", DT_FLOAT}}}, + {{"d"}, "Swap", {"c:o0", "c:o1"}, {{"T", DT_FLOAT}}}, + {{"e"}, "Swap", {"d:o0", "d:o1"}, {{"T", DT_FLOAT}}}, + {{"f"}, "Swap", {"e:o0", "e:o1"}, {{"T", DT_FLOAT}}}, + {{"g"}, "Identity", {"f:o0"}, {{"T", DT_FLOAT}}}}, + // Return + {{"o", "g:output"}}); + Init({test::function::Swap(), func}); + Graph* g = GetFuncBody("ManySwapsNodeDef", {}); + ASSERT_TRUE(g != nullptr); OptimizeGraph(lib_, &g); const char* e0 = R"P( (n3:float, n2:float) -> (n3:float) { @@ -410,8 +443,8 @@ TEST_F(FunctionLibraryRuntimeTest, ControlDeps) { {{"y2"}, "Mul", {"y", "y"}, {{"T", DT_FLOAT}}, {"a1"}}, {{"o"}, "Add", {"x2", "y2"}, {{"T", DT_FLOAT}}}}); Init({test::function::Swap(), func}); - Graph* g = GetFuncBody("ManySwapsFirst", {{"T", DT_FLOAT}}); - CHECK(g); + Graph* g = GetFuncBody("ManySwapsFirst", {}); + ASSERT_TRUE(g != nullptr); OptimizeGraph(lib_, &g); // NOTE: We can remove n8, n9, n10, n11 with a control edge n8->n5. @@ -588,7 +621,7 @@ TEST_F(FunctionLibraryRuntimeTest, Gradient_AddSum) { Init({test, grad}); Graph* g = GetFuncBody("TestGrad", {}); - CHECK(g); + ASSERT_TRUE(g != nullptr); const char* e0 = R"P( (n4:float, n3:float) -> (n8:float, n6:float) { n2 = Const[dtype=float, value=Tensor]() diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index 5be737f51ffcd54a813ed8ed9a6cecbdb91ea900..033d67772ce53a4d793ae7ba9b7e5c08f09a257d 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -597,7 +597,8 @@ Status BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, n = iter->second; } std::vector valid_gpu_ids; - GetValidDeviceIds(&valid_gpu_ids); + TF_RETURN_IF_ERROR(GetValidDeviceIds( + options.config.gpu_options().visible_device_list(), &valid_gpu_ids)); if (static_cast(n) > valid_gpu_ids.size()) { n = valid_gpu_ids.size(); } @@ -811,21 +812,60 @@ std::vector GetSupportedCudaComputeCapabilities() { } // namespace -void BaseGPUDeviceFactory::GetValidDeviceIds(std::vector* ids) { +Status BaseGPUDeviceFactory::GetValidDeviceIds( + const string& visible_device_list, std::vector* ids) { gpu::Platform* gpu_manager = GPUMachineManager(); if (gpu_manager == nullptr) { - return; + return Status::OK(); + } + + // If there are no GPUs visible, do nothing. + if (gpu_manager->VisibleDeviceCount() <= 0) { + return Status::OK(); } auto cuda_supported_capabilities = GetSupportedCudaComputeCapabilities(); - CHECK(!cuda_supported_capabilities.empty()); + if (cuda_supported_capabilities.empty()) { + return errors::FailedPrecondition( + "No supported cuda capabilities in binary."); + } CudaVersion min_supported_capability = *std::min_element( cuda_supported_capabilities.begin(), cuda_supported_capabilities.end()); int min_gpu_core_count = GetMinGPUMultiprocessorCount(gpu_manager); - for (int i = 0; i < gpu_manager->VisibleDeviceCount(); ++i) { - auto exec_status = gpu_manager->ExecutorForDevice(i); + // If the user wants to remap the visible to virtual GPU mapping, + // check for that here. + std::vector visible_gpu_order; + if (visible_device_list.empty()) { + visible_gpu_order.resize(gpu_manager->VisibleDeviceCount()); + // By default, visible to virtual mapping is unchanged. + std::iota(visible_gpu_order.begin(), visible_gpu_order.end(), 0); + } else { + std::vector order_str = str_util::Split(visible_device_list, ','); + for (int i = 0; i < order_str.size(); ++i) { + const string& gpu_id_str = order_str[i]; + int32 gpu_id; + if (!strings::safe_strto32(gpu_id_str, &gpu_id)) { + return errors::InvalidArgument( + "Could not parse entry in 'visible_device_list': '", gpu_id_str, + "'. visible_device_list = ", visible_device_list); + } + + if (gpu_id < 0 || gpu_id >= gpu_manager->VisibleDeviceCount()) { + return errors::InvalidArgument( + "'visible_device_list' listed an invalid GPU id '", gpu_id, + "' but visible device count is ", + gpu_manager->VisibleDeviceCount()); + } + + visible_gpu_order.push_back(gpu_id); + } + } + + for (int i = 0; i < visible_gpu_order.size(); ++i) { + const int32 visible_gpu_id = visible_gpu_order[i]; + auto exec_status = gpu_manager->ExecutorForDevice(visible_gpu_id); if (!exec_status.ok()) { continue; } @@ -839,8 +879,9 @@ void BaseGPUDeviceFactory::GetValidDeviceIds(std::vector* ids) { // Only GPUs with no less than the minimum supported compute capability is // accepted. if (device_capability < min_supported_capability) { - LOG(INFO) << "Ignoring gpu device " - << "(" << GetShortDeviceDescription(i, desc) << ") " + LOG(INFO) << "Ignoring physical gpu device " + << "(" << GetShortDeviceDescription(visible_gpu_id, desc) + << ") " << "with Cuda compute capability " << device_capability << ". The minimum required Cuda capability is " << min_supported_capability << "."; @@ -853,7 +894,8 @@ void BaseGPUDeviceFactory::GetValidDeviceIds(std::vector* ids) { // variable is set, its value will be used to filter out GPUs. if (desc.core_count() < min_gpu_core_count) { LOG(INFO) << "Ignoring gpu device " - << "(" << GetShortDeviceDescription(i, desc) << ") " + << "(" << GetShortDeviceDescription(visible_gpu_id, desc) + << ") " << "with Cuda multiprocessor count: " << desc.core_count() << ". The minimum required count is " << min_gpu_core_count << ". You can adjust this requirement with the env var " @@ -862,11 +904,13 @@ void BaseGPUDeviceFactory::GetValidDeviceIds(std::vector* ids) { } int new_id = ids->size(); - ids->push_back(i); + ids->push_back(visible_gpu_id); LOG(INFO) << "Creating TensorFlow device (/gpu:" << new_id << ") -> " - << "(" << GetShortDeviceDescription(i, desc) << ")"; + << "(" << GetShortDeviceDescription(visible_gpu_id, desc) << ")"; } + + return Status::OK(); } } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.h b/tensorflow/core/common_runtime/gpu/gpu_device.h index 03090aa53741089dcaf40b09cf60358af0b7f0a7..abe7c0f687e4939b8085ca8e704637e9d16e94b0 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.h +++ b/tensorflow/core/common_runtime/gpu/gpu_device.h @@ -123,7 +123,12 @@ class BaseGPUDeviceFactory : public DeviceFactory { Allocator* gpu_allocator, Allocator* cpu_allocator) = 0; - void GetValidDeviceIds(std::vector* ids); + // Returns into 'ids' the list of valid GPU ids, in the order that + // they should map to logical gpu ids "/gpu:0", "/gpu:1", etc, based + // upon 'visible_device_list', a comma-separated list of 'visible + // gpu ids'. + Status GetValidDeviceIds(const string& visible_device_list, + std::vector* ids); }; } // namespace tensorflow diff --git a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc index 7d0aefa70feca56a09bb7e27583a6640526953d8..c568896de7ff92aa4f40cd3fedfe7bab68dd2b59 100644 --- a/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc +++ b/tensorflow/core/common_runtime/kernel_benchmark_testlib.cc @@ -26,7 +26,7 @@ limitations under the License. #include "tensorflow/core/lib/core/notification.h" #include "tensorflow/core/lib/core/threadpool.h" #include "tensorflow/core/lib/strings/str_util.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/test_benchmark.h" #include "tensorflow/core/platform/types.h" diff --git a/tensorflow/core/common_runtime/local_device.cc b/tensorflow/core/common_runtime/local_device.cc index bee63fc61fb6826773ce54c4557ecae77215db97..bbd04e2dbbd0e537d3e7e773d374ef12a381c4a3 100644 --- a/tensorflow/core/common_runtime/local_device.cc +++ b/tensorflow/core/common_runtime/local_device.cc @@ -19,7 +19,7 @@ limitations under the License. #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/common_runtime/eigen_thread_pool.h" #include "tensorflow/core/lib/core/threadpool.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/types.h" #include "tensorflow/core/public/session_options.h" diff --git a/tensorflow/core/common_runtime/process_util.cc b/tensorflow/core/common_runtime/process_util.cc index 9c264342810f81a2ac0da1d605c35dc46ac27eb5..d738fef7be5b04f166651644542b2eadbe38715d 100644 --- a/tensorflow/core/common_runtime/process_util.cc +++ b/tensorflow/core/common_runtime/process_util.cc @@ -18,7 +18,7 @@ limitations under the License. #include #include "tensorflow/core/lib/core/threadpool.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/tracing.h" #include "tensorflow/core/platform/types.h" diff --git a/tensorflow/core/debug/debug_graph_utils.cc b/tensorflow/core/debug/debug_graph_utils.cc index 118847686d3a5036cd19ce2e59062696ff28af25..c2e50f4d1b158e801e4140de7b2fc0dff5fc7263 100644 --- a/tensorflow/core/debug/debug_graph_utils.cc +++ b/tensorflow/core/debug/debug_graph_utils.cc @@ -154,7 +154,7 @@ Status DebugNodeInserter::InsertNodes( // Create all requested debug nodes and their edges to the Copy node. std::vector node_added_debug_nodes; - for (int i = 0; i < tensor_watches[tensor_name].size(); ++i) { + for (size_t i = 0; i < tensor_watches[tensor_name].size(); ++i) { const string& debug_op_name = tensor_watches[tensor_name][i]; Node* debug_node; diff --git a/tensorflow/core/distributed_runtime/BUILD b/tensorflow/core/distributed_runtime/BUILD index 601a4f34b4284af389eae146de9b447c543c887d..3223d66b3df1a66e2a70e72a6ef3a6337e8c76c2 100644 --- a/tensorflow/core/distributed_runtime/BUILD +++ b/tensorflow/core/distributed_runtime/BUILD @@ -145,6 +145,7 @@ cc_library( "//tensorflow/core:core_cpu_internal", "//tensorflow/core:framework", "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", "//tensorflow/core:master_proto_cc", "//tensorflow/core:worker_proto_cc", ], diff --git a/tensorflow/core/distributed_runtime/rpc/BUILD b/tensorflow/core/distributed_runtime/rpc/BUILD index 527e5281e01c200a6a4ea0d1bc02ce34acdb7bd1..5c13c0e6547ced9248c2f2cc1bed570a4daf00f3 100644 --- a/tensorflow/core/distributed_runtime/rpc/BUILD +++ b/tensorflow/core/distributed_runtime/rpc/BUILD @@ -92,6 +92,7 @@ cc_library( deps = [ ":grpc_util", "//tensorflow/core:lib", + "//tensorflow/core:lib_internal", "@grpc//:grpc++_unsecure", ], ) @@ -101,7 +102,6 @@ cc_library( srcs = ["grpc_tensor_coding.cc"], hdrs = ["grpc_tensor_coding.h"], deps = [ - ":grpc_util", "//tensorflow/core:core_cpu_internal", "//tensorflow/core:framework", "//tensorflow/core:framework_internal", @@ -160,12 +160,10 @@ cc_library( "//tensorflow/core:lib", "//tensorflow/core:lib_internal", "//tensorflow/core:worker_proto_cc", - "//tensorflow/core/distributed_runtime:call_options", "//tensorflow/core/distributed_runtime:graph_mgr", "//tensorflow/core/distributed_runtime:rendezvous_mgr_interface", "//tensorflow/core/distributed_runtime:worker_cache", "//tensorflow/core/distributed_runtime:worker_env", - "//tensorflow/core/distributed_runtime:worker_interface", "@grpc//:grpc++_unsecure", ], ) diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_call.h b/tensorflow/core/distributed_runtime/rpc/grpc_call.h index 3b6cbf44c266f07e69e6b44a36fc120308cd3bf6..70627973c7835f093d8519d7a9b7472f7180a6e5 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_call.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_call.h @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/core/platform/macros.h" #include "grpc++/grpc++.h" +#include "grpc++/impl/codegen/service_type.h" #include "grpc++/server_builder.h" namespace tensorflow { @@ -86,13 +87,6 @@ class UntypedCall : public core::RefCounted { // otherwise false. virtual void RequestReceived(Service* service, bool ok) = 0; - // This method will be called when the response has been sent by - // `service` and the call is no longer used. - // - // `ok` is true if the response sending completed as a "regular - // event", otherwise it is false. - void ResponseSent(Service* service, bool ok) {} - // This method will be called either (i) when the server is notified // that the request has been cancelled, or (ii) when the request completes // normally. The implementation should distinguish these cases by querying @@ -100,27 +94,31 @@ class UntypedCall : public core::RefCounted { virtual void RequestCancelled(Service* service, bool ok) = 0; // Associates a tag in a `::grpc::CompletionQueue` with a callback - // for an incoming RPC. A Tag owns a reference on the corresponding + // for an incoming RPC. An active Tag owns a reference on the corresponding // Call object. class Tag { public: - using Callback = void (UntypedCall::*)(Service*, bool); - - // Creates a new `Tag` for the given `UntypedCall`. When the - // request associated with this tag is complete, `callback` will - // be called. - Tag(UntypedCall* call, Callback callback) - : call_(call), callback_(callback) { - call_->Ref(); - } + // One enum value per supported callback. + enum Callback { kRequestReceived, kResponseSent, kCancelled }; - ~Tag() { call_->Unref(); } + Tag(UntypedCall* call, Callback cb) : call_(call), callback_(cb) {} // Calls the callback associated with this tag. // // The callback takes ownership of `this->call_`. void OnCompleted(Service* service, bool ok) { - (call_->*callback_)(service, ok); + switch (callback_) { + case kRequestReceived: + call_->RequestReceived(service, ok); + break; + case kResponseSent: + // No special handling needed apart from the Unref below. + break; + case kCancelled: + call_->RequestCancelled(service, ok); + break; + } + call_->Unref(); // Ref acquired when tag handed to grpc. } private: @@ -161,9 +159,8 @@ class Call : public UntypedCall { } void SendResponse(::grpc::Status status) { - responder_.Finish(response, status, - new typename UntypedCall::Tag( - this, &UntypedCall::ResponseSent)); + this->Ref(); // Ref for grpc; released in Tag callback. + responder_.Finish(response, status, &response_sent_tag_); this->Unref(); } @@ -174,9 +171,6 @@ class Call : public UntypedCall { cancel_callback_(); } } - // NOTE(mrry): This can be called before or after RequestReceived, so we - // release `cancel_tag_` (in order to allow the event loop to free it). - cancel_tag_.release(); } // Registers `callback` as the function that should be called if and when this @@ -208,11 +202,31 @@ class Call : public UntypedCall { call->RegisterCancellationHandler(); } - (grpc_service->*enqueue_function)( - &call->ctx_, &call->request, &call->responder_, cq, cq, - new typename UntypedCall::Tag( - call, &UntypedCall::RequestReceived)); - call->Unref(); + // Initial ref for call handed to grpc; released in Tag callback. + (grpc_service->*enqueue_function)(&call->ctx_, &call->request, + &call->responder_, cq, cq, + &call->request_received_tag_); + } + + // Enqueues a new request for the given service on the given + // completion queue, using the given `method_id`. + // + // The request will be handled with the given + // `handle_request_function`. + static void EnqueueRequestForMethod( + GrpcService* grpc_service, ::grpc::ServerCompletionQueue* cq, + int method_id, HandleRequestFunction handle_request_function, + bool supports_cancel) { + auto call = new Call( + handle_request_function); + if (supports_cancel) { + call->RegisterCancellationHandler(); + } + + // Initial ref for call handed to grpc; released in Tag callback. + grpc_service->RequestAsyncUnary(method_id, &call->ctx_, &call->request, + &call->responder_, cq, cq, + &call->request_received_tag_); } RequestMessage request; @@ -223,22 +237,23 @@ class Call : public UntypedCall { // NOTE: This method must be called before this call is enqueued on a // completion queue. void RegisterCancellationHandler() { - cancel_tag_.reset(new typename UntypedCall::Tag( - this, &UntypedCall::RequestCancelled)); - ctx_.AsyncNotifyWhenDone(cancel_tag_.get()); + this->Ref(); // Ref for grpc; released in Tag callback. + ctx_.AsyncNotifyWhenDone(&cancelled_tag_); } HandleRequestFunction handle_request_function_; ::grpc::ServerContext ctx_; ::grpc::ServerAsyncResponseWriter responder_; + + // Used as void* completion markers from grpc to indicate different + // events of interest for a Call. + using typename UntypedCall::Tag; + Tag request_received_tag_{this, Tag::kRequestReceived}; + Tag response_sent_tag_{this, Tag::kResponseSent}; + Tag cancelled_tag_{this, Tag::kCancelled}; + mutex mu_; std::function cancel_callback_ GUARDED_BY(mu_); - - // This tag is initially owned by `*this` and borrowed by - // `ctx_->AsyncNotifyWhenDone()`. Ownership is transferred to the - // appropriate service's completion queue after - // `this->RequestReceived(..., true)` is called. - std::unique_ptr::Tag> cancel_tag_; }; } // namespace tensorflow diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h b/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h index b305ab44fe8c47b8649ddf6438714a14084dd478..95c2c935f091abc808a7fb0ee8446ced5e1d184b 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_client_cq_tag.h @@ -28,26 +28,14 @@ namespace tensorflow { // stored in a `grpc::CompletionQueue`. class GrpcClientCQTag { public: - GrpcClientCQTag(::grpc::ClientContext* context, StatusCallback cb) - : context_(context), cb_(std::move(cb)) {} - ~GrpcClientCQTag() { delete context_; } + GrpcClientCQTag() {} + virtual ~GrpcClientCQTag() {} - void OnCompleted(bool ok) { - if (!ok) { - VLOG(2) << "Call returned with non-ok status: " - << status_.error_message(); - } - cb_(FromGrpcStatus(status_)); - } - - ::grpc::ClientContext* context() { return context_; } - ::grpc::Status* status() { return &status_; } + // OnCompleted is invoked when the RPC has finished. + // Implementations of OnCompleted must delete *this. + virtual void OnCompleted(bool ok) = 0; private: - ::grpc::ClientContext* context_; - ::grpc::Status status_; - StatusCallback cb_; - TF_DISALLOW_COPY_AND_ASSIGN(GrpcClientCQTag); }; diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_master_service.cc b/tensorflow/core/distributed_runtime/rpc/grpc_master_service.cc index 9823980e835b3042e3d61d7e581a628935ee509a..c8a0892842f0595497c28fefb7fab0996cc98384 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_master_service.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_master_service.cc @@ -118,7 +118,6 @@ class GrpcMasterService : public AsyncServiceInterface { static_cast::Tag*>(tag); if (callback_tag) { callback_tag->OnCompleted(this, ok); - delete callback_tag; } else { // NOTE(mrry): A null `callback_tag` indicates that this is // the shutdown alarm. diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.cc b/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.cc index 14ad1e0355ffd2465962db2f4e991b3f165bdb15..79d3b3e2f64988ca6d68e2c296d995ef54ce3a42 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_remote_worker.cc @@ -37,8 +37,17 @@ class GrpcRemoteWorker : public WorkerInterface { explicit GrpcRemoteWorker(SharedGrpcChannelPtr channel, ::grpc::CompletionQueue* completion_queue, WorkerCacheLogger* logger) - : stub_(grpc::WorkerService::NewStub(channel)), + : channel_(channel), cq_(completion_queue), + getstatus_(Method(GrpcWorkerMethod::kGetStatus)), + registergraph_(Method(GrpcWorkerMethod::kRegisterGraph)), + deregistergraph_(Method(GrpcWorkerMethod::kDeregisterGraph)), + rungraph_(Method(GrpcWorkerMethod::kRunGraph)), + cleanupgraph_(Method(GrpcWorkerMethod::kCleanupGraph)), + cleanupall_(Method(GrpcWorkerMethod::kCleanupAll)), + recvtensor_(Method(GrpcWorkerMethod::kRecvTensor)), + logging_(Method(GrpcWorkerMethod::kLogging)), + tracing_(Method(GrpcWorkerMethod::kTracing)), logger_(logger) {} ~GrpcRemoteWorker() override {} @@ -46,45 +55,36 @@ class GrpcRemoteWorker : public WorkerInterface { void GetStatusAsync(const GetStatusRequest* request, GetStatusResponse* response, StatusCallback done) override { - IssueRequest(request, response, &grpc::WorkerService::Stub::AsyncGetStatus, - std::move(done)); + IssueRequest(request, response, getstatus_, std::move(done)); } void RegisterGraphAsync(const RegisterGraphRequest* request, RegisterGraphResponse* response, StatusCallback done) override { - IssueRequest(request, response, - &grpc::WorkerService::Stub::AsyncRegisterGraph, - std::move(done)); + IssueRequest(request, response, registergraph_, std::move(done)); } void DeregisterGraphAsync(const DeregisterGraphRequest* request, DeregisterGraphResponse* response, StatusCallback done) override { - IssueRequest(request, response, - &grpc::WorkerService::Stub::AsyncDeregisterGraph, - std::move(done)); + IssueRequest(request, response, deregistergraph_, std::move(done)); } void RunGraphAsync(CallOptions* call_opts, const RunGraphRequest* request, RunGraphResponse* response, StatusCallback done) override { - IssueRequest(request, response, &grpc::WorkerService::Stub::AsyncRunGraph, - std::move(done), call_opts); + IssueRequest(request, response, rungraph_, std::move(done), call_opts); } void CleanupGraphAsync(const CleanupGraphRequest* request, CleanupGraphResponse* response, StatusCallback done) override { - IssueRequest(request, response, - &grpc::WorkerService::Stub::AsyncCleanupGraph, - std::move(done)); + IssueRequest(request, response, cleanupgraph_, std::move(done)); } void CleanupAllAsync(const CleanupAllRequest* request, CleanupAllResponse* response, StatusCallback done) override { - IssueRequest(request, response, &grpc::WorkerService::Stub::AsyncCleanupAll, - std::move(done)); + IssueRequest(request, response, cleanupall_, std::move(done)); } void RecvTensorAsync(CallOptions* call_opts, const RecvTensorRequest* request, @@ -156,59 +156,98 @@ class GrpcRemoteWorker : public WorkerInterface { cb_to_use = &wrapper_done; } - IssueRequest(req_copy ? req_copy : request, response, - &grpc::WorkerService::Stub::AsyncRecvTensor, + IssueRequest(req_copy ? req_copy : request, response, recvtensor_, std::move(*cb_to_use), call_opts); } void LoggingAsync(const LoggingRequest* request, LoggingResponse* response, StatusCallback done) override { - IssueRequest(request, response, &grpc::WorkerService::Stub::AsyncLogging, - done); + IssueRequest(request, response, logging_, done); } void TracingAsync(const TracingRequest* request, TracingResponse* response, StatusCallback done) override { - IssueRequest(request, response, &grpc::WorkerService::Stub::AsyncTracing, - done); + IssueRequest(request, response, tracing_, done); } private: + // Object allocated per active RPC. template - using AsyncMethod = - std::unique_ptr<::grpc::ClientAsyncResponseReader> ( - grpc::WorkerService::Stub::*)(::grpc::ClientContext*, - const RequestMessage&, - ::grpc::CompletionQueue*); + class RPCState final : public GrpcClientCQTag { + public: + RPCState(::grpc::ChannelInterface* channel, ::grpc::CompletionQueue* cq, + const ::grpc::RpcMethod& method, const RequestMessage& request, + StatusCallback done, CallOptions* call_opts) + : call_opts_(call_opts), + reader_(channel, cq, method, InitContext(call_opts), request), + done_(std::move(done)) {} + + ~RPCState() override {} + + void StartRPC(ResponseMessage* response) { + reader_.Finish(response, &status_, this); + } + + void OnCompleted(bool ok) override { + if (!ok) { + VLOG(2) << "Call returned with non-ok status: " + << status_.error_message(); + } + if (call_opts_) { + call_opts_->ClearCancelCallback(); + } + done_(FromGrpcStatus(status_)); + delete this; + } + + private: + CallOptions* call_opts_; + ::grpc::ClientContext context_; + ::grpc::ClientAsyncResponseReader reader_; + ::grpc::Status status_; + StatusCallback done_; + + ::grpc::ClientContext* InitContext(CallOptions* call_opts) { + // The initialization and recovery protocols rely on blocking + // until we get a response. + context_.set_fail_fast(false); + if (call_opts) { + call_opts->SetCancelCallback([this]() { context_.TryCancel(); }); + } + return &context_; + } + }; // Utility method for issuing a generic asynchronous request. The // given callback, `done`, will be called when the RPC completes. template void IssueRequest(const RequestMessage* request, ResponseMessage* response, - AsyncMethod async_method, - StatusCallback done, CallOptions* call_opts = nullptr) { - ::grpc::ClientContext* context = new ::grpc::ClientContext; - // The initialization and recovery protocols rely on blocking - // until we get a response. - context->set_fail_fast(false); - if (call_opts) { - call_opts->SetCancelCallback([context]() { context->TryCancel(); }); - } - auto rpc = (stub_.get()->*async_method)(context, *request, cq_).release(); - GrpcClientCQTag* tag = - new GrpcClientCQTag(context, [rpc, done, call_opts](Status s) { - if (call_opts) { - call_opts->ClearCancelCallback(); - } - delete rpc; - done(s); - }); - rpc->Finish(response, tag->status(), tag); + const ::grpc::RpcMethod& method, StatusCallback done, + CallOptions* call_opts = nullptr) { + auto state = new RPCState( + channel_.get(), cq_, method, *request, std::move(done), call_opts); + state->StartRPC(response); } - std::unique_ptr stub_; + // Helper function for initializing the RpcMethod objects below. + ::grpc::RpcMethod Method(GrpcWorkerMethod id) { + return ::grpc::RpcMethod(GrpcWorkerMethodName(id), + ::grpc::RpcMethod::NORMAL_RPC, channel_); + } + + SharedGrpcChannelPtr channel_; ::grpc::CompletionQueue* cq_; + const ::grpc::RpcMethod getstatus_; + const ::grpc::RpcMethod registergraph_; + const ::grpc::RpcMethod deregistergraph_; + const ::grpc::RpcMethod rungraph_; + const ::grpc::RpcMethod cleanupgraph_; + const ::grpc::RpcMethod cleanupall_; + const ::grpc::RpcMethod recvtensor_; + const ::grpc::RpcMethod logging_; + const ::grpc::RpcMethod tracing_; + // Support for logging. WorkerCacheLogger* logger_; bool retry_unavailable_; diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.cc b/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.cc index 485ed14c0f599de95b30b7c26f20fcd5ecc82127..0c0c80117acecda0a6a043dfc7e485a04916f3ef 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.cc @@ -38,7 +38,6 @@ class GrpcWorkerCache : public WorkerCachePartial { while (completion_queue_.Next(&tag, &ok)) { GrpcClientCQTag* callback_tag = static_cast(tag); callback_tag->OnCompleted(ok); - delete callback_tag; } }); } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc index 9f7d009a36acc158aad3e22821768014b6ede858..9a87bbda1be954d6ccd0bf0ea4ae322a3cc50396 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service.cc @@ -85,7 +85,7 @@ class GrpcWorkerService : public AsyncServiceInterface { } // This macro creates a new request for the given RPC method name -// (e.g., `ENQUEUE_REQUEST(GetStatus);`), and enqueues it on +// (e.g., `ENQUEUE_REQUEST(GetStatus, false);`), and enqueues it on // `this->cq_`. // // This macro is invoked one or more times for each RPC method to @@ -95,17 +95,17 @@ class GrpcWorkerService : public AsyncServiceInterface { // The implementation of the request handler for each RPC method // must ensure that it calls ENQUEUE_REQUEST() for that RPC method, // to keep accepting new requests. -#define ENQUEUE_REQUEST(method, supports_cancel) \ - do { \ - mutex_lock l(shutdown_mu_); \ - if (!is_shutdown_) { \ - Call:: \ - EnqueueRequest(&worker_service_, cq_, \ - &grpc::WorkerService::AsyncService::Request##method, \ - &GrpcWorkerService::method##Handler, \ - (supports_cancel)); \ - } \ +#define ENQUEUE_REQUEST(method, supports_cancel) \ + do { \ + mutex_lock l(shutdown_mu_); \ + if (!is_shutdown_) { \ + Call:: \ + EnqueueRequestForMethod( \ + &worker_service_, cq_, \ + static_cast(GrpcWorkerMethod::k##method), \ + &GrpcWorkerService::method##Handler, (supports_cancel)); \ + } \ } while (0) // This method blocks forever handling requests from the completion queue. @@ -145,7 +145,6 @@ class GrpcWorkerService : public AsyncServiceInterface { static_cast::Tag*>(tag); if (callback_tag) { callback_tag->OnCompleted(this, ok); - delete callback_tag; } else { // NOTE(mrry): A null `callback_tag` indicates that this is // the shutdown alarm. @@ -267,9 +266,9 @@ class GrpcWorkerService : public AsyncServiceInterface { if (!is_shutdown_) { Call:: - EnqueueRequest( + EnqueueRequestForMethod( &worker_service_, cq_, - &grpc::WorkerService::AsyncService::RequestRecvTensorRaw, + static_cast(GrpcWorkerMethod::kRecvTensor), &GrpcWorkerService::RecvTensorHandlerRaw, true /* supports cancel*/); } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.cc b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.cc index 9f5e50f90ecd833ef11398e41f3df2a1902ae8a0..a3ba22a95d80919887241c44cfd9e22affb097ea 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.cc @@ -26,127 +26,36 @@ limitations under the License. namespace tensorflow { -namespace grpc { - -static const char* grpcWorkerService_method_names[] = { - "/tensorflow.WorkerService/GetStatus", - "/tensorflow.WorkerService/RegisterGraph", - "/tensorflow.WorkerService/DeregisterGraph", - "/tensorflow.WorkerService/RunGraph", - "/tensorflow.WorkerService/CleanupGraph", - "/tensorflow.WorkerService/CleanupAll", - "/tensorflow.WorkerService/RecvTensor", - "/tensorflow.WorkerService/Logging", - "/tensorflow.WorkerService/Tracing", -}; - -std::unique_ptr WorkerService::NewStub( - const std::shared_ptr< ::grpc::ChannelInterface>& channel, - const ::grpc::StubOptions& options) { - std::unique_ptr stub(new WorkerService::Stub(channel)); - return stub; -} - -WorkerService::Stub::Stub( - const std::shared_ptr< ::grpc::ChannelInterface>& channel) - : channel_(channel), - rpcmethod_GetStatus_(grpcWorkerService_method_names[0], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_RegisterGraph_(grpcWorkerService_method_names[1], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_DeregisterGraph_(grpcWorkerService_method_names[2], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_RunGraph_(grpcWorkerService_method_names[3], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_CleanupGraph_(grpcWorkerService_method_names[4], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_CleanupAll_(grpcWorkerService_method_names[5], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_RecvTensor_(grpcWorkerService_method_names[6], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_Logging_(grpcWorkerService_method_names[7], - ::grpc::RpcMethod::NORMAL_RPC, channel), - rpcmethod_Tracing_(grpcWorkerService_method_names[8], - ::grpc::RpcMethod::NORMAL_RPC, channel) {} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncGetStatusRaw(::grpc::ClientContext* context, - const GetStatusRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_GetStatus_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncRegisterGraphRaw(::grpc::ClientContext* context, - const RegisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_RegisterGraph_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncDeregisterGraphRaw( - ::grpc::ClientContext* context, const DeregisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_DeregisterGraph_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncRunGraphRaw(::grpc::ClientContext* context, - const RunGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_RunGraph_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncCleanupGraphRaw(::grpc::ClientContext* context, - const CleanupGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_CleanupGraph_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncCleanupAllRaw(::grpc::ClientContext* context, - const CleanupAllRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_CleanupAll_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncRecvTensorRaw(::grpc::ClientContext* context, - const RecvTensorRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_RecvTensor_, context, request); -} - -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncLoggingRaw(::grpc::ClientContext* context, - const LoggingRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_Logging_, context, request); +const char* GrpcWorkerMethodName(GrpcWorkerMethod id) { + switch (id) { + case GrpcWorkerMethod::kGetStatus: + return "/tensorflow.WorkerService/GetStatus"; + case GrpcWorkerMethod::kRegisterGraph: + return "/tensorflow.WorkerService/RegisterGraph"; + case GrpcWorkerMethod::kDeregisterGraph: + return "/tensorflow.WorkerService/DeregisterGraph"; + case GrpcWorkerMethod::kRunGraph: + return "/tensorflow.WorkerService/RunGraph"; + case GrpcWorkerMethod::kCleanupGraph: + return "/tensorflow.WorkerService/CleanupGraph"; + case GrpcWorkerMethod::kCleanupAll: + return "/tensorflow.WorkerService/CleanupAll"; + case GrpcWorkerMethod::kRecvTensor: + return "/tensorflow.WorkerService/RecvTensor"; + case GrpcWorkerMethod::kLogging: + return "/tensorflow.WorkerService/Logging"; + case GrpcWorkerMethod::kTracing: + return "/tensorflow.WorkerService/Tracing"; + } } -::grpc::ClientAsyncResponseReader* -WorkerService::Stub::AsyncTracingRaw(::grpc::ClientContext* context, - const TracingRequest& request, - ::grpc::CompletionQueue* cq) { - return new ::grpc::ClientAsyncResponseReader( - channel_.get(), cq, rpcmethod_Tracing_, context, request); -} +namespace grpc { WorkerService::AsyncService::AsyncService() { - (void)grpcWorkerService_method_names; - for (int i = 0; i < TF_ARRAYSIZE(grpcWorkerService_method_names); ++i) { - AddMethod(new ::grpc::RpcServiceMethod(grpcWorkerService_method_names[i], - ::grpc::RpcMethod::NORMAL_RPC, - nullptr)); + for (int i = 0; i < kGrpcNumWorkerMethods; ++i) { + AddMethod(new ::grpc::RpcServiceMethod( + GrpcWorkerMethodName(static_cast(i)), + ::grpc::RpcMethod::NORMAL_RPC, nullptr)); ::grpc::Service::MarkMethodAsync(i); } } diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h index 0513bc6894c2235daa07ff36531efe1c8f6e0502..f3aac795cab31dd95c807f77ad8f168c39b8e471 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h +++ b/tensorflow/core/distributed_runtime/rpc/grpc_worker_service_impl.h @@ -106,6 +106,23 @@ class SerializationTraits namespace tensorflow { +// Names of worker methods. +enum class GrpcWorkerMethod { + kGetStatus, + kRegisterGraph, + kDeregisterGraph, + kRunGraph, + kCleanupGraph, + kCleanupAll, + kRecvTensor, + kLogging, + kTracing, +}; +static const int kGrpcNumWorkerMethods = + static_cast(GrpcWorkerMethod::kTracing) + 1; + +const char* GrpcWorkerMethodName(GrpcWorkerMethod id); + namespace grpc { // Implementation of `tensorflow.WorkerService`, based on the @@ -114,364 +131,13 @@ namespace grpc { // See the proto file for the definition of methods and messages. class WorkerService GRPC_FINAL { public: - class StubInterface { - public: - virtual ~StubInterface() {} - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::GetStatusResponse>> - AsyncGetStatus(::grpc::ClientContext* context, - const ::tensorflow::GetStatusRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::GetStatusResponse>>( - AsyncGetStatusRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RegisterGraphResponse>> - AsyncRegisterGraph(::grpc::ClientContext* context, - const ::tensorflow::RegisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RegisterGraphResponse>>( - AsyncRegisterGraphRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::DeregisterGraphResponse>> - AsyncDeregisterGraph(::grpc::ClientContext* context, - const ::tensorflow::DeregisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::DeregisterGraphResponse>>( - AsyncDeregisterGraphRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RunGraphResponse>> - AsyncRunGraph(::grpc::ClientContext* context, - const ::tensorflow::RunGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RunGraphResponse>>( - AsyncRunGraphRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupGraphResponse>> - AsyncCleanupGraph(::grpc::ClientContext* context, - const ::tensorflow::CleanupGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupGraphResponse>>( - AsyncCleanupGraphRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupAllResponse>> - AsyncCleanupAll(::grpc::ClientContext* context, - const ::tensorflow::CleanupAllRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupAllResponse>>( - AsyncCleanupAllRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TensorResponse>> - AsyncRecvTensor(::grpc::ClientContext* context, - const ::tensorflow::RecvTensorRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TensorResponse>>( - AsyncRecvTensorRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::LoggingResponse>> - AsyncLogging(::grpc::ClientContext* context, - const ::tensorflow::LoggingRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::LoggingResponse>>( - AsyncLoggingRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TracingResponse>> - AsyncTracing(::grpc::ClientContext* context, - const ::tensorflow::TracingRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TracingResponse>>( - AsyncTracingRaw(context, request, cq)); - } - - private: - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::GetStatusResponse>* - AsyncGetStatusRaw(::grpc::ClientContext* context, - const ::tensorflow::GetStatusRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RegisterGraphResponse>* - AsyncRegisterGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::RegisterGraphRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::DeregisterGraphResponse>* - AsyncDeregisterGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::DeregisterGraphRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::RunGraphResponse>* - AsyncRunGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::RunGraphRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupGraphResponse>* - AsyncCleanupGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::CleanupGraphRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::CleanupAllResponse>* - AsyncCleanupAllRaw(::grpc::ClientContext* context, - const ::tensorflow::CleanupAllRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TensorResponse>* - AsyncRecvTensorRaw(::grpc::ClientContext* context, - const ::tensorflow::RecvTensorRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::LoggingResponse>* - AsyncLoggingRaw(::grpc::ClientContext* context, - const ::tensorflow::LoggingRequest& request, - ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< - ::tensorflow::TracingResponse>* - AsyncTracingRaw(::grpc::ClientContext* context, - const ::tensorflow::TracingRequest& request, - ::grpc::CompletionQueue* cq) = 0; - }; - class Stub GRPC_FINAL : public StubInterface { - public: - Stub(const std::shared_ptr<::grpc::ChannelInterface>& channel); - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::GetStatusResponse>> - AsyncGetStatus(::grpc::ClientContext* context, - const ::tensorflow::GetStatusRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::GetStatusResponse>>( - AsyncGetStatusRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::RegisterGraphResponse>> - AsyncRegisterGraph(::grpc::ClientContext* context, - const ::tensorflow::RegisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReader< - ::tensorflow::RegisterGraphResponse>>( - AsyncRegisterGraphRaw(context, request, cq)); - } - std::unique_ptr<::grpc::ClientAsyncResponseReader< - ::tensorflow::DeregisterGraphResponse>> - AsyncDeregisterGraph(::grpc::ClientContext* context, - const ::tensorflow::DeregisterGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReader< - ::tensorflow::DeregisterGraphResponse>>( - AsyncDeregisterGraphRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::RunGraphResponse>> - AsyncRunGraph(::grpc::ClientContext* context, - const ::tensorflow::RunGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::RunGraphResponse>>( - AsyncRunGraphRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::CleanupGraphResponse>> - AsyncCleanupGraph(::grpc::ClientContext* context, - const ::tensorflow::CleanupGraphRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr<::grpc::ClientAsyncResponseReader< - ::tensorflow::CleanupGraphResponse>>( - AsyncCleanupGraphRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::CleanupAllResponse>> - AsyncCleanupAll(::grpc::ClientContext* context, - const ::tensorflow::CleanupAllRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::CleanupAllResponse>>( - AsyncCleanupAllRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::TensorResponse>> - AsyncRecvTensor(::grpc::ClientContext* context, - const ::tensorflow::RecvTensorRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::TensorResponse>>( - AsyncRecvTensorRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::LoggingResponse>> - AsyncLogging(::grpc::ClientContext* context, - const ::tensorflow::LoggingRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::LoggingResponse>>( - AsyncLoggingRaw(context, request, cq)); - } - std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::TracingResponse>> - AsyncTracing(::grpc::ClientContext* context, - const ::tensorflow::TracingRequest& request, - ::grpc::CompletionQueue* cq) { - return std::unique_ptr< - ::grpc::ClientAsyncResponseReader<::tensorflow::TracingResponse>>( - AsyncTracingRaw(context, request, cq)); - } - - private: - std::shared_ptr<::grpc::ChannelInterface> channel_; - ::grpc::ClientAsyncResponseReader<::tensorflow::GetStatusResponse>* - AsyncGetStatusRaw(::grpc::ClientContext* context, - const ::tensorflow::GetStatusRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::RegisterGraphResponse>* - AsyncRegisterGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::RegisterGraphRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::DeregisterGraphResponse>* - AsyncDeregisterGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::DeregisterGraphRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::RunGraphResponse>* - AsyncRunGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::RunGraphRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::CleanupGraphResponse>* - AsyncCleanupGraphRaw(::grpc::ClientContext* context, - const ::tensorflow::CleanupGraphRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::CleanupAllResponse>* - AsyncCleanupAllRaw(::grpc::ClientContext* context, - const ::tensorflow::CleanupAllRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::TensorResponse>* - AsyncRecvTensorRaw(::grpc::ClientContext* context, - const ::tensorflow::RecvTensorRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::LoggingResponse>* - AsyncLoggingRaw(::grpc::ClientContext* context, - const ::tensorflow::LoggingRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - ::grpc::ClientAsyncResponseReader<::tensorflow::TracingResponse>* - AsyncTracingRaw(::grpc::ClientContext* context, - const ::tensorflow::TracingRequest& request, - ::grpc::CompletionQueue* cq) GRPC_OVERRIDE; - const ::grpc::RpcMethod rpcmethod_GetStatus_; - const ::grpc::RpcMethod rpcmethod_RegisterGraph_; - const ::grpc::RpcMethod rpcmethod_DeregisterGraph_; - const ::grpc::RpcMethod rpcmethod_RunGraph_; - const ::grpc::RpcMethod rpcmethod_CleanupGraph_; - const ::grpc::RpcMethod rpcmethod_CleanupAll_; - const ::grpc::RpcMethod rpcmethod_RecvTensor_; - const ::grpc::RpcMethod rpcmethod_Logging_; - const ::grpc::RpcMethod rpcmethod_Tracing_; - }; - static std::unique_ptr NewStub( - const std::shared_ptr<::grpc::ChannelInterface>& channel, - const ::grpc::StubOptions& options = ::grpc::StubOptions()); - class AsyncService : public ::grpc::Service { public: AsyncService(); virtual ~AsyncService(); - void RequestGetStatus( - ::grpc::ServerContext* context, ::tensorflow::GetStatusRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::GetStatusResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestRegisterGraph( - ::grpc::ServerContext* context, - ::tensorflow::RegisterGraphRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::RegisterGraphResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(1, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestDeregisterGraph( - ::grpc::ServerContext* context, - ::tensorflow::DeregisterGraphRequest* request, - ::grpc::ServerAsyncResponseWriter< - ::tensorflow::DeregisterGraphResponse>* response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(2, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestRunGraph( - ::grpc::ServerContext* context, ::tensorflow::RunGraphRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::RunGraphResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(3, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestCleanupGraph( - ::grpc::ServerContext* context, - ::tensorflow::CleanupGraphRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::CleanupGraphResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(4, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestCleanupAll( - ::grpc::ServerContext* context, - ::tensorflow::CleanupAllRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::CleanupAllResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(5, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestRecvTensorRaw( - ::grpc::ServerContext* context, - ::tensorflow::RecvTensorRequest* request, - ::grpc::ServerAsyncResponseWriter<::grpc::ByteBuffer>* response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(6, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestLogging( - ::grpc::ServerContext* context, ::tensorflow::LoggingRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::LoggingResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(7, context, request, response, - new_call_cq, notification_cq, tag); - } - void RequestTracing( - ::grpc::ServerContext* context, ::tensorflow::TracingRequest* request, - ::grpc::ServerAsyncResponseWriter<::tensorflow::TracingResponse>* - response, - ::grpc::CompletionQueue* new_call_cq, - ::grpc::ServerCompletionQueue* notification_cq, void* tag) { - ::grpc::Service::RequestAsyncUnary(8, context, request, response, - new_call_cq, notification_cq, tag); - } + + // Make RequestAsyncUnary public for grpc_call.h + using ::grpc::Service::RequestAsyncUnary; }; }; diff --git a/tensorflow/core/framework/attr_value_util.cc b/tensorflow/core/framework/attr_value_util.cc index 57c2801ac924da418d920ea346a0159c11992abd..36c42db8004d5799ed5428e2bf91ad4cbd672595 100644 --- a/tensorflow/core/framework/attr_value_util.cc +++ b/tensorflow/core/framework/attr_value_util.cc @@ -167,7 +167,7 @@ Status AttrValueHasType(const AttrValue& attr_value, StringPiece type) { if (attr_value.value_case() == AttrValue::kPlaceholder) { return errors::InvalidArgument( - "AttrValue had value with unexpected type 'placeholder"); + "AttrValue had value with unexpected type 'placeholder'"); } // If the attr type is 'list', we expect attr_value.has_list() to be diff --git a/tensorflow/core/framework/common_shape_fns.cc b/tensorflow/core/framework/common_shape_fns.cc index 090d9804e2f67994c36234540e41ec81ee61b2cc..c345d3c742507cd5bfb96e388bb2cb4bd6d75ba4 100644 --- a/tensorflow/core/framework/common_shape_fns.cc +++ b/tensorflow/core/framework/common_shape_fns.cc @@ -75,22 +75,22 @@ Status UnchangedShape(shape_inference::InferenceContext* c) { } Status MatMulShape(shape_inference::InferenceContext* c) { - const Shape* a; + ShapeHandle a; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &a)); - const Shape* b; + ShapeHandle b; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &b)); bool transpose_a, transpose_b; TF_RETURN_IF_ERROR(c->GetAttr("transpose_a", &transpose_a)); TF_RETURN_IF_ERROR(c->GetAttr("transpose_b", &transpose_b)); - const Dimension* output_rows = transpose_a ? c->Dim(a, 1) : c->Dim(a, 0); - const Dimension* output_cols = transpose_b ? c->Dim(b, 0) : c->Dim(b, 1); + DimensionHandle output_rows = transpose_a ? c->Dim(a, 1) : c->Dim(a, 0); + DimensionHandle output_cols = transpose_b ? c->Dim(b, 0) : c->Dim(b, 1); // Validate that the inner shapes are compatible. - const Dimension* inner_a = transpose_a ? c->Dim(a, 0) : c->Dim(a, 1); - const Dimension* inner_b = transpose_b ? c->Dim(b, 1) : c->Dim(b, 0); - const Dimension* merged; + DimensionHandle inner_a = transpose_a ? c->Dim(a, 0) : c->Dim(a, 1); + DimensionHandle inner_b = transpose_b ? c->Dim(b, 1) : c->Dim(b, 0); + DimensionHandle merged; TF_RETURN_IF_ERROR(c->Merge(inner_a, inner_b, &merged)); c->set_output(0, c->Matrix(output_rows, output_cols)); @@ -98,7 +98,7 @@ Status MatMulShape(shape_inference::InferenceContext* c) { } Status BiasAddShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; // Fetch the data_format attribute, which may not exist. string data_format; @@ -110,9 +110,9 @@ Status BiasAddShape(shape_inference::InferenceContext* c) { TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 2, &input_shape)); } - const Shape* bias_shape; + ShapeHandle bias_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &bias_shape)); - const Dimension* bias_dim = c->Dim(bias_shape, 0); + DimensionHandle bias_dim = c->Dim(bias_shape, 0); // If rank unknown, return unknown shape. if (!c->RankKnown(input_shape)) { @@ -122,32 +122,32 @@ Status BiasAddShape(shape_inference::InferenceContext* c) { // Output has the same shape as the input, and matches the length of // the bias in its bias dimension. - const Shape* output_shape; + ShapeHandle output_shape; if (s.ok() && data_format == "NCHW") { // Merge the length of bias_shape into the third to last dimension - const Shape* first; + ShapeHandle first; TF_RETURN_IF_ERROR(c->Subshape(input_shape, 0, -3, &first)); - const Shape* last; + ShapeHandle last; TF_RETURN_IF_ERROR(c->Subshape(input_shape, -2, &last)); - const Dimension* input_bias_dim = c->Dim(input_shape, -3); - const Dimension* merged_bias_dim; + DimensionHandle input_bias_dim = c->Dim(input_shape, -3); + DimensionHandle merged_bias_dim; TF_RETURN_IF_ERROR(c->Merge(input_bias_dim, bias_dim, &merged_bias_dim)); - const Shape* merged_bias = c->Vector(merged_bias_dim); + ShapeHandle merged_bias = c->Vector(merged_bias_dim); - const Shape* temp; + ShapeHandle temp; TF_RETURN_IF_ERROR(c->Concatenate(first, merged_bias, &temp)); TF_RETURN_IF_ERROR(c->Concatenate(temp, last, &output_shape)); } else { - const Shape* all_but_bias; + ShapeHandle all_but_bias; TF_RETURN_IF_ERROR(c->Subshape(input_shape, 0, -1, &all_but_bias)); - const Dimension* input_bias_dim = c->Dim(input_shape, -1); - const Dimension* merged_bias_dim; + DimensionHandle input_bias_dim = c->Dim(input_shape, -1); + DimensionHandle merged_bias_dim; TF_RETURN_IF_ERROR(c->Merge(input_bias_dim, bias_dim, &merged_bias_dim)); - const Shape* merged_bias = c->Vector(merged_bias_dim); + ShapeHandle merged_bias = c->Vector(merged_bias_dim); TF_RETURN_IF_ERROR( c->Concatenate(all_but_bias, merged_bias, &output_shape)); } @@ -157,7 +157,7 @@ Status BiasAddShape(shape_inference::InferenceContext* c) { } Status BiasAddGradShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; // Fetch the data_format attribute, which may not exist. string data_format; Status s = c->GetAttr("data_format", &data_format); @@ -174,9 +174,9 @@ Status BiasAddGradShape(shape_inference::InferenceContext* c) { } Status Conv2DShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); - const Shape* filter_shape; + ShapeHandle filter_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 4, &filter_shape)); string data_format; @@ -205,12 +205,12 @@ Status Conv2DShape(shape_inference::InferenceContext* c) { stride_cols = strides[2]; } - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* filter_rows_dim = c->Dim(filter_shape, 0); - const Dimension* filter_cols_dim = c->Dim(filter_shape, 1); - const Dimension* output_depth_dim = c->Dim(filter_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle filter_rows_dim = c->Dim(filter_shape, 0); + DimensionHandle filter_cols_dim = c->Dim(filter_shape, 1); + DimensionHandle output_depth_dim = c->Dim(filter_shape, 3); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_rows_dim, "in_rows")); @@ -223,7 +223,7 @@ Status Conv2DShape(shape_inference::InferenceContext* c) { auto filter_rows = c->Value(filter_rows_dim); auto filter_cols = c->Value(filter_cols_dim); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input_shape, 3), c->Dim(filter_shape, 2), &unused)); @@ -239,7 +239,7 @@ Status Conv2DShape(shape_inference::InferenceContext* c) { in_cols, filter_cols, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape; + ShapeHandle output_shape; if (data_format == "NCHW") { output_shape = c->MakeShape( {batch_size_dim, output_depth_dim, output_rows, output_cols}); @@ -253,9 +253,9 @@ Status Conv2DShape(shape_inference::InferenceContext* c) { } Status Conv3DShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 5, &input_shape)); - const Shape* filter_shape; + ShapeHandle filter_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 5, &filter_shape)); std::vector strides; @@ -270,15 +270,15 @@ Status Conv3DShape(shape_inference::InferenceContext* c) { int32 stride_rows = strides[2]; int32 stride_cols = strides[3]; - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_planes_dim = c->Dim(input_shape, 1); - const Dimension* in_rows_dim = c->Dim(input_shape, 2); - const Dimension* in_cols_dim = c->Dim(input_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_planes_dim = c->Dim(input_shape, 1); + DimensionHandle in_rows_dim = c->Dim(input_shape, 2); + DimensionHandle in_cols_dim = c->Dim(input_shape, 3); - const Dimension* filter_planes_dim = c->Dim(filter_shape, 0); - const Dimension* filter_rows_dim = c->Dim(filter_shape, 1); - const Dimension* filter_cols_dim = c->Dim(filter_shape, 2); - const Dimension* output_depth_dim = c->Dim(filter_shape, 4); + DimensionHandle filter_planes_dim = c->Dim(filter_shape, 0); + DimensionHandle filter_rows_dim = c->Dim(filter_shape, 1); + DimensionHandle filter_cols_dim = c->Dim(filter_shape, 2); + DimensionHandle output_depth_dim = c->Dim(filter_shape, 4); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_planes_dim, "in_planes")); @@ -295,7 +295,7 @@ Status Conv3DShape(shape_inference::InferenceContext* c) { auto filter_rows = c->Value(filter_rows_dim); auto filter_cols = c->Value(filter_cols_dim); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input_shape, 4), c->Dim(filter_shape, 3), &unused)); @@ -314,7 +314,7 @@ Status Conv3DShape(shape_inference::InferenceContext* c) { in_cols, filter_cols, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape = + ShapeHandle output_shape = c->MakeShape({batch_size_dim, output_planes, output_rows, output_cols, output_depth_dim}); c->set_output(0, output_shape); @@ -322,9 +322,9 @@ Status Conv3DShape(shape_inference::InferenceContext* c) { } Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); - const Shape* filter_shape; + ShapeHandle filter_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 4, &filter_shape)); std::vector strides; @@ -337,13 +337,13 @@ Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) { strides.size()); } - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* filter_rows_dim = c->Dim(filter_shape, 0); - const Dimension* filter_cols_dim = c->Dim(filter_shape, 1); - const Dimension* input_depth = c->Dim(filter_shape, 2); - const Dimension* depth_multiplier = c->Dim(filter_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle filter_rows_dim = c->Dim(filter_shape, 0); + DimensionHandle filter_cols_dim = c->Dim(filter_shape, 1); + DimensionHandle input_depth = c->Dim(filter_shape, 2); + DimensionHandle depth_multiplier = c->Dim(filter_shape, 3); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_rows_dim, "in_rows")); @@ -357,7 +357,7 @@ Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) { TF_RETURN_IF_ERROR( c->Merge(c->Dim(input_shape, 3), input_depth, &input_depth)); - const Dimension* output_depth; + DimensionHandle output_depth; TF_RETURN_IF_ERROR(c->Multiply(input_depth, depth_multiplier, &output_depth)); const int32 stride_rows = strides[1]; @@ -383,14 +383,14 @@ Status DepthwiseConv2DNativeShape(shape_inference::InferenceContext* c) { in_cols, filter_cols, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape = + ShapeHandle output_shape = c->MakeShape({batch_size_dim, output_rows, output_cols, output_depth}); c->set_output(0, output_shape); return Status::OK(); } Status AvgPoolShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); string data_format; @@ -432,10 +432,10 @@ Status AvgPoolShape(shape_inference::InferenceContext* c) { kernel_cols = kernel_sizes[2]; } - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* output_depth_dim = c->Dim(input_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle output_depth_dim = c->Dim(input_shape, 3); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_rows_dim, "in_rows")); @@ -459,7 +459,7 @@ Status AvgPoolShape(shape_inference::InferenceContext* c) { in_cols, kernel_cols, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape; + ShapeHandle output_shape; if (data_format == "NCHW") { output_shape = c->MakeShape( {batch_size_dim, output_depth_dim, output_rows, output_cols}); @@ -473,7 +473,7 @@ Status AvgPoolShape(shape_inference::InferenceContext* c) { } Status MaxPoolShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); string data_format; @@ -519,10 +519,10 @@ Status MaxPoolShape(shape_inference::InferenceContext* c) { kernel_depth = kernel_sizes[3]; } - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* in_depth_dim = c->Dim(input_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle in_depth_dim = c->Dim(input_shape, 3); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_rows_dim, "in_rows")); @@ -551,7 +551,7 @@ Status MaxPoolShape(shape_inference::InferenceContext* c) { in_depth, kernel_depth, stride_depth, padding, &output_depth, &padding_before, &padding_after)); - const Shape* output_shape = + ShapeHandle output_shape = c->MakeShape({batch_size_dim, output_rows, output_cols, output_depth}); if (data_format == "NCHW") { @@ -566,7 +566,7 @@ Status MaxPoolShape(shape_inference::InferenceContext* c) { } Status Pool3DShape(shape_inference::InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 5, &input_shape)); std::vector strides; @@ -596,11 +596,11 @@ Status Pool3DShape(shape_inference::InferenceContext* c) { kernel_rows = kernel_sizes[2]; kernel_cols = kernel_sizes[3]; - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_planes_dim = c->Dim(input_shape, 1); - const Dimension* in_rows_dim = c->Dim(input_shape, 2); - const Dimension* in_cols_dim = c->Dim(input_shape, 3); - const Dimension* output_depth_dim = c->Dim(input_shape, 4); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_planes_dim = c->Dim(input_shape, 1); + DimensionHandle in_rows_dim = c->Dim(input_shape, 2); + DimensionHandle in_cols_dim = c->Dim(input_shape, 3); + DimensionHandle output_depth_dim = c->Dim(input_shape, 4); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_planes_dim, "in_planes")); @@ -629,7 +629,7 @@ Status Pool3DShape(shape_inference::InferenceContext* c) { in_cols, kernel_cols, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape = + ShapeHandle output_shape = c->MakeShape({batch_size_dim, output_planes, output_rows, output_cols, output_depth_dim}); @@ -645,9 +645,9 @@ Status UnknownShape(shape_inference::InferenceContext* c) { } Status ReductionShape(InferenceContext* c) { - const Shape* input = c->input(0); + ShapeHandle input = c->input(0); - const Shape* indices; + ShapeHandle indices; TF_RETURN_IF_ERROR(c->WithRankAtMost(c->input(1), 1, &indices)); const Tensor* reduction_indices_t = c->input_tensor(1); @@ -679,7 +679,7 @@ Status ReductionShape(InferenceContext* c) { wrapped_index += input_rank; } - const Dimension* reduce_dim = c->Dim(input, wrapped_index); + DimensionHandle reduce_dim = c->Dim(input, wrapped_index); if (c->ValueKnown(reduce_dim) && c->Value(reduce_dim) == 0) { return errors::InvalidArgument("Cannot reduce dimension ", reduction_index, " with size 0"); @@ -688,7 +688,7 @@ Status ReductionShape(InferenceContext* c) { true_indices.insert(wrapped_index); } - std::vector dims; + std::vector dims; bool reduce_all = reduction_indices_t->NumElements() == 0; for (int i = 0; i < input_rank; ++i) { if (reduce_all || true_indices.count(i) > 0) { @@ -705,7 +705,7 @@ Status ReductionShape(InferenceContext* c) { } Status ConcatShape(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); const Tensor* concat_dim_t = c->input_tensor(0); @@ -730,7 +730,7 @@ Status ConcatShape(InferenceContext* c) { "Can't concatenate scalars (use tf.pack instead)"); } // Build result of different unknown dims. - std::vector dims; + std::vector dims; for (int i = 0; i < rank; ++i) dims.push_back(c->UnknownDim()); c->set_output(0, c->MakeShape(dims)); return Status::OK(); @@ -744,22 +744,22 @@ Status ConcatShape(InferenceContext* c) { concat_dim); } - const Shape* output_before; - const Shape* output_after; + ShapeHandle output_before; + ShapeHandle output_after; - const Shape* input = c->input(c->num_inputs() - 1); + ShapeHandle input = c->input(c->num_inputs() - 1); TF_RETURN_IF_ERROR(c->WithRankAtLeast(input, concat_dim + 1, &input)); TF_RETURN_IF_ERROR(c->Subshape(input, 0, concat_dim, &output_before)); - const Dimension* output_middle = c->Dim(input, concat_dim); + DimensionHandle output_middle = c->Dim(input, concat_dim); TF_RETURN_IF_ERROR(c->Subshape(input, concat_dim + 1, &output_after)); for (int i = c->num_inputs() - 2; i > 0; --i) { - const Shape* before; - const Shape* after; + ShapeHandle before; + ShapeHandle after; input = c->input(i); TF_RETURN_IF_ERROR(c->WithRankAtLeast(input, concat_dim + 1, &input)); TF_RETURN_IF_ERROR(c->Subshape(input, 0, concat_dim, &before)); - const Dimension* middle = c->Dim(input, concat_dim); + DimensionHandle middle = c->Dim(input, concat_dim); TF_RETURN_IF_ERROR(c->Subshape(input, concat_dim + 1, &after)); TF_RETURN_IF_ERROR(c->Merge(before, output_before, &output_before)); @@ -767,7 +767,7 @@ Status ConcatShape(InferenceContext* c) { TF_RETURN_IF_ERROR(c->Merge(after, output_after, &output_after)); } - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR( c->Concatenate(output_before, c->Vector(output_middle), &s)); TF_RETURN_IF_ERROR(c->Concatenate(s, output_after, &s)); diff --git a/tensorflow/core/framework/common_shape_fns.h b/tensorflow/core/framework/common_shape_fns.h index 71692cec1e5325b1a4d30bfe72f6f0a1da2e041b..b828b23dfe74b62b122c9d30abf4a5b61b18c5af 100644 --- a/tensorflow/core/framework/common_shape_fns.h +++ b/tensorflow/core/framework/common_shape_fns.h @@ -102,7 +102,7 @@ Status UnchangedShape(shape_inference::InferenceContext* c); // Transfers shape of input(0) to output(0), after asserting its rank is . inline Status UnchangedShapeWithRank(shape_inference::InferenceContext* c, int32 rank) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), rank, &out)); c->set_output(0, out); return Status::OK(); @@ -111,7 +111,7 @@ inline Status UnchangedShapeWithRank(shape_inference::InferenceContext* c, // Transfers shape of input(0) to output(0), after asserting its rank >= . inline Status UnchangedShapeWithRankAtLeast( shape_inference::InferenceContext* c, int32 rank) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), rank, &out)); c->set_output(0, out); return Status::OK(); @@ -120,7 +120,7 @@ inline Status UnchangedShapeWithRankAtLeast( // Transfers shape of input(0) to output(0), after asserting its rank <= . inline Status UnchangedShapeWithRankAtMost(shape_inference::InferenceContext* c, int32 rank) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->WithRankAtMost(c->input(0), rank, &out)); c->set_output(0, out); return Status::OK(); @@ -139,7 +139,7 @@ inline Status ScalarShape(shape_inference::InferenceContext* c) { // Shape function for binary ops where both inputs and the output match. inline Status MergeBothInputsShapeFn(InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Merge(c->input(0), c->input(1), &out)); c->set_output(0, out); return Status::OK(); diff --git a/tensorflow/core/framework/common_shape_fns_test.cc b/tensorflow/core/framework/common_shape_fns_test.cc index e12a33adf412217a3ecee57acf967c914ee26ce3..45968fda7355e5e544bbc1b839632ffa781bf092 100644 --- a/tensorflow/core/framework/common_shape_fns_test.cc +++ b/tensorflow/core/framework/common_shape_fns_test.cc @@ -58,14 +58,14 @@ TEST(CommonShapeFnsTest, ScalarShapeTest) { { InferenceContext c(&def, op_def, {"[]"}, {}); TF_EXPECT_OK(ScalarShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(0, c.Rank(output)); } { InferenceContext c(&def, op_def, {"[1,23,4,4,2]"}, {}); TF_EXPECT_OK(ScalarShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(0, c.Rank(output)); } } @@ -92,7 +92,7 @@ TEST(CommonShapeFnsTest, MatMulShapeTest) { { InferenceContext c(&def, op_def, {"[2,3]", "[3,4]"}, {}); TF_EXPECT_OK(MatMulShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_EQ(4, c.Value(c.Dim(output, 1))); } @@ -101,7 +101,7 @@ TEST(CommonShapeFnsTest, MatMulShapeTest) { // Unknown inner dimension for one InferenceContext c(&def, op_def, {"[2,?]", "[3,4]"}, {}); TF_EXPECT_OK(MatMulShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_EQ(4, c.Value(c.Dim(output, 1))); } @@ -119,7 +119,7 @@ TEST(CommonShapeFnsTest, MatMulShapeTest) { // Unknown outer dimension InferenceContext c(&def, op_def, {"[2,3]", "[3,?]"}, {}); TF_EXPECT_OK(MatMulShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_FALSE(c.ValueKnown(c.Dim(output, 1))); } @@ -154,7 +154,7 @@ TEST(CommonShapeFnsTest, MatMulShapeTest) { InferenceContext c(&def, op_def, {"[3,2]", "[3,4]"}, {}); auto s = MatMulShape(&c); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_EQ(4, c.Value(c.Dim(output, 1))); } @@ -171,7 +171,7 @@ TEST(CommonShapeFnsTest, MatMulShapeTest) { InferenceContext c(&def, op_def, {"[2,3]", "[4,3]"}, {}); auto s = MatMulShape(&c); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_EQ(4, c.Value(c.Dim(output, 1))); } @@ -195,7 +195,7 @@ TEST(CommonShapeFnsTest, BiasAddShapeTest) { { InferenceContext c(&def, op_def, {"[2,10]", "[10]"}, {}); TF_EXPECT_OK(BiasAddShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(2, c.Value(c.Dim(output, 0))); EXPECT_EQ(10, c.Value(c.Dim(output, 1))); } @@ -204,7 +204,7 @@ TEST(CommonShapeFnsTest, BiasAddShapeTest) { // Unknown ranks. InferenceContext c(&def, op_def, {"?", "?"}, {}); TF_EXPECT_OK(BiasAddShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_FALSE(c.RankKnown(output)); } @@ -212,7 +212,7 @@ TEST(CommonShapeFnsTest, BiasAddShapeTest) { // Rank > 2 InferenceContext c(&def, op_def, {"[4,3,4,2,15]", "[15]"}, {}); TF_EXPECT_OK(BiasAddShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ("[4,3,4,2,15]", c.DebugString(output)); } @@ -225,7 +225,7 @@ TEST(CommonShapeFnsTest, BiasAddShapeTest) { .Finalize(&def)); InferenceContext c(&def, op_def, {"[2,3,4,5]", "[3]"}, {}); TF_EXPECT_OK(BiasAddShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ("[2,3,4,5]", c.DebugString(output)); } @@ -238,7 +238,7 @@ TEST(CommonShapeFnsTest, BiasAddShapeTest) { .Finalize(&def)); InferenceContext c(&def, op_def, {"[8,6,4,2,3,4,5]", "[3]"}, {}); TF_EXPECT_OK(BiasAddShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ("[8,6,4,2,3,4,5]", c.DebugString(output)); } @@ -277,7 +277,7 @@ TEST(CommonShapeFnsTest, BiasAddGradShapeTest) { { InferenceContext c(&def, op_def, {"[2,10]"}, {}); TF_EXPECT_OK(BiasAddGradShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(10, c.Value(c.Dim(output, 0))); } @@ -285,7 +285,7 @@ TEST(CommonShapeFnsTest, BiasAddGradShapeTest) { // Rank > 2 InferenceContext c(&def, op_def, {"[5,7,2,10]"}, {}); TF_EXPECT_OK(BiasAddGradShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(10, c.Value(c.Dim(output, 0))); } @@ -297,7 +297,7 @@ TEST(CommonShapeFnsTest, BiasAddGradShapeTest) { .Finalize(&def)); InferenceContext c(&def, op_def, {"[2,3,4,5]"}, {}); TF_EXPECT_OK(BiasAddGradShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(3, c.Value(c.Dim(output, 0))); } @@ -309,7 +309,7 @@ TEST(CommonShapeFnsTest, BiasAddGradShapeTest) { .Finalize(&def)); InferenceContext c(&def, op_def, {"[8,6,4,2,3,4,5]"}, {}); TF_EXPECT_OK(BiasAddGradShape(&c)); - const Shape* output = c.output(0); + ShapeHandle output = c.output(0); EXPECT_EQ(3, c.Value(c.Dim(output, 0))); } diff --git a/tensorflow/core/framework/function.cc b/tensorflow/core/framework/function.cc index 5fade3601667d7e948549bbfdc01d30e779524c1..f2ca053df42233d1836c893883d27137b2e64bab 100644 --- a/tensorflow/core/framework/function.cc +++ b/tensorflow/core/framework/function.cc @@ -106,17 +106,40 @@ Status ValidateSignatureWithAttrs(const OpDef& sig, const InstantiateAttrValueMap& attr_values) { // attr_values should specify all attrs defined in fdef. for (const auto& a : sig.attr()) { - if (attr_values.find(a.name()) == attr_values.end()) { - return errors::NotFound("Attr ", a.name(), " is not found."); + auto const iter = attr_values.find(a.name()); + if (iter == attr_values.end()) { + return errors::NotFound("Attr ", a.name(), " is not found from ", + SummarizeOpDef(sig)); + } + Status status = AttrValueHasType(iter->second, a.type()); + if (!status.ok()) { + errors::AppendToMessage(&status, "for attr '", iter->first, "'"); + return status; } } - for (const auto& p : attr_values) { - if (HasPlaceHolder(p.second)) { - return errors::InvalidArgument(p.first, - " in attr_values is still a placeholder."); +// TODO(josh11b): Enable this code once it works with function gradients. +// Right now the C++ function gradient code assumes it can pass +// all the attrs of the function to the gradient, and any attrs that +// the gradient doesn't care about will be ignored. +#if 0 + if (attr_values.size() != sig.attr_size()) { + for (const auto& a : attr_values) { + // TODO(josh11b): Possibly should ignore attrs that start with "_" here? + bool found = false; + for (const auto& s : sig.attr()) { + if (a.first == s.name()) { + found = true; + break; + } + } + if (!found) { + return errors::NotFound("Attr ", a.first, " is not found in ", + SummarizeOpDef(sig)); + } } } +#endif return Status::OK(); } @@ -225,6 +248,38 @@ Status BuildNodeOutputIndex(const FunctionDef::Node& node, return Status::OK(); } +Status BuildNodeOutputIndex(const NodeDef& node, + const InstantiateAttrValueMap& attrs, + GetFunctionSignature get_function, + const int arg_index, NameInfoIndex* name_info) { + const OpDef* node_sig = nullptr; + TF_RETURN_IF_ERROR(get_function(node.op(), &node_sig)); + if (node_sig->output_arg_size() == 0) { + return AddRetName(name_info, node.name(), {false, arg_index, 0, false, {}}); + } + const int num_retval = node_sig->output_arg_size(); + int start = 0; + bool is_type_list; + DataTypeVector dtypes; + for (int i = 0; i < num_retval; ++i) { + TF_RETURN_IF_ERROR( + ArgNumType(attrs, node_sig->output_arg(i), &is_type_list, &dtypes)); + // Note that we rely on the backwards-compatibility test enforcing + // that output_arg(*).name() doesn't change here. + const string base_name = + strings::StrCat(node.name(), ":", node_sig->output_arg(i).name()); + TF_RETURN_IF_ERROR(AddRetName( + name_info, base_name, {false, arg_index, start, is_type_list, dtypes})); + for (int j = 0; j < static_cast(dtypes.size()); ++j) { + TF_RETURN_IF_ERROR( + AddRetName(name_info, strings::StrCat(base_name, ":", j), + {false, arg_index, start + j, false, {dtypes[j]}})); + } + start += dtypes.size(); + } + return Status::OK(); +} + Status InstantiateNode(const FunctionDef::Node& fnode, const InstantiateAttrValueMap& attrs, GetFunctionSignature get_function, @@ -252,7 +307,7 @@ Status InstantiateNode(const FunctionDef::Node& fnode, } if (dtypes != item->dtypes) { return errors::InvalidArgument("Invalid arg(", i, - ") for function arg: ", " ", + ") for function arg: ", DataTypeSliceString(dtypes), " vs. ", DataTypeSliceString(item->dtypes), "."); } @@ -274,7 +329,7 @@ Status InstantiateNode(const FunctionDef::Node& fnode, } if (item->dtypes.size() != 1 || (item->dtypes[0] != dtypes[j])) { return errors::InvalidArgument( - "Invalid typelist arg(", i + j, ") for function arg: ", " ", + "Invalid typelist arg(", i + j, ") for function arg: ", DataTypeSliceString(dtypes), " vs. ", DataTypeSliceString(item->dtypes), "."); } @@ -306,6 +361,105 @@ Status InstantiateNode(const FunctionDef::Node& fnode, return Status::OK(); } +Status InstantiateNode(const NodeDef& fnode, + const InstantiateAttrValueMap& attrs, + GetFunctionSignature get_function, + const NameInfoIndex& name_info, GraphDef* gdef) { + const OpDef* fnode_sig = nullptr; + TF_CHECK_OK(get_function(fnode.op(), &fnode_sig)); + NodeDef* gnode = gdef->add_node(); + gnode->set_name(Name(gdef->node_size() - 1)); + gnode->set_op(fnode.op()); + + // Input + const int num_args = fnode_sig->input_arg_size(); + bool is_type_list; + DataTypeVector dtypes; + int fnode_arg_index = 0; + for (int i = 0; i < num_args; ++i) { + TF_RETURN_IF_ERROR( + ArgNumType(attrs, fnode_sig->input_arg(i), &is_type_list, &dtypes)); + if (!is_type_list) { + if (fnode_arg_index >= fnode.input_size()) { + return errors::InvalidArgument("Attempt to access beyond input size: ", + fnode_arg_index, " >= ", + fnode.input_size()); + } + const NameInfoItem* item = + gtl::FindOrNull(name_info, fnode.input(fnode_arg_index)); + if (item == nullptr) { + return errors::InvalidArgument("input[", i, "] == '", + fnode.input(fnode_arg_index), + "' is not found"); + } + if (dtypes != item->dtypes) { + return errors::InvalidArgument("Invalid type of input(", i, + ") for function node: ", + DataTypeSliceString(dtypes), " vs. ", + DataTypeSliceString(item->dtypes), "."); + } + for (size_t j = 0; j < dtypes.size(); ++j) { + if (item->is_func_arg) { + gnode->add_input(Name(item->nid + j)); + } else { + gnode->add_input(Name(item->nid, item->idx + j)); + } + } + ++fnode_arg_index; + } else { + for (size_t j = 0; j < dtypes.size(); ++j) { + if (fnode_arg_index + j >= fnode.input_size()) { + return errors::InvalidArgument( + "Attempt to access beyond input size: ", fnode_arg_index + j, + " >= ", fnode.input_size()); + } + const NameInfoItem* item = + gtl::FindOrNull(name_info, fnode.input(fnode_arg_index + j)); + if (item == nullptr) { + return errors::InvalidArgument("input[", i + j, "] is not found: ", + SummarizeNodeDef(fnode)); + } + if (item->dtypes.size() != 1 || (item->dtypes[0] != dtypes[j])) { + return errors::InvalidArgument( + "Invalid typelist input(", i + j, ") for function arg: ", " ", + DataTypeSliceString(dtypes), " vs. ", + DataTypeSliceString(item->dtypes), "."); + } + if (item->is_func_arg) { + gnode->add_input(Name(item->nid)); + } else { + gnode->add_input(Name(item->nid, item->idx)); + } + } + fnode_arg_index += dtypes.size(); + } + } + // Control deps. + for (int i = fnode_arg_index; i < fnode.input_size(); ++i) { + const string& input = fnode.input(i); + if (input.empty() || input[0] != '^') { + return errors::InvalidArgument("Expected input[", i, "] == '", input, + "' to be a control input."); + } + const NameInfoItem* item = gtl::FindOrNull(name_info, input.substr(1)); + if (item == nullptr) { + return errors::InvalidArgument("input[", i, "] == '", input, + "', is not found."); + } + gnode->add_input(Dep(item->nid)); + } + + // Attrs. + for (const auto& p : attrs) { + (*gnode->mutable_attr())[p.first] = p.second; + } + + AddDefaultsToNodeDef(*fnode_sig, gnode); + + return Status::OK(); +} + +// FunctionDef::Node version Status AddReturnNode(const OpDef::ArgDef& ret_def, const InstantiateAttrValueMap& attrs, const NameInfoIndex& name_info, int* ret_index, @@ -336,6 +490,43 @@ Status AddReturnNode(const OpDef::ArgDef& ret_def, return Status::OK(); } +// NodeDef version +Status AddReturnNode(const OpDef::ArgDef& ret_def, + const InstantiateAttrValueMap& attrs, + const ::tensorflow::protobuf::Map& ret_map, + const NameInfoIndex& name_info, int* ret_index, + InstantiationResult* result) { + auto ret_iter = ret_map.find(ret_def.name()); + if (ret_iter == ret_map.end()) { + return errors::InvalidArgument("Return ", ret_def.name(), " missing."); + } + bool is_type_list; + DataTypeVector dtypes; + TF_RETURN_IF_ERROR(ArgNumType(attrs, ret_def, &is_type_list, &dtypes)); + CHECK_GE(dtypes.size(), size_t{1}); + const NameInfoItem* item = gtl::FindOrNull(name_info, ret_iter->second); + if (item == nullptr) { + return errors::InvalidArgument("Return ", ret_def.name(), " -> ", + ret_iter->second, " is not found."); + } + if (dtypes != item->dtypes) { + return errors::InvalidArgument("Invalid ret types ", ret_def.name(), " : ", + DataTypeVectorString(dtypes), " vs. ", + DataTypeVectorString(item->dtypes)); + } + GraphDef* gdef = &result->gdef; + for (size_t i = 0; i < dtypes.size(); ++i) { + NodeDef* gnode = gdef->add_node(); + gnode->set_name(Name(gdef->node_size() - 1)); + gnode->set_op("_Retval"); + gnode->add_input(Name(item->nid, item->idx + i)); + AddAttr("T", dtypes[i], gnode); + AddAttr("index", (*ret_index)++, gnode); + result->ret_types.push_back(dtypes[i]); + } + return Status::OK(); +} + // Various helpers Print(proto) to print relevant protos to ascii. string Print(const OpDef::ArgDef& arg) { string out; @@ -353,6 +544,7 @@ string Print(const OpDef::ArgDef& arg) { return out; } +// TODO(josh11b): Merge this with SummarizeAttrValue(). string Print(const AttrValue& attr_value) { if (attr_value.value_case() == AttrValue::kType) { return DataTypeString(attr_value.type()); @@ -412,6 +604,35 @@ string Print(const FunctionDef::Node& node) { return out; } +// TODO(josh11b): Merge this with SummarizeNodeDef(). +string Print(const NodeDef& n) { + string out; + strings::StrAppend(&out, n.name(), " = ", n.op()); + if (n.attr_size() > 0) { + std::vector entries; + for (auto& a : n.attr()) { + entries.push_back(strings::StrCat(a.first, "=", Print(a.second))); + } + sort(entries.begin(), entries.end()); + strings::StrAppend(&out, "[", str_util::Join(entries, ", "), "]"); + } + strings::StrAppend(&out, "("); + std::vector dat; + std::vector dep; + for (StringPiece s : n.input()) { + if (s.Consume("^")) { + dep.push_back(s.ToString()); + } else { + dat.push_back(s); + } + } + strings::StrAppend(&out, str_util::Join(dat, ", "), ")"); + if (!dep.empty()) { + strings::StrAppend(&out, " @ ", str_util::Join(dep, ", ")); + } + return out; +} + string Print(const FunctionDef& fdef) { string out; const OpDef& sig = fdef.signature(); @@ -440,38 +661,19 @@ string Print(const FunctionDef& fdef) { strings::StrAppend(&out, Print(sig.output_arg(i))); } strings::StrAppend(&out, ") {\n"); - for (const auto& n : fdef.node()) { - strings::StrAppend(&out, " ", Print(n), "\n"); - } - strings::StrAppend(&out, "}\n"); - return out; -} - -string Print(const NodeDef& n) { - string out; - strings::StrAppend(&out, n.name(), " = ", n.op()); - if (n.attr_size() > 0) { - std::vector entries; - for (auto& a : n.attr()) { - entries.push_back(strings::StrCat(a.first, "=", Print(a.second))); + if (fdef.node_def_size() > 0) { + for (const auto& n : fdef.node_def()) { + strings::StrAppend(&out, " ", Print(n), "\n"); } - sort(entries.begin(), entries.end()); - strings::StrAppend(&out, "[", str_util::Join(entries, ", "), "]"); - } - strings::StrAppend(&out, "("); - std::vector dat; - std::vector dep; - for (StringPiece s : n.input()) { - if (s.Consume("^")) { - dep.push_back(s.ToString()); - } else { - dat.push_back(s); + for (const auto& r : fdef.ret()) { + strings::StrAppend(&out, " return ", r.first, " = ", r.second, "\n"); + } + } else { // TODO(josh11b): Eventually remove this case. + for (const auto& n : fdef.node()) { + strings::StrAppend(&out, " ", Print(n), "\n"); } } - strings::StrAppend(&out, str_util::Join(dat, ", "), ")"); - if (!dep.empty()) { - strings::StrAppend(&out, " @ ", str_util::Join(dep, ", ")); - } + strings::StrAppend(&out, "}\n"); return out; } @@ -554,14 +756,27 @@ Status InstantiateFunction(const FunctionDef& fdef, // Makes a copy of all attrs in fdef and substitutes placeholders. // After this step, every attr is bound to a concrete value. std::vector node_attrs; - node_attrs.resize(fdef.node_size()); - for (int i = 0; i < fdef.node_size(); ++i) { - for (auto attr : fdef.node(i).attr()) { - if (!SubstitutePlaceholders(substitute, &attr.second)) { - return errors::InvalidArgument("Failed to bind all placeholders in ", - SummarizeAttrValue(attr.second)); + if (fdef.node_def_size() > 0) { + node_attrs.resize(fdef.node_def_size()); + for (int i = 0; i < fdef.node_def_size(); ++i) { + for (auto attr : fdef.node_def(i).attr()) { + if (!SubstitutePlaceholders(substitute, &attr.second)) { + return errors::InvalidArgument("Failed to bind all placeholders in ", + SummarizeAttrValue(attr.second)); + } + CHECK(node_attrs[i].insert(attr).second); + } + } + } else { // TODO(josh11b): Eventually remove this case. + node_attrs.resize(fdef.node_size()); + for (int i = 0; i < fdef.node_size(); ++i) { + for (auto attr : fdef.node(i).attr()) { + if (!SubstitutePlaceholders(substitute, &attr.second)) { + return errors::InvalidArgument("Failed to bind all placeholders in ", + SummarizeAttrValue(attr.second)); + } + CHECK(node_attrs[i].insert(attr).second); } - CHECK(node_attrs[i].insert(attr).second); } } @@ -570,36 +785,66 @@ Status InstantiateFunction(const FunctionDef& fdef, for (const OpDef::ArgDef& arg_def : sig.input_arg()) { s = BuildInputArgIndex(arg_def, attr_values, &name_info, result); if (!s.ok()) { - errors::AppendToMessage(&s, " In ", Print(arg_def)); + errors::AppendToMessage(&s, "In ", Print(arg_def)); return s; } } - for (int i = 0; i < fdef.node_size(); ++i) { - s = BuildNodeOutputIndex(fdef.node(i), node_attrs[i], get_function, - gdef->node_size() + i, &name_info); - if (!s.ok()) { - errors::AppendToMessage(&s, " In ", Print(fdef.node(i))); - return s; + if (fdef.node_def_size() > 0) { + for (int i = 0; i < fdef.node_def_size(); ++i) { + s = BuildNodeOutputIndex(fdef.node_def(i), node_attrs[i], get_function, + gdef->node_size() + i, &name_info); + if (!s.ok()) { + errors::AppendToMessage(&s, "In ", SummarizeNodeDef(fdef.node_def(i))); + return s; + } + } + // Emits one gdef.node for each fdef.node_def. + for (int i = 0; i < fdef.node_def_size(); ++i) { + s = InstantiateNode(fdef.node_def(i), node_attrs[i], get_function, + name_info, gdef); + if (!s.ok()) { + errors::AppendToMessage(&s, "In ", SummarizeNodeDef(fdef.node_def(i))); + return s; + } } - } - // Emits one gdef.node for each fdef.node. - for (int i = 0; i < fdef.node_size(); ++i) { - s = InstantiateNode(fdef.node(i), node_attrs[i], get_function, name_info, - gdef); - if (!s.ok()) { - errors::AppendToMessage(&s, " In ", Print(fdef.node(i))); - return s; + // Emits nodes for the function's return values. + int ret_index = 0; + for (const OpDef::ArgDef& ret_def : sig.output_arg()) { + s = AddReturnNode(ret_def, attr_values, fdef.ret(), name_info, &ret_index, + result); + if (!s.ok()) { + errors::AppendToMessage(&s, "In function output ", Print(ret_def)); + return s; + } + } + } else { // TODO(josh11b): Eventually remove this case. + for (int i = 0; i < fdef.node_size(); ++i) { + s = BuildNodeOutputIndex(fdef.node(i), node_attrs[i], get_function, + gdef->node_size() + i, &name_info); + if (!s.ok()) { + errors::AppendToMessage(&s, "In ", Print(fdef.node(i))); + return s; + } + } + // Emits one gdef.node for each fdef.node. + for (int i = 0; i < fdef.node_size(); ++i) { + s = InstantiateNode(fdef.node(i), node_attrs[i], get_function, name_info, + gdef); + if (!s.ok()) { + errors::AppendToMessage(&s, "In ", Print(fdef.node(i))); + return s; + } } - } - // Emits nodes for the function's return values. - int ret_index = 0; - for (const OpDef::ArgDef& ret_def : sig.output_arg()) { - s = AddReturnNode(ret_def, attr_values, name_info, &ret_index, result); - if (!s.ok()) { - errors::AppendToMessage(&s, " In ", Print(ret_def)); - return s; + // Emits nodes for the function's return values. + int ret_index = 0; + for (const OpDef::ArgDef& ret_def : sig.output_arg()) { + s = AddReturnNode(ret_def, attr_values, name_info, &ret_index, result); + if (!s.ok()) { + errors::AppendToMessage(&s, "In function output ", Print(ret_def)); + return s; + } } } @@ -844,7 +1089,53 @@ FunctionDef::Node FunctionDefHelper::Node::ToProto() const { return n; } -/* static */ +NodeDef FunctionDefHelper::Node::ToNodeDef() const { + NodeDef n; + n.set_op(this->op); + n.set_name(this->ret[0]); + for (const string& a : arg) { + n.add_input(a); + } + for (const auto& a : this->attr) { + n.mutable_attr()->insert({a.first, a.second.proto}); + } + for (const string& d : dep) { + n.add_input(strings::StrCat("^", d)); + } + return n; +} + +/* static */ +FunctionDef FunctionDefHelper::Create( + const string& function_name, gtl::ArraySlice in_def, + gtl::ArraySlice out_def, gtl::ArraySlice attr_def, + gtl::ArraySlice node_def, + gtl::ArraySlice> ret_def) { + FunctionDef fdef; + + // Signature + OpDefBuilder b(function_name); + for (const auto& i : in_def) b.Input(i); + for (const auto& o : out_def) b.Output(o); + for (const auto& a : attr_def) b.Attr(a); + + OpRegistrationData op_reg_data; + TF_CHECK_OK(b.Finalize(&op_reg_data)); + fdef.mutable_signature()->Swap(&op_reg_data.op_def); + + // Function body + for (const auto& n : node_def) { + *(fdef.add_node_def()) = n.ToNodeDef(); + } + + // Returns + for (const auto& r : ret_def) { + fdef.mutable_ret()->insert({r.first, r.second}); + } + return fdef; +} + +/* static */ FunctionDef FunctionDefHelper::Define(const string& name, gtl::ArraySlice arg_def, gtl::ArraySlice ret_def, diff --git a/tensorflow/core/framework/function.h b/tensorflow/core/framework/function.h index c8f49524951d0d47439db8fe482ec2106b2e7e08..4a9c62f08cece8d007523b85bb9346f20f991e8a 100644 --- a/tensorflow/core/framework/function.h +++ b/tensorflow/core/framework/function.h @@ -37,9 +37,22 @@ class Node; class OpKernel; class ResourceMgr; -// FunctionDefHelper::Define is a convenient helper to construct a +// FunctionDefHelper::Create is a convenient helper to construct a // FunctionDef proto. +// E.g., +// FunctionDef my_func = FunctionDefHelper::Create( +// "my_func_name", +// {"x:T", "y:T" /* one string per argument */}, +// {"z:T" /* one string per return value */}, +// {"T: {float, double}" /* one string per attribute */}, +// { +// {{"o"}, "Mul", {"x", "y"}, {{"T", "$T"}}} +// /* one entry per function node */ +// }, +// /* Mapping between function returns and function node outputs. */ +// {{"z", "o:z"}}); // +// For the old Function::Node approach, use FunctionDefHelper::Define() // E.g., // FunctionDef my_func = FunctionDefHelper::Define( // "my_func_name", @@ -49,10 +62,7 @@ class ResourceMgr; // { // {{"z"}, "Mul", {"x", "y"}, {{"T", "$T"}}} // /* one entry per function node */ -// }) -// -// NOTE: When we have a TFLang parser, we can add another helper: -// FunctionDef FunctionDefHelper::Define(const string& tf_func); +// }); class FunctionDefHelper { public: // AttrValueWrapper has copy constructors for the type T so that @@ -90,6 +100,8 @@ class FunctionDefHelper { // lists. E.g., // Node n = {{"z"}, "Mul", {"x", "y"}, {{"T", "$T"}}}; // z = x * y struct Node { + // When constructing a NodeDef, the first entry in ret is used as + // the node name, the remaining values are ignored. std::vector ret; string op; std::vector arg; @@ -97,8 +109,21 @@ class FunctionDefHelper { std::vector dep; FunctionDef::Node ToProto() const; + NodeDef ToNodeDef() const; }; + // The Create() function uses the new NodeDef field. `ret_def` + // holds a mapping from the function output names from `out_def` to + // the node outputs from `node_def`. + static FunctionDef Create(const string& function_name, + gtl::ArraySlice in_def, + gtl::ArraySlice out_def, + gtl::ArraySlice attr_def, + gtl::ArraySlice node_def, + gtl::ArraySlice> ret_def); + + // The two Define() functions use the old FunctionDef::Node field. + // TODO(josh11b): Get rid of these and transition to the one above. static FunctionDef Define(const string& function_name, gtl::ArraySlice arg_def, gtl::ArraySlice ret_def, diff --git a/tensorflow/core/framework/function.proto b/tensorflow/core/framework/function.proto index 4003943a8526e46d867368b6f7dde53bfc506b0d..4a1ad7a12596bf32bf0967e8bf4dfac3ddc51816 100644 --- a/tensorflow/core/framework/function.proto +++ b/tensorflow/core/framework/function.proto @@ -7,6 +7,7 @@ option java_multiple_files = true; option java_package = "org.tensorflow.framework"; import "tensorflow/core/framework/attr_value.proto"; +import "tensorflow/core/framework/node_def.proto"; import "tensorflow/core/framework/op_def.proto"; // A library is a set of named functions. @@ -26,6 +27,8 @@ message FunctionDef { // attrs etc. OpDef signature = 1; + // TO BE REPLACED + // The body of the function. repeated Node node = 2; // function.node.ret[*] are unique. @@ -69,6 +72,56 @@ message FunctionDef { // signature. map attr = 5; } + + // WILL REPLACE THE ABOVE + + // If node_def is present, and the consumer is at GraphDef version + // >= 12, then these fields are used and `node` is ignored. If the + // consumer's GraphDef version is < 12 or this field is empty, then + // `node` is used. This allows producers to fill both fields to + // remain compatible with old consumers. At some future GraphDef + // version, `node` will be ignored even if `node_def` is empty. + // TODO(josh11b): Finish this transition. + + // In both of the following fields, there is the need to specify an + // output that is used as either the input to another node (in + // `node_def`) or as a return value of the function (in `ret`). + // Unlike the NodeDefs in GraphDef, we need to be able to specify a + // list in some cases (instead of just single outputs). Also, we + // need to be able to deal with lists of unknown length (so the + // output index may not be known at function definition time). So + // we use the following format instead: + // * "fun_in" where "fun_in" is the name of a function input arg in + // the `signature` field above. This represents that input, whether + // it is a single tensor or a list. + // * "fun_in:0" gives the first element of a function input arg (a + // non-list input is considered a list of length 1 for these + // purposes). + // * "node:out" where "node" is the name of a node in `node_def` and + // "out" is the name one of its op's output arguments (the name + // comes from the OpDef of the node's op). This represents that + // node's output, whether it is a single tensor or a list. + // Note: We enforce that an op's output arguments are never + // renamed in the backwards-compatibility test. + // * "node:out:0" gives the first element of a node output arg (a + // non-list output is considered a list of length 1 for these + // purposes). + // + // NOT CURRENTLY SUPPORTED (but may be in the future): + // * "node:out:-1" gives last element in a node output list + // * "node:out:1:" gives a list with all but the first element in a + // node output list + // * "node:out::-1" gives a list with all but the last element in a + // node output list + + // The body of the function. Unlike the NodeDefs in a GraphDef, attrs + // may have values of type `placeholder` and the `input` field uses + // the "output" format above. + repeated NodeDef node_def = 3; + + // A mapping from the output arg names from `signature` to the + // outputs from `node_def` that should be returned by the function. + map ret = 4; } // GradientDef defines the gradient function of a function defined in diff --git a/tensorflow/core/framework/function_test.cc b/tensorflow/core/framework/function_test.cc index 82fbe759889b7b5221d45dcea60de3a0282a71a3..23fd5f724723ae2f7c4582230a94bb07a7d2d08d 100644 --- a/tensorflow/core/framework/function_test.cc +++ b/tensorflow/core/framework/function_test.cc @@ -48,8 +48,8 @@ y: A scalar in type T. static InstantiateAttrValueMap kNoAttrs; -TEST(TFunc, SquarePlusOne) { - auto fdef = FDH::Define( +TEST(TFunc, SquarePlusOneOld) { + auto fdef = FDH::Define( // Create a FunctionDef using Function::Nodes. // Name "SquarePlusOne", // Args @@ -78,7 +78,53 @@ SquarePlusOne[T:{float, double, int32, int64}](x:T) -> (y:T) { // Instantiate one with T=float InstantiationResult result; - TF_CHECK_OK(InstantiateFunction(fdef, {{"T", DT_FLOAT}}, GetOpSig, &result)); + TF_ASSERT_OK(InstantiateFunction(fdef, {{"T", DT_FLOAT}}, GetOpSig, &result)); + const char* e2 = R"P( +(n0:float) -> (n3:float) { + n1 = Square[T=float](n0) + n2 = One[T=float]() + n3 = Add[T=float](n1, n2) +} +)P"; + EXPECT_EQ(result.arg_types, DataTypeVector({DT_FLOAT})); + EXPECT_EQ(result.ret_types, DataTypeVector({DT_FLOAT})); + EXPECT_EQ(DebugString(result.gdef), e2); +} + +TEST(TFunc, SquarePlusOneNodeDef) { + auto fdef = FDH::Create( // Create a FunctionDef using NodeDefs. + // Name + "SquarePlusOne", + // Inputs + {"x: T"}, + // Outputs + {"y: T"}, + // Attrs + {"T: {float, double, int32, int64}"}, + // Nodes + {// a = Square(x) + {{"a"}, "Square", {"x"}, {{"T", "$T"}}}, + // o = One() + // NOTE: We can also have a Cast(x) instead. + {{"o"}, "One", {}, {{"T", "$T"}}}, + // y = Add(a, o) + {{"y"}, "Add", {"a:y", "o:y"}, {{"T", "$T"}}}}, + // Returns + {{"y", "y:z:0"}}); + + const char* e = R"P( +SquarePlusOne[T:{float, double, int32, int64}](x:T) -> (y:T) { + a = Square[T=$T](x) + o = One[T=$T]() + y = Add[T=$T](a:y, o:y) + return y = y:z:0 +} +)P"; + EXPECT_EQ(DebugString(fdef), e); + + // Instantiate one with T=float + InstantiationResult result; + TF_ASSERT_OK(InstantiateFunction(fdef, {{"T", DT_FLOAT}}, GetOpSig, &result)); const char* e2 = R"P( (n0:float) -> (n3:float) { n1 = Square[T=float](n0) @@ -141,8 +187,8 @@ AddSquared[N:int, T:{float, double, int32, int64}](x:N*T) -> (y:T) { // Instantiate one with T=float InstantiationResult result; - TF_CHECK_OK(InstantiateFunction(fdef, {{"N", 3}, {"T", DT_FLOAT}}, GetOpSig, - &result)); + TF_ASSERT_OK(InstantiateFunction(fdef, {{"N", 3}, {"T", DT_FLOAT}}, GetOpSig, + &result)); const char* e2 = R"P( (n0:float, n1:float, n2:float) -> (n4:float) { n3 = Map[N=3, T=float, U=float, func=Square[T=float]](n0, n1, n2) @@ -184,7 +230,7 @@ ControlDeps(x:float) -> () { EXPECT_EQ(DebugString(fdef), e); InstantiationResult result; - TF_CHECK_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); + TF_ASSERT_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); const char* e2 = R"P( (n0:float) -> () { n1 = One[T=float]() @ n0 @@ -264,7 +310,7 @@ Test(i:float) -> (o:float) { EXPECT_EQ(DebugString(fdef), e); InstantiationResult result; - TF_CHECK_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); + TF_ASSERT_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); const char* e2 = R"P( (n0:float) -> (n7:float) { n1 = Const[dtype=int32, value=Tensor]() @@ -336,7 +382,7 @@ MySelect(x:float) -> (z:float) { EXPECT_EQ(DebugString(fdef), e); InstantiationResult result; - TF_CHECK_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); + TF_ASSERT_OK(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result)); const char* e2 = R"P( (n0:float) -> (n2:float) { n1 = Cond[Tin={float}, cond=MyCond, else_branch=MyElse, out_types={float}, then_branch=MyThen](n0) @@ -350,7 +396,7 @@ MySelect(x:float) -> (z:float) { static void HasError(const Status& s, const string& substr) { EXPECT_TRUE(StringPiece(s.ToString()).contains(substr)) - << s << ", expected substring " << substr; + << ">>" << s << "<<, expected substring >>" << substr << "<<"; } TEST(InstantiateErrors, Not_Sufficient_Attrs) { @@ -358,15 +404,27 @@ TEST(InstantiateErrors, Not_Sufficient_Attrs) { FDH::Define("nop", {}, {}, {"T:{float, double, int32, int64}"}, {}); InstantiationResult result; HasError(InstantiateFunction(fdef, {{"U", DT_FLOAT}}, GetOpSig, &result), - "T is not found"); + "Attr T is not found from "); +} + +#if 0 // TODO(josh11b): Enable this test once having an extra attr is an error. +TEST(InstantiateErrors, Too_Many_Attrs) { + auto fdef = + FDH::Define("nop", {}, {}, {"T:{float, double, int32, int64}"}, {}); + InstantiationResult result; + HasError(InstantiateFunction(fdef, {{"T", DT_INT32}, {"U", DT_FLOAT}}, + GetOpSig, &result), + "Attr U is not found in "); } +#endif TEST(InstantiateErrors, AttrValue_Value_Placeholder) { auto fdef = FDH::Define("nop", {}, {}, {"T:{float, double, int32, int64}"}, {}); InstantiationResult result; - HasError(InstantiateFunction(fdef, {{"T", "$bad"}}, GetOpSig, &result), - "T in attr_values is still a placeholder"); + HasError( + InstantiateFunction(fdef, {{"T", "$bad"}}, GetOpSig, &result), + "AttrValue had value with unexpected type 'placeholder'\n\tfor attr 'T'"); } TEST(InstantiateErrors, Unbounded_Attr) { @@ -475,7 +533,7 @@ TEST(InstantiateErrors, FuncRet_Mismatch) { }); InstantiationResult result; HasError(InstantiateFunction(fdef, kNoAttrs, GetOpSig, &result), - "Invalid ret types y : float vs. double\n\t In y"); + "Invalid ret types y : float vs. double\n\tIn function output y"); } TEST(InstantiateErrors, TypeList_Missing_Retval_Attr) { diff --git a/tensorflow/core/framework/graph.proto b/tensorflow/core/framework/graph.proto index 1d3e7c9e76e78d77a6852ba461392cd0802cb130..7d6e16d5c129a068775fabc474770af929d99620 100644 --- a/tensorflow/core/framework/graph.proto +++ b/tensorflow/core/framework/graph.proto @@ -6,7 +6,7 @@ option java_outer_classname = "GraphProtos"; option java_multiple_files = true; option java_package = "org.tensorflow.framework"; -import "tensorflow/core/framework/attr_value.proto"; +import "tensorflow/core/framework/node_def.proto"; import "tensorflow/core/framework/function.proto"; import "tensorflow/core/framework/versions.proto"; @@ -34,7 +34,7 @@ message GraphDef { // different orgs. E.g., // { "/google/nn", { ... }}, // { "/google/vision", { ... }} - // { "/org_foo/module_bar", {...}} + // { "/org_foo/module_bar", { ... }} // map named_lib; // * If node[i].op is the name of one function in "library", // node[i] is deemed as a function call. Otherwise, node[i].op @@ -54,59 +54,3 @@ message GraphDef { // function are ready. FunctionDefLibrary library = 2; }; - -message NodeDef { - // The name given to this operator. Used for naming inputs, - // logging, visualization, etc. Unique within a single GraphDef. - // Must match the regexp "[A-Za-z0-9.][A-Za-z0-9_./]*". - string name = 1; - - // The operation name. There may be custom parameters in attrs. - // Op names starting with an underscore are reserved for internal use. - string op = 2; - - // Each input is "node:src_output" with "node" being a string name and - // "src_output" indicating which output tensor to use from "node". If - // "src_output" is 0 the ":0" suffix can be omitted. Regular inputs - // may optionally be followed by control inputs that have the format - // "^node". - repeated string input = 3; - - // A (possibly partial) specification for the device on which this - // node should be placed. - // The expected syntax for this string is as follows: - // - // DEVICE_SPEC ::= COLOCATED_NODE | PARTIAL_SPEC - // - // COLOCATED_NODE ::= "@" NODE_NAME // See NodeDef.name above. - // PARTIAL_SPEC ::= ("/" CONSTRAINT) * - // CONSTRAINT ::= ("job:" JOB_NAME) - // | ("replica:" [1-9][0-9]*) - // | ("task:" [1-9][0-9]*) - // | ( ("gpu" | "cpu") ":" ([1-9][0-9]* | "*") ) - // - // Valid values for this string include: - // * "@other/node" (colocate with "other/node") - // * "/job:worker/replica:0/task:1/gpu:3" (full specification) - // * "/job:worker/gpu:3" (partial specification) - // * "" (no specification) - // - // If the constraints do not resolve to a single device (or if this - // field is empty or not present), the runtime will attempt to - // choose a device automatically. - string device = 4; - - // Operation-specific graph-construction-time configuration. - // Note that this should include all attrs defined in the - // corresponding OpDef, including those with a value matching - // the default -- this allows the default to change and makes - // NodeDefs easier to interpret on their own. However, if - // an attr with a default is not specified in this list, the - // default will be used. - // The "names" (keys) must match the regexp "[a-z][a-z0-9_]+" (and - // one of the names from the corresponding OpDef's attr field). - // The values must have a type matching the corresponding OpDef - // attr's type field. - // TODO(josh11b): Add some examples here showing best practices. - map attr = 5; -}; diff --git a/tensorflow/core/framework/log_memory.cc b/tensorflow/core/framework/log_memory.cc index ba221179cea78447a5eae8df6b8225d2dfb7ed3d..dc82504d43d6a0d16025706f884f4e069d301f78 100644 --- a/tensorflow/core/framework/log_memory.cc +++ b/tensorflow/core/framework/log_memory.cc @@ -30,7 +30,7 @@ namespace { template void OutputToLog(const T& proto) { string type_name = proto.GetTypeName(); - const int index = type_name.find_last_of("."); + const size_t index = type_name.find_last_of("."); if (index != string::npos) type_name = type_name.substr(index + 1); LOG(INFO) << LogMemory::kLogMemoryLabel << " " << type_name << " { " << ProtoShortDebugString(proto) << " }"; diff --git a/tensorflow/core/framework/node_def.proto b/tensorflow/core/framework/node_def.proto new file mode 100644 index 0000000000000000000000000000000000000000..8d3811582a20f0d50dd61abded29f4dc04b20389 --- /dev/null +++ b/tensorflow/core/framework/node_def.proto @@ -0,0 +1,65 @@ +syntax = "proto3"; + +package tensorflow; +option cc_enable_arenas = true; +option java_outer_classname = "NodeProto"; +option java_multiple_files = true; +option java_package = "org.tensorflow.framework"; + +import "tensorflow/core/framework/attr_value.proto"; + +message NodeDef { + // The name given to this operator. Used for naming inputs, + // logging, visualization, etc. Unique within a single GraphDef. + // Must match the regexp "[A-Za-z0-9.][A-Za-z0-9_./]*". + string name = 1; + + // The operation name. There may be custom parameters in attrs. + // Op names starting with an underscore are reserved for internal use. + string op = 2; + + // Each input is "node:src_output" with "node" being a string name and + // "src_output" indicating which output tensor to use from "node". If + // "src_output" is 0 the ":0" suffix can be omitted. Regular inputs + // may optionally be followed by control inputs that have the format + // "^node". + repeated string input = 3; + + // A (possibly partial) specification for the device on which this + // node should be placed. + // The expected syntax for this string is as follows: + // + // DEVICE_SPEC ::= COLOCATED_NODE | PARTIAL_SPEC + // + // COLOCATED_NODE ::= "@" NODE_NAME // See NodeDef.name above. + // PARTIAL_SPEC ::= ("/" CONSTRAINT) * + // CONSTRAINT ::= ("job:" JOB_NAME) + // | ("replica:" [1-9][0-9]*) + // | ("task:" [1-9][0-9]*) + // | ( ("gpu" | "cpu") ":" ([1-9][0-9]* | "*") ) + // + // Valid values for this string include: + // * "@other/node" (colocate with "other/node") + // * "/job:worker/replica:0/task:1/gpu:3" (full specification) + // * "/job:worker/gpu:3" (partial specification) + // * "" (no specification) + // + // If the constraints do not resolve to a single device (or if this + // field is empty or not present), the runtime will attempt to + // choose a device automatically. + string device = 4; + + // Operation-specific graph-construction-time configuration. + // Note that this should include all attrs defined in the + // corresponding OpDef, including those with a value matching + // the default -- this allows the default to change and makes + // NodeDefs easier to interpret on their own. However, if + // an attr with a default is not specified in this list, the + // default will be used. + // The "names" (keys) must match the regexp "[a-z][a-z0-9_]+" (and + // one of the names from the corresponding OpDef's attr field). + // The values must have a type matching the corresponding OpDef + // attr's type field. + // TODO(josh11b): Add some examples here showing best practices. + map attr = 5; +}; diff --git a/tensorflow/core/framework/node_def_util.h b/tensorflow/core/framework/node_def_util.h index d74431b679e646a2beacf37944664c34718a8c78..dfc7b9b9078936deb09b07a0b5ecadb8e6f560b0 100644 --- a/tensorflow/core/framework/node_def_util.h +++ b/tensorflow/core/framework/node_def_util.h @@ -21,7 +21,7 @@ limitations under the License. #include #include "tensorflow/core/framework/attr_value_util.h" -#include "tensorflow/core/framework/graph.pb.h" +#include "tensorflow/core/framework/node_def.pb.h" #include "tensorflow/core/framework/op_def.pb.h" #include "tensorflow/core/framework/types.h" #include "tensorflow/core/lib/core/stringpiece.h" diff --git a/tensorflow/core/framework/op.cc b/tensorflow/core/framework/op.cc index 65bfd47433fe24f8b63d967af4ef21e97543ac70..6bff192b1ec2f08b1e6f8ac0664713449526d683 100644 --- a/tensorflow/core/framework/op.cc +++ b/tensorflow/core/framework/op.cc @@ -156,7 +156,7 @@ string OpRegistry::DebugString(bool include_internal) const { bool OpRegistry::MustCallDeferred() const { if (initialized_) return false; initialized_ = true; - for (int i = 0; i < deferred_.size(); ++i) { + for (size_t i = 0; i < deferred_.size(); ++i) { TF_QCHECK_OK(RegisterAlreadyLocked(deferred_[i])); } deferred_.clear(); @@ -166,7 +166,7 @@ bool OpRegistry::MustCallDeferred() const { Status OpRegistry::CallDeferred() const { if (initialized_) return Status::OK(); initialized_ = true; - for (int i = 0; i < deferred_.size(); ++i) { + for (size_t i = 0; i < deferred_.size(); ++i) { Status s = RegisterAlreadyLocked(deferred_[i]); if (!s.ok()) { return s; diff --git a/tensorflow/core/framework/op_compatibility_test.cc b/tensorflow/core/framework/op_compatibility_test.cc index 3d85c973325b34f51766185039e6a05b1837a1f2..ae2fdae379a21289df2e0eb2dd5cbda0a6d5ed81 100644 --- a/tensorflow/core/framework/op_compatibility_test.cc +++ b/tensorflow/core/framework/op_compatibility_test.cc @@ -150,6 +150,19 @@ class OpCompatibilityTest : public OpsTestBase { ExpectIncompatible(old_op_def, *new_op_def, compatibility_error); } + + void ExpectRenameFailure(const OpDef& old_op_def, + const string& compatibility_error) { + // This should be all that is needed to get compatibility. + const OpDef* new_op_def = RegisteredOpDef(); + AddDefaultsToNodeDef(*new_op_def, node_def()); + + // Validate that the NodeDef is valid. This will ignore + // problems caused by output name changes for functions. + TF_ASSERT_OK(ValidateNodeDef(*node_def(), *new_op_def)); + + ExpectIncompatible(old_op_def, *new_op_def, compatibility_error); + } }; // Should be compatible if the Op hasn't changed (sanity check). @@ -986,7 +999,7 @@ TEST_F(OpCompatibilityTest, InputAddRefFails) { REGISTER_OP("OutputRemoveRef").Output("o: int32"); -TEST_F(OpCompatibilityTest, OutputRemoveRef) { +TEST_F(OpCompatibilityTest, OutputRemoveRefFails) { OpRegistrationData old_op; TF_ASSERT_OK(OpDefBuilder("OutputRemoveRef") .Output("o: Ref(int32)") @@ -996,6 +1009,51 @@ TEST_F(OpCompatibilityTest, OutputRemoveRef) { ExpectTypeMismatch(old_op.op_def, "Output 0 changed from ref to non-ref"); } +// Can't rename an output, to avoid problems in FunctionDefs. + +REGISTER_OP("RenameOutput").Output("new: int32"); + +TEST_F(OpCompatibilityTest, RenameOutputFails) { + OpRegistrationData old_op; + TF_ASSERT_OK( + OpDefBuilder("RenameOutput").Output("old: int32").Finalize(&old_op)); + TF_ASSERT_OK( + NodeDefBuilder("rename_output", &old_op.op_def).Finalize(node_def())); + ExpectRenameFailure(old_op.op_def, + "Output signature mismatch 'old:int32' vs. 'new:int32'"); +} + +REGISTER_OP("RenameNOutputs").Output("new: N*int32").Attr("N: int"); + +TEST_F(OpCompatibilityTest, RenameNOutputsFails) { + OpRegistrationData old_op; + TF_ASSERT_OK(OpDefBuilder("RenameNOutputs") + .Output("old: N*int32") + .Attr("N: int") + .Finalize(&old_op)); + TF_ASSERT_OK(NodeDefBuilder("rename_n_outputs", &old_op.op_def) + .Attr("N", 2) + .Finalize(node_def())); + ExpectRenameFailure( + old_op.op_def, + "Output signature mismatch 'old:N * int32' vs. 'new:N * int32'"); +} + +REGISTER_OP("RenameOutputList").Output("new: T").Attr("T: list(type)"); + +TEST_F(OpCompatibilityTest, RenameOutputListFails) { + OpRegistrationData old_op; + TF_ASSERT_OK(OpDefBuilder("RenameOutputList") + .Output("old: T") + .Attr("T: list(type)") + .Finalize(&old_op)); + TF_ASSERT_OK(NodeDefBuilder("rename_output_list", &old_op.op_def) + .Attr("T", {DT_INT32, DT_FLOAT}) + .Finalize(node_def())); + ExpectRenameFailure(old_op.op_def, + "Output signature mismatch 'old:T' vs. 'new:T'"); +} + // Changing an attr's default is not technically illegal, but should // be forbidden if it the attr ever didn't exist since it likely // affects semantics. diff --git a/tensorflow/core/framework/op_def_util.cc b/tensorflow/core/framework/op_def_util.cc index d92a1d47ac41603014b5747b47baf582e3eeb6dd..5717488b1cb732c659c00be8628bbbee40358fdd 100644 --- a/tensorflow/core/framework/op_def_util.cc +++ b/tensorflow/core/framework/op_def_util.cc @@ -471,6 +471,13 @@ void AddComma(string* s, bool* add_comma) { } } +// Will add the `name` from arg if name is true. +void AddName(string* s, bool name, const OpDef::ArgDef& arg) { + if (name) { + strings::StrAppend(s, arg.name(), ":"); + } +} + // Compute a signature for either inputs or outputs that will be the // same for both the old and new OpDef if they are compatible. We // assume that new_attrs is a superset of old_attrs, and that any attr @@ -484,8 +491,8 @@ void AddComma(string* s, bool* add_comma) { // old_attrs, or substituting the default value from new_attrs. string ComputeArgSignature( const protobuf::RepeatedPtrField& args, - const AttrMap& old_attrs, const AttrMap& new_attrs, - std::vector* ref) { + const AttrMap& old_attrs, const AttrMap& new_attrs, std::vector* ref, + bool names) { string s; bool add_comma = false; for (const OpDef::ArgDef& arg : args) { @@ -495,6 +502,7 @@ string ComputeArgSignature( if (old_attr) { // Both old and new have the list(type) attr, so can use it directly. AddComma(&s, &add_comma); + AddName(&s, names, arg); strings::StrAppend(&s, arg.type_list_attr()); ref->push_back(arg.is_ref()); } else { @@ -506,6 +514,7 @@ string ComputeArgSignature( if (type_list.empty()) continue; for (int i = 0; i < type_list.size(); ++i) { AddComma(&s, &add_comma); + AddName(&s, names, arg); strings::StrAppend( &s, DataTypeString(static_cast(type_list.Get(i)))); ref->push_back(arg.is_ref()); @@ -513,15 +522,15 @@ string ComputeArgSignature( } } else { int num = 1; // How many input/outputs does this represent? + string type; // What is the type of this arg? + AddName(&type, names, arg); if (!arg.number_attr().empty()) { // N * type case. const OpDef::AttrDef* old_attr = gtl::FindPtrOrNull(old_attrs, arg.number_attr()); if (old_attr) { // Both old and new have the number attr, so can use it directly. - AddComma(&s, &add_comma); - strings::StrAppend(&s, arg.number_attr(), " * "); - add_comma = false; // Don't add another comma before the type. + strings::StrAppend(&type, arg.number_attr(), " * "); } else { // Missing the number attr in the old, so use the default // value for the attr from new instead. @@ -531,22 +540,22 @@ string ComputeArgSignature( } } - string type; // What is the type of this arg? if (arg.type() != DT_INVALID) { // int32, float, etc. case - type = DataTypeString(arg.type()); + strings::StrAppend(&type, DataTypeString(arg.type())); } else { const OpDef::AttrDef* old_attr = gtl::FindPtrOrNull(old_attrs, arg.type_attr()); if (old_attr) { // Both old and new have the type attr, so can use it directly. - type = arg.type_attr(); + strings::StrAppend(&type, arg.type_attr()); } else { // Missing the type attr in the old, so use the default // value for the attr from new instead. const OpDef::AttrDef* new_attr = gtl::FindPtrOrNull(new_attrs, arg.type_attr()); - type = DataTypeString(new_attr->default_value().type()); + strings::StrAppend(&type, + DataTypeString(new_attr->default_value().type())); } } @@ -600,10 +609,10 @@ Status OpDefCompatible(const OpDef& old_op, const OpDef& new_op) { } std::vector old_in_ref, new_in_ref, old_out_ref, new_out_ref; - const string old_in_sig = ComputeArgSignature(old_op.input_arg(), old_attrs, - new_attrs, &old_in_ref); - const string new_in_sig = ComputeArgSignature(new_op.input_arg(), old_attrs, - new_attrs, &new_in_ref); + const string old_in_sig = ComputeArgSignature( + old_op.input_arg(), old_attrs, new_attrs, &old_in_ref, false /* names */); + const string new_in_sig = ComputeArgSignature( + new_op.input_arg(), old_attrs, new_attrs, &new_in_ref, false /* names */); VALIDATE(old_in_sig == new_in_sig, "Input signature mismatch '", old_in_sig, "' vs. '", new_in_sig, "'"); VALIDATE(old_in_ref.size() == new_in_ref.size(), // Should not happen @@ -614,10 +623,12 @@ Status OpDefCompatible(const OpDef& old_op, const OpDef& new_op) { " changed from non-ref to ref"); } - const string old_out_sig = ComputeArgSignature(old_op.output_arg(), old_attrs, - new_attrs, &old_out_ref); - const string new_out_sig = ComputeArgSignature(new_op.output_arg(), old_attrs, - new_attrs, &new_out_ref); + const string old_out_sig = + ComputeArgSignature(old_op.output_arg(), old_attrs, new_attrs, + &old_out_ref, true /* names */); + const string new_out_sig = + ComputeArgSignature(new_op.output_arg(), old_attrs, new_attrs, + &new_out_ref, true /* names */); VALIDATE(old_out_sig == new_out_sig, "Output signature mismatch '", old_out_sig, "' vs. '", new_out_sig, "'"); VALIDATE(old_out_ref.size() == new_out_ref.size(), // Should not happen diff --git a/tensorflow/core/framework/shape_inference.cc b/tensorflow/core/framework/shape_inference.cc index b4cf7120197df4153c8047d8cd89c698b2f716c6..6118bf1288220ca324eb5a59c2c421cfc35a128b 100644 --- a/tensorflow/core/framework/shape_inference.cc +++ b/tensorflow/core/framework/shape_inference.cc @@ -31,54 +31,81 @@ InferenceContext::InferenceContext( const NodeDef* node_def, const OpDef& op_def, const std::vector& input_shapes, const std::vector& input_tensors) - : input_tensors_(input_tensors), node_def_(*CHECK_NOTNULL(node_def)) { + : node_def_(*CHECK_NOTNULL(node_def)) { + PreInputInit(op_def, input_tensors); + + for (const string& spec : input_shapes) { + ShapeHandle shape; + construction_status_.Update(MakeShapeFromString(spec, &shape)); + if (!construction_status_.ok()) { + return; + } + inputs_.push_back(shape); + } + + PostInputInit(); +} + +InferenceContext::InferenceContext( + const NodeDef* node_def, const OpDef& op_def, + const std::vector& input_shapes_string, + const std::vector& input_shapes, + const std::vector& input_tensors) + : node_def_(*CHECK_NOTNULL(node_def)) { + PreInputInit(op_def, input_tensors); + if (!construction_status_.ok()) return; + for (const TensorShapeProto& p : input_shapes) { + ShapeHandle shape; + construction_status_.Update(MakeShapeFromShapeProto(p, &shape)); + if (!construction_status_.ok()) { + return; + } + inputs_.push_back(shape); + } + PostInputInit(); +} + +InferenceContext::InferenceContext( + const NodeDef* node_def, const OpDef& op_def, + const std::vector& input_shapes_string, + const std::vector& input_shapes, + const std::vector& input_tensors) + : node_def_(*CHECK_NOTNULL(node_def)) { + PreInputInit(op_def, input_tensors); + if (!construction_status_.ok()) return; + inputs_ = input_shapes; + PostInputInit(); +} + +InferenceContext::~InferenceContext() { + for (auto* s : all_shapes_) delete s; + for (auto* d : all_dims_) delete d; +} + +void InferenceContext::PreInputInit( + const OpDef& op_def, const std::vector& input_tensors) { + input_tensors_ = input_tensors; + construction_status_ = - NameRangesForNode(*node_def, op_def, &input_name_map_, &output_name_map_); + NameRangesForNode(node_def_, op_def, &input_name_map_, &output_name_map_); if (!construction_status_.ok()) return; int num_outputs = 0; for (const auto& e : output_name_map_) { num_outputs = std::max(num_outputs, e.second.second); } + for (int i = 0; i < num_outputs; ++i) { + outputs_.push_back(nullptr); + } +} + +void InferenceContext::PostInputInit() { int num_inputs_from_node_def = 0; for (const auto& e : input_name_map_) { num_inputs_from_node_def = std::max(num_inputs_from_node_def, e.second.second); } - for (const string& spec : input_shapes) { - if (spec == "?") { - inputs_.push_back(UnknownShape()); - } else { - std::vector dims; - strings::Scanner scanner(spec); - scanner.OneLiteral("["); - while (scanner.Peek() != ']') { - if (scanner.Peek() == '?') { - scanner.OneLiteral("?"); - dims.push_back(UnknownDim()); - } else { - scanner.RestartCapture().Many(strings::Scanner::DIGIT); - StringPiece match; - int64 dim_size = 0; - CHECK(scanner.GetResult(nullptr, &match) && - strings::safe_strto64(match, &dim_size)) - << spec; - dims.push_back(MakeDim(dim_size)); - } - - if (scanner.Peek() == ',') { - scanner.OneLiteral(","); - } else if (scanner.Peek() != ']') { - construction_status_ = errors::InvalidArgument( - "Invalid input spec (] not found in dim shape): ", spec); - return; - } - } - CHECK(scanner.OneLiteral("]").Eos().GetResult()); - inputs_.push_back(MakeShape(dims)); - } - } if (inputs_.size() != num_inputs_from_node_def) { construction_status_ = errors::InvalidArgument( "Wrong number of inputs passed: ", inputs_.size(), " while ", @@ -86,20 +113,12 @@ InferenceContext::InferenceContext( return; } - CHECK_LE(input_tensors_.size(), input_shapes.size()); - input_tensors_.resize(input_shapes.size()); - - for (int i = 0; i < num_outputs; ++i) { - outputs_.push_back(UnknownShape()); - } -} - -InferenceContext::~InferenceContext() { - for (auto* s : all_shapes_) delete s; - for (auto* d : all_dims_) delete d; + CHECK_LE(input_tensors_.size(), inputs_.size()); + input_tensors_.resize(inputs_.size()); + requested_input_tensor_.resize(inputs_.size()); } -bool InferenceContext::FullyDefined(const Shape* s) { +bool InferenceContext::FullyDefined(ShapeHandle s) { if (!RankKnown(s)) return false; for (int i = 0; i < Rank(s); ++i) { if (!ValueKnown(Dim(s, i))) return false; @@ -107,7 +126,7 @@ bool InferenceContext::FullyDefined(const Shape* s) { return true; } -const Dimension* InferenceContext::NumElements(const Shape* s) { +DimensionHandle InferenceContext::NumElements(ShapeHandle s) { const auto rank = Rank(s); if (rank == kUnknownRank) return UnknownDim(); int64 size = 1; @@ -119,7 +138,7 @@ const Dimension* InferenceContext::NumElements(const Shape* s) { return MakeDim(size); } -string InferenceContext::DebugString(const Shape* s) { +string InferenceContext::DebugString(ShapeHandle s) { if (RankKnown(s)) { std::vector vals; for (auto d : s->dims_) vals.push_back(DebugString(d)); @@ -129,19 +148,19 @@ string InferenceContext::DebugString(const Shape* s) { } } -string InferenceContext::DebugString(const Dimension* d) { +string InferenceContext::DebugString(DimensionHandle d) { return ValueKnown(d) ? strings::StrCat(Value(d)) : "?"; } -Status InferenceContext::WithRank(const Shape* shape, int32 rank, - const Shape** out) { +Status InferenceContext::WithRank(ShapeHandle shape, int32 rank, + ShapeHandle* out) { const int32 existing = Rank(shape); if (existing == rank) { *out = shape; return Status::OK(); } if (existing == kUnknownRank) { - std::vector dims; + std::vector dims; dims.reserve(rank); for (int i = 0; i < rank; ++i) { all_dims_.push_back(new Dimension()); @@ -156,8 +175,8 @@ Status InferenceContext::WithRank(const Shape* shape, int32 rank, existing); } -Status InferenceContext::WithRankAtLeast(const Shape* shape, int32 rank, - const Shape** out) { +Status InferenceContext::WithRankAtLeast(ShapeHandle shape, int32 rank, + ShapeHandle* out) { const int32 existing = Rank(shape); if (existing >= rank) { *out = shape; @@ -171,8 +190,8 @@ Status InferenceContext::WithRankAtLeast(const Shape* shape, int32 rank, " but is rank ", existing); } -Status InferenceContext::WithRankAtMost(const Shape* shape, int32 rank, - const Shape** out) { +Status InferenceContext::WithRankAtMost(ShapeHandle shape, int32 rank, + ShapeHandle* out) { const int32 existing = Rank(shape); if (existing == kUnknownRank) { return ReturnUnknownShape(out); @@ -186,8 +205,8 @@ Status InferenceContext::WithRankAtMost(const Shape* shape, int32 rank, " but is rank ", existing); } -Status InferenceContext::WithValue(const Dimension* dim, int64 value, - const Dimension** out) { +Status InferenceContext::WithValue(DimensionHandle dim, int64 value, + DimensionHandle* out) { const int64 existing = Value(dim); if (existing == value) { *out = dim; @@ -203,9 +222,9 @@ Status InferenceContext::WithValue(const Dimension* dim, int64 value, existing); } -Status InferenceContext::Merge(const Dimension* d0, const Dimension* d1, - const Dimension** out) { - if (d0 == d1 || !ValueKnown(d1)) { +Status InferenceContext::Merge(DimensionHandle d0, DimensionHandle d1, + DimensionHandle* out) { + if (d0.SameHandle(d1) || !ValueKnown(d1)) { *out = d0; return Status::OK(); } else if (!ValueKnown(d0)) { @@ -221,9 +240,9 @@ Status InferenceContext::Merge(const Dimension* d0, const Dimension* d1, } } -Status InferenceContext::MergePrefix(const Shape* s, const Shape* prefix, - const Shape** s_out, - const Shape** prefix_out) { +Status InferenceContext::MergePrefix(ShapeHandle s, ShapeHandle prefix, + ShapeHandle* s_out, + ShapeHandle* prefix_out) { *s_out = *prefix_out = nullptr; if (!RankKnown(prefix) || !RankKnown(s)) { *s_out = s; @@ -234,7 +253,7 @@ Status InferenceContext::MergePrefix(const Shape* s, const Shape* prefix, TF_RETURN_IF_ERROR(WithRankAtLeast(s, rank, &s)); // Merge the prefix dims and create the new output shapes. - std::vector dims; + std::vector dims; dims.resize(rank); for (int i = 0; i < rank; ++i) { TF_RETURN_IF_ERROR(Merge(Dim(s, i), Dim(prefix, i), &dims[i])); @@ -245,9 +264,9 @@ Status InferenceContext::MergePrefix(const Shape* s, const Shape* prefix, return Status::OK(); } -Status InferenceContext::Merge(const Shape* s0, const Shape* s1, - const Shape** out) { - if (s0 == s1 || !RankKnown(s1)) { +Status InferenceContext::Merge(ShapeHandle s0, ShapeHandle s1, + ShapeHandle* out) { + if (s0.SameHandle(s1) || !RankKnown(s1)) { *out = s0; return Status::OK(); } else if (!RankKnown(s0)) { @@ -267,7 +286,7 @@ Status InferenceContext::Merge(const Shape* s0, const Shape* s1, for (int i = 0; i < rank; ++i) { auto d0 = Dim(s0, i); auto d1 = Dim(s1, i); - if (d0 == d1) continue; + if (d0.SameHandle(d1)) continue; auto v0 = Value(d0); auto v1 = Value(d1); @@ -290,7 +309,7 @@ Status InferenceContext::Merge(const Shape* s0, const Shape* s1, } // Merge dims. - std::vector dims(rank, nullptr); + std::vector dims(rank, nullptr); for (int i = 0; i < rank; ++i) { // Invariant for merge was checked earlier, so CHECK is ok. TF_CHECK_OK(Merge(Dim(s0, i), Dim(s1, i), &dims[i])); @@ -298,13 +317,13 @@ Status InferenceContext::Merge(const Shape* s0, const Shape* s1, return ReturnCreatedShape(dims, out); } -Status InferenceContext::Subshape(const Shape* s, int64 start, - const Shape** out) { +Status InferenceContext::Subshape(ShapeHandle s, int64 start, + ShapeHandle* out) { return Subshape(s, start, std::numeric_limits::max() /* end */, out); } -Status InferenceContext::Subshape(const Shape* s, int64 start_in, int64 end_in, - const Shape** out) { +Status InferenceContext::Subshape(ShapeHandle s, int64 start_in, int64 end_in, + ShapeHandle* out) { int64 start = start_in; int64 end = end_in; const int32 rank = Rank(s); @@ -343,7 +362,7 @@ Status InferenceContext::Subshape(const Shape* s, int64 start_in, int64 end_in, end, " (computed from start ", start_in, " and end ", end_in, " over shape with rank ", rank, ")"); } - std::vector dims; + std::vector dims; dims.reserve(end - start); for (int i = start; i < end; ++i) { dims.push_back(Dim(s, i)); @@ -351,24 +370,23 @@ Status InferenceContext::Subshape(const Shape* s, int64 start_in, int64 end_in, return ReturnCreatedShape(dims, out); } -Status InferenceContext::Concatenate(const Shape* s1, const Shape* s2, - const Shape** out) { +Status InferenceContext::Concatenate(ShapeHandle s1, ShapeHandle s2, + ShapeHandle* out) { if (!RankKnown(s1) || !RankKnown(s2)) { return ReturnUnknownShape(out); } const int32 s1_rank = Rank(s1); const int32 s2_rank = Rank(s2); const int32 rank = s1_rank + s2_rank; - std::vector dims; + std::vector dims; dims.reserve(rank); for (int i = 0; i < s1_rank; ++i) dims.push_back(Dim(s1, i)); for (int i = 0; i < s2_rank; ++i) dims.push_back(Dim(s2, i)); return ReturnCreatedShape(dims, out); } -Status InferenceContext::ReplaceDim(const Shape* s, int dim_index_in, - const Dimension* new_dim, - const Shape** out) { +Status InferenceContext::ReplaceDim(ShapeHandle s, int dim_index_in, + DimensionHandle new_dim, ShapeHandle* out) { if (!RankKnown(s)) { return ReturnUnknownShape(out); } @@ -382,20 +400,20 @@ Status InferenceContext::ReplaceDim(const Shape* s, int dim_index_in, " for shape with ", s->dims_.size(), " dimensions"); } - std::vector dims(s->dims_); + std::vector dims(s->dims_); dims[dim_index] = new_dim; return ReturnCreatedShape(dims, out); } -const Shape* InferenceContext::MakeShape( - const std::vector& dims) { +ShapeHandle InferenceContext::MakeShape( + const std::vector& dims) { all_shapes_.push_back(new Shape(dims)); return all_shapes_.back(); } -const Shape* InferenceContext::MakeShape( +ShapeHandle InferenceContext::MakeShape( std::initializer_list dims) { - std::vector dims_actual; + std::vector dims_actual; dims_actual.reserve(dims.size()); for (const DimensionOrConstant& d : dims) { dims_actual.push_back(MakeDim(d)); @@ -403,45 +421,45 @@ const Shape* InferenceContext::MakeShape( return MakeShape(dims_actual); } -const Shape* InferenceContext::UnknownShape() { +ShapeHandle InferenceContext::UnknownShape() { all_shapes_.push_back(new Shape()); return all_shapes_.back(); } -const Shape* InferenceContext::UnknownShapeOfRank(int32 rank) { - std::vector dims(rank); +ShapeHandle InferenceContext::UnknownShapeOfRank(int32 rank) { + std::vector dims(rank); for (int32 i = 0; i < rank; ++i) { dims[i] = UnknownDim(); } return MakeShape(dims); } -const Shape* InferenceContext::Scalar() { return MakeShape({}); } +ShapeHandle InferenceContext::Scalar() { return MakeShape({}); } -const Shape* InferenceContext::Vector(DimensionOrConstant dim) { +ShapeHandle InferenceContext::Vector(DimensionOrConstant dim) { return MakeShape({dim}); } -const Shape* InferenceContext::Matrix(DimensionOrConstant dim1, - DimensionOrConstant dim2) { +ShapeHandle InferenceContext::Matrix(DimensionOrConstant dim1, + DimensionOrConstant dim2) { return MakeShape({dim1, dim2}); } Status InferenceContext::MakeShapeFromShapeTensor(int input_idx, - const Shape** out) { - const Shape* input_shape; + ShapeHandle* out) { + ShapeHandle input_shape; TF_RETURN_IF_ERROR(WithRank(input(input_idx), 1, &input_shape)); const Tensor* t = input_tensor(input_idx); if (t == nullptr) { // Shape tensor is not known, but if the shape of the shape tensor is then // the right number of unknown dims can be created. - const Dimension* shape_dim = Dim(input_shape, 0); + DimensionHandle shape_dim = Dim(input_shape, 0); if (!ValueKnown(shape_dim)) { return ReturnUnknownShape(out); } const auto num_dims = Value(shape_dim); - std::vector dims; + std::vector dims; for (int i = 0; i < num_dims; i++) dims.push_back(UnknownDim()); return ReturnCreatedShape(dims, out); } @@ -451,7 +469,7 @@ Status InferenceContext::MakeShapeFromShapeTensor(int input_idx, return errors::InvalidArgument("Input tensor must be rank 1, but was rank ", t->shape().dims()); } - std::vector dims; + std::vector dims; if (t->dtype() == DataType::DT_INT32) { auto flat_t = t->flat(); for (int i = 0; i < flat_t.size(); ++i) { @@ -473,7 +491,7 @@ Status InferenceContext::MakeShapeFromShapeTensor(int input_idx, } Status InferenceContext::MakeShapeFromShapeProto(const TensorShapeProto& proto, - const Shape** out) { + ShapeHandle* out) { *out = nullptr; TF_RETURN_IF_ERROR(PartialTensorShape::IsValidShape(proto)); PartialTensorShape partial_shape(proto); @@ -481,7 +499,7 @@ Status InferenceContext::MakeShapeFromShapeProto(const TensorShapeProto& proto, return ReturnUnknownShape(out); } const int num_dims = partial_shape.dims(); - std::vector dims; + std::vector dims; dims.reserve(partial_shape.dims()); for (int i = 0; i < num_dims; ++i) { // -1 is unknown in proto and in InferenceContext, so this size can be @@ -492,7 +510,7 @@ Status InferenceContext::MakeShapeFromShapeProto(const TensorShapeProto& proto, } // Returns a new dimension whose value is given by a scalar input tensor. -Status InferenceContext::MakeDimForScalarInput(int idx, const Dimension** out) { +Status InferenceContext::MakeDimForScalarInput(int idx, DimensionHandle* out) { const Tensor* t = input_tensor(idx); if (t == nullptr) { *out = UnknownDim(); @@ -520,8 +538,8 @@ Status InferenceContext::MakeDimForScalarInput(int idx, const Dimension** out) { return Status::OK(); } -Status InferenceContext::Divide(const Dimension* dividend, int64 divisor, - const Dimension** out) { +Status InferenceContext::Divide(DimensionHandle dividend, int64 divisor, + DimensionHandle* out) { if (divisor == 1) { *out = dividend; } else if (!ValueKnown(dividend)) { @@ -541,8 +559,8 @@ Status InferenceContext::Divide(const Dimension* dividend, int64 divisor, return Status::OK(); } -Status InferenceContext::Add(const Dimension* first, DimensionOrConstant second, - const Dimension** out) { +Status InferenceContext::Add(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out) { const int64 first_value = Value(first); const int64 second_value = Value(second); // Special cases. @@ -564,9 +582,9 @@ Status InferenceContext::Add(const Dimension* first, DimensionOrConstant second, return Status::OK(); } -Status InferenceContext::Subtract(const Dimension* first, +Status InferenceContext::Subtract(DimensionHandle first, DimensionOrConstant second, - const Dimension** out) { + DimensionHandle* out) { const int64 first_value = Value(first); const int64 second_value = Value(second); // Special cases. @@ -587,9 +605,9 @@ Status InferenceContext::Subtract(const Dimension* first, return Status::OK(); } -Status InferenceContext::Multiply(const Dimension* first, +Status InferenceContext::Multiply(DimensionHandle first, DimensionOrConstant second, - const Dimension** out) { + DimensionHandle* out) { const int64 first_value = Value(first); const int64 second_value = Value(second); // Special cases. @@ -616,8 +634,8 @@ Status InferenceContext::Multiply(const Dimension* first, return Status::OK(); } -Status InferenceContext::Min(const Dimension* first, DimensionOrConstant second, - const Dimension** out) { +Status InferenceContext::Min(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out) { const int64 first_value = Value(first); const int64 second_value = Value(second); if (first_value == 0) { @@ -636,8 +654,8 @@ Status InferenceContext::Min(const Dimension* first, DimensionOrConstant second, return Status::OK(); } -Status InferenceContext::Max(const Dimension* first, DimensionOrConstant second, - const Dimension** out) { +Status InferenceContext::Max(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out) { const int64 first_value = Value(first); const int64 second_value = Value(second); if (first_value == kUnknownDim || second_value == kUnknownDim) { @@ -652,5 +670,42 @@ Status InferenceContext::Max(const Dimension* first, DimensionOrConstant second, return Status::OK(); } +Status InferenceContext::MakeShapeFromString(const string& spec, + ShapeHandle* output) { + if (spec == "?") { + *output = UnknownShape(); + return Status::OK(); + } + + std::vector dims; + strings::Scanner scanner(spec); + scanner.OneLiteral("["); + while (scanner.Peek() != ']') { + if (scanner.Peek() == '?') { + scanner.OneLiteral("?"); + dims.push_back(UnknownDim()); + } else { + scanner.RestartCapture().Many(strings::Scanner::DIGIT); + StringPiece match; + int64 dim_size = 0; + CHECK(scanner.GetResult(nullptr, &match) && + strings::safe_strto64(match, &dim_size)) + << spec; + dims.push_back(MakeDim(dim_size)); + } + + if (scanner.Peek() == ',') { + scanner.OneLiteral(","); + } else if (scanner.Peek() != ']') { + return errors::InvalidArgument( + "Invalid input spec (] not found in dim shape): ", spec); + } + } + CHECK(scanner.OneLiteral("]").Eos().GetResult()); + *output = MakeShape(dims); + + return Status::OK(); +} + } // namespace shape_inference } // namespace tensorflow diff --git a/tensorflow/core/framework/shape_inference.h b/tensorflow/core/framework/shape_inference.h index cc7b604150a37b3f3889eafd09557cdae6823054..74cfbba72ea1632a60482bbe7840262af5724818 100644 --- a/tensorflow/core/framework/shape_inference.h +++ b/tensorflow/core/framework/shape_inference.h @@ -28,6 +28,7 @@ limitations under the License. namespace tensorflow { namespace shape_inference { +struct DimensionOrConstant; class InferenceContext; // Dimension values are accessed through InferenceContext. @@ -43,32 +44,73 @@ class Dimension { TF_DISALLOW_COPY_AND_ASSIGN(Dimension); }; +class DimensionHandle { + public: + DimensionHandle() {} + + private: + DimensionHandle(const Dimension* dim) { ptr_ = dim; } + + const Dimension* operator->() { return ptr_; } + bool IsSet() const { return ptr_ != nullptr; } + bool SameHandle(DimensionHandle d) const { return ptr_ == d.ptr_; } + + const Dimension* ptr_ = nullptr; + + friend struct DimensionOrConstant; + friend class InferenceContext; + friend class ShapeInferenceTest; + friend class ShapeInferenceTestutil; + + // Intentionally copyable. +}; + // Shape rank and dimensions are accessed through InferenceContext. class Shape { private: Shape(); - Shape(const std::vector& dims); + Shape(const std::vector& dims); ~Shape() {} const int32 rank_; - const std::vector dims_; + const std::vector dims_; friend class InferenceContext; + TF_DISALLOW_COPY_AND_ASSIGN(Shape); }; -// Struct used to allow functions to take const Dimension* or a dimension value. +class ShapeHandle { + public: + ShapeHandle() {} + + private: + ShapeHandle(const Shape* shape) { ptr_ = shape; } + const Shape* operator->() { return ptr_; } + bool IsSet() const { return ptr_ != nullptr; } + bool SameHandle(ShapeHandle s) const { return ptr_ == s.ptr_; } + + const Shape* ptr_ = nullptr; + + friend class InferenceContext; + friend class ShapeInferenceTest; + friend class ShapeInferenceTestutil; + + // Intentionally copyable. +}; + +// Struct used to allow functions to take DimensionHandle or a dimension value. // Not meant to be constructed directly. struct DimensionOrConstant { public: // Intentionally not explicit. - DimensionOrConstant(const Dimension* dim); + DimensionOrConstant(DimensionHandle dim); // val must be non-negative or InferenceContext::kUnknownDim. DimensionOrConstant(int64 val); // dim takes precedence. If dim != nullptr, val is ignored. - const Dimension* dim; + DimensionHandle dim; int64 val; private: @@ -89,6 +131,28 @@ class InferenceContext { static constexpr int64 kUnknownDim = -1; static constexpr int32 kUnknownRank = -1; + // is NULL-padded to be the same size as . + // + // REQUIRES: is not NULL, and must outlive the InferenceContext. + // + // TODO(vrv): Remove 'input_shapes_string' once we can move the + // creation of Shapes from strings out of this class (or hide it). + InferenceContext(const NodeDef* node_def, const OpDef& op_def, + const std::vector& input_shapes_string, + const std::vector& input_shapes, + const std::vector& input_tensors); + + // is NULL-padded to be the same size as . + // + // REQUIRES: is not NULL, and must outlive the InferenceContext. + // + // TODO(cwhipkey): Remove 'input_shapes_string' once we can move the creation + // of Shapes from strings out of this class (or hide it). + InferenceContext(const NodeDef* node_def, const OpDef& op_def, + const std::vector& input_shapes_string, + const std::vector& input_shapes, + const std::vector& input_tensors); + // This is a temporary constructor used for initial testing. // // TODO(cwhipkey): remove this temporary constructor. @@ -106,22 +170,36 @@ class InferenceContext { InferenceContext(const NodeDef* node_def, const OpDef& op_def, const std::vector& input_shapes, const std::vector& input_tensors); + ~InferenceContext(); - const Shape* input(int idx) const { return inputs_[idx]; } + ShapeHandle input(int idx) const { return inputs_[idx]; } int num_inputs() const { return inputs_.size(); } // Returns the input tensor at index , or nullptr if the input tensor is // not available at the time of shape inference. - const Tensor* input_tensor(int idx) const { return input_tensors_[idx]; } + const Tensor* input_tensor(int idx) { + // Mark that this idx was requested. + requested_input_tensor_[idx] = true; + return input_tensors_[idx]; + } + + // Returns true iff input_tensor(idx) was called by the shape function. + bool requested_input_tensor(int idx) const { + return requested_input_tensor_[idx]; + } + + void set_input_tensors(const std::vector& input_tensors) { + input_tensors_ = input_tensors; + } - void set_output(int idx, const Shape* shape) { outputs_[idx] = shape; } + void set_output(int idx, ShapeHandle shape) { outputs_[idx] = shape; } int num_outputs() const { return outputs_.size(); } - const Shape* output(int idx) { return outputs_[idx]; } + ShapeHandle output(int idx) { return outputs_[idx]; } // idx can be negative for an offset from end of dimensions. // idx must be in the range [-1 * s.rank, s.rank). - const Dimension* Dim(const Shape* s, int32 idx) { + DimensionHandle Dim(ShapeHandle s, int32 idx) { if (s->rank_ == kUnknownRank) { return UnknownDim(); } @@ -130,134 +208,134 @@ class InferenceContext { } return s->dims_[idx]; } - int32 Rank(const Shape* s) { return s->rank_; } - bool RankKnown(const Shape* s) { return Rank(s) != kUnknownRank; } + int32 Rank(ShapeHandle s) { return s->rank_; } + bool RankKnown(ShapeHandle s) { return Rank(s) != kUnknownRank; } inline int64 Value(DimensionOrConstant d) { - return d.dim ? d.dim->value_ : d.val; + return d.dim.IsSet() ? d.dim->value_ : d.val; } inline bool ValueKnown(DimensionOrConstant d) { return Value(d) != kUnknownDim; } // Returns true if the rank and all dimensions of the Shape are known. - bool FullyDefined(const Shape* s); + bool FullyDefined(ShapeHandle s); // Returns the total number of elements, or an unknown dimension for an // incomplete shape. - const Dimension* NumElements(const Shape* s); + DimensionHandle NumElements(ShapeHandle s); - string DebugString(const Shape* s); - string DebugString(const Dimension* d); + string DebugString(ShapeHandle s); + string DebugString(DimensionHandle d); // If has rank , or its rank is unknown, return OK and return // the shape with asserted rank in <*out>. Otherwise return an error. // // Note that <*out> may be set to . - Status WithRank(const Shape* shape, int32 rank, - const Shape** out) TF_MUST_USE_RESULT; - Status WithRankAtLeast(const Shape* shape, int32 rank, - const Shape** out) TF_MUST_USE_RESULT; - Status WithRankAtMost(const Shape* shape, int32 rank, - const Shape** out) TF_MUST_USE_RESULT; + Status WithRank(ShapeHandle shape, int32 rank, + ShapeHandle* out) TF_MUST_USE_RESULT; + Status WithRankAtLeast(ShapeHandle shape, int32 rank, + ShapeHandle* out) TF_MUST_USE_RESULT; + Status WithRankAtMost(ShapeHandle shape, int32 rank, + ShapeHandle* out) TF_MUST_USE_RESULT; // If has value , or its value is unknown, returns OK and returns // the dimension with asserted value in <*out>. Otherwise returns an error. // // Note that <*out> may be set to . - Status WithValue(const Dimension* dim, int64 value, - const Dimension** out) TF_MUST_USE_RESULT; + Status WithValue(DimensionHandle dim, int64 value, + DimensionHandle* out) TF_MUST_USE_RESULT; // Merges and and returns the merged shape in <*out>. If and // are incompatible in rank, or in the value of any dimension, returns // an error. // // Note that <*out> may be set to or . - Status Merge(const Shape* in0, const Shape* in1, - const Shape** out) TF_MUST_USE_RESULT; + Status Merge(ShapeHandle in0, ShapeHandle in1, + ShapeHandle* out) TF_MUST_USE_RESULT; // Asserts that 's rank >= 's rank, and the first // dimensions of are compatible with the dimensions of // . // Returns the merged results in <*s_out> and <*prefix_out>. - Status MergePrefix(const Shape* s, const Shape* prefix, const Shape** s_out, - const Shape** prefix_out) TF_MUST_USE_RESULT; + Status MergePrefix(ShapeHandle s, ShapeHandle prefix, ShapeHandle* s_out, + ShapeHandle* prefix_out) TF_MUST_USE_RESULT; // Merges and and returns the merged dimension in <*out>. If // and have incompatible values, returns an error. // // Note that <*out> may be set to or . - Status Merge(const Dimension* d0, const Dimension* d1, - const Dimension** out) TF_MUST_USE_RESULT; + Status Merge(DimensionHandle d0, DimensionHandle d1, + DimensionHandle* out) TF_MUST_USE_RESULT; // Returns in <*out> a sub-shape of with dimensions [start:]. // can be negative to index from the end of the shape. If > // rank of , then an empty subshape is returned. // Returns an error if the rank of is < . - Status Subshape(const Shape* s, int64 start, - const Shape** out) TF_MUST_USE_RESULT; + Status Subshape(ShapeHandle s, int64 start, + ShapeHandle* out) TF_MUST_USE_RESULT; // Returns in <*out> a sub-shape of , with dimensions [start:end]. // and can be negative, to index from the end of the shape. // and are set to the rank of if > rank of . // Returns an error if the rank of is insufficient. - Status Subshape(const Shape* s, int64 start, int64 end, - const Shape** out) TF_MUST_USE_RESULT; + Status Subshape(ShapeHandle s, int64 start, int64 end, + ShapeHandle* out) TF_MUST_USE_RESULT; // Returns in <*out> the result of appending the dimensions of to those // of . - Status Concatenate(const Shape* s1, const Shape* s2, - const Shape** out) TF_MUST_USE_RESULT; + Status Concatenate(ShapeHandle s1, ShapeHandle s2, + ShapeHandle* out) TF_MUST_USE_RESULT; // Returns in the shape from replacing with // . - Status ReplaceDim(const Shape* s, int dim_index, const Dimension* new_dim, - const Shape** out) TF_MUST_USE_RESULT; + Status ReplaceDim(ShapeHandle s, int dim_index, DimensionHandle new_dim, + ShapeHandle* out) TF_MUST_USE_RESULT; // Returns a new shape with the given dims. The returned value is owned by // this context. - const Shape* MakeShape(const std::vector& dims); - const Shape* MakeShape(std::initializer_list dims); + ShapeHandle MakeShape(const std::vector& dims); + ShapeHandle MakeShape(std::initializer_list dims); // Returns a new unknown shape. - const Shape* UnknownShape(); + ShapeHandle UnknownShape(); // Returns a shape with specified rank but unknown dims. - const Shape* UnknownShapeOfRank(int32 rank); + ShapeHandle UnknownShapeOfRank(int32 rank); // Returns a new shape of zero dimensions. - const Shape* Scalar(); + ShapeHandle Scalar(); // Returns a new shape of one dimension. - const Shape* Vector(DimensionOrConstant dim); + ShapeHandle Vector(DimensionOrConstant dim); // Returns a new shape of two dimensions. - const Shape* Matrix(DimensionOrConstant dim1, DimensionOrConstant dim2); + ShapeHandle Matrix(DimensionOrConstant dim1, DimensionOrConstant dim2); // Returns in a new shape whose dimension sizes come from input tensor // . The tensor must be a 1-dimensional int32 or int64 tensor. If // the input tensor is NULL, then an unknown shape is returned. - Status MakeShapeFromShapeTensor(int input_idx, const Shape** out); + Status MakeShapeFromShapeTensor(int input_idx, ShapeHandle* out); // Returns in a new shape corresponding to . Status MakeShapeFromShapeProto(const TensorShapeProto& proto, - const Shape** out); + ShapeHandle* out); // Returns a new dimension of the given size. The returned value is owned by // this context. - inline const Dimension* MakeDim(DimensionOrConstant d) { - if (d.dim) { + inline DimensionHandle MakeDim(DimensionOrConstant d) { + if (d.dim.IsSet()) { return d.dim; } else { all_dims_.push_back(new Dimension(d.val)); return all_dims_.back(); } } - inline const Dimension* UnknownDim() { return MakeDim(kUnknownDim); } + inline DimensionHandle UnknownDim() { return MakeDim(kUnknownDim); } // Returns a new dimension whose value is given by a scalar input tensor. // The input tensor must be in host memory, since it is dereferenced to get // the value. - Status MakeDimForScalarInput(int idx, const Dimension** out); + Status MakeDimForScalarInput(int idx, DimensionHandle* out); // Look up the attr for the NodeDef being evaluated with name attr_name and // set *value to its value. If no attr with attr_name is found in def(), or @@ -268,37 +346,36 @@ class InferenceContext { // Returns in the result of dividing by . // Returns an error if is not positive or does not evenly // divide . - Status Divide(const Dimension* dividend, int64 divisor, - const Dimension** out); + Status Divide(DimensionHandle dividend, int64 divisor, DimensionHandle* out); // Returns in the sum of and . - Status Add(const Dimension* first, DimensionOrConstant second, - const Dimension** out); + Status Add(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out); // Returns in the dimension that is minus . - Status Subtract(const Dimension* first, DimensionOrConstant second, - const Dimension** out); + Status Subtract(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out); // Returns in the product of and . - Status Multiply(const Dimension* first, DimensionOrConstant second, - const Dimension** out); + Status Multiply(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out); // Returns in the minimum of and . If either or // is zero the results is zero. Otherwise, if either or // is unknown the results is unknown. - Status Min(const Dimension* first, DimensionOrConstant second, - const Dimension** out); + Status Min(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out); // Returns in the maximum of and . If either or // is unknown the results is unknown. - Status Max(const Dimension* first, DimensionOrConstant second, - const Dimension** out); + Status Max(DimensionHandle first, DimensionOrConstant second, + DimensionHandle* out); Status construction_status() const { return construction_status_; } // Validates that 'dim' has a known value, and prints an error // message containing 'name' if validation fails. - Status ValidateKnownDim(const Dimension* dim, const char* name) { + Status ValidateKnownDim(DimensionHandle dim, const char* name) { if (!ValueKnown(dim)) { return errors::InvalidArgument("Cannot infer shape because dimension ", name, " is not known."); @@ -308,19 +385,19 @@ class InferenceContext { // Validates the 3 component tensors of a sparse tensor have the proper // shapes. This mimics SparseTensor.__init__ in python/framework/ops.py. - Status ValidateSparseTensor(const Shape* indices_shape, - const Shape* values_shape, - const Shape* shape_shape) { + Status ValidateSparseTensor(ShapeHandle indices_shape, + ShapeHandle values_shape, + ShapeHandle shape_shape) { // Validate ranks. - const Shape* unused_shape; + ShapeHandle unused_shape; TF_RETURN_IF_ERROR(WithRank(indices_shape, 2, &unused_shape)); TF_RETURN_IF_ERROR(WithRank(values_shape, 1, &unused_shape)); TF_RETURN_IF_ERROR(WithRank(shape_shape, 1, &unused_shape)); // Number of elements in indices and values must match. - const Dimension* num_index_elements_dim = Dim(indices_shape, 0); + DimensionHandle num_index_elements_dim = Dim(indices_shape, 0); if (ValueKnown(num_index_elements_dim)) { - const Dimension* num_values_elements_dim = Dim(values_shape, 0); + DimensionHandle num_values_elements_dim = Dim(values_shape, 0); if (ValueKnown(num_values_elements_dim)) { int64 num_index_elements = Value(num_index_elements_dim); int64 num_values_elements = Value(num_values_elements_dim); @@ -333,9 +410,9 @@ class InferenceContext { } // Rank embedded in indices must match shape. - const Dimension* index_rank_dim = Dim(indices_shape, 1); + DimensionHandle index_rank_dim = Dim(indices_shape, 1); if (ValueKnown(index_rank_dim)) { - const Dimension* shape_rank_dim = Dim(shape_shape, 0); + DimensionHandle shape_rank_dim = Dim(shape_shape, 0); if (ValueKnown(shape_rank_dim)) { int64 index_rank = Value(index_rank_dim); int32 shape_rank = Value(shape_rank_dim); @@ -351,14 +428,23 @@ class InferenceContext { } private: - const Dimension* GetDimension(const DimensionOrConstant& d); + // Shared initialization across the two constructors. Remove + // once we get rid of one of them. + void PreInputInit(const OpDef& op_def, + const std::vector& input_tensors); + void PostInputInit(); + + // Returns a shape from 'shape_string'. + Status MakeShapeFromString(const string& shape_string, ShapeHandle* output); + + DimensionHandle GetDimension(const DimensionOrConstant& d); - Status ReturnUnknownShape(const Shape** out) { + Status ReturnUnknownShape(ShapeHandle* out) { *out = UnknownShape(); return Status::OK(); } - Status ReturnCreatedShape(const std::vector& dims, - const Shape** out) { + Status ReturnCreatedShape(const std::vector& dims, + ShapeHandle* out) { *out = MakeShape(dims); return Status::OK(); } @@ -367,9 +453,10 @@ class InferenceContext { std::vector all_dims_; // values are owned. // inputs_ and outputs_ refer to values from all_shapes_. - std::vector inputs_; + std::vector inputs_; std::vector input_tensors_; - std::vector outputs_; + std::vector requested_input_tensor_; + std::vector outputs_; const NodeDef& node_def_; NameRangeMap input_name_map_; @@ -394,16 +481,15 @@ inline Dimension::Dimension(int64 value) : value_(value) { } inline Shape::Shape() : rank_(InferenceContext::kUnknownRank) {} -inline Shape::Shape(const std::vector& dims) +inline Shape::Shape(const std::vector& dims) : rank_(dims.size()), dims_(dims) {} -inline DimensionOrConstant::DimensionOrConstant(const Dimension* dim) +inline DimensionOrConstant::DimensionOrConstant(DimensionHandle dim) : dim(dim) { - DCHECK(dim != nullptr) << "Internal error: Got nullptr for Dimension."; + DCHECK(dim.IsSet()) << "Internal error: Got nullptr for Dimension."; } -inline DimensionOrConstant::DimensionOrConstant(int64 val) - : dim(nullptr), val(val) { +inline DimensionOrConstant::DimensionOrConstant(int64 val) : val(val) { DCHECK(val >= 0 || val == InferenceContext::kUnknownDim) << "Dimension must be non-negative or equal to " "InferenceContext::kUnknownDim but got" diff --git a/tensorflow/core/framework/shape_inference_test.cc b/tensorflow/core/framework/shape_inference_test.cc index 7be573d24924eddd1adc76afb16c4dc0266ebb3e..fe5fc45b8a9a1408763130f0b69c2e5579e420cc 100644 --- a/tensorflow/core/framework/shape_inference_test.cc +++ b/tensorflow/core/framework/shape_inference_test.cc @@ -24,6 +24,17 @@ limitations under the License. namespace tensorflow { namespace shape_inference { +class ShapeInferenceTest : public ::testing::Test { + protected: + // These give access to private functions of DimensionHandle and ShapeHandle. + bool SameHandle(DimensionHandle a, DimensionHandle b) { + return a.SameHandle(b); + } + bool SameHandle(ShapeHandle a, ShapeHandle b) { return a.SameHandle(b); } + bool IsSet(DimensionHandle d) { return d.IsSet(); } + bool IsSet(ShapeHandle s) { return s.IsSet(); } +}; + static OpDef MakeOpDef(int num_inputs, int num_outputs) { OpRegistrationData op_reg_data; OpDefBuilder b("dummy"); @@ -37,7 +48,7 @@ static OpDef MakeOpDef(int num_inputs, int num_outputs) { return op_reg_data.op_def; } -TEST(ShapeInferenceTest, DimensionOrConstant) { +TEST_F(ShapeInferenceTest, DimensionOrConstant) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 1), {"?"}, {}); EXPECT_EQ(InferenceContext::kUnknownDim, @@ -50,7 +61,7 @@ TEST(ShapeInferenceTest, DimensionOrConstant) { #endif } -TEST(ShapeInferenceTest, RankAndDimInspection) { +TEST_F(ShapeInferenceTest, RankAndDimInspection) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 2), {"?", "[1,?,3]", "[]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -70,17 +81,17 @@ TEST(ShapeInferenceTest, RankAndDimInspection) { EXPECT_EQ(3, c.Rank(in1)); auto d = c.Dim(in1, 0); EXPECT_EQ(1, c.Value(d)); - EXPECT_TRUE(d == c.Dim(in1, -3)); + EXPECT_TRUE(SameHandle(d, c.Dim(in1, -3))); EXPECT_TRUE(c.ValueKnown(d)); EXPECT_EQ("1", c.DebugString(d)); d = c.Dim(in1, 1); EXPECT_EQ(InferenceContext::kUnknownDim, c.Value(d)); EXPECT_FALSE(c.ValueKnown(d)); - EXPECT_TRUE(d == c.Dim(in1, -2)); + EXPECT_TRUE(SameHandle(d, c.Dim(in1, -2))); EXPECT_EQ("?", c.DebugString(d)); d = c.Dim(in1, 2); EXPECT_EQ(3, c.Value(d)); - EXPECT_TRUE(d == c.Dim(in1, -1)); + EXPECT_TRUE(SameHandle(d, c.Dim(in1, -1))); EXPECT_TRUE(c.ValueKnown(d)); EXPECT_EQ("3", c.DebugString(d)); @@ -90,27 +101,27 @@ TEST(ShapeInferenceTest, RankAndDimInspection) { EXPECT_EQ(0, c.Rank(in2)); } -TEST(ShapeInferenceTest, NumElements) { +TEST_F(ShapeInferenceTest, NumElements) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 2), {"?", "[1,?,3]", "[5,4,3,2]"}, {}); EXPECT_EQ("?", c.DebugString(c.NumElements(c.input(0)))); EXPECT_EQ("?", c.DebugString(c.NumElements(c.input(1)))); - // Different pointers (not the same unknown value). - EXPECT_TRUE(c.Dim(c.input(1), 1) != c.NumElements(c.input(1))); + // Different handles (not the same unknown value). + EXPECT_FALSE(SameHandle(c.Dim(c.input(1), 1), c.NumElements(c.input(1)))); EXPECT_EQ("120", c.DebugString(c.NumElements(c.input(2)))); } -TEST(ShapeInferenceTest, WithRank) { +TEST_F(ShapeInferenceTest, WithRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(2, 2), {"?", "[1,?,3]"}, {}); auto in0 = c.input(0); auto in1 = c.input(1); - const Shape* s1 = nullptr; - const Shape* s2 = nullptr; + ShapeHandle s1; + ShapeHandle s2; // WithRank on a shape with unknown dimensionality always succeeds. EXPECT_TRUE(c.WithRank(in0, 1, &s1).ok()); @@ -118,12 +129,12 @@ TEST(ShapeInferenceTest, WithRank) { EXPECT_TRUE(c.WithRank(in0, 2, &s2).ok()); EXPECT_EQ("[?,?]", c.DebugString(s2)); - EXPECT_TRUE(s1 != s2); // different pointers - EXPECT_TRUE(c.Dim(s2, 0) != c.Dim(s2, 1)); // different pointers. + EXPECT_FALSE(SameHandle(s1, s2)); + EXPECT_FALSE(SameHandle(c.Dim(s2, 0), c.Dim(s2, 1))); EXPECT_TRUE(c.WithRank(in0, 1, &s2).ok()); EXPECT_EQ("[?]", c.DebugString(s2)); - EXPECT_TRUE(s1 != s2); // different pointers + EXPECT_FALSE(SameHandle(s1, s2)); EXPECT_TRUE(c.WithRank(in0, 0, &s1).ok()); EXPECT_EQ("[]", c.DebugString(s1)); @@ -132,93 +143,93 @@ TEST(ShapeInferenceTest, WithRank) { s1 = in1; EXPECT_EQ("Invalid argument: Shape must be rank 2 but is rank 3", c.WithRank(in1, 2, &s1).ToString()); - EXPECT_TRUE(s1 == nullptr); + EXPECT_FALSE(IsSet(s1)); EXPECT_TRUE(c.WithRank(in1, 3, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); // Inputs are unchanged. EXPECT_EQ("?", c.DebugString(in0)); EXPECT_EQ("[1,?,3]", c.DebugString(in1)); } -TEST(ShapeInferenceTest, WithRankAtMost) { +TEST_F(ShapeInferenceTest, WithRankAtMost) { NodeDef def; InferenceContext c(&def, MakeOpDef(2, 2), {"?", "[1,?,3]"}, {}); auto in0 = c.input(0); auto in1 = c.input(1); - const Shape* s1 = nullptr; - const Shape* s2 = nullptr; + ShapeHandle s1; + ShapeHandle s2; // WithRankAtMost on a shape with unknown dimensionality always succeeds. EXPECT_TRUE(c.WithRankAtMost(in0, 1, &s1).ok()); EXPECT_EQ("?", c.DebugString(s1)); - EXPECT_TRUE(in0 != s1); // different pointers + EXPECT_FALSE(SameHandle(in0, s1)); EXPECT_TRUE(c.WithRankAtMost(in0, 2, &s2).ok()); EXPECT_EQ("?", c.DebugString(s2)); - EXPECT_TRUE(s1 != s2); // different pointers + EXPECT_FALSE(SameHandle(s1, s2)); // WithRankAtMost on shape with known dimensionality. s1 = in1; EXPECT_EQ("Invalid argument: Shape must be at most rank 2 but is rank 3", c.WithRankAtMost(in1, 2, &s1).ToString()); - EXPECT_TRUE(s1 == nullptr); + EXPECT_FALSE(IsSet(s1)); EXPECT_TRUE(c.WithRankAtMost(in1, 3, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); EXPECT_TRUE(c.WithRankAtMost(in1, 4, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); EXPECT_TRUE(c.WithRankAtMost(in1, 5, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); // Inputs are unchanged. EXPECT_EQ("?", c.DebugString(in0)); EXPECT_EQ("[1,?,3]", c.DebugString(in1)); } -TEST(ShapeInferenceTest, WithRankAtLeast) { +TEST_F(ShapeInferenceTest, WithRankAtLeast) { NodeDef def; InferenceContext c(&def, MakeOpDef(2, 2), {"?", "[1,?,3]"}, {}); auto in0 = c.input(0); auto in1 = c.input(1); - const Shape* s1 = nullptr; - const Shape* s2 = nullptr; + ShapeHandle s1; + ShapeHandle s2; // WithRankAtLeast on a shape with unknown dimensionality always succeeds. EXPECT_TRUE(c.WithRankAtLeast(in0, 1, &s1).ok()); EXPECT_EQ("?", c.DebugString(s1)); - EXPECT_TRUE(in0 != s1); // different pointers + EXPECT_FALSE(SameHandle(in0, s1)); EXPECT_TRUE(c.WithRankAtLeast(in0, 2, &s2).ok()); EXPECT_EQ("?", c.DebugString(s2)); - EXPECT_TRUE(s1 != s2); // different pointers + EXPECT_FALSE(SameHandle(s1, s2)); // WithRankAtLeast on shape with known dimensionality. s1 = in1; EXPECT_EQ("Invalid argument: Shape must be at least rank 4 but is rank 3", c.WithRankAtLeast(in1, 4, &s1).ToString()); - EXPECT_TRUE(s1 == nullptr); + EXPECT_FALSE(IsSet(s1)); EXPECT_TRUE(c.WithRankAtLeast(in1, 3, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); EXPECT_TRUE(c.WithRankAtLeast(in1, 2, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); EXPECT_TRUE(c.WithRankAtLeast(in1, 0, &s1).ok()); - EXPECT_TRUE(s1 == in1); // same pointers + EXPECT_TRUE(SameHandle(s1, in1)); // Inputs are unchanged. EXPECT_EQ("?", c.DebugString(in0)); EXPECT_EQ("[1,?,3]", c.DebugString(in1)); } -TEST(ShapeInferenceTest, WithValue) { +TEST_F(ShapeInferenceTest, WithValue) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[1,?]"}, {}); auto d0 = c.Dim(c.input(0), 0); auto d1 = c.Dim(c.input(0), 1); - const Dimension* out1 = nullptr; - const Dimension* out2 = nullptr; + DimensionHandle out1; + DimensionHandle out2; // WithValue on a dimension with unknown value always succeeds. EXPECT_TRUE(c.WithValue(d1, 1, &out1).ok()); @@ -226,31 +237,31 @@ TEST(ShapeInferenceTest, WithValue) { EXPECT_TRUE(c.WithValue(d1, 2, &out2).ok()); EXPECT_EQ(2, c.Value(out2)); - EXPECT_TRUE(out1 != out2); // different pointers - EXPECT_TRUE(out1 != d1); // different pointers + EXPECT_FALSE(SameHandle(out1, out2)); + EXPECT_FALSE(SameHandle(out1, d1)); EXPECT_TRUE(c.WithValue(d1, 1, &out2).ok()); EXPECT_EQ(1, c.Value(out2)); - EXPECT_TRUE(out1 != out2); // different pointers + EXPECT_FALSE(SameHandle(out1, out2)); // WithValue on dimension with known size. out1 = d0; EXPECT_EQ("Invalid argument: Dimension must be 0 but is 1", c.WithValue(d0, 0, &out1).ToString()); - EXPECT_TRUE(out1 == nullptr); + EXPECT_FALSE(IsSet(out1)); out1 = d0; EXPECT_EQ("Invalid argument: Dimension must be 2 but is 1", c.WithValue(d0, 2, &out1).ToString()); - EXPECT_TRUE(out1 == nullptr); + EXPECT_FALSE(IsSet(out1)); EXPECT_TRUE(c.WithValue(d0, 1, &out1).ok()); - EXPECT_TRUE(d0 == out1); // same pointers + EXPECT_TRUE(SameHandle(d0, out1)); // Inputs are unchanged. EXPECT_EQ("1", c.DebugString(d0)); EXPECT_EQ("?", c.DebugString(d1)); } -TEST(ShapeInferenceTest, MergeDim) { +TEST_F(ShapeInferenceTest, MergeDim) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[2,?,2,1,?]"}, {}); @@ -259,38 +270,38 @@ TEST(ShapeInferenceTest, MergeDim) { auto d2_b = c.Dim(c.input(0), 2); auto d1 = c.Dim(c.input(0), 3); auto d_unknown_b = c.Dim(c.input(0), 4); - const Dimension* out = nullptr; + DimensionHandle out; // Merging anything with unknown returns the same pointer. EXPECT_TRUE(c.Merge(d2, d_unknown, &out).ok()); - EXPECT_TRUE(d2 == out); + EXPECT_TRUE(SameHandle(d2, out)); EXPECT_TRUE(c.Merge(d_unknown, d2, &out).ok()); - EXPECT_TRUE(d2 == out); + EXPECT_TRUE(SameHandle(d2, out)); EXPECT_TRUE(c.Merge(d_unknown, d_unknown_b, &out).ok()); - EXPECT_TRUE(d_unknown == out); + EXPECT_TRUE(SameHandle(d_unknown, out)); // Merging with self returns self. EXPECT_TRUE(c.Merge(d2, d2, &out).ok()); - EXPECT_TRUE(d2 == out); + EXPECT_TRUE(SameHandle(d2, out)); EXPECT_TRUE(c.Merge(d_unknown, d_unknown, &out).ok()); - EXPECT_TRUE(d_unknown == out); + EXPECT_TRUE(SameHandle(d_unknown, out)); // Merging equal values returns first one. EXPECT_TRUE(c.Merge(d2, d2_b, &out).ok()); - EXPECT_TRUE(d2 == out); + EXPECT_TRUE(SameHandle(d2, out)); EXPECT_TRUE(c.Merge(d2_b, d2, &out).ok()); - EXPECT_TRUE(d2_b == out); + EXPECT_TRUE(SameHandle(d2_b, out)); // Merging inequal values is an error. EXPECT_EQ("Invalid argument: Dimensions must be equal, but are 2 and 1", c.Merge(d2, d1, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); EXPECT_EQ("Invalid argument: Dimensions must be equal, but are 1 and 2", c.Merge(d1, d2, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); } -TEST(ShapeInferenceTest, MergeShape) { +TEST_F(ShapeInferenceTest, MergeShape) { NodeDef def; InferenceContext c(&def, MakeOpDef(7, 2), {"?", "[1,2]", "[?,2]", "[1,?]", "[1,3]", "?", "[1]"}, {}); @@ -302,54 +313,54 @@ TEST(ShapeInferenceTest, MergeShape) { auto s_1_3 = c.input(4); auto s_unknown_b = c.input(5); auto s_1 = c.input(6); - const Shape* out = nullptr; + ShapeHandle out; // Merging any shape with unknown returns the shape. EXPECT_TRUE(c.Merge(s_unknown, s_1_2, &out).ok()); - EXPECT_TRUE(s_1_2 == out); + EXPECT_TRUE(SameHandle(s_1_2, out)); EXPECT_TRUE(c.Merge(s_u_2, s_unknown, &out).ok()); - EXPECT_TRUE(s_u_2 == out); + EXPECT_TRUE(SameHandle(s_u_2, out)); EXPECT_TRUE(c.Merge(s_unknown, s_unknown_b, &out).ok()); - EXPECT_TRUE(s_unknown == out); + EXPECT_TRUE(SameHandle(s_unknown, out)); // Merging with self returns self. EXPECT_TRUE(c.Merge(s_1_2, s_1_2, &out).ok()); - EXPECT_TRUE(out == s_1_2); + EXPECT_TRUE(SameHandle(out, s_1_2)); // Merging where one of the inputs is the right answer - return that input. - out = nullptr; + out = ShapeHandle(); EXPECT_TRUE(c.Merge(s_1_2, s_u_2, &out).ok()); - EXPECT_TRUE(s_1_2 == out); - out = nullptr; + EXPECT_TRUE(SameHandle(s_1_2, out)); + out = ShapeHandle(); EXPECT_TRUE(c.Merge(s_u_2, s_1_2, &out).ok()); - EXPECT_TRUE(s_1_2 == out); + EXPECT_TRUE(SameHandle(s_1_2, out)); // Merging where neither input is the right answer. EXPECT_TRUE(c.Merge(s_u_2, s_1_u, &out).ok()); - EXPECT_TRUE(out != s_u_2); - EXPECT_TRUE(out != s_1_u); + EXPECT_FALSE(SameHandle(out, s_u_2)); + EXPECT_FALSE(SameHandle(out, s_1_u)); EXPECT_EQ("[1,2]", c.DebugString(out)); - EXPECT_TRUE(c.Dim(s_1_u, 0) == c.Dim(out, 0)); // same pointers - EXPECT_TRUE(c.Dim(s_u_2, 1) == c.Dim(out, 1)); // same pointers + EXPECT_TRUE(SameHandle(c.Dim(s_1_u, 0), c.Dim(out, 0))); + EXPECT_TRUE(SameHandle(c.Dim(s_u_2, 1), c.Dim(out, 1))); // Incompatible merges give errors and set out to nullptr. out = s_unknown; EXPECT_EQ(("Invalid argument: Dimension 1 in both shapes must be equal, but " "are 2 and 3"), c.Merge(s_u_2, s_1_3, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); out = s_unknown; EXPECT_EQ(("Invalid argument: Dimension 1 in both shapes must be equal, but " "are 3 and 2"), c.Merge(s_1_3, s_u_2, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); out = s_unknown; EXPECT_EQ("Invalid argument: Shapes must be equal rank, but are 1 and 2", c.Merge(s_1, s_1_2, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); } -TEST(ShapeInferenceTest, MergePrefix) { +TEST_F(ShapeInferenceTest, MergePrefix) { NodeDef def; InferenceContext c(&def, MakeOpDef(4, 2), {"?", "[?,2]", "[1,?,3]", "[2,4]"}, {}); @@ -359,64 +370,64 @@ TEST(ShapeInferenceTest, MergePrefix) { auto s_1_u_3 = c.input(2); auto s_2_4 = c.input(3); - const Shape* s_out = nullptr; - const Shape* s_prefix_out = nullptr; + ShapeHandle s_out; + ShapeHandle s_prefix_out; // Merging with unknown returns the inputs. EXPECT_TRUE(c.MergePrefix(s_unknown, s_u_2, &s_out, &s_prefix_out).ok()); - EXPECT_TRUE(s_out == s_unknown); - EXPECT_TRUE(s_prefix_out == s_u_2); + EXPECT_TRUE(SameHandle(s_out, s_unknown)); + EXPECT_TRUE(SameHandle(s_prefix_out, s_u_2)); EXPECT_TRUE(c.MergePrefix(s_1_u_3, s_unknown, &s_out, &s_prefix_out).ok()); - EXPECT_TRUE(s_out == s_1_u_3); - EXPECT_TRUE(s_prefix_out == s_unknown); + EXPECT_TRUE(SameHandle(s_out, s_1_u_3)); + EXPECT_TRUE(SameHandle(s_prefix_out, s_unknown)); EXPECT_TRUE(c.MergePrefix(s_1_u_3, s_u_2, &s_out, &s_prefix_out).ok()); - EXPECT_TRUE(s_out != s_1_u_3); + EXPECT_FALSE(SameHandle(s_out, s_1_u_3)); EXPECT_EQ("[1,2]", c.DebugString(s_prefix_out)); EXPECT_EQ("[1,2,3]", c.DebugString(s_out)); - EXPECT_TRUE(c.Dim(s_prefix_out, 0) == c.Dim(s_out, 0)); - EXPECT_TRUE(c.Dim(s_out, 0) == c.Dim(s_1_u_3, 0)); - EXPECT_TRUE(c.Dim(s_prefix_out, 1) == c.Dim(s_out, 1)); - EXPECT_TRUE(c.Dim(s_prefix_out, 1) == c.Dim(s_u_2, 1)); + EXPECT_TRUE(SameHandle(c.Dim(s_prefix_out, 0), c.Dim(s_out, 0))); + EXPECT_TRUE(SameHandle(c.Dim(s_out, 0), c.Dim(s_1_u_3, 0))); + EXPECT_TRUE(SameHandle(c.Dim(s_prefix_out, 1), c.Dim(s_out, 1))); + EXPECT_TRUE(SameHandle(c.Dim(s_prefix_out, 1), c.Dim(s_u_2, 1))); // Incompatible merges give errors and set outs to nullptr. s_out = s_unknown; s_prefix_out = s_unknown; EXPECT_EQ(("Invalid argument: Dimensions must be equal, but are 1 and 2"), c.MergePrefix(s_1_u_3, s_2_4, &s_out, &s_prefix_out).ToString()); - EXPECT_TRUE(s_out == nullptr); - EXPECT_TRUE(s_prefix_out == nullptr); + EXPECT_FALSE(IsSet(s_out)); + EXPECT_FALSE(IsSet(s_prefix_out)); s_out = s_unknown; s_prefix_out = s_unknown; EXPECT_EQ(("Invalid argument: Shape must be at least rank 3 but is rank 2"), c.MergePrefix(s_2_4, s_1_u_3, &s_out, &s_prefix_out).ToString()); - EXPECT_TRUE(s_out == nullptr); - EXPECT_TRUE(s_prefix_out == nullptr); + EXPECT_FALSE(IsSet(s_out)); + EXPECT_FALSE(IsSet(s_prefix_out)); } -TEST(ShapeInferenceTest, Subshape) { +TEST_F(ShapeInferenceTest, Subshape) { NodeDef def; InferenceContext c(&def, MakeOpDef(2, 2), {"[1,2,3,?,5]", "?"}, {}); - const Shape* unknown = c.input(1); - const Shape* out; + ShapeHandle unknown = c.input(1); + ShapeHandle out; EXPECT_TRUE(c.Subshape(unknown, 0, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out == unknown); + EXPECT_TRUE(SameHandle(out, unknown)); EXPECT_TRUE(c.Subshape(unknown, 1, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != unknown); + EXPECT_FALSE(SameHandle(out, unknown)); EXPECT_TRUE(c.Subshape(unknown, 200, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != unknown); + EXPECT_FALSE(SameHandle(out, unknown)); const int kFullRank = 5; - const Shape* out_arr[4]; + ShapeHandle out_arr[4]; auto in0 = c.input(0); EXPECT_TRUE(c.Subshape(in0, 0, &out).ok()); EXPECT_EQ("[1,2,3,?,5]", c.DebugString(out)); - EXPECT_TRUE(out == in0); + EXPECT_TRUE(SameHandle(out, in0)); EXPECT_EQ(kFullRank, c.Rank(out)); for (int start = 0; start <= kFullRank + 1; ++start) { for (int end = start; end <= kFullRank + 1; ++end) { @@ -438,8 +449,8 @@ TEST(ShapeInferenceTest, Subshape) { << "start: " << start << " end: " << end << " arr_idx: " << arr_idx << " in0: " << c.DebugString(in0) << " out: " << c.DebugString(out); for (int d = 0; d < c.Rank(out); ++d) { - EXPECT_TRUE(c.Dim(in0, start + d) == c.Dim(out, d)) << "arr_idx: " - << arr_idx; + EXPECT_TRUE(SameHandle(c.Dim(in0, start + d), c.Dim(out, d))) + << "arr_idx: " << arr_idx; } } } @@ -451,55 +462,55 @@ TEST(ShapeInferenceTest, Subshape) { "Invalid argument: Subshape must have computed start <= end, but is 5 " "and 2 (computed from start 6 and end -3 over shape with rank 5)", c.Subshape(in0, 6, -3, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); out = unknown; EXPECT_EQ( "Invalid argument: Subshape start out of bounds: -50, for shape with " "rank 5", c.Subshape(in0, -50, 100, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); out = unknown; EXPECT_EQ( "Invalid argument: Subshape end out of bounds: -50, for shape with rank " "5", c.Subshape(in0, 0, -50, &out).ToString()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); } -TEST(ShapeInferenceTest, Concatenate) { +TEST_F(ShapeInferenceTest, Concatenate) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 2), {"[1,?,3]", "[4,5]", "?"}, {}); auto in0 = c.input(0); auto in1 = c.input(1); - const Shape* unknown = c.input(2); - const Shape* out; + ShapeHandle unknown = c.input(2); + ShapeHandle out; EXPECT_TRUE(c.Concatenate(unknown, unknown, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != unknown); + EXPECT_FALSE(SameHandle(out, unknown)); EXPECT_TRUE(c.Concatenate(unknown, in0, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != unknown); + EXPECT_FALSE(SameHandle(out, unknown)); EXPECT_TRUE(c.Concatenate(in0, in1, &out).ok()); EXPECT_EQ("[1,?,3,4,5]", c.DebugString(out)); int out_i = 0; for (int i = 0; i < c.Rank(in0); ++i, ++out_i) { - EXPECT_TRUE(c.Dim(in0, i) == c.Dim(out, out_i)); + EXPECT_TRUE(SameHandle(c.Dim(in0, i), c.Dim(out, out_i))); } for (int i = 0; i < c.Rank(in1); ++i, ++out_i) { - EXPECT_TRUE(c.Dim(in1, i) == c.Dim(out, out_i)); + EXPECT_TRUE(SameHandle(c.Dim(in1, i), c.Dim(out, out_i))); } } -TEST(ShapeInferenceTest, ReplaceDim) { +TEST_F(ShapeInferenceTest, ReplaceDim) { NodeDef def; InferenceContext c(&def, MakeOpDef(2, 0), {"[1,2,3]", "?"}, {}); auto in = c.input(0); auto unknown = c.input(1); - const Shape* replaced; + ShapeHandle replaced; EXPECT_TRUE(c.ReplaceDim(in, 0, c.Dim(in, 1), &replaced).ok()); EXPECT_EQ("[2,2,3]", c.DebugString(replaced)); EXPECT_TRUE(c.ReplaceDim(in, 2, c.Dim(in, 1), &replaced).ok()); @@ -517,17 +528,17 @@ TEST(ShapeInferenceTest, ReplaceDim) { // out of range indexing. EXPECT_FALSE(c.ReplaceDim(in, 3, c.Dim(in, 1), &replaced).ok()); - EXPECT_TRUE(replaced == nullptr); + EXPECT_FALSE(IsSet(replaced)); replaced = in; EXPECT_FALSE(c.ReplaceDim(in, -4, c.Dim(in, 1), &replaced).ok()); - EXPECT_TRUE(replaced == nullptr); + EXPECT_FALSE(IsSet(replaced)); } -TEST(ShapeInferenceTest, MakeShape) { +TEST_F(ShapeInferenceTest, MakeShape) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[1,2,3,?,5]"}, {}); - std::vector dims; + std::vector dims; auto in0 = c.input(0); const int rank = c.Rank(in0); for (int i = 0; i < rank; ++i) { @@ -536,18 +547,18 @@ TEST(ShapeInferenceTest, MakeShape) { auto s = c.MakeShape(dims); EXPECT_EQ("[5,?,3,2,1]", c.DebugString(s)); - EXPECT_TRUE(c.Dim(s, 0) == c.Dim(in0, rank - 1)); + EXPECT_TRUE(SameHandle(c.Dim(s, 0), c.Dim(in0, rank - 1))); auto s2 = c.MakeShape(dims); - EXPECT_TRUE(s != s2); // different pointers - EXPECT_TRUE(c.Dim(s2, 0) == c.Dim(in0, rank - 1)); + EXPECT_FALSE(SameHandle(s, s2)); + EXPECT_TRUE(SameHandle(c.Dim(s2, 0), c.Dim(in0, rank - 1))); auto s3 = c.MakeShape({1, 2, dims[2]}); - EXPECT_TRUE(s != s3); // different pointers + EXPECT_FALSE(SameHandle(s, s3)); EXPECT_EQ("[1,2,3]", c.DebugString(s3)); } -TEST(ShapeInferenceTest, UnknownShape) { +TEST_F(ShapeInferenceTest, UnknownShape) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); @@ -555,10 +566,10 @@ TEST(ShapeInferenceTest, UnknownShape) { auto u1 = c.UnknownShape(); EXPECT_EQ("?", c.DebugString(u0)); EXPECT_EQ("?", c.DebugString(u1)); - EXPECT_TRUE(u0 != u1); // different pointers + EXPECT_FALSE(SameHandle(u0, u1)); } -TEST(ShapeInferenceTest, Scalar) { +TEST_F(ShapeInferenceTest, Scalar) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); @@ -568,7 +579,7 @@ TEST(ShapeInferenceTest, Scalar) { EXPECT_EQ("[]", c.DebugString(s1)); } -TEST(ShapeInferenceTest, Vector) { +TEST_F(ShapeInferenceTest, Vector) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); @@ -580,40 +591,40 @@ TEST(ShapeInferenceTest, Vector) { auto d1 = c.UnknownDim(); auto s2 = c.Vector(d1); EXPECT_EQ("[?]", c.DebugString(s2)); - EXPECT_TRUE(d1 == c.Dim(s2, 0)); + EXPECT_TRUE(SameHandle(d1, c.Dim(s2, 0))); } -TEST(ShapeInferenceTest, Matrix) { +TEST_F(ShapeInferenceTest, Matrix) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); auto s0 = c.Matrix(1, 2); EXPECT_EQ("[1,2]", c.DebugString(s0)); - auto s1 = c.Matrix(static_cast(0), InferenceContext::kUnknownDim); + auto s1 = c.Matrix(0, InferenceContext::kUnknownDim); EXPECT_EQ("[0,?]", c.DebugString(s1)); auto d1 = c.UnknownDim(); auto d2 = c.UnknownDim(); auto s2 = c.Matrix(d1, d2); EXPECT_EQ("[?,?]", c.DebugString(s2)); - EXPECT_TRUE(d1 == c.Dim(s2, 0)); - EXPECT_TRUE(d2 == c.Dim(s2, 1)); + EXPECT_TRUE(SameHandle(d1, c.Dim(s2, 0))); + EXPECT_TRUE(SameHandle(d2, c.Dim(s2, 1))); auto s3 = c.Matrix(d1, 100); EXPECT_EQ("[?,100]", c.DebugString(s3)); - EXPECT_TRUE(d1 == c.Dim(s2, 0)); + EXPECT_TRUE(SameHandle(d1, c.Dim(s2, 0))); } -TEST(ShapeInferenceTest, MakeShapeFromShapeTensor) { - auto create = [](Tensor* t) { +TEST_F(ShapeInferenceTest, MakeShapeFromShapeTensor) { + auto create = [&](Tensor* t) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 0), {"?"}, {t}); - const Shape* out; + ShapeHandle out; Status s = c.MakeShapeFromShapeTensor(0, &out); if (s.ok()) { return c.DebugString(out); } else { - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); return s.error_message(); } }; @@ -643,26 +654,26 @@ TEST(ShapeInferenceTest, MakeShapeFromShapeTensor) { { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 0), {"[1,?]"}, {nullptr}); - const Shape* out; + ShapeHandle out; EXPECT_EQ("Shape must be rank 1 but is rank 2", c.MakeShapeFromShapeTensor(0, &out).error_message()); } } -TEST(ShapeInferenceTest, MakeShapeFromShapeProto) { +TEST_F(ShapeInferenceTest, MakeShapeFromShapeProto) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); TensorShapeProto proto; // With a set unknown rank. - const Shape* out; + ShapeHandle out; proto.set_unknown_rank(true); EXPECT_TRUE(c.MakeShapeFromShapeProto(proto, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); proto.add_dim()->set_size(0); EXPECT_EQ("An unknown shape must not have any dimensions set.", c.MakeShapeFromShapeProto(proto, &out).error_message()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); // With known rank. proto.set_unknown_rank(false); @@ -678,45 +689,45 @@ TEST(ShapeInferenceTest, MakeShapeFromShapeProto) { EXPECT_EQ(("Shape [0,?,1000,-2] has dimensions with values below -1 " "(where -1 means unknown)"), c.MakeShapeFromShapeProto(proto, &out).error_message()); - EXPECT_TRUE(out == nullptr); + EXPECT_FALSE(IsSet(out)); } -TEST(ShapeInferenceTest, MakeDim) { +TEST_F(ShapeInferenceTest, MakeDim) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); - auto* d0 = c.MakeDim(1); - auto* d1 = c.MakeDim(1); - auto* d2 = c.MakeDim(2); + auto d0 = c.MakeDim(1); + auto d1 = c.MakeDim(1); + auto d2 = c.MakeDim(2); EXPECT_EQ("1", c.DebugString(d0)); EXPECT_EQ("1", c.DebugString(d1)); - EXPECT_TRUE(d0 != d1); // different pointers + EXPECT_FALSE(SameHandle(d0, d1)); EXPECT_EQ("2", c.DebugString(d2)); } -TEST(ShapeInferenceTest, UnknownDim) { +TEST_F(ShapeInferenceTest, UnknownDim) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); - auto* d0 = c.UnknownDim(); - auto* d1 = c.UnknownDim(); + auto d0 = c.UnknownDim(); + auto d1 = c.UnknownDim(); EXPECT_EQ("?", c.DebugString(d0)); EXPECT_EQ("?", c.DebugString(d1)); - EXPECT_TRUE(d0 != d1); // different pointers + EXPECT_FALSE(SameHandle(d0, d1)); } -TEST(ShapeInferenceTest, UnknownShapeOfRank) { +TEST_F(ShapeInferenceTest, UnknownShapeOfRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); - auto* unknown_shape_of_rank_3 = c.UnknownShapeOfRank(3); + auto unknown_shape_of_rank_3 = c.UnknownShapeOfRank(3); EXPECT_EQ("[?,?,?]", c.DebugString(unknown_shape_of_rank_3)); - auto* unknown_shape_of_rank_0 = c.UnknownShapeOfRank(0); + auto unknown_shape_of_rank_0 = c.UnknownShapeOfRank(0); EXPECT_EQ("[]", c.DebugString(unknown_shape_of_rank_0)); } -TEST(ShapeInferenceTest, InputTensors) { +TEST_F(ShapeInferenceTest, InputTensors) { const Tensor t1 = tensorflow::test::AsTensor({10}); const Tensor t2 = tensorflow::test::AsTensor({20, 30}); NodeDef def; @@ -727,13 +738,13 @@ TEST(ShapeInferenceTest, InputTensors) { EXPECT_TRUE(c.input_tensor(2) == nullptr); } -TEST(ShapeInferenceTest, MakeDimForScalarInput) { +TEST_F(ShapeInferenceTest, MakeDimForScalarInput) { Tensor t1 = tensorflow::test::AsScalar(20); Tensor t2 = tensorflow::test::AsScalar(-1); NodeDef def; InferenceContext c(&def, MakeOpDef(2, 2), {"[]", "[]"}, {&t1, &t2}); - const Dimension* d; + DimensionHandle d; EXPECT_TRUE(c.MakeDimForScalarInput(0, &d).ok()); EXPECT_EQ("20", c.DebugString(d)); @@ -752,7 +763,7 @@ TEST(ShapeInferenceTest, MakeDimForScalarInput) { c.MakeDimForScalarInput(1, &d).error_message()); } -TEST(ShapeInferenceTest, GetAttr) { +TEST_F(ShapeInferenceTest, GetAttr) { OpRegistrationData op_reg_data; op_reg_data.op_def = MakeOpDef(0, 2); NodeDef def; @@ -767,7 +778,7 @@ TEST(ShapeInferenceTest, GetAttr) { EXPECT_EQ("bar", value); } -TEST(ShapeInferenceTest, Divide) { +TEST_F(ShapeInferenceTest, Divide) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[6,?]"}, {}); @@ -776,16 +787,16 @@ TEST(ShapeInferenceTest, Divide) { auto d_unknown = c.Dim(s, 1); // Dividing unknown by non-1 gives new unknown. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Divide(d_unknown, 2, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != d_unknown); + EXPECT_FALSE(SameHandle(out, d_unknown)); // Dividing anything by 1 returns the input. EXPECT_TRUE(c.Divide(d_unknown, 1, &out).ok()); - EXPECT_TRUE(out == d_unknown); + EXPECT_TRUE(SameHandle(out, d_unknown)); EXPECT_TRUE(c.Divide(d_6, 1, &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); EXPECT_TRUE(c.Divide(d_6, 2, &out).ok()); EXPECT_EQ("3", c.DebugString(out)); @@ -798,7 +809,7 @@ TEST(ShapeInferenceTest, Divide) { c.Divide(d_6, -1, &out).error_message()); } -TEST(ShapeInferenceTest, Add) { +TEST_F(ShapeInferenceTest, Add) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[6,?,0]"}, {}); @@ -808,22 +819,22 @@ TEST(ShapeInferenceTest, Add) { auto d_0 = c.Dim(s, 2); // Adding non-zero to unknown gives new unknown. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Add(d_unknown, 1, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != d_unknown); + EXPECT_FALSE(SameHandle(out, d_unknown)); // Adding 0 to anything gives input. - EXPECT_TRUE(c.Add(d_unknown, static_cast(0), &out).ok()); - EXPECT_TRUE(out == d_unknown); - EXPECT_TRUE(c.Add(d_6, static_cast(0), &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(c.Add(d_unknown, 0, &out).ok()); + EXPECT_TRUE(SameHandle(out, d_unknown)); + EXPECT_TRUE(c.Add(d_6, 0, &out).ok()); + EXPECT_TRUE(SameHandle(out, d_6)); // Adding dimension with value 0 to anything gives input. EXPECT_TRUE(c.Add(d_unknown, c.MakeDim(0ll), &out).ok()); - EXPECT_TRUE(out == d_unknown); + EXPECT_TRUE(SameHandle(out, d_unknown)); EXPECT_TRUE(c.Add(d_6, c.MakeDim(0ll), &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); // Test addition. EXPECT_TRUE(c.Add(d_6, 2, &out).ok()); @@ -840,14 +851,14 @@ TEST(ShapeInferenceTest, Add) { EXPECT_TRUE(c.Add(d_6, c.UnknownDim(), &out).ok()); EXPECT_EQ("?", c.DebugString(out)); EXPECT_TRUE(c.Add(d_0, d_6, &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); EXPECT_EQ( "Dimension size overflow from adding 6 and 9223372036854775802", c.Add(d_6, std::numeric_limits::max() - 5, &out).error_message()); } -TEST(ShapeInferenceTest, Subtract) { +TEST_F(ShapeInferenceTest, Subtract) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[6,?,0,5]"}, {}); @@ -858,22 +869,22 @@ TEST(ShapeInferenceTest, Subtract) { auto d_5 = c.Dim(s, 3); // Subtracting non-zero from unknown gives new unknown. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Subtract(d_unknown, 1, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); - EXPECT_TRUE(out != d_unknown); + EXPECT_FALSE(SameHandle(out, d_unknown)); // Subtracting 0 from anything gives input. EXPECT_TRUE(c.Subtract(d_unknown, 0ll, &out).ok()); - EXPECT_TRUE(out == d_unknown); + EXPECT_TRUE(SameHandle(out, d_unknown)); EXPECT_TRUE(c.Subtract(d_6, 0ll, &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); // Subtracting dimension with value 0 from anything gives input. EXPECT_TRUE(c.Subtract(d_unknown, c.MakeDim(0ll), &out).ok()); - EXPECT_TRUE(out == d_unknown); + EXPECT_TRUE(SameHandle(out, d_unknown)); EXPECT_TRUE(c.Subtract(d_6, c.MakeDim(0ll), &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); // Test subtraction. EXPECT_TRUE(c.Subtract(d_6, 2, &out).ok()); @@ -889,13 +900,13 @@ TEST(ShapeInferenceTest, Subtract) { EXPECT_TRUE(c.Subtract(d_6, c.UnknownDim(), &out).ok()); EXPECT_EQ("?", c.DebugString(out)); EXPECT_TRUE(c.Subtract(d_6, d_0, &out).ok()); - EXPECT_TRUE(out == d_6); + EXPECT_TRUE(SameHandle(out, d_6)); EXPECT_EQ("Negative dimension size caused by subtracting 6 from 5", c.Subtract(d_5, d_6, &out).error_message()); } -TEST(ShapeInferenceTest, Multiply) { +TEST_F(ShapeInferenceTest, Multiply) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[6,?,0,1]"}, {}); @@ -906,12 +917,12 @@ TEST(ShapeInferenceTest, Multiply) { auto d_1 = c.Dim(s, 3); // Multiplying non-zero to unknown gives new unknown. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Multiply(d_unknown, 2, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); // Multiplying 0 to anything gives 0. - EXPECT_TRUE(c.Multiply(d_unknown, static_cast(0), &out).ok()); + EXPECT_TRUE(c.Multiply(d_unknown, 0, &out).ok()); EXPECT_EQ("0", c.DebugString(out)); EXPECT_TRUE(c.Multiply(d_unknown, d_0, &out).ok()); EXPECT_EQ("0", c.DebugString(out)); @@ -921,18 +932,18 @@ TEST(ShapeInferenceTest, Multiply) { // Multiplying 1 to anything gives the original. // (unknown -> unknown) EXPECT_TRUE(c.Multiply(d_unknown, 1, &out).ok()); - EXPECT_EQ(d_unknown, out); + EXPECT_TRUE(SameHandle(d_unknown, out)); EXPECT_TRUE(c.Multiply(d_unknown, d_1, &out).ok()); - EXPECT_EQ(d_unknown, out); + EXPECT_TRUE(SameHandle(d_unknown, out)); EXPECT_TRUE(c.Multiply(d_1, d_unknown, &out).ok()); - EXPECT_EQ(d_unknown, out); + EXPECT_TRUE(SameHandle(d_unknown, out)); // (known -> known) EXPECT_TRUE(c.Multiply(d_6, 1, &out).ok()); - EXPECT_EQ(d_6, out); + EXPECT_TRUE(SameHandle(d_6, out)); EXPECT_TRUE(c.Multiply(d_6, d_1, &out).ok()); - EXPECT_EQ(d_6, out); + EXPECT_TRUE(SameHandle(d_6, out)); EXPECT_TRUE(c.Multiply(d_1, d_6, &out).ok()); - EXPECT_EQ(d_6, out); + EXPECT_TRUE(SameHandle(d_6, out)); // Test multiplication. EXPECT_TRUE(c.Multiply(d_6, 2, &out).ok()); @@ -947,7 +958,7 @@ TEST(ShapeInferenceTest, Multiply) { EXPECT_EQ("?", c.DebugString(out)); } -TEST(ShapeInferenceTest, FullyDefined) { +TEST_F(ShapeInferenceTest, FullyDefined) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); @@ -960,7 +971,7 @@ TEST(ShapeInferenceTest, FullyDefined) { EXPECT_TRUE(c.FullyDefined(c.Scalar())); } -TEST(ShapeInferenceTest, ValidateKnownDim) { +TEST_F(ShapeInferenceTest, ValidateKnownDim) { NodeDef def; InferenceContext c(&def, MakeOpDef(0, 2), {}, {}); @@ -968,7 +979,7 @@ TEST(ShapeInferenceTest, ValidateKnownDim) { EXPECT_TRUE(c.ValidateKnownDim(c.Dim(c.Matrix(1, 2), 0), "known").ok()); } -TEST(ShapeInferenceTest, Min) { +TEST_F(ShapeInferenceTest, Min) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[1,2,?,0]"}, {}); @@ -979,11 +990,11 @@ TEST(ShapeInferenceTest, Min) { auto d_0 = c.Dim(s, 3); // Minimum involving zero and unknown returns zero. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Min(d_0, d_unknown, &out).ok()); - EXPECT_EQ(d_0, out); + EXPECT_TRUE(SameHandle(d_0, out)); EXPECT_TRUE(c.Min(d_unknown, d_0, &out).ok()); - EXPECT_EQ(d_0, out); + EXPECT_TRUE(SameHandle(d_0, out)); EXPECT_TRUE(c.Min(c.MakeDim(0ll), d_unknown, &out).ok()); EXPECT_EQ("0", c.DebugString(out)); EXPECT_TRUE(c.Min(d_unknown, 0ll, &out).ok()); @@ -999,24 +1010,24 @@ TEST(ShapeInferenceTest, Min) { // Minimum with constant second arg. EXPECT_TRUE(c.Min(d_1, 1, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Min(d_1, 3, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Min(d_2, 1, &out).ok()); EXPECT_EQ("1", c.DebugString(out)); // Minimum with two dimensions. EXPECT_TRUE(c.Min(d_1, d_1, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Min(d_1, d_2, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Min(d_2, d_1, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Min(d_2, d_2, &out).ok()); - EXPECT_EQ(d_2, out); + EXPECT_TRUE(SameHandle(d_2, out)); } -TEST(ShapeInferenceTest, Max) { +TEST_F(ShapeInferenceTest, Max) { NodeDef def; InferenceContext c(&def, MakeOpDef(1, 2), {"[1,2,?]"}, {}); @@ -1026,7 +1037,7 @@ TEST(ShapeInferenceTest, Max) { auto d_unknown = c.Dim(s, 2); // Maximum involving unknowns gives new unknown. - const Dimension* out; + DimensionHandle out; EXPECT_TRUE(c.Max(d_unknown, d_unknown, &out).ok()); EXPECT_EQ("?", c.DebugString(out)); EXPECT_TRUE(c.Max(d_unknown, 1, &out).ok()); @@ -1036,24 +1047,24 @@ TEST(ShapeInferenceTest, Max) { // Maximum with constant second arg. EXPECT_TRUE(c.Max(d_1, 1, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Max(d_2, 1, &out).ok()); - EXPECT_EQ(d_2, out); + EXPECT_TRUE(SameHandle(d_2, out)); EXPECT_TRUE(c.Max(d_2, 3, &out).ok()); EXPECT_EQ("3", c.DebugString(out)); // Maximum with two dimensions. EXPECT_TRUE(c.Max(d_1, d_1, &out).ok()); - EXPECT_EQ(d_1, out); + EXPECT_TRUE(SameHandle(d_1, out)); EXPECT_TRUE(c.Max(d_1, d_2, &out).ok()); - EXPECT_EQ(d_2, out); + EXPECT_TRUE(SameHandle(d_2, out)); EXPECT_TRUE(c.Max(d_2, d_1, &out).ok()); - EXPECT_EQ(d_2, out); + EXPECT_TRUE(SameHandle(d_2, out)); EXPECT_TRUE(c.Max(d_2, d_2, &out).ok()); - EXPECT_EQ(d_2, out); + EXPECT_TRUE(SameHandle(d_2, out)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownShapes) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownShapes) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"?", "?", "?"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1065,7 +1076,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownShapes) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownDims) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownDims) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[?,?]", "[?]", "[?]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1077,7 +1088,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownDims) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidIndicesRank) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_InvalidIndicesRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[?]", "[?]", "[?]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1090,7 +1101,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidIndicesRank) { c.ValidateSparseTensor(indices, values, shape).code()); } -TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidNumElements) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_InvalidNumElements) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,3]", "[4]", "[3]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1103,7 +1114,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidNumElements) { c.ValidateSparseTensor(indices, values, shape).code()); } -TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidRank) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_InvalidRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,3]", "[5]", "[4]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1116,7 +1127,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_InvalidRank) { c.ValidateSparseTensor(indices, values, shape).code()); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownNumIndexElements) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownNumIndexElements) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[?,3]", "[5]", "[3]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1128,7 +1139,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownNumIndexElements) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownNumValueElements) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownNumValueElements) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,3]", "[?]", "[3]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1140,7 +1151,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownNumValueElements) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownIndexRank) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownIndexRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,?]", "[5]", "[3]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1152,7 +1163,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownIndexRank) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownShapeRank) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor_UnknownShapeRank) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,3]", "[5]", "[?]"}, {}); EXPECT_EQ(3, c.num_inputs()); @@ -1164,7 +1175,7 @@ TEST(ShapeInferenceTest, ValidateSparseTensor_UnknownShapeRank) { TF_EXPECT_OK(c.ValidateSparseTensor(indices, values, shape)); } -TEST(ShapeInferenceTest, ValidateSparseTensor) { +TEST_F(ShapeInferenceTest, ValidateSparseTensor) { NodeDef def; InferenceContext c(&def, MakeOpDef(3, 1), {"[5,3]", "[5]", "[3]"}, {}); EXPECT_EQ(3, c.num_inputs()); diff --git a/tensorflow/core/framework/shape_inference_testutil.cc b/tensorflow/core/framework/shape_inference_testutil.cc index 60a9cb101fd1a0a6e00017dc350a71ec8c055730..ea6711163cb91125843be8e533ec46f86637bb7b 100644 --- a/tensorflow/core/framework/shape_inference_testutil.cc +++ b/tensorflow/core/framework/shape_inference_testutil.cc @@ -14,8 +14,6 @@ limitations under the License. ==============================================================================*/ #include "tensorflow/core/framework/shape_inference_testutil.h" -#include - #include "tensorflow/core/framework/node_def_util.h" #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/shape_inference.h" @@ -24,13 +22,13 @@ limitations under the License. #include "tensorflow/core/lib/strings/str_util.h" namespace tensorflow { +namespace shape_inference { -using shape_inference::Dimension; -using shape_inference::Shape; using errors::Unknown; -Status InferShapes(ShapeInferenceTestOp op, const string& ins, - const string& expected_outs) { +Status ShapeInferenceTestutil::InferShapes(ShapeInferenceTestOp op, + const string& ins, + const string& expected_outs) { const OpRegistrationData* op_reg_data; TF_RETURN_IF_ERROR(OpRegistry::Global()->LookUp(op.name, &op_reg_data)); @@ -48,16 +46,6 @@ Status InferShapes(ShapeInferenceTestOp op, const string& ins, TF_RETURN_IF_ERROR(op_reg_data->shape_inference_fn(&c)); const int num_outputs = c.num_outputs(); - std::unordered_map> - dim_to_input_and_dim_idx; - std::unordered_map shape_to_input_idx; - for (int i = 0; i < c.num_inputs(); ++i) { - auto in = c.input(i); - shape_to_input_idx[in] = i; - for (int j = 0; j < c.Rank(in); ++j) { - dim_to_input_and_dim_idx[c.Dim(in, j)] = std::make_pair(i, j); - } - } if (expected_outs == "e") { return Unknown("Shape inference should have returned error"); } @@ -70,13 +58,19 @@ Status InferShapes(ShapeInferenceTestOp op, const string& ins, } for (int i = 0; i < num_outputs; ++i) { StringPiece expected(expected_outs_v[i]); - const shape_inference::Shape* out = c.output(i); + shape_inference::ShapeHandle out = c.output(i); string err_prefix = strings::StrCat("Output ", i); string err_suffix = strings::StrCat("; output shape was ", c.DebugString(out)); - const int in_index = gtl::FindWithDefault(shape_to_input_idx, out, -1); + int in_index = -1; + for (int i = 0; i < c.num_inputs(); ++i) { + if (c.input(i).SameHandle(out)) { + in_index = i; + } + } + if (expected.starts_with("in")) { if (in_index == -1) { return Unknown(err_prefix, " did not match any input shape", @@ -120,9 +114,18 @@ Status InferShapes(ShapeInferenceTestOp op, const string& ins, for (int j = 0; j < expected_dims.size(); ++j) { err_prefix = strings::StrCat("Output dim ", i, ",", j); StringPiece expected_dim(expected_dims[j]); - const Dimension* out_dim = c.Dim(out, j); - std::pair in_dim_idx = gtl::FindWithDefault( - dim_to_input_and_dim_idx, out_dim, std::make_pair(-1, -1)); + DimensionHandle out_dim = c.Dim(out, j); + + std::pair in_dim_idx(-1, -1); + for (int i = 0; i < c.num_inputs(); ++i) { + auto in = c.input(i); + for (int j = 0; j < c.Rank(in); ++j) { + if (c.Dim(in, j).SameHandle(out_dim)) { + in_dim_idx = std::make_pair(i, j); + } + } + } + if (expected_dim == "?") { if (in_dim_idx.first != -1) { return Unknown(err_prefix, @@ -167,4 +170,5 @@ Status InferShapes(ShapeInferenceTestOp op, const string& ins, return Status::OK(); } +} // namespace shape_inference } // namespace tensorflow diff --git a/tensorflow/core/framework/shape_inference_testutil.h b/tensorflow/core/framework/shape_inference_testutil.h index b4561496c5ce95dbaed6263082e39d37ed107374..b5d187405adf139ac7530c2445ddf9de4c2163ed 100644 --- a/tensorflow/core/framework/shape_inference_testutil.h +++ b/tensorflow/core/framework/shape_inference_testutil.h @@ -35,39 +35,56 @@ struct ShapeInferenceTestOp { std::vector input_tensors; }; -// Run shape inference for , given inputs specified by -// and returns an error if the inferred shape does not match expected_outs. -// -// is a semicolon separated list of shapes. Each shape is formatted -// according to the formatting per -// shape_inference::InferenceContext::InferenceContext. -// -// is a semicolon separated list of shapes. Each shape is -// formatted as one of: -// * ? - an unknown shape, but not matching an input shape -// * in0|in2|... - output shape must be the same as one of these input shapes. -// * [1,?,d0_0|d0_1] - output shape is of known rank, with comma-separated -// dimension values. -// Each dimension value is one of: -// * a constant, which means that constant not equal to a specific input -// * ?, which means an unknown dim size not equal to a specific input -// * d0_0|d1_2, indicating that the dim size must be equal to one of -// the given input dimensions; the first number is the input # and -// the second is which dimension in that input it corresponds to. -// can be "e"; this is used to indicate that shape inference -// should have failed. -Status InferShapes(ShapeInferenceTestOp op, const string& ins, - const string& expected_outs); +namespace shape_inference { -#define INFER_OK(op, i, o) EXPECT_EQ("", InferShapes(op, i, o).error_message()) -#define INFER_ERROR(error_substring, op, i) \ - { \ - string error_message = InferShapes(op, i, "e").error_message(); \ - const string& substring = error_substring; \ - EXPECT_NE("", error_message); \ - EXPECT_TRUE(StringPiece(error_message).contains(substring)) \ - << "Expected to see '" << substring << "' in '" << error_message \ - << "'"; \ +class ShapeInferenceTestutil { + public: + // Run shape inference for , given inputs specified by + // and returns an error if the inferred shape does not match expected_outs. + // + // is a semicolon separated list of shapes. Each shape is formatted + // according to the formatting per + // shape_inference::InferenceContext::InferenceContext. + // + // is a semicolon separated list of shapes. Each shape is + // formatted as one of: + // * ? - an unknown shape, but not matching an input shape + // * in0|in2|... - output shape must be the same as one of these input shapes. + // * [1,?,d0_0|d0_1] - output shape is of known rank, with comma-separated + // dimension values. + // Each dimension value is one of: + // * a constant, which means that constant not equal to a specific input + // * ?, which means an unknown dim size not equal to a specific input + // * d0_0|d1_2, indicating that the dim size must be equal to one of + // the given input dimensions; the first number is the input # and + // the second is which dimension in that input it corresponds to. + // can be "e"; this is used to indicate that shape inference + // should have failed. + static Status InferShapes(ShapeInferenceTestOp op, const string& ins, + const string& expected_outs); + + private: + ShapeInferenceTestutil() {} +}; + +} // namespace shape_inference + +#define INFER_OK(op, i, o) \ + EXPECT_EQ( \ + "", ::tensorflow::shape_inference::ShapeInferenceTestutil::InferShapes( \ + op, i, o) \ + .error_message()) +#define INFER_ERROR(error_substring, op, i) \ + { \ + string error_message = \ + ::tensorflow::shape_inference::ShapeInferenceTestutil::InferShapes( \ + op, i, "e") \ + .error_message(); \ + const string& substring = error_substring; \ + EXPECT_NE("", error_message); \ + EXPECT_TRUE(StringPiece(error_message).contains(substring)) \ + << "Expected to see '" << substring << "' in '" << error_message \ + << "'"; \ } } // namespace tensorflow diff --git a/tensorflow/core/framework/shape_inference_testutil_test.cc b/tensorflow/core/framework/shape_inference_testutil_test.cc index 4d6d5858b4afa5613a1e144017027169cda09ed7..61a8f8c9c2749dbcade987c283c442e68f1163d3 100644 --- a/tensorflow/core/framework/shape_inference_testutil_test.cc +++ b/tensorflow/core/framework/shape_inference_testutil_test.cc @@ -21,9 +21,7 @@ limitations under the License. #include "tensorflow/core/platform/test.h" namespace tensorflow { - -using shape_inference::InferenceContext; -static constexpr auto kUnknownDim = InferenceContext::kUnknownDim; +namespace shape_inference { namespace { @@ -54,7 +52,8 @@ string RunInferShapes(const string& op_name, const string& ins, .Attr("N", num_inputs) .Finalize(&op.node_def)); global_fn_ptr = &fn; - return InferShapes(op, ins, expected_outs).error_message(); + return ShapeInferenceTestutil::InferShapes(op, ins, expected_outs) + .error_message(); } } // namespace @@ -79,7 +78,7 @@ TEST(ShapeInferenceTestutilTest, Failures) { return Status::OK(); }; auto fn_output_u_2 = [](InferenceContext* c) { - c->set_output(0, c->Matrix(kUnknownDim, 2)); + c->set_output(0, c->Matrix(InferenceContext::kUnknownDim, 2)); return Status::OK(); }; const string& op = "OpOneOut"; @@ -88,9 +87,10 @@ TEST(ShapeInferenceTestutilTest, Failures) { RunInferShapes(op, "[1];[2];[1]", "e", fn_copy_input_0)); EXPECT_EQ("Wrong number of expected outputs (2 vs 1)", RunInferShapes(op, "[1];[2];[1]", "[1];[2]", fn_copy_input_0)); - EXPECT_EQ( - "Op type not registered 'NoSuchOp'", - InferShapes(ShapeInferenceTestOp("NoSuchOp"), "", "").error_message()); + EXPECT_EQ("Op type not registered 'NoSuchOp'", + ShapeInferenceTestutil::InferShapes( + ShapeInferenceTestOp("NoSuchOp"), "", "") + .error_message()); // Wrong shape error messages. EXPECT_EQ( @@ -176,4 +176,5 @@ TEST(ShapeInferenceTestutilTest, Failures) { RunInferShapes(op, ins, "[d0_1,2,?,d0_0|d2_0]", fn)); } +} // namespace shape_inference } // namespace tensorflow diff --git a/tensorflow/core/framework/tensor.cc b/tensorflow/core/framework/tensor.cc index 6361791cb0096498a5863e7ba04f05d00b3244cc..c6c5aab4764769c2ec5d7390228acef89b73c338 100644 --- a/tensorflow/core/framework/tensor.cc +++ b/tensorflow/core/framework/tensor.cc @@ -740,7 +740,7 @@ string Tensor::SummarizeValue(int64 max_entries) const { string ret; // TODO(irving): Don't call flat every time around this // loop. - for (int64 i = 0; i < limit; ++i) { + for (size_t i = 0; i < limit; ++i) { if (i > 0) strings::StrAppend(&ret, " "); switch (dtype()) { case DT_STRING: diff --git a/tensorflow/core/framework/tensor_slice.cc b/tensorflow/core/framework/tensor_slice.cc index f5f8c8d3e971dd2ea8eda4f40dad4b987cadebd7..c98ef1353549a65ebf76e7470f30d926d0ec5614 100644 --- a/tensorflow/core/framework/tensor_slice.cc +++ b/tensorflow/core/framework/tensor_slice.cc @@ -82,6 +82,13 @@ void TensorSlice::Clear() { lengths_.clear(); } +bool TensorSlice::IsFull() const { + for (int d = 0; d < dims(); ++d) { + if (!IsFullAt(d)) return false; + } + return true; +} + void TensorSlice::SetFullSlice(int dim) { Clear(); starts_.reserve(dim); diff --git a/tensorflow/core/framework/tensor_slice.h b/tensorflow/core/framework/tensor_slice.h index 2ccb4d10839287f496d7d580ec57ecd12e2ac176..8c4a2adeb37d96d045e05fcf672f01d682e1e670 100644 --- a/tensorflow/core/framework/tensor_slice.h +++ b/tensorflow/core/framework/tensor_slice.h @@ -96,6 +96,9 @@ class TensorSlice { // If we have a full slice along dimension "d". bool IsFullAt(int d) const { return lengths_[d] < 0; } + // If this is a full slice, i.e. IsFullAt(d) for every d. + bool IsFull() const; + // Set the slice to be a full slice of "dim" dimensions void SetFullSlice(int dim); diff --git a/tensorflow/core/framework/tensor_slice_test.cc b/tensorflow/core/framework/tensor_slice_test.cc index a88a4443583af3ffa8288f6ebfd7179f844b6251..e26c840998095ff52f14fdb903b1840f903329f1 100644 --- a/tensorflow/core/framework/tensor_slice_test.cc +++ b/tensorflow/core/framework/tensor_slice_test.cc @@ -29,9 +29,11 @@ TEST(TensorSliceTest, Basic) { // Repeatedly setting FullSlice should work. TensorSlice s(3); EXPECT_EQ("-:-:-", s.DebugString()); + EXPECT_TRUE(s.IsFull()); s.SetFullSlice(4); EXPECT_EQ("-:-:-:-", s.DebugString()); + EXPECT_TRUE(s.IsFull()); } } @@ -41,6 +43,7 @@ TEST(TensorSliceTest, Serialization) { { TensorSlice s({{0, -1}, {0, 10}, {14, 1}, {0, -1}}); EXPECT_EQ("-:0,10:14,1:-", s.DebugString()); + EXPECT_TRUE(!s.IsFull()); } { @@ -58,6 +61,7 @@ TEST(TensorSliceTest, Serialization) { ASSERT_TRUE(protobuf::TextFormat::ParseFromString(ptxt, &proto)); TensorSlice s(proto); EXPECT_EQ("-:0,10:14,1:-", s.DebugString()); + EXPECT_TRUE(!s.IsFull()); } // Parsing @@ -71,6 +75,7 @@ TEST(TensorSliceTest, Serialization) { "extent { start: 1 length: 3 } " "extent { start: 4 length: 5 }", proto.ShortDebugString()); + EXPECT_TRUE(!s.IsFull()); } // Failed parsing @@ -102,6 +107,7 @@ TEST(TensorSliceTest, Serialization) { EXPECT_EQ( "extent { start: 9223372036854775807 length: 9223372036854775807 }", proto.ShortDebugString()); + EXPECT_TRUE(!s.IsFull()); } // int64 parsing failure @@ -282,5 +288,16 @@ TEST(TensorSliceTest, UpdateToCover) { EXPECT_EQ("-:-:2,8", s.DebugString()); } +TEST(TensorSliceTest, IsFull) { + TensorSlice slice(3); + EXPECT_TRUE(slice.IsFull()); + + TensorSlice slice2({{0, -1}}); + EXPECT_TRUE(slice2.IsFull()); + + TensorSlice slice3({{0, -1}, {0, -1}, {14, 1}}); + EXPECT_TRUE(!slice3.IsFull()); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/core/framework/tensor_testutil.cc b/tensorflow/core/framework/tensor_testutil.cc index e307d2526819b2e108b91a9257816b007b911d4b..a8d141230093152397c792588a716c00556df77d 100644 --- a/tensorflow/core/framework/tensor_testutil.cc +++ b/tensorflow/core/framework/tensor_testutil.cc @@ -22,7 +22,7 @@ namespace test { template bool IsClose(const T& x, const T& y, double atol, double rtol) { // Need x == y so that infinities are close to themselves - return x == y || fabs(x - y) < atol + rtol * fabs(x); + return x == y || std::abs(x - y) < atol + rtol * std::abs(x); } template @@ -34,7 +34,7 @@ void ExpectClose(const Tensor& x, const Tensor& y, double atol, double rtol) { LOG(ERROR) << "x = " << x.DebugString(); LOG(ERROR) << "y = " << y.DebugString(); LOG(ERROR) << "atol = " << atol << " rtol = " << rtol - << " tol = " << atol + rtol * std::fabs(Tx(i)); + << " tol = " << atol + rtol * std::abs(Tx(i)); EXPECT_TRUE(false) << i << "-th element is not close " << Tx(i) << " vs. " << Ty(i); } @@ -50,6 +50,12 @@ void ExpectClose(const Tensor& x, const Tensor& y, double atol, double rtol) { case DT_DOUBLE: ExpectClose(x, y, atol, rtol); break; + case DT_COMPLEX64: + ExpectClose(x, y, atol, rtol); + break; + case DT_COMPLEX128: + ExpectClose(x, y, atol, rtol); + break; default: LOG(FATAL) << "Unexpected type : " << DataTypeString(x.dtype()); } diff --git a/tensorflow/core/framework/types.proto b/tensorflow/core/framework/types.proto index 051361bbed257a1867327f0b06cb7231084e2d52..c744594a49f0588d461e2bd1c4774b17b17713b1 100644 --- a/tensorflow/core/framework/types.proto +++ b/tensorflow/core/framework/types.proto @@ -6,6 +6,7 @@ option java_outer_classname = "TypesProtos"; option java_multiple_files = true; option java_package = "org.tensorflow.framework"; +// LINT.IfChange enum DataType { // Not a legal value for DataType. Used to indicate a DataType field // has not been set. @@ -58,3 +59,4 @@ enum DataType { DT_COMPLEX128_REF = 118; DT_HALF_REF = 119; } +// LINT.ThenChange(https://www.tensorflow.org/code/tensorflow/c/c_api.h,https://www.tensorflow.org/code/tensorflow/go/tensor.go) diff --git a/tensorflow/core/graph/graph.cc b/tensorflow/core/graph/graph.cc index a47fd89975979bed2fbca709fb7fbf27c43285b1..648f4396074eff544e65218d4219a56680570c14 100644 --- a/tensorflow/core/graph/graph.cc +++ b/tensorflow/core/graph/graph.cc @@ -46,8 +46,6 @@ Node::Node() : id_(-1), cost_id_(-1), class_(NC_UNINITIALIZED), - is_host_send_(false), - is_host_recv_(false), props_(nullptr), assigned_device_name_() {} @@ -89,8 +87,10 @@ void Node::Initialize(int id, int cost_id, Properties* props) { SET_CLASS(NC_NEXT_ITERATION, ts, "NextIteration", "RefNextIteration"); SET_CLASS(NC_LOOP_COND, ts, "LoopCond", ""); SET_CLASS(NC_CONTROL_TRIGGER, ts, "ControlTrigger", ""); - SET_CLASS(NC_SEND, ts, "_Send", "_HostSend"); - SET_CLASS(NC_RECV, ts, "_Recv", "_HostRecv"); + SET_CLASS(NC_SEND, ts, "_Send", ""); + SET_CLASS(NC_HOST_SEND, ts, "_HostSend", ""); + SET_CLASS(NC_RECV, ts, "_Recv", ""); + SET_CLASS(NC_HOST_RECV, ts, "_HostRecv", ""); SET_CLASS(NC_CONSTANT, ts, "Const", "HostConst"); SET_CLASS(NC_VARIABLE, ts, "Variable", ""); SET_CLASS(NC_IDENTITY, ts, "Identity", "RefIdentity"); @@ -101,12 +101,6 @@ void Node::Initialize(int id, int cost_id, Properties* props) { class_ = NC_OTHER; // Catch all } #undef SET_CLASS - - if (ts == "_HostSend") { - is_host_send_ = true; - } else if (ts == "_HostRecv") { - is_host_recv_ = true; - } } void Node::Clear() { @@ -150,6 +144,43 @@ void Node::ClearAttr(const string& name) { (*props_->node_def_.mutable_attr()).erase(name); } +Status Node::input_edge(int idx, const Edge** e) const { + if (idx < 0 || idx >= num_inputs()) { + return errors::InvalidArgument("Invalid input_edge index: ", idx, ", Node ", + name(), " only has ", num_inputs(), + " inputs."); + } + + // This does a linear search over the edges. In the common case, + // the number of elements is small enough that this search isn't + // expensive. Should it become a bottleneck, one can make an + // optimization where, if the number of edges is small, we use + // linear iteration, and if the number of edges is large, we perform + // an indexing step during construction that keeps an array of Edges + // indexed by pointer. This would keep the size of each Node small + // in the common case but make this function faster when the number + // of edges is large. + for (const Edge* edge : in_edges()) { + if (edge->dst_input() == idx) { + *e = edge; + return Status::OK(); + } + } + + return errors::NotFound("Could not find input edge ", idx, " for ", name()); +} + +Status Node::input_node(int idx, const Node** n) const { + const Edge* e; + TF_RETURN_IF_ERROR(input_edge(idx, &e)); + if (e == nullptr) { + *n = nullptr; + } else { + *n = e->src(); + } + return Status::OK(); +} + // Node::Properties Node::Properties::Properties(const OpDef* op_def, const NodeDef& node_def, diff --git a/tensorflow/core/graph/graph.h b/tensorflow/core/graph/graph.h index 3dc80a07a45805b8f59938c28ac1852902ccfb32..6bf88984c9258327b0bc5344dd8f47ad620ed64e 100644 --- a/tensorflow/core/graph/graph.h +++ b/tensorflow/core/graph/graph.h @@ -106,30 +106,30 @@ class Node { bool IsOp() const { return id() > 1; } // Node class helpers - bool IsSwitch() const { return (class_ == NC_SWITCH); } - bool IsMerge() const { return (class_ == NC_MERGE); } - bool IsEnter() const { return (class_ == NC_ENTER); } - bool IsExit() const { return (class_ == NC_EXIT); } - bool IsNextIteration() const { return (class_ == NC_NEXT_ITERATION); } - bool IsLoopCond() const { return (class_ == NC_LOOP_COND); } - bool IsControlTrigger() const { return (class_ == NC_CONTROL_TRIGGER); } - bool IsSend() const { return (class_ == NC_SEND); } - bool IsRecv() const { return (class_ == NC_RECV); } - bool IsConstant() const { return (class_ == NC_CONSTANT); } - bool IsVariable() const { return (class_ == NC_VARIABLE); } - bool IsIdentity() const { return (class_ == NC_IDENTITY); } - bool IsGetSessionHandle() const { return (class_ == NC_GET_SESSION_HANDLE); } - bool IsGetSessionTensor() const { return (class_ == NC_GET_SESSION_TENSOR); } + bool IsSwitch() const { return class_ == NC_SWITCH; } + bool IsMerge() const { return class_ == NC_MERGE; } + bool IsEnter() const { return class_ == NC_ENTER; } + bool IsExit() const { return class_ == NC_EXIT; } + bool IsNextIteration() const { return class_ == NC_NEXT_ITERATION; } + bool IsLoopCond() const { return class_ == NC_LOOP_COND; } + bool IsControlTrigger() const { return class_ == NC_CONTROL_TRIGGER; } + bool IsSend() const { return class_ == NC_SEND || class_ == NC_HOST_SEND; } + bool IsRecv() const { return class_ == NC_RECV || class_ == NC_HOST_RECV; } + bool IsConstant() const { return class_ == NC_CONSTANT; } + bool IsVariable() const { return class_ == NC_VARIABLE; } + bool IsIdentity() const { return class_ == NC_IDENTITY; } + bool IsGetSessionHandle() const { return class_ == NC_GET_SESSION_HANDLE; } + bool IsGetSessionTensor() const { return class_ == NC_GET_SESSION_TENSOR; } bool IsDeleteSessionTensor() const { - return (class_ == NC_DELETE_SESSION_TENSOR); + return class_ == NC_DELETE_SESSION_TENSOR; } bool IsControlFlow() const { return (class_ != NC_OTHER) && // Fast path (IsSwitch() || IsMerge() || IsEnter() || IsExit() || IsNextIteration()); } - bool IsHostSend() const { return is_host_send_; } - bool IsHostRecv() const { return is_host_recv_; } + bool IsHostSend() const { return class_ == NC_HOST_SEND; } + bool IsHostRecv() const { return class_ == NC_HOST_RECV; } template void AddAttr(const string& name, const T& val) { @@ -139,6 +139,13 @@ class Node { void ClearAttr(const string& name); + // Returns into '*e' the edge connecting to the 'idx' input of this Node. + Status input_edge(int idx, const Edge** e) const; + + // Returns into '*n' the node that has an output connected to the + // 'idx' input of this Node. + Status input_node(int idx, const Node** n) const; + private: friend class Graph; Node(); @@ -187,7 +194,9 @@ class Node { NC_LOOP_COND, NC_CONTROL_TRIGGER, NC_SEND, + NC_HOST_SEND, NC_RECV, + NC_HOST_RECV, NC_CONSTANT, NC_VARIABLE, NC_IDENTITY, @@ -200,8 +209,6 @@ class Node { int id_; // -1 until Initialize() is called int cost_id_; // -1 if there is no corresponding cost accounting node NodeClass class_; - bool is_host_send_; - bool is_host_recv_; EdgeSet in_edges_; EdgeSet out_edges_; diff --git a/tensorflow/core/graph/graph_test.cc b/tensorflow/core/graph/graph_test.cc index 1ae3ba545410b4e0888b11aa5fea85bd1eda7f46..e42e3d2bcd3f0b74770a546b49e083140f8b5b70 100644 --- a/tensorflow/core/graph/graph_test.cc +++ b/tensorflow/core/graph/graph_test.cc @@ -20,6 +20,7 @@ limitations under the License. #include "tensorflow/core/graph/graph_constructor.h" #include "tensorflow/core/graph/node_builder.h" #include "tensorflow/core/kernels/ops_util.h" +#include "tensorflow/core/lib/core/status_test_util.h" #include "tensorflow/core/lib/random/simple_philox.h" #include "tensorflow/core/lib/strings/stringprintf.h" #include "tensorflow/core/platform/logging.h" @@ -30,6 +31,20 @@ limitations under the License. namespace tensorflow { namespace { +REGISTER_OP("OneInput").Input("x: float"); + +REGISTER_OP("OneOutput").Output("y: float"); + +REGISTER_OP("OneInputTwoOutputs") + .Input("x: float") + .Output("y: float") + .Output("z: float"); + +REGISTER_OP("TwoInputsOneOutput") + .Input("x: float") + .Input("y: float") + .Output("z: float"); + class GraphTest : public ::testing::Test { protected: GraphTest() : graph_(OpRegistry::Global()) {} @@ -71,6 +86,22 @@ class GraphTest : public ::testing::Test { return node; } + Node* FromNodeDef(const string& name, const string& node_type, + int num_inputs) { + auto builder = NodeDefBuilder(name, node_type); + for (int i = 0; i < num_inputs; ++i) { + builder = builder.Input(strings::StrCat("node_", i), i, DT_FLOAT); + } + + NodeDef node_def; + TF_CHECK_OK(builder.Finalize(&node_def)); + + Status s; + Node* node = graph_.AddNode(node_def, &s); + TF_CHECK_OK(s); + return node; + } + Graph graph_; private: @@ -112,9 +143,9 @@ TEST_F(GraphTest, RemoveThenAdd) { } TEST_F(GraphTest, InNodesAndOutNodes) { - Node* a = AddNodeWithName("A"); + Node* a = FromNodeDef("A", "OneOutput", 0); Node* b = AddNodeWithName("B"); - Node* c = AddNodeWithName("C"); + Node* c = FromNodeDef("C", "OneInput", 1); graph_.RemoveNode(b); Node* d = AddNodeWithName("D"); @@ -147,11 +178,75 @@ TEST_F(GraphTest, InNodesAndOutNodes) { VerifyGraphStats(); } +TEST_F(GraphTest, NodeByIndex) { + Node* a = FromNodeDef("A", "OneOutput", 0); + Node* c = FromNodeDef("C", "OneInput", 1); + graph_.AddEdge(a, 0, c, 0); + + // Ask for 'a' from 'c' by index. + const Node* a_copy; + TF_ASSERT_OK(c->input_node(0, &a_copy)); + EXPECT_EQ(a, a_copy); + + const Edge* e; + TF_ASSERT_OK(c->input_edge(0, &e)); + EXPECT_EQ(0, e->dst_input()); + EXPECT_EQ(a, e->src()); + EXPECT_EQ(c, e->dst()); + EXPECT_EQ(0, e->src_output()); + + Node* t = FromNodeDef("T", "TwoInputsOneOutput", 2); + graph_.AddEdge(a, 0, t, 0); + // Weird self edge + graph_.AddEdge(t, 0, t, 1); + + const Node* t_0; + const Node* t_1; + TF_ASSERT_OK(t->input_node(0, &t_0)); + EXPECT_EQ(a, t_0); + TF_ASSERT_OK(t->input_node(1, &t_1)); + EXPECT_EQ(t, t_1); + + TF_ASSERT_OK(t->input_edge(1, &e)); + EXPECT_EQ(1, e->dst_input()); + EXPECT_EQ(t, e->src()); + + // Check out of bounds access + EXPECT_FALSE(c->input_node(1, &a_copy).ok()); + EXPECT_FALSE(c->input_node(-1, &a_copy).ok()); + + graph_.RemoveNode(a); + + // 'c's input_node entry should be invalidated. + Status s = c->input_node(0, &a_copy); + EXPECT_FALSE(s.ok()); + + // Add two new nodes. + Node* a_new = FromNodeDef("A_new", "OneOutput", 0); + Node* b_new = FromNodeDef("B_new", "OneOutput", 0); + + // Connect one up to c. + graph_.AddEdge(a_new, 0, c, 0); + const Edge* a_new_c_edge; + TF_ASSERT_OK(c->input_edge(0, &a_new_c_edge)); + + // Connect up the second edge + graph_.AddEdge(b_new, 0, c, 0); + const Edge* b_new_c_edge; + TF_ASSERT_OK(c->input_edge(0, &b_new_c_edge)); + + // Now remove the old one + graph_.RemoveEdge(a_new_c_edge); + + // Check that the second edge can still be retrieved + TF_ASSERT_OK(c->input_edge(0, &b_new_c_edge)); +} + TEST_F(GraphTest, NodeIteration) { // Set up the graph with some holes due to removals. - Node* a = AddNodeWithName("A"); + Node* a = FromNodeDef("A", "OneOutput", 0); Node* b = AddNodeWithName("B"); - Node* c = AddNodeWithName("C"); + Node* c = FromNodeDef("C", "OneInput", 1); graph_.RemoveNode(b); Node* d = AddNodeWithName("D"); const Edge* source_to_a = graph_.AddControlEdge(graph_.source_node(), a); @@ -245,8 +340,8 @@ static string EdgeIter(const Graph& g) { TEST_F(GraphTest, EdgeIteration) { EXPECT_EQ("0->1;", EdgeIter(graph_)); - Node* a = AddNodeWithName("A"); - Node* b = AddNodeWithName("B"); + Node* a = FromNodeDef("A", "OneInputTwoOutputs", 1); + Node* b = FromNodeDef("B", "OneInput", 1); EXPECT_EQ("0->1;", EdgeIter(graph_)); // Since a,b are currently disconnected graph_.AddEdge(a, 0, b, 0); diff --git a/tensorflow/core/graph/shape_refiner.cc b/tensorflow/core/graph/shape_refiner.cc new file mode 100644 index 0000000000000000000000000000000000000000..e45e4e0d633ffab38df8ab5623187697ba7b1889 --- /dev/null +++ b/tensorflow/core/graph/shape_refiner.cc @@ -0,0 +1,279 @@ +/* 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. +==============================================================================*/ +#include "tensorflow/core/graph/shape_refiner.h" + +#include +#include + +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/gtl/stl_util.h" + +namespace tensorflow { + +ShapeRefiner::ShapeRefiner() {} +ShapeRefiner::~ShapeRefiner() { gtl::STLDeleteValues(&node_to_context_); } + +Status ShapeRefiner::AddNode(const Node* node) { + // For each 'input' of this node, fetch the corresponding shape + // from 'input's InferenceContext, and store into a vector + // indexed by 'node's input. + std::vector input_nodes(node->num_inputs()); + std::vector input_shapes(node->num_inputs()); + for (const Edge* e : node->in_edges()) { + if (e->IsControlEdge()) continue; + + const Node* input = e->src(); + auto it = node_to_context_.find(input); + if (it == node_to_context_.end()) { + return errors::FailedPrecondition( + "Input ", e->dst_input(), " ('", input->name(), "') for '", + node->name(), "' was not previously added to ShapeRefiner."); + } + + shape_inference::InferenceContext* c = it->second; + DCHECK_GE(e->dst_input(), 0); + input_nodes[e->dst_input()] = input; + input_shapes[e->dst_input()] = c->output(e->src_output()); + } + + // Get the shape function for this node + const OpRegistrationData* op_reg_data; + // TODO(vrv): Take in the OpRegistryInterface* instead of taking + // the global one. + TF_RETURN_IF_ERROR( + OpRegistry::Global()->LookUp(node->type_string(), &op_reg_data)); + if (op_reg_data->shape_inference_fn == nullptr) { + return errors::InvalidArgument( + "No shape inference function exists for op '", node->type_string(), + "', did you forget to define it?"); + } + + // This needs to be filled in with real data in a second pass. + std::vector input_tensors(node->num_inputs()); + std::vector real_tensors(node->num_inputs()); + std::vector attempted_materialization(node->num_inputs()); + + // Create the inference context for this node with the existing input shapes. + std::unique_ptr c( + new shape_inference::InferenceContext(&node->def(), node->op_def(), + {} /* input_shapes_string */, + input_shapes, input_tensors)); + if (!c->construction_status().ok()) { + return c->construction_status(); + } + + // Run the shape inference function, and return if there was an error. + TF_RETURN_IF_ERROR(op_reg_data->shape_inference_fn(c.get())); + + // We must run the shape function repeatedly, in case users write + // shape functions where they only conditionally call input_tensor() + // based on the values of another input tensor. + bool rerun_shape_fn; + do { + // If the result of running shape inference would have benefitted + // from knowing the values of input tensors, try to materialize + // the results of those tensors, and then run the shape inference + // function again using those known tensors. + rerun_shape_fn = false; + for (int i = 0; i < c->num_inputs(); ++i) { + // Check if we have not already filled in the requested input, + // and if not, try to materialize the tensors. + if (c->requested_input_tensor(i) && !attempted_materialization[i]) { + rerun_shape_fn = true; + attempted_materialization[i] = true; + TF_RETURN_IF_ERROR( + ConstantValue(input_nodes[i], &real_tensors[i], &input_tensors[i])); + } + } + + if (rerun_shape_fn) { + // We have more information about the shapes on this pass, + // so re-run shape inference. + c->set_input_tensors(input_tensors); + TF_RETURN_IF_ERROR(op_reg_data->shape_inference_fn(c.get())); + } + } while (rerun_shape_fn); + + // Store the resulting InferenceContext object in the map. + node_to_context_[node] = c.release(); + + return Status::OK(); +} + +Status ShapeRefiner::ConstantValue(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + *input_tensor = nullptr; + // For now, we do a simple static analysis of the graph to + // materialize those tensors, but in the future, we should try to do + // a partial evaluation of the graph. + + // TODO(vrv): Handle other types of nodes, like we do in python: + // Cast, Concat, Pack. These require re-implementing the core + // kernels themselves, and we may want to switch this to partial + // evaluation instead of implementing these again. + if (node->IsConstant()) { + return Constant(node, tensor_storage, input_tensor); + } + if (node->type_string() == "Shape") { + return Shape(node, tensor_storage, input_tensor); + } + if (node->type_string() == "Size") { + return Size(node, tensor_storage, input_tensor); + } + if (node->type_string() == "Rank") { + return Rank(node, tensor_storage, input_tensor); + } + if (node->type_string() == "Range") { + return Range(node, tensor_storage, input_tensor); + } + + return Status::OK(); +} + +Status ShapeRefiner::Constant(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + TF_RETURN_IF_ERROR(GetNodeAttr(node->def(), "value", tensor_storage)); + *input_tensor = tensor_storage; + return Status::OK(); +} + +Status ShapeRefiner::Shape(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + // Get the input to the node. + const Node* shape_node; + TF_RETURN_IF_ERROR(node->input_node(0, &shape_node)); + auto ic = GetContext(shape_node); + if (!ic) { + return errors::Internal("Could not find InferenceContext for ", + shape_node->name()); + } + shape_inference::ShapeHandle input_shape = ic->output(0); + if (ic->FullyDefined(input_shape)) { + *tensor_storage = Tensor(DT_INT32, {ic->Rank(input_shape)}); + for (int i = 0; i < ic->Rank(input_shape); ++i) { + int64 dim = ic->Value(ic->Dim(input_shape, i)); + if (dim > std::numeric_limits::max()) { + // The output of Shape is 32-bits, so we cannot fill in anything + // here. See b/28119922. + return Status::OK(); + } + + tensor_storage->vec()(i) = dim; + } + *input_tensor = tensor_storage; + } + + return Status::OK(); +} + +Status ShapeRefiner::Size(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + // Get the input to the node. + const Node* size_node; + TF_RETURN_IF_ERROR(node->input_node(0, &size_node)); + auto ic = GetContext(size_node); + if (!ic) { + return errors::Internal("Could not find InferenceContext for ", + size_node->name()); + } + auto num_elements = ic->NumElements(ic->output(0)); + if (ic->ValueKnown(num_elements)) { + *tensor_storage = Tensor(DT_INT32, {}); + int64 ne = ic->Value(num_elements); + if (ne > std::numeric_limits::max()) { + // The output of Size is 32-bits, so we cannot fill in anything + // here. See b/28119922. + return Status::OK(); + } + tensor_storage->scalar()() = ic->Value(num_elements); + *input_tensor = tensor_storage; + } + + return Status::OK(); +} + +Status ShapeRefiner::Rank(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + // Get the input to the node. + const Node* rank_node; + TF_RETURN_IF_ERROR(node->input_node(0, &rank_node)); + auto ic = GetContext(rank_node); + if (!ic) { + return errors::Internal("Could not find InferenceContext for ", + rank_node->name()); + } + + if (ic->RankKnown(ic->output(0))) { + int32 rank = ic->Rank(ic->output(0)); + *tensor_storage = Tensor(DT_INT32, {}); + tensor_storage->scalar()() = rank; + *input_tensor = tensor_storage; + } + + return Status::OK(); +} + +Status ShapeRefiner::Range(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const { + const Node* start_node; + TF_RETURN_IF_ERROR(node->input_node(0, &start_node)); + const Node* limit_node; + TF_RETURN_IF_ERROR(node->input_node(1, &limit_node)); + const Node* delta_node; + TF_RETURN_IF_ERROR(node->input_node(2, &delta_node)); + + const Tensor* start_node_tensor; + TF_RETURN_IF_ERROR( + ConstantValue(start_node, tensor_storage, &start_node_tensor)); + if (start_node_tensor == nullptr) return Status::OK(); + const int32 start = start_node_tensor->scalar()(); + + const Tensor* limit_node_tensor; + TF_RETURN_IF_ERROR( + ConstantValue(limit_node, tensor_storage, &limit_node_tensor)); + if (limit_node_tensor == nullptr) return Status::OK(); + const int32 limit = limit_node_tensor->scalar()(); + + const Tensor* delta_node_tensor; + TF_RETURN_IF_ERROR( + ConstantValue(delta_node, tensor_storage, &delta_node_tensor)); + if (delta_node_tensor == nullptr) return Status::OK(); + const int32 delta = delta_node_tensor->scalar()(); + + if (start > limit) { + return errors::InvalidArgument("Range requires start <= limit: ", start, + "/", limit); + } + + if (delta <= 0) { + return errors::InvalidArgument("Range requires delta > 0: ", delta); + } + + int32 size = (limit - start + delta - 1) / delta; + *tensor_storage = Tensor(DT_INT32, {size}); + + auto flat = tensor_storage->flat(); + int32 val = start; + for (int32 i = 0; i < size; ++i) { + flat(i) = val; + val += delta; + } + + *input_tensor = tensor_storage; + return Status::OK(); +} + +} // namespace tensorflow diff --git a/tensorflow/core/graph/shape_refiner.h b/tensorflow/core/graph/shape_refiner.h new file mode 100644 index 0000000000000000000000000000000000000000..21551903c0366b1bc408b7afae852c1a87646525 --- /dev/null +++ b/tensorflow/core/graph/shape_refiner.h @@ -0,0 +1,87 @@ +/* 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. +==============================================================================*/ +#ifndef THIRD_PARTY_TENSORFLOW_CORE_GRAPH_SHAPE_REFINER_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_GRAPH_SHAPE_REFINER_H_ + +#include + +#include "tensorflow/core/framework/shape_inference.h" +#include "tensorflow/core/graph/graph.h" +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/platform/macros.h" + +namespace tensorflow { + +// ShapeRefiner performs shape inference for TensorFlow Graphs. It is +// responsible for instantiating InferenceContext objects for each +// Node in the Graph, and providing/storing the 'input_tensor' Tensors +// used by Shape Inference functions, when available at graph +// construction time. +class ShapeRefiner { + public: + ShapeRefiner(); + ~ShapeRefiner(); + + // Performs validation of 'node' and runs 'node's shape function, + // storing its shape outputs. + // + // All inputs of 'node' must be added to ShapeRefiner prior to + // adding 'node'. + // + // Returns an error if: + // - the shape function for 'node' was not registered. + // - 'node' was added before its inputs. + // - The shape inference function returns an error. + Status AddNode(const Node* node); + + // Returns the InferenceContext for 'node', if present. + shape_inference::InferenceContext* GetContext(const Node* node) const { + auto it = node_to_context_.find(node); + if (it == node_to_context_.end()) { + return nullptr; + } + return it->second; + } + + private: + // Extracts the 'constant_value' of 'input_node' if possible. Uses + // 'tensor_storage' for storage and sets '*input_tensor' to + // 'tensor_storage' if a constant value could be extracted. + Status ConstantValue(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + + // Helper functions to extract the Tensor associated with 'node'. + Status Constant(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + Status Shape(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + Status Size(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + Status Rank(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + Status Range(const Node* node, Tensor* tensor_storage, + const Tensor** input_tensor) const; + // Stores a map from a node to its InferenceContext. + // + // Owns values. + std::unordered_map + node_to_context_; + + TF_DISALLOW_COPY_AND_ASSIGN(ShapeRefiner); +}; + +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_GRAPH_SHAPE_REFINER_H_ diff --git a/tensorflow/core/graph/shape_refiner_test.cc b/tensorflow/core/graph/shape_refiner_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..94cd6dc74a9a78ec39a8e047a7d32d324634a26f --- /dev/null +++ b/tensorflow/core/graph/shape_refiner_test.cc @@ -0,0 +1,305 @@ +/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "tensorflow/core/graph/shape_refiner.h" + +#include "tensorflow/cc/framework/scope.h" +#include "tensorflow/cc/ops/standard_ops.h" +#include "tensorflow/core/framework/common_shape_fns.h" +#include "tensorflow/core/graph/node_builder.h" +#include "tensorflow/core/graph/testlib.h" +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { +namespace { + +#define EXPECT_SHAPE(EXPECTED, M, OP, IDX) \ + do { \ + shape_inference::InferenceContext* ctx = M.GetContext(OP.node()); \ + EXPECT_EQ(EXPECTED, ctx->DebugString(ctx->output(IDX))); \ + } while (0); + +TEST(ShapeRefinerTest, Constant) { + // Create a constant node and validate that adding it is successful + // and that its shape is correct. + Scope root = Scope::NewRootScope(); + auto c = ops::Const(root, 42.0f); + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(c.node())); + + EXPECT_SHAPE("[]", m, c, 0); +} + +TEST(ShapeRefinerTest, MatMul) { + ShapeRefiner m; + + Scope root = Scope::NewRootScope(); + auto a = ops::Const(root, {{1.0f}, {2.0f}}); + auto b = ops::Const(root, {{1.0f, 2.0f}}); + auto mm = ops::MatMul(root, a, b); + + TF_ASSERT_OK(m.AddNode(a.node())); + TF_ASSERT_OK(m.AddNode(b.node())); + TF_ASSERT_OK(m.AddNode(mm.node())); + + EXPECT_SHAPE("[2,1]", m, a, 0); + EXPECT_SHAPE("[1,2]", m, b, 0); + EXPECT_SHAPE("[2,2]", m, mm, 0); +} + +TEST(ShapeRefinerTest, InvalidOrder) { + ShapeRefiner m; + Scope root = Scope::NewRootScope(); + auto a = ops::Const(root, {{1.0f}, {2.0f}}); + auto b = ops::Const(root, {{1.0f, 2.0f}}); + auto mm = ops::MatMul(root, a, b); + + Status s = m.AddNode(mm.node()); + ASSERT_FALSE(s.ok()); + ASSERT_EQ( + "Input 0 ('Const') for 'MatMul' was not previously added to " + "ShapeRefiner.", + s.error_message()); +} + +TEST(ShapeRefinerTest, BadShapes) { + ShapeRefiner m; + Scope root = Scope::NewRootScope(); + auto a = ops::Const(root, {{1.0f}, {2.0f}}); + auto b = ops::Const(root, {{1.0f}, {2.0f}}); + auto mm = ops::MatMul(root, a, b); + + TF_ASSERT_OK(m.AddNode(a.node())); + TF_ASSERT_OK(m.AddNode(b.node())); + // The shape of the inputs are not compatible, so we should expect + // an error. + Status s = m.AddNode(mm.node()); + ASSERT_FALSE(s.ok()); + ASSERT_EQ("Dimensions must be equal, but are 1 and 2", s.error_message()); +} + +TEST(ShapeRefinerTest, PropagateConstants) { + // Reduction dimension is a variable, so we don't know its value. + // So the output shape value is unknown (though its rank is known). + { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + // Reduce along unspecified dimension + auto dim = ops::Variable(root, {}, DT_INT32); + + auto am = ops::ArgMax(root, input, dim); + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(dim.node())); + TF_ASSERT_OK(m.AddNode(am.node())); + EXPECT_SHAPE("[?]", m, am, 0); + } + + // Constant is used as dimension, which can be materialized, + // so the shape function can be more precise about the output. + { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + // Reduce along 2nd dimension + auto dim = ops::Const(root, 1); + + auto am = ops::ArgMax(root, input, dim); + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(dim.node())); + TF_ASSERT_OK(m.AddNode(am.node())); + EXPECT_SHAPE("[3]", m, am, 0); + } + + // Reduce along known first dimension. + { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + // Reduce along 1st dimension + auto dim = ops::Const(root, 0); + + auto am = ops::ArgMax(root, input, dim); + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(dim.node())); + TF_ASSERT_OK(m.AddNode(am.node())); + EXPECT_SHAPE("[2]", m, am, 0); + } +} + +namespace { + +// An op with a shape function whose outputs depend in a complex +// way on whether input tensors are available. +REGISTER_OP("TestOp") + .Input("a: float") + .Input("b: float") + .Output("o: float") + .SetShapeFn([](shape_inference::InferenceContext* c) { + if (c->input_tensor(0)) { + if (c->input_tensor(1)) { + c->set_output(0, c->Matrix(10, 10)); + return Status::OK(); + } + return shape_inference::ScalarShape(c); + } + return shape_inference::UnknownShape(c); + }); + +} // namespace + +TEST(ShapeRefinerTest, InputTensorDependencies) { + ShapeRefiner m; + Graph graph(OpRegistry::Global()); + Node* node; + + Tensor a(DT_FLOAT, TensorShape({})); + a.scalar()() = 0.0; + + Tensor b(DT_FLOAT, TensorShape({})); + b.scalar()() = 0.0; + + Node* input_a = test::graph::Constant(&graph, a); + Node* input_b = test::graph::Constant(&graph, b); + TF_ASSERT_OK(NodeBuilder("Test", "TestOp") + .Input(input_a) + .Input(input_b) + .Finalize(&graph, &node)); + + TF_ASSERT_OK(m.AddNode(input_a)); + TF_ASSERT_OK(m.AddNode(input_b)); + TF_ASSERT_OK(m.AddNode(node)); + shape_inference::InferenceContext* ctx = m.GetContext(node); + EXPECT_EQ("[10,10]", ctx->DebugString(ctx->output(0))); +} + +namespace { + +// An op with a shape function that looks at its input tensor +// data and makes a Shape out of it. +REGISTER_OP("ShapeData") + .Input("a: int32") + .Output("o: int32") + .SetShapeFn([](shape_inference::InferenceContext* c) { + const Tensor* shape_data = c->input_tensor(0); + if (shape_data == nullptr) { + return shape_inference::UnknownShape(c); + } + + std::vector dims; + for (int i = 0; i < shape_data->NumElements(); ++i) { + dims.emplace_back(c->MakeDim(shape_data->flat()(i))); + } + + c->set_output(0, c->MakeShape(dims)); + return Status::OK(); + }); + +} // namespace + +TEST(ShapeRefinerTest, PropagateShape) { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + + // Shape is a vector of 2 elements (3,2) + auto shape = ops::Shape(root, input); + + Node* shape_data; + TF_ASSERT_OK(NodeBuilder("Test", "ShapeData") + .Input(shape.node()) + .Finalize(root.graph(), &shape_data)); + + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(shape.node())); + TF_ASSERT_OK(m.AddNode(shape_data)); + + shape_inference::InferenceContext* ctx = m.GetContext(shape_data); + EXPECT_EQ("[3,2]", ctx->DebugString(ctx->output(0))); +} + +TEST(ShapeRefinerTest, PropagateSize) { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + + auto size = ops::Size(root, input); + + Node* shape_data; + TF_ASSERT_OK(NodeBuilder("Test", "ShapeData") + .Input(size.node()) + .Finalize(root.graph(), &shape_data)); + + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(size.node())); + TF_ASSERT_OK(m.AddNode(shape_data)); + + shape_inference::InferenceContext* ctx = m.GetContext(shape_data); + EXPECT_EQ("[6]", ctx->DebugString(ctx->output(0))); +} + +TEST(ShapeRefinerTest, PropagateRank) { + Scope root = Scope::NewRootScope(); + // 3x2 input + auto input = ops::Const(root, {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); + + auto rank = ops::Rank(root, input); + + Node* shape_data; + TF_ASSERT_OK(NodeBuilder("Test", "ShapeData") + .Input(rank.node()) + .Finalize(root.graph(), &shape_data)); + + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(input.node())); + TF_ASSERT_OK(m.AddNode(rank.node())); + TF_ASSERT_OK(m.AddNode(shape_data)); + + shape_inference::InferenceContext* ctx = m.GetContext(shape_data); + EXPECT_EQ("[2]", ctx->DebugString(ctx->output(0))); +} + +TEST(ShapeRefinerTest, PropagateRange) { + Scope root = Scope::NewRootScope(); + auto begin = ops::Const(root, 1); + auto limit = ops::Const(root, 11); + auto delta = ops::Const(root, 3); + auto range = ops::Range(root, begin, limit, delta); + + Node* shape_data; + TF_ASSERT_OK(NodeBuilder("Test", "ShapeData") + .Input(range.node()) + .Finalize(root.graph(), &shape_data)); + + ShapeRefiner m; + TF_ASSERT_OK(m.AddNode(begin.node())); + TF_ASSERT_OK(m.AddNode(limit.node())); + TF_ASSERT_OK(m.AddNode(delta.node())); + TF_ASSERT_OK(m.AddNode(range.node())); + TF_ASSERT_OK(m.AddNode(shape_data)); + + shape_inference::InferenceContext* ctx = m.GetContext(shape_data); + EXPECT_EQ("[1,4,7,10]", ctx->DebugString(ctx->output(0))); +} + +} // namespace +} // namespace tensorflow diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD index e9f8f8cb4840344d7f67ed301f9e9a82441e7785..aeda266a70cbfd1673e07c18b820ad09b3f31e9f 100644 --- a/tensorflow/core/kernels/BUILD +++ b/tensorflow/core/kernels/BUILD @@ -1103,6 +1103,7 @@ tf_kernel_libraries( "aggregate_ops", "argmax_op", "batch_matmul_op", + "betainc_op", "cast_op", "check_numerics_op", "cross_op", diff --git a/tensorflow/core/kernels/betainc_op.cc b/tensorflow/core/kernels/betainc_op.cc new file mode 100644 index 0000000000000000000000000000000000000000..f625520374d2c55a97f743856e69fdc3eede5ca4 --- /dev/null +++ b/tensorflow/core/kernels/betainc_op.cc @@ -0,0 +1,169 @@ +/* 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. +==============================================================================*/ + +// See docs in ../ops/nn_ops.cc. + +#define EIGEN_USE_THREADS +// TODO(b/31098934): Figure out why this is necessary here but not in +// any other place, e.g., the cwise lgamma ops. +#define EIGEN_HAS_C99_MATH 1 + +#include "tensorflow/core/kernels/betainc_op.h" +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/core/framework/numeric_op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/util/bcast.h" + +namespace tensorflow { + +typedef Eigen::ThreadPoolDevice CPUDevice; +typedef Eigen::GpuDevice GPUDevice; + +template +class BetaincOp : public OpKernel { + public: + explicit BetaincOp(OpKernelConstruction* ctx) : OpKernel(ctx) {} + + void Compute(OpKernelContext* ctx) { + const Tensor& a = ctx->input(0); + const Tensor& b = ctx->input(1); + const Tensor& x = ctx->input(2); + + const TensorShape& a_shape = a.shape(); + const TensorShape& b_shape = b.shape(); + const TensorShape& x_shape = x.shape(); + if (a_shape.dims() > 0 && b_shape.dims() > 0) { + OP_REQUIRES(ctx, a_shape == b_shape, + errors::InvalidArgument( + "Shapes of a and b are inconsistent: ", + a_shape.DebugString(), " vs. ", b_shape.DebugString())); + } + if (a_shape.dims() > 0 && x_shape.dims() > 0) { + OP_REQUIRES(ctx, a_shape == x_shape, + errors::InvalidArgument( + "Shapes of a and x are inconsistent: ", + a_shape.DebugString(), " vs. ", x_shape.DebugString())); + } + if (b_shape.dims() > 0 && x_shape.dims() > 0) { + OP_REQUIRES(ctx, b_shape == x_shape, + errors::InvalidArgument( + "Shapes of b and x are inconsistent: ", + b_shape.DebugString(), " vs. ", x_shape.DebugString())); + } + + TensorShape merged_shape(a_shape); + if (b_shape.dims() > 0) merged_shape = b_shape; + if (x_shape.dims() > 0) merged_shape = x_shape; + + Tensor* output = nullptr; + OP_REQUIRES_OK(ctx, ctx->allocate_output(0, merged_shape, &output)); + + if (a_shape == b_shape && a_shape == x_shape) { + functor::Betainc functor; + functor(ctx->eigen_device(), a.flat(), b.flat(), + x.flat(), output->flat()); + return; + } + + auto merged_shape_vec = BCast::FromShape(merged_shape); + BCast a_shaper(BCast::FromShape(a_shape), merged_shape_vec); + BCast b_shaper(BCast::FromShape(b_shape), merged_shape_vec); + BCast x_shaper(BCast::FromShape(x_shape), merged_shape_vec); + + int ndims = static_cast(a_shaper.x_reshape().size()); + + switch (ndims) { +#define CASE(NDIM) \ + case NDIM: { \ + functor::Betainc functor; \ + auto a_value = a.shaped(a_shaper.x_reshape()); \ + auto b_value = b.shaped(b_shaper.x_reshape()); \ + auto x_value = x.shaped(x_shaper.x_reshape()); \ + functor.BCast(ctx->eigen_device(), a_value, \ + BCast::ToIndexArray(a_shaper.x_bcast()), b_value, \ + BCast::ToIndexArray(b_shaper.x_bcast()), x_value, \ + BCast::ToIndexArray(x_shaper.x_bcast()), \ + output->shaped(a_shaper.y_reshape())); \ + return; \ + } + + CASE(1); + CASE(2); + default: { + ctx->SetStatus(errors::InvalidArgument( + "Broadcasting rank not supported: ", ndims)); + return; + } + } + } +}; + +#define REGISTER_KERNELS(type) \ + REGISTER_KERNEL_BUILDER( \ + Name("Betainc").Device(DEVICE_CPU).TypeConstraint("T"), \ + BetaincOp); + +REGISTER_KERNELS(float); +REGISTER_KERNELS(double); +#undef REGISTER_KERNELS + +#if GOOGLE_CUDA +// Forward declarations of the functor specializations for GPU. +namespace functor { +#define DECLARE_GPU_SPEC_NDIM(T, NDIM) \ + template <> \ + void Betainc::operator()( \ + const GPUDevice& d, typename TTypes::ConstTensor a, \ + typename TTypes::ConstTensor b, \ + typename TTypes::ConstTensor x, \ + typename TTypes::Tensor output); \ + template <> \ + void Betainc::BCast( \ + const GPUDevice& d, typename TTypes::ConstTensor a, \ + const typename Eigen::array& bcast_a, \ + typename TTypes::ConstTensor b, \ + const typename Eigen::array& bcast_b, \ + typename TTypes::ConstTensor x, \ + const typename Eigen::array& bcast_x, \ + typename TTypes::Tensor output); \ + extern template struct Betainc; + +#define DECLARE_GPU_SPEC(T) \ + DECLARE_GPU_SPEC_NDIM(T, 1) \ + DECLARE_GPU_SPEC_NDIM(T, 2) + +DECLARE_GPU_SPEC(float); +DECLARE_GPU_SPEC(double); + +#undef DECLARE_GPU_SPEC +#undef DECLARE_GPU_SPEC_NDIM +} // namespace functor + +// Registration of the GPU implementations. +#define REGISTER_GPU_KERNELS(type) \ + REGISTER_KERNEL_BUILDER( \ + Name("Betainc").Device(DEVICE_GPU).TypeConstraint("T"), \ + BetaincOp); + +REGISTER_GPU_KERNELS(float); +REGISTER_GPU_KERNELS(double); +#undef REGISTER_GPU_KERNELS + +#endif // GOOGLE_CUDA + +} // namespace tensorflow diff --git a/tensorflow/core/kernels/betainc_op.h b/tensorflow/core/kernels/betainc_op.h new file mode 100644 index 0000000000000000000000000000000000000000..c4aa9543abcbacb39b401b3038dc388ee1a1b9e1 --- /dev/null +++ b/tensorflow/core/kernels/betainc_op.h @@ -0,0 +1,51 @@ +/* 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. +==============================================================================*/ + +#ifndef TENSORFLOW_KERNELS_BETAINC_OP_H_ +#define TENSORFLOW_KERNELS_BETAINC_OP_H_ +// Functor definition for BetaincOp, must be compilable by nvcc. + +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" +#include "tensorflow/core/framework/tensor_types.h" + +namespace tensorflow { +namespace functor { + +// Functor used by BetaincOp to do the computations. +template +struct Betainc { + void operator()(const Device& d, typename TTypes::ConstTensor a, + typename TTypes::ConstTensor b, + typename TTypes::ConstTensor x, + typename TTypes::Tensor output) { + output.device(d) = Eigen::betainc(a, b, x); + } + + void BCast(const Device& d, typename TTypes::ConstTensor a, + const typename Eigen::array& bcast_a, + typename TTypes::ConstTensor b, + const typename Eigen::array& bcast_b, + typename TTypes::ConstTensor x, + const typename Eigen::array& bcast_x, + typename TTypes::Tensor output) { + output.device(d) = Eigen::betainc( + a.broadcast(bcast_a), b.broadcast(bcast_b), x.broadcast(bcast_x)); + } +}; + +} // namespace functor +} // namespace tensorflow + +#endif // TENSORFLOW_KERNELS_BETAINC_OP_H_ diff --git a/tensorflow/core/kernels/betainc_op_gpu.cu.cc b/tensorflow/core/kernels/betainc_op_gpu.cu.cc new file mode 100644 index 0000000000000000000000000000000000000000..3b99ef323d147eeaa9acc2135ba7f6dc2fca441d --- /dev/null +++ b/tensorflow/core/kernels/betainc_op_gpu.cu.cc @@ -0,0 +1,44 @@ +/* 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. +==============================================================================*/ + +#if GOOGLE_CUDA + +#define EIGEN_USE_GPU + +#include + +#include "tensorflow/core/kernels/betainc_op.h" + +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/tensor_types.h" + +namespace tensorflow { + +typedef Eigen::GpuDevice GPUDevice; + +// Definition of the GPU implementations declared in betainc_op.cc. +#define DEFINE_GPU_KERNELS_NDIM(T, NDIM) \ + template struct functor::Betainc; + +#define DEFINE_GPU_KERNELS(T) \ + DEFINE_GPU_KERNELS_NDIM(T, 1) \ + DEFINE_GPU_KERNELS_NDIM(T, 2) + +DEFINE_GPU_KERNELS(float); +DEFINE_GPU_KERNELS(double); + +} // end namespace tensorflow + +#endif // GOOGLE_CUDA diff --git a/tensorflow/core/kernels/cast_op.h b/tensorflow/core/kernels/cast_op.h index 0ed19646530474e3984ee2ac90cdde0261be2b0f..7bd08cfda6be7ea455bfa9ecc8ad75edb2f6e31b 100644 --- a/tensorflow/core/kernels/cast_op.h +++ b/tensorflow/core/kernels/cast_op.h @@ -19,7 +19,7 @@ limitations under the License. #include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" #include "tensorflow/core/framework/bfloat16.h" #include "tensorflow/core/framework/tensor_types.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/types.h" namespace tensorflow { diff --git a/tensorflow/core/kernels/cholesky_grad.cc b/tensorflow/core/kernels/cholesky_grad.cc index 027897a4195499a43e5a8429653da0d0d81b12a6..9d33845c2f47512b4f0e7b613cd32d365252b595 100644 --- a/tensorflow/core/kernels/cholesky_grad.cc +++ b/tensorflow/core/kernels/cholesky_grad.cc @@ -22,10 +22,10 @@ limitations under the License. namespace tensorflow { -template -class CholeskyGrad : public LinearAlgebraOp { +template +class CholeskyGrad : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit CholeskyGrad(OpKernelConstruction* context) : Base(context) {} @@ -156,8 +156,9 @@ class CholeskyGrad : public LinearAlgebraOp { } }; -REGISTER_LINALG_OP("CholeskyGrad", (CholeskyGrad), float); -REGISTER_LINALG_OP("CholeskyGrad", (CholeskyGrad), double); -REGISTER_LINALG_OP("BatchCholeskyGrad", (CholeskyGrad), float); -REGISTER_LINALG_OP("BatchCholeskyGrad", (CholeskyGrad), double); +REGISTER_LINALG_OP("CholeskyGrad", (CholeskyGrad), float); +REGISTER_LINALG_OP("CholeskyGrad", (CholeskyGrad), double); +REGISTER_LINALG_OP("BatchCholeskyGrad", (CholeskyGrad), float); +REGISTER_LINALG_OP("BatchCholeskyGrad", (CholeskyGrad), double); + } // namespace tensorflow diff --git a/tensorflow/core/kernels/cholesky_op.cc b/tensorflow/core/kernels/cholesky_op.cc index f124ce2cefc0625bf81039993055c8d84fdab1e4..e5bf164cfaa4cd8ef0836205a12deae525149eee 100644 --- a/tensorflow/core/kernels/cholesky_op.cc +++ b/tensorflow/core/kernels/cholesky_op.cc @@ -29,10 +29,10 @@ limitations under the License. namespace tensorflow { -template -class CholeskyOp : public LinearAlgebraOp { +template +class CholeskyOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit CholeskyOp(OpKernelConstruction* context) : Base(context) {} @@ -65,8 +65,9 @@ class CholeskyOp : public LinearAlgebraOp { } }; -REGISTER_LINALG_OP("Cholesky", (CholeskyOp), float); -REGISTER_LINALG_OP("Cholesky", (CholeskyOp), double); -REGISTER_LINALG_OP("BatchCholesky", (CholeskyOp), float); -REGISTER_LINALG_OP("BatchCholesky", (CholeskyOp), double); +REGISTER_LINALG_OP("Cholesky", (CholeskyOp), float); +REGISTER_LINALG_OP("Cholesky", (CholeskyOp), double); +REGISTER_LINALG_OP("BatchCholesky", (CholeskyOp), float); +REGISTER_LINALG_OP("BatchCholesky", (CholeskyOp), double); + } // namespace tensorflow diff --git a/tensorflow/core/kernels/conv_ops.cc b/tensorflow/core/kernels/conv_ops.cc index e2182d0ec058ee248b4526af62a4bbb40231ba4d..86d498fe4a54a7df7dbcd543bf11826ce7a69687 100644 --- a/tensorflow/core/kernels/conv_ops.cc +++ b/tensorflow/core/kernels/conv_ops.cc @@ -242,8 +242,12 @@ class Conv2DOp : public BinaryOp { Name("Conv2D").Device(DEVICE_CPU).TypeConstraint("T"), \ Conv2DOp); +// If we're using the alternative GEMM-based implementation of Conv2D for the +// CPU implementation, don't register this EigenTensor-based version. +#if !defined(USE_GEMM_FOR_CONV) TF_CALL_half(REGISTER_CPU); TF_CALL_float(REGISTER_CPU); +#endif // USE_GEMM_FOR_CONV // To be used inside depthwise_conv_op.cc. template class LaunchConv2DOp; diff --git a/tensorflow/core/kernels/conv_ops_using_gemm.cc b/tensorflow/core/kernels/conv_ops_using_gemm.cc new file mode 100644 index 0000000000000000000000000000000000000000..c39510a11a265be20d81dbf06c21a8d9af6c5d17 --- /dev/null +++ b/tensorflow/core/kernels/conv_ops_using_gemm.cc @@ -0,0 +1,622 @@ +/* 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. +==============================================================================*/ + +// This file contains a set of different implementations of the two-dimensional +// convolution operation. The standard TensorFlow Conv2d kernel uses EigenTensor +// to implement the computation, but this module has a variety of different ways +// of producing the same result. These methods are designed to be easier to +// understand and connect to other libraries, so that we can take advantage of +// platforms that have specialized implementations of GEMM for example. +// +// The basic interface is a Conv functor object that's templated by the types +// of the data it will be operating on, and is passed in the arguments needed to +// calculate the convolution. The simplest implementation of this functor is +// ReferenceConvFunctor, which is a readable but slow reference version. +// +// A faster version uses the approach of packing image patches into a matrix +// before calling a matrix multiply, the Im2ColConvFunctor. In turn, this can +// use a variety of different methods to calculate the matrix multiplication, +// or GEMM. The simplest but slowest is the ReferenceGemmFunctor, but the +// FastGemmFunctor will use whatever optimized libraries are available. By +// default it uses Eigen, but on Apple platforms it will take advantage of the +// system's Accelerate BLAS library to get better performance than the standard +// TensorFlow convolution kernel. +// +// The version actually used is defined at the bottom of this file using the +// REGISTER_KERNEL_BUILDER() macro. To try out different implementations (for +// example to switch to a reference one for easier debugging) you can swap out +// the default functors in that call. +// +// The registration itself is guarded with the USE_GEMM_FOR_CONV macro. The iOS +// makefile build defines this, but if you want to enable this implementation +// and disable the standard EigenTensor one in other build setups, you'll need +// to define it there too. + +#include +#include +#include +#include "tensorflow/core/framework/common_shape_fns.h" +#include "tensorflow/core/framework/numeric_op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/framework/resource_mgr.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/framework/tensor_shape.h" +#include "tensorflow/core/framework/tensor_slice.h" +#include "tensorflow/core/kernels/bounds_check.h" +#include "tensorflow/core/util/padding.h" +#include "tensorflow/core/util/tensor_format.h" + +#if defined(__APPLE__) +#include +#define USE_ACCELERATE_GEMM +#endif // __APPLE__ + +namespace tensorflow { + +namespace { +// This function implements the convolution operation in as simple a form as +// possible. It won't give great performance, but it is very useful for +// stepping through and instrumenting for debugging, creating minimal benchmarks +// to prototype with, and sharing with teams that want to run this outside of +// our environment. +// With that in mind, I've avoided using anything except pretty standard C++ +// types. This is especially noticeable in the data access through raw array +// indexing. It's deliberate in this case though, since it makes the underlying +// memory order very explicit, which is important for both inspecting memory +// contents during debugging and for specifying what we expect to others. +// The memory layout of the data is, from biggest stride to smallest: +// input_data = [input_batches, input_height, input_width, input_depth] +// filter_data = [filter_height, filter_width, input_depth, filter_count] +// output_data = [input_batches, output_height, output_width, filter_count] +template +class ReferenceConvFunctor { + public: + void operator()(OpKernelContext* context, const T1* input_data, + int input_batches, int input_height, int input_width, + int input_depth, const T2* filter_data, int filter_height, + int filter_width, int filter_count, int stride_rows, + int stride_cols, Padding padding, T3* output_data, + int output_height, int output_width) { + // The two different padding modes we support can be a bit confusing. SAME + // means we're trying to produce an output image that's the same size as the + // input. It's complicated by stride, which shrinks the output image by a + // a factor, but it means we end up sampling from outside the borders of the + // input. These out-of-bounds values are read as zeroes. VALID means only + // produce output values where the filters can read all their values from + // within the input image. It effectively removes the margins of the output + // image compared to the one produced by SAME. Stride complicates this + // definition though, because it can result in the right and bottom filter + // patches sampling from outside the borders if it's greater than 1. + // Most of the logic for sorting this all out is done before this function, + // when we calculate the output size, but the positioning of the origin of + // the filters is different between the two modes, since SAME positions the + // first filter off the edge of the input. + int filter_left_offset; + int filter_top_offset; + if (padding == VALID) { + filter_left_offset = + ((output_width - 1) * stride_cols + filter_width - input_width + 1) / + 2; + filter_top_offset = ((output_height - 1) * stride_rows + filter_height - + input_height + 1) / + 2; + } else { + filter_left_offset = + ((output_width - 1) * stride_cols + filter_width - input_width) / 2; + filter_top_offset = + ((output_height - 1) * stride_rows + filter_height - input_height) / + 2; + } + + // If we've got multiple images in our input, work through each of them. + for (int batch = 0; batch < input_batches; ++batch) { + // Walk through all the output image values, sliding the filter to + // different positions in the input. + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + // Each filter kernel produces one output channel. + for (int out_channel = 0; out_channel < filter_count; ++out_channel) { + // We're going to calculate a single output value, which means we + // need to multiply a three dimensional kernel of weights against + // the current location within the input image. + /* + *-------------------------------... + |\ ^ + | \in_depth + | \ v + | *-------------------------------... + | | ^ + | | in_y_origin + | | v \ + | |*---*^ + | | \| |filter_height + . | *---*v + . | <---> + . filter_width + . + */ + const int in_x_origin = (out_x * stride_cols) - filter_left_offset; + const int in_y_origin = (out_y * stride_rows) - filter_top_offset; + T3 total(0); + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int in_channel = 0; in_channel < input_depth; + ++in_channel) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + T1 input_value; + // If the location is outside the bounds of the input image, + // use zero as a default value. + if ((in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height)) { + input_value = + input_data[(batch * input_height * input_width * + input_depth) + + (in_y * input_width * input_depth) + + (in_x * input_depth) + in_channel]; + } else { + input_value = T1(0); + } + const T2 filter_value = + filter_data[(filter_y * filter_width * input_depth * + filter_count) + + (filter_x * input_depth * filter_count) + + (in_channel * filter_count) + out_channel]; + total += (input_value * filter_value); + } + } + } + output_data[(batch * output_height * output_width * filter_count) + + (out_y * output_width * filter_count) + + (out_x * filter_count) + out_channel] = total; + } + } + } + } + } +}; + +// A readable but slow implementation of matrix multiplication, useful for +// debugging and understanding the algorithm. Use instead of FastGemmFunctor in +// the Im2ColConvFunctor template definition inside the op registration to +// enable. Assumes row-major ordering of the values in memory. +template +class ReferenceGemmFunctor { + public: + void operator()(size_t m, size_t n, size_t k, const T1* a, size_t lda, + const T2* b, size_t ldb, T3* c, size_t ldc) { + const size_t a_i_stride = lda; + const size_t a_l_stride = 1; + const size_t b_j_stride = 1; + const size_t b_l_stride = ldb; + const size_t c_i_stride = ldc; + const size_t c_j_stride = 1; + size_t i, j, l; + for (j = 0; j < n; j++) { + for (i = 0; i < m; i++) { + T3 total(0); + for (l = 0; l < k; l++) { + const size_t a_index = ((i * a_i_stride) + (l * a_l_stride)); + const T1 a_value = a[a_index]; + const size_t b_index = ((j * b_j_stride) + (l * b_l_stride)); + const T2 b_value = b[b_index]; + total += (a_value * b_value); + } + const size_t c_index = ((i * c_i_stride) + (j * c_j_stride)); + c[c_index] = total; + } + } + } +}; + +// Uses the optimized Eigen library to implement the matrix multiplication +// required by the Im2ColConvFunctor class. We supply the two input and one +// output types so that the accumulator can potentially be higher-precision than +// the inputs, even though we don't currently take advantage of this. +template +class FastGemmFunctor { + public: + // Convenience wrappers for the Eigen matrix types we'll be using. + typedef Eigen::Map< + const Eigen::Matrix> + ConstMatrixT1; + typedef Eigen::Map< + const Eigen::Matrix> + ConstMatrixT2; + typedef Eigen::Map< + Eigen::Matrix> + MatrixT3; + void operator()(size_t m, size_t n, size_t k, const T1* a, size_t lda, + const T2* b, size_t ldb, T3* c, size_t ldc) { + ConstMatrixT1 a_matrix(a, m, k); + ConstMatrixT2 b_matrix(b, k, n); + MatrixT3 c_matrix(c, m, n); + c_matrix.noalias() = a_matrix * b_matrix; + } +}; + +// If we have Apple's Accelerate framework, use their implementation of GEMM to +// get a performance boost for float. +#if defined(USE_ACCELERATE_GEMM) +template <> +class FastGemmFunctor { + public: + void operator()(size_t m, size_t n, size_t k, const float* a, size_t lda, + const float* b, size_t ldb, float* c, size_t ldc) { + cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, 1.0f, a, + lda, b, ldb, 0.0f, c, ldc); + } +}; +#endif // USE_ACCELERATE_GEMM + +// Used to keep track of persistent memory buffers used within the op. +template +struct Im2ColBufferResource : public ResourceBase { + mutex mu; + T data[size]; + string DebugString() { return "Im2ColBufferResource"; } +}; + +// Implements convolution as a two stage process, first packing the patches of +// the input image into columns (im2col) and then running GEMM to produce the +// final result. +template +class Im2ColConvFunctor { + public: + void operator()(OpKernelContext* context, const T1* input_data, + int input_batches, int input_height, int input_width, + int input_depth, const T2* filter_data, int filter_height, + int filter_width, int filter_count, int stride_rows, + int stride_cols, Padding padding, T3* output_data, + int output_height, int output_width) { + if ((input_batches <= 0) || (input_width <= 0) || (input_height <= 0) || + (input_depth <= 0)) { + LOG(WARNING) << "Conv2D was called with bad input dimensions: " + << input_batches << ", " << input_height << ", " + << input_width << ", " << input_depth; + return; + } + if ((filter_width <= 0) || (filter_height <= 0) || (filter_count <= 0)) { + LOG(WARNING) << "Conv2D was called with bad filter dimensions: " + << filter_width << ", " << filter_height << ", " + << filter_count; + return; + } + if ((output_width <= 0) || (output_height <= 0)) { + LOG(WARNING) << "Conv2D was called with bad output width or height: " + << output_width << ", " << output_height; + return; + } + + // These calculations define how the patches will be positioned within the + // input image. The actual definitions are quite complex, and rely on the + // previously-calculated output size. + int filter_left_offset; + int filter_top_offset; + if (padding == VALID) { + filter_left_offset = + ((output_width - 1) * stride_cols + filter_width - input_width + 1) / + 2; + filter_top_offset = ((output_height - 1) * stride_rows + filter_height - + input_height + 1) / + 2; + } else { + filter_left_offset = + ((output_width - 1) * stride_cols + filter_width - input_width) / 2; + filter_top_offset = + ((output_height - 1) * stride_rows + filter_height - input_height) / + 2; + } + + // The im2col buffer has # of patches rows, and # of filters cols. + // It's laid out like this, in row major order in memory: + // < filter value count > + // ^ +---------------------+ + // patch | | + // count | | + // v +---------------------+ + // Each patch row contains a filter_width x filter_height patch of the + // input, with the depth channel as the most contiguous in memory, followed + // by the width, then the height. This is the standard memory order in the + // image world if it helps to visualize it. + const int filter_value_count = filter_width * filter_height * input_depth; + + // We don't want to allocate a buffer to hold all the patches if the size is + // going to be extremely large, so break it into chunks if it's bigger than + // a limit. Each chunk will be processed serially, so we can refill the + // buffer for the next chunk and reuse it, keeping maximum memory size down. + // In this case, we've picked 16 megabytes as a reasonable limit. + const size_t max_chunk_size = (16 * 1024 * 1024); + OP_REQUIRES(context, (filter_value_count * sizeof(T1)) <= max_chunk_size, + errors::InvalidArgument("Im2Col patch too large for buffer")); + const size_t patches_per_chunk = + max_chunk_size / (filter_value_count * sizeof(T1)); + + // Because memory allocation is very expensive on mobile platforms, try to + // allocate a persistent buffer that will be kept around between calls. We + // use TensorFlow's resource management to ensure that the memory will be + // released when the session is over. + Im2ColBufferResource* im2col_buffer_resource; + std::function**)> creator = + [](Im2ColBufferResource** resource) { + *resource = new Im2ColBufferResource(); + return Status::OK(); + }; + OP_REQUIRES_OK(context, context->resource_manager()->LookupOrCreate( + "Conv2d", "im2col_buffer", + &im2col_buffer_resource, creator)); + // This means that multiple ops can't be run simultaneously on different + // threads, because we have a single shared resource. The platforms this is + // aimed at have intra-op parallelism as their focus though, so it shouldn't + // be an issue. + mutex_lock lock_buffer(im2col_buffer_resource->mu); + core::ScopedUnref unref_buffer(im2col_buffer_resource); + T1* im2col_buffer = im2col_buffer_resource->data; + + for (int batch = 0; batch < input_batches; ++batch) { + const T1* input_batch_start = + input_data + (batch * input_height * input_width * input_depth); + for (int out_y = 0; out_y < output_height; ++out_y) { + const int in_y_origin = (out_y * stride_rows) - filter_top_offset; + for (int out_x = 0; out_x < output_width; ++out_x) { + const int in_x_origin = (out_x * stride_cols) - filter_left_offset; + const int patch_index = (batch * output_width * output_height) + + (out_y * output_width) + out_x; + const int patch_index_within_chunk = patch_index % patches_per_chunk; + T1* im2col_patch_start = + im2col_buffer + (patch_index_within_chunk * filter_value_count); + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + const int in_y = in_y_origin + filter_y; + T1* im2col_row_start = + im2col_patch_start + (filter_y * filter_width * input_depth); + // If we're off the top or the bottom of the input, fill the whole + // row with zeroes. + if ((in_y < 0) || (in_y >= input_height)) { + T1* im2col_row_end = + im2col_row_start + (filter_width * input_depth); + std::fill(im2col_row_start, im2col_row_end, T1(0)); + } else { + // What we're doing here is trying to copy and fill the im2col + // buffer as efficiently as possible, using functions to set or + // duplicate values en masse. We know we don't have to worry about + // vertical edges because we dealt with that case above, so we + // just need to handle filters that overlap the left or right + // edges. Here's what that looks like: + // + // < left_zero_count > < center_copy_count > < right_zero_count > + // +------------------+---------------------+--------------------+ + // | (filter) | (image) | (filter) | + // +------------------+---------------------+--------------------+ + // in_x_origin 0 input_width in_x_end + // + // In reality it's unlikely that a filter patch will be wider + // than an input, but this shows all the edge cases. + // We use std::fill() to set the left and right sections to zeroes + // and std::copy() to copy over the input data for the center. + const int in_x_end = in_x_origin + filter_width; + const int left_zero_count = std::max(0, 0 - in_x_origin); + const int right_zero_count = std::max(0, in_x_end - input_width); + const int center_copy_count = + filter_width - (left_zero_count + right_zero_count); + if (left_zero_count > 0) { + T1* im2col_left_start = im2col_row_start; + T1* im2col_left_end = + im2col_left_start + (left_zero_count * input_depth); + std::fill(im2col_left_start, im2col_left_end, T1(0)); + } + if (center_copy_count > 0) { + const T1* input_row_start = + input_batch_start + (in_y * input_width * input_depth) + + (std::max(0, in_x_origin) * input_depth); + const T1* input_row_end = + input_row_start + (center_copy_count * input_depth); + T1* im2col_center_start = + im2col_row_start + (left_zero_count * input_depth); + std::copy(input_row_start, input_row_end, im2col_center_start); + } + if (right_zero_count > 0) { + T1* im2col_right_start = + im2col_row_start + + ((left_zero_count + center_copy_count) * input_depth); + T1* im2col_right_end = + im2col_right_start + (right_zero_count * input_depth); + std::fill(im2col_right_start, im2col_right_end, T1(0)); + } + } + } + const bool is_last_in_chunk = + (patch_index_within_chunk == (patches_per_chunk - 1)); + const bool is_last_overall = + ((batch == (input_batches - 1)) && + (out_y == (output_height - 1)) && (out_x == (output_width - 1))); + if (is_last_in_chunk || is_last_overall) { + // Now we've assembled a set of image patches into a matrix, apply a + // GEMM matrix multiply of the patches as rows, times the filter + // weights in columns, to get partial results in the output matrix. + const int how_many_patches = patch_index_within_chunk + 1; + const int m = how_many_patches; + const int n = filter_count; + const int k = filter_value_count; + const int lda = filter_value_count; + const int ldb = filter_count; + const int ldc = filter_count; + const size_t start_patch_index = + patch_index - (how_many_patches - 1); + T3* chunk_output_data = + output_data + (start_patch_index * filter_count); + TGemmFunctor gemm_functor; + gemm_functor(m, n, k, im2col_buffer, lda, filter_data, ldb, + chunk_output_data, ldc); + } + } + } + } + } +}; + +} // namespace + +// This TensorFlow kernel class handles all of the IO and housekeeping for the +// functors that actually implement the underlying algorithm. To swap in +// different implementations of the main calculations, use a different +// TConvFunctor parameter when instantiating the template. +template +class Conv2DUsingGemmOp : public BinaryOp { + public: + explicit Conv2DUsingGemmOp(OpKernelConstruction* context) + : BinaryOp(context) { + OP_REQUIRES_OK(context, context->GetAttr("strides", &strides_)); + string data_format; + OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format)); + OP_REQUIRES(context, FormatFromString(data_format, &data_format_), + errors::InvalidArgument("Invalid data format")); + OP_REQUIRES(context, data_format_ == FORMAT_NHWC, + errors::InvalidArgument( + "Data format not supported by this kernel", data_format)); + OP_REQUIRES(context, strides_.size() == 4, + errors::InvalidArgument("Sliding window strides field must " + "specify 4 dimensions")); + const int64 stride_n = GetTensorDim(strides_, data_format_, 'N'); + const int64 stride_c = GetTensorDim(strides_, data_format_, 'C'); + OP_REQUIRES( + context, stride_n == 1 && stride_c == 1, + errors::InvalidArgument("Current implementation does not yet support " + "strides in the batch and depth dimensions.")); + OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_)); + } + + void Compute(OpKernelContext* context) override { + // Input tensor is of the following dimensions: + // [ batch, in_rows, in_cols, in_depth ] + const Tensor& input = context->input(0); + + // Input filter is of the following dimensions: + // [ filter_rows, filter_cols, in_depth, out_depth] + const Tensor& filter = context->input(1); + + // For 2D convolution, there should be 4 dimensions. + OP_REQUIRES(context, input.dims() == 4, + errors::InvalidArgument("input must be 4-dimensional", + input.shape().DebugString())); + OP_REQUIRES(context, filter.dims() == 4, + errors::InvalidArgument("filter must be 4-dimensional: ", + filter.shape().DebugString())); + + for (int i = 0; i < 3; i++) { + OP_REQUIRES(context, FastBoundsCheck(filter.dim_size(i), + std::numeric_limits::max()), + errors::InvalidArgument("filter too large")); + } + + // The last dimension for input is in_depth. It must be the same as the + // filter's in_depth. + const int64 in_depth = GetTensorDim(input, data_format_, 'C'); + OP_REQUIRES( + context, in_depth == filter.dim_size(2), + errors::InvalidArgument("input and filter must have the same depth: ", + in_depth, " vs ", filter.dim_size(2))); + + // The last dimension for filter is out_depth. + const int out_depth = static_cast(filter.dim_size(3)); + + // The second dimension for input is rows/height. + // The first dimension for filter is rows/height. + const int64 input_rows_raw = GetTensorDim(input, data_format_, 'H'); + OP_REQUIRES(context, FastBoundsCheck(input_rows_raw, + std::numeric_limits::max()), + errors::InvalidArgument("Input rows too large")); + const int input_rows = static_cast(input_rows_raw); + const int filter_rows = static_cast(filter.dim_size(0)); + + // The third dimension for input is columns/width. + // The second dimension for filter is columns/width. + const int64 input_cols_raw = GetTensorDim(input, data_format_, 'W'); + OP_REQUIRES(context, FastBoundsCheck(input_cols_raw, + std::numeric_limits::max()), + errors::InvalidArgument("Input cols too large")); + const int input_cols = static_cast(input_cols_raw); + const int filter_cols = static_cast(filter.dim_size(1)); + + // The first dimension for input is batch. + const int64 batch_raw = GetTensorDim(input, data_format_, 'N'); + OP_REQUIRES(context, + FastBoundsCheck(batch_raw, std::numeric_limits::max()), + errors::InvalidArgument("batch is too large")); + const int batch = static_cast(batch_raw); + + // For now we take the stride from the second and third dimensions only (we + // do not support striding on the batch or depth dimension). + const int stride_rows = GetTensorDim(strides_, data_format_, 'H'); + const int stride_cols = GetTensorDim(strides_, data_format_, 'W'); + + int64 out_rows = 0, out_cols = 0, pad_rows = 0, pad_cols = 0; + OP_REQUIRES_OK(context, + GetWindowedOutputSize(input_rows, filter_rows, stride_rows, + padding_, &out_rows, &pad_rows)); + OP_REQUIRES_OK(context, + GetWindowedOutputSize(input_cols, filter_cols, stride_cols, + padding_, &out_cols, &pad_cols)); + TensorShape out_shape = + ShapeFromFormat(data_format_, batch, out_rows, out_cols, out_depth); + + // Output tensor is of the following dimensions: + // [ in_batch, out_rows, out_cols, out_depth ] + Tensor* output = nullptr; + OP_REQUIRES_OK(context, context->allocate_output(0, out_shape, &output)); + + VLOG(2) << "Conv2D: in_depth = " << in_depth + << ", input_cols = " << input_cols + << ", filter_cols = " << filter_cols + << ", input_rows = " << input_rows + << ", filter_rows = " << filter_rows + << ", stride_rows = " << stride_rows + << ", stride_cols = " << stride_cols + << ", out_depth = " << out_depth; + + // If there is nothing to compute, return. + if (out_shape.num_elements() == 0) { + return; + } + TConvFunctor conv_functor; + conv_functor(context, input.flat().data(), batch, input_rows, input_cols, + in_depth, filter.flat().data(), filter_rows, filter_cols, + out_depth, stride_rows, stride_cols, padding_, + output->flat().data(), out_rows, out_cols); + } + + private: + std::vector strides_; + Padding padding_; + TensorFormat data_format_; + + TF_DISALLOW_COPY_AND_ASSIGN(Conv2DUsingGemmOp); +}; + +#define REGISTER_CPU(T) \ + REGISTER_KERNEL_BUILDER( \ + Name("Conv2D").Device(DEVICE_CPU).TypeConstraint("T"), \ + Conv2DUsingGemmOp< \ + T, Im2ColConvFunctor>>); + +// Only register this GEMM-based implementation of Conv2d if the compiler flags +// request the implementation explicitly, since otherwise it will clash with the +// default EigenTensor-based kernel. +#if defined(USE_GEMM_FOR_CONV) +TF_CALL_half(REGISTER_CPU); +TF_CALL_float(REGISTER_CPU); +#endif // USE_GEMM_FOR_CONV + +} // namespace tensorflow diff --git a/tensorflow/core/kernels/decode_raw_op.cc b/tensorflow/core/kernels/decode_raw_op.cc index 2ad2c94b61cbbcece112b498c623366b5afff848..d3bd9913e04344ed382b2e7169bf0bb021bf9093 100644 --- a/tensorflow/core/kernels/decode_raw_op.cc +++ b/tensorflow/core/kernels/decode_raw_op.cc @@ -21,7 +21,7 @@ limitations under the License. #include "tensorflow/core/framework/tensor_shape.h" #include "tensorflow/core/framework/types.h" #include "tensorflow/core/lib/core/errors.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" namespace tensorflow { diff --git a/tensorflow/core/kernels/determinant_op.cc b/tensorflow/core/kernels/determinant_op.cc index b2e69a8df5e4cb7b334539ea32733dc8a2aebf9f..d51563580b0444952a0a211b8df02d8dffd468bd 100644 --- a/tensorflow/core/kernels/determinant_op.cc +++ b/tensorflow/core/kernels/determinant_op.cc @@ -27,10 +27,10 @@ limitations under the License. namespace tensorflow { -template -class DeterminantOp : public LinearAlgebraOp { +template +class DeterminantOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit DeterminantOp(OpKernelConstruction* context) : Base(context) {} @@ -60,11 +60,9 @@ class DeterminantOp : public LinearAlgebraOp { } }; -REGISTER_LINALG_OP("MatrixDeterminant", (DeterminantOp), float); -REGISTER_LINALG_OP("MatrixDeterminant", (DeterminantOp), double); -REGISTER_LINALG_OP("BatchMatrixDeterminant", (DeterminantOp), - float); -REGISTER_LINALG_OP("BatchMatrixDeterminant", (DeterminantOp), - double); +REGISTER_LINALG_OP("MatrixDeterminant", (DeterminantOp), float); +REGISTER_LINALG_OP("MatrixDeterminant", (DeterminantOp), double); +REGISTER_LINALG_OP("BatchMatrixDeterminant", (DeterminantOp), float); +REGISTER_LINALG_OP("BatchMatrixDeterminant", (DeterminantOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/example_parsing_ops.cc b/tensorflow/core/kernels/example_parsing_ops.cc index a7091645faee70a0b8a5f2726551fcba2fc65913..6338638a3b85de8eac8ff98d0f95824cae797a00 100644 --- a/tensorflow/core/kernels/example_parsing_ops.cc +++ b/tensorflow/core/kernels/example_parsing_ops.cc @@ -24,8 +24,10 @@ limitations under the License. #include "tensorflow/core/framework/common_shape_fns.h" #include "tensorflow/core/framework/numeric_op.h" #include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/lib/gtl/array_slice.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/protobuf.h" +#include "tensorflow/core/util/example_proto_fast_parsing.h" #include "tensorflow/core/util/example_proto_helper.h" #include "tensorflow/core/util/sparse/sparse_tensor.h" #include "tensorflow/core/util/work_sharder.h" @@ -67,8 +69,7 @@ class ExampleParserOp : public OpKernel { sparse_keys_t[di] = sparse_keys[di].scalar()(); } - bool has_names = (names->NumElements() > 0); - if (has_names) { + if (names->NumElements() > 0) { OP_REQUIRES( ctx, TensorShapeUtils::IsVector(names->shape()), errors::InvalidArgument("Expected names to be a vector, got shape: ", @@ -79,7 +80,6 @@ class ExampleParserOp : public OpKernel { "Expected len(names) == len(serialized), but got: ", names->NumElements(), " vs. ", serialized->NumElements())); } - auto names_t = names->flat(); OP_REQUIRES(ctx, TensorShapeUtils::IsVector(serialized->shape()), errors::InvalidArgument( @@ -106,136 +106,43 @@ class ExampleParserOp : public OpKernel { } } - auto serialized_t = serialized->vec(); + example::Result result; + + example::FastParseExampleConfig config; + for (int d = 0; d < attrs_.num_dense; ++d) { + config.dense.push_back({dense_keys_t[d], attrs_.dense_types[d], + attrs_.dense_shapes[d], dense_defaults[d]}); + } + for (int d = 0; d < attrs_.num_sparse; ++d) { + config.sparse.push_back({sparse_keys_t[d], attrs_.sparse_types[d]}); + } + + auto serialized_t = serialized->flat(); + auto names_t = names->flat(); + gtl::ArraySlice slice(serialized_t.data(), serialized_t.size()); + gtl::ArraySlice names_slice(names_t.data(), names_t.size()); - const int64 batch_size = serialized_t.size(); + OP_REQUIRES_OK( + ctx, + FastParseExample( + config, slice, names_slice, + ctx->device()->tensorflow_cpu_worker_threads()->workers, &result)); + OpOutputList dense_values; OpOutputList sparse_indices; OpOutputList sparse_values; OpOutputList sparse_shapes; - OpOutputList dense_values; - + OP_REQUIRES_OK(ctx, ctx->output_list("dense_values", &dense_values)); OP_REQUIRES_OK(ctx, ctx->output_list("sparse_indices", &sparse_indices)); OP_REQUIRES_OK(ctx, ctx->output_list("sparse_values", &sparse_values)); OP_REQUIRES_OK(ctx, ctx->output_list("sparse_shapes", &sparse_shapes)); - OP_REQUIRES_OK(ctx, ctx->output_list("dense_values", &dense_values)); - - // Setup Dense features and the output_dense_values Tensor* vector. - std::vector fixed_len_features(attrs_.num_dense); - std::vector output_dense_values(attrs_.num_dense); - for (int d = 0; d < attrs_.num_dense; ++d) { - // Preallocate dense_values, since we know their sizes - TensorShape out_shape; - out_shape.AddDim(batch_size); - for (const int64 dim : attrs_.dense_shapes[d].dim_sizes()) { - out_shape.AddDim(dim); - } - Tensor* out = nullptr; - dense_values.allocate(d, out_shape, &out); - - FixedLenFeature config; - config.key = dense_keys_t[d]; - config.dtype = attrs_.dense_types[d]; - config.shape = attrs_.dense_shapes[d]; - config.default_value = dense_defaults[d]; - fixed_len_features[d] = config; - output_dense_values[d] = dense_values[d]; + dense_values.set(d, result.dense_values[d]); } - - // sparse_values_tmp will be attrs_.num_sparse size map of batch_size length - // tensor vector's, containing the sparse values from the input layer. - // After these are all stored, we can allocate properly sized outputs - // and copy data over. Doing it this way saves us the trouble of either - // performing deserialization twice, or alternatively storing all copies of - // the full Example protos. - std::vector> sparse_values_tmp( - attrs_.num_sparse, std::vector(batch_size)); - - // Setup Sparse features. - std::vector var_len_features(attrs_.num_sparse); for (int d = 0; d < attrs_.num_sparse; ++d) { - VarLenFeature config; - config.key = sparse_keys_t[d]; - config.dtype = attrs_.sparse_types[d]; - var_len_features[d] = config; - } - - auto worker_threads = *(ctx->device()->tensorflow_cpu_worker_threads()); - - // Estimate the cost of parsing each batch element. - int64 work_unit_size = 1000 + 100 * attrs_.num_sparse; - for (int d = 0; d < attrs_.num_dense; ++d) { - work_unit_size += 100 + attrs_.dense_shapes[d].num_elements(); - } - - mutex mu; - - auto DoWork = [&ctx, &mu, &serialized_t, has_names, &names_t, - &fixed_len_features, &var_len_features, &output_dense_values, - &sparse_values_tmp](int64 start, int64 limit) { - // Processing each Example in the batch starts here. - for (std::size_t b = static_cast(start); - b < static_cast(limit); ++b) { - // Benchmarks indicate that a tight Arena+Example is most performant. - protobuf::Arena arena; - // ex is owned by the arena. - Example* ex = protobuf::Arena::CreateMessage(&arena); - bool parse_success = ParseProtoUnlimited(ex, serialized_t(b)); - if (!TF_PREDICT_TRUE(parse_success)) { - mutex_lock l(mu); - ctx->CtxFailure(errors::InvalidArgument( - "Could not parse example input, value: '", serialized_t(b), "'")); - return; - } - const string& example_name = (has_names) ? names_t(b) : ""; - Status s = SingleExampleProtoToTensors( - *ex, example_name, b, fixed_len_features, var_len_features, - &output_dense_values, &sparse_values_tmp); - if (!TF_PREDICT_TRUE(s.ok())) { - mutex_lock l(mu); - ctx->CtxFailureWithWarning(s); - } - } - }; - - Shard(worker_threads.num_threads, worker_threads.workers, batch_size, - work_unit_size, DoWork); - - if (!TF_PREDICT_TRUE(ctx->status().ok())) { - return; - } - - // Copy from sparse_values_tmp into final resting Tensors - // ------------------------- - for (int d = 0; d < attrs_.num_sparse; ++d) { - const VarLenFeature& feature_config = var_len_features[d]; - const std::vector& sparse_values_tmp_tensors = - sparse_values_tmp[d]; - VarLenFeatureBatchShapes sparse_tensor_batch_shapes; - GetSparseTensorShapes(feature_config, sparse_values_tmp_tensors, - batch_size, &sparse_tensor_batch_shapes); - - Tensor* sp_indices_d = nullptr; - Tensor* sp_values_d = nullptr; - Tensor* sp_shape_d = nullptr; - - sparse_indices.allocate(d, sparse_tensor_batch_shapes.indices_shape, - &sp_indices_d); - sparse_values.allocate(d, sparse_tensor_batch_shapes.values_shape, - &sp_values_d); - sparse_shapes.allocate(d, TensorShape({2}), &sp_shape_d); - - auto shape_t = sp_shape_d->vec(); - shape_t(0) = batch_size; - shape_t(1) = sparse_tensor_batch_shapes.max_num_features; - - int64 offset = 0; - for (int b = 0; b < batch_size; ++b) { - const int64 num_elements = CopyIntoSparseTensor( - sparse_values_tmp_tensors[b], b, offset, sp_indices_d, sp_values_d); - offset += num_elements; - } + sparse_indices.set(d, result.sparse_indices[d]); + sparse_values.set(d, result.sparse_values[d]); + sparse_shapes.set(d, result.sparse_shapes[d]); } } diff --git a/tensorflow/core/kernels/example_parsing_ops_test.cc b/tensorflow/core/kernels/example_parsing_ops_test.cc index e58cecff147b8e3571f36c6e36bfae7d5671ffbf..187d72685ecd876bed9c41533eb73ec9c70e62a7 100644 --- a/tensorflow/core/kernels/example_parsing_ops_test.cc +++ b/tensorflow/core/kernels/example_parsing_ops_test.cc @@ -161,7 +161,7 @@ static Graph* ParseExample(int batch_size, int num_keys) { // Benchmark settings (Sparse, Dense) X (Bytes, Int64, Float) typedef BenchmarkOptions, false> SparseString; typedef BenchmarkOptions, true> DenseString; -typedef BenchmarkOptions, false> SparseIn64; +typedef BenchmarkOptions, false> SparseInt64; typedef BenchmarkOptions, true> DenseInt64; typedef BenchmarkOptions, false> SparseFloat; typedef BenchmarkOptions, true> DenseFloat; @@ -176,20 +176,19 @@ typedef BenchmarkOptions, true> DenseFloat; } \ BENCHMARK(BM_ParseExample##_##TYPE##_##B##_##K); -#define BM_AllParseExample(B, K) \ - BM_ParseExample(SparseString, B, K); \ - BM_ParseExample(DenseString, B, K); \ - BM_ParseExample(SparseIn64, B, K); \ - BM_ParseExample(DenseInt64, B, K); \ - BM_ParseExample(SparseFloat, B, K); \ - BM_ParseExample(DenseFloat, B, K); - -BM_AllParseExample(128, 10); -BM_AllParseExample(128, 100); -BM_AllParseExample(128, 1000); - -BM_AllParseExample(512, 10); -BM_AllParseExample(512, 100); -BM_AllParseExample(512, 1000); +#define BM_AllParseExample(Type) \ + BM_ParseExample(Type, 128, 10); \ + BM_ParseExample(Type, 512, 10); \ + BM_ParseExample(Type, 128, 100); \ + BM_ParseExample(Type, 512, 100); \ + BM_ParseExample(Type, 128, 1000); \ + BM_ParseExample(Type, 512, 1000); + +BM_AllParseExample(SparseString); +BM_AllParseExample(DenseString); +BM_AllParseExample(SparseInt64); +BM_AllParseExample(DenseInt64); +BM_AllParseExample(SparseFloat); +BM_AllParseExample(DenseFloat); } // end namespace tensorflow diff --git a/tensorflow/core/kernels/linalg_ops_common.cc b/tensorflow/core/kernels/linalg_ops_common.cc index bf127f9dc30b71f1d641781276e8c6b175f1cbf6..287e8901db92addeaa11b9242b5cfec539684584 100644 --- a/tensorflow/core/kernels/linalg_ops_common.cc +++ b/tensorflow/core/kernels/linalg_ops_common.cc @@ -27,8 +27,8 @@ limitations under the License. namespace tensorflow { // static -template -void LinearAlgebraOp::ValidateSingleMatrix( +template +void LinearAlgebraOp::ValidateSingleMatrix( OpKernelContext* context, const TensorShapes& input_matrix_shapes) { OP_REQUIRES(context, input_matrix_shapes.size() == 1, errors::InvalidArgument("Expected a single input matrix, got %d.", @@ -38,10 +38,9 @@ void LinearAlgebraOp::ValidateSingleMatrix( } // static -template -void LinearAlgebraOp:: - ValidateSingleSquareMatrix(OpKernelContext* context, - const TensorShapes& input_matrix_shapes) { +template +void LinearAlgebraOp::ValidateSingleSquareMatrix( + OpKernelContext* context, const TensorShapes& input_matrix_shapes) { OP_REQUIRES(context, input_matrix_shapes.size() == 1, errors::InvalidArgument("Expected a single input matrix, got %d.", input_matrix_shapes.size())); @@ -50,8 +49,8 @@ void LinearAlgebraOp:: } // static -template -void LinearAlgebraOp::ValidateSolver( +template +void LinearAlgebraOp::ValidateSolver( OpKernelContext* context, const TensorShapes& input_matrix_shapes) { OP_REQUIRES(context, input_matrix_shapes.size() == 2, errors::InvalidArgument("Expected two input matrices, got %d.", @@ -67,8 +66,8 @@ void LinearAlgebraOp::ValidateSolver( } // static -template -void LinearAlgebraOp::ValidateSquareSolver( +template +void LinearAlgebraOp::ValidateSquareSolver( OpKernelContext* context, const TensorShapes& input_matrix_shapes) { OP_REQUIRES(context, input_matrix_shapes.size() == 2, errors::InvalidArgument("Expected two input matrices, got %d.", @@ -84,9 +83,8 @@ void LinearAlgebraOp::ValidateSquareSolver( errors::InvalidArgument("Input matrix and rhs are incompatible.")); } -template -void LinearAlgebraOp::Compute( - OpKernelContext* context) { +template +void LinearAlgebraOp::Compute(OpKernelContext* context) { TensorInputs inputs; TensorShapes input_matrix_shapes; TensorShape batch_shape; @@ -110,27 +108,20 @@ void LinearAlgebraOp::Compute( batch_shape.num_elements(), GetCostPerUnit(input_matrix_shapes), shard); } -template -void LinearAlgebraOp::AnalyzeInputs( - OpKernelContext* context, TensorInputs* inputs, - TensorShapes* input_matrix_shapes, TensorShape* batch_shape) { +template +void LinearAlgebraOp::AnalyzeInputs(OpKernelContext* context, + TensorInputs* inputs, + TensorShapes* input_matrix_shapes, + TensorShape* batch_shape) { int input_rank = -1; for (int i = 0; i < NumMatrixInputs(context); ++i) { const Tensor& in = context->input(i); if (i == 0) { input_rank = in.dims(); - if (SupportsBatchOperation) { - OP_REQUIRES( - context, input_rank >= 2, - errors::InvalidArgument("Input tensor ", i, - " must have rank >= 2, got", input_rank)); - } else { - OP_REQUIRES( - context, input_rank == 2, - errors::InvalidArgument("Input tensor ", i, - " must have rank == 2, got", input_rank)); - } - + OP_REQUIRES( + context, input_rank >= 2, + errors::InvalidArgument("Input tensor ", i, + " must have rank >= 2, got", input_rank)); // If the tensor rank is greater than 2, we consider the inner-most // dimensions as matrices, and loop over all the other outer ("batch") // dimensions to compute the results. @@ -163,8 +154,8 @@ void LinearAlgebraOp::AnalyzeInputs( ValidateInputMatrixShapes(context, *input_matrix_shapes); } -template -void LinearAlgebraOp::PrepareOutputs( +template +void LinearAlgebraOp::PrepareOutputs( OpKernelContext* context, const TensorShapes& input_matrix_shapes, const TensorShape& batch_shape, TensorOutputs* outputs, TensorShapes* output_matrix_shapes) { @@ -205,8 +196,8 @@ void LinearAlgebraOp::PrepareOutputs( } } -template -void LinearAlgebraOp::ComputeTensorSlice( +template +void LinearAlgebraOp::ComputeTensorSlice( OpKernelContext* context, int64 matrix_index, const TensorInputs& inputs, const TensorShapes& input_matrix_shapes, const TensorOutputs& outputs, const TensorShapes& output_matrix_shapes) { @@ -238,15 +229,10 @@ void LinearAlgebraOp::ComputeTensorSlice( ComputeMatrix(context, matrix_inputs, &matrix_outputs); } -// Explicitly instantiate LinearAlgebraOp for the scalar types we expect to -// use. -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; -template class LinearAlgebraOp; +// Explicitly instantiate LinearAlgebraOp for the scalar types we expect to use. +template class LinearAlgebraOp; +template class LinearAlgebraOp; +template class LinearAlgebraOp; +template class LinearAlgebraOp; } // namespace tensorflow diff --git a/tensorflow/core/kernels/linalg_ops_common.h b/tensorflow/core/kernels/linalg_ops_common.h index 13325afca1bf128f30f30bbfcd183a1e714e9da7..e6c447a623dee0cd500a07bbd783627f3e57a0c0 100644 --- a/tensorflow/core/kernels/linalg_ops_common.h +++ b/tensorflow/core/kernels/linalg_ops_common.h @@ -39,7 +39,7 @@ limitations under the License. namespace tensorflow { // Base class for linear algebra operators. -template +template class LinearAlgebraOp : public OpKernel { public: explicit LinearAlgebraOp(OpKernelConstruction* context) : OpKernel(context) {} @@ -164,14 +164,10 @@ class LinearAlgebraOp : public OpKernel { // Declare that LinearAlgebraOp is explicitly instantiated in // linalg_ops_common.cc for float and double. -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; -extern template class LinearAlgebraOp; +extern template class LinearAlgebraOp; +extern template class LinearAlgebraOp; +extern template class LinearAlgebraOp; +extern template class LinearAlgebraOp; } // namespace tensorflow diff --git a/tensorflow/core/kernels/lookup_table_op.h b/tensorflow/core/kernels/lookup_table_op.h index cd44fb64c289246fceaa9754d017c2c63e896e2f..ffedbe4a97d953db94488428a6175a39ce7255f3 100644 --- a/tensorflow/core/kernels/lookup_table_op.h +++ b/tensorflow/core/kernels/lookup_table_op.h @@ -42,13 +42,16 @@ class LookupTableOp : public OpKernel { OP_REQUIRES_OK(ctx, ctx->allocate_persistent(tensorflow::DT_STRING, tensorflow::TensorShape({2}), &table_handle_, nullptr)); + OP_REQUIRES_OK( + ctx, ctx->GetAttr("use_node_name_sharing", &use_node_name_sharing_)); } // ctx is not owned by this function. void Compute(OpKernelContext* ctx) override { mutex_lock l(mu_); if (!table_handle_set_) { - OP_REQUIRES_OK(ctx, cinfo_.Init(ctx->resource_manager(), def())); + OP_REQUIRES_OK(ctx, cinfo_.Init(ctx->resource_manager(), def(), + use_node_name_sharing_)); auto creator = [ctx, this](lookup::LookupInterface** ret) { *ret = new Container(ctx, this); return Status::OK(); @@ -87,6 +90,7 @@ class LookupTableOp : public OpKernel { PersistentTensor table_handle_ GUARDED_BY(mu_); bool table_handle_set_ GUARDED_BY(mu_); ContainerInfo cinfo_; + bool use_node_name_sharing_; TF_DISALLOW_COPY_AND_ASSIGN(LookupTableOp); }; diff --git a/tensorflow/core/kernels/matrix_inverse_op.cc b/tensorflow/core/kernels/matrix_inverse_op.cc index d548e3f65bea5b391edb055ee6d7309b0cd6c87a..884e3d61a415b88b5a3460c3ca03ec3433d6a13d 100644 --- a/tensorflow/core/kernels/matrix_inverse_op.cc +++ b/tensorflow/core/kernels/matrix_inverse_op.cc @@ -28,10 +28,10 @@ limitations under the License. namespace tensorflow { -template -class MatrixInverseOp : public LinearAlgebraOp { +template +class MatrixInverseOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit MatrixInverseOp(OpKernelConstruction* context) : Base(context) { OP_REQUIRES_OK(context, context->GetAttr("adjoint", &adjoint_)); @@ -77,10 +77,9 @@ class MatrixInverseOp : public LinearAlgebraOp { TF_DISALLOW_COPY_AND_ASSIGN(MatrixInverseOp); }; -REGISTER_LINALG_OP("MatrixInverse", (MatrixInverseOp), float); -REGISTER_LINALG_OP("MatrixInverse", (MatrixInverseOp), double); -REGISTER_LINALG_OP("BatchMatrixInverse", (MatrixInverseOp), float); -REGISTER_LINALG_OP("BatchMatrixInverse", (MatrixInverseOp), - double); +REGISTER_LINALG_OP("MatrixInverse", (MatrixInverseOp), float); +REGISTER_LINALG_OP("MatrixInverse", (MatrixInverseOp), double); +REGISTER_LINALG_OP("BatchMatrixInverse", (MatrixInverseOp), float); +REGISTER_LINALG_OP("BatchMatrixInverse", (MatrixInverseOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/matrix_solve_ls_op.cc b/tensorflow/core/kernels/matrix_solve_ls_op.cc index 9ee3f2c924f5b324a8129e7a9aa3dab5131a5c16..716015e7de1f1fcfb3384996191fae4d97af7528 100644 --- a/tensorflow/core/kernels/matrix_solve_ls_op.cc +++ b/tensorflow/core/kernels/matrix_solve_ls_op.cc @@ -28,10 +28,10 @@ limitations under the License. namespace tensorflow { -template -class MatrixSolveLsOp : public LinearAlgebraOp { +template +class MatrixSolveLsOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit MatrixSolveLsOp(OpKernelConstruction* context) : Base(context) { OP_REQUIRES_OK(context, context->GetAttr("fast", &fast_)); @@ -155,10 +155,9 @@ class MatrixSolveLsOp : public LinearAlgebraOp { bool fast_; }; -REGISTER_LINALG_OP("MatrixSolveLs", (MatrixSolveLsOp), float); -REGISTER_LINALG_OP("MatrixSolveLs", (MatrixSolveLsOp), double); -REGISTER_LINALG_OP("BatchMatrixSolveLs", (MatrixSolveLsOp), float); -REGISTER_LINALG_OP("BatchMatrixSolveLs", (MatrixSolveLsOp), - double); +REGISTER_LINALG_OP("MatrixSolveLs", (MatrixSolveLsOp), float); +REGISTER_LINALG_OP("MatrixSolveLs", (MatrixSolveLsOp), double); +REGISTER_LINALG_OP("BatchMatrixSolveLs", (MatrixSolveLsOp), float); +REGISTER_LINALG_OP("BatchMatrixSolveLs", (MatrixSolveLsOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/matrix_solve_op.cc b/tensorflow/core/kernels/matrix_solve_op.cc index 32f3bd32c1abbc999be45215f667b2a2970ee478..1c881783e155afd88c661a0a01b922c7488cf120 100644 --- a/tensorflow/core/kernels/matrix_solve_op.cc +++ b/tensorflow/core/kernels/matrix_solve_op.cc @@ -28,10 +28,10 @@ limitations under the License. namespace tensorflow { -template -class MatrixSolveOp : public LinearAlgebraOp { +template +class MatrixSolveOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit MatrixSolveOp(OpKernelConstruction* context) : Base(context) { OP_REQUIRES_OK(context, context->GetAttr("adjoint", &adjoint_)); @@ -105,9 +105,9 @@ class MatrixSolveOp : public LinearAlgebraOp { TF_DISALLOW_COPY_AND_ASSIGN(MatrixSolveOp); }; -REGISTER_LINALG_OP("MatrixSolve", (MatrixSolveOp), float); -REGISTER_LINALG_OP("MatrixSolve", (MatrixSolveOp), double); -REGISTER_LINALG_OP("BatchMatrixSolve", (MatrixSolveOp), float); -REGISTER_LINALG_OP("BatchMatrixSolve", (MatrixSolveOp), double); +REGISTER_LINALG_OP("MatrixSolve", (MatrixSolveOp), float); +REGISTER_LINALG_OP("MatrixSolve", (MatrixSolveOp), double); +REGISTER_LINALG_OP("BatchMatrixSolve", (MatrixSolveOp), float); +REGISTER_LINALG_OP("BatchMatrixSolve", (MatrixSolveOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/matrix_triangular_solve_op.cc b/tensorflow/core/kernels/matrix_triangular_solve_op.cc index 50cab2b84e271e354efb57670c6994f93065c397..09f75f2d5ffb7546a39cb0b0be474206c6483bec 100644 --- a/tensorflow/core/kernels/matrix_triangular_solve_op.cc +++ b/tensorflow/core/kernels/matrix_triangular_solve_op.cc @@ -27,11 +27,10 @@ limitations under the License. namespace tensorflow { -template -class MatrixTriangularSolveOp - : public LinearAlgebraOp { +template +class MatrixTriangularSolveOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit MatrixTriangularSolveOp(OpKernelConstruction* context) : Base(context), lower_(true), adjoint_(false) { @@ -104,13 +103,13 @@ class MatrixTriangularSolveOp TF_DISALLOW_COPY_AND_ASSIGN(MatrixTriangularSolveOp); }; -REGISTER_LINALG_OP("MatrixTriangularSolve", - (MatrixTriangularSolveOp), float); -REGISTER_LINALG_OP("MatrixTriangularSolve", - (MatrixTriangularSolveOp), double); +REGISTER_LINALG_OP("MatrixTriangularSolve", (MatrixTriangularSolveOp), + float); +REGISTER_LINALG_OP("MatrixTriangularSolve", (MatrixTriangularSolveOp), + double); REGISTER_LINALG_OP("BatchMatrixTriangularSolve", - (MatrixTriangularSolveOp), float); + (MatrixTriangularSolveOp), float); REGISTER_LINALG_OP("BatchMatrixTriangularSolve", - (MatrixTriangularSolveOp), double); + (MatrixTriangularSolveOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/random_op.cc b/tensorflow/core/kernels/random_op.cc index 9b94fc5d603571352a8aa0c54b596c39a733bd15..d378764178a0f54496062c7eaf14ac43058a83fd 100644 --- a/tensorflow/core/kernels/random_op.cc +++ b/tensorflow/core/kernels/random_op.cc @@ -138,32 +138,29 @@ struct FillPhiloxRandomTask { // Partial specialization for CPU to fill the entire region with randoms // It splits the work into several tasks and run them in parallel template -struct FillPhiloxRandom { - typedef typename Distribution::ResultElementType T; - void operator()(OpKernelContext* context, const CPUDevice&, - random::PhiloxRandom gen, T* data, int64 size, - Distribution dist) { - const int kGroupSize = Distribution::kResultElementCount; - - auto worker_threads = *(context->device()->tensorflow_cpu_worker_threads()); - - int64 total_group_count = (size + kGroupSize - 1) / kGroupSize; - - const int kGroupCost = - random::PhiloxRandom::kResultElementCount * - (random::PhiloxRandom::kElementCost + Distribution::kElementCost); - Shard(worker_threads.num_threads, worker_threads.workers, total_group_count, - kGroupCost, - [&gen, data, size, dist](int64 start_group, int64 limit_group) { - FillPhiloxRandomTask< - Distribution, - Distribution::kVariableSamplesPerOutput>::Run(gen, data, size, - start_group, - limit_group, - dist); - }); - } -}; +void FillPhiloxRandom::operator()( + OpKernelContext* context, const CPUDevice&, random::PhiloxRandom gen, + typename Distribution::ResultElementType* data, int64 size, + Distribution dist) { + const int kGroupSize = Distribution::kResultElementCount; + + auto worker_threads = *(context->device()->tensorflow_cpu_worker_threads()); + + int64 total_group_count = (size + kGroupSize - 1) / kGroupSize; + + const int kGroupCost = + random::PhiloxRandom::kResultElementCount * + (random::PhiloxRandom::kElementCost + Distribution::kElementCost); + Shard(worker_threads.num_threads, worker_threads.workers, total_group_count, + kGroupCost, + [&gen, data, size, dist](int64 start_group, int64 limit_group) { + FillPhiloxRandomTask< + Distribution, + Distribution::kVariableSamplesPerOutput>::Run(gen, data, size, + start_group, + limit_group, dist); + }); +} } // namespace functor @@ -456,32 +453,34 @@ class RandomGammaOp : public OpKernel { } // namespace -#define REGISTER(TYPE) \ - REGISTER_KERNEL_BUILDER( \ - Name("RandomUniform") \ - .Device(DEVICE_CPU) \ - .HostMemory("shape") \ - .TypeConstraint("dtype"), \ - PhiloxRandomOp >); \ - REGISTER_KERNEL_BUILDER( \ - Name("RandomStandardNormal") \ - .Device(DEVICE_CPU) \ - .HostMemory("shape") \ - .TypeConstraint("dtype"), \ - PhiloxRandomOp >); \ - REGISTER_KERNEL_BUILDER( \ - Name("TruncatedNormal") \ - .Device(DEVICE_CPU) \ - .HostMemory("shape") \ - .TypeConstraint("dtype"), \ - PhiloxRandomOp< \ - CPUDevice, \ - random::TruncatedNormalDistribution< \ - random::SingleSampleAdapter, TYPE> >); \ - REGISTER_KERNEL_BUILDER( \ - Name("RandomGamma").Device(DEVICE_CPU).TypeConstraint("T"), \ +#define REGISTER(TYPE) \ + template struct functor::FillPhiloxRandom< \ + CPUDevice, random::UniformDistribution >; \ + REGISTER_KERNEL_BUILDER( \ + Name("RandomUniform") \ + .Device(DEVICE_CPU) \ + .HostMemory("shape") \ + .TypeConstraint("dtype"), \ + PhiloxRandomOp >); \ + REGISTER_KERNEL_BUILDER( \ + Name("RandomStandardNormal") \ + .Device(DEVICE_CPU) \ + .HostMemory("shape") \ + .TypeConstraint("dtype"), \ + PhiloxRandomOp >); \ + REGISTER_KERNEL_BUILDER( \ + Name("TruncatedNormal") \ + .Device(DEVICE_CPU) \ + .HostMemory("shape") \ + .TypeConstraint("dtype"), \ + PhiloxRandomOp< \ + CPUDevice, \ + random::TruncatedNormalDistribution< \ + random::SingleSampleAdapter, TYPE> >); \ + REGISTER_KERNEL_BUILDER( \ + Name("RandomGamma").Device(DEVICE_CPU).TypeConstraint("T"), \ RandomGammaOp) #define REGISTER_INT(IntType) \ diff --git a/tensorflow/core/kernels/random_op.h b/tensorflow/core/kernels/random_op.h index 362600fa34f46c162b13380bcb8d77cb998608ba..b52901c38e3ac9da548d44768ba2b322f3dd65b4 100644 --- a/tensorflow/core/kernels/random_op.h +++ b/tensorflow/core/kernels/random_op.h @@ -28,6 +28,20 @@ namespace functor { template struct FillPhiloxRandom; +typedef Eigen::ThreadPoolDevice CPUDevice; +// Declares the partially CPU-specialized functor struct. +// +// NOTE: Due to inlining done by the compiler, you may need to add +// explicit instantiation of the functor in random_op.cc. See example +// functor::FillPhiloxRandom. +template +struct FillPhiloxRandom { + void operator()(OpKernelContext* ctx, const CPUDevice& d, + random::PhiloxRandom gen, + typename Distribution::ResultElementType* data, int64 size, + Distribution dist); +}; + #if GOOGLE_CUDA typedef Eigen::GpuDevice GPUDevice; // Declares the partially GPU-specialized functor struct. diff --git a/tensorflow/core/kernels/reduce_join_op.cc b/tensorflow/core/kernels/reduce_join_op.cc index 1bd415c0d12cfeb0338c5ded40b735949f66a79a..b72bfeb15ff7164afbee1c75fe65bdf02df554eb 100644 --- a/tensorflow/core/kernels/reduce_join_op.cc +++ b/tensorflow/core/kernels/reduce_join_op.cc @@ -105,7 +105,7 @@ void MakeUnreducedIndices(gtl::InlinedVector index_is_reduced, TensorShape GetOutputShape(gtl::InlinedVector index_is_reduced, const TensorShape& input_shape, bool keep_dims) { TensorShape output_shape; - for (int32 index = 0; index < index_is_reduced.size(); ++index) { + for (size_t index = 0; index < index_is_reduced.size(); ++index) { if (index_is_reduced[index]) { if (keep_dims) output_shape.AddDim(1); } else { diff --git a/tensorflow/core/kernels/reduction_ops_max.cc b/tensorflow/core/kernels/reduction_ops_max.cc index 758a237c59d8f9adc56bea3fae21f0f3a8d8cebf..6d3feeb6667f1bb3b11567184b91d16a0d4fd84c 100644 --- a/tensorflow/core/kernels/reduction_ops_max.cc +++ b/tensorflow/core/kernels/reduction_ops_max.cc @@ -35,6 +35,19 @@ TF_CALL_REAL_NUMBER_TYPES(REGISTER_CPU_KERNELS); ReductionOp>); REGISTER_GPU_KERNELS(float); REGISTER_GPU_KERNELS(double); + +// A special GPU kernel for int32. +// TODO(b/25387198): Also enable int32 in device memory. This kernel +// registration requires all int32 inputs and outputs to be in host memory. +REGISTER_KERNEL_BUILDER( + Name("Max") + .Device(DEVICE_GPU) + .HostMemory("reduction_indices") + .HostMemory("input") + .HostMemory("output") + .TypeConstraint("T"), + ReductionOp>); + #undef REGISTER_GPU_KERNELS #endif diff --git a/tensorflow/core/kernels/reduction_ops_min.cc b/tensorflow/core/kernels/reduction_ops_min.cc index 2582356b926f980936ffca058c7def54dd9fc540..c567aca0b07448a0137293941ce0411ef90980be 100644 --- a/tensorflow/core/kernels/reduction_ops_min.cc +++ b/tensorflow/core/kernels/reduction_ops_min.cc @@ -35,6 +35,19 @@ TF_CALL_REAL_NUMBER_TYPES(REGISTER_CPU_KERNELS); ReductionOp>); REGISTER_GPU_KERNELS(float); REGISTER_GPU_KERNELS(double); + +// A special GPU kernel for int32. +// TODO(b/25387198): Also enable int32 in device memory. This kernel +// registration requires all int32 inputs and outputs to be in host memory. +REGISTER_KERNEL_BUILDER( + Name("Min") + .Device(DEVICE_GPU) + .HostMemory("reduction_indices") + .HostMemory("input") + .HostMemory("output") + .TypeConstraint("T"), + ReductionOp>); + #undef REGISTER_GPU_KERNELS #endif diff --git a/tensorflow/core/kernels/reverse_sequence_op.cc b/tensorflow/core/kernels/reverse_sequence_op.cc index 5825b1cd4d1b1ca99efdd9eda657c504734d068e..505c512cc424af9dee32d68d2cabb051812fd696 100644 --- a/tensorflow/core/kernels/reverse_sequence_op.cc +++ b/tensorflow/core/kernels/reverse_sequence_op.cc @@ -40,19 +40,19 @@ namespace tensorflow { typedef Eigen::ThreadPoolDevice CPUDevice; typedef Eigen::GpuDevice GPUDevice; -template +template void CheckErrors(OpKernelContext* context, int batch_dim, int seq_dim) { const Tensor& input = context->input(0); const Tensor& seq_lens = context->input(1); - auto seq_lens_t = seq_lens.vec(); + auto seq_lens_t = seq_lens.vec(); - std::vector seq_lens_vec(seq_lens_t.size()); + std::vector seq_lens_vec(seq_lens_t.size()); // Copy seq_len info down for validity checks context->eigen_device().memcpyDeviceToHost( seq_lens_vec.data(), seq_lens_t.data(), - sizeof(int64) * seq_lens_t.size()); + sizeof(Tlen) * seq_lens_t.size()); OP_REQUIRES(context, batch_dim != seq_dim, errors::InvalidArgument("batch_dim == seq_dim == ", seq_dim)); @@ -76,8 +76,7 @@ void CheckErrors(OpKernelContext* context, int batch_dim, int seq_dim) { } } -template <> -void CheckErrors(OpKernelContext* context, int batch_dim, +void CheckErrorsGPU(OpKernelContext* context, int batch_dim, int seq_dim) { const Tensor& input = context->input(0); const Tensor& seq_lens = context->input(1); @@ -97,7 +96,19 @@ void CheckErrors(OpKernelContext* context, int batch_dim, " vs. ", input.dim_size(batch_dim))); } -template +template <> +void CheckErrors(OpKernelContext* context, int batch_dim, + int seq_dim) { + CheckErrorsGPU(context, batch_dim, seq_dim); +} + +template <> +void CheckErrors(OpKernelContext* context, int batch_dim, + int seq_dim) { + CheckErrorsGPU(context, batch_dim, seq_dim); +} + +template class ReverseSequenceOp : public OpKernel { public: explicit ReverseSequenceOp(OpKernelConstruction* context) @@ -115,9 +126,9 @@ class ReverseSequenceOp : public OpKernel { errors::InvalidArgument("seq_lens input must be 1-dim, not ", seq_lens.dims())); - auto seq_lens_t = seq_lens.vec(); + auto seq_lens_t = seq_lens.vec(); - CheckErrors(context, batch_dim_, seq_dim_); + CheckErrors(context, batch_dim_, seq_dim_); const int input_dims = input.dims(); @@ -127,7 +138,7 @@ class ReverseSequenceOp : public OpKernel { #define HANDLE_DIM(NDIM) \ case NDIM: \ - functor::ReverseSequence::Compute( \ + functor::ReverseSequence::Compute( \ context->eigen_device(), input.tensor(), batch_dim_, \ seq_dim_, seq_lens_t, output->tensor()); \ break; @@ -153,42 +164,57 @@ class ReverseSequenceOp : public OpKernel { TF_DISALLOW_COPY_AND_ASSIGN(ReverseSequenceOp); }; -#define REGISTER_REVERSE_SEQUENCE(type) \ +#define REGISTER_REVERSE_SEQUENCE(type, len_type) \ REGISTER_KERNEL_BUILDER( \ - Name("ReverseSequence").Device(DEVICE_CPU).TypeConstraint("T"), \ - ReverseSequenceOp); + Name("ReverseSequence").Device(DEVICE_CPU).TypeConstraint("T"). \ + TypeConstraint("Tlen"), \ + ReverseSequenceOp); -TF_CALL_NUMBER_TYPES(REGISTER_REVERSE_SEQUENCE); +#define REGISTER_REVERSE_SEQUENCE_LEN(type) \ + REGISTER_REVERSE_SEQUENCE(type, int32); \ + REGISTER_REVERSE_SEQUENCE(type, int64); + +TF_CALL_NUMBER_TYPES(REGISTER_REVERSE_SEQUENCE_LEN); #if GOOGLE_CUDA // Forward declarations of the functor specializations for GPU. namespace functor { -#define DECLARE_GPU_SPEC(T, Dims) \ - template <> \ - void ReverseSequence::Compute( \ - const GPUDevice& d, typename TTypes::ConstTensor input, \ - int32 batch_dim, int32 seq_dim, TTypes::ConstVec seq_lens, \ - typename TTypes::Tensor output); \ - extern template struct ReverseSequence; - -#define DECLARE_GPU_SPECS(T) \ - DECLARE_GPU_SPEC(T, 2); \ - DECLARE_GPU_SPEC(T, 3); \ - DECLARE_GPU_SPEC(T, 4); \ - DECLARE_GPU_SPEC(T, 5); +#define DECLARE_GPU_SPEC(T, Tlen, Dims) \ + template <> \ + void ReverseSequence::Compute( \ + const GPUDevice& d, typename TTypes::ConstTensor input, \ + int32 batch_dim, int32 seq_dim, \ + typename TTypes::ConstVec seq_lens, \ + typename TTypes::Tensor output); \ + extern template struct ReverseSequence; + +#define DECLARE_GPU_SPEC_LEN(T, Dims) \ + DECLARE_GPU_SPEC(T, int32, Dims); \ + DECLARE_GPU_SPEC(T, int64, Dims); + +#define DECLARE_GPU_SPECS(T) \ + DECLARE_GPU_SPEC_LEN(T, 2); \ + DECLARE_GPU_SPEC_LEN(T, 3); \ + DECLARE_GPU_SPEC_LEN(T, 4); \ + DECLARE_GPU_SPEC_LEN(T, 5); TF_CALL_GPU_NUMBER_TYPES(DECLARE_GPU_SPECS); } // namespace functor // Registration of the GPU implementations. -#define REGISTER_REVERSE_SEQUENCE_GPU(type) \ +#define REGISTER_REVERSE_SEQUENCE_GPU(type, len_type) \ REGISTER_KERNEL_BUILDER( \ - Name("ReverseSequence").Device(DEVICE_GPU).TypeConstraint("T"), \ - ReverseSequenceOp); + Name("ReverseSequence").Device(DEVICE_GPU).TypeConstraint("T"). \ + TypeConstraint("Tlen"), \ + ReverseSequenceOp); + +#define REGISTER_REVERSE_SEQUENCE_GPU_LEN(type) \ + REGISTER_REVERSE_SEQUENCE_GPU(type, int32); \ + REGISTER_REVERSE_SEQUENCE_GPU(type, int64); -TF_CALL_GPU_NUMBER_TYPES(REGISTER_REVERSE_SEQUENCE_GPU); +TF_CALL_GPU_NUMBER_TYPES(REGISTER_REVERSE_SEQUENCE_GPU_LEN); #undef REGISTER_REVERSE_SEQUENCE_GPU diff --git a/tensorflow/core/kernels/reverse_sequence_op.h b/tensorflow/core/kernels/reverse_sequence_op.h index 72c59d59aadc4e7475a8b14789d30502e47fb5ca..8ccd32ea1609d91b39581ebb81d06100dfb5500e 100644 --- a/tensorflow/core/kernels/reverse_sequence_op.h +++ b/tensorflow/core/kernels/reverse_sequence_op.h @@ -25,12 +25,12 @@ namespace tensorflow { namespace generator { -template +template class ReverseGenerator { public: EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE ReverseGenerator(typename TTypes::ConstTensor input, int32 batch_dim, - int32 seq_dim, TTypes::ConstVec seq_lengths) + int32 seq_dim, typename TTypes::ConstVec seq_lengths) : input_(input), batch_dim_(batch_dim), seq_dim_(seq_dim), @@ -51,21 +51,22 @@ class ReverseGenerator { typename TTypes::ConstTensor input_; int32 batch_dim_; int32 seq_dim_; - TTypes::ConstVec seq_lengths_; + typename TTypes::ConstVec seq_lengths_; }; } // namespace generator namespace functor { -template +template struct ReverseSequence { EIGEN_ALWAYS_INLINE static void Compute( const Device& d, typename TTypes::ConstTensor input, - int32 batch_dim, int32 seq_dim, TTypes::ConstVec seq_lengths, + int32 batch_dim, int32 seq_dim, + typename TTypes::ConstVec seq_lengths, typename TTypes::Tensor output) { - generator::ReverseGenerator generator(input, batch_dim, seq_dim, - seq_lengths); + generator::ReverseGenerator generator(input, batch_dim, + seq_dim, seq_lengths); output.device(d) = input.generate(generator); } }; diff --git a/tensorflow/core/kernels/reverse_sequence_op_gpu.cu.cc b/tensorflow/core/kernels/reverse_sequence_op_gpu.cu.cc index bcc265c624df50c181fe8775ac09fcdb6bca275d..373fd60687391c289db99ff22301884b3f24d1c7 100644 --- a/tensorflow/core/kernels/reverse_sequence_op_gpu.cu.cc +++ b/tensorflow/core/kernels/reverse_sequence_op_gpu.cu.cc @@ -24,15 +24,19 @@ namespace tensorflow { typedef Eigen::GpuDevice GPUDevice; -#define DEFINE_GPU_SPEC(T, dims) \ - template class generator::ReverseGenerator; \ - template struct functor::ReverseSequence; +#define DEFINE_GPU_SPEC(T, Tlen, dims) \ + template class generator::ReverseGenerator; \ + template struct functor::ReverseSequence; + +#define DEFINE_GPU_SPEC_LEN(T, dims) \ + DEFINE_GPU_SPEC(T, int32, dims); \ + DEFINE_GPU_SPEC(T, int64, dims); #define DEFINE_GPU_SPECS(T) \ - DEFINE_GPU_SPEC(T, 2); \ - DEFINE_GPU_SPEC(T, 3); \ - DEFINE_GPU_SPEC(T, 4); \ - DEFINE_GPU_SPEC(T, 5); + DEFINE_GPU_SPEC_LEN(T, 2); \ + DEFINE_GPU_SPEC_LEN(T, 3); \ + DEFINE_GPU_SPEC_LEN(T, 4); \ + DEFINE_GPU_SPEC_LEN(T, 5); TF_CALL_GPU_NUMBER_TYPES(DEFINE_GPU_SPECS); diff --git a/tensorflow/core/kernels/scan_ops.cc b/tensorflow/core/kernels/scan_ops.cc index e6505dff6e77d3e623c7de307df1a33d9d2744fe..604e712b0fd9375fb704ea459d6a0a1639b0c6b4 100644 --- a/tensorflow/core/kernels/scan_ops.cc +++ b/tensorflow/core/kernels/scan_ops.cc @@ -62,6 +62,9 @@ public: Tensor* output = nullptr; OP_REQUIRES_OK(ctx, ctx->allocate_output(0, output_shape, &output)); + // Exit early if there's nothing to compute + if (output_shape.num_elements() == 0) return; + const Device& d = ctx->eigen_device(); Reducer reducer; diff --git a/tensorflow/core/kernels/self_adjoint_eig_op.cc b/tensorflow/core/kernels/self_adjoint_eig_op.cc index 9d3a411f3b2f504c9ecc9ce1375b9b7f2b43f8af..97657807268d30d66a01573bc3df09e318ce1d51 100644 --- a/tensorflow/core/kernels/self_adjoint_eig_op.cc +++ b/tensorflow/core/kernels/self_adjoint_eig_op.cc @@ -28,11 +28,10 @@ limitations under the License. namespace tensorflow { -template -class SelfAdjointEigOp - : public LinearAlgebraOp { +template +class SelfAdjointEigOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit SelfAdjointEigOp(OpKernelConstruction* context) : Base(context) {} @@ -69,10 +68,8 @@ class SelfAdjointEigOp } }; -REGISTER_LINALG_OP("SelfAdjointEig", (SelfAdjointEigOp), float); -REGISTER_LINALG_OP("SelfAdjointEig", (SelfAdjointEigOp), double); -REGISTER_LINALG_OP("BatchSelfAdjointEig", (SelfAdjointEigOp), - float); -REGISTER_LINALG_OP("BatchSelfAdjointEig", (SelfAdjointEigOp), - double); +REGISTER_LINALG_OP("SelfAdjointEig", (SelfAdjointEigOp), float); +REGISTER_LINALG_OP("SelfAdjointEig", (SelfAdjointEigOp), double); +REGISTER_LINALG_OP("BatchSelfAdjointEig", (SelfAdjointEigOp), float); +REGISTER_LINALG_OP("BatchSelfAdjointEig", (SelfAdjointEigOp), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/self_adjoint_eig_v2_op.cc b/tensorflow/core/kernels/self_adjoint_eig_v2_op.cc index 1b457ebe9efb8a7fe69857e98b737f8103f51bfb..c647d3aaac6bc486a850f3883a4533ba96160a1c 100644 --- a/tensorflow/core/kernels/self_adjoint_eig_v2_op.cc +++ b/tensorflow/core/kernels/self_adjoint_eig_v2_op.cc @@ -27,11 +27,10 @@ limitations under the License. namespace tensorflow { -template -class SelfAdjointEigV2Op - : public LinearAlgebraOp { +template +class SelfAdjointEigV2Op : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit SelfAdjointEigV2Op(OpKernelConstruction* context) : Base(context) { OP_REQUIRES_OK(context, context->GetAttr("compute_v", &compute_v_)); @@ -80,12 +79,9 @@ class SelfAdjointEigV2Op bool compute_v_; }; -REGISTER_LINALG_OP("SelfAdjointEigV2", (SelfAdjointEigV2Op), - float); -REGISTER_LINALG_OP("SelfAdjointEigV2", (SelfAdjointEigV2Op), - double); -REGISTER_LINALG_OP("BatchSelfAdjointEigV2", (SelfAdjointEigV2Op), - float); -REGISTER_LINALG_OP("BatchSelfAdjointEigV2", (SelfAdjointEigV2Op), +REGISTER_LINALG_OP("SelfAdjointEigV2", (SelfAdjointEigV2Op), float); +REGISTER_LINALG_OP("SelfAdjointEigV2", (SelfAdjointEigV2Op), double); +REGISTER_LINALG_OP("BatchSelfAdjointEigV2", (SelfAdjointEigV2Op), float); +REGISTER_LINALG_OP("BatchSelfAdjointEigV2", (SelfAdjointEigV2Op), double); } // namespace tensorflow diff --git a/tensorflow/core/kernels/softplus_op.h b/tensorflow/core/kernels/softplus_op.h index f019837f1674a23a2ba5ac550c812d6485c37d91..e17e175d410500899aa6ecceb3edab6e2df53a7b 100644 --- a/tensorflow/core/kernels/softplus_op.h +++ b/tensorflow/core/kernels/softplus_op.h @@ -33,9 +33,24 @@ struct Softplus { // activations: same shape as "features". void operator()(const Device& d, typename TTypes::ConstTensor features, typename TTypes::Tensor activations) { - activations.device(d) = - (features > features.constant(T(30))) - .select(features, (features.exp() + features.constant(T(1))).log()); + // Choose a threshold on x below which exp(x) may underflow + // when added to 1, but for which exp(x) is always within epsilon of the + // true softplus(x). Offset of 2 from machine epsilon checked + // experimentally for float16, float32, float64. Checked against + // softplus implemented with numpy's log1p and numpy's logaddexp. + static const T threshold = + Eigen::numext::log(Eigen::NumTraits::epsilon()) + T(2); + // Value above which exp(x) may overflow, but softplus(x) == x + // is within machine epsilon. + auto too_large = features > features.constant(-threshold); + // Value below which exp(x) may underflow, but softplus(x) == exp(x) + // is within machine epsilon. + auto too_small = features < features.constant(threshold); + auto features_exp = features.exp(); + activations.device(d) = too_large.select( + features, // softplus(x) ~= x for x large + too_small.select(features_exp, // softplus(x) ~= exp(x) for x small + (features_exp + features.constant(T(1))).log())); } }; diff --git a/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc b/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc index dbd1d9466c0d6ce77060dd212f4125401c8da806..2d1539fb9d993da38e5547520abda6bf5461684c 100644 --- a/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc +++ b/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc @@ -91,7 +91,7 @@ class SparseDenseBinaryOpShared : public OpKernel { auto VecGreaterEq = [](ArraySlice lhs, ArraySlice rhs) { if (lhs.size() > rhs.size()) return true; if (lhs.size() < rhs.size()) return false; - for (int i = 0; i < lhs.size(); ++i) { + for (size_t i = 0; i < lhs.size(); ++i) { if (lhs[i] < rhs[i]) return false; } return true; diff --git a/tensorflow/core/kernels/summary_op.cc b/tensorflow/core/kernels/summary_op.cc index 7cbced25908407c666b2d2019f061c67d777a739..af75fe92c9a95c0494d3c339d646807394e9c8ef 100644 --- a/tensorflow/core/kernels/summary_op.cc +++ b/tensorflow/core/kernels/summary_op.cc @@ -146,10 +146,12 @@ class SummaryMergeOp : public OpKernel { } for (int v = 0; v < summary_in.value_size(); v++) { - if (!tags.insert(summary_in.value(v).tag()).second) { - c->SetStatus(errors::InvalidArgument( - strings::StrCat("Duplicate tag ", summary_in.value(v).tag(), - " found in summary inputs"))); + const string& tag = summary_in.value(v).tag(); + // The tag is unused by the TensorSummary op, so no need to check + // for duplicates. + if ((tag != "") && !tags.insert(tag).second) { + c->SetStatus(errors::InvalidArgument(strings::StrCat( + "Duplicate tag ", tag, " found in summary inputs"))); return; } *s.add_value() = summary_in.value(v); diff --git a/tensorflow/core/kernels/svd_op.cc b/tensorflow/core/kernels/svd_op.cc index 16e0d5f9645c217a912b2edb1bc31a4f3dd7f69b..36d049895812e766d2503daa38b619274fa9947e 100644 --- a/tensorflow/core/kernels/svd_op.cc +++ b/tensorflow/core/kernels/svd_op.cc @@ -28,10 +28,10 @@ limitations under the License. namespace tensorflow { -template -class SvdOp : public LinearAlgebraOp { +template +class SvdOp : public LinearAlgebraOp { public: - typedef LinearAlgebraOp Base; + typedef LinearAlgebraOp Base; explicit SvdOp(OpKernelConstruction* context) : Base(context) { OP_REQUIRES_OK(context, context->GetAttr("compute_uv", &compute_uv_)); @@ -97,13 +97,13 @@ class SvdOp : public LinearAlgebraOp { TF_DISALLOW_COPY_AND_ASSIGN(SvdOp); }; -REGISTER_LINALG_OP("Svd", (SvdOp), float); -REGISTER_LINALG_OP("Svd", (SvdOp), double); -REGISTER_LINALG_OP("Svd", (SvdOp), complex64); -REGISTER_LINALG_OP("Svd", (SvdOp), complex128); -REGISTER_LINALG_OP("BatchSvd", (SvdOp), float); -REGISTER_LINALG_OP("BatchSvd", (SvdOp), double); -REGISTER_LINALG_OP("BatchSvd", (SvdOp), complex64); -REGISTER_LINALG_OP("BatchSvd", (SvdOp), complex128); +REGISTER_LINALG_OP("Svd", (SvdOp), float); +REGISTER_LINALG_OP("Svd", (SvdOp), double); +REGISTER_LINALG_OP("Svd", (SvdOp), complex64); +REGISTER_LINALG_OP("Svd", (SvdOp), complex128); +REGISTER_LINALG_OP("BatchSvd", (SvdOp), float); +REGISTER_LINALG_OP("BatchSvd", (SvdOp), double); +REGISTER_LINALG_OP("BatchSvd", (SvdOp), complex64); +REGISTER_LINALG_OP("BatchSvd", (SvdOp), complex128); } // namespace tensorflow diff --git a/tensorflow/core/kernels/transpose_functor_cpu.cc b/tensorflow/core/kernels/transpose_functor_cpu.cc index 07de6e0b6a270699ff639aea0322f9c7ca4cee7b..f8c87e7e2e1c112669364c5bff473bda960068ff 100644 --- a/tensorflow/core/kernels/transpose_functor_cpu.cc +++ b/tensorflow/core/kernels/transpose_functor_cpu.cc @@ -80,6 +80,7 @@ Status DoTranspose(const Device& d, const Tensor& in, break; case DT_BFLOAT16: + case DT_HALF: case DT_INT16: case DT_QINT16: case DT_QUINT16: diff --git a/tensorflow/core/lib/core/coding.cc b/tensorflow/core/lib/core/coding.cc index fb698cf53c9d1a0dcd3f0bcb571ca8595a3c7957..21fb548053c236ecc104dd838b1103e5e550bc83 100644 --- a/tensorflow/core/lib/core/coding.cc +++ b/tensorflow/core/lib/core/coding.cc @@ -15,7 +15,7 @@ limitations under the License. #include "tensorflow/core/lib/core/coding.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" namespace tensorflow { namespace core { diff --git a/tensorflow/core/lib/core/coding.h b/tensorflow/core/lib/core/coding.h index 94779f9f29c36e3407b8333abc56804514524005..77d52a909baa6c1795a753ee26f51cc3c17d9dc8 100644 --- a/tensorflow/core/lib/core/coding.h +++ b/tensorflow/core/lib/core/coding.h @@ -28,6 +28,9 @@ limitations under the License. namespace tensorflow { namespace core { +// Maximum number of bytes occupied by a varint32. +static const int kMaxVarint32Bytes = 5; + // Lower-level versions of Put... that write directly into a character buffer // REQUIRES: dst has enough space for the value being written extern void EncodeFixed16(char* dst, uint16 value); diff --git a/tensorflow/core/lib/core/notification.h b/tensorflow/core/lib/core/notification.h index 56e8ac6b2a7a28e2ab8247dd8a86abbad375f284..b3e515e28f96b5b62ba4a849b40840909d7603b2 100644 --- a/tensorflow/core/lib/core/notification.h +++ b/tensorflow/core/lib/core/notification.h @@ -16,52 +16,8 @@ limitations under the License. #ifndef TENSORFLOW_UTIL_NOTIFICATION_H_ #define TENSORFLOW_UTIL_NOTIFICATION_H_ -#include -#include // NOLINT -#include // NOLINT - -#include "tensorflow/core/platform/mutex.h" -#include "tensorflow/core/platform/types.h" - -namespace tensorflow { - -class Notification { - public: - Notification() : notified_(false) {} - ~Notification() {} - - void Notify() { - mutex_lock l(mu_); - assert(!notified_); - notified_ = true; - cv_.notify_all(); - } - - bool HasBeenNotified() { - mutex_lock l(mu_); - return notified_; - } - - void WaitForNotification() { - mutex_lock l(mu_); - while (!notified_) { - cv_.wait(l); - } - } - - bool WaitForNotificationWithTimeout(int64 timeout_in_ms) { - mutex_lock l(mu_); - std::cv_status s = - cv_.wait_for(l, std::chrono::milliseconds(timeout_in_ms)); - return (s == std::cv_status::timeout) ? true : false; - } - - private: - mutex mu_; - condition_variable cv_; - bool notified_; -}; - -} // namespace tensorflow +// Notification implementation is platform-dependent, to support +// alternative synchronization primitives. +#include "tensorflow/core/platform/notification.h" #endif // TENSORFLOW_UTIL_NOTIFICATION_H_ diff --git a/tensorflow/core/lib/core/notification_test.cc b/tensorflow/core/lib/core/notification_test.cc index a281437d4742c915b1c8d9bca4f9c15daa0268aa..8cb1c895ad7b25ac2b714395d02a56d2a2e1c451 100644 --- a/tensorflow/core/lib/core/notification_test.cc +++ b/tensorflow/core/lib/core/notification_test.cc @@ -76,5 +76,11 @@ TEST(NotificationTest, TestMultipleThreadsWaitingOnNotification) { EXPECT_EQ(4, counter); } +TEST(NotificationTest, TestWaitWithTimeoutOnNotifiedNotification) { + Notification n; + n.Notify(); + EXPECT_TRUE(WaitForNotificationWithTimeout(&n, 1000)); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/core/lib/core/raw_coding.h b/tensorflow/core/lib/core/raw_coding.h index 6cab6b86805d3bfa08b4de5326f6cc007b87be6d..bbfd33d3037456e88d43fdae6e8570155f7ae90b 100644 --- a/tensorflow/core/lib/core/raw_coding.h +++ b/tensorflow/core/lib/core/raw_coding.h @@ -17,7 +17,7 @@ limitations under the License. #define TENSORFLOW_LIB_CORE_RAW_CODING_H_ #include -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/types.h" namespace tensorflow { diff --git a/tensorflow/core/lib/gtl/inlined_vector.h b/tensorflow/core/lib/gtl/inlined_vector.h index 14b670530f7e65ae9a2e7e49818b26c2a342b2df..21af965da2e52520520830c878fc31557e42d004 100644 --- a/tensorflow/core/lib/gtl/inlined_vector.h +++ b/tensorflow/core/lib/gtl/inlined_vector.h @@ -42,7 +42,7 @@ limitations under the License. #include #include "tensorflow/core/lib/gtl/manual_constructor.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/types.h" diff --git a/tensorflow/core/lib/io/buffered_inputstream.cc b/tensorflow/core/lib/io/buffered_inputstream.cc new file mode 100644 index 0000000000000000000000000000000000000000..2a1cd0ca219fb7d7ce11e7c5643c57961fe3c64a --- /dev/null +++ b/tensorflow/core/lib/io/buffered_inputstream.cc @@ -0,0 +1,147 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/lib/io/buffered_inputstream.h" + +#include "tensorflow/core/lib/io/random_inputstream.h" + +namespace tensorflow { +namespace io { + +BufferedInputStream::BufferedInputStream(InputStreamInterface* input_stream, + size_t buffer_size, + bool owns_input_stream) + : input_stream_(input_stream), + size_(buffer_size), + owns_input_stream_(owns_input_stream) { + buf_.reserve(size_); +} + +BufferedInputStream::BufferedInputStream(RandomAccessFile* file, + size_t buffer_size) + : BufferedInputStream(new RandomAccessInputStream(file), buffer_size, + true) {} + +BufferedInputStream::~BufferedInputStream() { + if (owns_input_stream_) { + delete input_stream_; + } +} + +Status BufferedInputStream::FillBuffer() { + Status s = input_stream_->ReadNBytes(size_, &buf_); + pos_ = 0; + limit_ = buf_.size(); + return s; +} + +Status BufferedInputStream::ReadLineHelper(string* result, bool include_eol) { + result->clear(); + Status s; + while (true) { + if (pos_ == limit_) { + // Get more data into buffer + s = FillBuffer(); + if (limit_ == 0) { + break; + } + } + char c = buf_[pos_++]; + if (c == '\n') { + if (include_eol) { + *result += c; + } + return Status::OK(); + } + // We don't append '\r' to *result + if (c != '\r') { + *result += c; + } + } + if (errors::IsOutOfRange(s) && !result->empty()) { + return Status::OK(); + } + return s; +} + +Status BufferedInputStream::ReadNBytes(int64 bytes_to_read, string* result) { + if (bytes_to_read < 0) { + return errors::InvalidArgument("Can't read a negative number of bytes: ", + bytes_to_read); + } + result->clear(); + result->reserve(bytes_to_read); + + Status s; + while (result->size() < static_cast(bytes_to_read)) { + // Check whether the buffer is fully read or not. + if (pos_ == limit_) { + s = FillBuffer(); + // If we didn't read any bytes, we're at the end of the file; break out. + if (limit_ == 0) { + break; + } + } + const int64 bytes_to_copy = + std::min(limit_ - pos_, bytes_to_read - result->size()); + result->insert(result->size(), buf_, pos_, bytes_to_copy); + pos_ += bytes_to_copy; + } + // Filling the buffer might lead to a situation when we go past the end of + // the file leading to an OutOfRange() status return. But we might have + // obtained enough data to satisfy the function call. Returning OK then. + if (errors::IsOutOfRange(s) && + (result->size() == static_cast(bytes_to_read))) { + return Status::OK(); + } + return s; +} + +Status BufferedInputStream::SkipNBytes(int64 bytes_to_skip) { + if (bytes_to_skip < 0) { + return errors::InvalidArgument("Can only skip forward, not ", + bytes_to_skip); + } + if (pos_ + bytes_to_skip < limit_) { + // If we aren't skipping too much, then we can just move pos_; + pos_ += bytes_to_skip; + } else { + // Otherwise, we already have read limit_ - pos_, so skip the rest. At this + // point we need to get fresh data into the buffer, so reset pos_ and + // limit_. + Status s = input_stream_->SkipNBytes(bytes_to_skip - (limit_ - pos_)); + pos_ = 0; + limit_ = 0; + return s; + } + return Status::OK(); +} + +int64 BufferedInputStream::Tell() const { + return input_stream_->Tell() - (limit_ - pos_); +} + +Status BufferedInputStream::ReadLine(string* result) { + return ReadLineHelper(result, false); +} + +string BufferedInputStream::ReadLineAsString() { + string result; + ReadLineHelper(&result, true); + return result; +} + +} // namespace io +} // namespace tensorflow diff --git a/tensorflow/core/lib/io/buffered_inputstream.h b/tensorflow/core/lib/io/buffered_inputstream.h new file mode 100644 index 0000000000000000000000000000000000000000..013c2a80229ee7637c1e06d731fda9855ea331ef --- /dev/null +++ b/tensorflow/core/lib/io/buffered_inputstream.h @@ -0,0 +1,85 @@ +/* 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LIB_IO_BUFFERED_INPUTSTREAM_H_ +#define TENSORFLOW_LIB_IO_BUFFERED_INPUTSTREAM_H_ + +#include "tensorflow/core/lib/io/inputstream_interface.h" +#include "tensorflow/core/platform/file_system.h" + +namespace tensorflow { +namespace io { + +// Provides a buffer on top of an InputStreamInterface. A single instance of +// BufferedInputStream is NOT safe for concurrent use by multiple threads. +class BufferedInputStream : public InputStreamInterface { + public: + // Does not take ownership of input_stream unless owns_input_stream is set + // to true. input_stream must outlive *this then. + // TODO(rohanj): Remove owns_input_stream once the constructor below is + // removed. + BufferedInputStream(InputStreamInterface* input_stream, size_t buffer_bytes, + bool owns_input_stream = false); + + // For backwards compatibility, expose an interface that is similar to what + // InputBuffer exposes. Does not take ownership of file. file must outlive + // *this. This will be removed once we migrate all uses of this class to the + // constructor above. + BufferedInputStream(RandomAccessFile* file, size_t buffer_bytes); + + ~BufferedInputStream() override; + + Status ReadNBytes(int64 bytes_to_read, string* result) override; + + Status SkipNBytes(int64 bytes_to_skip) override; + + int64 Tell() const override; + + // Read one text line of data into "*result" until end-of-file or a + // \n is read. (The \n is not included in the result.) Overwrites + // any existing data in *result. + // + // If successful, returns OK. If we are already at the end of the + // file, we return an OUT_OF_RANGE error. Otherwise, we return + // some other non-OK status. + Status ReadLine(string* result); + + // Returns one text line of data until end-of-file or a '\n' is read. The '\n' + // is included in the result. + // This method is a substitute for ReadLine() when called from Python which is + // the expectation in the python File::readline() API. + // Also, '\0's are treated like any other character within the line and given + // no special treatment. + string ReadLineAsString(); + + private: + Status FillBuffer(); + Status ReadLineHelper(string* result, bool include_eol); + + InputStreamInterface* input_stream_; // not owned. + size_t size_; // buffer size. + string buf_; // the buffer itself. + // buf_[pos_, limit_) holds the valid "read ahead" data in the file. + size_t pos_ = 0; // current position in buf_. + size_t limit_ = 0; // just past the end of valid data in buf_. + bool owns_input_stream_ = false; + + TF_DISALLOW_COPY_AND_ASSIGN(BufferedInputStream); +}; + +} // namespace io +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_LIB_IO_BUFFERED_INPUTSTREAM_H_ diff --git a/tensorflow/core/lib/io/buffered_inputstream_test.cc b/tensorflow/core/lib/io/buffered_inputstream_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..1263f0f9aad24b52c07bbe874dd3fe7a60ff9d01 --- /dev/null +++ b/tensorflow/core/lib/io/buffered_inputstream_test.cc @@ -0,0 +1,298 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/lib/io/buffered_inputstream.h" + +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/lib/io/random_inputstream.h" +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { +namespace io { +namespace { + +static std::vector BufferSizes() { + return {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 65536}; +} + +TEST(BufferedInputStream, ReadLine_Empty) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, ""); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + BufferedInputStream in(input_stream.get(), buf_size); + string line; + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + } +} + +TEST(BufferedInputStream, ReadLine1) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "line one\nline two\nline three\n"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + BufferedInputStream in(input_stream.get(), buf_size); + string line; + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line one"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line two"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line three"); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + // A second call should also return end of file + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + } +} + +TEST(BufferedInputStream, ReadLine_NoTrailingNewLine) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "line one\nline two\nline three"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + BufferedInputStream in(input_stream.get(), buf_size); + string line; + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line one"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line two"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line three"); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + // A second call should also return end of file + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + } +} + +TEST(BufferedInputStream, ReadLine_EmptyLines) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "line one\n\n\nline two\nline three"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + BufferedInputStream in(input_stream.get(), buf_size); + string line; + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line one"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, ""); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, ""); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line two"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line three"); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + // A second call should also return end of file + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + } +} + +TEST(BufferedInputStream, ReadLine_CRLF) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "line one\r\n\r\n\r\nline two\r\nline three"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + BufferedInputStream in(input_stream.get(), buf_size); + string line; + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line one"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, ""); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, ""); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line two"); + TF_ASSERT_OK(in.ReadLine(&line)); + EXPECT_EQ(line, "line three"); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + // A second call should also return end of file + EXPECT_TRUE(errors::IsOutOfRange(in.ReadLine(&line))); + } +} + +TEST(BufferedInputStream, ReadNBytes) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffer_test"; + WriteStringToFile(env, fname, "0123456789"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + string read; + BufferedInputStream in(input_stream.get(), buf_size); + EXPECT_EQ(0, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(3, &read)); + EXPECT_EQ(read, "012"); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(4, &read)); + EXPECT_EQ(read, "3456"); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(7, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, "789"); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + } +} + +TEST(BufferedInputStream, SkipNBytes) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "0123456789"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr input_stream( + new RandomAccessInputStream(file.get())); + string read; + BufferedInputStream in(input_stream.get(), buf_size); + EXPECT_EQ(0, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(3)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(0)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(2, &read)); + EXPECT_EQ(read, "34"); + EXPECT_EQ(5, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(0)); + EXPECT_EQ(5, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(2)); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(1, &read)); + EXPECT_EQ(read, "7"); + EXPECT_EQ(8, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.SkipNBytes(5))); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.SkipNBytes(5))); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + } +} + +TEST(BufferedInputStream, ReadNBytesRandomAccessFile) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffer_test"; + WriteStringToFile(env, fname, "0123456789"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + string read; + BufferedInputStream in(file.get(), buf_size); + EXPECT_EQ(0, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(3, &read)); + EXPECT_EQ(read, "012"); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(4, &read)); + EXPECT_EQ(read, "3456"); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(7, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, "789"); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + } +} + +TEST(BufferedInputStream, SkipNBytesRandomAccessFile) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/buffered_inputstream_test"; + WriteStringToFile(env, fname, "0123456789"); + std::unique_ptr file; + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); + + for (auto buf_size : BufferSizes()) { + string read; + BufferedInputStream in(file.get(), buf_size); + EXPECT_EQ(0, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(3)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(0)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(2, &read)); + EXPECT_EQ(read, "34"); + EXPECT_EQ(5, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(0)); + EXPECT_EQ(5, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(2)); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(1, &read)); + EXPECT_EQ(read, "7"); + EXPECT_EQ(8, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.SkipNBytes(5))); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.SkipNBytes(5))); + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); + EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); + } +} + +} // anonymous namespace +} // namespace io +} // namespace tensorflow diff --git a/tensorflow/core/lib/io/inputbuffer.cc b/tensorflow/core/lib/io/inputbuffer.cc index 39b5d70da62508cc077c18ed9b54168713a7182b..9cff1d349e8724e73499755262283155c55fd58f 100644 --- a/tensorflow/core/lib/io/inputbuffer.cc +++ b/tensorflow/core/lib/io/inputbuffer.cc @@ -27,9 +27,7 @@ InputBuffer::InputBuffer(RandomAccessFile* file, size_t buffer_bytes) pos_(buf_), limit_(buf_) {} -InputBuffer::~InputBuffer() { - delete[] buf_; -} +InputBuffer::~InputBuffer() { delete[] buf_; } Status InputBuffer::FillBuffer() { StringPiece data; @@ -77,26 +75,56 @@ Status InputBuffer::ReadNBytes(int64 bytes_to_read, string* result) { return errors::InvalidArgument("Can't read a negative number of bytes: ", bytes_to_read); } - result->reserve(bytes_to_read); - Status s; - while (result->size() < static_cast(bytes_to_read)) { + result->resize(bytes_to_read); + size_t bytes_read = 0; + Status status = ReadNBytes(bytes_to_read, &(*result)[0], &bytes_read); + if (bytes_read < bytes_to_read) result->resize(bytes_read); + return status; +} + +Status InputBuffer::ReadNBytes(int64 bytes_to_read, char* result, + size_t* bytes_read) { + if (bytes_to_read < 0) { + return errors::InvalidArgument("Can't read a negative number of bytes: ", + bytes_to_read); + } + Status status; + *bytes_read = 0; + while (*bytes_read < static_cast(bytes_to_read)) { if (pos_ == limit_) { - // Get more data into buffer - s = FillBuffer(); + // Get more data into buffer. + status = FillBuffer(); if (limit_ == buf_) { break; } } + // Do not go over the buffer boundary. const int64 bytes_to_copy = - std::min(limit_ - pos_, bytes_to_read - result->size()); - result->insert(result->size(), pos_, bytes_to_copy); + std::min(limit_ - pos_, bytes_to_read - *bytes_read); + // Copies buffered data into the destination. + memcpy(result + *bytes_read, pos_, bytes_to_copy); pos_ += bytes_to_copy; + *bytes_read += bytes_to_copy; } - if (errors::IsOutOfRange(s) && - (result->size() == static_cast(bytes_to_read))) { + if (errors::IsOutOfRange(status) && + (*bytes_read == static_cast(bytes_to_read))) { return Status::OK(); } - return s; + return status; +} + +Status InputBuffer::ReadVarint32Fallback(uint32* result) { + uint8 scratch = 0; + char* p = reinterpret_cast(&scratch); + size_t unused_bytes_read = 0; + + *result = 0; + for (int shift = 0; shift <= 28; shift += 7) { + TF_RETURN_IF_ERROR(ReadNBytes(1, p, &unused_bytes_read)); + *result |= (scratch & 127) << shift; + if (!(scratch & 128)) return Status::OK(); + } + return errors::DataLoss("Stored data is too large to be a varint32."); } Status InputBuffer::SkipNBytes(int64 bytes_to_skip) { @@ -125,5 +153,24 @@ Status InputBuffer::SkipNBytes(int64 bytes_to_skip) { return s; } +Status InputBuffer::Seek(int64 position) { + if (position < 0) { + return errors::InvalidArgument("Seeking to a negative position: ", + position); + } + // Position of the buffer within file. + const int64 bufpos = file_pos_ - static_cast(limit_ - buf_); + if (position >= bufpos && position < file_pos_) { + // Seeks to somewhere inside the buffer. + pos_ = buf_ + (position - bufpos); + DCHECK(pos_ >= buf_ && pos_ < limit_); + } else { + // Seeks to somewhere outside. Discards the buffered data. + pos_ = limit_ = buf_; + file_pos_ = position; + } + return Status::OK(); +} + } // namespace io } // namespace tensorflow diff --git a/tensorflow/core/lib/io/inputbuffer.h b/tensorflow/core/lib/io/inputbuffer.h index 9665a452410ca27fd0ec456269fcd8f34d374512..02dfda74e3ffb92976f2c50a4c416343a18fe9ce 100644 --- a/tensorflow/core/lib/io/inputbuffer.h +++ b/tensorflow/core/lib/io/inputbuffer.h @@ -17,6 +17,7 @@ limitations under the License. #define TENSORFLOW_LIB_IO_INPUTBUFFER_H_ #include +#include "tensorflow/core/lib/core/coding.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/macros.h" @@ -51,15 +52,33 @@ class InputBuffer { // Otherwise, we return some other non-OK status. Status ReadNBytes(int64 bytes_to_read, string* result); + // An overload that writes to char*. Caller must ensure result[0, + // bytes_to_read) is valid to be overwritten. Returns OK iff "*bytes_read == + // bytes_to_read". + Status ReadNBytes(int64 bytes_to_read, char* result, size_t* bytes_read); + + // Reads a single varint32. + Status ReadVarint32(uint32* result); + // Like ReadNBytes() without returning the bytes read. Status SkipNBytes(int64 bytes_to_skip); + // Seek to this offset within the file. + // + // If we seek to somewhere within our pre-buffered data, we will re-use what + // data we can. Otherwise, Seek() throws out the current buffer and the next + // read will trigger a File::Read(). + Status Seek(int64 position); + // Returns the position in the file. int64 Tell() const { return file_pos_ - (limit_ - pos_); } private: Status FillBuffer(); + // Internal slow-path routine used by ReadVarint32(). + Status ReadVarint32Fallback(uint32* result); + RandomAccessFile* file_; // Not owned int64 file_pos_; // Next position to read from in "file_" size_t size_; // Size of "buf_" @@ -71,6 +90,22 @@ class InputBuffer { TF_DISALLOW_COPY_AND_ASSIGN(InputBuffer); }; +// Implementation details. + +// Inlined for performance. +inline Status InputBuffer::ReadVarint32(uint32* result) { + if (pos_ + core::kMaxVarint32Bytes <= limit_) { + // Fast path: directly parse from buffered data. + // Reads strictly from the range [pos_, limit_). + const char* offset = core::GetVarint32Ptr(pos_, limit_, result); + if (offset == nullptr) return errors::OutOfRange("Parsed past limit."); + pos_ = const_cast(offset); + return Status::OK(); + } else { + return ReadVarint32Fallback(result); + } +} + } // namespace io } // namespace tensorflow diff --git a/tensorflow/core/lib/io/inputbuffer_test.cc b/tensorflow/core/lib/io/inputbuffer_test.cc index cce9c6d3eec51e146353c7f8ba7136b7a35e16c3..31fa96bf769fe7d24416986d62399efce5a9c754 100644 --- a/tensorflow/core/lib/io/inputbuffer_test.cc +++ b/tensorflow/core/lib/io/inputbuffer_test.cc @@ -18,6 +18,7 @@ limitations under the License. #include #include "tensorflow/core/platform/env.h" +#include "tensorflow/core/lib/core/coding.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/status_test_util.h" @@ -26,6 +27,7 @@ limitations under the License. #include "tensorflow/core/platform/test.h" namespace tensorflow { +namespace { static std::vector BufferSizes() { return {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, @@ -147,6 +149,7 @@ TEST(InputBuffer, ReadNBytes) { string fname = testing::TmpDir() + "/inputbuffer_test"; WriteStringToFile(env, fname, "0123456789"); + // ReadNBytes(int64, string*). for (auto buf_size : BufferSizes()) { std::unique_ptr file; TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); @@ -175,6 +178,43 @@ TEST(InputBuffer, ReadNBytes) { EXPECT_EQ(read, ""); EXPECT_EQ(10, in.Tell()); } + // ReadNBytes(int64, char*, size_t*). + size_t bytes_read; + for (auto buf_size : BufferSizes()) { + std::unique_ptr file; + TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); + char read[5]; + io::InputBuffer in(file.get(), buf_size); + + EXPECT_EQ(0, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(3, read, &bytes_read)); + EXPECT_EQ(StringPiece(read, 3), "012"); + + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, read, &bytes_read)); + EXPECT_EQ(StringPiece(read, 3), "012"); + + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(4, read, &bytes_read)); + EXPECT_EQ(StringPiece(read, 4), "3456"); + + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, read, &bytes_read)); + EXPECT_EQ(StringPiece(read, 4), "3456"); + + EXPECT_EQ(7, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, read, &bytes_read))); + EXPECT_EQ(StringPiece(read, 3), "789"); + + EXPECT_EQ(10, in.Tell()); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, read, &bytes_read))); + EXPECT_EQ(StringPiece(read, 3), "789"); + + EXPECT_EQ(10, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, read, &bytes_read)); + EXPECT_EQ(StringPiece(read, 3), "789"); + EXPECT_EQ(10, in.Tell()); + } } TEST(InputBuffer, SkipNBytes) { @@ -212,4 +252,79 @@ TEST(InputBuffer, SkipNBytes) { } } +TEST(InputBuffer, Seek) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/inputbuffer_test"; + WriteStringToFile(env, fname, "0123456789"); + + for (auto buf_size : BufferSizes()) { + std::unique_ptr file; + TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); + string read; + io::InputBuffer in(file.get(), buf_size); + + TF_CHECK_OK(in.ReadNBytes(3, &read)); + EXPECT_EQ(read, "012"); + TF_CHECK_OK(in.ReadNBytes(3, &read)); + EXPECT_EQ(read, "345"); + + TF_CHECK_OK(in.Seek(0)); + TF_CHECK_OK(in.ReadNBytes(3, &read)); + EXPECT_EQ(read, "012"); + + TF_CHECK_OK(in.Seek(3)); + TF_CHECK_OK(in.ReadNBytes(4, &read)); + EXPECT_EQ(read, "3456"); + + TF_CHECK_OK(in.Seek(4)); + TF_CHECK_OK(in.ReadNBytes(4, &read)); + EXPECT_EQ(read, "4567"); + + TF_CHECK_OK(in.Seek(1 << 25)); + EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(1, &read))); + + EXPECT_TRUE( + StringPiece(in.Seek(-1).ToString()).contains("negative position")); + } +} + +TEST(InputBuffer, ReadVarint32) { + Env* env = Env::Default(); + string fname = testing::TmpDir() + "/inputbuffer_test"; + + // Generates data. + std::vector data; + uint32 i = 0; + for (; i < (1 << 10); i += 1) data.push_back(i); + for (; i < (1 << 15); i += 5) data.push_back(i); + for (; i < (1 << 31); i += 132817) data.push_back(i); + data.push_back(std::numeric_limits::max()); + + // Writes the varints. + { + std::unique_ptr file; + TF_CHECK_OK(env->NewWritableFile(fname, &file)); + string varint; + for (uint32 number : data) { + varint.clear(); + core::PutVarint32(&varint, number); + TF_CHECK_OK(file->Append(StringPiece(varint))); + } + } + + for (auto buf_size : BufferSizes()) { + std::unique_ptr file; + TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); + io::InputBuffer in(file.get(), buf_size); + uint32 result = 0; + + for (uint32 expected : data) { + TF_ASSERT_OK(in.ReadVarint32(&result)); + EXPECT_EQ(expected, result); + } + EXPECT_TRUE(errors::IsOutOfRange(in.ReadVarint32(&result))); + } +} + +} // namespace } // namespace tensorflow diff --git a/tensorflow/core/lib/io/inputstream_interface.h b/tensorflow/core/lib/io/inputstream_interface.h index 3d5d690a69629c0cbd7eba2b0b451ebd706adecb..e45e3c7a972b0b539d5b53a6256c9a5126af8f89 100644 --- a/tensorflow/core/lib/io/inputstream_interface.h +++ b/tensorflow/core/lib/io/inputstream_interface.h @@ -39,6 +39,13 @@ class InputStreamInterface { // * OK - in case of success. // * OUT_OF_RANGE - not enough bytes remaining before end of file. virtual Status SkipNBytes(int64 bytes_to_skip); + + // Return the offset of the current byte relative to the beginning of the + // file. + // If we Skip / Read beyond the end of the file, this should return the length + // of the file. + // If there are any errors, this must return -1. + virtual int64 Tell() const = 0; }; } // namespace io diff --git a/tensorflow/core/lib/io/inputstream_interface_test.cc b/tensorflow/core/lib/io/inputstream_interface_test.cc index 2b4454bedb06dcb6a6ff678c9ce9197979e55342..5ccc1455c1a1026bb757dd62a94ad473ca24b98a 100644 --- a/tensorflow/core/lib/io/inputstream_interface_test.cc +++ b/tensorflow/core/lib/io/inputstream_interface_test.cc @@ -37,6 +37,8 @@ class TestStringStream : public InputStreamInterface { return Status::OK(); } + int64 Tell() const override { return pos_; } + private: string content_; int64 pos_ = 0; diff --git a/tensorflow/core/lib/io/random_inputstream.cc b/tensorflow/core/lib/io/random_inputstream.cc index 0b06bad1a944fe661104ceafef0fad978e26e5ba..bb92f0f018d983a3309834562ad23c65b0838233 100644 --- a/tensorflow/core/lib/io/random_inputstream.cc +++ b/tensorflow/core/lib/io/random_inputstream.cc @@ -50,27 +50,7 @@ Status RandomAccessInputStream::ReadNBytes(int64 bytes_to_read, return Status::OK(); } -Status RandomAccessInputStream::SkipNBytes(int64 bytes_to_skip) { - if (bytes_to_skip < 0) { - return errors::InvalidArgument("Can only skip forward, not backwards"); - } - // Tries to read one byte at future location to see whether we've skipped - // beyond the end of file or not. - StringPiece data; - char scratch; - Status s = file_->Read(pos_ + bytes_to_skip, 1, &data, &scratch); - // Advance pointer if OK or OutOfRange status is returned. - if (s.ok() || errors::IsOutOfRange(s)) { - pos_ += bytes_to_skip; - } - // Passing on the return status from file_->Read(). We can get the following - // * OK: We have skipped to some portion in the file. Return OK. - // * OutOfRange: Despite b/30839063 an OutOfRange return status means that - // no bytes were read and we've skipped beyond EOF. The - // return semantics of SkipNBytes dictate we return OutOfRange. - // * other: if some other error is encountered we just pass that along. - return s; -} +int64 RandomAccessInputStream::Tell() const { return pos_; } } // namespace io } // namespace tensorflow diff --git a/tensorflow/core/lib/io/random_inputstream.h b/tensorflow/core/lib/io/random_inputstream.h index c45d6ddeb47680c878d0b5eaf3f8d73c5720d263..c02258a85f6457e4029416d5df02790e844d1479 100644 --- a/tensorflow/core/lib/io/random_inputstream.h +++ b/tensorflow/core/lib/io/random_inputstream.h @@ -31,7 +31,7 @@ class RandomAccessInputStream : public InputStreamInterface { Status ReadNBytes(int64 bytes_to_read, string* result) override; - Status SkipNBytes(int64 bytes_to_skip) override; + int64 Tell() const override; private: RandomAccessFile* file_; // Not owned. diff --git a/tensorflow/core/lib/io/random_inputstream_test.cc b/tensorflow/core/lib/io/random_inputstream_test.cc index af92585d3207d6f533cd299c890a723966f27ac3..c25a8efff4004382020191eb1c3ecf4ee0c9253d 100644 --- a/tensorflow/core/lib/io/random_inputstream_test.cc +++ b/tensorflow/core/lib/io/random_inputstream_test.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/lib/io/random_inputstream.h" +#include "tensorflow/core/lib/core/status_test_util.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/test.h" @@ -28,21 +29,27 @@ TEST(RandomInputStream, ReadNBytes) { WriteStringToFile(env, fname, "0123456789"); std::unique_ptr file; - TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); string read; RandomAccessInputStream in(file.get()); - TF_CHECK_OK(in.ReadNBytes(3, &read)); + TF_ASSERT_OK(in.ReadNBytes(3, &read)); EXPECT_EQ(read, "012"); - TF_CHECK_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); EXPECT_EQ(read, ""); - TF_CHECK_OK(in.ReadNBytes(5, &read)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(5, &read)); EXPECT_EQ(read, "34567"); - TF_CHECK_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(8, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); EXPECT_EQ(read, ""); + EXPECT_EQ(8, in.Tell()); EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(20, &read))); EXPECT_EQ(read, "89"); - TF_CHECK_OK(in.ReadNBytes(0, &read)); + EXPECT_EQ(10, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); } TEST(RandomInputStream, SkipNBytes) { @@ -51,22 +58,29 @@ TEST(RandomInputStream, SkipNBytes) { WriteStringToFile(env, fname, "0123456789"); std::unique_ptr file; - TF_CHECK_OK(env->NewRandomAccessFile(fname, &file)); + TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file)); string read; RandomAccessInputStream in(file.get()); - TF_CHECK_OK(in.SkipNBytes(3)); - TF_CHECK_OK(in.ReadNBytes(0, &read)); + TF_ASSERT_OK(in.SkipNBytes(3)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(0, &read)); EXPECT_EQ(read, ""); - TF_CHECK_OK(in.ReadNBytes(4, &read)); + EXPECT_EQ(3, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(4, &read)); EXPECT_EQ(read, "3456"); - TF_CHECK_OK(in.SkipNBytes(0)); - TF_CHECK_OK(in.ReadNBytes(2, &read)); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.SkipNBytes(0)); + EXPECT_EQ(7, in.Tell()); + TF_ASSERT_OK(in.ReadNBytes(2, &read)); EXPECT_EQ(read, "78"); + EXPECT_EQ(9, in.Tell()); EXPECT_TRUE(errors::IsOutOfRange(in.SkipNBytes(20))); + EXPECT_EQ(10, in.Tell()); // Making sure that if we read after we've skipped beyond end of file, we get // nothing. EXPECT_TRUE(errors::IsOutOfRange(in.ReadNBytes(5, &read))); EXPECT_EQ(read, ""); + EXPECT_EQ(10, in.Tell()); } } // anonymous namespace diff --git a/tensorflow/core/lib/io/snappy/snappy_buffers_test.cc b/tensorflow/core/lib/io/snappy/snappy_buffers_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..65bb34d5701c0d735b54435f527179f8ea9f9510 --- /dev/null +++ b/tensorflow/core/lib/io/snappy/snappy_buffers_test.cc @@ -0,0 +1,185 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/lib/io/inputbuffer.h" +#include "tensorflow/core/lib/io/snappy/snappy_inputbuffer.h" +#include "tensorflow/core/lib/io/snappy/snappy_outputbuffer.h" + +namespace tensorflow { + +// The current implementation of snappy compresses the below block to 619 bytes. +// We use this to validate the error messages. Please change this number if +// a new snappy implementation compresses to a different size. +const int COMPRESSED_RECORD_SIZE = 619; + +static string GetRecord() { + static const string lorem_ipsum = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + " Fusce vehicula tincidunt libero sit amet ultrices. Vestibulum non " + "felis augue. Duis vitae augue id lectus lacinia congue et ut purus. " + "Donec auctor, nisl at dapibus volutpat, diam ante lacinia dolor, vel" + "dignissim lacus nisi sed purus. Duis fringilla nunc ac lacus sagittis" + " efficitur. Praesent tincidunt egestas eros, eu vehicula urna ultrices" + " et. Aliquam erat volutpat. Maecenas vehicula risus consequat risus" + " dictum, luctus tincidunt nibh imperdiet. Aenean bibendum ac erat" + " cursus scelerisque. Cras lacinia in enim dapibus iaculis. Nunc porta" + " felis lectus, ac tincidunt massa pharetra quis. Fusce feugiat dolor" + " vel ligula rutrum egestas. Donec vulputate quam eros, et commodo" + " purus lobortis sed."; + return lorem_ipsum; +} + +static string GenTestString(uint copies = 1) { + string result = ""; + for (int i = 0; i < copies; i++) { + result += GetRecord(); + } + return result; +} + +Status TestMultipleWrites(size_t compress_input_buf_size, + size_t compress_output_buf_size, + size_t uncompress_input_buf_size, + size_t uncompress_output_buf_size, int num_writes = 1, + bool with_flush = false, int num_copies = 1, + bool corrupt_compressed_file = false) { + Env* env = Env::Default(); + + string fname = testing::TmpDir() + "/snappy_buffers_test"; + string data = GenTestString(num_copies); + std::unique_ptr file_writer; + string actual_result; + string expected_result; + + TF_RETURN_IF_ERROR(env->NewWritableFile(fname, &file_writer)); + io::SnappyOutputBuffer out(file_writer.get(), compress_input_buf_size, + compress_output_buf_size); + + for (int i = 0; i < num_writes; i++) { + TF_RETURN_IF_ERROR(out.Write(StringPiece(data))); + if (with_flush) { + TF_RETURN_IF_ERROR(out.Flush()); + } + strings::StrAppend(&expected_result, data); + } + TF_RETURN_IF_ERROR(out.Flush()); + TF_RETURN_IF_ERROR(file_writer->Flush()); + TF_RETURN_IF_ERROR(file_writer->Close()); + + if (corrupt_compressed_file) { + string corrupt_fname = testing::TmpDir() + "/snappy_buffers_test_corrupt"; + std::unique_ptr corrupt_file_writer; + TF_RETURN_IF_ERROR( + env->NewWritableFile(corrupt_fname, &corrupt_file_writer)); + + std::unique_ptr file_reader; + TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file_reader)); + + StringPiece data; + size_t file_pos = 0; + size_t bytes_to_read = 256; + char* scratch = new char[bytes_to_read]; + char* buffer = new char[bytes_to_read]; + size_t buffer_size = 0; + + while ((file_reader->Read(file_pos, bytes_to_read, &data, scratch)).ok()) { + file_pos += data.size(); + TF_CHECK_OK( + corrupt_file_writer->Append(StringPiece(buffer, buffer_size))); + memcpy(buffer, data.data(), data.size()); + buffer_size = data.size(); + } + + // Drop the last byte. File is now corrupt. + TF_CHECK_OK( + corrupt_file_writer->Append(StringPiece(buffer, buffer_size - 1))); + TF_CHECK_OK(corrupt_file_writer->Flush()); + TF_CHECK_OK(corrupt_file_writer->Close()); + delete[] scratch; + delete[] buffer; + fname = corrupt_fname; + } + + std::unique_ptr file_reader; + TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file_reader)); + io::SnappyInputBuffer in(file_reader.get(), uncompress_input_buf_size, + uncompress_output_buf_size); + + for (int i = 0; i < num_writes; i++) { + string decompressed_output; + TF_RETURN_IF_ERROR(in.ReadNBytes(data.size(), &decompressed_output)); + strings::StrAppend(&actual_result, decompressed_output); + } + + if (actual_result.compare(expected_result)) { + return errors::DataLoss("Actual and expected results don't match."); + } + return Status::OK(); +} + +static bool SnappyCompressionSupported() { + string out; + StringPiece in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + return port::Snappy_Compress(in.data(), in.size(), &out); +} + +TEST(SnappyBuffers, MultipleWritesWithoutFlush) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "Snappy disabled. Skipping test\n"); + return; + } + TF_CHECK_OK(TestMultipleWrites(10000, 10000, 10000, 10000, 2)); +} + +TEST(SnappyBuffers, MultipleWriteCallsWithFlush) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + TF_CHECK_OK(TestMultipleWrites(10000, 10000, 10000, 10000, 2, true)); +} + +TEST(SnappyBuffers, SmallUncompressInputBuffer) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + CHECK_EQ(TestMultipleWrites(10000, 10000, 10, 10000, 2, true), + errors::ResourceExhausted("Input buffer(size: 10 bytes) too small. ", + "Should be larger than ", + COMPRESSED_RECORD_SIZE, " bytes.")); +} + +TEST(SnappyBuffers, CorruptBlock) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + CHECK_EQ(TestMultipleWrites(10000, 10000, 700, 10000, 2, true, 1, true), + errors::DataLoss("Failed to read ", COMPRESSED_RECORD_SIZE, + " bytes from file. ", "Possible data corruption.")); +} + +TEST(SnappyBuffers, CorruptBlockLargeInputBuffer) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + CHECK_EQ(TestMultipleWrites(10000, 10000, 2000, 10000, 2, true, 1, true), + errors::OutOfRange("EOF reached")); +} + +} // namespace tensorflow diff --git a/tensorflow/core/lib/io/snappy/snappy_inputbuffer.cc b/tensorflow/core/lib/io/snappy/snappy_inputbuffer.cc new file mode 100644 index 0000000000000000000000000000000000000000..8a300efbdad6c31e5045def140850a76cd8ec72e --- /dev/null +++ b/tensorflow/core/lib/io/snappy/snappy_inputbuffer.cc @@ -0,0 +1,185 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/lib/io/snappy/snappy_inputbuffer.h" + +namespace tensorflow { +namespace io { +SnappyInputBuffer::SnappyInputBuffer( + RandomAccessFile* file, + size_t input_buffer_bytes, // size of input_buffer_ + size_t output_buffer_bytes // size of output_buffer_ + ) + : file_(file), + input_buffer_capacity_(input_buffer_bytes), + output_buffer_capacity_(output_buffer_bytes), + input_buffer_(new char[input_buffer_capacity_]), + output_buffer_(new char[output_buffer_capacity_]), + next_in_(input_buffer_.get()) {} + +Status SnappyInputBuffer::ReadNBytes(int64 bytes_to_read, string* result) { + result->clear(); + // Read as many bytes as possible from cache. + bytes_to_read -= ReadBytesFromCache(bytes_to_read, result); + + while (bytes_to_read > 0) { + // At this point we can be sure that cache has been emptied. + DCHECK(avail_out_ == 0); + + // Now that the cache is empty we need to inflate more data. + TF_RETURN_IF_ERROR(Inflate()); + + bytes_to_read -= ReadBytesFromCache(bytes_to_read, result); + } + + return Status::OK(); +} + +int64 SnappyInputBuffer::Tell() const { + // TODO(srbs): Implement this. + return -1; +} + +size_t SnappyInputBuffer::ReadBytesFromCache(size_t bytes_to_read, + string* result) { + size_t can_read_bytes = std::min(bytes_to_read, avail_out_); + if (can_read_bytes > 0) { + result->append(next_out_, can_read_bytes); + next_out_ += can_read_bytes; + avail_out_ -= can_read_bytes; + } + + return can_read_bytes; +} + +Status SnappyInputBuffer::Inflate() { + // Read length of compressed block. + uint32 compressed_block_length; + TF_RETURN_IF_ERROR(ReadCompressedBlockLength(&compressed_block_length)); + + // If the entire block is not in cache do a read from file. + if (avail_in_ < compressed_block_length) { + TF_RETURN_IF_ERROR(ReadFromFile()); + if (avail_in_ < compressed_block_length) { + if (compressed_block_length > input_buffer_capacity_) { + return errors::ResourceExhausted( + "Input buffer(size: ", input_buffer_capacity_, + " bytes) too small. Should be larger ", "than ", + compressed_block_length, " bytes."); + } else { + return errors::DataLoss( + strings::StrCat("Failed to read ", compressed_block_length, + " bytes from file. Possible data corruption.")); + } + } + } + + size_t uncompressed_length; + if (!port::Snappy_GetUncompressedLength(next_in_, compressed_block_length, + &uncompressed_length)) { + return errors::DataLoss("Parsing error in Snappy_GetUncompressedLength"); + } + + // Output buffer must have been cleared before uncompressing more input. + DCHECK_EQ(avail_out_, 0); + + // Output buffer must be large enough to fit the uncompressed block. + DCHECK_GE(output_buffer_capacity_, uncompressed_length); + next_out_ = (char*)output_buffer_.get(); + + bool status = port::Snappy_Uncompress(next_in_, compressed_block_length, + output_buffer_.get()); + if (!status) { + return errors::DataLoss("Snappy_Uncompress failed"); + } + next_in_ += compressed_block_length; + avail_in_ -= compressed_block_length; + avail_out_ += uncompressed_length; + return Status::OK(); +} + +Status SnappyInputBuffer::ReadCompressedBlockLength(uint32* length) { + *length = 0; + size_t bytes_to_read = 4; + while (bytes_to_read > 0) { + if (avail_in_ == 0) { + TF_RETURN_IF_ERROR(ReadFromFile()); + } + size_t readable = std::min(bytes_to_read, avail_in_); + + for (int i = 0; i < readable; i++) { + *length = (*length << 8) | next_in_[0]; + bytes_to_read--; + next_in_++; + avail_in_--; + } + } + return Status::OK(); +} + +Status SnappyInputBuffer::ReadFromFile() { + int bytes_to_read = input_buffer_capacity_; + char* read_location = reinterpret_cast(input_buffer_.get()); + + // If there are unread bytes in the input stream we move them to the head + // of the stream to maximize the space available to read new data into. + // TODO(srbs): A circular buffer would be useful here. + if (avail_in_ > 0) { + size_t read_bytes = next_in_ - input_buffer_.get(); + // Remove `read_bytes` from the head of the input stream. + // Move unread bytes to the head of the input stream. + if (read_bytes > 0) { + memmove(input_buffer_.get(), next_in_, avail_in_); + } + + bytes_to_read -= avail_in_; + read_location += avail_in_; + } + StringPiece data; + // Try to read enough data to fill up input_buffer_. + Status s = file_->Read(file_pos_, bytes_to_read, &data, read_location); + if (data.data() != read_location) { + memmove(read_location, data.data(), data.size()); + } + + // Since we moved unread data to the head of the input stream we can point + // next_in to the head of the input stream. + next_in_ = input_buffer_.get(); + + // Note: data.size() could be different from bytes_to_read. + avail_in_ += data.size(); + file_pos_ += data.size(); + + if (!s.ok() && !errors::IsOutOfRange(s)) { + return s; + } + + // We throw OutOfRange error iff no new data has been read from file. + // Since we never check how much data is remaining in the file, it is + // possible that on the last read there isn't enough data in the file to + // fill up the buffer in which case file_->ReadNBytes would return an + // OutOfRange error. + if (data.size() == 0) { + return errors::OutOfRange("EOF reached"); + } + if (errors::IsOutOfRange(s)) { + return Status::OK(); + } + + return s; +} + +} // namespace io +} // namespace tensorflow diff --git a/tensorflow/core/lib/io/snappy/snappy_inputbuffer.h b/tensorflow/core/lib/io/snappy/snappy_inputbuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..6df3c0d9a0f7d0523d99bbeb6d8b374f18e8f774 --- /dev/null +++ b/tensorflow/core/lib/io/snappy/snappy_inputbuffer.h @@ -0,0 +1,126 @@ +/* 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. +==============================================================================*/ + +#ifndef TENSORFLOW_LIB_IO_SNAPPY_INPUTBUFFER_H_ +#define TENSORFLOW_LIB_IO_SNAPPY_INPUTBUFFER_H_ + +#include +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/lib/io/inputstream_interface.h" +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/macros.h" +#include "tensorflow/core/platform/snappy.h" +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { +namespace io { + +// An SnappyInputBuffer provides support for reading from a file compressed +// using snappy (https://github.com/google/snappy). +// +// A given instance of an SnappyInputBuffer is NOT safe for concurrent use +// by multiple threads +class SnappyInputBuffer : public InputStreamInterface { + public: + // Create a SnappyInputBuffer for `file` with a buffer of size + // `input_buffer_bytes` bytes for reading contents from `file` and another + // buffer with size `output_buffer_bytes` for caching decompressed contents. + // Does *not* take ownership of "file". + SnappyInputBuffer(RandomAccessFile* file, size_t input_buffer_bytes, + size_t output_buffer_bytes); + + // Reads bytes_to_read bytes into *result, overwriting *result. + // + // Return Status codes: + // OK: + // If successful. + // OUT_OF_RANGE: + // If there are not enough bytes to read before the end of the file. + // DATA_LOSS: + // If uncompression failed or if the file is corrupted. + // RESOURCE_EXHAUSTED: + // If input_buffer_ is smaller in size than a compressed block. + // others: + // If reading from file failed. + Status ReadNBytes(int64 bytes_to_read, string* result) override; + + int64 Tell() const override; + + private: + // Reads data from `file_` and tries to fill up `input_buffer_` if enough + // unread data is left in `file_`. + // + // Looks up `next_in_` to check how much data in `input_buffer_` + // has already been read. The used data is removed and new data is added to + // after any unread data in `input_buffer_`. + // After this call `next_in` points to the start of `input_buffer_` + // and `avail_in_` stores the number of readable bytes in + // `input_buffer_`. + // + // Returns OutOfRange error if NO data could be read from file. Note that this + // won't return an OutOfRange if there wasn't sufficient data in file to + // completely fill up `input_buffer_`. + Status ReadFromFile(); + + // Reads the length of the next compressed block stored in the next 4 bytes at + // `next_in_`. Uncompresses the next compressed block and writes the output + // produced to the output_buffer_. + // Should be called only after the cached output has been consumed. + Status Inflate(); + + // Starts reading bytes at `next_out_` till either `bytes_to_read` + // bytes have been read or `next_out_` is reached. + // Returns the number of bytes read and advances the `next_out_` + // pointer to the next location to read from. + size_t ReadBytesFromCache(size_t bytes_to_read, string* result); + + // Reads the length of the next *compressed* block and stores in `length`. + // The length is stored in 4 bytes in little endian notation. + Status ReadCompressedBlockLength(uint32* length); + + RandomAccessFile* file_; // Not owned + int64 file_pos_ = 0; // Next position to read from in `file_` + size_t input_buffer_capacity_; // Size of `input_buffer_`. + // Must be at least as big as the size of + // the largest compressed block. + size_t output_buffer_capacity_; // Size of `output_buffer_` + + // Buffer for storing contents read from compressed file. + // TODO(srbs): Consider using circular buffers. That would greatly simplify + // the implementation. + std::unique_ptr input_buffer_; + + // Buffer for storing inflated contents of `file_`. + std::unique_ptr output_buffer_; + + // Next unread byte in `input_buffer_`. + char* next_in_; + + // Next unread byte in `output_buffer_` + char* next_out_; + + // Number of unread bytes bytes available at `next_in_` in `input_buffer_`. + size_t avail_in_ = 0; + + // Number of unread bytes bytes available at `next_out_` in `output_buffer_`. + size_t avail_out_ = 0; + + TF_DISALLOW_COPY_AND_ASSIGN(SnappyInputBuffer); +}; + +} // namespace io +} // namespace tensorflow + +#endif // TENSORFLOW_LIB_IO_SNAPPY_INPUTBUFFER_H_ diff --git a/tensorflow/core/lib/io/snappy/snappy_outputbuffer.cc b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.cc new file mode 100644 index 0000000000000000000000000000000000000000..be1fa22c69c27a5c57e3c397076a66dfe05eb035 --- /dev/null +++ b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.cc @@ -0,0 +1,182 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/lib/io/snappy/snappy_outputbuffer.h" + +namespace tensorflow { +namespace io { + +SnappyOutputBuffer::SnappyOutputBuffer(WritableFile* file, + int32 input_buffer_bytes, + int32 output_buffer_bytes) + : file_(file), + input_buffer_(new char[input_buffer_bytes]), + input_buffer_capacity_(input_buffer_bytes), + next_in_(input_buffer_.get()), + output_buffer_(new char[output_buffer_bytes]), + output_buffer_capacity_(output_buffer_bytes), + next_out_(output_buffer_.get()), + avail_out_(output_buffer_bytes) {} + +Status SnappyOutputBuffer::Write(StringPiece data) { + // + // The deflated output is accumulated in output_buffer_ and gets written to + // file as and when needed. + + size_t bytes_to_write = data.size(); + + // If there is sufficient free space in input_buffer_ to fit data we + // add it there and return. + if (bytes_to_write <= AvailableInputSpace()) { + AddToInputBuffer(data); + return Status::OK(); + } + + // If there isn't enough available space in the input_buffer_ we empty it + // by uncompressing its contents. If data now fits in input_buffer_ + // we add it there else we directly deflate it. + TF_RETURN_IF_ERROR(DeflateBuffered()); + + // input_buffer_ should be empty at this point. + if (bytes_to_write <= AvailableInputSpace()) { + AddToInputBuffer(data); + return Status::OK(); + } + + // `data` is too large to fit in input buffer so we deflate it directly. + // Note that at this point we have already deflated all existing input so + // we do not need to backup next_in and avail_in. + next_in_ = const_cast(data.data()); + avail_in_ = bytes_to_write; + + TF_RETURN_IF_ERROR(Deflate()); + + DCHECK(avail_in_ == 0); // All input will be used up. + + next_in_ = input_buffer_.get(); + + return Status::OK(); +} + +Status SnappyOutputBuffer::Flush() { + TF_RETURN_IF_ERROR(DeflateBuffered()); + TF_RETURN_IF_ERROR(FlushOutputBufferToFile()); + return Status::OK(); +} + +int32 SnappyOutputBuffer::AvailableInputSpace() const { + return input_buffer_capacity_ - avail_in_; +} + +void SnappyOutputBuffer::AddToInputBuffer(StringPiece data) { + size_t bytes_to_write = data.size(); + DCHECK_LE(bytes_to_write, AvailableInputSpace()); + + // Input stream -> + // [....................input_buffer_capacity_...............] + // [<...read_bytes...><...avail_in...>......empty space......] + // ^ ^ + // | | + // input_buffer_ next_in + // + // Data in the input stream is sharded as shown above. next_in_ could + // be pointing to some byte in the buffer with avail_in number of bytes + // available to be read. + // + // In order to avoid shifting the avail_in bytes at next_in to the head of + // the buffer we try to fit `data` in the empty space at the tail of the + // input stream. + // TODO(srbs): This could be avoided if we had a circular buffer. + // If it doesn't fit we free the space at the head of the stream and then + // append `data` at the end of existing data. + + const int32 read_bytes = next_in_ - input_buffer_.get(); + const int32 unread_bytes = avail_in_; + const int32 free_tail_bytes = + input_buffer_capacity_ - (read_bytes + unread_bytes); + + if (bytes_to_write > free_tail_bytes) { + memmove(input_buffer_.get(), next_in_, avail_in_); + next_in_ = input_buffer_.get(); + } + memcpy(next_in_ + avail_in_, data.data(), bytes_to_write); + avail_in_ += bytes_to_write; +} + +Status SnappyOutputBuffer::AddToOutputBuffer(const char* data, size_t length) { + while (length > 0) { + size_t bytes_to_copy = std::min(length, avail_out_); + memcpy(next_out_, data, bytes_to_copy); + data += bytes_to_copy; + next_out_ += bytes_to_copy; + avail_out_ -= bytes_to_copy; + length -= bytes_to_copy; + if (avail_out_ == 0) { + TF_RETURN_IF_ERROR(FlushOutputBufferToFile()); + } + } + return Status::OK(); +} + +Status SnappyOutputBuffer::DeflateBuffered() { + TF_RETURN_IF_ERROR(Deflate()); + DCHECK(avail_in_ == 0); + next_in_ = input_buffer_.get(); + return Status::OK(); +} + +Status SnappyOutputBuffer::FlushOutputBufferToFile() { + size_t bytes_to_write = output_buffer_capacity_ - avail_out_; + if (bytes_to_write > 0) { + Status s = file_->Append(StringPiece( + reinterpret_cast(output_buffer_.get()), bytes_to_write)); + if (s.ok()) { + next_out_ = output_buffer_.get(); + avail_out_ = output_buffer_capacity_; + } + return s; + } + return Status::OK(); +} + +Status SnappyOutputBuffer::Deflate() { + if (avail_in_ == 0) { + return Status::OK(); + } + string output; + if (!port::Snappy_Compress(next_in_, avail_in_, &output)) { + return errors::DataLoss("Snappy_Compress failed"); + } + + // Write length of compressed block to output buffer. + char* compressed_length_array = new char[4]; + std::fill(compressed_length_array, compressed_length_array + 4, 0); + for (int i = 0; i < 4; i++) { + // Little endian. + compressed_length_array[i] = output.size() >> (8 * (3 - i)); + } + TF_RETURN_IF_ERROR(AddToOutputBuffer(compressed_length_array, 4)); + + // Write compressed output to buffer. + TF_RETURN_IF_ERROR(AddToOutputBuffer(output.data(), output.size())); + next_in_ += avail_in_; + avail_in_ = 0; + delete[] compressed_length_array; + + return Status::OK(); +} + +} // namespace io +} // namespace tensorflow diff --git a/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..5d330a2c5a3d97456495893d3bb87c376beeeb1f --- /dev/null +++ b/tensorflow/core/lib/io/snappy/snappy_outputbuffer.h @@ -0,0 +1,120 @@ +/* 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. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ + +#include +#include "tensorflow/core/lib/core/status.h" +#include "tensorflow/core/platform/env.h" +#include "tensorflow/core/platform/macros.h" +#include "tensorflow/core/platform/snappy.h" +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { +namespace io { + +// Compresses input data using Snappy (https://github.com/google/snappy) and +// writes to `file`. +// +// The input data is cached in a buffer of size `input_buffer_bytes`. When the +// buffer does not have enough available space to fit new data (in the call to +// `Write`), the contents of the buffer are compressed and sent to the output +// buffer. +// +// The compressed output is buffered in a buffer of size `output_buffer_bytes` +// which gets flushed to file when full. +// +// Output file format: +// The output file consists of a sequence of compressed blocks. Each block +// starts with a 4 byte header which stores the length (in bytes) of the +// _compressed_ block _excluding_ this header. The compressed +// block (excluding the 4 byte header) is a valid snappy block and can directly +// be uncompressed using Snappy_Uncompress. +class SnappyOutputBuffer { + public: + // Create an SnappyOutputBuffer for `file` with two buffers that cache the + // 1. input data to be deflated + // 2. the deflated output + // with sizes `input_buffer_bytes` and `output_buffer_bytes` respectively. + // Does not take ownership of `file`. + SnappyOutputBuffer(WritableFile* file, int32 input_buffer_bytes, + int32 output_buffer_bytes); + + // Adds `data` to the compression pipeline. + // + // The input data is buffered in `input_buffer_` and is compressed in bulk + // when the buffer gets full. The compressed output may not be immediately + // written to file but rather buffered in `output_buffer_` and gets written + // to file when the buffer is full. + // + // To immediately write contents to file call `Flush()`. + Status Write(StringPiece data); + + // Compresses any cached input and writes all output to file. This must be + // called before the destructor to avoid any data loss. + Status Flush(); + + private: + // Appends `data` to `input_buffer_`. + // Throws if `data.size()` > AvailableInputSpace(). + void AddToInputBuffer(StringPiece data); + + // Appends `data` to `output_buffer_`. Flushes buffer contents to file when + // buffer gets full. + Status AddToOutputBuffer(const char* data, size_t length); + + // Returns the total space available in `input_buffer_`. + int32 AvailableInputSpace() const; + + // Deflate contents in input_buffer_ and store results in output_buffer_. + // The contents of output stream are written to file if more space is needed. + // + // Note: This method does not flush contents to file. + // Returns non-ok status if writing contents to file fails. + Status DeflateBuffered(); + + // Appends contents of `output_buffer_` to `file_`. + // Returns non-OK status if writing to file fails. + Status FlushOutputBufferToFile(); + + // Compresses `avail_in_` bytes at `next_in_` location in `input_buffer_` and + // writes the results to output using `AddToOutputBuffer`. + // Returns non-OK status if writing to file failed. + Status Deflate(); + + WritableFile* file_; // Not owned + + // Buffer for storing contents read from input `file_`. + // TODO(srbs): Consider using circular buffers. That would greatly simplify + // the implementation. + std::unique_ptr input_buffer_; + size_t input_buffer_capacity_; + char* next_in_; + size_t avail_in_ = 0; + + // Buffer for storing deflated contents of `file_`. + std::unique_ptr output_buffer_; + size_t output_buffer_capacity_; + char* next_out_; + size_t avail_out_; + + TF_DISALLOW_COPY_AND_ASSIGN(SnappyOutputBuffer); +}; + +} // namespace io +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_LIB_IO_SNAPPY_OUTPUTBUFFER_H_ diff --git a/tensorflow/core/lib/png/png_io.cc b/tensorflow/core/lib/png/png_io.cc index ada783f8a4cdf8689587bedccada420634b27d65..cbee7a416e35397ede414e863d255c64fc2c66a4 100644 --- a/tensorflow/core/lib/png/png_io.cc +++ b/tensorflow/core/lib/png/png_io.cc @@ -25,7 +25,7 @@ limitations under the License. #include "tensorflow/core/lib/core/casts.h" #include "tensorflow/core/lib/png/png_io.h" -#include "tensorflow/core/platform/host_info.h" // endian +#include "tensorflow/core/platform/cpu_info.h" // endian #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/png.h" diff --git a/tensorflow/core/lib/strings/base64.cc b/tensorflow/core/lib/strings/base64.cc index 5eaa35f2b724cbd1d448f9de7010c317920bb471..7f0b8987a58dd543abfb09809f246423f827efdd 100644 --- a/tensorflow/core/lib/strings/base64.cc +++ b/tensorflow/core/lib/strings/base64.cc @@ -15,6 +15,7 @@ limitations under the License. #include "tensorflow/core/lib/strings/base64.h" +#include #include #include "tensorflow/core/lib/core/errors.h" @@ -57,38 +58,14 @@ inline uint32 Convert(char x) { return static_cast(z); } -Status DecodeOneChar(const char* codes, char* result) { - const uint32 packed = (Convert(codes[0]) << 2) | - (Convert(codes[1]) >> 4); +Status DecodeThreeChars(const char* codes, char* result) { + const uint32 packed = (Convert(codes[0]) << 18) | (Convert(codes[1]) << 12) | + (Convert(codes[2]) << 6) | (Convert(codes[3])); // Convert() return value has upper 25 bits set if input is invalid. // Therefore `packed` has high bits set iff at least one of code is invalid. if (TF_PREDICT_FALSE((packed & 0xFF000000) != 0)) { return errors::InvalidArgument("Invalid character found in base64."); } - *result = static_cast(packed); - return Status::OK(); -} - -Status DecodeTwoChars(const char* codes, char* result) { - const uint32 packed = (Convert(codes[0]) << 10) | - (Convert(codes[1]) << 4) | - (Convert(codes[2]) >> 2); - if (TF_PREDICT_FALSE((packed & 0xFF000000) != 0)) { - return errors::InvalidArgument("Invalid character found in base64."); - } - result[0] = static_cast(packed >> 8); - result[1] = static_cast(packed); - return Status::OK(); -} - -Status DecodeThreeChars(const char* codes, char* result) { - const uint32 packed = (Convert(codes[0]) << 18) | - (Convert(codes[1]) << 12) | - (Convert(codes[2]) << 6) | - (Convert(codes[3])); - if (TF_PREDICT_FALSE((packed & 0xFF000000) != 0)) { - return errors::InvalidArgument("Invalid character found in base64."); - } result[0] = static_cast(packed >> 16); result[1] = static_cast(packed >> 8); result[2] = static_cast(packed); @@ -106,7 +83,10 @@ Status Base64Decode(StringPiece data, string* decoded) { return Status::OK(); } - // max_decoded_size may overestimate by up to 3 bytes. + // This decoding procedure will write 3 * ceil(data.size() / 4) bytes to be + // output buffer, then truncate if necessary. Therefore we must overestimate + // and allocate sufficient amount. Currently max_decoded_size may overestimate + // by up to 3 bytes. const size_t max_decoded_size = 3 * (data.size() / 4) + 3; std::unique_ptr buffer(new char[max_decoded_size]); char* current = buffer.get(); @@ -135,25 +115,22 @@ Status Base64Decode(StringPiece data, string* decoded) { } } - switch (end - b64) { - case 4: - TF_RETURN_IF_ERROR(DecodeThreeChars(b64, current)); - current += 3; - break; - case 3: - TF_RETURN_IF_ERROR(DecodeTwoChars(b64, current)); - current += 2; - break; - case 2: - TF_RETURN_IF_ERROR(DecodeOneChar(b64, current)); - current += 1; - break; - default: // case 1 - // We may check this condition early by checking data.size() % 4 == 1. - return errors::InvalidArgument( - "Base64 string length cannot be 1 modulo 4."); + const int remain = end - b64; + if (TF_PREDICT_FALSE(remain == 1)) { + // We may check this condition early by checking data.size() % 4 == 1. + return errors::InvalidArgument( + "Base64 string length cannot be 1 modulo 4."); } + // A valid base64 character will replace paddings, if any. + char tail[4] = {kBase64UrlSafeChars[0], kBase64UrlSafeChars[0], + kBase64UrlSafeChars[0], kBase64UrlSafeChars[0]}; + // Copy tail of the input into the array, then decode. + std::memcpy(tail, b64, remain * sizeof(*b64)); + TF_RETURN_IF_ERROR(DecodeThreeChars(tail, current)); + // We know how many parsed characters are valid. + current += remain - 1; + decoded->assign(buffer.get(), current - buffer.get()); return Status::OK(); } diff --git a/tensorflow/core/lib/wav/wav_io.cc b/tensorflow/core/lib/wav/wav_io.cc index 825d4f59575f22175b7b86c4f8cd6b65fd6b509c..31c81b7dde2cf5cfb80a7b9e908a74f972e358c8 100644 --- a/tensorflow/core/lib/wav/wav_io.cc +++ b/tensorflow/core/lib/wav/wav_io.cc @@ -23,7 +23,7 @@ limitations under the License. #include "tensorflow/core/lib/core/coding.h" #include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/wav/wav_io.h" -#include "tensorflow/core/platform/host_info.h" +#include "tensorflow/core/platform/cpu_info.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/macros.h" diff --git a/tensorflow/core/ops/array_ops.cc b/tensorflow/core/ops/array_ops.cc index 528d6407d42c238c98563456bbcd59c564f37e08..82d9924665c1ec90644b548c1aa6bb4aa8931ace 100644 --- a/tensorflow/core/ops/array_ops.cc +++ b/tensorflow/core/ops/array_ops.cc @@ -21,9 +21,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { @@ -41,14 +41,14 @@ Status GetAxisForPackAndUnpack(InferenceContext* c, int32 rank_after_pack, Status PadShapeFn(InferenceContext* c) { // Paddings is a matrix of [input_rank, 2]. - const Shape* paddings; + ShapeHandle paddings; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &paddings)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->WithValue(c->Dim(paddings, 1), 2, &unused)); // n_dim and input.rank are equivalent. - const Shape* input = c->input(0); - const Dimension* n_dim = c->Dim(paddings, 0); + ShapeHandle input = c->input(0); + DimensionHandle n_dim = c->Dim(paddings, 0); if (c->ValueKnown(n_dim)) { TF_RETURN_IF_ERROR(c->WithRank(input, c->Value(n_dim), &input)); } else if (c->RankKnown(input)) { @@ -75,7 +75,7 @@ Status PadShapeFn(InferenceContext* c) { // paddings_t is known. auto paddings_data = paddings_t->matrix(); - std::vector dims(num_dims); + std::vector dims(num_dims); for (int i = 0; i < num_dims; ++i) { const int32 pad0 = paddings_data(i, 0); const int32 pad1 = paddings_data(i, 1); @@ -98,7 +98,7 @@ REGISTER_OP("Pack") .Attr("axis: int = 0") .SetShapeFn([](InferenceContext* c) { // Validate shapes of all inputs are compatible - const Shape* cur = c->input(c->num_inputs() - 1); + ShapeHandle cur = c->input(c->num_inputs() - 1); for (int i = c->num_inputs() - 2; i >= 0; --i) { TF_RETURN_WITH_CONTEXT_IF_ERROR(c->Merge(c->input(i), cur, &cur), "From merging shape ", i, @@ -116,7 +116,7 @@ REGISTER_OP("Pack") // Copy all dimensions over, inserting a dimension of value #inputs // at . - std::vector dims; + std::vector dims; int index = 0; while (index < axis) dims.push_back(c->Dim(cur, index++)); dims.push_back(c->MakeDim(c->num_inputs())); @@ -162,8 +162,8 @@ REGISTER_OP("Unpack") .Attr("T: type") .Attr("axis: int = 0") .SetShapeFn([](InferenceContext* c) { - const Shape* s = c->input(0); - const Shape* out; + ShapeHandle s = c->input(0); + ShapeHandle out; if (c->RankKnown(s)) { // Determine the axis that will be removed, converting from negative // axes to a positive point per negative indexing rules. @@ -172,12 +172,12 @@ REGISTER_OP("Unpack") TF_RETURN_IF_ERROR(GetAxisForPackAndUnpack(c, rank, &axis)); // The axis dim matches the number of outputs. - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->WithValue(c->Dim(s, axis), c->num_outputs(), &unused)); // Copy all dimensions, removing the dimension. - std::vector dims; + std::vector dims; for (int i = 0; i < rank; ++i) { if (i != axis) dims.push_back(c->Dim(s, i)); } @@ -272,11 +272,11 @@ REGISTER_OP("Split") .Attr("num_split: int >= 1") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Dimension* split_dimension; + DimensionHandle split_dimension; TF_RETURN_IF_ERROR(c->MakeDimForScalarInput(0, &split_dimension)); int num_split = c->num_outputs(); - const Shape* input = c->input(1); - const Shape* out; + ShapeHandle input = c->input(1); + ShapeHandle out; if (!c->ValueKnown(split_dimension)) { if (c->RankKnown(input)) { out = c->UnknownShapeOfRank(c->Rank(input)); @@ -286,7 +286,7 @@ REGISTER_OP("Split") } else { int64 split_dim = c->Value(split_dimension); TF_RETURN_IF_ERROR(c->WithRankAtLeast(input, split_dim + 1, &input)); - const Dimension* split_dim_size; + DimensionHandle split_dim_size; TF_RETURN_WITH_CONTEXT_IF_ERROR( c->Divide(c->Dim(input, split_dim), num_split, &split_dim_size), "Number of ways to split should evenly divide the split dimension"); @@ -319,7 +319,7 @@ REGISTER_OP("Const") TF_RETURN_IF_ERROR(c->GetAttr("value", &proto)); TF_RETURN_IF_ERROR(TensorShape::IsValidShape(proto->tensor_shape())); TensorShape shape(proto->tensor_shape()); - std::vector dims; + std::vector dims; for (int i = 0; i < shape.dims(); ++i) { dims.push_back(c->MakeDim(shape.dim_size(i))); } @@ -345,7 +345,7 @@ REGISTER_OP("ImmutableConst") TF_RETURN_IF_ERROR(c->GetAttr("shape", &shape_from_attr)); TensorShapeProto shape_proto; shape_from_attr.AsProto(&shape_proto); - const Shape* output_shape; + ShapeHandle output_shape; TF_RETURN_IF_ERROR( c->MakeShapeFromShapeProto(shape_proto, &output_shape)); c->set_output(0, output_shape); @@ -381,10 +381,10 @@ REGISTER_OP("Diag") .Output("output: T") .Attr("T: {float, double, int32, int64, complex64}") .SetShapeFn([](InferenceContext* c) { - const Shape* in = c->input(0); + ShapeHandle in = c->input(0); TF_RETURN_IF_ERROR(c->WithRankAtMost(in, 3, &in)); // Output shape is original concatenated with itself. - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate(in, in, &out)); c->set_output(0, out); return Status::OK(); @@ -419,7 +419,7 @@ REGISTER_OP("DiagPart") .Output("diagonal: T") .Attr("T: {float, double, int32, int64, complex64}") .SetShapeFn([](InferenceContext* c) { - const Shape* in = c->input(0); + ShapeHandle in = c->input(0); if (!c->RankKnown(in)) { c->set_output(0, c->UnknownShape()); return Status::OK(); @@ -433,7 +433,7 @@ REGISTER_OP("DiagPart") const int32 mid = rank / 2; // output dim[i] is the merge of in.dim[i] and in.dim[i+mid]. - std::vector dims(mid); + std::vector dims(mid); for (int i = 0; i < mid; ++i) { TF_RETURN_IF_ERROR( c->Merge(c->Dim(in, i), c->Dim(in, i + mid), &dims[i])); @@ -474,14 +474,14 @@ REGISTER_OP("BatchMatrixDiag") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* in; + ShapeHandle in; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &in)); if (!c->RankKnown(in)) { c->set_output(0, c->UnknownShape()); return Status::OK(); } const int32 rank = c->Rank(in); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR( c->Concatenate(in, c->Vector(c->Dim(in, rank - 1)), &out)); c->set_output(0, out); @@ -528,17 +528,17 @@ REGISTER_OP("BatchMatrixSetDiag") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* input; - const Shape* diag; + ShapeHandle input; + ShapeHandle diag; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 2, &input)); TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 1, &diag)); - const Dimension* square_dim; + DimensionHandle square_dim; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input, -2), c->Dim(input, -1), &square_dim)); TF_RETURN_IF_ERROR(c->Merge(square_dim, c->Dim(diag, -1), &square_dim)); - const Shape* output; + ShapeHandle output; TF_RETURN_IF_ERROR(c->Concatenate(diag, c->Vector(square_dim), &output)); TF_RETURN_IF_ERROR(c->Merge(input, output, &output)); @@ -573,7 +573,7 @@ REGISTER_OP("BatchMatrixDiagPart") .Output("diagonal: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* in; + ShapeHandle in; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 2, &in)); if (!c->RankKnown(in)) { c->set_output(0, c->UnknownShape()); @@ -581,12 +581,12 @@ REGISTER_OP("BatchMatrixDiagPart") } const int32 rank = c->Rank(in); // Last two dims must match. - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->Merge(c->Dim(in, rank - 1), c->Dim(in, rank - 2), &unused)); // Output shape has all dims but last of input. - std::vector dims; + std::vector dims; for (int i = 0; i < rank - 1; ++i) dims.push_back(c->Dim(in, i)); c->set_output(0, c->MakeShape(dims)); return Status::OK(); @@ -695,10 +695,10 @@ REGISTER_OP("Reverse") "T: {uint8, int8, int32, int64, bool, half, float, double, complex64, " "complex128}") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); - const Shape* dims; + ShapeHandle input = c->input(0); + ShapeHandle dims; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &dims)); - const Dimension* dims_dim = c->Dim(dims, 0); + DimensionHandle dims_dim = c->Dim(dims, 0); if (c->ValueKnown(dims_dim)) { TF_RETURN_IF_ERROR(c->WithRank(input, c->Value(dims_dim), &input)); } @@ -795,7 +795,7 @@ REGISTER_OP("EditDistance") auto h_values = hypothesis_shape_t->flat(); auto t_values = truth_shape_t->flat(); - std::vector dims(hypothesis_shape_t->NumElements() - 1); + std::vector dims(hypothesis_shape_t->NumElements() - 1); for (int i = 0; i < dims.size(); ++i) { dims[i] = c->MakeDim(std::max(h_values(i), t_values(i))); } @@ -869,7 +869,7 @@ REGISTER_OP("Fill") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &out)); c->set_output(0, out); return Status::OK(); @@ -900,12 +900,12 @@ REGISTER_OP("Gather") .Attr("Tparams: type") .Attr("Tindices: {int32,int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &unused)); - const Shape* params_subshape; + ShapeHandle params_subshape; TF_RETURN_IF_ERROR(c->Subshape(c->input(0), 1, ¶ms_subshape)); - const Shape* indices_shape = c->input(1); - const Shape* out; + ShapeHandle indices_shape = c->input(1); + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate(indices_shape, params_subshape, &out)); c->set_output(0, out); return Status::OK(); @@ -941,10 +941,10 @@ REGISTER_OP("GatherNd") .Attr("Tparams: type") .Attr("Tindices: {int32,int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* params = c->input(0); - const Shape* indices; + ShapeHandle params = c->input(0); + ShapeHandle indices; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 1, &indices)); - const Dimension* r_dim = c->Dim(indices, -1); + DimensionHandle r_dim = c->Dim(indices, -1); if (!c->RankKnown(params) || !c->ValueKnown(r_dim)) { c->set_output(0, c->UnknownShape()); @@ -959,11 +959,11 @@ REGISTER_OP("GatherNd") } // Remove r_dim from indices to get output. - const Shape* indices_slice; - const Shape* params_slice; + ShapeHandle indices_slice; + ShapeHandle params_slice; TF_RETURN_IF_ERROR(c->Subshape(indices, 0, -1, &indices_slice)); TF_RETURN_IF_ERROR(c->Subshape(params, c->Value(r_dim), ¶ms_slice)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate(indices_slice, params_slice, &out)); c->set_output(0, out); return Status::OK(); @@ -1131,8 +1131,8 @@ REGISTER_OP("Reshape") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* in = c->input(0); - const Shape* out; + ShapeHandle in = c->input(0); + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(1, &out)); // If the rank and all dimensions of the input tensor are known, we may @@ -1141,8 +1141,8 @@ REGISTER_OP("Reshape") // dimension information. // Additionally, if the rank of the out shape is unknown we have no shape // information to go off of. - const Dimension* num_in_elems = c->NumElements(in); - const Dimension* num_out_elems = c->NumElements(out); + DimensionHandle num_in_elems = c->NumElements(in); + DimensionHandle num_out_elems = c->NumElements(out); if (!c->ValueKnown(num_in_elems) || !c->RankKnown(out)) { // Do nothing. We have no shape information to infer from so we directly // return out as our shape. @@ -1159,9 +1159,9 @@ REGISTER_OP("Reshape") // If we don't know the number of output elements, we can infer // the missing dimension. int32 unknown_idx = -1; - const Dimension* known_elems = c->MakeDim(1); + DimensionHandle known_elems = c->MakeDim(1); for (int32 i = 0; i < c->Rank(out); ++i) { - const Dimension* dim = c->Dim(out, i); + DimensionHandle dim = c->Dim(out, i); if (!c->ValueKnown(dim)) { if (unknown_idx >= 0) { return errors::InvalidArgument( @@ -1173,7 +1173,7 @@ REGISTER_OP("Reshape") TF_RETURN_IF_ERROR(c->Multiply(known_elems, dim, &known_elems)); } } - const Dimension* inferred_dim; + DimensionHandle inferred_dim; TF_RETURN_IF_ERROR( c->Divide(num_in_elems, c->Value(known_elems), &inferred_dim)); TF_RETURN_IF_ERROR(c->ReplaceDim(out, unknown_idx, inferred_dim, &out)); @@ -1250,7 +1250,7 @@ REGISTER_OP("InvertPermutation") .Input("x: int32") .Output("y: int32") .SetShapeFn([](InferenceContext* c) { - const Shape* x; + ShapeHandle x; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &x)); c->set_output(0, x); return Status::OK(); @@ -1285,10 +1285,10 @@ REGISTER_OP("Transpose") .Output("y: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); - const Shape* perm_shape = c->input(1); + ShapeHandle input = c->input(0); + ShapeHandle perm_shape = c->input(1); const Tensor* perm = c->input_tensor(1); - const Dimension* perm_elems = c->NumElements(perm_shape); + DimensionHandle perm_elems = c->NumElements(perm_shape); // If we don't have rank information on the input or value information on // perm we can't return any shape information, otherwise we have enough // information to at least find the rank of the output. @@ -1307,7 +1307,7 @@ REGISTER_OP("Transpose") } else { rank = perm->NumElements(); } - std::vector dims; + std::vector dims; dims.resize(rank); TF_RETURN_IF_ERROR(c->WithRank(input, rank, &input)); // Ensure that perm is a vector and has rank elements. @@ -1386,7 +1386,7 @@ REGISTER_OP("UniqueWithCounts") .Output("count: int32") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - auto* uniq = c->Vector(InferenceContext::kUnknownDim); + auto uniq = c->Vector(InferenceContext::kUnknownDim); c->set_output(0, uniq); c->set_output(1, c->input(0)); c->set_output(2, uniq); @@ -1423,7 +1423,7 @@ namespace { Status ShapeShapeFn(InferenceContext* c) { for (int i = 0; i < c->num_inputs(); ++i) { - const Dimension* dim; + DimensionHandle dim; if (c->RankKnown(c->input(i))) { dim = c->MakeDim(c->Rank(c->input(i))); } else { @@ -1471,14 +1471,15 @@ This operation returns N 1-D integer tensors representing shape of `input[i]s`. // -------------------------------------------------------------------------- REGISTER_OP("ReverseSequence") .Input("input: T") - .Input("seq_lengths: int64") + .Input("seq_lengths: Tlen") .Output("output: T") .Attr("seq_dim: int") .Attr("batch_dim: int = 0") .Attr("T: type") + .Attr("Tlen: {int32, int64} = DT_INT64") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); - const Shape* seq_lens_shape; + ShapeHandle input = c->input(0); + ShapeHandle seq_lens_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &seq_lens_shape)); int64 seq_dim; @@ -1501,12 +1502,12 @@ REGISTER_OP("ReverseSequence") seq_dim, " vs. ", input_rank); } - const Dimension* batch_dim_dim = c->Dim(input, batch_dim); + DimensionHandle batch_dim_dim = c->Dim(input, batch_dim); TF_RETURN_IF_ERROR( c->Merge(batch_dim_dim, c->Dim(seq_lens_shape, 0), &batch_dim_dim)); // Replace batch_dim of input with batch_size - const Shape* output_shape; + ShapeHandle output_shape; TF_RETURN_IF_ERROR( c->ReplaceDim(input, batch_dim, batch_dim_dim, &output_shape)); c->set_output(0, output_shape); @@ -1627,11 +1628,11 @@ namespace { template Status SliceHelper(InferenceContext* c, const Tensor* begin_t, - const Tensor* sizes_t, std::vector* dims) { + const Tensor* sizes_t, std::vector* dims) { auto begin_vec = begin_t->vec(); auto sizes_vec = sizes_t->vec(); for (int i = 0; i < sizes_t->NumElements(); ++i) { - const Dimension* dim = c->Dim(c->input(0), i); + DimensionHandle dim = c->Dim(c->input(0), i); if (sizes_vec(i) != -1) { if (c->ValueKnown(dim)) { auto dim_val = c->Value(dim); @@ -1664,7 +1665,7 @@ Status SliceHelper(InferenceContext* c, const Tensor* begin_t, dims->emplace_back(c->MakeDim(sizes_vec(i))); } else { - const Dimension* result; + DimensionHandle result; TF_RETURN_IF_ERROR(c->Subtract(dim, begin_vec(i), &result)); dims->emplace_back(result); } @@ -1684,16 +1685,16 @@ REGISTER_OP("Slice") .Attr("T: type") .Attr("Index: {int32,int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); - const Shape* begin_shape; + ShapeHandle input = c->input(0); + ShapeHandle begin_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &begin_shape)); - const Shape* sizes_shape; + ShapeHandle sizes_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &sizes_shape)); // Merge to check compatibility of begin and sizes tensors. TF_RETURN_IF_ERROR(c->Merge(begin_shape, sizes_shape, &begin_shape)); - const Dimension* ndims = c->Dim(begin_shape, 0); + DimensionHandle ndims = c->Dim(begin_shape, 0); if (c->ValueKnown(ndims)) { TF_RETURN_IF_ERROR(c->WithRank(input, c->Value(ndims), &input)); } @@ -1702,7 +1703,7 @@ REGISTER_OP("Slice") const Tensor* sizes_t = c->input_tensor(2); if (sizes_t != nullptr && begin_t != nullptr) { - std::vector dims; + std::vector dims; // If the begin and sizes tensors are available, then // we can be precise about the shape of the output. if (begin_t->dtype() == DT_INT64) { @@ -1831,10 +1832,10 @@ REGISTER_OP("Tile") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* input; - const Shape* multiples; + ShapeHandle input; + ShapeHandle multiples; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &multiples)); - const Dimension* multiples_dim0 = c->Dim(multiples, 0); + DimensionHandle multiples_dim0 = c->Dim(multiples, 0); if (!c->ValueKnown(multiples_dim0)) { // Length of multiples vector unknown, so output is unknown. // @@ -1856,7 +1857,7 @@ REGISTER_OP("Tile") // Multiply each input dimension by its corresponding value // from the multiples tensor. auto multiples_data = multiples_t->vec(); - std::vector dims(rank); + std::vector dims(rank); for (int i = 0; i < rank; ++i) { const int32 multiple = multiples_data(i); TF_RETURN_IF_ERROR(c->Multiply(c->Dim(input, i), multiple, &dims[i])); @@ -1945,7 +1946,7 @@ REGISTER_OP("BroadcastGradientArgs") .Output("r1: int32") .SetShapeFn([](InferenceContext* c) { // TODO(mrry): Implement constant_value for BroadcastGradientArgs? - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); c->set_output(0, c->Vector(InferenceContext::kUnknownDim)); @@ -2049,9 +2050,9 @@ REGISTER_OP("MirrorPadGrad") .Attr("T: type") .Attr(GetMirrorPadModeAttrString()) .SetShapeFn([](InferenceContext* c) { - const Shape* paddings; + ShapeHandle paddings; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &paddings)); - const Dimension* pad_0 = c->Dim(paddings, 0); + DimensionHandle pad_0 = c->Dim(paddings, 0); if (!c->ValueKnown(pad_0)) { // We don't know the rank of the output since the first // padding dimension is unknown. @@ -2060,7 +2061,7 @@ REGISTER_OP("MirrorPadGrad") } int64 input_rank = c->Value(pad_0); - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), input_rank, &input)); TF_RETURN_IF_ERROR( c->Merge(paddings, c->Matrix(input_rank, 2), &paddings)); @@ -2075,7 +2076,7 @@ REGISTER_OP("MirrorPadGrad") } auto paddings_data = paddings_t->matrix(); - std::vector dims(input_rank); + std::vector dims(input_rank); for (int i = 0; i < input_rank; ++i) { const int64 pad0 = static_cast(paddings_data(i, 0)); const int64 pad1 = static_cast(paddings_data(i, 1)); @@ -2137,7 +2138,7 @@ REGISTER_OP("Placeholder") TensorShapeProto shape_proto; shape.AsProto(&shape_proto); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &out)); c->set_output(0, out); return Status::OK(); @@ -2162,17 +2163,17 @@ REGISTER_OP("PlaceholderWithDefault") .Attr("dtype: type") .Attr("shape: shape") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); + ShapeHandle input = c->input(0); PartialTensorShape shape; TF_RETURN_IF_ERROR(c->GetAttr("shape", &shape)); TensorShapeProto shape_proto; shape.AsProto(&shape_proto); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &out)); // We merge for compatibility checking, but return the output, // since output_shape may be less precise than input_shape. - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->Merge(input, out, &unused)); c->set_output(0, out); return Status::OK(); @@ -2193,8 +2194,8 @@ REGISTER_OP("ExpandDims") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); - const Shape* expand_dim; + ShapeHandle input = c->input(0); + ShapeHandle expand_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &expand_dim)); const Tensor* dim_t = c->input_tensor(1); @@ -2207,11 +2208,11 @@ REGISTER_OP("ExpandDims") which_dim += c->Rank(input) + 1; } - const Shape* end; + ShapeHandle end; TF_RETURN_IF_ERROR(c->Subshape(input, which_dim, &end)); // Build output as start + 1 + end. - const Shape* output; + ShapeHandle output; TF_RETURN_IF_ERROR(c->Subshape(input, 0, which_dim, &output)); TF_RETURN_IF_ERROR(c->Concatenate(output, c->Vector(1), &output)); TF_RETURN_IF_ERROR(c->Concatenate(output, end, &output)); @@ -2265,7 +2266,7 @@ REGISTER_OP("Squeeze") .Attr("T: type") .Attr("squeeze_dims: list(int) >= 0 = []") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); + ShapeHandle input = c->input(0); if (!c->RankKnown(input)) { // Input shape unknown. return shape_inference::UnknownShape(c); @@ -2287,7 +2288,7 @@ REGISTER_OP("Squeeze") } } - std::vector result_shape; + std::vector result_shape; for (int i = 0; i < input_rank; ++i) { // True if squeeze_dims contains an entry to squeeze this // dimension. @@ -2295,7 +2296,7 @@ REGISTER_OP("Squeeze") std::find(squeeze_dims.begin(), squeeze_dims.end(), i) != squeeze_dims.end(); - const Dimension* dim = c->Dim(input, i); + DimensionHandle dim = c->Dim(input, i); if (!c->ValueKnown(dim)) { // Assume that the squeezed dimension will be 1 at runtime. @@ -2362,11 +2363,11 @@ REGISTER_OP("ListDiff") .Output("idx: int32") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); // TODO(mrry): Indicate that the length falls within an interval? - const Shape* out = c->Vector(InferenceContext::kUnknownDim); + ShapeHandle out = c->Vector(InferenceContext::kUnknownDim); c->set_output(0, out); c->set_output(1, out); return Status::OK(); @@ -2410,14 +2411,14 @@ REGISTER_OP("SpaceToBatch") .Attr("T: type") .Attr("block_size: int >= 2") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Shape* paddings; + ShapeHandle paddings; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &paddings)); - const Dimension* pad0_dim = c->Dim(paddings, 0); - const Dimension* pad1_dim = c->Dim(paddings, 1); + DimensionHandle pad0_dim = c->Dim(paddings, 0); + DimensionHandle pad1_dim = c->Dim(paddings, 1); if (!c->ValueKnown(pad0_dim) || !c->ValueKnown(pad1_dim)) { return shape_inference::UnknownShape(c); @@ -2433,8 +2434,8 @@ REGISTER_OP("SpaceToBatch") int32 block_size; TF_RETURN_IF_ERROR(c->GetAttr("block_size", &block_size)); - const Dimension* output_height; - const Dimension* output_width; + DimensionHandle output_height; + DimensionHandle output_width; const Tensor* paddings_t = c->input_tensor(1); if (paddings_t == nullptr) { @@ -2457,7 +2458,7 @@ REGISTER_OP("SpaceToBatch") c->Add(c->Dim(input, 2), pad_left + pad_right, &output_width)); } - const Dimension* batch; + DimensionHandle batch; TF_RETURN_IF_ERROR( c->Multiply(c->Dim(input, 0), block_size * block_size, &batch)); @@ -2575,14 +2576,14 @@ REGISTER_OP("BatchToSpace") .Attr("T: type") .Attr("block_size: int >= 2") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Shape* crops; + ShapeHandle crops; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &crops)); - const Dimension* crops0_dim = c->Dim(crops, 0); - const Dimension* crops1_dim = c->Dim(crops, 1); + DimensionHandle crops0_dim = c->Dim(crops, 0); + DimensionHandle crops1_dim = c->Dim(crops, 1); if (!c->ValueKnown(crops0_dim) || !c->ValueKnown(crops1_dim)) { return shape_inference::UnknownShape(c); @@ -2598,13 +2599,13 @@ REGISTER_OP("BatchToSpace") int32 block_size; TF_RETURN_IF_ERROR(c->GetAttr("block_size", &block_size)); - const Dimension* batch; + DimensionHandle batch; // Will return an error if does not evenly divide TF_RETURN_IF_ERROR( c->Divide(c->Dim(input, 0), block_size * block_size, &batch)); - const Dimension* output_height; - const Dimension* output_width; + DimensionHandle output_height; + DimensionHandle output_width; const Tensor* crops_t = c->input_tensor(1); if (crops_t == nullptr) { @@ -2733,15 +2734,15 @@ REGISTER_OP("SpaceToDepth") .Attr("T: type") .Attr("block_size: int >= 2") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); int32 block_size; TF_RETURN_IF_ERROR(c->GetAttr("block_size", &block_size)); - const Dimension* output_height; - const Dimension* output_width; - const Dimension* output_depth; + DimensionHandle output_height; + DimensionHandle output_width; + DimensionHandle output_depth; // Will return an error if does not evenly divide TF_RETURN_IF_ERROR( c->Divide(c->Dim(input, 1), block_size, &output_height)); @@ -2840,15 +2841,15 @@ REGISTER_OP("DepthToSpace") .Attr("T: type") .Attr("block_size: int >= 2") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); int32 block_size; TF_RETURN_IF_ERROR(c->GetAttr("block_size", &block_size)); - const Dimension* output_height; - const Dimension* output_width; - const Dimension* output_depth; + DimensionHandle output_height; + DimensionHandle output_width; + DimensionHandle output_depth; TF_RETURN_IF_ERROR( c->Multiply(c->Dim(input, 1), block_size, &output_height)); TF_RETURN_IF_ERROR( @@ -2956,7 +2957,7 @@ REGISTER_OP("ExtractImagePatches") .Attr("T: realnumbertype") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); std::vector ksizes; @@ -2998,10 +2999,10 @@ REGISTER_OP("ExtractImagePatches") int32 ksize_rows_eff = ksize_rows + (ksize_rows - 1) * (rate_rows - 1); int32 ksize_cols_eff = ksize_cols + (ksize_cols - 1) * (rate_cols - 1); - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* output_depth_dim = c->Dim(input_shape, 3); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle output_depth_dim = c->Dim(input_shape, 3); // At the moment we need to know the values of several fields. TF_RETURN_IF_ERROR(c->ValidateKnownDim(in_rows_dim, "in_rows")); @@ -3020,7 +3021,7 @@ REGISTER_OP("ExtractImagePatches") TF_RETURN_IF_ERROR(GetWindowedOutputSizeVerbose( in_cols, ksize_cols_eff, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape = c->MakeShape( + ShapeHandle output_shape = c->MakeShape( {batch_size_dim, output_rows, output_cols, output_depth_dim}); c->set_output(0, output_shape); return Status::OK(); @@ -3057,7 +3058,7 @@ REGISTER_OP("Bitcast") .Attr("T: numbertype") .Attr("type: numbertype") .SetShapeFn([](InferenceContext* c) { - const Shape* input = c->input(0); + ShapeHandle input = c->input(0); if (!c->RankKnown(input)) { // Input shape unknown. return shape_inference::UnknownShape(c); @@ -3079,7 +3080,7 @@ REGISTER_OP("Bitcast") "one of the type sizes is zero."); } - const Shape* new_shape; + ShapeHandle new_shape; if (input_type_size == output_type_size) { // No change in size. new_shape = input; @@ -3087,7 +3088,7 @@ REGISTER_OP("Bitcast") TF_RETURN_IF_ERROR(c->WithRankAtLeast(input, 1, &new_shape)); int64 divisor_val = output_type_size / input_type_size; - const Dimension* last_dim = c->Dim(new_shape, -1); + DimensionHandle last_dim = c->Dim(new_shape, -1); if (!c->ValueKnown(last_dim) || c->Value(last_dim) == divisor_val) { TF_RETURN_IF_ERROR(c->Subshape(new_shape, 0, -1, &new_shape)); } else { @@ -3098,7 +3099,7 @@ REGISTER_OP("Bitcast") } else { // Input type size is larger than output type size. int64 divisor_val = input_type_size / output_type_size; - const Shape* extension = c->Vector(divisor_val); + ShapeHandle extension = c->Vector(divisor_val); TF_RETURN_IF_ERROR(c->Concatenate(input, extension, &new_shape)); } @@ -3136,10 +3137,10 @@ REGISTER_OP("OneHot") TF_RETURN_IF_ERROR(c->GetAttr("axis", &axis)); if (axis < -1) return errors::InvalidArgument("axis must be >= -1"); - const Dimension* depth; + DimensionHandle depth; TF_RETURN_IF_ERROR(c->MakeDimForScalarInput(1, &depth)); - const Shape* indices = c->input(0); + ShapeHandle indices = c->input(0); if (!c->RankKnown(indices)) return shape_inference::UnknownShape(c); int32 new_rank = c->Rank(indices) + 1; @@ -3147,9 +3148,9 @@ REGISTER_OP("OneHot") // C++ returns negative values from % if the dividend is negative. int32 depth_index = (axis + new_rank) % new_rank; // Out shape is indices[0:depth_index] + [depth] + indices[depth_index:]. - const Shape* front; - const Shape* back; - const Shape* out; + ShapeHandle front; + ShapeHandle back; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Subshape(indices, 0, depth_index, &front)); TF_RETURN_IF_ERROR(c->Subshape(indices, depth_index, &back)); TF_RETURN_IF_ERROR(c->Concatenate(front, c->Vector(depth), &front)); diff --git a/tensorflow/core/ops/candidate_sampling_ops.cc b/tensorflow/core/ops/candidate_sampling_ops.cc index 556090231fcf9155f228a70062860e005a1eb8dd..037c393574dcbe4ea6bf705b5048b657e97573df 100644 --- a/tensorflow/core/ops/candidate_sampling_ops.cc +++ b/tensorflow/core/ops/candidate_sampling_ops.cc @@ -18,9 +18,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { @@ -30,11 +30,11 @@ Status CandidateSamplerShapeFn(InferenceContext* c) { int64 num_true; TF_RETURN_IF_ERROR(c->GetAttr("num_true", &num_true)); - const Shape* true_classes_shape; + ShapeHandle true_classes_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &true_classes_shape)); - const Dimension* batch_size = c->Dim(true_classes_shape, 0); + DimensionHandle batch_size = c->Dim(true_classes_shape, 0); - const Shape* num_sampled_v = c->Vector(num_sampled); + ShapeHandle num_sampled_v = c->Vector(num_sampled); c->set_output(0, num_sampled_v); c->set_output(1, c->Matrix(batch_size, num_true)); c->set_output(2, num_sampled_v); @@ -378,14 +378,14 @@ REGISTER_OP("ComputeAccidentalHits") TF_RETURN_IF_ERROR(c->GetAttr("num_true", &num_true)); // Validate true_classes. - const Shape* true_classes; + ShapeHandle true_classes; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &true_classes)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->WithValue(c->Dim(true_classes, 1), num_true, &unused)); // All three outputs are the same shape. - const Shape* v = c->Vector(InferenceContext::kUnknownDim); + ShapeHandle v = c->Vector(InferenceContext::kUnknownDim); c->set_output(0, v); c->set_output(1, v); c->set_output(2, v); diff --git a/tensorflow/core/ops/compat/ops_history.v0.pbtxt b/tensorflow/core/ops/compat/ops_history.v0.pbtxt index 1e84f7d99adaec6211fd20155b8fa96dd13b5098..41a8ad3b66ee856fee1c1de75a0f67d57a58a1df 100644 --- a/tensorflow/core/ops/compat/ops_history.v0.pbtxt +++ b/tensorflow/core/ops/compat/ops_history.v0.pbtxt @@ -5485,6 +5485,35 @@ op { minimum: 2 } } +op { + name: "Betainc" + input_arg { + name: "a" + type_attr: "T" + } + input_arg { + name: "b" + type_attr: "T" + } + input_arg { + name: "x" + type_attr: "T" + } + output_arg { + name: "z" + type_attr: "T" + } + attr { + name: "T" + type: "type" + allowed_values { + list { + type: DT_FLOAT + type: DT_DOUBLE + } + } + } +} op { name: "BiasAdd" input_arg { @@ -10777,6 +10806,44 @@ op { } is_stateful: true } +op { + name: "HashTable" + output_arg { + name: "table_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + } + attr { + name: "key_dtype" + type: "type" + } + attr { + name: "value_dtype" + type: "type" + } + is_stateful: true +} op { name: "HistogramSummary" input_arg { @@ -14980,6 +15047,44 @@ op { } is_stateful: true } +op { + name: "MutableHashTable" + output_arg { + name: "table_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + } + attr { + name: "key_dtype" + type: "type" + } + attr { + name: "value_dtype" + type: "type" + } + is_stateful: true +} op { name: "MutableHashTableOfTensors" output_arg { @@ -15019,6 +15124,52 @@ op { } is_stateful: true } +op { + name: "MutableHashTableOfTensors" + output_arg { + name: "table_handle" + type: DT_STRING + is_ref: true + } + attr { + name: "container" + type: "string" + default_value { + s: "" + } + } + attr { + name: "shared_name" + type: "string" + default_value { + s: "" + } + } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + } + attr { + name: "key_dtype" + type: "type" + } + attr { + name: "value_dtype" + type: "type" + } + attr { + name: "value_shape" + type: "shape" + default_value { + shape { + } + } + } + is_stateful: true +} op { name: "Neg" input_arg { diff --git a/tensorflow/core/ops/control_flow_ops.cc b/tensorflow/core/ops/control_flow_ops.cc index 3b1b7c63d3e920e737e82aa258cde0906e19a6d8..321401793928a15d8303e11aebd908617099866f 100644 --- a/tensorflow/core/ops/control_flow_ops.cc +++ b/tensorflow/core/ops/control_flow_ops.cc @@ -20,14 +20,14 @@ limitations under the License. namespace tensorflow { using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; // -------------------------------------------------------------------------- namespace { Status SwitchShape(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); - const Shape* out = c->input(0); + ShapeHandle out = c->input(0); c->set_output(0, out); c->set_output(1, out); return Status::OK(); @@ -85,16 +85,16 @@ REGISTER_OP("RefSelect") .Attr("T: type") .Attr("N: int >= 1") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - const Shape* first_input = c->input(1); + ShapeHandle first_input = c->input(1); if (!c->FullyDefined(first_input)) { c->set_output(0, c->UnknownShape()); return Status::OK(); } // If any inputs aren't fully defined or don't match, we return unknown. for (int i = 2; i < c->num_inputs(); ++i) { - const Shape* input = c->input(i); + ShapeHandle input = c->input(i); if (!c->FullyDefined(input) || !c->Merge(first_input, input, &unused).ok()) { c->set_output(0, c->UnknownShape()); @@ -115,13 +115,13 @@ output: The forwarded tensor. // -------------------------------------------------------------------------- namespace { Status MergeShape(InferenceContext* c) { - const Shape* out = c->input(0); + ShapeHandle out = c->input(0); if (!c->RankKnown(out)) { out = c->UnknownShape(); } else { int32 rank = c->Rank(out); for (int i = 1; i < c->num_inputs(); ++i) { - const Shape* input = c->input(i); + ShapeHandle input = c->input(i); if (c->Rank(input) != rank) { out = c->UnknownShape(); break; diff --git a/tensorflow/core/ops/ctc_ops.cc b/tensorflow/core/ops/ctc_ops.cc index 7e2313ea3a1d133b54cb4bdb0c8c9ee994420b5b..0b58a8d817d0db69648b013213aba6bd1d1c62f2 100644 --- a/tensorflow/core/ops/ctc_ops.cc +++ b/tensorflow/core/ops/ctc_ops.cc @@ -18,9 +18,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; // CTC is Connectionist Temporal Classification. See util/ctc/ for details. @@ -34,23 +34,23 @@ REGISTER_OP("CTCLoss") .Output("loss: float") .Output("gradient: float") .SetShapeFn([](InferenceContext* c) { - const Shape* inputs; - const Shape* labels_indices; - const Shape* labels_values; - const Shape* sequence_length; + ShapeHandle inputs; + ShapeHandle labels_indices; + ShapeHandle labels_values; + ShapeHandle sequence_length; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 3, &inputs)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &labels_indices)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &labels_values)); TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 1, &sequence_length)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->Merge(c->Dim(labels_indices, 0), c->Dim(labels_values, 0), &unused)); // Get batch size from inputs and sequence_length, and update inputs // with the merged batch_size since it is returned. - const Dimension* batch_size; + DimensionHandle batch_size; TF_RETURN_IF_ERROR( c->Merge(c->Dim(inputs, 1), c->Dim(sequence_length, 0), &batch_size)); TF_RETURN_IF_ERROR(c->ReplaceDim(inputs, 1, batch_size, &inputs)); @@ -89,18 +89,18 @@ REGISTER_OP("CTCGreedyDecoder") .Output("decoded_shape: int64") .Output("log_probability: float") .SetShapeFn([](InferenceContext* c) { - const Shape* inputs; - const Shape* sequence_length; + ShapeHandle inputs; + ShapeHandle sequence_length; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 3, &inputs)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &sequence_length)); // Get batch size from inputs and sequence_length. - const Dimension* batch_size; + DimensionHandle batch_size; TF_RETURN_IF_ERROR( c->Merge(c->Dim(inputs, 1), c->Dim(sequence_length, 0), &batch_size)); - const Dimension* total_decoded_outputs = c->UnknownDim(); + DimensionHandle total_decoded_outputs = c->UnknownDim(); c->set_output(0, c->Matrix(total_decoded_outputs, 2)); c->set_output(1, c->Vector(total_decoded_outputs)); c->set_output(2, c->Vector(2)); @@ -144,14 +144,14 @@ REGISTER_OP("CTCBeamSearchDecoder") .Output("decoded_shape: top_paths * int64") .Output("log_probability: float") .SetShapeFn([](InferenceContext* c) { - const Shape* inputs; - const Shape* sequence_length; + ShapeHandle inputs; + ShapeHandle sequence_length; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 3, &inputs)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &sequence_length)); // Get batch size from inputs and sequence_length. - const Dimension* batch_size; + DimensionHandle batch_size; TF_RETURN_IF_ERROR( c->Merge(c->Dim(inputs, 1), c->Dim(sequence_length, 0), &batch_size)); @@ -166,7 +166,7 @@ REGISTER_OP("CTCBeamSearchDecoder") for (int i = 0; i < top_paths; ++i) { // decoded_values c->set_output(out_idx++, c->Vector(InferenceContext::kUnknownDim)); } - const Shape* shape_v = c->Vector(2); + ShapeHandle shape_v = c->Vector(2); for (int i = 0; i < top_paths; ++i) { // decoded_shape c->set_output(out_idx++, shape_v); } diff --git a/tensorflow/core/ops/data_flow_ops.cc b/tensorflow/core/ops/data_flow_ops.cc index fbf43a984b653c2b1a1575dcd6a8dc5f7a8c773d..724d83b7f0246748b56fe5a276fbd6ed74e5c84b 100644 --- a/tensorflow/core/ops/data_flow_ops.cc +++ b/tensorflow/core/ops/data_flow_ops.cc @@ -20,9 +20,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; // -------------------------------------------------------------------------- @@ -36,8 +36,8 @@ REGISTER_OP("DynamicPartition") int64 num_partitions; TF_RETURN_IF_ERROR(c->GetAttr("num_partitions", &num_partitions)); - const Shape* data_shape = c->input(0); - const Shape* partitions_shape = c->input(1); + ShapeHandle data_shape = c->input(0); + ShapeHandle partitions_shape = c->input(1); if (!c->RankKnown(partitions_shape)) { return shape_inference::UnknownShape(c); @@ -46,17 +46,17 @@ REGISTER_OP("DynamicPartition") const int64 rank = c->Rank(partitions_shape); // data shape must start with partitions_shape - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR( c->MergePrefix(data_shape, partitions_shape, &unused, &unused)); // The partition shape is dynamic in the 0th dimension, and matches // data_shape in the remaining dimensions. - const Shape* unknown_dim0 = c->MakeShape({c->UnknownDim()}); + ShapeHandle unknown_dim0 = c->MakeShape({c->UnknownDim()}); - const Shape* data_suffix_shape; + ShapeHandle data_suffix_shape; TF_RETURN_IF_ERROR(c->Subshape(data_shape, rank, &data_suffix_shape)); - const Shape* result_shape; + ShapeHandle result_shape; TF_RETURN_IF_ERROR( c->Concatenate(unknown_dim0, data_suffix_shape, &result_shape)); @@ -115,10 +115,10 @@ REGISTER_OP("DynamicStitch") int64 num_partitions; TF_RETURN_IF_ERROR(c->GetAttr("N", &num_partitions)); - const Shape* extra_shape = c->UnknownShape(); + ShapeHandle extra_shape = c->UnknownShape(); for (int i = 0; i < num_partitions; ++i) { - const Shape* indices_shape = c->input(i); - const Shape* data_shape = c->input(i + num_partitions); + ShapeHandle indices_shape = c->input(i); + ShapeHandle data_shape = c->input(i + num_partitions); if (!c->RankKnown(indices_shape)) { continue; } @@ -126,17 +126,17 @@ REGISTER_OP("DynamicStitch") const int64 indices_rank = c->Rank(indices_shape); // Assert that data_shape starts with indices_shape. - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR( c->MergePrefix(data_shape, indices_shape, &unused, &unused)); // The rest belongs to output. - const Shape* rest; + ShapeHandle rest; TF_RETURN_IF_ERROR(c->Subshape(data_shape, indices_rank, &rest)); TF_RETURN_IF_ERROR(c->Merge(extra_shape, rest, &extra_shape)); } - const Shape* output_shape = c->Vector(c->UnknownDim()); + ShapeHandle output_shape = c->Vector(c->UnknownDim()); TF_RETURN_IF_ERROR( c->Concatenate(output_shape, extra_shape, &output_shape)); c->set_output(0, output_shape); @@ -547,7 +547,7 @@ REGISTER_OP("TensorArray") .Output("handle: Ref(string)") .SetIsStateful() .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); c->set_output(0, c->Vector(2)); return Status::OK(); @@ -576,8 +576,8 @@ REGISTER_OP("TensorArrayGrad") .Attr("source: string") .SetIsStateful() .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); c->set_output(0, c->Vector(2)); @@ -637,8 +637,8 @@ REGISTER_OP("TensorArrayWrite") .Output("flow_out: float") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); @@ -662,8 +662,8 @@ REGISTER_OP("TensorArrayRead") .Output("value: dtype") .Attr("dtype: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); @@ -686,8 +686,8 @@ REGISTER_OP("TensorArrayPack") .Attr("dtype: type") .Attr("element_shape: shape = { unknown_rank: true }") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); @@ -715,8 +715,8 @@ REGISTER_OP("TensorArrayUnpack") .Output("flow_out: float") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); @@ -739,8 +739,8 @@ REGISTER_OP("TensorArrayConcat") .Attr("dtype: type") .Attr("element_shape_except0: shape = { unknown_rank: true }") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); @@ -785,8 +785,8 @@ REGISTER_OP("TensorArraySplit") .Output("flow_out: float") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); @@ -827,8 +827,8 @@ REGISTER_OP("TensorArraySize") .Input("flow_in: float") .Output("size: int32") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); return shape_inference::ScalarShape(c); @@ -844,8 +844,8 @@ size: The current size of the TensorArray. REGISTER_OP("TensorArrayClose") .Input("handle: Ref(string)") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(c->input(0), 0), 2, &unused_dim)); return Status::OK(); @@ -900,9 +900,9 @@ REGISTER_OP("BarrierInsertMany") .Attr("T: type") .Attr("component_index: int") .SetShapeFn([](InferenceContext* c) { - const Shape* keys = c->input(1); - const Shape* values = c->input(2); - const Shape* unused; + ShapeHandle keys = c->input(1); + ShapeHandle values = c->input(2); + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(keys, 1, &keys)); TF_RETURN_IF_ERROR(c->WithRankAtLeast(values, 1, &values)); @@ -1016,7 +1016,7 @@ REGISTER_OP("LookupTableFind") .Attr("Tin: type") .Attr("Tout: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); c->set_output(0, c->UnknownShape()); @@ -1044,7 +1044,7 @@ REGISTER_OP("LookupTableInsert") .Attr("Tin: type") .Attr("Tout: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->Merge(c->input(1), c->input(2), &unused)); return Status::OK(); @@ -1064,7 +1064,7 @@ REGISTER_OP("LookupTableSize") .Input("table_handle: Ref(string)") .Output("size: int64") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); c->set_output(0, c->Scalar()); return Status::OK(); @@ -1083,12 +1083,12 @@ REGISTER_OP("LookupTableExport") .Attr("Tkeys: type") .Attr("Tvalues: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - const Shape* values = c->UnknownShape(); + ShapeHandle values = c->UnknownShape(); TF_RETURN_IF_ERROR(c->WithRankAtLeast(values, 1, &values)); - const Shape* keys = c->Vector(c->Dim(values, 0)); + ShapeHandle keys = c->Vector(c->Dim(values, 0)); c->set_output(0, keys); c->set_output(1, values); return Status::OK(); @@ -1108,7 +1108,7 @@ REGISTER_OP("LookupTableImport") .Attr("Tin: type") .Attr("Tout: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->Merge(c->input(1), c->input(2), &unused)); return Status::OK(); @@ -1128,6 +1128,7 @@ REGISTER_OP("HashTable") .Output("table_handle: Ref(string)") .Attr("container: string = ''") .Attr("shared_name: string = ''") + .Attr("use_node_name_sharing: bool = false") .Attr("key_dtype: type") .Attr("value_dtype: type") .SetIsStateful() @@ -1144,6 +1145,8 @@ container: If non-empty, this table is placed in the given container. Otherwise, a default container is used. shared_name: If non-empty, this table is shared under the given name across multiple sessions. +use_node_name_sharing: If true and shared_name is empty, the table is shared + using the node name. key_dtype: Type of the table keys. value_dtype: Type of the table values. )doc"); @@ -1152,6 +1155,7 @@ REGISTER_OP("MutableHashTable") .Output("table_handle: Ref(string)") .Attr("container: string = ''") .Attr("shared_name: string = ''") + .Attr("use_node_name_sharing: bool = false") .Attr("key_dtype: type") .Attr("value_dtype: type") .SetIsStateful() @@ -1168,6 +1172,8 @@ container: If non-empty, this table is placed in the given container. Otherwise, a default container is used. shared_name: If non-empty, this table is shared under the given name across multiple sessions. +use_node_name_sharing: If true and shared_name is empty, the table is shared + using the node name. key_dtype: Type of the table keys. value_dtype: Type of the table values. )doc"); @@ -1176,6 +1182,7 @@ REGISTER_OP("MutableHashTableOfTensors") .Output("table_handle: Ref(string)") .Attr("container: string = ''") .Attr("shared_name: string = ''") + .Attr("use_node_name_sharing: bool = false") .Attr("key_dtype: type") .Attr("value_dtype: type") .Attr("value_shape: shape = {}") @@ -1204,9 +1211,9 @@ REGISTER_OP("InitializeTable") .Attr("Tkey: type") .Attr("Tval: type") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - const Shape* keys; + ShapeHandle keys; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &keys)); TF_RETURN_IF_ERROR(c->Merge(keys, c->input(2), &keys)); return Status::OK(); @@ -1227,7 +1234,7 @@ REGISTER_OP("InitializeTableFromTextFile") .Attr("vocab_size: int >= -1 = -1") .Attr("delimiter: string = '\t'") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); return Status::OK(); diff --git a/tensorflow/core/ops/image_ops.cc b/tensorflow/core/ops/image_ops.cc index 5a55493517b8cef94adc20cefe19b633f130051f..7eb380798c5c1900e07b678dc0b067615853554b 100644 --- a/tensorflow/core/ops/image_ops.cc +++ b/tensorflow/core/ops/image_ops.cc @@ -19,26 +19,26 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { // Sets output[0] to shape [batch_dim,height,width,channel_dim], where // height and width come from the size_tensor. -Status SetOutputToSizedImage(InferenceContext* c, const Dimension* batch_dim, - int size_input_idx, const Dimension* channel_dim) { +Status SetOutputToSizedImage(InferenceContext* c, DimensionHandle batch_dim, + int size_input_idx, DimensionHandle channel_dim) { // Verify shape of size input. - const Shape* size; + ShapeHandle size; TF_RETURN_IF_ERROR(c->WithRank(c->input(size_input_idx), 1, &size)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->WithValue(c->Dim(size, 0), 2, &unused)); // Get size values from the size tensor. const Tensor* size_tensor = c->input_tensor(size_input_idx); - const Dimension* width; - const Dimension* height; + DimensionHandle width; + DimensionHandle height; if (size_tensor == nullptr) { width = c->UnknownDim(); height = c->UnknownDim(); @@ -51,16 +51,16 @@ Status SetOutputToSizedImage(InferenceContext* c, const Dimension* batch_dim, } Status ResizeShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); return SetOutputToSizedImage(c, c->Dim(input, 0), 1 /* size_input_idx */, c->Dim(input, 3)); } Status DecodeImageShapeFn(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); - const Dimension* channels_dim; + DimensionHandle channels_dim; int32 channels; Status s = c->GetAttr("channels", &channels); if (s.ok()) { @@ -79,20 +79,20 @@ Status DecodeImageShapeFn(InferenceContext* c) { } Status EncodeImageShapeFn(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 3, &unused)); c->set_output(0, c->Scalar()); return Status::OK(); } Status ColorspaceShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &input)); // The last dimension value is always 3. - const Dimension* last_dim; + DimensionHandle last_dim; TF_RETURN_IF_ERROR(c->WithValue(c->Dim(input, -1), 3, &last_dim)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->ReplaceDim(input, -1, last_dim, &out)); c->set_output(0, out); @@ -224,10 +224,10 @@ REGISTER_OP("ResizeNearestNeighborGrad") .Attr("T: {uint8, int8, int32, half, float, double}") .Attr("align_corners: bool = false") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Shape* unused; - const Dimension* unused_dim; + ShapeHandle unused; + DimensionHandle unused_dim; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); TF_RETURN_IF_ERROR(c->WithValue(c->Dim(unused, 0), 2, &unused_dim)); const Tensor* size = c->input_tensor(1); @@ -665,15 +665,15 @@ REGISTER_OP("ExtractGlimpse") .Attr("normalized: bool = true") .Attr("uniform_noise: bool = true") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Shape* offsets; + ShapeHandle offsets; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 2, &offsets)); - const Dimension* batch_dim; + DimensionHandle batch_dim; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input, 0), c->Dim(offsets, 0), &batch_dim)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->WithValue(c->Dim(offsets, 1), 2, &unused)); return SetOutputToSizedImage(c, batch_dim, 1 /* size_input_idx */, @@ -734,20 +734,20 @@ REGISTER_OP("CropAndResize") .Attr("extrapolation_value: float = 0") .SetShapeFn([](InferenceContext* c) { // Get inputs and validate ranks. - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Shape* boxes; + ShapeHandle boxes; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &boxes)); - const Shape* box_ind; + ShapeHandle box_ind; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &box_ind)); // boxes[0] and box_ind[0] are both num_boxes. - const Dimension* num_boxes_dim; + DimensionHandle num_boxes_dim; TF_RETURN_IF_ERROR( c->Merge(c->Dim(boxes, 0), c->Dim(box_ind, 0), &num_boxes_dim)); // boxes.dim(1) is 4. - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->WithValue(c->Dim(boxes, 1), 4, &unused)); return SetOutputToSizedImage(c, num_boxes_dim, 3 /* size_input_idx */, @@ -797,7 +797,7 @@ REGISTER_OP("CropAndResizeGradImage") .Attr("T: {float, half, double}") .Attr("method: {'bilinear'} = 'bilinear'") .SetShapeFn([](InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(3, &out)); TF_RETURN_IF_ERROR(c->WithRank(out, 4, &out)); c->set_output(0, out); diff --git a/tensorflow/core/ops/io_ops.cc b/tensorflow/core/ops/io_ops.cc index 1d528660cfa820cc7f3a27e5cb57226f368c7dd1..83e4a83897afffc785fce3c0f17a79f2d6947ed6 100644 --- a/tensorflow/core/ops/io_ops.cc +++ b/tensorflow/core/ops/io_ops.cc @@ -19,14 +19,14 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { Status ScalarInputsAndOutputs(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; for (int i = 0; i < c->num_inputs(); ++i) { TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 0, &unused)); } @@ -44,9 +44,9 @@ REGISTER_OP("Save") .Input("data: T") .Attr("T: list(type)") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Shape* s; - const Dimension* unused_dim; + ShapeHandle unused; + ShapeHandle s; + DimensionHandle unused_dim; // Validate filename. TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); @@ -79,9 +79,9 @@ REGISTER_OP("SaveSlices") .Input("data: T") .Attr("T: list(type)") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Shape* s; - const Dimension* unused_dim; + ShapeHandle unused; + ShapeHandle s; + DimensionHandle unused_dim; // Validate filename. TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); @@ -136,7 +136,7 @@ REGISTER_OP("Restore") .Attr("dt: type") .Attr("preferred_shard: int = -1") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); c->set_output(0, c->UnknownShape()); @@ -180,7 +180,7 @@ REGISTER_OP("RestoreSlice") .Attr("dt: type") .Attr("preferred_shard: int = -1") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); @@ -353,11 +353,11 @@ REGISTER_OP("ReaderReadUpTo") .Output("keys: string") .Output("values: string") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); - const Shape* out = c->Vector(InferenceContext::kUnknownDim); + ShapeHandle out = c->Vector(InferenceContext::kUnknownDim); c->set_output(0, out); c->set_output(1, out); return Status::OK(); @@ -451,7 +451,7 @@ REGISTER_OP("MatchingFiles") .Input("pattern: string") .Output("filenames: string") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &unused)); c->set_output(0, c->Vector(InferenceContext::kUnknownDim)); return Status::OK(); diff --git a/tensorflow/core/ops/linalg_ops.cc b/tensorflow/core/ops/linalg_ops.cc index 4be9e0125558fa1a7f88a5136e4ab8bfcd3c89f4..ccbe039eabfe99ae962fa0d720af18c678e05f02 100644 --- a/tensorflow/core/ops/linalg_ops.cc +++ b/tensorflow/core/ops/linalg_ops.cc @@ -18,62 +18,61 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { // Return in the result of making a square matrix. -Status MakeSquareMatrix(InferenceContext* c, const Shape* s, - const Shape** out) { +Status MakeSquareMatrix(InferenceContext* c, ShapeHandle s, ShapeHandle* out) { TF_RETURN_IF_ERROR(c->WithRank(s, 2, &s)); - const Dimension* d; + DimensionHandle d; TF_RETURN_IF_ERROR(c->Merge(c->Dim(s, 0), c->Dim(s, 1), &d)); *out = c->Matrix(d, d); return Status::OK(); } Status UnchangedSquareShapeFn(InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(MakeSquareMatrix(c, c->input(0), &out)); c->set_output(0, out); return Status::OK(); } // Return in the result of making the end of a square matrix. -Status MakeBatchSquareMatrix(InferenceContext* c, const Shape* input, - const Shape** out) { - const Shape* s; +Status MakeBatchSquareMatrix(InferenceContext* c, ShapeHandle input, + ShapeHandle* out) { + ShapeHandle s; TF_RETURN_IF_ERROR(c->WithRankAtLeast(input, 2, &s)); - const Dimension* d; + DimensionHandle d; TF_RETURN_IF_ERROR(c->Merge(c->Dim(s, -2), c->Dim(s, -1), &d)); - const Shape* batch_shape; + ShapeHandle batch_shape; TF_RETURN_IF_ERROR(c->Subshape(s, 0, -2, &batch_shape)); TF_RETURN_IF_ERROR(c->Concatenate(batch_shape, c->Matrix(d, d), out)); return Status::OK(); } Status BatchUnchangedSquareShapeFn(InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(MakeBatchSquareMatrix(c, c->input(0), &out)); c->set_output(0, out); return Status::OK(); } Status SquareMatrixSolveShapeFn(InferenceContext* c) { - const Shape* lhs; - const Shape* rhs; + ShapeHandle lhs; + ShapeHandle rhs; TF_RETURN_IF_ERROR(MakeSquareMatrix(c, c->input(0), &lhs)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &rhs)); // lhs and rhs have the same number of rows. Make a new output // shape that uses rows to replace rhs.dim[0]. - const Dimension* rows; + DimensionHandle rows; TF_RETURN_IF_ERROR(c->Merge(c->Dim(lhs, 0), c->Dim(rhs, 0), &rows)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->ReplaceDim(rhs, 0, rows, &out)); c->set_output(0, out); return Status::OK(); @@ -82,8 +81,8 @@ Status SquareMatrixSolveShapeFn(InferenceContext* c) { // Inputs are [...,M,N] and [...,M,K]. Output is [...,N,K]. // If , then input is [...,M,M]. Status BatchMatrixSolveShapeFn(InferenceContext* c, bool square) { - const Shape* lhs; - const Shape* rhs; + ShapeHandle lhs; + ShapeHandle rhs; if (square) { TF_RETURN_IF_ERROR(MakeBatchSquareMatrix(c, c->input(0), &lhs)); } else { @@ -92,44 +91,44 @@ Status BatchMatrixSolveShapeFn(InferenceContext* c, bool square) { TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 2, &rhs)); // Make the common batch subshape between the two dimensions. - const Shape* lhs_batch_shape; - const Shape* batch_shape; + ShapeHandle lhs_batch_shape; + ShapeHandle batch_shape; TF_RETURN_IF_ERROR(c->Subshape(lhs, 0, -2, &lhs_batch_shape)); TF_RETURN_IF_ERROR(c->Subshape(rhs, 0, -2, &batch_shape)); TF_RETURN_IF_ERROR(c->Merge(lhs_batch_shape, batch_shape, &batch_shape)); // lhs and rhs have the same value for m. - const Dimension* m; + DimensionHandle m; TF_RETURN_IF_ERROR(c->Merge(c->Dim(lhs, -2), c->Dim(rhs, -2), &m)); - const Dimension* n = c->Dim(lhs, -1); + DimensionHandle n = c->Dim(lhs, -1); if (square) { TF_RETURN_IF_ERROR(c->Merge(m, n, &n)); } // Build final shape (batch_shape + n + k) in . - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate(batch_shape, c->Vector(n), &out)); TF_RETURN_IF_ERROR(c->Concatenate(out, c->Vector(c->Dim(rhs, -1)), &out)); c->set_output(0, out); return Status::OK(); } -Status BatchSvdShapeHelperFn(InferenceContext* c, const Shape* input) { - const Dimension* m = c->Dim(input, -2); - const Dimension* n = c->Dim(input, -1); - const Dimension* p; +Status BatchSvdShapeHelperFn(InferenceContext* c, ShapeHandle input) { + DimensionHandle m = c->Dim(input, -2); + DimensionHandle n = c->Dim(input, -1); + DimensionHandle p; TF_RETURN_IF_ERROR(c->Min(m, n, &p)); - const Shape* batch_shape; + ShapeHandle batch_shape; TF_RETURN_IF_ERROR(c->Subshape(input, 0, -2, &batch_shape)); - const Shape* e_shape; + ShapeHandle e_shape; TF_RETURN_IF_ERROR(c->Concatenate(batch_shape, c->Vector(p), &e_shape)); c->set_output(0, e_shape); bool compute_uv; TF_RETURN_IF_ERROR(c->GetAttr("compute_uv", &compute_uv)); if (compute_uv) { - const Shape* u_shape; - const Shape* v_shape; + ShapeHandle u_shape; + ShapeHandle v_shape; bool full_matrices; TF_RETURN_IF_ERROR(c->GetAttr("full_matrices", &full_matrices)); if (full_matrices) { @@ -159,7 +158,7 @@ Status BatchSvdShapeHelperFn(InferenceContext* c, const Shape* input) { // [M,P]; [N,P], if compute_uv is true and full_matrices is false, // where P = min(M,N). Status SvdShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &input)); return BatchSvdShapeHelperFn(c, input); } @@ -171,7 +170,7 @@ Status SvdShapeFn(InferenceContext* c) { // [...,M,P]; [...,N,P], if compute_uv is true and full_matrices is false, // where P = min(M,N). Status BatchSvdShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 2, &input)); return BatchSvdShapeHelperFn(c, input); } @@ -180,9 +179,9 @@ Status BatchSvdShapeFn(InferenceContext* c) { // [N];[0], if compute_v is false, // [N];[N,N], if compute_v is true. Status SelfAdjointEigV2ShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(MakeSquareMatrix(c, c->input(0), &input)); - const Dimension* n; + DimensionHandle n; TF_RETURN_IF_ERROR(c->Merge(c->Dim(input, 0), c->Dim(input, 1), &n)); c->set_output(0, c->Vector(n)); bool compute_v; @@ -199,19 +198,19 @@ Status SelfAdjointEigV2ShapeFn(InferenceContext* c) { // [...,N];[0], if compute_v is false, // [...,N];[...,N,N], if compute_v is true. Status BatchSelfAdjointEigV2ShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(MakeBatchSquareMatrix(c, c->input(0), &input)); - const Dimension* n; + DimensionHandle n; TF_RETURN_IF_ERROR(c->Merge(c->Dim(input, -2), c->Dim(input, -1), &n)); - const Shape* batch_shape; + ShapeHandle batch_shape; TF_RETURN_IF_ERROR(c->Subshape(input, 0, -2, &batch_shape)); - const Shape* e_shape; + ShapeHandle e_shape; TF_RETURN_IF_ERROR(c->Concatenate(batch_shape, c->Vector(n), &e_shape)); c->set_output(0, e_shape); bool compute_v; TF_RETURN_IF_ERROR(c->GetAttr("compute_v", &compute_v)); if (compute_v) { - const Shape* v_shape; + ShapeHandle v_shape; TF_RETURN_IF_ERROR(c->Concatenate(batch_shape, c->Matrix(n, n), &v_shape)); c->set_output(1, v_shape); } else { @@ -227,7 +226,7 @@ REGISTER_OP("MatrixDeterminant") .Output("output: T") .Attr("T: {float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(MakeSquareMatrix(c, c->input(0), &input)); c->set_output(0, c->Scalar()); return Status::OK(); @@ -244,14 +243,14 @@ REGISTER_OP("BatchMatrixDeterminant") .Output("output: T") .Attr("T: {float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 2, &input)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input, -1), c->Dim(input, -2), &unused)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Subshape(input, 0, -2, &out)); c->set_output(0, out); return Status::OK(); @@ -395,11 +394,11 @@ REGISTER_OP("SelfAdjointEig") .Attr("T: {double, float}") .Deprecated(11, "Use SelfAdjointEigV2 instead.") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(MakeSquareMatrix(c, c->input(0), &input)); - const Dimension* d = c->Dim(input, 0); - const Dimension* d_plus_1; + DimensionHandle d = c->Dim(input, 0); + DimensionHandle d_plus_1; TF_RETURN_IF_ERROR(c->Add(d, 1, &d_plus_1)); c->set_output(0, c->Matrix(d_plus_1, d)); return Status::OK(); @@ -423,14 +422,14 @@ REGISTER_OP("BatchSelfAdjointEig") .Attr("T: {double, float}") .Deprecated(11, "Use BatchSelfAdjointEigV2 instead.") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(MakeBatchSquareMatrix(c, c->input(0), &input)); - const Dimension* d = c->Dim(input, -1); - const Dimension* d_plus_1; + DimensionHandle d = c->Dim(input, -1); + DimensionHandle d_plus_1; TF_RETURN_IF_ERROR(c->Add(d, 1, &d_plus_1)); - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->Subshape(input, 0, -2, &s)); TF_RETURN_IF_ERROR(c->Concatenate(s, c->Matrix(d_plus_1, d), &s)); c->set_output(0, s); @@ -627,13 +626,13 @@ REGISTER_OP("MatrixSolveLs") .Attr("T: {double, float}") .Attr("fast: bool = True") .SetShapeFn([](InferenceContext* c) { - const Shape* lhs; - const Shape* rhs; + ShapeHandle lhs; + ShapeHandle rhs; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &lhs)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &rhs)); // The matrix and right-hand side must have the same number of rows. - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->Merge(c->Dim(lhs, 0), c->Dim(rhs, 0), &unused)); c->set_output(0, c->Matrix(c->Dim(lhs, 1), c->Dim(rhs, 1))); diff --git a/tensorflow/core/ops/math_grad.cc b/tensorflow/core/ops/math_grad.cc index 1d8f45ea7a0cb3af4ba37c42f4d4aa2343f7cbf0..f74ce32cef6c428451fcf24d717986051ad2a627 100644 --- a/tensorflow/core/ops/math_grad.cc +++ b/tensorflow/core/ops/math_grad.cc @@ -375,26 +375,42 @@ REGISTER_OP_GRADIENT("Div", DivGrad); Status PowGrad(const AttrSlice& attrs, FunctionDef* g) { // clang-format off - return GradForBinaryCwise(g, { - {{"z"}, "Pow", {"x", "y"}}, - // dz * y * Pow(x, y - 1) - FDH::Const("const_zero", 0.0f), - FDH::Const("const_one", 1.0f), - {{"zero"}, "Cast", {"const_zero"}, {{"SrcT", DT_FLOAT}, {"DstT", "$T"}}}, - {{"one"}, "Cast", {"const_one"}, {{"SrcT", DT_FLOAT}, {"DstT", "$T"}}}, - {{"t0"}, "Sub", {"y", "one"}, {}, {"dz"}}, - {{"t1"}, "Pow", {"x", "t0"}}, - {{"t2"}, "Mul", {"dz", "y"}}, - {{"gx"}, "Mul", {"t1", "t2"}}, - // dz * z * (x > 0 ? Log(x) : 0) + std::vector nodes = { + {{"z"}, "Pow", {"x", "y"}}, + // dz * y * Pow(x, y - 1) + FDH::Const("const_zero", 0.0f), + FDH::Const("const_one", 1.0f), + {{"zero"}, "Cast", {"const_zero"}, {{"SrcT", DT_FLOAT}, {"DstT", "$T"}}}, + {{"one"}, "Cast", {"const_one"}, {{"SrcT", DT_FLOAT}, {"DstT", "$T"}}}, + {{"t0"}, "Sub", {"y", "one"}, {}, {"dz"}}, + {{"t1"}, "Pow", {"x", "t0"}}, + {{"t2"}, "Mul", {"dz", "y"}}, + {{"gx"}, "Mul", {"t1", "t2"}}, + {{"unsafe_log"}, "Log", {"x"}, {}, {"dz"}}, + {{"zeros"}, "ZerosLike", {"x"}}}; + // clang-format on + std::vector log_x_handling; + DataType T; + TF_RETURN_IF_ERROR(GetNodeAttr(attrs, "T", &T)); + if (T == DT_COMPLEX64 || T == DT_COMPLEX128) { + // dz * z * (x != 0 ? Log(x) : 0) + // clang-format off + log_x_handling = { + {{"nz_x"}, "NotEqual", {"x", "zero"}}, + {{"safe_log"}, "Select", {"nz_x", "unsafe_log", "zeros"}}}; + // clang-format on + } else { + // dz * z * (x > 0 ? Log(x) : 0) + // clang-format off + log_x_handling = { {{"pos_x"}, "Greater", {"x", "zero"}}, - {{"unsafe_log"}, "Log", {"x"}, {}, {"dz"}}, - {{"zeros"}, "ZerosLike", {"x"}}, - {{"safe_log"}, "Select", {"pos_x", "unsafe_log", "zeros"}}, - {{"t4"}, "Mul", {"dz", "z"}}, - {{"gy"}, "Mul", {"safe_log", "t4"}}, - }); - // clang-format on + {{"safe_log"}, "Select", {"pos_x", "unsafe_log", "zeros"}}}; + // clang-format on + } + nodes.insert(nodes.end(), log_x_handling.begin(), log_x_handling.end()); + nodes.push_back({{"t4"}, "Mul", {"dz", "z"}}); + nodes.push_back({{"gy"}, "Mul", {"safe_log", "t4"}}); + return GradForBinaryCwise(g, nodes); } REGISTER_OP_GRADIENT("Pow", PowGrad); diff --git a/tensorflow/core/ops/math_grad_test.cc b/tensorflow/core/ops/math_grad_test.cc index 9af73b2da0d68bcbdc4f39d450e519d71afa4aa4..e937fc5ab14800d3dc4a82fdef6402aa2cbcaf92 100644 --- a/tensorflow/core/ops/math_grad_test.cc +++ b/tensorflow/core/ops/math_grad_test.cc @@ -684,6 +684,25 @@ TEST_F(MathGradTest, Pow) { } } +TEST_F(MathGradTest, ComplexPow) { + auto x = test::AsTensor({0.f, 2.f, -2.f}, TensorShape({3})); + auto y = test::AsTensor({2.f, 2.f, 2.f}, TensorShape({3})); + Tensor dx; + Tensor dy; + auto g = [](complex64 x, complex64 y) { return y * std::pow(x, y - 1.f); }; + auto h = [](complex64 x, complex64 y) { + return std::pow(x, y) * (x != complex64(0) ? std::log(x) : 0); + }; + SymGrad("Pow", x, y, &dx, &dy); + + test::ExpectClose( + dx, test::AsTensor({g(0.f, 2.f), g(2.f, 2.f), g(-2.f, 2.f)}, + TensorShape({3}))); + test::ExpectClose( + dy, test::AsTensor({h(0.f, 2.f), h(2.f, 2.f), h(-2.f, 2.f)}, + TensorShape({3}))); +} + TEST_F(MathGradTest, Maximum) { auto x = test::AsTensor({-3.f, -2.f, -1.f, 1.f, 2.f, 3.f}, TensorShape({2, 3})); diff --git a/tensorflow/core/ops/math_ops.cc b/tensorflow/core/ops/math_ops.cc index 6b5c450f0ecca3269236a4499a22c6ae5e25d1cc..f2087aa3ca359457329e45b0011b3c2156fae8e4 100644 --- a/tensorflow/core/ops/math_ops.cc +++ b/tensorflow/core/ops/math_ops.cc @@ -20,9 +20,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("AddN") .Input("inputs: N * T") @@ -32,7 +32,7 @@ REGISTER_OP("AddN") .SetIsCommutative() .SetIsAggregate() .SetShapeFn([](InferenceContext* c) { - const Shape* cur = c->input(c->num_inputs() - 1); + ShapeHandle cur = c->input(c->num_inputs() - 1); for (int i = c->num_inputs() - 2; i >= 0; --i) { TF_RETURN_WITH_CONTEXT_IF_ERROR(c->Merge(c->input(i), cur, &cur), "From merging shape ", i, @@ -51,8 +51,8 @@ namespace { // Shape inference function for binary operators that broadcast their inputs. Status BroadcastBinaryOpShapeFn(InferenceContext* c) { - const Shape* shape_x = c->input(0); - const Shape* shape_y = c->input(1); + ShapeHandle shape_x = c->input(0); + ShapeHandle shape_y = c->input(1); if (!c->RankKnown(shape_x) || !c->RankKnown(shape_y)) { c->set_output(0, c->UnknownShape()); return Status::OK(); @@ -64,15 +64,16 @@ Status BroadcastBinaryOpShapeFn(InferenceContext* c) { // To compute the broadcast dimensions, we zip together shape_x and shape_y // and // pad with 1 to make them the same length. - std::vector dims; - const Dimension* dim_one = rank_x == rank_y ? nullptr : c->MakeDim(1); + std::vector dims; + DimensionHandle dim_one; + if (rank_x != rank_y) dim_one = c->MakeDim(1); for (int i = 0; i < rank_out; ++i) { - const auto* dim_x = i < (rank_out - rank_x) - ? dim_one - : c->Dim(shape_x, i - (rank_out - rank_x)); - const auto* dim_y = i < (rank_out - rank_y) - ? dim_one - : c->Dim(shape_y, i - (rank_out - rank_y)); + const auto dim_x = i < (rank_out - rank_x) + ? dim_one + : c->Dim(shape_x, i - (rank_out - rank_x)); + const bool dim_y_is_one = (i < (rank_out - rank_y)); + const auto dim_y = + dim_y_is_one ? dim_one : c->Dim(shape_y, i - (rank_out - rank_y)); if (!c->ValueKnown(dim_x) || !c->ValueKnown(dim_y)) { // One or both dimensions is unknown. // @@ -94,7 +95,7 @@ Status BroadcastBinaryOpShapeFn(InferenceContext* c) { dims.push_back(c->UnknownDim()); } } else if (c->Value(dim_x) == 1 || c->Value(dim_y) == 1) { - if (c->Value(dim_x) == 1 && dim_y != dim_one) { + if (c->Value(dim_x) == 1 && !dim_y_is_one) { // We will broadcast dim_x to dim_y. dims.push_back(dim_y); } else { @@ -103,7 +104,7 @@ Status BroadcastBinaryOpShapeFn(InferenceContext* c) { dims.push_back(dim_x); } } else { - const Dimension* dim; + DimensionHandle dim; TF_RETURN_IF_ERROR(c->Merge(dim_x, dim_y, &dim)); dims.push_back(dim); } @@ -125,8 +126,8 @@ REGISTER_OP("BatchMatMul") .Attr("adj_x: bool = false") .Attr("adj_y: bool = false") .SetShapeFn([](InferenceContext* c) { - const Shape* a_shape; - const Shape* b_shape; + ShapeHandle a_shape; + ShapeHandle b_shape; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 3, &a_shape)); TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(1), 3, &b_shape)); @@ -135,23 +136,23 @@ REGISTER_OP("BatchMatMul") bool adj_y; TF_RETURN_IF_ERROR(c->GetAttr("adj_x", &adj_x)); TF_RETURN_IF_ERROR(c->GetAttr("adj_y", &adj_y)); - const Dimension* output_rows = c->Dim(a_shape, adj_x ? -1 : -2); - const Dimension* output_cols = c->Dim(b_shape, adj_y ? -2 : -1); + DimensionHandle output_rows = c->Dim(a_shape, adj_x ? -1 : -2); + DimensionHandle output_cols = c->Dim(b_shape, adj_y ? -2 : -1); // Batch dims match between inputs. - const Shape* a_batch_dims; - const Shape* b_batch_dims; - const Shape* batch_dims; + ShapeHandle a_batch_dims; + ShapeHandle b_batch_dims; + ShapeHandle batch_dims; TF_RETURN_IF_ERROR(c->Subshape(a_shape, 0, -2, &a_batch_dims)); TF_RETURN_IF_ERROR(c->Subshape(b_shape, 0, -2, &b_batch_dims)); TF_RETURN_IF_ERROR(c->Merge(a_batch_dims, b_batch_dims, &batch_dims)); // Assert inner dims match. - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->Merge(c->Dim(a_shape, adj_x ? -2 : -1), c->Dim(b_shape, adj_y ? -1 : -2), &unused)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate( batch_dims, c->Matrix(output_rows, output_cols), &out)); c->set_output(0, out); @@ -686,6 +687,30 @@ The polygamma function is defined as: where \\(\psi(x)\\) is the digamma function. )doc"); +REGISTER_OP("Betainc") + .Input("a: T") + .Input("b: T") + .Input("x: T") + .Output("z: T") + .Attr("T: {float, double}") + .Doc(R"doc( +Compute the regularized incomplete beta integral \\(I_x(a, b)\\). + +The regularized incomplete beta integral is defined as: + +``` +I_x(a, b) = \frac{B(x; a, b)}{B(a, b)} +``` +where + +``` +B(x; a, b) = \int_0^x t^{a-1} (1 - t)^{b-1} dt +``` + +is the incomplete beta function and \\(B(a, b)\\) is the *complete* +beta function. +)doc"); + // -------------------------------------------------------------------------- // Declares cwise binary comparison operations signature: 't, 't -> bool, @@ -814,8 +839,8 @@ REGISTER_OP("Select") .Output("output: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* cond = c->input(0); - const Shape* data = c->input(1); + ShapeHandle cond = c->input(0); + ShapeHandle data = c->input(1); TF_RETURN_IF_ERROR(c->Merge(data, c->input(2), &data)); // Validate condition's shape if possible. @@ -830,12 +855,12 @@ REGISTER_OP("Select") if (c->Rank(cond) == 1) { // Must be a vector whose first dimension matches first dimension // of the data vectors. - const Dimension* merged_dim; + DimensionHandle merged_dim; TF_RETURN_IF_ERROR( c->Merge(c->Dim(data, 0), c->Dim(cond, 0), &merged_dim)); - if (merged_dim != c->Dim(data, 0)) { + if (c->Value(merged_dim) != c->Value(c->Dim(data, 0))) { // Merging used the cond dim. Update data to refer to it. - std::vector dims{merged_dim}; + std::vector dims{merged_dim}; for (int i = 1; i < data_rank; ++i) { dims.push_back(c->Dim(data, i)); } @@ -1075,10 +1100,10 @@ output: The reduced tensor. namespace { Status ArgOpShape(shape_inference::InferenceContext* c) { - const Shape* dimension_shape; + ShapeHandle dimension_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &dimension_shape)); - const Shape* input_shape = c->input(0); + ShapeHandle input_shape = c->input(0); if (!c->RankKnown(input_shape)) { return shape_inference::UnknownShape(c); } @@ -1094,7 +1119,7 @@ Status ArgOpShape(shape_inference::InferenceContext* c) { // We don't know the value of the dimension, but we // know the rank of the input, so return the correct // rank with unknown dimensions. - std::vector dims(input_rank - 1); + std::vector dims(input_rank - 1); for (int i = 0; i < dims.size(); ++i) { dims[i] = c->UnknownDim(); } @@ -1112,7 +1137,7 @@ Status ArgOpShape(shape_inference::InferenceContext* c) { } // Return the input shape without the dimension being reduced. - std::vector dims; + std::vector dims; for (int i = 0; i < input_rank; ++i) { if (dimension_val != i) { dims.emplace_back(c->Dim(input_shape, i)); @@ -1153,15 +1178,15 @@ dimension: int32, 0 <= dimension < rank(input). Describes which dimension namespace { Status SegmentReductionShapeFn(InferenceContext* c) { - const Shape* data_shape; - const Shape* segment_ids_shape; + ShapeHandle data_shape; + ShapeHandle segment_ids_shape; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &data_shape)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &segment_ids_shape)); - const Shape* subshape; + ShapeHandle subshape; TF_RETURN_IF_ERROR(c->Subshape(data_shape, 1, &subshape)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR( c->Concatenate(c->Vector(InferenceContext::kUnknownDim), subshape, &out)); c->set_output(0, out); @@ -1169,23 +1194,23 @@ Status SegmentReductionShapeFn(InferenceContext* c) { } Status SparseSegmentReductionShapeFn(InferenceContext* c) { - const Shape* data_shape; + ShapeHandle data_shape; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &data_shape)); - const Shape* indices_shape; + ShapeHandle indices_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &indices_shape)); - const Shape* segment_ids_shape; + ShapeHandle segment_ids_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &segment_ids_shape)); // indices and segment_ids should merge cleanly. - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->Merge(indices_shape, segment_ids_shape, &unused)); - const Shape* subshape; + ShapeHandle subshape; TF_RETURN_IF_ERROR(c->Subshape(data_shape, 1, &subshape)); - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR( c->Concatenate(c->Vector(InferenceContext::kUnknownDim), subshape, &out)); c->set_output(0, out); @@ -1193,24 +1218,24 @@ Status SparseSegmentReductionShapeFn(InferenceContext* c) { } Status SparseSegmentReductionGradShapeFn(InferenceContext* c) { - const Shape* data_shape; + ShapeHandle data_shape; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &data_shape)); - const Shape* indices_shape; + ShapeHandle indices_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &indices_shape)); // indices and segment_ids should merge cleanly. - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->Merge(c->input(2), indices_shape, &unused)); // output_dim0 should be a scalar TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); - const Shape* subshape; + ShapeHandle subshape; TF_RETURN_IF_ERROR(c->Subshape(data_shape, 1, &subshape)); const Tensor* dim0 = c->input_tensor(3); - const Shape* dim0_shape; + ShapeHandle dim0_shape; if (dim0 == nullptr) { // We don't have the value at inference time, so the output // shape is unknown. @@ -1224,7 +1249,7 @@ Status SparseSegmentReductionGradShapeFn(InferenceContext* c) { dim0_shape = c->Vector(dim0_value); } - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate(dim0_shape, subshape, &out)); c->set_output(0, out); return Status::OK(); @@ -1384,12 +1409,12 @@ REGISTER_OP("UnsortedSegmentSum") .Attr("T: numbertype") .Attr("Tindices: {int32,int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* s_data = c->input(0); - const Shape* s_segment_ids = c->input(1); - const Shape* s_num_segments = c->input(2); + ShapeHandle s_data = c->input(0); + ShapeHandle s_segment_ids = c->input(1); + ShapeHandle s_num_segments = c->input(2); TF_RETURN_IF_ERROR(c->WithRank(s_num_segments, 0, &s_num_segments)); - const Shape* out; + ShapeHandle out; // Leading dimensions of data must be compatible with dimensions of // . @@ -1398,11 +1423,11 @@ REGISTER_OP("UnsortedSegmentSum") c->MergePrefix(s_data, s_segment_ids, &s_data, &s_segment_ids)); // Get the value of the num_segments input tensor. - const Dimension* num_segments_dim; + DimensionHandle num_segments_dim; TF_RETURN_IF_ERROR(c->MakeDimForScalarInput(2, &num_segments_dim)); // Output is {segment_id_rank} + s_data[segment_id_rank:]. - const Shape* s_data_suffix; + ShapeHandle s_data_suffix; TF_RETURN_IF_ERROR( c->Subshape(s_data, c->Rank(s_segment_ids), &s_data_suffix)); TF_RETURN_IF_ERROR( @@ -1629,7 +1654,7 @@ REGISTER_OP("Range") .Input("delta: int32") .Output("output: int32") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_WITH_CONTEXT_IF_ERROR(c->WithRank(c->input(0), 0, &unused), " for 'start'"); TF_RETURN_WITH_CONTEXT_IF_ERROR(c->WithRank(c->input(1), 0, &unused), @@ -1685,7 +1710,7 @@ REGISTER_OP("LinSpace") .Output("output: T") .Attr("T: {float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_WITH_CONTEXT_IF_ERROR(c->WithRank(c->input(0), 0, &unused), " for 'start'"); TF_RETURN_WITH_CONTEXT_IF_ERROR(c->WithRank(c->input(1), 0, &unused), diff --git a/tensorflow/core/ops/nn_ops.cc b/tensorflow/core/ops/nn_ops.cc index 38556f0e3549f9ff212dfcbbaedc73f70db11547..affbd2696699807c07696cc8829f74738360e41f 100644 --- a/tensorflow/core/ops/nn_ops.cc +++ b/tensorflow/core/ops/nn_ops.cc @@ -22,9 +22,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { @@ -33,7 +33,7 @@ namespace { // unknown dims. Status InputTensorShapeOrUnknown(InferenceContext* c, int input_idx, int ndims) { - const Shape* out; + ShapeHandle out; const Tensor* input = c->input_tensor(input_idx); if (input == nullptr) { out = c->UnknownShapeOfRank(ndims); @@ -122,17 +122,17 @@ REGISTER_OP("BatchNormWithGlobalNormalization") .Attr("scale_after_normalization: bool") .Deprecated(9, "Use tf.nn.batch_normalization()") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); - const Dimension* last_dim = c->Dim(input, 3); + DimensionHandle last_dim = c->Dim(input, 3); for (int i = 1; i < 5; ++i) { // covers m, v, beta, gamma - const Shape* vec; + ShapeHandle vec; TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 1, &vec)); TF_RETURN_IF_ERROR(c->Merge(last_dim, c->Dim(vec, 0), &last_dim)); } - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->ReplaceDim(input, 3, last_dim, &out)); c->set_output(0, out); return Status::OK(); @@ -175,23 +175,23 @@ REGISTER_OP("BatchNormWithGlobalNormalizationGrad") .Attr("scale_after_normalization: bool") .Deprecated(9, "Use tf.nn.batch_normalization()") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input)); TF_RETURN_IF_ERROR( c->Merge(input, c->input(4), &input)); // with backprop - const Dimension* last_dim = c->Dim(input, 3); + DimensionHandle last_dim = c->Dim(input, 3); for (int i = 1; i < 4; ++i) { // covers m, v, gamma - const Shape* vec; + ShapeHandle vec; TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 1, &vec)); TF_RETURN_IF_ERROR(c->Merge(last_dim, c->Dim(vec, 0), &last_dim)); } - const Shape* dx; + ShapeHandle dx; TF_RETURN_IF_ERROR(c->ReplaceDim(input, 3, last_dim, &dx)); c->set_output(0, dx); - const Shape* vector_shape = c->Vector(last_dim); + ShapeHandle vector_shape = c->Vector(last_dim); c->set_output(1, vector_shape); c->set_output(2, vector_shape); c->set_output(3, vector_shape); @@ -586,7 +586,7 @@ REGISTER_OP("Conv3DBackpropFilter") .Attr(GetPaddingAttrString()) .Deprecated(10, "Use Conv3DBackpropFilterV2") .SetShapeFn([](InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 5, &out)); c->set_output(0, out); return Status::OK(); @@ -614,7 +614,7 @@ REGISTER_OP("Conv3DBackpropInputV2") .Attr("strides: list(int) >= 5") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &s)); TF_RETURN_IF_ERROR(c->WithRank(s, 5, &s)); c->set_output(0, s); @@ -645,7 +645,7 @@ REGISTER_OP("Conv3DBackpropFilterV2") .Attr("strides: list(int) >= 5") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(1, &s)); TF_RETURN_IF_ERROR(c->WithRank(s, 5, &s)); c->set_output(0, s); @@ -698,7 +698,7 @@ REGISTER_OP("AvgPool3DGrad") .Attr(GetPaddingAttrString()) .Attr("T: numbertype") .SetShapeFn([](InferenceContext* c) { - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &s)); TF_RETURN_IF_ERROR(c->WithRank(s, 5, &s)); c->set_output(0, s); @@ -829,7 +829,7 @@ REGISTER_OP("LRNGrad") .Attr("beta: float = 0.5") .Attr("T: {float, half} = DT_FLOAT") .SetShapeFn([](InferenceContext* c) { - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &s)); // input_grads TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // input_image TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // output_image @@ -975,9 +975,9 @@ REGISTER_OP("Dilation2D") .Attr("rates: list(int) >= 4") .Attr(GetPaddingAttrString()) .SetShapeFn([](InferenceContext* c) { - const Shape* input_shape; + ShapeHandle input_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 4, &input_shape)); - const Shape* filter_shape; + ShapeHandle filter_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 3, &filter_shape)); std::vector strides; @@ -1004,14 +1004,14 @@ REGISTER_OP("Dilation2D") int32 rate_rows = rates[1]; int32 rate_cols = rates[2]; - const Dimension* batch_size_dim = c->Dim(input_shape, 0); - const Dimension* in_rows_dim = c->Dim(input_shape, 1); - const Dimension* in_cols_dim = c->Dim(input_shape, 2); - const Dimension* filter_rows_dim = c->Dim(filter_shape, 0); - const Dimension* filter_cols_dim = c->Dim(filter_shape, 1); - const Dimension* output_depth_dim = c->Dim(filter_shape, 2); + DimensionHandle batch_size_dim = c->Dim(input_shape, 0); + DimensionHandle in_rows_dim = c->Dim(input_shape, 1); + DimensionHandle in_cols_dim = c->Dim(input_shape, 2); + DimensionHandle filter_rows_dim = c->Dim(filter_shape, 0); + DimensionHandle filter_cols_dim = c->Dim(filter_shape, 1); + DimensionHandle output_depth_dim = c->Dim(filter_shape, 2); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->Merge(c->Dim(input_shape, 3), output_depth_dim, &unused)); @@ -1040,7 +1040,7 @@ REGISTER_OP("Dilation2D") in_cols, filter_cols_eff, stride_cols, padding, &output_cols, &padding_before, &padding_after)); - const Shape* output_shape = c->MakeShape( + ShapeHandle output_shape = c->MakeShape( {batch_size_dim, output_rows, output_cols, output_depth_dim}); c->set_output(0, output_shape); return Status::OK(); @@ -1305,11 +1305,11 @@ REGISTER_OP("SoftmaxCrossEntropyWithLogits") .Output("backprop: T") .Attr("T: {half, float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &input)); TF_RETURN_IF_ERROR(c->Merge(input, c->input(1), &input)); - const Dimension* batch_size = c->Dim(input, 0); + DimensionHandle batch_size = c->Dim(input, 0); c->set_output(0, c->Vector(batch_size)); c->set_output(1, input); return Status::OK(); @@ -1335,12 +1335,12 @@ REGISTER_OP("SparseSoftmaxCrossEntropyWithLogits") .Attr("T: {half, float, double}") .Attr("Tlabels: {int32, int64} = DT_INT64") .SetShapeFn([](InferenceContext* c) { - const Shape* features; - const Shape* labels; + ShapeHandle features; + ShapeHandle labels; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &features)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &labels)); - const Dimension* batch_size; + DimensionHandle batch_size; TF_RETURN_IF_ERROR( c->Merge(c->Dim(features, 0), c->Dim(labels, 0), &batch_size)); TF_RETURN_IF_ERROR(c->ReplaceDim(features, 0, batch_size, &features)); @@ -1375,11 +1375,11 @@ REGISTER_OP("InTopK") .Attr("k: int") .Attr("T: {int32, int64} = DT_INT32") .SetShapeFn([](InferenceContext* c) { - const Shape* predictions; - const Shape* targets; + ShapeHandle predictions; + ShapeHandle targets; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &predictions)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &targets)); - const Dimension* batch_size; + DimensionHandle batch_size; TF_RETURN_IF_ERROR( c->Merge(c->Dim(predictions, 0), c->Dim(targets, 0), &batch_size)); c->set_output(0, c->Vector(batch_size)); @@ -1413,11 +1413,11 @@ precision: Computed Precision at `k` as a `bool Tensor`. namespace { Status TopKShapeFn(InferenceContext* c) { - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), 1, &input)); // Get the k value, either from input tensor or attribute. - const Dimension* k_dim; + DimensionHandle k_dim; if (c->num_inputs() >= 2) { TF_RETURN_IF_ERROR(c->MakeDimForScalarInput(1, &k_dim)); } else { @@ -1429,7 +1429,7 @@ Status TopKShapeFn(InferenceContext* c) { k_dim = c->MakeDim(k); } - const Dimension* last_dim = c->Dim(input, -1); + DimensionHandle last_dim = c->Dim(input, -1); if (c->ValueKnown(last_dim) && c->ValueKnown(k_dim) && c->Value(last_dim) < c->Value(k_dim)) { return errors::InvalidArgument("input must have last dimension >= k = ", @@ -1438,7 +1438,7 @@ Status TopKShapeFn(InferenceContext* c) { } // Replace last_dim with k_dim. - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->Subshape(input, 0, -1, &s)); TF_RETURN_IF_ERROR(c->Concatenate(s, c->Vector(k_dim), &s)); c->set_output(0, s); diff --git a/tensorflow/core/ops/ops.pbtxt b/tensorflow/core/ops/ops.pbtxt index c16dd66908ddff6a1c1d2995eade17f0d0531cb3..3495f6ea14f522881c8fd3fcb9089f859ed6fa7b 100644 --- a/tensorflow/core/ops/ops.pbtxt +++ b/tensorflow/core/ops/ops.pbtxt @@ -2724,6 +2724,37 @@ op { summary: "BatchToSpace for 4-D tensors of type T." description: "Rearranges (permutes) data from batch into blocks of spatial data, followed by\ncropping. This is the reverse transformation of SpaceToBatch. More specifically,\nthis op outputs a copy of the input tensor where values from the `batch`\ndimension are moved in spatial blocks to the `height` and `width` dimensions,\nfollowed by cropping along the `height` and `width` dimensions." } +op { + name: "Betainc" + input_arg { + name: "a" + type_attr: "T" + } + input_arg { + name: "b" + type_attr: "T" + } + input_arg { + name: "x" + type_attr: "T" + } + output_arg { + name: "z" + type_attr: "T" + } + attr { + name: "T" + type: "type" + allowed_values { + list { + type: DT_FLOAT + type: DT_DOUBLE + } + } + } + summary: "Compute the regularized incomplete beta integral \\\\(I_x(a, b)\\\\)." + description: "The regularized incomplete beta integral is defined as:\n\n```\nI_x(a, b) = \\frac{B(x; a, b)}{B(a, b)}\n```\nwhere\n\n```\nB(x; a, b) = \\int_0^x t^{a-1} (1 - t)^{b-1} dt\n```\n\nis the incomplete beta function and \\\\(B(a, b)\\\\) is the *complete*\nbeta function." +} op { name: "BiasAdd" input_arg { @@ -6490,6 +6521,14 @@ op { } description: "If non-empty, this table is shared under the given name across\nmultiple sessions." } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + description: "If true and shared_name is empty, the table is shared\nusing the node name." + } attr { name: "key_dtype" type: "type" @@ -8896,6 +8935,14 @@ op { } description: "If non-empty, this table is shared under the given name across\nmultiple sessions." } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + description: "If true and shared_name is empty, the table is shared\nusing the node name." + } attr { name: "key_dtype" type: "type" @@ -8934,6 +8981,13 @@ op { } description: "If non-empty, this table is shared under the given name across\nmultiple sessions." } + attr { + name: "use_node_name_sharing" + type: "bool" + default_value { + b: false + } + } attr { name: "key_dtype" type: "type" diff --git a/tensorflow/core/ops/parsing_ops.cc b/tensorflow/core/ops/parsing_ops.cc index 1b1af7d68add35e8fbfe377d4ae34c6860e8a1a3..0dc743ee3b9af2ee9e3dd708c69c3cde591ed0f3 100644 --- a/tensorflow/core/ops/parsing_ops.cc +++ b/tensorflow/core/ops/parsing_ops.cc @@ -20,9 +20,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("DecodeRaw") .Input("bytes: string") @@ -31,7 +31,7 @@ REGISTER_OP("DecodeRaw") .Attr("little_endian: bool = true") .SetShapeFn([](InferenceContext* c) { // Note: last dimension is data dependent. - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->Concatenate( c->input(0), c->Vector(InferenceContext::kUnknownDim), &out)); c->set_output(0, out); @@ -68,9 +68,9 @@ REGISTER_OP("ParseExample") ParseSingleExampleAttrs attrs; TF_RETURN_IF_ERROR(attrs.Init(c)); - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 1, &input)); - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); // names // Output sparse_indices, sparse_values, and sparse_shapes. @@ -89,7 +89,7 @@ REGISTER_OP("ParseExample") TensorShapeProto shape_proto; for (int i = 0; i < attrs.num_dense; ++i) { attrs.dense_shapes[i].AsProto(&shape_proto); - const Shape* dense; + ShapeHandle dense; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &dense)); TF_RETURN_IF_ERROR(c->Concatenate(input, dense, &dense)); c->set_output(output_idx++, dense); @@ -161,11 +161,11 @@ REGISTER_OP("ParseSingleSequenceExample") .Attr("feature_list_sparse_types: list({float,int64,string}) >= 0 = []") .Attr("feature_list_dense_shapes: list(shape) >= 0 = []") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; ParseSingleSequenceExampleAttrs attrs; TF_RETURN_IF_ERROR(attrs.Init(c)); - const Shape* input; + ShapeHandle input; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &input)); // feature_list_dense_missing_assumed_empty @@ -189,7 +189,7 @@ REGISTER_OP("ParseSingleSequenceExample") TensorShapeProto shape_proto; for (int i = 0; i < attrs.num_context_dense; ++i) { attrs.context_dense_shapes[i].AsProto(&shape_proto); - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &s)); c->set_output(output_idx++, s); } @@ -209,7 +209,7 @@ REGISTER_OP("ParseSingleSequenceExample") // Output feature_list_dense_shapes. for (int i = 0; i < attrs.num_feature_list_dense; ++i) { attrs.feature_list_dense_shapes[i].AsProto(&shape_proto); - const Shape* s; + ShapeHandle s; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &s)); TF_RETURN_IF_ERROR( c->Concatenate(c->Vector(InferenceContext::kUnknownDim), s, &s)); @@ -312,7 +312,7 @@ REGISTER_OP("DecodeCSV") .SetShapeFn([](InferenceContext* c) { // Validate the record_defaults inputs. for (int i = 1; i < c->num_inputs(); ++i) { - const Shape* v; + ShapeHandle v; TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 1, &v)); if (c->Value(c->Dim(v, 0)) > 1) { return errors::InvalidArgument( diff --git a/tensorflow/core/ops/random_ops.cc b/tensorflow/core/ops/random_ops.cc index 5d648a6a7ebb4e4279e9017e2cc81c579f3627de..776523f33fb56b6f8a7d3e277f2d8694dd5366ff 100644 --- a/tensorflow/core/ops/random_ops.cc +++ b/tensorflow/core/ops/random_ops.cc @@ -19,14 +19,14 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { Status RandomShape(InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &out)); c->set_output(0, out); return Status::OK(); @@ -217,9 +217,9 @@ REGISTER_OP("Multinomial") .Attr("seed2: int = 0") .Attr("T: realnumbertype") .SetShapeFn([](InferenceContext* c) { - const Shape* logits_shape; - const Shape* unused; - const Dimension* num_samples; + ShapeHandle logits_shape; + ShapeHandle unused; + DimensionHandle num_samples; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &logits_shape)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); TF_RETURN_IF_ERROR(c->MakeDimForScalarInput(1, &num_samples)); @@ -249,7 +249,7 @@ REGISTER_OP("RandomGamma") .Attr("S: {int32, int64}") .Attr("T: {half, float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(0, &out)); TF_RETURN_IF_ERROR(c->Concatenate(out, c->input(1), &out)); c->set_output(0, out); diff --git a/tensorflow/core/ops/sparse_ops.cc b/tensorflow/core/ops/sparse_ops.cc index 17d5983d76f5506b191011d8959cbdc9599eeea8..f4544062b77eed86db00816e84bee301dcf6c844 100644 --- a/tensorflow/core/ops/sparse_ops.cc +++ b/tensorflow/core/ops/sparse_ops.cc @@ -19,14 +19,14 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; namespace { Status SparseSparseMinOrMaxShapeFn(InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unused)); // a_indices TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); // a_values TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); // a_shape @@ -50,8 +50,8 @@ REGISTER_OP("SparseAddGrad") .Output("b_val_grad: T") .Attr("T: numbertype") .SetShapeFn([](InferenceContext* c) { - const Shape* a_indices; - const Shape* b_indices; + ShapeHandle a_indices; + ShapeHandle b_indices; TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &a_indices)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 2, &b_indices)); c->set_output(0, c->Vector(c->Dim(a_indices, 0))); @@ -92,7 +92,7 @@ REGISTER_OP("SparseAdd") .Attr("T: numbertype") .Attr("Treal: realnumbertype") .SetShapeFn([](InferenceContext* c) { - const Shape* a_shape; + ShapeHandle a_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &a_shape)); c->set_output( 0, c->Matrix(InferenceContext::kUnknownDim, c->Dim(a_shape, 0))); @@ -137,10 +137,10 @@ REGISTER_OP("SparseTensorDenseMatMul") .Attr("adjoint_a: bool = false") .Attr("adjoint_b: bool = false") .SetShapeFn([](InferenceContext* c) { - const Dimension* unused_dim; - const Shape* unused; - const Shape* b; - const Shape* a_shape; + DimensionHandle unused_dim; + ShapeHandle unused; + ShapeHandle b; + ShapeHandle a_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unused)); // a_indices TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); // a_values TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &a_shape)); @@ -152,7 +152,7 @@ REGISTER_OP("SparseTensorDenseMatMul") // TODO(zongheng): 1) incorporate adjoint_a. 2) When both attrs are // considered, check the inner dimensions match. - const Dimension* output_right = c->Dim(b, adjoint_b ? 0 : 1); + DimensionHandle output_right = c->Dim(b, adjoint_b ? 0 : 1); c->set_output(0, c->Matrix(InferenceContext::kUnknownDim, output_right)); return Status::OK(); }) @@ -186,7 +186,7 @@ REGISTER_OP("SerializeSparse") .Attr("T: type") .Output("serialized_sparse: string") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); @@ -208,7 +208,7 @@ REGISTER_OP("SerializeManySparse") .Attr("T: type") .Output("serialized_sparse: string") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); @@ -239,9 +239,9 @@ REGISTER_OP("DeserializeManySparse") .Output("sparse_shape: int64") .SetShapeFn([](InferenceContext* c) { // serialized sparse is [?,3] matrix. - const Shape* serialized_sparse; + ShapeHandle serialized_sparse; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &serialized_sparse)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR( c->WithValue(c->Dim(serialized_sparse, 1), 3, &unused)); @@ -311,7 +311,7 @@ REGISTER_OP("SparseToDense") .Output("dense: T") .Attr("Tindices: {int32, int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* out; + ShapeHandle out; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(1, &out)); c->set_output(0, out); return Status::OK(); @@ -363,23 +363,23 @@ REGISTER_OP("SparseConcat") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { // These accumulates the sum. - const Dimension* output_row_count = c->MakeDim(0ll); + DimensionHandle output_row_count = c->MakeDim(0ll); // These are only merged. - const Dimension* output_ind_cols = c->UnknownDim(); - const Shape* output_shape = c->UnknownShape(); + DimensionHandle output_ind_cols = c->UnknownDim(); + ShapeHandle output_shape = c->UnknownShape(); const int n = c->num_inputs() / 3; for (int i = 0; i < n; i++) { - const Shape* ind; + ShapeHandle ind; TF_RETURN_IF_ERROR(c->WithRank(c->input(i), 2, &ind)); - const Shape* val; + ShapeHandle val; TF_RETURN_IF_ERROR(c->WithRank(c->input(i + n), 1, &val)); - const Shape* shape; + ShapeHandle shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(i + 2 * n), 1, &shape)); // Add to output_ind_rows. - const Dimension* num_dim; + DimensionHandle num_dim; TF_RETURN_IF_ERROR(c->Merge(c->Dim(ind, 0), c->Dim(val, 0), &num_dim)); TF_RETURN_IF_ERROR( c->Add(output_row_count, num_dim, &output_row_count)); @@ -460,11 +460,11 @@ REGISTER_OP("SparseSplit") .Attr("num_split: int >= 1") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* input_shape = c->input(3); - const Shape* output_indices = + ShapeHandle input_shape = c->input(3); + ShapeHandle output_indices = c->Matrix(InferenceContext::kUnknownDim, c->NumElements(input_shape)); - const Shape* output_values = c->Vector(InferenceContext::kUnknownDim); - const Shape* output_shape = input_shape; + ShapeHandle output_values = c->Vector(InferenceContext::kUnknownDim); + ShapeHandle output_shape = input_shape; // Copy the outputs into the output ranges. int num_splits = c->num_outputs() / 3; @@ -520,9 +520,9 @@ REGISTER_OP("SparseReorder") .Output("output_values: T") .Attr("T: type") .SetShapeFn([](InferenceContext* c) { - const Shape* indices; - const Shape* values; - const Shape* unused; + ShapeHandle indices; + ShapeHandle values; + ShapeHandle unused; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &indices)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &values)); @@ -560,9 +560,9 @@ REGISTER_OP("SparseReshape") .Output("output_indices: int64") .Output("output_shape: int64") .SetShapeFn([](InferenceContext* c) { - const Shape* indices; - const Shape* unused; - const Shape* new_shape; + ShapeHandle indices; + ShapeHandle unused; + ShapeHandle new_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &indices)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &unused)); @@ -670,7 +670,7 @@ output: `R-K`-D. The reduced Tensor. .Output("output: T") \ .Attr("T: numbertype") \ .SetShapeFn([](InferenceContext* c) { \ - const Shape* input; \ + ShapeHandle input; \ TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 2, &input)); \ c->set_output(0, c->Vector(c->Dim(input, 0))); \ return Status::OK(); \ @@ -737,8 +737,8 @@ REGISTER_OP("SparseSoftmax") .Output("output: T") .Attr("T: {float, double}") .SetShapeFn([](InferenceContext* c) { - const Shape* unused; - const Shape* values; + ShapeHandle unused; + ShapeHandle values; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unused)); // sp_indices TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &values)); // sp_values TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &unused)); diff --git a/tensorflow/core/ops/state_ops.cc b/tensorflow/core/ops/state_ops.cc index 684e86a00dc3b0c721028b86ff8a892f5f1a27da..cc0c652107746f1037c6a63e69b09cb393919b98 100644 --- a/tensorflow/core/ops/state_ops.cc +++ b/tensorflow/core/ops/state_ops.cc @@ -19,7 +19,7 @@ limitations under the License. namespace tensorflow { using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("Variable") .Output("ref: Ref(dtype)") @@ -69,7 +69,7 @@ REGISTER_OP("TemporaryVariable") .SetShapeFn([](InferenceContext* c) { TensorShapeProto shape_proto; TF_RETURN_IF_ERROR(c->GetAttr("shape", &shape_proto)); - const Shape* output; + ShapeHandle output; TF_RETURN_IF_ERROR(c->MakeShapeFromShapeProto(shape_proto, &output)); c->set_output(0, output); return Status::OK(); @@ -201,12 +201,12 @@ output_ref:= Same as "ref". Returned as a convenience for operations that want namespace { Status ScatterUpdateShape(InferenceContext* c) { - const Shape* var_shape = c->input(0); - const Shape* indices_shape = c->input(1); + ShapeHandle var_shape = c->input(0); + ShapeHandle indices_shape = c->input(1); - const Shape* unused_updates_shape; - const Shape* concat; - const Shape* var_subshape; + ShapeHandle unused_updates_shape; + ShapeHandle concat; + ShapeHandle var_subshape; TF_RETURN_IF_ERROR(c->Subshape(var_shape, 1, &var_subshape)); TF_RETURN_IF_ERROR(c->Concatenate(indices_shape, var_subshape, &concat)); TF_RETURN_IF_ERROR(c->Merge(c->input(2), concat, &unused_updates_shape)); @@ -354,7 +354,7 @@ REGISTER_OP("CountUpTo") .Attr("limit: int") .Attr("T: {int32, int64}") .SetShapeFn([](InferenceContext* c) { - const Shape* output; + ShapeHandle output; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 0, &output)); c->set_output(0, output); return Status::OK(); diff --git a/tensorflow/core/ops/string_ops.cc b/tensorflow/core/ops/string_ops.cc index 3b9f96e4964c047d7b9f294d98a48a7242a88335..dd4cb12f5d0c36d44d330e390962ca17385d56e0 100644 --- a/tensorflow/core/ops/string_ops.cc +++ b/tensorflow/core/ops/string_ops.cc @@ -19,9 +19,9 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; REGISTER_OP("StringToHashBucketFast") .Input("input: string") @@ -180,7 +180,7 @@ REGISTER_OP("StringJoin") // Merge the non-scalars to find the output shape. // Don't merge inputs with unknown rank, as they can actually be scalars // or the output shape. - const Shape* out = c->UnknownShape(); + ShapeHandle out = c->UnknownShape(); for (int i = 0; i < c->num_inputs(); ++i) { if (c->RankKnown(c->input(i)) && c->Rank(c->input(i)) != 0) { TF_RETURN_IF_ERROR(c->Merge(out, c->input(i), &out)); @@ -206,7 +206,7 @@ REGISTER_OP("StringSplit") .Output("values: string") .Output("shape: int64") .SetShapeFn([](InferenceContext* c) { - const Shape* unsed_shape; + ShapeHandle unsed_shape; TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 2, &unsed_shape)); TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unsed_shape)); diff --git a/tensorflow/core/ops/training_ops.cc b/tensorflow/core/ops/training_ops.cc index 04f30586517e3bfef18ac7649ddff8d649e03f06..ab82617a1365a134dd842f021e5c830ed4c82cca 100644 --- a/tensorflow/core/ops/training_ops.cc +++ b/tensorflow/core/ops/training_ops.cc @@ -18,28 +18,28 @@ limitations under the License. namespace tensorflow { -using shape_inference::Dimension; +using shape_inference::DimensionHandle; using shape_inference::InferenceContext; -using shape_inference::Shape; +using shape_inference::ShapeHandle; // Handle the gradient and, if , indices inputs. // is an input+output parameter, containing the current known input shape to // the gradient. static Status HandleGradAndIndicesInputs(InferenceContext* c, bool sparse, - int grad_idx, const Shape** s) { - const Shape* grad = c->input(grad_idx); + int grad_idx, ShapeHandle* s) { + ShapeHandle grad = c->input(grad_idx); if (!sparse) { TF_RETURN_IF_ERROR(c->Merge(*s, grad, s)); return Status::OK(); } // Indices is a vector where indices.dim[0].rank == grad[0].rank. - const Shape* indices; + ShapeHandle indices; TF_RETURN_IF_ERROR(c->WithRank(c->input(grad_idx + 1), 1, &indices)); - const Dimension* unused; + DimensionHandle unused; TF_RETURN_IF_ERROR(c->Merge(c->Dim(indices, 0), c->Dim(grad, 0), &unused)); // Trailing part of grad matches *s. - const Shape* grad_subshape; + ShapeHandle grad_subshape; TF_RETURN_IF_ERROR(c->Subshape(grad, 1, &grad_subshape)); TF_RETURN_IF_ERROR(c->Merge(*s, grad_subshape, s)); @@ -47,8 +47,8 @@ static Status HandleGradAndIndicesInputs(InferenceContext* c, bool sparse, } static Status ApplyGradientDescentShapeFn(InferenceContext* c) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); // alpha TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // delta c->set_output(0, s); @@ -76,8 +76,8 @@ use_locking: If `True`, the subtraction will be protected by a lock; static Status ApplyProximalGradientDescentShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 0, &unused)); // alpha TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); // l1 TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); // l2 @@ -146,8 +146,8 @@ use_locking: If True, the subtraction will be protected by a lock; otherwise the behavior is undefined, but may exhibit less contention. )doc"); static Status ApplyAdadeltaShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // accum TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // accum update TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); // lr @@ -224,8 +224,8 @@ a lock; otherwise the behavior is undefined, but may exhibit less contention. )doc"); static Status ApplyAdagradShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // accum TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); // lr TF_RETURN_IF_ERROR( @@ -261,8 +261,8 @@ use_locking: If `True`, updating of the var and accum tensors will be protected contention. )doc"); static Status ApplyProximalAdagradShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // accum TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); // lr TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); // l1 @@ -335,8 +335,8 @@ use_locking: If `True`, updating of the var and accum tensors will be protected )doc"); static Status ApplyAdagradDAShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // grad_accumulator TF_RETURN_IF_ERROR( c->Merge(s, c->input(2), &s)); // gradient_squared_accumulator @@ -453,8 +453,8 @@ a lock; otherwise the behavior is undefined, but may exhibit less contention. )doc"); static Status ApplyFtrlShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // accum TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // linear TF_RETURN_IF_ERROR( @@ -549,8 +549,8 @@ use_locking: If `True`, updating of the var and accum tensors will be protected )doc"); static Status ApplyMomentumShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // accum TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 0, &unused)); // lr TF_RETURN_IF_ERROR( @@ -635,8 +635,8 @@ var - lr * momentum * accum. )doc"); static Status ApplyAdamShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // m TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // v TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); // beta1_power @@ -693,8 +693,8 @@ use_locking: If `True`, updating of the var, m, and v tensors will be protected )doc"); static Status ApplyRMSPropShapeFn(InferenceContext* c, bool sparse) { - const Shape* unused; - const Shape* s = c->input(0); // var + ShapeHandle unused; + ShapeHandle s = c->input(0); // var TF_RETURN_IF_ERROR(c->Merge(s, c->input(1), &s)); // ms TF_RETURN_IF_ERROR(c->Merge(s, c->input(2), &s)); // mom TF_RETURN_IF_ERROR(c->WithRank(c->input(3), 0, &unused)); // lr diff --git a/tensorflow/core/platform/cloud/BUILD b/tensorflow/core/platform/cloud/BUILD index 7ee9f4e400c78da80af8c48a9c2a6f8859a52277..28e1c81e2c0d62f5871aa16eab7f9b6bce0e0252 100644 --- a/tensorflow/core/platform/cloud/BUILD +++ b/tensorflow/core/platform/cloud/BUILD @@ -38,6 +38,7 @@ cc_library( ":google_auth_provider", ":http_request", ":retrying_file_system", + ":time_util", "//tensorflow/core:framework_headers_lib", "//tensorflow/core:lib_internal", "@jsoncpp_git//:jsoncpp", @@ -122,6 +123,20 @@ cc_library( ], ) +cc_library( + name = "time_util", + srcs = [ + "time_util.cc", + ], + hdrs = [ + "time_util.h", + ], + deps = [ + "//tensorflow/core:framework_headers_lib", + "//tensorflow/core:lib_internal", + ], +) + tf_cc_test( name = "gcs_file_system_test", size = "small", @@ -191,3 +206,13 @@ tf_cc_test( "//tensorflow/core:test_main", ], ) + +tf_cc_test( + name = "time_util_test", + size = "small", + deps = [ + ":time_util", + "//tensorflow/core:test", + "//tensorflow/core:test_main", + ], +) diff --git a/tensorflow/core/platform/cloud/gcs_file_system.cc b/tensorflow/core/platform/cloud/gcs_file_system.cc index 910e144f353bea268d6d1201572f70f9631d537d..5abb954c7ba865026c1fb14b593b308b3bbcd24d 100644 --- a/tensorflow/core/platform/cloud/gcs_file_system.cc +++ b/tensorflow/core/platform/cloud/gcs_file_system.cc @@ -29,6 +29,7 @@ limitations under the License. #include "tensorflow/core/lib/strings/numbers.h" #include "tensorflow/core/lib/strings/str_util.h" #include "tensorflow/core/platform/cloud/google_auth_provider.h" +#include "tensorflow/core/platform/cloud/time_util.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/protobuf.h" #include "tensorflow/core/platform/regexp.h" @@ -106,13 +107,18 @@ class GcsRandomAccessFile : public RandomAccessFile { } // Update the buffer content based on the new requested range. - auto buffer_size = n + read_ahead_bytes_; - buffer_.reset(new char[buffer_size]); + const size_t desired_buffer_size = n + read_ahead_bytes_; + if (n > buffer_size_ || desired_buffer_size > 2 * buffer_size_) { + // Re-allocate only if buffer size increased significantly. + buffer_.reset(new char[desired_buffer_size]); + buffer_size_ = desired_buffer_size; + } + buffer_start_offset_ = offset; buffer_content_size_ = 0; StringPiece buffer_content; TF_RETURN_IF_ERROR( - ReadFromGCS(offset, buffer_size, &buffer_content, buffer_.get())); + ReadFromGCS(offset, buffer_size_, &buffer_content, buffer_.get())); buffer_content_size_ = buffer_content.size(); // Set the results. @@ -158,6 +164,7 @@ class GcsRandomAccessFile : public RandomAccessFile { // The buffer-related members need to be mutable, because they are modified // by the const Read() method. mutable std::unique_ptr buffer_; + mutable size_t buffer_size_ = 0; // The original file offset of the first byte in the buffer. mutable size_t buffer_start_offset_ = 0; mutable size_t buffer_content_size_ = 0; @@ -466,41 +473,9 @@ Status GcsFileSystem::GetChildren(const string& dirname, } Status GcsFileSystem::Stat(const string& fname, FileStatistics* stat) { - return errors::Unimplemented("Stat unimplemented"); -} - -Status GcsFileSystem::DeleteFile(const string& fname) { - string bucket, object; - TF_RETURN_IF_ERROR(ParseGcsPath(fname, &bucket, &object)); - - string auth_token; - TF_RETURN_IF_ERROR(AuthProvider::GetToken(auth_provider_.get(), &auth_token)); - - std::unique_ptr request(http_request_factory_->Create()); - TF_RETURN_IF_ERROR(request->Init()); - TF_RETURN_IF_ERROR(request->SetUri(strings::StrCat( - kGcsUriBase, "b/", bucket, "/o/", request->EscapeString(object)))); - TF_RETURN_IF_ERROR(request->AddAuthBearerHeader(auth_token)); - TF_RETURN_IF_ERROR(request->SetDeleteRequest()); - TF_RETURN_WITH_CONTEXT_IF_ERROR(request->Send(), " when deleting ", fname); - return Status::OK(); -} - -// Does nothing, because directories are not entities in GCS. -Status GcsFileSystem::CreateDir(const string& dirname) { return Status::OK(); } - -// Checks that the directory is empty (i.e no objects with this prefix exist). -// If it is, does nothing, because directories are not entities in GCS. -Status GcsFileSystem::DeleteDir(const string& dirname) { - std::vector children; - TF_RETURN_IF_ERROR(GetChildren(dirname, &children)); - if (!children.empty()) { - return errors::InvalidArgument("Cannot delete a non-empty directory."); + if (!stat) { + return errors::Internal("'stat' cannot be nullptr."); } - return Status::OK(); -} - -Status GcsFileSystem::GetFileSize(const string& fname, uint64* file_size) { string bucket, object_prefix; TF_RETURN_IF_ERROR(ParseGcsPath(fname, &bucket, &object_prefix)); @@ -512,9 +487,9 @@ Status GcsFileSystem::GetFileSize(const string& fname, uint64* file_size) { std::unique_ptr request(http_request_factory_->Create()); TF_RETURN_IF_ERROR(request->Init()); - TF_RETURN_IF_ERROR(request->SetUri( - strings::StrCat(kGcsUriBase, "b/", bucket, "/o/", - request->EscapeString(object_prefix), "?fields=size"))); + TF_RETURN_IF_ERROR(request->SetUri(strings::StrCat( + kGcsUriBase, "b/", bucket, "/o/", request->EscapeString(object_prefix), + "?fields=size%2Cupdated"))); TF_RETURN_IF_ERROR(request->AddAuthBearerHeader(auth_token)); TF_RETURN_IF_ERROR( request->SetResultBuffer(scratch.get(), kBufferSize, &response_piece)); @@ -528,19 +503,77 @@ Status GcsFileSystem::GetFileSize(const string& fname, uint64* file_size) { if (!reader.parse(response_stream.str(), root)) { return errors::Internal("Couldn't parse JSON response from GCS."); } + + // Parse file size. const auto size = root.get("size", Json::Value::null); if (size == Json::Value::null) { return errors::Internal("'size' was expected in the JSON response."); } if (size.isNumeric()) { - *file_size = size.asUInt64(); + stat->length = size.asUInt64(); } else if (size.isString()) { - if (!strings::safe_strtou64(size.asString().c_str(), file_size)) { + if (!strings::safe_strto64(size.asString().c_str(), &(stat->length))) { return errors::Internal("'size' couldn't be parsed as a nubmer."); } } else { return errors::Internal("'size' is not a number in the JSON response."); } + + // Parse file modification time. + const auto updated = root.get("updated", Json::Value::null); + if (updated == Json::Value::null) { + return errors::Internal("'updated' was expected in the JSON response."); + } + if (!updated.isString()) { + return errors::Internal( + "'updated' is expected to be a string in the JSON response."); + } + TF_RETURN_IF_ERROR(ParseRfc3339Time(updated.asString(), &(stat->mtime_nsec))); + + // Converting GCS ACL into mode_t is hard, return -rw------- instead. + stat->mode = 0600; + + return Status::OK(); +} + +Status GcsFileSystem::DeleteFile(const string& fname) { + string bucket, object; + TF_RETURN_IF_ERROR(ParseGcsPath(fname, &bucket, &object)); + + string auth_token; + TF_RETURN_IF_ERROR(AuthProvider::GetToken(auth_provider_.get(), &auth_token)); + + std::unique_ptr request(http_request_factory_->Create()); + TF_RETURN_IF_ERROR(request->Init()); + TF_RETURN_IF_ERROR(request->SetUri(strings::StrCat( + kGcsUriBase, "b/", bucket, "/o/", request->EscapeString(object)))); + TF_RETURN_IF_ERROR(request->AddAuthBearerHeader(auth_token)); + TF_RETURN_IF_ERROR(request->SetDeleteRequest()); + TF_RETURN_WITH_CONTEXT_IF_ERROR(request->Send(), " when deleting ", fname); + return Status::OK(); +} + +// Does nothing, because directories are not entities in GCS. +Status GcsFileSystem::CreateDir(const string& dirname) { return Status::OK(); } + +// Checks that the directory is empty (i.e no objects with this prefix exist). +// If it is, does nothing, because directories are not entities in GCS. +Status GcsFileSystem::DeleteDir(const string& dirname) { + std::vector children; + TF_RETURN_IF_ERROR(GetChildren(dirname, &children)); + if (!children.empty()) { + return errors::InvalidArgument("Cannot delete a non-empty directory."); + } + return Status::OK(); +} + +Status GcsFileSystem::GetFileSize(const string& fname, uint64* file_size) { + if (!file_size) { + return errors::Internal("'file_size' cannot be nullptr."); + } + FileStatistics stat; + TF_RETURN_IF_ERROR(Stat(fname, &stat)); + *file_size = stat.length; return Status::OK(); } diff --git a/tensorflow/core/platform/cloud/gcs_file_system_test.cc b/tensorflow/core/platform/cloud/gcs_file_system_test.cc index b43a5778ee64ba9fef82ce3975b681c3b3787cc6..70dd5744f85b065b343d8e4402345c114a4ecfb7 100644 --- a/tensorflow/core/platform/cloud/gcs_file_system_test.cc +++ b/tensorflow/core/platform/cloud/gcs_file_system_test.cc @@ -83,6 +83,43 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_NoReadAhead) { EXPECT_EQ("6789", result); } +TEST(GcsFileSystemTest, NewRandomAccessFile_NoReadAhead_differentN) { + std::vector requests( + {new FakeHttpRequest( + "Uri: https://bucket.storage.googleapis.com/random_access.txt\n" + "Auth Token: fake_token\n" + "Range: 0-2\n", + "012"), + new FakeHttpRequest( + "Uri: https://bucket.storage.googleapis.com/random_access.txt\n" + "Auth Token: fake_token\n" + "Range: 3-12\n", + "3456789")}); + GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* read ahead bytes */); + + std::unique_ptr file; + TF_EXPECT_OK(fs.NewRandomAccessFile("gs://bucket/random_access.txt", &file)); + + char small_scratch[3]; + StringPiece result; + + // Read the first chunk. + TF_EXPECT_OK(file->Read(0, sizeof(small_scratch), &result, small_scratch)); + EXPECT_EQ("012", result); + + // Read the second chunk that is larger. Requires allocation of new buffer. + char large_scratch[10]; + + EXPECT_EQ(errors::Code::OUT_OF_RANGE, + file->Read(sizeof(small_scratch), sizeof(large_scratch), &result, + large_scratch) + .code()); + EXPECT_EQ("3456789", result); +} + TEST(GcsFileSystemTest, NewRandomAccessFile_WithReadAhead) { std::vector requests( {new FakeHttpRequest( @@ -93,7 +130,7 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithReadAhead) { new FakeHttpRequest( "Uri: https://bucket.storage.googleapis.com/random_access.txt\n" "Auth Token: fake_token\n" - "Range: 6-15\n", + "Range: 6-14\n", "6789abcd"), new FakeHttpRequest( "Uri: https://bucket.storage.googleapis.com/random_access.txt\n" @@ -125,18 +162,18 @@ TEST(GcsFileSystemTest, NewRandomAccessFile_WithReadAhead) { EXPECT_EQ("4567", result); // The chunk is only partially cached -- the request will be made to - // reload the cache. 5 + 5 = 10 bytes will be requested. + // reload the cache. 9 bytes will be requested (same as initial buffer size). TF_EXPECT_OK(file->Read(6, 5, &result, scratch)); EXPECT_EQ("6789a", result); // The range can only be partially satisfied. An attempt to fill the cache - // with 10 + 5 = 15 bytes will be made. + // with 10 + 5 = 15 bytes will be made (buffer is resized for this request). EXPECT_EQ(errors::Code::OUT_OF_RANGE, file->Read(6, 10, &result, scratch).code()); EXPECT_EQ("6789abcd", result); // The range cannot be satisfied. An attempt to fill the cache - // with 10 + 5 = 15 bytes will be made. + // with 15 bytes will be made (same as current buffer size). EXPECT_EQ(errors::Code::OUT_OF_RANGE, file->Read(15, 10, &result, scratch).code()); EXPECT_TRUE(result.empty()); @@ -192,9 +229,10 @@ TEST(GcsFileSystemTest, NewReadOnlyMemoryRegionFromFile) { std::vector requests( {new FakeHttpRequest( "Uri: https://www.googleapis.com/storage/v1/b/bucket/o/" - "path%2Frandom_access.txt?fields=size\n" + "path%2Frandom_access.txt?fields=size%2Cupdated\n" "Auth Token: fake_token\n", - strings::StrCat("{\"size\": \"", content.size(), "\"}")), + strings::StrCat("{\"size\": \"", content.size(), + "\", \"updated\": \"2016-04-29T23:15:24.896Z\"}")), new FakeHttpRequest( strings::StrCat("Uri: https://bucket.storage.googleapis.com/" "path%2Frandom_access.txt\n" @@ -398,9 +436,10 @@ TEST(GcsFileSystemTest, DeleteDir_NonEmpty) { TEST(GcsFileSystemTest, GetFileSize) { std::vector requests({new FakeHttpRequest( "Uri: https://www.googleapis.com/storage/v1/b/bucket/o/" - "file.txt?fields=size\n" + "file.txt?fields=size%2Cupdated\n" "Auth Token: fake_token\n", - strings::StrCat("{\"size\": \"1010\"}"))}); + strings::StrCat("{\"size\": \"1010\"," + "\"updated\": \"2016-04-29T23:15:24.896Z\"}"))}); GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), std::unique_ptr( new FakeHttpRequestFactory(&requests)), @@ -434,5 +473,24 @@ TEST(GcsFileSystemTest, RenameFile) { fs.RenameFile("gs://bucket/path/src.txt", "gs://bucket/path/dst.txt")); } +TEST(GcsFileSystemTest, Stat) { + std::vector requests({new FakeHttpRequest( + "Uri: https://www.googleapis.com/storage/v1/b/bucket/o/" + "file.txt?fields=size%2Cupdated\n" + "Auth Token: fake_token\n", + strings::StrCat("{\"size\": \"1010\"," + "\"updated\": \"2016-04-29T23:15:24.896Z\"}"))}); + GcsFileSystem fs(std::unique_ptr(new FakeAuthProvider), + std::unique_ptr( + new FakeHttpRequestFactory(&requests)), + 0 /* read ahead bytes */); + + FileStatistics stat; + TF_EXPECT_OK(fs.Stat("gs://bucket/file.txt", &stat)); + EXPECT_EQ(1010, stat.length); + EXPECT_EQ(1461971724896, stat.mtime_nsec / 1000 / 1000); + EXPECT_EQ(0600, stat.mode); +} + } // namespace } // namespace tensorflow diff --git a/tensorflow/core/platform/cloud/time_util.cc b/tensorflow/core/platform/cloud/time_util.cc new file mode 100644 index 0000000000000000000000000000000000000000..633733a21c28ecee0ed24ff4ca0322f64a3b50c8 --- /dev/null +++ b/tensorflow/core/platform/cloud/time_util.cc @@ -0,0 +1,52 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/platform/cloud/time_util.h" +#include +#include +#include +#include +#include "tensorflow/core/lib/core/errors.h" + +namespace tensorflow { + +namespace { +constexpr int64 kNanosecondsPerSecond = 1000 * 1000 * 1000; + +} // namespace + +// Only implements one special case of RFC 3339 which is returned by +// GCS API, e.g 2016-04-29T23:15:24.896Z. +Status ParseRfc3339Time(const string& time, int64* mtime_nsec) { + tm parsed{0}; + float seconds; + if (sscanf(time.c_str(), "%4d-%2d-%2dT%2d:%2d:%fZ", &(parsed.tm_year), + &(parsed.tm_mon), &(parsed.tm_mday), &(parsed.tm_hour), + &(parsed.tm_min), &seconds) != 6) { + return errors::Internal( + strings::StrCat("Unrecognized RFC 3339 time format: ", time)); + } + const int int_seconds = floor(seconds); + parsed.tm_year -= 1900; // tm_year expects years since 1900. + parsed.tm_mon -= 1; // month is zero-based. + parsed.tm_sec = int_seconds; + + *mtime_nsec = timegm(&parsed) * kNanosecondsPerSecond + + floor((seconds - int_seconds) * kNanosecondsPerSecond); + + return Status::OK(); +} + +} // namespace tensorflow diff --git a/tensorflow/core/platform/cloud/time_util.h b/tensorflow/core/platform/cloud/time_util.h new file mode 100644 index 0000000000000000000000000000000000000000..b1bb7f111970b51dcd2dcba47a3c20f8388bca42 --- /dev/null +++ b/tensorflow/core/platform/cloud/time_util.h @@ -0,0 +1,29 @@ +/* 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. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ + +#include "tensorflow/core/lib/core/status.h" + +namespace tensorflow { + +/// Parses the timestamp in RFC 3339 format and returns it +/// as nanoseconds since epoch. +Status ParseRfc3339Time(const string& time, int64* mtime_nsec); + +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_PLATFORM_CLOUD_TIME_UTIL_H_ diff --git a/tensorflow/core/platform/cloud/time_util_test.cc b/tensorflow/core/platform/cloud/time_util_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..3fd8fcdab010b503400e20b20d39dfe7711c0f50 --- /dev/null +++ b/tensorflow/core/platform/cloud/time_util_test.cc @@ -0,0 +1,35 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/platform/cloud/time_util.h" +#include "tensorflow/core/lib/core/status_test_util.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { + +TEST(TimeUtil, ParseRfc3339Time) { + int64 mtime_nsec; + TF_EXPECT_OK(ParseRfc3339Time("2016-04-29T23:15:24.896Z", &mtime_nsec)); + // Compare milliseconds instead of nanoseconds. + EXPECT_EQ(1461971724896, mtime_nsec / 1000 / 1000); +} + +TEST(TimeUtil, ParseRfc3339Time_ParseError) { + int64 mtime_nsec; + EXPECT_EQ("Unrecognized RFC 3339 time format: 2016-04-29", + ParseRfc3339Time("2016-04-29", &mtime_nsec).error_message()); +} + +} // namespace tensorflow diff --git a/tensorflow/core/platform/cpu_info.h b/tensorflow/core/platform/cpu_info.h new file mode 100644 index 0000000000000000000000000000000000000000..706dc4dcc5152abd1b70d3816d2508c5c5d2577c --- /dev/null +++ b/tensorflow/core/platform/cpu_info.h @@ -0,0 +1,34 @@ +/* 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. +==============================================================================*/ + +#ifndef TENSORFLOW_PLATFORM_CPU_INFO_H_ +#define TENSORFLOW_PLATFORM_CPU_INFO_H_ + +namespace tensorflow { +namespace port { + +// TODO(jeff,sanjay): Make portable +static const bool kLittleEndian = true; + +// Returns an estimate of the number of schedulable CPUs for this +// process. Usually, it's constant throughout the lifetime of a +// process, but it might change if the underlying cluster management +// software can change it dynamically. +int NumSchedulableCPUs(); + +} // namespace port +} // namespace tensorflow + +#endif // TENSORFLOW_PLATFORM_CPU_INFO_H_ diff --git a/tensorflow/core/platform/default/notification.h b/tensorflow/core/platform/default/notification.h new file mode 100644 index 0000000000000000000000000000000000000000..13d2317e389de1a81679a333703d4d341ffdd878 --- /dev/null +++ b/tensorflow/core/platform/default/notification.h @@ -0,0 +1,73 @@ +/* Copyright 2015 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_CORE_PLATFORM_DEFAULT_NOTIFICATION_H_ +#define TENSORFLOW_CORE_PLATFORM_DEFAULT_NOTIFICATION_H_ + +#include +#include // NOLINT +#include // NOLINT + +#include "tensorflow/core/platform/mutex.h" +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { + +class Notification { + public: + Notification() : notified_(false) {} + ~Notification() {} + + void Notify() { + mutex_lock l(mu_); + assert(!notified_); + notified_ = true; + cv_.notify_all(); + } + + bool HasBeenNotified() { + mutex_lock l(mu_); + return notified_; + } + + void WaitForNotification() { + mutex_lock l(mu_); + while (!notified_) { + cv_.wait(l); + } + } + + private: + friend bool WaitForNotificationWithTimeout(Notification* n, + int64 timeout_in_ms); + bool WaitForNotificationWithTimeout(int64 timeout_in_ms) { + mutex_lock l(mu_); + return cv_.wait_for(l, std::chrono::milliseconds(timeout_in_ms), + [this]() { return notified_; }); + } + + mutex mu_; + condition_variable cv_; + bool notified_; +}; + +inline bool WaitForNotificationWithTimeout(Notification* n, + int64 timeout_in_ms) { + return n->WaitForNotificationWithTimeout(timeout_in_ms); +} + +} // namespace tensorflow + +#endif // TENSORFLOW_CORE_PLATFORM_DEFAULT_NOTIFICATION_H_ diff --git a/tensorflow/core/platform/hexagon/gemm_wrapper.h b/tensorflow/core/platform/hexagon/gemm_wrapper.h index 30890d4655920abb9b23c8dfadf841eb6a342f1b..b1c22bafdb4cf6ffb68db05d29aaf011ce61c7ed 100644 --- a/tensorflow/core/platform/hexagon/gemm_wrapper.h +++ b/tensorflow/core/platform/hexagon/gemm_wrapper.h @@ -23,9 +23,14 @@ limitations under the License. #ifdef __cplusplus extern "C" { #endif // __cplusplus -// Returns the version of loaded hexagon shared library. Assert if the version -// matches the expected version. -int hexagon_gemm_wrapper_GetVersion(); +// Returns the version of loaded hexagon wrapper shared library. +// You should assert that the version matches the expected version before +// calling APIs defined in this header. +int hexagon_gemm_wrapper_GetWrapperVersion(); +// Returns the version of hexagon binary. +// You should assert that the version matches the expected version before +// calling APIs defined in this header. +int hexagon_gemm_wrapper_GetHexagonBinaryVersion(); // TODO(satok): Support gemm APIs via RPC #ifdef __cplusplus } diff --git a/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.cc b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.cc new file mode 100644 index 0000000000000000000000000000000000000000..d94d9411f1875558f1cd91f382de56a9a783d802 --- /dev/null +++ b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.cc @@ -0,0 +1,86 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/core/platform/hexagon/profile_utils/cpu_utils.h" + +#include "tensorflow/core/platform/logging.h" + +namespace tensorflow { +namespace profile_utils { + +namespace { + +const class StaticVariableInitializer { + public: + StaticVariableInitializer() { + CpuUtils::GetCpuFrequency(); + CpuUtils::GetClockPerMicroSec(); + CpuUtils::GetMicroSecPerClock(); + } +} STATIC_VARIABLE_INITIALIZER; + +} // anonymous namespace for initializer + +/* static */ constexpr int64 CpuUtils::INVALID_FREQUENCY; + +/* static */ int64 CpuUtils::GetCpuFrequency() { + static const int64 cpu_frequency = GetCpuFrequencyImpl(); + return cpu_frequency; +} + +/* static */ int CpuUtils::GetClockPerMicroSec() { + static const int clock_per_micro_sec = + static_cast(GetCpuFrequency() / (1000LL * 1000LL)); + return clock_per_micro_sec; +} + +/* static */ double CpuUtils::GetMicroSecPerClock() { + static const double micro_sec_per_clock = + (1000.0 * 1000.0) / static_cast(GetCpuFrequency()); + return micro_sec_per_clock; +} + +/* static */ int64 CpuUtils::GetCpuFrequencyImpl() { +#if defined(__linux__) + double bogomips; + FILE* fp = popen("grep '^bogomips' /proc/cpuinfo | head -1", "r"); + const int retval_of_bogomips = fscanf(fp, "bogomips : %lf", &bogomips); + pclose(fp); + const double freq_ghz = bogomips / 1000.0 / 2.0; + if (retval_of_bogomips != 1 || freq_ghz < 0.01) { + LOG(WARNING) << "Failed to get CPU frequency: " << freq_ghz << " Hz"; + return INVALID_FREQUENCY; + } + return static_cast(freq_ghz * 1000.0 * 1000.0 * 1000.0); +#elif defined(__APPLE__) + int64 freq_hz; + FILE* fp = + popen("sysctl hw | grep hw.cpufrequency_max: | cut -d' ' -f 2", "r"); + fscanf(fp, "%lld", &freq_hz); + pclose(fp); + if (freq_hz < 1e6) { + LOG(WARNING) << "Failed to get CPU frequency: " << freq_hz << " Hz"; + return INVALID_FREQUENCY; + } + return freq_hz; +#else + // TODO(satok): Support other OS if needed + // Return INVALID_FREQUENCY on unsupported OS + return INVALID_FREQUENCY; +#endif +} + +} // namespace profile_utils +} // namespace tensorflow diff --git a/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.h b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..8e08f17fc631aad573f463cf92522b35052dc64a --- /dev/null +++ b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils.h @@ -0,0 +1,112 @@ +/* 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. +==============================================================================*/ +// This class is designed to get accurate profile for programs. + +#ifndef TENSORFLOW_PLATFORM_HEXAGON_PROFILEUTILS_CPU_UTILS_H__ +#define TENSORFLOW_PLATFORM_HEXAGON_PROFILEUTILS_CPU_UTILS_H__ + +#include "tensorflow/core/platform/macros.h" +#include "tensorflow/core/platform/types.h" + +#if defined(ARMV6) || defined(__ARM_ARCH_7A__) +#include +#endif + +namespace tensorflow { + +namespace profile_utils { + +class CpuUtils { + public: + // Constant for invalid frequency. + // This value is returned when the furequency is not obtained somehow. + static constexpr int64 INVALID_FREQUENCY = -1; + static constexpr uint64 DUMMY_CYCLE_CLOCK = 1; + + // Return cpu count obtained by rdtsc. This function is designed to + // minimize the overhead to get clock and maximize the accuracy of + // time for profile. + // This returns unsigned int because there is no guarantee that rdtsc + // is less than 2 ^ 61. + static inline uint64 GetCurrentCycleClock() { +// ---------------------------------------------------------------- +#if defined(__x86_64__) || defined(__amd64__) + uint64_t high, low; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + return (high << 32) | low; +// ---------------------------------------------------------------- +#elif defined(__aarch64__) + // System timer of ARMv8 runs at a different frequency than the CPU's. + // The frequency is fixed, typically in the range 1-50MHz. It can because + // read at CNTFRQ special register. We assume the OS has set up + // the virtual timer properly. + uint64_t virtual_timer_value; + asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); + return virtual_timer_value; +// ---------------------------------------------------------------- +// V6 is the earliest arm that has a standard cyclecount +#elif defined(ARMV6) || defined(__ARM_ARCH_7A__) + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cyclecount + return static_cast(pmccntr) * 64; // Should optimize to << 64 + } + } + // Returning dummy clock when can't access to the counter + return DUMMY_CYCLE_CLOCK; +#else + // TODO(satok): Support generic way to emulate clock count. + // TODO(satok): Support other architectures if wanted. + // Returning dummy clock when can't access to the counter + return DUMMY_CYCLE_CLOCK; +#endif + } + + // Return cpu frequency. As this method caches the cpu frequency internally, + // there is no overhead except function call to call this method. + static int64 GetCpuFrequency(); + + // Return cached cpu count per each micro second. + // As this method caches the cpu frequency internally, + // there is no overhead except function call to call this method. + static int GetClockPerMicroSec(); + + // Return micro secound per each clock + // As this method caches the cpu frequency internally, + // there is no overhead except function call to call this method. + static double GetMicroSecPerClock(); + + private: + // Return cpu frequency. + // CAVEAT: as this method calls system call and parse the mssage, + // this call may be slow. This is why this class caches the value by + // StaticVariableInitializer. + static int64 GetCpuFrequencyImpl(); + + TF_DISALLOW_COPY_AND_ASSIGN(CpuUtils); +}; + +} // namespace profile_utils + +} // namespace tensorflow + +#endif // TENSORFLOW_PLATFORM_HEXAGON_PROFILEUTILS_CPU_UTILS_H__ diff --git a/tensorflow/core/platform/hexagon/profile_utils/cpu_utils_test.cc b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..0db1903695be15c93d968e3c0d29b9ef3b83ab02 --- /dev/null +++ b/tensorflow/core/platform/hexagon/profile_utils/cpu_utils_test.cc @@ -0,0 +1,71 @@ +/* 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. +==============================================================================*/ +// This class is designed to get accurate profiles for programs + +#include "tensorflow/core/platform/hexagon/profile_utils/cpu_utils.h" +#include "tensorflow/core/platform/logging.h" +#include "tensorflow/core/platform/test.h" + +namespace tensorflow { +namespace profile_utils { + +static constexpr bool DBG = false; + +TEST(CpuUtils, CheckGetCurrentCycleClock) { + static constexpr int LOOP_COUNT = 10; + const uint64 start_clock_count = CpuUtils::GetCurrentCycleClock(); + CHECK_GT(start_clock_count, 0); + uint64 prev_clock_count = start_clock_count; + for (int i = 0; i < LOOP_COUNT; ++i) { + const uint64 clock_count = CpuUtils::GetCurrentCycleClock(); + CHECK_GE(clock_count, prev_clock_count); + prev_clock_count = clock_count; + } + const uint64 end_clock_count = CpuUtils::GetCurrentCycleClock(); + if (DBG) { + LOG(INFO) << "start clock = " << start_clock_count; + LOG(INFO) << "end clock = " << end_clock_count; + LOG(INFO) << "average clock = " + << ((end_clock_count - start_clock_count) / LOOP_COUNT); + } +} + +TEST(CpuUtils, CheckCpuFrequency) { + const int64 cpu_frequency = CpuUtils::GetCpuFrequency(); + CHECK_GT(cpu_frequency, 0); + CHECK_NE(cpu_frequency, CpuUtils::INVALID_FREQUENCY); + if (DBG) { + LOG(INFO) << "Cpu frequency = " << cpu_frequency; + } +} + +TEST(CpuUtils, CheckClockPerMicroSec) { + const int clock_per_micro_sec = CpuUtils::GetClockPerMicroSec(); + CHECK_GT(clock_per_micro_sec, 0); + if (DBG) { + LOG(INFO) << "Clock per micro sec = " << clock_per_micro_sec; + } +} + +TEST(CpuUtils, CheckMicroSecPerClock) { + const double micro_sec_per_clock = CpuUtils::GetMicroSecPerClock(); + CHECK_GT(micro_sec_per_clock, 0.0); + if (DBG) { + LOG(INFO) << "Micro sec per clock = " << micro_sec_per_clock; + } +} + +} // namespace profile_utils +} // namespace tensorflow diff --git a/tensorflow/core/platform/host_info.h b/tensorflow/core/platform/host_info.h index df51afb63f90fb034361ac8db9e0c5c44ce74cb2..6124c959233775f66242ad1fbd572defc9ea75f6 100644 --- a/tensorflow/core/platform/host_info.h +++ b/tensorflow/core/platform/host_info.h @@ -21,26 +21,9 @@ limitations under the License. namespace tensorflow { namespace port { -// TODO(jeff,sanjay): Make portable -static const bool kLittleEndian = true; - -// TODO(jeff,sanjay): Find appropriate places for all the code below. -// Possible places for any particular item below: -// (a) Here, so it gets reimplemented on every platform -// (b) Env -// (c) config.h (auto-generated by autotools?) -// (d) macros.h -// ... - // Return the hostname of the machine on which this process is running string Hostname(); -// Returns an estimate of the number of schedulable CPUs for this -// process. Usually, it's constant throughout the lifetime of a -// process, but it might change if the underlying cluster management -// software can change it dynamically. -int NumSchedulableCPUs(); - } // namespace port } // namespace tensorflow diff --git a/tensorflow/core/platform/notification.h b/tensorflow/core/platform/notification.h new file mode 100644 index 0000000000000000000000000000000000000000..dfea9e81687cedc429016265b9adf41ce6473d3f --- /dev/null +++ b/tensorflow/core/platform/notification.h @@ -0,0 +1,31 @@ +/* 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. +==============================================================================*/ + +#ifndef TENSORFLOW_CORE_PLATFORM_NOTIFICATION_H_ +#define TENSORFLOW_CORE_PLATFORM_NOTIFICATION_H_ + +#include "tensorflow/core/platform/platform.h" + +// Include appropriate platform-dependent implementations of Notification. +#if defined(PLATFORM_GOOGLE) +#include "tensorflow/core/platform/google/notification.h" +#elif defined(PLATFORM_POSIX) || defined(PLATFORM_POSIX_ANDROID) || \ + defined(PLATFORM_GOOGLE_ANDROID) +#include "tensorflow/core/platform/default/notification.h" +#else +#error Define the appropriate PLATFORM_ macro for this platform +#endif + +#endif // TENSORFLOW_CORE_PLATFORM_NOTIFICATION_H_ diff --git a/tensorflow/core/protobuf/config.proto b/tensorflow/core/protobuf/config.proto index cea68d43d4f9a1b52d2b9f4a2af76a57c6a375ac..f0ec90d7814fac3e844823fbd6e5d39ada407f35 100644 --- a/tensorflow/core/protobuf/config.proto +++ b/tensorflow/core/protobuf/config.proto @@ -35,6 +35,23 @@ message GPUOptions { // If true, the allocator does not pre-allocate the entire specified // GPU memory region, instead starting small and growing as needed. bool allow_growth = 4; + + // A comma-separated list of GPU ids that determines the 'visible' + // to 'virtual' mapping of GPU devices. For example, if TensorFlow + // can see 8 GPU devices in the process, and one wanted to map + // visible GPU devices 5 and 3 as "/gpu:0", and "/gpu:1", then one + // would specify this field as "5,3". This field is similar in + // spirit to the CUDA_VISIBLE_DEVICES environment variable, except + // it applies to the visible GPU devices in the process. + // + // NOTE: The GPU driver provides the process with the visible GPUs + // in an order which is not guaranteed to have any correlation to + // the *physical* GPU id in the machine. This field is used for + // remapping "visible" to "virtual", which means this operates only + // after the process starts. Users are required to use vendor + // specific mechanisms (e.g., CUDA_VISIBLE_DEVICES) to control the + // physical to visible device mapping prior to invoking TensorFlow. + string visible_device_list = 5; }; // Options passed to the graph optimizer diff --git a/tensorflow/core/public/version.h b/tensorflow/core/public/version.h index 3f6fa3826a090d20ad51f147d583a551bf722bae..a9b63ea1f4c66172a66885004b78e19e4c2c1a40 100644 --- a/tensorflow/core/public/version.h +++ b/tensorflow/core/public/version.h @@ -65,9 +65,10 @@ limitations under the License. // 9. Deprecate batch_norm_with_global_normalization (16feb2016). // 10. Deprecate conv3d_backprop_{filter,input} (10jun2016). // 11. Deprecate {batch}_self_adjoint_eig (3aug2016). +// 12. Graph consumers understand the node_def field of FunctionDef (22aug2016). #define TF_GRAPH_DEF_VERSION_MIN_PRODUCER 0 #define TF_GRAPH_DEF_VERSION_MIN_CONSUMER 0 -#define TF_GRAPH_DEF_VERSION 11 +#define TF_GRAPH_DEF_VERSION 12 // Checkpoint compatibility versions (the versions field in SavedSliceMeta). // diff --git a/tensorflow/core/util/example_proto_fast_parsing.cc b/tensorflow/core/util/example_proto_fast_parsing.cc new file mode 100644 index 0000000000000000000000000000000000000000..fee6b8885ffeee45d9166519eb81b16fc97dfeeb --- /dev/null +++ b/tensorflow/core/util/example_proto_fast_parsing.cc @@ -0,0 +1,761 @@ +/* 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. +==============================================================================*/ +#include "tensorflow/core/util/example_proto_fast_parsing.h" + +#include + +#include "tensorflow/core/example/example.pb.h" +#include "tensorflow/core/example/feature.pb_text.h" +#include "tensorflow/core/framework/numeric_op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/register_types.h" +#include "tensorflow/core/lib/core/blocking_counter.h" +#include "tensorflow/core/lib/core/casts.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/core/threadpool.h" +#include "tensorflow/core/platform/logging.h" +#include "tensorflow/core/platform/protobuf.h" +#include "tensorflow/core/util/presized_cuckoo_map.h" +#include "tensorflow/core/util/sparse/sparse_tensor.h" + +namespace tensorflow { +namespace example { + +namespace { +template +auto EnableAliasing(A* a) -> decltype(a->EnableAliasing(true), void()) { + a->EnableAliasing(true); +} + +template +void EnableAliasing(A&& a) {} + +uint8 PeekTag(protobuf::io::CodedInputStream* stream) { + DCHECK(stream != nullptr); + const void* ptr; + int size; + if (!stream->GetDirectBufferPointer(&ptr, &size)) return 0; + return *static_cast(ptr); +} + +constexpr uint8 kVarintTag(uint tag) { return (tag << 3) | 0; } +constexpr uint8 kDelimitedTag(uint tag) { return (tag << 3) | 2; } +constexpr uint8 kFixed32Tag(uint tag) { return (tag << 3) | 5; } + +namespace parsed { + +// ParseDataType has to be called first, then appropriate ParseZzzzList. +class Feature { + public: + Feature() {} + Feature(StringPiece serialized) : serialized_(serialized) {} + + Status ParseDataType(DataType* dtype) { + DCHECK(dtype != nullptr); + if (serialized_.empty()) { + *dtype = DT_INVALID; + return Status::OK(); + } + uint8 oneof_tag = static_cast(*serialized_.data()); + serialized_.remove_prefix(1); + switch (oneof_tag) { + case kDelimitedTag(1): + *dtype = DT_STRING; + break; + case kDelimitedTag(2): + *dtype = DT_FLOAT; + break; + case kDelimitedTag(3): + *dtype = DT_INT64; + break; + default: + return errors::InvalidArgument("Unsuported datatype."); + } + return Status::OK(); + } + + bool ParseBytesList(std::vector* bytes_list) { + DCHECK(bytes_list != nullptr); + protobuf::io::CodedInputStream stream( + reinterpret_cast(serialized_.data()), serialized_.size()); + + EnableAliasing(&stream); + + uint32 length; + if (!stream.ReadVarint32(&length)) return false; + auto limit = stream.PushLimit(length); + + while (!stream.ExpectAtEnd()) { + if (!stream.ExpectTag(kDelimitedTag(1))) return false; + // parse string + uint32 bytes_length; + if (!stream.ReadVarint32(&bytes_length)) return false; + string bytes; + if (!stream.ReadString(&bytes, bytes_length)) return false; + bytes_list->push_back(std::move(bytes)); + } + stream.PopLimit(limit); + return true; + } + + bool ParseFloatList(std::vector* float_list) { + DCHECK(float_list != nullptr); + protobuf::io::CodedInputStream stream( + reinterpret_cast(serialized_.data()), serialized_.size()); + EnableAliasing(&stream); + uint32 length; + if (!stream.ReadVarint32(&length)) return false; + auto limit = stream.PushLimit(length); + + if (!stream.ExpectAtEnd()) { + uint8 peek_tag = PeekTag(&stream); + if (peek_tag != kDelimitedTag(1) && peek_tag != kFixed32Tag(1)) { + return false; + } + + if (peek_tag == kDelimitedTag(1)) { // packed + if (!stream.ExpectTag(kDelimitedTag(1))) return false; // packed tag + uint32 packed_length; + if (!stream.ReadVarint32(&packed_length)) return false; + auto packed_limit = stream.PushLimit(packed_length); + + while (!stream.ExpectAtEnd()) { + uint32 buffer32; + if (!stream.ReadLittleEndian32(&buffer32)) return false; + float_list->push_back(bit_cast(buffer32)); + } + + stream.PopLimit(packed_limit); + } else { // non-packed + while (!stream.ExpectAtEnd()) { + if (!stream.ExpectTag(kFixed32Tag(1))) return false; + uint32 buffer32; + if (!stream.ReadLittleEndian32(&buffer32)) return false; + float_list->push_back(bit_cast(buffer32)); + } + } + } + + stream.PopLimit(limit); + return true; + } + + bool ParseInt64List(std::vector* int64_list) { + DCHECK(int64_list != nullptr); + protobuf::io::CodedInputStream stream( + reinterpret_cast(serialized_.data()), serialized_.size()); + EnableAliasing(&stream); + uint32 length; + if (!stream.ReadVarint32(&length)) return false; + auto limit = stream.PushLimit(length); + + if (!stream.ExpectAtEnd()) { + uint8 peek_tag = PeekTag(&stream); + if (peek_tag != kDelimitedTag(1) && peek_tag != kVarintTag(1)) { + return false; + } + if (peek_tag == kDelimitedTag(1)) { // packed + if (!stream.ExpectTag(kDelimitedTag(1))) return false; // packed tag + uint32 packed_length; + if (!stream.ReadVarint32(&packed_length)) return false; + auto packed_limit = stream.PushLimit(packed_length); + + while (!stream.ExpectAtEnd()) { + uint64 n; // There is no API for int64 + if (!stream.ReadVarint64(&n)) return false; + int64_list->push_back(n); + } + + stream.PopLimit(packed_limit); + } else { // non-packed + while (!stream.ExpectAtEnd()) { + if (!stream.ExpectTag(kVarintTag(1))) return false; + uint64 n; // There is no API for int64 + if (!stream.ReadVarint64(&n)) return false; + int64_list->push_back(n); + } + } + } + stream.PopLimit(limit); + return true; + } + + StringPiece GetSerialized() const { return serialized_; } + + private: + // TODO(lew): Pair of uint8* would be more natural. + StringPiece serialized_; +}; + +using FeatureMapEntry = std::pair; +using Example = std::vector; + +} // namespace parsed + +bool ParseString(protobuf::io::CodedInputStream* stream, StringPiece* result) { + DCHECK(stream != nullptr); + DCHECK(result != nullptr); + uint32 length; + if (!stream->ReadVarint32(&length)) return false; + if (length == 0) { + *result = StringPiece(nullptr, 0); + return true; + } + const void* stream_alias; + int stream_size; + if (!stream->GetDirectBufferPointer(&stream_alias, &stream_size)) { + return false; + } + if (static_cast(stream_size) < length) return false; + *result = StringPiece(static_cast(stream_alias), length); + stream->Skip(length); + return true; +} + +bool ParseFeatureMapEntry(protobuf::io::CodedInputStream* stream, + parsed::FeatureMapEntry* feature_map_entry) { + DCHECK(stream != nullptr); + DCHECK(feature_map_entry != nullptr); + uint32 length; + if (!stream->ReadVarint32(&length)) return false; + auto limit = stream->PushLimit(length); + if (!stream->ExpectTag(kDelimitedTag(1))) return false; + if (!ParseString(stream, &feature_map_entry->first)) return false; + if (!stream->ExpectTag(kDelimitedTag(2))) return false; + StringPiece feature_string_piece; + if (!ParseString(stream, &feature_string_piece)) return false; + feature_map_entry->second = parsed::Feature(feature_string_piece); + if (!stream->ExpectAtEnd()) return false; + stream->PopLimit(limit); + return true; +} + +bool ParseFeatures(protobuf::io::CodedInputStream* stream, + parsed::Example* example) { + DCHECK(stream != nullptr); + DCHECK(example != nullptr); + uint32 length; + if (!stream->ReadVarint32(&length)) return false; + auto limit = stream->PushLimit(length); + while (!stream->ExpectAtEnd()) { + parsed::FeatureMapEntry feature_map_entry; + if (!stream->ExpectTag(kDelimitedTag(1))) return false; + if (!ParseFeatureMapEntry(stream, &feature_map_entry)) return false; + example->push_back(std::move(feature_map_entry)); + } + stream->PopLimit(limit); + return true; +} + +bool ParseExample(protobuf::io::CodedInputStream* stream, + parsed::Example* example) { + DCHECK(stream != nullptr); + DCHECK(example != nullptr); + if (stream->ExpectTag(kDelimitedTag(1))) { + if (!ParseFeatures(stream, example)) return false; + } + if (!stream->ExpectAtEnd()) return false; + return true; +} + +bool ParseExample(StringPiece serialized, parsed::Example* example) { + DCHECK(example != nullptr); + protobuf::io::CodedInputStream stream( + reinterpret_cast(serialized.data()), serialized.size()); + EnableAliasing(&stream); + return ParseExample(&stream, example); +} + +} // namespace + +bool TestFastParse(const string& serialized, Example* example) { + DCHECK(example != nullptr); + parsed::Example parsed_example; + if (!ParseExample(serialized, &parsed_example)) return false; + auto& features = *example->mutable_features(); + for (parsed::FeatureMapEntry& entry : parsed_example) { + auto& value = (*features.mutable_feature())[entry.first.ToString()]; + DataType dtype; + if (!entry.second.ParseDataType(&dtype).ok()) return false; + switch (dtype) { + case DT_INVALID: + break; + case DT_STRING: { + std::vector list; + if (!entry.second.ParseBytesList(&list)) return false; + auto* result_list = value.mutable_bytes_list(); + for (auto& bytes : list) { + result_list->add_value(std::move(bytes)); + } + break; + } + case DT_FLOAT: { + std::vector list; + if (!entry.second.ParseFloatList(&list)) return false; + auto* result_list = value.mutable_float_list(); + for (float f : list) { + result_list->add_value(f); + } + break; + } + case DT_INT64: { + std::vector list; + if (!entry.second.ParseInt64List(&list)) return false; + auto* result_list = value.mutable_int64_list(); + for (int64 i : list) { + result_list->add_value(i); + } + break; + } + default: + CHECK(false) << "Should not happen."; + } + } + return true; +} + +// ----------------------------------------------------------------------------- + +namespace { + +using Config = FastParseExampleConfig; + +void ParallelFor(const std::function& f, size_t n, + thread::ThreadPool* thread_pool) { + DCHECK(thread_pool != nullptr); + if (n == 0) return; + BlockingCounter counter(n - 1); + for (size_t i = 1; i < n; ++i) { + thread_pool->Schedule([i, &f, &counter] { + f(i); + counter.DecrementCount(); + }); + } + f(0); + counter.Wait(); +} + +enum class Type { Sparse, Dense }; + +struct SparseBuffer { + // TODO(lew): Use InlinedVector. + // Features are in one of the 3 vectors below depending on config's dtype. + // Other 2 vectors remain empty. + std::vector bytes_list; + std::vector float_list; + std::vector int64_list; + + // Features of example i are elements with indices + // from example_end_indices[i-1] to example_end_indices[i]-1 on the + // appropriate xxxxx_list + std::vector example_end_indices; +}; + +struct SeededHasher { + uint64 operator()(StringPiece s) const { + return Hash64(s.data(), s.size(), seed); + } + uint64 seed{0xDECAFCAFFE}; +}; + +Status FastParseSerializedExample( + const string& serialized_example, const string& example_name, + const size_t example_index, const Config& config, + const PresizedCuckooMap>& config_index, + SeededHasher hasher, std::vector* output_dense, + std::vector* output_sparse) { + DCHECK(output_dense != nullptr); + DCHECK(output_sparse != nullptr); + parsed::Example parsed_example; + if (!ParseExample(serialized_example, &parsed_example)) { + return errors::InvalidArgument("Could not parse example input, value: '", + serialized_example, "'"); + } + constexpr size_t kMax = std::numeric_limits::max(); + std::vector sparse_features_found(config.sparse.size(), kMax); + std::vector dense_features_found(config.dense.size(), kMax); + + // Handle features present in the example. + for (parsed::FeatureMapEntry& name_and_feature : parsed_example) { + parsed::Feature& feature = name_and_feature.second; + std::pair d_and_type; + uint64 h = hasher(name_and_feature.first); + if (!config_index.Find(h, &d_and_type)) continue; + size_t d = d_and_type.first; + + auto parse_error = [&](StringPiece feature_name) { + return errors::InvalidArgument("Name: ", example_name, ", Key: ", + feature_name, ", Index: ", example_index, + ". Can't parse serialized Example."); + }; + + if (d_and_type.second == Type::Dense) { + DataType example_dtype; + TF_RETURN_IF_ERROR(feature.ParseDataType(&example_dtype)); + if (example_dtype == DT_INVALID) continue; + + dense_features_found[d] = example_index; + if (example_dtype != config.dense[d].dtype) { + return errors::InvalidArgument( + "Name: ", example_name, ", Feature: ", config.dense[d].feature_name, + ". Data types don't match. ", "Data type: ", + DataTypeString(example_dtype), "Expected type: ", + DataTypeString(config.dense[d].dtype)); + } + const string& feature_name = config.dense[d].feature_name; + const TensorShape& shape = config.dense[d].shape; + Tensor& out = (*output_dense)[d]; + + const std::size_t num_elements = shape.num_elements(); + const std::size_t offset = example_index * num_elements; + + auto shape_error = [&](size_t size, StringPiece type_str) { + return errors::InvalidArgument( + "Name: ", example_name, ", Key: ", feature_name, ", Index: ", + example_index, ". Number of ", type_str, + " values != expected. " + "Values size: ", + size, " but output shape: ", shape.DebugString()); + }; + + switch (config.dense[d].dtype) { + case DT_INT64: { + std::vector list; + if (!feature.ParseInt64List(&list)) return parse_error(feature_name); + if (list.size() != num_elements) { + return shape_error(list.size(), "int64"); + } + auto out_p = out.flat().data() + offset; + std::copy_n(list.begin(), list.size(), out_p); + break; + } + case DT_FLOAT: { + std::vector list; + if (!feature.ParseFloatList(&list)) return parse_error(feature_name); + if (list.size() != num_elements) { + return shape_error(list.size(), "float"); + } + auto out_p = out.flat().data() + offset; + std::copy_n(list.begin(), list.size(), out_p); + break; + } + case DT_STRING: { + std::vector list; + if (!feature.ParseBytesList(&list)) return parse_error(feature_name); + if (list.size() != num_elements) { + return shape_error(list.size(), "bytes"); + } + auto out_p = out.flat().data() + offset; + for (size_t i = 0; i < list.size(); ++i) { + out_p[i] = std::move(list[i]); + } + break; + } + default: + CHECK(false) << "Should not happen."; + } + } else { + // Handle sparse features. + sparse_features_found[d] = example_index; + const string& feature_name = config.sparse[d].feature_name; + SparseBuffer& out = (*output_sparse)[d]; + DataType example_dtype; + TF_RETURN_IF_ERROR(feature.ParseDataType(&example_dtype)); + if (example_dtype != DT_INVALID && + example_dtype != config.sparse[d].dtype) { + return errors::InvalidArgument( + "Name: ", example_name, ", Feature: ", + config.sparse[d].feature_name, ". Data types don't match. ", + "Expected type: ", DataTypeString(config.sparse[d].dtype)); + } + + switch (config.sparse[d].dtype) { + case DT_INT64: { + if (example_dtype != DT_INVALID) { + if (!feature.ParseInt64List(&out.int64_list)) { + return parse_error(feature_name); + } + } + out.example_end_indices.push_back(out.int64_list.size()); + break; + } + case DT_FLOAT: { + if (example_dtype != DT_INVALID) { + if (!feature.ParseFloatList(&out.float_list)) { + return parse_error(feature_name); + } + } + out.example_end_indices.push_back(out.float_list.size()); + break; + } + case DT_STRING: { + if (example_dtype != DT_INVALID) { + if (!feature.ParseBytesList(&out.bytes_list)) { + return parse_error(feature_name); + } + } + out.example_end_indices.push_back(out.bytes_list.size()); + break; + } + default: + CHECK(false) << "Should not happen."; + } + } + } + + // Handle missing dense features. + for (size_t d = 0; d < config.dense.size(); ++d) { + if (dense_features_found[d] == example_index) continue; + if (config.dense[d].default_value.NumElements() == 0) { + return errors::InvalidArgument("Name: ", example_name, ", Feature: ", + config.dense[d].feature_name, + " is required but could not be found."); + } + + const Tensor& in = config.dense[d].default_value; + Tensor& out = (*output_dense)[d]; + const std::size_t num_elements = in.shape().num_elements(); + const std::size_t offset = example_index * num_elements; + + switch (config.dense[d].dtype) { + case DT_INT64: { + std::copy_n(in.flat().data(), num_elements, + out.flat().data() + offset); + break; + } + case DT_FLOAT: { + std::copy_n(in.flat().data(), num_elements, + out.flat().data() + offset); + break; + } + case DT_STRING: { + std::copy_n(in.flat().data(), num_elements, + out.flat().data() + offset); + break; + } + default: + CHECK(false) << "Should not happen."; + } + } + + // Handle missing sparse features. + for (size_t d = 0; d < config.sparse.size(); ++d) { + if (sparse_features_found[d] == example_index) continue; + SparseBuffer& out = (*output_sparse)[d]; + size_t prev_example_end_index = + out.example_end_indices.empty() ? 0 : out.example_end_indices.back(); + out.example_end_indices.push_back(prev_example_end_index); + } + + return Status::OK(); +} + +Status CheckConfigDataType(DataType dtype) { + switch (dtype) { + case DT_INT64: + case DT_FLOAT: + case DT_STRING: + return Status::OK(); + default: + return errors::InvalidArgument("Invalid config dtype: ", + DataTypeString(dtype)); + } +} + +} // namespace + +Status FastParseExample(const Config& config, + gtl::ArraySlice serialized, + gtl::ArraySlice example_names, + thread::ThreadPool* thread_pool, Result* result) { + DCHECK(thread_pool != nullptr); + DCHECK(result != nullptr); + // Check config so we can safely CHECK(false) in switches on config.*.dtype + for (auto& c : config.sparse) { + TF_RETURN_IF_ERROR(CheckConfigDataType(c.dtype)); + } + for (auto& c : config.dense) { + TF_RETURN_IF_ERROR(CheckConfigDataType(c.dtype)); + } + + size_t config_size = config.dense.size() + config.sparse.size(); + SeededHasher hasher; + // Build config index. + PresizedCuckooMap> config_index(config_size); + bool ok = true; + for (size_t i = 0; i < 1000; ++i) { + for (size_t d = 0; d < config.dense.size(); ++d) { + ok &= config_index.InsertUnique(hasher(config.dense[d].feature_name), + {d, Type::Dense}); + } + for (size_t d = 0; d < config.sparse.size(); ++d) { + ok &= config_index.InsertUnique(hasher(config.sparse[d].feature_name), + {d, Type::Sparse}); + } + if (ok) break; + LOG(WARNING) << "Collision found. This should happen only if you have " + "around 2^32 entries in your config."; + hasher.seed++; + config_index.Clear(config_size); + } + if (!ok) { + return errors::Internal( + "Could not avoid collision. This should not happen."); + } + + // Allocate dense output (sparse have to be buffered). + for (size_t d = 0; d < config.dense.size(); ++d) { + TensorShape out_shape; + out_shape.AddDim(serialized.size()); + for (const int64 dim : config.dense[d].shape.dim_sizes()) { + out_shape.AddDim(dim); + } + result->dense_values.emplace_back(config.dense[d].dtype, out_shape); + } + + // This parameter affects performance in a big and data-dependent way. + const size_t kMiniBatchSizeBytes = 100000; + + // Split examples into mini-batches for parallel processing. + auto first_example_of_minibatch = [&] { + std::vector result; + size_t minibatch_bytes = 0; + for (size_t i = 0; i < serialized.size(); i++) { + if (minibatch_bytes == 0) { // start minibatch + result.push_back(i); + } + minibatch_bytes += serialized[i].size() + 1; + if (minibatch_bytes > kMiniBatchSizeBytes) { + minibatch_bytes = 0; + } + } + return result; + }(); + + size_t num_minibatches = first_example_of_minibatch.size(); + + // Do minibatches in parallel. + std::vector> sparse_buffers(num_minibatches); + std::vector status_of_minibatch(num_minibatches); + + auto ProcessMiniBatch = [&](size_t minibatch) { + sparse_buffers[minibatch].resize(config.sparse.size()); + size_t start = first_example_of_minibatch[minibatch]; + size_t end = minibatch + 1 < num_minibatches + ? first_example_of_minibatch[minibatch + 1] + : serialized.size(); + for (size_t e = start; e < end; ++e) { + status_of_minibatch[minibatch] = FastParseSerializedExample( + serialized[e], + (example_names.size() > 0 ? example_names[e] : ""), e, + config, config_index, hasher, &result->dense_values, + &sparse_buffers[minibatch]); + if (!status_of_minibatch[minibatch].ok()) break; + } + }; + + ParallelFor(ProcessMiniBatch, num_minibatches, thread_pool); + + for (Status& status : status_of_minibatch) { + TF_RETURN_IF_ERROR(status); + } + + // Merge SparseBuffers from all minibatches for every config.sparse. + auto MergeMinibatches = [&](size_t d) { + // Loop over minibatches + size_t total_num_features = 0; + size_t max_num_features = 0; + for (auto& sparse_values_tmp : sparse_buffers) { + std::vector& end_indices = + sparse_values_tmp[d].example_end_indices; + total_num_features += end_indices.back(); + max_num_features = std::max(max_num_features, end_indices[0]); + for (size_t i = 1; i < end_indices.size(); ++i) { + size_t example_size = end_indices[i] - end_indices[i - 1]; + max_num_features = std::max(max_num_features, example_size); + } + } + + TensorShape indices_shape; + indices_shape.AddDim(total_num_features); + indices_shape.AddDim(2); + result->sparse_indices.emplace_back(DT_INT64, indices_shape); + Tensor* indices = &result->sparse_indices.back(); + + TensorShape values_shape; + values_shape.AddDim(total_num_features); + result->sparse_values.emplace_back(config.sparse[d].dtype, values_shape); + Tensor* values = &result->sparse_values.back(); + + result->sparse_shapes.emplace_back(DT_INT64, TensorShape({2})); + auto shapes_shape_t = result->sparse_shapes.back().vec(); + shapes_shape_t(0) = serialized.size(); + shapes_shape_t(1) = max_num_features; + + size_t offset = 0; + for (size_t i = 0; i < sparse_buffers.size(); ++i) { + const SparseBuffer& buffer = sparse_buffers[i][d]; + + // Update indices. + int64* ix_p = &indices->matrix()(offset, 0); + size_t delta = 0; + size_t example_index = first_example_of_minibatch[i]; + for (size_t example_end_index : buffer.example_end_indices) { + size_t feature_index = 0; + for (; delta < example_end_index; ++delta) { + // Column 0: example index + *ix_p = example_index; + // Column 1: the feature index buffer example + *(ix_p + 1) = feature_index; + ix_p += 2; + ++feature_index; + } + ++example_index; + } + + // Copy values over. + switch (config.sparse[d].dtype) { + case DT_INT64: { + std::copy(buffer.int64_list.begin(), buffer.int64_list.end(), + values->flat().data() + offset); + break; + } + case DT_FLOAT: { + std::copy(buffer.float_list.begin(), buffer.float_list.end(), + values->flat().data() + offset); + break; + } + case DT_STRING: { + std::move(buffer.bytes_list.begin(), buffer.bytes_list.end(), + values->flat().data() + offset); + break; + } + default: + CHECK(false) << "Should not happen."; + } + + offset += delta; + } + }; + + for (size_t d = 0; d < config.sparse.size(); ++d) { + MergeMinibatches(d); + } + + return Status::OK(); +} + +} // namespace example +} // namespace tensorflow diff --git a/tensorflow/core/util/example_proto_fast_parsing.h b/tensorflow/core/util/example_proto_fast_parsing.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed9d5783851ab4128cc31d11a7c223ae40d70b7 --- /dev/null +++ b/tensorflow/core/util/example_proto_fast_parsing.h @@ -0,0 +1,88 @@ +/* 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. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ +#define THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ + +#include +#include +#include + +#include "tensorflow/core/example/example.pb.h" +#include "tensorflow/core/framework/allocator.h" +#include "tensorflow/core/framework/graph.pb.h" +#include "tensorflow/core/framework/op_kernel.h" +#include "tensorflow/core/framework/tensor.h" +#include "tensorflow/core/framework/types.h" +#include "tensorflow/core/lib/gtl/array_slice.h" +#include "tensorflow/core/platform/types.h" +#include "tensorflow/core/util/sparse/sparse_tensor.h" + +namespace tensorflow { +namespace example { + +// FastParseExampleConfig defines how to parse features in Example. +// Each sub-config is responsible for one feature identified with feautre_name. +// FastParseExampleConfig can't have two sub-configs with the same feature_name. +// dtype identifies the type of output vector and the kind of Feature expected +// in Example. +struct FastParseExampleConfig { + struct Dense { + string feature_name; + DataType dtype; + // These 2 fields correspond exactly to dense_shapes and dense_defaults in + // ParseExample op. + // Documentation is avaliable in: tensorflow/core/ops/parsing_ops.cc + TensorShape shape; + Tensor default_value; + }; + + struct Sparse { + string feature_name; + DataType dtype; + }; + + std::vector dense; + std::vector sparse; +}; + +// This is exactly the output of TF's ParseExample Op. +// Documentation is avaliable in: tensorflow/core/ops/parsing_ops.cc +struct Result { + std::vector sparse_indices; + std::vector sparse_values; + std::vector sparse_shapes; + std::vector dense_values; +}; + +// Parses a batch of serialized Example protos and converts them into result +// according to given config. +// Given example names have to either be empty or the same size as serialized. +// example_names are used only for error messages. +Status FastParseExample(const FastParseExampleConfig& config, + gtl::ArraySlice serialized, + gtl::ArraySlice example_names, + thread::ThreadPool* thread_pool, Result* result); + +// This function parses serialized Example and populates given example. +// It uses the same specialized parser as FastParseExample which is efficient. +// But then constructs Example which is relatively slow. +// It is exported here as a convenient API to test parser part separately. +bool TestFastParse(const string& serialized, Example* example); + +} // namespace example +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_CORE_UTIL_EXAMPLE_PROTO_FAST_PARSING_H_ diff --git a/tensorflow/core/util/example_proto_fast_parsing_test.cc b/tensorflow/core/util/example_proto_fast_parsing_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..6d3b548851bef3ccb8f88bfcc03be29dbc7d5c78 --- /dev/null +++ b/tensorflow/core/util/example_proto_fast_parsing_test.cc @@ -0,0 +1,184 @@ +/* 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. +==============================================================================*/ +#include "tensorflow/core/util/example_proto_fast_parsing.h" + +#include "tensorflow/core/example/example.pb.h" +#include "tensorflow/core/platform/protobuf.h" +#include "tensorflow/core/platform/test.h" +#include "tensorflow/core/platform/test_benchmark.h" + +namespace tensorflow { +namespace example { +namespace { + +constexpr char kDenseInt64Key[] = "dense_int64"; +constexpr char kDenseFloatKey[] = "dense_float"; +constexpr char kDenseStringKey[] = "dense_string"; + +constexpr char kSparseInt64Key[] = "sparse_int64"; +constexpr char kSparseFloatKey[] = "sparse_float"; +constexpr char kSparseStringKey[] = "sparse_string"; + +string SerializedToReadable(string serialized) { + string result; + result += '"'; + for (char c : serialized) + result += strings::StrCat("\\x", strings::Hex(c, strings::ZERO_PAD_2)); + result += '"'; + return result; +} + +string Serialize(const Example& example) { + string serialized; + example.SerializeToString(&serialized); + return serialized; +} + +void TestCorrectness(const string& serialized) { + Example example; + Example fast_example; + EXPECT_TRUE(example.ParseFromString(serialized)); + EXPECT_TRUE(TestFastParse(serialized, &fast_example)); + EXPECT_EQ(example.DebugString(), fast_example.DebugString()); + if (example.DebugString() != fast_example.DebugString()) { + LOG(ERROR) << "Bad serialized: " << SerializedToReadable(serialized); + } +} + +// Fast parsing does not differentiate between EmptyExample and EmptyFeatures +// TEST(FastParse, EmptyExample) { +// Example example; +// TestCorrectness(example); +// } + +TEST(FastParse, NonPacked) { + TestCorrectness( + "\x0a\x0e\x0a\x0c\x0a\x03\x61\x67\x65\x12\x05\x1a\x03\x0a\x01\x0d"); +} + +TEST(FastParse, Packed) { + TestCorrectness( + "\x0a\x0d\x0a\x0b\x0a\x03\x61\x67\x65\x12\x04\x1a\x02\x08\x0d"); +} + +TEST(FastParse, EmptyFeatures) { + Example example; + example.mutable_features(); + TestCorrectness(Serialize(example)); +} + +void TestCorrectnessJson(const string& json) { + auto resolver = protobuf::util::NewTypeResolverForDescriptorPool( + "type.googleapis.com", protobuf::DescriptorPool::generated_pool()); + string serialized; + auto s = protobuf::util::JsonToBinaryString( + resolver, "type.googleapis.com/tensorflow.Example", json, &serialized); + EXPECT_TRUE(s.ok()) << s; + delete resolver; + TestCorrectness(serialized); +} + +TEST(FastParse, JsonUnivalent) { + TestCorrectnessJson( + "{'features': {" + " 'feature': {'age': {'int64_list': {'value': [0]} }}, " + " 'feature': {'flo': {'float_list': {'value': [1.1]} }}, " + " 'feature': {'byt': {'bytes_list': {'value': ['WW8='] }}}" + "}}"); +} + +TEST(FastParse, JsonMultivalent) { + TestCorrectnessJson( + "{'features': {" + " 'feature': {'age': {'int64_list': {'value': [0, 13, 23]} }}, " + " 'feature': {'flo': {'float_list': {'value': [1.1, 1.2, 1.3]} }}, " + " 'feature': {'byt': {'bytes_list': {'value': ['WW8=', 'WW8K'] }}}" + "}}"); +} + +TEST(FastParse, SingleInt64) { + Example example; + (*example.mutable_features()->mutable_feature())["age"] + .mutable_int64_list() + ->add_value(13); + TestCorrectness(Serialize(example)); +} + +TEST(FastParse, SomeFeatures) { + Example example; + + (*example.mutable_features()->mutable_feature())[""]; + + (*example.mutable_features()->mutable_feature())["empty_bytes_list"] + .mutable_bytes_list(); + (*example.mutable_features()->mutable_feature())["empty_float_list"] + .mutable_float_list(); + (*example.mutable_features()->mutable_feature())["empty_int64_list"] + .mutable_int64_list(); + + BytesList* bytes_list = + (*example.mutable_features()->mutable_feature())["bytes_list"] + .mutable_bytes_list(); + bytes_list->add_value("bytes1"); + bytes_list->add_value("bytes2"); + + FloatList* float_list = + (*example.mutable_features()->mutable_feature())["float_list"] + .mutable_float_list(); + float_list->add_value(1.0); + float_list->add_value(2.0); + + Int64List* int64_list = + (*example.mutable_features()->mutable_feature())["int64_list"] + .mutable_int64_list(); + int64_list->add_value(3); + int64_list->add_value(270); + int64_list->add_value(86942); + + TestCorrectness(Serialize(example)); +} + +string MakeSerializedExample() { + Example example; + const int kFeatureNameLength = 10; + const int kFeatureValueLength = 20; + const int kBytesFeatureCount = 200; + const int kFloatFeatureCount = 200; + const int kInt64FeatureCount = 200; + auto& fmap = *example.mutable_features()->mutable_feature(); + for (int i = 0; i < kBytesFeatureCount; ++i) { + fmap[strings::StrCat(string('b', kFeatureNameLength), i)] + .mutable_bytes_list() + ->add_value(string('v', kFeatureValueLength)); + } + for (int i = 0; i < kFloatFeatureCount; ++i) { + fmap[strings::StrCat(string('f', kFeatureNameLength), i)] + .mutable_float_list() + ->add_value(123123123.123); + } + for (int i = 0; i < kInt64FeatureCount; ++i) { + fmap[strings::StrCat(string('i', kFeatureNameLength), i)] + .mutable_int64_list() + ->add_value(10 * i); + } + string serialized; + example.SerializeToString(&serialized); + return serialized; +} + +} // namespace + +} // namespace example +} // namespace tensorflow diff --git a/tensorflow/core/util/example_proto_helper.cc b/tensorflow/core/util/example_proto_helper.cc index acab74732e4123d505ab1b645000b8e9dcd4d8e3..658b3588e6b515eece3e6ea807ce25e841d18841 100644 --- a/tensorflow/core/util/example_proto_helper.cc +++ b/tensorflow/core/util/example_proto_helper.cc @@ -222,7 +222,7 @@ Status SingleExampleProtoToTensors( const auto& feature_dict = features.feature(); // Handle dense features. - for (int d = 0; d < fixed_len_features.size(); ++d) { + for (size_t d = 0; d < fixed_len_features.size(); ++d) { const FixedLenFeature& feature_config = fixed_len_features[d]; const string& key = feature_config.key; const DataType& dtype = feature_config.dtype; @@ -263,7 +263,7 @@ Status SingleExampleProtoToTensors( } // Handle sparse features. - for (int d = 0; d < var_len_features.size(); ++d) { + for (size_t d = 0; d < var_len_features.size(); ++d) { const VarLenFeature& feature_config = var_len_features[d]; const string& key = feature_config.key; const DataType& dtype = feature_config.dtype; @@ -338,7 +338,7 @@ Status BatchExampleProtoToTensors( fixed_len_features.size()); // Preallocate dense_values, since we know their sizes. - for (int d = 0; d < fixed_len_features.size(); ++d) { + for (size_t d = 0; d < fixed_len_features.size(); ++d) { const FixedLenFeature& config = fixed_len_features[d]; TensorShape out_shape; out_shape.AddDim(batch_size); @@ -352,11 +352,11 @@ Status BatchExampleProtoToTensors( // Temporary vector to hold sparse values. std::vector> sparse_values_tmp(var_len_features.size()); - for (int d = 0; d < var_len_features.size(); ++d) { + for (size_t d = 0; d < var_len_features.size(); ++d) { sparse_values_tmp[d] = std::vector(batch_size); } - for (int b = 0; b < examples.size(); ++b) { + for (size_t b = 0; b < examples.size(); ++b) { const Example& ex = *(examples[b]); const string& example_name = (has_names) ? names[b] : ""; SingleExampleProtoToTensors( @@ -364,7 +364,7 @@ Status BatchExampleProtoToTensors( &output_dense_values_tensor_ptrs, &sparse_values_tmp); } - for (int d = 0; d < var_len_features.size(); ++d) { + for (size_t d = 0; d < var_len_features.size(); ++d) { const VarLenFeature& feature_config = var_len_features[d]; const DataType& dtype = feature_config.dtype; const std::vector& sparse_values_tensor = sparse_values_tmp[d]; diff --git a/tensorflow/core/util/presized_cuckoo_map.h b/tensorflow/core/util/presized_cuckoo_map.h index b488d32e03d5545a852cae1320ce2db8a2cfd1f5..a1ae3ec248556e5afc5b9781159a95464b971e01 100644 --- a/tensorflow/core/util/presized_cuckoo_map.h +++ b/tensorflow/core/util/presized_cuckoo_map.h @@ -50,7 +50,10 @@ class PresizedCuckooMap { // The key type is fixed as a pre-hashed key for this specialized use. typedef uint64 key_type; - explicit PresizedCuckooMap(uint64 num_entries) : cpq_(new CuckooPathQueue) { + explicit PresizedCuckooMap(uint64 num_entries) { Clear(num_entries); } + + void Clear(uint64 num_entries) { + cpq_.reset(new CuckooPathQueue()); double n(num_entries); n /= kLoadFactor; num_buckets_ = (static_cast(n) / kSlotsPerBucket); @@ -62,8 +65,10 @@ class PresizedCuckooMap { for (int i = 0; i < kSlotsPerBucket; i++) { empty_bucket.keys[i] = kUnusedSlot; } + buckets_.clear(); buckets_.resize(num_buckets_, empty_bucket); -#if !defined(__GCUDACC__) && !defined(__GCUDACC_HOST__) +#if !defined(__GCUDACC__) && !defined(__GCUDACC_HOST__) && \ + !defined(IS_MOBILE_PLATFORM) buckets_divisor_ = Eigen::internal::TensorIntDivisor(num_buckets_); #endif } @@ -304,7 +309,8 @@ class PresizedCuckooMap { inline uint64 fast_mod_by_buckets(uint64 x) const { // Omitting the optimized bucket mod for CUDA platforms // until Eigen supports 2^63 divisors on GPU. -#if !defined(__GCUDACC__) && !defined(__GCUDACC_HOST__) +#if !defined(__GCUDACC__) && !defined(__GCUDACC_HOST__) && \ + !defined(IS_MOBILE_PLATFORM) x &= ~(1ULL << 63); // Fast div can only handle 2^63-1 return x - num_buckets_ * (x / buckets_divisor_); #else @@ -317,7 +323,7 @@ class PresizedCuckooMap { std::vector buckets_; Eigen::internal::TensorIntDivisor buckets_divisor_; // for fast mod - const std::unique_ptr cpq_; + std::unique_ptr cpq_; CuckooPathEntry visited_[kVisitedListSize]; TF_DISALLOW_COPY_AND_ASSIGN(PresizedCuckooMap); diff --git a/tensorflow/core/util/presized_cuckoo_map_test.cc b/tensorflow/core/util/presized_cuckoo_map_test.cc index 64ad315518d8ff62529e4c1c037a36e63612e37a..fe8e5dcfbd6cef8a6f60bff889aa851326a6d163 100644 --- a/tensorflow/core/util/presized_cuckoo_map_test.cc +++ b/tensorflow/core/util/presized_cuckoo_map_test.cc @@ -13,11 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#include "tensorflow/core/util/presized_cuckoo_map.h" #include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/fingerprint.h" #include "tensorflow/core/platform/test.h" #include "tensorflow/core/platform/test_benchmark.h" -#include "tensorflow/core/util/presized_cuckoo_map.h" namespace tensorflow { namespace { @@ -64,6 +64,22 @@ TEST(PresizedCuckooMapTest, ZeroSizeMap) { } } +TEST(PresizedCuckooMapTest, RepeatedClear) { + PresizedCuckooMap pscm(2); + int out; + for (int i = 0; i < 100; ++i) { + pscm.InsertUnique(0, 0); + pscm.InsertUnique(1, 1); + EXPECT_TRUE(pscm.Find(0, &out)); + EXPECT_EQ(0, out); + EXPECT_TRUE(pscm.Find(1, &out)); + EXPECT_EQ(1, out); + pscm.Clear(2); + EXPECT_FALSE(pscm.Find(0, &out)); + EXPECT_FALSE(pscm.Find(1, &out)); + } +} + void RunFill(int64 table_size) { PresizedCuckooMap pscm(table_size); for (int64 i = 0; i < table_size; i++) { diff --git a/tensorflow/core/util/sparse/sparse_tensor.h b/tensorflow/core/util/sparse/sparse_tensor.h index 79064e9988d7e6f499c0ae4b40a76cee01a3fabd..1665446aee41b747df6bf50cd88e881aa408b509 100644 --- a/tensorflow/core/util/sparse/sparse_tensor.h +++ b/tensorflow/core/util/sparse/sparse_tensor.h @@ -283,7 +283,7 @@ void SparseTensor::Reorder(const VarDimArray& order) { // permutation (the inverse). This can be calculated with O(1) // additional // and O(n) time (INVPERM) but we just do the simple thing here. - std::vector permutation(reorder.size()); + std::vector permutation(reorder.size()); for (std::size_t n = 0; n < reorder.size(); ++n) { permutation[reorder[n]] = n; } diff --git a/tensorflow/examples/image_retraining/retrain.py b/tensorflow/examples/image_retraining/retrain.py index 056664778d757123dad0d69fc363bd053eea0008..acd3005c48350f26a1aaea1e49b954bb3cada0c1 100644 --- a/tensorflow/examples/image_retraining/retrain.py +++ b/tensorflow/examples/image_retraining/retrain.py @@ -703,7 +703,7 @@ def variable_summaries(var, name): mean = tf.reduce_mean(var) tf.scalar_summary('mean/' + name, mean) with tf.name_scope('stddev'): - stddev = tf.sqrt(tf.reduce_sum(tf.square(var - mean))) + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) tf.scalar_summary('sttdev/' + name, stddev) tf.scalar_summary('max/' + name, tf.reduce_max(var)) tf.scalar_summary('min/' + name, tf.reduce_min(var)) diff --git a/tensorflow/examples/learn/wide_n_deep_tutorial.py b/tensorflow/examples/learn/wide_n_deep_tutorial.py index 5a23087b5a73f74bb85c56933fd5e10af043345e..cb51dc02870077bada4fdad436b40225ef1ac6a1 100644 --- a/tensorflow/examples/learn/wide_n_deep_tutorial.py +++ b/tensorflow/examples/learn/wide_n_deep_tutorial.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== + +# pylint: disable=g-bad-import-order """Example code for TensorFlow Wide & Deep Tutorial using TF.Learn API.""" from __future__ import absolute_import from __future__ import division @@ -19,7 +21,6 @@ from __future__ import print_function import tempfile import urllib - import pandas as pd import tensorflow as tf diff --git a/tensorflow/examples/skflow/iris_save_restore.py b/tensorflow/examples/skflow/iris_save_restore.py index 4836183e9d0e23c1788aa76944ded8546f0ebe30..8955f92b3af4d69ef634274e2c54718aa24335c8 100644 --- a/tensorflow/examples/skflow/iris_save_restore.py +++ b/tensorflow/examples/skflow/iris_save_restore.py @@ -29,10 +29,10 @@ iris = datasets.load_iris() x_train, x_test, y_train, y_test = cross_validation.train_test_split( iris.data, iris.target, test_size=0.2, random_state=42) -classifier = learn.TensorFlowLinearClassifier( +classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(x_train), n_classes=3) -classifier.fit(x_train, y_train) +classifier.fit(x_train, y_train, steps=200) score = metrics.accuracy_score(y_test, classifier.predict(x_test)) print('Accuracy: {0:f}'.format(score)) diff --git a/tensorflow/examples/skflow/mnist.py b/tensorflow/examples/skflow/mnist.py index 3b11708a27a198af9c280e690341dfcd8f415375..782d0915610b7647b5da1de38fa1bfeba6e3adc3 100644 --- a/tensorflow/examples/skflow/mnist.py +++ b/tensorflow/examples/skflow/mnist.py @@ -33,10 +33,10 @@ mnist = learn.datasets.load_dataset('mnist') ### Linear classifier. feature_columns = learn.infer_real_valued_columns_from_input(mnist.train.images) -classifier = learn.TensorFlowLinearClassifier( - feature_columns=feature_columns, n_classes=10, batch_size=100, steps=1000, - learning_rate=0.01) -classifier.fit(mnist.train.images, mnist.train.labels) +classifier = learn.LinearClassifier( + feature_columns=feature_columns, n_classes=10) +classifier.fit(mnist.train.images, mnist.train.labels, batch_size=100, + steps=1000) score = metrics.accuracy_score( mnist.test.labels, classifier.predict(mnist.test.images)) print('Accuracy: {0:f}'.format(score)) diff --git a/tensorflow/examples/skflow/mnist_weights.py b/tensorflow/examples/skflow/mnist_weights.py index c4e98f7bf11995e5ff3aa28c7a1d0e393bd35c0d..aa06f4adb0b258e4d91ce90ae32f00bffbb1f463 100644 --- a/tensorflow/examples/skflow/mnist_weights.py +++ b/tensorflow/examples/skflow/mnist_weights.py @@ -32,10 +32,10 @@ mnist = learn.datasets.load_dataset('mnist') ### Linear classifier. feature_columns = learn.infer_real_valued_columns_from_input(mnist.train.images) -classifier = learn.TensorFlowLinearClassifier( - feature_columns=feature_columns, n_classes=10, batch_size=100, steps=1000, - learning_rate=0.01) -classifier.fit(mnist.train.images, mnist.train.labels) +classifier = learn.LinearClassifier( + feature_columns=feature_columns, n_classes=10) +classifier.fit(mnist.train.images, mnist.train.labels, batch_size=100, + steps=1000) score = metrics.accuracy_score( mnist.test.labels, classifier.predict(mnist.test.images)) print('Accuracy: {0:f}'.format(score)) diff --git a/tensorflow/examples/skflow/out_of_core_data_classification.py b/tensorflow/examples/skflow/out_of_core_data_classification.py index 5ed6033cc091cc091e2a7339235ad6b0ce5fd7cb..760b4367d349f96f5972e9eed2e6990e43a04a3f 100644 --- a/tensorflow/examples/skflow/out_of_core_data_classification.py +++ b/tensorflow/examples/skflow/out_of_core_data_classification.py @@ -50,12 +50,12 @@ x_train, y_train, x_test, y_test = [ for data in [x_train, y_train, x_test, y_test]] # Initialize a TensorFlow linear classifier -classifier = learn.TensorFlowLinearClassifier( +classifier = learn.LinearClassifier( feature_columns=learn.infer_real_valued_columns_from_input(x_train), n_classes=3) # Fit the model using training set. -classifier.fit(x_train, y_train) +classifier.fit(x_train, y_train, steps=200) # Make predictions on each partitions of testing data predictions = x_test.map_partitions(classifier.predict).compute() # Calculate accuracy diff --git a/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py b/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py index c83239217aefcdc06b87e1634a6ed2e924b977f9..23492e5122c87b7f15fefa59852d569c7fe1011d 100644 --- a/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py +++ b/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py @@ -75,7 +75,7 @@ def train(): mean = tf.reduce_mean(var) tf.scalar_summary('mean/' + name, mean) with tf.name_scope('stddev'): - stddev = tf.sqrt(tf.reduce_sum(tf.square(var - mean))) + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) tf.scalar_summary('sttdev/' + name, stddev) tf.scalar_summary('max/' + name, tf.reduce_max(var)) tf.scalar_summary('min/' + name, tf.reduce_min(var)) diff --git a/tensorflow/g3doc/api_docs/python/array_ops.md b/tensorflow/g3doc/api_docs/python/array_ops.md index 52a6b995551092a8d329990b4fbb46167434b838..e0bf98a39d00685418d0e98299a16d14f2a5b89a 100644 --- a/tensorflow/g3doc/api_docs/python/array_ops.md +++ b/tensorflow/g3doc/api_docs/python/array_ops.md @@ -477,11 +477,14 @@ instructions for the first two dimensions are swapped. Examples: Calling `X, Y = meshgrid(x, y)` with the tensors + ```prettyprint x = [1, 2, 3] y = [4, 5, 6] ``` + results in + ```prettyprint X = [[1, 1, 1], [2, 2, 2], diff --git a/tensorflow/g3doc/api_docs/python/client.md b/tensorflow/g3doc/api_docs/python/client.md index 1490bbaec709ef7e91437629f3b3ee7bcf22b053..7a38444daf3c5b1a6949c33c4ad9f5c2e9193451 100644 --- a/tensorflow/g3doc/api_docs/python/client.md +++ b/tensorflow/g3doc/api_docs/python/client.md @@ -454,8 +454,8 @@ Creates a new `OpError` indicating that a particular op failed. ##### Args: -* `node_def`: The `graph_pb2.NodeDef` proto representing the op that failed, - if known; otherwise None. +* `node_def`: The `node_def_pb2.NodeDef` proto representing the op that + failed, if known; otherwise None. * `op`: The `ops.Operation` that failed, if known; otherwise None. * `message`: The message string describing the failure. * `error_code`: The `error_codes_pb2.Code` describing the error. diff --git a/tensorflow/g3doc/api_docs/python/constant_op.md b/tensorflow/g3doc/api_docs/python/constant_op.md index cfd488428afcca77601c8046379ab490a92774b9..eb9388f4eeab9bd1214feab8c807c4f9904219dc 100644 --- a/tensorflow/g3doc/api_docs/python/constant_op.md +++ b/tensorflow/g3doc/api_docs/python/constant_op.md @@ -121,8 +121,8 @@ tf.ones_like(tensor) ==> [[1, 1, 1], [1, 1, 1]] * `tensor`: A `Tensor`. * `dtype`: A type for the returned `Tensor`. Must be `float32`, `float64`, - `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, or `complex128`. - + `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, `complex128` or + `bool`. * `name`: A name for the operation (optional). * `optimize`: if true, attempt to statically determine the shape of 'tensor' and encode it as a constant. diff --git a/tensorflow/g3doc/api_docs/python/contrib.bayesflow.entropy.md b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.entropy.md new file mode 100644 index 0000000000000000000000000000000000000000..93816a914281b5d6f490975847919111240915b0 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.entropy.md @@ -0,0 +1,304 @@ + + +# BayesFlow Entropy (contrib) +[TOC] + +Entropy Ops. + +## Background + +Common Shannon entropy, the Evidence Lower BOund (ELBO), KL divergence, and more +all have information theoretic use and interpretations. They are also often +used in variational inference. This library brings together `Ops` for +estimating them, e.g. using Monte Carlo expectations. + +## Examples + +Example of fitting a variational posterior with the ELBO. + +``` +# We start by assuming knowledge of the log of a joint density p(z, x) over +# latent variable z and fixed measurement x. Since x is fixed, the Python +# function does not take x as an argument. +def log_joint(z): + theta = tf.Variable(0.) # Trainable variable that helps define log_joint. + ... + +# Next, define a Normal distribution with trainable parameters. +q = distributions.Normal(mu=tf.Variable(0.), sigma=tf.Variable(1.)) + +# Now, define a loss function (negative ELBO) that, when minimized, will adjust +# mu, sigma, and theta, increasing the ELBO, which we hope will both reduce the +# KL divergence between q(z) and p(z | x), and increase p(x). Note that we +# cannot guarantee both, but in general we expect both to happen. +elbo = entropy.elbo_ratio(log_p, q, n=10) +loss = -elbo + +# Minimize the loss +train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss) +tf.initialize_all_variables().run() +for step in range(100): + train_op.run() +``` + +## Ops + +- - - + +### `tf.contrib.bayesflow.entropy.elbo_ratio(log_p, q, z=None, n=None, seed=None, form=None, name='elbo_ratio')` {#elbo_ratio} + +Estimate of the ratio appearing in the `ELBO` and `KL` divergence. + +With `p(z) := exp{log_p(z)}`, this `Op` returns an approximation of + +``` +E_q[ Log[p(Z) / q(Z)] ] +``` + +The term `E_q[ Log[p(Z)] ]` is always computed as a sample mean. +The term `E_q[ Log[q(z)] ]` can be computed with samples, or an exact formula +if `q.entropy()` is defined. This is controlled with the kwarg `form`. + +This log-ratio appears in different contexts: + +#### `KL[q || p]` + +If `log_p(z) = Log[p(z)]` for distribution `p`, this `Op` approximates +the negative Kullback-Leibler divergence. + +``` +elbo_ratio(log_p, q, n=100) = -1 * KL[q || p], +KL[q || p] = E[ Log[q(Z)] - Log[p(Z)] ] +``` + +Note that if `p` is a `Distribution`, then `distributions.kl(q, p)` may be +defined and available as an exact result. + +#### ELBO + +If `log_p(z) = Log[p(z, x)]` is the log joint of a distribution `p`, this is +the Evidence Lower BOund (ELBO): + +``` +ELBO ~= E[ Log[p(Z, x)] - Log[q(Z)] ] + = Log[p(x)] - KL[q || p] + <= Log[p(x)] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_p`: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `q`: `tf.contrib.distributions.BaseDistribution`. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `form`: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. +* `name`: A name to give this `Op`. + +##### Returns: + + Scalar `Tensor` holding sample mean KL divergence. `shape` is the batch + shape of `q`, and `dtype` is the same as `q`. + +##### Raises: + + +* `ValueError`: If `form` is not handled by this function. + + +- - - + +### `tf.contrib.bayesflow.entropy.entropy_shannon(p, z=None, n=None, seed=None, form=None, name='entropy_shannon')` {#entropy_shannon} + +Monte Carlo or deterministic computation of Shannon's entropy. + +Depending on the kwarg `form`, this `Op` returns either the analytic entropy +of the distribution `p`, or the sampled entropy: + +``` +-n^{-1} sum_{i=1}^n p.log_prob(z_i), where z_i ~ p, + \approx - E_p[ Log[p(Z)] ] + = Entropy[p] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `p`: `tf.contrib.distributions.BaseDistribution` +* `z`: `Tensor` of samples from `p`, produced by `p.sample_n(n)` for some `n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `form`: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. +* `name`: A name to give this `Op`. + +##### Returns: + + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + +##### Raises: + + +* `ValueError`: If `form` not handled by this function. +* `ValueError`: If `form` is `ELBOForms.analytic_entropy` and `n` was provided. + + +- - - + +### `tf.contrib.bayesflow.entropy.renyi_ratio(log_p, q, alpha, z=None, n=None, seed=None, name='renyi_ratio')` {#renyi_ratio} + +Monte Carlo estimate of the ratio appearing in Renyi divergence. + +This can be used to compute the Renyi (alpha) divergence, or a log evidence +approximation based on Renyi divergence. + +#### Definition + +With `z_i` iid samples from `q`, and `exp{log_p(z)} = p(z)`, this `Op` returns +the (biased for finite `n`) estimate: + +``` +(1 - alpha)^{-1} Log[ n^{-1} sum_{i=1}^n ( p(z_i) / q(z_i) )^{1 - alpha}, +\approx (1 - alpha)^{-1} Log[ E_q[ (p(Z) / q(Z))^{1 - alpha} ] ] +``` + +This ratio appears in different contexts: + +#### Renyi divergence + +If `log_p(z) = Log[p(z)]` is the log prob of a distribution, and +`alpha > 0`, `alpha != 1`, this `Op` approximates `-1` times Renyi divergence: + +``` +# Choose reasonably high n to limit bias, see below. +renyi_ratio(log_p, q, alpha, n=100) + \approx -1 * D_alpha[q || p], where +D_alpha[q || p] := (1 - alpha)^{-1} Log E_q[(p(Z) / q(Z))^{1 - alpha}] +``` + +The Renyi (or "alpha") divergence is non-negative and equal to zero iff +`q = p`. Various limits of `alpha` lead to different special case results: + +``` +alpha D_alpha[q || p] +----- --------------- +--> 0 Log[ int_{q > 0} p(z) dz ] += 0.5, -2 Log[1 - Hel^2[q || p]], (\propto squared Hellinger distance) +--> 1 KL[q || p] += 2 Log[ 1 + chi^2[q || p] ], (\propto squared Chi-2 divergence) +--> infty Log[ max_z{q(z) / p(z)} ], (min description length principle). +``` + +See "Renyi Divergence Variational Inference", by Li and Turner. + +#### Log evidence approximation + +If `log_p(z) = Log[p(z, x)]` is the log of the joint distribution `p`, this is +an alternative to the ELBO common in variational inference. + +``` +L_alpha(q, p) = Log[p(x)] - D_alpha[q || p] +``` + +If `q` and `p` have the same support, and `0 < a <= b < 1`, one can show +`ELBO <= D_b <= D_a <= Log[p(x)]`. Thus, this `Op` allows a smooth +interpolation between the ELBO and the true evidence. + +#### Stability notes + +Note that when `1 - alpha` is not small, the ratio `(p(z) / q(z))^{1 - alpha}` +is subject to underflow/overflow issues. For that reason, it is evaluated in +log-space after centering. Nonetheless, infinite/NaN results may occur. For +that reason, one may wish to shrink `alpha` gradually. See the `Op` +`renyi_alpha`. Using `float64` will also help. + + +#### Bias for finite sample size + +Due to nonlinearity of the logarithm, for random variables `{X_1,...,X_n}`, +`E[ Log[sum_{i=1}^n X_i] ] != Log[ E[sum_{i=1}^n X_i] ]`. As a result, this +estimate is biased for finite `n`. For `alpha < 1`, it is non-decreasing +with `n` (in expectation). For example, if `n = 1`, this estimator yields the +same result as `elbo_ratio`, and as `n` increases the expected value +of the estimator increases. + +#### Call signature + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_p`: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `q`: `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `alpha`: `Tensor` with shape `q.batch_shape` and values not equal to 1. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. The number of samples to use if `z` is not provided. + Note that this can be highly biased for small `n`, see docstring. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + +* `renyi_result`: The scaled log of sample mean. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + + +- - - + +### `tf.contrib.bayesflow.entropy.renyi_alpha(step, decay_time, alpha_min, alpha_max=0.99999, name='renyi_alpha')` {#renyi_alpha} + +Exponentially decaying `Tensor` appropriate for Renyi ratios. + +When minimizing the Renyi divergence for `0 <= alpha < 1` (or maximizing the +Renyi equivalent of elbo) in high dimensions, it is not uncommon to experience +`NaN` and `inf` values when `alpha` is far from `1`. + +For that reason, it is often desirable to start the optimization with `alpha` +very close to 1, and reduce it to a final `alpha_min` according to some +schedule. The user may even want to optimize using `elbo_ratio` for +some fixed time before switching to Renyi based methods. + +This `Op` returns an `alpha` decaying exponentially with step: + +``` +s(step) = (exp{step / decay_time} - 1) / (e - 1) +t(s) = max(0, min(s, 1)), (smooth growth from 0 to 1) +alpha(t) = (1 - t) alpha_min + t alpha_max +``` + +##### Args: + + +* `step`: Non-negative scalar `Tensor`. Typically the global step or an + offset version thereof. +* `decay_time`: Postive scalar `Tensor`. +* `alpha_min`: `float` or `double` `Tensor`. + The minimal, final value of `alpha`, achieved when `step >= decay_time` +* `alpha_max`: `Tensor` of same `dtype` as `alpha_min`. + The maximal, beginning value of `alpha`, achieved when `step == 0` +* `name`: A name to give this `Op`. + +##### Returns: + + +* `alpha`: A `Tensor` of same `dtype` as `alpha_min`. + + diff --git a/tensorflow/g3doc/api_docs/python/contrib.bayesflow.monte_carlo.md b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.monte_carlo.md new file mode 100644 index 0000000000000000000000000000000000000000..2b1ab42011c2e349d9c1f899b7ad107cf58e99f1 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.monte_carlo.md @@ -0,0 +1,179 @@ + + +# BayesFlow Monte Carlo (contrib) +[TOC] + +Monte Carlo integration and helpers. + +## Background + +Monte Carlo integration refers to the practice of estimating an expectation with +a sample mean. For example, given random variable `Z in R^k` with density `p`, +the expectation of function `f` can be approximated like: + +``` +E_p[f(Z)] = \int f(z) p(z) dz + ~ S_n + := n^{-1} \sum_{i=1}^n f(z_i), z_i iid samples from p. +``` + +If `E_p[|f(Z)|] < infinity`, then `S_n --> E_p[f(Z)]` by the strong law of large +numbers. If `E_p[f(Z)^2] < infinity`, then `S_n` is asymptotically normal with +variance `Var[f(Z)] / n`. + +Practicioners of Bayesian statistics often find themselves wanting to estimate +`E_p[f(Z)]` when the distribution `p` is known only up to a constant. For +example, the joint distribution `p(z, x)` may be known, but the evidence +`p(x) = \int p(z, x) dz` may be intractable. In that case, a parameterized +distribution family `q_lambda(z)` may be chosen, and the optimal `lambda` is the +one minimizing the KL divergence between `q_lambda(z)` and +`p(z | x)`. We only know `p(z, x)`, but that is sufficient to find `lambda`. + + +## Log-space evaluation and subtracting the maximum. + +Care must be taken when the random variable lives in a high dimensional space. +For example, the naive importance sample estimate `E_q[f(Z) p(Z) / q(Z)]` +involves the ratio of two terms `p(Z) / q(Z)`, each of which must have tails +dropping off faster than `O(|z|^{-(k + 1)})` in order to have finite integral. +This ratio would often be zero or infinity up to numerical precision. + +For that reason, we write + +``` +Log E_q[ f(Z) p(Z) / q(Z) ] + = Log E_q[ exp{Log[f(Z)] + Log[p(Z)] - Log[q(Z)] - C} ] + C, where +C := Max[ Log[f(Z)] + Log[p(Z)] - Log[q(Z)] ]. +``` + +The maximum value of the exponentiated term will be 0.0, and the the expecation +can be evaluated in a stable manner. + +## Ops + +- - - + +### `tf.contrib.bayesflow.monte_carlo.expectation(f, p, z=None, n=None, seed=None, name='expectation')` {#expectation} + +Monte Carlo estimate of an expectation: `E_p[f(Z)]` with sample mean. + +This `Op` returns + +``` +n^{-1} sum_{i=1}^n f(z_i), where z_i ~ p +\approx E_p[f(Z)] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `f` works "just like" `sampling_dist_q.log_prob`. +* `p`: `tf.contrib.distributions.BaseDistribution`. +* `z`: `Tensor` of samples from `p`, produced by `p.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + + +- - - + +### `tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler(f, log_p, sampling_dist_q, z=None, n=None, seed=None, name='expectation_importance_sampler')` {#expectation_importance_sampler} + +Monte Carlo estimate of `E_p[f(Z)] = E_q[f(Z) p(Z) / q(Z)]`. + +With `p(z) := exp{log_p(z)}`, this `Op` returns + +``` +n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ], z_i ~ q, +\approx E_q[ f(Z) p(Z) / q(Z) ] += E_p[f(Z)] +``` + +This integral is done in log-space with max-subtraction to better handle the +often extreme values that `f(z) p(z) / q(z)` can take on. + +If `f >= 0`, it is up to 2x more efficient to exponentiate the result of +`expectation_importance_sampler_logspace` applied to `Log[f]`. + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with shape + broadcastable to `q.batch_shape`. + For example, `f` works "just like" `q.log_prob`. +* `log_p`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `sampling_dist_q.log_prob`. +* `sampling_dist_q`: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + The importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + + +- - - + +### `tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler_logspace(log_f, log_p, sampling_dist_q, z=None, n=None, seed=None, name='expectation_importance_sampler_logspace')` {#expectation_importance_sampler_logspace} + +Importance sampling with a positive function, in log-space. + +With `p(z) := exp{log_p(z)}`, and `f(z) = exp{log_f(z)}`, this `Op` +returns + +``` +Log[ n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ] ], z_i ~ q, +\approx Log[ E_q[ f(Z) p(Z) / q(Z) ] ] += Log[E_p[f(Z)]] +``` + +This integral is done in log-space with max-subtraction to better handle the +often extreme values that `f(z) p(z) / q(z)` can take on. + +In contrast to `expectation_importance_sampler`, this `Op` returns values in +log-space. + + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_f` works "just like" `sampling_dist_q.log_prob`. +* `log_p`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `sampling_dist_q`: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + Logarithm of the importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + + diff --git a/tensorflow/g3doc/api_docs/python/contrib.bayesflow.stochastic_graph.md b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.stochastic_graph.md index 31b4c876eee4e58664106d33268977b4920bb045..903b86ab30f5eaa476649c9fa07d1af3ca46d24a 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.bayesflow.stochastic_graph.md +++ b/tensorflow/g3doc/api_docs/python/contrib.bayesflow.stochastic_graph.md @@ -109,7 +109,7 @@ reparameterized distributions; it will also return None if the value type is ##### Args: -* `dist_cls`: a class deriving from `BaseDistribution`. +* `dist_cls`: a `Distribution` class. * `name`: a name for this `DistributionTensor` and its ops. * `dist_value_type`: a `_StochasticValueType`, which will determine what the `value` of this `DistributionTensor` will be. If not provided, the @@ -123,6 +123,12 @@ reparameterized distributions; it will also return None if the value type is * `**dist_args`: keyword arguments to be passed through to `dist_cls` on construction. +##### Raises: + + +* `TypeError`: if `dist_cls` is not a `Distribution`. +* `TypeError`: if `loss_fn` is not `callable`. + - - - diff --git a/tensorflow/g3doc/api_docs/python/contrib.distributions.md b/tensorflow/g3doc/api_docs/python/contrib.distributions.md index e8c68402c1656a603f655a8f913448267f555e10..25a5a53141e8d0e76ab1e2da0c24d7a45281176a 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.distributions.md +++ b/tensorflow/g3doc/api_docs/python/contrib.distributions.md @@ -16,22 +16,25 @@ initialized with parameters that define the distributions. ### `class tf.contrib.distributions.Distribution` {#Distribution} -Fully-featured abstract base class for probability distributions. +A generic probability distribution base class. -This class defines the API for probability distributions. Users will only ever -instantiate subclasses of `Distribution`. +`Distribution` is a base class for constructing and organizing properties +(e.g., mean, variance) of random variables (e.g, Bernoulli, Gaussian). -### API +### Subclassing -The key methods for probability distributions are defined here. +Subclasess are expected to implement a leading-underscore version of the +same-named function. The argument signature should be identical except for +the omission of `name="..."`. For example, to enable `log_prob(value, +name="log_prob")` a subclass should implement `_log_prob(value)`. -To keep ops generated by the distribution tied together by name, subclasses -should override `name` and use it to prepend names of ops in other methods -(see `cdf` for an example). +Subclasses can rewrite/append to public-level docstrings. For example, -Subclasses that wish to support `cdf` and `log_cdf` can override `log_cdf` -and use the base class's implementation for `cdf`, or vice versa. The same -goes for `log_prob` and `prob`. +```python +Subclass.prob.__func__.__doc__ += "Some other details." +``` + +would add the string "Some other details." to the `prob` function docstring. ### Broadcasting, batching, and shapes @@ -120,16 +123,57 @@ dist.mean().eval() ``` - - - +#### `tf.contrib.distributions.Distribution.__init__(dtype=None, parameters=None, is_continuous=True, is_reparameterized=False, validate_args=True, allow_nan_stats=False, name=None)` {#Distribution.__init__} + +Constructs the `Distribution`. + +##### Args: + + +* `dtype`: The type of the event samples. `None` implies no type-enforcement. +* `parameters`: Python dictionary of parameters used by this `Distribution`. +* `is_continuous`: Python boolean, default `True`. If `True` this + `Distribution` is continuous over its supported domain. +* `is_reparameterized`: Python boolean, default `False`. If `True` this + `Distribution` can be reparameterized in terms of some standard + distribution with a function whose Jacobian is constant for the support + of the standard distribution. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. +* `allow_nan_stats`: Python boolean, default `False`. If `False`, raise an + exception if a statistic (e.g., mean, mode) is undefined for any batch + member. If True, batch members with valid parameters leading to + undefined statistics will return `NaN` for this statistic. +* `name`: A name for this distribution (optional). + + +- - - + #### `tf.contrib.distributions.Distribution.allow_nan_stats` {#Distribution.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Distribution.batch_shape(name='batch_shape')` {#Distribution.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -141,7 +185,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -150,26 +195,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Distribution.dtype` {#Distribution.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Distribution.entropy(name='entropy')` {#Distribution.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Distribution.event_shape(name='event_shape')` {#Distribution.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -178,7 +235,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -198,8 +256,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -242,19 +300,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Distribution.get_batch_shape()` {#Distribution.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. + - - - #### `tf.contrib.distributions.Distribution.get_event_shape()` {#Distribution.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -274,49 +342,107 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Distribution.log_cdf(value, name='log_cdf')` {#Distribution.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.log_pdf(value, name='log_pdf')` {#Distribution.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.log_pmf(value, name='log_pmf')` {#Distribution.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.log_prob(value, name='log_prob')` {#Distribution.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.mean(name='mean')` {#Distribution.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Distribution.mode(name='mode')` {#Distribution.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.Distribution.name` {#Distribution.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -361,48 +487,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Distribution.parameters` {#Distribution.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Distribution.pdf(value, name='pdf')` {#Distribution.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.pmf(value, name='pmf')` {#Distribution.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.prob(value, name='prob')` {#Distribution.prob} -Probability density/mass function. +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.sample(sample_shape=(), seed=None, name='sample')` {#Distribution.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -414,36 +592,41 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Distribution.std(name='std')` {#Distribution.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Distribution.validate_args` {#Distribution.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Distribution.variance(name='variance')` {#Distribution.variance} -Variance of the distribution. +Variance. @@ -550,14 +733,28 @@ dist = Binomial(n=[4., 5], p=[.1, .3]) #### `tf.contrib.distributions.Binomial.allow_nan_stats` {#Binomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Binomial.batch_shape(name='batch_shape')` {#Binomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -569,7 +766,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -578,26 +776,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Binomial.dtype` {#Binomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Binomial.entropy(name='entropy')` {#Binomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Binomial.event_shape(name='event_shape')` {#Binomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -606,7 +816,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -626,8 +837,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -670,26 +881,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Binomial.get_batch_shape()` {#Binomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Binomial.get_event_shape()` {#Binomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -710,46 +923,86 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Binomial.log_cdf(value, name='log_cdf')` {#Binomial.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Binomial.log_pdf(value, name='log_pdf')` {#Binomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Binomial.log_pmf(value, name='log_pmf')` {#Binomial.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -#### `tf.contrib.distributions.Binomial.log_prob(counts, name='log_prob')` {#Binomial.log_prob} +* `AttributeError`: if `is_continuous`. -`Log(P[counts])`, computed for every batch member. -For each batch member of counts `k`, `P[counts]` is the probability that -after sampling `n` draws from this Binomial distribution, the number of -successes is `k`. Note that different sequences of draws can result in the -same counts, thus the probability includes a combinatorial coefficient. +- - - + +#### `tf.contrib.distributions.Binomial.log_prob(value, name='log_prob')` {#Binomial.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -763,27 +1016,14 @@ Log-odds. #### `tf.contrib.distributions.Binomial.mean(name='mean')` {#Binomial.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Binomial.mode(name='mode')` {#Binomial.mode} -Mode of the distribution. - -Note that when `(n + 1) * p` is an integer, there are actually two modes. -Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return -only the larger of the two modes. - -##### Args: - - -* `name`: The name for this op. - -##### Returns: - - The mode of the Binomial distribution. +Mode. - - - @@ -797,7 +1037,7 @@ Number of trials. #### `tf.contrib.distributions.Binomial.name` {#Binomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -851,106 +1091,144 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Binomial.pdf(value, name='pdf')` {#Binomial.pdf} +#### `tf.contrib.distributions.Binomial.parameters` {#Binomial.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Binomial.pmf(value, name='pmf')` {#Binomial.pmf} - -The probability mass function. - +#### `tf.contrib.distributions.Binomial.pdf(value, name='pdf')` {#Binomial.pdf} -- - - +Probability density function. -#### `tf.contrib.distributions.Binomial.prob(counts, name='prob')` {#Binomial.prob} +##### Args: -`P[counts]`, computed for every batch member. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -For each batch member of counts `k`, `P[counts]` is the probability that -after sampling `n` draws from this Binomial distribution, the number of -successes is `k`. Note that different sequences of draws can result in the -same counts, thus the probability includes a combinatorial coefficient. +##### Returns: -##### Args: +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. -* `name`: Name to give this Op, defaults to "prob". +##### Raises: -##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Binomial.sample(sample_shape=(), seed=None, name='sample')` {#Binomial.sample} - -Generate samples of the specified shape for each batched distribution. +#### `tf.contrib.distributions.Binomial.pmf(value, name='pmf')` {#Binomial.pmf} -Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +Probability mass function. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. -* `seed`: Python integer seed for RNG -* `name`: name to give to the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Binomial.sample_n(n, seed=None, name='sample_n')` {#Binomial.sample_n} +#### `tf.contrib.distributions.Binomial.prob(value, name='prob')` {#Binomial.prob} -Generate `n` samples. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. -* `seed`: Python integer seed for RNG -* `name`: name to give to the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Binomial.std(name='std')` {#Binomial.std} +#### `tf.contrib.distributions.Binomial.sample(sample_shape=(), seed=None, name='sample')` {#Binomial.sample} -Standard deviation of the distribution. +Generate samples of the specified shape. + +Note that a call to `sample()` without arguments will generate a single +sample. + +##### Args: + + +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. + +##### Returns: + + +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. + + +- - - + +#### `tf.contrib.distributions.Binomial.sample_n(n, seed=None, name='sample_n')` {#Binomial.sample_n} + +Generate `n` samples. + +##### Args: + + +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. + +##### Returns: + + +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. + + +- - - + +#### `tf.contrib.distributions.Binomial.std(name='std')` {#Binomial.std} + +Standard deviation. - - - #### `tf.contrib.distributions.Binomial.validate_args` {#Binomial.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Binomial.variance(name='variance')` {#Binomial.variance} -Variance of the distribution. +Variance. @@ -997,14 +1275,41 @@ Construct Bernoulli distributions. #### `tf.contrib.distributions.Bernoulli.allow_nan_stats` {#Bernoulli.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Bernoulli.batch_shape(name='batch_shape')` {#Bernoulli.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + +* `batch_shape`: `Tensor`. - - - @@ -1013,36 +1318,48 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Bernoulli.dtype` {#Bernoulli.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Bernoulli.entropy(name='entropy')` {#Bernoulli.entropy} -Entropy of the distribution. - -##### Args: +Shanon entropy in nats. -* `name`: Name for the op. +- - - -##### Returns: +#### `tf.contrib.distributions.Bernoulli.event_shape(name='event_shape')` {#Bernoulli.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: `Tensor` of the same type and shape as `p`. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.Bernoulli.event_shape(name='event_shape')` {#Bernoulli.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -1062,8 +1379,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -1106,14 +1423,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Bernoulli.get_batch_shape()` {#Bernoulli.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Bernoulli.get_event_shape()` {#Bernoulli.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -1134,88 +1465,114 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Bernoulli.log_cdf(value, name='log_cdf')` {#Bernoulli.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Bernoulli.log_pdf(value, name='log_pdf')` {#Bernoulli.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -#### `tf.contrib.distributions.Bernoulli.log_pmf(value, name='log_pmf')` {#Bernoulli.log_pmf} -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.log_prob(event, name='log_prob')` {#Bernoulli.log_prob} +#### `tf.contrib.distributions.Bernoulli.log_pmf(value, name='log_pmf')` {#Bernoulli.log_pmf} -Log of the probability mass function. +Log probability mass function. ##### Args: -* `event`: `int32` or `int64` binary Tensor. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the events. - -- - - +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.Bernoulli.logits` {#Bernoulli.logits} +##### Raises: +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.mean(name='mean')` {#Bernoulli.mean} +#### `tf.contrib.distributions.Bernoulli.log_prob(value, name='log_prob')` {#Bernoulli.log_prob} -Mean of the distribution. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: Name for the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `mean`: `Tensor` of the same type and shape as `p`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Bernoulli.mode(name='mode')` {#Bernoulli.mode} +#### `tf.contrib.distributions.Bernoulli.logits` {#Bernoulli.logits} -Mode of the distribution. -1 if p > 1-p. 0 otherwise. -##### Args: +- - - + +#### `tf.contrib.distributions.Bernoulli.mean(name='mean')` {#Bernoulli.mean} + +Mean. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Bernoulli.mode(name='mode')` {#Bernoulli.mode} -* `mode`: binary `Tensor` of type self.dtype. +Mode. - - - #### `tf.contrib.distributions.Bernoulli.name` {#Bernoulli.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -1267,35 +1624,78 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Bernoulli.parameters` {#Bernoulli.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Bernoulli.pdf(value, name='pdf')` {#Bernoulli.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Bernoulli.pmf(value, name='pmf')` {#Bernoulli.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.prob(event, name='prob')` {#Bernoulli.prob} +#### `tf.contrib.distributions.Bernoulli.prob(value, name='prob')` {#Bernoulli.prob} -Probability mass function. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `event`: `int32` or `int64` binary Tensor; must be broadcastable with `p`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the events. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -1309,23 +1709,22 @@ Probability mass function. #### `tf.contrib.distributions.Bernoulli.sample(sample_shape=(), seed=None, name='sample')` {#Bernoulli.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -1337,56 +1736,41 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. -* `seed`: Python integer seed for RNG. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape` with values of type - `self.dtype`. - - -- - - - -#### `tf.contrib.distributions.Bernoulli.std(name='std')` {#Bernoulli.std} +* `samples`: a `Tensor` with a prepended dimension (n,). -Standard deviation of the distribution. +##### Raises: -##### Args: +* `TypeError`: if `n` is not an integer type. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Bernoulli.std(name='std')` {#Bernoulli.std} -* `std`: `Tensor` of the same type and shape as `p`. +Standard deviation. - - - #### `tf.contrib.distributions.Bernoulli.validate_args` {#Bernoulli.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Bernoulli.variance(name='variance')` {#Bernoulli.variance} -Variance of the distribution. - -##### Args: - - -* `name`: Name for the op. - -##### Returns: - - -* `variance`: `Tensor` of the same type and shape as `p`. +Variance. @@ -1498,11 +1882,32 @@ dist = Beta([1.0, 2.0], [4.0, 5.0]) Shape parameter. +- - - + +#### `tf.contrib.distributions.Beta.a_b_sum` {#Beta.a_b_sum} + +Sum of parameters. + + - - - #### `tf.contrib.distributions.Beta.allow_nan_stats` {#Beta.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -1516,7 +1921,7 @@ Shape parameter. #### `tf.contrib.distributions.Beta.batch_shape(name='batch_shape')` {#Beta.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -1528,35 +1933,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Beta.cdf(x, name='cdf')` {#Beta.cdf} +#### `tf.contrib.distributions.Beta.cdf(value, name='cdf')` {#Beta.cdf} Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Beta.dtype` {#Beta.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Beta.entropy(name='entropy')` {#Beta.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Beta.event_shape(name='event_shape')` {#Beta.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -1565,7 +1983,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -1585,8 +2004,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -1629,26 +2048,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Beta.get_batch_shape()` {#Beta.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Beta.get_event_shape()` {#Beta.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -1667,100 +2088,130 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Beta.log_cdf(x, name='log_cdf')` {#Beta.log_cdf} +#### `tf.contrib.distributions.Beta.log_cdf(value, name='log_cdf')` {#Beta.log_cdf} -Log CDF. +Log cumulative distribution function. +##### Args: -- - - - -#### `tf.contrib.distributions.Beta.log_pdf(value, name='log_pdf')` {#Beta.log_pdf} - -Log of the probability density function. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -- - - +##### Returns: -#### `tf.contrib.distributions.Beta.log_pmf(value, name='log_pmf')` {#Beta.log_pmf} -Log of the probability mass function. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Beta.log_prob(x, name='log_prob')` {#Beta.log_prob} +#### `tf.contrib.distributions.Beta.log_pdf(value, name='log_pdf')` {#Beta.log_pdf} -`Log(P[counts])`, computed for every batch member. +Log probability density function. ##### Args: -* `x`: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents counts for the corresponding - Beta distribution in `self.a` and `self.b`. `x` is only legal if - 0 < x < 1. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Beta.mean(name='mean')` {#Beta.mean} -Mean of the distribution. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.mode(name='mode')` {#Beta.mode} - -Mode of the distribution. +#### `tf.contrib.distributions.Beta.log_pmf(value, name='log_pmf')` {#Beta.log_pmf} -Note that the mode for the Beta distribution is only defined -when `a > 1`, `b > 1`. This returns the mode when `a > 1` and `b > 1`, -and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. +Log probability mass function. ##### Args: -* `name`: The name for this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Mode of the Beta distribution. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Beta.name` {#Beta.name} -Name to prepend to all ops. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.param_shapes(cls, sample_shape, name='DistributionParamShapes')` {#Beta.param_shapes} - -Shapes of parameters given the desired shape of a call to `sample()`. +#### `tf.contrib.distributions.Beta.log_prob(value, name='log_prob')` {#Beta.log_prob} -Subclasses should override static method `_param_shapes`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `sample_shape`: `Tensor` or python list/tuple. Desired shape of a call to - `sample()`. -* `name`: name to prepend ops with. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - `dict` of parameter name to `Tensor` shapes. - + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + +- - - + +#### `tf.contrib.distributions.Beta.mean(name='mean')` {#Beta.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Beta.mode(name='mode')` {#Beta.mode} + +Mode. + + +- - - + +#### `tf.contrib.distributions.Beta.name` {#Beta.name} + +Name prepended to all ops created by this `Distribution`. + + +- - - + +#### `tf.contrib.distributions.Beta.param_shapes(cls, sample_shape, name='DistributionParamShapes')` {#Beta.param_shapes} + +Shapes of parameters given the desired shape of a call to `sample()`. + +Subclasses should override static method `_param_shapes`. + +##### Args: + + +* `sample_shape`: `Tensor` or python list/tuple. Desired shape of a call to + `sample()`. +* `name`: name to prepend ops with. + +##### Returns: + + `dict` of parameter name to `Tensor` shapes. + - - - @@ -1784,103 +2235,146 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Beta.parameters` {#Beta.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Beta.pdf(value, name='pdf')` {#Beta.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Beta.pmf(value, name='pmf')` {#Beta.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.prob(x, name='prob')` {#Beta.prob} +#### `tf.contrib.distributions.Beta.prob(value, name='prob')` {#Beta.prob} -`P[x]`, computed for every batch member. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents x for the corresponding Beta - distribution in `self.a` and `self.b`. `x` is only legal if is - between 0 and 1. -* `name`: Name to give this Op, defaults to "pdf". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Beta.sample(sample_shape=(), seed=None, name='sample')` {#Beta.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Beta.sample_n(n, seed=None, name='sample_n')` {#Beta.sample_n} -Sample `n` observations from the Beta Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Beta.std(name='std')` {#Beta.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Beta.validate_args` {#Beta.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Beta.variance(name='variance')` {#Beta.variance} -Variance of the distribution. +Variance. @@ -1918,14 +2412,41 @@ Initialize Categorical distributions using class log-probabilities. #### `tf.contrib.distributions.Categorical.allow_nan_stats` {#Categorical.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Categorical.batch_shape(name='batch_shape')` {#Categorical.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + +* `batch_shape`: `Tensor`. - - - @@ -1934,27 +2455,49 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: -- - - -#### `tf.contrib.distributions.Categorical.dtype` {#Categorical.dtype} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Categorical.entropy(name='sample')` {#Categorical.entropy} +#### `tf.contrib.distributions.Categorical.dtype` {#Categorical.dtype} + +The `DType` of `Tensor`s handled by this `Distribution`. + + +- - - +#### `tf.contrib.distributions.Categorical.entropy(name='entropy')` {#Categorical.entropy} +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Categorical.event_shape(name='event_shape')` {#Categorical.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: +* `event_shape`: `Tensor`. + - - - @@ -1973,8 +2516,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -2017,14 +2560,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Categorical.get_batch_shape()` {#Categorical.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Categorical.get_event_shape()` {#Categorical.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -2045,39 +2602,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Categorical.log_cdf(value, name='log_cdf')` {#Categorical.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Categorical.log_pdf(value, name='log_pdf')` {#Categorical.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Categorical.log_pmf(value, name='log_pmf')` {#Categorical.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Categorical.log_prob(k, name='log_prob')` {#Categorical.log_prob} +#### `tf.contrib.distributions.Categorical.log_prob(value, name='log_prob')` {#Categorical.log_prob} -Log-probability of class `k`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `k`: `int32` or `int64` Tensor. Must be broadcastable with a `batch_shape` - `Tensor`. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the classes indexed by `k` + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -2091,21 +2695,21 @@ Log-probability of class `k`. #### `tf.contrib.distributions.Categorical.mean(name='mean')` {#Categorical.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Categorical.mode(name='mode')` {#Categorical.mode} - +Mode. - - - #### `tf.contrib.distributions.Categorical.name` {#Categorical.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -2157,97 +2761,146 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Categorical.parameters` {#Categorical.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Categorical.pdf(value, name='pdf')` {#Categorical.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Categorical.pmf(value, name='pmf')` {#Categorical.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Categorical.prob(k, name='prob')` {#Categorical.prob} +#### `tf.contrib.distributions.Categorical.prob(value, name='prob')` {#Categorical.prob} -Probability of class `k`. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `k`: `int32` or `int64` Tensor. Must be broadcastable with logits. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the classes indexed by `k` + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Categorical.sample(sample_shape=(), seed=None, name='sample')` {#Categorical.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Categorical.sample_n(n, seed=None, name='sample_n')` {#Categorical.sample_n} -Sample `n` observations from the Categorical distribution. +Generate `n` samples. ##### Args: -* `n`: 0-D. Number of independent samples to draw for each distribution. -* `seed`: Random seed (optional). -* `name`: A name for this operation (optional). +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: - An `int64` `Tensor` with shape `[n, batch_shape, event_shape]` + +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Categorical.std(name='std')` {#Categorical.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Categorical.validate_args` {#Categorical.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Categorical.variance(name='variance')` {#Categorical.variance} -Variance of the distribution. +Variance. @@ -2288,7 +2941,21 @@ Construct Chi2 distributions with parameter `df`. #### `tf.contrib.distributions.Chi2.allow_nan_stats` {#Chi2.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -2302,7 +2969,7 @@ Shape parameter. #### `tf.contrib.distributions.Chi2.batch_shape(name='batch_shape')` {#Chi2.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -2314,7 +2981,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -2326,20 +2994,21 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Chi2.cdf(x, name='cdf')` {#Chi2.cdf} +#### `tf.contrib.distributions.Chi2.cdf(value, name='cdf')` {#Chi2.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -2353,40 +3022,21 @@ CDF of observations `x` under these Gamma distribution(s). #### `tf.contrib.distributions.Chi2.dtype` {#Chi2.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Chi2.entropy(name='entropy')` {#Chi2.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Chi2.event_shape(name='event_shape')` {#Chi2.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -2395,7 +3045,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -2415,8 +3066,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -2459,26 +3110,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Chi2.get_batch_shape()` {#Chi2.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Chi2.get_event_shape()` {#Chi2.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -2497,91 +3150,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Chi2.log_cdf(x, name='log_cdf')` {#Chi2.log_cdf} +#### `tf.contrib.distributions.Chi2.log_cdf(value, name='log_cdf')` {#Chi2.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Chi2.log_pdf(value, name='log_pdf')` {#Chi2.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -#### `tf.contrib.distributions.Chi2.log_pmf(value, name='log_pmf')` {#Chi2.log_pmf} -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.log_prob(x, name='log_prob')` {#Chi2.log_prob} +#### `tf.contrib.distributions.Chi2.log_pmf(value, name='log_pmf')` {#Chi2.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.mean(name='mean')` {#Chi2.mean} +#### `tf.contrib.distributions.Chi2.log_prob(value, name='log_prob')` {#Chi2.log_prob} -Mean of each batch member. +Log probability density/mass function (depending on `is_continuous`). +##### Args: -- - - -#### `tf.contrib.distributions.Chi2.mode(name='mode')` {#Chi2.mode} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Mode of each batch member. +##### Returns: -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. -##### Args: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Chi2.mean(name='mean')` {#Chi2.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Chi2.mode(name='mode')` {#Chi2.mode} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mode. - - - #### `tf.contrib.distributions.Chi2.name` {#Chi2.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -2628,106 +3299,144 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Chi2.pdf(value, name='pdf')` {#Chi2.pdf} +#### `tf.contrib.distributions.Chi2.parameters` {#Chi2.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Chi2.pmf(value, name='pmf')` {#Chi2.pmf} +#### `tf.contrib.distributions.Chi2.pdf(value, name='pdf')` {#Chi2.pdf} -The probability mass function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.prob(x, name='prob')` {#Chi2.prob} +#### `tf.contrib.distributions.Chi2.pmf(value, name='pmf')` {#Chi2.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Chi2.prob(value, name='prob')` {#Chi2.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Chi2.sample(sample_shape=(), seed=None, name='sample')` {#Chi2.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Chi2.sample_n(n, seed=None, name='sample_n')` {#Chi2.sample_n} -Draws `n` samples from the Gamma distribution(s). - -See the doc for tf.random_gamma for further detail. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Chi2.std(name='std')` {#Chi2.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Chi2.validate_args` {#Chi2.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Chi2.variance(name='variance')` {#Chi2.variance} -Variance of each batch member. +Variance. @@ -2768,7 +3477,21 @@ Construct Exponential distribution with parameter `lam`. #### `tf.contrib.distributions.Exponential.allow_nan_stats` {#Exponential.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -2782,7 +3505,7 @@ Shape parameter. #### `tf.contrib.distributions.Exponential.batch_shape(name='batch_shape')` {#Exponential.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -2794,7 +3517,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -2806,60 +3530,42 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Exponential.cdf(x, name='cdf')` {#Exponential.cdf} +#### `tf.contrib.distributions.Exponential.cdf(value, name='cdf')` {#Exponential.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.dtype` {#Exponential.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Exponential.entropy(name='entropy')` {#Exponential.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Exponential.event_shape(name='event_shape')` {#Exponential.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -2868,7 +3574,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -2888,8 +3595,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -2932,26 +3639,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Exponential.get_batch_shape()` {#Exponential.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Exponential.get_event_shape()` {#Exponential.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -2977,91 +3686,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Exponential.log_cdf(x, name='log_cdf')` {#Exponential.log_cdf} +#### `tf.contrib.distributions.Exponential.log_cdf(value, name='log_cdf')` {#Exponential.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.log_pdf(value, name='log_pdf')` {#Exponential.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Exponential.log_pmf(value, name='log_pmf')` {#Exponential.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.log_prob(x, name='log_prob')` {#Exponential.log_prob} +#### `tf.contrib.distributions.Exponential.log_pmf(value, name='log_pmf')` {#Exponential.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.mean(name='mean')` {#Exponential.mean} +#### `tf.contrib.distributions.Exponential.log_prob(value, name='log_prob')` {#Exponential.log_prob} -Mean of each batch member. +Log probability density/mass function (depending on `is_continuous`). +##### Args: -- - - -#### `tf.contrib.distributions.Exponential.mode(name='mode')` {#Exponential.mode} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Mode of each batch member. +##### Returns: -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. -##### Args: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Exponential.mean(name='mean')` {#Exponential.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Exponential.mode(name='mode')` {#Exponential.mode} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mode. - - - #### `tf.contrib.distributions.Exponential.name` {#Exponential.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -3108,103 +3835,144 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Exponential.pdf(value, name='pdf')` {#Exponential.pdf} +#### `tf.contrib.distributions.Exponential.parameters` {#Exponential.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Exponential.pmf(value, name='pmf')` {#Exponential.pmf} +#### `tf.contrib.distributions.Exponential.pdf(value, name='pdf')` {#Exponential.pdf} + +Probability density function. + +##### Args: + -The probability mass function. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.prob(x, name='prob')` {#Exponential.prob} +#### `tf.contrib.distributions.Exponential.pmf(value, name='pmf')` {#Exponential.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Exponential.prob(value, name='prob')` {#Exponential.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.sample(sample_shape=(), seed=None, name='sample')` {#Exponential.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Exponential.sample_n(n, seed=None, name='sample_n')` {#Exponential.sample_n} -Sample `n` observations from the Exponential Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Exponential.std(name='std')` {#Exponential.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Exponential.validate_args` {#Exponential.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Exponential.variance(name='variance')` {#Exponential.variance} -Variance of each batch member. +Variance. @@ -3269,7 +4037,21 @@ broadcasting (e.g. `alpha + beta` is a valid operation). #### `tf.contrib.distributions.Gamma.allow_nan_stats` {#Gamma.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -3283,7 +4065,7 @@ Shape parameter. #### `tf.contrib.distributions.Gamma.batch_shape(name='batch_shape')` {#Gamma.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -3295,7 +4077,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -3307,60 +4090,42 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Gamma.cdf(x, name='cdf')` {#Gamma.cdf} +#### `tf.contrib.distributions.Gamma.cdf(value, name='cdf')` {#Gamma.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.dtype` {#Gamma.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Gamma.entropy(name='entropy')` {#Gamma.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Gamma.event_shape(name='event_shape')` {#Gamma.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -3369,7 +4134,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -3389,8 +4155,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -3433,26 +4199,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Gamma.get_batch_shape()` {#Gamma.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Gamma.get_event_shape()` {#Gamma.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -3471,91 +4239,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Gamma.log_cdf(x, name='log_cdf')` {#Gamma.log_cdf} +#### `tf.contrib.distributions.Gamma.log_cdf(value, name='log_cdf')` {#Gamma.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.log_pdf(value, name='log_pdf')` {#Gamma.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Gamma.log_pmf(value, name='log_pmf')` {#Gamma.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -Log of the probability mass function. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Gamma.log_prob(x, name='log_prob')` {#Gamma.log_prob} +#### `tf.contrib.distributions.Gamma.log_pmf(value, name='log_pmf')` {#Gamma.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Gamma.log_prob(value, name='log_prob')` {#Gamma.log_prob} + +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.mean(name='mean')` {#Gamma.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.Gamma.mode(name='mode')` {#Gamma.mode} -Mode of each batch member. - -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. - -##### Args: - - -* `name`: A name to give this op. - -##### Returns: - - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mode. - - - #### `tf.contrib.distributions.Gamma.name` {#Gamma.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -3602,106 +4388,144 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Gamma.pdf(value, name='pdf')` {#Gamma.pdf} +#### `tf.contrib.distributions.Gamma.parameters` {#Gamma.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Gamma.pmf(value, name='pmf')` {#Gamma.pmf} +#### `tf.contrib.distributions.Gamma.pdf(value, name='pdf')` {#Gamma.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -The probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Gamma.prob(x, name='prob')` {#Gamma.prob} +#### `tf.contrib.distributions.Gamma.pmf(value, name='pmf')` {#Gamma.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Gamma.prob(value, name='prob')` {#Gamma.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.sample(sample_shape=(), seed=None, name='sample')` {#Gamma.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Gamma.sample_n(n, seed=None, name='sample_n')` {#Gamma.sample_n} -Draws `n` samples from the Gamma distribution(s). - -See the doc for tf.random_gamma for further detail. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Gamma.std(name='std')` {#Gamma.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Gamma.validate_args` {#Gamma.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Gamma.variance(name='variance')` {#Gamma.variance} -Variance of each batch member. +Variance. @@ -3765,7 +4589,21 @@ broadcasting (e.g. `alpha + beta` is a valid operation). #### `tf.contrib.distributions.InverseGamma.allow_nan_stats` {#InverseGamma.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -3779,7 +4617,7 @@ Shape parameter. #### `tf.contrib.distributions.InverseGamma.batch_shape(name='batch_shape')` {#InverseGamma.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -3791,7 +4629,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -3803,60 +4642,42 @@ Scale parameter. - - - -#### `tf.contrib.distributions.InverseGamma.cdf(x, name='cdf')` {#InverseGamma.cdf} +#### `tf.contrib.distributions.InverseGamma.cdf(value, name='cdf')` {#InverseGamma.cdf} -CDF of observations `x` under these InverseGamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.dtype` {#InverseGamma.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.InverseGamma.entropy(name='entropy')` {#InverseGamma.entropy} -The entropy of these InverseGamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.InverseGamma.event_shape(name='event_shape')` {#InverseGamma.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -3865,7 +4686,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -3885,8 +4707,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -3929,26 +4751,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.InverseGamma.get_batch_shape()` {#InverseGamma.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.InverseGamma.get_event_shape()` {#InverseGamma.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -3967,102 +4791,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.InverseGamma.log_cdf(x, name='log_cdf')` {#InverseGamma.log_cdf} +#### `tf.contrib.distributions.InverseGamma.log_cdf(value, name='log_cdf')` {#InverseGamma.log_cdf} -Log CDF of observations `x` under these InverseGamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.log_pdf(value, name='log_pdf')` {#InverseGamma.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.InverseGamma.log_pmf(value, name='log_pmf')` {#InverseGamma.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -Log of the probability mass function. + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.log_prob(x, name='log_prob')` {#InverseGamma.log_prob} +#### `tf.contrib.distributions.InverseGamma.log_pmf(value, name='log_pmf')` {#InverseGamma.log_pmf} -Log prob of observations in `x` under these InverseGamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.mean(name='mean')` {#InverseGamma.mean} - -Mean of each batch member. +#### `tf.contrib.distributions.InverseGamma.log_prob(value, name='log_prob')` {#InverseGamma.log_prob} -The mean of an inverse gamma distribution is `beta / (alpha - 1)`, -when `alpha > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is -`False`, an exception will be raised rather than returning `NaN` +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: A name to give this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. - -- - - +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.InverseGamma.mode(name='mode')` {#InverseGamma.mode} -Mode of each batch member. +- - - -The mode of an inverse gamma distribution is `beta / (alpha + 1)`. +#### `tf.contrib.distributions.InverseGamma.mean(name='mean')` {#InverseGamma.mean} -##### Args: +Mean. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.InverseGamma.mode(name='mode')` {#InverseGamma.mode} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mode. - - - #### `tf.contrib.distributions.InverseGamma.name` {#InverseGamma.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -4109,119 +4940,144 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.InverseGamma.pdf(value, name='pdf')` {#InverseGamma.pdf} +#### `tf.contrib.distributions.InverseGamma.parameters` {#InverseGamma.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.InverseGamma.pmf(value, name='pmf')` {#InverseGamma.pmf} +#### `tf.contrib.distributions.InverseGamma.pdf(value, name='pdf')` {#InverseGamma.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -The probability mass function. + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.prob(x, name='prob')` {#InverseGamma.prob} +#### `tf.contrib.distributions.InverseGamma.pmf(value, name='pmf')` {#InverseGamma.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.InverseGamma.prob(value, name='prob')` {#InverseGamma.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.sample(sample_shape=(), seed=None, name='sample')` {#InverseGamma.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.InverseGamma.sample_n(n, seed=None, name='sample_n')` {#InverseGamma.sample_n} -Draws `n` samples from these InverseGamma distribution(s). - -See the doc for tf.random_gamma for further details on sampling strategy. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.InverseGamma.std(name='std')` {#InverseGamma.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.InverseGamma.validate_args` {#InverseGamma.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.InverseGamma.variance(name='variance')` {#InverseGamma.variance} -Variance of each batch member. - -Variance for inverse gamma is defined only for `alpha > 2`. If -`self.allow_nan_stats` is `False`, an exception will be raised rather -than returning `NaN`. - -##### Args: - - -* `name`: A name to give this op. - -##### Returns: - - The variance for every batch member, a `Tensor` with same `dtype` as self. +Variance. @@ -4274,14 +5130,28 @@ broadcasting (e.g., `loc / scale` is a valid operation). #### `tf.contrib.distributions.Laplace.allow_nan_stats` {#Laplace.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Laplace.batch_shape(name='batch_shape')` {#Laplace.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -4289,69 +5159,62 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Laplace.cdf(x, name='cdf')` {#Laplace.cdf} +#### `tf.contrib.distributions.Laplace.cdf(value, name='cdf')` {#Laplace.cdf} -CDF of observations in `x` under the Laplace distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.dtype` {#Laplace.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Laplace.entropy(name='entropy')` {#Laplace.entropy} -The entropy of Laplace distribution(s). - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Laplace.event_shape(name='event_shape')` {#Laplace.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -4371,8 +5234,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -4415,26 +5278,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Laplace.get_batch_shape()` {#Laplace.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Laplace.get_event_shape()` {#Laplace.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -4460,80 +5325,109 @@ Distribution parameter for the location. - - - -#### `tf.contrib.distributions.Laplace.log_cdf(x, name='log_cdf')` {#Laplace.log_cdf} +#### `tf.contrib.distributions.Laplace.log_cdf(value, name='log_cdf')` {#Laplace.log_cdf} -Log CDF of observations `x` under the Laplace distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.log_pdf(value, name='log_pdf')` {#Laplace.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -#### `tf.contrib.distributions.Laplace.log_pmf(value, name='log_pmf')` {#Laplace.log_pmf} -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.log_prob(x, name='log_prob')` {#Laplace.log_prob} +#### `tf.contrib.distributions.Laplace.log_pmf(value, name='log_pmf')` {#Laplace.log_pmf} -Log prob of observations in `x` under these Laplace distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-probability of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.mean(name='mean')` {#Laplace.mean} +#### `tf.contrib.distributions.Laplace.log_prob(value, name='log_prob')` {#Laplace.log_prob} + +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -Mean of this distribution. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Laplace.median(name='median')` {#Laplace.median} +#### `tf.contrib.distributions.Laplace.mean(name='mean')` {#Laplace.mean} -Median of this distribution. +Mean. - - - #### `tf.contrib.distributions.Laplace.mode(name='mode')` {#Laplace.mode} -Mode of this distribution. +Mode. - - - #### `tf.contrib.distributions.Laplace.name` {#Laplace.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -4560,97 +5454,143 @@ Subclasses should override static method `_param_shapes`. #### `tf.contrib.distributions.Laplace.param_static_shapes(cls, sample_shape)` {#Laplace.param_static_shapes} -param_shapes with static (i.e. TensorShape) shapes. +param_shapes with static (i.e. TensorShape) shapes. + +##### Args: + + +* `sample_shape`: `TensorShape` or python list/tuple. Desired shape of a call + to `sample()`. + +##### Returns: + + `dict` of parameter name to `TensorShape`. + +##### Raises: + + +* `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. + + +- - - + +#### `tf.contrib.distributions.Laplace.parameters` {#Laplace.parameters} + +Dictionary of parameters used by this `Distribution`. + + +- - - + +#### `tf.contrib.distributions.Laplace.pdf(value, name='pdf')` {#Laplace.pdf} + +Probability density function. ##### Args: -* `sample_shape`: `TensorShape` or python list/tuple. Desired shape of a call - to `sample()`. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - `dict` of parameter name to `TensorShape`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.pdf(value, name='pdf')` {#Laplace.pdf} +#### `tf.contrib.distributions.Laplace.pmf(value, name='pmf')` {#Laplace.pmf} + +Probability mass function. -The probability density function. +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.Laplace.pmf(value, name='pmf')` {#Laplace.pmf} +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -The probability mass function. + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.prob(x, name='pdf')` {#Laplace.prob} +#### `tf.contrib.distributions.Laplace.prob(value, name='prob')` {#Laplace.prob} -The prob of observations in `x` under the Laplace distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `pdf`: tensor of dtype `dtype`, the pdf values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.sample(sample_shape=(), seed=None, name='sample')` {#Laplace.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Laplace.sample_n(n, seed=None, name='sample_n')` {#Laplace.sample_n} -Sample `n` observations from the Laplace Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the parameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -4664,21 +5604,21 @@ Distribution parameter for scale. #### `tf.contrib.distributions.Laplace.std(name='std')` {#Laplace.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Laplace.validate_args` {#Laplace.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Laplace.variance(name='variance')` {#Laplace.variance} -Variance of this distribution. +Variance. @@ -4761,14 +5701,28 @@ broadcasting (e.g. `mu + sigma` is a valid operation). #### `tf.contrib.distributions.Normal.allow_nan_stats` {#Normal.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Normal.batch_shape(name='batch_shape')` {#Normal.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -4776,69 +5730,62 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Normal.cdf(x, name='cdf')` {#Normal.cdf} +#### `tf.contrib.distributions.Normal.cdf(value, name='cdf')` {#Normal.cdf} -CDF of observations in `x` under these Normal distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.dtype` {#Normal.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Normal.entropy(name='entropy')` {#Normal.entropy} -The entropy of Normal distribution(s). - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Normal.event_shape(name='event_shape')` {#Normal.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -4858,8 +5805,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -4902,26 +5849,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Normal.get_batch_shape()` {#Normal.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Normal.get_event_shape()` {#Normal.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -4940,66 +5889,102 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Normal.log_cdf(x, name='log_cdf')` {#Normal.log_cdf} +#### `tf.contrib.distributions.Normal.log_cdf(value, name='log_cdf')` {#Normal.log_cdf} -Log CDF of observations `x` under these Normal distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.log_pdf(value, name='log_pdf')` {#Normal.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Normal.log_pmf(value, name='log_pmf')` {#Normal.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Normal.log_prob(x, name='log_prob')` {#Normal.log_prob} +#### `tf.contrib.distributions.Normal.log_prob(value, name='log_prob')` {#Normal.log_prob} -Log prob of observations in `x` under these Normal distribution(s). +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.mean(name='mean')` {#Normal.mean} -Mean of this distribution. +Mean. - - - #### `tf.contrib.distributions.Normal.mode(name='mode')` {#Normal.mode} -Mode of this distribution. +Mode. - - - @@ -5013,7 +5998,7 @@ Distribution parameter for the mean. #### `tf.contrib.distributions.Normal.name` {#Normal.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -5058,79 +6043,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Normal.parameters` {#Normal.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Normal.pdf(value, name='pdf')` {#Normal.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Normal.pmf(value, name='pmf')` {#Normal.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Normal.prob(x, name='prob')` {#Normal.prob} +#### `tf.contrib.distributions.Normal.prob(value, name='prob')` {#Normal.prob} -The PDF of observations in `x` under these Normal distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.sample(sample_shape=(), seed=None, name='sample')` {#Normal.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Normal.sample_n(n, seed=None, name='sample_n')` {#Normal.sample_n} -Sample `n` observations from the Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -5144,21 +6175,21 @@ Distribution parameter for standard deviation. #### `tf.contrib.distributions.Normal.std(name='std')` {#Normal.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Normal.validate_args` {#Normal.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Normal.variance(name='variance')` {#Normal.variance} -Variance of this distribution. +Variance. @@ -5202,53 +6233,91 @@ Construct Poisson distributions. #### `tf.contrib.distributions.Poisson.allow_nan_stats` {#Poisson.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Poisson.batch_shape(name='batch_shape')` {#Poisson.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Poisson.cdf(x, name='cdf')` {#Poisson.cdf} +#### `tf.contrib.distributions.Poisson.cdf(value, name='cdf')` {#Poisson.cdf} -Cumulative density function. +Cumulative distribution function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The CDF of the events. + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Poisson.dtype` {#Poisson.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Poisson.entropy(name='entropy')` {#Poisson.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Poisson.event_shape(name='event_shape')` {#Poisson.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + +* `event_shape`: `Tensor`. - - - @@ -5268,8 +6337,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -5312,15 +6381,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Poisson.get_batch_shape()` {#Poisson.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Poisson.get_event_shape()` {#Poisson.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -5345,98 +6428,109 @@ Rate parameter. - - - -#### `tf.contrib.distributions.Poisson.log_cdf(x, name='log_cdf')` {#Poisson.log_cdf} +#### `tf.contrib.distributions.Poisson.log_cdf(value, name='log_cdf')` {#Poisson.log_cdf} -Log cumulative density function. +Log cumulative distribution function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The Log CDF of the events. + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Poisson.log_pdf(value, name='log_pdf')` {#Poisson.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Poisson.log_pmf(value, name='log_pmf')` {#Poisson.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -Log of the probability mass function. + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.log_prob(x, name='log_prob')` {#Poisson.log_prob} +#### `tf.contrib.distributions.Poisson.log_pmf(value, name='log_pmf')` {#Poisson.log_pmf} Log probability mass function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the events. + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.mean(name='mean')` {#Poisson.mean} +#### `tf.contrib.distributions.Poisson.log_prob(value, name='log_prob')` {#Poisson.log_prob} -Mean of the distribution. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: Name for the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `mean`: `Tensor` of the same type and shape as `lam`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Poisson.mode(name='mode')` {#Poisson.mode} - -Mode of the distribution. - -Note that when `lam` is an integer, there are actually two modes. -Namely, `lam` and `lam - 1` are both modes. Here we return -only the larger of the two modes. - -##### Args: +#### `tf.contrib.distributions.Poisson.mean(name='mean')` {#Poisson.mean} +Mean. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Poisson.mode(name='mode')` {#Poisson.mode} -* `mode`: `Tensor` of the same type and shape as `lam`. +Mode. - - - #### `tf.contrib.distributions.Poisson.name` {#Poisson.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -5481,60 +6575,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Poisson.parameters` {#Poisson.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Poisson.pdf(value, name='pdf')` {#Poisson.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Poisson.pmf(value, name='pmf')` {#Poisson.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.prob(x, name='prob')` {#Poisson.prob} +#### `tf.contrib.distributions.Poisson.prob(value, name='prob')` {#Poisson.prob} -Probability mass function. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the events. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Poisson.sample(sample_shape=(), seed=None, name='sample')` {#Poisson.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -5546,56 +6680,41 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - - -- - - - -#### `tf.contrib.distributions.Poisson.std(name='std')` {#Poisson.std} +* `samples`: a `Tensor` with a prepended dimension (n,). -Standard deviation of the distribution. +##### Raises: -##### Args: +* `TypeError`: if `n` is not an integer type. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Poisson.std(name='std')` {#Poisson.std} -* `std`: `Tensor` of the same type and shape as `lam`. +Standard deviation. - - - #### `tf.contrib.distributions.Poisson.validate_args` {#Poisson.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Poisson.variance(name='variance')` {#Poisson.variance} -Variance of the distribution. - -##### Args: - - -* `name`: Name for the op. - -##### Returns: - - -* `variance`: `Tensor` of the same type and shape as `lam`. +Variance. @@ -5687,15 +6806,42 @@ broadcasting (e.g. `df + mu + sigma` is a valid operation). #### `tf.contrib.distributions.StudentT.allow_nan_stats` {#StudentT.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.StudentT.batch_shape(name='batch_shape')` {#StudentT.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: +* `batch_shape`: `Tensor`. + - - - @@ -5703,6 +6849,18 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -5715,31 +6873,31 @@ Degrees of freedom in these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.dtype` {#StudentT.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.StudentT.entropy(name='entropy')` {#StudentT.entropy} -The entropy of Student t distribution(s). - -##### Args: +Shanon entropy in nats. -* `name`: The name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.StudentT.event_shape(name='event_shape')` {#StudentT.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: tensor of dtype `dtype`, the entropy. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.StudentT.event_shape(name='event_shape')` {#StudentT.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -5759,8 +6917,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -5803,14 +6961,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.StudentT.get_batch_shape()` {#StudentT.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.StudentT.get_event_shape()` {#StudentT.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -5831,66 +7003,100 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.StudentT.log_cdf(value, name='log_cdf')` {#StudentT.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.StudentT.log_pdf(value, name='log_pdf')` {#StudentT.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.StudentT.log_pmf(value, name='log_pmf')` {#StudentT.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.StudentT.log_prob(x, name='log_prob')` {#StudentT.log_prob} +#### `tf.contrib.distributions.StudentT.log_pmf(value, name='log_pmf')` {#StudentT.log_pmf} -Log prob of observations in `x` under these Student's t-distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `df`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. +##### Raises: -- - - -#### `tf.contrib.distributions.StudentT.mean(name='mean')` {#StudentT.mean} +* `AttributeError`: if `is_continuous`. -Mean of the distribution. -The mean of Student's T equals `mu` if `df > 1`, otherwise it is `NaN`. If -`self.allow_nan_stats=False`, then an exception will be raised rather than -returning `NaN`. +- - - + +#### `tf.contrib.distributions.StudentT.log_prob(value, name='log_prob')` {#StudentT.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: A name to give this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.StudentT.mode(name='mode')` {#StudentT.mode} +#### `tf.contrib.distributions.StudentT.mean(name='mean')` {#StudentT.mean} + +Mean. + + +- - - +#### `tf.contrib.distributions.StudentT.mode(name='mode')` {#StudentT.mode} +Mode. - - - @@ -5904,7 +7110,7 @@ Locations of these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.name` {#StudentT.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -5949,80 +7155,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.StudentT.parameters` {#StudentT.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.StudentT.pdf(value, name='pdf')` {#StudentT.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.StudentT.pmf(value, name='pmf')` {#StudentT.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.StudentT.prob(x, name='prob')` {#StudentT.prob} +#### `tf.contrib.distributions.StudentT.prob(value, name='prob')` {#StudentT.prob} -The PDF of observations in `x` under these Student's t distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `df`, `mu`, and - `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.StudentT.sample(sample_shape=(), seed=None, name='sample')` {#StudentT.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.StudentT.sample_n(n, seed=None, name='sample_n')` {#StudentT.sample_n} -Sample `n` observations from the Student t Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -6036,42 +7287,21 @@ Scaling factors of these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.std(name='std')` {#StudentT.std} - +Standard deviation. - - - #### `tf.contrib.distributions.StudentT.validate_args` {#StudentT.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.StudentT.variance(name='variance')` {#StudentT.variance} -Variance of the distribution. - -Variance for Student's T equals - -``` -df / (df - 2), when df > 2 -infinity, when 1 < df <= 2 -NaN, when df <= 1 -``` - -The NaN state occurs because mean is undefined for `df <= 1`, and if -`self.allow_nan_stats` is `False`, an exception will be raised if any batch -members fall into this state. - -##### Args: - - -* `name`: A name for this op. - -##### Returns: - - The variance for every batch member, a `Tensor` with same `dtype` as self. +Variance. @@ -6139,7 +7369,21 @@ u1 = Uniform(3.0, [5.0, 6.0, 7.0]) # 3 distributions #### `tf.contrib.distributions.Uniform.allow_nan_stats` {#Uniform.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -6153,57 +7397,70 @@ Boolean describing behavior when a stat is undefined for batch member. #### `tf.contrib.distributions.Uniform.batch_shape(name='batch_shape')` {#Uniform.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: +* `batch_shape`: `Tensor`. + - - - -#### `tf.contrib.distributions.Uniform.cdf(x, name='cdf')` {#Uniform.cdf} +#### `tf.contrib.distributions.Uniform.cdf(value, name='cdf')` {#Uniform.cdf} -CDF of observations in `x` under these Uniform distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. If `x` is `nan`, will - return `nan`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Uniform.dtype` {#Uniform.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Uniform.entropy(name='entropy')` {#Uniform.entropy} -The entropy of Uniform distribution(s). - -##### Args: +Shanon entropy in nats. -* `name`: The name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Uniform.event_shape(name='event_shape')` {#Uniform.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: tensor of dtype `dtype`, the entropy. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.Uniform.event_shape(name='event_shape')` {#Uniform.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -6223,8 +7480,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -6256,88 +7513,160 @@ apply it externally and set `make_safe=False`. A distribution parameterized by possibly transformed parameters in `kwargs`. -##### Raises: +##### Raises: + + +* `TypeError`: if `make_safe` is `True` but `_safe_transforms` is not + implemented directly for `cls`. + + +- - - + +#### `tf.contrib.distributions.Uniform.get_batch_shape()` {#Uniform.get_batch_shape} + +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. + + +- - - + +#### `tf.contrib.distributions.Uniform.get_event_shape()` {#Uniform.get_event_shape} + +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. + + +- - - + +#### `tf.contrib.distributions.Uniform.is_continuous` {#Uniform.is_continuous} + + + + +- - - + +#### `tf.contrib.distributions.Uniform.is_reparameterized` {#Uniform.is_reparameterized} + + + + +- - - + +#### `tf.contrib.distributions.Uniform.log_cdf(value, name='log_cdf')` {#Uniform.log_cdf} + +Log cumulative distribution function. + +##### Args: + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -* `TypeError`: if `make_safe` is `True` but `_safe_transforms` is not - implemented directly for `cls`. +##### Returns: -- - - +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.Uniform.get_batch_shape()` {#Uniform.get_batch_shape} +- - - +#### `tf.contrib.distributions.Uniform.log_pdf(value, name='log_pdf')` {#Uniform.log_pdf} +Log probability density function. -- - - +##### Args: -#### `tf.contrib.distributions.Uniform.get_event_shape()` {#Uniform.get_event_shape} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. +##### Returns: -- - - +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.Uniform.is_continuous` {#Uniform.is_continuous} +##### Raises: +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Uniform.is_reparameterized` {#Uniform.is_reparameterized} - +#### `tf.contrib.distributions.Uniform.log_pmf(value, name='log_pmf')` {#Uniform.log_pmf} +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.Uniform.log_cdf(x, name='log_cdf')` {#Uniform.log_cdf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. +##### Returns: +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Uniform.log_pdf(value, name='log_pdf')` {#Uniform.log_pdf} -Log of the probability density function. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Uniform.log_pmf(value, name='log_pmf')` {#Uniform.log_pmf} +#### `tf.contrib.distributions.Uniform.log_prob(value, name='log_prob')` {#Uniform.log_prob} + +Log probability density/mass function (depending on `is_continuous`). -Log of the probability mass function. +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.Uniform.log_prob(x, name='log_prob')` {#Uniform.log_prob} +##### Returns: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Uniform.mean(name='mean')` {#Uniform.mean} - +Mean. - - - #### `tf.contrib.distributions.Uniform.mode(name='mode')` {#Uniform.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.Uniform.name` {#Uniform.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -6382,37 +7711,78 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Uniform.parameters` {#Uniform.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Uniform.pdf(value, name='pdf')` {#Uniform.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Uniform.pmf(value, name='pmf')` {#Uniform.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Uniform.prob(x, name='prob')` {#Uniform.prob} +#### `tf.contrib.distributions.Uniform.prob(value, name='prob')` {#Uniform.prob} -The PDF of observations in `x` under these Uniform distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. If `x` is `nan`, - will return `nan`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -6426,64 +7796,68 @@ The PDF of observations in `x` under these Uniform distribution(s). #### `tf.contrib.distributions.Uniform.sample(sample_shape=(), seed=None, name='sample')` {#Uniform.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Uniform.sample_n(n, seed=None, name='sample_n')` {#Uniform.sample_n} -Sample `n` observations from the Uniform Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Uniform.std(name='std')` {#Uniform.std} - +Standard deviation. - - - #### `tf.contrib.distributions.Uniform.validate_args` {#Uniform.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Uniform.variance(name='variance')` {#Uniform.variance} - +Variance. @@ -6577,14 +7951,41 @@ The mean of `X_i` is `mu[i]`, and the standard deviation is `diag_stdev[i]`. #### `tf.contrib.distributions.MultivariateNormalDiag.allow_nan_stats` {#MultivariateNormalDiag.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.batch_shape(name='batch_shape')` {#MultivariateNormalDiag.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -6593,36 +7994,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalDiag.dtype` {#MultivariateNormalDiag.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.entropy(name='entropy')` {#MultivariateNormalDiag.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalDiag.event_shape(name='event_shape')` {#MultivariateNormalDiag.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalDiag.event_shape(name='event_shape')` {#MultivariateNormalDiag.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -6642,8 +8055,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -6686,14 +8099,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiag.get_batch_shape()` {#MultivariateNormalDiag.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.get_event_shape()` {#MultivariateNormalDiag.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -6714,48 +8141,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiag.log_cdf(value, name='log_cdf')` {#MultivariateNormalDiag.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.log_pdf(value, name='log_pdf')` {#MultivariateNormalDiag.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.log_pmf(value, name='log_pmf')` {#MultivariateNormalDiag.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalDiag.log_prob(x, name='log_prob')` {#MultivariateNormalDiag.log_prob} -Log prob of observations `x` given these Multivariate Normals. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: +##### Raises: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.log_prob(value, name='log_prob')` {#MultivariateNormalDiag.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -6769,14 +8234,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiag.mean(name='mean')` {#MultivariateNormalDiag.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.mode(name='mode')` {#MultivariateNormalDiag.mode} -Mode of each batch member. +Mode. - - - @@ -6790,7 +8255,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalDiag.name` {#MultivariateNormalDiag.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -6835,88 +8300,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.parameters` {#MultivariateNormalDiag.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalDiag.pdf(value, name='pdf')` {#MultivariateNormalDiag.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.pmf(value, name='pmf')` {#MultivariateNormalDiag.pmf} -The probability mass function. +Probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.MultivariateNormalDiag.prob(x, name='prob')` {#MultivariateNormalDiag.prob} +##### Returns: -The PDF of observations `x` under these Multivariate Normals. -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.prob(value, name='prob')` {#MultivariateNormalDiag.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalDiag.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalDiag.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -6937,21 +8439,21 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiag.std(name='std')` {#MultivariateNormalDiag.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.validate_args` {#MultivariateNormalDiag.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.variance(name='variance')` {#MultivariateNormalDiag.variance} -Variance of each batch member. +Variance. @@ -7032,52 +8534,91 @@ User must provide means `mu` and `sigma`, the mean and covariance. #### `tf.contrib.distributions.MultivariateNormalFull.allow_nan_stats` {#MultivariateNormalFull.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.batch_shape(name='batch_shape')` {#MultivariateNormalFull.batch_shape} + +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.MultivariateNormalFull.batch_shape(name='batch_shape')` {#MultivariateNormalFull.batch_shape} +#### `tf.contrib.distributions.MultivariateNormalFull.cdf(value, name='cdf')` {#MultivariateNormalFull.cdf} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Cumulative distribution function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalFull.cdf(value, name='cdf')` {#MultivariateNormalFull.cdf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Cumulative distribution function. +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.dtype` {#MultivariateNormalFull.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.entropy(name='entropy')` {#MultivariateNormalFull.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalFull.event_shape(name='event_shape')` {#MultivariateNormalFull.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalFull.event_shape(name='event_shape')` {#MultivariateNormalFull.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -7097,8 +8638,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -7141,14 +8682,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalFull.get_batch_shape()` {#MultivariateNormalFull.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalFull.get_event_shape()` {#MultivariateNormalFull.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -7169,48 +8724,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalFull.log_cdf(value, name='log_cdf')` {#MultivariateNormalFull.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.log_pdf(value, name='log_pdf')` {#MultivariateNormalFull.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.log_pmf(value, name='log_pmf')` {#MultivariateNormalFull.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.MultivariateNormalFull.log_prob(x, name='log_prob')` {#MultivariateNormalFull.log_prob} +##### Returns: -Log prob of observations `x` given these Multivariate Normals. -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` + +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.log_prob(value, name='log_prob')` {#MultivariateNormalFull.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -7224,14 +8817,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalFull.mean(name='mean')` {#MultivariateNormalFull.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalFull.mode(name='mode')` {#MultivariateNormalFull.mode} -Mode of each batch member. +Mode. - - - @@ -7245,7 +8838,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalFull.name` {#MultivariateNormalFull.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -7290,88 +8883,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.parameters` {#MultivariateNormalFull.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalFull.pdf(value, name='pdf')` {#MultivariateNormalFull.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.pmf(value, name='pmf')` {#MultivariateNormalFull.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalFull.prob(x, name='prob')` {#MultivariateNormalFull.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -The PDF of observations `x` under these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.prob(value, name='prob')` {#MultivariateNormalFull.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalFull.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalFull.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -7392,21 +9022,21 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalFull.std(name='std')` {#MultivariateNormalFull.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalFull.validate_args` {#MultivariateNormalFull.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalFull.variance(name='variance')` {#MultivariateNormalFull.variance} -Variance of each batch member. +Variance. @@ -7496,14 +9126,41 @@ factors, such that the covariance of each batch member is `chol chol^T`. #### `tf.contrib.distributions.MultivariateNormalCholesky.allow_nan_stats` {#MultivariateNormalCholesky.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.batch_shape(name='batch_shape')` {#MultivariateNormalCholesky.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -7512,36 +9169,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.dtype` {#MultivariateNormalCholesky.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.entropy(name='entropy')` {#MultivariateNormalCholesky.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalCholesky.event_shape(name='event_shape')` {#MultivariateNormalCholesky.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalCholesky.event_shape(name='event_shape')` {#MultivariateNormalCholesky.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -7561,8 +9230,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -7605,14 +9274,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalCholesky.get_batch_shape()` {#MultivariateNormalCholesky.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.get_event_shape()` {#MultivariateNormalCholesky.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -7633,48 +9316,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalCholesky.log_cdf(value, name='log_cdf')` {#MultivariateNormalCholesky.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.log_pdf(value, name='log_pdf')` {#MultivariateNormalCholesky.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.log_pmf(value, name='log_pmf')` {#MultivariateNormalCholesky.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalCholesky.log_prob(x, name='log_prob')` {#MultivariateNormalCholesky.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.log_prob(value, name='log_prob')` {#MultivariateNormalCholesky.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -7688,14 +9409,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalCholesky.mean(name='mean')` {#MultivariateNormalCholesky.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.mode(name='mode')` {#MultivariateNormalCholesky.mode} -Mode of each batch member. +Mode. - - - @@ -7709,7 +9430,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalCholesky.name` {#MultivariateNormalCholesky.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -7754,88 +9475,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.parameters` {#MultivariateNormalCholesky.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.pdf(value, name='pdf')` {#MultivariateNormalCholesky.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.pmf(value, name='pmf')` {#MultivariateNormalCholesky.pmf} -The probability mass function. +Probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.MultivariateNormalCholesky.prob(x, name='prob')` {#MultivariateNormalCholesky.prob} +##### Returns: -The PDF of observations `x` under these Multivariate Normals. -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.prob(value, name='prob')` {#MultivariateNormalCholesky.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalCholesky.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalCholesky.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -7856,21 +9614,21 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalCholesky.std(name='std')` {#MultivariateNormalCholesky.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.validate_args` {#MultivariateNormalCholesky.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.variance(name='variance')` {#MultivariateNormalCholesky.variance} -Variance of each batch member. +Variance. @@ -8036,7 +9794,21 @@ dist = Dirichlet([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) #### `tf.contrib.distributions.Dirichlet.allow_nan_stats` {#Dirichlet.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -8046,11 +9818,18 @@ Boolean describing behavior when a stat is undefined for batch member. Shape parameter. +- - - + +#### `tf.contrib.distributions.Dirichlet.alpha_sum` {#Dirichlet.alpha_sum} + +Sum of shape parameter. + + - - - #### `tf.contrib.distributions.Dirichlet.batch_shape(name='batch_shape')` {#Dirichlet.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -8062,35 +9841,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Dirichlet.cdf(x, name='cdf')` {#Dirichlet.cdf} +#### `tf.contrib.distributions.Dirichlet.cdf(value, name='cdf')` {#Dirichlet.cdf} Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Dirichlet.dtype` {#Dirichlet.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Dirichlet.entropy(name='entropy')` {#Dirichlet.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Dirichlet.event_shape(name='event_shape')` {#Dirichlet.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -8099,7 +9891,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -8119,8 +9912,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -8163,26 +9956,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Dirichlet.get_batch_shape()` {#Dirichlet.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Dirichlet.get_event_shape()` {#Dirichlet.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -8201,78 +9996,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Dirichlet.log_cdf(x, name='log_cdf')` {#Dirichlet.log_cdf} +#### `tf.contrib.distributions.Dirichlet.log_cdf(value, name='log_cdf')` {#Dirichlet.log_cdf} + +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log CDF. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Dirichlet.log_pdf(value, name='log_pdf')` {#Dirichlet.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -#### `tf.contrib.distributions.Dirichlet.log_pmf(value, name='log_pmf')` {#Dirichlet.log_pmf} -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.log_prob(x, name='log_prob')` {#Dirichlet.log_prob} +#### `tf.contrib.distributions.Dirichlet.log_pmf(value, name='log_pmf')` {#Dirichlet.log_pmf} -`Log(P[counts])`, computed for every batch member. +Log probability mass function. ##### Args: -* `x`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet distribution - in `self.alpha`. `x` is only legal if it sums up to one. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Dirichlet.mean(name='mean')` {#Dirichlet.mean} -Mean of the distribution. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.mode(name='mode')` {#Dirichlet.mode} - -Mode of the distribution. +#### `tf.contrib.distributions.Dirichlet.log_prob(value, name='log_prob')` {#Dirichlet.log_prob} -Note that the mode for the Beta distribution is only defined -when `alpha > 1`. This returns the mode when `alpha > 1`, -and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: The name for this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Mode of the Dirichlet distribution. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + +- - - + +#### `tf.contrib.distributions.Dirichlet.mean(name='mean')` {#Dirichlet.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Dirichlet.mode(name='mode')` {#Dirichlet.mode} + +Mode. - - - #### `tf.contrib.distributions.Dirichlet.name` {#Dirichlet.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -8317,102 +10143,146 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Dirichlet.parameters` {#Dirichlet.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Dirichlet.pdf(value, name='pdf')` {#Dirichlet.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Dirichlet.pmf(value, name='pmf')` {#Dirichlet.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.prob(x, name='prob')` {#Dirichlet.prob} +#### `tf.contrib.distributions.Dirichlet.prob(value, name='prob')` {#Dirichlet.prob} -`P[x]`, computed for every batch member. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents x for the corresponding Dirichlet distribution in - `self.alpha` and `self.beta`. `x` is only legal if it sums up to one. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Dirichlet.sample(sample_shape=(), seed=None, name='sample')` {#Dirichlet.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Dirichlet.sample_n(n, seed=None, name='sample_n')` {#Dirichlet.sample_n} -Sample `n` observations from the distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Dirichlet.std(name='std')` {#Dirichlet.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Dirichlet.validate_args` {#Dirichlet.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Dirichlet.variance(name='variance')` {#Dirichlet.variance} -Variance of the distribution. +Variance. @@ -8531,7 +10401,21 @@ dist = DirichletMultinomial([3., 4], [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) #### `tf.contrib.distributions.DirichletMultinomial.allow_nan_stats` {#DirichletMultinomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -8541,11 +10425,18 @@ Boolean describing behavior when a stat is undefined for batch member. Parameter defining this distribution. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.alpha_sum` {#DirichletMultinomial.alpha_sum} + +Summation of alpha parameter. + + - - - #### `tf.contrib.distributions.DirichletMultinomial.batch_shape(name='batch_shape')` {#DirichletMultinomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -8557,35 +10448,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.DirichletMultinomial.cdf(x, name='cdf')` {#DirichletMultinomial.cdf} +#### `tf.contrib.distributions.DirichletMultinomial.cdf(value, name='cdf')` {#DirichletMultinomial.cdf} + +Cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.dtype` {#DirichletMultinomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.DirichletMultinomial.entropy(name='entropy')` {#DirichletMultinomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.DirichletMultinomial.event_shape(name='event_shape')` {#DirichletMultinomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -8594,7 +10498,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -8614,8 +10519,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -8658,26 +10563,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.DirichletMultinomial.get_batch_shape()` {#DirichletMultinomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.DirichletMultinomial.get_event_shape()` {#DirichletMultinomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -8696,64 +10603,102 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.DirichletMultinomial.log_cdf(x, name='log_cdf')` {#DirichletMultinomial.log_cdf} +#### `tf.contrib.distributions.DirichletMultinomial.log_cdf(value, name='log_cdf')` {#DirichletMultinomial.log_cdf} + +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.log_pdf(value, name='log_pdf')` {#DirichletMultinomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.DirichletMultinomial.log_pmf(value, name='log_pmf')` {#DirichletMultinomial.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. -#### `tf.contrib.distributions.DirichletMultinomial.log_prob(counts, name='log_prob')` {#DirichletMultinomial.log_prob} -`Log(P[counts])`, computed for every batch member. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.log_prob(value, name='log_prob')` {#DirichletMultinomial.log_prob} -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Dirichlet Multinomial -distribution, the number of draws falling in class `j` is `n_j`. Note that -different sequences of draws can result in the same counts, thus the -probability includes a combinatorial coefficient. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nn]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.mean(name='mean')` {#DirichletMultinomial.mean} -Class means for every batch member. +Mean. - - - #### `tf.contrib.distributions.DirichletMultinomial.mode(name='mode')` {#DirichletMultinomial.mode} -Mode of the distribution. +Mode. - - - @@ -8767,7 +10712,7 @@ Parameter defining this distribution. #### `tf.contrib.distributions.DirichletMultinomial.name` {#DirichletMultinomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -8812,68 +10757,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.parameters` {#DirichletMultinomial.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.DirichletMultinomial.pdf(value, name='pdf')` {#DirichletMultinomial.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.DirichletMultinomial.pmf(value, name='pmf')` {#DirichletMultinomial.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.DirichletMultinomial.prob(counts, name='prob')` {#DirichletMultinomial.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -`P[counts]`, computed for every batch member. -For each batch of counts `[c_1,...,c_k]`, `P[counts]` is the probability -that after sampling `sum_j c_j` draws from this Dirichlet Multinomial -distribution, the number of draws falling in class `j` is `c_j`. Note that -different sequences of draws can result in the same counts, thus the -probability includes a combinatorial coefficient. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.prob(value, name='prob')` {#DirichletMultinomial.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nn]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.sample(sample_shape=(), seed=None, name='sample')` {#DirichletMultinomial.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -8885,61 +10862,41 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - - -- - - - -#### `tf.contrib.distributions.DirichletMultinomial.std(name='std')` {#DirichletMultinomial.std} - -Standard deviation of the distribution. - +* `samples`: a `Tensor` with a prepended dimension (n,). -- - - +##### Raises: -#### `tf.contrib.distributions.DirichletMultinomial.validate_args` {#DirichletMultinomial.validate_args} -Boolean describing behavior on invalid input. +* `TypeError`: if `n` is not an integer type. - - - -#### `tf.contrib.distributions.DirichletMultinomial.variance(name='mean')` {#DirichletMultinomial.variance} - -Class variances for every batch member. - -The variance for each batch member is defined as the following: +#### `tf.contrib.distributions.DirichletMultinomial.std(name='std')` {#DirichletMultinomial.std} -``` -Var(X_j) = n * alpha_j / alpha_0 * (1 - alpha_j / alpha_0) * - (n + alpha_0) / (1 + alpha_0) -``` +Standard deviation. -where `alpha_0 = sum_j alpha_j`. -The covariance between elements in a batch is defined as: +- - - -``` -Cov(X_i, X_j) = -n * alpha_i * alpha_j / alpha_0 ** 2 * - (n + alpha_0) / (1 + alpha_0) -``` +#### `tf.contrib.distributions.DirichletMultinomial.validate_args` {#DirichletMultinomial.validate_args} -##### Args: +Python boolean indicated possibly expensive checks are enabled. -* `name`: The name for this op. +- - - -##### Returns: +#### `tf.contrib.distributions.DirichletMultinomial.variance(name='variance')` {#DirichletMultinomial.variance} - A `Tensor` representing the variances for each batch member. +Variance. @@ -9054,14 +11011,28 @@ dist = Multinomial(n=[4., 5], p=[[.1, .3, .6], [.4, .05, .55]]) #### `tf.contrib.distributions.Multinomial.allow_nan_stats` {#Multinomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Multinomial.batch_shape(name='batch_shape')` {#Multinomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -9073,7 +11044,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -9082,26 +11054,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Multinomial.dtype` {#Multinomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Multinomial.entropy(name='entropy')` {#Multinomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Multinomial.event_shape(name='event_shape')` {#Multinomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -9110,7 +11094,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -9130,8 +11115,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -9174,26 +11159,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Multinomial.get_batch_shape()` {#Multinomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Multinomial.get_event_shape()` {#Multinomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -9214,48 +11201,86 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Multinomial.log_cdf(value, name='log_cdf')` {#Multinomial.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Multinomial.log_pdf(value, name='log_pdf')` {#Multinomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Multinomial.log_pmf(value, name='log_pmf')` {#Multinomial.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. -#### `tf.contrib.distributions.Multinomial.log_prob(counts, name='log_prob')` {#Multinomial.log_prob} -`Log(P[counts])`, computed for every batch member. +- - - + +#### `tf.contrib.distributions.Multinomial.log_prob(value, name='log_prob')` {#Multinomial.log_prob} -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Multinomial distribution, the -number of draws falling in class `j` is `n_j`. Note that different -sequences of draws can result in the same counts, thus the probability -includes a combinatorial coefficient. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -9269,14 +11294,14 @@ Log-odds. #### `tf.contrib.distributions.Multinomial.mean(name='mean')` {#Multinomial.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Multinomial.mode(name='mode')` {#Multinomial.mode} -Mode of the distribution. +Mode. - - - @@ -9290,7 +11315,7 @@ Number of trials. #### `tf.contrib.distributions.Multinomial.name` {#Multinomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -9342,68 +11367,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Multinomial.parameters` {#Multinomial.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Multinomial.pdf(value, name='pdf')` {#Multinomial.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Multinomial.pmf(value, name='pmf')` {#Multinomial.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.Multinomial.prob(counts, name='prob')` {#Multinomial.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -`P[counts]`, computed for every batch member. -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Multinomial distribution, the -number of draws falling in class `j` is `n_j`. Note that different -sequences of draws can result in the same counts, thus the probability -includes a combinatorial coefficient. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Multinomial.prob(value, name='prob')` {#Multinomial.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Multinomial.sample(sample_shape=(), seed=None, name='sample')` {#Multinomial.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -9415,36 +11472,41 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Multinomial.std(name='std')` {#Multinomial.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Multinomial.validate_args` {#Multinomial.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Multinomial.variance(name='variance')` {#Multinomial.variance} -Variance of the distribution. +Variance. @@ -9513,7 +11575,7 @@ dist.pdf(x) # Shape is [2, 2]. ``` - - - -#### `tf.contrib.distributions.WishartCholesky.__init__(df, scale, cholesky_input_output_matrices=False, allow_nan_stats=False, validate_args=True, name='Wishart')` {#WishartCholesky.__init__} +#### `tf.contrib.distributions.WishartCholesky.__init__(df, scale, cholesky_input_output_matrices=False, validate_args=True, allow_nan_stats=False, name='WishartCholesky')` {#WishartCholesky.__init__} Construct Wishart distributions. @@ -9529,13 +11591,13 @@ Construct Wishart distributions. Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. * `allow_nan_stats`: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. -* `validate_args`: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. * `name`: The name scope to give class member ops. @@ -9543,14 +11605,41 @@ Construct Wishart distributions. #### `tf.contrib.distributions.WishartCholesky.allow_nan_stats` {#WishartCholesky.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.WishartCholesky.batch_shape(name='batch_shape')` {#WishartCholesky.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -9559,6 +11648,18 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -9585,21 +11686,31 @@ Dimension of underlying vector space. The `p` in `R^(p*p)`. #### `tf.contrib.distributions.WishartCholesky.dtype` {#WishartCholesky.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.WishartCholesky.entropy(name='entropy')` {#WishartCholesky.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.WishartCholesky.event_shape(name='event_shape')` {#WishartCholesky.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `event_shape`: `Tensor`. - - - @@ -9619,8 +11730,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -9663,33 +11774,40 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.WishartCholesky.get_batch_shape()` {#WishartCholesky.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.WishartCholesky.get_event_shape()` {#WishartCholesky.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. +Same meaning as `event_shape`. May be only partially defined. -- - - +##### Returns: -#### `tf.contrib.distributions.WishartCholesky.inputs` {#WishartCholesky.inputs} -Dictionary of inputs provided at initialization. +* `event_shape`: `TensorShape`, possibly unknown. - - - -#### `tf.contrib.distributions.WishartCholesky.is_continuous()` {#WishartCholesky.is_continuous} +#### `tf.contrib.distributions.WishartCholesky.is_continuous` {#WishartCholesky.is_continuous} - - - -#### `tf.contrib.distributions.WishartCholesky.is_reparameterized()` {#WishartCholesky.is_reparameterized} +#### `tf.contrib.distributions.WishartCholesky.is_reparameterized` {#WishartCholesky.is_reparameterized} @@ -9698,7 +11816,19 @@ Dictionary of inputs provided at initialization. #### `tf.contrib.distributions.WishartCholesky.log_cdf(value, name='log_cdf')` {#WishartCholesky.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -9712,26 +11842,60 @@ Computes the log normalizing constant, log(Z). #### `tf.contrib.distributions.WishartCholesky.log_pdf(value, name='log_pdf')` {#WishartCholesky.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartCholesky.log_pmf(value, name='log_pmf')` {#WishartCholesky.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.WishartCholesky.log_prob(x, name='log_prob')` {#WishartCholesky.log_prob} +#### `tf.contrib.distributions.WishartCholesky.log_prob(value, name='log_prob')` {#WishartCholesky.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: `float` or `double` `Tensor`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: @@ -9745,7 +11909,7 @@ Log of the probability density/mass function. #### `tf.contrib.distributions.WishartCholesky.mean(name='mean')` {#WishartCholesky.mean} -Mean of the distribution. +Mean. - - - @@ -9759,14 +11923,14 @@ Computes E[log(det(X))] under this Wishart distribution. #### `tf.contrib.distributions.WishartCholesky.mode(name='mode')` {#WishartCholesky.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.WishartCholesky.name` {#WishartCholesky.name} -Name prepended to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -9803,83 +11967,133 @@ param_shapes with static (i.e. TensorShape) shapes. ##### Returns: - `dict` of parameter name to `TensorShape`. + `dict` of parameter name to `TensorShape`. + +##### Raises: + + +* `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. + + +- - - + +#### `tf.contrib.distributions.WishartCholesky.parameters` {#WishartCholesky.parameters} + +Dictionary of parameters used by this `Distribution`. + + +- - - + +#### `tf.contrib.distributions.WishartCholesky.pdf(value, name='pdf')` {#WishartCholesky.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.WishartCholesky.pmf(value, name='pmf')` {#WishartCholesky.pmf} + +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.WishartCholesky.pdf(value, name='pdf')` {#WishartCholesky.pdf} - -The probability density function. - +#### `tf.contrib.distributions.WishartCholesky.prob(value, name='prob')` {#WishartCholesky.prob} -- - - +Probability density/mass function (depending on `is_continuous`). -#### `tf.contrib.distributions.WishartCholesky.pmf(value, name='pmf')` {#WishartCholesky.pmf} +##### Args: -The probability mass function. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -- - - +##### Returns: -#### `tf.contrib.distributions.WishartCholesky.prob(value, name='prob')` {#WishartCholesky.prob} -Probability density/mass function. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.WishartCholesky.sample(sample_shape=(), seed=None, name='sample')` {#WishartCholesky.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - -#### `tf.contrib.distributions.WishartCholesky.sample_n(n, seed=None, name='sample')` {#WishartCholesky.sample_n} +#### `tf.contrib.distributions.WishartCholesky.sample_n(n, seed=None, name='sample_n')` {#WishartCholesky.sample_n} Generate `n` samples. -Complexity: O(nbk^3) - -The sampling procedure is based on the [Bartlett decomposition]( -https://en.wikipedia.org/wiki/Wishart_distribution#Bartlett_decomposition) -and [using a Gamma distribution to generate Chi2 random variates]( -https://en.wikipedia.org/wiki/Chi-squared_distribution#Gamma.2C_exponential.2C_and_related_distributions). - ##### Args: -* `n`: Scalar. Number of samples to draw from each distribution. -* `seed`: Python integer; random number generator seed. -* `name`: The name of this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -9900,40 +12114,21 @@ Wishart distribution scale matrix as an OperatorPD. #### `tf.contrib.distributions.WishartCholesky.std(name='std')` {#WishartCholesky.std} -Standard deviation of the Wishart distribution. +Standard deviation. - - - #### `tf.contrib.distributions.WishartCholesky.validate_args` {#WishartCholesky.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.WishartCholesky.variance(name='variance')` {#WishartCholesky.variance} -Variance of the Wishart distribution. - -This function should not be confused with the covariance of the Wishart. The -covariance matrix would have shape `q x q` where, -`q = dimension * (dimension+1) / 2` -and having elements corresponding to some mapping from a lower-triangular -matrix to a vector-space. - -This function returns the diagonal of the Covariance matrix but shaped -as a `dimension x dimension` matrix. - -##### Args: - - -* `name`: The name of this op. - -##### Returns: - - -* `variance`: `Tensor` of dtype `self.dtype`. +Variance. @@ -9998,7 +12193,7 @@ dist.pdf(x) # Shape is [2, 2]. ``` - - - -#### `tf.contrib.distributions.WishartFull.__init__(df, scale, cholesky_input_output_matrices=False, allow_nan_stats=False, validate_args=True, name='Wishart')` {#WishartFull.__init__} +#### `tf.contrib.distributions.WishartFull.__init__(df, scale, cholesky_input_output_matrices=False, validate_args=True, allow_nan_stats=False, name='WishartFull')` {#WishartFull.__init__} Construct Wishart distributions. @@ -10014,13 +12209,13 @@ Construct Wishart distributions. Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. * `allow_nan_stats`: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. -* `validate_args`: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. * `name`: The name scope to give class member ops. @@ -10028,14 +12223,41 @@ Construct Wishart distributions. #### `tf.contrib.distributions.WishartFull.allow_nan_stats` {#WishartFull.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.WishartFull.batch_shape(name='batch_shape')` {#WishartFull.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -10044,6 +12266,18 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -10070,21 +12304,31 @@ Dimension of underlying vector space. The `p` in `R^(p*p)`. #### `tf.contrib.distributions.WishartFull.dtype` {#WishartFull.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.WishartFull.entropy(name='entropy')` {#WishartFull.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.WishartFull.event_shape(name='event_shape')` {#WishartFull.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `event_shape`: `Tensor`. - - - @@ -10104,8 +12348,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -10148,33 +12392,40 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.WishartFull.get_batch_shape()` {#WishartFull.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.WishartFull.get_event_shape()` {#WishartFull.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. +Same meaning as `event_shape`. May be only partially defined. -- - - +##### Returns: -#### `tf.contrib.distributions.WishartFull.inputs` {#WishartFull.inputs} -Dictionary of inputs provided at initialization. +* `event_shape`: `TensorShape`, possibly unknown. - - - -#### `tf.contrib.distributions.WishartFull.is_continuous()` {#WishartFull.is_continuous} +#### `tf.contrib.distributions.WishartFull.is_continuous` {#WishartFull.is_continuous} - - - -#### `tf.contrib.distributions.WishartFull.is_reparameterized()` {#WishartFull.is_reparameterized} +#### `tf.contrib.distributions.WishartFull.is_reparameterized` {#WishartFull.is_reparameterized} @@ -10183,7 +12434,19 @@ Dictionary of inputs provided at initialization. #### `tf.contrib.distributions.WishartFull.log_cdf(value, name='log_cdf')` {#WishartFull.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -10197,26 +12460,60 @@ Computes the log normalizing constant, log(Z). #### `tf.contrib.distributions.WishartFull.log_pdf(value, name='log_pdf')` {#WishartFull.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.log_pmf(value, name='log_pmf')` {#WishartFull.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.WishartFull.log_prob(x, name='log_prob')` {#WishartFull.log_prob} +#### `tf.contrib.distributions.WishartFull.log_prob(value, name='log_prob')` {#WishartFull.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: `float` or `double` `Tensor`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: @@ -10230,7 +12527,7 @@ Log of the probability density/mass function. #### `tf.contrib.distributions.WishartFull.mean(name='mean')` {#WishartFull.mean} -Mean of the distribution. +Mean. - - - @@ -10244,14 +12541,14 @@ Computes E[log(det(X))] under this Wishart distribution. #### `tf.contrib.distributions.WishartFull.mode(name='mode')` {#WishartFull.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.WishartFull.name` {#WishartFull.name} -Name prepended to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -10296,75 +12593,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.WishartFull.parameters` {#WishartFull.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.WishartFull.pdf(value, name='pdf')` {#WishartFull.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.pmf(value, name='pmf')` {#WishartFull.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.prob(value, name='prob')` {#WishartFull.prob} -Probability density/mass function. +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.WishartFull.sample(sample_shape=(), seed=None, name='sample')` {#WishartFull.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - -#### `tf.contrib.distributions.WishartFull.sample_n(n, seed=None, name='sample')` {#WishartFull.sample_n} +#### `tf.contrib.distributions.WishartFull.sample_n(n, seed=None, name='sample_n')` {#WishartFull.sample_n} Generate `n` samples. -Complexity: O(nbk^3) - -The sampling procedure is based on the [Bartlett decomposition]( -https://en.wikipedia.org/wiki/Wishart_distribution#Bartlett_decomposition) -and [using a Gamma distribution to generate Chi2 random variates]( -https://en.wikipedia.org/wiki/Chi-squared_distribution#Gamma.2C_exponential.2C_and_related_distributions). - ##### Args: -* `n`: Scalar. Number of samples to draw from each distribution. -* `seed`: Python integer; random number generator seed. -* `name`: The name of this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -10385,40 +12732,21 @@ Wishart distribution scale matrix as an OperatorPD. #### `tf.contrib.distributions.WishartFull.std(name='std')` {#WishartFull.std} -Standard deviation of the Wishart distribution. +Standard deviation. - - - #### `tf.contrib.distributions.WishartFull.validate_args` {#WishartFull.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.WishartFull.variance(name='variance')` {#WishartFull.variance} -Variance of the Wishart distribution. - -This function should not be confused with the covariance of the Wishart. The -covariance matrix would have shape `q x q` where, -`q = dimension * (dimension+1) / 2` -and having elements corresponding to some mapping from a lower-triangular -matrix to a vector-space. - -This function returns the diagonal of the Covariance matrix but shaped -as a `dimension x dimension` matrix. - -##### Args: - - -* `name`: The name of this op. - -##### Returns: - - -* `variance`: `Tensor` of dtype `self.dtype`. +Variance. @@ -10495,7 +12823,21 @@ Construct a Transformed Distribution. #### `tf.contrib.distributions.TransformedDistribution.allow_nan_stats` {#TransformedDistribution.allow_nan_stats} +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + +* `allow_nan_stats`: Python boolean. - - - @@ -10509,7 +12851,7 @@ Base distribution, p(x). #### `tf.contrib.distributions.TransformedDistribution.batch_shape(name='batch_shape')` {#TransformedDistribution.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -10517,11 +12859,12 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -10530,35 +12873,48 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.TransformedDistribution.dtype` {#TransformedDistribution.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.TransformedDistribution.entropy(name='entropy')` {#TransformedDistribution.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.TransformedDistribution.event_shape(name='event_shape')` {#TransformedDistribution.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -10578,8 +12934,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -10622,26 +12978,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.TransformedDistribution.get_batch_shape()` {#TransformedDistribution.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.TransformedDistribution.get_event_shape()` {#TransformedDistribution.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -10653,91 +13011,130 @@ Inverse function of transform, y => x. - - - -#### `tf.contrib.distributions.TransformedDistribution.is_continuous` {#TransformedDistribution.is_continuous} - +#### `tf.contrib.distributions.TransformedDistribution.is_continuous` {#TransformedDistribution.is_continuous} + + + + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.is_reparameterized` {#TransformedDistribution.is_reparameterized} + + + + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.log_cdf(value, name='log_cdf')` {#TransformedDistribution.log_cdf} + +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.log_det_jacobian` {#TransformedDistribution.log_det_jacobian} + +Function computing the log determinant of the Jacobian of transform. + + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.log_pdf(value, name='log_pdf')` {#TransformedDistribution.log_pdf} +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.TransformedDistribution.is_reparameterized` {#TransformedDistribution.is_reparameterized} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. +##### Returns: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.TransformedDistribution.log_cdf(value, name='log_cdf')` {#TransformedDistribution.log_cdf} -Log CDF. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.TransformedDistribution.log_det_jacobian` {#TransformedDistribution.log_det_jacobian} +#### `tf.contrib.distributions.TransformedDistribution.log_pmf(value, name='log_pmf')` {#TransformedDistribution.log_pmf} -Function computing the log determinant of the Jacobian of transform. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.TransformedDistribution.log_pdf(value, name='log_pdf')` {#TransformedDistribution.log_pdf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log of the probability density function. +##### Returns: -- - - +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.TransformedDistribution.log_pmf(value, name='log_pmf')` {#TransformedDistribution.log_pmf} +##### Raises: -Log of the probability mass function. +* `AttributeError`: if `is_continuous`. -- - - -#### `tf.contrib.distributions.TransformedDistribution.log_prob(y, name='log_prob')` {#TransformedDistribution.log_prob} +- - - -Log prob of observations in `y`. +#### `tf.contrib.distributions.TransformedDistribution.log_prob(value, name='log_prob')` {#TransformedDistribution.log_prob} -`log ( p(g(y)) / det|J(g(y))| )`, where `g` is the inverse of `transform`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `y`: tensor of dtype `dtype`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_pdf`: tensor of dtype `dtype`, the log-PDFs of `y`. - -##### Raises: - - -* `ValueError`: if `inverse` was not provided to the distribution and `y` was - not returned from `sample`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.TransformedDistribution.mean(name='mean')` {#TransformedDistribution.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.TransformedDistribution.mode(name='mode')` {#TransformedDistribution.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.TransformedDistribution.name` {#TransformedDistribution.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -10782,89 +13179,132 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.TransformedDistribution.parameters` {#TransformedDistribution.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.TransformedDistribution.pdf(value, name='pdf')` {#TransformedDistribution.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.TransformedDistribution.pmf(value, name='pmf')` {#TransformedDistribution.pmf} -The probability mass function. +Probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. -#### `tf.contrib.distributions.TransformedDistribution.prob(y, name='prob')` {#TransformedDistribution.prob} -The prob of observations in `y`. +- - - + +#### `tf.contrib.distributions.TransformedDistribution.prob(value, name='prob')` {#TransformedDistribution.prob} -`p(g(y)) / det|J(g(y))|`, where `g` is the inverse of `transform`. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `y`: `Tensor` of dtype `dtype`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `pdf`: `Tensor` of dtype `dtype`, the pdf values of `y`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.TransformedDistribution.sample(sample_shape=(), seed=None, name='sample')` {#TransformedDistribution.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.TransformedDistribution.sample_n(n, seed=None, name='sample_n')` {#TransformedDistribution.sample_n} -Sample `n` observations. - -Samples from the base distribution and then passes through the transform. +Generate `n` samples. ##### Args: -* `n`: scalar, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.TransformedDistribution.std(name='std')` {#TransformedDistribution.std} -Standard deviation of the distribution. +Standard deviation. - - - @@ -10878,14 +13318,14 @@ Function transforming x => y. #### `tf.contrib.distributions.TransformedDistribution.validate_args` {#TransformedDistribution.validate_args} - +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.TransformedDistribution.variance(name='variance')` {#TransformedDistribution.variance} -Variance of the distribution. +Variance. @@ -11083,55 +13523,32 @@ that want to fulfill a simpler distribution contract. #### `tf.contrib.distributions.BaseDistribution.log_prob(value, name='log_prob')` {#BaseDistribution.log_prob} -Log of the probability density/mass function. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.name` {#BaseDistribution.name} - -Name to prepend to all ops. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.prob(value, name='prob')` {#BaseDistribution.prob} - -Probability density/mass function. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.sample(sample_shape=(), seed=None, name='sample')` {#BaseDistribution.sample} - -Generate samples of the specified shape. - -Note that a call to `sample()` without arguments will generate a single -sample. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. -* `seed`: Python integer seed for RNG -* `name`: name to give to the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `samples`: a `Tensor` with prepended dimensions `sample_shape`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.BaseDistribution.sample_n(n, seed=None, name='sample_n')` {#BaseDistribution.sample_n} +#### `tf.contrib.distributions.BaseDistribution.sample_n(n, seed=None, name='sample')` {#BaseDistribution.sample_n} Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. @@ -11140,6 +13557,11 @@ Generate `n` samples. * `samples`: a `Tensor` with a prepended dimension (n,). +##### Raises: + + +* `TypeError`: if `n` is not an integer type. + - - - @@ -11254,14 +13676,41 @@ D = is diagonal (r x r), optional (defaults to identity). #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.allow_nan_stats` {#MultivariateNormalDiagPlusVDVT.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.batch_shape(name='batch_shape')` {#MultivariateNormalDiagPlusVDVT.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -11270,36 +13719,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.dtype` {#MultivariateNormalDiagPlusVDVT.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.entropy(name='entropy')` {#MultivariateNormalDiagPlusVDVT.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.event_shape(name='event_shape')` {#MultivariateNormalDiagPlusVDVT.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.event_shape(name='event_shape')` {#MultivariateNormalDiagPlusVDVT.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -11319,8 +13780,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -11363,14 +13824,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.get_batch_shape()` {#MultivariateNormalDiagPlusVDVT.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.get_event_shape()` {#MultivariateNormalDiagPlusVDVT.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -11391,48 +13866,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_cdf(value, name='log_cdf')` {#MultivariateNormalDiagPlusVDVT.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_pdf(value, name='log_pdf')` {#MultivariateNormalDiagPlusVDVT.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_pmf(value, name='log_pmf')` {#MultivariateNormalDiagPlusVDVT.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_prob(x, name='log_prob')` {#MultivariateNormalDiagPlusVDVT.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_prob(value, name='log_prob')` {#MultivariateNormalDiagPlusVDVT.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -11446,14 +13959,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.mean(name='mean')` {#MultivariateNormalDiagPlusVDVT.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.mode(name='mode')` {#MultivariateNormalDiagPlusVDVT.mode} -Mode of each batch member. +Mode. - - - @@ -11467,7 +13980,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.name` {#MultivariateNormalDiagPlusVDVT.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -11512,88 +14025,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.parameters` {#MultivariateNormalDiagPlusVDVT.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.pdf(value, name='pdf')` {#MultivariateNormalDiagPlusVDVT.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.pmf(value, name='pmf')` {#MultivariateNormalDiagPlusVDVT.pmf} -The probability mass function. +Probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.prob(x, name='prob')` {#MultivariateNormalDiagPlusVDVT.prob} +##### Returns: -The PDF of observations `x` under these Multivariate Normals. -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.prob(value, name='prob')` {#MultivariateNormalDiagPlusVDVT.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalDiagPlusVDVT.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalDiagPlusVDVT.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -11614,21 +14164,21 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.std(name='std')` {#MultivariateNormalDiagPlusVDVT.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.validate_args` {#MultivariateNormalDiagPlusVDVT.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.variance(name='variance')` {#MultivariateNormalDiagPlusVDVT.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/contrib.framework.md b/tensorflow/g3doc/api_docs/python/contrib.framework.md index 0a6c811924872aad44097107ae8949119c1f3ee9..63f612dbfd224088ee6a5372d92a53ad0d2ff6d0 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.framework.md +++ b/tensorflow/g3doc/api_docs/python/contrib.framework.md @@ -521,6 +521,116 @@ tensor (using `assert_global_step`). Otherwise find a global step tensor using was found. +- - - + +### `tf.contrib.framework.assign_from_checkpoint(model_path, var_list)` {#assign_from_checkpoint} + +Creates an operation to assign specific variables from a checkpoint. + +##### Args: + + +* `model_path`: The full path to the model checkpoint. To get latest checkpoint + use `model_path = tf.train.latest_checkpoint(checkpoint_dir)` +* `var_list`: A list of `Variable` objects or a dictionary mapping names in the + checkpoint to the correspoing variables to initialize. If empty or None, + it would return no_op(), None. + +##### Returns: + + the restore_op and the feed_dict that need to be run to restore var_list. + +##### Raises: + + +* `ValueError`: If the checkpoint specified at `model_path` is missing one of + the variables in `var_list`. + + +- - - + +### `tf.contrib.framework.assign_from_checkpoint_fn(model_path, var_list, ignore_missing_vars=False, reshape_variables=False)` {#assign_from_checkpoint_fn} + +Returns a function that assigns specific variables from a checkpoint. + +##### Args: + + +* `model_path`: The full path to the model checkpoint. To get latest checkpoint + use `model_path = tf.train.latest_checkpoint(checkpoint_dir)` +* `var_list`: A list of `Variable` objects or a dictionary mapping names in the + checkpoint to the correspoing variables to initialize. If empty or None, + it would return no_op(), None. +* `ignore_missing_vars`: Boolean, if True it would ignore variables missing in + the checkpoint with a warning instead of failing. +* `reshape_variables`: Boolean, if True it would automatically reshape variables + which are of different shape then the ones stored in the checkpoint but + which have the same number of elements. + +##### Returns: + + A function that takes a single argument, a `tf.Session`, that applies the + assignment operation. + +##### Raises: + + +* `ValueError`: If the checkpoint specified at `model_path` is missing one of + the variables in `var_list`. + + +- - - + +### `tf.contrib.framework.assign_from_values(var_names_to_values)` {#assign_from_values} + +Creates an assignment operation from a given mapping. + +This function provides a mechanism for performing assignment of variables +to values in a way that does not fill the graph with large assignment values. + +##### Args: + + +* `var_names_to_values`: A map from variable names to values. + +##### Returns: + + +* `assign_op`: An `Operation` that assigns each of the given variables to the + requested values. +* `feed_dict`: The feed dictionary to use when evaluating `assign_op`. + +##### Raises: + + +* `ValueError`: if any of the given variable names were not found. + + +- - - + +### `tf.contrib.framework.assign_from_values_fn(var_names_to_values)` {#assign_from_values_fn} + +Returns a function that assigns specific variables from the given values. + +This function provides a mechanism for performing assignment of variables +to values in a way that does not fill the graph with large assignment values. + +##### Args: + + +* `var_names_to_values`: A map from variable names to values. + +##### Returns: + + A function that takes a single argument, a `tf.Session`, that applies the + assignment operation. + +##### Raises: + + +* `ValueError`: if any of the given variable names were not found. + + - - - ### `tf.contrib.framework.create_global_step(graph=None)` {#create_global_step} diff --git a/tensorflow/g3doc/api_docs/python/contrib.graph_editor.md b/tensorflow/g3doc/api_docs/python/contrib.graph_editor.md index cd1935685cea2c94abc3d26d4fe92a0671e58596..a1efb756134a0f90c60789db528ff88b7a852128 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.graph_editor.md +++ b/tensorflow/g3doc/api_docs/python/contrib.graph_editor.md @@ -3,7 +3,7 @@ # Graph Editor (contrib) [TOC] -# TensorFlow Graph Editor. +TensorFlow Graph Editor. The TensorFlow Graph Editor library allows for modification of an existing tf.Graph instance in-place. @@ -52,7 +52,7 @@ Note that this procedure is very costly because a new session must be created after any modifications. Among other things, it takes time because the entire graph state must be saved and restored again. -### Sub-graph +## Sub-graph Most of the functions in the Graph Editor library operate on *sub-graph*. More precisely, they take as input arguments instances of the SubGraphView class @@ -85,7 +85,7 @@ to avoid any confusion, the default graph is never used and the graph on which to operate must always be explicitely given. This is the reason why *graph=tf.get_default_graph()* is used in the code snippets above. -### Modules overview +## Modules overview * util: utility functions. * select: various selection methods of TensorFlow tensors and operations. @@ -100,7 +100,7 @@ which to operate must always be explicitely given. This is the reason why * transform: the Transformer class, which enables transforming (or simply copying) a subgraph into another one. -### Module: util +## Module: util - - - @@ -348,7 +348,7 @@ tensor argument). -### Module: select +## Module: select - - - @@ -836,7 +836,7 @@ Helper to select operations and tensors. -### Module: subgraph +## Module: subgraph - - - @@ -1280,7 +1280,7 @@ Make a subgraph from a name scope. -### Module: reroute +## Module: reroute - - - @@ -1490,7 +1490,7 @@ Warning: this function is directly manipulating the internals of the tf.Graph. -### Module: edit +## Module: edit - - - @@ -1665,7 +1665,7 @@ Bypass the given subgraph by connecting its inputs to its outputs. -### Module: transform +## Module: transform - - - @@ -1857,11 +1857,15 @@ Copy a subgraph. * `src_scope`: the source scope. * `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. Otherwise, the scope is given a unique name based on the one given - by postfixing an underscore followed by a digit (default). + by appending an underscore followed by a digit (default). ##### Returns: - The subgraph view of the copied subgraph. + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. ##### Raises: @@ -1871,8 +1875,77 @@ Copy a subgraph. the same rules than the function subgraph.make_view. +- - - + +### `tf.contrib.graph_editor.copy_with_input_replacements(sgv, replacement_ts, dst_graph=None, dst_scope='', src_scope='', reuse_dst_scope=False)` {#copy_with_input_replacements} + +Copy a subgraph, replacing some of its inputs. + +Note a replacement only happens if the tensor to be replaced +is an input of the given subgraph. The inputs of a subgraph can +be queried using sgv.inputs. + +##### Args: + + +* `sgv`: the source subgraph-view. This argument is converted to a subgraph + using the same rules as the function subgraph.make_view. +* `replacement_ts`: dictionary mapping from original tensors to the + replaced one. +* `dst_graph`: the destination graph. +* `dst_scope`: the destination scope. +* `src_scope`: the source scope. +* `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + +##### Returns: + + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. + +##### Raises: + + +* `TypeError`: if dst_graph is not a tf.Graph. +* `StandardError`: if sgv cannot be converted to a SubGraphView using + the same rules as the function subgraph.make_view. + + +- - - + +### `tf.contrib.graph_editor.graph_replace(target_ts, replacement_ts, dst_scope='', src_scope='', reuse_dst_scope=False)` {#graph_replace} + +Create a new graph which compute the targets from the replaced Tensors. + +##### Args: + + +* `target_ts`: a single tf.Tensor or an iterabble of tf.Tensor. +* `replacement_ts`: dictionary mapping from original tensors to replaced tensors +* `dst_scope`: the destination scope. +* `src_scope`: the source scope. +* `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + +##### Returns: + + A single tf.Tensor or a list of target tf.Tensor, depending on + the type of the input argument `target_ts`. + The returned tensors are recomputed using the tensors from replacement_ts. + +##### Raises: + + +* `ValueError`: if the targets are not connected to replacement_ts. + + -### Module: match +## Module: match - - - @@ -1928,7 +2001,7 @@ Add output matches. -### Useful aliases +## Useful aliases - - - diff --git a/tensorflow/g3doc/api_docs/python/contrib.layers.md b/tensorflow/g3doc/api_docs/python/contrib.layers.md index b43a0c9c329d0b80fd0d21e3037b383cdfa22096..7d756b217d28f68adff5e21a21f06cd34cc1d038 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.layers.md +++ b/tensorflow/g3doc/api_docs/python/contrib.layers.md @@ -51,6 +51,18 @@ Adds a Batch Normalization layer from http://arxiv.org/abs/1502.03167. Can be used as a normalizer function for conv2d and fully_connected. +Note: When is_training is True the moving_mean and moving_variance need to be +updated, by default the update_ops are placed in tf.GraphKeys.UPDATE_OPS so +they need to be added as a dependency to the train_op, example: + + update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) + if update_ops: + updates = tf.group(update_ops) + total_loss = control_flow_ops.with_dependencies([updates], total_loss) + +One can set update_collections=None to force the updates in place, but that +can have speed penalty, specially in distributed settings. + ##### Args: @@ -64,8 +76,9 @@ Can be used as a normalizer function for conv2d and fully_connected. * `epsilon`: small float added to variance to avoid dividing by zero. * `activation_fn`: Optional activation function. * `updates_collections`: collections to collect the update ops for computation. + The updates_ops need to be excuted with the train_op. If None, a control dependency would be added to make sure the updates are - computed. + computed in place. * `is_training`: whether or not the layer is in training mode. In training mode it would accumulate the statistics of the moments into `moving_mean` and `moving_variance` using an exponential moving average with the given diff --git a/tensorflow/g3doc/api_docs/python/contrib.learn.md b/tensorflow/g3doc/api_docs/python/contrib.learn.md index cc4484493a76e7e5514ede5d167b05c6b75d578e..abef96774e93457283347d3664a88eaf11ffa73d 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.learn.md +++ b/tensorflow/g3doc/api_docs/python/contrib.learn.md @@ -37,6 +37,13 @@ Initializes a BaseEstimator instance. * `config`: A RunConfig instance. +- - - + +#### `tf.contrib.learn.BaseEstimator.config` {#BaseEstimator.config} + + + + - - - #### `tf.contrib.learn.BaseEstimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#BaseEstimator.evaluate} @@ -53,7 +60,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.BaseEstimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#BaseEstimator.export} +#### `tf.contrib.learn.BaseEstimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#BaseEstimator.export} Exports inference graph into given dir. @@ -295,6 +302,13 @@ Constructs an Estimator instance. * `ValueError`: parameters of `model_fn` don't match `params`. +- - - + +#### `tf.contrib.learn.Estimator.config` {#Estimator.config} + + + + - - - #### `tf.contrib.learn.Estimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#Estimator.evaluate} @@ -311,7 +325,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.Estimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#Estimator.export} +#### `tf.contrib.learn.Estimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#Estimator.export} Exports inference graph into given dir. @@ -514,251 +528,6 @@ The following standard keys are defined: * `EVAL`: evaluation mode. * `INFER`: inference mode. -- - - - -### `class tf.contrib.learn.TensorFlowClassifier` {#TensorFlowClassifier} - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.__init__(*args, **kwargs)` {#TensorFlowClassifier.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.bias_` {#TensorFlowClassifier.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.dnn_bias_` {#TensorFlowClassifier.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.dnn_weights_` {#TensorFlowClassifier.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowClassifier.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowClassifier.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowClassifier.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_params(deep=True)` {#TensorFlowClassifier.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_variable_names()` {#TensorFlowClassifier.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_variable_value(name)` {#TensorFlowClassifier.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.linear_bias_` {#TensorFlowClassifier.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.linear_weights_` {#TensorFlowClassifier.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.model_dir` {#TensorFlowClassifier.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowClassifier.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowClassifier.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowClassifier.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.save(path)` {#TensorFlowClassifier.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.set_params(**params)` {#TensorFlowClassifier.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.weights_` {#TensorFlowClassifier.weights_} - - - - - - - - ### `class tf.contrib.learn.DNNClassifier` {#DNNClassifier} @@ -867,6 +636,13 @@ Initializes a DNNClassifier instance. +- - - + +#### `tf.contrib.learn.DNNClassifier.config` {#DNNClassifier.config} + + + + - - - #### `tf.contrib.learn.DNNClassifier.dnn_bias_` {#DNNClassifier.dnn_bias_} @@ -897,7 +673,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.DNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#DNNClassifier.export} +#### `tf.contrib.learn.DNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#DNNClassifier.export} Exports inference graph into given dir. @@ -1231,6 +1007,13 @@ Initializes a `DNNRegressor` instance. +- - - + +#### `tf.contrib.learn.DNNRegressor.config` {#DNNRegressor.config} + + + + - - - #### `tf.contrib.learn.DNNRegressor.dnn_bias_` {#DNNRegressor.dnn_bias_} @@ -1261,7 +1044,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.DNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#DNNRegressor.export} +#### `tf.contrib.learn.DNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#DNNRegressor.export} Exports inference graph into given dir. @@ -1492,6 +1275,13 @@ component of a nested object. +- - - + +#### `tf.contrib.learn.TensorFlowDNNClassifier.config` {#TensorFlowDNNClassifier.config} + + + + - - - #### `tf.contrib.learn.TensorFlowDNNClassifier.dnn_bias_` {#TensorFlowDNNClassifier.dnn_bias_} @@ -1522,7 +1312,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.TensorFlowDNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNClassifier.export} +#### `tf.contrib.learn.TensorFlowDNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNClassifier.export} Exports inference graph into given dir. @@ -1739,7 +1529,14 @@ component of a nested object. - - - -#### `tf.contrib.learn.TensorFlowDNNRegressor.dnn_bias_` {#TensorFlowDNNRegressor.dnn_bias_} +#### `tf.contrib.learn.TensorFlowDNNRegressor.config` {#TensorFlowDNNRegressor.config} + + + + +- - - + +#### `tf.contrib.learn.TensorFlowDNNRegressor.dnn_bias_` {#TensorFlowDNNRegressor.dnn_bias_} Returns bias of deep neural network part. @@ -1767,7 +1564,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.TensorFlowDNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNRegressor.export} +#### `tf.contrib.learn.TensorFlowDNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNRegressor.export} Exports inference graph into given dir. @@ -2013,6 +1810,13 @@ Initializes a TensorFlowEstimator instance. * 2: log device placement is printed. +- - - + +#### `tf.contrib.learn.TensorFlowEstimator.config` {#TensorFlowEstimator.config} + + + + - - - #### `tf.contrib.learn.TensorFlowEstimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowEstimator.evaluate} @@ -2040,7 +1844,7 @@ See superclass Estimator for more details. - - - -#### `tf.contrib.learn.TensorFlowEstimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowEstimator.export} +#### `tf.contrib.learn.TensorFlowEstimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowEstimator.export} Exports inference graph into given dir. @@ -2409,6 +2213,13 @@ Construct a `LinearClassifier` estimator object. +- - - + +#### `tf.contrib.learn.LinearClassifier.config` {#LinearClassifier.config} + + + + - - - #### `tf.contrib.learn.LinearClassifier.dnn_bias_` {#LinearClassifier.dnn_bias_} @@ -2439,7 +2250,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.LinearClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#LinearClassifier.export} +#### `tf.contrib.learn.LinearClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#LinearClassifier.export} Exports inference graph into given dir. @@ -2756,6 +2567,13 @@ Construct a `LinearRegressor` estimator object. +- - - + +#### `tf.contrib.learn.LinearRegressor.config` {#LinearRegressor.config} + + + + - - - #### `tf.contrib.learn.LinearRegressor.dnn_bias_` {#LinearRegressor.dnn_bias_} @@ -2786,7 +2604,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.LinearRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#LinearRegressor.export} +#### `tf.contrib.learn.LinearRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#LinearRegressor.export} Exports inference graph into given dir. @@ -3000,54 +2818,103 @@ component of a nested object. - - - -### `class tf.contrib.learn.TensorFlowLinearClassifier` {#TensorFlowLinearClassifier} - +### `class tf.contrib.learn.TensorFlowRNNClassifier` {#TensorFlowRNNClassifier} +TensorFlow RNN Classifier model. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.__init__(*args, **kwargs)` {#TensorFlowLinearClassifier.__init__} +#### `tf.contrib.learn.TensorFlowRNNClassifier.__init__(rnn_size, n_classes, cell_type='gru', num_layers=1, input_op_fn=null_input_op_fn, initial_state=None, bidirectional=False, sequence_length=None, attn_length=None, attn_size=None, attn_vec_size=None, batch_size=32, steps=50, optimizer='Adagrad', learning_rate=0.1, class_weight=None, clip_gradients=5.0, continue_training=False, config=None, verbose=1)` {#TensorFlowRNNClassifier.__init__} +Initializes a TensorFlowRNNClassifier instance. +##### Args: -- - - +* `rnn_size`: The size for rnn cell, e.g. size of your word embeddings. +* `cell_type`: The type of rnn cell, including rnn, gru, and lstm. +* `num_layers`: The number of layers of the rnn model. +* `input_op_fn`: Function that will transform the input tensor, such as + creating word embeddings, byte list, etc. This takes + an argument x for input and returns transformed x. +* `bidirectional`: boolean, Whether this is a bidirectional rnn. +* `sequence_length`: If sequence_length is provided, dynamic calculation + is performed. This saves computational time when unrolling past max + sequence length. +* `initial_state`: An initial state for the RNN. This must be a tensor of + appropriate type and shape [batch_size x cell.state_size]. +* `attn_length`: integer, the size of attention vector attached to rnn cells. +* `attn_size`: integer, the size of an attention window attached to rnn cells. +* `attn_vec_size`: integer, the number of convolutional features calculated on + attention state and the size of the hidden layer built from base cell state. +* `n_classes`: Number of classes in the target. +* `batch_size`: Mini batch size. +* `steps`: Number of steps to run over data. +* `optimizer`: Optimizer name (or class), for example "SGD", "Adam", + "Adagrad". +* `learning_rate`: If this is constant float value, no decay function is + used. Instead, a customized decay function can be passed that accepts + global_step as parameter and returns a Tensor. + e.g. exponential decay function: -#### `tf.contrib.learn.TensorFlowLinearClassifier.bias_` {#TensorFlowLinearClassifier.bias_} + ````python + def exp_decay(global_step): + return tf.train.exponential_decay( + learning_rate=0.1, global_step, + decay_steps=2, decay_rate=0.001) + ```` +* `class_weight`: None or list of n_classes floats. Weight associated with + classes for loss computation. If not given, all classes are + supposed to have weight one. +* `continue_training`: when continue_training is True, once initialized + model will be continuely trained on every call of fit. +* `config`: RunConfig object that controls the configurations of the session, + e.g. num_cores, gpu_memory_fraction, etc. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.dnn_bias_` {#TensorFlowLinearClassifier.dnn_bias_} +#### `tf.contrib.learn.TensorFlowRNNClassifier.bias_` {#TensorFlowRNNClassifier.bias_} -Returns bias of deep neural network part. +Returns bias of the rnn layer. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.dnn_weights_` {#TensorFlowLinearClassifier.dnn_weights_} +#### `tf.contrib.learn.TensorFlowRNNClassifier.config` {#TensorFlowRNNClassifier.config} + -Returns weights of deep neural network part. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowLinearClassifier.evaluate} +#### `tf.contrib.learn.TensorFlowRNNClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRNNClassifier.evaluate} -See `Evaluable`. +Evaluates given model with provided evaluation data. -##### Raises: +See superclass Estimator for more details. +##### Args: -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. + +* `x`: features. +* `y`: targets. +* `input_fn`: Input function. +* `feed_fn`: Function creating a feed dict every time it is called. +* `batch_size`: minibatch size to use on the input. +* `steps`: Number of steps for which to evaluate model. +* `metrics`: Dict of metric ops to run. If None, the default metrics are used. +* `name`: Name of the evaluation. + +##### Returns: + + Returns `dict` with evaluation results. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowLinearClassifier.export} +#### `tf.contrib.learn.TensorFlowRNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNClassifier.export} Exports inference graph into given dir. @@ -3067,14 +2934,41 @@ Exports inference graph into given dir. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowLinearClassifier.fit} +#### `tf.contrib.learn.TensorFlowRNNClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowRNNClassifier.fit} + +Neural network model from provided `model_fn` and training data. + +Note: called first time constructs the graph and initializers +variables. Consecutives times it will continue training the same model. +This logic follows partial_fit() interface in scikit-learn. +To restart learning, create new estimator. + +##### Args: + + +* `x`: matrix or tensor of shape [n_samples, n_features...]. Can be + iterator that returns arrays of features. The training input + samples for fitting the model. + +* `y`: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be + iterator that returns array of targets. The training target values + (class labels in classification, real numbers in regression). + +* `steps`: int, number of steps to train. + If None or 0, train for `self.steps`. +* `monitors`: List of `BaseMonitor` objects to print training progress and + invoke early stopping. +* `logdir`: the directory to save the log file that can be used for + optional visualization. +##### Returns: + Returns self. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_params(deep=True)` {#TensorFlowLinearClassifier.get_params} +#### `tf.contrib.learn.TensorFlowRNNClassifier.get_params(deep=True)` {#TensorFlowRNNClassifier.get_params} Get parameters for this estimator. @@ -3094,62 +2988,63 @@ Get parameters for this estimator. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_variable_names()` {#TensorFlowLinearClassifier.get_variable_names} +#### `tf.contrib.learn.TensorFlowRNNClassifier.get_tensor(name)` {#TensorFlowRNNClassifier.get_tensor} -Returns list of all variable names in this model. +Returns tensor by name. -##### Returns: +##### Args: - List of names. +* `name`: string, name of the tensor. -- - - +##### Returns: -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_variable_value(name)` {#TensorFlowLinearClassifier.get_variable_value} + Tensor. -Returns value of the variable given by name. -##### Args: +- - - +#### `tf.contrib.learn.TensorFlowRNNClassifier.get_variable_names()` {#TensorFlowRNNClassifier.get_variable_names} -* `name`: string, name of the tensor. +Returns list of all variable names in this model. ##### Returns: - Numpy array - value of the tensor. + List of names. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.linear_bias_` {#TensorFlowLinearClassifier.linear_bias_} +#### `tf.contrib.learn.TensorFlowRNNClassifier.get_variable_value(name)` {#TensorFlowRNNClassifier.get_variable_value} -Returns bias of the linear part. +Returns value of the variable given by name. +##### Args: -- - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.linear_weights_` {#TensorFlowLinearClassifier.linear_weights_} +* `name`: string, name of the tensor. -Returns weights per feature of the linear part. +##### Returns: + + Numpy array - value of the tensor. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.model_dir` {#TensorFlowLinearClassifier.model_dir} +#### `tf.contrib.learn.TensorFlowRNNClassifier.model_dir` {#TensorFlowRNNClassifier.model_dir} - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowLinearClassifier.partial_fit} +#### `tf.contrib.learn.TensorFlowRNNClassifier.partial_fit(x, y)` {#TensorFlowRNNClassifier.partial_fit} Incremental fit on a batch of samples. This method is expected to be called several times consecutively on different or the same chunks of the dataset. This either can implement iterative training or out-of-core/online training. - This is especially useful when the whole dataset is too big to fit in memory at the same time. Or when model is taking long time to converge, and you want to split up training into subparts. @@ -3157,49 +3052,94 @@ to converge, and you want to split up training into subparts. ##### Args: -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. +* `x`: matrix or tensor of shape [n_samples, n_features...]. Can be + iterator that returns arrays of features. The training input + samples for fitting the model. + +* `y`: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be + iterator that returns array of targets. The training target values + (class label in classification, real numbers in regression). ##### Returns: - `self`, for chaining. + Returns self. -##### Raises: +- - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. +#### `tf.contrib.learn.TensorFlowRNNClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowRNNClassifier.predict} + +Predict class or regression for `x`. + +For a classification model, the predicted class for each sample in `x` is +returned. For a regression model, the predicted value based on `x` is +returned. + +##### Args: + + +* `x`: array-like matrix, [n_samples, n_features...] or iterator. +* `axis`: Which axis to argmax for classification. + By default axis 1 (next after batch) is used. + Use 2 for sequence predictions. +* `batch_size`: If test set is too big, use batch size to split + it into mini batches. By default the batch_size member + variable is used. + +##### Returns: + + +* `y`: array of shape [n_samples]. The predicted classes or predicted + value. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowLinearClassifier.predict} +#### `tf.contrib.learn.TensorFlowRNNClassifier.predict_proba(x, batch_size=None)` {#TensorFlowRNNClassifier.predict_proba} -Predict class or regression for `x`. +Predict class probability of the input samples `x`. + +##### Args: + + +* `x`: array-like matrix, [n_samples, n_features...] or iterator. +* `batch_size`: If test set is too big, use batch size to split + it into mini batches. By default the batch_size member variable is used. + +##### Returns: + + +* `y`: array of shape [n_samples, n_classes]. The predicted + probabilities for each class. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowLinearClassifier.predict_proba} +#### `tf.contrib.learn.TensorFlowRNNClassifier.restore(cls, path, config=None)` {#TensorFlowRNNClassifier.restore} + +Restores model from give path. + +##### Args: + + +* `path`: Path to the checkpoints and other model information. +* `config`: RunConfig object that controls the configurations of the session, + e.g. num_cores, gpu_memory_fraction, etc. This is allowed to be + reconfigured. + +##### Returns: + + Estimator, object of the subclass of TensorFlowEstimator. + +##### Raises: +* `ValueError`: if `path` does not contain a model definition. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.save(path)` {#TensorFlowLinearClassifier.save} +#### `tf.contrib.learn.TensorFlowRNNClassifier.save(path)` {#TensorFlowRNNClassifier.save} Saves checkpoints and graph to given path. @@ -3211,7 +3151,7 @@ Saves checkpoints and graph to given path. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.set_params(**params)` {#TensorFlowLinearClassifier.set_params} +#### `tf.contrib.learn.TensorFlowRNNClassifier.set_params(**params)` {#TensorFlowRNNClassifier.set_params} Set the parameters of this estimator. @@ -3237,629 +3177,24 @@ component of a nested object. - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.weights_` {#TensorFlowLinearClassifier.weights_} - +#### `tf.contrib.learn.TensorFlowRNNClassifier.weights_` {#TensorFlowRNNClassifier.weights_} +Returns weights of the rnn layer. - - - -### `class tf.contrib.learn.TensorFlowLinearRegressor` {#TensorFlowLinearRegressor} - +### `class tf.contrib.learn.TensorFlowRNNRegressor` {#TensorFlowRNNRegressor} +TensorFlow RNN Regressor model. - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.__init__(*args, **kwargs)` {#TensorFlowLinearRegressor.__init__} - - +#### `tf.contrib.learn.TensorFlowRNNRegressor.__init__(rnn_size, cell_type='gru', num_layers=1, input_op_fn=null_input_op_fn, initial_state=None, bidirectional=False, sequence_length=None, attn_length=None, attn_size=None, attn_vec_size=None, n_classes=0, batch_size=32, steps=50, optimizer='Adagrad', learning_rate=0.1, clip_gradients=5.0, continue_training=False, config=None, verbose=1)` {#TensorFlowRNNRegressor.__init__} +Initializes a TensorFlowRNNRegressor instance. -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.bias_` {#TensorFlowLinearRegressor.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.dnn_bias_` {#TensorFlowLinearRegressor.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.dnn_weights_` {#TensorFlowLinearRegressor.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowLinearRegressor.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowLinearRegressor.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowLinearRegressor.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_params(deep=True)` {#TensorFlowLinearRegressor.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_variable_names()` {#TensorFlowLinearRegressor.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_variable_value(name)` {#TensorFlowLinearRegressor.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.linear_bias_` {#TensorFlowLinearRegressor.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.linear_weights_` {#TensorFlowLinearRegressor.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.model_dir` {#TensorFlowLinearRegressor.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowLinearRegressor.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowLinearRegressor.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowLinearRegressor.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.save(path)` {#TensorFlowLinearRegressor.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.set_params(**params)` {#TensorFlowLinearRegressor.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.weights_` {#TensorFlowLinearRegressor.weights_} - - - - - -- - - - -### `class tf.contrib.learn.TensorFlowRNNClassifier` {#TensorFlowRNNClassifier} - -TensorFlow RNN Classifier model. -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.__init__(rnn_size, n_classes, cell_type='gru', num_layers=1, input_op_fn=null_input_op_fn, initial_state=None, bidirectional=False, sequence_length=None, attn_length=None, attn_size=None, attn_vec_size=None, batch_size=32, steps=50, optimizer='Adagrad', learning_rate=0.1, class_weight=None, clip_gradients=5.0, continue_training=False, config=None, verbose=1)` {#TensorFlowRNNClassifier.__init__} - -Initializes a TensorFlowRNNClassifier instance. - -##### Args: - - -* `rnn_size`: The size for rnn cell, e.g. size of your word embeddings. -* `cell_type`: The type of rnn cell, including rnn, gru, and lstm. -* `num_layers`: The number of layers of the rnn model. -* `input_op_fn`: Function that will transform the input tensor, such as - creating word embeddings, byte list, etc. This takes - an argument x for input and returns transformed x. -* `bidirectional`: boolean, Whether this is a bidirectional rnn. -* `sequence_length`: If sequence_length is provided, dynamic calculation - is performed. This saves computational time when unrolling past max - sequence length. -* `initial_state`: An initial state for the RNN. This must be a tensor of - appropriate type and shape [batch_size x cell.state_size]. -* `attn_length`: integer, the size of attention vector attached to rnn cells. -* `attn_size`: integer, the size of an attention window attached to rnn cells. -* `attn_vec_size`: integer, the number of convolutional features calculated on - attention state and the size of the hidden layer built from base cell state. -* `n_classes`: Number of classes in the target. -* `batch_size`: Mini batch size. -* `steps`: Number of steps to run over data. -* `optimizer`: Optimizer name (or class), for example "SGD", "Adam", - "Adagrad". -* `learning_rate`: If this is constant float value, no decay function is - used. Instead, a customized decay function can be passed that accepts - global_step as parameter and returns a Tensor. - e.g. exponential decay function: - - ````python - def exp_decay(global_step): - return tf.train.exponential_decay( - learning_rate=0.1, global_step, - decay_steps=2, decay_rate=0.001) - ```` - - -* `class_weight`: None or list of n_classes floats. Weight associated with - classes for loss computation. If not given, all classes are - supposed to have weight one. -* `continue_training`: when continue_training is True, once initialized - model will be continuely trained on every call of fit. -* `config`: RunConfig object that controls the configurations of the session, - e.g. num_cores, gpu_memory_fraction, etc. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.bias_` {#TensorFlowRNNClassifier.bias_} - -Returns bias of the rnn layer. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRNNClassifier.evaluate} - -Evaluates given model with provided evaluation data. - -See superclass Estimator for more details. - -##### Args: - - -* `x`: features. -* `y`: targets. -* `input_fn`: Input function. -* `feed_fn`: Function creating a feed dict every time it is called. -* `batch_size`: minibatch size to use on the input. -* `steps`: Number of steps for which to evaluate model. -* `metrics`: Dict of metric ops to run. If None, the default metrics are used. -* `name`: Name of the evaluation. - -##### Returns: - - Returns `dict` with evaluation results. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNClassifier.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowRNNClassifier.fit} - -Neural network model from provided `model_fn` and training data. - -Note: called first time constructs the graph and initializers -variables. Consecutives times it will continue training the same model. -This logic follows partial_fit() interface in scikit-learn. -To restart learning, create new estimator. - -##### Args: - - -* `x`: matrix or tensor of shape [n_samples, n_features...]. Can be - iterator that returns arrays of features. The training input - samples for fitting the model. - -* `y`: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). - -* `steps`: int, number of steps to train. - If None or 0, train for `self.steps`. -* `monitors`: List of `BaseMonitor` objects to print training progress and - invoke early stopping. -* `logdir`: the directory to save the log file that can be used for - optional visualization. - -##### Returns: - - Returns self. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.get_params(deep=True)` {#TensorFlowRNNClassifier.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.get_tensor(name)` {#TensorFlowRNNClassifier.get_tensor} - -Returns tensor by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.get_variable_names()` {#TensorFlowRNNClassifier.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.get_variable_value(name)` {#TensorFlowRNNClassifier.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.model_dir` {#TensorFlowRNNClassifier.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.partial_fit(x, y)` {#TensorFlowRNNClassifier.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: matrix or tensor of shape [n_samples, n_features...]. Can be - iterator that returns arrays of features. The training input - samples for fitting the model. - -* `y`: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class label in classification, real numbers in regression). - -##### Returns: - - Returns self. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowRNNClassifier.predict} - -Predict class or regression for `x`. - -For a classification model, the predicted class for each sample in `x` is -returned. For a regression model, the predicted value based on `x` is -returned. - -##### Args: - - -* `x`: array-like matrix, [n_samples, n_features...] or iterator. -* `axis`: Which axis to argmax for classification. - By default axis 1 (next after batch) is used. - Use 2 for sequence predictions. -* `batch_size`: If test set is too big, use batch size to split - it into mini batches. By default the batch_size member - variable is used. - -##### Returns: - - -* `y`: array of shape [n_samples]. The predicted classes or predicted - value. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.predict_proba(x, batch_size=None)` {#TensorFlowRNNClassifier.predict_proba} - -Predict class probability of the input samples `x`. - -##### Args: - - -* `x`: array-like matrix, [n_samples, n_features...] or iterator. -* `batch_size`: If test set is too big, use batch size to split - it into mini batches. By default the batch_size member variable is used. - -##### Returns: - - -* `y`: array of shape [n_samples, n_classes]. The predicted - probabilities for each class. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.restore(cls, path, config=None)` {#TensorFlowRNNClassifier.restore} - -Restores model from give path. - -##### Args: - - -* `path`: Path to the checkpoints and other model information. -* `config`: RunConfig object that controls the configurations of the session, - e.g. num_cores, gpu_memory_fraction, etc. This is allowed to be - reconfigured. - -##### Returns: - - Estimator, object of the subclass of TensorFlowEstimator. - -##### Raises: - - -* `ValueError`: if `path` does not contain a model definition. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.save(path)` {#TensorFlowRNNClassifier.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.set_params(**params)` {#TensorFlowRNNClassifier.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.weights_` {#TensorFlowRNNClassifier.weights_} - -Returns weights of the rnn layer. - - - -- - - - -### `class tf.contrib.learn.TensorFlowRNNRegressor` {#TensorFlowRNNRegressor} - -TensorFlow RNN Regressor model. -- - - - -#### `tf.contrib.learn.TensorFlowRNNRegressor.__init__(rnn_size, cell_type='gru', num_layers=1, input_op_fn=null_input_op_fn, initial_state=None, bidirectional=False, sequence_length=None, attn_length=None, attn_size=None, attn_vec_size=None, n_classes=0, batch_size=32, steps=50, optimizer='Adagrad', learning_rate=0.1, clip_gradients=5.0, continue_training=False, config=None, verbose=1)` {#TensorFlowRNNRegressor.__init__} - -Initializes a TensorFlowRNNRegressor instance. - -##### Args: +##### Args: * `rnn_size`: The size for rnn cell, e.g. size of your word embeddings. @@ -3913,6 +3248,13 @@ Initializes a TensorFlowRNNRegressor instance. Returns bias of the rnn layer. +- - - + +#### `tf.contrib.learn.TensorFlowRNNRegressor.config` {#TensorFlowRNNRegressor.config} + + + + - - - #### `tf.contrib.learn.TensorFlowRNNRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRNNRegressor.evaluate} @@ -3940,7 +3282,7 @@ See superclass Estimator for more details. - - - -#### `tf.contrib.learn.TensorFlowRNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNRegressor.export} +#### `tf.contrib.learn.TensorFlowRNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNRegressor.export} Exports inference graph into given dir. @@ -4209,251 +3551,6 @@ Returns weights of the rnn layer. -- - - - -### `class tf.contrib.learn.TensorFlowRegressor` {#TensorFlowRegressor} - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.__init__(*args, **kwargs)` {#TensorFlowRegressor.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.bias_` {#TensorFlowRegressor.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.dnn_bias_` {#TensorFlowRegressor.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.dnn_weights_` {#TensorFlowRegressor.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRegressor.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRegressor.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowRegressor.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_params(deep=True)` {#TensorFlowRegressor.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_variable_names()` {#TensorFlowRegressor.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_variable_value(name)` {#TensorFlowRegressor.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.linear_bias_` {#TensorFlowRegressor.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.linear_weights_` {#TensorFlowRegressor.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.model_dir` {#TensorFlowRegressor.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowRegressor.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowRegressor.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowRegressor.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.save(path)` {#TensorFlowRegressor.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.set_params(**params)` {#TensorFlowRegressor.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.weights_` {#TensorFlowRegressor.weights_} - - - - - ## Graph actions @@ -4476,23 +3573,60 @@ If you're a Google-internal user using command line flags with learn_runner.py probably want to use learn_runner.EstimatorConfig instead. - - - -#### `tf.contrib.learn.RunConfig.__init__(master='', task=0, num_ps_replicas=0, num_cores=4, log_device_placement=False, gpu_memory_fraction=1, cluster_spec=None, tf_random_seed=None, save_summary_steps=100, save_checkpoints_secs=60, keep_checkpoint_max=5, keep_checkpoint_every_n_hours=10000)` {#RunConfig.__init__} +#### `tf.contrib.learn.RunConfig.__init__(master=None, task=None, num_ps_replicas=None, num_cores=4, log_device_placement=False, gpu_memory_fraction=1, cluster_spec=None, tf_random_seed=None, save_summary_steps=100, save_checkpoints_secs=60, keep_checkpoint_max=5, keep_checkpoint_every_n_hours=10000, job_name=None, is_chief=None)` {#RunConfig.__init__} Constructor. +If set to None, `master`, `task`, `num_ps_replicas`, `cluster_spec`, +`job_name`, and `is_chief` are set based on the TF_CONFIG environment +variable, if the pertinent information is present; otherwise, the defaults +listed in the Args section apply. + +The TF_CONFIG environment variable is a JSON object with two relevant +attributes: `task` and `cluster_spec`. `cluster_spec` is a JSON serialized +version of the Python dict described in server_lib.py. `task` has two +attributes: `type` and `index`, where `type` can be any of the task types +in the cluster_spec. When TF_CONFIG contains said information, the +following properties are set on this class: + + * `job_name` is set to [`task`][`type`] + * `task` is set to [`task`][`index`] + * `cluster_spec` is parsed from [`cluster`] + * 'master' is determined by looking up `job_name` and `task` in the + cluster_spec. + * `num_ps_replicas` is set by counting the number of nodes listed + in the `ps` job of `cluster_spec`. + * `is_chief`: true when `job_name` == "master" and `task` == 0. + +Example: +``` + cluster = {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + os.environ['TF_CONFIG'] = json.dumps({ + {'cluster': cluster, + 'task': {'type': 'worker', 'index': 1}}}) + config = RunConfig() + assert config.master == 'host4:2222' + assert config.task == 1 + assert config.num_ps_replicas == 2 + assert config.cluster_spec == server_lib.ClusterSpec(cluster) + assert config.job_name == 'worker' + assert not config.is_chief +``` + ##### Args: -* `master`: TensorFlow master. Empty string (the default) for local. +* `master`: TensorFlow master. Defaults to empty string for local. * `task`: Task id of the replica running the training (default: 0). * `num_ps_replicas`: Number of parameter server tasks to use (default: 0). * `num_cores`: Number of cores to be used (default: 4). * `log_device_placement`: Log the op placement to devices (default: False). * `gpu_memory_fraction`: Fraction of GPU memory used by the process on each GPU uniformly on the same machine. -* `cluster_spec`: a tf.train.ClusterSpec object that describes the cluster in - the case of distributed computation. If missing, reasonable assumptions - are made for the addresses of jobs. +* `cluster_spec`: a `tf.train.ClusterSpec` object that describes the cluster + in the case of distributed computation. If missing, reasonable + assumptions are made for the addresses of jobs. * `tf_random_seed`: Random seed for TensorFlow initializers. Setting this value allows consistency between reruns. * `save_summary_steps`: Save summaries every this many steps. @@ -4504,6 +3638,30 @@ Constructor. * `keep_checkpoint_every_n_hours`: Number of hours between each checkpoint to be saved. The default value of 10,000 hours effectively disables the feature. +* `job_name`: the type of task, e.g., 'ps', 'worker', etc. The `job_name` + must exist in the `cluster_spec.jobs`. +* `is_chief`: whether or not this task (as identified by the other parameters) + should be the chief task. + +##### Raises: + + +* `ValueError`: if num_ps_replicas and cluster_spec are set (cluster_spec + may fome from the TF_CONFIG environment variable). + + +- - - + +#### `tf.contrib.learn.RunConfig.is_chief` {#RunConfig.is_chief} + + + + +- - - + +#### `tf.contrib.learn.RunConfig.job_name` {#RunConfig.job_name} + + @@ -4818,8 +3976,7 @@ Use `parse_fn` if you need to do parsing / processing on single examples. ##### Returns: - String `Tensor` of batched `Example` proto. If `keep_keys` is True, then - returns tuple of string `Tensor`s, where first value is the key. + String `Tensor` of batched `Example` proto. ##### Raises: @@ -4869,7 +4026,6 @@ All ops are added to the default graph. ##### Returns: A dict of `Tensor` or `SparseTensor` objects for each in `features`. - If `keep_keys` is `True`, returns tuple of string `Tensor` and above dict. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/contrib.rnn.md b/tensorflow/g3doc/api_docs/python/contrib.rnn.md index a77e22dd93a23f54a719ca516f3a95c682926b12..fca5817dd08a80d4c0fe0efd64628c1bfd0570aa 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.rnn.md +++ b/tensorflow/g3doc/api_docs/python/contrib.rnn.md @@ -73,6 +73,86 @@ the shapes `[batch_size x s]` for each s in `state_size`. +- - - + +### `class tf.contrib.rnn.GRUBlockCell` {#GRUBlockCell} + +Block GRU cell implementation. + +The implementation is based on: http://arxiv.org/abs/1406.1078 +Computes the LSTM cell forward propagation for 1 time step. + +This kernel op implements the following mathematical equations: + +Baises are initialized with : +`b_ru` - constant_initializer(1.0) +`b_c` - constant_initializer(0.0) +``` +x_h_prev = [x, h_prev] + +[r_bar u_bar] = x_h_prev * w_ru + b_ru + +r = sigmoid(r_bar) +u = sigmoid(u_bar) + +h_prevr = h_prev \circ r + +x_h_prevr = [x h_prevr] + +c_bar = x_h_prevr * w_c + b_c +c = tanh(c_bar) + +h = (1-u) \circ c + u \circ h_prev +``` +- - - + +#### `tf.contrib.rnn.GRUBlockCell.__init__(cell_size)` {#GRUBlockCell.__init__} + +Initialize the Block GRU cell. + +##### Args: + + +* `cell_size`: int, GRU cell size. + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.output_size` {#GRUBlockCell.output_size} + + + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.state_size` {#GRUBlockCell.state_size} + + + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.zero_state(batch_size, dtype)` {#GRUBlockCell.zero_state} + +Return zero-filled state tensor(s). + +##### Args: + + +* `batch_size`: int, float, or unit Tensor representing the batch size. +* `dtype`: the data type to use for the state. + +##### Returns: + + If `state_size` is an int or TensorShape, then the return value is a + `N-D` tensor of shape `[batch_size x state_size]` filled with zeros. + + If `state_size` is a nested list or tuple, then the return value is + a nested list or tuple (of the same structure) of `2-D` tensors with +the shapes `[batch_size x s]` for each s in `state_size`. + + + ### LSTM-like cells - - - diff --git a/tensorflow/g3doc/api_docs/python/contrib.training.md b/tensorflow/g3doc/api_docs/python/contrib.training.md index e5a93fd944fa98e12bb14f2bcb19004c563dd402..dc71191409f9269443bea6e7db16f4d0532eb70d 100644 --- a/tensorflow/g3doc/api_docs/python/contrib.training.md +++ b/tensorflow/g3doc/api_docs/python/contrib.training.md @@ -718,3 +718,138 @@ It should be run in a separate thread via e.g. a `QueueRunner`. + + +## Online data resampling + +Use ['stratified_sample'](#stratified_sample) or +['stratified_sample_unknown_dist'](#stratified_sample_unknown_dist) to resample +from the data and change the class proportions that the Tensorflow graph sees. +For instance, if you have a binary classification dataset that is 99.9% class +1, a common approach is to resample from the data so that the data is more +balanced. + +- - - + +### `tf.contrib.training.stratified_sample(tensors, labels, target_probs, batch_size, init_probs=None, enqueue_many=False, queue_capacity=16, threads_per_queue=1, name=None)` {#stratified_sample} + +Stochastically creates batches based on per-class probabilities. + +This method discards examples. Internally, it creates one queue to amortize +the cost of disk reads, and one queue to hold the properly-proportioned +batch. See `stratified_sample_unknown_dist` for a function that performs +stratified sampling with one queue per class and doesn't require knowing the +class data-distribution ahead of time. + +##### Args: + + +* `tensors`: List of tensors for data. All tensors are either one item or a + batch, according to enqueue_many. +* `labels`: Tensor for label of data. Label is a single integer or a batch, + depending on enqueue_many. It is not a one-hot vector. +* `target_probs`: Target class proportions in batch. An object whose type has a + registered Tensor conversion function. +* `batch_size`: Size of batch to be returned. +* `init_probs`: Class proportions in the data. An object whose type has a + registered Tensor conversion function, or `None` for estimating the + initial distribution. +* `enqueue_many`: Bool. If true, interpret input tensors as having a batch + dimension. +* `queue_capacity`: Capacity of the large queue that holds input examples. +* `threads_per_queue`: Number of threads for the large queue that holds input + examples and for the final queue with the proper class proportions. +* `name`: Optional prefix for ops created by this function. + +##### Raises: + + +* `ValueError`: enqueue_many is True and labels doesn't have a batch + dimension, or if enqueue_many is False and labels isn't a scalar. +* `ValueError`: enqueue_many is True, and batch dimension on data and labels + don't match. +* `ValueError`: if probs don't sum to one. +* `ValueError`: if a zero initial probability class has a nonzero target + probability. +* `TFAssertion`: if labels aren't integers in [0, num classes). + +##### Returns: + + (data_batch, label_batch), where data_batch is a list of tensors of the same + length as `tensors` + +##### Example: + + # Get tensor for a single data and label example. + data, label = data_provider.Get(['data', 'label']) + + # Get stratified batch according to per-class probabilities. + target_probs = [...distribution you want...] + [data_batch], labels = tf.contrib.framework.sampling_ops.stratified_sample( + [data], label, target_probs) + + # Run batch through network. + ... + + +- - - + +### `tf.contrib.training.stratified_sample_unknown_dist(tensors, labels, probs, batch_size, enqueue_many=False, queue_capacity=16, threads_per_queue=1, name=None)` {#stratified_sample_unknown_dist} + +Stochastically creates batches based on per-class probabilities. + +**NOTICE** This sampler can be significantly slower than `stratified_sample` +due to each thread discarding all examples not in its assigned class. + +This uses a number of threads proportional to the number of classes. See +`stratified_sample` for an implementation that discards fewer examples and +uses a fixed number of threads. This function's only advantage over +`stratified_sample` is that the class data-distribution doesn't need to be +known ahead of time. + +##### Args: + + +* `tensors`: List of tensors for data. All tensors are either one item or a + batch, according to enqueue_many. +* `labels`: Tensor for label of data. Label is a single integer or a batch, + depending on enqueue_many. It is not a one-hot vector. +* `probs`: Target class probabilities. An object whose type has a registered + Tensor conversion function. +* `batch_size`: Size of batch to be returned. +* `enqueue_many`: Bool. If true, interpret input tensors as having a batch + dimension. +* `queue_capacity`: Capacity of each per-class queue. +* `threads_per_queue`: Number of threads for each per-class queue. +* `name`: Optional prefix for ops created by this function. + +##### Raises: + + +* `ValueError`: enqueue_many is True and labels doesn't have a batch + dimension, or if enqueue_many is False and labels isn't a scalar. +* `ValueError`: enqueue_many is True, and batch dimension of data and labels + don't match. +* `ValueError`: if probs don't sum to one. +* `TFAssertion`: if labels aren't integers in [0, num classes). + +##### Returns: + + (data_batch, label_batch), where data_batch is a list of tensors of the same + length as `tensors` + +##### Example: + + # Get tensor for a single data and label example. + data, label = data_provider.Get(['data', 'label']) + + # Get stratified batch according to per-class probabilities. + init_probs = [1.0/NUM_CLASSES for _ in range(NUM_CLASSES)] + [data_batch], labels = ( + tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( + [data], label, init_probs, 16)) + + # Run batch through network. + ... + + diff --git a/tensorflow/g3doc/api_docs/python/control_flow_ops.md b/tensorflow/g3doc/api_docs/python/control_flow_ops.md index 365c6a821a1e8f726935e9b818305dcfa4de81fb..3eeddebf7f2bf1549fbfe5680222a07692774456 100644 --- a/tensorflow/g3doc/api_docs/python/control_flow_ops.md +++ b/tensorflow/g3doc/api_docs/python/control_flow_ops.md @@ -275,7 +275,7 @@ Example 2: - - - -### `tf.while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, swap_memory=False, name=None)` {#while_loop} +### `tf.while_loop(cond, body, loop_vars, shape_invariants=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None)` {#while_loop} Repeat `body` while the condition `cond` is true. @@ -286,11 +286,39 @@ arity (length and structure) and types as `loop_vars`. `loop_vars` is a and `body`. `cond` and `body` both take as many arguments as there are `loop_vars`. +While `cond` evaluates to true, `body` is executed. + In addition to regular Tensors or IndexedSlices, the body may accept and return TensorArray objects. The flows of the TensorArray objects will be appropriately forwarded between loops and during gradient calculations. -While `cond` evaluates to true, `body` is executed. +For correctness, `tf.while_loop()` strictly enforces shape invariants for +the loop variables. A shape invariant is a (possibly partial) shape that +is unchanged across the iterations of the loop. An error will be raised +if the shape of a loop variable after an iteration is determined to be more +general than or incompatible with its shape invariant. For example, a shape +of [11, None] is more general than a shape of [11, 17], and [11, 21] is not +compatible with [11, 17]. By default (if the argument `shape_invariants` is +not specified), it is assumed that the initial shape of each tensor in +`loop_vars` is the same in every iteration. The `shape_invariants` argument +allows the caller to specify a less specific shape invariant for each loop +variable, which is needed if the shape varies between iterations. The +[`Tensor.set_shape()`](../../api_docs/python/framework.md#Tensor.set_shape) +function may also be used in the `body` function to indicate that +the output loop variable has a particular shape. The shape invariant for +SparseTensor and IndexedSlices are treated specially as follows: + +a) If a loop variable is a SparseTensor, the shape invariant must be +TensorShape([r]) where r is the rank of the dense tensor represented +by the sparse tensor. It means the shapes of the three tensors of the +SparseTensor are ([None], [None, r], [r]). NOTE: The shape invariant here +is the shape of the SparseTensor.shape property. It must be the shape of +a vector. + +b) If a loop variable is an IndexedSlices, the shape invariant must be +a shape invariant of the values tensor of the IndexedSlices. It means +the shapes of the three tensors of the IndexedSlices are (shape, [shape[0]], +[shape.ndims]). `while_loop` implements non-strict semantics, enabling multiple iterations to run in parallel. The maximum number of parallel iterations can be @@ -312,6 +340,7 @@ sequences and large batches. * `body`: A callable that represents the loop body. * `loop_vars`: A (possibly nested) tuple or list of numpy array, `Tensor`, and `TensorArray` objects. +* `shape_invariants`: The shape invariants for the loop variables. * `parallel_iterations`: The number of iterations allowed to run in parallel. * `back_prop`: Whether backprop is enabled for this while loop. * `swap_memory`: Whether GPU-CPU memory swap is enabled for this loop. @@ -348,6 +377,18 @@ Example with nesting: ijk_final = tf.while_loop(c, b, ijk_0) ``` +Example using shape_invariants: + + ```python + i0 = tf.constant(0) + m0 = tf.ones([2, 2]) + c = lambda i, m: i < 10 + b = lambda i, m: [i+1, tf.concat(0, [m, m])] + tf.while_loop( + c, b, loop_vars=[i0, m0], + shape_invariants=[i0.get_shape(), tensor_shape.TensorShape([None, 2])]) + ``` + ## Logical Operators diff --git a/tensorflow/g3doc/api_docs/python/framework.md b/tensorflow/g3doc/api_docs/python/framework.md index 794f9d802359cca1fa6bc1d3b95947532f3b8f6b..0da2a8ec242bd2364bb847c952e805d1b7ed56f2 100644 --- a/tensorflow/g3doc/api_docs/python/framework.md +++ b/tensorflow/g3doc/api_docs/python/framework.md @@ -1028,8 +1028,8 @@ regular expression: ##### Args: -* `node_def`: `graph_pb2.NodeDef`. `NodeDef` for the `Operation`. - Used for attributes of `graph_pb2.NodeDef`, typically `name`, +* `node_def`: `node_def_pb2.NodeDef`. `NodeDef` for the `Operation`. + Used for attributes of `node_def_pb2.NodeDef`, typically `name`, `op`, and `device`. The `input` attribute is irrelevant here as it will be computed when generating the model. * `g`: `Graph`. The parent graph. @@ -1076,7 +1076,7 @@ Returns a serialized `NodeDef` representation of this operation. ##### Returns: A - [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/graph.proto) + [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/node_def.proto) protocol buffer. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.bayesflow.stochastic_graph.DistributionTensor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.bayesflow.stochastic_graph.DistributionTensor.md index 4f8e8d87d11582c7426a426db32324f61ce6e43e..f1c599588c455ceeb66a9a3728b016e77ae845f9 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.bayesflow.stochastic_graph.DistributionTensor.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.bayesflow.stochastic_graph.DistributionTensor.md @@ -26,7 +26,7 @@ reparameterized distributions; it will also return None if the value type is ##### Args: -* `dist_cls`: a class deriving from `BaseDistribution`. +* `dist_cls`: a `Distribution` class. * `name`: a name for this `DistributionTensor` and its ops. * `dist_value_type`: a `_StochasticValueType`, which will determine what the `value` of this `DistributionTensor` will be. If not provided, the @@ -40,6 +40,12 @@ reparameterized distributions; it will also return None if the value type is * `**dist_args`: keyword arguments to be passed through to `dist_cls` on construction. +##### Raises: + + +* `TypeError`: if `dist_cls` is not a `Distribution`. +* `TypeError`: if `loss_fn` is not `callable`. + - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Bernoulli.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Bernoulli.md index ce41346beefe071c0555b62d7a5a4ef92eae0312..235aac6bebaf0764c8f5cec2ace5e997c47fbd2c 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Bernoulli.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Bernoulli.md @@ -37,14 +37,41 @@ Construct Bernoulli distributions. #### `tf.contrib.distributions.Bernoulli.allow_nan_stats` {#Bernoulli.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Bernoulli.batch_shape(name='batch_shape')` {#Bernoulli.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + +* `batch_shape`: `Tensor`. - - - @@ -53,36 +80,48 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Bernoulli.dtype` {#Bernoulli.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Bernoulli.entropy(name='entropy')` {#Bernoulli.entropy} -Entropy of the distribution. - -##### Args: +Shanon entropy in nats. -* `name`: Name for the op. +- - - -##### Returns: +#### `tf.contrib.distributions.Bernoulli.event_shape(name='event_shape')` {#Bernoulli.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: `Tensor` of the same type and shape as `p`. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.Bernoulli.event_shape(name='event_shape')` {#Bernoulli.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -102,8 +141,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -146,15 +185,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Bernoulli.get_batch_shape()` {#Bernoulli.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Bernoulli.get_event_shape()` {#Bernoulli.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -174,88 +227,114 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Bernoulli.log_cdf(value, name='log_cdf')` {#Bernoulli.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Bernoulli.log_pdf(value, name='log_pdf')` {#Bernoulli.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Bernoulli.log_pmf(value, name='log_pmf')` {#Bernoulli.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -Log of the probability mass function. + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.log_prob(event, name='log_prob')` {#Bernoulli.log_prob} +#### `tf.contrib.distributions.Bernoulli.log_pmf(value, name='log_pmf')` {#Bernoulli.log_pmf} -Log of the probability mass function. +Log probability mass function. ##### Args: -* `event`: `int32` or `int64` binary Tensor. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the events. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - - -#### `tf.contrib.distributions.Bernoulli.logits` {#Bernoulli.logits} +##### Raises: +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.mean(name='mean')` {#Bernoulli.mean} +#### `tf.contrib.distributions.Bernoulli.log_prob(value, name='log_prob')` {#Bernoulli.log_prob} -Mean of the distribution. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: Name for the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `mean`: `Tensor` of the same type and shape as `p`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Bernoulli.mode(name='mode')` {#Bernoulli.mode} +#### `tf.contrib.distributions.Bernoulli.logits` {#Bernoulli.logits} -Mode of the distribution. -1 if p > 1-p. 0 otherwise. -##### Args: +- - - + +#### `tf.contrib.distributions.Bernoulli.mean(name='mean')` {#Bernoulli.mean} + +Mean. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Bernoulli.mode(name='mode')` {#Bernoulli.mode} -* `mode`: binary `Tensor` of type self.dtype. +Mode. - - - #### `tf.contrib.distributions.Bernoulli.name` {#Bernoulli.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -307,35 +386,78 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Bernoulli.parameters` {#Bernoulli.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Bernoulli.pdf(value, name='pdf')` {#Bernoulli.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Bernoulli.pmf(value, name='pmf')` {#Bernoulli.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Bernoulli.prob(event, name='prob')` {#Bernoulli.prob} +#### `tf.contrib.distributions.Bernoulli.prob(value, name='prob')` {#Bernoulli.prob} -Probability mass function. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `event`: `int32` or `int64` binary Tensor; must be broadcastable with `p`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the events. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -349,23 +471,22 @@ Probability mass function. #### `tf.contrib.distributions.Bernoulli.sample(sample_shape=(), seed=None, name='sample')` {#Bernoulli.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -377,55 +498,40 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. -* `seed`: Python integer seed for RNG. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape` with values of type - `self.dtype`. - - -- - - +* `samples`: a `Tensor` with a prepended dimension (n,). -#### `tf.contrib.distributions.Bernoulli.std(name='std')` {#Bernoulli.std} - -Standard deviation of the distribution. +##### Raises: -##### Args: +* `TypeError`: if `n` is not an integer type. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Bernoulli.std(name='std')` {#Bernoulli.std} -* `std`: `Tensor` of the same type and shape as `p`. +Standard deviation. - - - #### `tf.contrib.distributions.Bernoulli.validate_args` {#Bernoulli.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Bernoulli.variance(name='variance')` {#Bernoulli.variance} -Variance of the distribution. - -##### Args: - - -* `name`: Name for the op. - -##### Returns: - - -* `variance`: `Tensor` of the same type and shape as `p`. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Dirichlet.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Dirichlet.md index a99e3f0568f83eac7bb0a65ce205a1f29bced7c1..0da51e79e2ffd1c8d279b57fb83c8447770c0de2 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Dirichlet.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Dirichlet.md @@ -97,7 +97,21 @@ dist = Dirichlet([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) #### `tf.contrib.distributions.Dirichlet.allow_nan_stats` {#Dirichlet.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -107,11 +121,18 @@ Boolean describing behavior when a stat is undefined for batch member. Shape parameter. +- - - + +#### `tf.contrib.distributions.Dirichlet.alpha_sum` {#Dirichlet.alpha_sum} + +Sum of shape parameter. + + - - - #### `tf.contrib.distributions.Dirichlet.batch_shape(name='batch_shape')` {#Dirichlet.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -123,35 +144,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Dirichlet.cdf(x, name='cdf')` {#Dirichlet.cdf} +#### `tf.contrib.distributions.Dirichlet.cdf(value, name='cdf')` {#Dirichlet.cdf} Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Dirichlet.dtype` {#Dirichlet.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Dirichlet.entropy(name='entropy')` {#Dirichlet.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Dirichlet.event_shape(name='event_shape')` {#Dirichlet.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -160,7 +194,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -180,8 +215,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -224,26 +259,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Dirichlet.get_batch_shape()` {#Dirichlet.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Dirichlet.get_event_shape()` {#Dirichlet.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -262,78 +299,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Dirichlet.log_cdf(x, name='log_cdf')` {#Dirichlet.log_cdf} +#### `tf.contrib.distributions.Dirichlet.log_cdf(value, name='log_cdf')` {#Dirichlet.log_cdf} + +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log CDF. +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Dirichlet.log_pdf(value, name='log_pdf')` {#Dirichlet.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Dirichlet.log_pmf(value, name='log_pmf')` {#Dirichlet.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.log_prob(x, name='log_prob')` {#Dirichlet.log_prob} +#### `tf.contrib.distributions.Dirichlet.log_pmf(value, name='log_pmf')` {#Dirichlet.log_pmf} -`Log(P[counts])`, computed for every batch member. +Log probability mass function. ##### Args: -* `x`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet distribution - in `self.alpha`. `x` is only legal if it sums up to one. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Dirichlet.mean(name='mean')` {#Dirichlet.mean} -Mean of the distribution. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.mode(name='mode')` {#Dirichlet.mode} - -Mode of the distribution. +#### `tf.contrib.distributions.Dirichlet.log_prob(value, name='log_prob')` {#Dirichlet.log_prob} -Note that the mode for the Beta distribution is only defined -when `alpha > 1`. This returns the mode when `alpha > 1`, -and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: The name for this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Mode of the Dirichlet distribution. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + +- - - + +#### `tf.contrib.distributions.Dirichlet.mean(name='mean')` {#Dirichlet.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Dirichlet.mode(name='mode')` {#Dirichlet.mode} + +Mode. - - - #### `tf.contrib.distributions.Dirichlet.name` {#Dirichlet.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -378,101 +446,145 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Dirichlet.parameters` {#Dirichlet.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Dirichlet.pdf(value, name='pdf')` {#Dirichlet.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Dirichlet.pmf(value, name='pmf')` {#Dirichlet.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Dirichlet.prob(x, name='prob')` {#Dirichlet.prob} +#### `tf.contrib.distributions.Dirichlet.prob(value, name='prob')` {#Dirichlet.prob} -`P[x]`, computed for every batch member. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents x for the corresponding Dirichlet distribution in - `self.alpha` and `self.beta`. `x` is only legal if it sums up to one. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Dirichlet.sample(sample_shape=(), seed=None, name='sample')` {#Dirichlet.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Dirichlet.sample_n(n, seed=None, name='sample_n')` {#Dirichlet.sample_n} -Sample `n` observations from the distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Dirichlet.std(name='std')` {#Dirichlet.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Dirichlet.validate_args` {#Dirichlet.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Dirichlet.variance(name='variance')` {#Dirichlet.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Distribution.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Distribution.md index 10c613a163432d7168f965814d6b4aad778a831a..80ae0062e62df2a6ef027335a2ccf822106fdae0 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Distribution.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.Distribution.md @@ -1,19 +1,22 @@ -Fully-featured abstract base class for probability distributions. +A generic probability distribution base class. -This class defines the API for probability distributions. Users will only ever -instantiate subclasses of `Distribution`. +`Distribution` is a base class for constructing and organizing properties +(e.g., mean, variance) of random variables (e.g, Bernoulli, Gaussian). -### API +### Subclassing -The key methods for probability distributions are defined here. +Subclasess are expected to implement a leading-underscore version of the +same-named function. The argument signature should be identical except for +the omission of `name="..."`. For example, to enable `log_prob(value, +name="log_prob")` a subclass should implement `_log_prob(value)`. -To keep ops generated by the distribution tied together by name, subclasses -should override `name` and use it to prepend names of ops in other methods -(see `cdf` for an example). +Subclasses can rewrite/append to public-level docstrings. For example, -Subclasses that wish to support `cdf` and `log_cdf` can override `log_cdf` -and use the base class's implementation for `cdf`, or vice versa. The same -goes for `log_prob` and `prob`. +```python +Subclass.prob.__func__.__doc__ += "Some other details." +``` + +would add the string "Some other details." to the `prob` function docstring. ### Broadcasting, batching, and shapes @@ -102,16 +105,57 @@ dist.mean().eval() ``` - - - +#### `tf.contrib.distributions.Distribution.__init__(dtype=None, parameters=None, is_continuous=True, is_reparameterized=False, validate_args=True, allow_nan_stats=False, name=None)` {#Distribution.__init__} + +Constructs the `Distribution`. + +##### Args: + + +* `dtype`: The type of the event samples. `None` implies no type-enforcement. +* `parameters`: Python dictionary of parameters used by this `Distribution`. +* `is_continuous`: Python boolean, default `True`. If `True` this + `Distribution` is continuous over its supported domain. +* `is_reparameterized`: Python boolean, default `False`. If `True` this + `Distribution` can be reparameterized in terms of some standard + distribution with a function whose Jacobian is constant for the support + of the standard distribution. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. +* `allow_nan_stats`: Python boolean, default `False`. If `False`, raise an + exception if a statistic (e.g., mean, mode) is undefined for any batch + member. If True, batch members with valid parameters leading to + undefined statistics will return `NaN` for this statistic. +* `name`: A name for this distribution (optional). + + +- - - + #### `tf.contrib.distributions.Distribution.allow_nan_stats` {#Distribution.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Distribution.batch_shape(name='batch_shape')` {#Distribution.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -123,7 +167,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -132,26 +177,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Distribution.dtype` {#Distribution.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Distribution.entropy(name='entropy')` {#Distribution.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Distribution.event_shape(name='event_shape')` {#Distribution.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -160,7 +217,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -180,8 +238,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -224,19 +282,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Distribution.get_batch_shape()` {#Distribution.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. + - - - #### `tf.contrib.distributions.Distribution.get_event_shape()` {#Distribution.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -256,49 +324,107 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Distribution.log_cdf(value, name='log_cdf')` {#Distribution.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.log_pdf(value, name='log_pdf')` {#Distribution.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.log_pmf(value, name='log_pmf')` {#Distribution.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.log_prob(value, name='log_prob')` {#Distribution.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.mean(name='mean')` {#Distribution.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Distribution.mode(name='mode')` {#Distribution.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.Distribution.name` {#Distribution.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -343,48 +469,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Distribution.parameters` {#Distribution.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Distribution.pdf(value, name='pdf')` {#Distribution.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.pmf(value, name='pmf')` {#Distribution.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.Distribution.prob(value, name='prob')` {#Distribution.prob} -Probability density/mass function. +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Distribution.sample(sample_shape=(), seed=None, name='sample')` {#Distribution.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -396,35 +574,40 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Distribution.std(name='std')` {#Distribution.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Distribution.validate_args` {#Distribution.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Distribution.variance(name='variance')` {#Distribution.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.MultivariateNormalCholesky.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.MultivariateNormalCholesky.md index ff0218d03b7a62e72fd1518e54473cca6d9550af..085d7a660ef10d3b997ddeaf5a5f98016280dd71 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.MultivariateNormalCholesky.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.distributions.MultivariateNormalCholesky.md @@ -80,14 +80,41 @@ factors, such that the covariance of each batch member is `chol chol^T`. #### `tf.contrib.distributions.MultivariateNormalCholesky.allow_nan_stats` {#MultivariateNormalCholesky.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.batch_shape(name='batch_shape')` {#MultivariateNormalCholesky.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -96,36 +123,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.dtype` {#MultivariateNormalCholesky.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.entropy(name='entropy')` {#MultivariateNormalCholesky.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalCholesky.event_shape(name='event_shape')` {#MultivariateNormalCholesky.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalCholesky.event_shape(name='event_shape')` {#MultivariateNormalCholesky.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -145,8 +184,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -189,14 +228,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalCholesky.get_batch_shape()` {#MultivariateNormalCholesky.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.get_event_shape()` {#MultivariateNormalCholesky.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -217,48 +270,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalCholesky.log_cdf(value, name='log_cdf')` {#MultivariateNormalCholesky.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.log_pdf(value, name='log_pdf')` {#MultivariateNormalCholesky.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.log_pmf(value, name='log_pmf')` {#MultivariateNormalCholesky.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalCholesky.log_prob(x, name='log_prob')` {#MultivariateNormalCholesky.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.log_prob(value, name='log_prob')` {#MultivariateNormalCholesky.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -272,14 +363,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalCholesky.mean(name='mean')` {#MultivariateNormalCholesky.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.mode(name='mode')` {#MultivariateNormalCholesky.mode} -Mode of each batch member. +Mode. - - - @@ -293,7 +384,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalCholesky.name` {#MultivariateNormalCholesky.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -338,88 +429,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.parameters` {#MultivariateNormalCholesky.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.pdf(value, name='pdf')` {#MultivariateNormalCholesky.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.pmf(value, name='pmf')` {#MultivariateNormalCholesky.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalCholesky.prob(x, name='prob')` {#MultivariateNormalCholesky.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -The PDF of observations `x` under these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalCholesky.prob(value, name='prob')` {#MultivariateNormalCholesky.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalCholesky.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalCholesky.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -440,20 +568,20 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalCholesky.std(name='std')` {#MultivariateNormalCholesky.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.validate_args` {#MultivariateNormalCholesky.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalCholesky.variance(name='variance')` {#MultivariateNormalCholesky.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.framework.assign_from_checkpoint.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.framework.assign_from_checkpoint.md new file mode 100644 index 0000000000000000000000000000000000000000..947e672688b03feeb8c1e3f43b22619478ab3428 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.framework.assign_from_checkpoint.md @@ -0,0 +1,23 @@ +### `tf.contrib.framework.assign_from_checkpoint(model_path, var_list)` {#assign_from_checkpoint} + +Creates an operation to assign specific variables from a checkpoint. + +##### Args: + + +* `model_path`: The full path to the model checkpoint. To get latest checkpoint + use `model_path = tf.train.latest_checkpoint(checkpoint_dir)` +* `var_list`: A list of `Variable` objects or a dictionary mapping names in the + checkpoint to the correspoing variables to initialize. If empty or None, + it would return no_op(), None. + +##### Returns: + + the restore_op and the feed_dict that need to be run to restore var_list. + +##### Raises: + + +* `ValueError`: If the checkpoint specified at `model_path` is missing one of + the variables in `var_list`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.learn.LinearRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.learn.LinearRegressor.md index 84a4ee1c7e85c92aa1c38686fabeb091e321fd5f..62dccdf99f679d4d345dfe50c5b42c4a52517245 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.learn.LinearRegressor.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.contrib.learn.LinearRegressor.md @@ -83,6 +83,13 @@ Construct a `LinearRegressor` estimator object. +- - - + +#### `tf.contrib.learn.LinearRegressor.config` {#LinearRegressor.config} + + + + - - - #### `tf.contrib.learn.LinearRegressor.dnn_bias_` {#LinearRegressor.dnn_bias_} @@ -113,7 +120,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.LinearRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#LinearRegressor.export} +#### `tf.contrib.learn.LinearRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#LinearRegressor.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.nn.ctc_loss.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.nn.ctc_loss.md index 229df8bdbd9df09d63a30027581af99a5f63f7a2..7cc14a877a57997b8b5f33a29b9fbf352789c61e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.nn.ctc_loss.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.nn.ctc_loss.md @@ -19,6 +19,18 @@ max(labels.indices(labels.indices[:, 1] == b, 2)) <= sequence_length(b) for all b. ``` +Notes: + +This class performs the softmax operation for you, so inputs should +be e.g. linear projections of outputs by an LSTM. + +The `inputs` Tensor's innermost dimension size, `num_classes`, represents +`num_labels + 1` classes, where num_labels is the number of true labels, and +the largest value `(num_classes - 1)` is reserved for the blank label. + +For example, for a vocabulary containing 3 labels `[a, b, c]`, +`num_classes = 4` and the labels indexing is `{a: 0, b: 1, c: 2, blank: 3}`. + Regarding the arguments `preprocess_collapse_repeated` and `ctc_merge_repeated`: @@ -57,10 +69,12 @@ Here is a table of the (roughly) expected first order behavior: * `inputs`: 3-D `float` `Tensor` sized - `[max_time x batch_size x num_classes]`. The logits. + `[max_time x batch_size x num_classes]`. The logits. * `labels`: An `int32` `SparseTensor`. `labels.indices[i, :] == [b, t]` means `labels.values[i]` stores - the id for (batch b, time t). See `core/ops/ctc_ops.cc` for more details. + the id for (batch b, time t). + `labels.values[i]` must take on values in `[0, num_labels)`. + See `core/ops/ctc_ops.cc` for more details. * `sequence_length`: 1-D `int32` vector, size `[batch_size]`. The sequence lengths. * `preprocess_collapse_repeated`: Boolean. Default: False. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.zeros_initializer.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.zeros_initializer.md index 707393f8bed0ad2f8b9a5b523830f671353e0e56..0936c08b1a5789e1796fd1d5f708a5bbb04a4418 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.zeros_initializer.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard0/tf.zeros_initializer.md @@ -1,4 +1,4 @@ -### `tf.zeros_initializer(shape, dtype=tf.float32)` {#zeros_initializer} +### `tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)` {#zeros_initializer} An adaptor for zeros() to match the Initializer spec. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.MultivariateNormalDiag.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.MultivariateNormalDiag.md index 99cbd331dfed25fabed986efd7294f87461ff2fb..bc8fb0e82880e06489de5698df7ab12f6a74ec2a 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.MultivariateNormalDiag.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.MultivariateNormalDiag.md @@ -79,14 +79,41 @@ The mean of `X_i` is `mu[i]`, and the standard deviation is `diag_stdev[i]`. #### `tf.contrib.distributions.MultivariateNormalDiag.allow_nan_stats` {#MultivariateNormalDiag.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.batch_shape(name='batch_shape')` {#MultivariateNormalDiag.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -95,36 +122,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalDiag.dtype` {#MultivariateNormalDiag.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.entropy(name='entropy')` {#MultivariateNormalDiag.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalDiag.event_shape(name='event_shape')` {#MultivariateNormalDiag.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalDiag.event_shape(name='event_shape')` {#MultivariateNormalDiag.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -144,8 +183,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -188,14 +227,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiag.get_batch_shape()` {#MultivariateNormalDiag.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.get_event_shape()` {#MultivariateNormalDiag.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -216,48 +269,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiag.log_cdf(value, name='log_cdf')` {#MultivariateNormalDiag.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.log_pdf(value, name='log_pdf')` {#MultivariateNormalDiag.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.log_pmf(value, name='log_pmf')` {#MultivariateNormalDiag.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalDiag.log_prob(x, name='log_prob')` {#MultivariateNormalDiag.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.log_prob(value, name='log_prob')` {#MultivariateNormalDiag.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -271,14 +362,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiag.mean(name='mean')` {#MultivariateNormalDiag.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.mode(name='mode')` {#MultivariateNormalDiag.mode} -Mode of each batch member. +Mode. - - - @@ -292,7 +383,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalDiag.name` {#MultivariateNormalDiag.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -337,88 +428,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.parameters` {#MultivariateNormalDiag.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalDiag.pdf(value, name='pdf')` {#MultivariateNormalDiag.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.pmf(value, name='pmf')` {#MultivariateNormalDiag.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalDiag.prob(x, name='prob')` {#MultivariateNormalDiag.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -The PDF of observations `x` under these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiag.prob(value, name='prob')` {#MultivariateNormalDiag.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalDiag.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalDiag.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -439,20 +567,20 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiag.std(name='std')` {#MultivariateNormalDiag.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.validate_args` {#MultivariateNormalDiag.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalDiag.variance(name='variance')` {#MultivariateNormalDiag.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.StudentT.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.StudentT.md index 81ef29de738316c68c0bc7c264755a05287cb941..3109e3e4ace24d05c5f672058567cf641d1dfab2 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.StudentT.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.StudentT.md @@ -82,14 +82,41 @@ broadcasting (e.g. `df + mu + sigma` is a valid operation). #### `tf.contrib.distributions.StudentT.allow_nan_stats` {#StudentT.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.StudentT.batch_shape(name='batch_shape')` {#StudentT.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -98,6 +125,18 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -110,31 +149,31 @@ Degrees of freedom in these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.dtype` {#StudentT.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.StudentT.entropy(name='entropy')` {#StudentT.entropy} -The entropy of Student t distribution(s). - -##### Args: +Shanon entropy in nats. -* `name`: The name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.StudentT.event_shape(name='event_shape')` {#StudentT.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: tensor of dtype `dtype`, the entropy. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.StudentT.event_shape(name='event_shape')` {#StudentT.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -154,8 +193,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -198,14 +237,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.StudentT.get_batch_shape()` {#StudentT.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.StudentT.get_event_shape()` {#StudentT.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -226,66 +279,100 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.StudentT.log_cdf(value, name='log_cdf')` {#StudentT.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.StudentT.log_pdf(value, name='log_pdf')` {#StudentT.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.StudentT.log_pmf(value, name='log_pmf')` {#StudentT.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.StudentT.log_prob(x, name='log_prob')` {#StudentT.log_prob} +#### `tf.contrib.distributions.StudentT.log_pmf(value, name='log_pmf')` {#StudentT.log_pmf} -Log prob of observations in `x` under these Student's t-distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `df`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. +##### Raises: -- - - -#### `tf.contrib.distributions.StudentT.mean(name='mean')` {#StudentT.mean} +* `AttributeError`: if `is_continuous`. -Mean of the distribution. -The mean of Student's T equals `mu` if `df > 1`, otherwise it is `NaN`. If -`self.allow_nan_stats=False`, then an exception will be raised rather than -returning `NaN`. +- - - + +#### `tf.contrib.distributions.StudentT.log_prob(value, name='log_prob')` {#StudentT.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: A name to give this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.StudentT.mode(name='mode')` {#StudentT.mode} +#### `tf.contrib.distributions.StudentT.mean(name='mean')` {#StudentT.mean} + +Mean. +- - - + +#### `tf.contrib.distributions.StudentT.mode(name='mode')` {#StudentT.mode} + +Mode. - - - @@ -299,7 +386,7 @@ Locations of these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.name` {#StudentT.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -344,80 +431,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.StudentT.parameters` {#StudentT.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.StudentT.pdf(value, name='pdf')` {#StudentT.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.StudentT.pmf(value, name='pmf')` {#StudentT.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.StudentT.prob(x, name='prob')` {#StudentT.prob} +#### `tf.contrib.distributions.StudentT.prob(value, name='prob')` {#StudentT.prob} -The PDF of observations in `x` under these Student's t distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `df`, `mu`, and - `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.StudentT.sample(sample_shape=(), seed=None, name='sample')` {#StudentT.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.StudentT.sample_n(n, seed=None, name='sample_n')` {#StudentT.sample_n} -Sample `n` observations from the Student t Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -431,41 +563,20 @@ Scaling factors of these Student's t distribution(s). #### `tf.contrib.distributions.StudentT.std(name='std')` {#StudentT.std} - +Standard deviation. - - - #### `tf.contrib.distributions.StudentT.validate_args` {#StudentT.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.StudentT.variance(name='variance')` {#StudentT.variance} -Variance of the distribution. - -Variance for Student's T equals - -``` -df / (df - 2), when df > 2 -infinity, when 1 < df <= 2 -NaN, when df <= 1 -``` - -The NaN state occurs because mean is undefined for `df <= 1`, and if -`self.allow_nan_stats` is `False`, an exception will be raised if any batch -members fall into this state. - -##### Args: - - -* `name`: A name for this op. - -##### Returns: - - The variance for every batch member, a `Tensor` with same `dtype` as self. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.TransformedDistribution.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.TransformedDistribution.md index 6b1f752686518cd0fcb2074a95bc84d9dd8c9baa..6cc092faadeeeb6b8c88674a5f77677d0f39343a 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.TransformedDistribution.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.distributions.TransformedDistribution.md @@ -64,7 +64,21 @@ Construct a Transformed Distribution. #### `tf.contrib.distributions.TransformedDistribution.allow_nan_stats` {#TransformedDistribution.allow_nan_stats} +Python boolean describing behavior when a stat is undefined. +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -78,7 +92,7 @@ Base distribution, p(x). #### `tf.contrib.distributions.TransformedDistribution.batch_shape(name='batch_shape')` {#TransformedDistribution.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -86,11 +100,12 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -99,35 +114,48 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.TransformedDistribution.dtype` {#TransformedDistribution.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.TransformedDistribution.entropy(name='entropy')` {#TransformedDistribution.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.TransformedDistribution.event_shape(name='event_shape')` {#TransformedDistribution.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -147,8 +175,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -191,26 +219,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.TransformedDistribution.get_batch_shape()` {#TransformedDistribution.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.TransformedDistribution.get_event_shape()` {#TransformedDistribution.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -238,7 +268,19 @@ Inverse function of transform, y => x. #### `tf.contrib.distributions.TransformedDistribution.log_cdf(value, name='log_cdf')` {#TransformedDistribution.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -252,61 +294,88 @@ Function computing the log determinant of the Jacobian of transform. #### `tf.contrib.distributions.TransformedDistribution.log_pdf(value, name='log_pdf')` {#TransformedDistribution.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.TransformedDistribution.log_pmf(value, name='log_pmf')` {#TransformedDistribution.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.TransformedDistribution.log_prob(y, name='log_prob')` {#TransformedDistribution.log_prob} -Log prob of observations in `y`. +* `AttributeError`: if not `is_continuous`. -`log ( p(g(y)) / det|J(g(y))| )`, where `g` is the inverse of `transform`. + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.log_pmf(value, name='log_pmf')` {#TransformedDistribution.log_pmf} + +Log probability mass function. ##### Args: -* `y`: tensor of dtype `dtype`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_pdf`: tensor of dtype `dtype`, the log-PDFs of `y`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `ValueError`: if `inverse` was not provided to the distribution and `y` was - not returned from `sample`. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.TransformedDistribution.log_prob(value, name='log_prob')` {#TransformedDistribution.log_prob} + +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.TransformedDistribution.mean(name='mean')` {#TransformedDistribution.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.TransformedDistribution.mode(name='mode')` {#TransformedDistribution.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.TransformedDistribution.name` {#TransformedDistribution.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -351,89 +420,132 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.TransformedDistribution.parameters` {#TransformedDistribution.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.TransformedDistribution.pdf(value, name='pdf')` {#TransformedDistribution.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.TransformedDistribution.pmf(value, name='pmf')` {#TransformedDistribution.pmf} -The probability mass function. +Probability mass function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -- - - -#### `tf.contrib.distributions.TransformedDistribution.prob(y, name='prob')` {#TransformedDistribution.prob} +* `AttributeError`: if `is_continuous`. -The prob of observations in `y`. -`p(g(y)) / det|J(g(y))|`, where `g` is the inverse of `transform`. +- - - + +#### `tf.contrib.distributions.TransformedDistribution.prob(value, name='prob')` {#TransformedDistribution.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `y`: `Tensor` of dtype `dtype`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `pdf`: `Tensor` of dtype `dtype`, the pdf values of `y`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.TransformedDistribution.sample(sample_shape=(), seed=None, name='sample')` {#TransformedDistribution.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.TransformedDistribution.sample_n(n, seed=None, name='sample_n')` {#TransformedDistribution.sample_n} -Sample `n` observations. - -Samples from the base distribution and then passes through the transform. +Generate `n` samples. ##### Args: -* `n`: scalar, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.TransformedDistribution.std(name='std')` {#TransformedDistribution.std} -Standard deviation of the distribution. +Standard deviation. - - - @@ -447,13 +559,13 @@ Function transforming x => y. #### `tf.contrib.distributions.TransformedDistribution.validate_args` {#TransformedDistribution.validate_args} - +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.TransformedDistribution.variance(name='variance')` {#TransformedDistribution.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.learn.LinearClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.learn.LinearClassifier.md index 938e2dbc8ee0da862bf7bdf8885ebb3d1141b3fd..321c4a9fb316a649daaf523af2b15d93298a2b2e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.learn.LinearClassifier.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.learn.LinearClassifier.md @@ -101,6 +101,13 @@ Construct a `LinearClassifier` estimator object. +- - - + +#### `tf.contrib.learn.LinearClassifier.config` {#LinearClassifier.config} + + + + - - - #### `tf.contrib.learn.LinearClassifier.dnn_bias_` {#LinearClassifier.dnn_bias_} @@ -131,7 +138,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.LinearClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#LinearClassifier.export} +#### `tf.contrib.learn.LinearClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#LinearClassifier.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.training.stratified_sample_unknown_dist.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.training.stratified_sample_unknown_dist.md new file mode 100644 index 0000000000000000000000000000000000000000..e4932aa73b9b343b73ff98175365b78b5684e1f2 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.contrib.training.stratified_sample_unknown_dist.md @@ -0,0 +1,58 @@ +### `tf.contrib.training.stratified_sample_unknown_dist(tensors, labels, probs, batch_size, enqueue_many=False, queue_capacity=16, threads_per_queue=1, name=None)` {#stratified_sample_unknown_dist} + +Stochastically creates batches based on per-class probabilities. + +**NOTICE** This sampler can be significantly slower than `stratified_sample` +due to each thread discarding all examples not in its assigned class. + +This uses a number of threads proportional to the number of classes. See +`stratified_sample` for an implementation that discards fewer examples and +uses a fixed number of threads. This function's only advantage over +`stratified_sample` is that the class data-distribution doesn't need to be +known ahead of time. + +##### Args: + + +* `tensors`: List of tensors for data. All tensors are either one item or a + batch, according to enqueue_many. +* `labels`: Tensor for label of data. Label is a single integer or a batch, + depending on enqueue_many. It is not a one-hot vector. +* `probs`: Target class probabilities. An object whose type has a registered + Tensor conversion function. +* `batch_size`: Size of batch to be returned. +* `enqueue_many`: Bool. If true, interpret input tensors as having a batch + dimension. +* `queue_capacity`: Capacity of each per-class queue. +* `threads_per_queue`: Number of threads for each per-class queue. +* `name`: Optional prefix for ops created by this function. + +##### Raises: + + +* `ValueError`: enqueue_many is True and labels doesn't have a batch + dimension, or if enqueue_many is False and labels isn't a scalar. +* `ValueError`: enqueue_many is True, and batch dimension of data and labels + don't match. +* `ValueError`: if probs don't sum to one. +* `TFAssertion`: if labels aren't integers in [0, num classes). + +##### Returns: + + (data_batch, label_batch), where data_batch is a list of tensors of the same + length as `tensors` + +##### Example: + + # Get tensor for a single data and label example. + data, label = data_provider.Get(['data', 'label']) + + # Get stratified batch according to per-class probabilities. + init_probs = [1.0/NUM_CLASSES for _ in range(NUM_CLASSES)] + [data_batch], labels = ( + tf.contrib.framework.sampling_ops.stratified_sample_unknown_dist( + [data], label, init_probs, 16)) + + # Run batch through network. + ... + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.reduce_logsumexp.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.reduce_logsumexp.md new file mode 100644 index 0000000000000000000000000000000000000000..29c3c1c0fe9fc04efb9819e18232c377ec59611f --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard1/tf.reduce_logsumexp.md @@ -0,0 +1,41 @@ +### `tf.reduce_logsumexp(input_tensor, reduction_indices=None, keep_dims=False, name=None)` {#reduce_logsumexp} + +Computes log(sum(exp(elements across dimensions of a tensor))). + +Reduces `input_tensor` along the dimensions given in `reduction_indices`. +Unless `keep_dims` is true, the rank of the tensor is reduced by 1 for each +entry in `reduction_indices`. If `keep_dims` is true, the reduced dimensions +are retained with length 1. + +If `reduction_indices` has no entries, all dimensions are reduced, and a +tensor with a single element is returned. + +This funciton is more numerically stable than log(sum(exp(input))). It avoids +overflows caused by taking the exp of large inputs and underflows caused by +taking the log of small inputs. + +For example: + +```python +# 'x' is [[0, 0, 0]] +# [0, 0, 0]] +tf.reduce_logsumexp(x) ==> log(6) +tf.reduce_logsumexp(x, 0) ==> [log(2), log(2), log(2)] +tf.reduce_logsumexp(x, 1) ==> [log(3), log(3)] +tf.reduce_logsumexp(x, 1, keep_dims=True) ==> [[log(3)], [log(3)]] +tf.reduce_logsumexp(x, [0, 1]) ==> log(6) +``` + +##### Args: + + +* `input_tensor`: The tensor to reduce. Should have numeric type. +* `reduction_indices`: The dimensions to reduce. If `None` (the defaut), + reduces all dimensions. +* `keep_dims`: If true, retains reduced dimensions with length 1. +* `name`: A name for the operation (optional). + +##### Returns: + + The reduced tensor. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.betainc.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.betainc.md new file mode 100644 index 0000000000000000000000000000000000000000..9da04a364260e716a16cee5c5055a437d57d730e --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.betainc.md @@ -0,0 +1,30 @@ +### `tf.betainc(a, b, x, name=None)` {#betainc} + +Compute the regularized incomplete beta integral \\(I_x(a, b)\\). + +The regularized incomplete beta integral is defined as: + +``` +I_x(a, b) = \frac{B(x; a, b)}{B(a, b)} +``` +where + +``` +B(x; a, b) = \int_0^x t^{a-1} (1 - t)^{b-1} dt +``` + +is the incomplete beta function and \\(B(a, b)\\) is the *complete* +beta function. + +##### Args: + + +* `a`: A `Tensor`. Must be one of the following types: `float32`, `float64`. +* `b`: A `Tensor`. Must have the same type as `a`. +* `x`: A `Tensor`. Must have the same type as `a`. +* `name`: A name for the operation (optional). + +##### Returns: + + A `Tensor`. Has the same type as `a`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.bayesflow.monte_carlo.expectation.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.bayesflow.monte_carlo.expectation.md new file mode 100644 index 0000000000000000000000000000000000000000..f34649987b12d0afe84be243daa191b0de219e37 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.bayesflow.monte_carlo.expectation.md @@ -0,0 +1,29 @@ +### `tf.contrib.bayesflow.monte_carlo.expectation(f, p, z=None, n=None, seed=None, name='expectation')` {#expectation} + +Monte Carlo estimate of an expectation: `E_p[f(Z)]` with sample mean. + +This `Op` returns + +``` +n^{-1} sum_{i=1}^n f(z_i), where z_i ~ p +\approx E_p[f(Z)] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `f` works "just like" `sampling_dist_q.log_prob`. +* `p`: `tf.contrib.distributions.BaseDistribution`. +* `z`: `Tensor` of samples from `p`, produced by `p.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Categorical.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Categorical.md index 037e5f05d35ff4a311bf65bee24fd512e47f72fd..bd3b960af86e9148ef4b291d5c9c4e8139744947 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Categorical.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Categorical.md @@ -28,14 +28,41 @@ Initialize Categorical distributions using class log-probabilities. #### `tf.contrib.distributions.Categorical.allow_nan_stats` {#Categorical.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Categorical.batch_shape(name='batch_shape')` {#Categorical.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -44,27 +71,49 @@ Boolean describing behavior when a stat is undefined for batch member. Cumulative distribution function. +##### Args: + -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.Categorical.dtype` {#Categorical.dtype} +##### Returns: +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Categorical.entropy(name='sample')` {#Categorical.entropy} +#### `tf.contrib.distributions.Categorical.dtype` {#Categorical.dtype} + +The `DType` of `Tensor`s handled by this `Distribution`. + +- - - + +#### `tf.contrib.distributions.Categorical.entropy(name='entropy')` {#Categorical.entropy} +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Categorical.event_shape(name='event_shape')` {#Categorical.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: +* `name`: name to give to the op + +##### Returns: + + +* `event_shape`: `Tensor`. + - - - @@ -83,8 +132,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -127,15 +176,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Categorical.get_batch_shape()` {#Categorical.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Categorical.get_event_shape()` {#Categorical.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -155,39 +218,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Categorical.log_cdf(value, name='log_cdf')` {#Categorical.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Categorical.log_pdf(value, name='log_pdf')` {#Categorical.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Categorical.log_pmf(value, name='log_pmf')` {#Categorical.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Categorical.log_prob(k, name='log_prob')` {#Categorical.log_prob} +#### `tf.contrib.distributions.Categorical.log_prob(value, name='log_prob')` {#Categorical.log_prob} -Log-probability of class `k`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `k`: `int32` or `int64` Tensor. Must be broadcastable with a `batch_shape` - `Tensor`. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the classes indexed by `k` + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -201,21 +311,21 @@ Log-probability of class `k`. #### `tf.contrib.distributions.Categorical.mean(name='mean')` {#Categorical.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Categorical.mode(name='mode')` {#Categorical.mode} - +Mode. - - - #### `tf.contrib.distributions.Categorical.name` {#Categorical.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -267,96 +377,145 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Categorical.parameters` {#Categorical.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Categorical.pdf(value, name='pdf')` {#Categorical.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Categorical.pmf(value, name='pmf')` {#Categorical.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Categorical.prob(k, name='prob')` {#Categorical.prob} +#### `tf.contrib.distributions.Categorical.prob(value, name='prob')` {#Categorical.prob} -Probability of class `k`. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `k`: `int32` or `int64` Tensor. Must be broadcastable with logits. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the classes indexed by `k` + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Categorical.sample(sample_shape=(), seed=None, name='sample')` {#Categorical.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Categorical.sample_n(n, seed=None, name='sample_n')` {#Categorical.sample_n} -Sample `n` observations from the Categorical distribution. +Generate `n` samples. ##### Args: -* `n`: 0-D. Number of independent samples to draw for each distribution. -* `seed`: Random seed (optional). -* `name`: A name for this operation (optional). +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: - An `int64` `Tensor` with shape `[n, batch_shape, event_shape]` + +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Categorical.std(name='std')` {#Categorical.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Categorical.validate_args` {#Categorical.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Categorical.variance(name='variance')` {#Categorical.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Chi2.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Chi2.md index e1e7a63c22d2303998abb4db28ead8a7af22e4c6..9734c0420feb8b18fcf91dcdd4856bc51acfee80 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Chi2.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Chi2.md @@ -31,7 +31,21 @@ Construct Chi2 distributions with parameter `df`. #### `tf.contrib.distributions.Chi2.allow_nan_stats` {#Chi2.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -45,7 +59,7 @@ Shape parameter. #### `tf.contrib.distributions.Chi2.batch_shape(name='batch_shape')` {#Chi2.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -57,7 +71,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -69,20 +84,21 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Chi2.cdf(x, name='cdf')` {#Chi2.cdf} +#### `tf.contrib.distributions.Chi2.cdf(value, name='cdf')` {#Chi2.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -96,40 +112,21 @@ CDF of observations `x` under these Gamma distribution(s). #### `tf.contrib.distributions.Chi2.dtype` {#Chi2.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Chi2.entropy(name='entropy')` {#Chi2.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Chi2.event_shape(name='event_shape')` {#Chi2.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -138,7 +135,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -158,8 +156,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -202,26 +200,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Chi2.get_batch_shape()` {#Chi2.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Chi2.get_event_shape()` {#Chi2.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -240,91 +240,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Chi2.log_cdf(x, name='log_cdf')` {#Chi2.log_cdf} +#### `tf.contrib.distributions.Chi2.log_cdf(value, name='log_cdf')` {#Chi2.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Chi2.log_pdf(value, name='log_pdf')` {#Chi2.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Chi2.log_pmf(value, name='log_pmf')` {#Chi2.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.log_prob(x, name='log_prob')` {#Chi2.log_prob} +#### `tf.contrib.distributions.Chi2.log_pmf(value, name='log_pmf')` {#Chi2.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.mean(name='mean')` {#Chi2.mean} +#### `tf.contrib.distributions.Chi2.log_prob(value, name='log_prob')` {#Chi2.log_prob} -Mean of each batch member. +Log probability density/mass function (depending on `is_continuous`). +##### Args: -- - - -#### `tf.contrib.distributions.Chi2.mode(name='mode')` {#Chi2.mode} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Mode of each batch member. +##### Returns: -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. -##### Args: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Chi2.mean(name='mean')` {#Chi2.mean} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mean. + + +- - - + +#### `tf.contrib.distributions.Chi2.mode(name='mode')` {#Chi2.mode} + +Mode. - - - #### `tf.contrib.distributions.Chi2.name` {#Chi2.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -371,105 +389,143 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Chi2.pdf(value, name='pdf')` {#Chi2.pdf} +#### `tf.contrib.distributions.Chi2.parameters` {#Chi2.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Chi2.pmf(value, name='pmf')` {#Chi2.pmf} +#### `tf.contrib.distributions.Chi2.pdf(value, name='pdf')` {#Chi2.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -The probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Chi2.prob(x, name='prob')` {#Chi2.prob} +#### `tf.contrib.distributions.Chi2.pmf(value, name='pmf')` {#Chi2.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Chi2.prob(value, name='prob')` {#Chi2.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Chi2.sample(sample_shape=(), seed=None, name='sample')` {#Chi2.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Chi2.sample_n(n, seed=None, name='sample_n')` {#Chi2.sample_n} -Draws `n` samples from the Gamma distribution(s). - -See the doc for tf.random_gamma for further detail. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Chi2.std(name='std')` {#Chi2.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Chi2.validate_args` {#Chi2.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Chi2.variance(name='variance')` {#Chi2.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Uniform.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Uniform.md index f0d6fe0dbc610a9bdf1ea656128623d415cbdbae..c40c7637d6268641bf421ea1461dc8e54eeb4beb 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Uniform.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.Uniform.md @@ -58,7 +58,21 @@ u1 = Uniform(3.0, [5.0, 6.0, 7.0]) # 3 distributions #### `tf.contrib.distributions.Uniform.allow_nan_stats` {#Uniform.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -72,57 +86,70 @@ Boolean describing behavior when a stat is undefined for batch member. #### `tf.contrib.distributions.Uniform.batch_shape(name='batch_shape')` {#Uniform.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. + - - - -#### `tf.contrib.distributions.Uniform.cdf(x, name='cdf')` {#Uniform.cdf} +#### `tf.contrib.distributions.Uniform.cdf(value, name='cdf')` {#Uniform.cdf} -CDF of observations in `x` under these Uniform distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. If `x` is `nan`, will - return `nan`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Uniform.dtype` {#Uniform.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Uniform.entropy(name='entropy')` {#Uniform.entropy} -The entropy of Uniform distribution(s). +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. - -##### Returns: +#### `tf.contrib.distributions.Uniform.event_shape(name='event_shape')` {#Uniform.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. -* `entropy`: tensor of dtype `dtype`, the entropy. +##### Args: -- - - +* `name`: name to give to the op -#### `tf.contrib.distributions.Uniform.event_shape(name='event_shape')` {#Uniform.event_shape} +##### Returns: +* `event_shape`: `Tensor`. - - - @@ -142,8 +169,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -186,15 +213,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Uniform.get_batch_shape()` {#Uniform.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Uniform.get_event_shape()` {#Uniform.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -212,51 +253,109 @@ apply it externally and set `make_safe=False`. - - - -#### `tf.contrib.distributions.Uniform.log_cdf(x, name='log_cdf')` {#Uniform.log_cdf} +#### `tf.contrib.distributions.Uniform.log_cdf(value, name='log_cdf')` {#Uniform.log_cdf} + +Log cumulative distribution function. + +##### Args: +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Uniform.log_pdf(value, name='log_pdf')` {#Uniform.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Uniform.log_pmf(value, name='log_pmf')` {#Uniform.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Uniform.log_prob(x, name='log_prob')` {#Uniform.log_prob} +#### `tf.contrib.distributions.Uniform.log_prob(value, name='log_prob')` {#Uniform.log_prob} +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Uniform.mean(name='mean')` {#Uniform.mean} - +Mean. - - - #### `tf.contrib.distributions.Uniform.mode(name='mode')` {#Uniform.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.Uniform.name` {#Uniform.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -301,37 +400,78 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Uniform.parameters` {#Uniform.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Uniform.pdf(value, name='pdf')` {#Uniform.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Uniform.pmf(value, name='pmf')` {#Uniform.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Uniform.prob(x, name='prob')` {#Uniform.prob} +#### `tf.contrib.distributions.Uniform.prob(value, name='prob')` {#Uniform.prob} -The PDF of observations in `x` under these Uniform distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `a` and `b`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. If `x` is `nan`, - will return `nan`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -345,63 +485,67 @@ The PDF of observations in `x` under these Uniform distribution(s). #### `tf.contrib.distributions.Uniform.sample(sample_shape=(), seed=None, name='sample')` {#Uniform.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Uniform.sample_n(n, seed=None, name='sample_n')` {#Uniform.sample_n} -Sample `n` observations from the Uniform Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Uniform.std(name='std')` {#Uniform.std} - +Standard deviation. - - - #### `tf.contrib.distributions.Uniform.validate_args` {#Uniform.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Uniform.variance(name='variance')` {#Uniform.variance} - +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.WishartCholesky.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.WishartCholesky.md index de410d5eaef29b167d3346c7b4dc321952c3f1fe..fd5a7b705fe4a9cc41f180583c7b872b528ea86d 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.WishartCholesky.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.distributions.WishartCholesky.md @@ -59,7 +59,7 @@ dist.pdf(x) # Shape is [2, 2]. ``` - - - -#### `tf.contrib.distributions.WishartCholesky.__init__(df, scale, cholesky_input_output_matrices=False, allow_nan_stats=False, validate_args=True, name='Wishart')` {#WishartCholesky.__init__} +#### `tf.contrib.distributions.WishartCholesky.__init__(df, scale, cholesky_input_output_matrices=False, validate_args=True, allow_nan_stats=False, name='WishartCholesky')` {#WishartCholesky.__init__} Construct Wishart distributions. @@ -75,13 +75,13 @@ Construct Wishart distributions. Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. * `allow_nan_stats`: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. -* `validate_args`: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. * `name`: The name scope to give class member ops. @@ -89,14 +89,41 @@ Construct Wishart distributions. #### `tf.contrib.distributions.WishartCholesky.allow_nan_stats` {#WishartCholesky.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.WishartCholesky.batch_shape(name='batch_shape')` {#WishartCholesky.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -105,6 +132,18 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -131,21 +170,31 @@ Dimension of underlying vector space. The `p` in `R^(p*p)`. #### `tf.contrib.distributions.WishartCholesky.dtype` {#WishartCholesky.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.WishartCholesky.entropy(name='entropy')` {#WishartCholesky.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.WishartCholesky.event_shape(name='event_shape')` {#WishartCholesky.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `event_shape`: `Tensor`. - - - @@ -165,8 +214,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -209,33 +258,40 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.WishartCholesky.get_batch_shape()` {#WishartCholesky.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.WishartCholesky.get_event_shape()` {#WishartCholesky.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. +Same meaning as `event_shape`. May be only partially defined. -- - - +##### Returns: -#### `tf.contrib.distributions.WishartCholesky.inputs` {#WishartCholesky.inputs} -Dictionary of inputs provided at initialization. +* `event_shape`: `TensorShape`, possibly unknown. - - - -#### `tf.contrib.distributions.WishartCholesky.is_continuous()` {#WishartCholesky.is_continuous} +#### `tf.contrib.distributions.WishartCholesky.is_continuous` {#WishartCholesky.is_continuous} - - - -#### `tf.contrib.distributions.WishartCholesky.is_reparameterized()` {#WishartCholesky.is_reparameterized} +#### `tf.contrib.distributions.WishartCholesky.is_reparameterized` {#WishartCholesky.is_reparameterized} @@ -244,7 +300,19 @@ Dictionary of inputs provided at initialization. #### `tf.contrib.distributions.WishartCholesky.log_cdf(value, name='log_cdf')` {#WishartCholesky.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -258,26 +326,60 @@ Computes the log normalizing constant, log(Z). #### `tf.contrib.distributions.WishartCholesky.log_pdf(value, name='log_pdf')` {#WishartCholesky.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartCholesky.log_pmf(value, name='log_pmf')` {#WishartCholesky.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.WishartCholesky.log_prob(x, name='log_prob')` {#WishartCholesky.log_prob} +#### `tf.contrib.distributions.WishartCholesky.log_prob(value, name='log_prob')` {#WishartCholesky.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: `float` or `double` `Tensor`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: @@ -291,7 +393,7 @@ Log of the probability density/mass function. #### `tf.contrib.distributions.WishartCholesky.mean(name='mean')` {#WishartCholesky.mean} -Mean of the distribution. +Mean. - - - @@ -305,14 +407,14 @@ Computes E[log(det(X))] under this Wishart distribution. #### `tf.contrib.distributions.WishartCholesky.mode(name='mode')` {#WishartCholesky.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.WishartCholesky.name` {#WishartCholesky.name} -Name prepended to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -357,75 +459,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.WishartCholesky.parameters` {#WishartCholesky.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.WishartCholesky.pdf(value, name='pdf')` {#WishartCholesky.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartCholesky.pmf(value, name='pmf')` {#WishartCholesky.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.WishartCholesky.prob(value, name='prob')` {#WishartCholesky.prob} -Probability density/mass function. +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.WishartCholesky.sample(sample_shape=(), seed=None, name='sample')` {#WishartCholesky.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - -#### `tf.contrib.distributions.WishartCholesky.sample_n(n, seed=None, name='sample')` {#WishartCholesky.sample_n} +#### `tf.contrib.distributions.WishartCholesky.sample_n(n, seed=None, name='sample_n')` {#WishartCholesky.sample_n} Generate `n` samples. -Complexity: O(nbk^3) - -The sampling procedure is based on the [Bartlett decomposition]( -https://en.wikipedia.org/wiki/Wishart_distribution#Bartlett_decomposition) -and [using a Gamma distribution to generate Chi2 random variates]( -https://en.wikipedia.org/wiki/Chi-squared_distribution#Gamma.2C_exponential.2C_and_related_distributions). - ##### Args: -* `n`: Scalar. Number of samples to draw from each distribution. -* `seed`: Python integer; random number generator seed. -* `name`: The name of this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -446,39 +598,20 @@ Wishart distribution scale matrix as an OperatorPD. #### `tf.contrib.distributions.WishartCholesky.std(name='std')` {#WishartCholesky.std} -Standard deviation of the Wishart distribution. +Standard deviation. - - - #### `tf.contrib.distributions.WishartCholesky.validate_args` {#WishartCholesky.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.WishartCholesky.variance(name='variance')` {#WishartCholesky.variance} -Variance of the Wishart distribution. - -This function should not be confused with the covariance of the Wishart. The -covariance matrix would have shape `q x q` where, -`q = dimension * (dimension+1) / 2` -and having elements corresponding to some mapping from a lower-triangular -matrix to a vector-space. - -This function returns the diagonal of the Covariance matrix but shaped -as a `dimension x dimension` matrix. - -##### Args: - - -* `name`: The name of this op. - -##### Returns: - - -* `variance`: `Tensor` of dtype `self.dtype`. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.graph_editor.copy.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.graph_editor.copy.md index d892a6cc4b12daca2ab2956bb2318ff5f34b046b..60e3acd9bd98d286f4177e3f8584466403bd2f6a 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.graph_editor.copy.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.graph_editor.copy.md @@ -12,11 +12,15 @@ Copy a subgraph. * `src_scope`: the source scope. * `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. Otherwise, the scope is given a unique name based on the one given - by postfixing an underscore followed by a digit (default). + by appending an underscore followed by a digit (default). ##### Returns: - The subgraph view of the copied subgraph. + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.BaseEstimator.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.BaseEstimator.md index d28802d992af397443de3e7fe3298f386d2f38d5..586fb6314aada1595b8c2c61e264b3d36527d86a 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.BaseEstimator.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.BaseEstimator.md @@ -22,6 +22,13 @@ Initializes a BaseEstimator instance. * `config`: A RunConfig instance. +- - - + +#### `tf.contrib.learn.BaseEstimator.config` {#BaseEstimator.config} + + + + - - - #### `tf.contrib.learn.BaseEstimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#BaseEstimator.evaluate} @@ -38,7 +45,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.BaseEstimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#BaseEstimator.export} +#### `tf.contrib.learn.BaseEstimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#BaseEstimator.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.TensorFlowDNNRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.TensorFlowDNNRegressor.md index 3a3396aeafc988025aa0e5d15526c60d6a67a811..8fde3536042447aec1e07053e5c1bbac1b2b8227 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.TensorFlowDNNRegressor.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.learn.TensorFlowDNNRegressor.md @@ -13,6 +13,13 @@ +- - - + +#### `tf.contrib.learn.TensorFlowDNNRegressor.config` {#TensorFlowDNNRegressor.config} + + + + - - - #### `tf.contrib.learn.TensorFlowDNNRegressor.dnn_bias_` {#TensorFlowDNNRegressor.dnn_bias_} @@ -43,7 +50,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.TensorFlowDNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNRegressor.export} +#### `tf.contrib.learn.TensorFlowDNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNRegressor.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.rnn.GRUBlockCell.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.rnn.GRUBlockCell.md new file mode 100644 index 0000000000000000000000000000000000000000..b6713ee461d5b627b20590b35451eb0976bba043 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.contrib.rnn.GRUBlockCell.md @@ -0,0 +1,75 @@ +Block GRU cell implementation. + +The implementation is based on: http://arxiv.org/abs/1406.1078 +Computes the LSTM cell forward propagation for 1 time step. + +This kernel op implements the following mathematical equations: + +Baises are initialized with : +`b_ru` - constant_initializer(1.0) +`b_c` - constant_initializer(0.0) +``` +x_h_prev = [x, h_prev] + +[r_bar u_bar] = x_h_prev * w_ru + b_ru + +r = sigmoid(r_bar) +u = sigmoid(u_bar) + +h_prevr = h_prev \circ r + +x_h_prevr = [x h_prevr] + +c_bar = x_h_prevr * w_c + b_c +c = tanh(c_bar) + +h = (1-u) \circ c + u \circ h_prev +``` +- - - + +#### `tf.contrib.rnn.GRUBlockCell.__init__(cell_size)` {#GRUBlockCell.__init__} + +Initialize the Block GRU cell. + +##### Args: + + +* `cell_size`: int, GRU cell size. + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.output_size` {#GRUBlockCell.output_size} + + + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.state_size` {#GRUBlockCell.state_size} + + + + +- - - + +#### `tf.contrib.rnn.GRUBlockCell.zero_state(batch_size, dtype)` {#GRUBlockCell.zero_state} + +Return zero-filled state tensor(s). + +##### Args: + + +* `batch_size`: int, float, or unit Tensor representing the batch size. +* `dtype`: the data type to use for the state. + +##### Returns: + + If `state_size` is an int or TensorShape, then the return value is a + `N-D` tensor of shape `[batch_size x state_size]` filled with zeros. + + If `state_size` is a nested list or tuple, then the return value is + a nested list or tuple (of the same structure) of `2-D` tensors with +the shapes `[batch_size x s]` for each s in `state_size`. + + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.report_uninitialized_variables.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.report_uninitialized_variables.md index 5ff0341d83903277a568381f9eb374696b55571d..59c1394a4aaa2bf51b356e8fd0aa457ff2d1f4af 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.report_uninitialized_variables.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.report_uninitialized_variables.md @@ -15,6 +15,5 @@ variables if there are any, or an empty array if there are none. ##### Returns: A 1-D tensor containing names of the uninitialized variables, or an empty - 1-D - tensor if there are no variables or no uninitialized variables. + 1-D tensor if there are no variables or no uninitialized variables. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.summary.tensor_summary.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.summary.tensor_summary.md index ea842cde6041c6f256e704d14778762e96ed2388..61f16181b53980554218db95e93712f8e3ffdd12 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.summary.tensor_summary.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.summary.tensor_summary.md @@ -4,7 +4,7 @@ Outputs a `Summary` protocol buffer with a serialized tensor.proto. The generated [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) -has one summary value containing input_tensor. +has one summary value containing the input tensor. ##### Args: @@ -21,7 +21,7 @@ has one summary value containing input_tensor. other tensors that are all in a group. (e.g. bounding boxes and images) * `collections`: Optional list of graph collections keys. The new summary op is added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. -* `name`: A name for the operation (optional). +* `name`: An optional name for the generated node (optional). ##### Returns: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.uniform_unit_scaling_initializer.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.uniform_unit_scaling_initializer.md index 6033fbf53aed5b0ae76e3bfd5b668a9904b4bcc7..e2613a77a1d6f83a62b6dadff7a5dd52a5d1d99c 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.uniform_unit_scaling_initializer.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard2/tf.uniform_unit_scaling_initializer.md @@ -1,4 +1,4 @@ -### `tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32, full_shape=None)` {#uniform_unit_scaling_initializer} +### `tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32)` {#uniform_unit_scaling_initializer} Returns an initializer that generates tensors without scaling variance. @@ -18,12 +18,6 @@ See [Sussillo et al., 2014](https://arxiv.org/abs/1412.6558) and the calculation of constants. In section 2.3 there, the constants were numerically computed: for a linear layer it's 1.0, relu: ~1.43, tanh: ~1.15. -If the shape tuple `full_shape` is provided, the scale will be calculated from -this predefined shape. This is useful when a `Variable` is being partitioned -across several shards, and each shard has a smaller shape than the whole. -Since the shards are usually concatenated when used, the scale should be -based on the shape of the whole. - ##### Args: @@ -32,9 +26,6 @@ based on the shape of the whole. [`set_random_seed`](../../api_docs/python/constant_op.md#set_random_seed) for behavior. * `dtype`: The data type. Only floating point types are supported. -* `full_shape`: Tuple or list of integers. The shape used for calculating - scale normalization (instead of the shape passed at creation time). - Useful when creating sharded variables via partitioning. ##### Returns: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Binomial.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Binomial.md index 22c7c07aa5e49e110a3c0fca1e05e301abfa0968..1c7d8899462f95ad73828a71192a47fd0d1943d2 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Binomial.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Binomial.md @@ -94,14 +94,28 @@ dist = Binomial(n=[4., 5], p=[.1, .3]) #### `tf.contrib.distributions.Binomial.allow_nan_stats` {#Binomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Binomial.batch_shape(name='batch_shape')` {#Binomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -113,7 +127,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -122,26 +137,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Binomial.dtype` {#Binomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Binomial.entropy(name='entropy')` {#Binomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Binomial.event_shape(name='event_shape')` {#Binomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -150,7 +177,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -170,8 +198,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -214,26 +242,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Binomial.get_batch_shape()` {#Binomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Binomial.get_event_shape()` {#Binomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -254,46 +284,86 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Binomial.log_cdf(value, name='log_cdf')` {#Binomial.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Binomial.log_pdf(value, name='log_pdf')` {#Binomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Binomial.log_pmf(value, name='log_pmf')` {#Binomial.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.Binomial.log_prob(counts, name='log_prob')` {#Binomial.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -`Log(P[counts])`, computed for every batch member. -For each batch member of counts `k`, `P[counts]` is the probability that -after sampling `n` draws from this Binomial distribution, the number of -successes is `k`. Note that different sequences of draws can result in the -same counts, thus the probability includes a combinatorial coefficient. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Binomial.log_prob(value, name='log_prob')` {#Binomial.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -307,27 +377,14 @@ Log-odds. #### `tf.contrib.distributions.Binomial.mean(name='mean')` {#Binomial.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Binomial.mode(name='mode')` {#Binomial.mode} -Mode of the distribution. - -Note that when `(n + 1) * p` is an integer, there are actually two modes. -Namely, `(n + 1) * p` and `(n + 1) * p - 1` are both modes. Here we return -only the larger of the two modes. - -##### Args: - - -* `name`: The name for this op. - -##### Returns: - - The mode of the Binomial distribution. +Mode. - - - @@ -341,7 +398,7 @@ Number of trials. #### `tf.contrib.distributions.Binomial.name` {#Binomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -393,67 +450,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Binomial.parameters` {#Binomial.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Binomial.pdf(value, name='pdf')` {#Binomial.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Binomial.pmf(value, name='pmf')` {#Binomial.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.Binomial.prob(counts, name='prob')` {#Binomial.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -`P[counts]`, computed for every batch member. +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. +##### Raises: -For each batch member of counts `k`, `P[counts]` is the probability that -after sampling `n` draws from this Binomial distribution, the number of -successes is `k`. Note that different sequences of draws can result in the -same counts, thus the probability includes a combinatorial coefficient. + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Binomial.prob(value, name='prob')` {#Binomial.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.p` and `self.n`. `counts` is only legal if it is - less than or equal to `n` and its components are equal to integer - values. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Binomial.sample(sample_shape=(), seed=None, name='sample')` {#Binomial.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -465,35 +555,40 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Binomial.std(name='std')` {#Binomial.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Binomial.validate_args` {#Binomial.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Binomial.variance(name='variance')` {#Binomial.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.DirichletMultinomial.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.DirichletMultinomial.md index aba16da6f9342bcc3d5b1c99d197bedde1204b40..1a9d3c28b158ea3c0f42fe05ac056a159519edf6 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.DirichletMultinomial.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.DirichletMultinomial.md @@ -109,7 +109,21 @@ dist = DirichletMultinomial([3., 4], [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) #### `tf.contrib.distributions.DirichletMultinomial.allow_nan_stats` {#DirichletMultinomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -119,11 +133,18 @@ Boolean describing behavior when a stat is undefined for batch member. Parameter defining this distribution. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.alpha_sum` {#DirichletMultinomial.alpha_sum} + +Summation of alpha parameter. + + - - - #### `tf.contrib.distributions.DirichletMultinomial.batch_shape(name='batch_shape')` {#DirichletMultinomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -135,35 +156,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.DirichletMultinomial.cdf(x, name='cdf')` {#DirichletMultinomial.cdf} +#### `tf.contrib.distributions.DirichletMultinomial.cdf(value, name='cdf')` {#DirichletMultinomial.cdf} +Cumulative distribution function. + +##### Args: +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.DirichletMultinomial.dtype` {#DirichletMultinomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.DirichletMultinomial.entropy(name='entropy')` {#DirichletMultinomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.DirichletMultinomial.event_shape(name='event_shape')` {#DirichletMultinomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -172,7 +206,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -192,8 +227,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -236,26 +271,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.DirichletMultinomial.get_batch_shape()` {#DirichletMultinomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.DirichletMultinomial.get_event_shape()` {#DirichletMultinomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -274,64 +311,102 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.DirichletMultinomial.log_cdf(x, name='log_cdf')` {#DirichletMultinomial.log_cdf} +#### `tf.contrib.distributions.DirichletMultinomial.log_cdf(value, name='log_cdf')` {#DirichletMultinomial.log_cdf} +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.DirichletMultinomial.log_pdf(value, name='log_pdf')` {#DirichletMultinomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.DirichletMultinomial.log_pmf(value, name='log_pmf')` {#DirichletMultinomial.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.DirichletMultinomial.log_prob(counts, name='log_prob')` {#DirichletMultinomial.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - -`Log(P[counts])`, computed for every batch member. +#### `tf.contrib.distributions.DirichletMultinomial.log_prob(value, name='log_prob')` {#DirichletMultinomial.log_prob} -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Dirichlet Multinomial -distribution, the number of draws falling in class `j` is `n_j`. Note that -different sequences of draws can result in the same counts, thus the -probability includes a combinatorial coefficient. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nn]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.mean(name='mean')` {#DirichletMultinomial.mean} -Class means for every batch member. +Mean. - - - #### `tf.contrib.distributions.DirichletMultinomial.mode(name='mode')` {#DirichletMultinomial.mode} -Mode of the distribution. +Mode. - - - @@ -345,7 +420,7 @@ Parameter defining this distribution. #### `tf.contrib.distributions.DirichletMultinomial.name` {#DirichletMultinomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -390,68 +465,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.parameters` {#DirichletMultinomial.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.DirichletMultinomial.pdf(value, name='pdf')` {#DirichletMultinomial.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.DirichletMultinomial.pmf(value, name='pmf')` {#DirichletMultinomial.pmf} -The probability mass function. +Probability mass function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -- - - -#### `tf.contrib.distributions.DirichletMultinomial.prob(counts, name='prob')` {#DirichletMultinomial.prob} +* `AttributeError`: if `is_continuous`. -`P[counts]`, computed for every batch member. -For each batch of counts `[c_1,...,c_k]`, `P[counts]` is the probability -that after sampling `sum_j c_j` draws from this Dirichlet Multinomial -distribution, the number of draws falling in class `j` is `c_j`. Note that -different sequences of draws can result in the same counts, thus the -probability includes a combinatorial coefficient. +- - - + +#### `tf.contrib.distributions.DirichletMultinomial.prob(value, name='prob')` {#DirichletMultinomial.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can be - broadcast with `self.alpha`. For fixed leading dimensions, the last - dimension represents counts for the corresponding Dirichlet Multinomial - distribution in `self.alpha`. `counts` is only legal if it sums up to - `n` and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nn]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.DirichletMultinomial.sample(sample_shape=(), seed=None, name='sample')` {#DirichletMultinomial.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -463,60 +570,40 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. - +* `samples`: a `Tensor` with a prepended dimension (n,). -- - - +##### Raises: -#### `tf.contrib.distributions.DirichletMultinomial.std(name='std')` {#DirichletMultinomial.std} -Standard deviation of the distribution. +* `TypeError`: if `n` is not an integer type. - - - -#### `tf.contrib.distributions.DirichletMultinomial.validate_args` {#DirichletMultinomial.validate_args} +#### `tf.contrib.distributions.DirichletMultinomial.std(name='std')` {#DirichletMultinomial.std} -Boolean describing behavior on invalid input. +Standard deviation. - - - -#### `tf.contrib.distributions.DirichletMultinomial.variance(name='mean')` {#DirichletMultinomial.variance} - -Class variances for every batch member. - -The variance for each batch member is defined as the following: - -``` -Var(X_j) = n * alpha_j / alpha_0 * (1 - alpha_j / alpha_0) * - (n + alpha_0) / (1 + alpha_0) -``` - -where `alpha_0 = sum_j alpha_j`. - -The covariance between elements in a batch is defined as: - -``` -Cov(X_i, X_j) = -n * alpha_i * alpha_j / alpha_0 ** 2 * - (n + alpha_0) / (1 + alpha_0) -``` +#### `tf.contrib.distributions.DirichletMultinomial.validate_args` {#DirichletMultinomial.validate_args} -##### Args: +Python boolean indicated possibly expensive checks are enabled. -* `name`: The name for this op. +- - - -##### Returns: +#### `tf.contrib.distributions.DirichletMultinomial.variance(name='variance')` {#DirichletMultinomial.variance} - A `Tensor` representing the variances for each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Exponential.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Exponential.md index 5878273ca0b9a420b88eec61cf6b69874f7757d1..2c4cb44aaf4f3b524525ea0f1e2132437cce76f5 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Exponential.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Exponential.md @@ -31,7 +31,21 @@ Construct Exponential distribution with parameter `lam`. #### `tf.contrib.distributions.Exponential.allow_nan_stats` {#Exponential.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -45,7 +59,7 @@ Shape parameter. #### `tf.contrib.distributions.Exponential.batch_shape(name='batch_shape')` {#Exponential.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -57,7 +71,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -69,60 +84,42 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Exponential.cdf(x, name='cdf')` {#Exponential.cdf} +#### `tf.contrib.distributions.Exponential.cdf(value, name='cdf')` {#Exponential.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.dtype` {#Exponential.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Exponential.entropy(name='entropy')` {#Exponential.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Exponential.event_shape(name='event_shape')` {#Exponential.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -131,7 +128,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -151,8 +149,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -195,26 +193,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Exponential.get_batch_shape()` {#Exponential.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Exponential.get_event_shape()` {#Exponential.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -240,91 +240,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Exponential.log_cdf(x, name='log_cdf')` {#Exponential.log_cdf} +#### `tf.contrib.distributions.Exponential.log_cdf(value, name='log_cdf')` {#Exponential.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.log_pdf(value, name='log_pdf')` {#Exponential.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Exponential.log_pmf(value, name='log_pmf')` {#Exponential.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.log_prob(x, name='log_prob')` {#Exponential.log_prob} +#### `tf.contrib.distributions.Exponential.log_pmf(value, name='log_pmf')` {#Exponential.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.mean(name='mean')` {#Exponential.mean} +#### `tf.contrib.distributions.Exponential.log_prob(value, name='log_prob')` {#Exponential.log_prob} -Mean of each batch member. +Log probability density/mass function (depending on `is_continuous`). +##### Args: -- - - -#### `tf.contrib.distributions.Exponential.mode(name='mode')` {#Exponential.mode} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Mode of each batch member. +##### Returns: -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. -##### Args: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Exponential.mean(name='mean')` {#Exponential.mean} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mean. + + +- - - + +#### `tf.contrib.distributions.Exponential.mode(name='mode')` {#Exponential.mode} + +Mode. - - - #### `tf.contrib.distributions.Exponential.name` {#Exponential.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -371,102 +389,143 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Exponential.pdf(value, name='pdf')` {#Exponential.pdf} +#### `tf.contrib.distributions.Exponential.parameters` {#Exponential.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Exponential.pmf(value, name='pmf')` {#Exponential.pmf} +#### `tf.contrib.distributions.Exponential.pdf(value, name='pdf')` {#Exponential.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -The probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Exponential.prob(x, name='prob')` {#Exponential.prob} +#### `tf.contrib.distributions.Exponential.pmf(value, name='pmf')` {#Exponential.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Exponential.prob(value, name='prob')` {#Exponential.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Exponential.sample(sample_shape=(), seed=None, name='sample')` {#Exponential.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Exponential.sample_n(n, seed=None, name='sample_n')` {#Exponential.sample_n} -Sample `n` observations from the Exponential Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Exponential.std(name='std')` {#Exponential.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Exponential.validate_args` {#Exponential.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Exponential.variance(name='variance')` {#Exponential.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Gamma.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Gamma.md index a026df5d0a006991e8e1b3e4d2727949a35fb9bd..8c045924d395487652540f6f8df6f48deafe7e36 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Gamma.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Gamma.md @@ -55,7 +55,21 @@ broadcasting (e.g. `alpha + beta` is a valid operation). #### `tf.contrib.distributions.Gamma.allow_nan_stats` {#Gamma.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -69,7 +83,7 @@ Shape parameter. #### `tf.contrib.distributions.Gamma.batch_shape(name='batch_shape')` {#Gamma.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -81,7 +95,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -93,60 +108,42 @@ Inverse scale parameter. - - - -#### `tf.contrib.distributions.Gamma.cdf(x, name='cdf')` {#Gamma.cdf} +#### `tf.contrib.distributions.Gamma.cdf(value, name='cdf')` {#Gamma.cdf} -CDF of observations `x` under these Gamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.dtype` {#Gamma.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Gamma.entropy(name='entropy')` {#Gamma.entropy} -The entropy of Gamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Gamma.event_shape(name='event_shape')` {#Gamma.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -155,7 +152,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -175,8 +173,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -219,26 +217,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Gamma.get_batch_shape()` {#Gamma.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Gamma.get_event_shape()` {#Gamma.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -257,91 +257,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Gamma.log_cdf(x, name='log_cdf')` {#Gamma.log_cdf} +#### `tf.contrib.distributions.Gamma.log_cdf(value, name='log_cdf')` {#Gamma.log_cdf} -Log CDF of observations `x` under these Gamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.log_pdf(value, name='log_pdf')` {#Gamma.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Gamma.log_pmf(value, name='log_pmf')` {#Gamma.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Gamma.log_prob(x, name='log_prob')` {#Gamma.log_prob} +#### `tf.contrib.distributions.Gamma.log_pmf(value, name='log_pmf')` {#Gamma.log_pmf} -Log prob of observations in `x` under these Gamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Gamma.mean(name='mean')` {#Gamma.mean} +#### `tf.contrib.distributions.Gamma.log_prob(value, name='log_prob')` {#Gamma.log_prob} -Mean of each batch member. +Log probability density/mass function (depending on `is_continuous`). +##### Args: -- - - -#### `tf.contrib.distributions.Gamma.mode(name='mode')` {#Gamma.mode} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Mode of each batch member. +##### Returns: -The mode of a gamma distribution is `(alpha - 1) / beta` when `alpha > 1`, -and `NaN` otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. -##### Args: +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.Gamma.mean(name='mean')` {#Gamma.mean} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mean. + + +- - - + +#### `tf.contrib.distributions.Gamma.mode(name='mode')` {#Gamma.mode} + +Mode. - - - #### `tf.contrib.distributions.Gamma.name` {#Gamma.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -388,105 +406,143 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Gamma.pdf(value, name='pdf')` {#Gamma.pdf} +#### `tf.contrib.distributions.Gamma.parameters` {#Gamma.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Gamma.pmf(value, name='pmf')` {#Gamma.pmf} +#### `tf.contrib.distributions.Gamma.pdf(value, name='pdf')` {#Gamma.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -The probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Gamma.prob(x, name='prob')` {#Gamma.prob} +#### `tf.contrib.distributions.Gamma.pmf(value, name='pmf')` {#Gamma.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Gamma.prob(value, name='prob')` {#Gamma.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Gamma.sample(sample_shape=(), seed=None, name='sample')` {#Gamma.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Gamma.sample_n(n, seed=None, name='sample_n')` {#Gamma.sample_n} -Draws `n` samples from the Gamma distribution(s). - -See the doc for tf.random_gamma for further detail. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Gamma.std(name='std')` {#Gamma.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Gamma.validate_args` {#Gamma.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Gamma.variance(name='variance')` {#Gamma.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.InverseGamma.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.InverseGamma.md index 8956e3f890ab8a1944eb40c6c15d232d3eccbf3f..45c2201d61316d2b4ab3b2f6d52eb3c77e02b445 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.InverseGamma.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.InverseGamma.md @@ -54,7 +54,21 @@ broadcasting (e.g. `alpha + beta` is a valid operation). #### `tf.contrib.distributions.InverseGamma.allow_nan_stats` {#InverseGamma.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -68,7 +82,7 @@ Shape parameter. #### `tf.contrib.distributions.InverseGamma.batch_shape(name='batch_shape')` {#InverseGamma.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -80,7 +94,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -92,60 +107,42 @@ Scale parameter. - - - -#### `tf.contrib.distributions.InverseGamma.cdf(x, name='cdf')` {#InverseGamma.cdf} +#### `tf.contrib.distributions.InverseGamma.cdf(value, name='cdf')` {#InverseGamma.cdf} -CDF of observations `x` under these InverseGamma distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.dtype` {#InverseGamma.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.InverseGamma.entropy(name='entropy')` {#InverseGamma.entropy} -The entropy of these InverseGamma distribution(s). - -This is defined to be - -``` -entropy = alpha - log(beta) + log(Gamma(alpha)) - + (1-alpha)digamma(alpha) -``` - -where digamma(alpha) is the digamma function. - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.InverseGamma.event_shape(name='event_shape')` {#InverseGamma.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -154,7 +151,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -174,8 +172,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -218,26 +216,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.InverseGamma.get_batch_shape()` {#InverseGamma.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.InverseGamma.get_event_shape()` {#InverseGamma.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - `TensorShape` object. + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -256,102 +256,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.InverseGamma.log_cdf(x, name='log_cdf')` {#InverseGamma.log_cdf} +#### `tf.contrib.distributions.InverseGamma.log_cdf(value, name='log_cdf')` {#InverseGamma.log_cdf} -Log CDF of observations `x` under these InverseGamma distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.log_pdf(value, name='log_pdf')` {#InverseGamma.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.InverseGamma.log_pmf(value, name='log_pmf')` {#InverseGamma.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.log_prob(x, name='log_prob')` {#InverseGamma.log_prob} +#### `tf.contrib.distributions.InverseGamma.log_pmf(value, name='log_pmf')` {#InverseGamma.log_pmf} -Log prob of observations in `x` under these InverseGamma distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.mean(name='mean')` {#InverseGamma.mean} +#### `tf.contrib.distributions.InverseGamma.log_prob(value, name='log_prob')` {#InverseGamma.log_prob} -Mean of each batch member. - -The mean of an inverse gamma distribution is `beta / (alpha - 1)`, -when `alpha > 1`, and `NaN` otherwise. If `self.allow_nan_stats` is -`False`, an exception will be raised rather than returning `NaN` +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: A name to give this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The mean for every batch member, a `Tensor` with same `dtype` as self. - -- - - +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -#### `tf.contrib.distributions.InverseGamma.mode(name='mode')` {#InverseGamma.mode} -Mode of each batch member. +- - - -The mode of an inverse gamma distribution is `beta / (alpha + 1)`. +#### `tf.contrib.distributions.InverseGamma.mean(name='mean')` {#InverseGamma.mean} -##### Args: +Mean. -* `name`: A name to give this op. +- - - -##### Returns: +#### `tf.contrib.distributions.InverseGamma.mode(name='mode')` {#InverseGamma.mode} - The mode for every batch member, a `Tensor` with same `dtype` as self. +Mode. - - - #### `tf.contrib.distributions.InverseGamma.name` {#InverseGamma.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -398,118 +405,143 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.InverseGamma.pdf(value, name='pdf')` {#InverseGamma.pdf} +#### `tf.contrib.distributions.InverseGamma.parameters` {#InverseGamma.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.InverseGamma.pmf(value, name='pmf')` {#InverseGamma.pmf} +#### `tf.contrib.distributions.InverseGamma.pdf(value, name='pdf')` {#InverseGamma.pdf} + +Probability density function. + +##### Args: -The probability mass function. + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.InverseGamma.prob(x, name='prob')` {#InverseGamma.prob} +#### `tf.contrib.distributions.InverseGamma.pmf(value, name='pmf')` {#InverseGamma.pmf} -Pdf of observations in `x` under these Gamma distribution(s). +Probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `alpha` and `beta`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the PDFs of `x` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. ##### Raises: -* `TypeError`: if `x` and `alpha` are different dtypes. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.InverseGamma.prob(value, name='prob')` {#InverseGamma.prob} + +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.InverseGamma.sample(sample_shape=(), seed=None, name='sample')` {#InverseGamma.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.InverseGamma.sample_n(n, seed=None, name='sample_n')` {#InverseGamma.sample_n} -Draws `n` samples from these InverseGamma distribution(s). - -See the doc for tf.random_gamma for further details on sampling strategy. +Generate `n` samples. ##### Args: -* `n`: Python integer, the number of observations to sample from each - distribution. -* `seed`: Python integer, the random seed for this operation. -* `name`: Optional name for the operation. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.InverseGamma.std(name='std')` {#InverseGamma.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.InverseGamma.validate_args` {#InverseGamma.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.InverseGamma.variance(name='variance')` {#InverseGamma.variance} -Variance of each batch member. - -Variance for inverse gamma is defined only for `alpha > 2`. If -`self.allow_nan_stats` is `False`, an exception will be raised rather -than returning `NaN`. - -##### Args: - - -* `name`: A name to give this op. - -##### Returns: - - The variance for every batch member, a `Tensor` with same `dtype` as self. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Multinomial.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Multinomial.md index ff1317a83d7a6257dc3deb1ec44f00a47fc2c768..59a3dfa4ded0bf2ccdab3967baed0de1ff11aad6 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Multinomial.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.Multinomial.md @@ -105,14 +105,28 @@ dist = Multinomial(n=[4., 5], p=[[.1, .3, .6], [.4, .05, .55]]) #### `tf.contrib.distributions.Multinomial.allow_nan_stats` {#Multinomial.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Multinomial.batch_shape(name='batch_shape')` {#Multinomial.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -124,7 +138,8 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - @@ -133,26 +148,38 @@ independent distributions of this kind the instance represents. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Multinomial.dtype` {#Multinomial.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Multinomial.entropy(name='entropy')` {#Multinomial.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Multinomial.event_shape(name='event_shape')` {#Multinomial.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -161,7 +188,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -181,8 +209,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -225,26 +253,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Multinomial.get_batch_shape()` {#Multinomial.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Multinomial.get_event_shape()` {#Multinomial.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -265,48 +295,86 @@ Same meaning as `event_shape`. May be only partially defined. #### `tf.contrib.distributions.Multinomial.log_cdf(value, name='log_cdf')` {#Multinomial.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Multinomial.log_pdf(value, name='log_pdf')` {#Multinomial.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Multinomial.log_pmf(value, name='log_pmf')` {#Multinomial.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -#### `tf.contrib.distributions.Multinomial.log_prob(counts, name='log_prob')` {#Multinomial.log_prob} +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -`Log(P[counts])`, computed for every batch member. +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Multinomial distribution, the -number of draws falling in class `j` is `n_j`. Note that different -sequences of draws can result in the same counts, thus the probability -includes a combinatorial coefficient. +#### `tf.contrib.distributions.Multinomial.log_prob(value, name='log_prob')` {#Multinomial.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -320,14 +388,14 @@ Log-odds. #### `tf.contrib.distributions.Multinomial.mean(name='mean')` {#Multinomial.mean} -Mean of the distribution. +Mean. - - - #### `tf.contrib.distributions.Multinomial.mode(name='mode')` {#Multinomial.mode} -Mode of the distribution. +Mode. - - - @@ -341,7 +409,7 @@ Number of trials. #### `tf.contrib.distributions.Multinomial.name` {#Multinomial.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -393,68 +461,100 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Multinomial.parameters` {#Multinomial.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Multinomial.pdf(value, name='pdf')` {#Multinomial.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Multinomial.pmf(value, name='pmf')` {#Multinomial.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.Multinomial.prob(counts, name='prob')` {#Multinomial.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: -`P[counts]`, computed for every batch member. -For each batch of counts `[n_1,...,n_k]`, `P[counts]` is the probability -that after sampling `n` draws from this Multinomial distribution, the -number of draws falling in class `j` is `n_j`. Note that different -sequences of draws can result in the same counts, thus the probability -includes a combinatorial coefficient. +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.Multinomial.prob(value, name='prob')` {#Multinomial.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `counts`: Non-negative tensor with dtype `dtype` and whose shape can - be broadcast with `self.p` and `self.n`. For fixed leading dimensions, - the last dimension represents counts for the corresponding Multinomial - distribution in `self.p`. `counts` is only legal if it sums up to `n` - and its components are equal to integer values. -* `name`: Name to give this Op, defaults to "prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Multinomial.sample(sample_shape=(), seed=None, name='sample')` {#Multinomial.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - @@ -466,35 +566,40 @@ Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Multinomial.std(name='std')` {#Multinomial.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Multinomial.validate_args` {#Multinomial.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Multinomial.variance(name='variance')` {#Multinomial.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.md index e4aac2549fc8879011fece0dcfd1292ce3c5a790..977fd677395acdb42a42c55cc92fa03a342adf9d 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.md @@ -106,14 +106,41 @@ D = is diagonal (r x r), optional (defaults to identity). #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.allow_nan_stats` {#MultivariateNormalDiagPlusVDVT.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.batch_shape(name='batch_shape')` {#MultivariateNormalDiagPlusVDVT.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -122,36 +149,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.dtype` {#MultivariateNormalDiagPlusVDVT.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.entropy(name='entropy')` {#MultivariateNormalDiagPlusVDVT.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.event_shape(name='event_shape')` {#MultivariateNormalDiagPlusVDVT.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.event_shape(name='event_shape')` {#MultivariateNormalDiagPlusVDVT.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -171,8 +210,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -215,14 +254,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.get_batch_shape()` {#MultivariateNormalDiagPlusVDVT.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.get_event_shape()` {#MultivariateNormalDiagPlusVDVT.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -243,48 +296,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_cdf(value, name='log_cdf')` {#MultivariateNormalDiagPlusVDVT.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_pdf(value, name='log_pdf')` {#MultivariateNormalDiagPlusVDVT.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_pmf(value, name='log_pmf')` {#MultivariateNormalDiagPlusVDVT.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_prob(x, name='log_prob')` {#MultivariateNormalDiagPlusVDVT.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.log_prob(value, name='log_prob')` {#MultivariateNormalDiagPlusVDVT.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -298,14 +389,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.mean(name='mean')` {#MultivariateNormalDiagPlusVDVT.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.mode(name='mode')` {#MultivariateNormalDiagPlusVDVT.mode} -Mode of each batch member. +Mode. - - - @@ -319,7 +410,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.name` {#MultivariateNormalDiagPlusVDVT.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -364,88 +455,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.parameters` {#MultivariateNormalDiagPlusVDVT.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.pdf(value, name='pdf')` {#MultivariateNormalDiagPlusVDVT.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.pmf(value, name='pmf')` {#MultivariateNormalDiagPlusVDVT.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.prob(x, name='prob')` {#MultivariateNormalDiagPlusVDVT.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -The PDF of observations `x` under these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.prob(value, name='prob')` {#MultivariateNormalDiagPlusVDVT.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalDiagPlusVDVT.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalDiagPlusVDVT.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -466,20 +594,20 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.std(name='std')` {#MultivariateNormalDiagPlusVDVT.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.validate_args` {#MultivariateNormalDiagPlusVDVT.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalDiagPlusVDVT.variance(name='variance')` {#MultivariateNormalDiagPlusVDVT.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.learn.Estimator.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.learn.Estimator.md index 631156b06f347f2f64f8f94fd56ecf654878db0d..c7defcf60ad39bae6a7c34a0bbdb306ea7649de6 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.learn.Estimator.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.learn.Estimator.md @@ -45,6 +45,13 @@ Constructs an Estimator instance. * `ValueError`: parameters of `model_fn` don't match `params`. +- - - + +#### `tf.contrib.learn.Estimator.config` {#Estimator.config} + + + + - - - #### `tf.contrib.learn.Estimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#Estimator.evaluate} @@ -61,7 +68,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.Estimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#Estimator.export} +#### `tf.contrib.learn.Estimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#Estimator.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.training.stratified_sample.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.training.stratified_sample.md new file mode 100644 index 0000000000000000000000000000000000000000..95f2a69b1abbd5d193bf3aa2dbc2e65a1b6f2580 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard3/tf.contrib.training.stratified_sample.md @@ -0,0 +1,60 @@ +### `tf.contrib.training.stratified_sample(tensors, labels, target_probs, batch_size, init_probs=None, enqueue_many=False, queue_capacity=16, threads_per_queue=1, name=None)` {#stratified_sample} + +Stochastically creates batches based on per-class probabilities. + +This method discards examples. Internally, it creates one queue to amortize +the cost of disk reads, and one queue to hold the properly-proportioned +batch. See `stratified_sample_unknown_dist` for a function that performs +stratified sampling with one queue per class and doesn't require knowing the +class data-distribution ahead of time. + +##### Args: + + +* `tensors`: List of tensors for data. All tensors are either one item or a + batch, according to enqueue_many. +* `labels`: Tensor for label of data. Label is a single integer or a batch, + depending on enqueue_many. It is not a one-hot vector. +* `target_probs`: Target class proportions in batch. An object whose type has a + registered Tensor conversion function. +* `batch_size`: Size of batch to be returned. +* `init_probs`: Class proportions in the data. An object whose type has a + registered Tensor conversion function, or `None` for estimating the + initial distribution. +* `enqueue_many`: Bool. If true, interpret input tensors as having a batch + dimension. +* `queue_capacity`: Capacity of the large queue that holds input examples. +* `threads_per_queue`: Number of threads for the large queue that holds input + examples and for the final queue with the proper class proportions. +* `name`: Optional prefix for ops created by this function. + +##### Raises: + + +* `ValueError`: enqueue_many is True and labels doesn't have a batch + dimension, or if enqueue_many is False and labels isn't a scalar. +* `ValueError`: enqueue_many is True, and batch dimension on data and labels + don't match. +* `ValueError`: if probs don't sum to one. +* `ValueError`: if a zero initial probability class has a nonzero target + probability. +* `TFAssertion`: if labels aren't integers in [0, num classes). + +##### Returns: + + (data_batch, label_batch), where data_batch is a list of tensors of the same + length as `tensors` + +##### Example: + + # Get tensor for a single data and label example. + data, label = data_provider.Get(['data', 'label']) + + # Get stratified batch according to per-class probabilities. + target_probs = [...distribution you want...] + [data_batch], labels = tf.contrib.framework.sampling_ops.stratified_sample( + [data], label, target_probs) + + # Run batch through network. + ... + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.graph_editor.graph_replace.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.graph_editor.graph_replace.md new file mode 100644 index 0000000000000000000000000000000000000000..e28b21c50e006eb94088d89975c357722377c152 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.graph_editor.graph_replace.md @@ -0,0 +1,26 @@ +### `tf.contrib.graph_editor.graph_replace(target_ts, replacement_ts, dst_scope='', src_scope='', reuse_dst_scope=False)` {#graph_replace} + +Create a new graph which compute the targets from the replaced Tensors. + +##### Args: + + +* `target_ts`: a single tf.Tensor or an iterabble of tf.Tensor. +* `replacement_ts`: dictionary mapping from original tensors to replaced tensors +* `dst_scope`: the destination scope. +* `src_scope`: the source scope. +* `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + +##### Returns: + + A single tf.Tensor or a list of target tf.Tensor, depending on + the type of the input argument `target_ts`. + The returned tensors are recomputed using the tensors from replacement_ts. + +##### Raises: + + +* `ValueError`: if the targets are not connected to replacement_ts. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.layers.batch_norm.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.layers.batch_norm.md index a8c2a66341ca3f3d47f6ae086d05146f9d208aad..ad852cc6080424158d5d38bf11acb65c56cf86e9 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.layers.batch_norm.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.layers.batch_norm.md @@ -9,6 +9,18 @@ Adds a Batch Normalization layer from http://arxiv.org/abs/1502.03167. Can be used as a normalizer function for conv2d and fully_connected. +Note: When is_training is True the moving_mean and moving_variance need to be +updated, by default the update_ops are placed in tf.GraphKeys.UPDATE_OPS so +they need to be added as a dependency to the train_op, example: + + update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) + if update_ops: + updates = tf.group(update_ops) + total_loss = control_flow_ops.with_dependencies([updates], total_loss) + +One can set update_collections=None to force the updates in place, but that +can have speed penalty, specially in distributed settings. + ##### Args: @@ -22,8 +34,9 @@ Can be used as a normalizer function for conv2d and fully_connected. * `epsilon`: small float added to variance to avoid dividing by zero. * `activation_fn`: Optional activation function. * `updates_collections`: collections to collect the update ops for computation. + The updates_ops need to be excuted with the train_op. If None, a control dependency would be added to make sure the updates are - computed. + computed in place. * `is_training`: whether or not the layer is in training mode. In training mode it would accumulate the statistics of the moments into `moving_mean` and `moving_variance` using an exponential moving average with the given diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.DNNClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.DNNClassifier.md index c6c2fb92ffb4c1fe9fc6f9579fabad2a2f35e184..c9247a5446ec8dc9fc84ad01060a5e6fb3038732 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.DNNClassifier.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.DNNClassifier.md @@ -102,6 +102,13 @@ Initializes a DNNClassifier instance. +- - - + +#### `tf.contrib.learn.DNNClassifier.config` {#DNNClassifier.config} + + + + - - - #### `tf.contrib.learn.DNNClassifier.dnn_bias_` {#DNNClassifier.dnn_bias_} @@ -132,7 +139,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.DNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#DNNClassifier.export} +#### `tf.contrib.learn.DNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#DNNClassifier.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.RunConfig.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.RunConfig.md index 8dec07572fa42735cbd58160f4c40a4833ad25e8..409cb66b09e83ca7074853490ee302abaf3f0532 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.RunConfig.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.RunConfig.md @@ -5,23 +5,60 @@ If you're a Google-internal user using command line flags with learn_runner.py probably want to use learn_runner.EstimatorConfig instead. - - - -#### `tf.contrib.learn.RunConfig.__init__(master='', task=0, num_ps_replicas=0, num_cores=4, log_device_placement=False, gpu_memory_fraction=1, cluster_spec=None, tf_random_seed=None, save_summary_steps=100, save_checkpoints_secs=60, keep_checkpoint_max=5, keep_checkpoint_every_n_hours=10000)` {#RunConfig.__init__} +#### `tf.contrib.learn.RunConfig.__init__(master=None, task=None, num_ps_replicas=None, num_cores=4, log_device_placement=False, gpu_memory_fraction=1, cluster_spec=None, tf_random_seed=None, save_summary_steps=100, save_checkpoints_secs=60, keep_checkpoint_max=5, keep_checkpoint_every_n_hours=10000, job_name=None, is_chief=None)` {#RunConfig.__init__} Constructor. +If set to None, `master`, `task`, `num_ps_replicas`, `cluster_spec`, +`job_name`, and `is_chief` are set based on the TF_CONFIG environment +variable, if the pertinent information is present; otherwise, the defaults +listed in the Args section apply. + +The TF_CONFIG environment variable is a JSON object with two relevant +attributes: `task` and `cluster_spec`. `cluster_spec` is a JSON serialized +version of the Python dict described in server_lib.py. `task` has two +attributes: `type` and `index`, where `type` can be any of the task types +in the cluster_spec. When TF_CONFIG contains said information, the +following properties are set on this class: + + * `job_name` is set to [`task`][`type`] + * `task` is set to [`task`][`index`] + * `cluster_spec` is parsed from [`cluster`] + * 'master' is determined by looking up `job_name` and `task` in the + cluster_spec. + * `num_ps_replicas` is set by counting the number of nodes listed + in the `ps` job of `cluster_spec`. + * `is_chief`: true when `job_name` == "master" and `task` == 0. + +Example: +``` + cluster = {'ps': ['host1:2222', 'host2:2222'], + 'worker': ['host3:2222', 'host4:2222', 'host5:2222']} + os.environ['TF_CONFIG'] = json.dumps({ + {'cluster': cluster, + 'task': {'type': 'worker', 'index': 1}}}) + config = RunConfig() + assert config.master == 'host4:2222' + assert config.task == 1 + assert config.num_ps_replicas == 2 + assert config.cluster_spec == server_lib.ClusterSpec(cluster) + assert config.job_name == 'worker' + assert not config.is_chief +``` + ##### Args: -* `master`: TensorFlow master. Empty string (the default) for local. +* `master`: TensorFlow master. Defaults to empty string for local. * `task`: Task id of the replica running the training (default: 0). * `num_ps_replicas`: Number of parameter server tasks to use (default: 0). * `num_cores`: Number of cores to be used (default: 4). * `log_device_placement`: Log the op placement to devices (default: False). * `gpu_memory_fraction`: Fraction of GPU memory used by the process on each GPU uniformly on the same machine. -* `cluster_spec`: a tf.train.ClusterSpec object that describes the cluster in - the case of distributed computation. If missing, reasonable assumptions - are made for the addresses of jobs. +* `cluster_spec`: a `tf.train.ClusterSpec` object that describes the cluster + in the case of distributed computation. If missing, reasonable + assumptions are made for the addresses of jobs. * `tf_random_seed`: Random seed for TensorFlow initializers. Setting this value allows consistency between reruns. * `save_summary_steps`: Save summaries every this many steps. @@ -33,5 +70,29 @@ Constructor. * `keep_checkpoint_every_n_hours`: Number of hours between each checkpoint to be saved. The default value of 10,000 hours effectively disables the feature. +* `job_name`: the type of task, e.g., 'ps', 'worker', etc. The `job_name` + must exist in the `cluster_spec.jobs`. +* `is_chief`: whether or not this task (as identified by the other parameters) + should be the chief task. + +##### Raises: + + +* `ValueError`: if num_ps_replicas and cluster_spec are set (cluster_spec + may fome from the TF_CONFIG environment variable). + + +- - - + +#### `tf.contrib.learn.RunConfig.is_chief` {#RunConfig.is_chief} + + + + +- - - + +#### `tf.contrib.learn.RunConfig.job_name` {#RunConfig.job_name} + + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowEstimator.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowEstimator.md index 1d85fcdab6ae0701012683436c41dd264a0a450c..77a96151b60057f90151e89e8320b2c36914e230 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowEstimator.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowEstimator.md @@ -44,6 +44,13 @@ Initializes a TensorFlowEstimator instance. * 2: log device placement is printed. +- - - + +#### `tf.contrib.learn.TensorFlowEstimator.config` {#TensorFlowEstimator.config} + + + + - - - #### `tf.contrib.learn.TensorFlowEstimator.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowEstimator.evaluate} @@ -71,7 +78,7 @@ See superclass Estimator for more details. - - - -#### `tf.contrib.learn.TensorFlowEstimator.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowEstimator.export} +#### `tf.contrib.learn.TensorFlowEstimator.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowEstimator.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowLinearClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowLinearClassifier.md deleted file mode 100644 index ef6f13c7ab152c5c55ffcccb7877a0e6c6914408..0000000000000000000000000000000000000000 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowLinearClassifier.md +++ /dev/null @@ -1,240 +0,0 @@ - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.__init__(*args, **kwargs)` {#TensorFlowLinearClassifier.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.bias_` {#TensorFlowLinearClassifier.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.dnn_bias_` {#TensorFlowLinearClassifier.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.dnn_weights_` {#TensorFlowLinearClassifier.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowLinearClassifier.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowLinearClassifier.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowLinearClassifier.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_params(deep=True)` {#TensorFlowLinearClassifier.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_variable_names()` {#TensorFlowLinearClassifier.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.get_variable_value(name)` {#TensorFlowLinearClassifier.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.linear_bias_` {#TensorFlowLinearClassifier.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.linear_weights_` {#TensorFlowLinearClassifier.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.model_dir` {#TensorFlowLinearClassifier.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowLinearClassifier.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowLinearClassifier.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowLinearClassifier.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.save(path)` {#TensorFlowLinearClassifier.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.set_params(**params)` {#TensorFlowLinearClassifier.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearClassifier.weights_` {#TensorFlowLinearClassifier.weights_} - - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowRNNRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowRNNRegressor.md index 3dd086478bee429a506303ff64deb120abf8d056..99633b319379729630f5dd5398b0dbb380755a29 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowRNNRegressor.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.TensorFlowRNNRegressor.md @@ -59,6 +59,13 @@ Initializes a TensorFlowRNNRegressor instance. Returns bias of the rnn layer. +- - - + +#### `tf.contrib.learn.TensorFlowRNNRegressor.config` {#TensorFlowRNNRegressor.config} + + + + - - - #### `tf.contrib.learn.TensorFlowRNNRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRNNRegressor.evaluate} @@ -86,7 +93,7 @@ See superclass Estimator for more details. - - - -#### `tf.contrib.learn.TensorFlowRNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNRegressor.export} +#### `tf.contrib.learn.TensorFlowRNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNRegressor.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.read_batch_features.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.read_batch_features.md index 7c3dddb26a3ae76f4ccc833d41825f19203a925b..9c40083f502c690980b023d192a836aa11802480 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.read_batch_features.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.contrib.learn.read_batch_features.md @@ -38,7 +38,6 @@ All ops are added to the default graph. ##### Returns: A dict of `Tensor` or `SparseTensor` objects for each in `features`. - If `keep_keys` is `True`, returns tuple of string `Tensor` and above dict. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.fixed_size_partitioner.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.fixed_size_partitioner.md new file mode 100644 index 0000000000000000000000000000000000000000..fdeea7f2074a8dcd549c85db67689ed38dd98a25 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.fixed_size_partitioner.md @@ -0,0 +1,15 @@ +### `tf.fixed_size_partitioner(num_shards, axis=0)` {#fixed_size_partitioner} + +Partitioner to specify a fixed number of shards along given axis. + +##### Args: + + +* `num_shards`: `int`, number of shards to partition variable. +* `axis`: `int`, axis to partition on. + +##### Returns: + + A partition function usable as the `partitioner` argument to + `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.while_loop.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.while_loop.md index 8d8320962b96f7f98cb5f401c7ffb818e474f8f9..2574c0be69d7c01ae38a66e71dfe8cf65d72330c 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.while_loop.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.while_loop.md @@ -1,4 +1,4 @@ -### `tf.while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, swap_memory=False, name=None)` {#while_loop} +### `tf.while_loop(cond, body, loop_vars, shape_invariants=None, parallel_iterations=10, back_prop=True, swap_memory=False, name=None)` {#while_loop} Repeat `body` while the condition `cond` is true. @@ -9,11 +9,39 @@ arity (length and structure) and types as `loop_vars`. `loop_vars` is a and `body`. `cond` and `body` both take as many arguments as there are `loop_vars`. +While `cond` evaluates to true, `body` is executed. + In addition to regular Tensors or IndexedSlices, the body may accept and return TensorArray objects. The flows of the TensorArray objects will be appropriately forwarded between loops and during gradient calculations. -While `cond` evaluates to true, `body` is executed. +For correctness, `tf.while_loop()` strictly enforces shape invariants for +the loop variables. A shape invariant is a (possibly partial) shape that +is unchanged across the iterations of the loop. An error will be raised +if the shape of a loop variable after an iteration is determined to be more +general than or incompatible with its shape invariant. For example, a shape +of [11, None] is more general than a shape of [11, 17], and [11, 21] is not +compatible with [11, 17]. By default (if the argument `shape_invariants` is +not specified), it is assumed that the initial shape of each tensor in +`loop_vars` is the same in every iteration. The `shape_invariants` argument +allows the caller to specify a less specific shape invariant for each loop +variable, which is needed if the shape varies between iterations. The +[`Tensor.set_shape()`](../../api_docs/python/framework.md#Tensor.set_shape) +function may also be used in the `body` function to indicate that +the output loop variable has a particular shape. The shape invariant for +SparseTensor and IndexedSlices are treated specially as follows: + +a) If a loop variable is a SparseTensor, the shape invariant must be +TensorShape([r]) where r is the rank of the dense tensor represented +by the sparse tensor. It means the shapes of the three tensors of the +SparseTensor are ([None], [None, r], [r]). NOTE: The shape invariant here +is the shape of the SparseTensor.shape property. It must be the shape of +a vector. + +b) If a loop variable is an IndexedSlices, the shape invariant must be +a shape invariant of the values tensor of the IndexedSlices. It means +the shapes of the three tensors of the IndexedSlices are (shape, [shape[0]], +[shape.ndims]). `while_loop` implements non-strict semantics, enabling multiple iterations to run in parallel. The maximum number of parallel iterations can be @@ -35,6 +63,7 @@ sequences and large batches. * `body`: A callable that represents the loop body. * `loop_vars`: A (possibly nested) tuple or list of numpy array, `Tensor`, and `TensorArray` objects. +* `shape_invariants`: The shape invariants for the loop variables. * `parallel_iterations`: The number of iterations allowed to run in parallel. * `back_prop`: Whether backprop is enabled for this while loop. * `swap_memory`: Whether GPU-CPU memory swap is enabled for this loop. @@ -71,3 +100,15 @@ Example with nesting: ijk_final = tf.while_loop(c, b, ijk_0) ``` +Example using shape_invariants: + + ```python + i0 = tf.constant(0) + m0 = tf.ones([2, 2]) + c = lambda i, m: i < 10 + b = lambda i, m: [i+1, tf.concat(0, [m, m])] + tf.while_loop( + c, b, loop_vars=[i0, m0], + shape_invariants=[i0.get_shape(), tensor_shape.TensorShape([None, 2])]) + ``` + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.OpError.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.OpError.md index c23014ad17df15dfa894d4291ae78dafa089bba1..d28bd7ee1460c62450866552067ce9ac53e0d79e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.OpError.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.OpError.md @@ -39,8 +39,8 @@ Creates a new `OpError` indicating that a particular op failed. ##### Args: -* `node_def`: The `graph_pb2.NodeDef` proto representing the op that failed, - if known; otherwise None. +* `node_def`: The `node_def_pb2.NodeDef` proto representing the op that + failed, if known; otherwise None. * `op`: The `ops.Operation` that failed, if known; otherwise None. * `message`: The message string describing the failure. * `error_code`: The `error_codes_pb2.Code` describing the error. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.contrib.learn.TensorFlowDNNClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.contrib.learn.TensorFlowDNNClassifier.md index b8f451990ef2db25c83927a5f265df114bf40454..f9ce477baa13bd1562d21f7d5319a42e6256025f 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.contrib.learn.TensorFlowDNNClassifier.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.contrib.learn.TensorFlowDNNClassifier.md @@ -13,6 +13,13 @@ +- - - + +#### `tf.contrib.learn.TensorFlowDNNClassifier.config` {#TensorFlowDNNClassifier.config} + + + + - - - #### `tf.contrib.learn.TensorFlowDNNClassifier.dnn_bias_` {#TensorFlowDNNClassifier.dnn_bias_} @@ -43,7 +50,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.TensorFlowDNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNClassifier.export} +#### `tf.contrib.learn.TensorFlowDNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowDNNClassifier.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Optimizer.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Optimizer.md index 340e33a8df901991b2ef085467fd7a8166b7640a..cfd86f5bee2a8e7aa90a531bdb38ba09b87e9fe9 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Optimizer.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Optimizer.md @@ -258,7 +258,3 @@ Use `get_slot_names()` to get the list of slot names created by the - - - #### `tf.train.Optimizer.get_name()` {#Optimizer.get_name} - - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Saver.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Saver.md index 0dacbd809ae5b4a22a54a091c2f0efa5a66898e0..58b112a979b6ffdc6ef6bfdf38cbf91d957495d2 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Saver.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard5/tf.train.Saver.md @@ -72,7 +72,7 @@ protocol buffer file in the call to `save()`. - - - -#### `tf.train.Saver.__init__(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None, defer_build=False)` {#Saver.__init__} +#### `tf.train.Saver.__init__(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None, defer_build=False, allow_empty=False)` {#Saver.__init__} Creates a `Saver`. @@ -137,6 +137,9 @@ checkpoints per device. * `defer_build`: If `True`, defer adding the save and restore ops to the `build()` call. In that case `build()` should be called before finalizing the graph or using the saver. +* `allow_empty`: If `False` (default) raise an error if there are no + variables in the graph. Otherwise, construct the saver anyway and make + it a no-op. ##### Raises: @@ -181,6 +184,7 @@ path can be passed directly to a call to `restore()`. A string: path at which the variables were saved. If the saver is sharded, this string ends with: '-?????-of-nnnnn' where 'nnnnn' is the number of shards created. + If the saver is empty, returns None. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.QueueBase.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.QueueBase.md index 9a8c841778e8af6d81a2430b067749e7ee31534a..fe81a505499f810a2c2f5a4038ea9d7f86e670b6 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.QueueBase.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.QueueBase.md @@ -302,3 +302,10 @@ The list of names for each component of a queue element. The underlying queue reference. +- - - + +#### `tf.QueueBase.shapes` {#QueueBase.shapes} + +The list of shapes for each component of a queue element. + + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.elbo_ratio.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.elbo_ratio.md new file mode 100644 index 0000000000000000000000000000000000000000..b62875b66c47d9208e83c1ccc3eab677580e7758 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.elbo_ratio.md @@ -0,0 +1,68 @@ +### `tf.contrib.bayesflow.entropy.elbo_ratio(log_p, q, z=None, n=None, seed=None, form=None, name='elbo_ratio')` {#elbo_ratio} + +Estimate of the ratio appearing in the `ELBO` and `KL` divergence. + +With `p(z) := exp{log_p(z)}`, this `Op` returns an approximation of + +``` +E_q[ Log[p(Z) / q(Z)] ] +``` + +The term `E_q[ Log[p(Z)] ]` is always computed as a sample mean. +The term `E_q[ Log[q(z)] ]` can be computed with samples, or an exact formula +if `q.entropy()` is defined. This is controlled with the kwarg `form`. + +This log-ratio appears in different contexts: + +#### `KL[q || p]` + +If `log_p(z) = Log[p(z)]` for distribution `p`, this `Op` approximates +the negative Kullback-Leibler divergence. + +``` +elbo_ratio(log_p, q, n=100) = -1 * KL[q || p], +KL[q || p] = E[ Log[q(Z)] - Log[p(Z)] ] +``` + +Note that if `p` is a `Distribution`, then `distributions.kl(q, p)` may be +defined and available as an exact result. + +#### ELBO + +If `log_p(z) = Log[p(z, x)]` is the log joint of a distribution `p`, this is +the Evidence Lower BOund (ELBO): + +``` +ELBO ~= E[ Log[p(Z, x)] - Log[q(Z)] ] + = Log[p(x)] - KL[q || p] + <= Log[p(x)] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_p`: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `q`: `tf.contrib.distributions.BaseDistribution`. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `form`: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. +* `name`: A name to give this `Op`. + +##### Returns: + + Scalar `Tensor` holding sample mean KL divergence. `shape` is the batch + shape of `q`, and `dtype` is the same as `q`. + +##### Raises: + + +* `ValueError`: If `form` is not handled by this function. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.renyi_alpha.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.renyi_alpha.md new file mode 100644 index 0000000000000000000000000000000000000000..c8834f7182a35361e6058d2eced628f7ca88ebd6 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.entropy.renyi_alpha.md @@ -0,0 +1,38 @@ +### `tf.contrib.bayesflow.entropy.renyi_alpha(step, decay_time, alpha_min, alpha_max=0.99999, name='renyi_alpha')` {#renyi_alpha} + +Exponentially decaying `Tensor` appropriate for Renyi ratios. + +When minimizing the Renyi divergence for `0 <= alpha < 1` (or maximizing the +Renyi equivalent of elbo) in high dimensions, it is not uncommon to experience +`NaN` and `inf` values when `alpha` is far from `1`. + +For that reason, it is often desirable to start the optimization with `alpha` +very close to 1, and reduce it to a final `alpha_min` according to some +schedule. The user may even want to optimize using `elbo_ratio` for +some fixed time before switching to Renyi based methods. + +This `Op` returns an `alpha` decaying exponentially with step: + +``` +s(step) = (exp{step / decay_time} - 1) / (e - 1) +t(s) = max(0, min(s, 1)), (smooth growth from 0 to 1) +alpha(t) = (1 - t) alpha_min + t alpha_max +``` + +##### Args: + + +* `step`: Non-negative scalar `Tensor`. Typically the global step or an + offset version thereof. +* `decay_time`: Postive scalar `Tensor`. +* `alpha_min`: `float` or `double` `Tensor`. + The minimal, final value of `alpha`, achieved when `step >= decay_time` +* `alpha_max`: `Tensor` of same `dtype` as `alpha_min`. + The maximal, beginning value of `alpha`, achieved when `step == 0` +* `name`: A name to give this `Op`. + +##### Returns: + + +* `alpha`: A `Tensor` of same `dtype` as `alpha_min`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler.md new file mode 100644 index 0000000000000000000000000000000000000000..23c689c019898beb7f7d9c2afad8a1603dcb1a68 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler.md @@ -0,0 +1,43 @@ +### `tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler(f, log_p, sampling_dist_q, z=None, n=None, seed=None, name='expectation_importance_sampler')` {#expectation_importance_sampler} + +Monte Carlo estimate of `E_p[f(Z)] = E_q[f(Z) p(Z) / q(Z)]`. + +With `p(z) := exp{log_p(z)}`, this `Op` returns + +``` +n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ], z_i ~ q, +\approx E_q[ f(Z) p(Z) / q(Z) ] += E_p[f(Z)] +``` + +This integral is done in log-space with max-subtraction to better handle the +often extreme values that `f(z) p(z) / q(z)` can take on. + +If `f >= 0`, it is up to 2x more efficient to exponentiate the result of +`expectation_importance_sampler_logspace` applied to `Log[f]`. + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with shape + broadcastable to `q.batch_shape`. + For example, `f` works "just like" `q.log_prob`. +* `log_p`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `sampling_dist_q.log_prob`. +* `sampling_dist_q`: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + The importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Beta.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Beta.md index 341a185e5208e4ec8d43813503440e7bbee0f6c0..f7a6f0c8a86ff1aad8f2a06a3d904e3e2fbfb304 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Beta.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Beta.md @@ -102,11 +102,32 @@ dist = Beta([1.0, 2.0], [4.0, 5.0]) Shape parameter. +- - - + +#### `tf.contrib.distributions.Beta.a_b_sum` {#Beta.a_b_sum} + +Sum of parameters. + + - - - #### `tf.contrib.distributions.Beta.allow_nan_stats` {#Beta.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - @@ -120,7 +141,7 @@ Shape parameter. #### `tf.contrib.distributions.Beta.batch_shape(name='batch_shape')` {#Beta.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -132,35 +153,48 @@ independent distributions of this kind the instance represents. ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Beta.cdf(x, name='cdf')` {#Beta.cdf} +#### `tf.contrib.distributions.Beta.cdf(value, name='cdf')` {#Beta.cdf} Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.Beta.dtype` {#Beta.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Beta.entropy(name='entropy')` {#Beta.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Beta.event_shape(name='event_shape')` {#Beta.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: @@ -169,7 +203,8 @@ Shape of a sample from a single distribution as a 1-D int32 `Tensor`. ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -189,8 +224,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -233,26 +268,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Beta.get_batch_shape()` {#Beta.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Beta.get_event_shape()` {#Beta.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -271,79 +308,109 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Beta.log_cdf(x, name='log_cdf')` {#Beta.log_cdf} +#### `tf.contrib.distributions.Beta.log_cdf(value, name='log_cdf')` {#Beta.log_cdf} + +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log CDF. +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Beta.log_pdf(value, name='log_pdf')` {#Beta.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Beta.log_pmf(value, name='log_pmf')` {#Beta.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + -Log of the probability mass function. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.log_prob(x, name='log_prob')` {#Beta.log_prob} +#### `tf.contrib.distributions.Beta.log_pmf(value, name='log_pmf')` {#Beta.log_pmf} -`Log(P[counts])`, computed for every batch member. +Log probability mass function. ##### Args: -* `x`: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents counts for the corresponding - Beta distribution in `self.a` and `self.b`. `x` is only legal if - 0 < x < 1. -* `name`: Name to give this Op, defaults to "log_prob". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Log probabilities for each record, shape `[N1,...,Nm]`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Beta.mean(name='mean')` {#Beta.mean} -Mean of the distribution. +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.mode(name='mode')` {#Beta.mode} - -Mode of the distribution. +#### `tf.contrib.distributions.Beta.log_prob(value, name='log_prob')` {#Beta.log_prob} -Note that the mode for the Beta distribution is only defined -when `a > 1`, `b > 1`. This returns the mode when `a > 1` and `b > 1`, -and NaN otherwise. If `self.allow_nan_stats` is `False`, an exception -will be raised rather than returning `NaN`. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: The name for this op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Mode of the Beta distribution. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + + +- - - + +#### `tf.contrib.distributions.Beta.mean(name='mean')` {#Beta.mean} + +Mean. + + +- - - + +#### `tf.contrib.distributions.Beta.mode(name='mode')` {#Beta.mode} + +Mode. - - - #### `tf.contrib.distributions.Beta.name` {#Beta.name} -Name to prepend to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -388,102 +455,145 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Beta.parameters` {#Beta.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Beta.pdf(value, name='pdf')` {#Beta.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Beta.pmf(value, name='pmf')` {#Beta.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Beta.prob(x, name='prob')` {#Beta.prob} +#### `tf.contrib.distributions.Beta.prob(value, name='prob')` {#Beta.prob} -`P[x]`, computed for every batch member. +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Non-negative floating point tensor whose shape can - be broadcast with `self.a` and `self.b`. For fixed leading - dimensions, the last dimension represents x for the corresponding Beta - distribution in `self.a` and `self.b`. `x` is only legal if is - between 0 and 1. -* `name`: Name to give this Op, defaults to "pdf". +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - Probabilities for each record, shape `[N1,...,Nm]`. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Beta.sample(sample_shape=(), seed=None, name='sample')` {#Beta.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Beta.sample_n(n, seed=None, name='sample_n')` {#Beta.sample_n} -Sample `n` observations from the Beta Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - #### `tf.contrib.distributions.Beta.std(name='std')` {#Beta.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Beta.validate_args` {#Beta.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Beta.variance(name='variance')` {#Beta.variance} -Variance of the distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Laplace.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Laplace.md index 52cba8fcb5377251e0d236741626ff66aa5aa2c9..fd57c8369d6af130a64680aca46c16b465b58b25 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Laplace.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.distributions.Laplace.md @@ -43,14 +43,28 @@ broadcasting (e.g., `loc / scale` is a valid operation). #### `tf.contrib.distributions.Laplace.allow_nan_stats` {#Laplace.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Laplace.batch_shape(name='batch_shape')` {#Laplace.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -58,69 +72,62 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Laplace.cdf(x, name='cdf')` {#Laplace.cdf} +#### `tf.contrib.distributions.Laplace.cdf(value, name='cdf')` {#Laplace.cdf} -CDF of observations in `x` under the Laplace distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.dtype` {#Laplace.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Laplace.entropy(name='entropy')` {#Laplace.entropy} -The entropy of Laplace distribution(s). - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Laplace.event_shape(name='event_shape')` {#Laplace.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -140,8 +147,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -184,26 +191,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Laplace.get_batch_shape()` {#Laplace.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Laplace.get_event_shape()` {#Laplace.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -229,80 +238,109 @@ Distribution parameter for the location. - - - -#### `tf.contrib.distributions.Laplace.log_cdf(x, name='log_cdf')` {#Laplace.log_cdf} +#### `tf.contrib.distributions.Laplace.log_cdf(value, name='log_cdf')` {#Laplace.log_cdf} -Log CDF of observations `x` under the Laplace distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.log_pdf(value, name='log_pdf')` {#Laplace.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: -- - - +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -#### `tf.contrib.distributions.Laplace.log_pmf(value, name='log_pmf')` {#Laplace.log_pmf} +##### Returns: -Log of the probability mass function. + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.log_prob(x, name='log_prob')` {#Laplace.log_prob} +#### `tf.contrib.distributions.Laplace.log_pmf(value, name='log_pmf')` {#Laplace.log_pmf} -Log prob of observations in `x` under these Laplace distribution(s). +Log probability mass function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-probability of `x`. +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.mean(name='mean')` {#Laplace.mean} +#### `tf.contrib.distributions.Laplace.log_prob(value, name='log_prob')` {#Laplace.log_prob} -Mean of this distribution. +Log probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Laplace.median(name='median')` {#Laplace.median} +#### `tf.contrib.distributions.Laplace.mean(name='mean')` {#Laplace.mean} -Median of this distribution. +Mean. - - - #### `tf.contrib.distributions.Laplace.mode(name='mode')` {#Laplace.mode} -Mode of this distribution. +Mode. - - - #### `tf.contrib.distributions.Laplace.name` {#Laplace.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -347,79 +385,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Laplace.parameters` {#Laplace.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Laplace.pdf(value, name='pdf')` {#Laplace.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Laplace.pmf(value, name='pmf')` {#Laplace.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Laplace.prob(x, name='pdf')` {#Laplace.prob} +#### `tf.contrib.distributions.Laplace.prob(value, name='prob')` {#Laplace.prob} -The prob of observations in `x` under the Laplace distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `loc` and `scale`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `pdf`: tensor of dtype `dtype`, the pdf values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Laplace.sample(sample_shape=(), seed=None, name='sample')` {#Laplace.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Laplace.sample_n(n, seed=None, name='sample_n')` {#Laplace.sample_n} -Sample `n` observations from the Laplace Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the parameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -433,20 +517,20 @@ Distribution parameter for scale. #### `tf.contrib.distributions.Laplace.std(name='std')` {#Laplace.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Laplace.validate_args` {#Laplace.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Laplace.variance(name='variance')` {#Laplace.variance} -Variance of this distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.framework.assign_from_values.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.framework.assign_from_values.md new file mode 100644 index 0000000000000000000000000000000000000000..6560f082814b0c993d145c88091246287337345e --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.framework.assign_from_values.md @@ -0,0 +1,24 @@ +### `tf.contrib.framework.assign_from_values(var_names_to_values)` {#assign_from_values} + +Creates an assignment operation from a given mapping. + +This function provides a mechanism for performing assignment of variables +to values in a way that does not fill the graph with large assignment values. + +##### Args: + + +* `var_names_to_values`: A map from variable names to values. + +##### Returns: + + +* `assign_op`: An `Operation` that assigns each of the given variables to the + requested values. +* `feed_dict`: The feed dictionary to use when evaluating `assign_op`. + +##### Raises: + + +* `ValueError`: if any of the given variable names were not found. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.learn.read_batch_examples.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.learn.read_batch_examples.md index c4a52d71b8c85d8f1f352d8c8610b98e1517b0b8..be7d043bd696647a042a1776b74e5448813202e4 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.learn.read_batch_examples.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.contrib.learn.read_batch_examples.md @@ -36,8 +36,7 @@ Use `parse_fn` if you need to do parsing / processing on single examples. ##### Returns: - String `Tensor` of batched `Example` proto. If `keep_keys` is True, then - returns tuple of string `Tensor`s, where first value is the key. + String `Tensor` of batched `Example` proto. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.summary.scalar.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.summary.scalar.md new file mode 100644 index 0000000000000000000000000000000000000000..020c9c060dff6019a6b54d3d42593bda8a6d0530 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard6/tf.summary.scalar.md @@ -0,0 +1,27 @@ +### `tf.summary.scalar(display_name, tensor, description='', labels=None, collections=None, name=None)` {#scalar} + +Outputs a `Summary` protocol buffer containing a single scalar value. + +The generated Summary has a Tensor.proto containing the input Tensor. + +##### Args: + + +* `display_name`: A name to associate with the data series. Will be used to + organize output data and as a name in visualizers. +* `tensor`: A tensor containing a single floating point or integer value. +* `description`: An optional long description of the data being output. +* `labels`: a list of strings used to attach metadata. +* `collections`: Optional list of graph collections keys. The new summary op is + added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. +* `name`: An optional name for the generated node (optional). + +##### Returns: + + A scalar `Tensor` of type `string`. Which contains a `Summary` protobuf. + +##### Raises: + + +* `ValueError`: If tensor has the wrong shape or type. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.Operation.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.Operation.md index a9e21fb29e7fb4005a4c37ad5d15277104c9997e..4cbcf8af3e85fcaeb4d99b9ecc6544d9ab2269fa 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.Operation.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.Operation.md @@ -151,8 +151,8 @@ regular expression: ##### Args: -* `node_def`: `graph_pb2.NodeDef`. `NodeDef` for the `Operation`. - Used for attributes of `graph_pb2.NodeDef`, typically `name`, +* `node_def`: `node_def_pb2.NodeDef`. `NodeDef` for the `Operation`. + Used for attributes of `node_def_pb2.NodeDef`, typically `name`, `op`, and `device`. The `input` attribute is irrelevant here as it will be computed when generating the model. * `g`: `Graph`. The parent graph. @@ -199,7 +199,7 @@ Returns a serialized `NodeDef` representation of this operation. ##### Returns: A - [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/graph.proto) + [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/node_def.proto) protocol buffer. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.bayesflow.entropy.renyi_ratio.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.bayesflow.entropy.renyi_ratio.md new file mode 100644 index 0000000000000000000000000000000000000000..cf51e6cd099deb52ae1d040c377a7532aa9adf8c --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.bayesflow.entropy.renyi_ratio.md @@ -0,0 +1,103 @@ +### `tf.contrib.bayesflow.entropy.renyi_ratio(log_p, q, alpha, z=None, n=None, seed=None, name='renyi_ratio')` {#renyi_ratio} + +Monte Carlo estimate of the ratio appearing in Renyi divergence. + +This can be used to compute the Renyi (alpha) divergence, or a log evidence +approximation based on Renyi divergence. + +#### Definition + +With `z_i` iid samples from `q`, and `exp{log_p(z)} = p(z)`, this `Op` returns +the (biased for finite `n`) estimate: + +``` +(1 - alpha)^{-1} Log[ n^{-1} sum_{i=1}^n ( p(z_i) / q(z_i) )^{1 - alpha}, +\approx (1 - alpha)^{-1} Log[ E_q[ (p(Z) / q(Z))^{1 - alpha} ] ] +``` + +This ratio appears in different contexts: + +#### Renyi divergence + +If `log_p(z) = Log[p(z)]` is the log prob of a distribution, and +`alpha > 0`, `alpha != 1`, this `Op` approximates `-1` times Renyi divergence: + +``` +# Choose reasonably high n to limit bias, see below. +renyi_ratio(log_p, q, alpha, n=100) + \approx -1 * D_alpha[q || p], where +D_alpha[q || p] := (1 - alpha)^{-1} Log E_q[(p(Z) / q(Z))^{1 - alpha}] +``` + +The Renyi (or "alpha") divergence is non-negative and equal to zero iff +`q = p`. Various limits of `alpha` lead to different special case results: + +``` +alpha D_alpha[q || p] +----- --------------- +--> 0 Log[ int_{q > 0} p(z) dz ] += 0.5, -2 Log[1 - Hel^2[q || p]], (\propto squared Hellinger distance) +--> 1 KL[q || p] += 2 Log[ 1 + chi^2[q || p] ], (\propto squared Chi-2 divergence) +--> infty Log[ max_z{q(z) / p(z)} ], (min description length principle). +``` + +See "Renyi Divergence Variational Inference", by Li and Turner. + +#### Log evidence approximation + +If `log_p(z) = Log[p(z, x)]` is the log of the joint distribution `p`, this is +an alternative to the ELBO common in variational inference. + +``` +L_alpha(q, p) = Log[p(x)] - D_alpha[q || p] +``` + +If `q` and `p` have the same support, and `0 < a <= b < 1`, one can show +`ELBO <= D_b <= D_a <= Log[p(x)]`. Thus, this `Op` allows a smooth +interpolation between the ELBO and the true evidence. + +#### Stability notes + +Note that when `1 - alpha` is not small, the ratio `(p(z) / q(z))^{1 - alpha}` +is subject to underflow/overflow issues. For that reason, it is evaluated in +log-space after centering. Nonetheless, infinite/NaN results may occur. For +that reason, one may wish to shrink `alpha` gradually. See the `Op` +`renyi_alpha`. Using `float64` will also help. + + +#### Bias for finite sample size + +Due to nonlinearity of the logarithm, for random variables `{X_1,...,X_n}`, +`E[ Log[sum_{i=1}^n X_i] ] != Log[ E[sum_{i=1}^n X_i] ]`. As a result, this +estimate is biased for finite `n`. For `alpha < 1`, it is non-decreasing +with `n` (in expectation). For example, if `n = 1`, this estimator yields the +same result as `elbo_ratio`, and as `n` increases the expected value +of the estimator increases. + +#### Call signature + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_p`: Callable mapping samples from `q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `q`: `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `alpha`: `Tensor` with shape `q.batch_shape` and values not equal to 1. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. The number of samples to use if `z` is not provided. + Note that this can be highly biased for small `n`, see docstring. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + +* `renyi_result`: The scaled log of sample mean. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.BaseDistribution.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.BaseDistribution.md index 81699a03b514a0aca9b3f5d25e10660b29793d46..f864de22ff59737a9e1d3abdee6660bca53aa841 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.BaseDistribution.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.BaseDistribution.md @@ -7,55 +7,32 @@ that want to fulfill a simpler distribution contract. #### `tf.contrib.distributions.BaseDistribution.log_prob(value, name='log_prob')` {#BaseDistribution.log_prob} -Log of the probability density/mass function. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.name` {#BaseDistribution.name} - -Name to prepend to all ops. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.prob(value, name='prob')` {#BaseDistribution.prob} - -Probability density/mass function. - - -- - - - -#### `tf.contrib.distributions.BaseDistribution.sample(sample_shape=(), seed=None, name='sample')` {#BaseDistribution.sample} - -Generate samples of the specified shape. - -Note that a call to `sample()` without arguments will generate a single -sample. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. -* `seed`: Python integer seed for RNG -* `name`: name to give to the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `samples`: a `Tensor` with prepended dimensions `sample_shape`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.BaseDistribution.sample_n(n, seed=None, name='sample_n')` {#BaseDistribution.sample_n} +#### `tf.contrib.distributions.BaseDistribution.sample_n(n, seed=None, name='sample')` {#BaseDistribution.sample_n} Generate `n` samples. ##### Args: -* `n`: scalar. Number of samples to draw. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. * `seed`: Python integer seed for RNG * `name`: name to give to the op. @@ -64,4 +41,9 @@ Generate `n` samples. * `samples`: a `Tensor` with a prepended dimension (n,). +##### Raises: + + +* `TypeError`: if `n` is not an integer type. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.MultivariateNormalFull.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.MultivariateNormalFull.md index f8dfe3f7e5442f81c0c3ade68ac7035ff182074e..714c457a24918294ffa73c4c2301fac2d45a5ca1 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.MultivariateNormalFull.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.MultivariateNormalFull.md @@ -71,14 +71,41 @@ User must provide means `mu` and `sigma`, the mean and covariance. #### `tf.contrib.distributions.MultivariateNormalFull.allow_nan_stats` {#MultivariateNormalFull.allow_nan_stats} -`Boolean` describing behavior when stats are undefined. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.MultivariateNormalFull.batch_shape(name='batch_shape')` {#MultivariateNormalFull.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -87,36 +114,48 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - #### `tf.contrib.distributions.MultivariateNormalFull.dtype` {#MultivariateNormalFull.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.entropy(name='entropy')` {#MultivariateNormalFull.entropy} -The entropies of these Multivariate Normals. +Shanon entropy in nats. -##### Args: +- - - -* `name`: The name to give this op. +#### `tf.contrib.distributions.MultivariateNormalFull.event_shape(name='event_shape')` {#MultivariateNormalFull.event_shape} -##### Returns: +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. +##### Args: -* `entropy`: tensor of dtype `dtype`, the entropies. +* `name`: name to give to the op -- - - +##### Returns: -#### `tf.contrib.distributions.MultivariateNormalFull.event_shape(name='event_shape')` {#MultivariateNormalFull.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +* `event_shape`: `Tensor`. - - - @@ -136,8 +175,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -180,14 +219,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalFull.get_batch_shape()` {#MultivariateNormalFull.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.MultivariateNormalFull.get_event_shape()` {#MultivariateNormalFull.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: + + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -208,48 +261,86 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.MultivariateNormalFull.log_cdf(value, name='log_cdf')` {#MultivariateNormalFull.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.log_pdf(value, name='log_pdf')` {#MultivariateNormalFull.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.log_pmf(value, name='log_pmf')` {#MultivariateNormalFull.log_pmf} -Log of the probability mass function. +Log probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalFull.log_prob(x, name='log_prob')` {#MultivariateNormalFull.log_prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -Log prob of observations `x` given these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.log_prob(value, name='log_prob')` {#MultivariateNormalFull.log_prob} + +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -263,14 +354,14 @@ Log of determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalFull.mean(name='mean')` {#MultivariateNormalFull.mean} -Mean of each batch member. +Mean. - - - #### `tf.contrib.distributions.MultivariateNormalFull.mode(name='mode')` {#MultivariateNormalFull.mode} -Mode of each batch member. +Mode. - - - @@ -284,7 +375,7 @@ Mode of each batch member. #### `tf.contrib.distributions.MultivariateNormalFull.name` {#MultivariateNormalFull.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -329,88 +420,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.parameters` {#MultivariateNormalFull.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.MultivariateNormalFull.pdf(value, name='pdf')` {#MultivariateNormalFull.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.pmf(value, name='pmf')` {#MultivariateNormalFull.pmf} -The probability mass function. +Probability mass function. +##### Args: -- - - -#### `tf.contrib.distributions.MultivariateNormalFull.prob(x, name='prob')` {#MultivariateNormalFull.prob} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. -The PDF of observations `x` under these Multivariate Normals. +##### Returns: -`x` is a batch vector with compatible shape if `x` is a `Tensor` whose -shape can be broadcast up to either: -```` -self.batch_shape + self.event_shape -OR -[M1,...,Mm] + self.batch_shape + self.event_shape -``` +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. + + +- - - + +#### `tf.contrib.distributions.MultivariateNormalFull.prob(value, name='prob')` {#MultivariateNormalFull.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: Compatible batch vector with same `dtype` as this distribution. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.sample(sample_shape=(), seed=None, name='sample')` {#MultivariateNormalFull.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.MultivariateNormalFull.sample_n(n, seed=None, name='sample_n')` {#MultivariateNormalFull.sample_n} -Sample `n` observations from the Multivariate Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -431,20 +559,20 @@ Determinant of covariance matrix. #### `tf.contrib.distributions.MultivariateNormalFull.std(name='std')` {#MultivariateNormalFull.std} -Standard deviation of the distribution. +Standard deviation. - - - #### `tf.contrib.distributions.MultivariateNormalFull.validate_args` {#MultivariateNormalFull.validate_args} -`Boolean` describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.MultivariateNormalFull.variance(name='variance')` {#MultivariateNormalFull.variance} -Variance of each batch member. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.Normal.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.Normal.md index eed175c094675d47b51d072da6b041eb9872c437..af4a07e521e2e31ddc3fc9a571614460a3a060db 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.Normal.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.distributions.Normal.md @@ -73,14 +73,28 @@ broadcasting (e.g. `mu + sigma` is a valid operation). #### `tf.contrib.distributions.Normal.allow_nan_stats` {#Normal.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Normal.batch_shape(name='batch_shape')` {#Normal.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. The product of the dimensions of the `batch_shape` is the number of independent distributions of this kind the instance represents. @@ -88,69 +102,62 @@ independent distributions of this kind the instance represents. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `batch_shape` + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Normal.cdf(x, name='cdf')` {#Normal.cdf} +#### `tf.contrib.distributions.Normal.cdf(value, name='cdf')` {#Normal.cdf} -CDF of observations in `x` under these Normal distribution(s). +Cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `cdf`: tensor of dtype `dtype`, the CDFs of `x`. +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.dtype` {#Normal.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Normal.entropy(name='entropy')` {#Normal.entropy} -The entropy of Normal distribution(s). - -##### Args: - - -* `name`: The name to give this op. - -##### Returns: - - -* `entropy`: tensor of dtype `dtype`, the entropy. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Normal.event_shape(name='event_shape')` {#Normal.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. ##### Args: -* `name`: name to give to the op. +* `name`: name to give to the op ##### Returns: - `Tensor` `event_shape` + +* `event_shape`: `Tensor`. - - - @@ -170,8 +177,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -214,26 +221,28 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Normal.get_batch_shape()` {#Normal.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. Same meaning as `batch_shape`. May be only partially defined. ##### Returns: - batch shape + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Normal.get_event_shape()` {#Normal.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. Same meaning as `event_shape`. May be only partially defined. ##### Returns: - event shape + +* `event_shape`: `TensorShape`, possibly unknown. - - - @@ -252,66 +261,102 @@ Same meaning as `event_shape`. May be only partially defined. - - - -#### `tf.contrib.distributions.Normal.log_cdf(x, name='log_cdf')` {#Normal.log_cdf} +#### `tf.contrib.distributions.Normal.log_cdf(value, name='log_cdf')` {#Normal.log_cdf} -Log CDF of observations `x` under these Normal distribution(s). +Log cumulative distribution function. ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_cdf`: tensor of dtype `dtype`, the log-CDFs of `x`. +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.log_pdf(value, name='log_pdf')` {#Normal.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Normal.log_pmf(value, name='log_pmf')` {#Normal.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Normal.log_prob(x, name='log_prob')` {#Normal.log_prob} +#### `tf.contrib.distributions.Normal.log_prob(value, name='log_prob')` {#Normal.log_prob} -Log prob of observations in `x` under these Normal distribution(s). +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `log_prob`: tensor of dtype `dtype`, the log-PDFs of `x`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.mean(name='mean')` {#Normal.mean} -Mean of this distribution. +Mean. - - - #### `tf.contrib.distributions.Normal.mode(name='mode')` {#Normal.mode} -Mode of this distribution. +Mode. - - - @@ -325,7 +370,7 @@ Distribution parameter for the mean. #### `tf.contrib.distributions.Normal.name` {#Normal.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -370,79 +415,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.Normal.parameters` {#Normal.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.Normal.pdf(value, name='pdf')` {#Normal.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.Normal.pmf(value, name='pmf')` {#Normal.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Normal.prob(x, name='prob')` {#Normal.prob} +#### `tf.contrib.distributions.Normal.prob(value, name='prob')` {#Normal.prob} -The PDF of observations in `x` under these Normal distribution(s). +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: tensor of dtype `dtype`, must be broadcastable with `mu` and `sigma`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: -* `prob`: tensor of dtype `dtype`, the prob values of `x`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Normal.sample(sample_shape=(), seed=None, name='sample')` {#Normal.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - #### `tf.contrib.distributions.Normal.sample_n(n, seed=None, name='sample_n')` {#Normal.sample_n} -Sample `n` observations from the Normal Distributions. +Generate `n` samples. ##### Args: -* `n`: `Scalar`, type int32, the number of observations to sample. -* `seed`: Python integer, the random seed. -* `name`: The name to give this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: `[n, ...]`, a `Tensor` of `n` samples for each - of the distributions determined by broadcasting the hyperparameters. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -456,20 +547,20 @@ Distribution parameter for standard deviation. #### `tf.contrib.distributions.Normal.std(name='std')` {#Normal.std} -Standard deviation of this distribution. +Standard deviation. - - - #### `tf.contrib.distributions.Normal.validate_args` {#Normal.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.Normal.variance(name='variance')` {#Normal.variance} -Variance of this distribution. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.framework.assign_from_values_fn.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.framework.assign_from_values_fn.md new file mode 100644 index 0000000000000000000000000000000000000000..9a5a82c8c4d7efaac2668f5b208312a1aabfd7a8 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.framework.assign_from_values_fn.md @@ -0,0 +1,22 @@ +### `tf.contrib.framework.assign_from_values_fn(var_names_to_values)` {#assign_from_values_fn} + +Returns a function that assigns specific variables from the given values. + +This function provides a mechanism for performing assignment of variables +to values in a way that does not fill the graph with large assignment values. + +##### Args: + + +* `var_names_to_values`: A map from variable names to values. + +##### Returns: + + A function that takes a single argument, a `tf.Session`, that applies the + assignment operation. + +##### Raises: + + +* `ValueError`: if any of the given variable names were not found. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.learn.TensorFlowClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.learn.TensorFlowClassifier.md deleted file mode 100644 index fa099a4aad8118e4776433d5a29afb1df4bb377f..0000000000000000000000000000000000000000 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.contrib.learn.TensorFlowClassifier.md +++ /dev/null @@ -1,240 +0,0 @@ - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.__init__(*args, **kwargs)` {#TensorFlowClassifier.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.bias_` {#TensorFlowClassifier.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.dnn_bias_` {#TensorFlowClassifier.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.dnn_weights_` {#TensorFlowClassifier.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowClassifier.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowClassifier.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowClassifier.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_params(deep=True)` {#TensorFlowClassifier.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_variable_names()` {#TensorFlowClassifier.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.get_variable_value(name)` {#TensorFlowClassifier.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.linear_bias_` {#TensorFlowClassifier.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.linear_weights_` {#TensorFlowClassifier.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.model_dir` {#TensorFlowClassifier.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowClassifier.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowClassifier.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowClassifier.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.save(path)` {#TensorFlowClassifier.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.set_params(**params)` {#TensorFlowClassifier.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowClassifier.weights_` {#TensorFlowClassifier.weights_} - - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.ones_like.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.ones_like.md index dac818fdfe230d05350f2ea14049973599afd966..5ca57f52a50f38a58a61ee5ec488d7b07a0da7c8 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.ones_like.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard7/tf.ones_like.md @@ -18,8 +18,8 @@ tf.ones_like(tensor) ==> [[1, 1, 1], [1, 1, 1]] * `tensor`: A `Tensor`. * `dtype`: A type for the returned `Tensor`. Must be `float32`, `float64`, - `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, or `complex128`. - + `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, `complex128` or + `bool`. * `name`: A name for the operation (optional). * `optimize`: if true, attempt to statically determine the shape of 'tensor' and encode it as a constant. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.graph_editor.copy_with_input_replacements.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.graph_editor.copy_with_input_replacements.md new file mode 100644 index 0000000000000000000000000000000000000000..980efd52d1d27cc27b506d2b5cbcfa5c787ae801 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.graph_editor.copy_with_input_replacements.md @@ -0,0 +1,37 @@ +### `tf.contrib.graph_editor.copy_with_input_replacements(sgv, replacement_ts, dst_graph=None, dst_scope='', src_scope='', reuse_dst_scope=False)` {#copy_with_input_replacements} + +Copy a subgraph, replacing some of its inputs. + +Note a replacement only happens if the tensor to be replaced +is an input of the given subgraph. The inputs of a subgraph can +be queried using sgv.inputs. + +##### Args: + + +* `sgv`: the source subgraph-view. This argument is converted to a subgraph + using the same rules as the function subgraph.make_view. +* `replacement_ts`: dictionary mapping from original tensors to the + replaced one. +* `dst_graph`: the destination graph. +* `dst_scope`: the destination scope. +* `src_scope`: the source scope. +* `reuse_dst_scope`: if True the dst_scope is re-used if it already exists. + Otherwise, the scope is given a unique name based on the one given + by appending an underscore followed by a digit (default). + +##### Returns: + + A tuple `(sgv, info)` where: + `sgv` is the transformed subgraph view; + `info` is an instance of Transformer.ResultInfo containing + information about the transform, including mapping between + original and transformed tensors and operations. + +##### Raises: + + +* `TypeError`: if dst_graph is not a tf.Graph. +* `StandardError`: if sgv cannot be converted to a SubGraphView using + the same rules as the function subgraph.make_view. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.learn.TensorFlowRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.learn.TensorFlowRegressor.md deleted file mode 100644 index 69c99f3aa030d3c51318d87f25fc10b99f7597c7..0000000000000000000000000000000000000000 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.learn.TensorFlowRegressor.md +++ /dev/null @@ -1,240 +0,0 @@ - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.__init__(*args, **kwargs)` {#TensorFlowRegressor.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.bias_` {#TensorFlowRegressor.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.dnn_bias_` {#TensorFlowRegressor.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.dnn_weights_` {#TensorFlowRegressor.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRegressor.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRegressor.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowRegressor.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_params(deep=True)` {#TensorFlowRegressor.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_variable_names()` {#TensorFlowRegressor.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.get_variable_value(name)` {#TensorFlowRegressor.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.linear_bias_` {#TensorFlowRegressor.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.linear_weights_` {#TensorFlowRegressor.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.model_dir` {#TensorFlowRegressor.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowRegressor.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowRegressor.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowRegressor.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.save(path)` {#TensorFlowRegressor.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.set_params(**params)` {#TensorFlowRegressor.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowRegressor.weights_` {#TensorFlowRegressor.weights_} - - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.metrics.confusion_matrix.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.metrics.confusion_matrix.md index f06295f0811ae009390958ec16a8a2a9965b972f..50d7917926c4751877a0652abe7350b10987319e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.metrics.confusion_matrix.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.contrib.metrics.confusion_matrix.md @@ -35,7 +35,7 @@ the same shape in order for this function to work. ##### Returns: - A l X l matrix represeting the confusion matrix, where l in the number of + A k X k matrix represeting the confusion matrix, where k is the number of possible labels in the classification task. ##### Raises: diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.nn.bidirectional_dynamic_rnn.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.nn.bidirectional_dynamic_rnn.md new file mode 100644 index 0000000000000000000000000000000000000000..1252efa34dba22457e27c56e558cfd1b51ac44a0 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.nn.bidirectional_dynamic_rnn.md @@ -0,0 +1,86 @@ +### `tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, sequence_length=None, initial_state_fw=None, initial_state_bw=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None)` {#bidirectional_dynamic_rnn} + +Creates a dynamic version of bidirectional recurrent neural network. + +Similar to the unidirectional case above (rnn) but takes input and builds +independent forward and backward RNNs. The input_size of forward and +backward cell must match. The initial state for both directions is zero by +default (but can be set optionally) and no intermediate states are ever +returned -- the network is fully unrolled for the given (passed in) +length(s) of the sequence(s) or completely unrolled if length(s) is not +given. + +##### Args: + + +* `cell_fw`: An instance of RNNCell, to be used for forward direction. +* `cell_bw`: An instance of RNNCell, to be used for backward direction. +* `inputs`: The RNN inputs. + If time_major == False (default), this must be a tensor of shape: + `[batch_size, max_time, input_size]`. + If time_major == True, this must be a tensor of shape: + `[max_time, batch_size, input_size]`. + [batch_size, input_size]. +* `sequence_length`: An int32/int64 vector, size `[batch_size]`, + containing the actual lengths for each of the sequences. +* `initial_state_fw`: (optional) An initial state for the forward RNN. + This must be a tensor of appropriate type and shape + `[batch_size x cell_fw.state_size]`. + If `cell_fw.state_size` is a tuple, this should be a tuple of + tensors having shapes `[batch_size, s] for s in cell_fw.state_size`. +* `initial_state_bw`: (optional) Same as for `initial_state_fw`, but using + the corresponding properties of `cell_bw`. +* `dtype`: (optional) The data type for the initial states and expected output. + Required if initial_states are not provided or RNN states have a + heterogeneous dtype. +* `parallel_iterations`: (Default: 32). The number of iterations to run in + parallel. Those operations which do not have any temporal dependency + and can be run in parallel, will be. This parameter trades off + time for space. Values >> 1 use more memory but take less time, + while smaller values use less memory but computations take longer. +* `swap_memory`: Transparently swap the tensors produced in forward inference + but needed for back prop from GPU to CPU. This allows training RNNs + which would typically not fit on a single GPU, with very minimal (or no) + performance penalty. +* `time_major`: The shape format of the `inputs` and `outputs` Tensors. + If true, these `Tensors` must be shaped `[max_time, batch_size, depth]`. + If false, these `Tensors` must be shaped `[batch_size, max_time, depth]`. + Using `time_major = True` is a bit more efficient because it avoids + transposes at the beginning and end of the RNN calculation. However, + most TensorFlow data is batch-major, so by default this function + accepts input and emits output in batch-major form. +* `dtype`: (optional) The data type for the initial state. Required if + initial_state is not provided. +* `sequence_length`: An int32/int64 vector, size `[batch_size]`, + containing the actual lengths for each of the sequences. + either of the initial states are not provided. +* `scope`: VariableScope for the created subgraph; defaults to "BiRNN" + +##### Returns: + + A tuple (outputs, output_states) where: + +* `outputs`: A tuple (output_fw, output_bw) containing the forward and + the backward rnn output `Tensor`. + If time_major == False (default), + output_fw will be a `Tensor` shaped: + `[batch_size, max_time, cell_fw.output_size]` + and output_bw will be a `Tensor` shaped: + `[batch_size, max_time, cell_bw.output_size]`. + If time_major == True, + output_fw will be a `Tensor` shaped: + `[max_time, batch_size, cell_fw.output_size]` + and output_bw will be a `Tensor` shaped: + `[max_time, batch_size, cell_bw.output_size]`. + It returns a tuple instead of a single concatenated `Tensor`, unlike + in the `bidirectional_rnn`. If the concatenated one is preferred, + the forward and backward outputs can be concatenated as + `tf.concat(2, outputs)`. +* `output_states`: A tuple (output_state_fw, output_state_bw) containing + the forward and the backward final states of bidirectional rnn. + +##### Raises: + + +* `TypeError`: If `cell_fw` or `cell_bw` is not an instance of `RNNCell`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.ones_initializer.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.ones_initializer.md index 0ddbc8b80144d69f6ffd0c7a10bc50f74816a5b1..ebb90069ad6b07a14e7c47aa50fe2f5f032b1475 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.ones_initializer.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard8/tf.ones_initializer.md @@ -1,4 +1,4 @@ -### `tf.ones_initializer(shape, dtype=tf.float32)` {#ones_initializer} +### `tf.ones_initializer(shape, dtype=tf.float32, partition_info=None)` {#ones_initializer} An adaptor for ones() to match the Initializer spec. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.entropy.entropy_shannon.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.entropy.entropy_shannon.md new file mode 100644 index 0000000000000000000000000000000000000000..bf37868e33493f80819a5942c3d2542652e03548 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.entropy.entropy_shannon.md @@ -0,0 +1,38 @@ +### `tf.contrib.bayesflow.entropy.entropy_shannon(p, z=None, n=None, seed=None, form=None, name='entropy_shannon')` {#entropy_shannon} + +Monte Carlo or deterministic computation of Shannon's entropy. + +Depending on the kwarg `form`, this `Op` returns either the analytic entropy +of the distribution `p`, or the sampled entropy: + +``` +-n^{-1} sum_{i=1}^n p.log_prob(z_i), where z_i ~ p, + \approx - E_p[ Log[p(Z)] ] + = Entropy[p] +``` + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `p`: `tf.contrib.distributions.BaseDistribution` +* `z`: `Tensor` of samples from `p`, produced by `p.sample_n(n)` for some `n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `form`: Either `ELBOForms.analytic_entropy` (use formula for entropy of `q`) + or `ELBOForms.sample` (sample estimate of entropy), or `ELBOForms.default` + (attempt analytic entropy, fallback on sample). + Default value is `ELBOForms.default`. +* `name`: A name to give this `Op`. + +##### Returns: + + A `Tensor` with same `dtype` as `p`, and shape equal to `p.batch_shape`. + +##### Raises: + + +* `ValueError`: If `form` not handled by this function. +* `ValueError`: If `form` is `ELBOForms.analytic_entropy` and `n` was provided. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler_logspace.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler_logspace.md new file mode 100644 index 0000000000000000000000000000000000000000..dff7940d4b73fe99fbc0efc908bed60836bdf87c --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler_logspace.md @@ -0,0 +1,45 @@ +### `tf.contrib.bayesflow.monte_carlo.expectation_importance_sampler_logspace(log_f, log_p, sampling_dist_q, z=None, n=None, seed=None, name='expectation_importance_sampler_logspace')` {#expectation_importance_sampler_logspace} + +Importance sampling with a positive function, in log-space. + +With `p(z) := exp{log_p(z)}`, and `f(z) = exp{log_f(z)}`, this `Op` +returns + +``` +Log[ n^{-1} sum_{i=1}^n [ f(z_i) p(z_i) / q(z_i) ] ], z_i ~ q, +\approx Log[ E_q[ f(Z) p(Z) / q(Z) ] ] += Log[E_p[f(Z)]] +``` + +This integral is done in log-space with max-subtraction to better handle the +often extreme values that `f(z) p(z) / q(z)` can take on. + +In contrast to `expectation_importance_sampler`, this `Op` returns values in +log-space. + + +User supplies either `Tensor` of samples `z`, or number of samples to draw `n` + +##### Args: + + +* `log_f`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_f` works "just like" `sampling_dist_q.log_prob`. +* `log_p`: Callable mapping samples from `sampling_dist_q` to `Tensors` with + shape broadcastable to `q.batch_shape`. + For example, `log_p` works "just like" `q.log_prob`. +* `sampling_dist_q`: The sampling distribution. + `tf.contrib.distributions.BaseDistribution`. + `float64` `dtype` recommended. + `log_p` and `q` should be supported on the same set. +* `z`: `Tensor` of samples from `q`, produced by `q.sample_n`. +* `n`: Integer `Tensor`. Number of samples to generate if `z` is not provided. +* `seed`: Python integer to seed the random number generator. +* `name`: A name to give this `Op`. + +##### Returns: + + Logarithm of the importance sampling estimate. `Tensor` with `shape` equal + to batch shape of `q`, and `dtype` = `q.dtype`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.Poisson.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.Poisson.md index fda570b29091a3a8aa87a500638ca296052d2083..080df4c65754604601b927f375760c6e897a2e21 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.Poisson.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.Poisson.md @@ -34,54 +34,92 @@ Construct Poisson distributions. #### `tf.contrib.distributions.Poisson.allow_nan_stats` {#Poisson.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.Poisson.batch_shape(name='batch_shape')` {#Poisson.batch_shape} +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - -#### `tf.contrib.distributions.Poisson.cdf(x, name='cdf')` {#Poisson.cdf} +#### `tf.contrib.distributions.Poisson.cdf(value, name='cdf')` {#Poisson.cdf} -Cumulative density function. +Cumulative distribution function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The CDF of the events. + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Poisson.dtype` {#Poisson.dtype} - +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.Poisson.entropy(name='entropy')` {#Poisson.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.Poisson.event_shape(name='event_shape')` {#Poisson.event_shape} +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: +* `event_shape`: `Tensor`. + - - - @@ -100,8 +138,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -144,15 +182,29 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.Poisson.get_batch_shape()` {#Poisson.get_batch_shape} +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.Poisson.get_event_shape()` {#Poisson.get_event_shape} +Shape of a single sample from a single batch as a `TensorShape`. + +Same meaning as `event_shape`. May be only partially defined. + +##### Returns: +* `event_shape`: `TensorShape`, possibly unknown. + - - - @@ -177,98 +229,109 @@ Rate parameter. - - - -#### `tf.contrib.distributions.Poisson.log_cdf(x, name='log_cdf')` {#Poisson.log_cdf} +#### `tf.contrib.distributions.Poisson.log_cdf(value, name='log_cdf')` {#Poisson.log_cdf} -Log cumulative density function. +Log cumulative distribution function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The Log CDF of the events. + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.Poisson.log_pdf(value, name='log_pdf')` {#Poisson.log_pdf} -Log of the probability density function. +Log probability density function. +##### Args: -- - - -#### `tf.contrib.distributions.Poisson.log_pmf(value, name='log_pmf')` {#Poisson.log_pmf} +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + -Log of the probability mass function. +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.log_prob(x, name='log_prob')` {#Poisson.log_prob} +#### `tf.contrib.distributions.Poisson.log_pmf(value, name='log_pmf')` {#Poisson.log_pmf} Log probability mass function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. -* `name`: A name for this operation (optional). +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The log-probabilities of the events. + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.mean(name='mean')` {#Poisson.mean} +#### `tf.contrib.distributions.Poisson.log_prob(value, name='log_prob')` {#Poisson.log_prob} -Mean of the distribution. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `name`: Name for the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `mean`: `Tensor` of the same type and shape as `lam`. +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Poisson.mode(name='mode')` {#Poisson.mode} - -Mode of the distribution. - -Note that when `lam` is an integer, there are actually two modes. -Namely, `lam` and `lam - 1` are both modes. Here we return -only the larger of the two modes. - -##### Args: +#### `tf.contrib.distributions.Poisson.mean(name='mean')` {#Poisson.mean} +Mean. -* `name`: Name for the op. -##### Returns: +- - - +#### `tf.contrib.distributions.Poisson.mode(name='mode')` {#Poisson.mode} -* `mode`: `Tensor` of the same type and shape as `lam`. +Mode. - - - #### `tf.contrib.distributions.Poisson.name` {#Poisson.name} - +Name prepended to all ops created by this `Distribution`. - - - @@ -315,118 +378,143 @@ param_shapes with static (i.e. TensorShape) shapes. - - - -#### `tf.contrib.distributions.Poisson.pdf(value, name='pdf')` {#Poisson.pdf} +#### `tf.contrib.distributions.Poisson.parameters` {#Poisson.parameters} -The probability density function. +Dictionary of parameters used by this `Distribution`. - - - -#### `tf.contrib.distributions.Poisson.pmf(value, name='pmf')` {#Poisson.pmf} +#### `tf.contrib.distributions.Poisson.pdf(value, name='pdf')` {#Poisson.pdf} + +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: -The probability mass function. + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - -#### `tf.contrib.distributions.Poisson.prob(x, name='prob')` {#Poisson.prob} +#### `tf.contrib.distributions.Poisson.pmf(value, name='pmf')` {#Poisson.pmf} Probability mass function. ##### Args: -* `x`: Non-negative floating point tensor with dtype `dtype` and whose shape - can be broadcast with `self.lam`. `x` is only legal if it is - non-negative and its components are equal to integer values. -* `name`: A name for this operation. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: - The probabilities of the events. +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. -- - - +##### Raises: -#### `tf.contrib.distributions.Poisson.sample(sample_shape=(), seed=None, name='sample')` {#Poisson.sample} -Generate samples of the specified shape for each batched distribution. +* `AttributeError`: if `is_continuous`. -Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. + +- - - + +#### `tf.contrib.distributions.Poisson.prob(value, name='prob')` {#Poisson.prob} + +Probability density/mass function (depending on `is_continuous`). ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. -* `seed`: Python integer seed for RNG -* `name`: name to give to the op. +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - -#### `tf.contrib.distributions.Poisson.sample_n(n, seed=None, name='sample_n')` {#Poisson.sample_n} +#### `tf.contrib.distributions.Poisson.sample(sample_shape=(), seed=None, name='sample')` {#Poisson.sample} -Generate `n` samples. +Generate samples of the specified shape. + +Note that a call to `sample()` without arguments will generate a single +sample. ##### Args: -* `n`: scalar. Number of samples to draw from each distribution. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - -#### `tf.contrib.distributions.Poisson.std(name='std')` {#Poisson.std} +#### `tf.contrib.distributions.Poisson.sample_n(n, seed=None, name='sample_n')` {#Poisson.sample_n} -Standard deviation of the distribution. +Generate `n` samples. ##### Args: -* `name`: Name for the op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `std`: `Tensor` of the same type and shape as `lam`. - +* `samples`: a `Tensor` with a prepended dimension (n,). -- - - +##### Raises: -#### `tf.contrib.distributions.Poisson.validate_args` {#Poisson.validate_args} -Boolean describing behavior on invalid input. +* `TypeError`: if `n` is not an integer type. - - - -#### `tf.contrib.distributions.Poisson.variance(name='variance')` {#Poisson.variance} +#### `tf.contrib.distributions.Poisson.std(name='std')` {#Poisson.std} -Variance of the distribution. +Standard deviation. -##### Args: +- - - -* `name`: Name for the op. +#### `tf.contrib.distributions.Poisson.validate_args` {#Poisson.validate_args} + +Python boolean indicated possibly expensive checks are enabled. -##### Returns: +- - - + +#### `tf.contrib.distributions.Poisson.variance(name='variance')` {#Poisson.variance} -* `variance`: `Tensor` of the same type and shape as `lam`. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.WishartFull.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.WishartFull.md index 99e26f506638aa3c57add22dce1b9e0f8cc67735..96b878fcfe69c1dac95f1e2c3273225a090d0f6e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.WishartFull.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.distributions.WishartFull.md @@ -55,7 +55,7 @@ dist.pdf(x) # Shape is [2, 2]. ``` - - - -#### `tf.contrib.distributions.WishartFull.__init__(df, scale, cholesky_input_output_matrices=False, allow_nan_stats=False, validate_args=True, name='Wishart')` {#WishartFull.__init__} +#### `tf.contrib.distributions.WishartFull.__init__(df, scale, cholesky_input_output_matrices=False, validate_args=True, allow_nan_stats=False, name='WishartFull')` {#WishartFull.__init__} Construct Wishart distributions. @@ -71,13 +71,13 @@ Construct Wishart distributions. Cholesky factored matrix. Example`log_pdf` input takes a Cholesky and `sample_n` returns a Cholesky when `cholesky_input_output_matrices=True`. +* `validate_args`: Whether to validate input with asserts. If `validate_args` + is `False`, and the inputs are invalid, correct behavior is not + guaranteed. * `allow_nan_stats`: `Boolean`, default `False`. If `False`, raise an exception if a statistic (e.g., mean, mode) is undefined for any batch member. If True, batch members with valid parameters leading to undefined statistics will return `NaN` for this statistic. -* `validate_args`: Whether to validate input with asserts. If `validate_args` - is `False`, and the inputs are invalid, correct behavior is not - guaranteed. * `name`: The name scope to give class member ops. @@ -85,14 +85,41 @@ Construct Wishart distributions. #### `tf.contrib.distributions.WishartFull.allow_nan_stats` {#WishartFull.allow_nan_stats} -Boolean describing behavior when a stat is undefined for batch member. +Python boolean describing behavior when a stat is undefined. + +Stats return +/- infinity when it makes sense. E.g., the variance +of a Cauchy distribution is infinity. However, sometimes the +statistic is undefined, e.g., if a distribution's pdf does not achieve a +maximum within the support of the distribution, the mode is undefined. +If the mean is undefined, then by definition the variance is undefined. +E.g. the mean for Student's T for df = 1 is undefined (no clear way to say +it is either + or - infinity), so the variance = E[(X - mean)^2] is also +undefined. + +##### Returns: + + +* `allow_nan_stats`: Python boolean. - - - #### `tf.contrib.distributions.WishartFull.batch_shape(name='batch_shape')` {#WishartFull.batch_shape} -Batch dimensions of this instance as a 1-D int32 `Tensor`. +Shape of a single sample from a single event index as a 1-D `Tensor`. + +The product of the dimensions of the `batch_shape` is the number of +independent distributions of this kind the instance represents. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `batch_shape`: `Tensor`. - - - @@ -101,6 +128,18 @@ Batch dimensions of this instance as a 1-D int32 `Tensor`. Cumulative distribution function. +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `cdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + - - - @@ -127,21 +166,31 @@ Dimension of underlying vector space. The `p` in `R^(p*p)`. #### `tf.contrib.distributions.WishartFull.dtype` {#WishartFull.dtype} -dtype of samples from this distribution. +The `DType` of `Tensor`s handled by this `Distribution`. - - - #### `tf.contrib.distributions.WishartFull.entropy(name='entropy')` {#WishartFull.entropy} -Entropy of the distribution in nats. +Shanon entropy in nats. - - - #### `tf.contrib.distributions.WishartFull.event_shape(name='event_shape')` {#WishartFull.event_shape} -Shape of a sample from a single distribution as a 1-D int32 `Tensor`. +Shape of a single sample from a single batch as a 1-D int32 `Tensor`. + +##### Args: + + +* `name`: name to give to the op + +##### Returns: + + +* `event_shape`: `Tensor`. - - - @@ -161,8 +210,8 @@ shapes = MultiVariateNormalDiag.param_shapes([batch_size, 10]) # shapes has a Tensor shape for mu and sigma # shapes == { -# 'mu': tf.constant([batch_size, 10]), -# 'sigma': tf.constant([batch_size, 10]), +# "mu": tf.constant([batch_size, 10]), +# "sigma": tf.constant([batch_size, 10]), # } # Here we parameterize mu and sigma with the output of a linear @@ -205,33 +254,40 @@ apply it externally and set `make_safe=False`. #### `tf.contrib.distributions.WishartFull.get_batch_shape()` {#WishartFull.get_batch_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single event index as a `TensorShape`. + +Same meaning as `batch_shape`. May be only partially defined. + +##### Returns: + + +* `batch_shape`: `TensorShape`, possibly unknown. - - - #### `tf.contrib.distributions.WishartFull.get_event_shape()` {#WishartFull.get_event_shape} -`TensorShape` available at graph construction time. +Shape of a single sample from a single batch as a `TensorShape`. +Same meaning as `event_shape`. May be only partially defined. -- - - +##### Returns: -#### `tf.contrib.distributions.WishartFull.inputs` {#WishartFull.inputs} -Dictionary of inputs provided at initialization. +* `event_shape`: `TensorShape`, possibly unknown. - - - -#### `tf.contrib.distributions.WishartFull.is_continuous()` {#WishartFull.is_continuous} +#### `tf.contrib.distributions.WishartFull.is_continuous` {#WishartFull.is_continuous} - - - -#### `tf.contrib.distributions.WishartFull.is_reparameterized()` {#WishartFull.is_reparameterized} +#### `tf.contrib.distributions.WishartFull.is_reparameterized` {#WishartFull.is_reparameterized} @@ -240,7 +296,19 @@ Dictionary of inputs provided at initialization. #### `tf.contrib.distributions.WishartFull.log_cdf(value, name='log_cdf')` {#WishartFull.log_cdf} -Log CDF. +Log cumulative distribution function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `logcdf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - @@ -254,26 +322,60 @@ Computes the log normalizing constant, log(Z). #### `tf.contrib.distributions.WishartFull.log_pdf(value, name='log_pdf')` {#WishartFull.log_pdf} -Log of the probability density function. +Log probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.log_pmf(value, name='log_pmf')` {#WishartFull.log_pmf} -Log of the probability mass function. +Log probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `log_pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - -#### `tf.contrib.distributions.WishartFull.log_prob(x, name='log_prob')` {#WishartFull.log_prob} +#### `tf.contrib.distributions.WishartFull.log_prob(value, name='log_prob')` {#WishartFull.log_prob} -Log of the probability density/mass function. +Log probability density/mass function (depending on `is_continuous`). ##### Args: -* `x`: `float` or `double` `Tensor`. +* `value`: `float` or `double` `Tensor`. * `name`: The name to give this op. ##### Returns: @@ -287,7 +389,7 @@ Log of the probability density/mass function. #### `tf.contrib.distributions.WishartFull.mean(name='mean')` {#WishartFull.mean} -Mean of the distribution. +Mean. - - - @@ -301,14 +403,14 @@ Computes E[log(det(X))] under this Wishart distribution. #### `tf.contrib.distributions.WishartFull.mode(name='mode')` {#WishartFull.mode} -Mode of the distribution. +Mode. - - - #### `tf.contrib.distributions.WishartFull.name` {#WishartFull.name} -Name prepended to all ops. +Name prepended to all ops created by this `Distribution`. - - - @@ -353,75 +455,125 @@ param_shapes with static (i.e. TensorShape) shapes. * `ValueError`: if `sample_shape` is a `TensorShape` and is not fully defined. +- - - + +#### `tf.contrib.distributions.WishartFull.parameters` {#WishartFull.parameters} + +Dictionary of parameters used by this `Distribution`. + + - - - #### `tf.contrib.distributions.WishartFull.pdf(value, name='pdf')` {#WishartFull.pdf} -The probability density function. +Probability density function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if not `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.pmf(value, name='pmf')` {#WishartFull.pmf} -The probability mass function. +Probability mass function. + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `pmf`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. + +##### Raises: + + +* `AttributeError`: if `is_continuous`. - - - #### `tf.contrib.distributions.WishartFull.prob(value, name='prob')` {#WishartFull.prob} -Probability density/mass function. +Probability density/mass function (depending on `is_continuous`). + +##### Args: + + +* `value`: `float` or `double` `Tensor`. +* `name`: The name to give this op. + +##### Returns: + + +* `prob`: a `Tensor` of shape `sample_shape(x) + self.batch_shape` with + values of type `self.dtype`. - - - #### `tf.contrib.distributions.WishartFull.sample(sample_shape=(), seed=None, name='sample')` {#WishartFull.sample} -Generate samples of the specified shape for each batched distribution. +Generate samples of the specified shape. Note that a call to `sample()` without arguments will generate a single -sample per batched distribution. +sample. ##### Args: -* `sample_shape`: Rank 1 `int32` `Tensor`. Shape of the generated samples. +* `sample_shape`: 0D or 1D `int32` `Tensor`. Shape of the generated samples. * `seed`: Python integer seed for RNG * `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of dtype `self.dtype` and shape - `sample_shape + self.batch_shape + self.event_shape`. +* `samples`: a `Tensor` with prepended dimensions `sample_shape`. - - - -#### `tf.contrib.distributions.WishartFull.sample_n(n, seed=None, name='sample')` {#WishartFull.sample_n} +#### `tf.contrib.distributions.WishartFull.sample_n(n, seed=None, name='sample_n')` {#WishartFull.sample_n} Generate `n` samples. -Complexity: O(nbk^3) - -The sampling procedure is based on the [Bartlett decomposition]( -https://en.wikipedia.org/wiki/Wishart_distribution#Bartlett_decomposition) -and [using a Gamma distribution to generate Chi2 random variates]( -https://en.wikipedia.org/wiki/Chi-squared_distribution#Gamma.2C_exponential.2C_and_related_distributions). - ##### Args: -* `n`: Scalar. Number of samples to draw from each distribution. -* `seed`: Python integer; random number generator seed. -* `name`: The name of this op. +* `n`: `Scalar` `Tensor` of type `int32` or `int64`, the number of + observations to sample. +* `seed`: Python integer seed for RNG +* `name`: name to give to the op. ##### Returns: -* `samples`: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` - with values of type `self.dtype`. +* `samples`: a `Tensor` with a prepended dimension (n,). + +##### Raises: + + +* `TypeError`: if `n` is not an integer type. - - - @@ -442,39 +594,20 @@ Wishart distribution scale matrix as an OperatorPD. #### `tf.contrib.distributions.WishartFull.std(name='std')` {#WishartFull.std} -Standard deviation of the Wishart distribution. +Standard deviation. - - - #### `tf.contrib.distributions.WishartFull.validate_args` {#WishartFull.validate_args} -Boolean describing behavior on invalid input. +Python boolean indicated possibly expensive checks are enabled. - - - #### `tf.contrib.distributions.WishartFull.variance(name='variance')` {#WishartFull.variance} -Variance of the Wishart distribution. - -This function should not be confused with the covariance of the Wishart. The -covariance matrix would have shape `q x q` where, -`q = dimension * (dimension+1) / 2` -and having elements corresponding to some mapping from a lower-triangular -matrix to a vector-space. - -This function returns the diagonal of the Covariance matrix but shaped -as a `dimension x dimension` matrix. - -##### Args: - - -* `name`: The name of this op. - -##### Returns: - - -* `variance`: `Tensor` of dtype `self.dtype`. +Variance. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.framework.assign_from_checkpoint_fn.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.framework.assign_from_checkpoint_fn.md new file mode 100644 index 0000000000000000000000000000000000000000..e4d183b990ba487f0b33b9c8906763b4708d846b --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.framework.assign_from_checkpoint_fn.md @@ -0,0 +1,29 @@ +### `tf.contrib.framework.assign_from_checkpoint_fn(model_path, var_list, ignore_missing_vars=False, reshape_variables=False)` {#assign_from_checkpoint_fn} + +Returns a function that assigns specific variables from a checkpoint. + +##### Args: + + +* `model_path`: The full path to the model checkpoint. To get latest checkpoint + use `model_path = tf.train.latest_checkpoint(checkpoint_dir)` +* `var_list`: A list of `Variable` objects or a dictionary mapping names in the + checkpoint to the correspoing variables to initialize. If empty or None, + it would return no_op(), None. +* `ignore_missing_vars`: Boolean, if True it would ignore variables missing in + the checkpoint with a warning instead of failing. +* `reshape_variables`: Boolean, if True it would automatically reshape variables + which are of different shape then the ones stored in the checkpoint but + which have the same number of elements. + +##### Returns: + + A function that takes a single argument, a `tf.Session`, that applies the + assignment operation. + +##### Raises: + + +* `ValueError`: If the checkpoint specified at `model_path` is missing one of + the variables in `var_list`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.DNNRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.DNNRegressor.md index 88d52160d6a569ec8d2cda55f3dd1891fcbb3f67..fd7551e09a1f4f5519ec6d62321a53b6c6f2f83f 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.DNNRegressor.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.DNNRegressor.md @@ -100,6 +100,13 @@ Initializes a `DNNRegressor` instance. +- - - + +#### `tf.contrib.learn.DNNRegressor.config` {#DNNRegressor.config} + + + + - - - #### `tf.contrib.learn.DNNRegressor.dnn_bias_` {#DNNRegressor.dnn_bias_} @@ -130,7 +137,7 @@ See `Evaluable`. - - - -#### `tf.contrib.learn.DNNRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#DNNRegressor.export} +#### `tf.contrib.learn.DNNRegressor.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#DNNRegressor.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowLinearRegressor.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowLinearRegressor.md deleted file mode 100644 index 4d994c7be6060d2f3286e618d7a6ed3c46331df8..0000000000000000000000000000000000000000 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowLinearRegressor.md +++ /dev/null @@ -1,240 +0,0 @@ - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.__init__(*args, **kwargs)` {#TensorFlowLinearRegressor.__init__} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.bias_` {#TensorFlowLinearRegressor.bias_} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.dnn_bias_` {#TensorFlowLinearRegressor.dnn_bias_} - -Returns bias of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.dnn_weights_` {#TensorFlowLinearRegressor.dnn_weights_} - -Returns weights of deep neural network part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowLinearRegressor.evaluate} - -See `Evaluable`. - -##### Raises: - - -* `ValueError`: If at least one of `x` or `y` is provided, and at least one of - `input_fn` or `feed_fn` is provided. - Or if `metrics` is not `None` or `dict`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowLinearRegressor.export} - -Exports inference graph into given dir. - -##### Args: - - -* `export_dir`: A string containing a directory to write the exported graph - and checkpoints. -* `signature_fn`: Function that returns a default signature and a named - signature map, given `Tensor` of `Example` strings, `dict` of `Tensor`s - for features and `Tensor` or `dict` of `Tensor`s for predictions. -* `input_fn`: Function that given `Tensor` of `Example` strings, parses it - into features that are then passed to the model. -* `default_batch_size`: Default batch size of the `Example` placeholder. -* `exports_to_keep`: Number of exports to keep. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.fit(x, y, steps=None, batch_size=None, monitors=None, logdir=None)` {#TensorFlowLinearRegressor.fit} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_params(deep=True)` {#TensorFlowLinearRegressor.get_params} - -Get parameters for this estimator. - -##### Args: - - -* `deep`: boolean, optional - - If `True`, will return the parameters for this estimator and - contained subobjects that are estimators. - -##### Returns: - - params : mapping of string to any - Parameter names mapped to their values. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_variable_names()` {#TensorFlowLinearRegressor.get_variable_names} - -Returns list of all variable names in this model. - -##### Returns: - - List of names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.get_variable_value(name)` {#TensorFlowLinearRegressor.get_variable_value} - -Returns value of the variable given by name. - -##### Args: - - -* `name`: string, name of the tensor. - -##### Returns: - - Numpy array - value of the tensor. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.linear_bias_` {#TensorFlowLinearRegressor.linear_bias_} - -Returns bias of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.linear_weights_` {#TensorFlowLinearRegressor.linear_weights_} - -Returns weights per feature of the linear part. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.model_dir` {#TensorFlowLinearRegressor.model_dir} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.partial_fit(x=None, y=None, input_fn=None, steps=1, batch_size=None, monitors=None)` {#TensorFlowLinearRegressor.partial_fit} - -Incremental fit on a batch of samples. - -This method is expected to be called several times consecutively -on different or the same chunks of the dataset. This either can -implement iterative training or out-of-core/online training. - -This is especially useful when the whole dataset is too big to -fit in memory at the same time. Or when model is taking long time -to converge, and you want to split up training into subparts. - -##### Args: - - -* `x`: Matrix of shape [n_samples, n_features...]. Can be iterator that - returns arrays of features. The training input samples for fitting the - model. If set, `input_fn` must be `None`. -* `y`: Vector or matrix [n_samples] or [n_samples, n_outputs]. Can be - iterator that returns array of targets. The training target values - (class labels in classification, real numbers in regression). If set, - `input_fn` must be `None`. -* `input_fn`: Input function. If set, `x`, `y`, and `batch_size` must be - `None`. -* `steps`: Number of steps for which to train model. If `None`, train forever. -* `batch_size`: minibatch size to use on the input, defaults to first - dimension of `x`. Must be `None` if `input_fn` is provided. -* `monitors`: List of `BaseMonitor` subclass instances. Used for callbacks - inside the training loop. - -##### Returns: - - `self`, for chaining. - -##### Raises: - - -* `ValueError`: If at least one of `x` and `y` is provided, and `input_fn` is - provided. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.predict(x=None, input_fn=None, batch_size=None, outputs=None, axis=1)` {#TensorFlowLinearRegressor.predict} - -Predict class or regression for `x`. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.predict_proba(x=None, input_fn=None, batch_size=None, outputs=None)` {#TensorFlowLinearRegressor.predict_proba} - - - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.save(path)` {#TensorFlowLinearRegressor.save} - -Saves checkpoints and graph to given path. - -##### Args: - - -* `path`: Folder to save model to. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.set_params(**params)` {#TensorFlowLinearRegressor.set_params} - -Set the parameters of this estimator. - -The method works on simple estimators as well as on nested objects -(such as pipelines). The former have parameters of the form -``__`` so that it's possible to update each -component of a nested object. - -##### Args: - - -* `**params`: Parameters. - -##### Returns: - - self - -##### Raises: - - -* `ValueError`: If params contain invalid names. - - -- - - - -#### `tf.contrib.learn.TensorFlowLinearRegressor.weights_` {#TensorFlowLinearRegressor.weights_} - - - - diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowRNNClassifier.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowRNNClassifier.md index 80803e9a7e6b372ea300415a2dfac1e8d4f05951..94b378b63a29ddd8544727ed22fee6d1091486e8 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowRNNClassifier.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.contrib.learn.TensorFlowRNNClassifier.md @@ -58,6 +58,13 @@ Initializes a TensorFlowRNNClassifier instance. Returns bias of the rnn layer. +- - - + +#### `tf.contrib.learn.TensorFlowRNNClassifier.config` {#TensorFlowRNNClassifier.config} + + + + - - - #### `tf.contrib.learn.TensorFlowRNNClassifier.evaluate(x=None, y=None, input_fn=None, feed_fn=None, batch_size=None, steps=None, metrics=None, name=None)` {#TensorFlowRNNClassifier.evaluate} @@ -85,7 +92,7 @@ See superclass Estimator for more details. - - - -#### `tf.contrib.learn.TensorFlowRNNClassifier.export(export_dir, signature_fn=None, input_fn=default_input_fn, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNClassifier.export} +#### `tf.contrib.learn.TensorFlowRNNClassifier.export(export_dir, signature_fn=None, input_fn=None, default_batch_size=1, exports_to_keep=None)` {#TensorFlowRNNClassifier.export} Exports inference graph into given dir. diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.meshgrid.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.meshgrid.md index cb859eebbb8a62616a0961327c18bf0ae36c87eb..673a5c07178f79ca1ed5f6120b8d61a385d7347e 100644 --- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.meshgrid.md +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.meshgrid.md @@ -14,11 +14,14 @@ instructions for the first two dimensions are swapped. Examples: Calling `X, Y = meshgrid(x, y)` with the tensors + ```prettyprint x = [1, 2, 3] y = [4, 5, 6] ``` + results in + ```prettyprint X = [[1, 1, 1], [2, 2, 2], diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.crelu.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.crelu.md new file mode 100644 index 0000000000000000000000000000000000000000..8f6d282c1071e02d387e74130b03d58e0cdfd1b2 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.crelu.md @@ -0,0 +1,20 @@ +### `tf.nn.crelu(features, name=None)` {#crelu} + +Computes Concatenated ReLU. + +Concatenates a ReLU which selects only the positive part of the activation +with a ReLU which selects only the *negative* part of the activation. +Note that as a result this non-linearity doubles the depth of the activations. +Source: https://arxiv.org/abs/1603.05201 + +##### Args: + + +* `features`: A `Tensor` with type `float`, `double`, `int32`, `int64`, `uint8`, + `int16`, or `int8`. +* `name`: A name for the operation (optional). + +##### Returns: + + A `Tensor` with the same type as `features`. + diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.raw_rnn.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.raw_rnn.md new file mode 100644 index 0000000000000000000000000000000000000000..d0055a8a43803d22e488b22c62de0d3bfe7b0735 --- /dev/null +++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard9/tf.nn.raw_rnn.md @@ -0,0 +1,150 @@ +### `tf.nn.raw_rnn(cell, loop_fn, initial_state, parallel_iterations=None, swap_memory=False, scope=None)` {#raw_rnn} + +Creates an `RNN` specified by RNNCell `cell` and loop function `loop_fn`. + +**NOTE: This method is still in testing, and the API may change.** + +This function is a more primitive version of `dynamic_rnn` that provides +more direct access to the inputs each iteration. It also provides more +control over when to start and finish reading the sequence, and +what to emit for the output. + +For example, it can be used to implement the dynamic decoder of a seq2seq +model. + +Instead of working with `Tensor` objects, most operations work with +`TensorArray` objects directly. + +The operation of `raw_rnn`, in pseudo-code, is basically the following: +``` +emit_ta = TensorArray(dynamic_size=True, dtype=initial_state.dtype) +time = tf.constant(0, dtype=tf.int32) +(finished, next_input, _, loop_state) = loop_fn( + time=time, cell_output=None, loop_state=None) +state = initial_state +while not all(finished): + (output, next_state) = cell(next_input, state) + (next_finished, next_input, emit, loop_state) = loop_fn( + time=time + 1, cell_output=output, loop_state=loop_state) + # Emit zeros and copy forward state for minibatch entries that are finished. + state = tf.select(finished, state, next_state) + emit = tf.select(finished, tf.zeros_like(emit), emit) + emit_ta = emit_ta.write(time, emit) + # If any new minibatch entries are marked as finished, mark these + finished = tf.logical_or(finished, next_finished) + time += 1 +return (emit_ta, state, loop_state) +``` + +with the additional properties that output and state may be (possibly nested) +tuples, as determined by `cell.output_size` and `cell.state_size`, and +as a result the final `state` and `emit_ta` may themselves be tuples. + +A simple implementation of `dynamic_rnn` via `raw_rnn` looks like this: + +```python +inputs = tf.placeholder(shape=(max_time, batch_size, input_depth), + dtype=tf.float32) +sequence_length = tf.placeholder(shape=(batch_size,), dtype=tf.int32) +inputs_ta = tf.TensorArray(dtype=tf.float32, size=max_time) +inputs_ta = inputs_ta.unpack(inputs) + +def loop_fn(time, cell_output, loop_state): + emit_output = cell_output # == None for time == 0 + elements_finished = (time >= sequence_length) + finished = tf.reduce_all(elements_finished) + next_input = tf.cond( + finished, + lambda: tf.zeros([batch_size, input_depth], dtype=tf.float32), + lambda: inputs_ta.read(time)) + next_loop_state = None + return (elements_finished, next_input, emit_output, next_loop_state) + +cell = tf.nn.rnn_cell.LSTMCell(num_units, state_is_tuple=True) +initial_state = cell.zero_state(batch_size, tf.float32) +outputs_ta, final_state, _ = raw_rnn(cell, loop_fn, initial_state) +outputs = outputs_ta.pack() +``` + +##### Args: + + +* `cell`: An instance of RNNCell. +* `loop_fn`: A callable that takes inputs `(time, cell_output, loop_state)` and + returns the tuple `(finished, next_input, emit_output, next_loop_state)`. + Here `time` is an int32 scalar `Tensor`, `cell_output` is a + `Tensor` or (possibly nested) tuple of tensors as determined by + `cell.output_size`. In addition, `finished` is a boolean `Tensor` of + shape `[batch_size]`, `next_input` is the next input to feed to `cell`, + and `emit_output` is the output to store for this iteration. Note that + `emit_output` should be a `Tensor` or (possibly nested) tuple of tensors + with shapes and structure matching `cell.output_size` and `cell_output` + above. The parameter `loop_state` and output `next_loop_state` may be + either a single or (possibly nested) tuple of tensors. This paramter + may be ignored by `loop_fn` and the return value may be `None`. If it + is not `None`, then the `loop_state` will be propagated through the RNN + loop, for use purely by `loop_fn` to keep track of its own state. + The `next_loop_state` parameter returned may be `None`. + + The first call to `loop_fn` will be `time = 0`, `cell_output = None`, + and `loop_state = None`. Its `emit_output` value in this case may be + either `None` or a (possibly nested) tuple structure of Tensors, e.g., + `(tf.zeros(shape_0, dtype=dtype_0), tf.zeros(shape_1, dtype=dtype_1))`. + If this first `emit_output` return value is `None`, + then the `emit_ta` result of `raw_rnn` will have the same structure and + dtypes as `cell.output_size`. Otherwise `emit_ta` will have the same + structure, shapes (prepended with a `batch_size` dimension), and dtypes + as `emit_output`. The actual values returned for `emit_output` at this + initializing call are ignored. Note, this emit structure must be + consistent across all time steps. + + +* `initial_state`: An initial state for the RNN. + If `cell.state_size` is an integer, this must be + a `Tensor` of appropriate type and shape `[batch_size, cell.state_size]`. + If `cell.state_size` is a `TensorShape`, this must be a `Tensor` of + appropriate type and shape `[batch_size] + cell.state_size`. + If `cell.state_size` is a (possibly nested) tuple of ints or + `TensorShape`, this will be a tuple having the corresponding shapes. +* `parallel_iterations`: (Default: 32). The number of iterations to run in + parallel. Those operations which do not have any temporal dependency + and can be run in parallel, will be. This parameter trades off + time for space. Values >> 1 use more memory but take less time, + while smaller values use less memory but computations take longer. +* `swap_memory`: Transparently swap the tensors produced in forward inference + but needed for back prop from GPU to CPU. This allows training RNNs + which would typically not fit on a single GPU, with very minimal (or no) + performance penalty. +* `scope`: VariableScope for the created subgraph; defaults to "RNN". + +##### Returns: + + A tuple `(emit_ta, final_state, final_loop_state)` where: + + `emit_ta`: The RNN output `TensorArray`. + If `loop_fn` returns a (possibly nested) set of Tensors for + `emit_output` during initialization, (inputs `time = 0`, + `cell_output = None`, and `loop_state = None`), then `emit_ta` will + have the same structure, dtypes, and shapes as `emit_output` instead. + If `loop_fn` returns `emit_output = None` during this call, + the structure of `cell.output_size` is used: + + If `cell.output_size` is a (possibly nested) tuple of integers + or `TensorShape` objects, then `emit_ta` will be a tuple having the + same structure as `cell.output_size`, containing TensorArrays whose + elements' shapes correspond to the shape data in `cell.output_size`. + + `final_state`: The final cell state. If `cell.state_size` is an int, this + will be shaped `[batch_size, cell.state_size]`. If it is a + `TensorShape`, this will be shaped `[batch_size] + cell.state_size`. + If it is a (possibly nested) tuple of ints or `TensorShape`, this will + be a tuple having the corresponding shapes. + + `final_loop_state`: The final loop state as returned by `loop_fn`. + +##### Raises: + + +* `TypeError`: If `cell` is not an instance of RNNCell, or `loop_fn` is not + a `callable`. + diff --git a/tensorflow/g3doc/api_docs/python/index.md b/tensorflow/g3doc/api_docs/python/index.md index 9562ade43faaf478988e8336544ecdcdaebcccfe..1b176934a5440cb41975b896dc1127a26998bb5d 100644 --- a/tensorflow/g3doc/api_docs/python/index.md +++ b/tensorflow/g3doc/api_docs/python/index.md @@ -79,6 +79,7 @@ * [`count_up_to`](../../api_docs/python/state_ops.md#count_up_to) * [`device`](../../api_docs/python/state_ops.md#device) * [`export_meta_graph`](../../api_docs/python/state_ops.md#export_meta_graph) + * [`fixed_size_partitioner`](../../api_docs/python/state_ops.md#fixed_size_partitioner) * [`get_checkpoint_state`](../../api_docs/python/state_ops.md#get_checkpoint_state) * [`get_variable`](../../api_docs/python/state_ops.md#get_variable) * [`get_variable_scope`](../../api_docs/python/state_ops.md#get_variable_scope) @@ -188,6 +189,7 @@ * [`batch_self_adjoint_eig`](../../api_docs/python/math_ops.md#batch_self_adjoint_eig) * [`batch_self_adjoint_eigvals`](../../api_docs/python/math_ops.md#batch_self_adjoint_eigvals) * [`batch_svd`](../../api_docs/python/math_ops.md#batch_svd) + * [`betainc`](../../api_docs/python/math_ops.md#betainc) * [`ceil`](../../api_docs/python/math_ops.md#ceil) * [`cholesky`](../../api_docs/python/math_ops.md#cholesky) * [`cholesky_solve`](../../api_docs/python/math_ops.md#cholesky_solve) @@ -239,6 +241,7 @@ * [`real`](../../api_docs/python/math_ops.md#real) * [`reduce_all`](../../api_docs/python/math_ops.md#reduce_all) * [`reduce_any`](../../api_docs/python/math_ops.md#reduce_any) + * [`reduce_logsumexp`](../../api_docs/python/math_ops.md#reduce_logsumexp) * [`reduce_max`](../../api_docs/python/math_ops.md#reduce_max) * [`reduce_mean`](../../api_docs/python/math_ops.md#reduce_mean) * [`reduce_min`](../../api_docs/python/math_ops.md#reduce_min) @@ -445,12 +448,14 @@ * [`avg_pool3d`](../../api_docs/python/nn.md#avg_pool3d) * [`batch_normalization`](../../api_docs/python/nn.md#batch_normalization) * [`bias_add`](../../api_docs/python/nn.md#bias_add) + * [`bidirectional_dynamic_rnn`](../../api_docs/python/nn.md#bidirectional_dynamic_rnn) * [`bidirectional_rnn`](../../api_docs/python/nn.md#bidirectional_rnn) * [`compute_accidental_hits`](../../api_docs/python/nn.md#compute_accidental_hits) * [`conv1d`](../../api_docs/python/nn.md#conv1d) * [`conv2d`](../../api_docs/python/nn.md#conv2d) * [`conv2d_transpose`](../../api_docs/python/nn.md#conv2d_transpose) * [`conv3d`](../../api_docs/python/nn.md#conv3d) + * [`crelu`](../../api_docs/python/nn.md#crelu) * [`ctc_beam_search_decoder`](../../api_docs/python/nn.md#ctc_beam_search_decoder) * [`ctc_greedy_decoder`](../../api_docs/python/nn.md#ctc_greedy_decoder) * [`ctc_loss`](../../api_docs/python/nn.md#ctc_loss) @@ -478,6 +483,7 @@ * [`moments`](../../api_docs/python/nn.md#moments) * [`nce_loss`](../../api_docs/python/nn.md#nce_loss) * [`normalize_moments`](../../api_docs/python/nn.md#normalize_moments) + * [`raw_rnn`](../../api_docs/python/nn.md#raw_rnn) * [`relu`](../../api_docs/python/nn.md#relu) * [`relu6`](../../api_docs/python/nn.md#relu6) * [`rnn`](../../api_docs/python/nn.md#rnn) @@ -580,6 +586,7 @@ * [`py_func`](../../api_docs/python/script_ops.md#py_func) * **[Summary Operations](../../api_docs/python/summary.md)**: + * [`scalar`](../../api_docs/python/summary.md#scalar) * [`tensor_summary`](../../api_docs/python/summary.md#tensor_summary) * **[Testing](../../api_docs/python/test.md)**: @@ -590,6 +597,17 @@ * [`is_built_with_cuda`](../../api_docs/python/test.md#is_built_with_cuda) * [`main`](../../api_docs/python/test.md#main) +* **[BayesFlow Entropy (contrib)](../../api_docs/python/contrib.bayesflow.entropy.md)**: + * [`elbo_ratio`](../../api_docs/python/contrib.bayesflow.entropy.md#elbo_ratio) + * [`entropy_shannon`](../../api_docs/python/contrib.bayesflow.entropy.md#entropy_shannon) + * [`renyi_alpha`](../../api_docs/python/contrib.bayesflow.entropy.md#renyi_alpha) + * [`renyi_ratio`](../../api_docs/python/contrib.bayesflow.entropy.md#renyi_ratio) + +* **[BayesFlow Monte Carlo (contrib)](../../api_docs/python/contrib.bayesflow.monte_carlo.md)**: + * [`expectation`](../../api_docs/python/contrib.bayesflow.monte_carlo.md#expectation) + * [`expectation_importance_sampler`](../../api_docs/python/contrib.bayesflow.monte_carlo.md#expectation_importance_sampler) + * [`expectation_importance_sampler_logspace`](../../api_docs/python/contrib.bayesflow.monte_carlo.md#expectation_importance_sampler_logspace) + * **[BayesFlow Stochastic Graph (contrib)](../../api_docs/python/contrib.bayesflow.stochastic_graph.md)**: * [`DistributionTensor`](../../api_docs/python/contrib.bayesflow.stochastic_graph.md#DistributionTensor) * [`get_current_value_type`](../../api_docs/python/contrib.bayesflow.stochastic_graph.md#get_current_value_type) @@ -652,6 +670,10 @@ * [`assert_or_get_global_step`](../../api_docs/python/contrib.framework.md#assert_or_get_global_step) * [`assert_same_float_dtype`](../../api_docs/python/contrib.framework.md#assert_same_float_dtype) * [`assert_scalar_int`](../../api_docs/python/contrib.framework.md#assert_scalar_int) + * [`assign_from_checkpoint`](../../api_docs/python/contrib.framework.md#assign_from_checkpoint) + * [`assign_from_checkpoint_fn`](../../api_docs/python/contrib.framework.md#assign_from_checkpoint_fn) + * [`assign_from_values`](../../api_docs/python/contrib.framework.md#assign_from_values) + * [`assign_from_values_fn`](../../api_docs/python/contrib.framework.md#assign_from_values_fn) * [`convert_to_tensor_or_sparse_tensor`](../../api_docs/python/contrib.framework.md#convert_to_tensor_or_sparse_tensor) * [`create_global_step`](../../api_docs/python/contrib.framework.md#create_global_step) * [`deprecated`](../../api_docs/python/contrib.framework.md#deprecated) @@ -690,6 +712,7 @@ * [`ControlOutputs`](../../api_docs/python/contrib.graph_editor.md#ControlOutputs) * [`copy`](../../api_docs/python/contrib.graph_editor.md#copy) * [`copy_op_handler`](../../api_docs/python/contrib.graph_editor.md#copy_op_handler) + * [`copy_with_input_replacements`](../../api_docs/python/contrib.graph_editor.md#copy_with_input_replacements) * [`detach`](../../api_docs/python/contrib.graph_editor.md#detach) * [`detach_control_inputs`](../../api_docs/python/contrib.graph_editor.md#detach_control_inputs) * [`detach_control_outputs`](../../api_docs/python/contrib.graph_editor.md#detach_control_outputs) @@ -709,6 +732,7 @@ * [`get_walks_intersection_ops`](../../api_docs/python/contrib.graph_editor.md#get_walks_intersection_ops) * [`get_walks_union_ops`](../../api_docs/python/contrib.graph_editor.md#get_walks_union_ops) * [`get_within_boundary_ops`](../../api_docs/python/contrib.graph_editor.md#get_within_boundary_ops) + * [`graph_replace`](../../api_docs/python/contrib.graph_editor.md#graph_replace) * [`keep_t_if_possible_handler`](../../api_docs/python/contrib.graph_editor.md#keep_t_if_possible_handler) * [`make_list_of_op`](../../api_docs/python/contrib.graph_editor.md#make_list_of_op) * [`make_list_of_t`](../../api_docs/python/contrib.graph_editor.md#make_list_of_t) @@ -797,13 +821,9 @@ * [`run_feeds`](../../api_docs/python/contrib.learn.md#run_feeds) * [`run_n`](../../api_docs/python/contrib.learn.md#run_n) * [`RunConfig`](../../api_docs/python/contrib.learn.md#RunConfig) - * [`TensorFlowClassifier`](../../api_docs/python/contrib.learn.md#TensorFlowClassifier) * [`TensorFlowDNNClassifier`](../../api_docs/python/contrib.learn.md#TensorFlowDNNClassifier) * [`TensorFlowDNNRegressor`](../../api_docs/python/contrib.learn.md#TensorFlowDNNRegressor) * [`TensorFlowEstimator`](../../api_docs/python/contrib.learn.md#TensorFlowEstimator) - * [`TensorFlowLinearClassifier`](../../api_docs/python/contrib.learn.md#TensorFlowLinearClassifier) - * [`TensorFlowLinearRegressor`](../../api_docs/python/contrib.learn.md#TensorFlowLinearRegressor) - * [`TensorFlowRegressor`](../../api_docs/python/contrib.learn.md#TensorFlowRegressor) * [`TensorFlowRNNClassifier`](../../api_docs/python/contrib.learn.md#TensorFlowRNNClassifier) * [`TensorFlowRNNRegressor`](../../api_docs/python/contrib.learn.md#TensorFlowRNNRegressor) * [`train`](../../api_docs/python/contrib.learn.md#train) @@ -844,6 +864,7 @@ * [`AttentionCellWrapper`](../../api_docs/python/contrib.rnn.md#AttentionCellWrapper) * [`CoupledInputForgetGateLSTMCell`](../../api_docs/python/contrib.rnn.md#CoupledInputForgetGateLSTMCell) * [`GridLSTMCell`](../../api_docs/python/contrib.rnn.md#GridLSTMCell) + * [`GRUBlockCell`](../../api_docs/python/contrib.rnn.md#GRUBlockCell) * [`LSTMBlockCell`](../../api_docs/python/contrib.rnn.md#LSTMBlockCell) * [`TimeFreqLSTMCell`](../../api_docs/python/contrib.rnn.md#TimeFreqLSTMCell) @@ -879,6 +900,8 @@ * [`batch_sequences_with_states`](../../api_docs/python/contrib.training.md#batch_sequences_with_states) * [`NextQueuedSequenceBatch`](../../api_docs/python/contrib.training.md#NextQueuedSequenceBatch) * [`SequenceQueueingStateSaver`](../../api_docs/python/contrib.training.md#SequenceQueueingStateSaver) + * [`stratified_sample`](../../api_docs/python/contrib.training.md#stratified_sample) + * [`stratified_sample_unknown_dist`](../../api_docs/python/contrib.training.md#stratified_sample_unknown_dist) * **[Utilities (contrib)](../../api_docs/python/contrib.util.md)**: * [`constant_value`](../../api_docs/python/contrib.util.md#constant_value) diff --git a/tensorflow/g3doc/api_docs/python/io_ops.md b/tensorflow/g3doc/api_docs/python/io_ops.md index 464ef6f6ae8b538ae991fb2b69c29b4be920eb38..d00ffcd51b114d14e885da5b165e2e4470518fdd 100644 --- a/tensorflow/g3doc/api_docs/python/io_ops.md +++ b/tensorflow/g3doc/api_docs/python/io_ops.md @@ -1934,6 +1934,13 @@ The list of names for each component of a queue element. The underlying queue reference. +- - - + +#### `tf.QueueBase.shapes` {#QueueBase.shapes} + +The list of shapes for each component of a queue element. + + - - - diff --git a/tensorflow/g3doc/api_docs/python/math_ops.md b/tensorflow/g3doc/api_docs/python/math_ops.md index 906e5073ca652fc2d19e6cd4eabf92cf76c04038..84a00b4e61793c24c476bd45f4305a38f5c6ad7e 100644 --- a/tensorflow/g3doc/api_docs/python/math_ops.md +++ b/tensorflow/g3doc/api_docs/python/math_ops.md @@ -896,6 +896,39 @@ where \\(\psi(x)\\) is the digamma function. A `Tensor`. Has the same type as `a`. +- - - + +### `tf.betainc(a, b, x, name=None)` {#betainc} + +Compute the regularized incomplete beta integral \\(I_x(a, b)\\). + +The regularized incomplete beta integral is defined as: + +``` +I_x(a, b) = \frac{B(x; a, b)}{B(a, b)} +``` +where + +``` +B(x; a, b) = \int_0^x t^{a-1} (1 - t)^{b-1} dt +``` + +is the incomplete beta function and \\(B(a, b)\\) is the *complete* +beta function. + +##### Args: + + +* `a`: A `Tensor`. Must be one of the following types: `float32`, `float64`. +* `b`: A `Tensor`. Must have the same type as `a`. +* `x`: A `Tensor`. Must have the same type as `a`. +* `name`: A name for the operation (optional). + +##### Returns: + + A `Tensor`. Has the same type as `a`. + + ## Matrix Math Functions @@ -2667,6 +2700,50 @@ tf.reduce_any(x, 1) ==> [True, False] The reduced tensor. +- - - + +### `tf.reduce_logsumexp(input_tensor, reduction_indices=None, keep_dims=False, name=None)` {#reduce_logsumexp} + +Computes log(sum(exp(elements across dimensions of a tensor))). + +Reduces `input_tensor` along the dimensions given in `reduction_indices`. +Unless `keep_dims` is true, the rank of the tensor is reduced by 1 for each +entry in `reduction_indices`. If `keep_dims` is true, the reduced dimensions +are retained with length 1. + +If `reduction_indices` has no entries, all dimensions are reduced, and a +tensor with a single element is returned. + +This funciton is more numerically stable than log(sum(exp(input))). It avoids +overflows caused by taking the exp of large inputs and underflows caused by +taking the log of small inputs. + +For example: + +```python +# 'x' is [[0, 0, 0]] +# [0, 0, 0]] +tf.reduce_logsumexp(x) ==> log(6) +tf.reduce_logsumexp(x, 0) ==> [log(2), log(2), log(2)] +tf.reduce_logsumexp(x, 1) ==> [log(3), log(3)] +tf.reduce_logsumexp(x, 1, keep_dims=True) ==> [[log(3)], [log(3)]] +tf.reduce_logsumexp(x, [0, 1]) ==> log(6) +``` + +##### Args: + + +* `input_tensor`: The tensor to reduce. Should have numeric type. +* `reduction_indices`: The dimensions to reduce. If `None` (the defaut), + reduces all dimensions. +* `keep_dims`: If true, retains reduced dimensions with length 1. +* `name`: A name for the operation (optional). + +##### Returns: + + The reduced tensor. + + - - - diff --git a/tensorflow/g3doc/api_docs/python/nn.md b/tensorflow/g3doc/api_docs/python/nn.md index ed25ee474e1c7ceeed944dfbb49fce11be18a4a0..85cf91a4fae4a1154ce8bbe6986dcd16c6610f49 100644 --- a/tensorflow/g3doc/api_docs/python/nn.md +++ b/tensorflow/g3doc/api_docs/python/nn.md @@ -12,7 +12,7 @@ Note: Functions taking `Tensor` arguments can also take anything accepted by The activation ops provide different types of nonlinearities for use in neural networks. These include smooth nonlinearities (`sigmoid`, `tanh`, `elu`, `softplus`, and `softsign`), continuous but not everywhere differentiable -functions (`relu`, `relu6`, and `relu_x`), and random regularization +functions (`relu`, `relu6`, `crelu` and `relu_x`), and random regularization (`dropout`). All activation ops apply componentwise, and produce a tensor of the same @@ -44,6 +44,29 @@ Computes Rectified Linear 6: `min(max(features, 0), 6)`. ##### Args: +* `features`: A `Tensor` with type `float`, `double`, `int32`, `int64`, `uint8`, + `int16`, or `int8`. +* `name`: A name for the operation (optional). + +##### Returns: + + A `Tensor` with the same type as `features`. + + +- - - + +### `tf.nn.crelu(features, name=None)` {#crelu} + +Computes Concatenated ReLU. + +Concatenates a ReLU which selects only the positive part of the activation +with a ReLU which selects only the *negative* part of the activation. +Note that as a result this non-linearity doubles the depth of the activations. +Source: https://arxiv.org/abs/1603.05201 + +##### Args: + + * `features`: A `Tensor` with type `float`, `double`, `int32`, `int64`, `uint8`, `int16`, or `int8`. * `name`: A name for the operation (optional). @@ -1766,6 +1789,95 @@ RNN that accepts a state saver for time-truncated RNN calculation. type of `state_name` does not match that of `cell.state_size`. +- - - + +### `tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, inputs, sequence_length=None, initial_state_fw=None, initial_state_bw=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None)` {#bidirectional_dynamic_rnn} + +Creates a dynamic version of bidirectional recurrent neural network. + +Similar to the unidirectional case above (rnn) but takes input and builds +independent forward and backward RNNs. The input_size of forward and +backward cell must match. The initial state for both directions is zero by +default (but can be set optionally) and no intermediate states are ever +returned -- the network is fully unrolled for the given (passed in) +length(s) of the sequence(s) or completely unrolled if length(s) is not +given. + +##### Args: + + +* `cell_fw`: An instance of RNNCell, to be used for forward direction. +* `cell_bw`: An instance of RNNCell, to be used for backward direction. +* `inputs`: The RNN inputs. + If time_major == False (default), this must be a tensor of shape: + `[batch_size, max_time, input_size]`. + If time_major == True, this must be a tensor of shape: + `[max_time, batch_size, input_size]`. + [batch_size, input_size]. +* `sequence_length`: An int32/int64 vector, size `[batch_size]`, + containing the actual lengths for each of the sequences. +* `initial_state_fw`: (optional) An initial state for the forward RNN. + This must be a tensor of appropriate type and shape + `[batch_size x cell_fw.state_size]`. + If `cell_fw.state_size` is a tuple, this should be a tuple of + tensors having shapes `[batch_size, s] for s in cell_fw.state_size`. +* `initial_state_bw`: (optional) Same as for `initial_state_fw`, but using + the corresponding properties of `cell_bw`. +* `dtype`: (optional) The data type for the initial states and expected output. + Required if initial_states are not provided or RNN states have a + heterogeneous dtype. +* `parallel_iterations`: (Default: 32). The number of iterations to run in + parallel. Those operations which do not have any temporal dependency + and can be run in parallel, will be. This parameter trades off + time for space. Values >> 1 use more memory but take less time, + while smaller values use less memory but computations take longer. +* `swap_memory`: Transparently swap the tensors produced in forward inference + but needed for back prop from GPU to CPU. This allows training RNNs + which would typically not fit on a single GPU, with very minimal (or no) + performance penalty. +* `time_major`: The shape format of the `inputs` and `outputs` Tensors. + If true, these `Tensors` must be shaped `[max_time, batch_size, depth]`. + If false, these `Tensors` must be shaped `[batch_size, max_time, depth]`. + Using `time_major = True` is a bit more efficient because it avoids + transposes at the beginning and end of the RNN calculation. However, + most TensorFlow data is batch-major, so by default this function + accepts input and emits output in batch-major form. +* `dtype`: (optional) The data type for the initial state. Required if + initial_state is not provided. +* `sequence_length`: An int32/int64 vector, size `[batch_size]`, + containing the actual lengths for each of the sequences. + either of the initial states are not provided. +* `scope`: VariableScope for the created subgraph; defaults to "BiRNN" + +##### Returns: + + A tuple (outputs, output_states) where: + +* `outputs`: A tuple (output_fw, output_bw) containing the forward and + the backward rnn output `Tensor`. + If time_major == False (default), + output_fw will be a `Tensor` shaped: + `[batch_size, max_time, cell_fw.output_size]` + and output_bw will be a `Tensor` shaped: + `[batch_size, max_time, cell_bw.output_size]`. + If time_major == True, + output_fw will be a `Tensor` shaped: + `[max_time, batch_size, cell_fw.output_size]` + and output_bw will be a `Tensor` shaped: + `[max_time, batch_size, cell_bw.output_size]`. + It returns a tuple instead of a single concatenated `Tensor`, unlike + in the `bidirectional_rnn`. If the concatenated one is preferred, + the forward and backward outputs can be concatenated as + `tf.concat(2, outputs)`. +* `output_states`: A tuple (output_state_fw, output_state_bw) containing + the forward and the backward final states of bidirectional rnn. + +##### Raises: + + +* `TypeError`: If `cell_fw` or `cell_bw` is not an instance of `RNNCell`. + + - - - ### `tf.nn.bidirectional_rnn(cell_fw, cell_bw, inputs, initial_state_fw=None, initial_state_bw=None, dtype=None, sequence_length=None, scope=None)` {#bidirectional_rnn} @@ -1816,6 +1928,159 @@ length(s) of the sequence(s) or completely unrolled if length(s) is not given. * `ValueError`: If inputs is None or an empty list. +- - - + +### `tf.nn.raw_rnn(cell, loop_fn, initial_state, parallel_iterations=None, swap_memory=False, scope=None)` {#raw_rnn} + +Creates an `RNN` specified by RNNCell `cell` and loop function `loop_fn`. + +**NOTE: This method is still in testing, and the API may change.** + +This function is a more primitive version of `dynamic_rnn` that provides +more direct access to the inputs each iteration. It also provides more +control over when to start and finish reading the sequence, and +what to emit for the output. + +For example, it can be used to implement the dynamic decoder of a seq2seq +model. + +Instead of working with `Tensor` objects, most operations work with +`TensorArray` objects directly. + +The operation of `raw_rnn`, in pseudo-code, is basically the following: +``` +emit_ta = TensorArray(dynamic_size=True, dtype=initial_state.dtype) +time = tf.constant(0, dtype=tf.int32) +(finished, next_input, _, loop_state) = loop_fn( + time=time, cell_output=None, loop_state=None) +state = initial_state +while not all(finished): + (output, next_state) = cell(next_input, state) + (next_finished, next_input, emit, loop_state) = loop_fn( + time=time + 1, cell_output=output, loop_state=loop_state) + # Emit zeros and copy forward state for minibatch entries that are finished. + state = tf.select(finished, state, next_state) + emit = tf.select(finished, tf.zeros_like(emit), emit) + emit_ta = emit_ta.write(time, emit) + # If any new minibatch entries are marked as finished, mark these + finished = tf.logical_or(finished, next_finished) + time += 1 +return (emit_ta, state, loop_state) +``` + +with the additional properties that output and state may be (possibly nested) +tuples, as determined by `cell.output_size` and `cell.state_size`, and +as a result the final `state` and `emit_ta` may themselves be tuples. + +A simple implementation of `dynamic_rnn` via `raw_rnn` looks like this: + +```python +inputs = tf.placeholder(shape=(max_time, batch_size, input_depth), + dtype=tf.float32) +sequence_length = tf.placeholder(shape=(batch_size,), dtype=tf.int32) +inputs_ta = tf.TensorArray(dtype=tf.float32, size=max_time) +inputs_ta = inputs_ta.unpack(inputs) + +def loop_fn(time, cell_output, loop_state): + emit_output = cell_output # == None for time == 0 + elements_finished = (time >= sequence_length) + finished = tf.reduce_all(elements_finished) + next_input = tf.cond( + finished, + lambda: tf.zeros([batch_size, input_depth], dtype=tf.float32), + lambda: inputs_ta.read(time)) + next_loop_state = None + return (elements_finished, next_input, emit_output, next_loop_state) + +cell = tf.nn.rnn_cell.LSTMCell(num_units, state_is_tuple=True) +initial_state = cell.zero_state(batch_size, tf.float32) +outputs_ta, final_state, _ = raw_rnn(cell, loop_fn, initial_state) +outputs = outputs_ta.pack() +``` + +##### Args: + + +* `cell`: An instance of RNNCell. +* `loop_fn`: A callable that takes inputs `(time, cell_output, loop_state)` and + returns the tuple `(finished, next_input, emit_output, next_loop_state)`. + Here `time` is an int32 scalar `Tensor`, `cell_output` is a + `Tensor` or (possibly nested) tuple of tensors as determined by + `cell.output_size`. In addition, `finished` is a boolean `Tensor` of + shape `[batch_size]`, `next_input` is the next input to feed to `cell`, + and `emit_output` is the output to store for this iteration. Note that + `emit_output` should be a `Tensor` or (possibly nested) tuple of tensors + with shapes and structure matching `cell.output_size` and `cell_output` + above. The parameter `loop_state` and output `next_loop_state` may be + either a single or (possibly nested) tuple of tensors. This paramter + may be ignored by `loop_fn` and the return value may be `None`. If it + is not `None`, then the `loop_state` will be propagated through the RNN + loop, for use purely by `loop_fn` to keep track of its own state. + The `next_loop_state` parameter returned may be `None`. + + The first call to `loop_fn` will be `time = 0`, `cell_output = None`, + and `loop_state = None`. Its `emit_output` value in this case may be + either `None` or a (possibly nested) tuple structure of Tensors, e.g., + `(tf.zeros(shape_0, dtype=dtype_0), tf.zeros(shape_1, dtype=dtype_1))`. + If this first `emit_output` return value is `None`, + then the `emit_ta` result of `raw_rnn` will have the same structure and + dtypes as `cell.output_size`. Otherwise `emit_ta` will have the same + structure, shapes (prepended with a `batch_size` dimension), and dtypes + as `emit_output`. The actual values returned for `emit_output` at this + initializing call are ignored. Note, this emit structure must be + consistent across all time steps. + + +* `initial_state`: An initial state for the RNN. + If `cell.state_size` is an integer, this must be + a `Tensor` of appropriate type and shape `[batch_size, cell.state_size]`. + If `cell.state_size` is a `TensorShape`, this must be a `Tensor` of + appropriate type and shape `[batch_size] + cell.state_size`. + If `cell.state_size` is a (possibly nested) tuple of ints or + `TensorShape`, this will be a tuple having the corresponding shapes. +* `parallel_iterations`: (Default: 32). The number of iterations to run in + parallel. Those operations which do not have any temporal dependency + and can be run in parallel, will be. This parameter trades off + time for space. Values >> 1 use more memory but take less time, + while smaller values use less memory but computations take longer. +* `swap_memory`: Transparently swap the tensors produced in forward inference + but needed for back prop from GPU to CPU. This allows training RNNs + which would typically not fit on a single GPU, with very minimal (or no) + performance penalty. +* `scope`: VariableScope for the created subgraph; defaults to "RNN". + +##### Returns: + + A tuple `(emit_ta, final_state, final_loop_state)` where: + + `emit_ta`: The RNN output `TensorArray`. + If `loop_fn` returns a (possibly nested) set of Tensors for + `emit_output` during initialization, (inputs `time = 0`, + `cell_output = None`, and `loop_state = None`), then `emit_ta` will + have the same structure, dtypes, and shapes as `emit_output` instead. + If `loop_fn` returns `emit_output = None` during this call, + the structure of `cell.output_size` is used: + + If `cell.output_size` is a (possibly nested) tuple of integers + or `TensorShape` objects, then `emit_ta` will be a tuple having the + same structure as `cell.output_size`, containing TensorArrays whose + elements' shapes correspond to the shape data in `cell.output_size`. + + `final_state`: The final cell state. If `cell.state_size` is an int, this + will be shaped `[batch_size, cell.state_size]`. If it is a + `TensorShape`, this will be shaped `[batch_size] + cell.state_size`. + If it is a (possibly nested) tuple of ints or `TensorShape`, this will + be a tuple having the corresponding shapes. + + `final_loop_state`: The final loop state as returned by `loop_fn`. + +##### Raises: + + +* `TypeError`: If `cell` is not an instance of RNNCell, or `loop_fn` is not + a `callable`. + + ## Conectionist Temporal Classification (CTC) @@ -1842,6 +2107,18 @@ max(labels.indices(labels.indices[:, 1] == b, 2)) <= sequence_length(b) for all b. ``` +Notes: + +This class performs the softmax operation for you, so inputs should +be e.g. linear projections of outputs by an LSTM. + +The `inputs` Tensor's innermost dimension size, `num_classes`, represents +`num_labels + 1` classes, where num_labels is the number of true labels, and +the largest value `(num_classes - 1)` is reserved for the blank label. + +For example, for a vocabulary containing 3 labels `[a, b, c]`, +`num_classes = 4` and the labels indexing is `{a: 0, b: 1, c: 2, blank: 3}`. + Regarding the arguments `preprocess_collapse_repeated` and `ctc_merge_repeated`: @@ -1880,10 +2157,12 @@ Here is a table of the (roughly) expected first order behavior: * `inputs`: 3-D `float` `Tensor` sized - `[max_time x batch_size x num_classes]`. The logits. + `[max_time x batch_size x num_classes]`. The logits. * `labels`: An `int32` `SparseTensor`. `labels.indices[i, :] == [b, t]` means `labels.values[i]` stores - the id for (batch b, time t). See `core/ops/ctc_ops.cc` for more details. + the id for (batch b, time t). + `labels.values[i]` must take on values in `[0, num_labels)`. + See `core/ops/ctc_ops.cc` for more details. * `sequence_length`: 1-D `int32` vector, size `[batch_size]`. The sequence lengths. * `preprocess_collapse_repeated`: Boolean. Default: False. diff --git a/tensorflow/g3doc/api_docs/python/state_ops.md b/tensorflow/g3doc/api_docs/python/state_ops.md index 95f7405391cffaad0dd239ccf855db65b4ae9c59..52735d36b0f91deea5fabef892fec99eaac4789f 100644 --- a/tensorflow/g3doc/api_docs/python/state_ops.md +++ b/tensorflow/g3doc/api_docs/python/state_ops.md @@ -624,8 +624,7 @@ variables if there are any, or an empty array if there are none. ##### Returns: A 1-D tensor containing names of the uninitialized variables, or an empty - 1-D - tensor if there are no variables or no uninitialized variables. + 1-D tensor if there are no variables or no uninitialized variables. - - - @@ -736,7 +735,7 @@ protocol buffer file in the call to `save()`. - - - -#### `tf.train.Saver.__init__(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None, defer_build=False)` {#Saver.__init__} +#### `tf.train.Saver.__init__(var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None, defer_build=False, allow_empty=False)` {#Saver.__init__} Creates a `Saver`. @@ -801,6 +800,9 @@ checkpoints per device. * `defer_build`: If `True`, defer adding the save and restore ops to the `build()` call. In that case `build()` should be called before finalizing the graph or using the saver. +* `allow_empty`: If `False` (default) raise an error if there are no + variables in the graph. Otherwise, construct the saver anyway and make + it a no-op. ##### Raises: @@ -845,6 +847,7 @@ path can be passed directly to a call to `restore()`. A string: path at which the variables were saved. If the saver is sharded, this string ends with: '-?????-of-nnnnn' where 'nnnnn' is the number of shards created. + If the saver is empty, returns None. ##### Raises: @@ -1721,7 +1724,7 @@ Returns an initializer that generates tensors with a uniform distribution. - - - -### `tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32, full_shape=None)` {#uniform_unit_scaling_initializer} +### `tf.uniform_unit_scaling_initializer(factor=1.0, seed=None, dtype=tf.float32)` {#uniform_unit_scaling_initializer} Returns an initializer that generates tensors without scaling variance. @@ -1741,12 +1744,6 @@ See [Sussillo et al., 2014](https://arxiv.org/abs/1412.6558) and the calculation of constants. In section 2.3 there, the constants were numerically computed: for a linear layer it's 1.0, relu: ~1.43, tanh: ~1.15. -If the shape tuple `full_shape` is provided, the scale will be calculated from -this predefined shape. This is useful when a `Variable` is being partitioned -across several shards, and each shard has a smaller shape than the whole. -Since the shards are usually concatenated when used, the scale should be -based on the shape of the whole. - ##### Args: @@ -1755,9 +1752,6 @@ based on the shape of the whole. [`set_random_seed`](../../api_docs/python/constant_op.md#set_random_seed) for behavior. * `dtype`: The data type. Only floating point types are supported. -* `full_shape`: Tuple or list of integers. The shape used for calculating - scale normalization (instead of the shape passed at creation time). - Useful when creating sharded variables via partitioning. ##### Returns: @@ -1771,14 +1765,14 @@ based on the shape of the whole. - - - -### `tf.zeros_initializer(shape, dtype=tf.float32)` {#zeros_initializer} +### `tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)` {#zeros_initializer} An adaptor for zeros() to match the Initializer spec. - - - -### `tf.ones_initializer(shape, dtype=tf.float32)` {#ones_initializer} +### `tf.ones_initializer(shape, dtype=tf.float32, partition_info=None)` {#ones_initializer} An adaptor for ones() to match the Initializer spec. @@ -1786,6 +1780,24 @@ An adaptor for ones() to match the Initializer spec. ## Variable Partitioners for Sharding +- - - + +### `tf.fixed_size_partitioner(num_shards, axis=0)` {#fixed_size_partitioner} + +Partitioner to specify a fixed number of shards along given axis. + +##### Args: + + +* `num_shards`: `int`, number of shards to partition variable. +* `axis`: `int`, axis to partition on. + +##### Returns: + + A partition function usable as the `partitioner` argument to + `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + + - - - ### `tf.variable_axis_size_partitioner(max_shard_bytes, axis=0, bytes_per_string_element=16, max_shards=None)` {#variable_axis_size_partitioner} diff --git a/tensorflow/g3doc/api_docs/python/summary.md b/tensorflow/g3doc/api_docs/python/summary.md index 8f19460e2195893b74eda7c42a4cff7904c5713e..14dac8117fe2fa5978c8e2dfc1ab009c530ea55a 100644 --- a/tensorflow/g3doc/api_docs/python/summary.md +++ b/tensorflow/g3doc/api_docs/python/summary.md @@ -14,7 +14,7 @@ Outputs a `Summary` protocol buffer with a serialized tensor.proto. The generated [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) -has one summary value containing input_tensor. +has one summary value containing the input tensor. ##### Args: @@ -31,7 +31,7 @@ has one summary value containing input_tensor. other tensors that are all in a group. (e.g. bounding boxes and images) * `collections`: Optional list of graph collections keys. The new summary op is added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. -* `name`: A name for the operation (optional). +* `name`: An optional name for the generated node (optional). ##### Returns: @@ -39,3 +39,33 @@ has one summary value containing input_tensor. buffer. +- - - + +### `tf.summary.scalar(display_name, tensor, description='', labels=None, collections=None, name=None)` {#scalar} + +Outputs a `Summary` protocol buffer containing a single scalar value. + +The generated Summary has a Tensor.proto containing the input Tensor. + +##### Args: + + +* `display_name`: A name to associate with the data series. Will be used to + organize output data and as a name in visualizers. +* `tensor`: A tensor containing a single floating point or integer value. +* `description`: An optional long description of the data being output. +* `labels`: a list of strings used to attach metadata. +* `collections`: Optional list of graph collections keys. The new summary op is + added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. +* `name`: An optional name for the generated node (optional). + +##### Returns: + + A scalar `Tensor` of type `string`. Which contains a `Summary` protobuf. + +##### Raises: + + +* `ValueError`: If tensor has the wrong shape or type. + + diff --git a/tensorflow/g3doc/api_docs/python/train.md b/tensorflow/g3doc/api_docs/python/train.md index f821644850cc1bc2faa8bf8d69eab07913b9620c..d408a404890ddc3ea9a1311e8140883a556d86d8 100644 --- a/tensorflow/g3doc/api_docs/python/train.md +++ b/tensorflow/g3doc/api_docs/python/train.md @@ -311,7 +311,7 @@ Construct a new gradient descent optimizer. ### `class tf.train.AdadeltaOptimizer` {#AdadeltaOptimizer} -Optimizer that implements the Adadelta algorithm. +Optimizer that implements the Adadelta algorithm. See [M. D. Zeiler](http://arxiv.org/abs/1212.5701) ([pdf](http://arxiv.org/pdf/1212.5701v1.pdf)) @@ -3771,5 +3771,3 @@ Generates a checkpoint state proto. CheckpointState proto with model_checkpoint_path and all_model_checkpoint_paths updated to either absolute paths or relative paths to the current save_dir. - - diff --git a/tensorflow/g3doc/get_started/os_setup.md b/tensorflow/g3doc/get_started/os_setup.md index 30565a901d40cc478792a01f3e238cd451221d36..fe8e013767675f7c0e09e2c4098a24f304180764 100644 --- a/tensorflow/g3doc/get_started/os_setup.md +++ b/tensorflow/g3doc/get_started/os_setup.md @@ -240,7 +240,7 @@ packages needed by TensorFlow. * Activate the conda environment and install TensorFlow in it. * After the install you will activate the conda environment each time you want to use TensorFlow. -* Optionally install ipython and other packages into the conda environment +* Optionally install ipython and other packages into the conda environment Install Anaconda: @@ -358,7 +358,7 @@ $ source activate tensorflow ### Install IPython -To use tensorflow with IPython it may be necessary to install IPython into the tensorflow environment: +To use tensorflow with IPython it may be necessary to install IPython into the tensorflow environment: ```bash $ source activate tensorflow @@ -366,7 +366,7 @@ $ source activate tensorflow ``` Similarly, other Python packages like pandas may need to get installed into the tensorflow environment -before they can be used together with tensorflow. +before they can be used together with tensorflow. ## Docker installation diff --git a/tensorflow/g3doc/how_tos/summaries_and_tensorboard/index.md b/tensorflow/g3doc/how_tos/summaries_and_tensorboard/index.md index 8183cdf02477ab9af3337350c318dfe0e01dda11..ec617ca7be00690af71d3207bdf34c82dadf7ae2 100644 --- a/tensorflow/g3doc/how_tos/summaries_and_tensorboard/index.md +++ b/tensorflow/g3doc/how_tos/summaries_and_tensorboard/index.md @@ -86,7 +86,7 @@ def variable_summaries(var, name): mean = tf.reduce_mean(var) tf.scalar_summary('mean/' + name, mean) with tf.name_scope('stddev'): - stddev = tf.sqrt(tf.reduce_sum(tf.square(var - mean))) + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) tf.scalar_summary('sttdev/' + name, stddev) tf.scalar_summary('max/' + name, tf.reduce_max(var)) tf.scalar_summary('min/' + name, tf.reduce_min(var)) @@ -182,7 +182,8 @@ You're now all set to visualize this data using TensorBoard. ## Launching TensorBoard -To run TensorBoard, use the command +To run TensorBoard, use the following command (alternatively `python -m +tensorflow.tensorboard`) ```bash tensorboard --logdir=path/to/log-directory diff --git a/tensorflow/g3doc/how_tos/tool_developers/index.md b/tensorflow/g3doc/how_tos/tool_developers/index.md index 71f81de82afd0d036002b9f015abf5171a6b6a31..94eb182a521a1309dfa70449ffca3634db2a4c2f 100644 --- a/tensorflow/g3doc/how_tos/tool_developers/index.md +++ b/tensorflow/g3doc/how_tos/tool_developers/index.md @@ -90,9 +90,10 @@ of nodes stored in the node member. Here's the code that loops through those: for node in graph_def.node ``` -Each node is a `NodeDef` object, also defined in graph.proto. These are the -fundamental building blocks of TensorFlow graphs, with each one defining a -single operation along with its input connections. Here are the members of a +Each node is a `NodeDef` object, defined in +[tensorflow/core/framework/node_def.proto](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/node_def.proto). These +are the fundamental building blocks of TensorFlow graphs, with each one defining +a single operation along with its input connections. Here are the members of a `NodeDef`, and what they mean. ### `name` diff --git a/tensorflow/go/BUILD b/tensorflow/go/BUILD new file mode 100644 index 0000000000000000000000000000000000000000..d69233f4fe1cc12b596bb03e22df5b1900caf585 --- /dev/null +++ b/tensorflow/go/BUILD @@ -0,0 +1,22 @@ +# Description: +# Go API for TensorFlow. + +package( + default_visibility = ["//visibility:private"], +) + +licenses(["notice"]) # Apache 2.0 + +exports_files(["LICENSE"]) + +filegroup( + name = "all_files", + srcs = glob( + ["**/*"], + exclude = [ + "**/METADATA", + "**/OWNERS", + ], + ), + visibility = ["//tensorflow:__subpackages__"], +) diff --git a/tensorflow/go/doc.go b/tensorflow/go/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..4494d49556ca6b70005971a952691622f9a0fa74 --- /dev/null +++ b/tensorflow/go/doc.go @@ -0,0 +1,18 @@ +// 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. + +// Package tensorflow is a Go binding to TensorFlow. +// +// The API is subject to change and may break at any time. +package tensorflow diff --git a/tensorflow/go/graph.go b/tensorflow/go/graph.go new file mode 100644 index 0000000000000000000000000000000000000000..3e43a39817783c291709c288af33f21b2de6c0ba --- /dev/null +++ b/tensorflow/go/graph.go @@ -0,0 +1,38 @@ +// 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. + +package tensorflow + +// #include "tensorflow/c/c_api.h" +import "C" + +import ( + "runtime" +) + +// Graph represents a computation graph. Graphs may be shared between sessions. +type Graph struct { + c *C.TF_Graph +} + +// NewGraph returns a new Graph. +func NewGraph() *Graph { + g := &Graph{C.TF_NewGraph()} + runtime.SetFinalizer(g, (*Graph).finalizer) + return g +} + +func (g *Graph) finalizer() { + C.TF_DeleteGraph(g.c) +} diff --git a/tensorflow/go/lib.go b/tensorflow/go/lib.go new file mode 100644 index 0000000000000000000000000000000000000000..dcab7a90f85d7c1ef09f5d4d32d68073a2b42588 --- /dev/null +++ b/tensorflow/go/lib.go @@ -0,0 +1,19 @@ +// 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. + +package tensorflow + +// #cgo LDFLAGS: -ltensorflow +// #cgo CFLAGS: -I${SRCDIR}/../../ +import "C" diff --git a/tensorflow/go/operation.go b/tensorflow/go/operation.go new file mode 100644 index 0000000000000000000000000000000000000000..7d9a9655dc853709119a2250d4c3c519ff12aeef --- /dev/null +++ b/tensorflow/go/operation.go @@ -0,0 +1,84 @@ +// 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. + +package tensorflow + +// #include +// #include "tensorflow/c/c_api.h" +import "C" +import "unsafe" + +// Operation that has been added to the graph. +type Operation struct { + c *C.TF_Operation +} + +// Output represents one of the outputs of an operation in the graph. Has a +// DataType (and eventually a Shape). May be passed as an input argument to a +// function for adding operations to a graph, or to a Session's Run() method to +// fetch that output as a tensor. +type Output struct { + // Op is the Operation that produces this Output. + Op *Operation + + // Index specifies the index of the output within the Operation. + Index int +} + +func (p *Output) c() C.TF_Port { + return C.TF_Port{oper: p.Op.c, index: C.int(p.Index)} +} + +// opBuilder is for use by the generated op code to create new Operations. +// Build() must be called for any in-progress Operation, or else we leak. +type opBuilder struct { + c *C.TF_OperationDescription +} + +func newOpBuilder(g *Graph, typ string, name string) *opBuilder { + opType := C.CString(typ) + opName := C.CString(name) + b := &opBuilder{c: C.TF_NewOperation(g.c, opType, opName)} + C.free(unsafe.Pointer(opType)) + C.free(unsafe.Pointer(opName)) + return b +} + +func (b *opBuilder) SetAttrTensor(name string, t *Tensor) error { + status := newStatus() + attrName := C.CString(name) + C.TF_SetAttrTensor(b.c, attrName, t.c(), status.c) + C.free(unsafe.Pointer(attrName)) + return status.Err() +} + +func (b *opBuilder) SetAttrType(name string, typ DataType) { + attrName := C.CString(name) + C.TF_SetAttrType(b.c, attrName, C.TF_DataType(typ)) + C.free(unsafe.Pointer(attrName)) +} + +func (b *opBuilder) AddInput(port Output) { + C.TF_AddInput(b.c, port.c()) +} + +func (b *opBuilder) Build() (*Operation, error) { + status := newStatus() + op := &Operation{c: C.TF_FinishOperation(b.c, status.c)} + if err := status.Err(); err != nil { + return nil, err + } + b.c = nil + return op, nil +} diff --git a/tensorflow/go/session.go b/tensorflow/go/session.go new file mode 100644 index 0000000000000000000000000000000000000000..41b6ad46833b3ac17b1e988308def351a7228823 --- /dev/null +++ b/tensorflow/go/session.go @@ -0,0 +1,187 @@ +// 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. + +package tensorflow + +// #include +// #include "tensorflow/c/c_api.h" +import "C" + +import ( + "errors" + "runtime" + "sync" + "unsafe" +) + +// Session drives a TensorFlow graph computation. +// +// When a Session is created with a given target, a new Session object is bound +// to the universe of resources specified by that target. Those resources are +// available to this session to perform computation described in the GraphDef. +// After creating the session with a graph, the caller uses the Run() API to +// perform the computation and potentially fetch outputs as Tensors. +// A Session allows concurrent calls to Run(). +type Session struct { + c *C.TF_SessionWithGraph + + // For ensuring that: + // - Close() blocks on all Run() calls to complete. + // - Close() can be called multiple times. + wg sync.WaitGroup + mu sync.Mutex +} + +// NewSession creates a new execution session with the associated graph. +// options may be nil to use the default options. +func NewSession(graph *Graph, options *SessionOptions) (*Session, error) { + status := newStatus() + cOpt := options.c() + cSess := C.TF_NewSessionWithGraph(graph.c, cOpt, status.c) + C.TF_DeleteSessionOptions(cOpt) + if err := status.Err(); err != nil { + return nil, err + } + + s := &Session{c: cSess} + runtime.SetFinalizer(s, func(s *Session) { s.Close() }) + return s, nil +} + +// Run the graph with the associated session starting with the supplied inputs. +// inputs and outputs may be set to nil. Runs, but does not return Tensors +// for operations specified in targets. +// +// On success, returns the Tensor outputs in the same order as supplied in +// the outputs argument. If outputs is set to nil, the returned Tensor outputs +// is empty. +func (s *Session) Run(inputs map[Output]*Tensor, outputs []Output, targets []*Operation) ([]*Tensor, error) { + s.mu.Lock() + if s.c == nil { + s.mu.Unlock() + return nil, errors.New("session is closed") + } + s.wg.Add(1) + s.mu.Unlock() + defer s.wg.Done() + + var inputPorts []C.TF_Port + var inputValues []*C.TF_Tensor + if inputs != nil { + for port, tensor := range inputs { + inputPorts = append(inputPorts, port.c()) + inputValues = append(inputValues, tensor.c()) + } + } + + var outputPorts []C.TF_Port + for _, port := range outputs { + outputPorts = append(outputPorts, port.c()) + } + outputValues := make([]*C.TF_Tensor, len(outputs)) + var cTargets []*C.TF_Operation + for _, target := range targets { + cTargets = append(cTargets, target.c) + } + + status := newStatus() + var inputPortsPtr *C.TF_Port + var inputValuesPtr **C.TF_Tensor + if len(inputPorts) > 0 { + inputPortsPtr = &inputPorts[0] + inputValuesPtr = &inputValues[0] + } + + var outputPortsPtr *C.TF_Port + var outputValuesPtr **C.TF_Tensor + if len(outputPorts) > 0 { + outputPortsPtr = &outputPorts[0] + outputValuesPtr = &outputValues[0] + } + + var cTargetsPtr **C.TF_Operation + if len(cTargets) > 0 { + cTargetsPtr = &cTargets[0] + } + + C.TF_SessionRun(s.c, nil, inputPortsPtr, inputValuesPtr, C.int(len(inputPorts)), outputPortsPtr, outputValuesPtr, C.int(len(outputPorts)), cTargetsPtr, C.int(len(cTargets)), nil, status.c) + if err := status.Err(); err != nil { + return nil, err + } + + var tensors []*Tensor + for _, val := range outputValues { + tensors = append(tensors, newTensorFromC(val)) + C.TF_DeleteTensor(val) + } + + return tensors, nil +} + +// Close a session. This contacts any other processes associated with this +// session, if applicable. Blocks until all previous calls to Run have returned. +func (s *Session) Close() error { + s.mu.Lock() + defer s.mu.Unlock() + s.wg.Wait() + if s.c == nil { + return nil + } + status := newStatus() + C.TF_CloseSessionWithGraph(s.c, status.c) + if err := status.Err(); err != nil { + return err + } + C.TF_DeleteSessionWithGraph(s.c, status.c) + s.c = nil + return status.Err() +} + +// SessionOptions contains configuration information for a session. +type SessionOptions struct { + // Target indicates the TensorFlow runtime to connect to. + // + // If 'target' is empty or unspecified, the local TensorFlow runtime + // implementation will be used. Otherwise, the TensorFlow engine + // defined by 'target' will be used to perform all computations. + // + // "target" can be either a single entry or a comma separated list + // of entries. Each entry is a resolvable address of one of the + // following formats: + // local + // ip:port + // host:port + // ... other system-specific formats to identify tasks and jobs ... + // + // NOTE: at the moment 'local' maps to an in-process service-based + // runtime. + // + // Upon creation, a single session affines itself to one of the + // remote processes, with possible load balancing choices when the + // "target" resolves to a list of possible processes. + // + // If the session disconnects from the remote process during its + // lifetime, session calls may fail immediately. + Target string +} + +// c converts the SessionOptions to the C API's TF_SessionOptions. Callers must +// deallocate by calling C.TF_DeleteSessionOptions(). +func (o *SessionOptions) c() *C.TF_SessionOptions { + opt := C.TF_NewSessionOptions() + t := C.CString(o.Target) + C.TF_SetTarget(opt, t) + C.free(unsafe.Pointer(t)) + return opt +} diff --git a/tensorflow/go/session_test.go b/tensorflow/go/session_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bebe2ac4de745686901cee72d993c7d7edaa45af --- /dev/null +++ b/tensorflow/go/session_test.go @@ -0,0 +1,114 @@ +// 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. + +package tensorflow + +import ( + "reflect" + "testing" +) + +func Placeholder(g *Graph, name string, dt DataType) (Output, error) { + b := newOpBuilder(g, "Placeholder", name) + b.SetAttrType("dtype", dt) + op, err := b.Build() + if err != nil { + return Output{}, err + } + return Output{op, 0}, nil +} + +func Neg(g *Graph, name string, port Output) (Output, error) { + b := newOpBuilder(g, "Neg", name) + b.AddInput(port) + op, err := b.Build() + if err != nil { + return Output{}, err + } + return Output{op, 0}, nil +} + +func createTestGraph(t *testing.T, dt DataType) (*Graph, Output, Output) { + g := NewGraph() + inp, err := Placeholder(g, "p1", dt) + if err != nil { + t.Fatalf("Placeholder() for %v: %v", dt, err) + } + out, err := Neg(g, "neg1", inp) + if err != nil { + t.Fatalf("Neg() for %v: %v", dt, err) + } + return g, inp, out +} + +func TestSessionRunNeg(t *testing.T) { + var tests = []struct { + input interface{} + expected interface{} + }{ + {int64(1), int64(-1)}, + {[]float64{-1, -2, 3}, []float64{1, 2, -3}}, + {[][]float32{{1, -2}, {-3, 4}}, [][]float32{{-1, 2}, {3, -4}}}, + } + + for _, test := range tests { + t1, err := NewTensor(test.input) + if err != nil { + t.Fatalf("NewTensor(%v): %v", test.input, err) + } + graph, inp, out := createTestGraph(t, t1.DataType()) + s, err := NewSession(graph, &SessionOptions{}) + if err != nil { + t.Fatalf("NewSession() for %v: %v", test.input, err) + } + output, err := s.Run(map[Output]*Tensor{inp: t1}, []Output{out}, []*Operation{out.Op}) + if err != nil { + t.Fatalf("Run() for %v: %v", test.input, err) + } + if len(output) != 1 { + t.Errorf("%v: got %d outputs, want 1", test.input, len(output)) + continue + } + val := output[0].Value() + if !reflect.DeepEqual(test.expected, val) { + t.Errorf("got %v, want %v", val, test.expected) + } + if err := s.Close(); err != nil { + t.Errorf("Close(): %v", err) + } + } +} + +func TestConcurrency(t *testing.T) { + tensor, err := NewTensor(int64(1)) + if err != nil { + t.Fatalf("NewTensor(): %v", err) + } + + graph, inp, out := createTestGraph(t, tensor.DataType()) + s, err := NewSession(graph, &SessionOptions{}) + if err != nil { + t.Fatalf("NewSession(): %v", err) + } + for i := 0; i < 100; i++ { + // Session may close before Run() starts, so we don't check the error. + go s.Run(map[Output]*Tensor{inp: tensor}, []Output{out}, []*Operation{out.Op}) + } + if err = s.Close(); err != nil { + t.Errorf("Close() 1: %v", err) + } + if err = s.Close(); err != nil { + t.Errorf("Close() 2: %v", err) + } +} diff --git a/tensorflow/go/status.go b/tensorflow/go/status.go new file mode 100644 index 0000000000000000000000000000000000000000..a1f7ed54810301df0c5edf9f5ee1544e21a5cef9 --- /dev/null +++ b/tensorflow/go/status.go @@ -0,0 +1,65 @@ +// 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. + +package tensorflow + +// #include "tensorflow/c/c_api.h" +import "C" + +import "runtime" + +type code C.TF_Code + +// status holds error information returned by TensorFlow. We convert all +// TF statuses to Go errors. +type status struct { + c *C.TF_Status +} + +func newStatus() *status { + s := &status{C.TF_NewStatus()} + runtime.SetFinalizer(s, (*status).finalizer) + return s +} + +func (s *status) finalizer() { + C.TF_DeleteStatus(s.c) +} + +func (s *status) Code() code { + return code(C.TF_GetCode(s.c)) +} + +func (s *status) String() string { + return C.GoString(C.TF_Message(s.c)) +} + +// Err converts the status to a Go error and returns nil if the status is OK. +func (s *status) Err() error { + if s == nil || s.Code() == C.TF_OK { + return nil + } + return (*statusError)(s) +} + +// statusError is distinct from status because it fulfills the error interface. +// status itself may have a TF_OK code and is not always considered an error. +// +// TODO(jhseu): Make public, rename to Error, and provide a way for users to +// check status codes. +type statusError status + +func (s *statusError) Error() string { + return (*status)(s).String() +} diff --git a/tensorflow/go/tensor.go b/tensorflow/go/tensor.go new file mode 100644 index 0000000000000000000000000000000000000000..76a4615a7bf3e32bb6946ed1fa6114fd1a1c4526 --- /dev/null +++ b/tensorflow/go/tensor.go @@ -0,0 +1,259 @@ +// 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. + +package tensorflow + +// #include +// #include "tensorflow/c/c_api.h" +import "C" + +import ( + "bytes" + "encoding/binary" + "fmt" + "reflect" + "unsafe" +) + +// DataType holds the type for a scalar value. E.g., one slot in a tensor. +// The values here are identical to corresponding values in types.proto. +type DataType C.TF_DataType + +// Tensor holds a multi-dimensional array of elements of a single data type. +type Tensor struct { + // We create TF_Tensor on demand rather than keep a handle to C.TF_Tensor + // because many functions, such as Session.Run() and Operations take + // ownership of the C.TF_Tensor. Translating on-demand provides for a safe + // API. + // + // A memcpy is required because cgo rules prohibit us from maintaining + // a pointer to Go memory. + // call: https://golang.org/cmd/cgo/ + buf *bytes.Buffer + dt DataType + shape []int64 +} + +// NewTensor converts from a Go value to a Tensor. Valid values are scalars, +// slices, and arrays. Every element of a slice must have the same length so +// that the resulting Tensor has a valid shape. +func NewTensor(value interface{}) (*Tensor, error) { + val := reflect.ValueOf(value) + dims, dataType, err := dimsAndDataTypeOf(val.Type()) + if err != nil { + return nil, err + } + t := &Tensor{buf: bytes.NewBuffer(nil), dt: dataType, shape: make([]int64, dims)} + if err = encodeTensor(t.buf, t.shape, val); err != nil { + return nil, err + } + return t, nil +} + +// newTensorFromC converts from a C.TF_Tensor to a Tensor. +func newTensorFromC(ct *C.TF_Tensor) *Tensor { + t := &Tensor{dt: DataType(C.TF_TensorType(ct))} + numDims := int(C.TF_NumDims(ct)) + for i := 0; i < numDims; i++ { + t.shape = append(t.shape, int64(C.TF_Dim(ct, C.int(i)))) + } + b := make([]byte, int(C.TF_TensorByteSize(ct))) + if len(b) > 0 { + C.memcpy(unsafe.Pointer(&b[0]), C.TF_TensorData(ct), C.size_t(len(b))) + } + t.buf = bytes.NewBuffer(b) + return t +} + +// DataType returns the scalar datatype of the Tensor. +func (t *Tensor) DataType() DataType { + return t.dt +} + +// Shape returns the shape of the Tensor. +func (t *Tensor) Shape() []int64 { + return t.shape +} + +// Value converts the Tensor to a Go value. For now, not all Tensor types are +// supported, and this function may panic if it encounters an unsupported +// DataType. +// +// The type of the output depends on the Tensor type and dimensions. +// For example: +// Tensor(int64, 0): int64 +// Tensor(float64, 3): [][][]float64 +func (t *Tensor) Value() interface{} { + typ, err := typeOf(t.DataType(), t.Shape()) + if err != nil { + panic(err) + } + val := reflect.New(typ) + if err := decodeTensor(t.buf, t.Shape(), typ, val); err != nil { + panic(err) + } + return reflect.Indirect(val).Interface() +} + +// c converts the Tensor to a *C.TF_Tensor. Callers must take ownership of +// the *C.TF_Tensor, either by passing ownership to the C API or explicitly +// calling C.TF_DeleteTensor() on it. +func (t *Tensor) c() *C.TF_Tensor { + var shapePtr *C.int64_t + if len(t.shape) > 0 { + shapePtr = (*C.int64_t)(unsafe.Pointer(&t.shape[0])) + } + tensor := C.TF_AllocateTensor(C.TF_DataType(t.dt), shapePtr, C.int(len(t.shape)), C.size_t(t.buf.Len())) + if t.buf.Len() > 0 { + slice := t.buf.Bytes() // https://github.com/golang/go/issues/14210 + C.memcpy(C.TF_TensorData(tensor), unsafe.Pointer(&slice[0]), C.size_t(t.buf.Len())) + } + return tensor +} + +// deleteCTensor only exists to delete C.TF_Tensors in tests. go test doesn't +// support cgo. +func deleteCTensor(ct *C.TF_Tensor) { + C.TF_DeleteTensor(ct) +} + +var types = []struct { + typ reflect.Type + dataType C.TF_DataType +}{ + {reflect.TypeOf(float32(0)), C.TF_FLOAT}, + {reflect.TypeOf(float64(0)), C.TF_DOUBLE}, + {reflect.TypeOf(int32(0)), C.TF_INT32}, + {reflect.TypeOf(uint8(0)), C.TF_UINT8}, + {reflect.TypeOf(int16(0)), C.TF_INT16}, + {reflect.TypeOf(int8(0)), C.TF_INT8}, + {reflect.TypeOf(""), C.TF_STRING}, + {reflect.TypeOf(complex(float32(0), float32(0))), C.TF_COMPLEX64}, + {reflect.TypeOf(int64(0)), C.TF_INT64}, + {reflect.TypeOf(false), C.TF_BOOL}, + {reflect.TypeOf(uint16(0)), C.TF_UINT16}, + {reflect.TypeOf(complex(float64(0), float64(0))), C.TF_COMPLEX128}, +} + +// dimsAndDataTypeOf returns the data type and dimensions of a Go type for use +// when encoding. We fetch them separately from encoding to support 0-D tensors. +func dimsAndDataTypeOf(typ reflect.Type) (int, DataType, error) { + dims := 0 + elem := typ + for ; elem.Kind() == reflect.Array || elem.Kind() == reflect.Slice; elem = elem.Elem() { + dims++ + } + for _, t := range types { + if elem.Kind() == t.typ.Kind() { + return dims, DataType(t.dataType), nil + } + } + return 0, DataType(0), fmt.Errorf("unsupported type %v", typ) +} + +// typeOf converts from a DataType and Shape to the equivalent Go type. +func typeOf(dt DataType, shape []int64) (reflect.Type, error) { + var ret reflect.Type + for _, t := range types { + if dt == DataType(t.dataType) { + ret = t.typ + break + } + } + if ret == nil { + return nil, fmt.Errorf("DataType %v unsupported", dt) + } + for _ = range shape { + ret = reflect.SliceOf(ret) + } + return ret, nil +} + +// encodeTensor writes v to the specified buffer using the format specified in +// c_api.h +func encodeTensor(buf *bytes.Buffer, shape []int64, v reflect.Value) error { + switch v.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + if err := binary.Write(buf, nativeEndian, v.Interface()); err != nil { + return err + } + + case reflect.Array, reflect.Slice: + // If slice elements are slices, verify that all of them have the same size. + // Go's type system makes that guarantee for arrays. + if v.Len() > 0 && v.Type().Elem().Kind() == reflect.Slice { + expected := v.Index(0).Len() + for i := 1; i < v.Len(); i++ { + if v.Index(i).Len() != expected { + return fmt.Errorf("mismatched slice lengths: %d and %d", v.Index(i).Len(), expected) + } + } + } + + shape[0] = int64(v.Len()) + for i := 0; i < v.Len(); i++ { + err := encodeTensor(buf, shape[1:], v.Index(i)) + if err != nil { + return err + } + } + + default: + return fmt.Errorf("unsupported type %v", v.Type()) + } + return nil +} + +// decodeTensor decodes the Tensor from the buffer to ptr using the format +// specified in c_api.h +func decodeTensor(buf *bytes.Buffer, shape []int64, typ reflect.Type, ptr reflect.Value) error { + switch typ.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + if err := binary.Read(buf, nativeEndian, ptr.Interface()); err != nil { + return err + } + + case reflect.Slice: + val := reflect.Indirect(ptr) + val.Set(reflect.MakeSlice(typ, int(shape[0]), int(shape[0]))) + for i := 0; i < val.Len(); i++ { + if err := decodeTensor(buf, shape[1:], typ.Elem(), val.Index(i).Addr()); err != nil { + return err + } + } + + default: + return fmt.Errorf("unsupported type %v", typ) + } + return nil +} + +// nativeEndian is the byte order for the local platform. Used to send back and +// forth Tensors with the C API. We test for endianness at runtime because +// some architectures can be booted into different endian modes. +var nativeEndian binary.ByteOrder + +func init() { + buf := [2]byte{} + *(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD) + + switch buf { + case [2]byte{0xCD, 0xAB}: + nativeEndian = binary.LittleEndian + case [2]byte{0xAB, 0xCD}: + nativeEndian = binary.BigEndian + default: + panic("Could not determine native endianness.") + } +} diff --git a/tensorflow/go/tensor_test.go b/tensorflow/go/tensor_test.go new file mode 100644 index 0000000000000000000000000000000000000000..630d613729243f3284ba43bc4e81aff07b031adf --- /dev/null +++ b/tensorflow/go/tensor_test.go @@ -0,0 +1,97 @@ +// 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. + +package tensorflow + +import ( + "reflect" + "testing" +) + +func TestNewTensor(t *testing.T) { + var tests = []struct { + shape []int64 + value interface{} + }{ + {[]int64{}, int8(5)}, + {[]int64{}, int16(5)}, + {[]int64{}, int32(5)}, + {[]int64{}, int64(5)}, + {[]int64{}, int64(5)}, + {[]int64{}, uint8(5)}, + {[]int64{}, uint16(5)}, + {[]int64{}, float32(5)}, + {[]int64{}, float64(5)}, + {[]int64{}, complex(float32(5), float32(6))}, + {[]int64{}, complex(float64(5), float64(6))}, + {[]int64{1}, []float64{1}}, + {[]int64{1}, [1]float64{1}}, + {[]int64{3, 2}, [][]float64{{1, 2}, {3, 4}, {5, 6}}}, + {[]int64{2, 3}, [2][3]float64{{1, 2, 3}, {3, 4, 6}}}, + {[]int64{4, 3, 2}, [][][]float64{ + {{1, 2}, {3, 4}, {5, 6}}, + {{7, 8}, {9, 10}, {11, 12}}, + {{0, -1}, {-2, -3}, {-4, -5}}, + {{-6, -7}, {-8, -9}, {-10, -11}}, + }}, + {[]int64{2, 0}, [][]int64{{}, {}}}, + } + + var errorTests = []interface{}{ + struct{ a int }{5}, + new(int32), + new([]int32), + // native ints not supported + int(5), + []int{5}, + // uint32 and uint64 are not supported in TensorFlow + uint32(5), + []uint32{5}, + uint64(5), + []uint64{5}, + } + + for _, test := range tests { + tensor, err := NewTensor(test.value) + if err != nil { + t.Errorf("NewTensor(%v): %v", test.value, err) + continue + } + if !reflect.DeepEqual(test.shape, tensor.Shape()) { + t.Errorf("Tensor.Shape(): got %v, want %v", tensor.Shape(), test.shape) + } + + // Test that encode and decode gives the same value. We skip arrays because + // they're returned as slices. + if reflect.TypeOf(test.value).Kind() != reflect.Array { + cTensor := tensor.c() + gotTensor := newTensorFromC(cTensor) + deleteCTensor(cTensor) + got := gotTensor.Value() + if !reflect.DeepEqual(test.value, got) { + t.Errorf("encode/decode: got %v, want %v", got, test.value) + } + } + } + + for _, test := range errorTests { + tensor, err := NewTensor(test) + if err == nil { + t.Errorf("NewTensor(%v): %v", test, err) + } + if tensor != nil { + t.Errorf("NewTensor(%v) = %v, want nil", test, tensor) + } + } +} diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 21825e1bc237a42fa51164b2998e47c462fb9d36..4766a673a4d8c7c9232d875fa4ade9cec3b704d3 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -71,6 +71,34 @@ tf_py_test( ], ) +tf_py_test( + name = "flags_test", + size = "small", + srcs = ["platform/flags_test.py"], + additional_deps = [ + ":platform", + ":platform_test", + ], + tags = [ + "manual", + "notap", + ], +) + +tf_py_test( + name = "app_test", + size = "small", + srcs = ["platform/app_test.py"], + additional_deps = [ + ":platform", + ":platform_test", + ], + tags = [ + "manual", + "notap", + ], +) + cc_library( name = "numpy_lib", srcs = ["lib/core/numpy.cc"], @@ -168,6 +196,18 @@ cc_library( alwayslink = 1, ) +cc_library( + name = "cpp_shape_inference", + srcs = ["framework/cpp_shape_inference.cc"], + hdrs = ["framework/cpp_shape_inference.h"], + visibility = ["//visibility:public"], + deps = [ + "//tensorflow/c:tf_status_helper", + "//tensorflow/core:framework", + "//tensorflow/core:protos_cc", + ], +) + cc_library( name = "python_op_gen_main", srcs = [ @@ -299,9 +339,7 @@ py_test( tf_gen_op_wrapper_py( name = "functional_ops", out = "ops/gen_functional_ops.py", - hidden = [ - "SymbolicGradient", - ], + hidden_file = "ops/hidden_ops.txt", ) py_library( @@ -501,51 +539,19 @@ py_test( tf_gen_op_wrapper_py( name = "array_ops", - hidden = [ - "BroadcastGradientArgs", - "ConcatOffset", - "Concat", - "Const", - "EditDistance", - "MirrorPad", - "MirrorPadGrad", - "OneHot", - "Pack", - "Pad", - "Placeholder", - "RefIdentity", - "Split", - "Slice", - "TileGrad", # Exported through array_grad instead of array_ops. - "ZerosLike", # TODO(josh11b): Use this instead of the Python version. - "Unpack", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "candidate_sampling_ops", - hidden = [ - "AllCandidateSampler", - "ComputeAccidentalHits", - "FixedUnigramCandidateSampler", - "LearnedUnigramCandidateSampler", - "LogUniformCandidateSampler", - "ThreadUnsafeUnigramCandidateSampler", - "UniformCandidateSampler", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "control_flow_ops", - hidden = [ - "Switch", - "Merge", - "RefMerge", - "Exit", - "RefExit", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, deps = [ "//tensorflow/core:control_flow_ops_op_lib", @@ -555,263 +561,98 @@ tf_gen_op_wrapper_py( tf_gen_op_wrapper_py( name = "ctc_ops", - hidden = [ - "CTCLoss", - "CTCGreedyDecoder", - "CTCBeamSearchDecoder", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "data_flow_ops", - hidden = [ - "Barrier", - "BarrierClose", - "BarrierIncompleteSize", - "BarrierInsertMany", - "BarrierReadySize", - "BarrierTakeMany", - "PriorityQueue", - "FIFOQueue", - "HashTable", - "InitializeTable", - "InitializeTableFromTextFile", - "LookupTableExport", - "LookupTableFind", - "LookupTableImport", - "LookupTableInsert", - "LookupTableSize", - "MutableHashTable", - "MutableHashTableOfTensors", - "Mutex", - "MutexAcquire", - "MutexRelease", - "PaddingFIFOQueue", - "QueueClose", - "QueueDequeue", - "QueueDequeueMany", - "QueueDequeueUpTo", - "QueueEnqueue", - "QueueEnqueueMany", - "QueueSize", - "RandomShuffleQueue", - "Stack", - "StackPop", - "StackPush", - "StackClose", - "TensorArray", - "TensorArrayClose", - "TensorArrayConcat", - "TensorArrayGrad", - "TensorArrayRead", - "TensorArrayPack", - "TensorArraySize", - "TensorArraySplit", - "TensorArrayUnpack", - "TensorArrayWrite", - "GetSessionHandle", - "GetSessionTensor", - "DeleteSessionTensor", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "image_ops", - hidden = [ - "RandomCrop", - "ResizeBilinearGrad", - "ResizeNearestNeighborGrad", - "AdjustContrastv2", - "ScaleImageGrad", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "io_ops", - hidden = [ - "FixedLengthRecordReader", - "IdentityReader", - "ReaderClose", - "ReaderEnqueueWork", - "ReaderNumRecordsProduced", - "ReaderNumWorkUnitsCompleted", - "ReaderRead", - "ReaderReadUpTo", - "ReaderReset", - "ReaderRestoreState", - "ReaderSerializeState", - "ReaderWorkQueueLength", - "Restore", - "RestoreSlice", - "Save", - "SaveSlices", - "ShardedFilename", - "ShardedFilespec", - "TextLineReader", - "TFRecordReader", - "WholeFileReader", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "linalg_ops", + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "logging_ops", - hidden = [ - "Assert", - "AudioSummary", - "HistogramAccumulatorSummary", - "HistogramSummary", - "ImageSummary", - "MergeSummary", - "Print", - "ScalarSummary", - "TensorSummary", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "math_ops", - hidden = [ - "Abs", - "AddN", - "All", - "Any", - "BatchMatMul", - "Complex", - "Max", - "Mean", - "Min", - "Pow", - "Prod", - "Range", - "SparseMatMul", - "Sum", - "MatMul", - "Sigmoid", - "Tanh", - "SigmoidGrad", - "TanhGrad", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "nn_ops", - hidden = [ - "AvgPoolGrad", # "*Grad" accessible through nn_grad instead of nn_ops. - "BatchNormWithGlobalNormalization", - "BatchNormWithGlobalNormalizationGrad", - "SoftmaxCrossEntropyWithLogits", - "SparseSoftmaxCrossEntropyWithLogits", - "LRNGrad", - "MaxPoolGrad", - "MaxPoolGradWithArgmax", - "ReluGrad", - "Relu6Grad", - "EluGrad", - "SoftplusGrad", - "SoftsignGrad", - "TopK", - "TopKV2", - "BiasAdd", - "BiasAddV1", - "Relu6", - "AvgPool", - "MaxPool", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "parsing_ops", - hidden = [ - "ParseExample", - "ParseSingleSequenceExample", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "random_ops", - hidden = [ - "RandomGamma", - "RandomUniform", - "RandomUniformInt", - "RandomShuffle", - "RandomStandardNormal", - "ParameterizedTruncatedNormal", - "TruncatedNormal", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "script_ops", - hidden = [ - "PyFunc", - "PyFuncStateless", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "state_ops", - hidden = [ - "Variable", - "TemporaryVariable", - "DestroyTemporaryVariable", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "sparse_ops", - hidden = [ - "DeserializeManySparse", - "SerializeManySparse", - "SerializeSparse", - "SparseAdd", - "SparseAddGrad", - "SparseConcat", - "SparseSplit", - "SparseSelectLastK", - "SparseReorder", - "SparseReshape", - "SparseToDense", - "SparseTensorDenseAdd", - "SparseTensorDenseMatMul", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "string_ops", - hidden = [ - "StringSplit", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) tf_gen_op_wrapper_py( name = "user_ops", - hidden = [ - "Fact", - ], + hidden_file = "ops/hidden_ops.txt", require_shape_functions = False, ) tf_gen_op_wrapper_py( name = "training_ops", out = "training/gen_training_ops.py", + hidden_file = "ops/hidden_ops.txt", require_shape_functions = True, ) @@ -1125,6 +966,7 @@ tf_py_wrap_cc( "client/net_lib.i", "client/quantize_training.i", "client/tf_session.i", + "framework/cpp_shape_inference.i", "framework/python_op_gen.i", "lib/core/py_func.i", "lib/core/strings.i", @@ -1142,6 +984,7 @@ tf_py_wrap_cc( ":py_func_lib", ":py_record_reader_lib", ":py_record_writer_lib", + ":cpp_shape_inference", ":python_op_gen", ":tf_session_helper", "//tensorflow/core/distributed_runtime/rpc:grpc_server_lib", @@ -1418,6 +1261,7 @@ py_tests( "summary/impl/event_file_loader_test.py", "summary/impl/gcs_file_loader_test.py", "summary/impl/reservoir_test.py", + "summary/summary_test.py", ], additional_deps = [ ":summary", diff --git a/tensorflow/python/__init__.py b/tensorflow/python/__init__.py index df57b2fc170f3ea95b431228b0090196a411599f..974d3c245738e5926772a633abba641c5826676a 100644 --- a/tensorflow/python/__init__.py +++ b/tensorflow/python/__init__.py @@ -26,6 +26,7 @@ import tensorflow as tf """ import ctypes +import importlib import inspect import sys import traceback @@ -57,12 +58,11 @@ please exit the tensorflow source tree, and relaunch your python interpreter from there.""" % traceback.format_exc() raise ImportError(msg) +from tensorflow.core.framework.node_def_pb2 import * from tensorflow.core.framework.summary_pb2 import * from tensorflow.core.framework.attr_value_pb2 import * from tensorflow.core.protobuf.config_pb2 import * from tensorflow.core.util.event_pb2 import * -# Import things out of contrib -import tensorflow.contrib as contrib # Framework from tensorflow.python.framework.framework_lib import * @@ -118,7 +118,7 @@ from tensorflow.python.ops import string_ops from tensorflow.python.ops import tensor_array_ops # Don't export modules except for the few we really want -_whitelist = set([app, compat, contrib, errors, flags, gfile, image, logging, +_whitelist = set([app, compat, errors, flags, gfile, image, logging, nn, python_io, resource_loader, sysconfig, test, train, user_ops]) @@ -230,7 +230,6 @@ __all__.extend([ # Export modules and constants. __all__.extend([ 'app', - 'contrib', 'errors', 'flags', 'gfile', diff --git a/tensorflow/python/client/session.py b/tensorflow/python/client/session.py index 0c2edcb22791e2922179480ec9d1b869ad9c6ea6..6eccb4a65f4a7ab48c7dc71282f5bb04f1269e10 100644 --- a/tensorflow/python/client/session.py +++ b/tensorflow/python/client/session.py @@ -519,10 +519,17 @@ class BaseSession(SessionInterface): tf_session.TF_CloseSession(self._session, status) def __del__(self): - self.close() + # cleanly ignore all exceptions + try: + self.close() + except Exception: # pylint: disable=broad-except + pass if self._session is not None: - with errors.raise_exception_on_not_ok_status() as status: + try: + status = tf_session.TF_NewStatus() tf_session.TF_DeleteSession(self._session, status) + finally: + tf_session.TF_DeleteStatus(status) self._session = None @property diff --git a/tensorflow/python/client/session_test.py b/tensorflow/python/client/session_test.py index ad3c681b835c10d2bbeceb3df051f7a55bf57ac1..f0214d2bbeb2835b5de5b697a98f79f1ddf80b5b 100644 --- a/tensorflow/python/client/session_test.py +++ b/tensorflow/python/client/session_test.py @@ -38,6 +38,7 @@ from tensorflow.python.framework import test_util from tensorflow.python.framework import versions from tensorflow.python.ops import array_ops from tensorflow.python.ops import control_flow_ops +from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import math_ops from tensorflow.python.ops import state_ops from tensorflow.python.ops import variables @@ -1441,6 +1442,20 @@ class SessionTest(test_util.TensorFlowTestCase): with self.assertRaisesRegexp(TypeError, 'graph must be a tf.Graph'): session.Session(graph=37) + def testTimeoutWithShortOperations(self): + num_epochs = 5 + q = data_flow_ops.FIFOQueue( + capacity=50, dtypes=[dtypes.int32], shapes=[()]) + enqueue_op = q.enqueue_many(constant_op.constant([1, 2])) + + # Use a 10-second timeout, which should be longer than any + # non-blocking enqueue_many op. + config = config_pb2.ConfigProto(operation_timeout_in_ms=10000) + with session.Session(config=config) as sess: + for _ in range(num_epochs): + sess.run(enqueue_op) + self.assertEqual(sess.run(q.size()), num_epochs * 2) + if __name__ == '__main__': googletest.main() diff --git a/tensorflow/python/framework/common_shapes.py b/tensorflow/python/framework/common_shapes.py index 3e034579c033b683b0e0212559d088eecfb9a7a7..843317d3919dcb48a65056437c60d42d9c5a5566 100644 --- a/tensorflow/python/framework/common_shapes.py +++ b/tensorflow/python/framework/common_shapes.py @@ -19,6 +19,9 @@ from __future__ import print_function import six.moves +from tensorflow.core.framework import tensor_shape_pb2 +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.framework import errors from tensorflow.python.framework import tensor_shape @@ -586,3 +589,34 @@ def broadcast_shape(shape_x, shape_y): return tensor_shape.TensorShape(return_dims) +def call_cpp_shape_fn(op): + """A shape function that delegates to the registered C++ shape function. + + Args: + op: the node in the graph for which to compute output shapes. + + Returns: + A TensorShape list of the output shapes of the op, as computed using the + C++ shape inference function registered for the op. + + Raises: + ValueError: If the C++ shape function returned an error (e.g. because the + shapes of the inputs are of the wrong rank or otherwise incompatible + according to the shape function). + """ + node_def_str = op.node_def.SerializeToString() + input_shapes = [i.get_shape().as_proto().SerializeToString() for i in + op.inputs] + + try: + with errors.raise_exception_on_not_ok_status() as status: + output_shapes = pywrap_tensorflow.RunCppShapeInference( + node_def_str, input_shapes, status) + except errors.InvalidArgumentError as err: + raise ValueError(err.message) + + # Convert TensorShapeProto values in output_shapes. + return [ + tensor_shape.TensorShape(tensor_shape_pb2.TensorShapeProto.FromString(s)) + for s in output_shapes + ] diff --git a/tensorflow/python/framework/contrib_test.py b/tensorflow/python/framework/contrib_test.py index 5ca43b3849a5f06502566031dcef99fa71a41729..db6d7d0a7c6f94fb3ee40809ad7d7ea7f508e88d 100644 --- a/tensorflow/python/framework/contrib_test.py +++ b/tensorflow/python/framework/contrib_test.py @@ -27,6 +27,7 @@ class ContribTest(googletest.TestCase): def testContrib(self): # pylint: disable=g-import-not-at-top import tensorflow as tf + _ = tf.contrib.layers # `tf.contrib` is loaded lazily on first use. assert inspect.ismodule(tf.contrib) def testLayers(self): diff --git a/tensorflow/python/framework/cpp_shape_inference.cc b/tensorflow/python/framework/cpp_shape_inference.cc new file mode 100644 index 0000000000000000000000000000000000000000..dcf9243fb5ee7b8a70a7b2319bfdcb0484cce1a4 --- /dev/null +++ b/tensorflow/python/framework/cpp_shape_inference.cc @@ -0,0 +1,102 @@ +/* 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. +==============================================================================*/ + +#include "tensorflow/python/framework/cpp_shape_inference.h" + +#include "tensorflow/core/framework/graph.pb.h" +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/shape_inference.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/strings/strcat.h" + +namespace tensorflow { +namespace swig { +namespace { + +Status RunCppShapeInferenceImpl( + const string& serialized_node_def, + const std::vector& input_serialized_shapes, + std::vector* output_tensor_shape_protos) { + tensorflow::NodeDef node; + if (!node.ParseFromString(serialized_node_def)) { + return errors::InvalidArgument( + "Error parsing node_def during cpp shape inference"); + } + DCHECK_EQ(output_tensor_shape_protos->size(), 0); + + const OpRegistrationData* op_reg_data; + TF_RETURN_IF_ERROR(OpRegistry::Global()->LookUp(node.op(), &op_reg_data)); + + if (op_reg_data->shape_inference_fn == nullptr) { + return errors::InvalidArgument( + "No shape inference function exists for op '", node.op(), + "', did you forget to define it?"); + } + + std::vector input_shapes; + input_shapes.resize(input_serialized_shapes.size()); + for (int i = 0; i < input_serialized_shapes.size(); ++i) { + if (!input_shapes[i].ParseFromString(input_serialized_shapes[i])) { + return errors::InvalidArgument( + "Error parsing shape proto during cpp shape inference"); + } + } + + tensorflow::shape_inference::InferenceContext c( + &node, op_reg_data->op_def, {} /* input_shape_strings */, input_shapes, + {} /* input_tensors */); + TF_RETURN_IF_ERROR(c.construction_status()); + TF_RETURN_IF_ERROR(op_reg_data->shape_inference_fn(&c)); + + // Convert output shapes. + output_tensor_shape_protos->resize(c.num_outputs()); + TensorShapeProto out; + for (int i = 0; i < c.num_outputs(); ++i) { + shape_inference::ShapeHandle s = c.output(i); + out.Clear(); + if (c.RankKnown(s)) { + const int32 rank = c.Rank(s); + for (int i = 0; i < rank; ++i) { + shape_inference::DimensionHandle d = c.Dim(s, i); + auto* out_dim = out.add_dim(); + if (c.ValueKnown(d)) { + out_dim->set_size(c.Value(d)); + } else { + out_dim->set_size(-1); + } + } + } else { + out.set_unknown_rank(true); + } + CHECK(out.AppendToString(&(*output_tensor_shape_protos)[i])); + } + return Status::OK(); +} + +} // namespace + +std::vector RunCppShapeInference( + const string& serialized_node_def, + const std::vector& input_serialized_shapes, TF_Status* out_status) { + std::vector output_tensor_shape_protos; + tensorflow::Status status = + RunCppShapeInferenceImpl(serialized_node_def, input_serialized_shapes, + &output_tensor_shape_protos); + Set_TF_Status_from_Status(out_status, status); + return status.ok() ? output_tensor_shape_protos : std::vector(); +} + +} // namespace swig +} // namespace tensorflow diff --git a/tensorflow/python/framework/cpp_shape_inference.h b/tensorflow/python/framework/cpp_shape_inference.h new file mode 100644 index 0000000000000000000000000000000000000000..f10ac8cd3b67b50c4cd0bcdd50026c3f5073cf3d --- /dev/null +++ b/tensorflow/python/framework/cpp_shape_inference.h @@ -0,0 +1,48 @@ +/* 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. +==============================================================================*/ + +#ifndef THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ +#define THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ + +#include +#include "tensorflow/c/tf_status_helper.h" +#include "tensorflow/core/platform/types.h" + +namespace tensorflow { +namespace swig { + +// Calls the registered C++ shape inference function for (a serialized +// NodeDef). +// Should not be called for shape functions that access input tensors; constant +// input tensor values are not made available, and so the inferred shapes will +// be less precise than they could be. +// +// Returns an error, or OK, in according to whether the shape +// inference was successful. +// +// On success, <*output_shapes> is populated with the inferred output shapes (as +// serialized TensorShapeProtos). +// <*output_shapes> must be empty when this function is called. +// +// This is temporary code to be used during the migration +// from python shape inference functions to C++ shape inference functions. +std::vector RunCppShapeInference( + const string& serialized_node_def, + const std::vector& input_serialized_shapes, TF_Status* out_status); + +} // namespace swig +} // namespace tensorflow + +#endif // THIRD_PARTY_TENSORFLOW_PYTHON_FRAMEWORK_CPP_SHAPE_INFERENCE_H_ diff --git a/tensorflow/python/framework/cpp_shape_inference.i b/tensorflow/python/framework/cpp_shape_inference.i new file mode 100644 index 0000000000000000000000000000000000000000..7135f9380b4b3ce224828e3e638cccad4281eb17 --- /dev/null +++ b/tensorflow/python/framework/cpp_shape_inference.i @@ -0,0 +1,28 @@ +/* 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. +==============================================================================*/ + +%include "tensorflow/python/platform/base.i" + +%{ +#include "tensorflow/python/framework/cpp_shape_inference.h" +%} + +%ignoreall; +%unignore tensorflow; +%unignore tensorflow::swig; +%unignore tensorflow::swig::RunCppShapeInference; +%include "tensorflow/python/framework/cpp_shape_inference.h" + +%unignoreall diff --git a/tensorflow/python/framework/errors.py b/tensorflow/python/framework/errors.py index cdc515df0676deeba019651cc33a3607e0dccdac..db21f5895cecc15c3ef08966746f4206eb924fc7 100644 --- a/tensorflow/python/framework/errors.py +++ b/tensorflow/python/framework/errors.py @@ -41,8 +41,8 @@ class OpError(Exception): """Creates a new `OpError` indicating that a particular op failed. Args: - node_def: The `graph_pb2.NodeDef` proto representing the op that failed, - if known; otherwise None. + node_def: The `node_def_pb2.NodeDef` proto representing the op that + failed, if known; otherwise None. op: The `ops.Operation` that failed, if known; otherwise None. message: The message string describing the failure. error_code: The `error_codes_pb2.Code` describing the error. diff --git a/tensorflow/python/framework/function.py b/tensorflow/python/framework/function.py index 8556b68439b16ab6d4a6ab2666f00b9ece7b7b8d..c31e5c9079c1af78d9afe51c2fa023d5b8be73bb 100644 --- a/tensorflow/python/framework/function.py +++ b/tensorflow/python/framework/function.py @@ -166,7 +166,6 @@ def _add_op_node(graph, op, func): func.node.extend([node]) -# pylint: disable=line-too-long def graph_to_function_def(graph, name, inputs, outputs): """Returns `graph` as a `FunctionDef` protocol buffer. @@ -184,7 +183,7 @@ def graph_to_function_def(graph, name, inputs, outputs): different graph to make it available there. Args: - graph: GraphDef proto. + graph: Graph. name: string. The name to use for the function. inputs: List of tensors. Inputs to the function. outputs: List of tensors. Outputs of the function. @@ -192,13 +191,10 @@ def graph_to_function_def(graph, name, inputs, outputs): Returns: A FunctionDef protocol buffer. """ - # pylint: enable=line-too-long func = function_pb2.FunctionDef() func.signature.name = name - func.signature.input_arg.extend([_tensor_to_argdef(graph.get_tensor_by_name( - i.name)) for i in inputs]) - func.signature.output_arg.extend([_tensor_to_argdef(graph.get_tensor_by_name( - o.name)) for o in outputs]) + func.signature.input_arg.extend([_tensor_to_argdef(i) for i in inputs]) + func.signature.output_arg.extend([_tensor_to_argdef(o) for o in outputs]) func_arg_placeholders = set([i.name for i in inputs]) g = ops.get_default_graph() for op in graph.get_operations(): @@ -234,7 +230,8 @@ def call_function(func_def, *inputs, **kwargs): Args: func_def: A `FunctionDef` protocol buffer. *inputs: A list of tensors - **kwargs: Optional keyword arguments. Can only contain 'name'. + **kwargs: Optional keyword arguments. Can only contain 'name' or + 'noinline'. Returns: A list of tensors representing the outputs of the call to `func_def`. @@ -248,7 +245,7 @@ def call_function(func_def, *inputs, **kwargs): attrs = None else: attrs = {} - attrs["noinline"] = attr_value_pb2.AttrValue(b=bool(noinline)) + attrs["_noinline"] = attr_value_pb2.AttrValue(b=bool(noinline)) if kwargs: raise ValueError("Unknown keyword arguments: %s" % kwargs.keys()) func_name = func_def.signature.name diff --git a/tensorflow/python/framework/gen_docs_combined.py b/tensorflow/python/framework/gen_docs_combined.py index a5c255c25bbd2a9c1df9db3fe842496c1350af7a..42cf4ffe376d6847524bbc332163db0ce5af77f2 100644 --- a/tensorflow/python/framework/gen_docs_combined.py +++ b/tensorflow/python/framework/gen_docs_combined.py @@ -55,6 +55,8 @@ def module_names(): "tf.python_io", "tf.summary", "tf.test", + "tf.contrib.bayesflow.entropy", + "tf.contrib.bayesflow.monte_carlo", "tf.contrib.bayesflow.stochastic_graph", "tf.contrib.bayesflow.variational_inference", "tf.contrib.copy_graph", @@ -70,7 +72,6 @@ def module_names(): "tf.contrib.metrics", "tf.contrib.training", "tf.contrib.util", - "tf.contrib.slim", ] @@ -191,6 +192,12 @@ def all_libraries(module_to_name, members, documented): prefix=PREFIX_TEXT), library("summary", "Summary Operations", tf.summary), library("test", "Testing", tf.test), + library("contrib.bayesflow.entropy", + "BayesFlow Entropy (contrib)", + tf.contrib.bayesflow.entropy), + library("contrib.bayesflow.monte_carlo", + "BayesFlow Monte Carlo (contrib)", + tf.contrib.bayesflow.monte_carlo), library("contrib.bayesflow.stochastic_graph", "BayesFlow Stochastic Graph (contrib)", tf.contrib.bayesflow.stochastic_graph), diff --git a/tensorflow/python/framework/graph_util.py b/tensorflow/python/framework/graph_util.py index f2c086ed7f556e244a0314248f9f557ea4fa47be..ba693503c259df5e19be9c75e66e547ddbf88de9 100644 --- a/tensorflow/python/framework/graph_util.py +++ b/tensorflow/python/framework/graph_util.py @@ -24,6 +24,7 @@ import re from tensorflow.core.framework import attr_value_pb2 from tensorflow.core.framework import graph_pb2 +from tensorflow.core.framework import node_def_pb2 from tensorflow.python.framework import device as pydev from tensorflow.python.framework import dtypes from tensorflow.python.framework import ops @@ -81,7 +82,7 @@ def must_run_on_cpu(node, pin_variables_on_cpu=False): if isinstance(node, ops.Operation): node_def = node.node_def else: - assert isinstance(node, graph_pb2.NodeDef) + assert isinstance(node, node_def_pb2.NodeDef) node_def = node # If the op is a variable-related op, should we pin it on CPU? @@ -235,7 +236,7 @@ def convert_variables_to_constants(sess, input_graph_def, output_node_names, output_graph_def = graph_pb2.GraphDef() how_many_converted = 0 for input_node in inference_graph.node: - output_node = graph_pb2.NodeDef() + output_node = node_def_pb2.NodeDef() if input_node.name in found_variables: output_node.op = "Const" output_node.name = input_node.name @@ -283,7 +284,7 @@ def remove_training_nodes(input_graph): for node in input_nodes: if node.name in names_to_remove: continue - new_node = graph_pb2.NodeDef() + new_node = node_def_pb2.NodeDef() new_node.CopyFrom(node) input_before_removal = node.input del new_node.input[:] @@ -312,7 +313,7 @@ def remove_training_nodes(input_graph): for node in nodes_after_removal: if node.name in names_to_splice: continue - new_node = graph_pb2.NodeDef() + new_node = node_def_pb2.NodeDef() new_node.CopyFrom(node) input_before_removal = node.input del new_node.input[:] diff --git a/tensorflow/python/framework/ops.py b/tensorflow/python/framework/ops.py index 0189acc97f5a6c4b89d16d52084bda7578f63619..bc635c4d33783f9f626893252d3215e770fea97a 100644 --- a/tensorflow/python/framework/ops.py +++ b/tensorflow/python/framework/ops.py @@ -32,6 +32,7 @@ import six from tensorflow.core.framework import attr_value_pb2 from tensorflow.core.framework import function_pb2 from tensorflow.core.framework import graph_pb2 +from tensorflow.core.framework import node_def_pb2 from tensorflow.core.framework import versions_pb2 from tensorflow.python.framework import device as pydev from tensorflow.python.framework import dtypes @@ -1103,9 +1104,9 @@ def _NodeDef(op_type, name, device=None, attrs=None): AttrValue). Returns: - A graph_pb2.NodeDef protocol buffer. + A node_def_pb2.NodeDef protocol buffer. """ - node_def = graph_pb2.NodeDef() + node_def = node_def_pb2.NodeDef() node_def.op = compat.as_bytes(op_type) node_def.name = compat.as_bytes(name) if attrs is not None: @@ -1170,8 +1171,8 @@ class Operation(object): [A-Za-z0-9.][A-Za-z0-9_.\\-/]* Args: - node_def: `graph_pb2.NodeDef`. `NodeDef` for the `Operation`. - Used for attributes of `graph_pb2.NodeDef`, typically `name`, + node_def: `node_def_pb2.NodeDef`. `NodeDef` for the `Operation`. + Used for attributes of `node_def_pb2.NodeDef`, typically `name`, `op`, and `device`. The `input` attribute is irrelevant here as it will be computed when generating the model. g: `Graph`. The parent graph. @@ -1199,7 +1200,7 @@ class Operation(object): or if `inputs` and `input_types` are incompatible. ValueError: if the `node_def` name is not valid. """ - if not isinstance(node_def, graph_pb2.NodeDef): + if not isinstance(node_def, node_def_pb2.NodeDef): raise TypeError("node_def needs to be a NodeDef: %s" % node_def) if node_def.ByteSize() >= (1 << 31) or node_def.ByteSize() < 0: raise ValueError( @@ -1501,7 +1502,7 @@ class Operation(object): Returns: A - [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/graph.proto) + [`NodeDef`](https://www.tensorflow.org/code/tensorflow/core/framework/node_def.proto) protocol buffer. """ return self._node_def diff --git a/tensorflow/python/framework/python_op_gen.cc b/tensorflow/python/framework/python_op_gen.cc index 708170d9c13a7900a57547186a8164b0008242e2..675594034e52b674e4084cdedee958d59077320d 100644 --- a/tensorflow/python/framework/python_op_gen.cc +++ b/tensorflow/python/framework/python_op_gen.cc @@ -646,7 +646,7 @@ void GenerateLowerCaseOpName(const string& str, string* result) { } // namespace -string GetPythonOps(const OpList& ops, const string& hidden_ops, +string GetPythonOps(const OpList& ops, const std::vector& hidden_ops, bool require_shapes) { string result; // Header @@ -668,15 +668,13 @@ from tensorflow.python.framework import op_def_library )"); - std::vector hidden_vec = str_util::Split(hidden_ops, ','); - // We'll make a copy of ops that filters out descriptions. OpList cleaned_ops; auto out = cleaned_ops.mutable_op(); out->Reserve(ops.op_size()); for (const auto& op_def : ops.op()) { bool is_hidden = false; - for (const string& hidden : hidden_vec) { + for (const string& hidden : hidden_ops) { if (op_def.name() == hidden) { is_hidden = true; break; @@ -726,22 +724,16 @@ _op_def_lib = _InitOpDefLibrary() return result; } -void PrintPythonOps(const OpList& ops, const string& hidden_ops, +void PrintPythonOps(const OpList& ops, const std::vector& hidden_ops, bool require_shapes) { printf("%s", GetPythonOps(ops, hidden_ops, require_shapes).c_str()); } -string GetAllPythonOps(const char* hidden, bool require_shapes) { - OpList ops; - OpRegistry::Global()->Export(false, &ops); - return GetPythonOps(ops, hidden, require_shapes); -} - string GetPythonWrappers(const char* op_wrapper_buf, size_t op_wrapper_len) { string op_list_str(op_wrapper_buf, op_wrapper_len); OpList ops; ops.ParseFromString(op_list_str); - return GetPythonOps(ops, "", false); + return GetPythonOps(ops, {}, false); } } // namespace tensorflow diff --git a/tensorflow/python/framework/python_op_gen.h b/tensorflow/python/framework/python_op_gen.h index a852af7a7488e65c5801594ce44bab8e93429331..424244fcc55006943340ed865e97b9572a14102e 100644 --- a/tensorflow/python/framework/python_op_gen.h +++ b/tensorflow/python/framework/python_op_gen.h @@ -17,6 +17,7 @@ limitations under the License. #define TENSORFLOW_PYTHON_FRAMEWORK_PYTHON_OP_GEN_H_ #include +#include #include "tensorflow/core/framework/op_def.pb.h" #include "tensorflow/core/platform/types.h" @@ -26,9 +27,9 @@ namespace tensorflow { // list of Op names that should get a leading _ in the output. // The Print* version prints the output to stdout, Get* version returns the // output as a string. -void PrintPythonOps(const OpList& ops, const string& hidden_ops, +void PrintPythonOps(const OpList& ops, const std::vector& hidden_ops, bool require_shapes); -string GetPythonOps(const OpList& ops, const string& hidden_ops, +string GetPythonOps(const OpList& ops, const std::vector& hidden_ops, bool require_shapes); // Get the python wrappers for a list of ops in a OpList. diff --git a/tensorflow/python/framework/python_op_gen_main.cc b/tensorflow/python/framework/python_op_gen_main.cc index fd68996bf995772645175ecb97280113fc7f5aef..ca99f5fdc49500c79dcaa25861c8614ea530e60a 100644 --- a/tensorflow/python/framework/python_op_gen_main.cc +++ b/tensorflow/python/framework/python_op_gen_main.cc @@ -15,18 +15,73 @@ limitations under the License. #include "tensorflow/python/framework/python_op_gen.h" +#include +#include +#include + #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/op_def.pb.h" +#include "tensorflow/core/lib/core/errors.h" +#include "tensorflow/core/lib/io/inputbuffer.h" +#include "tensorflow/core/lib/strings/scanner.h" +#include "tensorflow/core/platform/env.h" #include "tensorflow/core/platform/init_main.h" #include "tensorflow/core/platform/logging.h" namespace tensorflow { namespace { -void PrintAllPythonOps(const char* hidden, bool require_shapes) { +Status ReadHiddenOpsFromFile(const string& filename, + std::vector* hidden_ops) { + std::unique_ptr file; + TF_CHECK_OK(Env::Default()->NewRandomAccessFile(filename, &file)); + std::unique_ptr input_buffer( + new io::InputBuffer(file.get(), 256 << 10)); + string line_contents; + Status s = input_buffer->ReadLine(&line_contents); + while (s.ok()) { + // The parser assumes that the op name is the first string on each + // line with no preceding whitespace, and ignores lines that do + // not start with an op name as a comment. + strings::Scanner scanner{StringPiece(line_contents)}; + StringPiece op_name; + if (scanner.One(strings::Scanner::LETTER_DIGIT_DOT) + .Any(strings::Scanner::LETTER_DIGIT_DASH_DOT_SLASH_UNDERSCORE) + .GetResult(nullptr, &op_name)) { + hidden_ops->emplace_back(op_name.ToString()); + } + s = input_buffer->ReadLine(&line_contents); + } + if (!errors::IsOutOfRange(s)) return s; + return Status::OK(); +} + +// The argument parsing is deliberately simplistic to support our only +// known use cases: +// +// 1. Read all op names from a file. +// 2. Read all op names from the arg as a comma-delimited list. +// +// Expected command-line argument syntax: +// ARG ::= '@' FILENAME +// | OP_NAME [',' OP_NAME]* +Status ParseHiddenOpsCommandLine(const char* arg, + std::vector* hidden_ops) { + std::vector op_names = str_util::Split(arg, ','); + if (op_names.size() == 1 && op_names[0].substr(0, 1) == "@") { + const string filename = op_names[0].substr(1); + return tensorflow::ReadHiddenOpsFromFile(filename, hidden_ops); + } else { + *hidden_ops = std::move(op_names); + } + return Status::OK(); +} + +void PrintAllPythonOps(const std::vector& hidden_ops, + bool require_shapes) { OpList ops; OpRegistry::Global()->Export(false, &ops); - PrintPythonOps(ops, hidden, require_shapes); + PrintPythonOps(ops, hidden_ops, require_shapes); } } // namespace @@ -34,10 +89,15 @@ void PrintAllPythonOps(const char* hidden, bool require_shapes) { int main(int argc, char* argv[]) { tensorflow::port::InitMain(argv[0], &argc, &argv); + // Usage: + // gen_main [ @FILENAME | OpName[,OpName]* ] (0 | 1) if (argc == 2) { - tensorflow::PrintAllPythonOps("", std::string(argv[1]) == "1"); + tensorflow::PrintAllPythonOps({}, tensorflow::string(argv[1]) == "1"); } else if (argc == 3) { - tensorflow::PrintAllPythonOps(argv[1], std::string(argv[2]) == "1"); + std::vector hidden_ops; + TF_CHECK_OK(tensorflow::ParseHiddenOpsCommandLine(argv[1], &hidden_ops)); + tensorflow::PrintAllPythonOps(hidden_ops, + tensorflow::string(argv[2]) == "1"); } else { return -1; } diff --git a/tensorflow/python/framework/tensor_shape.py b/tensorflow/python/framework/tensor_shape.py index bf24763e814908bf2bc2385c3b1105c98e4eea1c..dcc31f6701173658f4bf546a18b429d4ed3c4979 100644 --- a/tensorflow/python/framework/tensor_shape.py +++ b/tensorflow/python/framework/tensor_shape.py @@ -438,6 +438,8 @@ class TensorShape(object): # Protos store variable-size dimensions as -1 as_dimension(dim.size if dim.size != -1 else None) for dim in dims.dim] + elif isinstance(dims, TensorShape): + self._dims = dims.dims else: try: dims_iter = iter(dims) @@ -485,6 +487,13 @@ class TensorShape(object): # Python 3 wants __bool__, Python 2.7 wants __nonzero__ __nonzero__ = __bool__ + def __iter__(self): + """Returns `self.dims` if the rank is known, otherwise raises ValueError.""" + if self._dims is None: + raise ValueError("Cannot iterate over a shape with unknown rank.") + else: + return iter(self._dims) + def __getitem__(self, key): """Returns the value of a dimension or a shape, depending on the key. diff --git a/tensorflow/python/framework/tensor_shape_test.py b/tensorflow/python/framework/tensor_shape_test.py index 502be1df7df5825a1b99e21e6317a427f8fd07d0..01bcd2e2f2fff6f6a7e4f7efe41f1d212e299b83 100644 --- a/tensorflow/python/framework/tensor_shape_test.py +++ b/tensorflow/python/framework/tensor_shape_test.py @@ -187,6 +187,9 @@ class ShapeTest(test_util.TensorFlowTestCase): len(s) self.assertFalse(s) self.assertIs(None, s.dims) + with self.assertRaises(ValueError): + for _ in tensor_shape.TensorShape(None): + pass def testFullyDefinedShape(self): s = tensor_shape.TensorShape([tensor_shape.Dimension( @@ -205,6 +208,8 @@ class ShapeTest(test_util.TensorFlowTestCase): self.assertEqual([3, 4, 7], s.as_list()) s.assert_is_compatible_with([3, 4, 7]) s.assert_same_rank([6, 3, 7]) + for d1, d2 in zip(s, [3, 4, 7]): + assert d1.value == d2 def testPartiallyDefinedShape(self): s = tensor_shape.TensorShape([tensor_shape.Dimension( @@ -219,6 +224,8 @@ class ShapeTest(test_util.TensorFlowTestCase): self.assertEqual(tensor_shape.Dimension(None).value, s[1].value) self.assertEqual(tensor_shape.Dimension(7), s[2]) s.assert_same_rank([6, 3, 7]) + for d1, d2 in zip(s, [3, None, 7]): + assert d1.value == d2 def testMergeFullShapes(self): self.assertEqual([3, 4, 7], diff --git a/tensorflow/python/kernel_tests/BUILD b/tensorflow/python/kernel_tests/BUILD index 80d11107fede6b38e5ed3e413e26a0ed542c40bb..effe925df06427f0313bcaafb6697ec2ed6c63fd 100644 --- a/tensorflow/python/kernel_tests/BUILD +++ b/tensorflow/python/kernel_tests/BUILD @@ -111,6 +111,7 @@ cuda_py_tests( "array_ops_test.py", "batch_matmul_op_test.py", "batchtospace_op_test.py", + "betainc_op_test.py", "bias_op_test.py", "bitcast_op_test.py", "check_ops_test.py", @@ -189,7 +190,6 @@ cuda_py_tests( "conv_ops_test.py", "depthwise_conv_op_test.py", # http://b/30603882 "division_future_test.py", - "extract_image_patches_grad_test.py", "fft_ops_test.py", "pooling_ops_3d_test.py", # http://b/30600785 "pooling_ops_test.py", @@ -204,6 +204,15 @@ cuda_py_tests( ], ) +# TODO(gpapan): Revisit the gradient of extract_image_patches_op to resolve +# http://b/31080670. +cuda_py_test( + name = "extract_image_patches_grad_test", + size = "medium", + srcs = ["extract_image_patches_grad_test.py"], + tags = ["notap"], # http://b/31080670 +) + cuda_py_test( name = "concat_op_test", size = "medium", diff --git a/tensorflow/python/kernel_tests/betainc_op_test.py b/tensorflow/python/kernel_tests/betainc_op_test.py new file mode 100644 index 0000000000000000000000000000000000000000..a78a1b934f1200fe4f57dd43dbb25414198ffaa2 --- /dev/null +++ b/tensorflow/python/kernel_tests/betainc_op_test.py @@ -0,0 +1,103 @@ +# 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. +# ============================================================================== +"""Functional tests for 3d convolutional operations.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import itertools + +import numpy as np +import tensorflow as tf + + +class BetaincTest(tf.test.TestCase): + use_gpu = False + + def _testBetaInc(self, dtype): + try: + from scipy import special # pylint: disable=g-import-not-at-top + np_dt = dtype.as_numpy_dtype + + # Test random values + a_s = np.abs(np.random.randn(10, 10) * 30).astype(np_dt) # in (0, infty) + b_s = np.abs(np.random.randn(10, 10) * 30).astype(np_dt) # in (0, infty) + x_s = np.random.rand(10, 10).astype(np_dt) # in (0, 1) + with self.test_session(use_gpu=self.use_gpu): + tf_a_s = tf.constant(a_s, dtype=dtype) + tf_b_s = tf.constant(b_s, dtype=dtype) + tf_x_s = tf.constant(x_s, dtype=dtype) + tf_out = tf.betainc(tf_a_s, tf_b_s, tf_x_s).eval() + scipy_out = special.betainc(a_s, b_s, x_s).astype(np_dt) + + # the scipy version of betainc uses a double-only implementation. + # TODO(ebrevdo): identify reasons for (sometime) precision loss + # with doubles + tol = 1e-4 if dtype == tf.float32 else 5e-5 + self.assertAllCloseAccordingToType(scipy_out, tf_out, rtol=tol, atol=tol) + + # Test out-of-range values (most should return nan output) + combinations = list(itertools.product([-1, 0, 0.5, 1.0, 1.5], repeat=3)) + a_comb, b_comb, x_comb = np.asarray( + list(zip(*combinations)), dtype=np_dt) + with self.test_session(use_gpu=self.use_gpu): + tf_comb = tf.betainc(a_comb, b_comb, x_comb).eval() + scipy_comb = special.betainc(a_comb, b_comb, x_comb).astype(np_dt) + self.assertAllCloseAccordingToType(scipy_comb, tf_comb) + + # Test broadcasting between scalars and other shapes + with self.test_session(use_gpu=self.use_gpu): + self.assertAllCloseAccordingToType( + special.betainc(0.1, b_s, x_s).astype(np_dt), + tf.betainc(0.1, b_s, x_s).eval(), rtol=tol, atol=tol) + self.assertAllCloseAccordingToType( + special.betainc(a_s, 0.1, x_s).astype(np_dt), + tf.betainc(a_s, 0.1, x_s).eval(), rtol=tol, atol=tol) + self.assertAllCloseAccordingToType( + special.betainc(a_s, b_s, 0.1).astype(np_dt), + tf.betainc(a_s, b_s, 0.1).eval(), rtol=tol, atol=tol) + self.assertAllCloseAccordingToType( + special.betainc(0.1, b_s, 0.1).astype(np_dt), + tf.betainc(0.1, b_s, 0.1).eval(), rtol=tol, atol=tol) + self.assertAllCloseAccordingToType( + special.betainc(0.1, 0.1, 0.1).astype(np_dt), + tf.betainc(0.1, 0.1, 0.1).eval(), rtol=tol, atol=tol) + + with self.assertRaisesRegexp(ValueError, "Shapes .* are not compatible"): + tf.betainc(0.5, [0.5], [[0.5]]) + + with self.test_session(use_gpu=self.use_gpu): + with self.assertRaisesOpError("Shapes of .* are inconsistent"): + a_p = tf.placeholder(dtype) + b_p = tf.placeholder(dtype) + x_p = tf.placeholder(dtype) + tf.betainc(a_p, b_p, x_p).eval( + feed_dict={a_p: 0.5, b_p: [0.5], x_p: [[0.5]]}) + + except ImportError as e: + tf.logging.warn("Cannot test special functions: %s" % str(e)) + + def testBetaIncFloat(self): + self._testBetaInc(tf.float32) + + def testBetaIncDouble(self): + self._testBetaInc(tf.float64) + + +class BetaincTestGPU(BetaincTest): + use_gpu = True + +if __name__ == "__main__": + tf.test.main() diff --git a/tensorflow/python/kernel_tests/clip_ops_test.py b/tensorflow/python/kernel_tests/clip_ops_test.py index 1f9e69713a9975a06964a1473d10964d91a7f764..bb842a2998bd32267f541e5f64c3fe13c7fdc0de 100644 --- a/tensorflow/python/kernel_tests/clip_ops_test.py +++ b/tensorflow/python/kernel_tests/clip_ops_test.py @@ -57,8 +57,13 @@ class ClipTest(tf.test.TestCase): clip_norm = 4.0 ans = tf.clip_by_norm(x, clip_norm) tf_ans = ans.eval() + + clip_tensor = tf.constant(4.0) + ans = tf.clip_by_norm(x, clip_norm) + tf_ans_tensor = ans.eval() self.assertAllClose(np_ans, tf_ans) + self.assertAllClose(np_ans, tf_ans_tensor) def testClipByNormNotClipped(self): # No norm clipping when clip_norm >= 5 @@ -148,6 +153,28 @@ class ClipTest(tf.test.TestCase): self.assertAllClose(np_ans_0, tf_ans_1) self.assertAllClose(np_ans_1, tf_ans_2) + def testClipByGlobalNormClippedTensor(self): + # Norm clipping when clip_norm < 5 + with self.test_session(): + x0 = tf.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3]) + x1 = tf.constant([1.0, -2.0]) + # Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5 + clip_norm = tf.constant(4.0) + + # Answers are the original tensors scaled by 4.0/5.0 + np_ans_0 = [[-1.6, 0.0, 0.0], + [3.2, 0.0, 0.0]] + np_ans_1 = [0.8, -1.6] + + ans, norm = tf.clip_by_global_norm((x0, x1), clip_norm) + tf_ans_1 = ans[0].eval() + tf_ans_2 = ans[1].eval() + tf_norm = norm.eval() + + self.assertAllClose(tf_norm, 5.0) + self.assertAllClose(np_ans_0, tf_ans_1) + self.assertAllClose(np_ans_1, tf_ans_2) + def testClipByGlobalNormSupportsNone(self): # Norm clipping when clip_norm < 5 with self.test_session(): @@ -259,6 +286,19 @@ class ClipTest(tf.test.TestCase): self.assertAllClose(np_ans, tf_ans) + def testClipByAverageNormClippedTensor(self): + # Norm clipping when average clip_norm < 0.83333333 + with self.test_session(): + x = tf.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3]) + # Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333 + np_ans = [[-2.88, 0.0, 0.0], + [3.84, 0.0, 0.0]] + clip_norm = tf.constant(0.8) + ans = tf.clip_by_average_norm(x, clip_norm) + tf_ans = ans.eval() + + self.assertAllClose(np_ans, tf_ans) + def testClipByAverageNormNotClipped(self): # No norm clipping when average clip_norm >= 0.83333333 with self.test_session(): diff --git a/tensorflow/python/kernel_tests/constant_op_test.py b/tensorflow/python/kernel_tests/constant_op_test.py index adfedbed64bdd1ab24f9dc60b6bbaf19eb3d0e4f..71ffe8c61df615f4a82b5beb24f1328bd81a6ae8 100644 --- a/tensorflow/python/kernel_tests/constant_op_test.py +++ b/tensorflow/python/kernel_tests/constant_op_test.py @@ -298,19 +298,23 @@ class ZerosTest(tf.test.TestCase): z = tf.zeros([2, 3]) self.assertEqual(z.dtype, tf.float32) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.zeros([2, 3])) z = tf.zeros(tf.shape(d)) self.assertEqual(z.dtype, tf.float32) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.zeros([2, 3])) # Test explicit type control for dtype in [tf.float32, tf.float64, tf.int32, tf.uint8, tf.int16, tf.int8, - tf.complex64, tf.complex128, tf.int64]: + tf.complex64, tf.complex128, tf.int64, tf.bool]: z = tf.zeros([2, 3], dtype=dtype) self.assertEqual(z.dtype, dtype) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.zeros([2, 3])) z = tf.zeros(tf.shape(d), dtype=dtype) self.assertEqual(z.dtype, dtype) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.zeros([2, 3])) class ZerosLikeTest(tf.test.TestCase): @@ -404,19 +408,23 @@ class OnesTest(tf.test.TestCase): z = tf.ones([2, 3]) self.assertEqual(z.dtype, tf.float32) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.ones([2, 3])) z = tf.ones(tf.shape(d)) self.assertEqual(z.dtype, tf.float32) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.ones([2, 3])) # Test explicit type control for dtype in (tf.float32, tf.float64, tf.int32, tf.uint8, tf.int16, tf.int8, - tf.complex64, tf.complex128, tf.int64): + tf.complex64, tf.complex128, tf.int64, tf.bool): z = tf.ones([2, 3], dtype=dtype) self.assertEqual(z.dtype, dtype) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.ones([2, 3])) z = tf.ones(tf.shape(d), dtype=dtype) self.assertEqual(z.dtype, dtype) self.assertEqual([2, 3], z.get_shape()) + self.assertAllEqual(z.eval(), np.ones([2, 3])) class OnesLikeTest(tf.test.TestCase): diff --git a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py index f221387a1b8d4e22a00c2d477a6a84b2cbb8ade0..5cb9591f880678d8ec91215237289e3803a91bad 100644 --- a/tensorflow/python/kernel_tests/control_flow_ops_py_test.py +++ b/tensorflow/python/kernel_tests/control_flow_ops_py_test.py @@ -27,6 +27,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf from tensorflow.python.framework import function +from tensorflow.python.framework import tensor_shape from tensorflow.python.ops import control_flow_ops from tensorflow.python.ops import gen_array_ops from tensorflow.python.ops import gen_data_flow_ops @@ -585,12 +586,13 @@ class ControlFlowTest(tf.test.TestCase): return [i, c, o] i = tf.convert_to_tensor(0) - c = tf.convert_to_tensor(0) + c = tf.convert_to_tensor([0]) o = tf.convert_to_tensor([0]) x = tf.convert_to_tensor([1, 2, 3, 4, 5, 6]) s = tf.size(x) r = tf.while_loop( - lambda i, c, o: tf.less(i, s), compute, [i, c, o]) + lambda i, c, o: tf.less(i, s), compute, [i, c, o], + [i.get_shape(), c.get_shape(), tensor_shape.unknown_shape()]) result = r[2].eval() self.assertTrue(check_op_order(i.graph)) self.assertAllEqual(np.array([0, 1, 2, 3, 4, 5, 6]), result) @@ -630,7 +632,8 @@ class ControlFlowTest(tf.test.TestCase): new_i = tf.add(i, 1) new_j = tf.tile(j, [2, 2]) return [new_i, new_j] - r = tf.while_loop(c, _b, [i, m]) + r = tf.while_loop(c, _b, [i, m], + [i.get_shape(), tensor_shape.unknown_shape()]) r = r[1] * tf.ones([8, 8]) self.assertAllEqual(np.ones((8, 8)), r.eval()) @@ -655,14 +658,69 @@ class ControlFlowTest(tf.test.TestCase): i = tf.constant(0) m = tf.ones([2, 2]) c = lambda i, j: tf.less(i, 2) - def _b(i, j): + def b(i, j): new_i = tf.add(i, 1) new_j = tf.concat(0, [j, j]) return [new_i, new_j] - r = tf.while_loop(c, _b, [i, m]) + r = tf.while_loop(c, b, [i, m], + [i.get_shape(), tensor_shape.TensorShape([None, 2])]) self.assertTrue(r[1].get_shape()[0].value is None) self.assertEqual(r[1].get_shape()[1], tf.Dimension(2)) + with self.assertRaisesRegexp(ValueError, "not an invariant for"): + r = tf.while_loop(c, b, [i, m]) + + def testWhileShapeInferenceSparseTensor(self): + with self.test_session(): + values = tf.constant([2.0, 4.0], name="values") + indices = tf.constant([[0], [3]], dtype=tf.int64, name="indices") + shape = tf.constant([10], dtype=tf.int64, name="dense_shape") + i = tf.constant(0) + x = tf.SparseTensor(indices, values, shape=shape) + def c(i, _): + return i < 10 + def b(i, x): + return [i + 1, tf.SparseTensor(x.indices, x.values * 2.0, + x.shape)] + _, r = tf.while_loop(c, b, [i, x]) + self.assertEqual(r.shape.get_shape()[0].value, 1) + + _, r = tf.while_loop(c, b, [i, x], + [i.get_shape(), tensor_shape.TensorShape([None])]) + self.assertTrue(r.shape.get_shape()[0].value is None) + + with self.assertRaisesRegexp(ValueError, "is not compatible with"): + _, r = tf.while_loop(c, b, [i, x], + [i.get_shape(), tensor_shape.TensorShape([5])]) + + def testWhileShapeInferenceIndexedSlices(self): + with self.test_session(): + values = tf.constant([[2.0, 4.0], [3.0, 5.0]], name="values") + indices = tf.constant([0, 3], name="indices") + shape = tf.constant([10, 2], name="dense_shape") + i = tf.constant(0) + x = tf.IndexedSlices(values, indices, dense_shape=shape) + def c(i, _): + return i < 10 + def b(i, x): + return [i + 1, tf.IndexedSlices(x.values * 2.0, x.indices, + x.dense_shape)] + _, r = tf.while_loop(c, b, [i, x]) + self.assertEqual(r.dense_shape.get_shape()[0].value, 2) + self.assertEqual(r.values.get_shape(), tensor_shape.TensorShape([2, 2])) + + _, r = tf.while_loop(c, b, [i, x], + [i.get_shape(), tensor_shape.TensorShape([None, 2])]) + self.assertEqual(r.dense_shape.get_shape()[0].value, 2) + self.assertTrue(r.values.get_shape()[0].value is None) + self.assertEqual(r.values.get_shape()[1].value, 2) + + with self.assertRaisesRegexp(ValueError, "is not compatible with"): + _, r = tf.while_loop(c, b, [i, x], + [i.get_shape(), + tensor_shape.TensorShape([None, 5])]) + + def _testNestedWhile_1(self, use_gpu): with self.test_session(use_gpu=use_gpu): n = tf.constant(0) @@ -685,7 +743,7 @@ class ControlFlowTest(tf.test.TestCase): self._testNestedWhile_1(use_gpu=True) def _testNestedWhile_2(self, use_gpu): - """ Test the cases that A -> Enter and Exit -> A are partitioned.""" + # Test the cases that A -> Enter and Exit -> A are partitioned. with self.test_session(use_gpu=use_gpu): s0 = tf.constant(2.0) def inner_loop(s): @@ -722,8 +780,7 @@ class ControlFlowTest(tf.test.TestCase): r_ = tf.constant(12) return [n_, r_] - res = tf.while_loop(condition, body, [n, r], - parallel_iterations=1) + res = tf.while_loop(condition, body, [n, r], parallel_iterations=1) self.assertAllEqual(12, res[1].eval()) def testWhileWithControl_2(self): @@ -770,6 +827,25 @@ class ControlFlowTest(tf.test.TestCase): loop = tf.while_loop(cond, body, (tf.constant(5),)) self.assertEqual(0, sess.run(loop)) + def testWhileCondExitControl(self): + with self.test_session(): + v = tf.Variable(1) + def false_branch(): + cond = lambda i: i < 100 + def body(i): + x = tf.assign(v, i) + return x + 1 + loop = tf.while_loop(cond, body, [0]) + # Make sure to handle correctly control edge from Exit to a node. + with tf.control_dependencies([loop]): + return tf.constant(6.0) + r = tf.cond(tf.constant(False), + lambda: tf.constant(1.0), + false_branch) + tf.initialize_all_variables().run() + self.assertEqual(6.0, r.eval()) + self.assertEqual(99, v.eval()) + def testCondWhile_1(self): with self.test_session(): n = tf.convert_to_tensor(0, name="n") @@ -964,7 +1040,8 @@ class ControlFlowTest(tf.test.TestCase): inc_b = tf.identity(var_b) return inc_b - lpa = tf.while_loop(pred, loop_body, [var_b], 1, name="loop") + lpa = tf.while_loop(pred, loop_body, [var_b], parallel_iterations=1, + name="loop") self.assertEqual(0, var_b.eval()) lpa.eval() # Run the loop @@ -993,7 +1070,8 @@ class ControlFlowTest(tf.test.TestCase): ni = tf.add(i, 1, name="i_add") return ni - lpa = tf.while_loop(pred, loop_body, [c], 1, name="loop") + lpa = tf.while_loop(pred, loop_body, [c], parallel_iterations=1, + name="loop") self.assertEqual(0, var_b.eval()) lpa.eval() # Run the loop @@ -1039,7 +1117,9 @@ class ControlFlowTest(tf.test.TestCase): ni = tf.sub(i, 1) nx = x + gen_data_flow_ops._stack_pop(s, tf.int32) return [ni, nx] - _, rx = tf.while_loop(c1, b1, [r, x], parallel_iterations=1) + _, rx = tf.while_loop(c1, b1, [r, x], + [r.get_shape(), tensor_shape.unknown_shape()], + parallel_iterations=1) self.assertEqual(45, rx.eval()) def _testWhileGrad_ColocateGradients(self, colocate): @@ -1089,7 +1169,9 @@ class ControlFlowTest(tf.test.TestCase): n = tf.constant(0, name="n") c = lambda i, v: tf.less(i, 5) b = lambda i, v: [i + 1, tf.mul(x, v)] - r = tf.while_loop(c, b, [n, v], parallel_iterations=1) + r = tf.while_loop(c, b, [n, v], + [n.get_shape(), tensor_shape.unknown_shape()], + parallel_iterations=1) r = tf.gradients(r[1], x)[0] self.assertEqual([None], r.get_shape().as_list()) @@ -1387,6 +1469,26 @@ class ControlFlowTest(tf.test.TestCase): r = tf.gradients(r, v)[0] self.assertAllClose(512.0, r.eval()) + def testNestedWhileGrad_ParallelIterations(self): + # Make sure the stack pushes and pops of an inner loop are executed in + # the sequential order of the iterations of its outer loop. + with self.test_session() as sess: + def inner_loop(t): + fn = lambda n: n + tf.square(var) + return tf.map_fn(fn=fn, elems=t, parallel_iterations=10) + + def outer_loop(inp): + return tf.map_fn(fn=inner_loop, elems=inp, parallel_iterations=10) + + var = tf.Variable(tf.constant(3.0)) + inp = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + res = outer_loop(inp) + optimizer = tf.train.AdamOptimizer(learning_rate=0.001) + train_op = optimizer.minimize(tf.reduce_mean(tf.square(res))) + sess.run(tf.initialize_all_variables()) + sess.run(train_op) + self.assertAllClose(2.999, var.eval()) + def _testWhileCondGrad_Simple(self, use_gpu): with self.test_session(use_gpu=use_gpu): v = tf.convert_to_tensor(2.0, name="v") @@ -1424,6 +1526,29 @@ class ControlFlowTest(tf.test.TestCase): r = sess.run(r, feed_dict={v: 2.0}) self.assertAllClose(1024.0, r) + def testWhileGrad_Concat(self): + with self.test_session() as sess: + x = tf.get_variable("x", initializer=[[1., 2.]]) + i0 = tf.constant(0) + h0 = tf.zeros([0, 2]) + + def condition(i, _): + return i < 2 + + def body(i, h): + return i+1, tf.concat(0, [h, x]) + + _, h = tf.while_loop( + condition, body, [i0, h0], + [i0.get_shape(), tensor_shape.TensorShape([None, 2])]) + s = tf.reduce_sum(h) + + sess.run(tf.initialize_all_variables()) + optimizer = tf.train.GradientDescentOptimizer(0.01) + op = optimizer.minimize(s) + sess.run(op) + self.assertAllClose([[0.98000002, 1.98000002]], sess.run(x)) + def testWhileWithRefsWithGradients_1(self): with self.test_session() as sess: x = tf.Variable(0).ref() @@ -1991,7 +2116,8 @@ class TupleTest(tf.test.TestCase): r = tf.while_loop( lambda i, v: i < 4, lambda i, v: [i + 1, tf.py_func(func, [v], [tf.float32])[0]], - [tf.constant(0), tf.constant(2.0, tf.float32)]) + [tf.constant(0), tf.constant(2.0, tf.float32)], + [tensor_shape.unknown_shape(), tensor_shape.unknown_shape()]) self.assertEqual(r[1].eval(), 65536.0) def testWhileFuncBasic(self): @@ -2004,7 +2130,8 @@ class TupleTest(tf.test.TestCase): r = tf.while_loop( lambda i, v: i < 2, lambda i, v: [i + 1, func(v)], - [tf.constant(0), x]) + [tf.constant(0), x], + [tensor_shape.unknown_shape(), tensor_shape.unknown_shape()]) self.assertEqual(r[1].eval(), 65536.0) r = tf.gradients(r, x)[0] diff --git a/tensorflow/python/kernel_tests/cwise_ops_test.py b/tensorflow/python/kernel_tests/cwise_ops_test.py index e5406ff87adadd5512954da81a9cd243ddf14221..0890ea4a2afc74d02c796679f1ced175a89302ce 100644 --- a/tensorflow/python/kernel_tests/cwise_ops_test.py +++ b/tensorflow/python/kernel_tests/cwise_ops_test.py @@ -992,13 +992,34 @@ class BinaryOpTest(tf.test.TestCase): def testZeroPowGrad(self): with self.test_session(): - for dtype in np.float16, np.float32, np.float64: + for dtype in (np.float16, np.float32, np.float64, np.complex64, + np.complex128): x = tf.constant(0.0, dtype=dtype) y = tf.constant(2.0, dtype=dtype) z = tf.pow(x, y) error = tf.test.compute_gradient_error(y, [], z, []) self.assertEqual(error, 0) + def testComplexPowGradPositiveBase(self): + with self.test_session(): + for dtype in np.complex64, np.complex128: + x = tf.constant(2.0, dtype=dtype) + y = tf.constant(2.0, dtype=dtype) + z = tf.pow(x, y) + error = tf.test.compute_gradient_error(y, [], z, []) + self.assertLess(error, 1e-4) + + def testComplexPowGradNegativeBase(self): + with self.test_session() as session: + for dtype in np.complex64, np.complex128: + x = tf.constant(-2.0, dtype=dtype) + y = tf.constant(2.0, dtype=dtype) + z = tf.pow(x, y) + expected_x_grad = -4 + expected_y_grad = (-2)**2 * (np.log(2) + np.pi * 1j) + self.assertAllClose([expected_x_grad, expected_y_grad], + session.run(tf.gradients(z, [x, y]))) + class ComparisonOpTest(tf.test.TestCase): diff --git a/tensorflow/python/kernel_tests/matmul_op_test.py b/tensorflow/python/kernel_tests/matmul_op_test.py index aefcde0b89e4da99b574df4c109f8097daabcf9f..e6d39609807245caf836e5d0be8dd3d225bbdaf1 100644 --- a/tensorflow/python/kernel_tests/matmul_op_test.py +++ b/tensorflow/python/kernel_tests/matmul_op_test.py @@ -283,11 +283,35 @@ class MatMulTest(tf.test.TestCase): b = tf.placeholder(tf.float32, [36, 2]) c = tf.placeholder(tf.float32, [37]) with self.assertRaisesRegexp( - ValueError, "Dimensions 37 and 36 are not compatible"): + ValueError, "Dimensions must be equal, but are 37 and 36"): tf.matmul(a, b) - with self.assertRaisesRegexp(ValueError, "must have rank 2"): + with self.assertRaisesRegexp(ValueError, "must be rank 2"): tf.matmul(a, c) + def testShapeInference(self): + """Tests common_shapes.call_cpp_shape_fn.""" + a = tf.constant([2] * 6, shape=[3, 2]) + b = tf.constant([2] * 2, shape=[2, 1]) + mm = tf.matmul(a, b) + self.assertEqual([3, 1], mm.get_shape()) + + # Transpose arguments are respected. + a = tf.constant([2] * 6, shape=[2, 3]) + b = tf.constant([2] * 2, shape=[1, 2]) + mm = tf.matmul(a, b, transpose_a=True, transpose_b=True) + self.assertEqual([3, 1], mm.get_shape()) + + # Unknown dims come through in output. + a = tf.placeholder(np.float32) + b = tf.placeholder(np.float32) + mm = tf.matmul(a, b) + self.assertEqual([None, None], mm.get_shape().as_list()) + + a = tf.constant([1] * 6, shape=[2, 3]) + b = tf.constant([2] * 2, shape=[1, 2]) + with self.assertRaisesRegexp(ValueError, ".*must be equal.*"): + tf.matmul(a, b, transpose_a=False, transpose_b=True) + # TODO(zhifengc): Figures out how to test matmul gradients on GPU. class MatMulGradientTest(tf.test.TestCase): diff --git a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py index ad2a52cd437919951ed7677aa03425fc3064f1cf..15ebd4042c56f72650548de2702f66cf1be31e44 100644 --- a/tensorflow/python/kernel_tests/padding_fifo_queue_test.py +++ b/tensorflow/python/kernel_tests/padding_fifo_queue_test.py @@ -1483,5 +1483,55 @@ class PaddingFIFOQueueTest(tf.test.TestCase): tf.PaddingFIFOQueue(32, [tf.float32], [tf.TensorShape(None)]) +class QueueFromListTest(tf.test.TestCase): + + def testQueueFromListShapes(self): + which = tf.constant(1) + def _cmp(expected, *shapes): + qs = [ + tf.PaddingFIFOQueue(10, [tf.float32], [tf.TensorShape(s)]) + for s in shapes] + s_expected = tf.TensorShape(expected) + s = tf.QueueBase.from_list(which, qs).shapes[0] + if s_expected.ndims is None: + self.assertEqual(s_expected.ndims, s.ndims) + else: + self.assertEqual(s_expected.as_list(), s.as_list()) + + _cmp(None, [1, None], [None]) + _cmp([None], [1], [2]) + _cmp([1, None], [1, 1], [1, 2]) + _cmp([1, None], [1, 1], [1, None]) + _cmp([None, None], [None, 1], [1, None]) + _cmp([1], [1], [1], [1]) + _cmp([None], [1], [None], [1]) + _cmp(None, [1, None], [1], [1]) + + def testQueueFromListShapesMultipleComponents(self): + q_u_u = tf.PaddingFIFOQueue( + 10, + [tf.float32, tf.int32], + [tf.TensorShape([None]), tf.TensorShape([None])]) + q_u_f = tf.PaddingFIFOQueue( + 10, [tf.float32, tf.int32], + [tf.TensorShape([None]), tf.TensorShape([1, 2])]) + q_f_f = tf.PaddingFIFOQueue( + 10, [tf.float32, tf.int32], + [tf.TensorShape([3, 4]), tf.TensorShape([1, 2])]) + which = tf.constant(1) + + s_cmp_1 = tf.QueueBase.from_list(which, [q_u_u, q_u_u, q_u_u]).shapes + self.assertEqual([1, 1], [x.ndims for x in s_cmp_1]) + self.assertEqual([None, None], [x.as_list()[0] for x in s_cmp_1]) + + s_cmp_2 = tf.QueueBase.from_list(which, [q_u_u, q_u_u, q_u_f]).shapes + self.assertEqual([1, None], [x.ndims for x in s_cmp_2]) + self.assertEqual([None], s_cmp_2[0].as_list()) + + s_cmp_3 = tf.QueueBase.from_list(which, [q_f_f, q_f_f]).shapes + self.assertEqual([2, 2], [x.ndims for x in s_cmp_3]) + self.assertEqual([[3, 4], [1, 2]], [x.as_list() for x in s_cmp_3]) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/python/kernel_tests/partitioned_variables_test.py b/tensorflow/python/kernel_tests/partitioned_variables_test.py index a16ac20cc06ae070d9078d462b356efafc8bbb45..fda8264bbca01a1d7976431cf167ce1751541b14 100644 --- a/tensorflow/python/kernel_tests/partitioned_variables_test.py +++ b/tensorflow/python/kernel_tests/partitioned_variables_test.py @@ -25,6 +25,16 @@ import tensorflow as tf class PartitionerCreatorsTest(tf.test.TestCase): + def testFixedSizePartitioner(self): + with self.test_session(): + partitioner = tf.fixed_size_partitioner(5, axis=0) + with tf.variable_scope("root", partitioner=partitioner): + v0 = tf.get_variable("v0", dtype=tf.float32, shape=(10, 10)) + v0_list = v0._get_variable_list() + v0_part = v0._get_partitions() + self.assertEqual(len(v0_list), 5) + self.assertAllEqual(v0_part, (5, 1)) + def _testVariableAxisSizePartitioner(self, name, axis, max_shard_bytes, expected_axis_shards, expected_partitions, @@ -219,7 +229,7 @@ class PartitionerCreatorsTest(tf.test.TestCase): expected_partitions=[4, 1, 1]) -def _IotaInitializer(shape, dtype=tf.float32): +def _IotaInitializer(shape, dtype=tf.float32, partition_info=None): assert dtype == tf.float32 if len(shape) == 1: return range(shape[0]) @@ -456,6 +466,51 @@ class PartitionedVariablesTestCase(tf.test.TestCase): tf.create_partitioned_variables( [10, 43], [1, 50], rnd.initialized_value()) + def testControlDepsNone(self): + with self.test_session() as session: + c = tf.constant(1.0) + with tf.control_dependencies([c]): + # d get the control dependency. + d = tf.constant(2.0) + # Partitioned variables do not. + var_x = tf.get_variable( + "x", + initializer=tf.ones_initializer([2]), + partitioner=tf.variable_axis_size_partitioner(4)) + + ops_before_read = session.graph.get_operations() + var_x.as_tensor() # Caches the ops for subsequent reads. + reading_ops = [op for op in session.graph.get_operations() + if op not in ops_before_read] + + self.assertEqual([c.op], d.op.control_inputs) + # Tests that no control dependencies are added to reading a partitioned + # variable which is similar to reading a variable. + for op in reading_ops: + self.assertEqual([], op.control_inputs) + + def testConcat(self): + with self.test_session() as session: + var_x = tf.get_variable( + "x", + initializer=tf.constant([1., 2.]), + partitioner=tf.variable_axis_size_partitioner(4)) + + c = tf.constant(1.0) + with tf.control_dependencies([c]): + ops_before_concat = session.graph.get_operations() + value = var_x.concat() + concat_ops = [op for op in session.graph.get_operations() + if op not in ops_before_concat] + + concat_control_inputs = [ci for op in concat_ops + for ci in op.control_inputs] + self.assertTrue( + c.op in concat_control_inputs, + "var_x.concat() should get control dependencies from its scope.") + tf.initialize_all_variables().run() + self.assertAllClose(value.eval(), var_x.as_tensor().eval()) + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/python/kernel_tests/random_ops_test.py b/tensorflow/python/kernel_tests/random_ops_test.py index e9f2dde6ebb4df13f665a0a5bb85bc5b0f1fe965..046a23acc51c7c441d677339efaf2c582946ebdf 100644 --- a/tensorflow/python/kernel_tests/random_ops_test.py +++ b/tensorflow/python/kernel_tests/random_ops_test.py @@ -40,18 +40,17 @@ class RandomNormalTest(tf.test.TestCase): # to see the same sequence of values. Will catch buggy # implementations which uses the same random number seed. def testDistinct(self): - for use_gpu in [False, True]: - for dt in tf.float16, tf.float32, tf.float64: - sampler = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu) - x = sampler() - y = sampler() - # Number of different samples. - count = (x == y).sum() - if count >= 10: - print("x = ", x) - print("y = ", y) - print("count = ", count) - self.assertTrue(count < 10) + for dt in tf.float16, tf.float32, tf.float64: + sampler = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True) + x = sampler() + y = sampler() + # Number of different samples. + count = (x == y).sum() + if count >= 10: + print("x = ", x) + print("y = ", y) + print("count = ", count) + self.assertTrue(count < 10) # Checks that the CPU and GPU implementation returns the same results, # given the same random seed @@ -67,11 +66,10 @@ class RandomNormalTest(tf.test.TestCase): self.assertAllClose(results[False], results[True], rtol=1e-6, atol=1e-6) def testSeed(self): - for use_gpu in [False, True]: - for dt in tf.float16, tf.float32, tf.float64: - sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu, seed=345) - sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu, seed=345) - self.assertAllEqual(sx(), sy()) + for dt in tf.float16, tf.float32, tf.float64: + sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) + sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) + self.assertAllEqual(sx(), sy()) def testNoCSE(self): for use_gpu in [False, True]: @@ -101,9 +99,9 @@ class TruncatedNormalTest(tf.test.TestCase): # implementations which uses the same random number seed. def testDistinct(self): # NOTE: TruncatedNormal on GPU is not supported. - for use_gpu in [False]: + if not tf.test.is_gpu_available(): for dt in tf.float16, tf.float32, tf.float64: - sampler = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu) + sampler = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=False) x = sampler() y = sampler() # Number of different samples. @@ -131,31 +129,28 @@ class TruncatedNormalTest(tf.test.TestCase): self.assertAllClose(results[False], results[True], rtol=1e-6, atol=1e-6) def testSeed(self): - for use_gpu in [False, True]: - for dt in tf.float16, tf.float32, tf.float64: - sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu, seed=345) - sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=use_gpu, seed=345) - self.assertAllEqual(sx(), sy()) + for dt in tf.float16, tf.float32, tf.float64: + sx = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) + sy = self._Sampler(1000, 0.0, 1.0, dt, use_gpu=True, seed=345) + self.assertAllEqual(sx(), sy()) # The effective standard deviation of truncated normal is 85% of the # requested one. def testStdDev(self): - for use_gpu in [False, True]: - for dt in tf.float16, tf.float32, tf.float64: - stddev = 3.0 - sampler = self._Sampler(100000, 0.0, stddev, dt, use_gpu=use_gpu) - x = sampler() - print("std(x)", np.std(x), abs(np.std(x) / stddev - 0.85)) - self.assertTrue(abs(np.std(x) / stddev - 0.85) < 0.04) + for dt in tf.float16, tf.float32, tf.float64: + stddev = 3.0 + sampler = self._Sampler(100000, 0.0, stddev, dt, use_gpu=True) + x = sampler() + print("std(x)", np.std(x), abs(np.std(x) / stddev - 0.85)) + self.assertTrue(abs(np.std(x) / stddev - 0.85) < 0.04) def testNoCSE(self): - for use_gpu in [False, True]: - with self.test_session(use_gpu=use_gpu): - shape = [2, 3, 4] - rnd1 = tf.truncated_normal(shape, 0.0, 1.0, tf.float32) - rnd2 = tf.truncated_normal(shape, 0.0, 1.0, tf.float32) - diff = rnd2 - rnd1 - self.assertTrue(np.linalg.norm(diff.eval()) > 0.1) + with self.test_session(use_gpu=True): + shape = [2, 3, 4] + rnd1 = tf.truncated_normal(shape, 0.0, 1.0, tf.float32) + rnd2 = tf.truncated_normal(shape, 0.0, 1.0, tf.float32) + diff = rnd2 - rnd1 + self.assertTrue(np.linalg.norm(diff.eval()) > 0.1) class RandomUniformTest(tf.test.TestCase): @@ -172,32 +167,30 @@ class RandomUniformTest(tf.test.TestCase): return func def testRange(self): - for use_gpu in False, True: - for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: - sampler = self._Sampler(1000, minv=-2, maxv=8, dtype=dt, - use_gpu=use_gpu) - x = sampler() - self.assertTrue(-2 <= np.min(x)) - self.assertTrue(np.max(x) < 8) + for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: + sampler = self._Sampler(1000, minv=-2, maxv=8, dtype=dt, + use_gpu=True) + x = sampler() + self.assertTrue(-2 <= np.min(x)) + self.assertTrue(np.max(x) < 8) # Asserts that different trials (1000 samples per trial) is unlikely # to see the same sequence of values. Will catch buggy # implementations which uses the same random number seed. def testDistinct(self): - for use_gpu in False, True: - for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: - maxv = 1.0 if dt.is_floating else 1 << 30 - sampler = self._Sampler(1000, minv=0, maxv=maxv, dtype=dt, - use_gpu=use_gpu) - x = sampler() - y = sampler() - count = (x == y).sum() - count_limit = 50 if dt == tf.float16 else 10 - if count >= count_limit: - print("x = ", x) - print("y = ", y) - print("count = ", count) - self.assertTrue(count < count_limit) + for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: + maxv = 1.0 if dt.is_floating else 1 << 30 + sampler = self._Sampler(1000, minv=0, maxv=maxv, dtype=dt, + use_gpu=True) + x = sampler() + y = sampler() + count = (x == y).sum() + count_limit = 50 if dt == tf.float16 else 10 + if count >= count_limit: + print("x = ", x) + print("y = ", y) + print("count = ", count) + self.assertTrue(count < count_limit) # Check that uniform ints actually follow a uniform distribution. def testUniformInts(self): @@ -208,19 +201,18 @@ class RandomUniformTest(tf.test.TestCase): # The counts should follow an (n, p) binomial distribution. mean = p * n std = np.sqrt(n * p * (1 - p)) - for use_gpu in False, True: - for dt in tf.int32, tf.int64: - # Use a fixed seed here to make the test deterministic. - # Without the fixed seed, the 5 * std bound will (very rarely) fail. - sampler = self._Sampler(n // 10, minv=minv, maxv=maxv, dtype=dt, - use_gpu=use_gpu, seed=17) - x = sampler().ravel() - self.assertEqual(x.shape, (n,)) - counts, _ = np.histogram(x, bins=maxv - minv) - self.assertEqual(counts.shape, (maxv - minv,)) - self.assertEqual(counts.sum(), n) - error = np.abs(counts - mean) - self.assertLess(error.max(), 5 * std) + for dt in tf.int32, tf.int64: + # Use a fixed seed here to make the test deterministic. + # Without the fixed seed, the 5 * std bound will (very rarely) fail. + sampler = self._Sampler(n // 10, minv=minv, maxv=maxv, dtype=dt, + use_gpu=True, seed=17) + x = sampler().ravel() + self.assertEqual(x.shape, (n,)) + counts, _ = np.histogram(x, bins=maxv - minv) + self.assertEqual(counts.shape, (maxv - minv,)) + self.assertEqual(counts.sum(), n) + error = np.abs(counts - mean) + self.assertLess(error.max(), 5 * std) # Checks that the CPU and GPU implementation returns the same results, # given the same random seed @@ -235,22 +227,20 @@ class RandomUniformTest(tf.test.TestCase): self.assertAllEqual(results[False], results[True]) def testSeed(self): - for use_gpu in False, True: - for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: - for seed in [345, 2**100, -2**100]: - sx = self._Sampler(1000, 0, 17, dtype=dt, use_gpu=use_gpu, seed=seed) - sy = self._Sampler(1000, 0, 17, dtype=dt, use_gpu=use_gpu, seed=seed) - self.assertAllEqual(sx(), sy()) + for dt in tf.float16, tf.float32, tf.float64, tf.int32, tf.int64: + for seed in [345, 2**100, -2**100]: + sx = self._Sampler(1000, 0, 17, dtype=dt, use_gpu=True, seed=seed) + sy = self._Sampler(1000, 0, 17, dtype=dt, use_gpu=True, seed=seed) + self.assertAllEqual(sx(), sy()) def testNoCSE(self): shape = [2, 3, 4] - for use_gpu in False, True: - for dtype in tf.float16, tf.float32, tf.int32: - with self.test_session(use_gpu=use_gpu): - rnd1 = tf.random_uniform(shape, 0, 17, dtype=dtype) - rnd2 = tf.random_uniform(shape, 0, 17, dtype=dtype) - diff = (rnd2 - rnd1).eval() - self.assertTrue(np.linalg.norm(diff) > 0.1) + for dtype in tf.float16, tf.float32, tf.int32: + with self.test_session(use_gpu=True): + rnd1 = tf.random_uniform(shape, 0, 17, dtype=dtype) + rnd2 = tf.random_uniform(shape, 0, 17, dtype=dtype) + diff = (rnd2 - rnd1).eval() + self.assertTrue(np.linalg.norm(diff) > 0.1) class RandomShapeTest(tf.test.TestCase): diff --git a/tensorflow/python/kernel_tests/reverse_sequence_op_test.py b/tensorflow/python/kernel_tests/reverse_sequence_op_test.py index 48fbccd686aa27e20f86dcdc52b55e1ec37fd5a4..cea9711d322e7a1f8aa57c0bbde2b8c3f0093522 100644 --- a/tensorflow/python/kernel_tests/reverse_sequence_op_test.py +++ b/tensorflow/python/kernel_tests/reverse_sequence_op_test.py @@ -47,7 +47,7 @@ class ReverseSequenceTest(tf.test.TestCase): self._testReverseSequence(x, batch_dim, seq_dim, seq_lengths, truth, False, expected_err_re) - def _testBasic(self, dtype): + def _testBasic(self, dtype, len_dtype=np.int64): x = np.asarray([ [[1, 2, 3, 4], [5, 6, 7, 8]], [[9, 10, 11, 12], [13, 14, 15, 16]], @@ -56,7 +56,7 @@ class ReverseSequenceTest(tf.test.TestCase): x = x.transpose([2, 1, 0, 3, 4]) # permute axes 0 <=> 2 # reverse dim 2 up to (0:3, none, 0:4) along dim=0 - seq_lengths = np.asarray([3, 0, 4], dtype=np.int64) + seq_lengths = np.asarray([3, 0, 4], dtype=len_dtype) truth_orig = np.asarray( [[[3, 2, 1, 4], [7, 6, 5, 8]], # reverse 0:3 @@ -70,6 +70,9 @@ class ReverseSequenceTest(tf.test.TestCase): batch_dim = 2 self._testBothReverseSequence(x, batch_dim, seq_dim, seq_lengths, truth) + def testSeqLenghtInt32(self): + self._testBasic(np.float32, np.int32) + def testFloatBasic(self): self._testBasic(np.float32) diff --git a/tensorflow/python/kernel_tests/scan_ops_test.py b/tensorflow/python/kernel_tests/scan_ops_test.py index 4db5cf51c4e73296f3e47f2063c35a919f61aa50..677dac8cdab8714682f0c9af44d95850cd4bb1e8 100644 --- a/tensorflow/python/kernel_tests/scan_ops_test.py +++ b/tensorflow/python/kernel_tests/scan_ops_test.py @@ -71,6 +71,11 @@ class CumsumTest(tf.test.TestCase): for reverse in [True, False]: self._compare(x, axis, exclusive, reverse) + def testEmpty(self): + for dtype in self.valid_dtypes: + x = np.zeros([0]).astype(dtype) + self._compareAll(x, 0) + def test1D(self): for dtype in self.valid_dtypes: x = np.arange(1, 6).reshape([5]).astype(dtype) @@ -155,6 +160,10 @@ class CumprodTest(tf.test.TestCase): for reverse in [True, False]: self._compare(x, axis, exclusive, reverse) + def testEmpty(self): + for dtype in self.valid_dtypes: + x = np.zeros([0]).astype(dtype) + self._compareAll(x, 0) def test1D(self): for dtype in self.valid_dtypes: diff --git a/tensorflow/python/kernel_tests/softplus_op_test.py b/tensorflow/python/kernel_tests/softplus_op_test.py index 348e898343055740576161ad7f8def0f05db86fb..6223cacf61a1103abde6731f23a7acc20f0ff46b 100644 --- a/tensorflow/python/kernel_tests/softplus_op_test.py +++ b/tensorflow/python/kernel_tests/softplus_op_test.py @@ -25,24 +25,42 @@ import tensorflow as tf class SoftplusTest(tf.test.TestCase): def _npSoftplus(self, np_features): - return np.log(1 + np.exp(np_features)) + np_features = np.asarray(np_features) + zero = np.asarray(0).astype(np_features.dtype) + return np.logaddexp(zero, np_features) def _testSoftplus(self, np_features, use_gpu=False): np_softplus = self._npSoftplus(np_features) with self.test_session(use_gpu=use_gpu): softplus = tf.nn.softplus(np_features) tf_softplus = softplus.eval() - self.assertAllClose(np_softplus, tf_softplus) + self.assertAllCloseAccordingToType(np_softplus, tf_softplus) + self.assertTrue(np.all(tf_softplus > 0)) self.assertShapeEqual(np_softplus, softplus) def testNumbers(self): - for t in [np.float, np.double]: + for t in [np.float16, np.float32, np.float64]: self._testSoftplus( np.array([[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]]).astype(t), use_gpu=False) self._testSoftplus( np.array([[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]]).astype(t), use_gpu=True) + log_eps = np.log(np.finfo(t).eps) + one = t(1) + ten = t(10) + self._testSoftplus( + [log_eps, log_eps - one, log_eps + one, + log_eps - ten, log_eps + ten, + -log_eps, -log_eps - one, -log_eps + one, + -log_eps - ten, -log_eps + ten], + use_gpu=False) + self._testSoftplus( + [log_eps, log_eps - one, log_eps + one, + log_eps - ten, log_eps + ten + -log_eps, -log_eps - one, -log_eps + one, + -log_eps - ten, -log_eps + ten], + use_gpu=True) def testGradient(self): with self.test_session(): diff --git a/tensorflow/python/kernel_tests/sparse_ops_test.py b/tensorflow/python/kernel_tests/sparse_ops_test.py index 29b57e80944ed21e52c7359878b2e92db55dc3b1..d945af0081c54d4f5ad02f6836241f64c856dbb8 100644 --- a/tensorflow/python/kernel_tests/sparse_ops_test.py +++ b/tensorflow/python/kernel_tests/sparse_ops_test.py @@ -743,5 +743,28 @@ class SparseMinimumMaximumTest(test_util.TensorFlowTestCase): tf.sparse_maximum(sp_zero, sp_one).eval() +class SparseTransposeTest(tf.test.TestCase): + + def _SparseTensorPlaceholder(self): + return tf.SparseTensor( + tf.placeholder(tf.int64), + tf.placeholder(tf.float64), + tf.placeholder(tf.int64)) + + def testTranspose(self): + with self.test_session(use_gpu=False) as sess: + np.random.seed(1618) + shapes = [np.random.randint(1, 10, size=rank) for rank in range(1, 6)] + for shape in shapes: + for dtype in [np.int32, np.int64, np.float32, np.float64]: + dn_input = np.random.randn(*shape).astype(dtype) + rank = tf.rank(dn_input).eval() + perm = np.random.choice(rank, rank, False) + sp_input, unused_a_nnz = _sparsify(dn_input) + sp_trans = tf.sparse_transpose(sp_input, perm=perm) + dn_trans = tf.sparse_tensor_to_dense(sp_trans).eval() + expected_trans = tf.transpose(dn_input, perm=perm).eval() + self.assertAllEqual(dn_trans, expected_trans) + if __name__ == "__main__": googletest.main() diff --git a/tensorflow/python/kernel_tests/stack_ops_test.py b/tensorflow/python/kernel_tests/stack_ops_test.py index 352a0e0f1c7f366f48a8f8afa92881835a3b154c..bad141e7a818669018252f635c1b004feaee9644 100644 --- a/tensorflow/python/kernel_tests/stack_ops_test.py +++ b/tensorflow/python/kernel_tests/stack_ops_test.py @@ -22,6 +22,7 @@ import numpy as np import tensorflow as tf from tensorflow.python.framework import errors +from tensorflow.python.framework import tensor_shape from tensorflow.python.ops import gen_data_flow_ops @@ -75,7 +76,8 @@ class StackOpTest(tf.test.TestCase): nx = tf.sub(x, 1) ny = y + gen_data_flow_ops._stack_pop(h, tf.float32) return [nx, ny] - rx, ry = tf.while_loop(c1, b1, [r, v]) + rx, ry = tf.while_loop(c1, b1, [r, v], + [r.get_shape(), tensor_shape.unknown_shape()]) self.assertAllClose(np.ones(2000) * 10.0, ry.eval()) def testStackWhileSwap(self): diff --git a/tensorflow/python/kernel_tests/tensor_array_ops_test.py b/tensorflow/python/kernel_tests/tensor_array_ops_test.py index e21a1995953fa4732c577023900e65ddfd242ecc..532e619d59b3bbd6824eb1d7da6840d3c420005a 100644 --- a/tensorflow/python/kernel_tests/tensor_array_ops_test.py +++ b/tensorflow/python/kernel_tests/tensor_array_ops_test.py @@ -171,6 +171,22 @@ class TensorArrayCPUTest(tf.test.TestCase): self.assertAllEqual(convert([2.0, 2.1]), d1) self.assertAllEqual(convert([3.0, 3.1]), d2) + # Reset ta because we're going to change the shape, else shape + # inference will throw an error. + ta = tensor_array_ops.TensorArray( + dtype=tf_dtype, tensor_array_name="foo", size=3) + + # Try unpacking an empty matrix, which should not cause an error. + w2 = ta.unpack(convert([[], [], []])) + r0 = w2.read(0) + r1 = w2.read(1) + r2 = w2.read(2) + + d0, d1, d2 = session.run([r0, r1, r2]) + self.assertAllEqual(convert([]), d0) + self.assertAllEqual(convert([]), d1) + self.assertAllEqual(convert([]), d2) + def testTensorArrayUnpackRead(self): self._testTensorArrayUnpackRead(tf.float32) self._testTensorArrayUnpackRead(tf.float64) @@ -720,6 +736,9 @@ class TensorArrayCPUTest(tf.test.TestCase): cond=lambda time, unused_1, unused_2: time < 3, body=body, loop_vars=(time_0, ta, state0), + shape_invariants=(time_0.get_shape(), + tensor_shape.unknown_shape(), + tensor_shape.unknown_shape()), parallel_iterations=3) vout = h_final.pack() diff --git a/tensorflow/python/kernel_tests/transpose_op_test.py b/tensorflow/python/kernel_tests/transpose_op_test.py index 4b47cb9fa241a71236c46ca759911c7dce3b767e..ec8a41f59c1c40bc75b99c7588a7b98682b07b58 100644 --- a/tensorflow/python/kernel_tests/transpose_op_test.py +++ b/tensorflow/python/kernel_tests/transpose_op_test.py @@ -122,6 +122,13 @@ class TransposeTest(tf.test.TestCase): self._compareCpu(np.arange(0, 8).reshape([2, 4]).astype(np.float32), np.array([1, 0]).astype(np.int32)) + def testHalf(self): + self._compare(np.arange(0, 21).reshape([3, 7]).astype(np.float16)) + self._compare( + np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.float16)) + self._compare( + np.arange(0, 16).reshape([1, 2, 1, 2, 1, 2, 1, 2]).astype(np.float16)) + def testFloat(self): self._compare_cpu_gpu(np.arange(0, 21).reshape([3, 7]).astype(np.float32)) self._compare_cpu_gpu( diff --git a/tensorflow/python/kernel_tests/variable_scope_test.py b/tensorflow/python/kernel_tests/variable_scope_test.py index ff9716438ac5da02df4bfcab6a8a9685bd163e1b..bce249d8c5e2c35660356102da96a439f0d2322e 100644 --- a/tensorflow/python/kernel_tests/variable_scope_test.py +++ b/tensorflow/python/kernel_tests/variable_scope_test.py @@ -751,5 +751,63 @@ class VariableScopeWithCustomGetterTest(tf.test.TestCase): np_vars, np_v = sess.run([true_vars, v]) self.assertAllClose(np_v, sum(np_vars)) + +class PartitionInfoTest(tf.test.TestCase): + + def testConstructorChecks(self): + # Invalid arg types. + with self.assertRaises(TypeError): + variable_scope._PartitionInfo(full_shape=None, var_offset=[0, 1]) + with self.assertRaises(TypeError): + variable_scope._PartitionInfo(full_shape=[0, 1], var_offset=None) + with self.assertRaises(TypeError): + variable_scope._PartitionInfo(full_shape="foo", var_offset=[0, 1]) + with self.assertRaises(TypeError): + variable_scope._PartitionInfo(full_shape=[0, 1], var_offset="foo") + + # full_shape and var_offset must have same length. + with self.assertRaises(ValueError): + variable_scope._PartitionInfo(full_shape=[0, 1], var_offset=[0]) + # Offset must always be less than shape. + with self.assertRaises(ValueError): + variable_scope._PartitionInfo(full_shape=[1, 1], var_offset=[0, 1]) + + def testSingleOffset(self): + partition_info = variable_scope._PartitionInfo( + full_shape=[9, 3], var_offset=[4, 0]) + self.assertEqual(4, partition_info.single_offset([1, 3])) + + # Tests when the variable isn't partitioned at all. + partition_info = variable_scope._PartitionInfo( + full_shape=[9, 3], var_offset=[0, 0]) + self.assertEqual(0, partition_info.single_offset([9, 3])) + + def testSingleSliceDim(self): + partition_info = variable_scope._PartitionInfo( + full_shape=[9, 3], var_offset=[4, 0]) + # Invalid shape. + with self.assertRaises(TypeError): + partition_info.single_slice_dim(None) + + # Rank of shape differs from full_shape. + with self.assertRaises(ValueError): + partition_info.single_slice_dim([1, 2, 3]) + + # Shape is too large given var_offset (4+6 > 9). + with self.assertRaises(ValueError): + partition_info.single_slice_dim([6, 3]) + + # Multiple possible slice dim from shape. + with self.assertRaises(ValueError): + partition_info.single_slice_dim([1, 1]) + + partition_info = variable_scope._PartitionInfo( + full_shape=[9, 3], var_offset=[0, 0]) + self.assertEqual(1, partition_info.single_slice_dim([9, 2])) + partition_info = variable_scope._PartitionInfo( + full_shape=[9, 3], var_offset=[4, 0]) + self.assertEqual(0, partition_info.single_slice_dim([2, 3])) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/python/lib/io/file_io.i b/tensorflow/python/lib/io/file_io.i index 4e1c2aba69ddac63f24167ebafa1656b94d8f1aa..132894cf7a6c70a8ffd7bf71c57f33431510f128 100644 --- a/tensorflow/python/lib/io/file_io.i +++ b/tensorflow/python/lib/io/file_io.i @@ -21,6 +21,9 @@ limitations under the License. #include "tensorflow/core/framework/types.h" #include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/lib/core/stringpiece.h" +#include "tensorflow/core/lib/io/buffered_inputstream.h" +#include "tensorflow/core/lib/io/inputstream_interface.h" +#include "tensorflow/core/lib/io/random_inputstream.h" #include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/io/match.h" #include "tensorflow/core/platform/env.h" @@ -155,6 +158,20 @@ void Stat(const string& filename, FileStatistics* stats, Set_TF_Status_from_Status(out_status, status); } } + +tensorflow::io::BufferedInputStream* CreateBufferedInputStream( + const string& filename, size_t buffer_size) { + std::unique_ptr file; + if (!tensorflow::Env::Default()->NewRandomAccessFile(filename, &file).ok()) { + return nullptr; + } + std::unique_ptr input_stream( + new tensorflow::io::RandomAccessInputStream(file.release())); + std::unique_ptr buffered_input_stream( + new tensorflow::io::BufferedInputStream(input_stream.release(), + buffer_size)); + return buffered_input_stream.release(); +} %} // Wrap the above functions. @@ -174,6 +191,15 @@ void DeleteRecursively(const string& dirname, TF_Status* out_status); bool IsDirectory(const string& dirname, TF_Status* out_status); void Stat(const string& filename, tensorflow::FileStatistics* stats, TF_Status* out_status); +tensorflow::io::BufferedInputStream* CreateBufferedInputStream( + const string& filename, size_t buffer_size); + +%ignoreall +%unignore tensorflow::io::BufferedInputStream; +%unignore tensorflow::io::BufferedInputStream::ReadLineAsString; +%include "tensorflow/core/lib/io/inputstream_interface.h" +%include "tensorflow/core/lib/io/buffered_inputstream.h" +%unignoreall %include "tensorflow/core/lib/io/path.h" %include "tensorflow/core/platform/file_statistics.h" diff --git a/tensorflow/python/lib/io/file_io.py b/tensorflow/python/lib/io/file_io.py index bca92aeaa939c80c04f1d4570193ad925a6c53cf..f5b138c9dac798b56fb1f5262eeee8defcf780cb 100644 --- a/tensorflow/python/lib/io/file_io.py +++ b/tensorflow/python/lib/io/file_io.py @@ -28,6 +28,109 @@ from tensorflow.python.framework import errors from tensorflow.python.util import compat +class FileIO(object): + """FileIO class that exposes methods to read / write to / from files. + + The constructor takes the following arguments: + name: name of the file + mode: one of 'r', 'w', 'a', 'r+', 'w+', 'a+'. + + Can be used as an iterator to iterate over lines in the file. + + The default buffer size used for the BufferedInputStream used for reading + the file line by line is 1024 * 512 bytes. + """ + + def __init__(self, name, mode): + self.__name = name + self.__mode = mode + self._read_buf = None + if mode not in ("r", "w", "a", "r+", "w+", "a+"): + raise errors.InvalidArgumentError( + None, None, "mode is not 'r' or 'w' or 'a' or 'r+' or 'w+' or 'a+'") + self._read_check_passed = mode in ("r", "r+", "a+", "w+") + self._write_check_passed = mode in ("a", "w", "r+", "a+", "w+") + + @property + def name(self): + """Returns the file name.""" + return self.__name + + @property + def mode(self): + """Returns the mode in which the file was opened.""" + return self.__mode + + def _prereadline_check(self): + if not self._read_buf: + if not self._read_check_passed: + raise errors.PermissionDeniedError(None, None, + "File isn't open for reading") + self._read_buf = pywrap_tensorflow.CreateBufferedInputStream( + compat.as_bytes(self.__name), 1024 * 512) + if not self._read_buf: + raise errors.InternalError(None, None, + "Could not open file for streaming") + + def size(self): + """Returns the size of the file.""" + return stat(self.__name).length + + def write(self, file_content): + """Writes file_content to the file.""" + if not self._write_check_passed: + raise errors.PermissionDeniedError(None, None, + "File isn't open for writing") + with errors.raise_exception_on_not_ok_status() as status: + pywrap_tensorflow.WriteStringToFile( + compat.as_bytes(self.__name), compat.as_bytes(file_content), status) + + def read(self): + """Returns the contents of a file as a string.""" + if not self._read_check_passed: + raise errors.PermissionDeniedError(None, None, + "File isn't open for reading") + with errors.raise_exception_on_not_ok_status() as status: + return pywrap_tensorflow.ReadFileToString( + compat.as_bytes(self.__name), status) + + def readline(self): + r"""Reads the next line from the file. Leaves the '\n' at the end.""" + self._prereadline_check() + return self._read_buf.ReadLineAsString() + + def readlines(self): + """Returns all lines from the file in a list.""" + self._prereadline_check() + lines = [] + while True: + s = self.readline() + if not s: + break + lines.append(s) + return lines + + def __enter__(self): + """Make usable with "with" statement.""" + return self + + def __exit__(self, unused_type, unused_value, unused_traceback): + """Make usable with "with" statement.""" + self._read_buf = None + + def __iter__(self): + return self + + def next(self): + retval = self.readline() + if not retval: + raise StopIteration() + return retval + + def __next__(self): + return self.next() + + def file_exists(filename): """Determines whether a path exists or not. @@ -67,8 +170,8 @@ def read_file_to_string(filename): errors.OpError: Raises variety of errors that are subtypes e.g. NotFoundError etc. """ - with errors.raise_exception_on_not_ok_status() as status: - return pywrap_tensorflow.ReadFileToString(compat.as_bytes(filename), status) + f = FileIO(filename, mode="r") + return f.read() def write_string_to_file(filename, file_content): @@ -81,9 +184,8 @@ def write_string_to_file(filename, file_content): Raises: errors.OpError: If there are errors during the operation. """ - with errors.raise_exception_on_not_ok_status() as status: - pywrap_tensorflow.WriteStringToFile( - compat.as_bytes(filename), compat.as_bytes(file_content), status) + f = FileIO(filename, mode="w") + f.write(file_content) def get_matching_files(filename): @@ -133,9 +235,9 @@ def recursive_create_dir(dirname): errors.OpError: If the operation fails. """ with errors.raise_exception_on_not_ok_status() as status: - dirs = dirname.split('/') + dirs = dirname.split("/") for i in range(len(dirs)): - partial_dir = '/'.join(dirs[0:i + 1]) + partial_dir = "/".join(dirs[0:i + 1]) if partial_dir and not file_exists(partial_dir): pywrap_tensorflow.CreateDir(compat.as_bytes(partial_dir), status) @@ -219,8 +321,8 @@ def list_directory(dirname): errors.NotFoundError if directory doesn't exist """ if not is_directory(dirname): - raise errors.NotFoundError(None, None, 'Could not find directory') - file_list = get_matching_files(os.path.join(compat.as_str_any(dirname), '*')) + raise errors.NotFoundError(None, None, "Could not find directory") + file_list = get_matching_files(os.path.join(compat.as_str_any(dirname), "*")) return [compat.as_bytes(pywrap_tensorflow.Basename(compat.as_bytes(filename))) for filename in file_list] diff --git a/tensorflow/python/lib/io/file_io_test.py b/tensorflow/python/lib/io/file_io_test.py index f985f23d9ee1fce7e128af197c5ef35bda4a4641..a4cef8cb5a2e7ff5a263eba8c6547d16f9530b27 100644 --- a/tensorflow/python/lib/io/file_io_test.py +++ b/tensorflow/python/lib/io/file_io_test.py @@ -41,16 +41,28 @@ class FileIoTest(tf.test.TestCase): with self.assertRaises(errors.NotFoundError): _ = file_io.read_file_to_string(file_path) - def testFileWrite(self): + def testWriteToString(self): file_path = os.path.join(self._base_dir, "temp_file") file_io.write_string_to_file(file_path, "testing") self.assertTrue(file_io.file_exists(file_path)) file_contents = file_io.read_file_to_string(file_path) self.assertEqual(b"testing", file_contents) + def testFileWriteBadMode(self): + file_path = os.path.join(self._base_dir, "temp_file") + with self.assertRaises(errors.PermissionDeniedError): + file_io.FileIO(file_path, mode="r").write("testing") + + def testFileReadBadMode(self): + file_path = os.path.join(self._base_dir, "temp_file") + file_io.FileIO(file_path, mode="w").write("testing") + self.assertTrue(file_io.file_exists(file_path)) + with self.assertRaises(errors.PermissionDeniedError): + file_io.FileIO(file_path, mode="w").read() + def testFileDelete(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") file_io.delete_file(file_path) self.assertFalse(file_io.file_exists(file_path)) @@ -65,7 +77,7 @@ class FileIoTest(tf.test.TestCase): files = ["file1.txt", "file2.txt", "file3.txt"] for name in files: file_path = os.path.join(dir_path, name) - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") expected_match = [os.path.join(dir_path, name) for name in files] self.assertItemsEqual( file_io.get_matching_files(os.path.join(dir_path, "file*.txt")), @@ -77,14 +89,14 @@ class FileIoTest(tf.test.TestCase): dir_path = os.path.join(self._base_dir, "temp_dir/temp_dir1/temp_dir2") file_io.recursive_create_dir(dir_path) file_path = os.path.join(dir_path, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") self.assertTrue(file_io.file_exists(file_path)) file_io.delete_recursively(os.path.join(self._base_dir, "temp_dir")) self.assertFalse(file_io.file_exists(file_path)) def testCopy(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") copy_path = os.path.join(self._base_dir, "copy_file") file_io.copy(file_path, copy_path) self.assertTrue(file_io.file_exists(copy_path)) @@ -92,24 +104,24 @@ class FileIoTest(tf.test.TestCase): def testCopyOverwrite(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") copy_path = os.path.join(self._base_dir, "copy_file") - file_io.write_string_to_file(copy_path, "copy") + file_io.FileIO(copy_path, mode="w").write("copy") file_io.copy(file_path, copy_path, overwrite=True) self.assertTrue(file_io.file_exists(copy_path)) self.assertEqual(b"testing", file_io.read_file_to_string(file_path)) def testCopyOverwriteFalse(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") copy_path = os.path.join(self._base_dir, "copy_file") - file_io.write_string_to_file(copy_path, "copy") + file_io.FileIO(copy_path, mode="w").write("copy") with self.assertRaises(errors.AlreadyExistsError): file_io.copy(file_path, copy_path, overwrite=False) def testRename(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") rename_path = os.path.join(self._base_dir, "rename_file") file_io.rename(file_path, rename_path) self.assertTrue(file_io.file_exists(rename_path)) @@ -117,18 +129,18 @@ class FileIoTest(tf.test.TestCase): def testRenameOverwrite(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") rename_path = os.path.join(self._base_dir, "rename_file") - file_io.write_string_to_file(rename_path, "rename") + file_io.FileIO(rename_path, mode="w").write("rename") file_io.rename(file_path, rename_path, overwrite=True) self.assertTrue(file_io.file_exists(rename_path)) self.assertFalse(file_io.file_exists(file_path)) def testRenameOverwriteFalse(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") rename_path = os.path.join(self._base_dir, "rename_file") - file_io.write_string_to_file(rename_path, "rename") + file_io.FileIO(rename_path, mode="w").write("rename") with self.assertRaises(errors.AlreadyExistsError): file_io.rename(file_path, rename_path, overwrite=False) self.assertTrue(file_io.file_exists(rename_path)) @@ -147,7 +159,7 @@ class FileIoTest(tf.test.TestCase): file_io.create_dir(dir_path) self.assertTrue(file_io.is_directory(dir_path)) file_path = os.path.join(dir_path, "test_file") - file_io.write_string_to_file(file_path, "test") + file_io.FileIO(file_path, mode="w").write("test") # False for a file. self.assertFalse(file_io.is_directory(file_path)) @@ -157,11 +169,11 @@ class FileIoTest(tf.test.TestCase): files = [b"file1.txt", b"file2.txt", b"file3.txt"] for name in files: file_path = os.path.join(dir_path, compat.as_str_any(name)) - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") subdir_path = os.path.join(dir_path, "sub_dir") file_io.create_dir(subdir_path) subdir_file_path = os.path.join(subdir_path, "file4.txt") - file_io.write_string_to_file(subdir_file_path, "testing") + file_io.FileIO(subdir_file_path, mode="w").write("testing") dir_list = file_io.list_directory(dir_path) self.assertItemsEqual(files + [b"sub_dir"], dir_list) @@ -176,12 +188,14 @@ class FileIoTest(tf.test.TestCase): # subdir1_1 -> file: file3.txt # subdir1_2 -> dir: subdir2 file_io.create_dir(dir_path) - file_io.write_string_to_file(os.path.join(dir_path, "file1.txt"), "testing") + file_io.FileIO( + os.path.join(dir_path, "file1.txt"), mode="w").write("testing") sub_dirs1 = ["subdir1_1", "subdir1_2", "subdir1_3"] for name in sub_dirs1: file_io.create_dir(os.path.join(dir_path, name)) - file_io.write_string_to_file( - os.path.join(dir_path, "subdir1_1/file2.txt"), "testing") + file_io.FileIO( + os.path.join(dir_path, "subdir1_1/file2.txt"), + mode="w").write("testing") file_io.create_dir(os.path.join(dir_path, "subdir1_2/subdir2")) def testWalkInOrder(self): @@ -256,12 +270,48 @@ class FileIoTest(tf.test.TestCase): def testStat(self): file_path = os.path.join(self._base_dir, "temp_file") - file_io.write_string_to_file(file_path, "testing") + file_io.FileIO(file_path, mode="w").write("testing") file_statistics = file_io.stat(file_path) os_statistics = os.stat(file_path) self.assertEquals(7, file_statistics.length) self.assertEqual( int(os_statistics.st_mtime), int(file_statistics.mtime_nsec / 1e9)) + # 644 and 666 are the two possible default permissions of newly-created + # files. + self.assertTrue(file_statistics.mode in [0o100644, 0o100666]) + + def testReadLine(self): + file_path = os.path.join(self._base_dir, "temp_file") + f = file_io.FileIO(file_path, mode="r+") + f.write("testing1\ntesting2\ntesting3\n\ntesting5") + self.assertEqual(36, f.size()) + self.assertEqual(b"testing1\n", f.readline()) + self.assertEqual(b"testing2\n", f.readline()) + self.assertEqual(b"testing3\n", f.readline()) + self.assertEqual(b"\n", f.readline()) + self.assertEqual(b"testing5", f.readline()) + self.assertEqual(b"", f.readline()) + + def testReadingIterator(self): + file_path = os.path.join(self._base_dir, "temp_file") + f = file_io.FileIO(file_path, mode="r+") + data = ["testing1\n", "testing2\n", "testing3\n", "\n", "testing5"] + f.write("".join(data)) + actual_data = [] + for line in f: + actual_data.append(line) + self.assertSequenceEqual(actual_data, + [compat.as_bytes(item) for item in data]) + + def testReadlines(self): + file_path = os.path.join(self._base_dir, "temp_file") + f = file_io.FileIO(file_path, mode="r+") + data = ["testing1\n", "testing2\n", "testing3\n", "\n", "testing5"] + f.write("".join(data)) + lines = f.readlines() + self.assertSequenceEqual(lines, [compat.as_bytes(item) for item in data]) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 7e9a3cb115df02e4e66d303bc5d1215fd1e5c302..77487b65e42ccd37e8279ff1984209082b9ff82c 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -143,9 +143,6 @@ def shape_internal(input, name=None, optimize=True): else: input_tensor = ops.convert_to_tensor(input) input_shape = input_tensor.get_shape() - # Static shape inference can be incorrect when loops are involved: disable - # shape optimization in this case to avoid generating invalid constants. - optimize &= input_tensor.graph._get_control_flow_context() is None if optimize and input_shape.is_fully_defined(): return constant(input_shape.as_list(), dtypes.int32, name=name) return gen_array_ops.shape(input, name=name) @@ -192,9 +189,6 @@ def size_internal(input, name=None, optimize=True): else: input_tensor = ops.convert_to_tensor(input) input_shape = input_tensor.get_shape() - # Static shape inference can be incorrect when loops are involved: disable - # shape optimization in this case to avoid generating invalid constants. - optimize &= input_tensor.graph._get_control_flow_context() is None if optimize and input_shape.is_fully_defined(): return constant(input_shape.num_elements(), dtypes.int32, name=name) return gen_array_ops.size(input, name=name) @@ -244,9 +238,6 @@ def rank_internal(input, name=None, optimize=True): else: input_tensor = ops.convert_to_tensor(input) input_shape = input_tensor.get_shape() - # Static shape inference can be incorrect when loops are involved: disable - # shape optimization in this case to avoid generating invalid constants. - optimize &= input_tensor.graph._get_control_flow_context() is None if optimize and input_shape.ndims is not None: return constant(input_shape.ndims, dtypes.int32, name=name) return gen_array_ops.rank(input, name=name) @@ -254,7 +245,7 @@ def rank_internal(input, name=None, optimize=True): # DEPRECATED use init_ops.zeros_initializer # TODO(irving) Move it to init_ops.py -def zeros_initializer(shape, dtype=dtypes.float32): +def zeros_initializer(shape, dtype=dtypes.float32, partition_info=None): """An adaptor for zeros() to match the Initializer spec.""" return zeros(shape, dtype) @@ -1121,14 +1112,16 @@ def zeros(shape, dtype=dtypes.float32, name=None): Returns: A `Tensor` with all elements set to zero. """ + dtype = dtypes.as_dtype(dtype).base_dtype with ops.name_scope(name, "zeros", [shape]) as name: + zero = False if dtype == dtypes.bool else 0 try: shape = tensor_shape.as_shape(shape) - output = constant(0, shape=shape, dtype=dtype, name=name) + output = constant(zero, shape=shape, dtype=dtype, name=name) except (TypeError, ValueError): shape = ops.convert_to_tensor(shape, dtype=dtypes.int32, name="shape") - output = fill(shape, constant(0, dtype=dtype), name=name) - assert output.dtype.base_dtype == dtypes.as_dtype(dtype).base_dtype + output = fill(shape, constant(zero, dtype=dtype), name=name) + assert output.dtype.base_dtype == dtype return output @@ -1184,7 +1177,8 @@ def ones_like(tensor, dtype=None, name=None, optimize=True): Args: tensor: A `Tensor`. dtype: A type for the returned `Tensor`. Must be `float32`, `float64`, - `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, or `complex128`. + `int8`, `int16`, `int32`, `int64`, `uint8`, `complex64`, `complex128` or + `bool`. name: A name for the operation (optional). optimize: if true, attempt to statically determine the shape of 'tensor' and encode it as a constant. @@ -1222,14 +1216,16 @@ def ones(shape, dtype=dtypes.float32, name=None): Returns: A `Tensor` with all elements set to 1. """ + dtype = dtypes.as_dtype(dtype).base_dtype with ops.name_scope(name, "ones", [shape]) as name: + one = True if dtype == dtypes.bool else 1 try: shape = tensor_shape.as_shape(shape) - output = constant(1, shape=shape, dtype=dtype, name=name) + output = constant(one, shape=shape, dtype=dtype, name=name) except (TypeError, ValueError): shape = ops.convert_to_tensor(shape, dtype=dtypes.int32, name="shape") - output = fill(shape, constant(1, dtype=dtype), name=name) - assert output.dtype.base_dtype == dtypes.as_dtype(dtype).base_dtype + output = fill(shape, constant(one, dtype=dtype), name=name) + assert output.dtype.base_dtype == dtype return output @@ -1317,15 +1313,17 @@ def sparse_placeholder(dtype, shape=None, name=None): """ if shape is None: shape = placeholder( - dtypes.int64, name=(name + "/shape") if name is not None else None) + dtypes.int64, shape=[None], + name=(name + "/shape") if name is not None else None) else: shape = ops.convert_to_tensor( shape, name=(name + "/shape") if name is not None else None) return ops.SparseTensor( values=placeholder( - dtype, name=(name + "/values") if name is not None else None), + dtype, shape=[None], + name=(name + "/values") if name is not None else None), indices=placeholder( - dtypes.int64, + dtypes.int64, shape=[None, None], name=(name + "/indices") if name is not None else None), shape=shape ) @@ -1413,11 +1411,14 @@ def meshgrid(*args, **kwargs): Examples: Calling `X, Y = meshgrid(x, y)` with the tensors + ```prettyprint x = [1, 2, 3] y = [4, 5, 6] ``` + results in + ```prettyprint X = [[1, 1, 1], [2, 2, 2], diff --git a/tensorflow/python/ops/clip_ops.py b/tensorflow/python/ops/clip_ops.py index 9f2f972f7db20012b9ea18c567f61b38cf8e46ff..65e05626f04c7e639ff2718478c7e0925c9cae37 100644 --- a/tensorflow/python/ops/clip_ops.py +++ b/tensorflow/python/ops/clip_ops.py @@ -206,7 +206,7 @@ def clip_by_global_norm(t_list, clip_norm, use_norm=None, name=None): # Calculate L2-norm, clip elements by ratio of clip_norm to L2-norm scale = clip_norm * math_ops.minimum( 1.0 / use_norm, - constant_op.constant(1.0 / clip_norm, dtype=use_norm.dtype)) + constant_op.constant(1.0, dtype=use_norm.dtype) / clip_norm) values = [ ops.convert_to_tensor( @@ -268,7 +268,7 @@ def clip_by_average_norm(t, clip_norm, name=None): math_ops.reduce_sum(t * t, math_ops.range(array_ops.rank(t)))) tclip = array_ops.identity( t * clip_norm * math_ops.minimum( - l2norm_inv * n_element, constant_op.constant(1.0 / clip_norm)), + l2norm_inv * n_element, constant_op.constant(1.0) / clip_norm), name=name) return tclip diff --git a/tensorflow/python/ops/control_flow_ops.py b/tensorflow/python/ops/control_flow_ops.py index 1bd6481852b3b7653d54fe8b7e73b654e132359d..be263d1bbedf947e06cf22521a40eafd3958f170 100644 --- a/tensorflow/python/ops/control_flow_ops.py +++ b/tensorflow/python/ops/control_flow_ops.py @@ -155,7 +155,7 @@ def _NextIteration(data, name=None): def _Enter(data, frame_name, is_constant=False, parallel_iterations=10, - use_ref=True, name=None): + use_ref=True, use_input_shape=True, name=None): """Creates or finds a child frame, and makes `data` available to it. The unique `frame_name` is used by the `Executor` to identify frames. If @@ -177,27 +177,37 @@ def _Enter(data, frame_name, is_constant=False, parallel_iterations=10, data = ops.convert_to_tensor_or_indexed_slices(data, as_ref=True) if isinstance(data, ops.Tensor): if data.dtype.is_ref_dtype and use_ref: - return ref_enter(data, frame_name, is_constant, parallel_iterations, - name=name) + result = ref_enter(data, frame_name, is_constant, parallel_iterations, + name=name) else: - return enter(data, frame_name, is_constant, parallel_iterations, - name=name) + result = enter(data, frame_name, is_constant, parallel_iterations, + name=name) + if use_input_shape: + result.set_shape(data.get_shape()) + return result else: if not isinstance(data, (ops.IndexedSlices, ops.SparseTensor)): raise TypeError("Type %s not supported" % type(data)) values = _Enter(data.values, frame_name, is_constant, - parallel_iterations, name=name) + parallel_iterations=parallel_iterations, + use_input_shape=use_input_shape, name=name) indices = enter(data.indices, frame_name, is_constant, parallel_iterations, name="indices") + if use_input_shape: + indices.set_shape(data.indices.get_shape()) if isinstance(data, ops.IndexedSlices): dense_shape = data.dense_shape if dense_shape is not None: dense_shape = enter(dense_shape, frame_name, is_constant, parallel_iterations, name="dense_shape") + if use_input_shape: + dense_shape.set_shape(data.dense_shape.get_shape()) return ops.IndexedSlices(values, indices, dense_shape) else: dense_shape = enter(data.shape, frame_name, is_constant, parallel_iterations, name="dense_shape") + if use_input_shape: + dense_shape.set_shape(data.shape.get_shape()) return ops.SparseTensor(indices, values, dense_shape) @@ -432,16 +442,147 @@ def _IsLoopExit(op): return op.type == "Exit" or op.type == "RefExit" -def _ShapeIntersection(shape1, shape2): - if shape1.dims is None or shape1.ndims != shape2.ndims: - return tensor_shape.unknown_shape() - rdims = [] +def _GetOutputContext(op): + """Return the control flow context for the output of an op.""" + ctxt = op._get_control_flow_context() + if _IsLoopExit(op): + ctxt = ctxt.outer_context + return ctxt + + +def _ShapeLessThanOrEqual(shape1, shape2): + if shape2.dims is None: + return True + if shape1.ndims != shape2.ndims: + return False for dim1, dim2 in zip(shape1.dims, shape2.dims): - if dim1 == dim2: - rdims.append(dim1) + if dim2.value is not None and dim1.value != dim2.value: + return False + return True + + +def _SetShapeInvariants(input_vars, enter_vars, shapes): + """Set the shapes of the tensors in `enter_vars` to `shapes`. + + Args: + input_vars: A list of tensors that are inputs to `enter_vars`. + enter_vars: A list of tensors whose shapes will be set. + shapes: A (possibly nested) list of shapes. + + Raises: + ValueError: If any tensor in `enter_vars` has a less specific shape + than its corresponding shape in `shapes`. + """ + if shapes is None: + return + flat_shapes = nest.flatten(shapes) + if not all([isinstance(s, tensor_shape.TensorShape) for s in flat_shapes]): + raise ValueError("`shapes` must be a (possibly nested) list of shapes.") + # Check that the shapes of the inputs are less than the shape invariants, + # and set the shapes of `enter_vars` to the shape invariants. + for inp, var, shape in zip(input_vars, enter_vars, flat_shapes): + if isinstance(var, ops.Tensor): + if not _ShapeLessThanOrEqual(inp.get_shape(), shape): + raise ValueError( + "The shape invariant specified for %s is not compatible with " + "the initial shape of the loop variable. It enters the loop " + "with shape %s, but the specified shape invariant is %s." + % (inp.name, inp.get_shape(), shape)) + var.set_shape(shape) + else: + if not isinstance(var, (ops.IndexedSlices, ops.SparseTensor)): + raise TypeError("Type %s not supported" % type(var)) + if isinstance(var, ops.IndexedSlices): + if not _ShapeLessThanOrEqual(inp.values.get_shape(), shape): + raise ValueError( + "The shape invariant specified for %s is not compatible with " + "the initial shape of the values tensor of this IndexedSlices. " + "It enters the loop with shape %s, but the specified shape " + "invariant is %s." + % (inp.values.name, inp.values.get_shape(), shape)) + var.values.set_shape(shape) + var.indices.set_shape(tensor_shape.TensorShape([shape[0]])) + if var.dense_shape is not None: + var.dense_shape.set_shape(tensor_shape.TensorShape([shape.ndims])) + else: + if not _ShapeLessThanOrEqual(inp.shape.get_shape(), shape): + raise ValueError( + "The shape invariant specified for %s is not compatible with " + "the initial shape of the shape tensor of this SparseTensor. " + "It enters the loop with shape %s, but the specified shape " + "invariant is %s." + % (inp.shape.name, inp.shape.get_shape(), shape)) + var.values.set_shape(tensor_shape.TensorShape([None])) + var.indices.set_shape(tensor_shape.TensorShape([None, shape.ndims])) + var.shape.set_shape(shape) + + +def _EnforceShapeInvariant(merge_var, next_var): + """Check if the shapes of the loops variables are invariants. + + Args: + merge_vars: The list of tensors representing the initial values of the + loop variables. + next_vars: The list of tensors representing the values of the loop + variables after one loop iteration. + + Raises: + ValueError: If any tensor in `merge_vars` has a more specific shape than + its correspnding tensor in `next_var`. + """ + if isinstance(merge_var, ops.Tensor): + m_shape = merge_var.get_shape() + n_shape = next_var.get_shape() + if not _ShapeLessThanOrEqual(n_shape, m_shape): + raise ValueError( + "The shape for %s is not an invariant for the loop. It enters " + "the loop with shape %s, but has shape %s after one iteration. " + "Provide shape invariants using either the `shape_invariants` " + "argument of tf.while_loop or set_shape() on the loop variables." + % (merge_var.name, m_shape, n_shape)) + else: + if not isinstance(var, (ops.IndexedSlices, ops.SparseTensor)): + raise TypeError("Type %s not supported" % type(var)) + if isinstance(var, ops.IndexedSlices): + m_values_shape = merge_var.values.get_shape() + m_indices_shape = merge_var.indices.get_shape() + m_shape_shape = tensor_shape.TensorShape(None) + if merge_var.dense_shape is not None: + m_shape_shape = merge_var.dense_shape.get_shape() + n_values_shape = next_var.values.get_shape() + n_indices_shape = next_var.indices.get_shape() + n_shape_shape = tensor_shape.TensorShape(None) + if next_var.dense_shape is not None: + n_shape_shape = next_var.dense_shape.get_shape() + if (not _ShapeLessThanOrEqual(n_values_shape, m_values_shape) or + not _ShapeLessThanOrEqual(n_indices_shape, m_indices_shape)): + if not _ShapeLessThanOrEqual(n_values_shape, m_values_shape): + raise ValueError( + "The shape for %s is not an invariant for the loop. It enters " + "the loop with shape (%s, %s, %s), but has shape (%s, %s, %s) " + "after one iteration. Provide shape invariants using either the " + "`shape_invariants` argument of tf.while_loop or set_shape() " + "on the loop variables." + % (merge_var.name, m_values_shape, m_indices_shape, m_shape_shape, + n_values_shape, n_indices_shape, n_shape_shape)) else: - rdims.append(tensor_shape.Dimension(None)) - return tensor_shape.TensorShape(rdims) + m_values_shape = merge_var.values.get_shape() + m_indices_shape = merge_var.indices.get_shape() + m_shape_shape = merge_var.shape.get_shape() + n_values_shape = next_var.values.get_shape() + n_indices_shape = next_var.indices.get_shape() + n_shape_shape = next_var.shape.get_shape() + if (not _ShapeLessThanOrEqual(n_values_shape, m_values_shape) or + not _ShapeLessThanOrEqual(n_indices_shape, m_indices_shape) or + not _ShapeLessThanOrEqual(n_shape_shape, m_shape_shape)): + raise ValueError( + "The shape for %s is not an invariant for the loop. It enters " + "the loop with shape (%s, %s, %s), but has shape (%s, %s, %s) " + "after one iteration. Provide shape invariants using either " + "the `shape_invariants` argument of tf.while_loop or set_shape() " + "on the loop variables." + % (merge_var.name, m_values_shape, m_indices_shape, m_shape_shape, + n_values_shape, n_indices_shape, n_shape_shape)) def _AddNextAndBackEdge(m, v): @@ -496,7 +637,7 @@ class GradLoopState(object): # The while loop context for forward. self._forward_context = None - # The loop counter added by AddForwardCounter. It is the value + # The loop counter added by AddForwardLoopCounter. It is the value # of the loop counter for the next iteration. self._forward_index = None @@ -506,7 +647,7 @@ class GradLoopState(object): # The while loop context for backprop. self._grad_context = None - # The loop counter added by AddBackPropCounter. It is the value + # The loop counter added by AddBackPropLoopCounter. It is the value # of the loop counter for the current iteration. self._grad_index = None @@ -525,7 +666,7 @@ class GradLoopState(object): # Add the forward loop counter. if outer_forward_ctxt: outer_forward_ctxt.Enter() - cnt, forward_index = forward_ctxt.AddForwardCounter() + cnt, forward_index = forward_ctxt.AddForwardLoopCounter(outer_grad_state) if outer_forward_ctxt: outer_forward_ctxt.Exit() self._forward_context = forward_ctxt self._forward_index = forward_index @@ -545,7 +686,8 @@ class GradLoopState(object): forward_ctxt.name, self) real_cnt = outer_grad_state.AddBackPropAccumulatedValue(history_cnt, cnt) - self._grad_index = self._grad_context.AddBackPropCounter(real_cnt) + self._grad_index = self._grad_context.AddBackPropLoopCounter( + real_cnt, outer_grad_state) outer_grad_ctxt.Exit() else: if outer_forward_ctxt: outer_forward_ctxt.Enter() @@ -554,7 +696,8 @@ class GradLoopState(object): forward_ctxt.swap_memory, forward_ctxt.name, self) - self._grad_index = self._grad_context.AddBackPropCounter(cnt) + self._grad_index = self._grad_context.AddBackPropLoopCounter( + cnt, outer_grad_state) if outer_forward_ctxt: outer_forward_ctxt.Exit() @property @@ -665,9 +808,7 @@ class GradLoopState(object): # Add the stack_push op in the context of value.op. swap_enabled = self.forward_context.swap_memory - value_ctxt = value.op._get_control_flow_context() - if _IsLoopExit(value.op): - value_ctxt = value_ctxt.outer_context + value_ctxt = _GetOutputContext(value.op) if value_ctxt == self.forward_context: # value is not nested in the forward context. self.forward_context.Enter() @@ -1010,12 +1151,13 @@ class ControlFlowState(object): shape = None grad_state.grad_context.Enter() grad_val = constant_op.constant(0, dtype=dtype, shape=shape) - grad_val = _NextIteration(grad_val) + next_grad_val = _NextIteration(grad_val) grad_state.grad_context.Exit() # pylint: disable=protected-access if not shape: grad_val._shape = b_merge.op.inputs[0].get_shape() - b_merge.op._update_input(1, grad_val) + next_grad_val.set_shape(grad_val.get_shape()) + b_merge.op._update_input(1, next_grad_val) # pylint: enable=protected-access @@ -1136,6 +1278,15 @@ class ControlFlowContext(object): return self._outer_context.GetWhileContext() return None + def _IsInOuterContext(self, op): + op_ctxt = _GetOutputContext(op) + outer_ctxt = self.outer_context + while outer_ctxt != op_ctxt: + if outer_ctxt is None: + return False + outer_ctxt = outer_ctxt.outer_context + return True + def _MaybeAddToWhileContext(self, op): """Add a control dependency to the containing WhileContext. @@ -1152,8 +1303,17 @@ class ControlFlowContext(object): def _MaybeRemoveExternalControlEdges(self, op): """Remove any external control dependency on this op.""" - internal_control_inputs = [x for x in op.control_inputs - if x._get_control_flow_context() == self] + while_ctxt = self.GetWhileContext() + # A control input of `op` is internal if it is in the same while + # loop context as the enclosing while loop context of self. + if while_ctxt is None: + internal_control_inputs = op.control_inputs + else: + internal_control_inputs = [] + for x in op.control_inputs: + ctxt = _GetOutputContext(x) + if ctxt is not None and ctxt.GetWhileContext() == while_ctxt: + internal_control_inputs.append(x) if len(internal_control_inputs) != len(op.control_inputs): del op.control_inputs[:] op._add_control_inputs(internal_control_inputs) @@ -1349,6 +1509,9 @@ def cond(pred, fn1, fn2, name=None): pivot_1 = array_ops.identity(p_1, name="switch_t") pivot_2 = array_ops.identity(p_2, name="switch_f") pred = array_ops.identity(pred, name="pred_id") + # Disable the fetching of tensors that are only on one branch of cond. + for tensor in [p_1, p_2, pivot_1, pivot_2, pred]: + tensor.op.graph.prevent_fetching(tensor.op) # Build the graph for the true branch in a new context. context_t = CondContext(pred, pivot_1, branch=1) @@ -1566,7 +1729,7 @@ class WhileContext(ControlFlowContext): op._add_control_input(self.GetControlPivot().op) # pylint: enable=protected-access - def AddForwardCounter(self): + def AddForwardLoopCounter(self, outer_grad_state): """Adds a loop that counts the number of iterations. This is added to the forward loop at the time when we start to @@ -1576,11 +1739,21 @@ class WhileContext(ControlFlowContext): The pseudocode is: `n = 0; while (_pivot) { n++; }` + Note that a control dependency is added to `n` to ensure the correct + execution order of stack push ops. + + Args: + outer_grad_state: The outer grad state. None if not nested. + Returns: The number of iterations taken by the forward loop and the loop index. """ n = constant_op.constant(0, name="f_count") - assert n.op._get_control_flow_context() == self.outer_context + if outer_grad_state is not None: + # Force the stack pushes of i-th execution of an inner loop to be ordered + # before the pushes of (i+1)-th execution of the same inner loop. + outer_add_op = outer_grad_state.forward_index.op.inputs[0].op + n.op._add_control_input(outer_add_op) # pylint: disable=protected-access self.Enter() self.AddName(n.name) @@ -1599,7 +1772,7 @@ class WhileContext(ControlFlowContext): self.Exit() return total_iterations, next_n - def AddBackPropCounter(self, count): + def AddBackPropLoopCounter(self, count, outer_grad_state): """Add the backprop loop that controls the iterations. This is added to the backprop loop. It is used to control the loop @@ -1609,8 +1782,12 @@ class WhileContext(ControlFlowContext): The pseudocode is: `n = count; while (n >= 1) { n--; }` + Note that a control dependency is added to `final_zero` to ensure the + correct execution order of stack pop ops. + Args: count: The number of iterations for backprop. + outer_grad_state: The outer grad state. None if not nested. Returns: The loop index. @@ -1634,6 +1811,15 @@ class WhileContext(ControlFlowContext): next_count = _NextIteration(index) merge_count.op._update_input(1, next_count) + final_zero = exit(switch_count[0], name="b_count") + if outer_grad_state is not None: + # Force the stack pops of i-th execution of an inner loop to be ordered + # before the pops of (i+1)-th execution of the same inner loop. + # pylint: disable=protected-access + outer_grad_state.grad_sync._add_control_input(final_zero.op) + # pylint: enable=protected-access + + self.ExitResult([final_zero]) self.Exit() return next_count @@ -1783,6 +1969,7 @@ class WhileContext(ControlFlowContext): dense_shape=acc_exits[2] if shape_acc is not None else None) def _InitializeValues(self, values): + """Makes the values known to this context.""" self._values = set() for x in values: if isinstance(x, ops.Tensor): @@ -1799,7 +1986,8 @@ class WhileContext(ControlFlowContext): if dense_shape is not None: self._values.add(dense_shape.name) - def _BuildLoop(self, pred, body, original_loop_vars, loop_vars): + def _BuildLoop(self, pred, body, original_loop_vars, loop_vars, + shape_invariants): """Core: Add the loop termination condition and body to the graph.""" flat_loop_vars = nest.flatten(original_loop_vars) @@ -1811,8 +1999,11 @@ class WhileContext(ControlFlowContext): real_vars = [self._outer_context.AddValue(x) for x in loop_vars] with ops.control_dependencies(None): enter_vars = [_Enter(x, self._name, is_constant=False, - parallel_iterations=self._parallel_iterations) + parallel_iterations=self._parallel_iterations, + use_input_shape=(shape_invariants is None)) for x in real_vars] + _SetShapeInvariants(real_vars, enter_vars, shape_invariants) + # Fix the control inputs and control flow context of these enter ops. self._FixControlInputsAndContext(enter_vars) self._InitializeValues(enter_vars) @@ -1869,16 +2060,16 @@ class WhileContext(ControlFlowContext): self._loop_exits = exit_vars # Make sure the shapes of loop outputs are correct. - for m_var, n_var, e_var in zip(merge_vars, next_vars, exit_vars): + for m_var, n_var in zip(merge_vars, next_vars): if isinstance(m_var, ops.Tensor): - e_var._shape = _ShapeIntersection(m_var.get_shape(), n_var.get_shape()) + _EnforceShapeInvariant(m_var, n_var) # Exit the loop. self.ExitResult(exit_vars) return original_body_result, exit_vars - def BuildLoop(self, pred, body, loop_vars): + def BuildLoop(self, pred, body, loop_vars, shape_invariants): """Add the loop termination condition and body to the graph.""" # Keep original_loop_vars to identify which are TensorArrays @@ -1890,7 +2081,7 @@ class WhileContext(ControlFlowContext): try: self.Enter() original_body_result, exit_vars = self._BuildLoop( - pred, body, original_loop_vars, loop_vars) + pred, body, original_loop_vars, loop_vars, shape_invariants) finally: self.Exit() @@ -1921,16 +2112,17 @@ class WhileContext(ControlFlowContext): for x in xs: inp_op = x.op.inputs[0] control_inputs = graph._control_dependencies_for_inputs([inp_op]) - control_inputs = [op for op in control_inputs - if op._get_control_flow_context() != self] + outer_control_inputs = [op for op in control_inputs + if self._IsInOuterContext(op)] x.op._set_control_flow_context(self) - x.op._add_control_inputs(control_inputs) + x.op._add_control_inputs(outer_control_inputs) graph._record_op_seen_by_control_dependencies(x.op) # pylint: enable=protected-access -def while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, - swap_memory=False, name=None): +def while_loop(cond, body, loop_vars, shape_invariants=None, + parallel_iterations=10, back_prop=True, swap_memory=False, + name=None): """Repeat `body` while the condition `cond` is true. `cond` is a callable returning a boolean scalar tensor. `body` is a callable @@ -1940,11 +2132,39 @@ def while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, and `body`. `cond` and `body` both take as many arguments as there are `loop_vars`. + While `cond` evaluates to true, `body` is executed. + In addition to regular Tensors or IndexedSlices, the body may accept and return TensorArray objects. The flows of the TensorArray objects will be appropriately forwarded between loops and during gradient calculations. - While `cond` evaluates to true, `body` is executed. + For correctness, `tf.while_loop()` strictly enforces shape invariants for + the loop variables. A shape invariant is a (possibly partial) shape that + is unchanged across the iterations of the loop. An error will be raised + if the shape of a loop variable after an iteration is determined to be more + general than or incompatible with its shape invariant. For example, a shape + of [11, None] is more general than a shape of [11, 17], and [11, 21] is not + compatible with [11, 17]. By default (if the argument `shape_invariants` is + not specified), it is assumed that the initial shape of each tensor in + `loop_vars` is the same in every iteration. The `shape_invariants` argument + allows the caller to specify a less specific shape invariant for each loop + variable, which is needed if the shape varies between iterations. The + [`Tensor.set_shape()`](../../api_docs/python/framework.md#Tensor.set_shape) + function may also be used in the `body` function to indicate that + the output loop variable has a particular shape. The shape invariant for + SparseTensor and IndexedSlices are treated specially as follows: + + a) If a loop variable is a SparseTensor, the shape invariant must be + TensorShape([r]) where r is the rank of the dense tensor represented + by the sparse tensor. It means the shapes of the three tensors of the + SparseTensor are ([None], [None, r], [r]). NOTE: The shape invariant here + is the shape of the SparseTensor.shape property. It must be the shape of + a vector. + + b) If a loop variable is an IndexedSlices, the shape invariant must be + a shape invariant of the values tensor of the IndexedSlices. It means + the shapes of the three tensors of the IndexedSlices are (shape, [shape[0]], + [shape.ndims]). `while_loop` implements non-strict semantics, enabling multiple iterations to run in parallel. The maximum number of parallel iterations can be @@ -1964,6 +2184,7 @@ def while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, body: A callable that represents the loop body. loop_vars: A (possibly nested) tuple or list of numpy array, `Tensor`, and `TensorArray` objects. + shape_invariants: The shape invariants for the loop variables. parallel_iterations: The number of iterations allowed to run in parallel. back_prop: Whether backprop is enabled for this while loop. swap_memory: Whether GPU-CPU memory swap is enabled for this loop. @@ -1995,6 +2216,19 @@ def while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, b = lambda i, (j, k): (i + 1, ((j + k), (j - k))) ijk_final = tf.while_loop(c, b, ijk_0) ``` + + Example using shape_invariants: + + ```python + i0 = tf.constant(0) + m0 = tf.ones([2, 2]) + c = lambda i, m: i < 10 + b = lambda i, m: [i+1, tf.concat(0, [m, m])] + tf.while_loop( + c, b, loop_vars=[i0, m0], + shape_invariants=[i0.get_shape(), tensor_shape.TensorShape([None, 2])]) + ``` + """ with ops.name_scope(name, "while", loop_vars) as name: if not loop_vars: @@ -2004,19 +2238,14 @@ def while_loop(cond, body, loop_vars, parallel_iterations=10, back_prop=True, if not callable(body): raise TypeError("body must be callable.") + if shape_invariants is not None: + nest.assert_same_structure(loop_vars, shape_invariants) + context = WhileContext(parallel_iterations, back_prop, swap_memory, name) - result = context.BuildLoop(cond, body, loop_vars) + result = context.BuildLoop(cond, body, loop_vars, shape_invariants) return result -def While(cond, body, loop_vars, parallel_iterations=10, back_prop=True, - swap_memory=False, name=None): - """DEPRECATED: Use `while_loop`.""" - return while_loop(cond=cond, body=body, loop_vars=loop_vars, - parallel_iterations=parallel_iterations, - back_prop=back_prop, swap_memory=swap_memory, name=name) - - def _AsTensorList(x, p): """Return x as a list of Tensors or IndexedSlices. @@ -2388,7 +2617,7 @@ def case(pred_fn_pairs, default, exclusive=False, name="case"): return case_seq -ops.RegisterShape("Enter")(common_shapes.unchanged_shape) +ops.RegisterShape("Enter")(common_shapes.unknown_shape) ops.RegisterShape("Exit")(common_shapes.unchanged_shape) ops.RegisterShape("NextIteration")(common_shapes.unchanged_shape) ops.RegisterShape("RefEnter")(common_shapes.unchanged_shape) diff --git a/tensorflow/python/ops/control_flow_ops_test.py b/tensorflow/python/ops/control_flow_ops_test.py index 05d0bf46fed81963bc17bac881ed676c625f0151..23813c4001d9d8f56e7fcb0f9b3856678d0144a0 100644 --- a/tensorflow/python/ops/control_flow_ops_test.py +++ b/tensorflow/python/ops/control_flow_ops_test.py @@ -19,6 +19,7 @@ from __future__ import division from __future__ import print_function from tensorflow.core.framework import graph_pb2 +from tensorflow.core.framework import node_def_pb2 from tensorflow.python.framework import ops from tensorflow.python.framework.test_util import TensorFlowTestCase from tensorflow.python.ops import control_flow_ops @@ -31,7 +32,7 @@ from tensorflow.python.training import momentum class GroupTestCase(TensorFlowTestCase): def _StripNode(self, nd): - snode = graph_pb2.NodeDef(name=nd.name, op=nd.op, input=nd.input) + snode = node_def_pb2.NodeDef(name=nd.name, op=nd.op, input=nd.input) if nd.device: snode.device = nd.device return snode @@ -128,7 +129,7 @@ class SwitchTestCase(TensorFlowTestCase): embedding = embedding_ops.embedding_lookup(embedding_matrix + 0.0, [0]) cost += tf.reduce_sum(embedding) return it + 1, cost - _, cost = control_flow_ops.While( + _, cost = control_flow_ops.while_loop( Cond, Body, [tf.constant(0), tf.constant(0.0)]) optimizer = momentum.MomentumOptimizer(0.1, 0.9) train_op = optimizer.minimize(cost) @@ -151,7 +152,7 @@ class SwitchTestCase(TensorFlowTestCase): lambda: tf.square(cost), lambda: cost + tf.reduce_sum(embedding)) return it + 1, cost - _, cost = control_flow_ops.While( + _, cost = control_flow_ops.while_loop( Cond, Body, [tf.constant(0), tf.constant(0.0)]) dynamic_grads = tf.gradients(cost, [embedding_matrix])[0] diff --git a/tensorflow/python/ops/data_flow_ops.py b/tensorflow/python/ops/data_flow_ops.py index 982807de8ac2ec25017ac0a0988f10ea8e9086e2..7262267d5e2ed77b6a5e60971b4ecb27909348de 100644 --- a/tensorflow/python/ops/data_flow_ops.py +++ b/tensorflow/python/ops/data_flow_ops.py @@ -22,6 +22,8 @@ from __future__ import print_function import collections import re +import six + from tensorflow.python.framework import common_shapes from tensorflow.python.framework import dtypes as _dtypes from tensorflow.python.framework import ops @@ -88,6 +90,18 @@ def _as_name_list(names, dtypes): return list(names) +def _shape_common(s1, s2): + """The greatest lower bound (ordered by specificity) TensorShape.""" + s1 = tensor_shape.TensorShape(s1) + s2 = tensor_shape.TensorShape(s2) + if s1.ndims is None or s2.ndims is None or s1.ndims != s2.ndims: + return tensor_shape.unknown_shape() + d = [ + d1 if d1 is not None and d1 == d2 else None + for (d1, d2) in zip(s1.as_list(), s2.as_list())] + return tensor_shape.TensorShape(d) + + # pylint: disable=protected-access class QueueBase(object): """Base class for queue implementations. @@ -186,10 +200,13 @@ class QueueBase(object): if not all([names == q.names for q in queues[1:]]): raise TypeError("Queues do not have matching component names.") + queue_shapes = [q.shapes for q in queues] + reduced_shapes = [ + six.moves.reduce(_shape_common, s) for s in zip(*queue_shapes)] + queue_refs = [x.queue_ref for x in queues] selected_queue = control_flow_ops.ref_select(index, queue_refs) - # TODO(josh11b): Unify the shapes of the queues too? - return QueueBase(dtypes=dtypes, shapes=None, names=names, + return QueueBase(dtypes=dtypes, shapes=reduced_shapes, names=names, queue_ref=selected_queue) @property @@ -207,6 +224,11 @@ class QueueBase(object): """The list of dtypes for each component of a queue element.""" return self._dtypes + @property + def shapes(self): + """The list of shapes for each component of a queue element.""" + return self._shapes + @property def names(self): """The list of names for each component of a queue element.""" diff --git a/tensorflow/python/ops/hidden_ops.txt b/tensorflow/python/ops/hidden_ops.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1d163f5b68788ae50476b9f024116bc24e368ad --- /dev/null +++ b/tensorflow/python/ops/hidden_ops.txt @@ -0,0 +1,224 @@ +# array_ops +BroadcastGradientArgs +ConcatOffset +Concat +Const +EditDistance +MirrorPad +MirrorPadGrad +OneHot +Pack +Pad +Placeholder +RefIdentity +Split +Slice +TileGrad # Exported through array_grad instead of array_ops. +ZerosLike # TODO(josh11b): Use this instead of the Python version. +Unpack + +# candidate_sampling_ops +AllCandidateSampler +ComputeAccidentalHits +FixedUnigramCandidateSampler +LearnedUnigramCandidateSampler +LogUniformCandidateSampler +ThreadUnsafeUnigramCandidateSampler +UniformCandidateSampler + +# control_flow_ops +Switch +Merge +RefMerge +Exit +RefExit + +# ctc_ops +CTCLoss +CTCGreedyDecoder +CTCBeamSearchDecoder + +# data_flow_ops +Barrier +BarrierClose +BarrierIncompleteSize +BarrierInsertMany +BarrierReadySize +BarrierTakeMany +PriorityQueue +FIFOQueue +HashTable +InitializeTable +InitializeTableFromTextFile +LookupTableExport +LookupTableFind +LookupTableImport +LookupTableInsert +LookupTableSize +MutableHashTable +MutableHashTableOfTensors +Mutex +MutexAcquire +MutexRelease +PaddingFIFOQueue +QueueClose +QueueDequeue +QueueDequeueMany +QueueDequeueUpTo +QueueEnqueue +QueueEnqueueMany +QueueSize +RandomShuffleQueue +Stack +StackPop +StackPush +StackClose +TensorArray +TensorArrayClose +TensorArrayConcat +TensorArrayGrad +TensorArrayRead +TensorArrayPack +TensorArraySize +TensorArraySplit +TensorArrayUnpack +TensorArrayWrite +GetSessionHandle +GetSessionTensor +DeleteSessionTensor + +# functional_ops +SymbolicGradient + +# image_ops +RandomCrop +ResizeBilinearGrad +ResizeNearestNeighborGrad +AdjustContrastv2 +ScaleImageGrad + +# io_ops +FixedLengthRecordReader +IdentityReader +ReaderClose +ReaderEnqueueWork +ReaderNumRecordsProduced +ReaderNumWorkUnitsCompleted +ReaderRead +ReaderReadUpTo +ReaderReset +ReaderRestoreState +ReaderSerializeState +ReaderWorkQueueLength +Restore +RestoreSlice +Save +SaveSlices +ShardedFilename +ShardedFilespec +TextLineReader +TFRecordReader +WholeFileReader + +# linalg_ops +# (None) + +# logging_ops +Assert +AudioSummary +HistogramAccumulatorSummary +HistogramSummary +ImageSummary +MergeSummary +Print +ScalarSummary +TensorSummary + +# math_ops +Abs +AddN +All +Any +BatchMatMul +Complex +Max +Mean +Min +Pow +Prod +Range +SparseMatMul +Sum +MatMul +Sigmoid +Tanh +SigmoidGrad +TanhGrad + +# nn_ops +AvgPoolGrad # "*Grad" accessible through nn_grad instead of nn_ops. +BatchNormWithGlobalNormalization +BatchNormWithGlobalNormalizationGrad +SoftmaxCrossEntropyWithLogits +SparseSoftmaxCrossEntropyWithLogits +LRNGrad +MaxPoolGrad +MaxPoolGradWithArgmax +ReluGrad +Relu6Grad +EluGrad +SoftplusGrad +SoftsignGrad +TopK +TopKV2 +BiasAdd +BiasAddV1 +Relu6 +AvgPool +MaxPool + +# parsing_ops +ParseExample +ParseSingleSequenceExample + +# random_ops +RandomGamma +RandomUniform +RandomUniformInt +RandomShuffle +RandomStandardNormal +ParameterizedTruncatedNormal +TruncatedNormal + +# script_ops +PyFunc +PyFuncStateless + +# state_ops +Variable +TemporaryVariable +DestroyTemporaryVariable + +# sparse_ops +DeserializeManySparse +SerializeManySparse +SerializeSparse +SparseAdd +SparseAddGrad +SparseConcat +SparseSplit +SparseSelectLastK +SparseReorder +SparseReshape +SparseToDense +SparseTensorDenseAdd +SparseTensorDenseMatMul + +# string_ops +StringSplit + +# user_ops +Fact + +# training_ops +# (None) diff --git a/tensorflow/python/ops/init_ops.py b/tensorflow/python/ops/init_ops.py index 77a8ced83715638df1239593b9251cacda165c0b..24699b868bce872df849d59b7a94e7975935f29d 100644 --- a/tensorflow/python/ops/init_ops.py +++ b/tensorflow/python/ops/init_ops.py @@ -13,7 +13,22 @@ # limitations under the License. # ============================================================================== -"""Operations often used for initializing tensors.""" +"""Operations often used for initializing tensors. + +All variable initializers returned by functions in this file should have the +following signature: + +def _initializer(shape, dtype=dtypes.float32, partition_info=None): + Args: + shape: List of `int` representing the shape of the output `Tensor`. Some + initializers may also be able to accept a `Tensor`. + dtype: (Optional) Type of the output `Tensor`. + partition_info: (Optional) variable_scope._PartitionInfo object holding + additional information about how the variable is partitioned. May be + `None` if the variable is not partitioned. + Returns: + A `Tensor` of type `dtype` and `shape`. +""" from __future__ import absolute_import from __future__ import division from __future__ import print_function @@ -50,7 +65,7 @@ def _assert_float_dtype(dtype): zeros_initializer = array_ops.zeros_initializer -def ones_initializer(shape, dtype=dtypes.float32): +def ones_initializer(shape, dtype=dtypes.float32, partition_info=None): """An adaptor for ones() to match the Initializer spec.""" return array_ops.ones(shape, dtype) @@ -125,7 +140,7 @@ def constant_initializer(value=0, dtype=dtypes.float32): ValueError: Too many elements provided. Needed at most 6, but received 8 ``` """ - def _initializer(shape, dtype=dtype): + def _initializer(shape, dtype=dtype, partition_info=None): return constant_op.constant(value, dtype=dtype, shape=shape) return _initializer @@ -147,7 +162,7 @@ def random_uniform_initializer(minval=0, maxval=None, seed=None, Returns: An initializer that generates tensors with a uniform distribution. """ - def _initializer(shape, dtype=dtype): + def _initializer(shape, dtype=dtype, partition_info=None): return random_ops.random_uniform(shape, minval, maxval, dtype, seed=seed) return _initializer @@ -172,7 +187,8 @@ def random_normal_initializer(mean=0.0, stddev=1.0, seed=None, Raises: ValueError: if `dtype` is not a floating point type. """ - def _initializer(shape, dtype=_assert_float_dtype(dtype)): + def _initializer(shape, dtype=_assert_float_dtype(dtype), + partition_info=None): return random_ops.random_normal(shape, mean, stddev, dtype, seed=seed) return _initializer @@ -203,13 +219,16 @@ def truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, Raises: ValueError: if `dtype` is not a floating point type. """ - def _initializer(shape, dtype=_assert_float_dtype(dtype)): + def _initializer(shape, dtype=_assert_float_dtype(dtype), + partition_info=None): return random_ops.truncated_normal(shape, mean, stddev, dtype, seed=seed) + return _initializer -def uniform_unit_scaling_initializer(factor=1.0, seed=None, - dtype=dtypes.float32, full_shape=None): +def uniform_unit_scaling_initializer(factor=1.0, + seed=None, + dtype=dtypes.float32): """Returns an initializer that generates tensors without scaling variance. When initializing a deep network, it is in principle advantageous to keep @@ -228,21 +247,12 @@ def uniform_unit_scaling_initializer(factor=1.0, seed=None, and the calculation of constants. In section 2.3 there, the constants were numerically computed: for a linear layer it's 1.0, relu: ~1.43, tanh: ~1.15. - If the shape tuple `full_shape` is provided, the scale will be calculated from - this predefined shape. This is useful when a `Variable` is being partitioned - across several shards, and each shard has a smaller shape than the whole. - Since the shards are usually concatenated when used, the scale should be - based on the shape of the whole. - Args: factor: Float. A multiplicative factor by which the values will be scaled. seed: A Python integer. Used to create random seeds. See [`set_random_seed`](../../api_docs/python/constant_op.md#set_random_seed) for behavior. dtype: The data type. Only floating point types are supported. - full_shape: Tuple or list of integers. The shape used for calculating - scale normalization (instead of the shape passed at creation time). - Useful when creating sharded variables via partitioning. Returns: An initializer that generates tensors with unit variance. @@ -250,8 +260,12 @@ def uniform_unit_scaling_initializer(factor=1.0, seed=None, Raises: ValueError: if `dtype` is not a floating point type. """ - def _initializer(shape, dtype=_assert_float_dtype(dtype)): - scale_shape = full_shape if full_shape is not None else shape + def _initializer(shape, dtype=_assert_float_dtype(dtype), + partition_info=None): + scale_shape = shape + if partition_info is not None: + scale_shape = partition_info.full_shape + input_size = 1.0 # Estimating input size is not possible to do perfectly, but we try. # The estimate, obtained by multiplying all dimensions but the last one, @@ -319,7 +333,7 @@ class _RandomWalkInitializer(object): self._nonlinearity = nonlinearity self._seed = seed - def __call__(self, shape, dtype=dtypes.float32): + def __call__(self, shape, dtype=dtypes.float32, partition_info=None): """Generate a tensor used to initialize a variable.""" return random_ops._random_walk(shape, self._nonlinearity, dtype, seed=self._seed) diff --git a/tensorflow/python/ops/io_ops.py b/tensorflow/python/ops/io_ops.py index db8f043607e6383e28d4a4c8f12c3e989f062e04..7990dba3b6317b4c7d6a9a4a872766b2b1ae3825 100644 --- a/tensorflow/python/ops/io_ops.py +++ b/tensorflow/python/ops/io_ops.py @@ -80,6 +80,7 @@ Queues](../../how_tos/threading_and_queues/index.md). @@FIFOQueue @@PaddingFIFOQueue @@RandomShuffleQueue +@@PriorityQueue ## Dealing with the filesystem diff --git a/tensorflow/python/ops/math_grad.py b/tensorflow/python/ops/math_grad.py index 61d998ec4fe572772df64ab79172eb88c10d2d46..315fd4ffca0e3e7a3d8d477547b21d5879cf0626 100644 --- a/tensorflow/python/ops/math_grad.py +++ b/tensorflow/python/ops/math_grad.py @@ -552,7 +552,13 @@ def _PowGrad(op, grad): gx = array_ops.reshape( math_ops.reduce_sum(grad * y * math_ops.pow(x, y - 1), rx), sx) # Avoid false singularity at x = 0 - log_x = math_ops.select(x > 0, math_ops.log(x), array_ops.zeros_like(x)) + if x.dtype.is_complex: + # real(x) < 0 is fine for the complex case + log_x = math_ops.select( + math_ops.not_equal(x, 0), math_ops.log(x), array_ops.zeros_like(x)) + else: + # There's no sensible real value to return if x < 0, so return 0 + log_x = math_ops.select(x > 0, math_ops.log(x), array_ops.zeros_like(x)) gy = array_ops.reshape( math_ops.reduce_sum(grad * z * log_x, ry), sy) return gx, gy diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index 2f7c09b7ac10f8bae5b25e486991085a3714c1a2..78371c5c9ea1a37bba339a1fa522f002a293e827 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -67,6 +67,7 @@ mathematical functions to your graph. @@igammac @@zeta @@polygamma +@@betainc ## Matrix Math Functions @@ -150,6 +151,7 @@ common math computations that reduce various dimensions of a tensor. @@reduce_mean @@reduce_all @@reduce_any +@@reduce_logsumexp @@accumulate_n @@ -1250,6 +1252,56 @@ def reduce_any(input_tensor, reduction_indices=None, keep_dims=False, keep_dims, name=name) +def reduce_logsumexp(input_tensor, reduction_indices=None, keep_dims=False, + name=None): + """Computes log(sum(exp(elements across dimensions of a tensor))). + + Reduces `input_tensor` along the dimensions given in `reduction_indices`. + Unless `keep_dims` is true, the rank of the tensor is reduced by 1 for each + entry in `reduction_indices`. If `keep_dims` is true, the reduced dimensions + are retained with length 1. + + If `reduction_indices` has no entries, all dimensions are reduced, and a + tensor with a single element is returned. + + This funciton is more numerically stable than log(sum(exp(input))). It avoids + overflows caused by taking the exp of large inputs and underflows caused by + taking the log of small inputs. + + For example: + + ```python + # 'x' is [[0, 0, 0]] + # [0, 0, 0]] + tf.reduce_logsumexp(x) ==> log(6) + tf.reduce_logsumexp(x, 0) ==> [log(2), log(2), log(2)] + tf.reduce_logsumexp(x, 1) ==> [log(3), log(3)] + tf.reduce_logsumexp(x, 1, keep_dims=True) ==> [[log(3)], [log(3)]] + tf.reduce_logsumexp(x, [0, 1]) ==> log(6) + ``` + + Args: + input_tensor: The tensor to reduce. Should have numeric type. + reduction_indices: The dimensions to reduce. If `None` (the defaut), + reduces all dimensions. + keep_dims: If true, retains reduced dimensions with length 1. + name: A name for the operation (optional). + + Returns: + The reduced tensor. + """ + with ops.name_scope(name, "ReduceLogSumExp", [input_tensor]) as name: + my_max = array_ops.stop_gradient( + reduce_max(input_tensor, reduction_indices, keep_dims=True)) + result = gen_math_ops.log(reduce_sum( + gen_math_ops.exp(input_tensor - my_max), + reduction_indices, + keep_dims=True)) + my_max + if not keep_dims: + result = array_ops.squeeze(result, reduction_indices) + return result + + def trace(x, name=None): """ Compute the trace of a tensor `x`. @@ -1354,8 +1406,8 @@ def matmul(a, b, sparse_matmul = gen_math_ops._sparse_mat_mul batch_matmul = gen_math_ops._batch_mat_mul -ops.RegisterShape("MatMul")(common_shapes.matmul_shape) -ops.RegisterShape("SparseMatMul")(common_shapes.matmul_shape) +ops.RegisterShape("MatMul")(common_shapes.call_cpp_shape_fn) +ops.RegisterShape("SparseMatMul")(common_shapes.call_cpp_shape_fn) @ops.RegisterStatistics("MatMul", "flops") @@ -1767,6 +1819,21 @@ def _BroadcastShape(op): op.inputs[1].get_shape())] +@ops.RegisterShape("Betainc") +def _BetaincOpShape(op): # pylint: disable=invalid-name + """Shape function for BetaincOp.""" + a_shape = op.inputs[0].get_shape() + b_shape = op.inputs[1].get_shape() + x_shape = op.inputs[2].get_shape() + merged_shape = tensor_shape.TensorShape(None) + for shape in (a_shape, b_shape, x_shape): + if shape.ndims != 0: + merged_shape = merged_shape.merge_with(shape) + # Scalars get broadcasted; non-scalar shapes must all match. + # Output will be the merged non-scalar shape, if any. + return [merged_shape if merged_shape.ndims is not None else a_shape] + + @ops.RegisterShape("SparseDenseCwiseMul") @ops.RegisterShape("SparseDenseCwiseDiv") @ops.RegisterShape("SparseDenseCwiseAdd") diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index 1a71479ba851dfa151c2624fd3f762633360801b..0968bd0992fe6fd9a852b328ed3d20baaa16d45e 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -47,6 +47,70 @@ class ReduceTest(test_util.TensorFlowTestCase): math_ops.reduce_sum(x, axis) +class LogSumExpTest(test_util.TensorFlowTestCase): + + def testReduceLogSumExp(self): + for dtype in [np.float16, np.float32, np.double]: + x_np = np.random.rand(5, 5).astype(dtype) + with self.test_session(): + y_tf_np = math_ops.reduce_logsumexp(x_np).eval() + y_np = log(np.sum(exp(x_np))) + self.assertAllClose(y_tf_np, y_np) + + def testReductionIndices(self): + for dtype in [np.float16, np.float32, np.double]: + x_np = np.random.rand(5, 5).astype(dtype) + with self.test_session(): + y_tf = math_ops.reduce_logsumexp(x_np, reduction_indices=[0]) + y_np = log(np.sum(exp(x_np), axis=0)) + self.assertShapeEqual(y_np, y_tf) + y_tf_np = y_tf.eval() + self.assertAllClose(y_tf_np, y_np) + + def testKeepDims(self): + for dtype in [np.float16, np.float32, np.double]: + x_np = np.random.rand(5, 5).astype(dtype) + with self.test_session(): + y_tf_np = math_ops.reduce_logsumexp(x_np, keep_dims=True).eval() + self.assertEqual(y_tf_np.ndim, x_np.ndim) + y_np = log(np.sum(exp(x_np), keepdims=True)) + self.assertAllClose(y_tf_np, y_np) + + def testOverflow(self): + x = [1000, 1001, 1002, 1003] + for dtype in [np.float16, np.float32, np.double]: + x_np = np.array(x, dtype=dtype) + max_np = np.max(x_np) + with self.assertRaisesRegexp(RuntimeWarning, + "overflow encountered in exp"): + out = log(np.sum(exp(x_np))) + if out == np.inf: + raise RuntimeWarning("overflow encountered in exp") + + with self.test_session(): + x_tf = constant_op.constant(x_np, shape=x_np.shape) + y_tf_np = math_ops.reduce_logsumexp(x_tf).eval() + y_np = log(np.sum(exp(x_np - max_np))) + max_np + self.assertAllClose(y_tf_np, y_np) + + def testUnderflow(self): + x = [-1000, -1001, -1002, -1003] + for dtype in [np.float16, np.float32, np.double]: + x_np = np.array(x, dtype=dtype) + max_np = np.max(x_np) + with self.assertRaisesRegexp(RuntimeWarning, + "divide by zero encountered in log"): + out = log(np.sum(exp(x_np))) + if out == -np.inf: + raise RuntimeWarning("divide by zero encountered in log") + + with self.test_session(): + x_tf = constant_op.constant(x_np, shape=x_np.shape) + y_tf_np = math_ops.reduce_logsumexp(x_tf).eval() + y_np = log(np.sum(exp(x_np - max_np))) + max_np + self.assertAllClose(y_tf_np, y_np) + + class RoundTest(test_util.TensorFlowTestCase): def testRounding(self): diff --git a/tensorflow/python/ops/nn.py b/tensorflow/python/ops/nn.py index fd4eedcfcc59e754456646dd44ba8465b72aef9e..941bbfd271bb4eae26c405a0064c781310aaf20c 100644 --- a/tensorflow/python/ops/nn.py +++ b/tensorflow/python/ops/nn.py @@ -19,7 +19,7 @@ The activation ops provide different types of nonlinearities for use in neural networks. These include smooth nonlinearities (`sigmoid`, `tanh`, `elu`, `softplus`, and `softsign`), continuous but not everywhere differentiable -functions (`relu`, `relu6`, and `relu_x`), and random regularization +functions (`relu`, `relu6`, `crelu` and `relu_x`), and random regularization (`dropout`). All activation ops apply componentwise, and produce a tensor of the same @@ -27,6 +27,7 @@ shape as the input tensor. @@relu @@relu6 +@@crelu @@elu @@softplus @@softsign @@ -220,7 +221,9 @@ Neural Networks. Most accept an `RNNCell`-subclassed object @@dynamic_rnn @@rnn @@state_saving_rnn +@@bidirectional_dynamic_rnn @@bidirectional_rnn +@@raw_rnn ## Conectionist Temporal Classification (CTC) diff --git a/tensorflow/python/ops/nn_ops.py b/tensorflow/python/ops/nn_ops.py index 827be1c30212c716883ecfd08f79be7db3bc023e..11ca3ff0d72fe18c64d23c7fa8d3677ba5ca1f55 100644 --- a/tensorflow/python/ops/nn_ops.py +++ b/tensorflow/python/ops/nn_ops.py @@ -19,6 +19,8 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function +import numbers + import numpy as np from tensorflow.python.framework import common_shapes @@ -429,6 +431,28 @@ ops.RegisterShape("BiasAddV1")(common_shapes.bias_add_shape) ops.RegisterShape("BiasAddGradV1")(common_shapes.bias_add_grad_shape) +def crelu(features, name=None): + """Computes Concatenated ReLU. + + Concatenates a ReLU which selects only the positive part of the activation + with a ReLU which selects only the *negative* part of the activation. + Note that as a result this non-linearity doubles the depth of the activations. + Source: https://arxiv.org/abs/1603.05201 + + Args: + features: A `Tensor` with type `float`, `double`, `int32`, `int64`, `uint8`, + `int16`, or `int8`. + name: A name for the operation (optional). + + Returns: + A `Tensor` with the same type as `features`. + """ + with ops.name_scope(name, "CRelu", [features]) as name: + features = ops.convert_to_tensor(features, name="features") + return gen_nn_ops.relu(array_ops.concat(array_ops.rank(features) - 1, + [features, -features], name=name)) + + def relu6(features, name=None): """Computes Rectified Linear 6: `min(max(features, 0), 6)`. @@ -1109,7 +1133,7 @@ def dropout(x, keep_prob, noise_shape=None, seed=None, name=None): """ with ops.name_scope(name, "dropout", [x]) as name: x = ops.convert_to_tensor(x, name="x") - if isinstance(keep_prob, float) and not 0 < keep_prob <= 1: + if isinstance(keep_prob, numbers.Real) and not 0 < keep_prob <= 1: raise ValueError("keep_prob must be a scalar tensor or a float in the " "range (0, 1], got %g" % keep_prob) keep_prob = ops.convert_to_tensor(keep_prob, diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py index d146af478f9c4c7070fa3271d97fc25326c6f5c6..3f3bd5e94a24f2f729aaecdce9c3e1590da45305 100644 --- a/tensorflow/python/ops/nn_test.py +++ b/tensorflow/python/ops/nn_test.py @@ -701,5 +701,15 @@ class ComputeSampledLogitsTest(tf.test.TestCase): sampled_softmax_loss_np, sampled_softmax_loss_tf.eval(), 1e-4) +class CReluTest(tf.test.TestCase): + + def test(self): + x = np.random.rand(3, 4).astype(np.float32) + y = np.concatenate([x * (x > 0), -x * (x < 0)], axis=1) + with self.test_session(): + z = tf.nn.crelu(tf.constant(x)).eval() + self.assertAllClose(y, z, 1e-4) + + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/python/ops/partitioned_variables.py b/tensorflow/python/ops/partitioned_variables.py index 23e0c858ff231f9f24045af94ab4d230bb3a0778..fb7524b56b26f4605ba8ffed61aa66c9f00adc5b 100644 --- a/tensorflow/python/ops/partitioned_variables.py +++ b/tensorflow/python/ops/partitioned_variables.py @@ -65,6 +65,7 @@ __all__ = [ "create_partitioned_variables", "variable_axis_size_partitioner", "min_max_variable_partitioner", + "fixed_size_partitioner", ] @@ -215,6 +216,24 @@ def min_max_variable_partitioner(max_partitions=1, axis=0, return _partitioner +def fixed_size_partitioner(num_shards, axis=0): + """Partitioner to specify a fixed number of shards along given axis. + + Args: + num_shards: `int`, number of shards to partition variable. + axis: `int`, axis to partition on. + + Returns: + A partition function usable as the `partitioner` argument to + `variable_scope`, `get_variable`, and `get_partitioned_variable_list`. + """ + def _partitioner(shape, **unused_args): + partitions_list = [1] * len(shape) + partitions_list[axis] = min(num_shards, shape[axis].value) + return partitions_list + return _partitioner + + def create_partitioned_variables( shape, slicing, initializer, dtype=dtypes.float32, trainable=True, collections=None, name=None, reuse=None): diff --git a/tensorflow/python/ops/sparse_ops.py b/tensorflow/python/ops/sparse_ops.py index c42da9af5d78a7d53fc15b5248f2bcdcc1f1ce1a..198ccab0211a3b90b8d67834527c19aec336ed11 100644 --- a/tensorflow/python/ops/sparse_ops.py +++ b/tensorflow/python/ops/sparse_ops.py @@ -40,6 +40,7 @@ dimension, and dense along all other dimensions. @@sparse_retain @@sparse_reset_shape @@sparse_fill_empty_rows +@@sparse_transpose ## Reduction @@sparse_reduce_sum @@ -1582,3 +1583,49 @@ def _SparseSparseMaximumMinimumShape(op): # pylint: disable=invalid-name op.inputs[4].get_shape().assert_has_rank(1) # b_values op.inputs[5].get_shape().assert_has_rank(1) # b_shape return [tensor_shape.unknown_shape(2), tensor_shape.unknown_shape(1)] + + +def sparse_transpose(sp_input, perm=None, name=None): + """Transposes a `SparseTensor` + + The returned tensor's dimension i will correspond to the input dimension + `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is + the rank of the input tensor. Hence by default, this operation performs a + regular matrix transpose on 2-D input Tensors. + + For example, if `sp_input` has shape `[4, 5]` and `indices` / `values`: + + [0, 3]: b + [0, 1]: a + [3, 1]: d + [2, 0]: c + + then the output will be a `SparseTensor` of shape `[5, 4]` and + `indices` / `values`: + + [0, 2]: c + [1, 0]: a + [1, 3]: d + [3, 0]: b + + Args: + sp_input: The input `SparseTensor`. + perm: A permutation of the dimensions of `sp_input`. + name: A name prefix for the returned tensors (optional) + Returns: + A transposed `SparseTensor`. + + Raises: + TypeError: If `sp_input` is not a `SparseTensor`. + """ + with ops.op_scope([sp_input], name, "SparseTranspose") as name: + if perm is None: + rank = array_ops.rank(sp_input) + perm = (rank - 1) - math_ops.range(0, rank, 1) + indices = sp_input.indices + transposed_indices = array_ops.transpose(array_ops.gather(array_ops.transpose(indices), perm)) + dense_shape = sp_input.shape + transposed_dense_shape = array_ops.gather(dense_shape, perm) + transposed_st = ops.SparseTensor(transposed_indices, sp_input.values, transposed_dense_shape) + transposed_st = sparse_reorder(transposed_st) + return transposed_st diff --git a/tensorflow/python/ops/state_ops.py b/tensorflow/python/ops/state_ops.py index 7c188ca651b806b1bdc9fbef1403028cdddad31a..63fae7481262eb3395fcb44887fe8f97fbb7da48 100644 --- a/tensorflow/python/ops/state_ops.py +++ b/tensorflow/python/ops/state_ops.py @@ -67,6 +67,7 @@ create variables contingent on certain conditions. ## Variable Partitioners for Sharding +@@fixed_size_partitioner @@variable_axis_size_partitioner @@min_max_variable_partitioner diff --git a/tensorflow/python/ops/summary_ops.py b/tensorflow/python/ops/summary_ops.py index 1d34b8a47ee5c908645dca7e03260a0abd6c0446..81d57a6c203e107b4097301bf7a4d86cf7f00a15 100644 --- a/tensorflow/python/ops/summary_ops.py +++ b/tensorflow/python/ops/summary_ops.py @@ -24,6 +24,7 @@ from tensorflow.python.ops import gen_logging_ops # go/tf-wildcard-import # pylint: disable=wildcard-import from tensorflow.python.ops.gen_logging_ops import * + # pylint: enable=wildcard-import @@ -45,7 +46,7 @@ def tensor_summary(display_name, # pylint: disable=invalid-name The generated [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto) - has one summary value containing input_tensor. + has one summary value containing the input tensor. Args: display_name: A name to associate with the data series. Will be used to @@ -60,7 +61,7 @@ def tensor_summary(display_name, # pylint: disable=invalid-name other tensors that are all in a group. (e.g. bounding boxes and images) collections: Optional list of graph collections keys. The new summary op is added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. - name: A name for the operation (optional). + name: An optional name for the generated node (optional). Returns: A scalar `Tensor` of type `string`. The serialized `Summary` protocol @@ -69,14 +70,16 @@ def tensor_summary(display_name, # pylint: disable=invalid-name # pylint: enable=line-too-long with ops.name_scope(name, "TensorSummary", [tensor]) as scope: - val = gen_logging_ops._tensor_summary(display_name=display_name, - tensor=tensor, - description=description, - labels=labels, - name=scope) + val = gen_logging_ops._tensor_summary( + display_name=display_name, + tensor=tensor, + description=description, + labels=labels, + name=scope) _Collect(val, collections, [ops.GraphKeys.SUMMARIES]) return val + ops.NoGradient("TensorSummary") diff --git a/tensorflow/python/ops/variable_scope.py b/tensorflow/python/ops/variable_scope.py index c4c51aa443e30d8acd5ec813d5e9ec2990ffe416..217556df3c7066e7613e8d5d4ff72335ba49eea9 100644 --- a/tensorflow/python/ops/variable_scope.py +++ b/tensorflow/python/ops/variable_scope.py @@ -39,6 +39,133 @@ __all__ = ["VariableScope", "get_variable_scope", "no_regularizer"] +class _PartitionInfo(object): + """Holds partition info used by initializer functions. + """ + + def __init__(self, full_shape, var_offset): + """Constructor. + + Args: + full_shape: Tuple or list of `int` indicating the full combined shape + of the partitioned variables. + var_offset: Tuple or list of `int` specifying offset of this partition + with respect to the full variable for each dimension. + + Raises: + TypeError: If `full_shape` or `var_offset` is not a sequence. + ValueError: If `full_shape` or `var_offset` differ in length. If + `var_offset` exceeds `full_shape` in any dimension. + """ + if not isinstance(full_shape, collections_lib.Sequence) or isinstance( + full_shape, six.string_types): + raise TypeError( + "`full_shape` must be a sequence (like tuple or list) instead of " + + type(full_shape).__name__) + + if not isinstance(var_offset, collections_lib.Sequence) or isinstance( + var_offset, six.string_types): + raise TypeError( + "`var_offset` must be a sequence (like tuple or list) instead of " + + type(var_offset).__name__) + + if len(var_offset) != len(full_shape): + raise ValueError( + "Expected equal length, but `var_offset` is of length {} while " + "full_shape is of length {}.".format( + len(var_offset), len(full_shape))) + + for i in xrange(len(full_shape)): + offset = var_offset[i] + shape = full_shape[i] + if offset < 0 or offset >= shape: + raise ValueError( + "Expected 0 <= offset < shape but found offset={}, shape={} for " + "var_offset={}, full_shape={}".format(offset, shape, var_offset, + full_shape)) + + self._full_shape = full_shape + self._var_offset = var_offset + + @property + def full_shape(self): + return self._full_shape + + @property + def var_offset(self): + return self._var_offset + + def single_offset(self, shape): + """Returns the offset when the variable is partitioned in at most one dim. + + Args: + shape: Tuple or list of `int` indicating the shape of one specific + variable partition. + + Returns: + `int` representing the offset in the dimension along which the variable is + partitioned. Returns 0 if the variable is not being partitioned. + + Raises: + ValueError: Depending on self.single_slice_dim(). + """ + + single_slice_dim = self.single_slice_dim(shape) + # If this variable is not being partitioned at all, single_slice_dim() could + # return None. + if single_slice_dim is None: + return 0 + return self.var_offset[single_slice_dim] + + def single_slice_dim(self, shape): + """Returns the slice dim when the variable is partitioned only in one dim. + + Args: + shape: Tuple or list of `int` indicating the shape of one specific + variable partition. + + Returns: + `int` representing the dimension that the variable is partitioned in, or + `None` if the variable doesn't seem to be partitioned at all. + + Raises: + TypeError: If `shape` is not a sequence. + ValueError: If `shape` is not the same length as `self.full_shape`. If + the variable is partitioned in more than one dimension. + """ + if not isinstance(shape, collections_lib.Sequence) or isinstance( + shape, six.string_types): + raise TypeError( + "`shape` must be a sequence (like tuple or list) instead of " + + type(shape).__name__) + + if len(shape) != len(self.full_shape): + raise ValueError( + "Expected equal length, but received shape={} of length {} while " + "self.full_shape={} is of length {}.".format(shape, len( + shape), self.full_shape, len(self.full_shape))) + + for i in xrange(len(shape)): + if self.var_offset[i] + shape[i] > self.full_shape[i]: + raise ValueError( + "With self.var_offset={}, a partition of shape={} would exceed " + "self.full_shape={} in dimension {}.".format( + self.var_offset, shape, self.full_shape, i)) + + slice_dim = None + for i in xrange(len(shape)): + if shape[i] == self.full_shape[i]: + continue + if slice_dim is not None: + raise ValueError( + "Cannot use single_slice_dim() with shape={} and " + "self.full_shape={} since slice dim could be either dimension {} " + "or {}.".format(shape, self.full_shape, i, slice_dim)) + slice_dim = i + + return slice_dim + + class _VariableStore(object): """Variable store that carries a number of named Variables. @@ -390,6 +517,8 @@ class _VariableStore(object): for i in xrange(num_slices): var_shape = slice_shape[:] var_offset = slice_offset[:] + partition_info = _PartitionInfo( + full_shape=shape.as_list(), var_offset=var_offset) if i < num_slices_with_excess: var_shape[slice_dim] += 1 slice_offset[slice_dim] += var_shape[slice_dim] @@ -397,8 +526,7 @@ class _VariableStore(object): var_full_name = "%s/part_%d" % (name, i) with ops.name_scope(var_full_name + "/PartitionedInitializer"): if initializer is None: - init = init_ops.uniform_unit_scaling_initializer( - full_shape=shape.as_list()) + init = init_ops.uniform_unit_scaling_initializer() init_shape = var_shape elif callable(initializer): init = initializer @@ -419,6 +547,7 @@ class _VariableStore(object): shape=init_shape, dtype=dtype, initializer=init, + partition_info=partition_info, regularizer=regularizer, reuse=reuse, trainable=trainable, @@ -443,10 +572,18 @@ class _VariableStore(object): self._partitioned_vars[name] = partitioned_var return partitioned_var - def _get_single_variable(self, name, shape=None, dtype=dtypes.float32, - initializer=None, regularizer=None, reuse=None, - trainable=True, collections=None, - caching_device=None, validate_shape=True): + def _get_single_variable(self, + name, + shape=None, + dtype=dtypes.float32, + initializer=None, + regularizer=None, + partition_info=None, + reuse=None, + trainable=True, + collections=None, + caching_device=None, + validate_shape=True): """Get or create a single Variable (e.g. a shard or entire variable). See the documentation of get_variable above (ignore partitioning components) @@ -458,6 +595,7 @@ class _VariableStore(object): dtype: see get_variable. initializer: see get_variable. regularizer: see get_variable. + partition_info: _PartitionInfo object. reuse: see get_variable. trainable: see get_variable. collections: see get_variable. @@ -523,7 +661,8 @@ class _VariableStore(object): init_val = initializer variable_dtype = None else: - init_val = lambda: initializer(shape.as_list(), dtype=dtype) + init_val = lambda: initializer( + shape.as_list(), dtype=dtype, partition_info=partition_info) variable_dtype = dtype.base_dtype # Create the variable. diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index 4982bb30188d94155bc4e2ce931e273ef65344b9..d3d78dad5f885e6b0daf7311bb39ed8a4feb9997 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -772,31 +772,47 @@ class _PartitionedVariable(object): self._partitions = partitions self._as_tensor = None - def as_tensor(self): + def concat(self): """Returns the overall concatenated value as a `Tensor`. + This is different from using the partitioned variable directly as a tensor + (through tensor conversion and `as_tensor`) in that it creates a new set of + operations that keeps the control dependencies from its scope. + Returns: `Tensor` containing the concatenated value. """ - if self._as_tensor is not None: - return self._as_tensor - if len(self._variable_list) == 1: with ops.name_scope(None): - self._as_tensor = array_ops.identity( - self._variable_list[0], name=self._name) - return self._as_tensor + return array_ops.identity(self._variable_list[0], name=self._name) if all([p < 2 for p in self._partitions]): partition_ix = 0 else: partition_ix = [i for i, p in enumerate(self._partitions) if p > 1][0] + with ops.name_scope(self._name + "/ConcatPartitions/"): concatenated = array_ops.concat(partition_ix, self._variable_list) + with ops.name_scope(None): + return array_ops.identity(concatenated, name=self._name) + + def as_tensor(self): + """Returns the overall concatenated value as a `Tensor`. + + The returned tensor will not inherit the control dependencies from the scope + where the value is used, which is similar to getting the value of + `Variable`. + + Returns: + `Tensor` containing the concatenated value. + """ + if self._as_tensor is None: # Be sure to cache the concatenated tensor to not do extraneous # computations. - self._as_tensor = array_ops.identity(concatenated, name=self._name) + with ops.control_dependencies(None): + self._as_tensor = self.concat() + return self._as_tensor @staticmethod @@ -1030,20 +1046,19 @@ def report_uninitialized_variables(var_list=None, for op in ops.get_default_graph().get_operations(): if op.type in ["Variable", "AutoReloadVariable"]: var_list.append(op.outputs[0]) - if not var_list: - # Return an empty tensor so we only need to check for returned tensor - # size being 0 as an indication of model ready. - return array_ops.constant([], dtype=dtypes.string, name=name) - else: - # Get a 1-D boolean tensor listing whether each variable is initialized. - variables_mask = math_ops.logical_not( - array_ops.pack([state_ops.is_variable_initialized(v) for v in var_list - ])) - # Get a 1-D string tensor containing all the variable names. - variable_names_tensor = array_ops.constant([s.op.name for s in var_list]) - # Return a 1-D tensor containing all the names of uninitialized variables. - return array_ops.boolean_mask( - variable_names_tensor, variables_mask, name=name) + with ops.name_scope(name): + if not var_list: + # Return an empty tensor so we only need to check for returned tensor + # size being 0 as an indication of model ready. + return array_ops.constant([], dtype=dtypes.string) + else: + # Get a 1-D boolean tensor listing whether each variable is initialized. + variables_mask = math_ops.logical_not(array_ops.pack( + [state_ops.is_variable_initialized(v) for v in var_list])) + # Get a 1-D string tensor containing all the variable names. + variable_names_tensor = array_ops.constant([s.op.name for s in var_list]) + # Return a 1-D tensor containing all the names of uninitialized variables. + return array_ops.boolean_mask(variable_names_tensor, variables_mask) # pylint: disable=protected-access ops.register_tensor_conversion_function(Variable, diff --git a/tensorflow/python/platform/app.py b/tensorflow/python/platform/app.py index ebca21e075ad611395500db111bbef2339db3796..7419d844ffd41e03af11b5932966ba7ee17bf69c 100644 --- a/tensorflow/python/platform/app.py +++ b/tensorflow/python/platform/app.py @@ -25,6 +25,6 @@ from tensorflow.python.platform import flags def run(main=None): f = flags.FLAGS - f._parse_flags() + flags_passthrough = f._parse_flags() main = main or sys.modules['__main__'].main - sys.exit(main(sys.argv)) + sys.exit(main(sys.argv[:1] + flags_passthrough)) diff --git a/tensorflow/python/platform/app_test.py b/tensorflow/python/platform/app_test.py new file mode 100644 index 0000000000000000000000000000000000000000..b7a58dd9fb4f41c38dfdbda0faf94f4fa5a34504 --- /dev/null +++ b/tensorflow/python/platform/app_test.py @@ -0,0 +1,45 @@ +# Copyright 2015 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +"""Tests for our flags implementation.""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import sys + +from tensorflow.python.platform import app +from tensorflow.python.platform import flags + +FLAGS = flags.FLAGS +flags.DEFINE_boolean('myflag', False, '') + +def main(argv): + if (len(argv) != 3): + print("Length of argv was not 3: ", argv) + sys.exit(-1) + + if argv[1] != "--passthrough": + print("--passthrough argument not in argv") + sys.exit(-1) + + if argv[2] != "extra": + print("'extra' argument not in argv") + sys.exit(-1) + + +if __name__ == '__main__': + sys.argv.extend(["--myflag", "--passthrough", "extra"]) + app.run() diff --git a/tensorflow/python/platform/base.i b/tensorflow/python/platform/base.i index df40491ed30eacd7e51a005f1a5d4eadd747d384..a083913684aa474c3629a887cce1b861d2368bcb 100644 --- a/tensorflow/python/platform/base.i +++ b/tensorflow/python/platform/base.i @@ -17,6 +17,7 @@ limitations under the License. // %{ #include + #include #include "tensorflow/core/platform/types.h" using tensorflow::uint64; using tensorflow::string; @@ -75,6 +76,25 @@ limitations under the License. return PyUnicode_FromStringAndSize(s.data(), s.size()); #endif } + + template + bool tf_vector_input_helper(PyObject * seq, std::vector * out, + bool (*convert)(PyObject*, T * const)) { + PyObject *item, *it = PyObject_GetIter(seq); + if (!it) return false; + while ((item = PyIter_Next(it))) { + T elem; + bool success = convert(item, &elem); + Py_DECREF(item); + if (!success) { + Py_DECREF(it); + return false; + } + if (out) out->push_back(elem); + } + Py_DECREF(it); + return static_cast(!PyErr_Occurred()); + } %} %typemap(in) string { @@ -112,7 +132,7 @@ limitations under the License. %define _LIST_OUTPUT_TYPEMAP(type, py_converter) %typemap(in) std::vector(std::vector temp) { - if (!vector_input_helper($input, &temp, _PyObjAs)) { + if (!tf_vector_input_helper($input, &temp, _PyObjAs)) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "sequence(type) expected"); return NULL; @@ -121,7 +141,7 @@ limitations under the License. } %typemap(in) const std::vector& (std::vector temp), const std::vector* (std::vector temp) { - if (!vector_input_helper($input, &temp, _PyObjAs)) { + if (!tf_vector_input_helper($input, &temp, _PyObjAs)) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "sequence(type) expected"); return NULL; @@ -148,6 +168,7 @@ std::vector* OUTPUT (std::vector temp), _LIST_OUTPUT_TYPEMAP(string, _SwigBytes_FromString); _LIST_OUTPUT_TYPEMAP(long long, PyLong_FromLongLong); _LIST_OUTPUT_TYPEMAP(unsigned long long, PyLong_FromUnsignedLongLong); +_LIST_OUTPUT_TYPEMAP(unsigned int, PyLong_FromUnsignedLong); %typemap(in) uint64 { // TODO(gps): Check if another implementation @@ -180,6 +201,7 @@ _LIST_OUTPUT_TYPEMAP(unsigned long long, PyLong_FromUnsignedLongLong); _COPY_TYPEMAPS(unsigned long long, uint64); _COPY_TYPEMAPS(long long, int64); +_COPY_TYPEMAPS(unsigned int, mode_t); // SWIG macros for explicit API declaration. // Usage: @@ -191,3 +213,9 @@ _COPY_TYPEMAPS(long long, int64); %define %ignoreall %ignore ""; %enddef %define %unignore %rename("%s") %enddef %define %unignoreall %rename("%s") ""; %enddef + +#if SWIG_VERSION < 0x030000 +// Define some C++11 keywords safe to ignore so older SWIG does not choke. +%define final %enddef +%define override %enddef +#endif diff --git a/tensorflow/python/platform/flags.py b/tensorflow/python/platform/flags.py index 85f9e2cb860d02166e2171e1cebd9e5ebccfc25b..645f8acecb0c1eaae0a036e71bcb8eeb05e5b7d0 100644 --- a/tensorflow/python/platform/flags.py +++ b/tensorflow/python/platform/flags.py @@ -30,10 +30,11 @@ class _FlagValues(object): self.__dict__['__parsed'] = False def _parse_flags(self): - result, _ = _global_parser.parse_known_args() + result, unparsed = _global_parser.parse_known_args() for flag_name, val in vars(result).items(): self.__dict__['__flags'][flag_name] = val self.__dict__['__parsed'] = True + return unparsed def __getattr__(self, name): """Retrieves the 'value' attribute of the flag --name.""" diff --git a/tensorflow/python/summary/summary.py b/tensorflow/python/summary/summary.py index 90e3f009a82198d4d22d144a4d384fc440d61845..46e33aae271ee1e97df90eb296cae6126b1cf8d2 100644 --- a/tensorflow/python/summary/summary.py +++ b/tensorflow/python/summary/summary.py @@ -18,18 +18,70 @@ ## Summary Ops @@tensor_summary +@@scalar """ # pylint: enable=line-too-long -# Optimizers. from __future__ import absolute_import from __future__ import division from __future__ import print_function -# pylint: disable=g-bad-import-order,unused-import +from tensorflow.python.framework import ops +from tensorflow.python.framework import tensor_shape +from tensorflow.python.framework.dtypes import as_dtype from tensorflow.python.ops.summary_ops import tensor_summary - from tensorflow.python.util.all_util import make_all +SCALAR_SUMMARY_LABEL = "tf_summary_type:scalar" + + +def scalar(display_name, + tensor, + description="", + labels=None, + collections=None, + name=None): + """Outputs a `Summary` protocol buffer containing a single scalar value. + + The generated Summary has a Tensor.proto containing the input Tensor. + + Args: + display_name: A name to associate with the data series. Will be used to + organize output data and as a name in visualizers. + tensor: A tensor containing a single floating point or integer value. + description: An optional long description of the data being output. + labels: a list of strings used to attach metadata. + collections: Optional list of graph collections keys. The new summary op is + added to these collections. Defaults to `[GraphKeys.SUMMARIES]`. + name: An optional name for the generated node (optional). + + Returns: + A scalar `Tensor` of type `string`. Which contains a `Summary` protobuf. + + Raises: + ValueError: If tensor has the wrong shape or type. + """ + + dtype = as_dtype(tensor.dtype) + if dtype.is_quantized or not (dtype.is_integer or dtype.is_floating): + raise ValueError("Can't create scalar summary for type %s." % dtype) + + shape = tensor.get_shape() + if not shape.is_compatible_with(tensor_shape.scalar()): + raise ValueError("Can't create scalar summary for shape %s." % shape) + + if labels is None: + labels = [] + else: + labels = labels[:] # Otherwise we would mutate the input argument + + labels.append(SCALAR_SUMMARY_LABEL) + + with ops.name_scope(name, "ScalarSummary", [tensor]): + tensor = ops.convert_to_tensor(tensor) + return tensor_summary(display_name, tensor, description, labels, + collections, name) + + __all__ = make_all(__name__) diff --git a/tensorflow/python/summary/summary_test.py b/tensorflow/python/summary/summary_test.py new file mode 100644 index 0000000000000000000000000000000000000000..fb49759ba0b326ce5e800f0c10fe4b0148d42dba --- /dev/null +++ b/tensorflow/python/summary/summary_test.py @@ -0,0 +1,88 @@ +# 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. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import six +import tensorflow as tf + +from tensorflow.core.framework import types_pb2 + + +class ScalarSummaryTest(tf.test.TestCase): + + def testDtypeErrors(self): + def _TryMakingScalarSummary(dtype): + base = dtype.base_dtype + if base == tf.bool: + v = False + elif base == tf.string: + v = '' + elif base.is_complex: + v = complex(0, 0) + else: + v = base.min + c = tf.constant(v, dtype) + return tf.summary.scalar('name', c) + + for datatype_enum in types_pb2.DataType.values(): + if datatype_enum == types_pb2.DT_INVALID: + continue + dtype = tf.as_dtype(datatype_enum) + if dtype.is_quantized: + # Quantized ops are funky, and not expected to work. + continue + if dtype.is_integer or dtype.is_floating: + _TryMakingScalarSummary(dtype) + # No exception should be thrown + else: + with self.assertRaises(ValueError): + _TryMakingScalarSummary(dtype) + + def testShapeErrors(self): + c1 = tf.constant(0) + c2 = tf.zeros(5) + c3 = tf.zeros(5, 5) + + tf.summary.scalar('1', c1) + with self.assertRaises(ValueError): + tf.summary.scalar('2', c2) + with self.assertRaises(ValueError): + tf.summary.scalar('3', c3) + + def testLabelsAdded(self): + c = tf.constant(0) + + no_labels = tf.summary.scalar('2', c) + labels = tf.summary.scalar('1', c, labels=['foo']) + + def _GetLabels(n): + return n.op.get_attr('labels') + + expected_label = six.b(tf.summary.SCALAR_SUMMARY_LABEL) + self.assertEquals(_GetLabels(no_labels), [expected_label]) + self.assertEquals(_GetLabels(labels), [six.b('foo'), expected_label]) + + def testTensorSummaryOpCreated(self): + c = tf.constant(0) + s = tf.summary.scalar('', c) + self.assertEquals(s.op.type, 'TensorSummary') + self.assertEquals(s.op.inputs[0], c) + + +if __name__ == '__main__': + tf.test.main() diff --git a/tensorflow/python/tensorflow.i b/tensorflow/python/tensorflow.i index ef82a009f9208dd6d37190f3b9b4378cd842bec8..7a8fbf72016e9cade34ee1a939561a56e1466032 100644 --- a/tensorflow/python/tensorflow.i +++ b/tensorflow/python/tensorflow.i @@ -35,3 +35,5 @@ limitations under the License. %include "tensorflow/python/training/server_lib.i" %include "tensorflow/python/framework/python_op_gen.i" + +%include "tensorflow/python/framework/cpp_shape_inference.i" diff --git a/tensorflow/python/training/coordinator_test.py b/tensorflow/python/training/coordinator_test.py index 4e20e7c3d36415242c94e76cbe4e37ae68a10eef..1e691d2a7038df974bf9a7da4c4ad7f881e888bd 100644 --- a/tensorflow/python/training/coordinator_test.py +++ b/tensorflow/python/training/coordinator_test.py @@ -25,9 +25,10 @@ import time import tensorflow as tf -def StopInN(coord, n_secs): - time.sleep(n_secs) +def StopOnEvent(coord, wait_for_stop, set_when_stopped): + wait_for_stop.wait() coord.request_stop() + set_when_stopped.set() def RaiseInN(coord, n_secs, ex, report_exception): @@ -53,6 +54,14 @@ def SleepABit(n_secs, coord=None): time.sleep(n_secs) +def WaitForThreadsToRegister(coord, num_threads): + while True: + with coord._lock: + if len(coord._registered_threads) == num_threads: + break + time.sleep(0.001) + + class CoordinatorTest(tf.test.TestCase): def testStopAPI(self): @@ -67,9 +76,15 @@ class CoordinatorTest(tf.test.TestCase): coord = tf.train.Coordinator() self.assertFalse(coord.should_stop()) self.assertFalse(coord.wait_for_stop(0.1)) - threading.Thread(target=StopInN, args=(coord, 0.02)).start() + wait_for_stop_ev = threading.Event() + has_stopped_ev = threading.Event() + t = threading.Thread(target=StopOnEvent, + args=(coord, wait_for_stop_ev, has_stopped_ev)) + t.start() self.assertFalse(coord.should_stop()) self.assertFalse(coord.wait_for_stop(0.01)) + wait_for_stop_ev.set() + has_stopped_ev.wait() self.assertTrue(coord.wait_for_stop(0.05)) self.assertTrue(coord.should_stop()) @@ -93,6 +108,7 @@ class CoordinatorTest(tf.test.TestCase): threading.Thread(target=SleepABit, args=(0.01, coord))] for t in threads: t.start() + WaitForThreadsToRegister(coord, 3) coord.join() for t in threads: self.assertFalse(t.is_alive()) @@ -105,6 +121,7 @@ class CoordinatorTest(tf.test.TestCase): threading.Thread(target=SleepABit, args=(0.01, coord))] for t in threads: t.start() + WaitForThreadsToRegister(coord, 2) # threads[1] is not registered we must pass it in. coord.join(threads[1:1]) for t in threads: @@ -113,12 +130,17 @@ class CoordinatorTest(tf.test.TestCase): def testJoinGraceExpires(self): def TestWithGracePeriod(stop_grace_period): coord = tf.train.Coordinator() + wait_for_stop_ev = threading.Event() + has_stopped_ev = threading.Event() threads = [ - threading.Thread(target=StopInN, args=(coord, 0.01)), + threading.Thread(target=StopOnEvent, + args=(coord, wait_for_stop_ev, has_stopped_ev)), threading.Thread(target=SleepABit, args=(10.0,))] for t in threads: t.daemon = True t.start() + wait_for_stop_ev.set() + has_stopped_ev.wait() with self.assertRaisesRegexp(RuntimeError, "threads still running"): coord.join(threads, stop_grace_period_secs=stop_grace_period) TestWithGracePeriod(1e-10) diff --git a/tensorflow/python/training/device_setter.py b/tensorflow/python/training/device_setter.py index 4c723f55dc756f3bbc80abe26004185bb1833d14..a414116a741c0b38107833769b964daa97c13740 100644 --- a/tensorflow/python/training/device_setter.py +++ b/tensorflow/python/training/device_setter.py @@ -17,7 +17,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -from tensorflow.core.framework import graph_pb2 +from tensorflow.core.framework import node_def_pb2 from tensorflow.python.framework import device as pydev from tensorflow.python.platform import tf_logging as logging from tensorflow.python.training import server_lib @@ -76,7 +76,7 @@ class _ReplicaDeviceChooser(object): current_device = pydev.DeviceSpec.from_string(op.device or "") spec = pydev.DeviceSpec() if self._ps_tasks and self._ps_device: - node_def = op if isinstance(op, graph_pb2.NodeDef) else op.node_def + node_def = op if isinstance(op, node_def_pb2.NodeDef) else op.node_def if node_def.op in self._ps_ops: device_string = "%s/task:%d" % (self._ps_device, self._next_task()) if self._merge_devices: @@ -150,7 +150,7 @@ def replica_device_setter(ps_tasks=0, ps_device="/job:ps", else: cluster_spec = server_lib.ClusterSpec(cluster).as_dict() # Get ps_job_name from ps_device by striping "/job:". - ps_job_name = ps_device.lstrip("/job:") + ps_job_name = pydev.DeviceSpec.from_string(ps_device).job if ps_job_name not in cluster_spec or cluster_spec[ps_job_name] is None: return None ps_tasks = len(cluster_spec[ps_job_name]) diff --git a/tensorflow/python/training/device_setter_test.py b/tensorflow/python/training/device_setter_test.py index 8fb2768c5f77c7d1ba087791a6d4feb3bbfbcd4d..607cf2d20db5a18a9909742c47c2f7f3a948765d 100644 --- a/tensorflow/python/training/device_setter_test.py +++ b/tensorflow/python/training/device_setter_test.py @@ -77,6 +77,23 @@ class DeviceSetterTest(tf.test.TestCase): self.assertDeviceEqual("/job:moon/task:1", w.device) self.assertDeviceEqual("/job:moon/task:1", w.initializer.device) self.assertDeviceEqual("/job:sun", a.device) + + def testPS2TasksWithCPUConstraint(self): + cluster_spec = tf.train.ClusterSpec({ + "sun": ["sun0:2222", "sun1:2222", "sun2:2222"], + "moon": ["moon0:2222", "moon1:2222"]}) + + with tf.device(tf.train.replica_device_setter( + ps_device="/job:moon/cpu:0", worker_device="/job:sun", + cluster=cluster_spec.as_cluster_def())): + v = tf.Variable([1, 2]) + w = tf.Variable([2, 1]) + a = v + w + self.assertDeviceEqual("/job:moon/task:0/cpu:0", v.device) + self.assertDeviceEqual("/job:moon/task:0/cpu:0", v.initializer.device) + self.assertDeviceEqual("/job:moon/task:1/cpu:0", w.device) + self.assertDeviceEqual("/job:moon/task:1/cpu:0", w.initializer.device) + self.assertDeviceEqual("/job:sun", a.device) if __name__ == "__main__": diff --git a/tensorflow/python/training/saver.py b/tensorflow/python/training/saver.py index 6bd6362672c30ef99122ddda82ab0500aa54d2a6..c4f86b7a9e5d8eaa371aecc2b750bce8427e2cd5 100644 --- a/tensorflow/python/training/saver.py +++ b/tensorflow/python/training/saver.py @@ -396,7 +396,8 @@ class BaseSaverBuilder(object): name="restore_shard")) return control_flow_ops.group(*sharded_restores, name="restore_all") - def _IsVariable(self, v): + @staticmethod + def _IsVariable(v): return isinstance(v, ops.Tensor) and (v.op.type == "Variable" or v.op.type == "AutoReloadVariable") @@ -427,7 +428,8 @@ class BaseSaverBuilder(object): per_device[canonical_device.pop()].append(saveable) return sorted(per_device.items(), key=lambda t: t[0]) - def _OpListToDict(self, op_list): + @staticmethod + def OpListToDict(op_list): """Create a dictionary of names to operation lists. Args: @@ -462,7 +464,7 @@ class BaseSaverBuilder(object): names_to_saveables[name] = [var] else: var = ops.convert_to_tensor(var, as_ref=True) - if not self._IsVariable(var): + if not BaseSaverBuilder._IsVariable(var): raise TypeError("Variable to save is not a Variable: %s" % var) name = var.op.name if name in names_to_saveables: @@ -489,7 +491,7 @@ class BaseSaverBuilder(object): (this also applies to slices of SlicedVariables). """ if not isinstance(names_to_saveables, dict): - names_to_saveables = self._OpListToDict(names_to_saveables) + names_to_saveables = BaseSaverBuilder.OpListToDict(names_to_saveables) saveables = [] seen_ops = set() @@ -523,7 +525,7 @@ class BaseSaverBuilder(object): else: # A variable or tensor. variable = ops.convert_to_tensor(op, as_ref=True) - if not self._IsVariable(variable): + if not BaseSaverBuilder._IsVariable(variable): raise TypeError("names_to_saveables must be a dict mapping string " "names to Tensors/Variables. Not a variable: %s" % variable) @@ -879,7 +881,8 @@ class Saver(object): restore_sequentially=False, saver_def=None, builder=None, - defer_build=False): + defer_build=False, + allow_empty=False): """Creates a `Saver`. The constructor adds ops to save and restore variables. @@ -941,6 +944,9 @@ class Saver(object): defer_build: If `True`, defer adding the save and restore ops to the `build()` call. In that case `build()` should be called before finalizing the graph or using the saver. + allow_empty: If `False` (default) raise an error if there are no + variables in the graph. Otherwise, construct the saver anyway and make + it a no-op. Raises: TypeError: If `var_list` is invalid. @@ -960,6 +966,8 @@ class Saver(object): self.saver_def = saver_def self._builder = builder self._is_built = False + self._allow_empty = allow_empty + self._is_empty = None if not defer_build: self.build() if self.saver_def: @@ -977,7 +985,12 @@ class Saver(object): # pylint: disable=protected-access self._var_list = variables._all_saveable_objects() if not self._var_list: - raise ValueError("No variables to save") + if self._allow_empty: + self._is_empty = True + return + else: + raise ValueError("No variables to save") + self._is_empty = False self.saver_def = self._builder.build( self._var_list, reshape=self._reshape, @@ -1205,6 +1218,7 @@ class Saver(object): A string: path at which the variables were saved. If the saver is sharded, this string ends with: '-?????-of-nnnnn' where 'nnnnn' is the number of shards created. + If the saver is empty, returns None. Raises: TypeError: If `sess` is not a `Session`. @@ -1214,7 +1228,7 @@ class Saver(object): """ if not self._is_built: raise RuntimeError( - "`build()` should be called before save if deffer_build==True") + "`build()` should be called before save if defer_build==True") if latest_filename is None: latest_filename = "checkpoint" @@ -1242,25 +1256,26 @@ class Saver(object): if not isinstance(sess, session.SessionInterface): raise TypeError("'sess' must be a Session; %s" % sess) - # Note a few lines above save_path was set to os.path.dirname(save_path) - if not os.path.exists(save_path): - raise ValueError("Parent directory {} doesn't exist, can't save.".format(save_path)) - - model_checkpoint_path = sess.run( - self.saver_def.save_tensor_name, - {self.saver_def.filename_tensor_name: checkpoint_file}) - model_checkpoint_path = compat.as_str(model_checkpoint_path) - self._MaybeDeleteOldCheckpoints( - model_checkpoint_path, meta_graph_suffix=meta_graph_suffix) - update_checkpoint_state(save_path, model_checkpoint_path, - self.last_checkpoints, latest_filename) + if not self._is_empty: + model_checkpoint_path = sess.run( + self.saver_def.save_tensor_name, + {self.saver_def.filename_tensor_name: checkpoint_file}) + model_checkpoint_path = compat.as_str(model_checkpoint_path) + self._MaybeDeleteOldCheckpoints( + model_checkpoint_path, meta_graph_suffix=meta_graph_suffix) + update_checkpoint_state(save_path, model_checkpoint_path, + self.last_checkpoints, latest_filename) + if write_meta_graph: meta_graph_filename = self._MetaGraphFilename( checkpoint_file, meta_graph_suffix=meta_graph_suffix) with sess.graph.as_default(): self.export_meta_graph(meta_graph_filename) - return model_checkpoint_path + if self._is_empty: + return None + else: + return model_checkpoint_path def export_meta_graph(self, filename=None, @@ -1301,6 +1316,9 @@ class Saver(object): Raises: ValueError: If the given `save_path` does not point to a file. """ + if self._is_empty: + return + if not file_io.get_matching_files( _prefix_to_checkpoint_path(save_path, self.saver_def.version)): raise ValueError("Restore called with invalid save path %s" % save_path) diff --git a/tensorflow/python/training/saver_large_partitioned_variable_test.py b/tensorflow/python/training/saver_large_partitioned_variable_test.py index bc071eb270e83bf5eaaacfff5c96da5a9fc2723c..4c0526cc42b97346e295888af116c9edcd4edf9c 100644 --- a/tensorflow/python/training/saver_large_partitioned_variable_test.py +++ b/tensorflow/python/training/saver_large_partitioned_variable_test.py @@ -34,7 +34,8 @@ class SaverLargePartitionedVariableTest(tf.test.TestCase): with tf.device("/cpu:0"): # Create a partitioned variable which is larger than int32 size but # split into smaller sized variables. - init = lambda shape, dtype: tf.constant(True, dtype, shape) + init = lambda shape, dtype, partition_info: tf.constant( + True, dtype, shape) partitioned_var = tf.create_partitioned_variables( [1 << 31], [4], init, dtype=tf.bool, name=var_name) tf.initialize_all_variables().run() diff --git a/tensorflow/python/training/saver_test.py b/tensorflow/python/training/saver_test.py index 85d0392b0d6cccb972b3c460545a366cb6e4661e..92700c9414f40b667ec4ff36a27b801af763c8ff 100644 --- a/tensorflow/python/training/saver_test.py +++ b/tensorflow/python/training/saver_test.py @@ -338,6 +338,17 @@ class SaverTest(tf.test.TestCase): # The cached readers should know to re-read the file. self._SaveAndLoad("var1", 1.1, 2.2, save_path) + def testAllowEmpty(self): + save_path = os.path.join(self.get_temp_dir(), "allow_empty") + with self.test_session() as sess: + _ = tf.constant(1) + save = tf.train.Saver(allow_empty=True) + val = save.save(sess, save_path) + self.assertIsNone(val) + with self.test_session() as sess: + save = tf.train.Saver(allow_empty=True) + save.restore(sess, save_path) + def testGPU(self): if not tf.test.is_gpu_available(): return diff --git a/tensorflow/python/training/server_lib.py b/tensorflow/python/training/server_lib.py index 99e55aa36532318eff617811a3724c90fae58d40..b537eea61b34b992ab16ef3765c200b11d62d404 100644 --- a/tensorflow/python/training/server_lib.py +++ b/tensorflow/python/training/server_lib.py @@ -282,6 +282,18 @@ class ClusterSpec(object): "job names to lists of network addresses, or a " "`ClusterDef` protocol buffer") + def __nonzero__(self): + return bool(self._cluster_spec) + + # Python 3.x + __bool__ = __nonzero__ + + def __eq__(self, other): + return self._cluster_spec == other + + def __ne__(self, other): + return self._cluster_spec != other + def as_dict(self): """Returns a dictionary from job names to lists of network addresses.""" return self._cluster_spec diff --git a/tensorflow/python/training/server_lib_test.py b/tensorflow/python/training/server_lib_test.py index 9d71d5490999f4edb9e395c0e4ce76b5c85e8cce..d5da5dd2329ff89a65ad2d4c242e09fea5db1ff8 100644 --- a/tensorflow/python/training/server_lib_test.py +++ b/tensorflow/python/training/server_lib_test.py @@ -356,7 +356,10 @@ class ServerDefTest(tf.test.TestCase): cluster_spec = tf.train.ClusterSpec(cluster_def) self.assertProtoEquals(cluster_def, cluster_spec.as_cluster_def()) - def testClusterSpec(self): + +class ClusterSpecTest(tf.test.TestCase): + + def testProtoDictDefEquivalences(self): cluster_spec = tf.train.ClusterSpec( {"ps": ["ps0:2222", "ps1:2222"], "worker": ["worker0:2222", "worker1:2222", "worker2:2222"]}) @@ -379,6 +382,32 @@ class ServerDefTest(tf.test.TestCase): expected_proto, tf.train.ClusterSpec(cluster_spec.as_dict()).as_cluster_def()) + def testEmptyClusterSpecIsFalse(self): + self.assertFalse(tf.train.ClusterSpec({})) + + def testNonEmptyClusterSpecIsTrue(self): + self.assertTrue(tf.train.ClusterSpec({"job": ["host:port"]})) + + def testEq(self): + self.assertEquals(tf.train.ClusterSpec({}), tf.train.ClusterSpec({})) + self.assertEquals( + tf.train.ClusterSpec({"job": ["host:2222"]}), + tf.train.ClusterSpec({"job": ["host:2222"]}),) + + def testNe(self): + self.assertNotEquals( + tf.train.ClusterSpec({}), + tf.train.ClusterSpec({"job": ["host:2223"]}),) + self.assertNotEquals( + tf.train.ClusterSpec({"job1": ["host:2222"]}), + tf.train.ClusterSpec({"job2": ["host:2222"]}),) + self.assertNotEquals( + tf.train.ClusterSpec({"job": ["host:2222"]}), + tf.train.ClusterSpec({"job": ["host:2223"]}),) + self.assertNotEquals( + tf.train.ClusterSpec({"job": ["host:2222", "host:2223"]}), + tf.train.ClusterSpec({"job": ["host:2223", "host:2222"]}),) + if __name__ == "__main__": tf.test.main() diff --git a/tensorflow/stream_executor/dso_loader.cc b/tensorflow/stream_executor/dso_loader.cc index 5113f2febe29b5a5cda2a4ea963c50b2cdf2bd3c..4a96b048c4ae789080f6e34e6a7997ec1b74a283 100644 --- a/tensorflow/stream_executor/dso_loader.cc +++ b/tensorflow/stream_executor/dso_loader.cc @@ -13,6 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +// TODO(jhen): Replace hardcoded, platform specific path strings in GetXXXPath() +// with a function in e.g. cuda.h. + #include "tensorflow/stream_executor/dso_loader.h" #include diff --git a/tensorflow/stream_executor/lib/notification.h b/tensorflow/stream_executor/lib/notification.h index 26873c7a951efc5e4dc3d18839d9bd55a9b6b811..9bb3e170dc7c13ecaa636887315b4bc5cfc82f2b 100644 --- a/tensorflow/stream_executor/lib/notification.h +++ b/tensorflow/stream_executor/lib/notification.h @@ -16,7 +16,7 @@ limitations under the License. #ifndef TENSORFLOW_STREAM_EXECUTOR_LIB_NOTIFICATION_H_ #define TENSORFLOW_STREAM_EXECUTOR_LIB_NOTIFICATION_H_ -#include "tensorflow/core/lib/core/notification.h" +#include "tensorflow/core/platform/notification.h" namespace perftools { namespace gputools { diff --git a/tensorflow/tensorboard/BUILD b/tensorflow/tensorboard/BUILD index c957f3720fb08a31a92458873d7302f958ed9c73..ccb311b6f2b1880c3028a75bba2417742b16ba1a 100644 --- a/tensorflow/tensorboard/BUILD +++ b/tensorflow/tensorboard/BUILD @@ -20,7 +20,10 @@ filegroup( py_binary( name = "tensorboard", - srcs = ["tensorboard.py"], + srcs = [ + "__main__.py", + "tensorboard.py", + ], data = [":frontend"], srcs_version = "PY2AND3", deps = [ diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG index 6f4247a6255c99f420d1df558d68745592862ff7..f64f5d8d85ac0230d36724bd7e6ba351a95b4942 100644 --- a/tensorflow/tensorboard/TAG +++ b/tensorflow/tensorboard/TAG @@ -1 +1 @@ -26 +27 diff --git a/tensorflow/tensorboard/__main__.py b/tensorflow/tensorboard/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..187140954d17402fd25d65f55f726c73562e80a9 --- /dev/null +++ b/tensorflow/tensorboard/__main__.py @@ -0,0 +1,25 @@ +# 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. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import sys + +from tensorflow.tensorboard.tensorboard import main + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tensorflow/tensorboard/backend/handler.py b/tensorflow/tensorboard/backend/handler.py index 0fc094f4e64e5fdecc93233f145f35ebbc57639f..1c1e9411a4dbf1ce216cc12c2d8d562d6d6f9baf 100644 --- a/tensorflow/tensorboard/backend/handler.py +++ b/tensorflow/tensorboard/backend/handler.py @@ -31,7 +31,8 @@ import mimetypes import os import re -from six import BytesIO, StringIO +from six import BytesIO +from six import StringIO from six.moves import BaseHTTPServer from six.moves import urllib from six.moves import xrange # pylint: disable=redefined-builtin diff --git a/tensorflow/tensorboard/bower.json b/tensorflow/tensorboard/bower.json index 20095d92750a09eaec9b60da600338ecf9a2b132..355fd9684b4f9b2fa49384e669e11a1da6466bcf 100644 --- a/tensorflow/tensorboard/bower.json +++ b/tensorflow/tensorboard/bower.json @@ -48,6 +48,7 @@ "iron-flex-layout": "PolymerElements/iron-flex-layout#1.3.0", "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#1.0.6", "iron-icon": "PolymerElements/iron-icon#1.0.8", + "iron-icons": "PolymerElements/iron-icons#1.1.3", "iron-iconset-svg": "PolymerElements/iron-iconset-svg#1.0.9", "iron-input": "PolymerElements/iron-input#1.0.10", "iron-list": "PolymerElements/iron-list#1.1.7", diff --git a/tensorflow/tensorboard/bower/BUILD b/tensorflow/tensorboard/bower/BUILD index 4b43b5584438962cb3529f0ef54b1c6d412fec25..90d9910205bf387809c4aa5ecc4d524717f28829 100644 --- a/tensorflow/tensorboard/bower/BUILD +++ b/tensorflow/tensorboard/bower/BUILD @@ -22,6 +22,7 @@ filegroup( "@iron_flex_layout//:iron_flex_layout", "@iron_form_element_behavior//:iron_form_element_behavior", "@iron_icon//:iron_icon", + "@iron_icons//:iron_icons", "@iron_iconset_svg//:iron_iconset_svg", "@iron_input//:iron_input", "@iron_list//:iron_list", diff --git a/tensorflow/tensorboard/components/index.html b/tensorflow/tensorboard/components/index.html index 7bf454dba0c32f44abd81ee7a73772d12b163a19..afd151869bd540d234f2f746341453ce81a9784c 100644 --- a/tensorflow/tensorboard/components/index.html +++ b/tensorflow/tensorboard/components/index.html @@ -1,4 +1,21 @@ - + + + diff --git a/tensorflow/tensorboard/components/tf-audio-dashboard/demo/index.html b/tensorflow/tensorboard/components/tf-audio-dashboard/demo/index.html index 2f53b1fdde89119f9315b3f2ad6767eda2d44b58..e6c92b095e3781b00f1bcdf0611c988c4d5e5c2c 100644 --- a/tensorflow/tensorboard/components/tf-audio-dashboard/demo/index.html +++ b/tensorflow/tensorboard/components/tf-audio-dashboard/demo/index.html @@ -1,4 +1,21 @@ - + + + diff --git a/tensorflow/tensorboard/components/tf-audio-dashboard/test/index.html b/tensorflow/tensorboard/components/tf-audio-dashboard/test/index.html index 75349fbabef3c1bb605eadc25308d612fc64bc45..421a6658b025967ef4a1c785849fea1a1f418635 100644 --- a/tensorflow/tensorboard/components/tf-audio-dashboard/test/index.html +++ b/tensorflow/tensorboard/components/tf-audio-dashboard/test/index.html @@ -1,4 +1,21 @@ - + + + diff --git a/tensorflow/tensorboard/components/tf-audio-dashboard/tf-audio-dashboard.html b/tensorflow/tensorboard/components/tf-audio-dashboard/tf-audio-dashboard.html index 6b7ccb0f27cc5a1bedc64bc8e4fbe94e71050b6b..ad879210d6f95c616f8841c05e990799de8942ed 100644 --- a/tensorflow/tensorboard/components/tf-audio-dashboard/tf-audio-dashboard.html +++ b/tensorflow/tensorboard/components/tf-audio-dashboard/tf-audio-dashboard.html @@ -1,3 +1,20 @@ + + @@ -6,6 +23,9 @@