Score Krum-family rules on the paper neighborhoods - #65
ArthurDanjou wants to merge 13 commits into
Conversation
aggregate() passed num_peers=m to score(), conflating the scoring neighborhood with the number of averaged gradients. The paper always scores on n-f-2 peers and averages the top-m. Fix the call site and the score() default, correct the docstring, update tests.
Selection now follows Algorithm 1: every iteration scores the remaining candidates (removed gradients leave the distance matrix) on their n-i-f-2 closest peers instead of reusing frozen scores computed once with num_peers=m. Theta and the m default are unchanged.
… and Bulyan Medoid returned a view into the inputs; return a copy like the other selection rules. Aksel pivot uses quantile(0.5) for consistency with Median on even worker counts. Brute and Bulyan accept f=0, which the theory allows.
Removed comments explaining quantile calculation for median.
Top-m selection uses stable argsort so score ties resolve to the smallest indices, as the paper definitions state. The MultiKrum m docstring now separates the mechanical bound (m <= n) from the resilience bound (m <= n-2f-3); the Bulyan m-default docstring now matches the code (n-f).
|
|
|
Good point, and that is exactly what this PR does. There are two distinct parameters here.
So |
Updated reference for the sign-flip gradient attack.
Krum keeps exactly one vector and MultiKrum defaults to n - 2f - 3, so neither matched the previous n - f - 2 fallback. The selection test now mirrors the target class default, accepts an explicit m=None, and always scores on the n - f - 2 neighborhood.
Assert the score neighborhood argument, the per-class m defaults (1 for Krum, n - 2f - 3 for MultiKrum) and the explicit m=None fallback.
The n >= 2f + 3 check only ran for m = 1; larger m accepted f up to n, where n - f - 2 <= 0 silently produced all-zero scores or a wrong distance slice. The check is hoisted for every m. m itself stays free in [1, n]: values above n - 2f - 3 leave the resilience bound by design (larger m averages more gradients, m = n recovers Average), and the docstring now says so. Also align the documented f bounds with the code (Bulyan and MultiKrum accept f = 0, Brute documents its n >= 2f + 1 condition).
Design note: why
|
Problem
Two related fidelity gaps against the papers, plus the attack-side calibration that depends on them, all conflating the scoring neighborhood with the number of averaged gradients:
aggregatecalledscore(..., num_peers=m). The paper always scores on then-f-2nearest neighbors and averages the top-m. For Krum (m=1) the code scored each gradient on its single nearest neighbor. Thenum_peers=n-fdefault was additionally mislabeled as the paper score.num_peers=m, then frozen while removed gradients were masked withinf. Removed gradients therefore stayed in the distance matrix and scores were never updated between iterations.num_peers=minstead of then-f-2neighborhood, so the boundary search was miscalibrated whenever the target'smdiffered from that neighborhood.Fix
Scoring
MultiKrum.aggregatescores onn-f-2peers, top-mselection unchanged;score()default is nown-f-2; docstring corrected.Bulyanrecomputes Krum scores every iteration over the remaining candidates (masked-out gradients leave the matrix) on theirn-i-f-2closest peers.mselection uses a stable argsort, so score ties resolve to the smallest indices, as the paper definitions state.SmallPerturbation selection test
_is_selectedalways scores on then-f-2neighborhood and mirrors the target's selection size: the explicitmfromaggregator_kwargs,1for Krum, and MultiKrum'sn-2f-3default; an explicitm=Nonefalls back to the class default.Audit leftovers
Medoidreturns a clone instead of a view into the input list;Akselbuilds its median pivot withquantile(0.5)(consistent withMedianon even worker counts);BruteandBulyanacceptf = 0, which the theory allows.MultiKrumenforces the honest-majority premisen >= 2f + 3for everym(previously only form = 1; largermcould reachf = n, wheren - f - 2 <= 0silently produced all-zero scores or a wrong distance slice).fbounds now match the code:MultiKrumandBulyanacceptf = 0, andBrutedocuments itsn >= 2f + 1condition.References
sign_flip.pynow cites Xie et al., UAI 2020, PMLR 115:261-270 (the previous entry had the wrong title and venue).alie.pynow lists the published authors: Gilad Baruch, Moran Baruch, Yoav Goldberg.Tests
m=1matchesKrum,m=nmatchesAverage); stable tie-breaking on tied scores.mdefaults (Krum = 1, MultiKrum =n-2f-3) are asserted, and the explicitm=Nonefallback is covered.m > 1, which previously bypassed it.Deliberately unchanged
theta = n-2f-2and the Bulyanmdefault (n-f), kept by team decision and documented.Notes (by design)
MultiKrum'smis intentionally free in[1, n]: it is a trade-off knob (largermaverages more gradients,m = nrecoversAverage); values aboven-2f-3leave the Multi-Krum resilience bound and are documented as such. The bound is an assumption of the theorem, not an input constraint, so only the honest-majority premisen >= 2f + 3is enforced.Verification
ruff format --check,ruff checkandty checkclean (also as pre-commit hooks).Follow-ups (out of scope)