--- license: cc-by-4.0 library_name: pytorch pipeline_tag: image-classification tags: - forward-forward - local-learning - cifar-100 - layer-free-riding - neurips-2026 datasets: - uoft-cs/cifar100 metrics: - accuracy --- # Forward-Forward free-riding checkpoints (NeurIPS 2026) This repository holds four trained checkpoints from *Cumulative-Goodness Free-Riding in Forward-Forward Networks: Real, Repairable, but Not Accuracy-Dominant* (Amirhossein Yousefiramandi, NeurIPS 2026). Each file is the validation-selected Stage-1 network of the seed-42 run of one of the four central CIFAR-100 arms in the paper's Table 3: - block-local training (γ=0); - hardness-gated collaboration (κ=0); - cumulative-goodness training (γ=0.7); - missing-gradient compensation (MGC, c_d=1). This is a minimal release. The paper's other 94 result-bearing checkpoints are listed with their SHA-256 hashes in `release_manifest.json` and are available from the author on request (see [Other checkpoints](#other-checkpoints-on-request)). They cover all seeds, the Stage-2 heads and the CIFAR-10 runs. The checkpoints are research artifacts. They let you re-evaluate and probe the four Table 3 arms without retraining Stage 1. They are not general-purpose image classifiers. - **Paper:** [arXiv:2605.06240](https://arxiv.org/abs/2605.06240) - **Code** (trainers, analysis, reproduction manifest; Apache-2.0): - **Checkpoints** (this repository; CC BY 4.0): ## Files | File | Arm | Selected Stage-1 epoch (val. top-1) | Bytes | SHA-256 | |---|---|---|---:|---| | `checkpoints/c100_trio/ff_cifar100_cifar100_gamma0_seed42_L4_D256_P2_seed42_stage1_best.pt` | γ=0 (block-local) | 362 (65.72 %) | 211467565 | `d2e2a0548597355d633c7c3acad1ef01c274323f279ca1055e77a1c807e2848c` | | `checkpoints/c100_trio/ff_cifar100_cifar100_gated_k0_seed42_L4_D256_P2_seed42_stage1_best.pt` | hardness-gated κ=0 | 340 (66.22 %) | 211484697 | `58e0c770f80a4f70d9d6c814884ecbb1caf1162a270caf3294282b67d69fd4ca` | | `checkpoints/c100_trio/ff_cifar100_cifar100_cumulative_seed42_L4_D256_P2_seed42_stage1_best.pt` | cumulative γ=0.7 | 340 (66.22 %) | 211487237 | `537cf9e2e27e73009596a9de9f52097ee98d33ad1055783a8f434e20ab44cc3b` | | `checkpoints/mgc_c100/ff_cifar100_mgc_c100_L4_D256_P2_seed42_stage1_best.pt` | MGC (c_d=1) | 362 (66.96 %) | 211449657 | `6776a87e9afa3dcf6abc993b0e17646724b3b9f185ada825eebd54977c2c1a66` | The four files total 845,889,156 bytes (846 MB). All four arms share one setup: CIFAR-100, L4/D256 dense (no MoE), no SAM, 362 Stage-1 epochs, seed 42, and the same seed-42 train/validation split. The repository also contains: ``` README.md this model card SHA256SUMS sha256sum-compatible list of the four checkpoint files release_manifest.json all 98 result-bearing checkpoints of the paper: run, paper tables, trainer, source, lineage, size, SHA-256; `availability` is "public_hf" for the four files here and "on_request" for the others ``` Each file stores the following keys: - `net_ema`: the EMA weights, which give the S1 numbers; - `model`: the raw weights; - `cfg`: the run's full configuration, identical to the run's `config.json` except `device`; - `epoch_stage1`: the selected epoch; - `best_s1`: the validation top-1 at that epoch; - `stage`: 1; - `opt_states`, `sched_states` and `queues`: the optimizer states, the scheduler states and the contrastive feature queues. ## Numbers behind each file | Arm | S1 | S1-TTA | S2 (logged) | S2-TTA (logged) | |---|---:|---:|---:|---:| | γ=0 | 66.17 | 66.92 | 68.27 | 68.94 | | κ=0 (gated) | 66.07 | 66.85 | 68.29 | 68.64 | | Cumulative γ=0.7 | 66.70 | 67.18 | 68.09 | 68.57 | | MGC | 66.05 | 66.79 | 68.71 | 69.19 | The values are CIFAR-100 test top-1 (%) of the seed-42 runs. They enter the 3-seed means of Table 3 (`tab:dissociation_merged`). The seed-42 columns of the frozen-backbone readout table (`tab:readouts`, appendix) are computed on these four backbones. - **S1 and S1-TTA** are the Stage-1 readouts of these files. S1 is the goodness-sum readout of the EMA weights on a single crop; S1-TTA adds the horizontally flipped image. S1 was re-predicted from each file on the full test set and matched the run logs to within 0.01 pp: 66.18, 66.07, 66.70 and 66.06 against logged S1 values of 66.17, 66.07, 66.70 and 66.05. S1-TTA was not re-predicted; it is tied to these files by lineage (each run's `events.jsonl` names the file in its final test evaluation; see [Run history and disclosures](#run-history-and-disclosures)). - **S2 and S2-TTA** come from the Stage-2 attentive head. This head is a backprop-trained probe on the frozen backbone, not part of the FF method, and its checkpoints (`stage2_best.pt`) are not in this release. To get S2 numbers, retrain the probe as described in [Retraining the Stage-2 probe](#retraining-the-stage-2-probe). The original heads are available on request. - **Deepest-block separation** (the "sep" column of Table 3) is a training-log quantity: it was read at the last Stage-1 epoch (362), not recomputed from the validation-selected checkpoint. The code repository ships the per-seed values in `metric_summaries/camera_ready/`. ## Loading The network is defined by the CIFAR-100 trainer in the code repository, which works for all four files. MGC changes only the training loss, not the network. ```bash git clone https://github.com/amirhossein-yousefi/ff-free-riding && cd ff-free-riding pip install -r requirements.txt huggingface_hub ``` ```python import importlib.util, sys, torch from huggingface_hub import hf_hub_download from torchvision import datasets, transforms path = hf_hub_download("Amirhossein75/ff-free-riding", "checkpoints/c100_trio/ff_cifar100_cifar100_gamma0_seed42_L4_D256_P2_seed42_stage1_best.pt") spec = importlib.util.spec_from_file_location("ff_c100", "trainers/cp_fair_cifar100.py") T = importlib.util.module_from_spec(spec); sys.modules["ff_c100"] = T; spec.loader.exec_module(T) ckpt = torch.load(path, map_location="cpu", weights_only=True) cfg = T.FFConfig() for k, v in ckpt["cfg"].items(): # the run's configuration is stored in the checkpoint if hasattr(cfg, k): setattr(cfg, k, v) cfg.device = "cuda" if torch.cuda.is_available() else "cpu" net = T.FFHybridNet(cfg).to(cfg.device) net.load_state_dict(ckpt["net_ema"]) # EMA weights: the S1 / S1-TTA numbers net.eval() tf = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761))]) test = datasets.CIFAR100("./data_c100", train=False, download=True, transform=tf) loader = torch.utils.data.DataLoader(test, batch_size=256, shuffle=False) acc = T.evaluate_ff(net, loader, cfg.device, tta=False, topk=(1,)) # tta=True gives S1-TTA print(f"S1 top-1: {100 * acc[1]:.2f} %") # logged: 66.17 for this file ``` - **`weights_only`.** The files are PyTorch pickles. With PyTorch 2.14.0, all four load with `weights_only=True`, because they contain only tensors and plain Python containers. If your PyTorch version refuses a file, `torch.load(..., weights_only=False)` will load it, but that setting executes arbitrary pickle code. Use it only after `sha256sum -c SHA256SUMS` passes. The trainer's own `torch.load` calls, used by the Stage-2 retraining below, do not pass the argument, so they fall back to PyTorch's default. - **Side effects.** Importing the trainer creates an empty `./checkpoints/` directory, and `download=True` fetches CIFAR-100 into `./data_c100/`. - **Speed.** The goodness-sum readout scores all 100 label hypotheses for every image. On CPU it took about 1 s per test image with 4 threads, so use a GPU for the full test set. ## Retraining the Stage-2 probe When a Stage-1 checkpoint is complete, the trainer skips Stage 1 and does the following: 1. It trains only the Stage-2 head: 20 epochs, AdamW, on the frozen EMA backbone, with the same seed-42 train/validation split, which the trainer regenerates from the seed. 2. It runs the final test evaluation: S1, S1-TTA, S2 and S2-TTA, written to `events.jsonl` in a new run directory. This needs a GPU. ```bash # one arm per invocation; EP must equal the checkpoint's epoch_stage1 ARM=gamma0; EP=362; ENV="FF_GAMMA_SCALE=0" # ARM=gated_k0; EP=340; ENV="FF_GAMMA_GATING_MODE=adaptive FF_GAMMA_0=0.7 FF_GAMMA_KAPPA=0.0 FF_GAMMA_TAU=1.0" # ARM=cumulative; EP=340; ENV="FF_GAMMA_SCALE=0.7" F=ff_cifar100_cifar100_${ARM}_seed42_L4_D256_P2_seed42_stage1_best.pt huggingface-cli download Amirhossein75/ff-free-riding "checkpoints/c100_trio/$F" --local-dir ./hf mkdir -p ckpt_s2 && cp "hf/checkpoints/c100_trio/$F" ckpt_s2/ && cp "ckpt_s2/$F" "ckpt_s2/${F/_best/_last}" env $ENV FF_CKPT_DIR=./ckpt_s2 FF_VERSION_TAG=cifar100_${ARM}_seed42 FF_EPOCHS_STAGE1=$EP \ FF_NUM_BLOCKS=4 FF_D_MODEL=256 FF_NUM_HEADS=8 FF_USE_SAM=0 FF_N_EXPERTS=1 FF_MOE_TOP_K=1 \ FF_SEED=42 python trainers/cp_fair_cifar100.py # MGC (EP=362) F=ff_cifar100_mgc_c100_L4_D256_P2_seed42_stage1_best.pt huggingface-cli download Amirhossein75/ff-free-riding "checkpoints/mgc_c100/$F" --local-dir ./hf mkdir -p ckpt_s2 && cp "hf/checkpoints/mgc_c100/$F" ckpt_s2/ && cp "ckpt_s2/$F" "ckpt_s2/${F/_best/_last}" FF_CKPT_DIR=./ckpt_s2 FF_VERSION_TAG=mgc_c100 FF_USE_MGC=1 FF_MGC_C0=1.0 FF_N_EXPERTS=1 FF_MOE_TOP_K=1 \ FF_USE_SAM=0 FF_NUM_HEADS=8 FF_GAMMA_GATING_MODE=constant FF_GAMMA_SCALE=0.7 FF_SEED=42 \ python trainers/cp_fair_cifar100.py ``` The trainer loads two files from `FF_CKPT_DIR`: - It resumes Stage 1 from `_stage1_last.pt`. - It starts Stage 2 and the final Stage-1 evaluation from `_stage1_best.pt`. Both copies are therefore needed. If `FF_EPOCHS_STAGE1` is larger than the checkpoint's `epoch_stage1` (340 for κ=0 and cumulative), the trainer resumes Stage-1 training instead of skipping it. The per-arm environment matches the arm's row in the code repository's `repro_manifest.csv`, with `FF_EPOCHS_STAGE1` set to the selected epoch. A retrained head is not bitwise identical to the paper's. The trainer that produced these runs did not store RNG state, so the Stage-2 data order differs. Expect S2 values close to the logged ones, not equal to them. ## Run history and disclosures - **Not resumed.** None of the four released runs was resumed. Each ran from Stage-1 epoch 1 to epoch 362 in one run directory, and its layer log starts at epoch 1. The resumed runs reported in the paper are all among the on-request files: γ=0 seeds 123/456, κ=0 seed 456, cumulative seeds 123/456 and MGC seed 456 on CIFAR-100, plus some CIFAR-10 runs. The trainers that produced them did not save RNG state, so a resumed run is not a bitwise continuation of an uninterrupted one. `RELEASE_CHECKPOINTS.md` in the code repository lists them. - **Lineage.** - All four runs were trained on Colab A100 GPUs. - The three trio files are the extracted copies of the runs' Google Drive archive members, with equal CRC-32 and size. - Each file is the `stage1_best` that the result-bearing run's `events.jsonl` names in its final test evaluation. - Each file's `best_s1` equals the run's logged best validation accuracy, and its stored `cfg` equals the run's `config.json`. - **Trainers.** - The trio was trained with the v1 CIFAR-100 trainer, and the MGC run with the rebuttal-era MGC trainer. - The camera-ready `trainers/cp_fair_cifar100.py`, with its switches off, or with `FF_USE_MGC=1` for MGC, builds the same network. The code repository's CPU equivalence tests check this, and all four `net_ema` state dicts load into it with every key matched. - **MGC.** The MGC arm replaces the baseline's depth-scaled current-block term: block 0 loses its auxiliary and has no compensator. The implementation is faithful but not an exact recovery (ε=10⁻⁶, positive-part clamp). ## Other checkpoints (on request) `release_manifest.json` lists all 98 result-bearing checkpoint files of the paper: - the `stage1_best.pt` and `stage2_best.pt` of 49 runs on CIFAR-10 and CIFAR-100; - for each file: its run, the paper tables it supports, its trainer and configuration, its source and lineage, its size and its SHA-256. The 94 files marked `"availability": "on_request"` are available from the author on request (amir.usefi75@gmail.com). A recipient can check them against the SHA-256 values in the manifest. The following are not available at all: - the published CIFAR-10 γ=0 L4/D256 seed-42 checkpoint, which is not recoverable; - the Tiny ImageNet, text-domain and BP-control checkpoints (the paper reports their run logs and metrics only); - the seed-42 run of the CIFAR-100 32-expert γ=0.7 baseline, which was not retained. ## Integrity `SHA256SUMS` pins the four checkpoint files by their SHA-256 over the full file bytes, and `release_manifest.json` records the same hashes. To verify a download: ```bash sha256sum -c SHA256SUMS ``` The release was staged with `release/stage_release.py --subset minimal` from the code repository. ## License - **Checkpoints:** Creative Commons Attribution 4.0 International (CC BY 4.0). If you use them, please cite the paper (below). - **Code:** Apache-2.0 (the `LICENSE` file of the GitHub repository). - **Datasets:** the checkpoints were trained on CIFAR-100, which is not redistributed here. A checkpoint stores network weights, optimizer and scheduler states and the contrastive feature queues, which hold projected features of training images and their labels. It contains no images. Use of the dataset itself follows its authors' terms. ## Dataset The four files were trained on CIFAR-100 (Krizhevsky, 2009), loaded with torchvision: - The 50,000 training images are split into 45,000 for training and 5,000 for validation. - The split is seeded with the run seed (42 for all four files), so the four share it. - The 10,000-image test set is used only for the final evaluation. ## Intended use and limitations These checkpoints are for studying FF training. Possible uses: - per-block separation and goodness; - readouts and probes of the frozen backbones; - prediction churn between the four arms. The paper reports the accuracies, protocols and seed-level variation: Table 3, Appendix B and the appendix readout tables. A single seed per arm cannot reproduce the paper's paired multi-seed statistics, because those need the on-request files or retraining. The models are small CIFAR-scale classifiers trained with a local learning rule. They were not evaluated for robustness, fairness or out-of-distribution use. ## Citation ```bibtex @inproceedings{yousefiramandi2026cumulative, title = {Cumulative-Goodness Free-Riding in Forward-Forward Networks: Real, Repairable, but Not Accuracy-Dominant}, author = {Yousefiramandi, Amirhossein}, booktitle = {Advances in Neural Information Processing Systems (NeurIPS 2026)}, year = {2026}, url = {https://arxiv.org/abs/2605.06240} } ```