diff --git a/.clang-format b/.clang-format
index c5ab0983b7530..5c0f059e15f3f 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,5 @@
-BasedOnStyle: Chromium
-ColumnLimit: 80
+BasedOnStyle: Google
+ColumnLimit: 90
DerivePointerAlignment: false
IndentCaseLabels: false
PointerAlignment: Right
-SpaceAfterCStyleCast: true
diff --git a/.gitignore b/.gitignore
index abd60923e6314..91189b6f9c41a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,26 +4,17 @@
/python/build
/python/dist
/python/flatbuffers-1.7.1/
-/src/common/thirdparty/redis
-/src/thirdparty/arrow
/flatbuffers-1.7.1/
-/src/thirdparty/boost/
-/src/thirdparty/boost_1_65_1/
-/src/thirdparty/boost_1_60_0/
-/src/thirdparty/catapult/
-/src/thirdparty/flatbuffers/
-/src/thirdparty/parquet-cpp
/thirdparty/pkg/
# Files generated by flatc should be ignored
-/src/common/format/*.py
-/src/common/format/*_generated.h
-/src/plasma/format/
-/src/local_scheduler/format/*_generated.h
/src/ray/gcs/format/*_generated.h
/src/ray/object_manager/format/*_generated.h
/src/ray/raylet/format/*_generated.h
+# Modin source files
+/python/ray/modin
+
# Redis temporary files
*dump.rdb
@@ -54,9 +45,6 @@ python/.eggs
*.dylib
*.dll
-# Cython-generated files
-*.c
-
# Incremental linking files
*.ilk
diff --git a/.travis.yml b/.travis.yml
index 47bef360e51e5..795dff67b6108 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -53,8 +53,8 @@ matrix:
- sphinx-build -W -b html -d _build/doctrees source _build/html
- cd ..
# Run Python linting, ignore dict vs {} (C408), others are defaults
- - flake8 --exclude=python/ray/core/src/common/flatbuffers_ep-prefix/,python/ray/core/generated/,src/common/format/,doc/source/conf.py,python/ray/cloudpickle/ --ignore=C408,E121,E123,E126,E226,E24,E704,W503,W504
- - .travis/yapf.sh --all
+ - flake8 --exclude=python/ray/core/generated/,doc/source/conf.py,python/ray/cloudpickle/ --ignore=C408,E121,E123,E126,E226,E24,E704,W503,W504,W605
+ - .travis/format.sh --all
- os: linux
dist: trusty
@@ -69,16 +69,9 @@ matrix:
script:
- cd build
- - bash ../src/common/test/run_valgrind.sh
- - bash ../src/plasma/test/run_valgrind.sh
- - bash ../src/local_scheduler/test/run_valgrind.sh
- bash ../src/ray/test/run_object_manager_valgrind.sh
- cd ..
- - python ./python/ray/plasma/test/test.py valgrind
- - python ./python/ray/local_scheduler/test/test.py valgrind
- # - python ./python/ray/global_scheduler/test/test.py valgrind
-
# Build Linux wheels.
- os: linux
dist: trusty
@@ -107,63 +100,6 @@ matrix:
env:
- PYTHON=3.5
- RAY_USE_NEW_GCS=on
- - RAY_USE_XRAY=1
-
- - os: linux
- dist: trusty
- env: PYTHON=3.5 RAY_USE_XRAY=1
- install:
- - ./.travis/install-dependencies.sh
- - export PATH="$HOME/miniconda/bin:$PATH"
- - ./.travis/install-ray.sh
- - ./.travis/install-cython-examples.sh
- script:
- - export PATH="$HOME/miniconda/bin:$PATH"
- # The following is needed so cloudpickle can find some of the
- # class definitions: The main module of tests that are run
- # with pytest have the same name as the test file -- and this
- # module is only found if the test directory is in the PYTHONPATH.
- - export PYTHONPATH="$PYTHONPATH:./test/"
-
- - python -m pytest -v python/ray/common/test/test.py
- - python -m pytest -v python/ray/common/redis_module/runtest.py
- - python -m pytest -v python/ray/plasma/test/test.py
- # - python -m pytest -v python/ray/local_scheduler/test/test.py
- # - python -m pytest -v python/ray/global_scheduler/test/test.py
-
- - python -m pytest -v python/ray/test/test_global_state.py
- - python -m pytest -v python/ray/test/test_queue.py
- - python -m pytest -v test/xray_test.py
-
- - python -m pytest -v test/runtest.py
- - python -m pytest -v test/array_test.py
- - python -m pytest -v test/actor_test.py
- - python -m pytest -v test/autoscaler_test.py
- - python -m pytest -v test/tensorflow_test.py
- - python -m pytest -v test/failure_test.py
- - python -m pytest -v test/microbenchmarks.py
- - python -m pytest -v test/stress_tests.py
- - pytest test/component_failures_test.py
- - python test/multi_node_test.py
- - python -m pytest -v test/recursion_test.py
- - pytest test/monitor_test.py
- - python -m pytest -v test/cython_test.py
- - python -m pytest -v test/credis_test.py
-
- # ray tune tests
- - python python/ray/tune/test/dependency_test.py
- - python -m pytest -v python/ray/tune/test/trial_runner_test.py
- - python -m pytest -v python/ray/tune/test/trial_scheduler_test.py
- - python -m pytest -v python/ray/tune/test/experiment_test.py
- - python -m pytest -v python/ray/tune/test/tune_server_test.py
- - python -m pytest -v python/ray/tune/test/ray_trial_executor_test.py
- - python -m pytest -v python/ray/tune/test/automl_searcher_test.py
-
- # ray rllib tests
- - python -m pytest -v python/ray/rllib/test/test_catalog.py
- - python -m pytest -v python/ray/rllib/test/test_filters.py
- - python -m pytest -v python/ray/rllib/test/test_optimizers.py
- - python -m pytest -v python/ray/rllib/test/test_evaluators.py
install:
@@ -181,12 +117,10 @@ install:
- ./src/ray/raylet/lineage_cache_test
- ./src/ray/raylet/task_dependency_manager_test
- ./src/ray/raylet/reconstruction_policy_test
+ - ./src/ray/raylet/client_connection_test
- ./src/ray/util/logging_test --gtest_filter=PrintLogTest*
- ./src/ray/util/signal_test
- - bash ../src/common/test/run_tests.sh
- - bash ../src/plasma/test/run_tests.sh
- - bash ../src/local_scheduler/test/run_tests.sh
- cd ..
script:
@@ -197,14 +131,27 @@ script:
# module is only found if the test directory is in the PYTHONPATH.
- export PYTHONPATH="$PYTHONPATH:./test/"
- - python -m pytest -v python/ray/common/test/test.py
- - python -m pytest -v python/ray/common/redis_module/runtest.py
- - python -m pytest -v python/ray/plasma/test/test.py
- - python -m pytest -v python/ray/local_scheduler/test/test.py
- - python -m pytest -v python/ray/global_scheduler/test/test.py
+ # ray tune tests
+ - python python/ray/tune/test/dependency_test.py
+ - python -m pytest -v python/ray/tune/test/trial_runner_test.py
+ - python -m pytest -v python/ray/tune/test/trial_scheduler_test.py
+ - python -m pytest -v python/ray/tune/test/experiment_test.py
+ - python -m pytest -v python/ray/tune/test/tune_server_test.py
+ - python -m pytest -v python/ray/tune/test/ray_trial_executor_test.py
+ - python -m pytest -v python/ray/tune/test/automl_searcher_test.py
+
+ # ray rllib tests
+ - python -m pytest -v python/ray/rllib/test/test_catalog.py
+ - python -m pytest -v python/ray/rllib/test/test_filters.py
+ - python -m pytest -v python/ray/rllib/test/test_optimizers.py
+ - python -m pytest -v python/ray/rllib/test/test_evaluators.py
+
+ # Python3.5+ only. Otherwise we will get `SyntaxError` regardless of how we set the tester.
+ - python -c 'import sys;exit(sys.version_info>=(3,5))' || python -m pytest -v python/ray/experimental/test/async_test.py
- python -m pytest -v python/ray/test/test_global_state.py
- python -m pytest -v python/ray/test/test_queue.py
+ - python -m pytest -v python/ray/test/test_ray_init.py
- python -m pytest -v test/xray_test.py
- python -m pytest -v test/runtest.py
@@ -216,26 +163,19 @@ script:
- python -m pytest -v test/microbenchmarks.py
- python -m pytest -v test/stress_tests.py
- python -m pytest -v test/component_failures_test.py
- - python test/multi_node_test.py
+ - python -m pytest -v test/multi_node_test.py
+ - python -m pytest -v test/multi_node_test_2.py
- python -m pytest -v test/recursion_test.py
- python -m pytest -v test/monitor_test.py
- python -m pytest -v test/cython_test.py
- python -m pytest -v test/credis_test.py
+ - python -m pytest -v test/node_manager_test.py
- # ray tune tests
- - python python/ray/tune/test/dependency_test.py
- - python -m pytest -v python/ray/tune/test/trial_runner_test.py
- - python -m pytest -v python/ray/tune/test/trial_scheduler_test.py
- - python -m pytest -v python/ray/tune/test/experiment_test.py
- - python -m pytest -v python/ray/tune/test/tune_server_test.py
- - python -m pytest -v python/ray/tune/test/ray_trial_executor_test.py
- - python -m pytest -v python/ray/tune/test/automl_searcher_test.py
+ # ray temp file tests
+ - python -m pytest -v test/tempfile_test.py
- # ray rllib tests
- - python -m pytest -v python/ray/rllib/test/test_catalog.py
- - python -m pytest -v python/ray/rllib/test/test_filters.py
- - python -m pytest -v python/ray/rllib/test/test_optimizers.py
- - python -m pytest -v python/ray/rllib/test/test_evaluators.py
+ # modin test files
+ - python python/ray/test/test_modin.py
deploy:
- provider: s3
diff --git a/.travis/yapf.sh b/.travis/format.sh
similarity index 74%
rename from .travis/yapf.sh
rename to .travis/format.sh
index d90aec89531d2..9313e641065a8 100755
--- a/.travis/yapf.sh
+++ b/.travis/format.sh
@@ -1,4 +1,6 @@
#!/usr/bin/env bash
+# YAPF + Clang formatter (if installed). This script formats all changed files from the last mergebase.
+# You are encouraged to run this locally before pushing changes for review.
# Cause the script to exit if a single command fails
set -eo pipefail
@@ -28,7 +30,6 @@ YAPF_EXCLUDES=(
'--exclude' 'python/build/*'
'--exclude' 'python/ray/pyarrow_files/*'
'--exclude' 'python/ray/core/src/ray/gcs/*'
- '--exclude' 'python/ray/common/thirdparty/*'
)
# Format specified files
@@ -50,6 +51,18 @@ format_changed() {
if ! git diff --diff-filter=ACM --quiet --exit-code "$MERGEBASE" -- '*.py' &>/dev/null; then
git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.py' | xargs -P 5 \
yapf --in-place "${YAPF_EXCLUDES[@]}" "${YAPF_FLAGS[@]}"
+ if which flake8 >/dev/null; then
+ git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.py' | xargs -P 5 \
+ flake8 --exclude=python/ray/core/generated/,doc/source/conf.py,python/ray/cloudpickle/ \
+ --ignore=C408,E121,E123,E126,E226,E24,E704,W503,W504,W605
+ fi
+ fi
+
+ if which clang-format >/dev/null; then
+ if ! git diff --diff-filter=ACM --quiet --exit-code "$MERGEBASE" -- '*.cc' '*.h' &>/dev/null; then
+ git diff --name-only --diff-filter=ACM "$MERGEBASE" -- '*.cc' '*.h' | xargs -P 5 \
+ clang-format -i
+ fi
fi
}
diff --git a/.travis/install-dependencies.sh b/.travis/install-dependencies.sh
index 1c6c3a342a616..5bae4ba87f8db 100755
--- a/.travis/install-dependencies.sh
+++ b/.travis/install-dependencies.sh
@@ -24,8 +24,8 @@ if [[ "$PYTHON" == "2.7" ]] && [[ "$platform" == "linux" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda2-4.5.4-Linux-x86_64.sh -O miniconda.sh -nv
bash miniconda.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
- pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.22 requests \
- feather-format lxml openpyxl xlrd
+ pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.23.4 requests \
+ feather-format lxml openpyxl xlrd py-spy setproctitle faulthandler pytest-timeout mock
elif [[ "$PYTHON" == "3.5" ]] && [[ "$platform" == "linux" ]]; then
sudo apt-get update
sudo apt-get install -y cmake pkg-config python-dev python-numpy build-essential autoconf curl libtool unzip
@@ -33,8 +33,8 @@ elif [[ "$PYTHON" == "3.5" ]] && [[ "$platform" == "linux" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-4.5.4-Linux-x86_64.sh -O miniconda.sh -nv
bash miniconda.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
- pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.22 requests \
- feather-format lxml openpyxl xlrd
+ pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.23.4 requests \
+ feather-format lxml openpyxl xlrd py-spy setproctitle pytest-timeout
elif [[ "$PYTHON" == "2.7" ]] && [[ "$platform" == "macosx" ]]; then
# check that brew is installed
which -s brew
@@ -50,8 +50,8 @@ elif [[ "$PYTHON" == "2.7" ]] && [[ "$platform" == "macosx" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda2-4.5.4-MacOSX-x86_64.sh -O miniconda.sh -nv
bash miniconda.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
- pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.22 requests \
- feather-format lxml openpyxl xlrd
+ pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.23.4 requests \
+ feather-format lxml openpyxl xlrd py-spy setproctitle faulthandler pytest-timeout mock
elif [[ "$PYTHON" == "3.5" ]] && [[ "$platform" == "macosx" ]]; then
# check that brew is installed
which -s brew
@@ -67,8 +67,8 @@ elif [[ "$PYTHON" == "3.5" ]] && [[ "$platform" == "macosx" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-4.5.4-MacOSX-x86_64.sh -O miniconda.sh -nv
bash miniconda.sh -b -p $HOME/miniconda
export PATH="$HOME/miniconda/bin:$PATH"
- pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.22 requests \
- feather-format lxml openpyxl xlrd
+ pip install -q cython==0.27.3 cmake tensorflow gym opencv-python pyyaml pandas==0.23.4 requests \
+ feather-format lxml openpyxl xlrd py-spy setproctitle pytest-timeout
elif [[ "$LINT" == "1" ]]; then
sudo apt-get update
sudo apt-get install -y cmake build-essential autoconf curl libtool unzip
diff --git a/.travis/test-wheels.sh b/.travis/test-wheels.sh
index 1b77209c3ddc7..f7870ea52d496 100755
--- a/.travis/test-wheels.sh
+++ b/.travis/test-wheels.sh
@@ -56,10 +56,10 @@ if [[ "$platform" == "linux" ]]; then
# Check that the other wheels are present.
NUMBER_OF_WHEELS=$(ls -1q $ROOT_DIR/../.whl/*.whl | wc -l)
- if [[ "$NUMBER_OF_WHEELS" != "4" ]]; then
+ if [[ "$NUMBER_OF_WHEELS" != "5" ]]; then
echo "Wrong number of wheels found."
ls -l $ROOT_DIR/../.whl/
- exit 1
+ exit 2
fi
elif [[ "$platform" == "macosx" ]]; then
@@ -67,12 +67,14 @@ elif [[ "$platform" == "macosx" ]]; then
PY_MMS=("2.7"
"3.4"
"3.5"
- "3.6")
+ "3.6"
+ "3.7")
# This array is just used to find the right wheel.
PY_WHEEL_VERSIONS=("27"
"34"
"35"
- "36")
+ "36"
+ "37")
for ((i=0; i<${#PY_MMS[@]}; ++i)); do
PY_MM=${PY_MMS[i]}
@@ -92,5 +94,5 @@ elif [[ "$platform" == "macosx" ]]; then
done
else
echo "Unrecognized environment."
- exit 1
+ exit 3
fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d02e88a5c4203..a6734e62ce144 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,18 +82,15 @@ include_directories(SYSTEM ${PLASMA_INCLUDE_DIR})
include_directories("${CMAKE_CURRENT_LIST_DIR}/src/")
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/ray/)
-add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/common/)
-add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/plasma/)
-add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/local_scheduler/)
-add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/global_scheduler/)
# final target copy_ray
add_custom_target(copy_ray ALL)
# copy plasma_store_server
add_custom_command(TARGET copy_ray POST_BUILD
+ COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/src/plasma
COMMAND ${CMAKE_COMMAND} -E
- copy ${ARROW_HOME}/bin/plasma_store_server ${CMAKE_CURRENT_BINARY_DIR}/src/plasma)
+ copy ${ARROW_HOME}/bin/plasma_store_server ${CMAKE_CURRENT_BINARY_DIR}/src/plasma/)
if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
# add pyarrow as the dependency
@@ -102,12 +99,9 @@ if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
# NOTE: The lists below must be kept in sync with ray/python/setup.py.
set(ray_file_list
- "src/common/thirdparty/redis/src/redis-server"
- "src/common/redis_module/libray_redis_module.so"
- "src/plasma/plasma_manager"
- "src/local_scheduler/local_scheduler"
- "src/local_scheduler/liblocal_scheduler_library_python.so"
- "src/global_scheduler/global_scheduler"
+ "src/ray/thirdparty/redis/src/redis-server"
+ "src/ray/gcs/redis_module/libray_redis_module.so"
+ "src/ray/raylet/liblocal_scheduler_library_python.so"
"src/ray/raylet/raylet_monitor"
"src/ray/raylet/raylet")
@@ -117,7 +111,10 @@ if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
list(APPEND ray_file_list "src/credis/redis/src/redis-server")
endif()
- if (DEFINED ENV{INCLUDE_UI} AND "$ENV{INCLUDE_UI}" STREQUAL "1")
+ # The goal of the if statement below is to require the catapult files to be
+ # present INCLUDE_UI=1 is set and to include the UI files if they are present.
+ # This should match the logic in build_ui.sh.
+ if (EXISTS "${CMAKE_BINARY_DIR}/src/catapult_files/index.html" OR "$ENV{INCLUDE_UI}" STREQUAL "1")
list(APPEND ray_file_list "src/catapult_files/index.html")
list(APPEND ray_file_list "src/catapult_files/trace_viewer_full.html")
endif()
@@ -154,5 +151,6 @@ if ("${CMAKE_RAY_LANG_JAVA}" STREQUAL "YES")
# copy libplasma_java files
add_custom_command(TARGET copy_ray POST_BUILD
- COMMAND bash -c "cp ${ARROW_LIBRARY_DIR}/libplasma_java.* ${CMAKE_CURRENT_BINARY_DIR}/src/plasma")
+ COMMAND bash -c "mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/src/plasma"
+ COMMAND bash -c "cp ${ARROW_LIBRARY_DIR}/libplasma_java.* ${CMAKE_CURRENT_BINARY_DIR}/src/plasma/")
endif()
diff --git a/README.rst b/README.rst
index 356ef60ebf6f9..5fd892f95f037 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,6 @@
-Ray
-===
+.. raw:: html
+
+
.. image:: https://travis-ci.com/ray-project/ray.svg?branch=master
:target: https://travis-ci.com/ray-project/ray
@@ -7,9 +8,12 @@ Ray
.. image:: https://readthedocs.org/projects/ray/badge/?version=latest
:target: http://ray.readthedocs.io/en/latest/?badge=latest
+.. image:: https://img.shields.io/badge/pypi-0.6.0-blue.svg
+ :target: https://pypi.org/project/ray/
+
|
-Ray is a flexible, high-performance distributed execution framework.
+**Ray is a flexible, high-performance distributed execution framework.**
Ray is easy to install: ``pip install ray``
@@ -37,11 +41,12 @@ Example Use
Ray comes with libraries that accelerate deep learning and reinforcement learning development:
-- `Ray Tune`_: Hyperparameter Optimization Framework
-- `Ray RLlib`_: Scalable Reinforcement Learning
+- `Tune`_: Hyperparameter Optimization Framework
+- `RLlib`_: Scalable Reinforcement Learning
+- `Distributed Training `__
-.. _`Ray Tune`: http://ray.readthedocs.io/en/latest/tune.html
-.. _`Ray RLlib`: http://ray.readthedocs.io/en/latest/rllib.html
+.. _`Tune`: http://ray.readthedocs.io/en/latest/tune.html
+.. _`RLlib`: http://ray.readthedocs.io/en/latest/rllib.html
Installation
------------
diff --git a/build.sh b/build.sh
index 496bbdddb5750..6aa695b83a924 100755
--- a/build.sh
+++ b/build.sh
@@ -25,7 +25,7 @@ function usage()
# Determine how many parallel jobs to use for make based on the number of cores
unamestr="$(uname)"
if [[ "$unamestr" == "Linux" ]]; then
- PARALLEL=$(nproc)
+ PARALLEL=$(nproc --all)
elif [[ "$unamestr" == "Darwin" ]]; then
PARALLEL=$(sysctl -n hw.ncpu)
else
@@ -101,12 +101,16 @@ fi
pushd "$BUILD_DIR"
+# avoid the command failed and exits
+# and cmake will check some directories to determine whether some targets built
+make clean || true
+rm -rf external/arrow-install
+
cmake -DCMAKE_BUILD_TYPE=$CBUILD_TYPE \
-DCMAKE_RAY_LANG_JAVA=$RAY_BUILD_JAVA \
-DCMAKE_RAY_LANG_PYTHON=$RAY_BUILD_PYTHON \
-DRAY_USE_NEW_GCS=$RAY_USE_NEW_GCS \
-DPYTHON_EXECUTABLE:FILEPATH=$PYTHON_EXECUTABLE $ROOT_DIR
-make clean
make -j${PARALLEL}
popd
diff --git a/cmake/Modules/ArrowExternalProject.cmake b/cmake/Modules/ArrowExternalProject.cmake
index dfb25f244f9a2..3e19dfbd2672f 100644
--- a/cmake/Modules/ArrowExternalProject.cmake
+++ b/cmake/Modules/ArrowExternalProject.cmake
@@ -9,25 +9,21 @@
# - ARROW_INCLUDE_DIR
# - ARROW_SHARED_LIB
# - ARROW_STATIC_LIB
+# - ARROW_LIBRARY_DIR
# - PLASMA_INCLUDE_DIR
# - PLASMA_STATIC_LIB
# - PLASMA_SHARED_LIB
set(arrow_URL https://github.com/apache/arrow.git)
-# The PR for this commit is https://github.com/apache/arrow/pull/2522. We
+# The PR for this commit is https://github.com/apache/arrow/pull/3093. We
# include the link here to make it easier to find the right commit because
# Arrow often rewrites git history and invalidates certain commits.
-set(arrow_TAG 7104d64ff2cd6c20e29d3cf4ec5c58bc10798f66)
+set(arrow_TAG 187b98ed338d4995317dae9efd19870c532192cb)
set(ARROW_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/external/arrow-install)
set(ARROW_HOME ${ARROW_INSTALL_PREFIX})
set(ARROW_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/arrow/src/arrow_ep)
-# The following is needed because in CentOS, the lib directory is named lib64
-if(EXISTS "/etc/redhat-release" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(LIB_SUFFIX 64)
-endif()
-
set(ARROW_INCLUDE_DIR ${ARROW_HOME}/include)
set(ARROW_LIBRARY_DIR ${ARROW_HOME}/lib${LIB_SUFFIX})
set(ARROW_SHARED_LIB ${ARROW_LIBRARY_DIR}/libarrow${CMAKE_SHARED_LIBRARY_SUFFIX})
@@ -58,7 +54,8 @@ set(ARROW_CMAKE_ARGS
-DARROW_WITH_LZ4=off
-DARROW_WITH_ZSTD=off
-DFLATBUFFERS_HOME=${FLATBUFFERS_HOME}
- -DBOOST_ROOT=${BOOST_ROOT})
+ -DBOOST_ROOT=${BOOST_ROOT}
+ -DGLOG_HOME=${GLOG_HOME})
if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
# PyArrow needs following settings.
@@ -92,19 +89,24 @@ endif()
ExternalProject_Add(arrow_ep
PREFIX external/arrow
- DEPENDS flatbuffers boost
+ DEPENDS flatbuffers boost glog
GIT_REPOSITORY ${arrow_URL}
GIT_TAG ${arrow_TAG}
+ UPDATE_COMMAND ""
${ARROW_CONFIGURE}
BUILD_BYPRODUCTS "${ARROW_SHARED_LIB}" "${ARROW_STATIC_LIB}")
if ("${CMAKE_RAY_LANG_JAVA}" STREQUAL "YES")
- ExternalProject_Add_Step(arrow_ep arrow_ep_install_java_lib
- COMMAND bash -c "cd ${ARROW_SOURCE_DIR}/java && mvn clean install -pl plasma -am -Dmaven.test.skip > /dev/null"
- DEPENDEES build)
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${ARROW_SOURCE_DIR}/java/target/")
+
+ if(NOT EXISTS ${ARROW_SOURCE_DIR}/java/target/)
+ ExternalProject_Add_Step(arrow_ep arrow_ep_install_java_lib
+ COMMAND bash -c "cd ${ARROW_SOURCE_DIR}/java && mvn clean install -pl plasma -am -Dmaven.test.skip > /dev/null"
+ DEPENDEES build)
+ endif()
# add install of library plasma_java, it is not configured in plasma CMakeLists.txt
ExternalProject_Add_Step(arrow_ep arrow_ep_install_plasma_java
- COMMAND bash -c "cp ${CMAKE_CURRENT_BINARY_DIR}/external/arrow/src/arrow_ep-build/release/libplasma_java.* ${ARROW_LIBRARY_DIR}/"
+ COMMAND bash -c "cp -rf ${CMAKE_CURRENT_BINARY_DIR}/external/arrow/src/arrow_ep-build/release/libplasma_java.* ${ARROW_LIBRARY_DIR}/"
DEPENDEES install)
endif ()
diff --git a/cmake/Modules/BoostExternalProject.cmake b/cmake/Modules/BoostExternalProject.cmake
index bab016a02b7a3..1fbbb0c0b58ef 100644
--- a/cmake/Modules/BoostExternalProject.cmake
+++ b/cmake/Modules/BoostExternalProject.cmake
@@ -9,9 +9,9 @@
# boost is a stable library in ray, and it supports to find
# the boost pre-built in environment to speed up build process
-if (DEFINED ENV{BOOST_ROOT} AND EXISTS ENV{BOOST_ROOT})
+if (DEFINED ENV{RAY_BOOST_ROOT} AND EXISTS $ENV{RAY_BOOST_ROOT})
set(Boost_USE_STATIC_LIBS ON)
- set(BOOST_ROOT "$ENV{BOOST_ROOT}")
+ set(BOOST_ROOT "$ENV{RAY_BOOST_ROOT}")
message(STATUS "Find BOOST_ROOT: ${BOOST_ROOT}")
# find_package(Boost COMPONENTS system filesystem REQUIRED)
set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include)
diff --git a/cmake/Modules/Common.cmake b/cmake/Modules/Common.cmake
index cc2a5d5ff9926..7d33f13e9d450 100644
--- a/cmake/Modules/Common.cmake
+++ b/cmake/Modules/Common.cmake
@@ -41,6 +41,3 @@ if ("${CMAKE_RAY_LANG_JAVA}" STREQUAL "YES")
message (WARNING "NOT FIND JNI")
endif()
endif()
-
-include_directories(${CMAKE_SOURCE_DIR}/src/common)
-include_directories(${CMAKE_SOURCE_DIR}/src/common/thirdparty)
diff --git a/cmake/Modules/FlatBuffersExternalProject.cmake b/cmake/Modules/FlatBuffersExternalProject.cmake
index 57c2216cecfb7..508010afced49 100644
--- a/cmake/Modules/FlatBuffersExternalProject.cmake
+++ b/cmake/Modules/FlatBuffersExternalProject.cmake
@@ -10,13 +10,8 @@
# - FLATBUFFERS_COMPILER
# - FBS_DEPENDS, to keep compatible
-# The following is needed because in CentOS, the lib directory is named lib64
-if(EXISTS "/etc/redhat-release" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- set(LIB_SUFFIX 64)
-endif()
-
-if(DEFINED ENV{FLATBUFFERS_HOME} AND EXISTS ENV{FLATBUFFERS_HOME})
- set(FLATBUFFERS_HOME "$ENV{FLATBUFFERS_HOME}")
+if(DEFINED ENV{RAY_FLATBUFFERS_HOME} AND EXISTS $ENV{RAY_FLATBUFFERS_HOME})
+ set(FLATBUFFERS_HOME "$ENV{RAY_FLATBUFFERS_HOME}")
set(FLATBUFFERS_INCLUDE_DIR "${FLATBUFFERS_HOME}/include")
set(FLATBUFFERS_STATIC_LIB "${FLATBUFFERS_HOME}/lib${LIB_SUFFIX}/libflatbuffers.a")
set(FLATBUFFERS_COMPILER "${FLATBUFFERS_HOME}/bin/flatc")
diff --git a/cmake/Modules/GlogExternalProject.cmake b/cmake/Modules/GlogExternalProject.cmake
index 47f11fbdbd6ad..2900bae4d523b 100644
--- a/cmake/Modules/GlogExternalProject.cmake
+++ b/cmake/Modules/GlogExternalProject.cmake
@@ -6,8 +6,8 @@
# - GLOG_INCLUDE_DIR
# - GLOG_STATIC_LIB
-if(DEFINED ENV{GLOG_HOME} AND EXISTS ENV{GLOG_HOME})
- set(GLOG_HOME "$ENV{GLOG_HOME}")
+if(DEFINED ENV{RAY_GLOG_HOME} AND EXISTS $ENV{RAY_GLOG_HOME})
+ set(GLOG_HOME "$ENV{RAY_GLOG_HOME}")
set(GLOG_INCLUDE_DIR "${GLOG_HOME}/include")
set(GLOG_STATIC_LIB "${GLOG_HOME}/lib/libglog.a")
@@ -23,7 +23,7 @@ else()
endif()
set(GLOG_URL "https://github.com/google/glog/archive/v${GLOG_VERSION}.tar.gz")
- set(GLOG_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/external/glog/src/glog_ep")
+ set(GLOG_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/external/glog-install")
set(GLOG_HOME "${GLOG_PREFIX}")
set(GLOG_INCLUDE_DIR "${GLOG_PREFIX}/include")
set(GLOG_STATIC_LIB "${GLOG_PREFIX}/lib/libglog.a")
diff --git a/cmake/Modules/GtestExternalProject.cmake b/cmake/Modules/GtestExternalProject.cmake
index 5570066c60fbb..66e5a76f1d87e 100644
--- a/cmake/Modules/GtestExternalProject.cmake
+++ b/cmake/Modules/GtestExternalProject.cmake
@@ -7,18 +7,31 @@
# - GTEST_MAIN_STATIC_LIB
# - GMOCK_MAIN_STATIC_LIB
-if(DEFINED ENV{GTEST_HOME} AND EXISTS ENV{GTEST_HOME})
- set(GTEST_HOME "$ENV{GTEST_HOME}")
- set(GTEST_INCLUDE_DIR "${GTEST_HOME}/include")
- set(GTEST_STATIC_LIB
- "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
- set(GTEST_MAIN_STATIC_LIB
- "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
- set(GMOCK_MAIN_STATIC_LIB
- "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set(GTEST_FOUND FALSE)
+
+if(DEFINED ENV{RAY_GTEST_HOME} AND EXISTS $ENV{RAY_GTEST_HOME})
+ set(GTEST_HOME "$ENV{RAY_GTEST_HOME}")
+ find_path(GTEST_INCLUDE_DIR NAMES gtest/gtest.h
+ PATHS ${GTEST_HOME} NO_DEFAULT_PATH
+ PATH_SUFFIXES "include")
+ find_library(GTEST_LIBRARIES NAMES gtest gtest_main gmock_main
+ PATHS ${GTEST_HOME} NO_DEFAULT_PATH
+ PATH_SUFFIXES "lib")
+ if(GTEST_INCLUDE_DIR AND GTEST_LIBRARIES)
+ set(GTEST_FOUND TRUE)
+ set(GTEST_STATIC_LIB
+ "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set(GTEST_MAIN_STATIC_LIB
+ "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ set(GMOCK_MAIN_STATIC_LIB
+ "${GTEST_HOME}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}")
+
+ add_custom_target(googletest_ep)
+ endif()
+
+endif()
- add_custom_target(googletest_ep)
-else()
+if(NOT GTEST_FOUND)
set(GTEST_VERSION "1.8.0")
if(APPLE)
@@ -31,7 +44,7 @@ else()
endif()
set(GTEST_CMAKE_CXX_FLAGS "${EP_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${UPPERCASE_BUILD_TYPE}} ${GTEST_CMAKE_CXX_FLAGS}")
- set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/external/googletest/src/googletest_ep")
+ set(GTEST_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/external/googletest-install")
set(GTEST_INCLUDE_DIR "${GTEST_PREFIX}/include")
set(GTEST_STATIC_LIB
"${GTEST_PREFIX}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}")
diff --git a/cmake/Modules/ThirdpartyToolchain.cmake b/cmake/Modules/ThirdpartyToolchain.cmake
index 0e0553483ec23..723b3cd6aa001 100644
--- a/cmake/Modules/ThirdpartyToolchain.cmake
+++ b/cmake/Modules/ThirdpartyToolchain.cmake
@@ -4,6 +4,11 @@
# we have to turn it on for dependencies too
set(EP_CXX_FLAGS "${EP_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
+# The following is needed because in CentOS, the lib directory is named lib64
+if(EXISTS "/etc/redhat-release" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(LIB_SUFFIX 64)
+endif()
+
if(RAY_BUILD_TESTS OR RAY_BUILD_BENCHMARKS)
add_custom_target(unittest ctest -L unittest)
@@ -25,18 +30,16 @@ if(RAY_BUILD_TESTS OR RAY_BUILD_BENCHMARKS)
add_dependencies(gmock_main googletest_ep)
endif()
-if(RAY_USE_GLOG)
- include(GlogExternalProject)
- message(STATUS "Glog home: ${GLOG_HOME}")
- message(STATUS "Glog include dir: ${GLOG_INCLUDE_DIR}")
- message(STATUS "Glog static lib: ${GLOG_STATIC_LIB}")
+include(GlogExternalProject)
+message(STATUS "Glog home: ${GLOG_HOME}")
+message(STATUS "Glog include dir: ${GLOG_INCLUDE_DIR}")
+message(STATUS "Glog static lib: ${GLOG_STATIC_LIB}")
- include_directories(${GLOG_INCLUDE_DIR})
- ADD_THIRDPARTY_LIB(glog
- STATIC_LIB ${GLOG_STATIC_LIB})
+include_directories(${GLOG_INCLUDE_DIR})
+ADD_THIRDPARTY_LIB(glog
+ STATIC_LIB ${GLOG_STATIC_LIB})
- add_dependencies(glog glog_ep)
-endif()
+add_dependencies(glog glog_ep)
# boost
include(BoostExternalProject)
@@ -95,19 +98,6 @@ ADD_THIRDPARTY_LIB(plasma STATIC_LIB ${PLASMA_STATIC_LIB})
add_dependencies(plasma plasma_ep)
if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
- # pyarrow
- find_package(PythonInterp REQUIRED)
- message(STATUS "PYTHON_EXECUTABLE for pyarrow: ${PYTHON_EXECUTABLE}")
-
- set(pyarrow_ENV
- "PKG_CONFIG_PATH=${ARROW_LIBRARY_DIR}/pkgconfig"
- "PYARROW_WITH_PLASMA=1"
- "PYARROW_WITH_TENSORFLOW=1"
- "PYARROW_BUNDLE_ARROW_CPP=1"
- "PARQUET_HOME=${PARQUET_HOME}"
- "PYARROW_WITH_PARQUET=1"
- )
-
# clean the arrow_ep/python/build/lib.xxxxx directory,
# or when you build with another python version, it creates multiple lib.xxxx directories
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${ARROW_SOURCE_DIR}/python/build/")
@@ -115,13 +105,40 @@ if ("${CMAKE_RAY_LANG_PYTHON}" STREQUAL "YES")
# here we use externalProject to process pyarrow building
# add_custom_command would have problem with setup.py
- ExternalProject_Add(pyarrow_ext
- PREFIX external/pyarrow
- DEPENDS arrow_ep
- DOWNLOAD_COMMAND ""
- BUILD_IN_SOURCE 1
- CONFIGURE_COMMAND cd ${ARROW_SOURCE_DIR}/python && ${CMAKE_COMMAND} -E env ${pyarrow_ENV} ${PYTHON_EXECUTABLE} setup.py build
- BUILD_COMMAND cd ${ARROW_SOURCE_DIR}/python && ${CMAKE_COMMAND} -E env ${pyarrow_ENV} ${PYTHON_EXECUTABLE} setup.py build_ext
- INSTALL_COMMAND bash -c "cp -rf \$(find ${ARROW_SOURCE_DIR}/python/build/ -maxdepth 1 -type d -print | grep -m1 'lib')/pyarrow ${CMAKE_SOURCE_DIR}/python/ray/pyarrow_files/")
+ if(EXISTS ${ARROW_SOURCE_DIR}/python/build/)
+ # if we did not run `make clean`, skip the rebuild of pyarrow
+ add_custom_target(pyarrow_ext)
+ else()
+ # pyarrow
+ find_package(PythonInterp REQUIRED)
+ message(STATUS "PYTHON_EXECUTABLE for pyarrow: ${PYTHON_EXECUTABLE}")
+
+ # PYARROW_PARALLEL= , so it will add -j to pyarrow build
+ set(pyarrow_ENV
+ "PKG_CONFIG_PATH=${ARROW_LIBRARY_DIR}/pkgconfig"
+ "PYARROW_WITH_PLASMA=1"
+ "PYARROW_WITH_TENSORFLOW=1"
+ "PYARROW_BUNDLE_ARROW_CPP=1"
+ "PARQUET_HOME=${PARQUET_HOME}"
+ "PYARROW_WITH_PARQUET=1"
+ "PYARROW_PARALLEL=")
+
+ if (APPLE)
+ # Since 10.14, the XCode toolchain only accepts libc++ as the
+ # standard library. This should also work on macOS starting from 10.9.
+ set(pyarrow_ENV ${pyarrow_ENV} "CXXFLAGS='-stdlib=libc++'")
+ set(pyarrow_ENV ${pyarrow_ENV} "MACOSX_DEPLOYMENT_TARGET=10.7")
+ endif()
+
+ ExternalProject_Add(pyarrow_ext
+ PREFIX external/pyarrow
+ DEPENDS arrow_ep
+ DOWNLOAD_COMMAND ""
+ BUILD_IN_SOURCE 1
+ CONFIGURE_COMMAND cd ${ARROW_SOURCE_DIR}/python && ${CMAKE_COMMAND} -E env ${pyarrow_ENV} ${PYTHON_EXECUTABLE} setup.py build
+ BUILD_COMMAND cd ${ARROW_SOURCE_DIR}/python && ${CMAKE_COMMAND} -E env ${pyarrow_ENV} ${PYTHON_EXECUTABLE} setup.py build_ext
+ INSTALL_COMMAND bash -c "cp -rf \$(find ${ARROW_SOURCE_DIR}/python/build/ -maxdepth 1 -type d -print | grep -m1 'lib')/pyarrow ${CMAKE_SOURCE_DIR}/python/ray/pyarrow_files/")
+
+ endif()
endif ()
diff --git a/doc/requirements-doc.txt b/doc/requirements-doc.txt
index 5d953d3463400..f598baa081679 100644
--- a/doc/requirements-doc.txt
+++ b/doc/requirements-doc.txt
@@ -9,6 +9,7 @@ pyarrow
pyyaml
recommonmark
redis
+setproctitle
sphinx
sphinx-click
sphinx_rtd_theme
diff --git a/doc/source/actors.rst b/doc/source/actors.rst
index c7594592f5124..0d8b3c94285b5 100644
--- a/doc/source/actors.rst
+++ b/doc/source/actors.rst
@@ -65,8 +65,7 @@ When ``a1.increment.remote()`` is called, the following events happens.
1. A task is created.
2. The task is assigned directly to the local scheduler responsible for the
- actor by the driver's local scheduler. Thus, this scheduling procedure
- bypasses the global scheduler.
+ actor by the driver's local scheduler.
3. An object ID is returned.
We can then call ``ray.get`` on the object ID to retrieve the actual value.
diff --git a/doc/source/async_api.rst b/doc/source/async_api.rst
new file mode 100644
index 0000000000000..95867745f8ee6
--- /dev/null
+++ b/doc/source/async_api.rst
@@ -0,0 +1,87 @@
+Async API (Experimental)
+========================
+
+Since Python 3.5, it is possible to write concurrent code using the ``async/await`` `syntax `__.
+
+This document describes Ray's support for asyncio, which enables integration with popular async frameworks (e.g., aiohttp, aioredis, etc.) for high performance web and prediction serving.
+
+Starting Ray
+------------
+
+You must initialize Ray first.
+
+Please refer to `Starting Ray`_ for instructions.
+
+.. _`Starting Ray`: http://ray.readthedocs.io/en/latest/tutorial.html#starting-ray
+
+
+Converting Ray objects into asyncio futures
+-------------------------------------------
+
+Ray object IDs can be converted into asyncio futures with ``ray.experimental.async_api``.
+
+.. code-block:: python
+
+ import asyncio
+ import time
+ import ray
+ from ray.experimental import async_api
+
+ @ray.remote
+ def f():
+ time.sleep(1)
+ return {'key1': ['value']}
+
+ ray.init()
+ future = async_api.as_future(f.remote())
+ asyncio.get_event_loop().run_until_complete(future) # {'key1': ['value']}
+
+
+.. autofunction:: ray.experimental.async_api.as_future
+
+
+Example Usage
+-------------
+
++----------------------------------------+-----------------------------------------------------+
+| **Basic Python** | **Distributed with Ray** |
++----------------------------------------+-----------------------------------------------------+
+| .. code-block:: python | .. code-block:: python |
+| | |
+| # Execute f serially. | # Execute f in parallel. |
+| | |
+| | |
+| def f(): | @ray.remote |
+| time.sleep(1) | def f(): |
+| return 1 | time.sleep(1) |
+| | return 1 |
+| | |
+| | ray.init() |
+| results = [f() for i in range(4)] | results = ray.get([f.remote() for i in range(4)]) |
++----------------------------------------+-----------------------------------------------------+
+| **Async Python** | **Async Ray** |
++----------------------------------------+-----------------------------------------------------+
+| .. code-block:: python | .. code-block:: python |
+| | |
+| # Execute f asynchronously. | # Execute f asynchronously with Ray/asyncio. |
+| | |
+| | from ray.experimental import async_api |
+| | |
+| | @ray.remote |
+| async def f(): | def f(): |
+| await asyncio.sleep(1) | time.sleep(1) |
+| return 1 | return 1 |
+| | |
+| | ray.init() |
+| loop = asyncio.get_event_loop() | loop = asyncio.get_event_loop() |
+| tasks = [f() for i in range(4)] | tasks = [async_api.as_future(f.remote()) |
+| | for i in range(4)] |
+| results = loop.run_until_complete( | results = loop.run_until_complete( |
+| asyncio.gather(tasks)) | asyncio.gather(tasks)) |
++----------------------------------------+-----------------------------------------------------+
+
+
+Known Issues
+------------
+
+Async API support is experimental, and we are working to improve its performance. Please `let us know `__ any issues you encounter.
diff --git a/doc/source/autoscaling.rst b/doc/source/autoscaling.rst
index 54ebcc350e5e0..90c8e92f3d278 100644
--- a/doc/source/autoscaling.rst
+++ b/doc/source/autoscaling.rst
@@ -76,6 +76,14 @@ You can use ``ray exec`` to conveniently run commands on clusters. Note that scr
# Run a command in a screen (experimental)
$ ray exec cluster.yaml 'echo "hello world"' --screen
+You can also use ``ray submit`` to execute Python scripts on clusters. This will ``rsync`` the designated file onto the cluster and execute it with the given arguments.
+
+.. code-block:: bash
+
+ # Run a Python script in a detached tmux session
+ $ ray submit cluster.yaml --tmux --start --stop tune_experiment.py
+
+
Attaching to the cluster
------------------------
@@ -136,7 +144,8 @@ The default idle timeout is 5 minutes. This is to prevent excessive node churn w
Monitoring cluster status
-------------------------
-You can monitor cluster usage and auto-scaling status by tailing the autoscaling logs in ``/tmp/raylogs/monitor-*``.
+You can monitor cluster usage and auto-scaling status by tailing the autoscaling
+logs in ``/tmp/ray/session_*/logs/monitor*``.
The Ray autoscaler also reports per-node status in the form of instance tags. In your cloud provider console, you can click on a Node, go the the "Tags" pane, and add the ``ray-node-status`` tag as a column. This lets you see per-node statuses at a glance:
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 27d0c1200d9c9..2a2b1a37c207e 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -18,44 +18,41 @@
# These lines added to enable Sphinx to work without installing Ray.
import mock
-MOCK_MODULES = ["gym",
- "gym.spaces",
- "scipy",
- "scipy.signal",
- "tensorflow",
- "tensorflow.contrib",
- "tensorflow.contrib.layers",
- "tensorflow.contrib.slim",
- "tensorflow.contrib.rnn",
- "tensorflow.core",
- "tensorflow.core.util",
- "tensorflow.python",
- "tensorflow.python.client",
- "tensorflow.python.util",
- "ray.local_scheduler",
- "ray.plasma",
- "ray.core",
- "ray.core.generated",
- "ray.core.generated.DriverTableMessage",
- "ray.core.generated.LocalSchedulerInfoMessage",
- "ray.core.generated.ResultTableReply",
- "ray.core.generated.SubscribeToDBClientTableReply",
- "ray.core.generated.SubscribeToNotificationsReply",
- "ray.core.generated.TaskInfo",
- "ray.core.generated.TaskReply",
- "ray.core.generated.TaskExecutionDependencies",
- "ray.core.generated.ClientTableData",
- "ray.core.generated.GcsTableEntry",
- "ray.core.generated.HeartbeatTableData",
- "ray.core.generated.DriverTableData",
- "ray.core.generated.ErrorTableData",
- "ray.core.generated.ProfileTableData",
- "ray.core.generated.ObjectTableData",
- "ray.core.generated.ray.protocol.Task",
- "ray.core.generated.TablePrefix",
- "ray.core.generated.TablePubsub",]
+MOCK_MODULES = [
+ "gym",
+ "gym.spaces",
+ "scipy",
+ "scipy.signal",
+ "tensorflow",
+ "tensorflow.contrib",
+ "tensorflow.contrib.all_reduce",
+ "tensorflow.contrib.all_reduce.python",
+ "tensorflow.contrib.layers",
+ "tensorflow.contrib.slim",
+ "tensorflow.contrib.rnn",
+ "tensorflow.core",
+ "tensorflow.core.util",
+ "tensorflow.python",
+ "tensorflow.python.client",
+ "tensorflow.python.util",
+ "ray.raylet",
+ "ray.plasma",
+ "ray.core",
+ "ray.core.generated",
+ "ray.core.generated.ClientTableData",
+ "ray.core.generated.GcsTableEntry",
+ "ray.core.generated.HeartbeatTableData",
+ "ray.core.generated.HeartbeatBatchTableData",
+ "ray.core.generated.DriverTableData",
+ "ray.core.generated.ErrorTableData",
+ "ray.core.generated.ProfileTableData",
+ "ray.core.generated.ObjectTableData",
+ "ray.core.generated.ray.protocol.Task",
+ "ray.core.generated.TablePrefix",
+ "ray.core.generated.TablePubsub",
+]
for mod_name in MOCK_MODULES:
- sys.modules[mod_name] = mock.Mock()
+ sys.modules[mod_name] = mock.Mock()
# ray.rllib.models.action_dist.py and
# ray.rllib.models.lstm.py will use tf.VERSION
sys.modules["tensorflow"].VERSION = "9.9.9"
@@ -89,7 +86,7 @@
source_suffix = ['.rst', '.md']
source_parsers = {
- '.md': CommonMarkParser,
+ '.md': CommonMarkParser,
}
# The encoding of source files.
@@ -259,25 +256,24 @@
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
+ # The paper size ('letterpaper' or 'a4paper').
+ #'papersize': 'letterpaper',
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
+ # The font size ('10pt', '11pt' or '12pt').
+ #'pointsize': '10pt',
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+ # Additional stuff for the LaTeX preamble.
+ #'preamble': '',
-# Latex figure (float) alignment
-#'figure_align': 'htbp',
+ # Latex figure (float) alignment
+ #'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
- (master_doc, 'Ray.tex', u'Ray Documentation',
- u'The Ray Team', 'manual'),
+ (master_doc, 'Ray.tex', u'Ray Documentation', u'The Ray Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -300,29 +296,23 @@
# If false, no module index is generated.
#latex_domain_indices = True
-
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
-man_pages = [
- (master_doc, 'ray', u'Ray Documentation',
- [author], 1)
-]
+man_pages = [(master_doc, 'ray', u'Ray Documentation', [author], 1)]
# If true, show URL addresses after external links.
#man_show_urls = False
-
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- (master_doc, 'Ray', u'Ray Documentation',
- author, 'Ray', 'One line description of project.',
- 'Miscellaneous'),
+ (master_doc, 'Ray', u'Ray Documentation', author, 'Ray',
+ 'One line description of project.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
diff --git a/doc/source/custom_metric.png b/doc/source/custom_metric.png
new file mode 100644
index 0000000000000..3f448613711a3
Binary files /dev/null and b/doc/source/custom_metric.png differ
diff --git a/doc/source/distributed_sgd.rst b/doc/source/distributed_sgd.rst
new file mode 100644
index 0000000000000..5d1e480766258
--- /dev/null
+++ b/doc/source/distributed_sgd.rst
@@ -0,0 +1,56 @@
+Distributed SGD (Experimental)
+==============================
+
+Ray includes an implementation of synchronous distributed stochastic gradient descent (SGD), which is competitive in performance with implementations in Horovod and Distributed TensorFlow.
+
+Ray SGD is built on top of the Ray task and actor abstractions to provide seamless integration into existing Ray applications.
+
+Interface
+---------
+
+To use Ray SGD, define a `model class `__ with ``loss`` and ``optimizer`` attributes:
+
+.. autoclass:: ray.experimental.sgd.Model
+
+Then, pass a model creator function to the ``ray.experimental.sgd.DistributedSGD`` class. To drive the distributed training, ``sgd.step()`` can be called repeatedly:
+
+.. code-block:: python
+
+ model_creator = lambda worker_idx, device_idx: YourModelClass()
+
+ sgd = DistributedSGD(
+ model_creator,
+ num_workers=2,
+ devices_per_worker=4,
+ gpu=True,
+ strategy="ps")
+
+ for i in range(NUM_ITERS):
+ sgd.step()
+
+Under the hood, Ray SGD will create *replicas* of your model onto each hardware device (GPU) allocated to workers (controlled by ``num_workers``). Multiple devices can be managed by each worker process (controlled by ``devices_per_worker``). Each model instance will be in a separate TF variable scope. The ``DistributedSGD`` class coordinates the distributed computation and application of gradients to improve the model.
+
+There are two distributed SGD strategies available for use:
+ - ``strategy="simple"``: Gradients are averaged centrally on the driver before being applied to each model replica. This is a reference implementation for debugging purposes.
+ - ``strategy="ps"``: Gradients are computed and averaged within each node. Gradients are then averaged across nodes through a number of parameter server actors. To pipeline the computation of gradients and transmission across the network, we use a custom TensorFlow op that can read and write to the Ray object store directly.
+
+Note that when ``num_workers=1``, only local allreduce will be used and the choice of distributed strategy is irrelevant.
+
+The full documentation for ``DistributedSGD`` is as follows:
+
+.. autoclass:: ray.experimental.sgd.DistributedSGD
+
+Examples
+--------
+
+For examples of end-to-end usage, check out the `ImageNet synthetic data test `__ and also the simple `MNIST training example `__, which includes examples of how access the model weights and monitor accuracy as training progresses.
+
+Performance
+-----------
+
+When using the new Ray backend (which will be enabled by default in Ray 0.6+), we `expect `__ performance competitive with other synchronous SGD implementations on 25Gbps Ethernet.
+
+.. figure:: sgd.png
+ :width: 756px
+
+ Images per second reached when distributing the training of a ResNet-101 TensorFlow model (from the official TF benchmark). All experiments were run on p3.16xl instances connected by 25Gbps Ethernet, and workers allocated 4 GPUs per node as done in the Horovod benchmark.
diff --git a/doc/source/example-a3c.rst b/doc/source/example-a3c.rst
index 665d49a365512..47378fce9f915 100644
--- a/doc/source/example-a3c.rst
+++ b/doc/source/example-a3c.rst
@@ -9,11 +9,11 @@ View the `code for this example`_.
.. _`A3C`: https://arxiv.org/abs/1602.01783
.. _`Universe Starter Agent`: https://github.com/openai/universe-starter-agent
-.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/a3c
+.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/agents/a3c
.. note::
- For an overview of Ray's reinforcement learning library, see `Ray RLlib `__.
+ For an overview of Ray's reinforcement learning library, see `RLlib `__.
To run the application, first install **ray** and then some dependencies:
@@ -29,7 +29,7 @@ You can run the code with
.. code-block:: bash
- python/ray/rllib/train.py --env=Pong-ram-v4 --run=A3C --config='{"num_workers": N}'
+ rllib train --env=Pong-ram-v4 --run=A3C --config='{"num_workers": N}'
Reinforcement Learning
----------------------
diff --git a/doc/source/example-evolution-strategies.rst b/doc/source/example-evolution-strategies.rst
index 16cdc3126d8f5..d048d261fff95 100644
--- a/doc/source/example-evolution-strategies.rst
+++ b/doc/source/example-evolution-strategies.rst
@@ -11,20 +11,20 @@ To run the application, first install some dependencies.
You can view the `code for this example`_.
-.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/es
+.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/agents/es
The script can be run as follows. Note that the configuration is tuned to work
on the ``Humanoid-v1`` gym environment.
.. code-block:: bash
- python/ray/rllib/train.py --env=Humanoid-v1 --run=ES
+ rllib train --env=Humanoid-v1 --run=ES
To train a policy on a cluster (e.g., using 900 workers), run the following.
.. code-block:: bash
- python ray/python/ray/rllib/train.py \
+ rllib train \
--env=Humanoid-v1 \
--run=ES \
--redis-address= \
diff --git a/doc/source/example-policy-gradient.rst b/doc/source/example-policy-gradient.rst
index 806764560ba95..9b58575044c3b 100644
--- a/doc/source/example-policy-gradient.rst
+++ b/doc/source/example-policy-gradient.rst
@@ -6,7 +6,7 @@ View the `code for this example`_.
.. note::
- For an overview of Ray's reinforcement learning library, see `Ray RLlib `__.
+ For an overview of Ray's reinforcement learning library, see `RLlib `__.
To run this example, you will need to install `TensorFlow with GPU support`_ (at
@@ -21,7 +21,7 @@ Then you can run the example as follows.
.. code-block:: bash
- python/ray/rllib/train.py --env=Pong-ram-v4 --run=PPO
+ rllib train --env=Pong-ram-v4 --run=PPO
This will train an agent on the ``Pong-ram-v4`` Atari environment. You can also
try passing in the ``Pong-v0`` environment or the ``CartPole-v0`` environment.
@@ -39,4 +39,4 @@ Many of the TensorBoard metrics are also printed to the console, but you might
find it easier to visualize and compare between runs using the TensorBoard UI.
.. _`TensorFlow with GPU support`: https://www.tensorflow.org/install/
-.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/ppo
+.. _`code for this example`: https://github.com/ray-project/ray/tree/master/python/ray/rllib/agents/ppo
diff --git a/doc/source/fault-tolerance.rst b/doc/source/fault-tolerance.rst
index a4692f904feea..6c388c9f8883e 100644
--- a/doc/source/fault-tolerance.rst
+++ b/doc/source/fault-tolerance.rst
@@ -6,16 +6,9 @@ This document describes the handling of failures in Ray.
Machine and Process Failures
----------------------------
-Currently, each **local scheduler** and each **plasma manager** send heartbeats
-to a **monitor** process. If the monitor does not receive any heartbeats from a
-given process for some duration of time (about ten seconds), then it will mark
-that process as dead. The monitor process will then clean up the associated
-state in the Redis servers. If a manager is marked as dead, the object table
-will be updated to remove all occurrences of that manager so that other managers
-don't try to fetch objects from the dead manager. If a local scheduler is marked
-as dead, all of the tasks that are marked as executing on that local scheduler
-in the task table will be marked as lost and all actors associated with that
-local scheduler will be recreated by other local schedulers.
+Each **raylet** (the scheduler process) sends heartbeats to a **monitor**
+process. If the monitor does not receive any heartbeats from a given raylet for
+some period of time (about ten seconds), then it will mark that process as dead.
Lost Objects
------------
@@ -23,19 +16,16 @@ Lost Objects
If an object is needed but is lost or was never created, then the task that
created the object will be re-executed to create the object. If necessary, tasks
needed to create the input arguments to the task being re-executed will also be
-re-executed.
+re-executed. This is the standard *lineage-based fault tolerance* strategy used
+by other systems like Spark.
Actors
------
-When a local scheduler is marked as dead, all actors associated with that local
-scheduler that were still alive will be recreated by other local schedulers. By
-default, all of the actor methods will be re-executed in the same order that
-they were initially executed. If actor checkpointing is enabled, then the actor
-state will be loaded from the most recent checkpoint and the actor methods that
-occurred after the checkpoint will be re-executed. Note that actor checkpointing
-is currently an experimental feature.
-
+When an actor dies (either because the actor process crashed or because the node
+that the actor was on died), by default any attempt to get an object from that
+actor that cannot be created will raise an exception. Subsequent releases will
+include an option for automatically restarting actors.
Current Limitations
-------------------
@@ -47,7 +37,7 @@ Process Failures
~~~~~~~~~~~~~~~~
1. Ray does not recover from the failure of any of the following processes:
- a Redis server, the global scheduler, the monitor process.
+ a Redis server and the monitor process.
2. If a driver fails, that driver will not be restarted and the job will not
complete.
@@ -58,9 +48,3 @@ Lost Objects
evicted, and is later needed, Ray will not reconstruct this object.
2. If an object is constructed by an actor method, is then evicted, and is later
needed, Ray will not reconstruct this object.
-
-Actor Reconstruction
-~~~~~~~~~~~~~~~~~~~~
-
-1. Actor reconstruction follows the order of initial execution, but new tasks
- may get interleaved with the re-executed tasks.
diff --git a/doc/source/images/ray_logo.png b/doc/source/images/ray_logo.png
new file mode 100644
index 0000000000000..05840a7ff453e
Binary files /dev/null and b/doc/source/images/ray_logo.png differ
diff --git a/doc/source/impala.png b/doc/source/impala.png
index a7d12e4b5a0f9..0d42fe6e07dc9 100644
Binary files a/doc/source/impala.png and b/doc/source/impala.png differ
diff --git a/doc/source/index.rst b/doc/source/index.rst
index b71987108be05..68a33676c80d8 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -42,6 +42,7 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
- `Tune`_: Scalable Hyperparameter Search
- `RLlib`_: Scalable Reinforcement Learning
+- `Distributed Training `__
.. _`Tune`: tune.html
.. _`RLlib`: rllib.html
@@ -64,6 +65,7 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
actors.rst
using-ray-with-gpus.rst
webui.rst
+ async_api.rst
.. toctree::
:maxdepth: 1
@@ -74,10 +76,11 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
tune-schedulers.rst
tune-searchalg.rst
tune-package-ref.rst
+ tune-examples.rst
.. toctree::
:maxdepth: 1
- :caption: Ray RLlib
+ :caption: RLlib
rllib.rst
rllib-training.rst
@@ -89,8 +92,9 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
.. toctree::
:maxdepth: 1
- :caption: Pandas on Ray
+ :caption: Other Libraries
+ distributed_sgd.rst
pandas_on_ray.rst
.. toctree::
@@ -118,6 +122,7 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
plasma-object-store.rst
resources.rst
redis-memory-management.rst
+ tempfile.rst
.. toctree::
:maxdepth: 1
@@ -134,6 +139,7 @@ Ray comes with libraries that accelerate deep learning and reinforcement learnin
troubleshooting.rst
user-profiling.rst
+ security.rst
development.rst
profiling.rst
contact.rst
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index 4c4bc3f165ef7..68bd37ae96f5d 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -3,17 +3,23 @@ Installing Ray
Ray should work with Python 2 and Python 3. We have tested Ray on Ubuntu 14.04, Ubuntu 16.04, OS X 10.11 and 10.12.
-You can install Ray as follows.
+Latest stable version
+---------------------
+
+You can install the latest stable version of Ray as follows.
.. code-block:: bash
- pip install ray
+ pip install -U ray # also recommended: ray[debug]
+
+Trying snapshots from master
+----------------------------
+
+Here are links to the latest wheels (which are built off of master). To install these wheels, run the following command:
-Trying the latest version of Ray
---------------------------------
+.. danger::
-Here are links to the latest wheels (which are built off of master). These versions will have newer
-features but may be subject to more bugs. To install these wheels, run the following command:
+ These versions will have newer features but are subject to more bugs. If you encounter crashes or other instabilities, please revert to the latest stable version.
.. code-block:: bash
@@ -23,6 +29,7 @@ features but may be subject to more bugs. To install these wheels, run the follo
=================== ===================
Linux MacOS
=================== ===================
+`Linux Python 3.7`_ `MacOS Python 3.7`_
`Linux Python 3.6`_ `MacOS Python 3.6`_
`Linux Python 3.5`_ `MacOS Python 3.5`_
`Linux Python 3.4`_ `MacOS Python 3.4`_
@@ -30,14 +37,16 @@ features but may be subject to more bugs. To install these wheels, run the follo
=================== ===================
-.. _`Linux Python 3.6`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp36-cp36m-manylinux1_x86_64.whl
-.. _`Linux Python 3.5`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp35-cp35m-manylinux1_x86_64.whl
-.. _`Linux Python 3.4`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp34-cp34m-manylinux1_x86_64.whl
-.. _`Linux Python 2.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp27-cp27mu-manylinux1_x86_64.whl
-.. _`MacOS Python 3.6`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp36-cp36m-macosx_10_6_intel.whl
-.. _`MacOS Python 3.5`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp35-cp35m-macosx_10_6_intel.whl
-.. _`MacOS Python 3.4`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp34-cp34m-macosx_10_6_intel.whl
-.. _`MacOS Python 2.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.5.2-cp27-cp27m-macosx_10_6_intel.whl
+.. _`Linux Python 3.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp37-cp37m-manylinux1_x86_64.whl
+.. _`Linux Python 3.6`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp36-cp36m-manylinux1_x86_64.whl
+.. _`Linux Python 3.5`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp35-cp35m-manylinux1_x86_64.whl
+.. _`Linux Python 3.4`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp34-cp34m-manylinux1_x86_64.whl
+.. _`Linux Python 2.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp27-cp27mu-manylinux1_x86_64.whl
+.. _`MacOS Python 3.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp37-cp37m-macosx_10_6_intel.whl
+.. _`MacOS Python 3.6`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp36-cp36m-macosx_10_6_intel.whl
+.. _`MacOS Python 3.5`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp35-cp35m-macosx_10_6_intel.whl
+.. _`MacOS Python 3.4`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp34-cp34m-macosx_10_6_intel.whl
+.. _`MacOS Python 2.7`: https://s3-us-west-2.amazonaws.com/ray-wheels/latest/ray-0.6.0-cp27-cp27m-macosx_10_6_intel.whl
Building Ray from source
@@ -67,7 +76,7 @@ For Ubuntu, run the following commands:
# If you are on Ubuntu 14.04, you need the following.
pip install cmake
- pip install cython
+ pip install cython==0.27.3
For MacOS, run the following commands:
@@ -76,7 +85,7 @@ For MacOS, run the following commands:
brew update
brew install cmake pkg-config automake autoconf libtool openssl bison wget
- pip install cython
+ pip install cython==0.27.3
If you are using Anaconda, you may also need to run the following.
diff --git a/doc/source/internals-overview.rst b/doc/source/internals-overview.rst
index 69ac1895a55c7..a2516de1d10ce 100644
--- a/doc/source/internals-overview.rst
+++ b/doc/source/internals-overview.rst
@@ -15,8 +15,8 @@ Running Ray standalone
Ray can be used standalone by calling ``ray.init()`` within a script. When the
call to ``ray.init()`` happens, all of the relevant processes are started.
-These include a local scheduler, a global scheduler, an object store and
-manager, a Redis server, and a number of worker processes.
+These include a local scheduler, an object store and manager, a Redis server,
+and a number of worker processes.
When the script exits, these processes will be killed.
@@ -112,7 +112,7 @@ When a driver or worker invokes a remote function, a number of things happen.
- The task object is then sent to the local scheduler on the same node as the
driver or worker.
- The local scheduler makes a decision to either schedule the task locally or to
- pass the task on to a global scheduler.
+ pass the task on to another local scheduler.
- If all of the task's object dependencies are present in the local object
store and there are enough CPU and GPU resources available to execute the
diff --git a/doc/source/profiling.rst b/doc/source/profiling.rst
index 59d12d635cdeb..55ed8de6fae2b 100644
--- a/doc/source/profiling.rst
+++ b/doc/source/profiling.rst
@@ -14,54 +14,20 @@ symbolize on Mac OS have failed.
sudo apt-get install google-perftools libgoogle-perftools-dev
-Changes to compilation and linking
-----------------------------------
-
-Let's say we want to profile the ``plasma_manager``. Change the link
-instruction in ``src/plasma/CMakeLists.txt`` from
-
-.. code-block:: cmake
-
- target_link_libraries(plasma_manager common ${PLASMA_STATIC_LIB} ray_static ${ARROW_STATIC_LIB} -lpthread)
-
-to additionally include ``-lprofiler``:
-
-.. code-block:: cmake
-
- target_link_libraries(plasma_manager common ${PLASMA_STATIC_LIB} ray_static ${ARROW_STATIC_LIB} -lpthread -lprofiler)
-
-Additionally, add ``-g -ggdb`` to ``CMAKE_C_FLAGS`` and ``CMAKE_CXX_FLAGS`` to
-enable the debug symbols. (Keeping ``-O3`` seems okay.)
-
-Recompile.
-
Launching the to-profile binary
-------------------------------
-In various places, instead of launching the target binary via
-``plasma_manager ``, it must be launched with
+If you want to launch Ray in profiling mode, define the following variables:
.. code-block:: bash
- LD_PRELOAD=/usr/lib/libprofiler.so CPUPROFILE=/tmp/pprof.out plasma_manager
-
-In practice, this means modifying ``python/ray/plasma/plasma.py`` so that the
-manager is launched with a command that passes a ``modified_env`` into
-``Popen``.
-
-.. code-block:: python
-
- modified_env = os.environ.copy()
- modified_env["LD_PRELOAD"] = "/usr/lib/libprofiler.so"
- modified_env["CPUPROFILE"] = "/tmp/pprof.out"
+ export RAYLET_PERFTOOLS_PATH=/usr/lib/x86_64-linux-gnu/libprofiler.so
+ export RAYLET_PERFTOOLS_LOGFILE=/tmp/pprof.out
- process = subprocess.Popen(command,
- stdout=stdout_file,
- stderr=stderr_file,
- env=modified_env)
The file ``/tmp/pprof.out`` will be empty until you let the binary run the
-target workload for a while and then ``kill`` it.
+target workload for a while and then ``kill`` it via ``ray stop`` or by
+letting the driver exit.
Visualizing the CPU profile
---------------------------
@@ -72,14 +38,14 @@ zoomable ``.svg`` image displaying the call graph annotated with hot paths.
.. code-block:: bash
# Use the appropriate path.
- PLASMA_MANAGER=ray/python/ray/core/src/plasma/plasma_manager
+ RAYLET=ray/python/ray/core/src/ray/raylet/raylet
- google-pprof -svg $PLASMA_MANAGER /tmp/pprof.out > /tmp/pprof.svg
+ google-pprof -svg $RAYLET /tmp/pprof.out > /tmp/pprof.svg
# Then open the .svg file with Chrome.
# If you realize the call graph is too large, use -focus= to zoom
# into subtrees.
- google-pprof -focus=epoll_wait -svg $PLASMA_MANAGER /tmp/pprof.out > /tmp/pprof.svg
+ google-pprof -focus=epoll_wait -svg $RAYLET /tmp/pprof.out > /tmp/pprof.svg
Here's a snapshot of an example svg output, taken from the official
documentation:
diff --git a/doc/source/redis-memory-management.rst b/doc/source/redis-memory-management.rst
index 64d2035ed0f31..5e6edcc02f6c4 100644
--- a/doc/source/redis-memory-management.rst
+++ b/doc/source/redis-memory-management.rst
@@ -1,4 +1,4 @@
-Redis Memory Management (EXPERIMENTAL)
+Redis Memory Management (Experimental)
======================================
Ray stores metadata associated with tasks and objects in one or more Redis
@@ -7,92 +7,9 @@ servers, as described in `An Overview of the Internals
task/object generation rate could risk high memory pressure, potentially leading
to out-of-memory (OOM) errors.
-Here, we describe an experimental feature that transparently flushes metadata
-entries out of Redis memory.
+In Ray `0.6.1+` Redis shards can be configured to LRU evict task and object
+metadata by setting ``redis_max_memory`` when starting Ray. This supercedes the
+previously documented flushing functionality.
-Requirements
-------------
-
-As of early July 2018, the automatic memory management feature requires building
-Ray from source. We are planning on eliminating this step in the near future by
-releasing official wheels.
-
-Building Ray
-~~~~~~~~~~~~
-
-First, follow `instructions to build Ray from source
-`__ to install prerequisites. After
-the prerequisites are installed, instead of doing the regular ``pip install`` as
-referenced in that document, pass an additional special flag,
-``RAY_USE_NEW_GCS=on``:
-
-.. code-block:: bash
-
- git clone https://github.com/ray-project/ray.git
- cd ray/python
- RAY_USE_NEW_GCS=on pip install -e . --verbose # Add --user if you see a permission denied error.
-
-Running Ray applications
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-At run time the environment variables ``RAY_USE_NEW_GCS=on`` and
-``RAY_USE_XRAY=1`` are required.
-
-.. code-block:: bash
-
- export RAY_USE_NEW_GCS=on
- export RAY_USE_XRAY=1
- python my_ray_script.py # Or launch python/ipython.
-
-Activate memory flushing
-------------------------
-
-After building Ray using the method above, simply add these two lines after
-``ray.init()`` to activate automatic memory flushing:
-
-.. code-block:: python
-
- ray.init(...)
-
- policy = ray.experimental.SimpleGcsFlushPolicy()
- ray.experimental.set_flushing_policy(policy)
-
- # My awesome Ray application logic follows.
-
-Paramaters of the flushing policy
----------------------------------
-
-There are three `user-configurable parameters
-`_
-of the ``SimpleGcsFlushPolicy``:
-
-* ``flush_when_at_least_bytes``: Wait until this many bytes of memory usage
- accumulated in the redis server before flushing kicks in.
-* ``flush_period_secs``: Issue a flush to the Redis server every this many
- seconds.
-* ``flush_num_entries_each_time``: A hint to the system on the number of entries
- to flush on each request.
-
-The default values should serve to be non-invasive for lightweight Ray
-applications. ``flush_when_at_least_bytes`` is set to ``(1<<31)`` or 2GB,
-``flush_period_secs`` to 10, and ``flush_num_entries_each_time`` to 10000:
-
-.. code-block:: python
-
- # Default parameters.
- ray.experimental.SimpleGcsFlushPolicy(
- flush_when_at_least_bytes=(1 << 31),
- flush_period_secs=10,
- flush_num_entries_each_time=10000)
-
-In particular, these default values imply that
-
-1. the Redis server would accumulate memory usage up to 2GB without any entries
-being flushed, then the flushing would kick in; and
-
-2. generally, "older" metadata entries would be flushed first, and the Redis
-server would always keep the most recent window of metadata of 2GB in size.
-
-**For advanced users.** Advanced users can tune the above parameters to their
-applications' needs; note that the desired flush rate is equal to (flush
-period) * (num entries each flush).
+Note that profiling is disabled when ``redis_max_memory`` is set. This is because
+profiling data cannot be LRU evicted.
diff --git a/doc/source/resources.rst b/doc/source/resources.rst
index e0dc9d742ec28..4be2f61afbe4b 100644
--- a/doc/source/resources.rst
+++ b/doc/source/resources.rst
@@ -1,5 +1,5 @@
-Resource (CPUs, GPUs)
-=====================
+Resources (CPUs, GPUs)
+======================
This document describes how resources are managed in Ray. Each node in a Ray
cluster knows its own resource capacities, and each task specifies its resource
@@ -39,7 +39,8 @@ Specifying a task's CPU and GPU requirements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To specify a task's CPU and GPU requirements, pass the ``num_cpus`` and
-``num_gpus`` arguments into the remote decorator.
+``num_gpus`` arguments into the remote decorator. Note that Ray supports
+**fractional** resource requirements.
.. code-block:: python
@@ -47,7 +48,11 @@ To specify a task's CPU and GPU requirements, pass the ``num_cpus`` and
def f():
return 1
-When ``f`` tasks will be scheduled on machines that have at least 4 CPUs and 2
+ @ray.remote(num_gpus=0.5)
+ def h():
+ return 1
+
+The ``f`` tasks will be scheduled on machines that have at least 4 CPUs and 2
GPUs, and when one of the ``f`` tasks executes, 4 CPUs and 2 GPUs will be
reserved for that task. The IDs of the GPUs that are reserved for the task can
be accessed with ``ray.get_gpu_ids()``. Ray will automatically set the
@@ -108,3 +113,9 @@ decorator.
@ray.remote(resources={'Resource2': 1})
def f():
return 1
+
+Fractional Resources
+--------------------
+
+Task and actor resource requirements can be fractional. This is particularly
+useful if you want multiple tasks or actors to share a single GPU.
diff --git a/doc/source/rllib-algorithms.rst b/doc/source/rllib-algorithms.rst
index d764fc7ad8ea3..1d0501215745c 100644
--- a/doc/source/rllib-algorithms.rst
+++ b/doc/source/rllib-algorithms.rst
@@ -38,14 +38,21 @@ SpaceInvaders 646 ~300
Ape-X using 32 workers in RLlib vs vanilla DQN (orange) and A3C (blue) on PongNoFrameskip-v4.
+**Ape-X specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/dqn/apex.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
Importance Weighted Actor-Learner Architecture (IMPALA)
-------------------------------------------------------
`[paper] `__
`[implementation] `__
-In IMPALA, a central learner runs SGD in a tight loop while asynchronously pulling sample batches from many actor processes. RLlib's IMPALA implementation uses DeepMind's reference `V-trace code `__. Note that we do not provide a deep residual network out of the box, but one can be plugged in as a `custom model `__.
+In IMPALA, a central learner runs SGD in a tight loop while asynchronously pulling sample batches from many actor processes. RLlib's IMPALA implementation uses DeepMind's reference `V-trace code `__. Note that we do not provide a deep residual network out of the box, but one can be plugged in as a `custom model `__. Multiple learner GPUs and experience replay are also supported.
-Tuned examples: `PongNoFrameskip-v4 `__, `vectorized configuration `__, `{BeamRider,Breakout,Qbert,SpaceInvaders}NoFrameskip-v4 `__
+Tuned examples: `PongNoFrameskip-v4 `__, `vectorized configuration `__, `multi-gpu configuration `__, `{BeamRider,Breakout,Qbert,SpaceInvaders}NoFrameskip-v4 `__
**Atari results @10M steps**: `more details `__
@@ -71,7 +78,15 @@ SpaceInvaders 843 ~300
.. figure:: impala.png
- IMPALA solves Atari several times faster than A2C / A3C, with similar sample efficiency. Here IMPALA scales from 16 to 128 workers to solve PongNoFrameskip-v4 in ~8 minutes.
+ Multi-GPU IMPALA scales up to solve PongNoFrameskip-v4 in ~3 minutes using a pair of V100 GPUs and 128 CPU workers.
+ The maximum training throughput reached is ~30k transitions per second (~120k environment frames per second).
+
+**IMPALA-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/impala/impala.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
Gradient-based
~~~~~~~~~~~~~~
@@ -97,17 +112,31 @@ Qbert 3620 ~1000
SpaceInvaders 692 ~600
============= ======================== ==============================
-Deep Deterministic Policy Gradients (DDPG)
-------------------------------------------
+**A3C-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/a3c/a3c.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
+Deep Deterministic Policy Gradients (DDPG, TD3)
+-----------------------------------------------
`[paper] `__ `[implementation] `__
-DDPG is implemented similarly to DQN (below). The algorithm can be scaled by increasing the number of workers, switching to AsyncGradientsOptimizer, or using Ape-X.
+DDPG is implemented similarly to DQN (below). The algorithm can be scaled by increasing the number of workers, switching to AsyncGradientsOptimizer, or using Ape-X. The improvements from `TD3 `__ are available though not enabled by default.
+
+Tuned examples: `Pendulum-v0 `__, `TD3 configuration `__, `MountainCarContinuous-v0 `__, `HalfCheetah-v2 `__
-Tuned examples: `Pendulum-v0 `__, `MountainCarContinuous-v0 `__, `HalfCheetah-v2 `__
+**DDPG-specific configs** (see also `common configs `__):
-Deep Q Networks (DQN, Rainbow)
-------------------------------
+.. literalinclude:: ../../python/ray/rllib/agents/ddpg/ddpg.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
+Deep Q Networks (DQN, Rainbow, Parametric DQN)
+----------------------------------------------
`[paper] `__ `[implementation] `__
-RLlib DQN is implemented using the SyncReplayOptimizer. The algorithm can be scaled by increasing the number of workers, using the AsyncGradientsOptimizer for async DQN, or using Ape-X. Memory usage is reduced by compressing samples in the replay buffer with LZ4. All of the DQN improvements evaluated in `Rainbow `__ are available, though not all are enabled by default.
+RLlib DQN is implemented using the SyncReplayOptimizer. The algorithm can be scaled by increasing the number of workers, using the AsyncGradientsOptimizer for async DQN, or using Ape-X. Memory usage is reduced by compressing samples in the replay buffer with LZ4. All of the DQN improvements evaluated in `Rainbow `__ are available, though not all are enabled by default. See also how to use `parametric-actions in DQN `__.
Tuned examples: `PongDeterministic-v4 `__, `Rainbow configuration `__, `{BeamRider,Breakout,Qbert,SpaceInvaders}NoFrameskip-v4 `__, `with Dueling and Double-Q `__, `with Distributional DQN `__.
@@ -125,12 +154,26 @@ Qbert 3921 7968 15780
SpaceInvaders 650 1001 1025 ~500
============= ======================== ============================= ============================== ===============================
+**DQN-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/dqn/dqn.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
Policy Gradients
----------------
`[paper] `__ `[implementation] `__ We include a vanilla policy gradients implementation as an example algorithm. This is usually outperformed by PPO.
Tuned examples: `CartPole-v0 `__
+**PG-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/pg/pg.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
Proximal Policy Optimization (PPO)
----------------------------------
`[paper] `__ `[implementation] `__
@@ -158,6 +201,13 @@ SpaceInvaders 671 944 ~800
RLlib's multi-GPU PPO scales to multiple GPUs and hundreds of CPUs on solving the Humanoid-v1 task. Here we compare against a reference MPI-based implementation.
+**PPO-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/ppo/ppo.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
Derivative-free
~~~~~~~~~~~~~~~
@@ -168,6 +218,13 @@ ARS is a random search method for training linear policies for continuous contro
Tuned examples: `CartPole-v0 `__, `Swimmer-v2 `__
+**ARS-specific configs** (see also `common configs `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/ars/ars.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
Evolution Strategies
--------------------
`[paper] `__ `[implementation] `__
@@ -181,3 +238,10 @@ Tuned examples: `Humanoid-v1 `__):
+
+.. literalinclude:: ../../python/ray/rllib/agents/es/es.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
diff --git a/doc/source/rllib-concepts.rst b/doc/source/rllib-concepts.rst
index f752279cb58d3..68c160c912b05 100644
--- a/doc/source/rllib-concepts.rst
+++ b/doc/source/rllib-concepts.rst
@@ -17,7 +17,7 @@ Policy Evaluation
Given an environment and policy graph, policy evaluation produces `batches `__ of experiences. This is your classic "environment interaction loop". Efficient policy evaluation can be burdensome to get right, especially when leveraging vectorization, RNNs, or when operating in a multi-agent environment. RLlib provides a `PolicyEvaluator `__ class that manages all of this, and this class is used in most RLlib algorithms.
-You can also use policy evaluation standalone to produce batches of experiences. This can be done by calling ``ev.sample()`` on an evaluator instance, or ``ev.sample.remote()`` in parallel on evaluator instances created as Ray actors (see ``PolicyEvalutor.as_remote()``).
+You can also use policy evaluation standalone to produce batches of experiences. This can be done by calling ``ev.sample()`` on an evaluator instance, or ``ev.sample.remote()`` in parallel on evaluator instances created as Ray actors (see ``PolicyEvaluator.as_remote()``).
Policy Optimization
-------------------
diff --git a/doc/source/rllib-env.rst b/doc/source/rllib-env.rst
index 6de076785707f..4f8a4c66ae4c3 100644
--- a/doc/source/rllib-env.rst
+++ b/doc/source/rllib-env.rst
@@ -5,27 +5,58 @@ RLlib works with several different types of environments, including `OpenAI Gym
.. image:: rllib-envs.svg
-In the high-level agent APIs, environments are identified with string names. By default, the string will be interpreted as a gym `environment name `__, however you can also register custom environments by name:
+**Compatibility matrix**:
+
+============= ======================= ================== =========== ==================
+Algorithm Discrete Actions Continuous Actions Multi-Agent Recurrent Policies
+============= ======================= ================== =========== ==================
+A2C, A3C **Yes** `+parametric`_ **Yes** **Yes** **Yes**
+PPO **Yes** `+parametric`_ **Yes** **Yes** **Yes**
+PG **Yes** `+parametric`_ **Yes** **Yes** **Yes**
+IMPALA **Yes** `+parametric`_ No **Yes** **Yes**
+DQN, Rainbow **Yes** `+parametric`_ No **Yes** No
+DDPG, TD3 No **Yes** **Yes** No
+APEX-DQN **Yes** `+parametric`_ No **Yes** No
+APEX-DDPG No **Yes** **Yes** No
+ES **Yes** **Yes** No No
+ARS **Yes** **Yes** No No
+============= ======================= ================== =========== ==================
+
+.. _`+parametric`: rllib-models.html#variable-length-parametric-action-spaces
+
+You can pass either a string name or a Python class to specify an environment. By default, strings will be interpreted as a gym `environment name `__. Custom env classes must take a single ``env_config`` parameter in their constructor:
.. code-block:: python
import ray
- from ray.tune.registry import register_env
from ray.rllib.agents import ppo
- def env_creator(env_config):
- import gym
- return gym.make("CartPole-v0") # or return your own custom env
+ class MyEnv(gym.Env):
+ def __init__(self, env_config):
+ self.action_space = ...
+ self.observation_space = ...
+ ...
- register_env("my_env", env_creator)
ray.init()
- trainer = ppo.PPOAgent(env="my_env", config={
- "env_config": {}, # config to pass to env creator
+ trainer = ppo.PPOAgent(env=MyEnv, config={
+ "env_config": {}, # config to pass to env class
})
while True:
print(trainer.train())
+You can also register a custom env creator function with a string name. This function must take a single ``env_config`` parameter and return an env instance:
+
+.. code-block:: python
+
+ from ray.tune.registry import register_env
+
+ def env_creator(env_config):
+ return MyEnv(...) # return an env instance
+
+ register_env("my_env", env_creator)
+ trainer = ppo.PPOAgent(env="my_env")
+
Configuring Environments
------------------------
@@ -50,14 +81,14 @@ In the above example, note that the ``env_creator`` function takes in an ``env_c
OpenAI Gym
----------
-RLlib uses Gym as its environment interface for single-agent training. For more information on how to implement a custom Gym environment, see the `gym.Env class definition `__. You may also find the `SimpleCorridor `__ and `Carla simulator `__ example env implementations useful as a reference.
+RLlib uses Gym as its environment interface for single-agent training. For more information on how to implement a custom Gym environment, see the `gym.Env class definition `__. You may also find the `SimpleCorridor `__ and `Carla simulator `__ example env implementations useful as a reference.
Performance
~~~~~~~~~~~
There are two ways to scale experience collection with Gym environments:
- 1. **Vectorization within a single process:** Though many envs can very achieve high frame rates per core, their throughput is limited in practice by policy evaluation between steps. For example, even small TensorFlow models incur a couple milliseconds of latency to evaluate. This can be worked around by creating multiple envs per process and batching policy evaluations across these envs.
+ 1. **Vectorization within a single process:** Though many envs can achieve high frame rates per core, their throughput is limited in practice by policy evaluation between steps. For example, even small TensorFlow models incur a couple milliseconds of latency to evaluate. This can be worked around by creating multiple envs per process and batching policy evaluations across these envs.
You can configure ``{"num_envs_per_worker": M}`` to have RLlib create ``M`` concurrent environments per worker. RLlib auto-vectorizes Gym environments via `VectorEnv.wrap() `__.
@@ -76,6 +107,10 @@ RLlib will auto-vectorize Gym envs for batch evaluation if the ``num_envs_per_wo
Multi-Agent
-----------
+.. note::
+
+ Learn more about multi-agent reinforcement learning in RLlib by reading the `blog post `__.
+
A multi-agent environment is one which has multiple acting entities per step, e.g., in a traffic simulation, there may be multiple "car" and "traffic light" agents in the environment. The model for multi-agent in RLlib as follows: (1) as a user you define the number of policies available up front, and (2) a function that maps agent ids to policy ids. This is summarized by the below figure:
.. image:: multi-agent.svg
@@ -132,25 +167,93 @@ If all the agents will be using the same algorithm class to train, then you can
RLlib will create three distinct policies and route agent decisions to its bound policy. When an agent first appears in the env, ``policy_mapping_fn`` will be called to determine which policy it is bound to. RLlib reports separate training statistics for each policy in the return from ``train()``, along with the combined reward.
-Here is a simple `example training script `__ in which you can vary the number of agents and policies in the environment. For how to use multiple training methods at once (here DQN and PPO), see the `two-trainer example `__.
+Here is a simple `example training script `__ in which you can vary the number of agents and policies in the environment. For how to use multiple training methods at once (here DQN and PPO), see the `two-trainer example `__. Metrics are reported for each policy separately, for example:
+
+.. code-block:: bash
+ :emphasize-lines: 6,14,22
+
+ Result for PPO_multi_cartpole_0:
+ episode_len_mean: 34.025862068965516
+ episode_reward_max: 159.0
+ episode_reward_mean: 86.06896551724138
+ info:
+ policy_0:
+ cur_lr: 4.999999873689376e-05
+ entropy: 0.6833480000495911
+ kl: 0.010264254175126553
+ policy_loss: -11.95590591430664
+ total_loss: 197.7039794921875
+ vf_explained_var: 0.0010995268821716309
+ vf_loss: 209.6578826904297
+ policy_1:
+ cur_lr: 4.999999873689376e-05
+ entropy: 0.6827034950256348
+ kl: 0.01119876280426979
+ policy_loss: -8.787769317626953
+ total_loss: 88.26161193847656
+ vf_explained_var: 0.0005457401275634766
+ vf_loss: 97.0471420288086
+ policy_reward_mean:
+ policy_0: 21.194444444444443
+ policy_1: 21.798387096774192
To scale to hundreds of agents, MultiAgentEnv batches policy evaluations across multiple agents internally. It can also be auto-vectorized by setting ``num_envs_per_worker > 1``.
-Agent-Driven
-------------
+Variable-Sharing Between Policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In many situations, it does not make sense for an environment to be "stepped" by RLlib. For example, if a policy is to be used in a web serving system, then it is more natural for an agent to query a service that serves policy decisions, and for that service to learn from experience over time.
+RLlib will create each policy's model in a separate ``tf.variable_scope``. However, variables can still be shared between policies by explicitly entering a globally shared variable scope with ``tf.VariableScope(reuse=tf.AUTO_REUSE)``:
-RLlib provides the `ServingEnv `__ class for this purpose. Unlike other envs, ServingEnv has its own thread of control. At any point, agents on that thread can query the current policy for decisions via ``self.get_action()`` and reports rewards via ``self.log_returns()``. This can be done for multiple concurrent episodes as well.
+.. code-block:: python
+
+ with tf.variable_scope(
+ tf.VariableScope(tf.AUTO_REUSE, "name_of_global_shared_scope"),
+ reuse=tf.AUTO_REUSE,
+ auxiliary_name_scope=False):
+
+
+There is a full example of this in the `example training script `__.
+
+Implementing a Centralized Critic
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Implementing a centralized critic that takes as input the observations and actions of other concurrent agents requires the definition of custom policy graphs. It can be done as follows:
+
+1. Querying the critic: this can be done in the ``postprocess_trajectory`` method of a custom policy graph, which has full access to the policies and observations of concurrent agents via the ``other_agent_batches`` and ``episode`` arguments. The batch of critic predictions can then be added to the postprocessed trajectory. Here's an example:
+
+.. code-block:: python
-For example, ServingEnv can be used to implement a simple REST policy `server `__ that learns over time using RLlib. In this example RLlib runs with ``num_workers=0`` to avoid port allocation issues, but in principle this could be scaled by increasing ``num_workers``.
+ def postprocess_trajectory(self, sample_batch, other_agent_batches, episode):
+ agents = ["agent_1", "agent_2", "agent_3"] # simple example of 3 agents
+ global_obs_batch = np.stack(
+ [other_agent_batches[agent_id][1]["obs"] for agent_id in agents],
+ axis=1)
+ # add the global obs and global critic value
+ sample_batch["global_obs"] = global_obs_batch
+ sample_batch["central_vf"] = self.sess.run(
+ self.critic_network, feed_dict={"obs": global_obs_batch})
+ return sample_batch
-Offline Data
-~~~~~~~~~~~~
+2. Updating the critic: the centralized critic loss can be added to the loss of the custom policy graph, the same as with any other value function. For an example of defining loss inputs, see the `PGPolicyGraph example `__.
-ServingEnv also provides a ``self.log_action()`` call to support off-policy actions. This allows the client to make independent decisions, e.g., to compare two different policies, and for RLlib to still learn from those off-policy actions. Note that this requires the algorithm used to support learning from off-policy decisions (e.g., DQN).
+Interfacing with External Agents
+--------------------------------
+
+In many situations, it does not make sense for an environment to be "stepped" by RLlib. For example, if a policy is to be used in a web serving system, then it is more natural for an agent to query a service that serves policy decisions, and for that service to learn from experience over time. This case also naturally arises with **external simulators** that run independently outside the control of RLlib, but may still want to leverage RLlib for training.
+
+RLlib provides the `ExternalEnv `__ class for this purpose. Unlike other envs, ExternalEnv has its own thread of control. At any point, agents on that thread can query the current policy for decisions via ``self.get_action()`` and reports rewards via ``self.log_returns()``. This can be done for multiple concurrent episodes as well.
+
+ExternalEnv can be used to implement a simple REST policy `server `__ that learns over time using RLlib. In this example RLlib runs with ``num_workers=0`` to avoid port allocation issues, but in principle this could be scaled by increasing ``num_workers``.
+
+Logging off-policy actions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ExternalEnv also provides a ``self.log_action()`` call to support off-policy actions. This allows the client to make independent decisions, e.g., to compare two different policies, and for RLlib to still learn from those off-policy actions. Note that this requires the algorithm used to support learning from off-policy decisions (e.g., DQN).
+
+Data ingest
+~~~~~~~~~~~
-The ``log_action`` API of ServingEnv can be used to ingest data from offline logs. The pattern would be as follows: First, some policy is followed to produce experience data which is stored in some offline storage system. Then, RLlib creates a number of workers that use a ServingEnv to read the logs in parallel and ingest the experiences. After a round of training completes, the new policy can be deployed to collect more experiences.
+The ``log_action`` API of ExternalEnv can be used to ingest data from offline logs. The pattern would be as follows: First, some policy is followed to produce experience data which is stored in some offline storage system. Then, RLlib creates a number of workers that use a ExternalEnv to read the logs in parallel and ingest the experiences. After a round of training completes, the new policy can be deployed to collect more experiences.
Note that envs can read from different partitions of the logs based on the ``worker_index`` attribute of the `env context `__ passed into the environment constructor.
diff --git a/doc/source/rllib-envs.svg b/doc/source/rllib-envs.svg
index 37d6d66e6e1e5..2cc45dbf96fa7 100644
--- a/doc/source/rllib-envs.svg
+++ b/doc/source/rllib-envs.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/doc/source/rllib-models.rst b/doc/source/rllib-models.rst
index a234ba0022420..9e7070b66c489 100644
--- a/doc/source/rllib-models.rst
+++ b/doc/source/rllib-models.rst
@@ -13,15 +13,24 @@ Built-in Models and Preprocessors
RLlib picks default models based on a simple heuristic: a `vision network `__ for image observations, and a `fully connected network `__ for everything else. These models can be configured via the ``model`` config key, documented in the model `catalog `__. Note that you'll probably have to configure ``conv_filters`` if your environment observations have custom sizes, e.g., ``"model": {"dim": 42, "conv_filters": [[16, [4, 4], 2], [32, [4, 4], 2], [512, [11, 11], 1]]}`` for 42x42 observations.
-In addition, if you set ``"model": {"use_lstm": true}``, then the model output will be further processed by a `LSTM cell `__. More generally, RLlib supports the use of recurrent models for its algorithms (A3C, PG out of the box), and RNN support is built into its policy evaluation utilities.
+In addition, if you set ``"model": {"use_lstm": true}``, then the model output will be further processed by a `LSTM cell `__. More generally, RLlib supports the use of recurrent models for its policy gradient algorithms (A3C, PPO, PG, IMPALA), and RNN support is built into its policy evaluation utilities.
-For preprocessors, RLlib tries to pick one of its built-in preprocessor based on the environment's observation space. Discrete observations are one-hot encoded, Atari observations downscaled, and Tuple observations flattened (there isn't native tuple support yet, but you can reshape the flattened observation in a custom model). Note that for Atari, RLlib defaults to using the `DeepMind preprocessors `__, which are also used by the OpenAI baselines library.
+For preprocessors, RLlib tries to pick one of its built-in preprocessor based on the environment's observation space. Discrete observations are one-hot encoded, Atari observations downscaled, and Tuple and Dict observations flattened (these are unflattened and accessible via the ``input_dict`` parameter in custom models). Note that for Atari, RLlib defaults to using the `DeepMind preprocessors `__, which are also used by the OpenAI baselines library.
+Built-in Model Parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following is a list of the built-in model hyperparameters:
+
+.. literalinclude:: ../../python/ray/rllib/models/catalog.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
Custom Models
-------------
-Custom models should subclass the common RLlib `model class `__ and override the ``_build_layers`` method. This method takes in a tensor input (observation), and returns a feature layer and float vector of the specified output size. The model can then be registered and used in place of a built-in model:
+Custom models should subclass the common RLlib `model class `__ and override the ``_build_layers_v2`` method. This method takes in a dict of tensor inputs (the observation ``obs``, ``prev_action``, and ``prev_reward``, ``is_training``), and returns a feature layer and float vector of the specified output size. You can also override the ``value_function`` method to implement a custom value branch. A self-supervised loss can be defined via the ``loss`` method. The model can then be registered and used in place of a built-in model:
.. code-block:: python
@@ -30,12 +39,66 @@ Custom models should subclass the common RLlib `model class >> print(input_dict)
+ {'prev_actions': ,
+ 'prev_rewards': ,
+ 'is_training': ,
+ 'obs': OrderedDict([
+ ('sensors', OrderedDict([
+ ('front_cam', [
+ ,
+ ]),
+ ('position', ),
+ ('velocity', )]))])}
+ """
+
+ layer1 = slim.fully_connected(input_dict["obs"], 64, ...)
+ layer2 = slim.fully_connected(layer1, 64, ...)
...
return layerN, layerN_minus_1
+ def value_function(self):
+ """Builds the value function output.
+
+ This method can be overridden to customize the implementation of the
+ value function (e.g., not sharing hidden layers).
+
+ Returns:
+ Tensor of size [BATCH_SIZE] for the value function.
+ """
+ return tf.reshape(
+ linear(self.last_layer, 1, "value", normc_initializer(1.0)), [-1])
+
+ def loss(self):
+ """Builds any built-in (self-supervised) loss for the model.
+
+ For example, this can be used to incorporate auto-encoder style losses.
+ Note that this loss has to be included in the policy graph loss to have
+ an effect (done for built-in algorithms).
+
+ Returns:
+ Scalar tensor for the self-supervised loss.
+ """
+ return tf.constant(0.0)
+
ModelCatalog.register_custom_model("my_model", MyModelClass)
ray.init()
@@ -46,12 +109,53 @@ Custom models should subclass the common RLlib `model class `__ and associated `training scripts `__. The ``CarlaModel`` class defined there operates over a composite (Tuple) observation space including both images and scalar measurements.
+For a full example of a custom model in code, see the `Carla RLlib model `__ and associated `training scripts `__. You can also reference the `unit tests `__ for Tuple and Dict spaces, which show how to access nested observation fields.
+
+Custom Recurrent Models
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Instead of using the ``use_lstm: True`` option, it can be preferable use a custom recurrent model. This provides more control over postprocessing of the LSTM output and can also allow the use of multiple LSTM cells to process different portions of the input. The only difference from a normal custom model is that you have to define ``self.state_init``, ``self.state_in``, and ``self.state_out``. You can refer to the existing `lstm.py `__ model as an example to implement your own model:
+
+.. code-block:: python
+
+ class MyCustomLSTM(Model):
+ def _build_layers_v2(self, input_dict, num_outputs, options):
+ # Some initial layers to process inputs, shape [BATCH, OBS...].
+ features = some_hidden_layers(input_dict["obs"])
+
+ # Add back the nested time dimension for tf.dynamic_rnn, new shape
+ # will be [BATCH, MAX_SEQ_LEN, OBS...].
+ last_layer = add_time_dimension(features, self.seq_lens)
+
+ # Setup the LSTM cell (see lstm.py for an example)
+ lstm = rnn.BasicLSTMCell(256, state_is_tuple=True)
+ self.state_init = ...
+ self.state_in = ...
+ lstm_out, lstm_state = tf.nn.dynamic_rnn(
+ lstm,
+ last_layer,
+ initial_state=...,
+ sequence_length=self.seq_lens,
+ time_major=False,
+ dtype=tf.float32)
+ self.state_out = list(lstm_state)
+
+ # Drop the time dimension again so back to shape [BATCH, OBS...].
+ # Note that we retain the zero padding (see issue #2992).
+ last_layer = tf.reshape(lstm_out, [-1, cell_size])
+ logits = linear(last_layer, num_outputs, "action",
+ normc_initializer(0.01))
+ return logits, last_layer
+
+Batch Normalization
+~~~~~~~~~~~~~~~~~~~
+
+You can use ``tf.layers.batch_normalization(x, training=input_dict["is_training"])`` to add batch norm layers to your custom model: `code example `__. RLlib will automatically run the update ops for the batch norm layers during optimization (see `tf_policy_graph.py `__ and `multi_gpu_impl.py `__ for the exact handling of these updates).
Custom Preprocessors
--------------------
-Similarly, custom preprocessors should subclass the RLlib `preprocessor class `__ and be registered in the model catalog:
+Similarly, custom preprocessors should subclass the RLlib `preprocessor class `__ and be registered in the model catalog. Note that you can alternatively use `gym wrapper classes `__ around your environment instead of preprocessors.
.. code-block:: python
@@ -60,8 +164,8 @@ Similarly, custom preprocessors should subclass the RLlib `preprocessor class `__ and `Horizon `__. The general idea is that the meaning of actions can be completely conditioned on the observation, i.e., the ``a`` in ``Q(s, a)`` becomes just a token in ``[0, MAX_AVAIL_ACTIONS)`` that only has meaning in the context of ``s``. This works with algorithms in the `DQN and policy-gradient families `__ and can be implemented as follows:
+
+1. The environment should return a mask and/or list of valid action embeddings as part of the observation for each step. To enable batching, the number of actions can be allowed to vary from 1 to some max number:
+
+.. code-block:: python
+
+ class MyParamActionEnv(gym.Env):
+ def __init__(self, max_avail_actions):
+ self.action_space = Discrete(max_avail_actions)
+ self.observation_space = Dict({
+ "action_mask": Box(0, 1, shape=(max_avail_actions, )),
+ "avail_actions": Box(-1, 1, shape=(max_avail_actions, action_embedding_sz)),
+ "real_obs": ...,
+ })
+
+2. A custom model can be defined that can interpret the ``action_mask`` and ``avail_actions`` portions of the observation. Here the model computes the action logits via the dot product of some network output and each action embedding. Invalid actions can be masked out of the softmax by scaling the probability to zero:
+
+.. code-block:: python
+
+ class MyParamActionModel(Model):
+ def _build_layers_v2(self, input_dict, num_outputs, options):
+ avail_actions = input_dict["obs"]["avail_actions"]
+ action_mask = input_dict["obs"]["action_mask"]
+
+ output = FullyConnectedNetwork(
+ input_dict["obs"]["real_obs"], num_outputs=action_embedding_sz)
+
+ # Expand the model output to [BATCH, 1, EMBED_SIZE]. Note that the
+ # avail actions tensor is of shape [BATCH, MAX_ACTIONS, EMBED_SIZE].
+ intent_vector = tf.expand_dims(output, 1)
+
+ # Shape of logits is [BATCH, MAX_ACTIONS].
+ action_logits = tf.reduce_sum(avail_actions * intent_vector, axis=2)
+
+ # Mask out invalid actions (use tf.float32.min for stability)
+ inf_mask = tf.maximum(tf.log(action_mask), tf.float32.min)
+ masked_logits = inf_mask + action_logits
+
+ return masked_logits, last_layer
+
+
+Depending on your use case it may make sense to use just the masking, just action embeddings, or both. For a runnable example of this in code, check out `parametric_action_cartpole.py `__. Note that since masking introduces ``tf.float32.min`` values into the model output, this technique might not work with all algorithm options. For example, algorithms might crash if they incorrectly process the ``tf.float32.min`` values. The cartpole example has working configurations for DQN and several policy gradient algorithms.
+
Model-Based Rollouts
--------------------
@@ -137,7 +288,8 @@ With a custom policy graph, you can also perform model-based rollouts and option
def compute_actions(self,
obs_batch,
state_batches,
- is_training=False,
+ prev_action_batch=None,
+ prev_reward_batch=None,
episodes=None):
# compute a batch of actions based on the current obs_batch
# and state of each episode (i.e., for multiagent). You can do
diff --git a/doc/source/rllib-training.rst b/doc/source/rllib-training.rst
index 25cd0d8931850..dc350d272c99e 100644
--- a/doc/source/rllib-training.rst
+++ b/doc/source/rllib-training.rst
@@ -10,11 +10,11 @@ be trained, checkpointed, or an action computed.
.. image:: rllib-api.svg
-You can train a simple DQN agent with the following command
+You can train a simple DQN agent with the following command:
.. code-block:: bash
- python ray/python/ray/rllib/train.py --run DQN --env CartPole-v0
+ rllib train --run DQN --env CartPole-v0
By default, the results will be logged to a subdirectory of ``~/ray_results``.
This subdirectory will contain a file ``params.json`` which contains the
@@ -26,10 +26,12 @@ training process with TensorBoard by running
tensorboard --logdir=~/ray_results
-The ``train.py`` script has a number of options you can show by running
+The ``rllib train`` command (same as the ``train.py`` script in the repo) has a number of options you can show by running:
.. code-block:: bash
+ rllib train --help
+ -or-
python ray/python/ray/rllib/train.py --help
The most important options are for choosing the environment
@@ -37,46 +39,57 @@ with ``--env`` (any OpenAI gym environment including ones registered by the user
can be used) and for choosing the algorithm with ``--run``
(available options are ``PPO``, ``PG``, ``A2C``, ``A3C``, ``IMPALA``, ``ES``, ``DDPG``, ``DQN``, ``APEX``, and ``APEX_DDPG``).
+Evaluating Trained Agents
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to save checkpoints from which to evaluate agents,
+set ``--checkpoint-freq`` (number of training iterations between checkpoints)
+when running ``rllib train``.
+
+
+An example of evaluating a previously trained DQN agent is as follows:
+
+.. code-block:: bash
+
+ rllib rollout \
+ ~/ray_results/default/DQN_CartPole-v0_0upjmdgr0/checkpoint_1/checkpoint-1 \
+ --run DQN --env CartPole-v0 --steps 10000
+
+The ``rollout.py`` helper script reconstructs a DQN agent from the checkpoint
+located at ``~/ray_results/default/DQN_CartPole-v0_0upjmdgr0/checkpoint_1/checkpoint-1``
+and renders its behavior in the environment specified by ``--env``.
+
+Configuration
+-------------
+
Specifying Parameters
~~~~~~~~~~~~~~~~~~~~~
Each algorithm has specific hyperparameters that can be set with ``--config``, in addition to a number of `common hyperparameters `__. See the
`algorithms documentation `__ for more information.
-In an example below, we train A2C by specifying 8 workers through the config flag. We also set ``"monitor": true`` to save episode videos to the result dir:
+In an example below, we train A2C by specifying 8 workers through the config flag.
.. code-block:: bash
- python ray/python/ray/rllib/train.py --env=PongDeterministic-v4 \
- --run=A2C --config '{"num_workers": 8, "monitor": true}'
-
-.. image:: rllib-config.svg
+ rllib train --env=PongDeterministic-v4 --run=A2C --config '{"num_workers": 8}'
Specifying Resources
~~~~~~~~~~~~~~~~~~~~
-You can control the degree of parallelism used by setting the ``num_workers`` hyperparameter for most agents. Many agents also provide a ``num_gpus`` or ``gpu`` option. In addition, you can allocate a fraction of a GPU by setting ``gpu_fraction: f``. For example, with DQN you can pack five agents onto one GPU by setting ``gpu_fraction: 0.2``. Note that fractional GPU support requires enabling the experimental Xray backend by setting the environment variable ``RAY_USE_XRAY=1``.
->>>>>>> 01b030bd57f014386aa5e4c67a2e069938528abb
-
-Evaluating Trained Agents
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In order to save checkpoints from which to evaluate agents,
-set ``--checkpoint-freq`` (number of training iterations between checkpoints)
-when running ``train.py``.
-
+You can control the degree of parallelism used by setting the ``num_workers`` hyperparameter for most agents. The number of GPUs the driver should use can be set via the ``num_gpus`` option. Similarly, the resource allocation to workers can be controlled via ``num_cpus_per_worker``, ``num_gpus_per_worker``, and ``custom_resources_per_worker``. The number of GPUs can be a fractional quantity to allocate only a fraction of a GPU. For example, with DQN you can pack five agents onto one GPU by setting ``num_gpus: 0.2``. Note that in Ray < 0.6.0 fractional GPU support requires setting the environment variable ``RAY_USE_XRAY=1``.
-An example of evaluating a previously trained DQN agent is as follows:
+.. image:: rllib-config.svg
-.. code-block:: bash
+Common Parameters
+~~~~~~~~~~~~~~~~~
- python ray/python/ray/rllib/rollout.py \
- ~/ray_results/default/DQN_CartPole-v0_0upjmdgr0/checkpoint-1 \
- --run DQN --env CartPole-v0
+The following is a list of the common agent hyperparameters:
-The ``rollout.py`` helper script reconstructs a DQN agent from the checkpoint
-located at ``~/ray_results/default/DQN_CartPole-v0_0upjmdgr0/checkpoint-1``
-and renders its behavior in the environment specified by ``--env``.
+.. literalinclude:: ../../python/ray/rllib/agents/agent.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
Tuned Examples
~~~~~~~~~~~~~~
@@ -86,16 +99,16 @@ Some good hyperparameters and settings are available in
(some of them are tuned to run on GPUs). If you find better settings or tune
an algorithm on a different domain, consider submitting a Pull Request!
-You can run these with the ``train.py`` script as follows:
+You can run these with the ``rllib train`` command as follows:
.. code-block:: bash
- python ray/python/ray/rllib/train.py -f /path/to/tuned/example.yaml
+ rllib train -f /path/to/tuned/example.yaml
Python API
----------
-The Python API provides the needed flexibility for applying RLlib to new problems. You will need to use this API if you wish to use custom environments, preprocesors, or models with RLlib.
+The Python API provides the needed flexibility for applying RLlib to new problems. You will need to use this API if you wish to use `custom environments, preprocessors, or models `__ with RLlib.
Here is an example of the basic usage:
@@ -155,7 +168,7 @@ Tune will schedule the trials to run in parallel on your Ray cluster:
== Status ==
Using FIFO scheduling algorithm.
Resources requested: 4/4 CPUs, 0/0 GPUs
- Result logdir: /home/eric/ray_results/my_experiment
+ Result logdir: ~/ray_results/my_experiment
PENDING trials:
- PPO_CartPole-v0_2_sgd_stepsize=0.0001: PENDING
RUNNING trials:
@@ -184,11 +197,194 @@ You can also access just the "master" copy of the agent state through ``agent.lo
agent.optimizer.foreach_evaluator_with_index(
lambda ev, i: ev.for_policy(lambda p: p.get_weights()))
+Global Coordination
+~~~~~~~~~~~~~~~~~~~
+Sometimes, it is necessary to coordinate between pieces of code that live in different processes managed by RLlib. For example, it can be useful to maintain a global average of a certain variable, or centrally control a hyperparameter used by policies. Ray provides a general way to achieve this through *named actors* (learn more about Ray actors `here `__). As an example, consider maintaining a shared global counter that is incremented by environments and read periodically from your driver program:
+
+.. code-block:: python
+
+ from ray.experimental import named_actors
+
+ @ray.remote
+ class Counter:
+ def __init__(self):
+ self.count = 0
+ def inc(self, n):
+ self.count += n
+ def get(self):
+ return self.count
+
+ # on the driver
+ counter = Counter.remote()
+ named_actors.register_actor("global_counter", counter)
+ print(ray.get(counter.get.remote())) # get the latest count
+
+ # in your envs
+ counter = named_actors.get_actor("global_counter")
+ counter.inc.remote(1) # async call to increment the global count
+
+Ray actors provide high levels of performance, so in more complex cases they can be used implement communication patterns such as parameter servers and allreduce.
+
+Callbacks and Custom Metrics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can provide callback functions to be called at points during policy evaluation. These functions have access to an info dict containing state for the current `episode `__. Custom state can be stored for the `episode `__ in the ``info["episode"].user_data`` dict, and custom scalar metrics reported by saving values to the ``info["episode"].custom_metrics`` dict. These custom metrics will be aggregated and reported as part of training results. The following example (full code `here `__) logs a custom metric from the environment:
+
+.. code-block:: python
+
+ def on_episode_start(info):
+ print(info.keys()) # -> "env", 'episode"
+ episode = info["episode"]
+ print("episode {} started".format(episode.episode_id))
+ episode.user_data["pole_angles"] = []
+
+ def on_episode_step(info):
+ episode = info["episode"]
+ pole_angle = abs(episode.last_observation_for()[2])
+ episode.user_data["pole_angles"].append(pole_angle)
+
+ def on_episode_end(info):
+ episode = info["episode"]
+ pole_angle = np.mean(episode.user_data["pole_angles"])
+ print("episode {} ended with length {} and pole angles {}".format(
+ episode.episode_id, episode.length, pole_angle))
+ episode.custom_metrics["pole_angle"] = pole_angle
+
+ def on_train_result(info):
+ print("agent.train() result: {} -> {} episodes".format(
+ info["agent"].__name__, info["result"]["episodes_this_iter"]))
+
+ ray.init()
+ trials = tune.run_experiments({
+ "test": {
+ "env": "CartPole-v0",
+ "run": "PG",
+ "config": {
+ "callbacks": {
+ "on_episode_start": tune.function(on_episode_start),
+ "on_episode_step": tune.function(on_episode_step),
+ "on_episode_end": tune.function(on_episode_end),
+ "on_train_result": tune.function(on_train_result),
+ },
+ },
+ }
+ })
+
+Custom metrics can be accessed and visualized like any other training result:
+
+.. image:: custom_metric.png
+
+Example: Curriculum Learning
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's look at two ways to use the above APIs to implement `curriculum learning `__. In curriculum learning, the agent task is adjusted over time to improve the learning process. Suppose that we have an environment class with a ``set_phase()`` method that we can call to adjust the task difficulty over time:
+
+Approach 1: Use the Agent API and update the environment between calls to ``train()``. This example shows the agent being run inside a Tune function:
+
+.. code-block:: python
+
+ import ray
+ from ray import tune
+ from ray.rllib.agents.ppo import PPOAgent
+
+ def train(config, reporter):
+ agent = PPOAgent(config=config, env=YourEnv)
+ while True:
+ result = agent.train()
+ reporter(**result)
+ if result["episode_reward_mean"] > 200:
+ phase = 2
+ elif result["episode_reward_mean"] > 100:
+ phase = 1
+ else:
+ phase = 0
+ agent.optimizer.foreach_evaluator(lambda ev: ev.env.set_phase(phase))
+
+ ray.init()
+ tune.run_experiments({
+ "curriculum": {
+ "run": train,
+ "config": {
+ "num_gpus": 0,
+ "num_workers": 2,
+ },
+ "trial_resources": {
+ "cpu": 1,
+ "gpu": lambda spec: spec.config.num_gpus,
+ "extra_cpu": lambda spec: spec.config.num_workers,
+ },
+ },
+ })
+
+Approach 2: Use the callbacks API to update the environment on new training results:
+
+.. code-block:: python
+
+ import ray
+ from ray import tune
+
+ def on_train_result(info):
+ result = info["result"]
+ if result["episode_reward_mean"] > 200:
+ phase = 2
+ elif result["episode_reward_mean"] > 100:
+ phase = 1
+ else:
+ phase = 0
+ agent = info["agent"]
+ agent.optimizer.foreach_evaluator(lambda ev: ev.env.set_phase(phase))
+
+ ray.init()
+ tune.run_experiments({
+ "curriculum": {
+ "run": "PPO",
+ "env": YourEnv,
+ "config": {
+ "callbacks": {
+ "on_train_result": tune.function(on_train_result),
+ },
+ },
+ },
+ })
+
+Debugging
+---------
+
+Gym Monitor
+~~~~~~~~~~~
+
+The ``"monitor": true`` config can be used to save Gym episode videos to the result dir. For example:
+
+.. code-block:: bash
+
+ rllib train --env=PongDeterministic-v4 \
+ --run=A2C --config '{"num_workers": 2, "monitor": true}'
+
+ # videos will be saved in the ~/ray_results/ dir, for example
+ openaigym.video.0.31401.video000000.meta.json
+ openaigym.video.0.31401.video000000.mp4
+ openaigym.video.0.31403.video000000.meta.json
+ openaigym.video.0.31403.video000000.mp4
+
+Log Verbosity
+~~~~~~~~~~~~~
+
+You can control the agent log level via the ``"log_level"`` flag. Valid values are "INFO" (default), "DEBUG", "WARN", and "ERROR". This can be used to increase or decrease the verbosity of internal logging. For example:
+
+.. code-block:: bash
+
+ rllib train --env=PongDeterministic-v4 \
+ --run=A2C --config '{"num_workers": 2, "log_level": "DEBUG"}'
+
+Stack Traces
+~~~~~~~~~~~~
+
+You can use the ``ray stack`` command to dump the stack traces of all the Python workers on a single node. This can be useful for debugging unexpected hangs or performance issues.
REST API
--------
-In some cases (i.e., when interacting with an external environment) it makes more sense to interact with RLlib as if were an independently running service, rather than RLlib hosting the simulations itself. This is possible via RLlib's serving env `interface `__.
+In some cases (i.e., when interacting with an externally hosted simulator or production environment) it makes more sense to interact with RLlib as if were an independently running service, rather than RLlib hosting the simulations itself. This is possible via RLlib's external agents `interface `__.
.. autoclass:: ray.rllib.utils.policy_client.PolicyClient
:members:
diff --git a/doc/source/rllib.rst b/doc/source/rllib.rst
index ea5bbbf583810..e96bd6fccbcb9 100644
--- a/doc/source/rllib.rst
+++ b/doc/source/rllib.rst
@@ -10,14 +10,14 @@ Learn more about RLlib's design by reading the `ICML paper `__ or `TensorFlow `__. Then, install the Ray RLlib module:
+RLlib has extra dependencies on top of ``ray``. First, you'll need to install either `PyTorch `__ or `TensorFlow `__. Then, install the RLlib module:
.. code-block:: bash
pip install tensorflow # or tensorflow-gpu
- pip install ray[rllib]
+ pip install ray[rllib] # also recommended: ray[debug]
-You might also want to clone the Ray repo for convenient access to RLlib helper scripts:
+You might also want to clone the `Ray repo `__ for convenient access to RLlib helper scripts:
.. code-block:: bash
@@ -27,7 +27,9 @@ You might also want to clone the Ray repo for convenient access to RLlib helper
Training APIs
-------------
* `Command-line `__
+* `Configuration `__
* `Python API `__
+* `Debugging `__
* `REST API `__
Environments
@@ -36,8 +38,7 @@ Environments
* `OpenAI Gym `__
* `Vectorized `__
* `Multi-Agent `__
-* `Agent-Driven `__
-* `Offline Data Ingest `__
+* `Interfacing with External Agents `__
* `Batch Asynchronous `__
Algorithms
@@ -53,9 +54,9 @@ Algorithms
- `Advantage Actor-Critic (A2C, A3C) `__
- - `Deep Deterministic Policy Gradients (DDPG) `__
+ - `Deep Deterministic Policy Gradients (DDPG, TD3) `__
- - `Deep Q Networks (DQN, Rainbow) `__
+ - `Deep Q Networks (DQN, Rainbow, Parametric DQN) `__
- `Policy Gradients `__
@@ -74,6 +75,7 @@ Models and Preprocessors
* `Custom Models `__
* `Custom Preprocessors `__
* `Customizing Policy Graphs `__
+* `Variable-length / Parametric Action Spaces `__
* `Model-Based Rollouts `__
RLlib Concepts
@@ -98,3 +100,6 @@ If you encounter errors like
`blas_thread_init: pthread_create: Resource temporarily unavailable` when using many workers,
try setting ``OMP_NUM_THREADS=1``. Similarly, check configured system limits with
`ulimit -a` for other resource limit errors.
+
+For debugging unexpected hangs or performance problems, you can run ``ray stack`` to dump
+the stack traces of all Ray workers on the current node. This requires py-spy to be installed.
diff --git a/doc/source/security.rst b/doc/source/security.rst
new file mode 100644
index 0000000000000..6b636c66858e2
--- /dev/null
+++ b/doc/source/security.rst
@@ -0,0 +1,55 @@
+Security
+========
+
+This document describes best security practices for using Ray.
+
+Intended Use and Threat Model
+-----------------------------
+
+Ray instances should run on a secure network without public facing ports.
+The most common threat for Ray instances is unauthorized access to Redis,
+which can be exploited to gain shell access and run arbitray code.
+The best fix is to run Ray instances on a secure, trusted network.
+
+Running Ray on a secured network is not always feasible, so Ray
+provides some basic security features:
+
+
+Redis Port Authentication
+-------------------------
+
+To prevent exploits via unauthorized Redis access, Ray provides the option to
+password-protect Redis ports. While this is not a replacement for running Ray
+behind a firewall, this feature is useful for instances exposed to the internet
+where configuring a firewall is not possible. Because Redis is
+very fast at serving queries, the chosen password should be long.
+
+Redis authentication is only supported on the raylet code path.
+
+To add authentication via the Python API, start Ray using:
+
+.. code-block:: python
+
+ ray.init(redis_password="password")
+
+To add authentication via the CLI, or connect to an existing Ray instance with
+password-protected Redis ports:
+
+.. code-block:: bash
+
+ ray start [--head] --redis-password="password"
+
+While Redis port authentication may protect against external attackers,
+Ray does not encrypt traffic between nodes so man-in-the-middle attacks are
+possible for clusters on untrusted networks.
+
+Cloud Security
+--------------
+
+Launching Ray clusters on AWS or GCP using the ``ray up`` command
+automatically configures security groups that prevent external Redis access.
+
+References
+----------
+
+- The `Redis security documentation `
diff --git a/doc/source/sgd.png b/doc/source/sgd.png
new file mode 100644
index 0000000000000..aed38161cb159
Binary files /dev/null and b/doc/source/sgd.png differ
diff --git a/doc/source/tempfile.rst b/doc/source/tempfile.rst
new file mode 100644
index 0000000000000..d68e835e0261b
--- /dev/null
+++ b/doc/source/tempfile.rst
@@ -0,0 +1,86 @@
+Temporary Files
+===============
+
+Ray will produce some temporary files during running.
+They are useful for logging, debugging & sharing object store with other programs.
+
+Location of Temporary Files
+---------------------------
+
+First we introduce the concept of a session of Ray.
+
+A session contains a set of processes. A session is created by executing
+``ray start`` command or call ``ray.init()`` in a Python script and ended by
+executing ``ray stop`` or call ``ray.shutdown()``.
+
+For each session, Ray will create a *root temporary directory* to place all its
+temporary files. The path is ``/tmp/ray/session_{datetime}_{pid}`` by default.
+The pid belongs to the startup process (the process calling ``ray.init()`` or
+the Ray process executed by a shell in ``ray start``).
+You can sort by their names to find the latest session.
+
+You are allowed to change the *root temporary directory* in one of these ways:
+
+* Pass ``--temp-dir={your temp path}`` to ``ray start``
+* Specify ``temp_dir`` when call ``ray.init()``
+
+You can also use ``default_worker.py --temp-dir={your temp path}`` to
+start a new worker with given *root temporary directory*.
+
+The *root temporary directory* you specified will be given as it is,
+without pids or datetime attached.
+
+Layout of Temporary Files
+-------------------------
+
+A typical layout of temporary files could look like this:
+
+.. code-block:: text
+
+ /tmp
+ └── ray
+ └── session_{datetime}_{pid}
+ ├── logs # for logging
+ │  ├── log_monitor.err
+ │  ├── log_monitor.out
+ │  ├── monitor.err
+ │  ├── monitor.out
+ │  ├── plasma_store_0.err # array of plasma stores' outputs
+ │  ├── plasma_store_0.out
+ │  ├── raylet_0.err # array of raylets' outputs. Control it with `--no-redirect-worker-output` (in Ray's command line) or `redirect_worker_output` (in ray.init())
+ │  ├── raylet_0.out
+ │  ├── redis-shard_0.err # array of redis shards' outputs
+ │  ├── redis-shard_0.out
+ │  ├── redis.err # redis
+ │  ├── redis.out
+ │  ├── webui.err # ipython notebook web ui
+ │  ├── webui.out
+ │  ├── worker-{worker_id}.err # redirected output of workers
+ │  ├── worker-{worker_id}.out
+ │  └── {other workers}
+ ├── ray_ui.ipynb # ipython notebook file
+ └── sockets # for sockets
+ ├── plasma_store
+ └── raylet # this could be deleted by Ray's shutdown cleanup.
+
+
+Plasma Object Store Socket
+--------------------------
+
+Plasma object store sockets can be used to share objects with other programs using Apache Arrow.
+
+You are allowed to specify the plasma object store socket in one of these ways:
+
+* Pass ``--plasma-store-socket-name={your socket path}`` to ``ray start``
+* Specify ``plasma_store_socket_name`` when call ``ray.init()``
+
+The path you specified will be given as it is without being affected any other paths.
+
+
+Notes
+-----
+
+Temporary file policies are defined in ``python/ray/tempfile_services.py``.
+
+Currently, we keep ``/tmp/ray`` as the default directory for temporary data files of RLlib as before.
+It is not very reasonable and could be changed later.
diff --git a/doc/source/troubleshooting.rst b/doc/source/troubleshooting.rst
index ff4b3039e8c15..86f56e7755957 100644
--- a/doc/source/troubleshooting.rst
+++ b/doc/source/troubleshooting.rst
@@ -61,10 +61,10 @@ of the following reasons.
- **Stressful workloads:** Workloads that create many many tasks in a short
amount of time can sometimes interfere with the heartbeat mechanism that we
use to check that processes are still alive. On the head node in the cluster,
- you can check the files ``/tmp/raylogs/monitor-******.out`` and
- ``/tmp/raylogs/monitor-******.err``. They will indicate which processes Ray
- has marked as dead (due to a lack of heartbeats). However, it is currently
- possible for a process to get marked as dead without actually having died.
+ you can check the files ``/tmp/ray/session_*/logs/monitor*``. They will
+ indicate which processes Ray has marked as dead (due to a lack of heartbeats).
+ However, it is currently possible for a process to get marked as dead without
+ actually having died.
- **Starting many actors:** Workloads that start a large number of actors all at
once may exhibit problems when the processes (or libraries that they use)
@@ -92,6 +92,11 @@ of the following reasons.
Hanging
-------
+.. tip::
+
+ You can run ``ray stack`` to dump the stack traces of all Ray workers on
+ the current node. This requires py-spy to be installed.
+
If a workload is hanging and not progressing, the problem may be one of the
following.
diff --git a/doc/source/tune-examples.rst b/doc/source/tune-examples.rst
new file mode 100644
index 0000000000000..e0af86bcb6956
--- /dev/null
+++ b/doc/source/tune-examples.rst
@@ -0,0 +1,62 @@
+Tune Examples
+=============
+
+.. Keep this in sync with ray/python/ray/tune/examples/README.rst
+
+In our repository, we provide a variety of examples for the various use cases and features of Tune.
+
+If any example is broken, or if you'd like to add an example to this page, feel free to raise an issue on our Github repository.
+
+
+General Examples
+----------------
+
+- `async_hyperband_example `__:
+ Example of using a Trainable class with AsyncHyperBandScheduler.
+- `hyperband_example `__:
+ Example of using a Trainable class with HyperBandScheduler. Also uses the Experiment class API for specifying the experiment configuration.
+- `hyperopt_example `__:
+ Optimizes a basic function using the function-based API and the HyperOptSearch (SearchAlgorithm wrapper for HyperOpt TPE).
+ Also uses the AsyncHyperBandScheduler.
+- `pbt_example `__:
+ Example of using a Trainable class with PopulationBasedTraining scheduler.
+- `pbt_ppo_example `__:
+ Example of optimizing a distributed RLlib algorithm (PPO) with the PopulationBasedTraining scheduler.
+
+
+Keras Examples
+--------------
+
+- `tune_mnist_keras `__:
+ Converts the Keras MNIST example to use Tune with the function-based API and a Keras callback. Also shows how to easily convert something relying on argparse to use Tune.
+
+
+PyTorch Examples
+----------------
+
+- `mnist_pytorch `__:
+ Converts the PyTorch MNIST example to use Tune with the function-based API. Also shows how to easily convert something relying on argparse to use Tune.
+- `mnist_pytorch_trainable `__:
+ Converts the PyTorch MNIST example to use Tune with Trainable API. Also uses the HyperBandScheduler and checkpoints the model at the end.
+
+
+TensorFlow Examples
+-------------------
+
+- `tune_mnist_ray `__:
+ A basic example of tuning a TensorFlow model on MNIST using the Trainable class.
+- `tune_mnist_ray_hyperband `__:
+ A basic example of tuning a TensorFlow model on MNIST using the Trainable class and the HyperBand scheduler.
+- `tune_mnist_async_hyperband `__:
+ Example of tuning a TensorFlow model on MNIST using AsyncHyperBand.
+
+
+Contributed Examples
+--------------------
+
+- `pbt_tune_cifar10_with_keras `__:
+ A contributed example of tuning a Keras model on CIFAR10 with the PopulationBasedTraining scheduler.
+- `genetic_example `__:
+ Optimizing the michalewicz function using the contributed GeneticSearch search algorithm with AsyncHyperBandScheduler.
+
+
diff --git a/doc/source/tune-package-ref.rst b/doc/source/tune-package-ref.rst
index d6f13cd981556..e7f3d3167adab 100644
--- a/doc/source/tune-package-ref.rst
+++ b/doc/source/tune-package-ref.rst
@@ -12,6 +12,11 @@ ray.tune
:members:
:private-members:
+
+.. autoclass:: ray.tune.function_runner.StatusReporter
+ :members: __call__
+
+
ray.tune.schedulers
-------------------
@@ -24,7 +29,7 @@ ray.tune.suggest
.. automodule:: ray.tune.suggest
:members:
- :exclude-members: function, grid_search, SuggestionAlgorithm
+ :exclude-members: function, sample_from, grid_search, SuggestionAlgorithm
:show-inheritance:
.. autoclass:: ray.tune.suggest.SuggestionAlgorithm
diff --git a/doc/source/tune-searchalg.rst b/doc/source/tune-searchalg.rst
index 97e8ce1bc295c..e8e5b0fa672ef 100644
--- a/doc/source/tune-searchalg.rst
+++ b/doc/source/tune-searchalg.rst
@@ -25,10 +25,13 @@ By default, Tune uses the `default search space and variant generation process <
:noindex:
+Note that other search algorithms will not necessarily extend this class and may require a different search space declaration than the default Tune format.
+
HyperOpt Search (Tree-structured Parzen Estimators)
---------------------------------------------------
-The ``HyperOptSearch`` is a SearchAlgorithm that is backed by `HyperOpt `__ to perform sequential model-based hyperparameter optimization.
+The ``HyperOptSearch`` is a SearchAlgorithm that is backed by `HyperOpt `__ to perform sequential model-based hyperparameter optimization. Note that this class does not extend ``ray.tune.suggest.BasicVariantGenerator``, so you will not be able to use Tune's default variant generation/search space declaration when using HyperOptSearch.
+
In order to use this search algorithm, you will need to install HyperOpt via the following command:
.. code-block:: bash
@@ -47,7 +50,6 @@ An example of this can be found in `hyperopt_example.py `__.
-
-More information about Tune's `trial schedulers can be found here `__.
-
+More information about Tune's `search algorithms can be found here `__. More information about Tune's `trial schedulers can be found here `__.
Start by installing, importing, and initializing Ray.
@@ -22,29 +19,48 @@ Start by installing, importing, and initializing Ray.
ray.init()
-Tune provides a ``run_experiments`` function that generates and runs the trials as described by the `experiment specification `__.
-.. autofunction:: ray.tune.run_experiments
- :noindex:
+Experiment Configuration
+------------------------
-This function will report status on the command line until all Trials stop:
+This section will cover the main steps needed to modify your code to run Tune: using the `Training API `__ and `executing your Tune experiment `__.
-::
+You can checkout out our `examples page `__ for more code examples.
- == Status ==
- Using FIFO scheduling algorithm.
- Resources used: 4/8 CPUs, 0/0 GPUs
- Result logdir: ~/ray_results/my_experiment
- - train_func_0_lr=0.2,momentum=1: RUNNING [pid=6778], 209 s, 20604 ts, 7.29 acc
- - train_func_1_lr=0.4,momentum=1: RUNNING [pid=6780], 208 s, 20522 ts, 53.1 acc
- - train_func_2_lr=0.6,momentum=1: TERMINATED [pid=6789], 21 s, 2190 ts, 100 acc
- - train_func_3_lr=0.2,momentum=2: RUNNING [pid=6791], 208 s, 41004 ts, 8.37 acc
- - train_func_4_lr=0.4,momentum=2: RUNNING [pid=6800], 209 s, 41204 ts, 70.1 acc
- - train_func_5_lr=0.6,momentum=2: TERMINATED [pid=6809], 10 s, 2164 ts, 100 acc
+Training API
+~~~~~~~~~~~~
+Training can be done with either the **function-based API** or **Trainable API**.
+
+**Python functions** will need to have the following signature:
+
+.. code-block:: python
+
+ def trainable(config, reporter):
+ """
+ Args:
+ config (dict): Parameters provided from the search algorithm
+ or variant generation.
+ reporter (Reporter): Handle to report intermediate metrics to Tune.
+ """
+
+ while True:
+ # ...
+ reporter(**kwargs)
+
+The reporter will allow you to report metrics used for scheduling, search, or early stopping.
+
+Tune will run this function on a separate thread in a Ray actor process. Note that this API is not checkpointable, since the thread will never return control back to its caller. The reporter documentation can be `found here `__.
+
+.. note::
+ If you have a lambda function that you want to train, you will need to first register the function: ``tune.register_trainable("lambda_id", lambda x: ...)``. You can then use ``lambda_id`` in place of ``my_trainable``.
+
+**Python classes** passed into Tune will need to subclass ``ray.tune.Trainable``. The Trainable interface `can be found here `__.
+
+Both the Trainable and function-based API will have `autofilled metrics `__ in addition to the metrics reported.
+
+See the `experiment specification `__ section on how to specify and execute your training.
-Experiment Configuration
-------------------------
Specifying Experiments
~~~~~~~~~~~~~~~~~~~~~~
@@ -79,54 +95,33 @@ dictionary. Tune will convert the dict into an ``ray.tune.Experiment`` object.
"max_failures": 2
}
}
- run_experiments(experiment_spec)
-
-
-An example of this can be found in `async_hyperband_example.py `__.
-
-Model API
-~~~~~~~~~
-
-You can either pass in a Python function or Python class for model training as follows, each requiring a specific signature/interface:
-
-.. code-block:: python
- :emphasize-lines: 3,8
-
- experiment_spec = {
- "my_experiment_name": {
- "run": my_trainable
- }
- }
- # or with the Experiment API
- experiment_spec = Experiment("my_experiment_name", my_trainable)
+Tune provides a ``run_experiments`` function that generates and runs the trials.
- run_experiments(experiments=experiment_spec)
-
-
-**Python functions** will need to have the following signature:
+.. autofunction:: ray.tune.run_experiments
+ :noindex:
-.. code-block:: python
+This function will report status on the command line until all Trials stop:
- def trainable(config, reporter):
- """
- Args:
- config (dict): Parameters provided from the search algorithm
- or variant generation.
- reporter (Reporter): Handle to report intermediate metrics to Tune.
- """
+::
-Tune will run this function on a separate thread in a Ray actor process. Note that trainable functions are not checkpointable, since they never return control back to their caller. See `Trial Checkpointing for more details `__.
+ == Status ==
+ Using FIFO scheduling algorithm.
+ Resources used: 4/8 CPUs, 0/0 GPUs
+ Result logdir: ~/ray_results/my_experiment
+ - train_func_0_lr=0.2,momentum=1: RUNNING [pid=6778], 209 s, 20604 ts, 7.29 acc
+ - train_func_1_lr=0.4,momentum=1: RUNNING [pid=6780], 208 s, 20522 ts, 53.1 acc
+ - train_func_2_lr=0.6,momentum=1: TERMINATED [pid=6789], 21 s, 2190 ts, 100 acc
+ - train_func_3_lr=0.2,momentum=2: RUNNING [pid=6791], 208 s, 41004 ts, 8.37 acc
+ - train_func_4_lr=0.4,momentum=2: RUNNING [pid=6800], 209 s, 41204 ts, 70.1 acc
+ - train_func_5_lr=0.6,momentum=2: TERMINATED [pid=6809], 10 s, 2164 ts, 100 acc
-.. note::
- If you have a lambda function that you want to train, you will need to first register the function: ``tune.register_trainable("lambda_id", lambda x: ...)``. You can then use ``lambda_id`` in place of ``my_trainable``.
-**Python classes** passed into Tune will need to subclass ``ray.tune.Trainable``.
+An example of this can be found in `async_hyperband_example.py `__.
-.. autoclass:: ray.tune.Trainable
- :members: __init__, _save, _restore, _train, _setup, _stop
- :noindex:
+Training Features
+-----------------
Tune Search Space (Default)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -134,6 +129,9 @@ Tune Search Space (Default)
You can use ``tune.grid_search`` to specify an axis of a grid search. By default, Tune also supports sampling parameters from user-specified lambda functions, which can be used independently or in combination with grid search.
+.. note::
+ If you specify an explicit Search Algorithm such as any SuggestionAlgorithm, you may not be able to specify lambdas or grid search with this interface, as the search algorithm may require a different search space declaration.
+
The following shows grid search over two nested parameters combined with random sampling from two lambda functions, generating 9 different trials. Note that the value of ``beta`` depends on the value of ``alpha``, which is represented by referencing ``spec.config.alpha`` in the lambda function. This lets you specify conditional parameter distributions.
.. code-block:: python
@@ -143,8 +141,8 @@ The following shows grid search over two nested parameters combined with random
"my_experiment_name": {
"run": my_trainable,
"config": {
- "alpha": lambda spec: np.random.uniform(100),
- "beta": lambda spec: spec.config.alpha * np.random.normal(),
+ "alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
+ "beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
@@ -155,10 +153,7 @@ The following shows grid search over two nested parameters combined with random
.. note::
- Lambda functions will be evaluated during trial variant generation. If you need to pass a literal function in your config, use ``tune.function(...)`` to escape it.
-
-.. warning::
- If you specify a Search Algorithm, you may not be able to use this feature, as the algorithm may require a different search space declaration.
+ Use ``tune.sample_from(...)`` to sample from a function during trial variant generation. If you need to pass a literal function in your config, use ``tune.function(...)`` to escape it.
For more information on variant generation, see `basic_variant.py `__.
@@ -174,8 +169,8 @@ By default, each random variable and grid search point is sampled once. To take
"my_experiment_name": {
"run": my_trainable,
"config": {
- "alpha": lambda spec: np.random.uniform(100),
- "beta": lambda spec: spec.config.alpha * np.random.normal(),
+ "alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
+ "beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
@@ -193,9 +188,12 @@ Using GPUs (Resource Allocation)
Tune will allocate the specified GPU and CPU ``trial_resources`` to each individual trial (defaulting to 1 CPU per trial). Under the hood, Tune runs each trial as a Ray actor, using Ray's resource handling to allocate resources and place actors. A trial will not be scheduled unless at least that amount of resources is available in the cluster, preventing the cluster from being overloaded.
+Fractional values are also supported, (i.e., ``"gpu": 0.2``). You can find an example of this in the `Keras MNIST example `__.
+
If GPU resources are not requested, the ``CUDA_VISIBLE_DEVICES`` environment variable will be set as empty, disallowing GPU access.
Otherwise, it will be set to the GPUs in the list (this is managed by Ray).
+
If your trainable function / class creates further Ray actors or tasks that also consume CPU / GPU resources, you will also want to set ``extra_cpu`` or ``extra_gpu`` to reserve extra resource slots for the actors you will create. For example, if a trainable class requires 1 GPU itself, but will launch 4 actors each using another GPU, then it should set ``"gpu": 1, "extra_gpu": 4``.
.. code-block:: python
@@ -216,14 +214,14 @@ If your trainable function / class creates further Ray actors or tasks that also
Trial Checkpointing
~~~~~~~~~~~~~~~~~~~
-To enable checkpointing, you must implement a `Trainable class `__ (Trainable functions are not checkpointable, since they never return control back to their caller). The easiest way to do this is to subclass the pre-defined ``Trainable`` class and implement its ``_train``, ``_save``, and ``_restore`` abstract methods `(example) `__. Implementing this interface is required to support resource multiplexing in Trial Schedulers such as HyperBand and PBT.
+To enable checkpointing, you must implement a `Trainable class `__ (Trainable functions are not checkpointable, since they never return control back to their caller). The easiest way to do this is to subclass the pre-defined ``Trainable`` class and implement its ``_train``, ``_save``, and ``_restore`` abstract methods `(example) `__. Implementing this interface is required to support resource multiplexing in Trial Schedulers such as HyperBand and PBT.
For TensorFlow model training, this would look something like this `(full tensorflow example) `__:
.. code-block:: python
class MyClass(Trainable):
- def _setup(self):
+ def _setup(self, config):
self.saver = tf.train.Saver()
self.sess = ...
self.iteration = 0
@@ -297,6 +295,28 @@ You often will want to compute a large object (e.g., training data, model weight
}
})
+Auto-Filled Results
+-------------------
+
+During training, Tune will automatically fill certain fields if not already provided. All of these can be used as stopping conditions or in the Scheduler/Search Algorithm specification.
+
+.. literalinclude:: ../../python/ray/tune/result.py
+ :language: python
+ :start-after: __sphinx_doc_begin__
+ :end-before: __sphinx_doc_end__
+
+The following fields will automatically show up on the console output, if provided:
+
+1. ``episode_reward_mean``
+2. ``mean_loss``
+3. ``mean_accuracy``
+4. ``timesteps_this_iter`` (aggregated into ``timesteps_total``).
+
+.. code-block:: bash
+
+ Example_0: TERMINATED [pid=68248], 179 s, 2 iter, 60000 ts, 94 rew
+
+
Logging and Visualizing Results
-------------------------------
@@ -360,12 +380,6 @@ Then, on the client side, you can use the following class. The server address de
For an example notebook for using the Client API, see the `Client API Example `__.
-Examples
---------
-
-You can find a comprehensive of examples `using Tune and its various features here `__, including examples using Keras, TensorFlow, and Population-Based Training.
-
-
Further Questions or Issues?
----------------------------
diff --git a/doc/source/tune.rst b/doc/source/tune.rst
index a849f3b811d58..14c95fb0edcb0 100644
--- a/doc/source/tune.rst
+++ b/doc/source/tune.rst
@@ -7,7 +7,10 @@ Tune: Scalable Hyperparameter Search
Tune is a scalable framework for hyperparameter search with a focus on deep learning and deep reinforcement learning.
-You can find the code for Tune `here on GitHub `__.
+You can find the code for Tune `here on GitHub `__. To get started with Tune, try going through `our tutorial of using Tune with Keras `__.
+
+(Experimental): You can try out `the above tutorial on a free hosted server via Binder `__.
+
Features
--------
@@ -42,7 +45,7 @@ You'll need to first `install ray `__ to import Tune.
.. code-block:: bash
- pip install ray
+ pip install ray # also recommended: ray[debug]
Quick Start
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
index 0493b69169909..81de87a571ced 100644
--- a/doc/source/tutorial.rst
+++ b/doc/source/tutorial.rst
@@ -9,7 +9,7 @@ To use Ray, you need to understand the following:
Overview
--------
-Ray is a Python-based distributed execution engine. The same code can be run on
+Ray is a distributed execution engine. The same code can be run on
a single machine to achieve efficient multiprocessing, and it can be used on a
cluster for large computations.
@@ -21,8 +21,6 @@ When using Ray, several processes are involved.
allows workers to efficiently share objects on the same node with minimal
copying and deserialization.
- One **local scheduler** per node assigns tasks to workers on the same node.
-- A **global scheduler** receives tasks from local schedulers and assigns them
- to other local schedulers.
- A **driver** is the Python process that the user controls. For example, if the
user is running a script or using a Python shell, then the driver is the Python
process that runs the script or the shell. A driver is similar to a worker in
diff --git a/doc/source/user-profiling.rst b/doc/source/user-profiling.rst
index e7c18dd5ee737..cdbabff391884 100644
--- a/doc/source/user-profiling.rst
+++ b/doc/source/user-profiling.rst
@@ -1,11 +1,11 @@
Profiling for Ray Users
=======================
-This document is intended for users of Ray who want to know how to evaluate
-the performance of their code while running on Ray. Profiling the
-performance of your code can be very helpful to determine performance
-bottlenecks or to find out where your code may not be parallelized properly.
-If you are interested in pinpointing why your Ray application may not be
+This document is intended for users of Ray who want to know how to evaluate
+the performance of their code while running on Ray. Profiling the
+performance of your code can be very helpful to determine performance
+bottlenecks or to find out where your code may not be parallelized properly.
+If you are interested in pinpointing why your Ray application may not be
achieving the expected speedup, read on!
@@ -28,26 +28,26 @@ let's define our remote function to just sleep for 0.5 seconds:
def func():
time.sleep(0.5)
-In our example setup, we wish to call our remote function ``func()`` five
-times, and store the result of each call into a list. To compare the
-performance of different ways of looping our calls to our remote function,
+In our example setup, we wish to call our remote function ``func()`` five
+times, and store the result of each call into a list. To compare the
+performance of different ways of looping our calls to our remote function,
we can define each loop version as a separate function on the driver script.
-For the first version **ex1**, each iteration of the loop calls the remote
-function, then calls ``ray.get`` in an attempt to store the current result
+For the first version **ex1**, each iteration of the loop calls the remote
+function, then calls ``ray.get`` in an attempt to store the current result
into the list, as follows:
.. code-block:: python
# This loop is suboptimal in Ray, and should only be used for the sake of this example
- def ex1():
+ def ex1():
list1 = []
for i in range(5):
list1.append(ray.get(func.remote()))
-For the second version **ex2**, each iteration of the loop calls the remote
-function, and stores it into the list **without** calling ``ray.get`` each time.
-``ray.get`` is used after the loop has finished, in preparation for processing
+For the second version **ex2**, each iteration of the loop calls the remote
+function, and stores it into the list **without** calling ``ray.get`` each time.
+``ray.get`` is used after the loop has finished, in preparation for processing
``func()``'s results:
.. code-block:: python
@@ -59,8 +59,8 @@ function, and stores it into the list **without** calling ``ray.get`` each time.
list2.append(func.remote())
ray.get(list2)
-Finally, for an example that's not so parallelizable, let's create a
-third version **ex3** where the driver has to call a local
+Finally, for an example that's not so parallelizable, let's create a
+third version **ex3** where the driver has to call a local
function in between each call to the remote function ``func()``:
.. code-block:: python
@@ -81,14 +81,14 @@ Timing Performance Using Python's Timestamps
--------------------------------------------
One way to sanity-check the performance of the three loops is simply to
-time how long it takes to complete each loop version. We can do this using
+time how long it takes to complete each loop version. We can do this using
python's built-in ``time`` `module`_.
.. _`module`: https://docs.python.org/3/library/time.html
-The ``time`` module contains a useful ``time()`` function that returns the
-current timestamp in unix time whenever it's called. We can create a generic
-function wrapper to call ``time()`` right before and right after each loop
+The ``time`` module contains a useful ``time()`` function that returns the
+current timestamp in unix time whenever it's called. We can create a generic
+function wrapper to call ``time()`` right before and right after each loop
function to print out how long each loop takes overall:
.. code-block:: python
@@ -106,8 +106,8 @@ function to print out how long each loop takes overall:
return result
return timed_wrapper
-To always print out how long the loop takes to run each time the loop
-function ``ex1()`` is called, we can evoke our ``time_this`` wrapper with
+To always print out how long the loop takes to run each time the loop
+function ``ex1()`` is called, we can evoke our ``time_this`` wrapper with
a function decorator. This can similarly be done to functions ``ex2()``
and ``ex3()``:
@@ -136,9 +136,9 @@ Then, running the three timed loops should yield output similar to this:
| func:'ex2' args:[(), {}] took: 1.0032 seconds |
| func:'ex3' args:[(), {}] took: 2.0039 seconds |
-Let's interpret these results.
+Let's interpret these results.
-Here, ``ex1()`` took substantially more time than ``ex2()``, where
+Here, ``ex1()`` took substantially more time than ``ex2()``, where
their only difference is that ``ex1()`` calls ``ray.get`` on the remote
function before adding it to the list, while ``ex2()`` waits to fetch the
entire list with ``ray.get`` at once.
@@ -160,28 +160,28 @@ entire list with ``ray.get`` at once.
list2.append(func.remote())
ray.get(list2)
-Notice how ``ex1()`` took 2.5 seconds, exactly five times 0.5 seconds, or
-the time it would take to wait for our remote function five times in a row.
+Notice how ``ex1()`` took 2.5 seconds, exactly five times 0.5 seconds, or
+the time it would take to wait for our remote function five times in a row.
-By calling ``ray.get`` after each call to the remote function, ``ex1()``
-removes all ability to parallelize work, by forcing the driver to wait for
-each ``func()``'s result in succession. We are not taking advantage of Ray
-parallelization here!
+By calling ``ray.get`` after each call to the remote function, ``ex1()``
+removes all ability to parallelize work, by forcing the driver to wait for
+each ``func()``'s result in succession. We are not taking advantage of Ray
+parallelization here!
-Meanwhile, ``ex2()`` takes about 1 second, much faster than it would normally
-take to call ``func()`` five times iteratively. Ray is running each call to
-``func()`` in parallel, saving us time.
+Meanwhile, ``ex2()`` takes about 1 second, much faster than it would normally
+take to call ``func()`` five times iteratively. Ray is running each call to
+``func()`` in parallel, saving us time.
-``ex1()`` is actually a common user mistake in Ray. ``ray.get`` is not
-necessary to do before adding the result of ``func()`` to the list. Instead,
-the driver should send out all parallelizable calls to the remote function
+``ex1()`` is actually a common user mistake in Ray. ``ray.get`` is not
+necessary to do before adding the result of ``func()`` to the list. Instead,
+the driver should send out all parallelizable calls to the remote function
to Ray before waiting to receive their results with ``ray.get``. ``ex1()``'s
suboptimal behavior can be noticed just using this simple timing test.
-Realistically, however, many applications are not as highly parallelizable
-as ``ex2()``, and the application includes sections where the code must run in
+Realistically, however, many applications are not as highly parallelizable
+as ``ex2()``, and the application includes sections where the code must run in
serial. ``ex3()`` is such an example, where the local function ``other_func()``
-must run first before each call to ``func()`` can be submitted to Ray.
+must run first before each call to ``func()`` can be submitted to Ray.
.. code-block:: python
@@ -196,23 +196,23 @@ must run first before each call to ``func()`` can be submitted to Ray.
list2.append(func.remote())
ray.get(list3)
-What results is that while ``ex3()`` still gained 0.5 seconds of speedup
+What results is that while ``ex3()`` still gained 0.5 seconds of speedup
compared to the completely serialized ``ex1()`` version, this speedup is
-still nowhere near the ideal speedup of ``ex2()``.
+still nowhere near the ideal speedup of ``ex2()``.
-The dramatic speedup of ``ex2()`` is possible because ``ex2()`` is
-theoretically completely parallelizable: if we were given 5 CPUs, all 5 calls
-to ``func()`` can be run in parallel. What is happening with ``ex3()``,
-however, is that each parallelized call to ``func()`` is staggered by a wait
+The dramatic speedup of ``ex2()`` is possible because ``ex2()`` is
+theoretically completely parallelizable: if we were given 5 CPUs, all 5 calls
+to ``func()`` can be run in parallel. What is happening with ``ex3()``,
+however, is that each parallelized call to ``func()`` is staggered by a wait
of 0.3 seconds for the local ``other_func()`` to finish.
-``ex3()`` is thus a manifestation of `Amdahls Law`_: the fastest theoretically
-possible execution time from parallelizing an application is limited to be
-no better than the time it takes to run all serial parts in serial.
+``ex3()`` is thus a manifestation of `Amdahls Law`_: the fastest theoretically
+possible execution time from parallelizing an application is limited to be
+no better than the time it takes to run all serial parts in serial.
.. _`Amdahls Law`: https://en.wikipedia.org/wiki/Amdahl%27s_law
-Due to Amdahl's Law, ``ex3()`` must take at least 1.5
+Due to Amdahl's Law, ``ex3()`` must take at least 1.5
seconds -- the time it takes for 5 serial calls to ``other_func()`` to finish!
After an additional 0.5 seconds to execute func and get the result, the
computation is done.
@@ -224,7 +224,7 @@ Profiling Using An External Profiler (Line Profiler)
One way to profile the performance of our code using Ray is to use a third-party
profiler such as `Line_profiler`_. Line_profiler is a useful line-by-line
profiler for pure Python applications that formats its output side-by-side with
-the profiled code itself.
+the profiled code itself.
Alternatively, another third-party profiler (not covered in this documentation)
that you could use is `Pyflame`_, which can generate profiling graphs.
@@ -238,11 +238,11 @@ First install ``line_profiler`` with pip:
pip install line_profiler
-``line_profiler`` requires each section of driver code that you want to profile as
-its own independent function. Conveniently, we have already done so by defining
+``line_profiler`` requires each section of driver code that you want to profile as
+its own independent function. Conveniently, we have already done so by defining
each loop version as its own function. To tell ``line_profiler`` which functions
-to profile, just add the ``@profile`` decorator to ``ex1()``, ``ex2()`` and
-``ex3()``. Note that you do not need to import ``line_profiler`` into your Ray
+to profile, just add the ``@profile`` decorator to ``ex1()``, ``ex2()`` and
+``ex3()``. Note that you do not need to import ``line_profiler`` into your Ray
application:
.. code-block:: python
@@ -262,16 +262,16 @@ application:
if __name__ == "__main__":
main()
-Then, when we want to execute our Python script from the command line, instead
-of ``python your_script_here.py``, we use the following shell command to run the
+Then, when we want to execute our Python script from the command line, instead
+of ``python your_script_here.py``, we use the following shell command to run the
script with ``line_profiler`` enabled:
.. code-block:: bash
- kernprof -l your_script_here.py
+ kernprof -l your_script_here.py
-This command runs your script and prints only your script's output as usual.
-``Line_profiler`` instead outputs its profiling results to a corresponding
+This command runs your script and prints only your script's output as usual.
+``Line_profiler`` instead outputs its profiling results to a corresponding
binary file called ``your_script_here.py.lprof``.
To read ``line_profiler``'s results to terminal, use this shell command:
@@ -300,10 +300,10 @@ Note that execution time is given in units of 1e-06 seconds:
33 5 2508805.0 501761.0 100.0 list1.append(ray.get(func.remote()))
-Notice that each hit to ``list1.append(ray.get(func.remote()))`` at line 33
-takes the full 0.5 seconds waiting for ``func()`` to finish. Meanwhile, in
-``ex2()`` below, each call of ``func.remote()`` at line 40 only takes 0.127 ms,
-and the majority of the time (about 1 second) is spent on waiting for ``ray.get()``
+Notice that each hit to ``list1.append(ray.get(func.remote()))`` at line 33
+takes the full 0.5 seconds waiting for ``func()`` to finish. Meanwhile, in
+``ex2()`` below, each call of ``func.remote()`` at line 40 only takes 0.127 ms,
+and the majority of the time (about 1 second) is spent on waiting for ``ray.get()``
at the end:
@@ -323,11 +323,11 @@ at the end:
41 1 1002919.0 1002919.0 99.9 ray.get(list2)
-And finally, ``line_profiler``'s output for ``ex3()``. Each call to
-``func.remote()`` at line 50 still take magnitudes faster than 0.5 seconds,
-showing that Ray is successfully parallelizing the remote calls. However, each
-call to the local function ``other_func()`` takes the full 0.3 seconds,
-totalling up to the guaranteed minimum application execution time of 1.5
+And finally, ``line_profiler``'s output for ``ex3()``. Each call to
+``func.remote()`` at line 50 still take magnitudes faster than 0.5 seconds,
+showing that Ray is successfully parallelizing the remote calls. However, each
+call to the local function ``other_func()`` takes the full 0.3 seconds,
+totalling up to the guaranteed minimum application execution time of 1.5
seconds:
.. code-block:: bash
@@ -351,20 +351,20 @@ seconds:
Profiling Using Python's CProfile
---------------------------------
-A second way to profile the performance of your Ray application is to
-use Python's native cProfile `profiling module`_. Rather than tracking
+A second way to profile the performance of your Ray application is to
+use Python's native cProfile `profiling module`_. Rather than tracking
line-by-line of your application code, cProfile can give the total runtime
of each loop function, as well as list the number of calls made and
-execution time of all function calls made within the profiled code.
+execution time of all function calls made within the profiled code.
.. _`profiling module`: https://docs.python.org/3/library/profile.html#module-cProfile
-Unlike ``line_profiler`` above, this detailed list of profiled function calls
-**includes** internal function calls and function calls made within Ray!
+Unlike ``line_profiler`` above, this detailed list of profiled function calls
+**includes** internal function calls and function calls made within Ray!
-However, similar to ``line_profiler``, cProfile can be enabled with minimal
-changes to your application code (given that each section of the code you want
-to profile is defined as its own function). To use cProfile, add an import
+However, similar to ``line_profiler``, cProfile can be enabled with minimal
+changes to your application code (given that each section of the code you want
+to profile is defined as its own function). To use cProfile, add an import
statement, then replace calls to the loop functions as follows:
.. code-block:: python
@@ -385,17 +385,17 @@ statement, then replace calls to the loop functions as follows:
if __name__ == "__main__":
main()
-Now, when executing your Python script, a cProfile list of profiled function
+Now, when executing your Python script, a cProfile list of profiled function
calls will be outputted to terminal for each call made to ``cProfile.run()``.
-At the very top of cProfile's output gives the total execution time for
+At the very top of cProfile's output gives the total execution time for
``'ex1()'``:
.. code-block:: bash
601 function calls (595 primitive calls) in 2.509 seconds
-Following is a snippet of profiled function calls for ``'ex1()'``. Most of
-these calls are quick and take around 0.000 seconds, so the functions of
+Following is a snippet of profiled function calls for ``'ex1()'``. Most of
+these calls are quick and take around 0.000 seconds, so the functions of
interest are the ones with non-zero execution times:
.. code-block:: bash
@@ -405,7 +405,7 @@ interest are the ones with non-zero execution times:
1 0.000 0.000 2.509 2.509 your_script_here.py:31(ex1)
5 0.000 0.000 0.001 0.000 remote_function.py:103(remote)
5 0.000 0.000 0.001 0.000 remote_function.py:107(_submit)
- ...
+ ...
10 0.000 0.000 0.000 0.000 worker.py:2459(__init__)
5 0.000 0.000 2.508 0.502 worker.py:2535(get)
5 0.000 0.000 0.000 0.000 worker.py:2695(get_global_worker)
@@ -414,25 +414,25 @@ interest are the ones with non-zero execution times:
5 0.000 0.000 0.000 0.000 worker.py:514(submit_task)
...
-The 5 separate calls to Ray's ``get``, taking the full 0.502 seconds each call,
-can be noticed at ``worker.py:2535(get)``. Meanwhile, the act of calling the
-remote function itself at ``remote_function.py:103(remote)`` only takes 0.001
-seconds over 5 calls, and thus is not the source of the slow performance of
+The 5 separate calls to Ray's ``get``, taking the full 0.502 seconds each call,
+can be noticed at ``worker.py:2535(get)``. Meanwhile, the act of calling the
+remote function itself at ``remote_function.py:103(remote)`` only takes 0.001
+seconds over 5 calls, and thus is not the source of the slow performance of
``ex1()``.
Profiling Ray Actors with cProfile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Considering that the detailed output of cProfile can be quite different depending
-on what Ray functionalities we use, let us see what cProfile's output might look
-like if our example involved Actors (for an introduction to Ray actors, see our
-`Actor documentation here`_).
+Considering that the detailed output of cProfile can be quite different depending
+on what Ray functionalities we use, let us see what cProfile's output might look
+like if our example involved Actors (for an introduction to Ray actors, see our
+`Actor documentation here`_).
.. _`Actor documentation here`: http://ray.readthedocs.io/en/latest/actors.html
Now, instead of looping over five calls to a remote function like in ``ex1``,
-let's create a new example and loop over five calls to a remote function
+let's create a new example and loop over five calls to a remote function
**inside an actor**. Our actor's remote function again just sleeps for 0.5
seconds:
@@ -440,7 +440,7 @@ seconds:
# Our actor
@ray.remote
- class Sleeper(object):
+ class Sleeper(object):
def __init__(self):
self.sleepValue = 0.5
@@ -448,7 +448,7 @@ seconds:
def actor_func(self):
time.sleep(self.sleepValue)
-Recalling the suboptimality of ``ex1``, let's first see what happens if we
+Recalling the suboptimality of ``ex1``, let's first see what happens if we
attempt to perform all five ``actor_func()`` calls within a single actor:
.. code-block:: python
@@ -470,7 +470,7 @@ We enable cProfile on this example as follows:
def main():
ray.init()
- cProfile.run('ex4()')
+ cProfile.run('ex4()')
if __name__ == "__main__":
main()
@@ -497,22 +497,22 @@ Running our new Actor example, cProfile's abbreviated output is as follows:
8 0.000 0.000 0.001 0.000 worker.py:514(submit_task)
...
-It turns out that the entire example still took 2.5 seconds to execute, or the
-time for five calls to ``actor_func()`` to run in serial. We remember in ``ex1``
-that this behavior was because we did not wait until after submitting all five
+It turns out that the entire example still took 2.5 seconds to execute, or the
+time for five calls to ``actor_func()`` to run in serial. We remember in ``ex1``
+that this behavior was because we did not wait until after submitting all five
remote function tasks to call ``ray.get()``, but we can verify on cProfile's
-output line ``worker.py:2535(get)`` that ``ray.get()`` was only called once at
-the end, for 2.509 seconds. What happened?
+output line ``worker.py:2535(get)`` that ``ray.get()`` was only called once at
+the end, for 2.509 seconds. What happened?
-It turns out Ray cannot parallelize this example, because we have only
-initialized a single ``Sleeper`` actor. Because each actor is a single,
-stateful worker, our entire code is submitted and ran on a single worker the
+It turns out Ray cannot parallelize this example, because we have only
+initialized a single ``Sleeper`` actor. Because each actor is a single,
+stateful worker, our entire code is submitted and ran on a single worker the
whole time.
To better parallelize the actors in ``ex4``, we can take advantage
that each call to ``actor_func()`` is independent, and instead
create five ``Sleeper`` actors. That way, we are creating five workers
-that can run in parallel, instead of creating a single worker that
+that can run in parallel, instead of creating a single worker that
can only handle one call to ``actor_func()`` at a time.
.. code-block:: python
@@ -530,7 +530,7 @@ can only handle one call to ``actor_func()`` at a time.
Our example in total now takes only 1.5 seconds to run:
-.. code-block:: bash
+.. code-block:: bash
1378 function calls (1363 primitive calls) in 1.567 seconds
@@ -553,27 +553,27 @@ Our example in total now takes only 1.5 seconds to run:
Visualizing Tasks in the Ray Timeline
-------------------------------------
-Profiling the performance of your Ray application doesn't need to be
-an eye-straining endeavor of interpreting numbers among hundreds of
-lines of text. Ray comes with its own visual web UI to visualize the
+Profiling the performance of your Ray application doesn't need to be
+an eye-straining endeavor of interpreting numbers among hundreds of
+lines of text. Ray comes with its own visual web UI to visualize the
parallelization (or lack thereof) of user tasks submitted to Ray!
-This method does have its own limitations, however. The Ray Timeline
+This method does have its own limitations, however. The Ray Timeline
can only show timing info about Ray tasks, and not timing for normal
Python functions. This can be an issue especially for debugging slow
-Python code that is running on the driver, and not running as a task on
-one of the workers. The other profiling techniques above are options that
+Python code that is running on the driver, and not running as a task on
+one of the workers. The other profiling techniques above are options that
do cover profiling normal Python functions.
Currently, whenever initializing Ray, a URL is generated and printed
-in the terminal. This URL can be used to view Ray's web UI as a Jupyter
+in the terminal. This URL can be used to view Ray's web UI as a Jupyter
notebook:
.. code-block:: bash
~$: python your_script_here.py
- Process STDOUT and STDERR is being redirected to /tmp/raylogs/.
+ Process STDOUT and STDERR is being redirected to /tmp/ray/session_2018-11-01_14-31-43_27211/logs.
Waiting for redis server at 127.0.0.1:61150 to respond...
Waiting for redis server at 127.0.0.1:21607 to respond...
Starting local scheduler with the following resources: {'CPU': 4, 'GPU': 0}.
@@ -582,13 +582,13 @@ notebook:
View the web UI at http://localhost:8897/notebooks/ray_ui84907.ipynb?token=025e8ab295270a57fac209204b37349fdf34e037671a13ff
======================================================================
-Ray's web UI attempts to run on localhost at port 8888, and if it fails
-it tries successive ports until it finds an open port. In this above
+Ray's web UI attempts to run on localhost at port 8888, and if it fails
+it tries successive ports until it finds an open port. In this above
example, it has opened on port 8897.
-Because this web UI is only available as long as your Ray application
-is currently running, you may need to add a user prompt to prevent
-your Ray application from exiting once it has finished executing,
+Because this web UI is only available as long as your Ray application
+is currently running, you may need to add a user prompt to prevent
+your Ray application from exiting once it has finished executing,
such as below. You can then browse the web UI for as long as you like:
.. code-block:: python
@@ -606,44 +606,44 @@ such as below. You can then browse the web UI for as long as you like:
main()
Now, when executing your python script, you can access the Ray timeline
-by copying the web UI URL into your web browser on the Ray machine. To
-load the web UI in the jupyter notebook, select **Kernel -> Restart and
+by copying the web UI URL into your web browser on the Ray machine. To
+load the web UI in the jupyter notebook, select **Kernel -> Restart and
Run All** in the jupyter menu.
-The Ray timeline can be viewed in the fourth cell of the UI notebook by
-using the task filter options, then clicking on the **View task timeline**
+The Ray timeline can be viewed in the fourth cell of the UI notebook by
+using the task filter options, then clicking on the **View task timeline**
button.
-For example, here are the results of executing ``ex1()``, ``ex2()``, and
-``ex3()`` visualized in the Ray timeline. Each red block is a call to one
-of our user-defined remote functions, namely ``func()``, which sleeps for
+For example, here are the results of executing ``ex1()``, ``ex2()``, and
+``ex3()`` visualized in the Ray timeline. Each red block is a call to one
+of our user-defined remote functions, namely ``func()``, which sleeps for
0.5 seconds:
.. image:: user-profiling-timeline.gif
-(highlighted color boxes for ``ex1()``, ``ex2()``, and ``ex3()`` added for
+(highlighted color boxes for ``ex1()``, ``ex2()``, and ``ex3()`` added for
the sake of this example)
-Note how ``ex1()`` executes all five calls to ``func()`` in serial,
+Note how ``ex1()`` executes all five calls to ``func()`` in serial,
while ``ex2()`` and ``ex3()`` are able to parallelize their remote
-function calls.
+function calls.
-Because we have 4 CPUs available on our machine, we can only able to
-execute up to 4 remote functions in parallel. So, the fifth call to the
-remote function in ``ex2()`` must wait until the first batch of ``func()``
+Because we have 4 CPUs available on our machine, we can only able to
+execute up to 4 remote functions in parallel. So, the fifth call to the
+remote function in ``ex2()`` must wait until the first batch of ``func()``
calls is finished.
-In ``ex3()``, because of the serial dependency on ``other_func()``, we
+In ``ex3()``, because of the serial dependency on ``other_func()``, we
aren't even able to use all 4 of our cores to parallelize calls to ``func()``.
The time gaps between the ``func()`` blocks are a result of staggering the
-calls to ``func()`` in between waiting 0.3 seconds for ``other_func()``.
+calls to ``func()`` in between waiting 0.3 seconds for ``other_func()``.
-Also, notice that due to the aforementioned limitation of the Ray timeline,
-``other_func()``, as a driver function and not a Ray task, is never
+Also, notice that due to the aforementioned limitation of the Ray timeline,
+``other_func()``, as a driver function and not a Ray task, is never
visualized on the Ray timeline.
**For more on Ray's Web UI,** such as how to access the UI on a remote
-node over ssh, or for troubleshooting installation, please see our
+node over ssh, or for troubleshooting installation, please see our
`Web UI documentation section`_.
.. _`Web UI documentation section`: http://ray.readthedocs.io/en/latest/webui.html
diff --git a/doc/source/using-ray-and-docker-on-a-cluster.md b/doc/source/using-ray-and-docker-on-a-cluster.md
index 9ae39d17851ef..4e7b7a52d9bd6 100644
--- a/doc/source/using-ray-and-docker-on-a-cluster.md
+++ b/doc/source/using-ray-and-docker-on-a-cluster.md
@@ -1,4 +1,4 @@
-# Using Ray and Docker on a Cluster (EXPERIMENTAL)
+# Using Ray and Docker on a Cluster (Experimental)
Packaging and deploying an application using Docker can provide certain advantages. It can make managing dependencies easier, help ensure that each cluster node receives a uniform configuration, and facilitate swapping hardware resources between applications.
diff --git a/doc/source/using-ray-on-a-cluster.rst b/doc/source/using-ray-on-a-cluster.rst
index 29c2585ac7cfe..611e47b79db23 100644
--- a/doc/source/using-ray-on-a-cluster.rst
+++ b/doc/source/using-ray-on-a-cluster.rst
@@ -51,7 +51,6 @@ Now we've started all of the Ray processes on each node Ray. This includes
- An object store on each machine.
- A local scheduler on each machine.
- Multiple Redis servers (on the head node).
-- One global scheduler (on the head node).
To run some commands, start up Python on one of the nodes in the cluster, and do
the following.
diff --git a/doc/source/using-ray-on-a-large-cluster.rst b/doc/source/using-ray-on-a-large-cluster.rst
index c3d6d8a8d2389..b87c8c05f5125 100644
--- a/doc/source/using-ray-on-a-large-cluster.rst
+++ b/doc/source/using-ray-on-a-large-cluster.rst
@@ -154,7 +154,6 @@ Now you have started all of the Ray processes on each node. These include:
- An object store on each machine.
- A local scheduler on each machine.
- Multiple Redis servers (on the head node).
-- One global scheduler (on the head node).
To confirm that the Ray cluster setup is working, start up Python on one of the
nodes in the cluster and enter the following commands to connect to the Ray
diff --git a/docker/examples/Dockerfile b/docker/examples/Dockerfile
index d4e6c34b22179..9cdee4ff117eb 100644
--- a/docker/examples/Dockerfile
+++ b/docker/examples/Dockerfile
@@ -5,6 +5,7 @@ FROM ray-project/deploy
# This updates numpy to 1.14 and mutes errors from other libraries
RUN conda install -y numpy
RUN apt-get install -y zlib1g-dev
-RUN pip install gym[atari] opencv-python==3.2.0.8 tensorflow lz4 keras
+RUN pip install gym[atari] opencv-python==3.2.0.8 tensorflow lz4 keras pytest-timeout
+RUN pip install -U h5py # Mutes FutureWarnings
RUN pip install --upgrade git+git://github.com/hyperopt/hyperopt.git
RUN conda install pytorch-cpu torchvision-cpu -c pytorch
diff --git a/examples/carla/a3c_lane_keep.py b/examples/carla/a3c_lane_keep.py
deleted file mode 100644
index 1338736d23f5e..0000000000000
--- a/examples/carla/a3c_lane_keep.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import ray
-from ray.tune import register_env, run_experiments
-
-from env import CarlaEnv, ENV_CONFIG
-from models import register_carla_model
-from scenarios import LANE_KEEP
-
-env_name = "carla_env"
-env_config = ENV_CONFIG.copy()
-env_config.update({
- "verbose": False,
- "x_res": 80,
- "y_res": 80,
- "use_depth_camera": False,
- "discrete_actions": False,
- "server_map": "/Game/Maps/Town02",
- "reward_function": "lane_keep",
- "enable_planner": False,
- "scenarios": [LANE_KEEP],
-})
-
-register_env(env_name, lambda env_config: CarlaEnv(env_config))
-register_carla_model()
-
-ray.init()
-run_experiments({
- "carla-a3c": {
- "run": "A3C",
- "env": "carla_env",
- "trial_resources": {"cpu": 4, "gpu": 1},
- "config": {
- "env_config": env_config,
- "model": {
- "custom_model": "carla",
- "custom_options": {
- "image_shape": [80, 80, 6],
- },
- "conv_filters": [
- [16, [8, 8], 4],
- [32, [4, 4], 2],
- [512, [10, 10], 1],
- ],
- },
- "gamma": 0.8,
- "num_workers": 1,
- },
- },
-})
diff --git a/examples/carla/dqn_lane_keep.py b/examples/carla/dqn_lane_keep.py
deleted file mode 100644
index 2746a1c4bbd89..0000000000000
--- a/examples/carla/dqn_lane_keep.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import ray
-from ray.tune import register_env, run_experiments
-
-from env import CarlaEnv, ENV_CONFIG
-from models import register_carla_model
-from scenarios import LANE_KEEP
-
-env_name = "carla_env"
-env_config = ENV_CONFIG.copy()
-env_config.update({
- "verbose": False,
- "x_res": 80,
- "y_res": 80,
- "use_depth_camera": False,
- "discrete_actions": True,
- "server_map": "/Game/Maps/Town02",
- "reward_function": "lane_keep",
- "enable_planner": False,
- "scenarios": [LANE_KEEP],
-})
-
-register_env(env_name, lambda env_config: CarlaEnv(env_config))
-register_carla_model()
-
-ray.init()
-run_experiments({
- "carla-dqn": {
- "run": "DQN",
- "env": "carla_env",
- "trial_resources": {"cpu": 4, "gpu": 1},
- "config": {
- "env_config": env_config,
- "model": {
- "custom_model": "carla",
- "custom_options": {
- "image_shape": [80, 80, 6],
- },
- "conv_filters": [
- [16, [8, 8], 4],
- [32, [4, 4], 2],
- [512, [10, 10], 1],
- ],
- },
- "timesteps_per_iteration": 100,
- "learning_starts": 1000,
- "schedule_max_timesteps": 100000,
- "gamma": 0.8,
- "tf_session_args": {
- "gpu_options": {"allow_growth": True},
- },
- },
- },
-})
diff --git a/examples/carla/ppo_lane_keep.py b/examples/carla/ppo_lane_keep.py
deleted file mode 100644
index 25e5acbf328c4..0000000000000
--- a/examples/carla/ppo_lane_keep.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-import ray
-from ray.tune import register_env, run_experiments
-
-from env import CarlaEnv, ENV_CONFIG
-from models import register_carla_model
-from scenarios import LANE_KEEP
-
-env_name = "carla_env"
-env_config = ENV_CONFIG.copy()
-env_config.update({
- "verbose": False,
- "x_res": 80,
- "y_res": 80,
- "use_depth_camera": False,
- "discrete_actions": False,
- "server_map": "/Game/Maps/Town02",
- "reward_function": "lane_keep",
- "enable_planner": False,
- "scenarios": [LANE_KEEP],
-})
-
-register_env(env_name, lambda env_config: CarlaEnv(env_config))
-register_carla_model()
-
-ray.init()
-run_experiments({
- "carla-ppo": {
- "run": "PPO",
- "env": "carla_env",
- "trial_resources": {"cpu": 4, "gpu": 1},
- "config": {
- "env_config": env_config,
- "model": {
- "custom_model": "carla",
- "custom_options": {
- "image_shape": [80, 80, 6],
- },
- "conv_filters": [
- [16, [8, 8], 4],
- [32, [4, 4], 2],
- [512, [10, 10], 1],
- ],
- },
- "num_workers": 1,
- "timesteps_per_batch": 2000,
- "min_steps_per_task": 100,
- "lambda": 0.95,
- "clip_param": 0.2,
- "num_sgd_iter": 20,
- "sgd_stepsize": 0.0001,
- "sgd_batchsize": 32,
- "devices": ["/gpu:0"],
- "tf_session_args": {
- "gpu_options": {"allow_growth": True}
- }
- },
- },
-})
diff --git a/examples/carla/scenarios.py b/examples/carla/scenarios.py
deleted file mode 100644
index e6494af1830d0..0000000000000
--- a/examples/carla/scenarios.py
+++ /dev/null
@@ -1,119 +0,0 @@
-"""Collection of Carla scenarios, including those from the CoRL 2017 paper."""
-
-
-TEST_WEATHERS = [0, 2, 5, 7, 9, 10, 11, 12, 13]
-TRAIN_WEATHERS = [1, 3, 4, 6, 8, 14]
-
-
-def build_scenario(
- city, start, end, vehicles, pedestrians, max_steps, weathers):
- return {
- "city": city,
- "num_vehicles": vehicles,
- "num_pedestrians": pedestrians,
- "weather_distribution": weathers,
- "start_pos_id": start,
- "end_pos_id": end,
- "max_steps": max_steps,
- }
-
-
-# Simple scenario for Town02 that involves driving down a road
-DEFAULT_SCENARIO = build_scenario(
- city="Town02", start=36, end=40, vehicles=20, pedestrians=40,
- max_steps=200, weathers=[0])
-
-# Simple scenario for Town02 that involves driving down a road
-LANE_KEEP = build_scenario(
- city="Town02", start=36, end=40, vehicles=0, pedestrians=0,
- max_steps=2000, weathers=[0])
-
-# Scenarios from the CoRL2017 paper
-POSES_TOWN1_STRAIGHT = [
- [36, 40], [39, 35], [110, 114], [7, 3], [0, 4],
- [68, 50], [61, 59], [47, 64], [147, 90], [33, 87],
- [26, 19], [80, 76], [45, 49], [55, 44], [29, 107],
- [95, 104], [84, 34], [53, 67], [22, 17], [91, 148],
- [20, 107], [78, 70], [95, 102], [68, 44], [45, 69]]
-
-
-POSES_TOWN1_ONE_CURVE = [
- [138, 17], [47, 16], [26, 9], [42, 49], [140, 124],
- [85, 98], [65, 133], [137, 51], [76, 66], [46, 39],
- [40, 60], [0, 29], [4, 129], [121, 140], [2, 129],
- [78, 44], [68, 85], [41, 102], [95, 70], [68, 129],
- [84, 69], [47, 79], [110, 15], [130, 17], [0, 17]]
-
-POSES_TOWN1_NAV = [
- [105, 29], [27, 130], [102, 87], [132, 27], [24, 44],
- [96, 26], [34, 67], [28, 1], [140, 134], [105, 9],
- [148, 129], [65, 18], [21, 16], [147, 97], [42, 51],
- [30, 41], [18, 107], [69, 45], [102, 95], [18, 145],
- [111, 64], [79, 45], [84, 69], [73, 31], [37, 81]]
-
-
-POSES_TOWN2_STRAIGHT = [
- [38, 34], [4, 2], [12, 10], [62, 55], [43, 47],
- [64, 66], [78, 76], [59, 57], [61, 18], [35, 39],
- [12, 8], [0, 18], [75, 68], [54, 60], [45, 49],
- [46, 42], [53, 46], [80, 29], [65, 63], [0, 81],
- [54, 63], [51, 42], [16, 19], [17, 26], [77, 68]]
-
-POSES_TOWN2_ONE_CURVE = [
- [37, 76], [8, 24], [60, 69], [38, 10], [21, 1],
- [58, 71], [74, 32], [44, 0], [71, 16], [14, 24],
- [34, 11], [43, 14], [75, 16], [80, 21], [3, 23],
- [75, 59], [50, 47], [11, 19], [77, 34], [79, 25],
- [40, 63], [58, 76], [79, 55], [16, 61], [27, 11]]
-
-POSES_TOWN2_NAV = [
- [19, 66], [79, 14], [19, 57], [23, 1],
- [53, 76], [42, 13], [31, 71], [33, 5],
- [54, 30], [10, 61], [66, 3], [27, 12],
- [79, 19], [2, 29], [16, 14], [5, 57],
- [70, 73], [46, 67], [57, 50], [61, 49], [21, 12],
- [51, 81], [77, 68], [56, 65], [43, 54]]
-
-TOWN1_STRAIGHT = [
- build_scenario("Town01", start, end, 0, 0, 300, TEST_WEATHERS)
- for (start, end) in POSES_TOWN1_STRAIGHT]
-
-TOWN1_ONE_CURVE = [
- build_scenario("Town01", start, end, 0, 0, 600, TEST_WEATHERS)
- for (start, end) in POSES_TOWN1_ONE_CURVE]
-
-TOWN1_NAVIGATION = [
- build_scenario("Town01", start, end, 0, 0, 900, TEST_WEATHERS)
- for (start, end) in POSES_TOWN1_NAV]
-
-TOWN1_NAVIGATION_DYNAMIC = [
- build_scenario("Town01", start, end, 20, 50, 900, TEST_WEATHERS)
- for (start, end) in POSES_TOWN1_NAV]
-
-TOWN2_STRAIGHT = [
- build_scenario("Town02", start, end, 0, 0, 300, TRAIN_WEATHERS)
- for (start, end) in POSES_TOWN2_STRAIGHT]
-
-TOWN2_STRAIGHT_DYNAMIC = [
- build_scenario("Town02", start, end, 20, 50, 300, TRAIN_WEATHERS)
- for (start, end) in POSES_TOWN2_STRAIGHT]
-
-TOWN2_ONE_CURVE = [
- build_scenario("Town02", start, end, 0, 0, 600, TRAIN_WEATHERS)
- for (start, end) in POSES_TOWN2_ONE_CURVE]
-
-TOWN2_NAVIGATION = [
- build_scenario("Town02", start, end, 0, 0, 900, TRAIN_WEATHERS)
- for (start, end) in POSES_TOWN2_NAV]
-
-TOWN2_NAVIGATION_DYNAMIC = [
- build_scenario("Town02", start, end, 20, 50, 900, TRAIN_WEATHERS)
- for (start, end) in POSES_TOWN2_NAV]
-
-TOWN1_ALL = (
- TOWN1_STRAIGHT + TOWN1_ONE_CURVE + TOWN1_NAVIGATION +
- TOWN1_NAVIGATION_DYNAMIC)
-
-TOWN2_ALL = (
- TOWN2_STRAIGHT + TOWN2_ONE_CURVE + TOWN2_NAVIGATION +
- TOWN2_NAVIGATION_DYNAMIC)
diff --git a/examples/custom_env/README b/examples/custom_env/README
deleted file mode 100644
index 75ffcad88fb35..0000000000000
--- a/examples/custom_env/README
+++ /dev/null
@@ -1 +0,0 @@
-Example of using a custom gym env with RLlib.
diff --git a/java/README.rst b/java/README.rst
index 95ab961e769dc..e016169357874 100644
--- a/java/README.rst
+++ b/java/README.rst
@@ -7,6 +7,7 @@ Ray will read your configurations in the following order:
* Java system properties: e.g., ``-Dray.home=/path/to/ray``.
* A ``ray.conf`` file in the classpath: `example `_.
+* Customise your own ``ray.conf`` path using system property ``-Dray.config=/path/to/ray.conf``
For all available config items and default values, see `this file `_.
diff --git a/java/api/src/main/java/org/ray/api/Ray.java b/java/api/src/main/java/org/ray/api/Ray.java
index 053f01d5534d3..7e252274ef735 100644
--- a/java/api/src/main/java/org/ray/api/Ray.java
+++ b/java/api/src/main/java/org/ray/api/Ray.java
@@ -41,7 +41,10 @@ public static synchronized void init(RayRuntimeFactory factory) {
* Shutdown Ray runtime.
*/
public static void shutdown() {
- runtime.shutdown();
+ if (runtime != null) {
+ runtime.shutdown();
+ runtime = null;
+ }
}
/**
diff --git a/java/api/src/main/java/org/ray/api/RayCall.java b/java/api/src/main/java/org/ray/api/RayCall.java
index ef40a238c0e29..967830199402c 100644
--- a/java/api/src/main/java/org/ray/api/RayCall.java
+++ b/java/api/src/main/java/org/ray/api/RayCall.java
@@ -2,6 +2,7 @@
package org.ray.api;
+import org.ray.api.function.RayFunc;
import org.ray.api.function.RayFunc0;
import org.ray.api.function.RayFunc1;
import org.ray.api.function.RayFunc2;
@@ -9,6 +10,9 @@
import org.ray.api.function.RayFunc4;
import org.ray.api.function.RayFunc5;
import org.ray.api.function.RayFunc6;
+import org.ray.api.options.ActorCreationOptions;
+import org.ray.api.options.BaseTaskOptions;
+import org.ray.api.options.CallOptions;
/**
* This class provides type-safe interfaces for `Ray.call` and `Ray.createActor`.
@@ -20,511 +24,1019 @@ class RayCall {
// =======================================
public static RayObject call(RayFunc0 f) {
Object[] args = new Object[]{};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
+ }
+ public static RayObject call(RayFunc0 f, CallOptions options) {
+ Object[] args = new Object[]{};
+ return Ray.internal().call(f, args, options);
}
public static RayObject call(RayFunc1 f, T0 t0) {
Object[] args = new Object[]{t0};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
}
public static RayObject call(RayFunc1 f, RayObject t0) {
Object[] args = new Object[]{t0};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
+ }
+ public static RayObject call(RayFunc1 f, T0 t0, CallOptions options) {
+ Object[] args = new Object[]{t0};
+ return Ray.internal().call(f, args, options);
+ }
+ public static RayObject call(RayFunc1 f, RayObject t0, CallOptions options) {
+ Object[] args = new Object[]{t0};
+ return Ray.internal().call(f, args, options);
}
public static RayObject call(RayFunc2 f, T0 t0, T1 t1) {
Object[] args = new Object[]{t0, t1};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
}
public static RayObject call(RayFunc2 f, T0 t0, RayObject t1) {
Object[] args = new Object[]{t0, t1};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
}
public static RayObject call(RayFunc2 f, RayObject t0, T1 t1) {
Object[] args = new Object[]{t0, t1};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
}
public static RayObject call(RayFunc2 f, RayObject t0, RayObject t1) {
Object[] args = new Object[]{t0, t1};
- return Ray.internal().call(f, args);
+ return Ray.internal().call(f, args, null);
+ }
+ public static RayObject call(RayFunc2 f, T0 t0, T1 t1, CallOptions options) {
+ Object[] args = new Object[]{t0, t1};
+ return Ray.internal().call(f, args, options);
+ }
+ public static RayObject call(RayFunc2 f, T0 t0, RayObject t1, CallOptions options) {
+ Object[] args = new Object[]{t0, t1};
+ return Ray.internal().call(f, args, options);
+ }
+ public static RayObject call(RayFunc2 f, RayObject