# Step-by-Step Usage

### CIFAR-10 / Synthetic

#### Step 1 — Generate dataset

```bash
# CIFAR-10
python gen_data.py --dataset cifar10 --alpha 0.1 --seed1 777

# Synthetic
python gen_data.py --dataset synthetic --alpha 0.1 --beta 1 --iid 0 --seed1 777 --seed2 777
```

#### Step 2 — Observation phase

Run with `--observation 1` to record per-client gradient norms. This must be done before the dropout index list can be built.

```bash
python main.py --observation 1 --algorithm FedAvg_var --dataset cifar10 \
    --alpha 0.1 --seed 777 --seed1 777 --seed2 777 \
    --global_round 200 --local_round 25 --K 100 --M 100 --Beta 10.0
```

#### Step 3 — Build dropout index list

```bash
python gen_shadow.py --intermediate 1 --algorithm FedAvg_var --alpha 0.1 --T1 5 --T2 150 --K1 25 --K2 10
python gen_shadow.py --intermediate 1 --algorithm cclip      --alpha 0.1 --T1 5 --T2 150 --K1 25 --K2 10

python gen_shadow.py --intermediate 0 --algorithm FedAvg_var --alpha 0.1 --K1 25 --K2 10
```

#### Step 4 — Main training

```bash
python main.py --algorithm FedAvg     --dataset cifar10 --seed 777 --alpha 0.1 
python main.py --algorithm FedAvg_var --dataset cifar10 --seed 777 --alpha 0.1 --Beta 10.0 
python main.py --algorithm FedProx    --dataset cifar10 --seed 777 --alpha 0.1 --mu 0.1 
python main.py --algorithm FedProx_var --dataset cifar10 --seed 777 --alpha 0.1 --Beta 10.0 --mu 0.1 
```


---

### Shakespeare

The Shakespeare dataset uses the [LEAF](https://leaf.cmu.edu/) federated learning benchmark.


#### Step 0 — Download the raw text
```bash
cd leaf/data/shakespeare
bash preprocess/get_data.sh
cd -
```

#### Step 1 — Preprocess the data

```bash
python gen_shakespeare.py --seed1 777 --sf 1.0 --k 0 --tf 0.8
```


#### Steps 2–4 — Observation, shadow, training (same as above)

```bash
# Observation phase
python main.py --observation 1 --algorithm FedAvg_var --dataset shakespeare \
    --alpha 0.1 --seed 777 --seed1 777 \
    --lr 0.8 --bs 10 --global_round 200 --local_round 1 \
    --K 10 --M 100 --Beta 1.0

# Shadow experiments
python gen_shadow.py --dataset shakespeare --alpha 0.1 \
    --seed 777 --seed1 777 --lr 0.8 --bs 10 \
    --global_round 200 --local_round 1 --K 100 --M 100 \
    --Beta 1.0 --epsilon 0.9 \
    --algorithm FedAvg_var --intermediate 1 --T1 5 --T2 150 --K1 25 --K2 10

python gen_shadow.py --dataset shakespeare --alpha 0.1 \
    --seed 777 --seed1 777 --lr 0.8 --bs 10 \
    --global_round 200 --local_round 1 --K 100 --M 100 \
    --Beta 1.0 --epsilon 0.9 \
    --algorithm cclip --intermediate 1 --T1 5 --T2 150 --K1 25 --K2 10

python gen_shadow.py --dataset shakespeare --alpha 0.1 \
    --seed 777 --seed1 777 --lr 0.8 --bs 10 \
    --global_round 200 --local_round 1 --K 100 --M 100 \
    --Beta 1.0 --epsilon 0.9 \
    --algorithm FedAvg_var --intermediate 0 --K1 25 --K2 10

# Main experiments
python main.py --algorithm FedAvg --dataset shakespeare \
    --alpha 0.1 --seed 777 --seed1 777 \
    --lr 0.8 --bs 10 --global_round 200 --local_round 1 \
    --K 10 --M 100 --epsilon 0.9
```


**Recommended Shakespeare hyperparameters:**

| Parameter | Value | Notes |
|---|---|---|
| `--lr` | `0.8` | Higher LR works well for CharLSTM |
| `--bs` | `10` | Mini-batch size per client |
| `--local_round` | `1` | Local steps |
| `--K` | `10` | Clients sampled per round |
| `--global_round` | `200`–`500` | Global rounds |
| `--Beta` | `1.0` | Global stepsize for FedAvg_var and FedProx_var |
| `--balanced` | `1` | Uniform batch size across clients |

---

## Argument Reference

### `gen_data.py`

| Argument | Type | Default | Description |
|---|---|---|---|
| `--dataset` | str | `cifar10` | Dataset to generate. Choices: `cifar10`, `synthetic`. |
| `--M` | int | `100` | Number of clients. |
| `--alpha` | str | `0.1` | For CIFAR-10: Dirichlet concentration parameter controlling data heterogeneity. For Synthetic: controls the variance of per-client model mean vectors `W_i`. |
| `--beta` | str | `1` | Synthetic data only. Controls the variance of the per-client bias shift `B_i`. |
| `--iid` | int | `0` | Synthetic data only. Set to `1` to generate IID data across clients. |
| `--train_num` | int | `50000` | Total number of training samples (CIFAR-10 only). |
| `--test_num` | int | `10000` | Total number of test samples (CIFAR-10 only). |
| `--class_num` | int | `10` | Number of output classes. |
| `--balanced` | int | `1` | `1`: each client gets equal number of samples. `0`: sample counts follow a power-law (log-normal) distribution. |
| `--seed1` | int | `777` | For CIFAR-10: random seed for Dirichlet partition. For Synthetic: seed for generating mean vectors `u_i`, `v_i`. |
| `--seed2` | int | `777` | Synthetic data only. Seed for generating the actual data samples `x_i`, `y_i`. |
| `--save` | int | `1` | Set to `1` to write generated data to disk, `0` to skip saving. |

---

### `gen_shakespeare.py`

| Argument | Type | Default | Description |
|---|---|---|---|
| `--seed1` | int | `777` | Seed label for the output directory. Must match `--seed1` used in `main.py`. |
| `--sf` | float | `1.0` | Sampling fraction: fraction of Shakespeare characters (users) to keep. `1.0` = all characters. |
| `--k` | int | `0` | Minimum number of samples per user. Users with fewer samples are discarded. |
| `--tf` | float | `0.8` | Train fraction for the per-user train/test split. |

---

### `configuration.py`

#### Dataset

| Argument | Type | Default | Description |
|---|---|---|---|
| `--dataset` | str | `cifar10` | Dataset to train on. Choices: `cifar10`, `synthetic`, `shakespeare`. |
| `--datapath` | str | `./data/` | Path prefix used when loading the dataset. |
| `--alpha` | str | `0.1` | Dirichlet / synthetic heterogeneity parameter. Must match the value used in `gen_data.py`. |
| `--beta0` | float | `1.0` | Synthetic data parameter. Must match `--beta` used in `gen_data.py`. |
| `--iid` | float | `0` | Synthetic data IID flag. Must match the value used in `gen_data.py`. |

#### Algorithm

| Argument | Type | Default | Description |
|---|---|---|---|
| `--algorithm` | str | `FedAvg_var` | Federated learning algorithm to run. See the algorithm table above. |
| `--Beta` | float | `10.0` | Global aggregation stepsize used by `FedAvg_var` and `FedProx_var`. Scales how aggressively the server moves toward the client average each round. Only relevant for `FedAvg_var` / `FedProx_var`. |
| `--mu` | float | `0.1` | Proximal term coefficient for `FedProx` and `FedProx_var`. Penalises local iterates that drift far from the global model. |

#### Federated training

| Argument | Type | Default | Description |
|---|---|---|---|
| `--M` | int | `100` | Total number of clients. |
| `--K` | int | `10` | Number of clients sampled per communication round. Automatically set to `M` when `--observation 1`. |
| `--global_round` | int | `3000` | Number of communication rounds (server aggregation steps). |
| `--local_round` | int | `25` | Number of local SGD steps each sampled client performs per round. |
| `--bs` | int | `100` | Mini-batch size for local training. Used as the uniform batch size when `--balanced 1`. |
| `--balanced` | int | `1` | `1`: all clients use batch size `--bs`. `0`: each client uses its full local dataset (or a proportional slice for CIFAR-10). |

#### Optimisation

| Argument | Type | Default | Description |
|---|---|---|---|
| `--lr` | float | `0.1` | Initial local learning rate (SGD step size). |
| `--lr_decay` | int | `0` | Set to `1` to enable 1/sqrt(t) learning rate decay. `0` keeps the learning rate constant. |
| `--wd` | float | `0` | L2 weight decay coefficient applied to the local SGD optimizer. |

#### Dropout

| Argument | Type | Default | Description |
|---|---|---|---|
| `--epsilon` | float | `0.9` | Dropout threshold. A client is eligible for dropout if its local sample count is below `epsilon * K * mean_samples / M`.|

#### Observation

| Argument | Type | Default | Description |
|---|---|---|---|
| `--observation` | int | `0` | Set to `1` to run in observation mode: all `M` clients participate every round and per-client gradient norms are recorded.|
| `--threshold_l` | str | `5,10,15,50,100,150,200` | List of rounds at which gradient norms are recorded during observation mode. |

#### Logging

| Argument | Type | Default | Description |
|---|---|---|---|
| `--verbose` | int | `0` | Set to `1` to print per-batch training progress to stdout. |
| `--print_every` | int | `1` | Evaluate and log train/test metrics every this many communication rounds. |

#### Random seeds

| Argument | Type | Default | Description |
|---|---|---|---|
| `--seed` | int | `777` | Master random seed controlling client sampling order and model initialisation. |
| `--seed1` | int | `777` | Must match `--seed1` used in `gen_data.py` to load the correct dataset partition. |
| `--seed2` | int | `777` | Must match `--seed2` used in `gen_data.py` (synthetic data only). |

---

### `gen_shadow.py`

Shares all arguments from `main.py` / `configuration.py` above, plus the following:

| Argument | Type | Default | Description |
|---|---|---|---|
| `--intermediate` | int | `1` | `1`: build a per-algorithm candidate set from observation data and save to `index_list_1_{alpha}_{algorithm}.json`. `0`: merge the candidate sets from `FedAvg_var` and `cclip` into the final dropout index list `index_list_{alpha}.json`. |
| `--T1` | int | `5` | Earlier observation round used to compute gradient norm differences. |
| `--T2` | int | `150` | Later observation round used to compute gradient norm differences. Clients whose norm changes most between `T1` and `T2` are ranked as candidate non-responsive clients. |
| `--K1` | int | `25` | Number of top-ranked candidates taken from the `FedAvg_var` observation to form set C1. |
| `--K2` | int | `10` | Number of additional candidates taken from the `cclip` observation (not already in C1) to form set C2. The final dropout list is C1 $\Cup$ C2. |
