2019-03-25 11:20:41 -06:00
|
|
|
# Copyright 2019, The TensorFlow Authors.
|
2018-12-04 16:50:21 -07:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
2019-03-25 11:20:41 -06:00
|
|
|
"""Implements DPQuery interface for normalized queries.
|
2018-12-04 16:50:21 -07:00
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import absolute_import
|
|
|
|
from __future__ import division
|
|
|
|
from __future__ import print_function
|
|
|
|
|
2019-05-15 17:06:15 -06:00
|
|
|
import collections
|
|
|
|
|
2019-04-29 15:00:20 -06:00
|
|
|
from distutils.version import LooseVersion
|
2019-03-25 11:20:41 -06:00
|
|
|
import tensorflow as tf
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-03-25 11:20:41 -06:00
|
|
|
from privacy.dp_query import dp_query
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-04-29 15:00:20 -06:00
|
|
|
if LooseVersion(tf.__version__) < LooseVersion('2.0.0'):
|
|
|
|
nest = tf.contrib.framework.nest
|
|
|
|
else:
|
|
|
|
nest = tf.nest
|
2018-12-04 16:50:21 -07:00
|
|
|
|
|
|
|
|
2019-03-25 11:20:41 -06:00
|
|
|
class NormalizedQuery(dp_query.DPQuery):
|
|
|
|
"""DPQuery for queries with a DPQuery numerator and fixed denominator."""
|
|
|
|
|
2019-05-15 17:06:15 -06:00
|
|
|
# pylint: disable=invalid-name
|
|
|
|
_GlobalState = collections.namedtuple(
|
|
|
|
'_GlobalState', ['numerator_state', 'denominator'])
|
|
|
|
|
2019-03-25 11:20:41 -06:00
|
|
|
def __init__(self, numerator_query, denominator):
|
|
|
|
"""Initializer for NormalizedQuery.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
numerator_query: A DPQuery for the numerator.
|
2019-05-13 12:28:33 -06:00
|
|
|
denominator: A value for the denominator. May be None if it will be
|
|
|
|
supplied via the set_denominator function before get_noised_result is
|
|
|
|
called.
|
2019-03-25 11:20:41 -06:00
|
|
|
"""
|
|
|
|
self._numerator = numerator_query
|
2019-05-15 17:06:15 -06:00
|
|
|
self._denominator = denominator
|
2019-03-25 11:20:41 -06:00
|
|
|
|
2019-06-04 11:14:09 -06:00
|
|
|
def set_ledger(self, ledger):
|
|
|
|
"""See base class."""
|
|
|
|
self._numerator.set_ledger(ledger)
|
|
|
|
|
2018-12-04 16:50:21 -07:00
|
|
|
def initial_global_state(self):
|
2019-05-13 12:28:33 -06:00
|
|
|
"""See base class."""
|
2019-05-15 17:06:15 -06:00
|
|
|
if self._denominator is not None:
|
|
|
|
denominator = tf.cast(self._denominator, tf.float32)
|
|
|
|
else:
|
|
|
|
denominator = None
|
|
|
|
return self._GlobalState(
|
|
|
|
self._numerator.initial_global_state(), denominator)
|
2018-12-04 16:50:21 -07:00
|
|
|
|
|
|
|
def derive_sample_params(self, global_state):
|
2019-05-13 12:28:33 -06:00
|
|
|
"""See base class."""
|
2019-05-15 17:06:15 -06:00
|
|
|
return self._numerator.derive_sample_params(global_state.numerator_state)
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-06-27 15:37:30 -06:00
|
|
|
def initial_sample_state(self, template):
|
2019-05-13 12:28:33 -06:00
|
|
|
"""See base class."""
|
2019-03-25 11:20:41 -06:00
|
|
|
# NormalizedQuery has no sample state beyond the numerator state.
|
2019-06-27 15:37:30 -06:00
|
|
|
return self._numerator.initial_sample_state(template)
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-05-13 12:28:33 -06:00
|
|
|
def preprocess_record(self, params, record):
|
|
|
|
return self._numerator.preprocess_record(params, record)
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-05-13 12:28:33 -06:00
|
|
|
def accumulate_preprocessed_record(
|
|
|
|
self, sample_state, preprocessed_record):
|
|
|
|
"""See base class."""
|
|
|
|
return self._numerator.accumulate_preprocessed_record(
|
|
|
|
sample_state, preprocessed_record)
|
2018-12-04 16:50:21 -07:00
|
|
|
|
2019-01-23 14:51:58 -07:00
|
|
|
def get_noised_result(self, sample_state, global_state):
|
2019-05-13 12:28:33 -06:00
|
|
|
"""See base class."""
|
2019-03-25 11:20:41 -06:00
|
|
|
noised_sum, new_sum_global_state = self._numerator.get_noised_result(
|
2019-05-15 17:06:15 -06:00
|
|
|
sample_state, global_state.numerator_state)
|
2019-03-25 11:20:41 -06:00
|
|
|
def normalize(v):
|
2019-05-15 17:06:15 -06:00
|
|
|
return tf.truediv(v, global_state.denominator)
|
2019-03-25 11:20:41 -06:00
|
|
|
|
2019-05-15 17:06:15 -06:00
|
|
|
return (nest.map_structure(normalize, noised_sum),
|
|
|
|
self._GlobalState(new_sum_global_state, global_state.denominator))
|
2019-03-25 11:20:41 -06:00
|
|
|
|
2019-05-13 12:28:33 -06:00
|
|
|
def merge_sample_states(self, sample_state_1, sample_state_2):
|
|
|
|
"""See base class."""
|
|
|
|
return self._numerator.merge_sample_states(sample_state_1, sample_state_2)
|