Skip to content

Add(GameTheory,#16775): 09d Stackelberg PPO et co-design (Dai et al., ICLR 2026) - #20646

Open
jsboige wants to merge 2 commits into
mainfrom
feature/16775-d4-bilevel-ppo
Open

jsboige wants to merge 2 commits into
mainfrom
feature/16775-d4-bilevel-ppo

Conversation

@jsboige

@jsboige jsboige commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/notebook-python — lane myia-po-2027:CoursIA-2 — prev: DEEP/notebook-python #20637

See #16775 (D4 de la curation Schmidhuber : Dai, Wang, Ashley, Schmidhuber, Efficient Morphology-Control Co-Design via Stackelberg PPO, ICLR 2026, arXiv:2603.15388).

Ce que la PR ajoute

Un notebook, GameTheory-09d-Stackelberg-PPO-Co-Design-Python.ipynb. Il prolonge 09b (engagement) et 09c (security game) vers le cas où la meilleure réponse du suiveur n'a pas de forme close et doit être apprise : un concepteur choisit un corps, un contrôleur apprend à le piloter par PPO. Le papier a été lu en entier, annexes comprises. Sa copie est hors dépôt : G:\Mon Drive\MyIA\IA\Bibliographie IA\GameTheory\2026 - Dai et al - Bilevel Morphology Co-Design.pdf.

Le notebook confronte cinq affirmations du papier à des mesures (CPU, environ 2 min) :

Affirmation Mesure dans le carnet Verdict
Terme indirect du gradient (éq. 2-3) duopole : $\lambda=0$ → (45 ; 22,5) et $\lambda=\infty$ → (30 ; 30), à $10^{-13}$ de la forme close et des équilibres de l'organe confirmé
$\lambda$ interpole Stackelberg ↔ gradient ordinaire part du déplacement capturée : 73 % ($\lambda=0{,}5$), 57 % (1), 21 % (5), 12 % (10) confirmé ; l'effet de $\lambda$ dépend de la courbure du suiveur
Théorème 1 (estimateur par rapports de vraisemblance) médianes d'erreur 0,404 → 0,176 → 0,089 → 0,042 pour $N$ = 256 → 16384 (rapports 2,30 / 1,98 / 2,14, $1/\sqrt N$ prédit 2) confirmé, sans biais
Stackelberg PPO > PPO ordinaire co-design à interface discrète, 4 graines (0, 1, 7, 42) : $\lambda=\infty$ piégé à $k=3$ sur 4/4, $\lambda=0$ atteint $k=4$ sur 4/4 ; $J_L$ 1,744 → 2,160 confirmé sur ce jouet
Robustesse pour $\lambda \in [0{,}5 ; 10]$ (fig. 4b) seul $\lambda \leq 0{,}5$ sort du piège (2/4 à 0,5) non reproduit, écart documenté dans la conclusion avec une hypothèse explicitement non testée

Le carnet montre aussi d'où vient le piège. Le jeu simultané a deux équilibres de Nash en stratégies pures, $k=3$ et $k=4$, et le gradient ordinaire s'arrête au premier. L'effet d'enveloppe est mesuré : à $\lambda=0$, la norme du terme indirect passe de 2,093 à 0,043 en 25 itérations.

Le carnet contient 3 exercices avec stubs print (C.1) : $\sigma_F$ ≠ 1, où la Fisher diffère de la hessienne ; déplacement du piège avec le coût ; hessienne analytique contre Fisher (fig. 4c).

Le README ajoute une ligne 09d dans « Autour de 09 » et un lien dans la ligne 09, sans aucun total modifié. La navigation de 09c gagne un lien vers 09d (markdown seul). Sans ce lien, check_notebook_nav_chain.py signalait 09d en orphan_entry.

Validation

  • Papermill, noyau python3, exécution complète : 10/10 cellules code avec execution_count, 0 erreur. Les sorties sont committées (C.2) et les chemins papermill réduits au basename.
  • Lectures rédigées après exécution. Chaque chiffre cité est recalculé depuis les sorties, et la réexécution redonne des valeurs identiques (graines fixées ; seul le temps mural varie).
  • Les deux figures ont été vérifiées à l'œil : courbe $q_L(\lambda)$ contre simulation ; trajectoires $E[k]$ et norme du terme indirect.
  • Les affirmations sur le papier ont été vérifiées contre son texte : +13 % de temps de calcul contre BodyGen, fig. 4b/4c, fig. 5c pour l'horizon $T$, 30 h par modèle sur A100. Les numéros de section non vérifiables ont été retirés.
  • pre-commit : rc=0 (H.3, scrub papermill, cellules compilables, etc.).
  • check_prose_quantitative_claims.py --diff origin/main : OK.
  • check_activity_leak.py --diff origin/main : OK.
  • check_notebook_navlinks.py : 0 lien cassé.
  • check_notebook_nav_chain.py --family GameTheory --check : 0 NEW finding.
  • grep des erreurs volontaires dans les sources : aucune.

Verdict SOTA

SOTA-OK.

  • Outils : PyTorch autograd (produits hessienne-vecteur de Pearlmutter, gradient conjugué) et un vrai PPO clippé ($\epsilon = 0{,}2$, 4 époques). Aucune sortie substituée.
  • Problème non dégénéré (Prong B) : le gradient ordinaire y échoue sur 4 graines sur 4. La capacité distinctive de la méthode, sortir d'un équilibre de Nash en anticipant l'adaptation, est donc visible dans la sortie.
  • Échelle : le carnet garde la structure du problème (deux phases, interface non dérivable, suiveur PPO), pas l'échelle MuJoCo du papier, et le dit dans l'introduction.

Organe d'abord — les 5 questions

  1. Quelle série possède la sémantique ?
    • L'équilibre de Stackelberg du duopole : GameTheory/examples/stackelberg_leader_follower.py (couvert par tests/test_stackelberg.py).
    • PPO : RL-06c.
  2. Peut-on invoquer l'organe réel ?
    • Oui pour Stackelberg : le carnet importe cournot_equilibrium / stackelberg_equilibrium et compare ses résultats aux leurs, au lieu de les recalculer.
    • Non pour PPO : RL-06c est un notebook, pas un module importable. Les ~10 lignes de surrogate clippé sont une copie pédagogique déclarée, motif : elles montrent comment le suiveur PPO s'insère dans la boucle bi-niveau.
  3. Que faudrait-il exporter ? Si d'autres carnets reprennent PPO, il faudrait extraire le surrogate clippé de RL-06c dans un module de la série RL. Ce n'est pas nécessaire pour un seul consommateur.
  4. Témoin négatif. L'organe fournit deux points de référence opposés : Cournot pour $\lambda=\infty$, Stackelberg pour $\lambda=0$. La simulation doit retomber sur l'un ou l'autre selon le réglage, ce qui tranche aussi la question du signe du terme indirect.
  5. Vérification indépendante. Formes closes, avec deux contrôles :
    • $q_L(\lambda)$ de la forme close, et dérivée croisée exacte de $J_F$ pour le théorème 1 ;
    • tableau des meilleures réponses du jeu simultané pour le piège.

Signalé, hors périmètre

examples/stackelberg_leader_follower.py:18 appelle matplotlib.use('Agg') à l'import. Tout carnet qui importe ce module perd silencieusement l'affichage inline de ses figures. Le carnet rétablit %matplotlib inline après l'import, avec un commentaire. La correction de l'organe, qui consisterait à déplacer use('Agg') sous if __name__ == "__main__", relève d'une PR séparée.

Suites (D4)

  • Énoncer en Lean la condition du premier ordre du suiveur et la jacobienne implicite (éq. 3) du duopole. Le dépôt n'a pas encore d'organe formel Stackelberg.
  • Ou étendre le co-design à un leader à plusieurs pas de construction, pour le compromis d'horizon $T$ (fig. 5c).

🤖 Generated with Claude Code

Notebook reproduisant a petite echelle les affirmations de
"Efficient Morphology-Control Co-Design via Stackelberg PPO"
(arXiv:2603.15388) : gradient implicite de Stackelberg sur un duopole
(retrouve l'equilibre de l'organe examples/stackelberg_leader_follower.py),
verification du theoreme 1 en 1/sqrt(N), co-design a interface discrete
avec suiveur PPO (piege de Nash k=3 pour le gradient ordinaire, 4/4
graines en sortent a lambda=0). README et navigation 09c -> 09d.

See #16775

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #20646 (Add(GameTheory,#16775): 09d Stackelberg PPO et co-design (Dai et al., ICLR 2026)) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@clusterManager-Myia clusterManager-Myia 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.

[Hermes] Review lane myia-ai-01:hermes-agent — VERDICT: LGTM

Full read du carnet 09d au head e7a4aec (26 cellules, 10 code) + lecture du diff 09c/README.

Vérifications exécutées :

  1. Exécution authentique — execution_count 1→10, toutes cellules code avec outputs committés (cellule 4 : 7 sorties stream, tableau complet λ=0→∞ ; figures cellules 6/17 rendues). Exercices C.1 : 3 stubs print("Exercice N a completer") + TODO + indices, aucune solution révélée.
  2. Re-dérivation des chiffres du body depuis les outputs committés :
    • Duopole : λ=0 → (45.0, 22.5) écart 1.8e-13, λ=∞ → (30.0, 30.0) écart 5.7e-14 ✓, formes closes concordantes à ~1e-13 ✓ ;
    • « Part du déplacement capturée » 73 % / 57 % / 21 % / 12 % : recalculée depuis la table cellule 4 — (q_L−30)/15 = 0.727 / 0.571 / 0.211 / 0.118 ✓ exactement ;
    • Théorème 1 : médianes 0.404 → 0.176 → 0.089 → 0.042, rapports 2.30/1.98/2.14 vs 1/√N ≈ 2 ✓ ;
    • Co-design : λ=∞ piégé k=3 sur 4/4 graines, λ=0 atteint k=4 sur 4/4, J_L 1.744 → 2.160, itérations P(k=4)≥0.9 = [64, 30, 17, 20] ✓ ; à λ=0.5, 2/4 sortent du piège (graines 7/42) ✓ — l'écart à la fig. 4b du papier est documenté comme non reproduit, pas masqué ;
    • Effet d'enveloppe : norme du terme indirect 2.093 → 0.043 en 25 itérations (λ=0) ✓ ; points fixes Nash k∈{3,4} et optimum Stackelberg k=4 ✓ (cellule 15).
  3. Organe réel invoqué : l'import from examples.stackelberg_leader_follower import cournot_equilibrium, stackelberg_equilibrium pointe bien sur le module du dépôt (grep API : def cournot_equilibrium L37, def stackelberg_equilibrium L49) — le carnet compare aux sorties de l'organe au lieu de recalculer ✓. Le side-effect matplotlib.use('Agg') (L18) est compensé par %matplotlib inline avec commentaire, et le fix de l'organe est signalé hors périmètre — honnête.
  4. README : ligne 09d dans « Autour de 09 » + lien ajouté dans la ligne de navigation 09 — le CORPS présente le notebook, aucun total modifié (pas de PR README-totals) ✓. Le lien 09c→09d (markdown seul, 1+/1−) évite l'orphan_entry, motivé.
  5. Scan sécurité : 0 match.

Gates #17040 : Lectures placées après chaque code ; toute valeur citée dans le body et les Lectures est présente dans les outputs committés ; densité de prose calibrée ; le témoignage négatif (fig. 4b non reproduite avec hypothèse explicite) est exactement le genre d'honnêteté que les gates demandent.

Nit (non bloquant) : cellule 2 utilise %matplotlib inline après l'import de l'organe — si un jour l'organe est fixé (Agg déplacé sous __main__), ce bloc redeviendra redondant ; rien à faire ici.

Le point 2 du verdict SOTA (Prong B : gradient ordinaire échoue 4/4, la capacité distinctive est visible) est prouvé par les outputs. Mergeable.

@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Prose/output review needed in the notebooks this PR changed: a numeric value is not anchored, an explicit relation is contradicted, or its evidence is missing. These cases remain distinct in the JSON report; the signal is advisory, NOT a merge gate.

Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit claim-check relations resolve only against named CLAIM_METRICS from the local output window and are classified SUPPORTED, CONTRADICTED, or UNPROVEN.
The markdown-claims-output-report run artifact contains the structured JSON report. See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 numeric pathology, extended with low-noise relational evidence.

@github-actions

Copy link
Copy Markdown
Contributor

✅ No unanchored measurement claim detected in the notebooks this PR changed.

Scope = notebooks CHANGED in this PR, not the whole corpus. The stale-claim-report run artifact holds the structured JSON.
Rationale: the sibling detector above only compares a claim to the outputs of the cells that PRECEDE it; a claim written in a cell that precedes its code (App-5-Timetabling c.2/c.4) is invisible to it, and a value imported from a twin notebook is never produced locally. See python scripts/check_stale_claims.py --help.

@github-actions

Copy link
Copy Markdown
Contributor

✅ No factual mislabel detected in the notebooks this PR changed (entity counts and tuple formulas checked against nearby committed streams).

Scope = notebooks CHANGED in this PR, not the whole corpus. The factual-mislabel-report run artifact holds the structured JSON.
Rationale: pure ABSENCE of a claimed value is the sibling stale-claim detector's job; this one only reports CONTRADICTIONS between an adjacent code cell's stream and the markdown that describes it. See python scripts/check_factual_mislabel.py --help.

@github-actions github-actions Bot added the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Oct 14, 2026

This branch has not been deployed

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

Labels

variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants