From 8d5e61d3c0969ddf365f992c5befef3c7b76a8d1 Mon Sep 17 00:00:00 2001 From: Robert Nishihara Date: Thu, 28 Jul 2016 20:47:37 -0700 Subject: [PATCH] update tutorial (#318) --- README.md | 41 ++--- doc/about-the-system.md | 12 +- doc/basic-usage.md | 207 ----------------------- doc/figures/compgraph1.png | Bin 2819 -> 4914 bytes doc/figures/compgraph2.png | Bin 4557 -> 2645 bytes doc/figures/compgraph3.png | Bin 2645 -> 0 bytes doc/install-on-macosx.md | 10 +- doc/install-on-ubuntu.md | 10 +- doc/install-on-windows.md | 4 +- doc/remote-functions.md | 79 +++++++++ doc/tutorial.md | 307 +++++++++++++++++++++++++--------- doc/using-ray-on-a-cluster.md | 12 +- examples/hyperopt/README.md | 8 +- examples/lbfgs/README.md | 6 +- 14 files changed, 357 insertions(+), 339 deletions(-) delete mode 100644 doc/basic-usage.md delete mode 100644 doc/figures/compgraph3.png create mode 100644 doc/remote-functions.md diff --git a/README.md b/README.md index 1bfbe9250..4cc3d939d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ [![Build Status](https://travis-ci.org/amplab/ray.svg?branch=master)](https://travis-ci.org/amplab/ray) -Ray is an experimental distributed execution framework with a Python-like -programming model. It is under development and not ready for general use. +Ray is an experimental distributed extension of Python. It is under development +and not ready for general use. The goal of Ray is to make it easy to write machine learning applications that run on a cluster while providing the development and debugging experience of @@ -12,35 +12,37 @@ working on a single machine. Before jumping into the details, here's a simple Python example for doing a Monte Carlo estimation of pi (using multiple cores or potentially multiple machines). -```python -import ray -import functions # See definition below -results = [] -for _ in range(10): - results.append(functions.estimate_pi(100)) -estimate = np.mean([ray.get(ref) for ref in results]) -print "Pi is approximately {}.".format(estimate) -``` - -This assumes that we've defined the file `functions.py` as below. ```python import ray import numpy as np +# Start a scheduler, an object store, and some workers. +ray.services.start_ray_local(num_workers=10) + +# Define a remote function for estimating pi. @ray.remote([int], [float]) def estimate_pi(n): x = np.random.uniform(size=n) y = np.random.uniform(size=n) return 4 * np.mean(x ** 2 + y ** 2 < 1) + +# Launch 10 tasks, each of which estimates pi. +results = [] +for _ in range(10): + results.append(estimate_pi(100)) + +# Fetch the results of the tasks and print their average. +estimate = np.mean([ray.get(ref) for ref in results]) +print "Pi is approximately {}.".format(estimate) ``` -Within the for loop, each call to `functions.estimate_pi(100)` sends a message -to the scheduler asking it to schedule the task of running -`functions.estimate_pi` with the argument `100`. This call returns right away -without waiting for the actual estimation of pi to take place. Instead of -returning a float, it returns an **object reference**, which represents the -eventual output of the computation. +Within the for loop, each call to `estimate_pi(100)` sends a message to the +scheduler asking it to schedule the task of running `estimate_pi` with the +argument `100`. This call returns right away without waiting for the actual +estimation of pi to take place. Instead of returning a float, it returns an +**object reference**, which represents the eventual output of the computation +(this is a similar to a Future). The call to `ray.get(ref)` takes an object reference and returns the actual estimate of pi (waiting until the computation has finished if necessary). @@ -48,7 +50,6 @@ estimate of pi (waiting until the computation has finished if necessary). ## Next Steps - Installation on [Ubuntu](doc/install-on-ubuntu.md), [Mac OS X](doc/install-on-macosx.md), [Windows](doc/install-on-windows.md) -- [Basic Usage](doc/basic-usage.md) - [Tutorial](doc/tutorial.md) - [About the System](doc/about-the-system.md) - [Using Ray on a Cluster](doc/using-ray-on-a-cluster.md) diff --git a/doc/about-the-system.md b/doc/about-the-system.md index 52b7eb164..9bc2611a5 100644 --- a/doc/about-the-system.md +++ b/doc/about-the-system.md @@ -1,9 +1,9 @@ -## About the System +# About the System This document describes the current architecture of Ray. However, some of these decisions are likely to change. -### Components +## Components A Ray cluster consists of several components. @@ -12,20 +12,20 @@ A Ray cluster consists of several components. - One object store per node - One (or more) drivers -#### The scheduler +### The scheduler The scheduler assigns tasks to the workers. -#### The workers +### The workers The workers execute tasks and submit tasks to the scheduler. -#### The object store +### The object store The object store shares objects between the worker processes on the same node so that the workers don't need to each have their own copies of the objects. -#### The driver +### The driver The driver submits tasks to the scheduler. If you use Ray in a script, the Python process running the script is the driver. If you use Ray interactively diff --git a/doc/basic-usage.md b/doc/basic-usage.md deleted file mode 100644 index feeeb09e2..000000000 --- a/doc/basic-usage.md +++ /dev/null @@ -1,207 +0,0 @@ -## Basic Usage - -To use Ray, you need to understand the following: - -- How Ray uses object references to represent immutable remote objects. -- How Ray constructs computation graphs using remote functions. - -### Immutable remote objects - -In Ray, we can create and manipulate objects. We refer to these objects as -**remote objects**, and we use **object references** to refer to them. Remote -objects are stored in **object stores**, and there is one object store per node -in the cluster. In the cluster setting, we may not actually know which machine -each object lives on. - -An **object reference** is essentially a unique ID that can be used to refer to -a remote object. If you're familiar with Futures, our object references are -conceptually similar. - -We assume that remote objects are immutable. That is, their values cannot be -changed after creation. This allows remote objects to be replicated in multiple -object stores without needing to synchronize the copies. - -#### Put and Get - -The commands `ray.get` and `ray.put` can be used to convert between Python -objects and object references, as shown in the example below. -```python ->>> x = [1, 2, 3] ->>> ray.put(x) - -``` - -The command `ray.put(x)` would be run by a worker process or by the driver -process (the driver process is the one running your script). It takes a Python -object and copies it to the local object store (here *local* means *on the same -node*). Once the object has been stored in the object store, its value cannot be -changed. - -In addition, `ray.put(x)` returns an object reference, which is essentially an -ID that can be used to refer to the newly created remote object. If we save the -object reference in a variable with `ref = ray.put(x)`, then we can pass `ref` -into remote functions, and those remote functions will operate on the -corresponding remote object. - -The command `ray.get(ref)` takes an object reference and creates a Python object -from the corresponding remote object. For some objects like arrays, we can use -shared memory and avoid copying the object. For other objects, this currently -copies the object from the object store into the memory of the worker process. -If the remote object corresponding to the object reference `ref` does not live -on the same node as the worker that calls `ray.get(ref)`, then the remote object -will first be copied from an object store that has it to the object store that -needs it. -```python ->>> ref = ray.put([1, 2, 3]) ->>> ray.get(ref) -[1, 2, 3] -``` - -If the remote object corresponding to the object reference `ref` has not been -created yet, the command `ray.get(ref)` will wait until the remote object has -been created. - -### Computation graphs in Ray - -Ray represents computation with a directed acyclic graph of tasks. Tasks are -added to this graph by calling **remote functions**. - -For example, a normal Python function looks like this. -```python -def add(a, b): - return a + b -``` -A remote function in Ray looks like this. -```python -@ray.remote([int, int], [int]) -def add(a, b): - return a + b -``` - -The information passed to the `@ray.remote` decorator includes type information -for the arguments and for the return values of the function. Because of the -distinction that we make between *submitting a task* and *executing the task*, -we require type information so that we can catch type errors when the remote -function is called instead of catching them when the task is actually executed. - -However, the only piece of information that is fundamentally required by the -system is the number of return values (because the system must assign the -correct number of object references to the outputs before the function has -actually executed and produced any outputs). - -#### Remote functions - -Whereas in regular Python, calling `add(1, 2)` would return `3`, in Ray, calling -`add(1, 2)` does not actually execute the task. Instead, it adds a task to the -computation graph and immediately returns an object reference to the output of -the computation. - -```python ->>> ref = add(1, 2) ->>> ray.get(ref) -3 -``` - -There is a sharp distinction between *submitting a task* and *executing the -task*. When a remote function is called, the task of executing that function is -submitted to the scheduler, and the scheduler immediately returns object -references for the outputs of the task. However, the task will not be executed -until the scheduler actually schedules the task on a worker. - -When a task is submitted, each argument may be passed in by value or by object -reference. For example, these lines have the same behavior. - -```python ->>> add(1, 2) ->>> add(1, ray.put(2)) ->>> add(ray.put(1), ray.put(2)) -``` - -Remote functions never return actual values, they always return object -references. - -When the remote function is actually executed, it operates on Python objects. -That is, if the remote function was called with any object references, the -Python objects corresponding to those object references will be retrieved and -passed into the actual execution of the remote function. - -#### Blocking computation - -In a regular Python script, the specification of a computation is intimately -linked to the actual execution of the code. For example, consider the following -code. -```python -result = [] -for i in range(10): - result.append(np.zeros(size=[100, 100])) -``` - -At the core of the above script, there are 10 separate tasks, each of which -generates a 100x100 matrix of zeros. These tasks do not depend on each other, so -in principle, they could be executed in parallel. However, in the above -implementation, they will be executed serially. - -Ray gets around this by representing computation as a graph of tasks, where some -tasks depend on the outputs of other tasks and where tasks can be executed once -their dependencies have been executed. - -For example, suppose we define the remote function `zeros` to be a wrapper -around `np.zeros`. -```python -from typing import List -import numpy as np - -@ray.remote([List[int]], [np.ndarray]) -def zeros(shape): - return np.zeros(shape) -``` -Then we can write -```python -result_refs = [] -for i in range(10): - result.append(zeros([100, 100])) -``` -This adds 10 tasks to the computation graph, with no dependencies between the -tasks. - -The computation graph looks like this. - -

- -

- -In this figure, boxes are tasks and ovals are objects. - -The box that says `op-root` in it just refers to the overall script itself. The -dotted lines indicate that the script launched 10 tasks (tasks are denoted by -rectangular boxes). The solid lines indicate that each task produces one output -(represented by an oval). - -It is clear from the computation graph that these ten tasks can be executed in -parallel. - -Computation graphs encode dependencies. For example, suppose we define -```python -ray.remote([np.ndarray, np.ndarray], [np.ndarray]) -def dot(a, b): - return np.dot(a, b) -``` -Then we run -```python -aref = zeros([10, 10]) -bref = zeros([10, 10]) -cref = dot(aref, bref) -``` -The corresponding computation graph looks like this. - -

- -

- - -The three dashed lines indicate that the script launched three tasks (the two -`zeros` tasks and the one `dot` task). Each task produces a single output, and -the `dot` task depends on the outputs of the two `zeros` tasks. - -This makes it clear that the two `zeros` tasks can execute in parallel but that -the `dot` task must wait until the two `zeros` tasks have finished. diff --git a/doc/figures/compgraph1.png b/doc/figures/compgraph1.png index 9abd43a362b2a9716c915d1e42ddde6daaf2f2ee..bc34726b07f488ab7518f30e83e9ab5e7003ff41 100644 GIT binary patch literal 4914 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 literal 2819 zcmZ{mdpHyNAIE1~o9o;)!%Qicj{D9p$zsYax1De(i-}HdEw{~`v15p&6iL~rlkhVn zvHh$pPDrF&=E!A^+rmas)Lee+_uuc2^Ld`{=kt9&&*%9(@6YFXJ>Tb>hx2q+kVVJ> z000G7ms4i|0ALCL09Ka*Niu806!K=a zgO4ugA>t2Qd%k#+PnyA$uILcuR#~ATrrWDe+APGs7{7XS#nhpp*2A(wdc!>kF^aKi zt+**~*~722=Yd}Z=-=+h2nPvrM!3&qwr>Myl~OCJ_LD~`ob-!>??FS}G^!rFz~F{8 zt_llH?+e*DsX2_?SOVQGNA5$DVRk{Z(mpfaUp7bfK0cf9&kV*w#jA9pkx<>*1P-J* zhP^wXJ0QAsKPclp|5iLLuu zN~ik`K~tPE>Ss}1L0!N5pnZ~E#6Vqt&W(t#CHyI z4g^0s{BoqBzNR@6^5He5K1ateN z+KC}jCmwRshiV}w@X1H(lUi7Pl+2qW9j&WuGtRLs)?d3O-*8Wp!=UON@4{l23p>}| zo~;%da0Tg0CD8k;({?ng#o6f$uSd_PU8iC9O-A|+Wb^_5EOHONWym~)n&z%q(K|E!uRE05%d ziPYrIIRiW!8IN`DEEB6N;Myu&C546W4Nt1e|`BS1vq|&fYTk+hH0yjpz7>E z=ivn1_jXL#qXIYb(R?Pi`peN8k&_8KGLi<`p^SZh(u8m@8M8h#3rx!+l6}jAh{uwP zS?{0R5ECNriJe(J#AxC)vYku$a8HhbtO{qiHgSHD^KOBPHBR}C2Rg7EDZSz-)ees@ zo)x6X1NPZS>6?CslnMWdR_Rxbe-gHgKjnHBAO=Ai1aIuxcUT%7v)bvo`QS#6hz3O-%oh39FBXooy=x`5(x#pFie{ zMotqrs>dp+2a>{#A5JYj+clxD7vacdGFdH&CY{)HAA!?&_kzjQD(QPOazgIFRsXQ) zA<#=Ej>_#XD;Tm<9=4}?pu>2`HD4qmK~8~;V!ZLWYy+qCnTuIqj(o9S z;x*>KbkJkAStajlFosdpUr{?f*GfUbeWAFP@OkXG^O9d!ku&D0mRno*g-fF*Ery+P z=sO5kWkQ60w(S(()tD@4J4k3|Ue-)wG%>41t-j!Rm*<@DpHPiPt*Fq&W7-hRdHVuHd6@tq>p4uvdWy)rF@^V3CVW7m6x>LfNpG zpa`&W#ewW~6>9azoT(VJAw0B*TMTHBBGgiazz(5}V==k(4OLBhF0+DL4Y^h}=cVP| zt&WJQ^$ovy%ACGj z0r^p2AHo!mUr#oH^zunUx+V3kEcqS35WhLn=}0ZN-i&KRQt_96i0Gu~A%+*Bv6%k} z(#sow$)2|E8KGez*EMXJ-kZ6l`_D)K{sK1e$7y3fr^dg^3*O->$&VWGc2qM>wdI#! zhrK3KlyJj3K7_#>VPiMX`7MdQiby47PDXsx2LL{{&nYlgIBe|yhJz*N?n zn7NGFYYXO%9I7`Gf5anO-(nU_A@ns1^EkP+`X;~SHQ zbXB?+Qkf~&zySayOhGI&1(4fA$`~`UIKbo7?7cKOV$I{Ufq(6~7)bh_qg#gGj5jY{ zu7Hi&@OF$TERmno8xozCT9hN1Mkbjlj`Gl7WWSxVT4X!_uAsA3D0fR>srKV3jH6)C z@G7hV!~|^!Wah|QZpjlA6=-2NDt0)ua9NKkUjhW7A9ES%!#cKg5zQ0P#F_Sy8Zk@- zuidjA!(S@0UE97QPqUA1TF!)UBNyTXoIF zasVgMxsl0zaW7Po_(?G?fdhl6Sc8<96+gX%tNZE58YKmYJx=Bg_I%}UA40b*MziwlrH7iQj+|7(EK&MgybI0c(WOePDt5D9nKRm7xjA(sG#s74}@ zPMV>EfLNyZU@yrFq`(rnGK_c_p^;YXq$+lRl%aw80bqC8as?KmX=~oY5@m8F=v(&u zpFlly5tWFaCP)N#dIKK{TBtkM$!NP diff --git a/doc/figures/compgraph2.png b/doc/figures/compgraph2.png index f05f7eeb52189380876350d631919e7ed6038897..92309630483a9e1da3dc03441fa0b24f14dec0f1 100644 GIT binary patch delta 2633 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 diff --git a/doc/figures/compgraph3.png b/doc/figures/compgraph3.png deleted file mode 100644 index 92309630483a9e1da3dc03441fa0b24f14dec0f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2645 zcmV-b3aa&qP)~&2Ae1l z#4|rcHPxid?y6aHz4ZsiBTMGb-OZ}%4|bOsBauiX5{X12kw_#Gi9{liNF)-8^v9Kz zhy)2G5|Lt|9{+KSa`EabM!CGIJQ%1;{QJnkhHykdtLPnHBBDkrj)+P@-q*UD>5Fdk z@k*EnVl;E;i0H|0T^$m(9HXn=;5m4P7XCodsju5YviKpM`8*N+#4|HAl!u3kH_wRj zdr@0m)Uxk`)lL^R@B1L%p;>6YN3&2&RE}4{9L)(=cqlJV@oK1tIv00Wdj5Q_kN5PP z&^=e;r=2j)TPlBd`>nLHD_LJ16?J^uzFDbqLpY%bMW{X$&lFTW%F;%;k%AJ2D92Y& zp&=>=6cjf^`FNl#!ullMG4{F`oSLJo8pSbCJpQgmMR3$d3AF{GnhF-E6xvqT2h`r&M8)-Y zk0^fqBd?5MV~*nM8}|`)cO%?41u6kJ&JW@P^Q;Gc>lKbOgACR7V#~txt+n&uqdpsN z0NH{16Z6)|<^JTHTrib!&@y)-#z5XDf;>~{Y<-hhqyHwM^{jj^ccjQui zz6pO7PIMOKb+py;?&13G;Zj0b58_sccdyQ(!c;|V?jF|3Ln5L0y|{Jxt$sh4^*+%>Sy{^0$!GZviZydxev|5=cv_&corLmufm(00QAvq`JKFH+Q#!e?QelxtH7f>+D`eO}}|?#oEzEO`O$z z@@4%_LM{KAyZoaY>7v42>}7GeJaj;e z3Z`RhtFLGb>i#?9?Th0?#p-f`=~mBiqC&M{R@;|^^3;YIyc^m6YAB(i!l9@WXBBG0 z)Q|grQ`9M0MVW3*=W4@v>9eCO6=iy4(o!47^dRRbQ6kSzts$&eb9L1$10Qc`@s>fk z!bcAj?J%=?yrrQ*m?@)iEZ=;-Yu!&&>>4$|{t3U^}P^K&LRKwOm zWy4o6iD zQ=bJWOHvo7?j3DiRK0mvMsY(_eHNf}lQv4|28Px~>lR95VxOugrj2@qhw|}I0UpZ1 zLoq@bp|sBe^rN)T0-T8qzUt1}gS84(p9PSEj4%u`bwF-~zDyU@>Z#;_+|^I&pqPRh z)=l_I=f%~|YZxlP>rx%1%XHPDtVT!gsNY0}!w*}HhJMdb^~o6k!cdKM3?L)blr&~0 zmO2)-b;qJzzcy2XfmSN3OeunVxz;Rhp%g)`l&gb6oa0Q?m&=aX@DsW`X^oj$l#Pzl zNR7Nu8fdUB*zM_i^XfPU9=slAx0{2jivwCW@Yq7qM1G@uHcXy+-AuRDPuCJQ3SB!} z%2rtxIxHTAy6bbXdfo1H?PzFYm1VHx)%!R(uH5O!+8==jd)gj>dNte>&$wD|6cEG9y5MLi8xO@sio!Edfrqm3P!1l-$3sP8i!i;BXi8KDS8 zC_)j6P=q2Bp$J7NLJ^8kFCXOr_fn1?C4f6TM~~tdyR65Ig6@X>Iw*#TVq-+D@KA3@ ziF%EPn!Rw;lYfG3u!_~+9SW)3c8?Qg%Jf+RV=0>L(R`=gjxG>tSZ7AG5NddZ=R8f` zT5u$7_Q-Q^V|C=-G1W1T68N<2vI7cib@(Z4@G*1Nbv^W8Dq^Al#7qc?sU8q>SuA=g zYoM&>78po20FGs$;3P0fA6MVldut0acA&Z2t@u8NqYh^QKzWKP13#Pvh!9ZqSpWpo z;Vi%u9vJ8>fCh@r0t`pdS%AUrd^ig*MF=uA3L(fG&H}u^#Bl--h1jKXypA3*2VHwm z1VbSX)u7qldIs3Qv8dlO@CJ_CfwMRl%LQ?hp`~3fp@s!KX^xtet0M(2d~sj_MRoiw zA>%NUVYT{kp#i+ia7@jMu;?VJ8uAQ|s?+?&@TRJBSy(8mndM(Ci!%%qTjdOxx8)cT z@*M3!4&oyr5{X12kw_#Gi9{liNF)-8L?V$$zaRY{>> xref = ray.put([1, 2, 3]) +import ray +ray.services.start_ray_local(num_workers=10) ``` -We can use `ray.get` to retrieve the object corresponding to an object -reference. +That command starts a scheduler, one object store, and ten workers. Each of +these are distinct processes. They will be killed when you exit the Python +interpreter. They can also be killed manually with the following command. + +``` +killall scheduler objstore python +``` + +## Immutable remote objects + +In Ray, we can create and manipulate objects. We refer to these objects as +**remote objects**, and we use **object references** to refer to them. Remote +objects are stored in **object stores**, and there is one object store per node +in the cluster. In the cluster setting, we may not actually know which machine +each object lives on. + +An **object reference** is essentially a unique ID that can be used to refer to +a remote object. If you're familiar with Futures, our object references are +conceptually similar. + +We assume that remote objects are immutable. That is, their values cannot be +changed after creation. This allows remote objects to be replicated in multiple +object stores without needing to synchronize the copies. + +### Put and Get + +The commands `ray.get` and `ray.put` can be used to convert between Python +objects and object references, as shown in the example below. ```python ->>> ray.get(xref) -[1, 2, 3] -``` -We can call a remote function. -```python ->>> ref = example_functions.increment(1) ->>>ray.get(ref) -2 +x = [1, 2, 3] +ray.put(x) # prints ``` -Note that `example_functions.increment` is defined in -[`scripts/example_functions.py`](../scripts/example_functions.py) as +The command `ray.put(x)` would be run by a worker process or by the driver +process (the driver process is the one running your script). It takes a Python +object and copies it to the local object store (here *local* means *on the same +node*). Once the object has been stored in the object store, its value cannot be +changed. + +In addition, `ray.put(x)` returns an object reference, which is essentially an +ID that can be used to refer to the newly created remote object. If we save the +object reference in a variable with `ref = ray.put(x)`, then we can pass `ref` +into remote functions, and those remote functions will operate on the +corresponding remote object. + +The command `ray.get(ref)` takes an object reference and creates a Python object +from the corresponding remote object. For some objects like arrays, we can use +shared memory and avoid copying the object. For other objects, this currently +copies the object from the object store into the memory of the worker process. +If the remote object corresponding to the object reference `ref` does not live +on the same node as the worker that calls `ray.get(ref)`, then the remote object +will first be copied from an object store that has it to the object store that +needs it. + +```python +>>> ref = ray.put([1, 2, 3]) +>>> ray.get(ref) # prints [1, 2, 3] +``` + +If the remote object corresponding to the object reference `ref` has not been +created yet, *the command `ray.get(ref)` will wait until the remote object has +been created.* + +## Computation graphs in Ray + +Ray represents computation with a directed acyclic graph of tasks. Tasks are +added to this graph by calling **remote functions**. + +For example, a normal Python function looks like this. +```python +def add(a, b): + return a + b +``` +A remote function in Ray looks like this. +```python +@ray.remote([int, int], [int]) +def add(a, b): + return a + b +``` + +The information passed to the `@ray.remote` decorator includes type information +for the arguments and for the return values of the function. Because of the +distinction that we make between *submitting a task* and *executing the task*, +we require type information so that we can catch type errors when the remote +function is called instead of catching them when the task is actually executed +(which could be much later and could be on a different machine). + +### Remote functions + +Whereas in regular Python, calling `add(1, 2)` would return `3`, in Ray, calling +`add(1, 2)` does not actually execute the task. Instead, it adds a task to the +computation graph and immediately returns an object reference to the output of +the computation. + +```python +>>> ref = add(1, 2) +>>> ray.get(ref) # prints 3 +``` + +There is a sharp distinction between *submitting a task* and *executing the +task*. When a remote function is called, the task of executing that function is +submitted to the scheduler, and the scheduler immediately returns object +references for the outputs of the task. However, the task will not be executed +until the scheduler actually schedules the task on a worker. + +When a task is submitted, each argument may be passed in by value or by object +reference. For example, these lines have the same behavior. + +```python +>>> add(1, 2) +>>> add(1, ray.put(2)) +>>> add(ray.put(1), ray.put(2)) +``` + +Remote functions never return actual values, they always return object +references. + +When the remote function is actually executed, it operates on Python objects. +That is, if the remote function was called with any object references, the +Python objects corresponding to those object references will be retrieved and +passed into the actual execution of the remote function. + +### Blocking computation + +In a regular Python script, the specification of a computation is intimately +linked to the actual execution of the code. For example, consider the following +code. + +```python +import time + +# This takes 50 seconds. +for i in range(10): + time.sleep(5) +``` + +At the core of the above script, there are ten separate tasks, each of which +sleeps for five seconds (this is a toy example, but you could imagine replacing +the call to `sleep` with some computationally intensive task). These tasks do +not depend on each other, so in principle, they could be executed in parallel. +However, in the above implementation, they will be executed serially, which will +take fifty seconds. + +Ray gets around this by representing computation as a graph of tasks, where some +tasks depend on the outputs of other tasks and where tasks can be executed once +their dependencies are done. + +For example, suppose we define the remote function `sleep` to be a wrapper +around `time.sleep`. ```python @ray.remote([int], [int]) -def increment(x): - return x + 1 +def sleep(n): + time.sleep(n) + return 0 ``` -Note that, we can pass arguments into remote functions either by value or by -object reference. That is, these two lines have the same behavior. +Then we can write ```python ->>> ray.get(example_functions.increment(1)) -2 ->>> ray.get(example_functions.increment(ray.put(1))) -2 -``` -This is convenient for chaining remote functions together, for example, -```python ->>> ref = example_functions.increment(1) ->>> ref = example_functions.increment(ref) ->>> ref = example_functions.increment(ref) ->>> ray.get(ref) -4 +# Submit ten tasks to the scheduler. This finishes almost immediately. +result_refs = [] +for i in range(10): + result_refs.append(sleep(5)) + +# Wait for the results. If we have at least ten workers, this takes 5 seconds. +[ray.get(ref) for ref in result_refs] # prints [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ``` -### Visualize the computation graph +The for loop simply adds ten tasks to the computation graph, with no +dependencies between the tasks. It executes almost instantaneously. Afterwards, +we use `ray.get` to wait for the tasks to finish. If we have at least ten +workers, then all ten tasks can be executed in parallel, and so the overall +script should take five seconds. + +### Visualizing the Computation Graph + +The computation graph can be viewed as follows. -At any point, we can visualize the computation graph by running ```python ->>> ray.visualize_computation_graph(view=True) +ray.visualize_computation_graph(view=True) ``` -This will display an image like the following one.

- +

-### Restart workers +In this figure, boxes are tasks and ovals are objects. -During development, suppose that you want to change the implementation of -`example_functions.increment`, but you've already done a bunch of work in the -shell loading and preprocessing data, and you don't want to have to recompute -all of that work. +The box that says `op-root` in it just refers to the overall script itself. The +dotted lines indicate that the script launched 10 tasks (tasks are denoted by +rectangular boxes). The solid lines indicate that each task produces one output +(represented by an oval). -We can simply restart the workers. +It is clear from the computation graph that these ten tasks can be executed in +parallel. -First, change the code, for example, modify the function -`example_functions.increment` in -[`scripts/example_functions.py`](../scripts/example_functions.py) to add 10 -instead of 1. +Computation graphs encode dependencies. For example, suppose we define ```python -@ray.remote([int], [int]) -def increment(x): - return x + 10 -``` -Then from the shell, restart the workers like this. -```python ->>> ray.restart_workers("scripts/example_worker.py") # This should be the correct relative path to the example_worker.py code -``` -We can check that the code has been updated by running. -```python ->>> ray.get(example_functions.increment(1)) -11 +import numpy as np + +@ray.remote([list], [np.ndarray]) +def zeros(shape): + return np.zeros(shape) + +@ray.remote([np.ndarray, np.ndarray], [np.ndarray]) +def dot(a, b): + return np.dot(a, b) ``` -Note that it is not as simple as running `reload(example_functions)` because we -need to reload the Python module on all of the workers as well, and the workers -are separate Python processes. Calling `reload(example_functions)` would only -reload the module on the driver. +Then we run + +```python +aref = zeros([10, 10]) +bref = zeros([10, 10]) +cref = dot(aref, bref) +``` + +The corresponding computation graph looks like this. + +

+ +

+ +The three dashed lines indicate that the script launched three tasks (the two +`zeros` tasks and the one `dot` task). Each task produces a single output, and +the `dot` task depends on the outputs of the two `zeros` tasks. + +This makes it clear that the two `zeros` tasks can execute in parallel but that +the `dot` task must wait until the two `zeros` tasks have finished. diff --git a/doc/using-ray-on-a-cluster.md b/doc/using-ray-on-a-cluster.md index 3edb9dd85..cc2b970c3 100644 --- a/doc/using-ray-on-a-cluster.md +++ b/doc/using-ray-on-a-cluster.md @@ -1,4 +1,4 @@ -## Using Ray on a cluster +# Using Ray on a cluster Running Ray on a cluster is still experimental. @@ -6,12 +6,12 @@ Ray can be used in several ways. In addition to running on a single machine, Ray is designed to run on a cluster of machines. This document is about how to use Ray on a cluster. -### Launching a cluster on EC2 +## Launching a cluster on EC2 This section describes how to start a cluster on EC2. These instructions are copied and adapted from https://github.com/amplab/spark-ec2. -#### Before you start +### Before you start - Create an Amazon EC2 key pair for yourself. This can be done by logging into your Amazon Web Services account through the [AWS @@ -25,7 +25,7 @@ and secret access key. These can be obtained from the [AWS homepage](http://aws.amazon.com/) by clicking Account > Security Credentials > Access Credentials. -#### Launching a Cluster +### Launching a Cluster - Go into the `ray/scripts` directory. - Run `python ec2.py -k -i -s launch @@ -56,7 +56,7 @@ capacity in one zone, and you should try to launch in another. Instances](http://aws.amazon.com/ec2/spot-instances/), bidding for the given maximum price (in dollars). -### Getting started with Ray on a cluster +## Getting started with Ray on a cluster These instructions work on EC2, but they may require some modifications to run on your own cluster. In particular, on EC2, running `sudo` does not require a @@ -125,8 +125,6 @@ For example, - `cluster.update_ray()` - This pulls the latest Ray source code and builds it. -### Running Ray on a cluster - Once you've started a Ray cluster using the above instructions, to actually use Ray, ssh to the head node (the first node listed in the `nodes.txt` file) and attach a shell to the already running cluster. diff --git a/examples/hyperopt/README.md b/examples/hyperopt/README.md index 578b9a5ae..ed7f68806 100644 --- a/examples/hyperopt/README.md +++ b/examples/hyperopt/README.md @@ -1,4 +1,4 @@ -## Hyperparameter Optimization +# Hyperparameter Optimization This document provides a walkthrough of the hyperparameter optimization example. To run the application, first install this dependency. @@ -22,7 +22,7 @@ Choosing these parameters can be challenging, and so a common practice is to search over the space of hyperparameters. One approach that works surprisingly well is to randomly sample different options. -### The serial version +## The serial version Suppose that we want to train a convolutional network, but we aren't sure how to choose the following hyperparameters: @@ -74,7 +74,7 @@ Of course, as there are no dependencies between the different invocations of `train_cnn_and_compute_accuracy`, this computation could easily be parallelized over multiple cores or multiple machines. Let's do that now. -### The distributed version +## The distributed version First, let's turn `train_cnn_and_compute_accuracy` into a remote function in Ray by writing it as follows. In this example application, a slightly more @@ -115,7 +115,7 @@ their values with `ray.get`. results = [(params, ray.get(ref)) for (params, ref) in result_refs] ``` -### Additional notes +## Additional notes **Early Stopping:** Sometimes when running an optimization, it is clear early on that the hyperparameters being used are bad (for example, the loss function may diff --git a/examples/lbfgs/README.md b/examples/lbfgs/README.md index 2b48bdea1..2d4400e85 100644 --- a/examples/lbfgs/README.md +++ b/examples/lbfgs/README.md @@ -1,4 +1,4 @@ -## Batch L-BFGS +# Batch L-BFGS This document provides a walkthrough of the L-BFGS example. To run the application, first install these dependencies. @@ -21,7 +21,7 @@ one such algorithm. It is a quasi-Newton method that uses gradient information to approximate the inverse Hessian of the loss function in a computationally efficient manner. -### The serial version +## The serial version First we load the data in batches. Here, each element in `batches` is a tuple whose first component is a batch of `100` images and whose second component is a @@ -73,7 +73,7 @@ theta_init = 1e-2 * np.random.normal(size=dim) result = scipy.optimize.fmin_l_bfgs_b(full_loss, theta_init, fprime=full_grad) ``` -### The distributed version +## The distributed version In this example, the computation of the gradient itself can be done in parallel on a number of workers or machines.