Flower AI Summit 2026·April 15–16·London

@zzsikungfu/nanogpt-shakespeare

1
0
flwr new @zzsikungfu/nanogpt-shakespeare

Federated Learning with NanoGPT and Flower

This example demonstrates federated learning for character-level language modeling using NanoGPT and Flower. Multiple clients each train a small GPT model on their own partition of the Tiny Shakespeare dataset, and the server aggregates weights using FedAvg. After training, the server generates a Shakespeare-style text sample from the final model.

The model is a "baby GPT" (~10.8M parameters) — small enough to train on CPU.

Fetch the App

Install Flower and clone the app:

pip install "flwr[simulation]>=1.26.1"
flwr new @kungfuai/nanogpt-shakespeare

This will create the following project layout:

nanogpt-shakespeare
├── nanogpt_shakespeare
│   ├── __init__.py
│   ├── client_app.py   # Defines your ClientApp
│   ├── server_app.py   # Defines your ServerApp
│   └── task.py         # NanoGPT model, data loading, train/test
├── pyproject.toml      # Project metadata and Flower config
└── README.md

Install the dependencies:

pip install -e .

Run the App

Run with the Simulation Engine

TIP

Learn more about Flower's Simulation Engine in the documentation.

flwr run .

You can override configuration values:

flwr run . --run-config "num-server-rounds=10 learning-rate=5e-4 max-steps=100"

Expected output over 5 rounds (2 simulated clients, 50 steps each, CPU):

RoundTrain LossVal LossPerplexity
04.2369.0
13.262.9719.5
22.742.6414.0
32.602.5613.0
42.532.5212.5
52.502.5212.4

Run with the Deployment Engine

TIP

Follow the Deployment Engine guide to learn about deploying Flower apps. For production use, consider enabling TLS and SuperNode authentication.

First, prepare demo data partitions. The dataset is Tiny Shakespeare (~1MB) which is downloaded automatically. To create partitions for deployment, run:

python -c "
from nanogpt_shakespeare.task import _download_shakespeare, _get_meta, _encode
import numpy as np
from pathlib import Path

text = _download_shakespeare()
meta = _get_meta()
ids = np.array(_encode(text, meta['stoi']), dtype=np.uint16)
n = len(ids)
split = int(n * 0.9)
train_ids, val_ids = ids[:split], ids[split:]

for i, num in enumerate([2]):
    chunk = len(train_ids) // num
    for p in range(num):
        out = Path(f'datasets/shakespeare_part_{p}')
        out.mkdir(parents=True, exist_ok=True)
        start = p * chunk
        end = start + chunk if p < num - 1 else len(train_ids)
        train_ids[start:end].tofile(out / 'train.bin')
        val_ids.tofile(out / 'val.bin')
        print(f'Created partition {p} at {out}')
"

Then launch SuperNodes, each pointing to a data partition:

flower-supernode --insecure --superlink="SUPERLINK_IP:9092" \
                 --node-config="data-path='datasets/shakespeare_part_0'"

Finally, run the app in your federation:

flwr run . my-federation

Configuration

ParameterDefaultDescription
num-server-rounds5Number of federated rounds
local-epochs1Training epochs per client per round
learning-rate1e-3AdamW learning rate
batch-size64Training batch size
block-size256Context window length (chars)
max-steps50Max training steps per round (0 = unlimited)
n-layer6Transformer layers
n-head6Attention heads
n-embd384Embedding dimension
dropout0.2Dropout rate