Caffe2 - Python API
A deep learning, cross platform ML framework
functional.py
1 
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, schema, scope, workspace
9 from caffe2.python.layers.layers import (
10  ModelLayer,
11 )
12 import caffe2.proto.caffe2_pb2 as caffe2_pb2
13 import numpy as np
14 import logging
15 
16 logger = logging.getLogger(__name__)
17 logger.setLevel(logging.INFO)
18 
19 
20 class Functional(ModelLayer):
21 
22  def __init__(self, model, input_record, output_names_or_num, function,
23  name='functional', **kwargs):
24  # allow coercion
25  input_record = schema.as_record(input_record)
26 
27  super(Functional, self).__init__(model, name, input_record, **kwargs)
28  self._function = function
29 
30  with scope.NameScope(self.name):
31  if isinstance(output_names_or_num, int):
33  model.net, schema.RawTuple(output_names_or_num))
34  else:
35  if not isinstance(output_names_or_num, list):
36  output_names_or_num = [output_names_or_num]
37  out_tuple = [(out, np.void) for out in output_names_or_num]
39  model.net, schema.Struct(*out_tuple))
40 
41  num_outputs = len(self.output_schema.field_blobs())
42 
43  # Fake execution of the function to infer shapes and types automatically
44  had_issues = False
45  try:
46  type_net = core.Net('_temp_type_and_shape_inference_net')
47  schema.InitEmptyRecord(type_net, input_record, enforce_types=True)
48 
49  function(type_net, self.input_record, self.output_schema)
50  (shapes, types) = workspace.InferShapesAndTypes([type_net], {})
51  for i in range(num_outputs):
52  blob = self.output_schema[i]()
53  if blob not in types or blob not in shapes:
54  had_issues = True
55  continue
56  if shapes[blob] == []:
57  # Scalar type
58  shape = tuple()
59  elif shapes[blob][0] == 0:
60  shape = tuple(shapes[blob][1:])
61  else:
62  logger.warning("unexpeced shape: {}".format(shapes[blob]))
63  # If batch dimension is not first - give up on shape
64  # inference for that blob
65  had_issues = True
66  continue
67 
68  # TODO(amalevich): Move it to some shared library
69  dtype = None
70  if types[blob] == caffe2_pb2.TensorProto.DOUBLE:
71  dtype = (np.float64, shape)
72  elif types[blob] == caffe2_pb2.TensorProto.FLOAT:
73  dtype = (np.float32, shape)
74  elif types[blob] == caffe2_pb2.TensorProto.INT32:
75  dtype = (np.int32, shape)
76  elif types[blob] == caffe2_pb2.TensorProto.INT64:
77  dtype = (np.int64, shape)
78 
79  if dtype is not None:
80  self.output_schema[i].set_type(dtype)
81  except TypeError as ex:
82  had_issues = True
83  logger.warning(str(ex))
84 
85  if had_issues:
86  logger.warning(
87  "Type inference had problems for layer: {}".format(self.name))
88 
89  def add_ops(self, net):
90  self._function(net, self.input_record, self.output_schema)
def as_record(value)
Definition: schema.py:844
def input_record(self)
Definition: layers.py:149
def NewRecord(net, schema)
Definition: schema.py:908
def RawTuple(num_fields, name_prefix='field')
Definition: schema.py:666
def InferShapesAndTypes(nets, blob_dimensions=None)
Definition: workspace.py:184
def NameScope(prefix, reset=False)
Definition: scope.py:41
def InitEmptyRecord(net, schema_or_record, enforce_types=False)
Definition: schema.py:944