Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ac6e3c8
Fix module paths in aggregator and attack docs
ArthurDanjou Jul 21, 2026
7d90408
Simplify quickstart to focus on essentials
ArthurDanjou Jul 21, 2026
d8d390e
Fix import path in README example
ArthurDanjou Jul 21, 2026
2117573
Add tutorial on aggregators and attacks
ArthurDanjou Jul 21, 2026
2ba4b3c
Move visualization dependencies to optional experiments extra
ArthurDanjou Jul 21, 2026
401f64b
Update quickstart docs with new dependencies
ArthurDanjou Jul 21, 2026
9f93e5c
Update tutorial links to using_simulations
ArthurDanjou Jul 21, 2026
f2e7b1b
Update using_aggregators_attacks.rst
ArthurDanjou Jul 21, 2026
fd5ff8e
Create working_with_models.rst
ArthurDanjou Jul 21, 2026
98de555
Create using_simulations.rst
ArthurDanjou Jul 21, 2026
db627c0
Create working_with_orchestrator.rst
ArthurDanjou Jul 21, 2026
3dfe3fc
Create implement_simulation.rst
ArthurDanjou Jul 21, 2026
4d93f55
Create implement_aggregator.rst
ArthurDanjou Jul 21, 2026
58d9a72
Create implement_attack.rst
ArthurDanjou Jul 21, 2026
f13df35
Create index.rst
ArthurDanjou Jul 21, 2026
54105fa
Rework simulations tutorials
ArthurDanjou Jul 21, 2026
660148e
docs(tutorials): add results analysis tutorial (item 2/6)
ArthurDanjou Jul 21, 2026
90c2df0
docs(tutorials): add systematic benchmark tutorial (item 3/6)
ArthurDanjou Jul 21, 2026
cf88a55
docs(tutorials): add understanding byzantine attacks tutorial (item 4/6)
ArthurDanjou Jul 21, 2026
fbff756
docs(tutorials): add custom dataset tutorials
ArthurDanjou Jul 21, 2026
4f55d41
Delete todo.md
ArthurDanjou Jul 21, 2026
c73a9f5
Remove Byzantine attacks tutorial
ArthurDanjou Jul 22, 2026
2c72169
Add new documentation links to tutorial walkthroughs
ArthurDanjou Jul 22, 2026
82abf85
Add end-to-end tutorial and troubleshooting guide
ArthurDanjou Jul 22, 2026
40607c0
Remove tutorial documentation files
ArthurDanjou Jul 24, 2026
69da104
Add problem statements to tutorial documentation
ArthurDanjou Jul 24, 2026
2305858
Normalize bullet point separators and wording in documentation
ArthurDanjou Jul 24, 2026
d5fba50
Delete implement_simulation.rst
ArthurDanjou Jul 24, 2026
8c00fcf
Delete end_to_end.rst
ArthurDanjou Jul 24, 2026
e36dd7f
Update attack tutorial to demonstrate RepeatAttack
ArthurDanjou Jul 24, 2026
f46ec5e
Use FirstGrad for simpler aggregator tutorial
ArthurDanjou Jul 24, 2026
2136e32
Add working_with_models to next steps section
ArthurDanjou Jul 24, 2026
78f2973
Update decentralised simulation walkthrough tutorial
ArthurDanjou Jul 24, 2026
77a3698
Update tutorial next steps sections
ArthurDanjou Jul 24, 2026
905e184
Add structured experiments tutorial
ArthurDanjou Jul 24, 2026
cbb62a0
Restructure tutorials index documentation
ArthurDanjou Jul 24, 2026
33e6458
Refine tutorials index page text and formatting
ArthurDanjou Jul 24, 2026
dc42cb2
Clarify aggregator_kwargs usage in implement_aggregator tutorial
ArthurDanjou Jul 24, 2026
ec866b3
Add baseline Average comparison in attacks tutorial
ArthurDanjou Jul 24, 2026
9f5abe0
Simplify tutorial by linking to reference docs for model list
ArthurDanjou Jul 24, 2026
1af1fa8
Update using_aggregators_attacks.rst
ArthurDanjou Jul 24, 2026
0207283
Move tutorial docs to reference pages
ArthurDanjou Jul 24, 2026
0b95224
Clarify test command in implement_attack tutorial
ArthurDanjou Jul 24, 2026
7ad4025
Add section headers to structured experiments tutorial
ArthurDanjou Jul 24, 2026
181b39f
Add section headers to structured experiments tutorial
ArthurDanjou Jul 24, 2026
ad97280
Streamline tutorials: remove redundant listings, add seealso refs
ArthurDanjou Jul 24, 2026
7e05aaf
Restructure tutorial walkthroughs for clearer flow
ArthurDanjou Jul 24, 2026
e8a17b2
Remove 'Going further' section from walkthrough tutorial
ArthurDanjou Jul 24, 2026
d47c28c
Remove comparing two configurations tutorial
ArthurDanjou Jul 24, 2026
dc44690
Clarify simulation API and update tutorial examples
ArthurDanjou Jul 27, 2026
1a6c5a4
Document NearestNeighborAverage aggregator in tutorials
ArthurDanjou Jul 27, 2026
c1c5a3b
Fix title underline too short
ArthurDanjou Jul 30, 2026
4c1beac
Fix table
ArthurDanjou Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The reference documentation is available at
```python
import torch
from krum.primitives.aggregators import Krum, Average
from krum.primitives.attacks import Gaussian
from krum.primitives.attacks.gaussian import Gaussian

# Simulate gradients from 10 workers (8 honest, 2 Byzantine)
honest = torch.randn(8, 100)
Expand Down Expand Up @@ -44,12 +44,21 @@ This project supports Python **3.10 through 3.14**.
pip install krum
```

This installs **PyTorch**, **torchvision**, and **pandas**. Additional
dependencies (``matplotlib``, ``numpy``, ``seaborn``) are required for running experiments
and visualisations:

```bash
pip install "krum[experiments]"
```

With `uv` (Recommended):

```bash
uv pip install krum
# or directly in a uv project
uv add krum
uv add "krum[experiments]" # with optional experiment deps
```

### From source
Expand All @@ -60,15 +69,15 @@ install in editable mode with the development dependencies:
```bash
git clone https://github.com/calicarpa/krum.git
cd krum
pip install -e ".[dev]"
pip install -e ".[dev,experiments]"
```

With `uv` (Recommended):

```bash
git clone https://github.com/calicarpa/krum.git
cd krum
uv sync --extra dev
uv sync --all-extras --all-groups
```

This installs all linting, type-checking, and documentation tools.
Expand Down
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def linkcode_resolve(domain, info):
"title": "Quickstart",
"url": "quickstart",
},
{
"title": "Tutorials",
"url": "tutorials/index",
},
{
"title": "Reference",
"children": [
Expand Down
9 changes: 9 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ Quickstart

quickstart

Tutorials
---------

.. toctree::
:maxdepth: 1
:caption: Tutorials

tutorials/index

Reference
---------

Expand Down
186 changes: 20 additions & 166 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Quickstart
==========

This guide walks you through installation, basic usage, and key concepts
of Krum.
This guide walks you through installing Krum and running your first command.

Installation
------------
Expand Down Expand Up @@ -37,190 +36,45 @@ install in editable mode with the development dependencies:

git clone https://github.com/calicarpa/krum.git
cd krum
pip install -e ".[dev]"
pip install -e ".[dev,experiments]"

With ``uv`` (recommended):

.. code-block:: bash

git clone https://github.com/calicarpa/krum.git
cd krum
uv sync --extra dev
uv sync --all-extras --all-groups

Dependencies
~~~~~~~~~~~~

Krum's only runtime dependencies are **PyTorch** and **torchvision**. If you plan
to use CUDA, ensure your PyTorch build matches your CUDA version. All other
requirements are pulled in automatically when you install Krum.
Krum's runtime dependencies are **PyTorch**, **torchvision**, and **pandas**.
If you plan to use CUDA, ensure your PyTorch build matches your CUDA version.
For experiments and visualisations, install the optional extras:

Basic Usage
-----------

Here's a minimal example showing how to use Krum's aggregators and attacks:

.. code-block:: python

import torch
from krum.primitives.aggregators import Krum, Average
from krum.primitives.attacks import Gaussian, SignFlip

# Simulate gradients from 10 workers (each gradient has 100 parameters)
n_workers = 10
grad_dim = 100
n_byzantine = 2

# Honest worker gradients (normally distributed)
honest_gradients = torch.randn(n_workers - n_byzantine, grad_dim)

# Byzantine attack: generate malicious gradients
attack = Gaussian(std=10.0)
byzantine_gradients = attack.generate(honest_gradients, f=n_byzantine)

# Combine all gradients
all_gradients = torch.cat([honest_gradients, byzantine_gradients], dim=0)

# Aggregate using Krum (Byzantine-resilient)
robust_result = Krum.aggregate(all_gradients, n=n_workers, f=n_byzantine)
.. code-block:: bash

# Compare with simple average (not resilient)
naive_result = Average.aggregate(all_gradients)
pip install "krum[experiments]"

print(f"Krum result norm: {robust_result.norm().item():.4f}")
print(f"Average result norm: {naive_result.norm().item():.4f}")
This adds ``matplotlib``, ``numpy``, and ``seaborn``.

Key Concepts
Sanity check
------------

Aggregators
~~~~~~~~~~~

Aggregators are **stateless** gradient aggregation rules. Call them as classmethods:

.. code-block:: python

from krum.primitives.aggregators import Average, Median, TrimmedMean, Krum, MultiKrum, Bulyan, Brute, GeoMed

# Simple average (baseline, no resilience)
result = Average.aggregate(gradients)

# Coordinate-wise median (basic resilience)
result = Median.aggregate(gradients)

# Trimmed mean (basic resilience, requires 2f+1 workers)
result = TrimmedMean.aggregate(gradients, f=2)

# Krum (moderate resilience, requires 2f+3 workers)
result = Krum.aggregate(gradients, n=10, f=2)

# Multi-Krum (moderate resilience, averages m= n-f-2 gradients)
result = MultiKrum.aggregate(gradients, n=10, f=2)

# Bulyan (strong resilience, two-stage, requires 4f+3 workers)
result = Bulyan.aggregate(gradients, n=15, f=2)

Attacks
~~~~~~~

Attacks generate Byzantine gradients from honest worker gradients:

.. code-block:: python

from krum.primitives.attacks import SignFlip, ALIE, Gaussian, Omniscient, SmallPerturbation

# Sign flip attack
byzantine = SignFlip.generate(honest_gradients, f=2, scale=1.5)

# ALIE (A Little Is Enough) attack
byzantine = ALIE.generate(honest_gradients, f=2, z=2.0)

# Gaussian attack
byzantine = Gaussian.generate(honest_gradients, f=2, std=10.0)

# Omniscient attack (requires full dataset gradient)
byzantine = Omniscient.generate(honest_gradients, f=2, kappa=100.0, full_gradient=full_grad)

# Small perturbation attack (exploits curse of dimensionality)
byzantine = SmallPerturbation.generate(honest_gradients, f=2, aggregator=Krum, n=10, p=2)

Model Wrapper
~~~~~~~~~~~~~

Krum provides a ``Model`` wrapper for zero-copy flat views of PyTorch parameters and gradients:

.. code-block:: python

from krum.primitives.models import Model
import torch.nn as nn

module = nn.Linear(10, 5)
model = Model(module)

# Flat parameter view (zero-copy, lazy-initialized)
flat_params = model.parameters # shape: (55,)

# Flat gradients after backward()
loss = module(torch.randn(3, 10)).sum()
loss.backward()
flat_grads = model.gradients # shape: (55,)

# Write aggregated gradients back (zero-copy relink)
model.gradients = aggregated_flat

.. note::

``zero_grad(set_to_none=True)`` (the default since PyTorch 2.11) replaces
each ``.grad`` with ``None``, breaking the cached flat gradient view.
After calling ``zero_grad()``, access ``.gradients`` via
``relink_gradients()`` to restore the link in a single call:

.. code-block:: python

optimizer.zero_grad() # drops .grad tensors
grads = model.relink_gradients() # re-link + get flat view
grads[:] = 0 # equivalent to zero_grad

The same pattern applies to :meth:`~krum.primitives.models.Model.relink_parameters`
when a parameter's ``.data`` has been replaced externally.

Both methods return the flat tensor directly, so no further property access is
needed.

Standard Models
~~~~~~~~~~~~~~~

Krum provides standard models used in the literature for Byzantine-resilient
distributed learning simulations:

.. code-block:: python

from krum.primitives.models import Krum2017MLPMnist, Krum2017MLPSpambase, Krum2017CNN, Monna2023SmallMnist

# MLP for MNIST (784 → 100 → 10)
mlp = Krum2017MLPMnist()

# MLP for Spambase (57 → 20 → 20 → 2)
spambase = Krum2017MLPSpambase()

# CNN for CIFAR-10 (3×32×32 → 10)
cnn = Krum2017CNN()

# Small MLP for MNIST (784 → 128 → 10)
small_mnist = Monna2023SmallMnist()

These models can be wrapped with the ``Model`` class for zero-copy flat views:

.. code-block:: python

from krum.primitives.models import Model, Krum2017MLPMnist
import torch
from krum.primitives.aggregators.krum import Krum

model = Model(Krum2017MLPMnist())
flat_params = model.parameters # shape: (d,) where d ≈ 80,000
result = Krum.aggregate(torch.randn(10, 100), n=10, f=2)
print(result.shape) # (100,)

Next Steps
Next steps
----------

- Browse the :doc:`reference/primitives/models/index` for standard models
- Browse the :doc:`reference/primitives/aggregators/index` for all available aggregation rules
- Browse the :doc:`reference/primitives/attacks/index` for all available attack strategies
- See :doc:`reference/simulations/index` for reproducing published experiments in distributed settings
Dive into the :doc:`tutorials/index` for step-by-step guides:

* :doc:`tutorials/centralised_simulation_walkthrough` — using the built-in simulations
* :doc:`tutorials/using_aggregators_attacks` — how to use all built-in aggregators and attacks
* :doc:`tutorials/working_with_models` — zero-copy flat tensor views and standard models
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/aksel.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
AKSEL
=====

.. automodule:: aggregators.aksel
.. automodule:: krum.primitives.aggregators.aksel
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/average.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Average
=======

.. automodule:: aggregators.average
.. automodule:: krum.primitives.aggregators.average
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/brute.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Brute
=====

.. automodule:: aggregators.brute
.. automodule:: krum.primitives.aggregators.brute
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/bulyan.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Bulyan
======

.. automodule:: aggregators.bulyan
.. automodule:: krum.primitives.aggregators.bulyan
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/geomed.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GeoMed
======

.. automodule:: aggregators.geomed
.. automodule:: krum.primitives.aggregators.geomed
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/krum.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Krum
====

.. automodule:: aggregators.krum
.. automodule:: krum.primitives.aggregators.krum
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/aggregators/classes/median.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Median
======

.. automodule:: aggregators.median
.. automodule:: krum.primitives.aggregators.median
:members:
:undoc-members:
:show-inheritance:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MultiKrum
=========

.. automodule:: aggregators.multikrum
.. automodule:: krum.primitives.aggregators.multikrum
:members:
:undoc-members:
:show-inheritance:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Nearest Neighbor Average
========================

.. automodule:: aggregators.nearest_neighbor_average
.. automodule:: krum.primitives.aggregators.nearest_neighbor_average
:members:
:undoc-members:
:show-inheritance:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Trimmed Mean
============

.. automodule:: aggregators.trimmed_mean
.. automodule:: krum.primitives.aggregators.trimmed_mean
:members:
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/primitives/attacks/classes/alie.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
A Little Is Enough
==================

.. automodule:: attacks.alie
.. automodule:: krum.primitives.attacks.alie
:members:
:undoc-members:
:show-inheritance:
Expand Down
Loading