1

I'm following this tutorial to get started with tensorflow federated. My aim is to run federated sgd (not federated avg) with some manipulations on client gradient values before they are sent to the server.

Before moving forward, to briefly reiterate the federated sgd process, for each turn clients will send their computed gradients (not updated weights) to the server, the server aggregates them and broadcasts the updated model to the clients.

Now from what I've gathered so far, I can use the function build_federated_sgd_process instead of build_federated_averaging_process in the mentioned tutorial to perform federated sgd the way described above.

Where I'm lost is, I need to clip the client gradients and add some noise to them (independently generated for each gradient value) before sending the gradients to the server and I'm not sure how to do it. Generating the noise is straightforward enough, but which function should I modify/implement to be able to do apply the noise to the gradients?

Saam
  • 385
  • 1
  • 3
  • 12

1 Answers1

1

build_federated_sgd_process is fully-canned; it is really designed to serve as a reference implementation, not as a point of extensibility.

I believe what you are looking for is the function that build_federated_sgd_process calls under the hoos, tff.learning.framework.build_model_delta_optimizer_process. This function allows you to supply your own mapping from a model function (IE, a zero-arg callable that returns a tff.learning.Model) to a tff.learning.framework.ClientDeltaFn.

Your ClientDeltaFn would look something like:

@tf.function
def _clip_and_noise(grads):
  return ...

class ClippedGradClientDeltaFn(tff.learning.framework.ClientDeltaFn)

def __init__(self, model, ...):
  self._model = model
  ...

@tf.function
def __call__(dataset, weights):
  # Compute gradients grads
  return _clip_and_noise(grads)

And you would be able to construct a tff.templates.IterativeProcess by calling:

def clipped_sgd(model_fn: Callable[[], model_lib.Model]) -> ClippedGradClientDeltaFn:
    return ClippedGradClientDeltaFn(
        model_fn(),
        ...)

iterproc = optimizer_utils.build_model_delta_optimizer_process(
      model_fn, model_to_client_delta_fn=clipped_sgd, ...)

as more or less in the body of build_federated_sgd_process.

It sounds to me like you are interested in differential privacy; TFF is actually designed to compose with differential privacy generally through the aggregation processes rather than writing different client updates, though this is certainly one approach. See the pointers from the TFF for research documentation for idiomatic ways to wire differential privacy in to TFF.

Keith Rush
  • 1,360
  • 7
  • 6
  • Hey @Keith-Rush. Thanks a lot for the elaborate answer. I tried to make it work and your answer is intuitive and certainly correct, but I got lost in details, e.g. in implementing the `call` function; I looked at its implementation in the class `ClientSgd` for the `build_federated_sgd_process` function and I wasn't sure about some of the stuff in there, whether to include them or not. Would a quick and dirty modification of the class `ClientSgd` and **clip_and_nois**ing `flat_grads` in `reduce_fn` right after obtaining it from gradient tape do the trick? – Saam Oct 20 '20 at 16:31
  • my `_clip_and_noise` function is simply `return tf.clip_by_norm(grads,1.0) + tf.random.uniform(shape=tf.shape(grads), minval=minv, maxval=maxv, dtype=tf.float32)`. And you're absolutely right, I'm working on a DP deep learning scheme, but the noise addition mechanism is a bit different, also the upper-lower bound calculations. – Saam Oct 20 '20 at 16:33
  • 1
    That definitely could work. The appropriate place to insert the clipping and noising will depend on the semantics of differential privacy desired. Clipping and noising *inside* the `_reduce_fn` would give example-level differential privacy; if you desire *user*-level differential privacy, the appropriate place would be before returning [`weights_delta`](https://github.com/tensorflow/federated/blob/master/tensorflow_federated/python/learning/federated_sgd.py#L135) – Keith Rush Oct 21 '20 at 02:22
  • 1
    Another option for something quick is forking the [`simple_fedavg`](https://github.com/tensorflow/federated/blob/master/tensorflow_federated/python/examples/simple_fedavg/simple_fedavg_tff.py#L103) example implementation; you could implement the clip and noise [before returning from the clients](https://github.com/tensorflow/federated/blob/master/tensorflow_federated/python/examples/simple_fedavg/simple_fedavg_tff.py#L106) – Keith Rush Oct 21 '20 at 02:24
  • awesome! Thanks a lot for the help :) – Saam Oct 21 '20 at 05:28