コード例 #1
0
def _dp_factory(
    config: DifferentialPrivacyConfig
) -> dp_factory.DifferentiallyPrivateFactory:
    """Creates DifferentiallyPrivateFactory based on config settings."""
    if isinstance(config.clipping, FixedClippingConfig):
        stddev = config.clipping.clip * config.noise_multiplier
        query = tfp.GaussianAverageQuery(l2_norm_clip=config.clipping.clip,
                                         sum_stddev=stddev,
                                         denominator=config.clients_per_round)
    elif isinstance(config.clipping, AdaptiveClippingConfig):
        query = tfp.QuantileAdaptiveClipAverageQuery(
            initial_l2_norm_clip=config.clipping.initial_clip,
            noise_multiplier=config.noise_multiplier,
            denominator=config.clients_per_round,
            target_unclipped_quantile=config.clipping.target_quantile,
            learning_rate=config.clipping.learning_rate,
            clipped_count_stddev=config.clipped_count_stddev,
            expected_num_records=config.clients_per_round,
            geometric_update=True)
    else:
        raise TypeError(
            f'config.clipping is not a supported type of ClippingConfig. Found '
            f'type {type(config.clipping)}.')

    return dp_factory.DifferentiallyPrivateFactory(query)
コード例 #2
0
  def test_simple_sum(self):
    agg_factory = dp_factory.DifferentiallyPrivateFactory(_test_dp_query)
    value_type = computation_types.to_type(tf.float32)
    process = agg_factory.create(value_type)

    # The test query has clip 1.0 and no noise, so this computes clipped sum.

    state = process.initialize()

    client_data = [0.5, 1.0, 1.5]
    output = process.next(state, client_data)
    self.assertAllClose(2.5, output.result)
コード例 #3
0
  def test_inner_sum(self):
    agg_factory = dp_factory.DifferentiallyPrivateFactory(
        _test_dp_query, _test_inner_agg_factory)
    value_type = computation_types.to_type(tf.float32)
    process = agg_factory.create(value_type)

    # The test query has clip 1.0 and no noise, so this computes clipped sum.
    # Inner agg adds another 1.0 (post-clipping).

    state = process.initialize()
    self.assertAllEqual(0, state[1])

    client_data = [0.5, 1.0, 1.5]
    output = process.next(state, client_data)
    self.assertAllEqual(1, output.state[1])
    self.assertAllClose(3.5, output.result)
    self.assertAllEqual(test_utils.MEASUREMENT_CONSTANT,
                        output.measurements['record_agg_process'])
コード例 #4
0
  def to_factory(self) -> dp_factory.DifferentiallyPrivateFactory:
    """Creates factory based on config settings."""
    if self._clipping.is_fixed:
      stddev = self._clipping.clip * self._noise_multiplier
      query = tfp.GaussianAverageQuery(
          l2_norm_clip=self._clipping.clip,
          sum_stddev=stddev,
          denominator=self._clients_per_round)
    else:
      query = tfp.QuantileAdaptiveClipAverageQuery(
          initial_l2_norm_clip=self._clipping.clip.initial_estimate,
          noise_multiplier=self._noise_multiplier,
          denominator=self._clients_per_round,
          target_unclipped_quantile=self._clipping.clip.target_quantile,
          learning_rate=self._clipping.clip.learning_rate,
          clipped_count_stddev=self._clipped_count_stddev,
          expected_num_records=self._clients_per_round,
          geometric_update=True)

    return dp_factory.DifferentiallyPrivateFactory(query)
コード例 #5
0
    def test_structure_sum(self):
        agg_factory = dp_factory.DifferentiallyPrivateFactory(_test_dp_query)
        value_type = computation_types.to_type([tf.float32, tf.float32])
        process = agg_factory.create_unweighted(value_type)

        # The test query has clip 1.0 and no noise, so this computes clipped sum.

        state = process.initialize()

        # pyformat: disable
        client_data = [
            [0.1, 0.2],  # not clipped (norm < 1)
            [5 / 13, 12 / 13],  # not clipped (norm == 1)
            [3.0, 4.0]  # clipped to 3/5, 4/5
        ]
        output = process.next(state, client_data)

        expected_result = [0.1 + 5 / 13 + 3 / 5, 0.2 + 12 / 13 + 4 / 5]
        # pyformat: enable
        self.assertAllClose(expected_result, output.result)
コード例 #6
0
    def test_type_properties(self, value_type, inner_agg_factory):
        agg_factory = dp_factory.DifferentiallyPrivateFactory(
            _test_dp_query, inner_agg_factory)
        self.assertIsInstance(agg_factory,
                              factory.UnweightedAggregationFactory)
        value_type = computation_types.to_type(value_type)
        process = agg_factory.create_unweighted(value_type)
        self.assertIsInstance(process, aggregation_process.AggregationProcess)

        query_state = _test_dp_query.initial_global_state()
        query_state_type = type_conversions.type_from_tensors(query_state)
        query_metrics_type = type_conversions.type_from_tensors(
            _test_dp_query.derive_metrics(query_state))

        inner_state_type = tf.int32 if inner_agg_factory else ()

        server_state_type = computation_types.at_server(
            (query_state_type, inner_state_type))
        expected_initialize_type = computation_types.FunctionType(
            parameter=None, result=server_state_type)
        self.assertTrue(
            process.initialize.type_signature.is_equivalent_to(
                expected_initialize_type))

        inner_measurements_type = tf.int32 if inner_agg_factory else ()
        expected_measurements_type = computation_types.at_server(
            collections.OrderedDict(
                query_metrics=query_metrics_type,
                record_agg_process=inner_measurements_type))

        expected_next_type = computation_types.FunctionType(
            parameter=collections.OrderedDict(
                state=server_state_type,
                value=computation_types.at_clients(value_type)),
            result=measured_process.MeasuredProcessOutput(
                state=server_state_type,
                result=computation_types.at_server(value_type),
                measurements=expected_measurements_type))
        self.assertTrue(
            process.next.type_signature.is_equivalent_to(expected_next_type))
コード例 #7
0
    def test_adaptive_query(self):
        query = tfp.QuantileAdaptiveClipSumQuery(initial_l2_norm_clip=1.0,
                                                 noise_multiplier=0.0,
                                                 target_unclipped_quantile=1.0,
                                                 learning_rate=1.0,
                                                 clipped_count_stddev=0.0,
                                                 expected_num_records=3.0,
                                                 geometric_update=False)
        agg_factory = dp_factory.DifferentiallyPrivateFactory(query)
        value_type = computation_types.to_type(tf.float32)
        process = agg_factory.create_unweighted(value_type)

        state = process.initialize()

        client_data = [0.5, 1.5, 2.0]  # Two clipped on first round.
        expected_result = 0.5 + 1.0 + 1.0
        output = process.next(state, client_data)
        self.assertAllClose(expected_result, output.result)

        # Clip is increased by 2/3 to 5/3.
        expected_result = 0.5 + 1.5 + 5 / 3
        output = process.next(output.state, client_data)
        self.assertAllClose(expected_result, output.result)
コード例 #8
0
 def test_incorrect_value_type_raises(self, bad_value_type):
   agg_factory = dp_factory.DifferentiallyPrivateFactory(_test_dp_query)
   with self.assertRaises(TypeError):
     agg_factory.create(bad_value_type)
コード例 #9
0
 def test_init_non_agg_factory_raises(self):
   with self.assertRaises(TypeError):
     dp_factory.DifferentiallyPrivateFactory(_test_dp_query,
                                             'not an agg factory')