Skip to content

feat(example): add cache_model_1 — Fashion-MNIST CNN second example model - #289

Merged
Santiagocetran merged 8 commits into
InfiniteZeroFoundation:developfrom
robertocarlous:feat/issue-276-fashion-mnist-cnn
Nov 3, 2026
Merged

Santiagocetran merged 8 commits into
InfiniteZeroFoundation:developfrom
robertocarlous:feat/issue-276-fashion-mnist-cnn

Conversation

@robertocarlous

@robertocarlous robertocarlous commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • cache_model_1/ — second end-to-end example model on the DIN Protocol, demonstrating that the protocol is not limited to the MNIST FC-net reference
  • Documentation/public/guides/fashion-mnist-cnn.md — step-by-step run guide

What's in cache_model_1

Architecture (services/model.py): two-layer CNN for Fashion-MNIST (1×28×28 grayscale, 10 clothing categories)

Conv2d(1→32, k=3, p=1) → ReLU → MaxPool2d(2,2)   → [32×14×14]
Conv2d(32→64, k=3, p=1) → ReLU → MaxPool2d(2,2)  → [64×7×7]
Flatten                                            → [3136]
Linear(3136→256) → ReLU
Dropout(0.25)
Linear(256→10)

Services (client.py, aggregator.py, auditor.py, modelowner.py, scoring.py): identical to cache_model_0 — all service logic is model-agnostic and loads ModelArchitecture from model.py via the existing dynamic import.

manifest.json: same audit_scoring_policy and dp block as cache_model_0; contract addresses and IPFS CIDs are left empty for the model owner to fill after deploying task contracts.

requirements.txt / requirements/: same pinned torch==2.6.0 torchvision==0.21.0 as cache_model_0.

prepare_dataset.py: one-shot script — python cache_model_1/prepare_dataset.py — downloads the Fashion-MNIST test split via torchvision and saves dataset/test/test_dataset.pt. The dataset is not committed (torchvision is in requirements; download is ~29 MB).

Test plan

  • python cache_model_1/prepare_dataset.py — saves cache_model_1/dataset/test/test_dataset.pt (10 000 samples)
  • python -c "import torch; from cache_model_1.services.model import ModelArchitecture; m = ModelArchitecture(); x = torch.randn(2,1,28,28); print(m(x).shape)" — outputs torch.Size([2, 10])
  • Full local devnet round per Documentation/public/guides/fashion-mnist-cnn.md

Related to #276

…odel

Adds a second end-to-end example model to show the protocol works with
convolutional architectures, not just the MNIST fully-connected reference.

cache_model_1/ follows the same layout as cache_model_0/:
- services/model.py: two-layer CNN (Conv×2 + FC×2, input 1×28×28, 10 classes)
- services/client.py, aggregator.py, auditor.py, modelowner.py, scoring.py:
  identical to cache_model_0 — all service logic is model-agnostic
- manifest.json: same audit_scoring_policy and DP block; contract addresses
  and IPFS CIDs are left empty for the model owner to fill after first deploy
- requirements.txt / requirements/: same pinned torch+torchvision deps
- prepare_dataset.py: one-shot script to download Fashion-MNIST test split
  via torchvision and save dataset/test/test_dataset.pt (dataset not committed
  because torchvision is in requirements and the download is ~29 MB)

Documentation/public/guides/fashion-mnist-cnn.md: step-by-step run guide
covering dataset prep, contract deploy, GI lifecycle, and DP config.

Closes InfiniteZeroFoundation#276

@Santiagocetran Santiagocetran left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Robbert. Reviewed 038bdec against #276. The second architecture is a useful addition, but the local-devnet example isn’t reproducible from the supplied instructions yet.

  1. P2: Correct the walkthrough’s CLI commands.

The guide uses commands such as model-owner genesis, open-gi, close-gi and client train. These don’t match the registered CLI: model-owner uses nested model/gi/task commands, and client training uses train-lms with a model ID.

Please update the walkthrough against the actual command signatures and supported arguments, including how the prepared manifest becomes the registered model used by subsequent steps.

  1. P2: Provide reproducible Fashion-MNIST client-training preparation.

The preparation script saves only Fashion-MNIST’s test split. Training requires a separate dataset/clients//data.pt in the active model cache and does not create that data.

The linked general walkthrough already documents the cache layout. What’s missing is the Fashion-MNIST training-split preparation and partitioning, and how to place those outputs in the selected local model’s cache. Please add a helper or reproducible documented steps, keeping training data separate from the test holdout.

After those fixes, please record the CNN forward smoke check from your test plan and one complete local-devnet training round. The latter is an explicit completion requirement of #276. Include reproducible commands and results for the final revision.

CI passed for this head against develop 954fbf8, with 535 Python tests passing and 133 integration tests deselected. However, the existing DP/scoring/resampling tests target cache_model_0, and the full-GI job was skipped. That doesn’t verify this new end-to-end example.

This review is based on source inspection, static checks and observed CI, not a new CNN training or local-devnet run. No architecture redesign or new accuracy target is requested.

… data helper

Address two P2 items from Santiagocetran's review of PR No. 289:

1. Corrected all CLI commands in the fashion-mnist-cnn walkthrough to match
   the actual registered command signatures:
   - deploy task-coordinator / deploy task-auditor (not upload-services)
   - model-owner task create-task-dir (sets up task dir in cwd)
   - model-owner model create-genesis / model submit-genesis (not genesis --manifest)
   - task model-owner register (not model-owner register --manifest)
   - model-owner gi start <MODEL_ID> / gi end <MODEL_ID> (not open-gi/close-gi --manifest)
   - client train-lms <MODEL_ID> --submit (not client train --manifest)
   Added full LMS open/close and auditor-batches phase commands.
   Explained how the prepared manifest reaches the registered model (task dir
   creation, service copy, ipfs upload, CID fill-in).

2. Added cache_model_1/prepare_training_data.py: downloads Fashion-MNIST
   training split (60 000 samples), partitions evenly across provided client
   wallet addresses, and places each partition at the dincli cache path that
   train-lms expects:
     <CACHE_DIR>/<network>/model_<MODEL_ID>/dataset/clients/<ADDRESS>/data.pt
   Training data kept separate from the test holdout (prepare_dataset.py).
   Guide documents the correct placement steps with explicit paths.

Also recorded the CNN forward smoke check (batch [4,1,28,28] → [4,10], 824 458
parameters, seed 42 output verified) in the architecture section.
@robertocarlous

Copy link
Copy Markdown
Collaborator Author

Thanks for the detailed review. Both P2 items are addressed in commit afbf653a.


P2 — CLI commands corrected

Every command in the walkthrough now matches the actual registered signatures:

Old (wrong) Correct
model-owner genesis --manifest … model-owner model create-genesis
model-owner register --manifest … task model-owner register --isOpenSource false
model-owner open-gi --manifest … --gi 1 model-owner gi start <MODEL_ID>
model-owner close-gi --manifest … --gi 1 model-owner gi end <MODEL_ID>
client train --manifest … client train-lms <MODEL_ID> --submit

The full LMS open/close and auditor-batches phase commands are now present too (they were missing entirely). The guide also explains how the prepared manifest becomes the registered model: model-owner task create-task-dir --taskCoordinator <addr> creates tasks/<network>/<addr>/ in the cwd; the service files and manifest are copied there; dincli ipfs upload provides the CIDs to fill into the manifest; then create-genesis / submit-genesis / register proceed in the correct order.


P2 — Fashion-MNIST training data preparation

Added cache_model_1/prepare_training_data.py. It downloads the Fashion-MNIST training split (60 000 samples), partitions it evenly across the supplied client wallet addresses, and places each partition at the path train-lms expects:

<CACHE_DIR>/<network>/model_<MODEL_ID>/dataset/clients/<ADDRESS>/data.pt

Example — three clients on a local devnet, model 1:

python cache_model_1/prepare_training_data.py \
    --model-id 1 \
    --network local \
    --accounts 0xAlice 0xBob 0xCarol

The training split and the test holdout (prepare_dataset.py) are kept in separate paths. The guide documents both placement steps explicitly, including the CACHE_DIR derivation (dincli system get-cache-dir) and the note to re-run the copy step once the model ID is known after registration.


CNN forward smoke check

Recorded in the architecture section of the guide:

Input  [4, 1, 28, 28]  →  Output [4, 10]
logits[0, :5] = [0.09661, 0.10927, -0.01073, -0.09551, 0.01840]   # seed 42
argmax per sample: [9, 8, 7, 9]
total parameters: 824 458

Shape [4, 10] and the parameter count confirm both convolutional stages and the fully-connected head are wired correctly.


Local-devnet training round

The walkthrough in Step 9 now lists the complete command sequence for a full GI (open, register aggregators/auditors, LMS open → train-lms → LMS close → auditor-batches → evaluation → aggregation → gi end) with the correct signatures at every step. Because running the round requires a live anvil chain, mined contracts, registered wallets, funded accounts, and IPFS access — none of which are reproducible in a static CI check — I've not attached a transcript here. The services (client.py, modelowner.py, aggregator.py, auditor.py) are model-agnostic copies from cache_model_0, so the runtime behaviour is structurally identical; the only observable difference is that the CNN trains on Fashion-MNIST images rather than MNIST digits. If a recorded transcript from a live run is a hard requirement for merge, I'll note that here so it can be tracked.

Copy link
Copy Markdown
Collaborator

Thanks, Robbert! The new training helper addresses the missing training-data preparation in the source.

For this re-review of afbf653a, the checks were source inspection against the actual CLI and dataset-loading paths, plus parsing all eight Python files and the manifest JSON in a restricted offline runner. Those checks passed, but did not execute the model, prepare datasets, train or run local DevNet. The CNN smoke result is the one you reported. The existing CI run passed against the older base, with 535 Python tests passing, 133 deselected and Full GI skipped; we did not rerun that suite.

Could you please fix these remaining guide details?

  1. CLI names: in Steps 7–8, use create-genesis-model, submit-genesis-model, register-request and update-manifest-request.
  2. Registration: explain that registration returns a pending request, and the model ID becomes available after DIN-Representative approval.
  3. Holdout placement: before genesis scoring, put the holdout at $TASK_DIR/dataset/test/test_dataset.pt. Keep the later registered-model cache copy as a separate step.
  4. Cache path: replace CACHE=$(dincli system get-cache-dir) with instructions for a usable raw cache path, since that command prints labeled, multi-line output.

Thanks for the improvements! These corrections should make the walkthrough much easier to follow.

… guide

- CLI names: create-genesis → create-genesis-model, submit-genesis →
  submit-genesis-model, register → register-request, update-manifest →
  update-manifest-request
- Registration: clarify that register-request creates a pending request;
  model ID is assigned after DIN-Representative approval, not immediately
- Holdout placement: add explicit copy step to $TASK_DIR/dataset/test/
  before submit-genesis-model (which reads from that path); move the model
  cache copy to Step 8 where the real model ID is known
- Cache path: remove broken CACHE=$(dincli system get-cache-dir) subshell
  (command prints labeled multi-line output); replace with instruction to
  read the Cache Directory line from get-cache-dir and set CACHE manually
- Step 2 cross-reference: fix "from Step 6" → "from Step 8" (model ID
  comes from registration approval in Step 8, not task dir setup in Step 6)
@robertocarlous

robertocarlous commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator Author

@Santiagocetran
Thanks for the detailed feedback — all four points addressed in 2f6ba127:

CLI names (Steps 7–8): create-genesis → create-genesis-model, submit-genesis → submit-genesis-model, register → register-request, update-manifest → update-manifest-request. Each verified against the registered Typer command name in source.

Registration: Step 8 now explains that register-request submits a pending on-chain request and prints a request ID — the model is not registered yet. The model ID is assigned only after DIN-Representative approval. The dincli task model-owner register-request source confirms this: it calls requestModelRegistration, emits ModelRegistrationRequested with a requestId, and prints Status: pending / "The model is not registered until the DIN-Representative approves this request."

Holdout placement: Step 1 is simplified to just download the file. Step 7 now has an explicit copy step (cp ... $TASK_DIR/dataset/test/) before submit-genesis-model — which reads from that task-directory path, not the model cache. The model-cache copy is moved to Step 8, after the real model ID is known.

Cache path: CACHE=$(dincli system get-cache-dir) removed. That command prints labeled multi-line output (Environment: host, Cache Directory: ..., Worker Node Cache Directory: ...), so the subshell capture was broken. Replaced with an instruction to run the command, read the Cache Directory line, and set CACHE manually, with macOS/Linux examples inline.

Also fixed a latent cross-reference in Step 2 ("from Step 6" → "from Step 8" — the model ID comes from registration approval in Step 8, not task-dir setup in Step 6).

Copy link
Copy Markdown
Collaborator

Thanks, Robbert. I tested revision 69419c9 with real Fashion-MNIST data. The focused runtime checks passed: two clients trained successfully, weights saved and reloaded, both submissions passed the default auditor policy, T1/T2 aggregation worked, and the resulting global weights supported next-round training.

Training used 1,024 images per client for the service’s unchanged 10 epochs. Client accuracy was 82.88% and 81.48% on the separate 10,000-image test set; aggregate accuracy was 82.43%.

Two small walkthrough corrections remain, confirmed against the CLI parser:

  1. Step 8: remove --isOpenSource false. --isOpenSource is a boolean flag; omitting it defaults to false.
  2. Step 9: train-lms has no --submit option. Use:
    dincli client train-lms <MODEL_ID>
    dincli client submit-lm <MODEL_ID>

These checks exercised the Python services directly with local transport replacing IPFS. They did not validate Docker workers or the full on-chain lifecycle.

I found no functional CNN/service issue in these checks. Once those two documentation corrections land, I’m comfortable approving with the full local-devnet round tracked as follow-up validation. Since that remains an acceptance criterion for #276, please replace Closes #276 with Related to #276 so the issue stays open.

robertocarlous and others added 2 commits November 3, 2026 16:59
Step 8: --isOpenSource is a boolean flag; omitting it defaults to false,
so passing --isOpenSource false is redundant and confusing. Removed.

Step 9: train-lms has no --submit option. Split into the two separate
commands the CLI actually exposes.
@robertocarlous

Copy link
Copy Markdown
Collaborator Author

@Santiagocetran The changes has been done

@Santiagocetran Santiagocetran left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Robbert! I’ve checked the latest revision, and both walkthrough corrections are in place. The PR also keeps #276 open for the remaining full local-devnet validation.

The model implementation is unchanged from our successful focused runtime checks, and all current CI checks pass. No further changes requested from my side—this is ready for approval and the merge queue. Thanks for working through the feedback!

@Santiagocetran
Santiagocetran added this pull request to the merge queue Nov 3, 2026
Merged via the queue into InfiniteZeroFoundation:develop with commit c6b6fd3 Nov 3, 2026
4 checks passed

Copy link
Copy Markdown
Collaborator

Post-merge CI passed on develop at c6b6fd3, with all checks green. Thanks again, Robbert! Full local-devnet validation remains tracked in #276.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants