Part XII: Edge, Embedded, Streaming, and Federated Sensor AI
Chapter 64: Federated and Privacy-Preserving Sensor AI

Federated learning (FedAvg family) and non-IID sensors

"You told me to learn from a thousand people without meeting any of them. So I asked each to teach me privately, then quietly averaged what they said. The trouble was, no two of them lived in the same world."

A Diplomatic AI Agent

Prerequisites

This section assumes you can train a neural model with minibatch SGD and read a training curve (Chapter 13), and that you accept the premise of the previous section, Section 64.1: raw sensor data may not leave the device. It leans on the idea of distribution shift between data sources, treated in general in Chapter 66, and on leakage-safe, per-subject evaluation splits (Chapter 5). The mathematics is elementary: weighted averages and the SGD update rule.

The Big Picture

Section 64.1 established the constraint: the data stays on the device. This section supplies the mechanism that lets you still train one shared model from it. Federated learning ships the model to the data instead of the data to the model. Each device improves the model locally on its own sensor stream, and a server averages those improvements without ever seeing a raw sample. The canonical recipe, FedAvg, is deceptively simple, and it works beautifully when every client sees the same kind of data. Sensors break that assumption harder than almost any other data source: your gait is not mine, a phone in a pocket reads differently from one on an armband, and a warehouse robot and a home robot inhabit different physical worlds. That statistical heterogeneity, called non-IID data, is the central difficulty of federated sensing, and the FedAvg family exists to tame it. When you finish, you will be able to run a federated training round in your head, diagnose why it stalls on skewed sensor data, and name the fix.

FedAvg: ship the model, average the updates

The global objective is an average of per-client losses. With \(K\) clients, client \(k\) holding \(n_k\) local samples and \(n = \sum_k n_k\), federated training minimizes

\[ F(w) = \sum_{k=1}^{K} \frac{n_k}{n}\, F_k(w), \qquad F_k(w) = \frac{1}{n_k}\sum_{i \in \mathcal{D}_k} \ell(w; x_i, y_i). \]

The what of FedAvg (McMahan et al., AISTATS 2017) is a communication-round loop. In each round the server broadcasts the current weights \(w^t\) to a sampled subset of clients. Each selected client runs \(E\) local epochs of SGD on its own data, producing \(w_k^{t+1}\). The clients send back only those updated weights (or the delta), and the server forms the next global model as a size-weighted average,

\[ w^{t+1} = \sum_{k \in S_t} \frac{n_k}{\sum_{j\in S_t} n_j}\, w_k^{t+1}. \]

The why is communication. Naive distributed SGD would exchange a gradient after every minibatch, which over a cellular link is prohibitive (recall the radio-energy argument of Chapter 59). By letting each client take many local steps (\(E\) epochs) before synchronizing, FedAvg trades computation, which is cheap and local, for communication, which is expensive and shared. The when: use it whenever the data is partitioned across many devices that cannot pool it, and a single global model is still the goal. That is exactly the shape of a wearable fleet, a network of factory sensors, or a set of phones.

Key Insight

The number of local epochs \(E\) is the master dial of federated learning. Large \(E\) means fewer communication rounds and cheaper training, which is what you want. But each extra local step lets a client drift further toward its own optimum before the average pulls it back. When clients disagree about where the optimum is, averaging models that each ran far into their own valley can land the global model in a worse place than any of them started. Communication cost and statistical heterogeneity therefore pull \(E\) in opposite directions, and the whole FedAvg family is a search for a setting of \(E\) that is both cheap and stable.

Why sensor fleets are aggressively non-IID

Averaging assumes the things being averaged point roughly the same way. That holds when every client draws from the same distribution (independent and identically distributed, IID). Sensor fleets violate it along several axes at once, and understanding which axis you face determines the fix.

Feature skew is the most physical. The same activity produces different signals depending on sensor placement, body, and hardware: a phone in a trouser pocket, a smartwatch, and a chest strap record walking as three distinct accelerometer signatures (Chapter 26). Label skew is quantity imbalance: an office worker's wearable logs almost no swimming, an athlete's logs little sitting, so each client's label histogram \(P_k(y)\) is wildly different. Concept drift across clients means \(P_k(y \mid x)\) itself differs, for instance the same heart-rate pattern signaling exertion in one user and arrhythmia risk in another. On top of statistical heterogeneity sits systems heterogeneity: devices differ in speed, battery, and availability, so clients complete different numbers of local steps and some drop out mid-round.

The consequence has a name: client drift. When \(P_k\) differ, each client's local optimum \(w_k^\star\) sits somewhere different, and the FedAvg average of far-run local models is biased away from the true global optimum \(w^\star\). Empirically this shows up as an accuracy curve that climbs, then oscillates or plateaus well below what centralized training on the pooled data would reach. Non-IID data does not merely slow federated learning; past a point it caps the achievable accuracy.

Real-World Application: keyboard-free fall detection across a care-home fleet

A vendor deploys wrist wearables to a thousand elderly residents to detect falls from IMU data. Falls are rare and personal: a frail resident who shuffles produces motion statistics nothing like an active one, and a genuine fall looks different from a controlled sit-down that a brisk resident performs a hundred times a day. Under plain FedAvg with a generous \(E\), the global model swung toward whichever residents happened to be sampled each round, and its false-alarm rate lurched between deployments. The team diagnosed classic client drift from label and feature skew. They cut \(E\), added a proximal term to keep each local model near the global one (FedProx, below), and evaluated with a strictly subject-disjoint split so no resident appeared in both training and test (Chapter 5). The oscillation flattened, and the shared model finally beat the per-device models it had been losing to.

The FedAvg family: correcting client drift

The family keeps FedAvg's ship-model-average-updates skeleton and adds a term that fights drift. FedProx (Li et al., MLSys 2020) is the gentlest: each client minimizes its local loss plus a proximal penalty \(\tfrac{\mu}{2}\lVert w - w^t \rVert^2\) that anchors the local model to the broadcast global weights, so no client wanders too far in \(E\) epochs. It also tolerates stragglers by accepting partial local work. SCAFFOLD (Karimireddy et al., ICML 2020) is more surgical: it maintains control variates, per-client and global correction vectors that estimate the drift direction and subtract it from each local update, in effect variance-reducing the client updates. It converges in far fewer rounds on heterogeneous data at the cost of communicating and storing an extra vector the size of the model. FedAvgM (Hsu et al., 2019) simply applies momentum on the server when aggregating updates, which smooths the noisy round-to-round direction that skew induces. The how you choose: start with FedProx for a cheap, robust default; reach for SCAFFOLD when communication rounds are the binding cost and you can afford the extra state; add server momentum when the global curve is jittery.

The listing below simulates FedAvg versus FedProx on a deliberately skewed two-client problem so you can see drift and its correction without any networking. It is referenced in the discussion that follows.

import numpy as np

rng = np.random.default_rng(0)
# Two clients, opposite feature skew: same task, shifted inputs (non-IID).
def make_client(shift, n=400):
    X = rng.normal(shift, 1.0, size=(n, 2))
    y = (X[:, 0] + X[:, 1] > 2 * shift).astype(float)   # local decision boundary
    return X, y

clients = [make_client(-1.5), make_client(+1.5)]

def local_train(w, X, y, w_glob, mu, epochs=5, lr=0.1):
    for _ in range(epochs):
        z = X @ w
        p = 1 / (1 + np.exp(-z))
        grad = X.T @ (p - y) / len(y) + mu * (w - w_glob)  # mu>0 => FedProx
        w = w - lr * grad
    return w

def federated(mu, rounds=30):
    w = np.zeros(2)
    for _ in range(rounds):
        updates = [local_train(w.copy(), X, y, w, mu) for X, y in clients]
        w = np.mean(updates, axis=0)          # size-weighted avg (equal here)
    return w

def acc(w):
    correct = sum(((X @ w > 0).astype(float) == y).mean() for X, y in clients)
    return correct / len(clients)

print(f"FedAvg  (mu=0.0): global acc = {acc(federated(0.0)):.3f}")
print(f"FedProx (mu=0.5): global acc = {acc(federated(0.5)):.3f}")
Listing 64.2.1. A 40-line federated simulation with two feature-skewed clients. Setting the proximal weight \(\mu = 0\) recovers plain FedAvg, whose averaged model is pulled apart by the opposing local optima; \(\mu = 0.5\) is FedProx, whose anchor term keeps each local model near the global one and recovers a boundary that serves both clients. Running it shows FedProx reaching a higher global accuracy on this deliberately non-IID split.

As Listing 64.2.1 makes concrete, the only structural change from FedAvg to FedProx is one extra term in the gradient. That is the family's design signature: the communication loop is sacred; the correction lives inside the local objective or the aggregation step. Note also that this simulation, like all federated evaluation, must be read against a per-client, subject-disjoint test set, or the reported accuracy is an illusion, a theme Section 64.7 makes rigorous.

The Right Tool

You do not build the client-sampling, serialization, and aggregation machinery by hand. Flower (flwr) provides FedAvg, FedProx, and FedAvgM as drop-in strategies; you supply a NumPyClient that trains locally, and the framework runs the rounds across processes or real devices.

import flwr as fl

class SensorClient(fl.client.NumPyClient):
    def get_parameters(self, config):        return get_weights(model)
    def fit(self, parameters, config):
        set_weights(model, parameters)
        train_one_round(model, local_loader)   # your normal training loop
        return get_weights(model), len(local_loader.dataset), {}
    def evaluate(self, parameters, config):
        set_weights(model, parameters)
        return local_loss(model), len(val_loader.dataset), {"acc": local_acc(model)}

fl.simulation.start_simulation(
    client_fn=lambda cid: SensorClient(),
    num_clients=1000,
    strategy=fl.server.strategy.FedProx(proximal_mu=0.1),  # swap to FedAvg/FedAvgM freely
)
Listing 64.2.2. A full 1000-client federated simulation in roughly a dozen lines. Flower handles round orchestration, client sampling, weight (de)serialization, straggler timeouts, and the weighted aggregation. Hand-rolling that transport and strategy layer is hundreds of lines; here changing the algorithm is one constructor swap.

Listing 64.2.2 removes the plumbing, not the science: which strategy and what \(E\), \(\mu\), and client-sampling rate keep your skewed sensor fleet stable is still an experiment you own.

Research Frontier

The current work pushes past a single global model. FedProx and SCAFFOLD remain the reference drift correctors, but on heavily non-IID sensor data the field increasingly concedes that one model cannot fit every user and turns to personalization (Ditto, and per-client fine-tuning; the subject of Section 64.3) and to clustered federated learning that discovers device sub-populations and trains a model per cluster. A second frontier is communication efficiency at foundation-model scale: federated fine-tuning of large sensor and wearable backbones (Chapter 20) by exchanging only low-rank adapters rather than full weights, cutting per-round traffic by orders of magnitude. The open question that ties the two together is how to certify that an averaged or personalized model is safe and calibrated per client (Chapter 18) when the server never sees the data it was evaluated on.

Exercise

Extend Listing 64.2.1 to sweep the local-epoch count \(E \in \{1, 5, 20\}\) at \(\mu = 0\) (plain FedAvg) and plot global accuracy versus communication rounds for each. Then repeat at \(\mu = 0.5\). Confirm two predictions from this section: that large \(E\) speeds convergence when clients agree but destabilizes it when they are skewed, and that the proximal term buys back stability at large \(E\). Report the \((E, \mu)\) pair that reaches target accuracy in the fewest rounds, and state which force, communication or heterogeneity, was binding.

Self-Check

1. In one sentence each, state what FedAvg ships from server to client and what it ships back, and why this is cheaper than distributed SGD.

2. Name the three axes of non-IID sensor data (feature, label, concept) and give a wearable example of each.

3. FedProx and SCAFFOLD both fight client drift. Where does each place its correction (local objective vs. update direction), and what extra cost does SCAFFOLD pay for its faster convergence?

What's Next

In Section 64.3, we take seriously the admission this section ended on: when clients are heterogeneous enough, no single averaged model is the right answer. We turn from forcing everyone onto one global model to personalization and local adaptation, giving each device a model that starts from the shared knowledge but bends to fit its own wearer, placement, and hardware.