Beispiel #1
0
 def test_returns_string_for_placement(self):
   comp = building_blocks.Placement(placements.CLIENTS)
   compact_string = comp.compact_representation()
   self.assertEqual(compact_string, 'CLIENTS')
   formatted_string = comp.formatted_representation()
   self.assertEqual(formatted_string, 'CLIENTS')
   structural_string = comp.structural_representation()
   self.assertEqual(structural_string, 'Placement')
 def test_basic_functionality_of_placement_class(self):
   x = building_blocks.Placement(placement_literals.CLIENTS)
   self.assertEqual(str(x.type_signature), 'placement')
   self.assertEqual(x.uri, 'clients')
   self.assertEqual(repr(x), 'Placement(\'clients\')')
   self.assertEqual(x.compact_representation(), 'CLIENTS')
   x_proto = x.proto
   self.assertEqual(
       type_serialization.deserialize_type(x_proto.type), x.type_signature)
   self.assertEqual(x_proto.WhichOneof('computation'), 'placement')
   self.assertEqual(x_proto.placement.uri, x.uri)
   self._serialize_deserialize_roundtrip_test(x)
Beispiel #3
0
 def test_returns_true_for_placements(self):
     placement_1 = building_blocks.Placement(placements.CLIENTS)
     placement_2 = building_blocks.Placement(placements.CLIENTS)
     self.assertTrue(tree_analysis.trees_equal(placement_1, placement_2))
Beispiel #4
0
 def test_returns_false_for_placements_with_literals(self):
     placement_1 = building_blocks.Placement(placements.CLIENTS)
     placement_2 = building_blocks.Placement(placements.SERVER)
     self.assertFalse(tree_analysis.trees_equal(placement_1, placement_2))
Beispiel #5
0
def to_value(
    arg: Any,
    type_spec,
    context_stack: context_stack_base.ContextStack,
    parameter_type_hint=None,
) -> ValueImpl:
  """Converts the argument into an instance of `tff.Value`.

  The types of non-`tff.Value` arguments that are currently convertible to
  `tff.Value` include the following:

  * Lists, tuples, `structure.Struct`s, named tuples, and dictionaries, all
    of which are converted into instances of `tff.Tuple`.
  * Placement literals, converted into instances of `tff.Placement`.
  * Computations.
  * Python constants of type `str`, `int`, `float`, `bool`
  * Numpy objects inherting from `np.ndarray` or `np.generic` (the parent
    of numpy scalar types)

  Args:
    arg: Either an instance of `tff.Value`, or an argument convertible to
      `tff.Value`. The argument must not be `None`.
    type_spec: An optional `computation_types.Type` or value convertible to it
      by `computation_types.to_type` which specifies the desired type signature
      of the resulting value. This allows for disambiguating the target type
      (e.g., when two TFF types can be mapped to the same Python
      representations), or `None` if none available, in which case TFF tries to
      determine the type of the TFF value automatically.
    context_stack: The context stack to use.
    parameter_type_hint: An optional `computation_types.Type` or value
      convertible to it by `computation_types.to_type` which specifies an
      argument type to use in the case that `arg` is a
      `function_utils.PolymorphicFunction`.

  Returns:
    An instance of `tff.Value` corresponding to the given `arg`, and of TFF type
    matching the `type_spec` if specified (not `None`).

  Raises:
    TypeError: if `arg` is of an unsupported type, or of a type that does not
      match `type_spec`. Raises explicit error message if TensorFlow constructs
      are encountered, as TensorFlow code should be sealed away from TFF
      federated context.
  """
  py_typecheck.check_type(context_stack, context_stack_base.ContextStack)
  _check_symbol_binding_context(context_stack.current)
  if type_spec is not None:
    type_spec = computation_types.to_type(type_spec)
  if isinstance(arg, ValueImpl):
    result = arg
  elif isinstance(arg, building_blocks.ComputationBuildingBlock):
    result = ValueImpl(arg, context_stack)
  elif isinstance(arg, placement_literals.PlacementLiteral):
    result = ValueImpl(building_blocks.Placement(arg), context_stack)
  elif isinstance(
      arg, (computation_base.Computation, function_utils.PolymorphicFunction)):
    if isinstance(arg, function_utils.PolymorphicFunction):
      if parameter_type_hint is None:
        raise TypeError(
            'Polymorphic computations cannot be converted to TFF values '
            'without a type hint. Consider explicitly specifying the '
            'argument types of a computation before passing it to a '
            'function that requires a TFF value (such as a TFF intrinsic '
            'like `federated_map`). If you are a TFF developer and think '
            'this should be supported, consider providing `parameter_type_hint` '
            'as an argument to the encompassing `to_value` conversion.')
      parameter_type_hint = computation_types.to_type(parameter_type_hint)
      arg = arg.fn_for_argument_type(parameter_type_hint)
    py_typecheck.check_type(arg, computation_base.Computation)
    result = ValueImpl(arg.to_compiled_building_block(), context_stack)
  elif type_spec is not None and type_spec.is_sequence():
    result = _wrap_sequence_as_value(arg, type_spec.element, context_stack)
  elif isinstance(arg, structure.Struct):
    result = ValueImpl(
        building_blocks.Struct([
            (k, ValueImpl.get_comp(to_value(v, None, context_stack)))
            for k, v in structure.iter_elements(arg)
        ]), context_stack)
  elif py_typecheck.is_named_tuple(arg):
    items = arg._asdict().items()  # pytype: disable=attribute-error
    result = _dictlike_items_to_value(items, context_stack, type(arg))
  elif py_typecheck.is_attrs(arg):
    items = attr.asdict(
        arg, dict_factory=collections.OrderedDict, recurse=False).items()
    result = _dictlike_items_to_value(items, context_stack, type(arg))
  elif isinstance(arg, dict):
    if isinstance(arg, collections.OrderedDict):
      items = arg.items()
    else:
      items = sorted(arg.items())
    result = _dictlike_items_to_value(items, context_stack, type(arg))
  elif isinstance(arg, (tuple, list)):
    result = ValueImpl(
        building_blocks.Struct(
            [ValueImpl.get_comp(to_value(x, None, context_stack)) for x in arg],
            type(arg)), context_stack)
  elif isinstance(arg, tensorflow_utils.TENSOR_REPRESENTATION_TYPES):
    result = _wrap_constant_as_value(arg, context_stack)
  elif isinstance(arg, (tf.Tensor, tf.Variable)):
    raise TypeError(
        'TensorFlow construct {} has been encountered in a federated '
        'context. TFF does not support mixing TF and federated orchestration '
        'code. Please wrap any TensorFlow constructs with '
        '`tff.tf_computation`.'.format(arg))
  else:
    raise TypeError(
        'Unable to interpret an argument of type {} as a TFF value.'.format(
            py_typecheck.type_string(type(arg))))
  py_typecheck.check_type(result, ValueImpl)
  if (type_spec is not None and
      not type_spec.is_assignable_from(result.type_signature)):
    raise TypeError(
        'The supplied argument maps to TFF type {}, which is incompatible with '
        'the requested type {}.'.format(result.type_signature, type_spec))
  return result
Beispiel #6
0
def to_value(arg, type_spec, context_stack):
    """Converts the argument into an instance of `tff.Value`.

  The types of non-`tff.Value` arguments that are currently convertible to
  `tff.Value` include the following:

  * Lists, tuples, anonymous tuples, named tuples, and dictionaries, all
    of which are converted into instances of `tff.Tuple`.
  * Placement literals, converted into instances of `tff.Placement`.
  * Computations.
  * Python constants of type `str`, `int`, `float`, `bool`
  * Numpy objects inherting from `np.ndarray` or `np.generic` (the parent
    of numpy scalar types)

  Args:
    arg: Either an instance of `tff.Value`, or an argument convertible to
      `tff.Value`. The argument must not be `None`.
    type_spec: A type specifier that allows for disambiguating the target type
      (e.g., when two TFF types can be mapped to the same Python
      representations), or `None` if none available, in which case TFF tries to
      determine the type of the TFF value automatically.
    context_stack: The context stack to use.

  Returns:
    An instance of `tff.Value` corresponding to the given `arg`, and of TFF type
    matching the `type_spec` if specified (not `None`).

  Raises:
    TypeError: if `arg` is of an unsupported type, or of a type that does not
      match `type_spec`. Raises explicit error message if TensorFlow constructs
      are encountered, as TensorFlow code should be sealed away from TFF
      federated context.
  """
    py_typecheck.check_type(context_stack, context_stack_base.ContextStack)
    if type_spec is not None:
        type_spec = computation_types.to_type(type_spec)
        type_utils.check_well_formed(type_spec)
    if isinstance(arg, ValueImpl):
        result = arg
    elif isinstance(arg, building_blocks.ComputationBuildingBlock):
        result = ValueImpl(arg, context_stack)
    elif isinstance(arg, placement_literals.PlacementLiteral):
        result = ValueImpl(building_blocks.Placement(arg), context_stack)
    elif isinstance(arg, computation_base.Computation):
        result = ValueImpl(
            building_blocks.CompiledComputation(
                computation_impl.ComputationImpl.get_proto(arg)),
            context_stack)
    elif type_spec is not None and isinstance(type_spec,
                                              computation_types.SequenceType):
        result = _wrap_sequence_as_value(arg, type_spec.element, context_stack)
    elif isinstance(arg, anonymous_tuple.AnonymousTuple):
        result = ValueImpl(
            building_blocks.Tuple([
                (k, ValueImpl.get_comp(to_value(v, None, context_stack)))
                for k, v in anonymous_tuple.to_elements(arg)
            ]), context_stack)
    elif py_typecheck.is_named_tuple(arg):
        result = to_value(arg._asdict(), None, context_stack)
    elif py_typecheck.is_attrs(arg):
        result = to_value(
            attr.asdict(arg,
                        dict_factory=collections.OrderedDict,
                        recurse=False), None, context_stack)
    elif isinstance(arg, dict):
        if isinstance(arg, collections.OrderedDict):
            items = six.iteritems(arg)
        else:
            items = sorted(six.iteritems(arg))
        value = building_blocks.Tuple([
            (k, ValueImpl.get_comp(to_value(v, None, context_stack)))
            for k, v in items
        ])
        result = ValueImpl(value, context_stack)
    elif isinstance(arg, (tuple, list)):
        result = ValueImpl(
            building_blocks.Tuple([
                ValueImpl.get_comp(to_value(x, None, context_stack))
                for x in arg
            ]), context_stack)
    elif isinstance(arg, dtype_utils.TENSOR_REPRESENTATION_TYPES):
        result = _wrap_constant_as_value(arg, context_stack)
    elif isinstance(arg, (tf.Tensor, tf.Variable)):
        raise TypeError(
            'TensorFlow construct {} has been encountered in a federated '
            'context. TFF does not support mixing TF and federated orchestration '
            'code. Please wrap any TensorFlow constructs with '
            '`tff.tf_computation`.'.format(arg))
    else:
        raise TypeError(
            'Unable to interpret an argument of type {} as a TFF value.'.
            format(py_typecheck.type_string(type(arg))))
    py_typecheck.check_type(result, ValueImpl)
    if (type_spec is not None and not type_utils.is_assignable_from(
            type_spec, result.type_signature)):
        raise TypeError(
            'The supplied argument maps to TFF type {}, which is incompatible with '
            'the requested type {}.'.format(result.type_signature, type_spec))
    return result
Beispiel #7
0
def to_value(
    arg: Any,
    type_spec,
    parameter_type_hint=None,
) -> Value:
    """Converts the argument into an instance of the abstract class `tff.Value`.

  Instances of `tff.Value` represent TFF values that appear internally in
  federated computations. This helper function can be used to wrap a variety of
  Python objects as `tff.Value` instances to allow them to be passed as
  arguments, used as functions, or otherwise manipulated within bodies of
  federated computations.

  At the moment, the supported types include:

  * Simple constants of `str`, `int`, `float`, and `bool` types, mapped to
    values of a TFF tensor type.

  * Numpy arrays (`np.ndarray` objects), also mapped to TFF tensors.

  * Dictionaries (`collections.OrderedDict` and unordered `dict`), `list`s,
    `tuple`s, `namedtuple`s, and `Struct`s, all of which are mapped to
    TFF tuple type.

  * Computations (constructed with either the `tff.tf_computation` or with the
    `tff.federated_computation` decorator), typically mapped to TFF functions.

  * Placement literals (`tff.CLIENTS`, `tff.SERVER`), mapped to values of the
    TFF placement type.

  This function is also invoked when attempting to execute a TFF computation.
  All arguments supplied in the invocation are converted into TFF values prior
  to execution. The types of Python objects that can be passed as arguments to
  computations thus matches the types listed here.

  Args:
    arg: An instance of one of the Python types that are convertible to TFF
      values (instances of `tff.Value`).
    type_spec: An optional type specifier that allows for disambiguating the
      target type (e.g., when two TFF types can be mapped to the same Python
      representations). If not specified, TFF tried to determine the type of the
      TFF value automatically.
    parameter_type_hint: An optional `tff.Type` or value convertible to it by
      `tff.to_type()` which specifies an argument type to use in the case that
      `arg` is a `function_utils.PolymorphicFunction`.

  Returns:
    An instance of `tff.Value` as described above.

  Raises:
    TypeError: if `arg` is of an unsupported type, or of a type that does not
      match `type_spec`. Raises explicit error message if TensorFlow constructs
      are encountered, as TensorFlow code should be sealed away from TFF
      federated context.
  """
    if type_spec is not None:
        type_spec = computation_types.to_type(type_spec)
    if isinstance(arg, Value):
        result = arg
    elif isinstance(arg, building_blocks.ComputationBuildingBlock):
        result = Value(arg)
    elif isinstance(arg, placements.PlacementLiteral):
        result = Value(building_blocks.Placement(arg))
    elif isinstance(
            arg,
        (computation_base.Computation, function_utils.PolymorphicFunction)):
        if isinstance(arg, function_utils.PolymorphicFunction):
            if parameter_type_hint is None:
                raise TypeError(
                    'Polymorphic computations cannot be converted to `tff.Value`s '
                    'without a type hint. Consider explicitly specifying the '
                    'argument types of a computation before passing it to a '
                    'function that requires a `tff.Value` (such as a TFF intrinsic '
                    'like `federated_map`). If you are a TFF developer and think '
                    'this should be supported, consider providing `parameter_type_hint` '
                    'as an argument to the encompassing `to_value` conversion.'
                )
            parameter_type_hint = computation_types.to_type(
                parameter_type_hint)
            arg = arg.fn_for_argument_type(parameter_type_hint)
        py_typecheck.check_type(arg, computation_base.Computation)
        result = Value(arg.to_compiled_building_block())
    elif type_spec is not None and type_spec.is_sequence():
        result = _wrap_sequence_as_value(arg, type_spec.element)
    elif isinstance(arg, structure.Struct):
        items = structure.iter_elements(arg)
        result = _dictlike_items_to_value(items, type_spec, None)
    elif py_typecheck.is_named_tuple(arg):
        items = arg._asdict().items()
        result = _dictlike_items_to_value(items, type_spec, type(arg))
    elif py_typecheck.is_attrs(arg):
        items = attr.asdict(arg,
                            dict_factory=collections.OrderedDict,
                            recurse=False).items()
        result = _dictlike_items_to_value(items, type_spec, type(arg))
    elif isinstance(arg, dict):
        if isinstance(arg, collections.OrderedDict):
            items = arg.items()
        else:
            items = sorted(arg.items())
        result = _dictlike_items_to_value(items, type_spec, type(arg))
    elif isinstance(arg, (tuple, list)):
        items = zip(itertools.repeat(None), arg)
        result = _dictlike_items_to_value(items, type_spec, type(arg))
    elif isinstance(arg, tensorflow_utils.TENSOR_REPRESENTATION_TYPES):
        result = _wrap_constant_as_value(arg)
    elif isinstance(arg, (tf.Tensor, tf.Variable)):
        raise TypeError(
            'TensorFlow construct {} has been encountered in a federated '
            'context. TFF does not support mixing TF and federated orchestration '
            'code. Please wrap any TensorFlow constructs with '
            '`tff.tf_computation`.'.format(arg))
    else:
        raise TypeError(
            'Unable to interpret an argument of type {} as a `tff.Value`.'.
            format(py_typecheck.type_string(type(arg))))
    py_typecheck.check_type(result, Value)
    if (type_spec is not None
            and not type_spec.is_assignable_from(result.type_signature)):
        raise TypeError(
            'The supplied argument maps to TFF type {}, which is incompatible with '
            'the requested type {}.'.format(result.type_signature, type_spec))
    return result
Beispiel #8
0
 def test_placement_children_is_empty(self):
     placement = building_blocks.Placement(placements.CLIENTS)
     self.assertEqual([], list(placement.children()))