Caffe2 - Python API
A deep learning, cross platform ML framework
net_builder.py
1 ## @package net_builder
2 # Module caffe2.python.net_builder
3 from __future__ import absolute_import
4 from __future__ import division
5 from __future__ import print_function
6 from __future__ import unicode_literals
7 
8 from caffe2.python import core, context
9 from caffe2.python.task import Task, TaskGroup
10 from caffe2.python.control_ops_util import add_if_op, add_while_op
11 
12 
13 @context.define_context()
14 class NetBuilder(object):
15  """
16  Scope-driven mechanism for building nets, loops and conditional blocks.
17  Arguments:
18  name: NetBuilder's name
19  initial_scope: list of blobs that are available for reading/writing
20  Example:
21  from caffe2.python.net_builder import NetBuilder, ops
22  with NetBuilder() as nb:
23  c = ops.Const(5)
24  d = ops.Const(0)
25  with ops.loop():
26  ops.stop_if(ops.LE([c, ops.Const(0)]))
27  ops.Add([c, ops.Const(-1)], [c])
28  with ops.If(ops.GE([c, ops.Const(3)])):
29  ops.Add([d, ops.Const(10)], [d])
30  ops.Print(c, [])
31  ops.Print(d, [])
32  step = core.to_execution_step(nb)
33  """
34  def __init__(self, name=None, initial_scope=None, _stop_blob_required=False,
35  _stop_blob=None, _fullname=None, _use_control_ops=False):
36  parent = NetBuilder.current(required=False)
37  assert not _fullname or not name, 'Cannot set both _fullname and name'
38  assert not _use_control_ops or \
39  (not _stop_blob_required and not _stop_blob), \
40  'Stop blobs are not used with control operators'
41  self.name = _fullname or '/'.join(
42  n for n in (parent.name if parent else None, name) if n
43  )
44  self._frozen = False
45  self._current_net = None
46  self._children = []
47  if parent:
48  # make sure parent has an up to date lexical scope computed
49  parent._update_lexical_scope()
50  self._init_lexical_scope = set(parent._lexical_scope) if parent else set()
51  if initial_scope:
52  self._init_lexical_scope |= set([str(b) for b in initial_scope])
53  self._lexical_scope = set(self._init_lexical_scope)
54  self._stop_blob = _stop_blob
55  self._stop_blob_required = _stop_blob_required
56  self._use_control_ops = _use_control_ops
57 
58  def stop_blob(self):
59  """
60  Returns the BlobReference to the stop_blob of this NetBuilder.
61  If one is not yet available, creates one.
62  This function assumes that the stop_blob() will be used immediatelly
63  in the current net, so it doesn't initialize it if the current net is
64  the first of the builder.
65  """
66  assert not self._use_control_ops, \
67  'Stop blobs are not used with control operators'
68  if self._stop_blob is None:
69  net = self.current_net()
71  net.NextName('stop_blob'), net=net)
72  net.Const(False, blob_out=self._stop_blob)
73  if self._current_net != self._children[0]:
74  self._children.insert(0, core.Net('stop_blob_init'))
75  self._children[0].Const(False, blob_out=self._stop_blob)
76  return self._stop_blob
77 
78  def stop_if(self, blob):
79  assert not self._use_control_ops, \
80  'Stop blobs are not used with control operators'
81  stop_blob = self.stop_blob()
82  ops.Or([stop_blob, blob], [stop_blob])
83  self._current_net = None
84 
85  def _assert_mutable(self):
86  assert not self._frozen, (
87  'This NetBuilder (%s) has been built already.' % self.name)
88 
89  def _update_lexical_scope(self):
90  """
91  Updates lexical scope based on the current list of children.
92  Lexical scope contains names of blobs that are currently available
93  and were introduced in the net builder
94  """
95  self._lexical_scope = set(self._init_lexical_scope)
96  for child in self._children:
97  if isinstance(child, core.Net):
98  self._lexical_scope |= child.UsedBlobNames()
99  elif isinstance(child, NetBuilder) and child._use_control_ops:
100  self._lexical_scope |= child._lexical_scope
101 
102  def _reset_children(self):
103  self._current_net = None
104  self._children = []
105  self._lexical_scope = set(self._init_lexical_scope)
106 
107  def add(self, child):
108  self._assert_mutable()
109 
110  if self._use_control_ops:
111  assert isinstance(child, core.Net) or (
112  isinstance(child, NetBuilder) and child._use_control_ops), \
113  "Expected Net or NetBuilder with control ops"
114 
115  self._current_net = None
116  self._children.append(child)
117  # to-do : check it's not a dag net
118  if isinstance(child, core.Net):
119  self._current_net = child
120  self._update_lexical_scope()
121  return child
122 
123  def current_net(self, name=None):
124  self._assert_mutable()
125  if self._current_net is None or name is not None:
126  self.add(core.Net(name))
127  return self._current_net
128 
129  def freeze(self):
130  for child in self._children:
131  if hasattr(child, 'freeze'):
132  child.freeze()
133  self._current_net = None
134  self._frozen = True
135 
136  def get(self):
137  self.freeze()
138  return self._children
139 
140  def __exit__(self, etype, *args):
141  if self._use_control_ops and len(self._children) > 0:
142  _children = self._children
143  self._reset_children()
144  merged_net = NetBuilder.merge_nets(
145  _children, self._lexical_scope)
146  assert merged_net, "Expected a non-empty merge of children"
147  self._children = [merged_net]
148 
149  self.freeze()
150  if etype is not None:
151  return
152  assert (not self._stop_blob_required) or self._stop_blob is not None, (
153  'This NetBuilder (%s) requires a stop condition ' % self.name +
154  'to be set with `stop` or `stop_if`')
155 
156  @staticmethod
157  def merge_nets(nets_or_builders, outer_blob_names):
158  # Only nets or builders with control ops are allowed.
159  # Need to pay attention to external outputs, e.g.
160  # ...
161  # IfNet1 (cond_blob):
162  # (Net1)
163  # X = 1
164  # IfNet2 (...):
165  # X = X + 1
166  # ...
167  # In this example there're two children in then branch of IfNet1:
168  # a subnet Net1 that creates blob X and sets its value to one, and
169  # a net builder IfNet2 that (conditionally) increments X.
170  # From IfNet2's point of view X is an external input
171  # and output blob, it will be put into IfNet2 net's external_output.
172  # At the same time, from the point of view of IfNet1 X is purely local.
173  # Net.AppendNet just merges external outputs of the networks, so
174  # without checking this the result of Net1.AppendNet(IfNet2's net)
175  # would have blob X in external_output
176 
177  net = None
178  for n in nets_or_builders:
179  cur = None
180  if isinstance(n, NetBuilder):
181  assert n._use_control_ops, \
182  "Merging of NetBuilder supported only for control ops"
183  nets = n.get()
184  assert len(nets) == 1 and isinstance(nets[0], core.Net), \
185  "Invalid control op net builder"
186  cur = nets[0]
187  else:
188  assert isinstance(n, core.Net)
189  cur = n
190  if net:
191  net.AppendNet(cur)
192  else:
193  net = cur
194  if net:
195  # correct external output
196  external_outputs = [o for o in net.Proto().external_output
197  if o in outer_blob_names]
198  net.Proto().external_output[:] = external_outputs
199  return net
200 
201  def __str__(self):
202  return self.name or 'Un-named NetBuilder'
203 
204 
205 class Operations(object):
206  """
207  Operations to be used in the context of a NetBuilder.
208  """
209  def net(self, net=None, name=None):
210  """
211  Retrieves the current net, or add a new net to the builder.
212  Args:
213  net: If provided, add the given net to the active builder.
214  Else, returns the current Net or creates a new one as needed.
215  name: if provided, creates a new Net with given name and makes
216  it the new current net of the active builder. Cannot
217  be provided if net is provided.
218  """
219  assert name is None or net is None, (
220  'Cannot provide both `net` and `name`.')
221  if net is not None:
222  NetBuilder.current().add(net)
223  return net
224  return NetBuilder.current().current_net(name=name)
225 
226  def __getattr__(self, op_type):
227  """
228  Adds an operator call to the currently active Net.
229  """
230  if op_type.startswith('__'):
231  raise AttributeError()
232  # We want hasattr to work properly even if no context is active.
233  if NetBuilder.current(required=False) is None:
234  raise AttributeError('No active NetBuilder.')
235  return getattr(self.net(), op_type)
236 
237  def task_group(self):
238  """
239  Creates a local task group which will execute as the next step of
240  the current NetBuilder.
241  """
242  from caffe2.python import task
243  group = NetBuilder.current()
244  with task.Cluster():
245  with task.Node('local'):
246  tg = task.TaskGroup()
247  group.add(tg)
248  return tg
249 
250  def stop(self):
251  """
252  Stop execution of the current execution step.
253  Example:
254  ops.Print(a, 0)
255  ops.stop()
256  ops.Print(b, 0)
257  In the example, 'b' will never be printed.
258  """
259  return self.stop_if(ops.Const(True))
260 
261  def stop_if(self, blob):
262  """
263  Stop execution of the current execution step if the
264  condition `blob` is met.
265  Example:
266  ops.Print(a, 0)
267  ops.stop_if(ops.LE([x, ops.Const(0)]))
268  ops.Print(b, 0)
269  In the example, 'b' will only be printed if the value of scalar
270  tensor 'x' is greater than 0.
271  """
272  return NetBuilder.current().stop_if(blob)
273 
274  def loop(self, iters=None, name=None):
275  """
276  Creates a NetBuilder that will execute in a loop as the next step of
277  the current NetBuilder. If `iters` is provided, the loop will execute
278  for `iters` iterations and then stop. `iters` can be a constant or a
279  BlobReference. If `iters` is not provided, the loop will execute
280  until `ops.stop` or `ops.stop_if` is called.
281  Examples:
282  a = ops.Const(5)
283  with ops.loop():
284  ops.stop_if(ops.LE([a, ops.Const(0)]))
285  ops.Print(a, 0)
286  ops.Add([a, ops.Const(-1)], [a])
287  Above, 'a' will be printed 5 times, with values 5 to 1.
288 
289  with ops.loop(10) as loop:
290  ops.LogInfo(loop.iter())
291  This will print the numbers from 0 to 9.
292 
293  x = ops.Add([ops.Const(10), ops.Const(10)])
294  with ops.loop(x) as loop:
295  ops.LogInfo(loop.iter())
296  This will print the numbers from 0 to 19.
297  """
298  return NetBuilder.current().add(_Loop(iters, name=name))
299 
300  def stop_guard(self, has_stopped_blob=None, name=None):
301  """
302  Creates a NetBuilder that will execute once as the next step of the
303  current NetBuilder. After execution, a bool tensor will indicate
304  whether the inner execution was halted with `stop` or `stop_if`.
305  Example:
306  a = ops.Const(True)
307  with ops.stop_guard() as sg1:
308  ops.stop_if(a)
309  ops.Print(ops.Const('did not stop'))
310  b = ops.Const(False)
311  with ops.stop_guard() as sg2:
312  ops.stop_if(b)
313  ops.Print(ops.Const('did not stop'))
314  ops.Print(sg1.has_stopped(), [])
315  ops.Print(sg2.has_stopped(), [])
316  In the example, 'did not stop' will be printed once,
317  followed by True and False.
318  """
319  return NetBuilder.current().add(
320  _StopGuard(has_stopped_blob=has_stopped_blob, name=name))
321 
322  def If(self, cond, name=None):
323  """
324  Creates a NetBuilder that will execute once as the next step of the
325  current NetBuilder if the blob `cond` is True.
326  Example:
327  with ops.If(ops.Const(True)):
328  ops.Print(ops.Const('Will print'))
329  with ops.If(ops.Const(False)):
330  ops.Print(ops.Const('Wont print'))
331  The example will print 'Will print' once.
332  """
333  return NetBuilder.current().add(_RunIf(cond, name=name))
334 
335  def IfNet(self, cond, name=None):
336  """
337  Same as If, but uses 'If' operator instead of execution step logic
338  """
339  return NetBuilder.current().add(_RunIfNet(cond, name=name))
340 
341  def Else(self, name=None):
342  """
343  Else branch of IfNet, has to be specified immediately after IfNet.
344  Example:
345  with ops.IfNet(ops.LT([x, y])):
346  ...
347  with ops.Else():
348  ...
349  """
350  return _RunElseNet(name=name)
351 
352  def WhileNet(self, name=None):
353  """
354  NetBuilder for 'While' control operator
355  """
356  return NetBuilder.current().add(_RunWhileNet(name=name))
357 
358  def Condition(self, name=None):
359  """
360  Loop's condition, executed within WhileNet context
361  """
362  assert isinstance(NetBuilder.current(), _RunWhileNet), \
363  "Use of Condition outside of WhileNet"
364  return _RunWhileCondition(name=name)
365 
366  def task_init(self):
367  """
368  Defines operations that will be executed once at task startup.
369  Useful when implementing processors, that don't have access to the Task
370  top-level structure.
371 
372  This setup will be run only once, even if multiple instances of the task
373  will run in parallel. For instance-local initialization, use
374  `task_instance_init` instead.
375 
376  Example:
377  def my_processor(rec):
378  with ops.task_init():
379  one = ops.Const(1)
380  two = ops.Const(1)
381  return Tuple(
382  ops.Add(rec[0](), zero), ops.Add(rec[1](), two))
383  """
384  setup = _SetupBuilder(_SetupBuilder.INIT)
385  self.net().add_attribute(Task.TASK_SETUP, setup)
386  return setup
387 
388  def task_exit(self):
389  """
390  Define operations to be executed once at task shutdown.
391  Useful when implementing processors, that don't have access to the Task
392  top-level structure.
393 
394  This shutdown will be run only once, after all concurrent instances of
395  the task have already finished. For instance-local shutdown,
396  use `task_instance_exit` instead.
397 
398  Example:
399  def read_queue(queue):
400  with ops.task_exit():
401  queue.close(ops.net())
402  return queue.read(ops.net())
403  """
404  setup = _SetupBuilder(_SetupBuilder.EXIT)
405  self.net().add_attribute(Task.TASK_SETUP, setup)
406  return setup
407 
409  """
410  Defines operations that will be executed once at startup of each
411  instance of a task. This can be seen as "thread_local" initialization.
412  It is guaranteed to run only after all `task_init` logic finishes.
413 
414  This setup will be run concurrently for each instance of a task.
415  For global task initialization, use `task_init` instead.
416  """
417  setup = _SetupBuilder(_SetupBuilder.INIT)
418  self.net().add_attribute(Task.TASK_INSTANCE_SETUP, setup)
419  return setup
420 
422  """
423  Defines operations that will be executed once at shutdown of each
424  instance of a task. This can be seen as "thread_local" finalization.
425 
426  This shutdown will be run concurrently for each instance of a task.
427  For global task shutdown, use `task_exit` instead.
428  """
429  setup = _SetupBuilder(_SetupBuilder.EXIT)
430  self.net().add_attribute(Task.TASK_INSTANCE_SETUP, setup)
431  return setup
432 
433  def local_init(self):
434  """
435  Similar to `task_init`, but executes at TaskGroup's startup instead,
436  before any task of the group starts executing. This will run only
437  once on each node, before initialization of any task, so it can be
438  used e.g. to initialize blobs shared across tasks.
439  """
440  setup = _SetupBuilder(_SetupBuilder.INIT)
441  self.net().add_attribute(TaskGroup.LOCAL_SETUP, setup)
442  return setup
443 
444  def local_exit(self, name=None):
445  """
446  Similar to `task_exit`, but executes at TaskGroup's exit instead,
447  after all tasks of the group finished execution.
448  This will run only once on each node.
449  """
450  setup = _SetupBuilder(_SetupBuilder.EXIT, name)
451  self.net().add_attribute(TaskGroup.LOCAL_SETUP, setup)
452  return setup
453 
454  def task_reporter(self, interval_ms=1000, name=None):
455  """
456  Define operations to be executed at every time interval from
457  task start-up to finish. These operations are guaranteed to
458  execute at least once after all other operations of the task are
459  finished.
460 
461  Example:
462  with ops.task_reporter(interval_ms=10000):
463  ops.LogInfo('10s elapsed')
464  """
465  return _ReporterBuilder(interval_ms, net=self.net(), name=name)
466 
467  def local_reporter(self, interval_ms=1000, name=None):
468  """
469  Similar to task_report, but operations defined within this block
470  will run repeatedly for as long as any of the tasks in the current
471  TaskGroup have not finished.
472  """
473  return _ReporterBuilder(interval_ms, name=name)
474 
475 
476 ops = Operations()
477 
478 
480  def __init__(self, interval_ms, net=None, name=None):
481  NetBuilder.__init__(self, name)
482  self._net = net
483  self.interval_ms = interval_ms
484 
485  def __exit__(self, etype, *args):
486  if etype is None:
487  step = core.to_execution_step(self)
488  step.RunEveryMillis(self.interval_ms)
489  if self._net:
490  self._net.add_attribute(Task.REPORT_STEP, step)
491  else:
492  TaskGroup.current().report_step(
493  step, interval_ms=self.interval_ms)
494  NetBuilder.__exit__(self, etype, *args)
495 
496 
498  INIT = 'init'
499  EXIT = 'exit'
500 
501  def __init__(self, type, name=None):
502  NetBuilder.__init__(self, name)
503  self.type = type
504 
505  def setup(self, net):
506  if self.type == _SetupBuilder.INIT:
507  return core.to_execution_step(self)
508 
509  def exit(self, net):
510  if self.type == _SetupBuilder.EXIT:
511  return core.to_execution_step(self)
512 
513 
515  def __init__(self, name=None):
516  NetBuilder.__init__(self, name)
517 
518  def __exit__(self, etype, *args):
519  if etype is None and self._stop_blob is not None:
520  ops.stop()
521  NetBuilder.__exit__(self, etype, *args)
522 
523 
525  def __init__(self, has_stopped_blob=None, name=None):
526  _RunOnce.__init__(self, name)
527  self._stopped = has_stopped_blob
528  self._ran = False
529 
530  def __enter__(self):
531  r = _RunOnce.__enter__(self)
532  self._stopped = ops.Const(True, blob_out=self._stopped)
533  return r
534 
535  def __exit__(self, etype, *args):
536  if etype is None:
537  self._ran = True
538  ops.Const(False, blob_out=self._stopped)
539  _RunOnce.__exit__(self, etype, *args)
540 
541  def has_stopped(self):
542  """
543  Return a blob that will be set to scalar bool `True` after
544  this net builder ran, iff it was halted early.
545  """
546  assert self._ran, 'Context not used yet.'
547  return self._stopped
548 
549 
551  def __init__(self, iters=None, name=None):
552  NetBuilder.__init__(self, name, _stop_blob_required=True)
553  if iters is not None:
554  self._inc = ops.Const(1)
555  self._iter = ops.Const(0)
556  self._num_iters = (
557  iters if isinstance(iters, core.BlobReference)
558  else ops.Const(iters))
559  else:
560  self._num_iters = None
561 
562  def iter(self):
563  assert self._num_iters is not None, (
564  'This loop does not have a number of iterations.')
565  assert self._iter is not None, (
566  'iter() must be called from inside the loop context')
567  return self._iter
568 
569  def __enter__(self):
570  builder = NetBuilder.__enter__(self)
571  if self._num_iters is not None:
572  ops.stop_if(ops.GE([self._iter, self._num_iters]))
573  return builder
574 
575  def __exit__(self, type, *args):
576  if type is None and self._num_iters is not None:
577  self.current_net().Add([self._iter, self._inc], [self._iter])
578  NetBuilder.__exit__(self, type, *args)
579 
580 
582  def __init__(self, cond_blob=None, name=None, _already_ran=None):
583  _RunOnce.__init__(self, name)
584  assert cond_blob or _already_ran
585  self._is_else = cond_blob is None
586  if _already_ran is None:
587  self._else_blob = ops.Not(cond_blob)
588  self._already_ran = ops.Const(False)
589  else:
590  self._already_ran = _already_ran
591  self._else_blob = _already_ran if cond_blob is None else (
592  ops.Or([_already_ran, ops.Not(cond_blob)]))
593 
594  def __enter__(self):
595  r = _RunOnce.__enter__(self)
596  ops.stop_if(self._else_blob)
597  ops.Const(True, blob_out=self._already_ran)
598  return r
599 
600  def Elif(self, cond, name=None):
601  assert not self._is_else, 'Else not allowed for an Else.'
602  return NetBuilder.current().add(_RunIf(
603  cond, name=name or self.name, _already_ran=self._already_ran))
604 
605  def Else(self, name=None):
606  assert not self._is_else, 'Elif not allowed for an Else.'
607  return NetBuilder.current().add(
608  _RunIf(name=name or self.name, _already_ran=self._already_ran))
609 
610 
612  """
613  Generates a single net that uses If operator
614  """
615  def __init__(self, cond_blob, name=None):
616  NetBuilder.__init__(self, name=name, _use_control_ops=True)
617  assert cond_blob, 'Conditional blob is not specified for an If net'
618  self._cond_blob = cond_blob
619  self._then_net = None
620  self._else_net = None
621 
622  def add(self, child):
623  return NetBuilder.add(self, child)
624 
625  def __exit__(self, type, *args):
626  if type is None:
627  _then_nets = self._children
628  self._reset_children()
629 
630  self._then_net = NetBuilder.merge_nets(
631  _then_nets, self._lexical_scope)
632  if not self._then_net:
633  self._then_net = core.Net('empty_then_net')
634 
635  if_net = core.Net(self.name + '/if_net')
636  add_if_op(if_net, self._cond_blob, self._lexical_scope,
637  self._then_net, self._else_net)
638 
639  self._current_net = if_net
640  self._children = [if_net]
641  NetBuilder.__exit__(self, type, *args)
642 
643 
645  """
646  Else branch for _RunIfNet builder
647  """
648  def __init__(self, name=None):
649  NetBuilder.__init__(self, name=name, _use_control_ops=True)
650  parent = NetBuilder.current(required=False)
651  assert parent and len(parent._children) > 0 and \
652  isinstance(parent._children[-1], _RunIfNet), \
653  'Invalid use of Else builder'
654  self._if_builder = parent._children[-1]
655 
656  def __exit__(self, type, *args):
657  if type is None:
658  _else_nets = self._children
659  self._reset_children()
660 
661  self._if_builder._else_net = NetBuilder.merge_nets(
662  _else_nets, self._lexical_scope)
663  if self._if_builder._else_net:
664  if_else_net = core.Net(self.name + '/if_else_net')
665  add_if_op(
666  if_else_net,
667  self._if_builder._cond_blob,
668  self._lexical_scope,
669  self._if_builder._then_net,
670  self._if_builder._else_net)
671  self._if_builder._current_net = if_else_net
672  self._if_builder._children = [if_else_net]
673  NetBuilder.__exit__(self, type, *args)
674 
675 
677  """
678  Generates a single net that uses While operator
679  """
680  def __init__(self, name=None):
681  NetBuilder.__init__(self, name=name, _use_control_ops=True)
682  self._cond_builder = None
683 
684  def __exit__(self, type, *args):
685  if type is None:
686  assert self._cond_builder, \
687  'Condition builder must be specified in While op'
688 
689  _cond_blob = self._cond_builder._cond_blob
690  _cond_net = self._cond_builder._cond_net
691 
692  loop_body = self._children
693  self._reset_children()
694  loop_body_net = NetBuilder.merge_nets(
695  loop_body, self._lexical_scope)
696  if not loop_body_net:
697  loop_body_net = core.Net('empty_loop_body_net')
698 
699  while_net = core.Net(self.name + '/while_net')
700  add_while_op(while_net, _cond_blob, self._lexical_scope,
701  loop_body_net, _cond_net)
702 
703  self._current_net = while_net
704  self._children = [while_net]
705  NetBuilder.__exit__(self, type, *args)
706 
707 
709  """
710  Computes loop's condition, used in the context of WhileNet.
711  Last operator must have a single scalar boolean output that will be used
712  as a condition value, no other blobs created in the condition net are
713  visible outside of it
714  """
715  def __init__(self, name=None):
716  NetBuilder.__init__(self, name=name, _use_control_ops=True)
717  parent = NetBuilder.current(required=False)
718  assert parent and isinstance(parent, _RunWhileNet), \
719  'Invalid use of loop condition builder'
720  assert not parent._cond_builder, \
721  'Multiple loop condition builders specified'
722  assert len(parent._children) == 0, \
723  'Condition definition must be specified before the loop\'s body'
724  parent._cond_builder = self
725  self._cond_blob = None
726  self._cond_net = None
727 
728  def __exit__(self, type, *args):
729  if type is None:
730  condition_body = self._children
731  self._reset_children()
732  self._cond_net = NetBuilder.merge_nets(
733  condition_body, self._lexical_scope)
734  assert self._cond_net, 'Invalid loop condition specified'
735  assert len(self._cond_net.Proto().op) > 0, 'Invalid condition net'
736  last_op = self._cond_net.Proto().op[-1]
737  assert len(last_op.output) == 1, 'Invalid condition net'
738  self._cond_blob = core.BlobReference(name=last_op.output[0], net=None)
739 
740  self._current_net = self._cond_net
741  self._children = [self._cond_net]
742  NetBuilder.__exit__(self, type, *args)
Definition: setup.py:1
def loop(self, iters=None, name=None)
Definition: net_builder.py:274
def local_reporter(self, interval_ms=1000, name=None)
Definition: net_builder.py:467
def current_net(self, name=None)
Definition: net_builder.py:123
def If(self, cond, name=None)
Definition: net_builder.py:322
def IfNet(self, cond, name=None)
Definition: net_builder.py:335
def stop_guard(self, has_stopped_blob=None, name=None)
Definition: net_builder.py:300
def net(self, net=None, name=None)
Definition: net_builder.py:209
def task_reporter(self, interval_ms=1000, name=None)
Definition: net_builder.py:454