Skip to main content

ES-MoE Toolkit

Drop-in expert-sparse MoE block for Ultralytics YOLO


Python PyPI Docs Colab DeepWiki License

One call adds the block, the router loss reaches the optimiser, and every number here has a run record behind it.

Docs: English · 中文 · Quick start in Colab: notebooks/quickstart.ipynb · Ask questions about the code: DeepWiki.


Install

pip install esmoe

The distribution, the import and the CLI are all esmoe; the project is written ES-MoE in prose.

Requires ultralytics.

Use

One call covers register, graft, build and wire:

import esmoe

model = esmoe.equip("yolo11n.yaml", weight=0.01)
model.train(data="coco8.yaml", epochs=10)

Or take the steps apart when you need control over each one:

from ultralytics import YOLO
import esmoe

esmoe.inject_esmoe()                                    # make `ESMoE` resolvable in model.yaml
esmoe.graft("yolov8n.yaml", out="v8-esmoe.yaml", at=[4, 6])  # insert blocks, renumber the head
model = YOLO("v8-esmoe.yaml")
esmoe.attach_aux_loss(model, weight=0.01)               # router loss joins the training loss

From the shell:

esmoe graft yolo11n.yaml -o yolo11n-esmoe.yaml -e 4 -k 2 --at backbone_end

attach_aux_loss adds an esmoe_aux entry to the trainer's loss table, so a non-zero, back-propagated auxiliary term shows up in results.csv rather than merely in a config.

Written by hand, a grafted config layer is just:

[-1, 1, ESMoE, [4, 2]]   # num_experts, top_k

The block is channel preserving and infers its width on the first forward, which is what lets stock parse_model size it without a patch.

Extend

Experts and the balancing objective are plain callables, so a variant is a few lines:

esmoe.ESMoE(num_experts=4, top_k=2, expert=MyExpert, balance=my_balance_fn)

MyExpert(c1, c2, k) -> Module, my_balance_fn(probs, gate) -> scalar. esmoe.blocks(model) walks every block in a model, and esmoe.collect_aux_loss(model) returns the current step's router loss for custom training loops.

Compatibility

backbone build + forward grafted config aux loss in training
YOLOv8 yes yes yes
YOLO11 yes yes yes
YOLO12 yes yes yes
YOLO26 yes yes yes

Verified by tests/test_ultralytics.py on ultralytics 8.4.101 and 8.4.132, which report loss items in two different shapes; both are handled. The training column is backed by real 1-epoch VisDrone runs on all four generations (results/*-compat-*.json), each logging a non-zero train/esmoe_aux.

DDP works: attach_aux_loss routes model.train() through a trainer class that lives in esmoe.trainer, so the worker processes ultralytics spawns register the block and the auxiliary loss before they build. Verified by scripts/verify.py (the real worker file in a fresh interpreter; two gloo ranks with agreeing router gradients). Not supported together with compile=True, which turns off find_unused_parameters.

Selected default

ESMoE(num_experts=4, top_k=2) with attach_aux_loss(weight=0.01), chosen under one budget over 2/4/8-expert and top-1 variants. Under the repository protocol (VisDrone, imgsz 800, 120 epochs, three seeds) the paired result on YOLOv8n is +0.0025 mAP50 (2/3 seeds) and +0.0004 mAP50-95, at +10.4% parameters and about 9% more wall-clock per epoch. By COCO-style area bucket, large objects get consistently worse (APl −0.010, 0/3) and small-object recall consistently better (ARs +0.003, 3/3). On YOLO11n the same comparison is a wash: the mechanics transfer across backbones, the accuracy effect does not.

The default graft leaves YOLOv8's P5 lateral reading SPPF rather than the block; graft(..., rewire=True) changes that and is the next comparison to run. Reasoning and full tables: docs/SELECTION.md, results/buckets.md, results/routing.md.

Develop and reproduce

uv sync --group dev
uv run pytest -q
uv run python scripts/capture_env.py                  # freeze environment into env/
EPOCHS=20 FRACTION=0.25 SEEDS="0 1 2" bash scripts/sweep.sh
uv run python scripts/report.py                       # results/summary.md

Every run writes one machine-readable record to results/ (config, dataset, hardware, budget, seed, metrics, artifact, status, limitation). Read limitations.md before quoting any number.

Linked projects

License

AGPL-3.0-only, matching the Ultralytics ecosystem it builds on.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

esmoe-0.1.4.tar.gz (32.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

esmoe-0.1.4-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

Details for the file esmoe-0.1.4.tar.gz.

File metadata

  • Download URL: esmoe-0.1.4.tar.gz
  • Upload date:
  • Size: 32.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for esmoe-0.1.4.tar.gz
Algorithm Hash digest
SHA256 3d4c564cc345fa0579189740a3b7cb6bb916916e352576f070fd4a2edc19c86f
MD5 0b11d56606a9c3fac169d7060a4a3a36
BLAKE2b-256 caa3fe868011209978c4e08b818e4274ba84f5fb7ae382d2f84a749d53a30f27

See more details on using hashes here.

File details

Details for the file esmoe-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: esmoe-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 26.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for esmoe-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 07b940b7768f4fa40c1f6efcbcc599020318504c8ff36fd15ea51d04cfdbc869
MD5 134fa48e279ffb4f19561ea1b63ff8a8
BLAKE2b-256 8f0a888957a03e4b2f4e50b3ee2813f9f6e9a84c3877134ab5f2127268e95772

See more details on using hashes here.

Release history Release notifications | RSS feed

1.0.0

2 files

0.1.6

2 files

0.1.5

2 files

This release

0.1.4 This release

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page