4 Implement functions for controlling execution of nets and steps, including 14 from __future__
import absolute_import
15 from __future__
import division
16 from __future__
import print_function
17 from __future__
import unicode_literals
19 from caffe2.python
import core
25 _used_step_names = set()
28 def _get_next_step_name(control_name, base_name):
29 global _current_idx, _used_step_names
30 concat_name =
'%s/%s' % (base_name, control_name)
31 next_name = concat_name
32 while next_name
in _used_step_names:
33 next_name =
'%s_%d' % (concat_name, _current_idx)
35 _used_step_names.add(next_name)
42 (a, b, c) --> [a, b, c] 44 ([a, b, c]) --> [a, b, c] 48 'input cannot be empty.')
51 if not isinstance(output, list):
58 def _IsNets(nets_or_steps):
59 if isinstance(nets_or_steps, list):
60 return all(isinstance(n,
core.Net)
for n
in nets_or_steps)
62 return isinstance(nets_or_steps,
core.Net)
65 def _PrependNets(nets_or_steps, *nets):
66 nets_or_steps = _MakeList((nets_or_steps,))
67 nets = _MakeList(nets)
68 if _IsNets(nets_or_steps):
69 return nets + nets_or_steps
71 return [
Do(
'prepend', nets)] + nets_or_steps
74 def _AppendNets(nets_or_steps, *nets):
75 nets_or_steps = _MakeList((nets_or_steps,))
76 nets = _MakeList(nets)
77 if _IsNets(nets_or_steps):
78 return nets_or_steps + nets
80 return nets_or_steps + [
Do(
'append', nets)]
85 The condition blob is the last external_output that must 88 assert len(condition_net.Proto().external_output) > 0, (
89 "Condition net %s must has at least one external output" %
90 condition_net.Proto.name)
98 """A net assigning constant bool values to blobs. It is mainly used for 99 initializing condition blobs, for example, in multi-task learning, we 100 need to access reader_done blobs before reader_net run. In that case, 101 the reader_done blobs must be initialized. 104 blobs_with_bool_value: one or more (blob, bool_value) pairs. The net will 105 assign each bool_value to the corresponding blob. 108 bool_net: A net assigning constant bool values to blobs. 111 - BoolNet((blob_1, bool_value_1), ..., (blob_n, bool_value_n)) 112 - BoolNet([(blob_1, net1), ..., (blob_n, bool_value_n)]) 113 - BoolNet((cond_1, bool_value_1)) 115 blobs_with_bool_value = _MakeList(blobs_with_bool_value)
117 for blob, bool_value
in blobs_with_bool_value:
118 out_blob = bool_net.ConstantFill(
123 dtype=core.DataType.BOOL)
124 bool_net.AddExternalOutput(out_blob)
130 """Not of a condition blob or net 133 condition_blob_or_net can be either blob or net. If condition_blob_or_net 134 is Net, the condition is its last external_output 135 that must be a single bool. 138 not_net: the net NOT the input 139 out_blob: the output blob of the not_net 141 if isinstance(condition_blob_or_net,
core.Net):
144 condition_blob = condition_blob_or_net
147 out_blob = not_net.Not(condition_blob)
148 not_net.AddExternalOutput(out_blob)
150 return not_net, out_blob
153 def _CopyConditionBlobNet(condition_blob):
154 """Make a condition net that copies the condition_blob 157 condition_blob is a single bool. 160 not_net: the net NOT the input 161 out_blob: the output blob of the not_net 163 condition_net =
core.Net(
'copy_condition_blob_net')
164 out_blob = condition_net.Copy(condition_blob)
165 condition_net.AddExternalOutput(out_blob)
167 return condition_net, out_blob
172 Merge multi condition nets into a single condition nets. 175 name: name of the new condition net. 176 condition_nets: a list of condition nets. The last external_output 177 of each condition net must be single bool value. 178 relation: can be 'And' or 'Or'. 181 - A new condition net. Its last external output is relation of all 184 if not isinstance(condition_nets, list):
185 return condition_nets
186 if len(condition_nets) <= 1:
187 return condition_nets[0]
if condition_nets
else None 190 for i
in range(len(condition_nets)):
191 net_proto = condition_nets[i].Proto()
192 assert net_proto.device_option == merged_net.Proto().device_option
193 assert net_proto.type == merged_net.Proto().type
194 merged_net.Proto().op.extend(net_proto.op)
195 merged_net.Proto().external_input.extend(net_proto.external_input)
199 last_cond = curr_cond
201 last_cond = merged_net.__getattr__(relation)([last_cond, curr_cond])
203 for k, v
in condition_nets[i]._attr_dict.items():
204 merged_net._attr_dict[k] += v
206 merged_net.AddExternalOutput(last_cond)
213 Combine conditions of multi nets into a single condition nets. Unlike 214 MergeConditionNets, the actual body of condition_nets is not copied into 215 the combine condition net. 217 One example is about multi readers. Each reader net has a reader_done 218 condition. When we want to check whether all readers are done, we can 219 use this function to build a new net. 222 name: name of the new condition net. 223 condition_nets: a list of condition nets. The last external_output 224 of each condition net must be single bool value. 225 relation: can be 'And' or 'Or'. 228 - A new condition net. Its last external output is relation of all 231 if not condition_nets:
233 if not isinstance(condition_nets, list):
234 raise ValueError(
'condition_nets must be a list of nets.')
236 if len(condition_nets) == 1:
238 condition_net, _ = _CopyConditionBlobNet(condition_blob)
242 for i
in range(len(condition_nets)):
245 last_cond = curr_cond
247 last_cond = combined_net.__getattr__(relation)(
248 [last_cond, curr_cond])
250 combined_net.AddExternalOutput(last_cond)
255 def Do(name, *nets_or_steps):
257 Execute the sequence of nets or steps once. 260 - Do('myDo', net1, net2, ..., net_n) 261 - Do('myDo', list_of_nets) 262 - Do('myDo', step1, step2, ..., step_n) 263 - Do('myDo', list_of_steps) 265 nets_or_steps = _MakeList(nets_or_steps)
266 if (len(nets_or_steps) == 1
and isinstance(
268 return nets_or_steps[0]
271 _get_next_step_name(
'Do', name), nets_or_steps)
276 Execute the nets or steps in parallel, waiting for all of them to finish 279 - DoParallel('pDo', net1, net2, ..., net_n) 280 - DoParallel('pDo', list_of_nets) 281 - DoParallel('pDo', step1, step2, ..., step_n) 282 - DoParallel('pDo', list_of_steps) 284 nets_or_steps = _MakeList(nets_or_steps)
285 if (len(nets_or_steps) == 1
and isinstance(
287 return nets_or_steps[0]
290 _get_next_step_name(
'DoParallel', name),
292 concurrent_substeps=
True)
295 def _RunOnceIf(name, condition_blob_or_net, nets_or_steps):
297 Execute nets_or_steps once if condition_blob_or_net evaluates as true. 299 If condition_blob_or_net is Net, the condition is its last external_output 300 that must be a single bool. And this net will be executed before 301 nets_or_steps so as to get the condition. 303 condition_not_net, stop_blob =
NotNet(condition_blob_or_net)
304 if isinstance(condition_blob_or_net,
core.Net):
305 nets_or_steps = _PrependNets(
306 nets_or_steps, condition_blob_or_net, condition_not_net)
308 nets_or_steps = _PrependNets(nets_or_steps, condition_not_net)
310 def if_step(control_name):
312 _get_next_step_name(control_name, name),
314 should_stop_blob=stop_blob,
318 if _IsNets(nets_or_steps):
319 bool_net =
BoolNet((stop_blob,
False))
320 return Do(name +
'/_RunOnceIf',
321 bool_net, if_step(
'_RunOnceIf-inner'))
323 return if_step(
'_RunOnceIf')
326 def _RunOnceIfNot(name, condition_blob_or_net, nets_or_steps):
328 Similar to _RunOnceIf() but Execute nets_or_steps once if 329 condition_blob_or_net evaluates as false. 331 if isinstance(condition_blob_or_net,
core.Net):
333 nets_or_steps = _PrependNets(nets_or_steps, condition_blob_or_net)
335 copy_net, condition_blob = _CopyConditionBlobNet(condition_blob_or_net)
336 nets_or_steps = _PrependNets(nets_or_steps, copy_net)
339 _get_next_step_name(
'_RunOnceIfNot', name),
341 should_stop_blob=condition_blob,
346 def For(name, nets_or_steps, iter_num):
348 Execute nets_or_steps iter_num times. 351 nets_or_steps: a ExecutionStep or a Net or a list of ExecutionSteps or 353 iter_num: the number times to execute the nets_or_steps. 356 A ExecutionStep instance. 359 iter_cnt = init_net.CreateCounter([], init_count=iter_num)
361 iter_done = iter_net.CountDown([iter_cnt])
364 _get_next_step_name(
'For-inner', name),
365 _PrependNets(nets_or_steps, iter_net),
366 should_stop_blob=iter_done)
367 return Do(name +
'/For',
368 Do(name +
'/For-init-net', init_net),
372 def While(name, condition_blob_or_net, nets_or_steps):
374 Execute nets_or_steps when condition_blob_or_net returns true. 377 condition_blob_or_net: If it is an instance of Net, its last 378 external_output must be a single bool. 379 nets_or_steps: a ExecutionStep or a Net or a list of ExecutionSteps or 383 A ExecutionStep instance. 385 condition_not_net, stop_blob =
NotNet(condition_blob_or_net)
386 if isinstance(condition_blob_or_net,
core.Net):
387 nets_or_steps = _PrependNets(
388 nets_or_steps, condition_blob_or_net, condition_not_net)
390 nets_or_steps = _PrependNets(nets_or_steps, condition_not_net)
392 def while_step(control_name):
394 _get_next_step_name(control_name, name),
396 should_stop_blob=stop_blob,
399 if _IsNets(nets_or_steps):
406 bool_net =
BoolNet((stop_blob,
False))
407 return Do(name +
'/While', bool_net, while_step(
'While-inner'))
409 return while_step(
'While')
412 def Until(name, condition_blob_or_net, nets_or_steps):
414 Similar to While() but execute nets_or_steps when 415 condition_blob_or_net returns false 417 if isinstance(condition_blob_or_net,
core.Net):
419 nets_or_steps = _PrependNets(nets_or_steps, condition_blob_or_net)
424 _get_next_step_name(
'Until', name),
426 should_stop_blob=stop_blob)
429 def DoWhile(name, condition_blob_or_net, nets_or_steps):
431 Execute nets_or_steps when condition_blob_or_net returns true. It will 432 execute nets_or_steps before evaluating condition_blob_or_net. 435 condition_blob_or_net: if it is an instance of Net, tts last external_output 436 must be a single bool. 437 nets_or_steps: a ExecutionStep or a Net or a list of ExecutionSteps or 441 A ExecutionStep instance. 443 condition_not_net, stop_blob =
NotNet(condition_blob_or_net)
444 if isinstance(condition_blob_or_net,
core.Net):
445 nets_or_steps = _AppendNets(
446 nets_or_steps, condition_blob_or_net, condition_not_net)
448 nets_or_steps = _AppendNets(nets_or_steps, condition_not_net)
454 bool_net =
BoolNet((stop_blob,
False))
456 _get_next_step_name(
'DoWhile-inner', name),
458 should_stop_blob=stop_blob,
462 def DoUntil(name, condition_blob_or_net, nets_or_steps):
464 Similar to DoWhile() but execute nets_or_steps when 465 condition_blob_or_net returns false. It will execute 466 nets_or_steps before evaluating condition_blob_or_net. 468 Special case: if condition_blob_or_net is a blob and is pre-set to 469 true, then only the first net/step of nets_or_steps will be executed and 470 loop is exited. So you need to be careful about the initial value the 471 condition blob when using DoUntil(), esp when DoUntil() is called twice. 473 if not isinstance(condition_blob_or_net,
core.Net):
476 _get_next_step_name(
'DoUntil', name),
478 should_stop_blob=stop_blob)
480 nets_or_steps = _AppendNets(nets_or_steps, condition_blob_or_net)
487 bool_net =
BoolNet((stop_blob,
False))
489 _get_next_step_name(
'DoUntil-inner', name),
491 should_stop_blob=stop_blob,
497 Execute the steps for which the condition is true. 498 Each condition is a tuple (condition_blob_or_net, nets_or_steps). 500 1. Multi steps can be executed if their conditions are true. 501 2. The conditions_blob_or_net (if it is Net) of all steps will be 505 - Switch('name', (cond_1, net_1), (cond_2, net_2), ..., (cond_n, net_n)) 506 - Switch('name', [(cond_1, net1), (cond_2, net_2), ..., (cond_n, net_n)]) 507 - Switch('name', (cond_1, net_1)) 509 conditions = _MakeList(conditions)
511 _get_next_step_name(
'Switch', name),
512 [_RunOnceIf(name +
'/Switch', cond, step)
for cond, step
in conditions])
517 Similar to Switch() but execute the steps for which the condition is False. 519 conditions = _MakeList(conditions)
521 _get_next_step_name(
'SwitchNot', name),
522 [_RunOnceIfNot(name +
'/SwitchNot', cond, step)
523 for cond, step
in conditions])
526 def If(name, condition_blob_or_net,
527 true_nets_or_steps, false_nets_or_steps=None):
529 condition_blob_or_net is first evaluated or executed. If the condition is 530 true, true_nets_or_steps is then executed, otherwise, false_nets_or_steps 533 If condition_blob_or_net is Net, the condition is its last external_output 534 that must be a single bool. And this Net will be executred before both 535 true/false_nets_or_steps so as to get the condition. 537 if not false_nets_or_steps:
538 return _RunOnceIf(name +
'/If',
539 condition_blob_or_net, true_nets_or_steps)
541 if isinstance(condition_blob_or_net,
core.Net):
544 condition_blob = condition_blob_or_net
548 _RunOnceIf(name +
'/If-true',
549 condition_blob_or_net, true_nets_or_steps),
550 _RunOnceIfNot(name +
'/If-false', condition_blob, false_nets_or_steps)
554 def IfNot(name, condition_blob_or_net,
555 true_nets_or_steps, false_nets_or_steps=None):
557 If condition_blob_or_net returns false, executes true_nets_or_steps, 558 otherwise executes false_nets_or_steps 560 if not false_nets_or_steps:
561 return _RunOnceIfNot(name +
'/IfNot',
562 condition_blob_or_net, true_nets_or_steps)
564 if isinstance(condition_blob_or_net,
core.Net):
567 condition_blob = condition_blob_or_net
571 _RunOnceIfNot(name +
'/IfNot-true',
572 condition_blob_or_net, true_nets_or_steps),
573 _RunOnceIf(name +
'/IfNot-false', condition_blob, false_nets_or_steps)
def GetConditionBlobFromNet(condition_net)
def NotNet(condition_blob_or_net)
def Switch(name, conditions)
def If(name, condition_blob_or_net, true_nets_or_steps, false_nets_or_steps=None)
def Until(name, condition_blob_or_net, nets_or_steps)
def MergeConditionNets(name, condition_nets, relation)
def DoUntil(name, condition_blob_or_net, nets_or_steps)
def scoped_execution_step(name, args, kwargs)
def DoWhile(name, condition_blob_or_net, nets_or_steps)
def CombineConditions(name, condition_nets, relation)
def DoParallel(name, nets_or_steps)
def Do(name, nets_or_steps)
def BoolNet(blobs_with_bool_value)
def IfNot(name, condition_blob_or_net, true_nets_or_steps, false_nets_or_steps=None)
def While(name, condition_blob_or_net, nets_or_steps)
def SwitchNot(name, conditions)
def For(name, nets_or_steps, iter_num)