Hierarchical Regional Aggregation Topologies

A flat federated topology sends every client’s update to one server, which makes the server a bandwidth bottleneck, a latency bottleneck, and a single point at which every update in the fleet is present at once. Inserting a tier of regional aggregators fixes the first two and changes the third: raw client updates now land at a regional node instead. Whether that is an improvement or a new exposure depends entirely on what the regional tier is allowed to see, which is a cryptographic question rather than a topology one. This page works through both, under model synchronization strategies in Federated Learning Workflows for Geospatial Data.

Parameter Configuration and Calibration

  • fan_in — clients per regional aggregator. Server ingress falls by roughly this factor. Values between 8 and 64 are typical; beyond that the regional node becomes its own bottleneck and its failure takes out a whole region’s round.
  • regional_rounds — local aggregations per global round. Running several regional rounds before a global sync reduces cross-region traffic further and lets regional models specialise, at the cost of divergence between regions. One to three is the usual range; beyond that the global merge starts to lose the specialisation it was supposed to combine.
  • secagg_scope — where masking is applied. Three options: client-to-regional only (regional node sees the regional aggregate, not individual clients), client-to-global end-to-end (regional node sees nothing useful, and merely forwards), or none. Only the first two are defensible, and the second is strictly stronger.
  • min_clients_per_region — the floor for a regional aggregate to be forwarded. A regional aggregate over three clients is close to one client’s update. Below the floor, either hold the aggregate for the next round or forward the masked updates directly to the global tier.
Topology Server ingress What the middle tier sees Extra latency
Flat star n×n \times model n/a none
Regional, SecAgg to region n/f×n/f \times model the regional aggregate one hop
Regional, SecAgg end-to-end n/f×n/f \times model ciphertext only one hop + key setup
Regional, no SecAgg n/f×n/f \times model every client update one hop
Server ingress per round against fan-in Three rising curves of server ingress against cohort size on a logarithmic axis. The flat topology reaches about 50 gigabytes per round at four thousand clients. A fan-in of eight divides that by eight and a fan-in of thirty-two by thirty-two, at the cost of a middle tier that must be covered by secure aggregation. Server ingress per round against fan-in 12.4 MB model, one upload per client per round 100 1000 0 20000 40000 clients per round server ingress (MB) flat star fan-in 8 fan-in 32
The saving is real and it is not free: every regional node is a place client updates arrive, which is why the masking has to reach at least that far.

Reference Implementation

python
from __future__ import annotations

import math
from dataclasses import dataclass, field
from typing import Mapping, Sequence


class RegionTooSmall(RuntimeError):
    """A regional aggregate would expose too few clients to forward."""


@dataclass(frozen=True)
class Topology:
    """A two-tier aggregation plan and the properties that follow from it."""

    clients: int
    fan_in: int
    model_mb: float
    regional_rounds: int = 1
    min_clients_per_region: int = 8

    @property
    def regions(self) -> int:
        return max(1, math.ceil(self.clients / self.fan_in))

    def server_ingress_mb(self) -> float:
        """Traffic reaching the global server per global round."""
        return self.regions * self.model_mb

    def regional_ingress_mb(self) -> float:
        """Traffic reaching ONE regional aggregator per global round."""
        return self.fan_in * self.model_mb * self.regional_rounds

    def flat_ingress_mb(self) -> float:
        return self.clients * self.model_mb

    def saving(self) -> float:
        return 1.0 - self.server_ingress_mb() / self.flat_ingress_mb()


@dataclass
class RegionalAggregator:
    """One middle-tier node. Holds masked updates only if SecAgg reaches the region."""

    region: str
    topology: Topology
    _received: list[tuple[str, float]] = field(default_factory=list)

    def submit(self, client_id: str, masked_norm: float) -> None:
        self._received.append((client_id, masked_norm))

    def forward(self) -> tuple[float, int]:
        """Aggregate and forward, refusing to expose an under-populated region.

        Refusing is the correct default: a regional aggregate over a handful of
        clients is close to an individual update, and forwarding it upward would
        make the middle tier a disclosure point rather than a bandwidth optimisation.
        """
        if len(self._received) < self.topology.min_clients_per_region:
            raise RegionTooSmall(
                f"{self.region}: {len(self._received)} clients, floor is "
                f"{self.topology.min_clients_per_region} — hold or forward masked"
            )
        total = sum(v for _, v in self._received)
        count = len(self._received)
        self._received.clear()
        return total / count, count


def divergence_bound(regional_rounds: int, lr: float, grad_norm: float) -> float:
    """Worst-case drift between two regional models before a global merge.

    Regional specialisation is the point of the middle tier and its risk: after
    `regional_rounds` local steps two regions can be this far apart, and a naive
    average of two badly diverged models is worse than either.
    """
    return 2.0 * regional_rounds * lr * grad_norm

Validation Checkpoint

python
def _validate() -> None:
    flat = Topology(clients=1024, fan_in=1024, model_mb=12.4)
    tiered = Topology(clients=1024, fan_in=8, model_mb=12.4)

    # 1. The tier must actually reduce server ingress by roughly the fan-in.
    assert tiered.server_ingress_mb() < flat.flat_ingress_mb() / 7
    assert 0.85 < tiered.saving() < 0.95, tiered.saving()

    # 2. The saving at the server is paid for at the regional node.
    assert tiered.regional_ingress_mb() == 8 * 12.4

    # 3. More regional rounds increase regional traffic, not server traffic.
    chatty = Topology(clients=1024, fan_in=8, model_mb=12.4, regional_rounds=3)
    assert chatty.server_ingress_mb() == tiered.server_ingress_mb()
    assert chatty.regional_ingress_mb() == 3 * tiered.regional_ingress_mb()

    # 4. An under-populated region must refuse to forward.
    node = RegionalAggregator("islet", tiered)
    for i in range(4):
        node.submit(f"c{i}", 1.0)
    try:
        node.forward()
    except RegionTooSmall as exc:
        assert "floor is 8" in str(exc)
    else:
        raise AssertionError("a small region must refuse to forward")

    # 5. A populated region forwards a mean and its contributor count.
    for i in range(8):
        node.submit(f"d{i}", 2.0)
    mean, count = node.forward()
    assert abs(mean - 2.0) < 1e-9 and count == 12

    # 6. Divergence grows linearly in the number of regional rounds.
    assert abs(divergence_bound(3, 0.01, 1.0) / divergence_bound(1, 0.01, 1.0) - 3.0) < 1e-9

    print("hierarchical topology: all assertions passed")


_validate()
How far regions drift before the global merge Two rising curves against the number of regional rounds run before a global merge. The worst-case divergence bound grows linearly. The measured penalty the merge pays grows faster than linearly, so past about three regional rounds the specialisation gained is outweighed by what the average destroys. How far regions drift before the global merge lr = 0.01, unit gradient norm 2 4 6 8 0 0.1 0.2 0.3 regional rounds per global round divergence / loss worst-case model divergence measured merge loss penalty
One to three regional rounds is the usual window. Beyond it the global average starts destroying the specialisation the tier was added to capture.

Assertion 4 is the one that turns a topology decision into a privacy decision. Adding a middle tier without a population floor creates a place where a near-individual update sits in the clear, which is precisely the exposure the federated design was built to avoid.

Incident Response and Edge Cases

  • One regional aggregator fails. Its whole region misses the round, which is a much larger correlated dropout than the flat topology ever produces. Plan for it: allow clients to fall back to a neighbouring region or directly to the global tier, and make the fallback path part of the regular test suite rather than an emergency measure.
  • Regional models diverge and the global merge degrades. Reduce regional_rounds, or merge with a weighted average that accounts for each region’s sample count rather than a plain mean. The divergence bound above gives an a-priori estimate of when this will start.
  • A region is consistently under the client floor. It is not a region. Merge it with its neighbour for aggregation, and be explicit that the finest aggregation granularity is coarser than the administrative map suggests.
  • The middle tier is operated by a different party. Then the trust model changed and the topology question became a contractual one. End-to-end secure aggregation is the technical answer: the regional node forwards ciphertext it cannot open, and its role reduces to bandwidth.
  • Latency rose more than the extra hop explains. Regional rounds are synchronous within the region, so a straggler now blocks a region rather than the fleet — smaller blast radius, but the same failure. Apply the same deadline or staleness policy at the regional tier as at the global one.
Why a regional aggregate needs a client floor A falling bar chart of one client's share of its regional aggregate against the region's client count. In a three-client region a single client contributes a third of the forwarded aggregate; at forty clients it contributes two and a half percent. Below roughly eight clients the aggregate is close enough to an individual update to be treated as one. Why a regional aggregate needs a client floor a small region's aggregate is close to one client's update 0 10 20 30 % of the aggregate 33.3 3 clients 16.7 6 clients 12.5 8 clients 6.2 16 clients 2.5 40 clients
Adding a middle tier without a client floor creates a place a near-individual update sits in the clear — the exact exposure the architecture exists to remove.

Before adopting a middle tier at all, measure whether the flat topology is actually constrained. Server ingress is the usual justification, and it is frequently not the binding constraint: rounds are more often limited by client-side compute, by straggler latency, or by the cohort size the privacy budget allows. A regional tier that solves a bandwidth problem you did not have adds a failure domain, a trust boundary and an extra hop of latency for nothing.

Frequently Asked Questions

Does a regional tier weaken the privacy guarantee?

It does unless secure aggregation covers the client-to-regional hop. Without masking, the regional node holds individual client updates in the clear — which is exactly the exposure the architecture exists to prevent, now moved somewhere less scrutinised. With masking to the region, the node sees only a regional aggregate; with end-to-end masking it sees nothing at all.

How many regional rounds before a global sync?

One to three for most deployments. More regional rounds save cross-region traffic and let regions specialise, but the models drift apart and the global merge starts destroying what it was meant to combine. The divergence grows linearly in the number of local rounds, so the trade is easy to bound in advance.

Should regions be geographic or network-topological?

Network-topological for bandwidth — the point is to keep traffic local — and geographic for the data. Where they conflict, prefer network topology for the aggregation tree and keep geography for stratified selection and reporting; conflating the two makes both harder to reason about.

What happens to the privacy budget in a two-tier design?

It is unchanged: a client still makes one release per round regardless of how many hops the update takes. What changes is where the noise is added — once, at the global aggregate — and that noise must be calibrated to the sensitivity of the whole fleet, not of a single region.

Up one level: Model Synchronization Strategies · Section: Federated Learning Workflows for Geospatial Data.