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