(self, model, input_record, output_names_or_num, function,
name='functional', output_dtypes=None, tags=None, **kwargs)
| 20 | class Functional(ModelLayer): |
| 21 | |
| 22 | def __init__(self, model, input_record, output_names_or_num, function, |
| 23 | name='functional', output_dtypes=None, tags=None, **kwargs): |
| 24 | |
| 25 | # allow coercion |
| 26 | input_record = schema.as_record(input_record) |
| 27 | |
| 28 | super().__init__(model, name, input_record, tags=tags, **kwargs) |
| 29 | self._function = function |
| 30 | self._kwargs = kwargs |
| 31 | return_struct = ( |
| 32 | isinstance(output_names_or_num, list) or |
| 33 | (isinstance(output_names_or_num, int) and |
| 34 | output_names_or_num != 1) |
| 35 | ) |
| 36 | |
| 37 | with scope.NameScope(self.name, reset=True): |
| 38 | if isinstance(output_names_or_num, int): |
| 39 | struct_output_schema = schema.NewRecord( |
| 40 | model.net, schema.RawTuple(output_names_or_num)) |
| 41 | elif isinstance(output_names_or_num, schema.Field): |
| 42 | self.output_schema = output_names_or_num.clone(keep_blobs=True) |
| 43 | return |
| 44 | else: |
| 45 | if not isinstance(output_names_or_num, list): |
| 46 | output_names_or_num = [output_names_or_num] |
| 47 | out_tuple = [(out, np.void) for out in output_names_or_num] |
| 48 | struct_output_schema = schema.NewRecord( |
| 49 | model.net, schema.Struct(*out_tuple)) |
| 50 | |
| 51 | num_outputs = len(struct_output_schema.field_blobs()) |
| 52 | |
| 53 | # functional layer returns Struct if more than one outputs or output is |
| 54 | # a list, otherwise Scalar |
| 55 | if return_struct: |
| 56 | self.output_schema = struct_output_schema |
| 57 | else: |
| 58 | self.output_schema = struct_output_schema[0] |
| 59 | |
| 60 | # If output_dtypes is provided, use it for output schema. Otherwise |
| 61 | # the shape and type will be inferred. |
| 62 | if output_dtypes is not None: |
| 63 | if not isinstance(output_dtypes, list): |
| 64 | output_dtypes = [output_dtypes] * num_outputs |
| 65 | assert len(output_dtypes) == num_outputs |
| 66 | for dtype, scalar in zip(output_dtypes, |
| 67 | self.output_schema.all_scalars()): |
| 68 | scalar.set_type(dtype) |
| 69 | return |
| 70 | |
| 71 | # Fake execution of the function to infer shapes and types automatically |
| 72 | had_issues = False |
| 73 | try: |
| 74 | type_net = core.Net('_temp_type_and_shape_inference_net') |
| 75 | schema.InitEmptyRecord(type_net, input_record, enforce_types=True) |
| 76 | |
| 77 | function(type_net, self.input_record, self.output_schema, **kwargs) |
| 78 | (shapes, types) = workspace.InferShapesAndTypes([type_net], {}) |
| 79 | for i in range(num_outputs): |
nothing calls this directly
no test coverage detected