mirror of
https://github.com/wassname/ray.git
synced 2026-09-12 12:51:15 +08:00
Change API for remote function declaration, actor instantiation, and actor method invocation. (#541)
* Direction substitution of @ray.remote -> @ray.task. * Changes to make '@ray.task' work. * Instantiate actors with Class.remote() instead of Class(). * Convert actor instantiation in tests and examples from Class() to Class.remote(). * Change actor method invocation from object.method() to object.method.remote(). * Update tests and examples to invoke actor methods with .remote(). * Fix bugs in jenkins tests. * Fix example applications. * Change @ray.task back to @ray.remote. * Changes to make @ray.actor -> @ray.remote work. * Direct substitution of @ray.actor -> @ray.remote. * Fixes. * Raise exception if @ray.actor decorator is used. * Simplify ActorMethod class.
This commit is contained in:
committed by
Philipp Moritz
parent
22c6a22f28
commit
9f91eb8c91
+26
-25
@@ -27,7 +27,7 @@ An actor can be defined as follows.
|
||||
|
||||
import gym
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class GymEnvironment(object):
|
||||
def __init__(self, name):
|
||||
self.env = gym.make(name)
|
||||
@@ -63,19 +63,20 @@ We can use the actor by calling one of its methods.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
a1.step(0)
|
||||
a2.step(0)
|
||||
a1.step.remote(0)
|
||||
a2.step.remote(0)
|
||||
|
||||
When ``a1.step(0)`` is called, a task is created and scheduled on the first
|
||||
actor. This scheduling procedure bypasses the global scheduler, and is assigned
|
||||
directly to the local scheduler responsible for the actor by the driver's local
|
||||
scheduler. Since the method call is a task, ``a1.step(0)`` returns an object ID.
|
||||
We can call `ray.get` on the object ID to retrieve the actual value.
|
||||
When ``a1.step.remote(0)`` is called, a task is created and scheduled on the
|
||||
first actor. This scheduling procedure bypasses the global scheduler, and is
|
||||
assigned directly to the local scheduler responsible for the actor by the
|
||||
driver's local scheduler. Since the method call is a task, ``a1.step(0)``
|
||||
returns an object ID. We can call `ray.get` on the object ID to retrieve the
|
||||
actual value.
|
||||
|
||||
The call to ``a2.step(0)`` generates a task which is scheduled on the second
|
||||
actor. Since these two tasks run on different actors, they can be executed in
|
||||
parallel (note that only actor methods will be scheduled on actor workers, not
|
||||
regular remote functions).
|
||||
The call to ``a2.step.remote(0)`` generates a task which is scheduled on the
|
||||
second actor. Since these two tasks run on different actors, they can be
|
||||
executed in parallel (note that only actor methods will be scheduled on actor
|
||||
workers, not regular remote functions).
|
||||
|
||||
On the other hand, methods called on the same actor are executed serially and
|
||||
share in the order that they are called and share state with one another. We
|
||||
@@ -83,7 +84,7 @@ illustrate this with a simple example.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Counter(object):
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
@@ -96,12 +97,12 @@ illustrate this with a simple example.
|
||||
|
||||
# Increment each counter once and get the results. These tasks all happen in
|
||||
# parallel.
|
||||
results = ray.get([c.increment() for c in counters])
|
||||
results = ray.get([c.increment.remote() for c in counters])
|
||||
print(results) # prints [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
|
||||
# Increment the first counter five times. These tasks are executed serially
|
||||
# and share state.
|
||||
results = ray.get([counters[0].increment() for _ in range(5)])
|
||||
results = ray.get([counters[0].increment.remote() for _ in range(5)])
|
||||
print(results) # prints [2, 3, 4, 5, 6]
|
||||
|
||||
Using GPUs on actors
|
||||
@@ -136,8 +137,8 @@ We can then define an actor for this network as follows.
|
||||
import os
|
||||
|
||||
# Define an actor that runs on GPUs. If there are no GPUs, then simply use
|
||||
# ray.actor without any arguments and no parentheses.
|
||||
@ray.actor(num_gpus=1)
|
||||
# ray.remote without any arguments and no parentheses.
|
||||
@ray.remote(num_gpus=1)
|
||||
class NeuralNetOnGPU(object):
|
||||
def __init__(self):
|
||||
# Set an environment variable to tell TensorFlow which GPUs to use. Note
|
||||
@@ -154,15 +155,15 @@ We can then define an actor for this network as follows.
|
||||
self.sess.run(init)
|
||||
|
||||
To indicate that an actor requires one GPU, we pass in ``num_gpus=1`` to
|
||||
``ray.actor``. Note that in order for this to work, Ray must have been started
|
||||
``ray.remote``. Note that in order for this to work, Ray must have been started
|
||||
with some GPUs, e.g., via ``ray.init(num_gpus=2)``. Otherwise, when you try to
|
||||
instantiate the GPU version with ``NeuralNetOnGPU()``, an exception will be
|
||||
thrown saying that there aren't enough GPUs in the system.
|
||||
instantiate the GPU version with ``NeuralNetOnGPU.remote()``, an exception will
|
||||
be thrown saying that there aren't enough GPUs in the system.
|
||||
|
||||
When the actor is created, it will have access to a list of the IDs of the GPUs
|
||||
that it is allowed to use via ``ray.get_gpu_ids()``. This is a list of integers,
|
||||
like ``[]``, or ``[1]``, or ``[2, 5, 6]``. Since we passed in
|
||||
``ray.actor(num_gpus=1)``, this list will have length one.
|
||||
``ray.remote(num_gpus=1)``, this list will have length one.
|
||||
|
||||
We can put this all together as follows.
|
||||
|
||||
@@ -190,7 +191,7 @@ We can put this all together as follows.
|
||||
|
||||
return x, y_, train_step, accuracy
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class NeuralNetOnGPU(object):
|
||||
def __init__(self, mnist_data):
|
||||
self.mnist = mnist_data
|
||||
@@ -223,9 +224,9 @@ We can put this all together as follows.
|
||||
ray.register_class(type(mnist.train))
|
||||
|
||||
# Create the actor.
|
||||
nn = NeuralNetOnGPU(mnist)
|
||||
nn = NeuralNetOnGPU.remote(mnist)
|
||||
|
||||
# Run a few steps of training and print the accuracy.
|
||||
nn.train(100)
|
||||
accuracy = ray.get(nn.get_accuracy())
|
||||
nn.train.remote(100)
|
||||
accuracy = ray.get(nn.get_accuracy.remote())
|
||||
print("Accuracy is {}.".format(accuracy))
|
||||
|
||||
@@ -73,7 +73,7 @@ We use a Ray Actor to simulate the environment.
|
||||
import numpy as np
|
||||
import ray
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Runner(object):
|
||||
"""Actor object to start running simulation on workers.
|
||||
Gradient computation is also executed on this object."""
|
||||
@@ -127,7 +127,7 @@ global model parameters. The main training script looks like the following.
|
||||
|
||||
# Start gradient calculation tasks on each actor
|
||||
parameters = policy.get_weights()
|
||||
gradient_list = [agent.compute_gradient(parameters) for agent in agents]
|
||||
gradient_list = [agent.compute_gradient.remote(parameters) for agent in agents]
|
||||
|
||||
while True: # Replace with your termination condition
|
||||
# wait for some gradient to be computed - unblock as soon as the earliest arrives
|
||||
@@ -147,6 +147,12 @@ global model parameters. The main training script looks like the following.
|
||||
Benchmarks and Visualization
|
||||
----------------------------
|
||||
|
||||
For the :code:`PongDeterministic-v3` and an Amazon EC2 m4.16xlarge instance, we are able to train the agent with 16 workers in around 15 minutes. With 8 workers, we can train the agent in around 25 minutes.
|
||||
For the :code:`PongDeterministic-v3` and an Amazon EC2 m4.16xlarge instance, we
|
||||
are able to train the agent with 16 workers in around 15 minutes. With 8
|
||||
workers, we can train the agent in around 25 minutes.
|
||||
|
||||
You can visualize performance by running :code:`tensorboard --logdir [directory]` in a separate screen, where :code:`[directory]` is defaulted to :code:`./results/`. If you are running multiple experiments, be sure to vary the directory to which Tensorflow saves its progress (found in :code:`driver.py`).
|
||||
You can visualize performance by running
|
||||
:code:`tensorboard --logdir [directory]` in a separate screen, where
|
||||
:code:`[directory]` is defaulted to :code:`./results/`. If you are running
|
||||
multiple experiments, be sure to vary the directory to which Tensorflow saves
|
||||
its progress (found in :code:`driver.py`).
|
||||
|
||||
@@ -53,7 +53,7 @@ The core of the script is the actor definition.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class ResNetTrainActor(object):
|
||||
def __init__(self, path, num_gpus):
|
||||
# Set the CUDA_VISIBLE_DEVICES environment variable in order to restrict
|
||||
@@ -78,7 +78,7 @@ The main script first creates one actor for each GPU.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
train_actors = [ResNetTrainActor(train_data, num_gpus) for _ in range(num_gpus)]
|
||||
train_actors = [ResNetTrainActor.remote(train_data, num_gpus) for _ in range(num_gpus)]
|
||||
|
||||
Then after initializing the actors with the same weights, the main loop performs
|
||||
updates on each model, averages the updates, and puts the new weights in the
|
||||
@@ -87,7 +87,7 @@ object store.
|
||||
.. code-block:: python
|
||||
|
||||
while True:
|
||||
all_weights = ray.get([actor.compute_steps(weight_id) for actor in train_actors])
|
||||
all_weights = ray.get([actor.compute_steps.remote(weight_id) for actor in train_actors])
|
||||
mean_weights = {k: sum([weights[k] for weights in all_weights]) / num_gpus for k in all_weights[0]}
|
||||
weight_id = ray.put(mean_weights)
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ the actor.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class PongEnv(object):
|
||||
def __init__(self):
|
||||
# Tell numpy to only use one core. If we don't do this, each actor may try
|
||||
@@ -93,7 +93,7 @@ perform rollouts and compute gradients in parallel.
|
||||
actions = []
|
||||
# Launch tasks to compute gradients from multiple rollouts in parallel.
|
||||
for i in range(batch_size):
|
||||
action_id = actors[i].compute_gradient(model_id)
|
||||
action_id = actors[i].compute_gradient.remote(model_id)
|
||||
actions.append(action_id)
|
||||
|
||||
|
||||
|
||||
@@ -158,11 +158,11 @@ complex Python objects.
|
||||
x_test, y_test = ray.get(generate_fake_x_y_data.remote(BATCH_SIZE, seed=NUM_BATCHES))
|
||||
|
||||
# Create actors to store the networks.
|
||||
remote_network = ray.actor(Network)
|
||||
actor_list = [remote_network(x_ids[i], y_ids[i]) for i in range(NUM_BATCHES)]
|
||||
remote_network = ray.remote(Network)
|
||||
actor_list = [remote_network.remote(x_ids[i], y_ids[i]) for i in range(NUM_BATCHES)]
|
||||
|
||||
# Get initial weights of some actor.
|
||||
weights = ray.get(actor_list[0].get_weights())
|
||||
weights = ray.get(actor_list[0].get_weights.remote())
|
||||
|
||||
# Do some steps of training.
|
||||
for iteration in range(NUM_ITERS):
|
||||
@@ -173,7 +173,7 @@ complex Python objects.
|
||||
# more efficient.
|
||||
weights_id = ray.put(weights)
|
||||
# Call the remote function multiple times in parallel.
|
||||
new_weights_ids = [actor.step(weights_id) for actor in actor_list]
|
||||
new_weights_ids = [actor.step.remote(weights_id) for actor in actor_list]
|
||||
# Get all of the weights.
|
||||
new_weights_list = ray.get(new_weights_ids)
|
||||
# Add up all the different weights. Each element of new_weights_list is a dict
|
||||
@@ -288,8 +288,8 @@ For reference, the full code is below:
|
||||
x_test, y_test = ray.get(generate_fake_x_y_data.remote(BATCH_SIZE, seed=NUM_BATCHES))
|
||||
|
||||
# Create actors to store the networks.
|
||||
remote_network = ray.actor(Network)
|
||||
actor_list = [remote_network(x_ids[i], y_ids[i]) for i in range(NUM_BATCHES)]
|
||||
remote_network = ray.remote(Network)
|
||||
actor_list = [remote_network.remote(x_ids[i], y_ids[i]) for i in range(NUM_BATCHES)]
|
||||
local_network = Network(x_test, y_test)
|
||||
|
||||
# Get initial weights of local network.
|
||||
@@ -304,7 +304,7 @@ For reference, the full code is below:
|
||||
# more efficient.
|
||||
weights_id = ray.put(weights)
|
||||
# Call the remote function multiple times in parallel.
|
||||
gradients_ids = [actor.step(weights_id) for actor in actor_list]
|
||||
gradients_ids = [actor.step.remote(weights_id) for actor in actor_list]
|
||||
# Get all of the weights.
|
||||
gradients_list = ray.get(gradients_ids)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from datetime import datetime, timedelta
|
||||
from misc import timestamp, time_string
|
||||
from envs import create_env
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Runner(object):
|
||||
"""Actor object to start running simulation on workers.
|
||||
Gradient computation is also executed from this object."""
|
||||
@@ -58,9 +58,9 @@ class Runner(object):
|
||||
def train(num_workers, env_name="PongDeterministic-v3"):
|
||||
env = create_env(env_name)
|
||||
policy = LSTMPolicy(env.observation_space.shape, env.action_space.n, 0)
|
||||
agents = [Runner(env_name, i) for i in range(num_workers)]
|
||||
agents = [Runner.remote(env_name, i) for i in range(num_workers)]
|
||||
parameters = policy.get_weights()
|
||||
gradient_list = [agent.compute_gradient(parameters) for agent in agents]
|
||||
gradient_list = [agent.compute_gradient.remote(parameters) for agent in agents]
|
||||
steps = 0
|
||||
obs = 0
|
||||
while True:
|
||||
@@ -70,7 +70,7 @@ def train(num_workers, env_name="PongDeterministic-v3"):
|
||||
parameters = policy.get_weights()
|
||||
steps += 1
|
||||
obs += info["size"]
|
||||
gradient_list.extend([agents[info["id"]].compute_gradient(parameters)])
|
||||
gradient_list.extend([agents[info["id"]].compute_gradient.remote(parameters)])
|
||||
return policy
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -60,7 +60,7 @@ class LinearModel(object):
|
||||
"""Computes the gradients of the network."""
|
||||
return self.sess.run(self.cross_entropy_grads, feed_dict={self.x: xs, self.y_: ys})
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class NetActor(object):
|
||||
def __init__(self, xs, ys):
|
||||
os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
||||
@@ -88,13 +88,13 @@ class NetActor(object):
|
||||
# Compute the loss on the entire dataset.
|
||||
def full_loss(theta):
|
||||
theta_id = ray.put(theta)
|
||||
loss_ids = [actor.loss(theta_id) for actor in actors]
|
||||
loss_ids = [actor.loss.remote(theta_id) for actor in actors]
|
||||
return sum(ray.get(loss_ids))
|
||||
|
||||
# Compute the gradient of the loss on the entire dataset.
|
||||
def full_grad(theta):
|
||||
theta_id = ray.put(theta)
|
||||
grad_ids = [actor.grad(theta_id) for actor in actors]
|
||||
grad_ids = [actor.grad.remote(theta_id) for actor in actors]
|
||||
return sum(ray.get(grad_ids)).astype("float64") # This conversion is necessary for use with fmin_l_bfgs_b.
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -117,9 +117,9 @@ if __name__ == "__main__":
|
||||
batch_size = mnist.train.num_examples // num_batches
|
||||
batches = [mnist.train.next_batch(batch_size) for _ in range(num_batches)]
|
||||
print("Putting MNIST in the object store.")
|
||||
actors = [NetActor(xs, ys) for (xs, ys) in batches]
|
||||
actors = [NetActor.remote(xs, ys) for (xs, ys) in batches]
|
||||
# Initialize the weights for the network to the vector of all zeros.
|
||||
dim = ray.get(actors[0].get_flat_size())
|
||||
dim = ray.get(actors[0].get_flat_size.remote())
|
||||
theta_init = 1e-2 * np.random.normal(size=dim)
|
||||
|
||||
# Use L-BFGS to minimize the loss function.
|
||||
|
||||
@@ -47,7 +47,7 @@ if __name__ == "__main__":
|
||||
preprocessor = AtariPixelPreprocessor()
|
||||
|
||||
print("Using the environment {}.".format(mdp_name))
|
||||
agents = [RemoteAgent(mdp_name, 1, preprocessor, config, False) for _ in range(5)]
|
||||
agents = [RemoteAgent.remote(mdp_name, 1, preprocessor, config, False) for _ in range(5)]
|
||||
agent = Agent(mdp_name, 1, preprocessor, config, True)
|
||||
|
||||
kl_coeff = config["kl_coeff"]
|
||||
@@ -55,7 +55,7 @@ if __name__ == "__main__":
|
||||
for j in range(1000):
|
||||
print("== iteration", j)
|
||||
weights = ray.put(agent.get_weights())
|
||||
[a.load_weights(weights) for a in agents]
|
||||
[a.load_weights.remote(weights) for a in agents]
|
||||
trajectory, total_reward, traj_len_mean = collect_samples(agents, config["timesteps_per_batch"], 0.995, 1.0, 2000)
|
||||
print("total reward is ", total_reward)
|
||||
print("trajectory length mean is ", traj_len_mean)
|
||||
|
||||
@@ -40,4 +40,4 @@ class Agent(object):
|
||||
add_advantage_values(trajectory, gamma, lam, self.reward_filter)
|
||||
return trajectory
|
||||
|
||||
RemoteAgent = ray.actor(Agent)
|
||||
RemoteAgent = ray.remote(Agent)
|
||||
|
||||
@@ -79,7 +79,7 @@ def collect_samples(agents, num_timesteps, gamma, lam, horizon, observation_filt
|
||||
total_rewards = []
|
||||
traj_len_means = []
|
||||
while num_timesteps_so_far < num_timesteps:
|
||||
trajectory_batch = ray.get([agent.compute_trajectory(gamma, lam, horizon) for agent in agents])
|
||||
trajectory_batch = ray.get([agent.compute_trajectory.remote(gamma, lam, horizon) for agent in agents])
|
||||
trajectory = concatenate(trajectory_batch)
|
||||
total_rewards.append(trajectory["raw_rewards"].sum(axis=0).mean() / len(agents))
|
||||
trajectory = flatten(trajectory)
|
||||
|
||||
@@ -44,7 +44,7 @@ def get_data(path, size, dataset):
|
||||
images[int(2 * size / 3):, :],
|
||||
labels)
|
||||
|
||||
@ray.actor(num_gpus=use_gpu)
|
||||
@ray.remote(num_gpus=use_gpu)
|
||||
class ResNetTrainActor(object):
|
||||
def __init__(self, data, dataset, num_gpus):
|
||||
if num_gpus > 0:
|
||||
@@ -89,7 +89,7 @@ class ResNetTrainActor(object):
|
||||
def get_weights(self):
|
||||
return self.model.variables.get_weights()
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class ResNetTestActor(object):
|
||||
def __init__(self, data, dataset, eval_batch_count, eval_dir):
|
||||
hps = resnet_model.HParams(batch_size=100,
|
||||
@@ -162,25 +162,25 @@ def train():
|
||||
train_data = get_data.remote(FLAGS.train_data_path, 50000, FLAGS.dataset)
|
||||
test_data = get_data.remote(FLAGS.eval_data_path, 10000, FLAGS.dataset)
|
||||
if num_gpus > 0:
|
||||
train_actors = [ResNetTrainActor(train_data, FLAGS.dataset, num_gpus) for _ in range(num_gpus)]
|
||||
train_actors = [ResNetTrainActor.remote(train_data, FLAGS.dataset, num_gpus) for _ in range(num_gpus)]
|
||||
else:
|
||||
train_actors = [ResNetTrainActor(train_data, num_gpus)]
|
||||
test_actor = ResNetTestActor(test_data, FLAGS.dataset, FLAGS.eval_batch_count, FLAGS.eval_dir)
|
||||
print('The log files for tensorboard are stored at ip {}.'.format(ray.get(test_actor.get_ip_addr())))
|
||||
train_actors = [ResNetTrainActor.remote(train_data, num_gpus, 0)]
|
||||
test_actor = ResNetTestActor.remote(test_data, FLAGS.dataset, FLAGS.eval_batch_count, FLAGS.eval_dir)
|
||||
print('The log files for tensorboard are stored at ip {}.'.format(ray.get(test_actor.get_ip_addr.remote())))
|
||||
step = 0
|
||||
weight_id = train_actors[0].get_weights()
|
||||
acc_id = test_actor.accuracy(weight_id, step)
|
||||
weight_id = train_actors[0].get_weights.remote()
|
||||
acc_id = test_actor.accuracy.remote(weight_id, step)
|
||||
if num_gpus == 0:
|
||||
num_gpus = 1
|
||||
print("Starting computation.")
|
||||
while True:
|
||||
all_weights = ray.get([actor.compute_steps(weight_id) for actor in train_actors])
|
||||
all_weights = ray.get([actor.compute_steps.remote(weight_id) for actor in train_actors])
|
||||
mean_weights = {k: sum([weights[k] for weights in all_weights]) / num_gpus for k in all_weights[0]}
|
||||
weight_id = ray.put(mean_weights)
|
||||
step += 10
|
||||
if step % 200 == 0:
|
||||
acc = ray.get(acc_id)
|
||||
acc_id = test_actor.accuracy(weight_id, step)
|
||||
acc_id = test_actor.accuracy.remote(weight_id, step)
|
||||
print('Step {0}: {1:.6f}'.format(step - 200, acc))
|
||||
|
||||
def main(_):
|
||||
|
||||
@@ -72,7 +72,7 @@ def policy_backward(eph, epx, epdlogp, model):
|
||||
dW1 = np.dot(dh.T, epx)
|
||||
return {"W1": dW1, "W2": dW2}
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class PongEnv(object):
|
||||
def __init__(self):
|
||||
# Tell numpy to only use one core. If we don't do this, each actor may try
|
||||
@@ -158,14 +158,14 @@ if __name__ == "__main__":
|
||||
grad_buffer = {k: np.zeros_like(v) for k, v in model.items()}
|
||||
# Update the rmsprop memory.
|
||||
rmsprop_cache = {k: np.zeros_like(v) for k, v in model.items()}
|
||||
actors = [PongEnv() for _ in range(batch_size)]
|
||||
actors = [PongEnv.remote() for _ in range(batch_size)]
|
||||
while True:
|
||||
model_id = ray.put(model)
|
||||
actions = []
|
||||
# Launch tasks to compute gradients from multiple rollouts in parallel.
|
||||
start_time = time.time()
|
||||
for i in range(batch_size):
|
||||
action_id = actors[i].compute_gradient(model_id)
|
||||
action_id = actors[i].compute_gradient.remote(model_id)
|
||||
actions.append(action_id)
|
||||
for i in range(batch_size):
|
||||
action_id, actions = ray.wait(actions)
|
||||
|
||||
+107
-93
@@ -269,110 +269,124 @@ def export_actor(actor_id, class_id, actor_method_names, num_cpus, num_gpus,
|
||||
|
||||
|
||||
def actor(*args, **kwargs):
|
||||
def make_actor_decorator(num_cpus=1, num_gpus=0):
|
||||
def make_actor(Class):
|
||||
class_id = random_actor_class_id()
|
||||
# The list exported will have length 0 if the class has not been exported
|
||||
# yet, and length one if it has. This is just implementing a bool, but we
|
||||
# don't use a bool because we need to modify it inside of the NewClass
|
||||
# constructor.
|
||||
exported = []
|
||||
raise Exception("The @ray.actor decorator is deprecated. Instead, please "
|
||||
"use @ray.remote.")
|
||||
|
||||
# The function actor_method_call gets called if somebody tries to call a
|
||||
# method on their local actor stub object.
|
||||
def actor_method_call(actor_id, attr, function_signature, *args,
|
||||
**kwargs):
|
||||
ray.worker.check_connected()
|
||||
ray.worker.check_main_thread()
|
||||
args = signature.extend_args(function_signature, args, kwargs)
|
||||
|
||||
function_id = get_actor_method_function_id(attr)
|
||||
object_ids = ray.worker.global_worker.submit_task(function_id, "",
|
||||
args,
|
||||
actor_id=actor_id)
|
||||
if len(object_ids) == 1:
|
||||
return object_ids[0]
|
||||
elif len(object_ids) > 1:
|
||||
return object_ids
|
||||
def make_actor(Class, num_cpus, num_gpus):
|
||||
class_id = random_actor_class_id()
|
||||
# The list exported will have length 0 if the class has not been exported
|
||||
# yet, and length one if it has. This is just implementing a bool, but we
|
||||
# don't use a bool because we need to modify it inside of the NewClass
|
||||
# constructor.
|
||||
exported = []
|
||||
|
||||
class NewClass(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._ray_actor_id = random_actor_id()
|
||||
self._ray_actor_methods = {
|
||||
k: v for (k, v) in inspect.getmembers(
|
||||
Class, predicate=(lambda x: (inspect.isfunction(x) or
|
||||
inspect.ismethod(x))))}
|
||||
# Extract the signatures of each of the methods. This will be used to
|
||||
# catch some errors if the methods are called with inappropriate
|
||||
# arguments.
|
||||
self._ray_method_signatures = dict()
|
||||
for k, v in self._ray_actor_methods.items():
|
||||
# Print a warning message if the method signature is not supported.
|
||||
# We don't raise an exception because if the actor inherits from a
|
||||
# class that has a method whose signature we don't support, we
|
||||
# there may not be much the user can do about it.
|
||||
signature.check_signature_supported(v, warn=True)
|
||||
self._ray_method_signatures[k] = signature.extract_signature(
|
||||
v, ignore_first=True)
|
||||
# The function actor_method_call gets called if somebody tries to call a
|
||||
# method on their local actor stub object.
|
||||
def actor_method_call(actor_id, attr, function_signature, *args, **kwargs):
|
||||
ray.worker.check_connected()
|
||||
ray.worker.check_main_thread()
|
||||
args = signature.extend_args(function_signature, args, kwargs)
|
||||
|
||||
# Export the actor class if it has not been exported yet.
|
||||
if len(exported) == 0:
|
||||
export_actor_class(class_id, Class, self._ray_actor_methods.keys(),
|
||||
ray.worker.global_worker)
|
||||
exported.append(0)
|
||||
# Export the actor.
|
||||
export_actor(self._ray_actor_id, class_id,
|
||||
self._ray_actor_methods.keys(), num_cpus, num_gpus,
|
||||
ray.worker.global_worker)
|
||||
# Call __init__ as a remote function.
|
||||
if "__init__" in self._ray_actor_methods.keys():
|
||||
actor_method_call(self._ray_actor_id, "__init__",
|
||||
self._ray_method_signatures["__init__"],
|
||||
*args, **kwargs)
|
||||
else:
|
||||
print("WARNING: this object has no __init__ method.")
|
||||
function_id = get_actor_method_function_id(attr)
|
||||
object_ids = ray.worker.global_worker.submit_task(function_id, "", args,
|
||||
actor_id=actor_id)
|
||||
if len(object_ids) == 1:
|
||||
return object_ids[0]
|
||||
elif len(object_ids) > 1:
|
||||
return object_ids
|
||||
|
||||
# Make tab completion work.
|
||||
def __dir__(self):
|
||||
return self._ray_actor_methods
|
||||
class ActorMethod(object):
|
||||
def __init__(self, method_name, actor_id, method_signature):
|
||||
self.method_name = method_name
|
||||
self.actor_id = actor_id
|
||||
self.method_signature = method_signature
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
# The following is needed so we can still access self.actor_methods.
|
||||
if attr in ["_ray_actor_id", "_ray_actor_methods",
|
||||
"_ray_method_signatures"]:
|
||||
return super(NewClass, self).__getattribute__(attr)
|
||||
if attr in self._ray_actor_methods.keys():
|
||||
return lambda *args, **kwargs: actor_method_call(
|
||||
self._ray_actor_id, attr, self._ray_method_signatures[attr],
|
||||
*args, **kwargs)
|
||||
# There is no method with this name, so raise an exception.
|
||||
raise AttributeError("'{}' Actor object has no attribute '{}'"
|
||||
.format(Class, attr))
|
||||
def __call__(self, *args, **kwargs):
|
||||
raise Exception("Actor methods cannot be called directly. Instead "
|
||||
"of running 'object.{}()', try 'object.{}.remote()'."
|
||||
.format(self.method_name, self.method_name))
|
||||
|
||||
def __repr__(self):
|
||||
return "Actor(" + self._ray_actor_id.hex() + ")"
|
||||
def remote(self, *args, **kwargs):
|
||||
return actor_method_call(self.actor_id, self.method_name,
|
||||
self.method_signature, *args, **kwargs)
|
||||
|
||||
return NewClass
|
||||
return make_actor
|
||||
class NewClass(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
raise Exception("Actor classes cannot be instantiated directly. "
|
||||
"Instead of running '{}()', try '{}.remote()'."
|
||||
.format(Class.__name__, Class.__name__))
|
||||
|
||||
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
||||
# In this case, the actor decorator was applied directly to a class
|
||||
# definition.
|
||||
Class = args[0]
|
||||
return make_actor_decorator(num_cpus=1, num_gpus=0)(Class)
|
||||
@classmethod
|
||||
def remote(cls, *args, **kwargs):
|
||||
actor_object = cls.__new__(cls)
|
||||
actor_object._manual_init(*args, **kwargs)
|
||||
return actor_object
|
||||
|
||||
# In this case, the actor decorator is something like @ray.actor(num_gpus=1).
|
||||
if len(args) == 0 and len(kwargs) > 0 and all([key
|
||||
in ["num_cpus", "num_gpus"]
|
||||
for key in kwargs.keys()]):
|
||||
num_cpus = kwargs["num_cpus"] if "num_cpus" in kwargs.keys() else 1
|
||||
num_gpus = kwargs["num_gpus"] if "num_gpus" in kwargs.keys() else 0
|
||||
return make_actor_decorator(num_cpus=num_cpus, num_gpus=num_gpus)
|
||||
def _manual_init(self, *args, **kwargs):
|
||||
self._ray_actor_id = random_actor_id()
|
||||
self._ray_actor_methods = {
|
||||
k: v for (k, v) in inspect.getmembers(
|
||||
Class, predicate=(lambda x: (inspect.isfunction(x) or
|
||||
inspect.ismethod(x))))}
|
||||
# Extract the signatures of each of the methods. This will be used to
|
||||
# catch some errors if the methods are called with inappropriate
|
||||
# arguments.
|
||||
self._ray_method_signatures = dict()
|
||||
for k, v in self._ray_actor_methods.items():
|
||||
# Print a warning message if the method signature is not supported.
|
||||
# We don't raise an exception because if the actor inherits from a
|
||||
# class that has a method whose signature we don't support, we
|
||||
# there may not be much the user can do about it.
|
||||
signature.check_signature_supported(v, warn=True)
|
||||
self._ray_method_signatures[k] = signature.extract_signature(
|
||||
v, ignore_first=True)
|
||||
|
||||
raise Exception("The ray.actor decorator must either be applied with no "
|
||||
"arguments as in '@ray.actor', or it must be applied using "
|
||||
"some of the arguments 'num_cpus' or 'num_gpus' as in "
|
||||
"'ray.actor(num_gpus=1)'.")
|
||||
# Create objects to wrap method invocations. This is done so that we
|
||||
# can invoke methods with actor.method.remote() instead of
|
||||
# actor.method().
|
||||
self._actor_method_invokers = dict()
|
||||
for k, v in self._ray_actor_methods.items():
|
||||
self._actor_method_invokers[k] = ActorMethod(
|
||||
k, self._ray_actor_id, self._ray_method_signatures[k])
|
||||
|
||||
# Export the actor class if it has not been exported yet.
|
||||
if len(exported) == 0:
|
||||
export_actor_class(class_id, Class, self._ray_actor_methods.keys(),
|
||||
ray.worker.global_worker)
|
||||
exported.append(0)
|
||||
# Export the actor.
|
||||
export_actor(self._ray_actor_id, class_id,
|
||||
self._ray_actor_methods.keys(), num_cpus, num_gpus,
|
||||
ray.worker.global_worker)
|
||||
# Call __init__ as a remote function.
|
||||
if "__init__" in self._ray_actor_methods.keys():
|
||||
actor_method_call(self._ray_actor_id, "__init__",
|
||||
self._ray_method_signatures["__init__"],
|
||||
*args, **kwargs)
|
||||
else:
|
||||
print("WARNING: this object has no __init__ method.")
|
||||
|
||||
# Make tab completion work.
|
||||
def __dir__(self):
|
||||
return self._ray_actor_methods
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
# The following is needed so we can still access self.actor_methods.
|
||||
if attr in ["_manual_init", "_ray_actor_id", "_ray_actor_methods",
|
||||
"_actor_method_invokers", "_ray_method_signatures"]:
|
||||
return super(NewClass, self).__getattribute__(attr)
|
||||
if attr in self._ray_actor_methods.keys():
|
||||
return self._actor_method_invokers[attr]
|
||||
# There is no method with this name, so raise an exception.
|
||||
raise AttributeError("'{}' Actor object has no attribute '{}'"
|
||||
.format(Class, attr))
|
||||
|
||||
def __repr__(self):
|
||||
return "Actor(" + self._ray_actor_id.hex() + ")"
|
||||
|
||||
return NewClass
|
||||
|
||||
|
||||
ray.worker.global_worker.fetch_and_register_actor = fetch_and_register_actor
|
||||
ray.worker.global_worker.make_actor = make_actor
|
||||
|
||||
+12
-1
@@ -448,6 +448,7 @@ class Worker(object):
|
||||
self.cached_remote_functions = []
|
||||
self.cached_functions_to_run = []
|
||||
self.fetch_and_register_actor = None
|
||||
self.make_actor = None
|
||||
self.actors = {}
|
||||
# Use a defaultdict for the actor counts. If this is accessed with a
|
||||
# missing key, the default value of 0 is returned, and that key value pair
|
||||
@@ -2105,7 +2106,15 @@ def remote(*args, **kwargs):
|
||||
worker = global_worker
|
||||
|
||||
def make_remote_decorator(num_return_vals, num_cpus, num_gpus, func_id=None):
|
||||
def remote_decorator(func):
|
||||
def remote_decorator(func_or_class):
|
||||
if inspect.isfunction(func_or_class):
|
||||
return remote_function_decorator(func_or_class)
|
||||
if inspect.isclass(func_or_class):
|
||||
return worker.make_actor(func_or_class, num_cpus, num_gpus)
|
||||
raise Exception("The @ray.remote decorator must be applied to either a "
|
||||
"function or to a class.")
|
||||
|
||||
def remote_function_decorator(func):
|
||||
func_name = "{}.{}".format(func.__module__, func.__name__)
|
||||
if func_id is None:
|
||||
function_id = compute_function_id(func_name, func)
|
||||
@@ -2195,6 +2204,8 @@ def remote(*args, **kwargs):
|
||||
assert len(args) == 0 and ("num_return_vals" in kwargs or
|
||||
"num_cpus" in kwargs or
|
||||
"num_gpus" in kwargs), error_string
|
||||
for key in kwargs:
|
||||
assert key in ["num_return_vals", "num_cpus", "num_gpus"], error_string
|
||||
assert "function_id" not in kwargs
|
||||
return make_remote_decorator(num_return_vals, num_cpus, num_gpus)
|
||||
|
||||
|
||||
+137
-131
@@ -16,7 +16,7 @@ class ActorAPI(unittest.TestCase):
|
||||
def testKeywordArgs(self):
|
||||
ray.init(num_workers=0, driver_mode=ray.SILENT_MODE)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, arg0, arg1=1, arg2="a"):
|
||||
self.arg0 = arg0
|
||||
@@ -26,43 +26,45 @@ class ActorAPI(unittest.TestCase):
|
||||
def get_values(self, arg0, arg1=2, arg2="b"):
|
||||
return self.arg0 + arg0, self.arg1 + arg1, self.arg2 + arg2
|
||||
|
||||
actor = Actor(0)
|
||||
self.assertEqual(ray.get(actor.get_values(1)), (1, 3, "ab"))
|
||||
actor = Actor.remote(0)
|
||||
self.assertEqual(ray.get(actor.get_values.remote(1)), (1, 3, "ab"))
|
||||
|
||||
actor = Actor(1, 2)
|
||||
self.assertEqual(ray.get(actor.get_values(2, 3)), (3, 5, "ab"))
|
||||
actor = Actor.remote(1, 2)
|
||||
self.assertEqual(ray.get(actor.get_values.remote(2, 3)), (3, 5, "ab"))
|
||||
|
||||
actor = Actor(1, 2, "c")
|
||||
self.assertEqual(ray.get(actor.get_values(2, 3, "d")), (3, 5, "cd"))
|
||||
actor = Actor.remote(1, 2, "c")
|
||||
self.assertEqual(ray.get(actor.get_values.remote(2, 3, "d")), (3, 5, "cd"))
|
||||
|
||||
actor = Actor(1, arg2="c")
|
||||
self.assertEqual(ray.get(actor.get_values(0, arg2="d")), (1, 3, "cd"))
|
||||
self.assertEqual(ray.get(actor.get_values(0, arg2="d", arg1=0)),
|
||||
actor = Actor.remote(1, arg2="c")
|
||||
self.assertEqual(ray.get(actor.get_values.remote(0, arg2="d")),
|
||||
(1, 3, "cd"))
|
||||
self.assertEqual(ray.get(actor.get_values.remote(0, arg2="d", arg1=0)),
|
||||
(1, 1, "cd"))
|
||||
|
||||
actor = Actor(1, arg2="c", arg1=2)
|
||||
self.assertEqual(ray.get(actor.get_values(0, arg2="d")), (1, 4, "cd"))
|
||||
self.assertEqual(ray.get(actor.get_values(0, arg2="d", arg1=0)),
|
||||
actor = Actor.remote(1, arg2="c", arg1=2)
|
||||
self.assertEqual(ray.get(actor.get_values.remote(0, arg2="d")),
|
||||
(1, 4, "cd"))
|
||||
self.assertEqual(ray.get(actor.get_values.remote(0, arg2="d", arg1=0)),
|
||||
(1, 2, "cd"))
|
||||
|
||||
# Make sure we get an exception if the constructor is called incorrectly.
|
||||
with self.assertRaises(Exception):
|
||||
actor = Actor()
|
||||
actor = Actor.remote()
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
actor = Actor(0, 1, 2, arg3=3)
|
||||
actor = Actor.remote(0, 1, 2, arg3=3)
|
||||
|
||||
# Make sure we get an exception if the method is called incorrectly.
|
||||
actor = Actor(1)
|
||||
actor = Actor.remote(1)
|
||||
with self.assertRaises(Exception):
|
||||
ray.get(actor.get_values())
|
||||
ray.get(actor.get_values.remote())
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
def testVariableNumberOfArgs(self):
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, arg0, arg1=1, *args):
|
||||
self.arg0 = arg0
|
||||
@@ -72,21 +74,21 @@ class ActorAPI(unittest.TestCase):
|
||||
def get_values(self, arg0, arg1=2, *args):
|
||||
return self.arg0 + arg0, self.arg1 + arg1, self.args, args
|
||||
|
||||
actor = Actor(0)
|
||||
self.assertEqual(ray.get(actor.get_values(1)), (1, 3, (), ()))
|
||||
actor = Actor.remote(0)
|
||||
self.assertEqual(ray.get(actor.get_values.remote(1)), (1, 3, (), ()))
|
||||
|
||||
actor = Actor(1, 2)
|
||||
self.assertEqual(ray.get(actor.get_values(2, 3)), (3, 5, (), ()))
|
||||
actor = Actor.remote(1, 2)
|
||||
self.assertEqual(ray.get(actor.get_values.remote(2, 3)), (3, 5, (), ()))
|
||||
|
||||
actor = Actor(1, 2, "c")
|
||||
self.assertEqual(ray.get(actor.get_values(2, 3, "d")),
|
||||
actor = Actor.remote(1, 2, "c")
|
||||
self.assertEqual(ray.get(actor.get_values.remote(2, 3, "d")),
|
||||
(3, 5, ("c",), ("d",)))
|
||||
|
||||
actor = Actor(1, 2, "a", "b", "c", "d")
|
||||
self.assertEqual(ray.get(actor.get_values(2, 3, 1, 2, 3, 4)),
|
||||
actor = Actor.remote(1, 2, "a", "b", "c", "d")
|
||||
self.assertEqual(ray.get(actor.get_values.remote(2, 3, 1, 2, 3, 4)),
|
||||
(3, 5, ("a", "b", "c", "d"), (1, 2, 3, 4)))
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, *args):
|
||||
self.args = args
|
||||
@@ -94,19 +96,19 @@ class ActorAPI(unittest.TestCase):
|
||||
def get_values(self, *args):
|
||||
return self.args, args
|
||||
|
||||
a = Actor()
|
||||
self.assertEqual(ray.get(a.get_values()), ((), ()))
|
||||
a = Actor(1)
|
||||
self.assertEqual(ray.get(a.get_values(2)), ((1,), (2,)))
|
||||
a = Actor(1, 2)
|
||||
self.assertEqual(ray.get(a.get_values(3, 4)), ((1, 2), (3, 4)))
|
||||
a = Actor.remote()
|
||||
self.assertEqual(ray.get(a.get_values.remote()), ((), ()))
|
||||
a = Actor.remote(1)
|
||||
self.assertEqual(ray.get(a.get_values.remote(2)), ((1,), (2,)))
|
||||
a = Actor.remote(1, 2)
|
||||
self.assertEqual(ray.get(a.get_values.remote(3, 4)), ((1, 2), (3, 4)))
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
def testNoArgs(self):
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@@ -114,8 +116,8 @@ class ActorAPI(unittest.TestCase):
|
||||
def get_values(self):
|
||||
pass
|
||||
|
||||
actor = Actor()
|
||||
self.assertEqual(ray.get(actor.get_values()), None)
|
||||
actor = Actor.remote()
|
||||
self.assertEqual(ray.get(actor.get_values.remote()), None)
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -123,13 +125,13 @@ class ActorAPI(unittest.TestCase):
|
||||
# If no __init__ method is provided, that should not be a problem.
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def get_values(self):
|
||||
pass
|
||||
|
||||
actor = Actor()
|
||||
self.assertEqual(ray.get(actor.get_values()), None)
|
||||
actor = Actor.remote()
|
||||
self.assertEqual(ray.get(actor.get_values.remote()), None)
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -141,7 +143,7 @@ class ActorAPI(unittest.TestCase):
|
||||
self.x = x
|
||||
ray.register_class(Foo)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, f2):
|
||||
self.f1 = Foo(1)
|
||||
@@ -153,11 +155,11 @@ class ActorAPI(unittest.TestCase):
|
||||
def get_values2(self, f3):
|
||||
return self.f1, self.f2, f3
|
||||
|
||||
actor = Actor(Foo(2))
|
||||
results1 = ray.get(actor.get_values1())
|
||||
actor = Actor.remote(Foo(2))
|
||||
results1 = ray.get(actor.get_values1.remote())
|
||||
self.assertEqual(results1[0].x, 1)
|
||||
self.assertEqual(results1[1].x, 2)
|
||||
results2 = ray.get(actor.get_values2(Foo(3)))
|
||||
results2 = ray.get(actor.get_values2.remote(Foo(3)))
|
||||
self.assertEqual(results2[0].x, 1)
|
||||
self.assertEqual(results2[1].x, 2)
|
||||
self.assertEqual(results2[2].x, 3)
|
||||
@@ -173,39 +175,39 @@ class ActorAPI(unittest.TestCase):
|
||||
|
||||
# This is an invalid way of using the actor decorator.
|
||||
with self.assertRaises(Exception):
|
||||
@ray.actor()
|
||||
@ray.remote()
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# This is an invalid way of using the actor decorator.
|
||||
with self.assertRaises(Exception):
|
||||
@ray.actor(invalid_kwarg=0) # noqa: F811
|
||||
@ray.remote(invalid_kwarg=0) # noqa: F811
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# This is an invalid way of using the actor decorator.
|
||||
with self.assertRaises(Exception):
|
||||
@ray.actor(num_cpus=0, invalid_kwarg=0) # noqa: F811
|
||||
@ray.remote(num_cpus=0, invalid_kwarg=0) # noqa: F811
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# This is a valid way of using the decorator.
|
||||
@ray.actor(num_cpus=1) # noqa: F811
|
||||
@ray.remote(num_cpus=1) # noqa: F811
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# This is a valid way of using the decorator.
|
||||
@ray.actor(num_gpus=1) # noqa: F811
|
||||
@ray.remote(num_gpus=1) # noqa: F811
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
# This is a valid way of using the decorator.
|
||||
@ray.actor(num_cpus=1, num_gpus=1) # noqa: F811
|
||||
@ray.remote(num_cpus=1, num_gpus=1) # noqa: F811
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@@ -215,7 +217,7 @@ class ActorAPI(unittest.TestCase):
|
||||
def testRandomIDGeneration(self):
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Foo(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@@ -224,10 +226,10 @@ class ActorAPI(unittest.TestCase):
|
||||
# actor IDs.
|
||||
np.random.seed(1234)
|
||||
random.seed(1234)
|
||||
f1 = Foo()
|
||||
f1 = Foo.remote()
|
||||
np.random.seed(1234)
|
||||
random.seed(1234)
|
||||
f2 = Foo()
|
||||
f2 = Foo.remote()
|
||||
|
||||
self.assertNotEqual(f1._ray_actor_id.id(), f2._ray_actor_id.id())
|
||||
|
||||
@@ -239,7 +241,7 @@ class ActorMethods(unittest.TestCase):
|
||||
def testDefineActor(self):
|
||||
ray.init()
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Test(object):
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
@@ -247,15 +249,19 @@ class ActorMethods(unittest.TestCase):
|
||||
def f(self, y):
|
||||
return self.x + y
|
||||
|
||||
t = Test(2)
|
||||
self.assertEqual(ray.get(t.f(1)), 3)
|
||||
t = Test.remote(2)
|
||||
self.assertEqual(ray.get(t.f.remote(1)), 3)
|
||||
|
||||
# Make sure that calling an actor method directly raises an exception.
|
||||
with self.assertRaises(Exception):
|
||||
t.f(1)
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
def testActorState(self):
|
||||
ray.init()
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Counter(object):
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
@@ -266,14 +272,14 @@ class ActorMethods(unittest.TestCase):
|
||||
def value(self):
|
||||
return self.value
|
||||
|
||||
c1 = Counter()
|
||||
c1.increase()
|
||||
self.assertEqual(ray.get(c1.value()), 1)
|
||||
c1 = Counter.remote()
|
||||
c1.increase.remote()
|
||||
self.assertEqual(ray.get(c1.value.remote()), 1)
|
||||
|
||||
c2 = Counter()
|
||||
c2.increase()
|
||||
c2.increase()
|
||||
self.assertEqual(ray.get(c2.value()), 2)
|
||||
c2 = Counter.remote()
|
||||
c2.increase.remote()
|
||||
c2.increase.remote()
|
||||
self.assertEqual(ray.get(c2.value.remote()), 2)
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -281,7 +287,7 @@ class ActorMethods(unittest.TestCase):
|
||||
# Create a bunch of actors and call a bunch of methods on all of them.
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Counter(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
@@ -296,11 +302,11 @@ class ActorMethods(unittest.TestCase):
|
||||
num_actors = 20
|
||||
num_increases = 50
|
||||
# Create multiple actors.
|
||||
actors = [Counter(i) for i in range(num_actors)]
|
||||
actors = [Counter.remote(i) for i in range(num_actors)]
|
||||
results = []
|
||||
# Call each actor's method a bunch of times.
|
||||
for i in range(num_actors):
|
||||
results += [actors[i].increase() for _ in range(num_increases)]
|
||||
results += [actors[i].increase.remote() for _ in range(num_increases)]
|
||||
result_values = ray.get(results)
|
||||
for i in range(num_actors):
|
||||
self.assertEqual(
|
||||
@@ -308,12 +314,12 @@ class ActorMethods(unittest.TestCase):
|
||||
list(range(i + 1, num_increases + i + 1)))
|
||||
|
||||
# Reset the actor values.
|
||||
[actor.reset() for actor in actors]
|
||||
[actor.reset.remote() for actor in actors]
|
||||
|
||||
# Interweave the method calls on the different actors.
|
||||
results = []
|
||||
for j in range(num_increases):
|
||||
results += [actor.increase() for actor in actors]
|
||||
results += [actor.increase.remote() for actor in actors]
|
||||
result_values = ray.get(results)
|
||||
for j in range(num_increases):
|
||||
self.assertEqual(result_values[(num_actors * j):(num_actors * (j + 1))],
|
||||
@@ -340,7 +346,7 @@ class ActorNesting(unittest.TestCase):
|
||||
def g(x):
|
||||
return ray.get(f.remote(x))
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
@@ -360,16 +366,16 @@ class ActorNesting(unittest.TestCase):
|
||||
def h(self, object_ids):
|
||||
return ray.get(object_ids)
|
||||
|
||||
actor = Actor(1)
|
||||
values = ray.get(actor.get_values())
|
||||
actor = Actor.remote(1)
|
||||
values = ray.get(actor.get_values.remote())
|
||||
self.assertEqual(values[0], 1)
|
||||
self.assertEqual(values[1], val2)
|
||||
self.assertEqual(ray.get(values[2]), list(range(1, 6)))
|
||||
self.assertEqual(values[3], list(range(1, 6)))
|
||||
|
||||
self.assertEqual(ray.get(ray.get(actor.f())), list(range(1, 6)))
|
||||
self.assertEqual(ray.get(actor.g()), list(range(1, 6)))
|
||||
self.assertEqual(ray.get(actor.h([f.remote(i) for i in range(5)])),
|
||||
self.assertEqual(ray.get(ray.get(actor.f.remote())), list(range(1, 6)))
|
||||
self.assertEqual(ray.get(actor.g.remote()), list(range(1, 6)))
|
||||
self.assertEqual(ray.get(actor.h.remote([f.remote(i) for i in range(5)])),
|
||||
list(range(1, 6)))
|
||||
|
||||
ray.worker.cleanup()
|
||||
@@ -378,27 +384,27 @@ class ActorNesting(unittest.TestCase):
|
||||
# Make sure we can use remote funtions within actors.
|
||||
ray.init(num_cpus=10)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor1(object):
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
def new_actor(self, z):
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor2(object):
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
def get_value(self):
|
||||
return self.x
|
||||
self.actor2 = Actor2(z)
|
||||
self.actor2 = Actor2.remote(z)
|
||||
|
||||
def get_values(self, z):
|
||||
self.new_actor(z)
|
||||
return self.x, ray.get(self.actor2.get_value())
|
||||
return self.x, ray.get(self.actor2.get_value.remote())
|
||||
|
||||
actor1 = Actor1(3)
|
||||
self.assertEqual(ray.get(actor1.get_values(5)), (3, 5))
|
||||
actor1 = Actor1.remote(3)
|
||||
self.assertEqual(ray.get(actor1.get_values.remote(5)), (3, 5))
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -408,14 +414,14 @@ class ActorNesting(unittest.TestCase):
|
||||
# # Make sure we can use remote funtions within actors.
|
||||
# ray.init(num_cpus=10)
|
||||
#
|
||||
# @ray.actor
|
||||
# @ray.remote
|
||||
# class Actor1(object):
|
||||
# def __init__(self, x):
|
||||
# self.x = x
|
||||
# def get_val(self):
|
||||
# return self.x
|
||||
#
|
||||
# @ray.actor
|
||||
# @ray.remote
|
||||
# class Actor2(object):
|
||||
# def __init__(self, x, y):
|
||||
# self.x = x
|
||||
@@ -435,15 +441,15 @@ class ActorNesting(unittest.TestCase):
|
||||
|
||||
@ray.remote
|
||||
def f(x, n):
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor1(object):
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
def get_value(self):
|
||||
return self.x
|
||||
actor = Actor1(x)
|
||||
return ray.get([actor.get_value() for _ in range(n)])
|
||||
actor = Actor1.remote(x)
|
||||
return ray.get([actor.get_value.remote() for _ in range(n)])
|
||||
|
||||
self.assertEqual(ray.get(f.remote(3, 1)), [3])
|
||||
self.assertEqual(ray.get([f.remote(i, 20) for i in range(10)]),
|
||||
@@ -456,7 +462,7 @@ class ActorNesting(unittest.TestCase):
|
||||
# # Make sure we can create and use actors within remote funtions.
|
||||
# ray.init(num_cpus=10)
|
||||
#
|
||||
# @ray.actor
|
||||
# @ray.remote
|
||||
# class Actor1(object):
|
||||
# def __init__(self, x):
|
||||
# self.x = x
|
||||
@@ -487,7 +493,7 @@ class ActorNesting(unittest.TestCase):
|
||||
|
||||
@ray.remote
|
||||
def g():
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
# This should use the last version of f.
|
||||
@@ -496,8 +502,8 @@ class ActorNesting(unittest.TestCase):
|
||||
def get_val(self):
|
||||
return self.x
|
||||
|
||||
actor = Actor()
|
||||
return ray.get(actor.get_val())
|
||||
actor = Actor.remote()
|
||||
return ray.get(actor.get_val.remote())
|
||||
|
||||
self.assertEqual(ray.get(g.remote()), num_remote_functions - 1)
|
||||
|
||||
@@ -521,7 +527,7 @@ class ActorInheritance(unittest.TestCase):
|
||||
def g(self, y):
|
||||
return self.x + y
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(Foo):
|
||||
def __init__(self, x):
|
||||
Foo.__init__(self, x)
|
||||
@@ -529,9 +535,9 @@ class ActorInheritance(unittest.TestCase):
|
||||
def get_value(self):
|
||||
return self.f()
|
||||
|
||||
actor = Actor(1)
|
||||
self.assertEqual(ray.get(actor.get_value()), 1)
|
||||
self.assertEqual(ray.get(actor.g(5)), 6)
|
||||
actor = Actor.remote(1)
|
||||
self.assertEqual(ray.get(actor.get_value.remote()), 1)
|
||||
self.assertEqual(ray.get(actor.g.remote(5)), 6)
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -542,12 +548,12 @@ class ActorSchedulingProperties(unittest.TestCase):
|
||||
# Make sure that regular remote functions are not scheduled on actors.
|
||||
ray.init(num_workers=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
Actor()
|
||||
Actor.remote()
|
||||
|
||||
@ray.remote
|
||||
def f():
|
||||
@@ -568,13 +574,13 @@ class ActorsOnMultipleNodes(unittest.TestCase):
|
||||
def testActorsOnNodesWithNoCPUs(self):
|
||||
ray.init(num_cpus=0)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Foo(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
Foo()
|
||||
Foo.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -583,7 +589,7 @@ class ActorsOnMultipleNodes(unittest.TestCase):
|
||||
ray.worker._init(start_ray_local=True, num_workers=0,
|
||||
num_local_schedulers=num_local_schedulers)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@@ -599,8 +605,8 @@ class ActorsOnMultipleNodes(unittest.TestCase):
|
||||
# Make sure that actors are spread between the local schedulers.
|
||||
attempts = 0
|
||||
while attempts < num_attempts:
|
||||
actors = [Actor1() for _ in range(num_actors)]
|
||||
locations = ray.get([actor.get_location() for actor in actors])
|
||||
actors = [Actor1.remote() for _ in range(num_actors)]
|
||||
locations = ray.get([actor.get_location.remote() for actor in actors])
|
||||
names = set(locations)
|
||||
counts = [locations.count(name) for name in names]
|
||||
print("Counts are {}.".format(counts))
|
||||
@@ -614,7 +620,7 @@ class ActorsOnMultipleNodes(unittest.TestCase):
|
||||
results = []
|
||||
for _ in range(1000):
|
||||
index = np.random.randint(num_actors)
|
||||
results.append(actors[index].get_location())
|
||||
results.append(actors[index].get_location.remote())
|
||||
ray.get(results)
|
||||
|
||||
ray.worker.cleanup()
|
||||
@@ -630,7 +636,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
num_local_schedulers=num_local_schedulers,
|
||||
num_gpus=(num_local_schedulers * [num_gpus_per_scheduler]))
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -641,10 +647,10 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
tuple(self.gpu_ids))
|
||||
|
||||
# Create one actor per GPU.
|
||||
actors = [Actor1() for _
|
||||
actors = [Actor1.remote() for _
|
||||
in range(num_local_schedulers * num_gpus_per_scheduler)]
|
||||
# Make sure that no two actors are assigned to the same GPU.
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids()
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids.remote()
|
||||
for actor in actors])
|
||||
node_names = set([location for location, gpu_id in locations_and_ids])
|
||||
self.assertEqual(len(node_names), num_local_schedulers)
|
||||
@@ -656,7 +662,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
# Creating a new actor should fail because all of the GPUs are being used.
|
||||
with self.assertRaises(Exception):
|
||||
Actor1()
|
||||
Actor1.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -668,7 +674,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
num_local_schedulers=num_local_schedulers,
|
||||
num_gpus=(num_local_schedulers * [num_gpus_per_scheduler]))
|
||||
|
||||
@ray.actor(num_gpus=2)
|
||||
@ray.remote(num_gpus=2)
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -678,9 +684,9 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
tuple(self.gpu_ids))
|
||||
|
||||
# Create some actors.
|
||||
actors = [Actor1() for _ in range(num_local_schedulers * 2)]
|
||||
actors = [Actor1.remote() for _ in range(num_local_schedulers * 2)]
|
||||
# Make sure that no two actors are assigned to the same GPU.
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids()
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids.remote()
|
||||
for actor in actors])
|
||||
node_names = set([location for location, gpu_id in locations_and_ids])
|
||||
self.assertEqual(len(node_names), num_local_schedulers)
|
||||
@@ -694,10 +700,10 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
# Creating a new actor should fail because all of the GPUs are being used.
|
||||
with self.assertRaises(Exception):
|
||||
Actor1()
|
||||
Actor1.remote()
|
||||
|
||||
# We should be able to create more actors that use only a single GPU.
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor2(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -707,9 +713,9 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
tuple(self.gpu_ids))
|
||||
|
||||
# Create some actors.
|
||||
actors = [Actor2() for _ in range(num_local_schedulers)]
|
||||
actors = [Actor2.remote() for _ in range(num_local_schedulers)]
|
||||
# Make sure that no two actors are assigned to the same GPU.
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids()
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids.remote()
|
||||
for actor in actors])
|
||||
self.assertEqual(node_names,
|
||||
set([location for location, gpu_id in locations_and_ids]))
|
||||
@@ -721,7 +727,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
# Creating a new actor should fail because all of the GPUs are being used.
|
||||
with self.assertRaises(Exception):
|
||||
Actor2()
|
||||
Actor2.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -731,7 +737,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
ray.worker._init(start_ray_local=True, num_workers=0,
|
||||
num_local_schedulers=3, num_gpus=[0, 5, 10])
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -741,9 +747,9 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
tuple(self.gpu_ids))
|
||||
|
||||
# Create some actors.
|
||||
actors = [Actor1() for _ in range(0 + 5 + 10)]
|
||||
actors = [Actor1.remote() for _ in range(0 + 5 + 10)]
|
||||
# Make sure that no two actors are assigned to the same GPU.
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids()
|
||||
locations_and_ids = ray.get([actor.get_location_and_ids.remote()
|
||||
for actor in actors])
|
||||
node_names = set([location for location, gpu_id in locations_and_ids])
|
||||
self.assertEqual(len(node_names), 2)
|
||||
@@ -756,7 +762,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
# Creating a new actor should fail because all of the GPUs are being used.
|
||||
with self.assertRaises(Exception):
|
||||
Actor1()
|
||||
Actor1.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -770,7 +776,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
@ray.remote
|
||||
def create_actors(n):
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -780,12 +786,12 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
tuple(self.gpu_ids))
|
||||
# Create n actors.
|
||||
for _ in range(n):
|
||||
Actor()
|
||||
Actor.remote()
|
||||
|
||||
ray.get([create_actors.remote(num_gpus_per_scheduler)
|
||||
for _ in range(num_local_schedulers)])
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -796,7 +802,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
|
||||
# All the GPUs should be used up now.
|
||||
with self.assertRaises(Exception):
|
||||
Actor()
|
||||
Actor.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
@@ -844,7 +850,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
return (ray.worker.global_worker.plasma_client.store_socket_name,
|
||||
tuple(gpu_ids), [t1, t2])
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -883,8 +889,8 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
check_intervals_non_overlapping(locations_to_intervals[locations])
|
||||
|
||||
# Create an actor that uses a GPU.
|
||||
a = Actor1()
|
||||
actor_location = ray.get(a.get_location_and_ids())
|
||||
a = Actor1.remote()
|
||||
actor_location = ray.get(a.get_location_and_ids.remote())
|
||||
actor_location = (actor_location[0], actor_location[1][0])
|
||||
# This check makes sure that actor_location is formatted the same way that
|
||||
# the keys of locations_to_intervals are formatted.
|
||||
@@ -903,8 +909,8 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
self.assertNotIn(actor_location, locations_to_intervals)
|
||||
|
||||
# Create several more actors that use GPUs.
|
||||
actors = [Actor1() for _ in range(3)]
|
||||
actor_locations = ray.get([actor.get_location_and_ids()
|
||||
actors = [Actor1.remote() for _ in range(3)]
|
||||
actor_locations = ray.get([actor.get_location_and_ids.remote()
|
||||
for actor in actors])
|
||||
|
||||
# Run a bunch of GPU tasks.
|
||||
@@ -922,11 +928,11 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
self.assertNotIn(location, locations_to_intervals)
|
||||
|
||||
# Create more actors to fill up all the GPUs.
|
||||
more_actors = [Actor1() for _ in
|
||||
more_actors = [Actor1.remote() for _ in
|
||||
range(num_local_schedulers *
|
||||
num_gpus_per_scheduler - 1 - 3)]
|
||||
# Wait for the actors to finish being created.
|
||||
ray.get([actor.get_location_and_ids() for actor in more_actors])
|
||||
ray.get([actor.get_location_and_ids.remote() for actor in more_actors])
|
||||
|
||||
# Now if we run some GPU tasks, they should not be scheduled.
|
||||
results = [f1.remote() for _ in range(30)]
|
||||
@@ -947,7 +953,7 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
assert len(gpu_ids) == 1
|
||||
return gpu_ids[0]
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor(object):
|
||||
def __init__(self):
|
||||
self.gpu_ids = ray.get_gpu_ids()
|
||||
@@ -960,8 +966,8 @@ class ActorsWithGPUs(unittest.TestCase):
|
||||
results = []
|
||||
for _ in range(5):
|
||||
results.append(f.remote())
|
||||
a = Actor()
|
||||
results.append(a.get_gpu_id())
|
||||
a = Actor.remote()
|
||||
results.append(a.get_gpu_id.remote())
|
||||
|
||||
gpu_ids = ray.get(results)
|
||||
self.assertEqual(set(gpu_ids), set(range(10)))
|
||||
|
||||
+14
-12
@@ -209,7 +209,7 @@ def temporary_helper_function():
|
||||
|
||||
# Define an actor that closes over this temporary module. This should fail
|
||||
# when it is unpickled.
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Foo(object):
|
||||
def __init__(self):
|
||||
self.x = module.temporary_python_file()
|
||||
@@ -221,7 +221,7 @@ def temporary_helper_function():
|
||||
self.assertEqual(len(ray.error_info()), 0)
|
||||
|
||||
# Create an actor.
|
||||
foo = Foo()
|
||||
foo = Foo.remote()
|
||||
|
||||
# Wait for the error to arrive.
|
||||
wait_for_errors(b"register_actor", 1)
|
||||
@@ -235,7 +235,7 @@ def temporary_helper_function():
|
||||
# Check that if we try to get the function it throws an exception and does
|
||||
# not hang.
|
||||
with self.assertRaises(Exception):
|
||||
ray.get(foo.get_val())
|
||||
ray.get(foo.get_val.remote())
|
||||
|
||||
# Wait for the error from when the call to get_val.
|
||||
wait_for_errors(b"task", 2)
|
||||
@@ -257,7 +257,7 @@ class ActorTest(unittest.TestCase):
|
||||
error_message1 = "actor constructor failed"
|
||||
error_message2 = "actor method failed"
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class FailedActor(object):
|
||||
def __init__(self):
|
||||
raise Exception(error_message1)
|
||||
@@ -268,7 +268,7 @@ class ActorTest(unittest.TestCase):
|
||||
def fail_method(self):
|
||||
raise Exception(error_message2)
|
||||
|
||||
a = FailedActor()
|
||||
a = FailedActor.remote()
|
||||
|
||||
# Make sure that we get errors from a failed constructor.
|
||||
wait_for_errors(b"task", 1)
|
||||
@@ -277,7 +277,7 @@ class ActorTest(unittest.TestCase):
|
||||
ray.error_info()[0][b"message"].decode("ascii"))
|
||||
|
||||
# Make sure that we get errors from a failed method.
|
||||
a.fail_method()
|
||||
a.fail_method.remote()
|
||||
wait_for_errors(b"task", 2)
|
||||
self.assertEqual(len(ray.error_info()), 2)
|
||||
self.assertIn(error_message2,
|
||||
@@ -288,7 +288,7 @@ class ActorTest(unittest.TestCase):
|
||||
def testIncorrectMethodCalls(self):
|
||||
ray.init(num_workers=0, driver_mode=ray.SILENT_MODE)
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor(object):
|
||||
def __init__(self, missing_variable_name):
|
||||
pass
|
||||
@@ -300,25 +300,27 @@ class ActorTest(unittest.TestCase):
|
||||
|
||||
# Create an actor with too few arguments.
|
||||
with self.assertRaises(Exception):
|
||||
a = Actor()
|
||||
a = Actor.remote()
|
||||
|
||||
# Create an actor with too many arguments.
|
||||
with self.assertRaises(Exception):
|
||||
a = Actor(1, 2)
|
||||
a = Actor.remote(1, 2)
|
||||
|
||||
# Create an actor the correct number of arguments.
|
||||
a = Actor(1)
|
||||
a = Actor.remote(1)
|
||||
|
||||
# Call a method with too few arguments.
|
||||
with self.assertRaises(Exception):
|
||||
a.get_val()
|
||||
a.get_val.remote()
|
||||
|
||||
# Call a method with too many arguments.
|
||||
with self.assertRaises(Exception):
|
||||
a.get_val(1, 2)
|
||||
a.get_val.remote(1, 2)
|
||||
# Call a method that doesn't exist.
|
||||
with self.assertRaises(AttributeError):
|
||||
a.nonexistent_method()
|
||||
with self.assertRaises(AttributeError):
|
||||
a.nonexistent_method.remote()
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ max_concurrent_drivers = 15
|
||||
num_gpus_per_driver = 5
|
||||
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor1(object):
|
||||
def __init__(self):
|
||||
assert len(ray.get_gpu_ids()) == 1
|
||||
@@ -50,7 +50,7 @@ def driver(redis_address, driver_index):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
actor = actor_class()
|
||||
actor = actor_class.remote()
|
||||
except Exception as e:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
@@ -64,7 +64,7 @@ def driver(redis_address, driver_index):
|
||||
actors_one_gpu.append(try_to_create_actor(Actor1))
|
||||
|
||||
for _ in range(100):
|
||||
ray.get([actor.check_ids() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_one_gpu])
|
||||
|
||||
_broadcast_event("DRIVER_{}_DONE".format(driver_index), redis_address)
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def long_running_task(driver_index, task_index, redis_address):
|
||||
num_long_running_tasks_per_driver = 2
|
||||
|
||||
|
||||
@ray.actor
|
||||
@ray.remote
|
||||
class Actor0(object):
|
||||
def __init__(self, driver_index, actor_index, redis_address):
|
||||
_broadcast_event(actor_event_name(driver_index, actor_index),
|
||||
@@ -77,7 +77,7 @@ class Actor0(object):
|
||||
time.sleep(100)
|
||||
|
||||
|
||||
@ray.actor(num_gpus=1)
|
||||
@ray.remote(num_gpus=1)
|
||||
class Actor1(object):
|
||||
def __init__(self, driver_index, actor_index, redis_address):
|
||||
_broadcast_event(actor_event_name(driver_index, actor_index),
|
||||
@@ -94,7 +94,7 @@ class Actor1(object):
|
||||
time.sleep(100)
|
||||
|
||||
|
||||
@ray.actor(num_gpus=2)
|
||||
@ray.remote(num_gpus=2)
|
||||
class Actor2(object):
|
||||
def __init__(self, driver_index, actor_index, redis_address):
|
||||
_broadcast_event(actor_event_name(driver_index, actor_index),
|
||||
@@ -128,18 +128,19 @@ def driver_0(redis_address, driver_index):
|
||||
long_running_task.remote(driver_index, i, redis_address)
|
||||
|
||||
# Create some actors that require one GPU.
|
||||
actors_one_gpu = [Actor1(driver_index, i, redis_address) for i in range(5)]
|
||||
actors_one_gpu = [Actor1.remote(driver_index, i, redis_address)
|
||||
for i in range(5)]
|
||||
# Create some actors that don't require any GPUs.
|
||||
actors_no_gpus = [Actor0(driver_index, 5 + i, redis_address)
|
||||
actors_no_gpus = [Actor0.remote(driver_index, 5 + i, redis_address)
|
||||
for i in range(5)]
|
||||
|
||||
for _ in range(1000):
|
||||
ray.get([actor.check_ids() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids() for actor in actors_no_gpus])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_no_gpus])
|
||||
|
||||
# Start a long-running method on one actor and make sure this doesn't affect
|
||||
# anything.
|
||||
actors_no_gpus[0].long_running_method()
|
||||
actors_no_gpus[0].long_running_method.remote()
|
||||
|
||||
_broadcast_event("DRIVER_0_DONE", redis_address)
|
||||
|
||||
@@ -162,22 +163,23 @@ def driver_1(redis_address, driver_index):
|
||||
long_running_task.remote(driver_index, i, redis_address)
|
||||
|
||||
# Create an actor that requires two GPUs.
|
||||
actors_two_gpus = [Actor2(driver_index, i, redis_address) for i in range(1)]
|
||||
actors_two_gpus = [Actor2.remote(driver_index, i, redis_address)
|
||||
for i in range(1)]
|
||||
# Create some actors that require one GPU.
|
||||
actors_one_gpu = [Actor1(driver_index, 1 + i, redis_address)
|
||||
actors_one_gpu = [Actor1.remote(driver_index, 1 + i, redis_address)
|
||||
for i in range(3)]
|
||||
# Create some actors that don't require any GPUs.
|
||||
actors_no_gpus = [Actor0(driver_index, 1 + 3 + i, redis_address)
|
||||
actors_no_gpus = [Actor0.remote(driver_index, 1 + 3 + i, redis_address)
|
||||
for i in range(5)]
|
||||
|
||||
for _ in range(1000):
|
||||
ray.get([actor.check_ids() for actor in actors_two_gpus])
|
||||
ray.get([actor.check_ids() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids() for actor in actors_no_gpus])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_two_gpus])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_no_gpus])
|
||||
|
||||
# Start a long-running method on one actor and make sure this doesn't affect
|
||||
# anything.
|
||||
actors_one_gpu[0].long_running_method()
|
||||
actors_one_gpu[0].long_running_method.remote()
|
||||
|
||||
_broadcast_event("DRIVER_1_DONE", redis_address)
|
||||
|
||||
@@ -195,7 +197,7 @@ def cleanup_driver(redis_address, driver_index):
|
||||
# We go ahead and create some actors that don't require any GPUs. We don't
|
||||
# need to wait for the other drivers to finish. We call methods on these
|
||||
# actors later to make sure they haven't been killed.
|
||||
actors_no_gpus = [Actor0(driver_index, i, redis_address)
|
||||
actors_no_gpus = [Actor0.remote(driver_index, i, redis_address)
|
||||
for i in range(10)]
|
||||
|
||||
_wait_for_event("DRIVER_0_DONE", redis_address)
|
||||
@@ -207,7 +209,7 @@ def cleanup_driver(redis_address, driver_index):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
actor = actor_class(driver_index, actor_index, redis_address)
|
||||
actor = actor_class.remote(driver_index, actor_index, redis_address)
|
||||
except Exception as e:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
@@ -271,9 +273,9 @@ def cleanup_driver(redis_address, driver_index):
|
||||
# Only one of the cleanup drivers should create and use more actors.
|
||||
if driver_index == 2:
|
||||
for _ in range(1000):
|
||||
ray.get([actor.check_ids() for actor in actors_two_gpus])
|
||||
ray.get([actor.check_ids() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids() for actor in actors_no_gpus])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_two_gpus])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_one_gpu])
|
||||
ray.get([actor.check_ids.remote() for actor in actors_no_gpus])
|
||||
|
||||
_broadcast_event("DRIVER_{}_DONE".format(driver_index), redis_address)
|
||||
|
||||
|
||||
+10
-8
@@ -166,10 +166,11 @@ class TensorFlowTest(unittest.TestCase):
|
||||
ray.experimental.TensorFlowVariables(loss1, sess1)
|
||||
sess1.run(init1)
|
||||
|
||||
net2 = ray.actor(NetActor)()
|
||||
weights2 = ray.get(net2.get_weights())
|
||||
net2 = ray.remote(NetActor).remote()
|
||||
weights2 = ray.get(net2.get_weights.remote())
|
||||
|
||||
new_weights2 = ray.get(net2.set_and_get_weights(net2.get_weights()))
|
||||
new_weights2 = ray.get(net2.set_and_get_weights.remote(
|
||||
net2.get_weights.remote()))
|
||||
self.assertEqual(weights2, new_weights2)
|
||||
|
||||
ray.worker.cleanup()
|
||||
@@ -193,23 +194,24 @@ class TensorFlowTest(unittest.TestCase):
|
||||
def testRemoteTrainingStep(self):
|
||||
ray.init(num_workers=1)
|
||||
|
||||
net = ray.actor(TrainActor)()
|
||||
ray.get(net.training_step(net.get_weights()))
|
||||
net = ray.remote(TrainActor).remote()
|
||||
ray.get(net.training_step.remote(net.get_weights.remote()))
|
||||
|
||||
ray.worker.cleanup()
|
||||
|
||||
def testRemoteTrainingLoss(self):
|
||||
ray.init(num_workers=2)
|
||||
|
||||
net = ray.actor(TrainActor)()
|
||||
net = ray.remote(TrainActor).remote()
|
||||
loss, variables, _, sess, grads, train, placeholders = TrainActor().values
|
||||
|
||||
before_acc = sess.run(loss, feed_dict=dict(zip(placeholders,
|
||||
[[2] * 100, [4] * 100])))
|
||||
|
||||
for _ in range(3):
|
||||
gradients_list = ray.get([net.training_step(variables.get_weights())
|
||||
for _ in range(2)])
|
||||
gradients_list = ray.get(
|
||||
[net.training_step.remote(variables.get_weights())
|
||||
for _ in range(2)])
|
||||
mean_grads = [sum([gradients[i] for gradients in gradients_list]) /
|
||||
len(gradients_list) for i in range(len(gradients_list[0]))]
|
||||
feed_dict = {grad[0]: mean_grad for (grad, mean_grad)
|
||||
|
||||
Reference in New Issue
Block a user