Skip to content

Extending fed-playground

Every concern is an ABC. Subclass one, and the rest of the framework — the Environment, the benchmark engine, the CLI registry — picks it up for free.

Add an aggregation strategy

Implement one method. It receives the per-party updates and the active encryption scheme.

import numpy as np
from fed_playground import AggregationStrategy

class TopKMeanAggregation(AggregationStrategy):
    """Average only the k updates closest to the coordinate-wise median."""
    def __init__(self, k: int) -> None:
        self.k = k

    def aggregate(self, encrypted_models, encryption_scheme):
        if encryption_scheme.is_linear_only:        # honour the masking contract
            raise ValueError("needs plaintext updates")
        X = np.stack(encrypted_models)              # (n_parties, n_params)
        med = np.median(X, axis=0)
        order = np.argsort(np.linalg.norm(X - med, axis=1))
        return X[order[: self.k]].mean(axis=0)

Use it anywhere a built-in goes:

from fed_playground import Environment
Environment(n_parties=10, n_features=5, n_samples=500,
            aggregation_strategy=TopKMeanAggregation(k=6)).run_simulation(rounds=8)

Add a Byzantine attack

An Attack poisons the byzantine parties' updates, given the whole round's updates (so omniscient attacks can read the honest statistics).

import numpy as np
from fed_playground import Attack

class ConstantAttack(Attack):
    """Byzantine parties all send the same fixed vector."""
    def __init__(self, value: float) -> None:
        self.value = value

    def corrupt(self, updates, byzantine_ids):
        out = list(updates)
        for i in byzantine_ids:
            out[i] = np.full_like(updates[i], self.value)
        return out

Use it in a config

Anything exported from fed_playground (i.e. in __all__) is addressable by name in a fedbench TOML config:

[grid]
aggregations = [{ name = "TopKMeanAggregation", k = 6 }]

To make a new class addressable by name, export it from fed_playground/__init__.py (add it to __all__). The benchmark engine and CLI resolve names via getattr(fed_playground, name) — no registry to update.