I have a tiny Ray pipeline like this:
JavaScript
x
95
95
1
import ray
2
import numpy as np
3
import time
4
5
@ray.remote
6
class PersonDetector:
7
8
def __init__(self) -> None:
9
self.model = self._init_model()
10
11
def _init_model(self):
12
s = np.random.random([100, 4])
13
return s
14
15
def infer(self, img):
16
b = self.model[0:np.random.randint(100), :]
17
# random batch boxes
18
print(b.shape)
19
time.sleep(4)
20
return b
21
22
@ray.remote
23
class KptsDetector:
24
25
def __init__(self) -> None:
26
self.model = self._init_model()
27
28
def _init_model(self):
29
s = np.random.random([100, 17])
30
return s
31
32
def infer(self, img, boxes):
33
sh1 = boxes.shape[0]
34
kpts = self.model[0: sh1, :]
35
time.sleep(2)
36
return kpts
37
38
39
@ray.remote
40
class HandDetector:
41
42
def __init__(self) -> None:
43
self.model = self._init_model()
44
45
def _init_model(self):
46
s = np.random.random([100, 4])
47
return s
48
49
def infer(self, img):
50
b = self.model[0:np.random.randint(100), :]
51
# random batch boxes
52
data = {}
53
data['hands'] = b
54
time.sleep(3)
55
return data
56
57
@ray.remote
58
def gather_all(hands, kpts):
59
t0 = time.time()
60
if isinstance(hands, dict):
61
print(f'in hands info: {hands.keys()}')
62
hands = hands['hands']
63
if hands.shape[0] > kpts.shape[0]:
64
out = hands.copy()
65
out[:kpts.shape[0], :] += kpts[ , :4]
66
else:
67
out = kpts.copy()[ , :4]
68
out[:hands.shape[0], :] += hands
69
print(f'[gather time] {time.time() - t0}')
70
return out
71
72
# how to written DAG in classes?
73
P = PersonDetector.remote()
74
K = KptsDetector.remote()
75
H = HandDetector.remote()
76
77
t0 = time.time()
78
img = []
79
boxes = P.infer.remote(img)
80
hands = H.infer.remote(img)
81
kpts = K.infer.remote(img, boxes)
82
83
# out = gather.remote(hands, kpts)
84
out = gather_all.remote(hands, kpts)
85
t1 = time.time()
86
print(t1 - t0)
87
88
out = ray.get(out)
89
t2 = time.time()
90
print(t2 - t0)
91
print(t2 - t1)
92
print(out.shape)
93
94
95
I using time.sleep()
for fake time consuming. As you can see, the HandDetector should running in a sub process, so the whole time should be 6s.
But I got (you can have a try on your computer):
JavaScript
1
3
1
6.45377516746521
2
6.4489240646362305
3
Why there are 0.4s time more?
Advertisement
Answer
It looks like you posted the same question to the Ray GitHub (link to comment). I am copying the answer here so other StackOverflow users can benefit.
@robertnishihara: You are recreating the actors every time you call do_it, and there is some overhead to creating actors (it starts a new Python process).
If you rewrite it as follows, the overhead drops.
JavaScript
1
97
97
1
import ray
2
import numpy as np
3
import time
4
5
ray.init()
6
7
@ray.remote
8
class PersonDetector:
9
10
def __init__(self) -> None:
11
self.model = self._init_model()
12
13
def _init_model(self):
14
s = np.random.random([100, 4])
15
return s
16
17
def infer(self, img):
18
b = self.model[0:np.random.randint(100), :]
19
# random batch boxes
20
print(b.shape)
21
time.sleep(4)
22
return b
23
24
@ray.remote
25
class KptsDetector:
26
27
def __init__(self) -> None:
28
self.model = self._init_model()
29
30
def _init_model(self):
31
s = np.random.random([100, 17])
32
return s
33
34
def infer(self, img, boxes):
35
sh1 = boxes.shape[0]
36
kpts = self.model[0: sh1, :]
37
time.sleep(2)
38
return kpts
39
40
41
@ray.remote
42
class HandDetector:
43
44
def __init__(self) -> None:
45
self.model = self._init_model()
46
47
def _init_model(self):
48
s = np.random.random([100, 4])
49
return s
50
51
def infer(self, img):
52
b = self.model[0:np.random.randint(100), :]
53
# random batch boxes
54
data = {}
55
data['hands'] = b
56
time.sleep(3)
57
return data
58
59
@ray.remote
60
def gather_all(hands, kpts):
61
t0 = time.time()
62
if isinstance(hands, dict):
63
print(f'in hands info: {hands.keys()}')
64
hands = hands['hands']
65
if hands.shape[0] > kpts.shape[0]:
66
out = hands.copy()
67
out[:kpts.shape[0], :] += kpts[ , :4]
68
else:
69
out = kpts.copy()[ , :4]
70
out[:hands.shape[0], :] += hands
71
print(f'[gather time] {time.time() - t0}')
72
return out
73
74
75
def do_it(i, P, K, H):
76
t0 = time.time()
77
img = []
78
boxes = P.infer.remote(img)
79
hands = H.infer.remote(img)
80
kpts = K.infer.remote(img, boxes)
81
82
# out = gather.remote(hands, kpts)
83
out = gather_all.remote(hands, kpts)
84
t1 = time.time()
85
out_value = ray.get(out)
86
t2 = time.time()
87
print(f'{i}. {t2 - t1}')
88
print(out_value.shape)
89
90
91
if __name__ == '__main__':
92
P = PersonDetector.remote()
93
K = KptsDetector.remote()
94
H = HandDetector.remote()
95
for i in range(3):
96
do_it(i, P, K, H)
97
In this case, I get the output
JavaScript
1
17
17
1
(PersonDetector pid=36472) (35, 4)
2
0. 7.073965072631836
3
(95, 4)
4
(PersonDetector pid=36472) (34, 4)
5
(gather_all pid=36421) in hands info: dict_keys(['hands'])
6
(gather_all pid=36421) [gather time] 6.890296936035156e-05
7
1. 6.016530275344849
8
(47, 4)
9
(PersonDetector pid=36472) (87, 4)
10
(gather_all pid=36421) in hands info: dict_keys(['hands'])
11
(gather_all pid=36421) [gather time] 9.608268737792969e-05
12
2. 6.006845235824585
13
(88, 4)
14
15
(gather_all pid=36421) in hands info: dict_keys(['hands'])
16
(gather_all pid=36421) [gather time] 9.870529174804688e-05
17