def _create_next_with_fake_client_output(tree): """Creates a next computation with a fake client output. This function is intended to be used by `get_canonical_form_for_iterative_process` to create a next computation with a fake client output when no client output is returned by the `next` function of the `tff.utils.IterativeProcess`. NOTE: This function does not assert that there is no client output in `tree`, the caller is expected to perform this check before calling this function. Args: tree: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A new `building_blocks.ComputationBuildingBlock` representing a next computaiton with a fake client output. """ if isinstance(tree.result, building_blocks.Tuple): arg_1 = tree.result[0] arg_2 = tree.result[1] else: arg_1 = building_blocks.Selection(tree.result, index=0) arg_2 = building_blocks.Selection(tree.result, index=1) empty_tuple = building_blocks.Tuple([]) client_output = building_block_factory.create_federated_value( empty_tuple, placements.CLIENTS) output = building_blocks.Tuple([arg_1, arg_2, client_output]) return building_blocks.Lambda(tree.parameter_name, tree.parameter_type, output)
def federated_value(value, placement): """Returns a federated value at `placement`, with `value` as the constituent. Deprecation warning: Using `tff.federated_value` with arguments other than simple Python constants is deprecated. When placing the result of a `tf_computation`, prefer `tff.federated_eval`. Args: value: A value of a non-federated TFF type to be placed. placement: The desired result placement (either `tff.SERVER` or `tff.CLIENTS`). Returns: A federated value with the given placement `placement`, and the member constituent `value` equal at all locations. Raises: TypeError: If the arguments are not of the appropriate types. """ if isinstance(value, value_impl.Value): warnings.warn( 'Deprecation warning: Using `tff.federated_value` with arguments ' 'other than simple Python constants is deprecated. When placing the ' 'result of a `tf_computation`, prefer `tff.federated_eval`.', DeprecationWarning) value = value_impl.to_value(value, None) if type_analysis.contains(value.type_signature, lambda t: t.is_federated()): raise TypeError('Cannot place value {} containing federated types at ' 'another placement; requested to be placed at {}.'.format( value, placement)) comp = building_block_factory.create_federated_value(value.comp, placement) comp = _bind_comp_as_reference(comp) return value_impl.Value(comp)
def federated_secure_modular_sum(arg): py_typecheck.check_type(arg, building_blocks.ComputationBuildingBlock) arg.type_signature.check_struct() if arg.type_signature.is_struct_with_python(): container_type = arg.type_signature.python_container else: container_type = None summand_arg = building_blocks.Selection(arg, index=0) raw_summed_values = building_block_factory.create_federated_sum(summand_arg) unplaced_modulus = building_blocks.Selection(arg, index=1) placed_modulus = building_block_factory.create_federated_value( unplaced_modulus, placements.SERVER) modulus_arg = building_block_factory.create_federated_zip( building_blocks.Struct([raw_summed_values, placed_modulus], container_type=container_type)) def map_structure_mod(summed_values, modulus): modulus = _ensure_structure(modulus, unplaced_modulus.type_signature, raw_summed_values.type_signature.member) return structure.map_structure(tf.math.mod, summed_values, modulus) modulus_fn = building_block_factory.create_tensorflow_binary_operator( map_structure_mod, operand_type=raw_summed_values.type_signature.member, second_operand_type=placed_modulus.type_signature.member) modulus_computed = building_block_factory.create_federated_apply( modulus_fn, modulus_arg) return modulus_computed
def federated_value(self, value, placement): """Implements `federated_value` as defined in `api/intrinsics.py`.""" # TODO(b/113112108): Verify that neither the value, nor any of its parts # are of a federated type. value = value_impl.to_value(value, None, self._context_stack) value = value_impl.ValueImpl.get_comp(value) comp = building_block_factory.create_federated_value(value, placement) return value_impl.ValueImpl(comp, self._context_stack)
def test_reduces_federated_value_at_server_to_equivalent_noarg_function(self): zero = building_block_factory.create_tensorflow_constant( computation_types.TensorType(tf.int32, shape=[]), 0) federated_value = building_block_factory.create_federated_value( zero, placements.SERVER) extracted_tf = transformations.consolidate_and_extract_local_processing( federated_value, DEFAULT_GRAPPLER_CONFIG) executable_tf = computation_wrapper_instances.building_block_to_computation( extracted_tf) self.assertEqual(executable_tf(), 0)
def test_strip_placement_federated_value_at_clients(self): int_data = building_blocks.Data('x', tf.int32) float_data = building_blocks.Data('x', tf.float32) fed_int = building_block_factory.create_federated_value( int_data, placements.CLIENTS) fed_float = building_block_factory.create_federated_value( float_data, placements.CLIENTS) tup = building_blocks.Struct([fed_int, fed_float], container_type=tuple) before = building_block_factory.create_federated_zip(tup) after, modified = tree_transformations.strip_placement(before) self.assertTrue(modified) self.assert_has_no_intrinsics_nor_federated_types(after) tuple_type = computation_types.StructWithPythonType( [(None, tf.int32), (None, tf.float32)], tuple) type_test_utils.assert_types_identical( before.type_signature, computation_types.at_clients(tuple_type)) type_test_utils.assert_types_identical(after.type_signature, tuple_type)
def federated_value(self, value, placement): """Implements `federated_value` as defined in `api/intrinsics.py`.""" value = value_impl.to_value(value, None, self._context_stack) if type_analysis.contains(value.type_signature, lambda t: t.is_federated()): raise TypeError('Cannt place value {} containing federated types at ' 'another placement; requested to be placed at {}.'.format( value, placement)) value = value_impl.ValueImpl.get_comp(value) comp = building_block_factory.create_federated_value(value, placement) comp = self._bind_comp_as_reference(comp) return value_impl.ValueImpl(comp, self._context_stack)
def federated_value(self, value, placement): """Implements `federated_value` as defined in `api/intrinsics.py`.""" value = value_impl.to_value(value, None, self._context_stack) if type_utils.type_tree_contains_types(value.type_signature, computation_types.FederatedType): raise TypeError('Cannt place value {} containing federated types at ' 'another placement; requested to be placed at {}.'.format( value, placement)) value = value_impl.ValueImpl.get_comp(value) comp = building_block_factory.create_federated_value(value, placement) return value_impl.ValueImpl(comp, self._context_stack)
def test_reduces_federated_value_at_clients_to_equivalent_noarg_function( self): zero = building_block_factory.create_tensorflow_constant( computation_types.TensorType(tf.int32, shape=[]), 0) federated_value = building_block_factory.create_federated_value( zero, placements.CLIENTS) federated_value_func = building_blocks.Lambda(None, None, federated_value) extracted_tf = compiler.consolidate_and_extract_local_processing( federated_value_func, DEFAULT_GRAPPLER_CONFIG) executable_tf = computation_impl.ConcreteComputation.from_building_block( extracted_tf) self.assertEqual(executable_tf(), 0)
def _create_before_and_after_broadcast_for_no_broadcast(tree): """Creates a before and after broadcast computations for the given `tree`. This function is intended to be used by `get_canonical_form_for_iterative_process` to create before and after broadcast computations for the given `tree` when there is no `intrinsic_defs.FEDERATED_BROADCAST` in `tree`. NOTE: This function does not assert that there is no `intrinsic_defs.FEDERATED_BROADCAST` in `tree`, the caller is expected to perform this check before calling this function. Args: tree: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A pair of the form `(before, after)`, where each of `before` and `after` is a `tff_framework.ComputationBuildingBlock` that represents a part of the result as specified by `transformations.force_align_and_split_by_intrinsics`. """ name_generator = building_block_factory.unique_name_generator(tree) parameter_name = next(name_generator) empty_tuple = building_blocks.Tuple([]) value = building_block_factory.create_federated_value( empty_tuple, placements.SERVER) before_broadcast = building_blocks.Lambda(parameter_name, tree.type_signature.parameter, value) parameter_name = next(name_generator) type_signature = computation_types.FederatedType( before_broadcast.type_signature.result.member, placements.CLIENTS) parameter_type = computation_types.NamedTupleType( [tree.type_signature.parameter, type_signature]) ref = building_blocks.Reference(parameter_name, parameter_type) arg = building_blocks.Selection(ref, index=0) call = building_blocks.Call(tree, arg) after_broadcast = building_blocks.Lambda(ref.name, ref.type_signature, call) return before_broadcast, after_broadcast
def _create_next_with_fake_client_output(tree): r"""Creates a next computation with a fake client output. This function returns the AST: Lambda | [Comp, Comp, Tuple] | [] In the AST, `Lambda` and the first two `Comps`s in the result of `Lambda` are `tree` and the empty `Tuple` is the fake client output. This function is intended to be used by `get_canonical_form_for_iterative_process` to create a next computation with a fake client output when no client output is returned by `tree` (which represents the `next` function of the `tff.utils.IterativeProcess`). As a result, this function does not assert that there is no client output in `tree` and it does not assert that `tree` has the expected structure, the caller is expected to perform these checks before calling this function. Args: tree: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A new `building_blocks.ComputationBuildingBlock` representing a next computaiton with a fake client output. """ if isinstance(tree.result, building_blocks.Tuple): arg_1 = tree.result[0] arg_2 = tree.result[1] else: arg_1 = building_blocks.Selection(tree.result, index=0) arg_2 = building_blocks.Selection(tree.result, index=1) empty_tuple = building_blocks.Tuple([]) client_output = building_block_factory.create_federated_value( empty_tuple, placements.CLIENTS) output = building_blocks.Tuple([arg_1, arg_2, client_output]) return building_blocks.Lambda(tree.parameter_name, tree.parameter_type, output)
def _create_dummy_before_and_after_broadcast(comp): """Creates a before and after broadcast computations for the given `comp`. This function is intended to be used instead of `transformations.force_align_and_split_by_intrinsic` to generate dummy before and after computations, when there is no `intrinsic_defs.FEDERATED_BROADCAST` present in `comp`. Note: This function does not assert that there is no `intrinsic_defs.FEDERATED_BROADCAST` present in `comp`, the caller is expected to perform this check before calling this function. Args: comp: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A pair of the form `(before, after)`, where each of `before` and `after` is a `tff_framework.ComputationBuildingBlock` that represents a part of the result as specified by `transformations.force_align_and_split_by_intrinsic`. """ name_generator = building_block_factory.unique_name_generator(comp) parameter_name = six.next(name_generator) empty_tuple = building_blocks.Tuple([]) federated_value_at_server = building_block_factory.create_federated_value( empty_tuple, placements.SERVER) before_broadcast = building_blocks.Lambda(parameter_name, comp.type_signature.parameter, federated_value_at_server) parameter_name = six.next(name_generator) type_signature = computation_types.FederatedType( before_broadcast.type_signature.result.member, placements.CLIENTS) parameter_type = computation_types.NamedTupleType( [comp.type_signature.parameter, type_signature]) ref = building_blocks.Reference(parameter_name, parameter_type) arg = building_blocks.Selection(ref, index=0) call = building_blocks.Call(comp, arg) after_broadcast = building_blocks.Lambda(ref.name, ref.type_signature, call) return before_broadcast, after_broadcast
def create_whimsy_called_federated_value( placement: placements.PlacementLiteral, value_type=tf.int32): value = building_blocks.Data('data', value_type) return building_block_factory.create_federated_value(value, placement)
def _create_before_and_after_aggregate_for_no_federated_secure_sum(tree): r"""Creates a before and after aggregate computations for the given `tree`. Lambda | Tuple | [Comp, Tuple] | [Tuple, []] | [] Lambda(x) | Call / \ Comp Tuple | [Sel(0), Sel(0)] / / Ref(x) Sel(1) / Ref(x) In the first AST, the first element returned by `Lambda`, `Comp`, is the result of the before aggregate returned by force aligning and splitting `tree` by `intrinsic_defs.FEDERATED_AGGREGATE.uri` and the second element returned by `Lambda` is an empty structure that represents the argument to the secure sum intrinsic. Therefore, the first AST has a type signature satisfying the requirements of before aggregate. In the second AST, `Comp` is the after aggregate returned by force aligning and splitting `tree` by intrinsic_defs.FEDERATED_AGGREGATE.uri; `Lambda` has a type signature satisfying the requirements of after aggregate; and the argument passed to `Comp` is a selection from the parameter of `Lambda` which intentionally drops `s4` on the floor. This function is intended to be used by `get_canonical_form_for_iterative_process` to create before and after broadcast computations for the given `tree` when there is no `intrinsic_defs.FEDERATED_SECURE_SUM` in `tree`. As a result, this function does not assert that there is no `intrinsic_defs.FEDERATED_SECURE_SUM` in `tree` and it does not assert that `tree` has the expected structure, the caller is expected to perform these checks before calling this function. Args: tree: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A pair of the form `(before, after)`, where each of `before` and `after` is a `tff_framework.ComputationBuildingBlock` that represents a part of the result as specified by `transformations.force_align_and_split_by_intrinsics`. """ name_generator = building_block_factory.unique_name_generator(tree) before_aggregate, after_aggregate = ( transformations.force_align_and_split_by_intrinsics( tree, [intrinsic_defs.FEDERATED_AGGREGATE.uri])) empty_tuple = building_blocks.Struct([]) value = building_block_factory.create_federated_value(empty_tuple, placements.CLIENTS) bitwidth = empty_tuple args = building_blocks.Struct([value, bitwidth]) result = building_blocks.Struct([before_aggregate.result, args]) before_aggregate = building_blocks.Lambda(before_aggregate.parameter_name, before_aggregate.parameter_type, result) ref_name = next(name_generator) s4_type = computation_types.FederatedType([], placements.SERVER) ref_type = computation_types.StructType([ after_aggregate.parameter_type[0], computation_types.StructType([ after_aggregate.parameter_type[1], s4_type, ]), ]) ref = building_blocks.Reference(ref_name, ref_type) sel_arg = building_blocks.Selection(ref, index=0) sel = building_blocks.Selection(ref, index=1) sel_s3 = building_blocks.Selection(sel, index=0) arg = building_blocks.Struct([sel_arg, sel_s3]) call = building_blocks.Call(after_aggregate, arg) after_aggregate = building_blocks.Lambda(ref.name, ref.type_signature, call) return before_aggregate, after_aggregate
def _create_before_and_after_broadcast_for_no_broadcast(tree): r"""Creates a before and after broadcast computations for the given `tree`. This function returns the two ASTs: Lambda | Tuple | [] Lambda(x) | Call / \ Comp Sel(0) / Ref(x) The first AST is an empty structure that has a type signature satisfying the requirements of before broadcast. In the second AST, `Comp` is `tree`; `Lambda` has a type signature satisfying the requirements of after broadcast; and the argument passed to `Comp` is a selection from the parameter of `Lambda` which intentionally drops `c2` on the floor. This function is intended to be used by `get_canonical_form_for_iterative_process` to create before and after broadcast computations for the given `tree` when there is no `intrinsic_defs.FEDERATED_BROADCAST` in `tree`. As a result, this function does not assert that there is no `intrinsic_defs.FEDERATED_BROADCAST` in `tree` and it does not assert that `tree` has the expected structure, the caller is expected to perform these checks before calling this function. Args: tree: An instance of `building_blocks.ComputationBuildingBlock`. Returns: A pair of the form `(before, after)`, where each of `before` and `after` is a `tff_framework.ComputationBuildingBlock` that represents a part of the result as specified by `transformations.force_align_and_split_by_intrinsics`. """ name_generator = building_block_factory.unique_name_generator(tree) parameter_name = next(name_generator) empty_tuple = building_blocks.Struct([]) value = building_block_factory.create_federated_value(empty_tuple, placements.SERVER) before_broadcast = building_blocks.Lambda(parameter_name, tree.type_signature.parameter, value) parameter_name = next(name_generator) type_signature = computation_types.FederatedType( before_broadcast.type_signature.result.member, placements.CLIENTS) parameter_type = computation_types.StructType( [tree.type_signature.parameter, type_signature]) ref = building_blocks.Reference(parameter_name, parameter_type) arg = building_blocks.Selection(ref, index=0) call = building_blocks.Call(tree, arg) after_broadcast = building_blocks.Lambda(ref.name, ref.type_signature, call) return before_broadcast, after_broadcast