Skip to content

feat(qc,#18962): FinBERT re-entraine - portage 06/19/02 + mesure hors echantillon - #19670

Merged
myia-ai-01 merged 3 commits into
mainfrom
feature/qc-18962-finbert-finetune
Oct 7, 2026
Merged

myia-ai-01 merged 3 commits into
mainfrom
feature/qc-18962-finbert-finetune

Conversation

@jsboige

@jsboige jsboige commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/qc — lane myia-po-2023:CoursIA — prev: MED/docs #19559

See #18962 — la moitié FinBERT. La moitié Chronos du même exemple est portée par la PR #19622, ouverte. See #18903 (verdict INCONCLUSIVE du modèle de base, critère 4). See #18957 (ligne retirée de « Exemples sans reproduction »).

Ce que la PR livre

Le ré-entraînement FinBERT du livre (exemple 06/19/02) n'existait pas dans le dépôt : la table du chapitre 06 le portait en GAP. Cette PR le porte, et le mesure hors échantillon — ce que le livre ne fait pas.

Artefact Rôle
main_finetuned.py Portage fidèle du FinbertFineTunedModelAlgorithm du livre ; écarts n1–n8 documentés en tête de fichier. Non exécutable en CI ni sur un nœud QC ordinaire : le ré-entraînement tourne dans l'algorithme et demande un GPU.
finetune/run_finetune_finbert.py Harnais hors ligne : corpus, étiquetage, ré-entraînement GPU, évaluation hors échantillon base contre ré-entraîné.
finetune/measures/ Une mesure par graine (1, 2, 3, 42) plus l'agrégat.
README.md Sections « Corpus et étiquetage », « Sélecteur d'actif », « Résultat », verdict.
BOOK_MAPPING.md Lignes 19/01, 19/02 et la table des chiffres du livre (critères 3 et 5 de l'issue) ; ligne 04/05, 04/18, 05/02, 05/15 retirée de « Exemples sans reproduction » (#18957, portées par #19163) et ligne 06/18/02, 06/19/02 réduite à Chronos (addendum du coordinateur).
README.md (§Métriques) Verdict écrit du modèle de base : INCONCLUSIVE, avec son motif (critère 4 de #18903).

Critères de l'issue #18962, un par un

# Critère État
1 Porter le ré-entraînement (GPU, RECOVERABLE-MACHINE) Fait — main_finetuned.py (portage) + finetune/ (harnais), exécuté sur le RTX 3080 Ti de po-2023
2 Comparer base et ré-entraîné sur la même période hors échantillon Fait — exactitude de classification et effet sur la stratégie, 4 graines, période tenue à l'écart
3 FinBERT : le portage de base ne produisait aucune transaction (#18903) — régler d'abord ou dans le même travail Fait ailleurs, dans le même travail — livrable v7 du 2026-10-05, mesuré (voir plus bas). #18903 reste ouverte : sa fermeture revient au coordinateur
4 Verdict §C, au moins 4 graines Fait — 4 graines, verdict NO BEATS
5 Mettre à jour les lignes 18/02 et 19/02 de la table du chapitre 06 Fait pour 19/02 (et 19/01) ; 18/02 est portée par #19622

Protocole

  • Corpus : FNSPID Stock_news/All_external.csv (date + ticker + titre, même forme que le Tiingo News du livre). Cache local hors dépôt (CC BY-NC 4.0) : seules les mesures sont committées.
  • Découpage : entraînement 1 680 échantillons sur 53 mois ; hors échantillon 268 échantillons sur 6 mois (2019-07 → 2019-12), retirés avant l'entraînement. Le livre n'a aucune séparation entraînement / hors échantillon : il ré-entraîne et prédit sur les mêmes 100 échantillons du mois.
  • Recette du livre : sélection mensuelle (les 10 plus liquides → la plus volatile), 30 derniers jours d'actualité, étiquette = réaction du cours, 100 derniers échantillons, découpage 25/75 en trois classes, from_pretrained(..., num_labels=3) frais chaque mois, Adam lr 3e-5, 2 époques.
  • Graines : 1, 2, 3, 42.

Résultat — 4 graines

Graine Exactitude ré-entraînée Exactitude de base Écart McNemar p Classes prédites [nég, neu, pos]
1 0,2948 0,4515 −0,1567 0,0001 [109, 14, 145]
2 0,3694 0,4515 −0,0821 0,0507 [20, 6, 242]
3 0,3731 0,4515 −0,0784 0,0640 [36, 0, 232]
42 0,3470 0,4515 −0,1045 0,0175 [203, 4, 61]
vérité — — — — [90, 75, 103]

Écart moyen −0,1054, écart-type inter-graines 0,0361, soit −2,92 σ ; aucune graine sur quatre ne bat le modèle de base (graines_gagnantes = 0).

Significativité. McNemar exact sur les paires discordantes, l'analogue classé de Diebold-Mariano : les quatre graines ont plus de paires où la base a raison et le ré-entraîné tort que l'inverse (79/37, 69/47, 69/48, 79/51). Ce n'est pas un σ seul : les deux jambes concordent.

Effet sur la stratégie (mêmes règles des deux côtés, même graine de tirage) : rendement cumulé −0,037 (base) contre −0,046 (ré-entraîné). Les deux bras perdent ; le ré-entraîné perd davantage. Aucune métrique de performance n'est revendiquée ici : ce rendement vient du harnais hors ligne, pas d'un backtest QC.

Verdict : NO BEATS

Au sens strict : ce n'est pas « amélioration non démontrée », c'est dégradation démontrée. Le modèle ré-entraîné est moins exact que le modèle de base sur les quatre graines, d'un écart significatif.

Ce que la distribution des classes prédites ajoute, et que l'exactitude seule ne montrerait pas. Le modèle de base prédit [70, 105, 93] : il sur-prédit le neutre, biais connu de FinBERT sur du texte court. Le ré-entraîné prédit 0 à 14 neutres sur 268, quelle que soit la graine — la classe neutre disparaît. Le signe du déséquilibre dépend en revanche de la graine (242 positifs pour la graine 2, 203 négatifs pour la graine 42) : ce n'est donc pas un effondrement sur une classe fixe, mais la perte du neutre et une instabilité de signe d'une graine à l'autre. Deux époques à 3e-5 sur 1 680 étiquettes bruitées suffisent à détruire la frontière du neutre d'un modèle pré-entraîné.

Ce que ce verdict ne dit pas. Il ne condamne pas la recette du livre ; il condamne sa mesure hors échantillon dans ces conditions. Le livre ré-entraîne et prédit sur les mêmes 100 échantillons du mois : sa mesure ne peut pas voir cette perte. C'est exactement l'écart que l'issue demandait de mesurer.

Portée. Un univers de 24 grandes capitalisations, une fenêtre (2015-2019), un modèle de base, quatre graines. Falsifiable via finetune/measures/, reproductible par finetune/run_finetune_finbert.py.

Preuves d'exécution

  • Appareil : device = NVIDIA GeForce RTX 3080 Ti Laptop GPU, torch = 2.8.0+cu126. Le nom de la carte est journalisé par le harnais, pas seulement l'index — sur une machine à deux GPU, cuda:0 ne dit pas laquelle a travaillé.
  • Corpus : 13,06 M d'enregistrements parcourus, 22 496 articles retenus, 18 tickers. Le corpus complet révèle une couverture très inégale (HD 2 587 articles … AMD 14) ; la tête de classement du livre est AMD, ce qui écartait 37 des 60 mois pour une raison de couverture, pas de stratégie.
  • Découpage : 1 680 / 53 mois en entraînement, 268 / 6 mois hors échantillon, 59 des 60 mois couverts (seul 2015-01 tombe, faute d'articles).
  • Histogrammes : pred_base, pred_finetuned, vrai sont committés par graine — c'est l'instrument qui sépare « il se trompe » de « il a effondré sa sortie ».

Pas de backtest pour le bras ré-entraîné — pourquoi

main_finetuned.py ré-entraîne dans l'algorithme et demande un GPU : il n'est pas déployable sur QC Cloud, pour la même raison que l'exemple du livre lui-même. C'est l'exception GPU-only de la règle F, déclarée, pas un contournement.

Le bras de base est, lui, backtesté : livrable v7, 2022-01-01 → 2022-03-01, capital 1 M, 40 séances, statut Completed., 2 ordres (= les deux rebalancements mensuels), Sharpe −1,137, rendement net −26,230 %, drawdown max 37,800 % (projet QC 29936073 ; table complète au §Historique du README). Ces chiffres étaient déjà sur main avant cette PR.

Deux écarts au livre — mesurés, pas supposés

  1. Fenêtre de réaction. Le livre mesure la réaction entre deux parutions consécutives à la seconde (Resolution.SECOND). À résolution quotidienne, la règle s'effondre : 410 des 680 paires (60 %) tombent dans la même séance, donc 429 étiquettes (63 %) sont nulles exactement — une classe neutre majoritaire à 75 % que le livre ne connaît pas. Le harnais mesure la réaction à la parution. La distribution des classes passe de 12/75/13 à 32/29/38, contre les 37,5/25/37,5 que la règle du livre vise.
  2. Sélecteur d'actif. Le livre suppose une couverture d'actualité universelle (Tiingo News). Hors ligne, FNSPID est très inégale : le harnais descend d'un rang quand le candidat n'est pas observable. Quand le premier choix du livre est couvert, il reste retenu à l'identique.

Les deux sont écrites en tête du harnais et détaillées dans le README.

Conflit attendu, déclaré

La ligne 306 de BOOK_MAPPING.md (table « Exemples sans reproduction ») est également réécrite par la PR #19622. Cette PR la touche sur instruction du coordinateur (addendum du 07/10, msg-20261007T065859-z4zhz5) : elle la réduit à 06/18/02 — la part Chronos, qui dépend de #19622 — puisque 06/19/02 passe COVERED ici. Quand l'une des deux PRs mergera, l'autre devra une résolution d'une ligne : garder la version réduite à Chronos, ou retirer la ligne entière si #19622 est déjà mergée.

Les lignes 19/01 et 19/02 que j'ai modifiées sont voisines de la ligne 18/02 que #19622 modifie : un conflit de voisinage reste possible, il se résout en gardant les deux modifications (aucune ne se recouvre).

Observation, non corrigée ici : la réécriture de la ligne 306 par #19622 porte « 06/19/02 … bloqué par #18903 ». #18903 est encore ouverte, mais son blocage est levé par la mesure (le livrable v7 produit ses deux ordres, cf. ci-dessus) — la formulation sera à revoir au merge.

Ce que la PR ne fait pas

  • Elle ne touche pas main.py ni le notebook de la série : le portage de base n'est pas modifié.
  • Elle ne ferme aucune issue (See, jamais Closes).
  • Elle ne revendique aucune amélioration : le verdict est NO BEATS, et il est rapporté comme tel.

🤖 Generated with Claude Code

jsboige and others added 2 commits October 7, 2026 08:42
… echantillon

Portage fidele du re-entrainement FinBERT du livre (exemple 06/19/02) et mesure
hors echantillon contre le modele de base pre-entraine.

Artefacts :
- main_finetuned.py : portage du FinbertFineTunedModelAlgorithm (ecarts n1-n8
  documentes en tete de fichier)
- finetune/run_finetune_finbert.py : harnais hors ligne (corpus FNSPID,
  etiquetage par reaction de cours, re-entrainement GPU, evaluation hors
  echantillon base contre re-entraine)
- finetune/measures/ : une mesure par graine + agregat
- README.md : section resultat mesuree et verdict

Mesure (graines 1/2/3/42, RTX 3080 Ti Laptop, torch 2.8.0+cu126, 1 680
echantillons d'entrainement sur 53 mois, 268 hors echantillon sur 6 mois) :
- exactitude du modele de base : 0,4515
- exactitude re-entrainee moyenne : 0,3461
- ecart moyen -0,1054, ecart-type inter-graines 0,0361, soit -2,92 sigma
- aucune graine sur quatre ne bat le modele de base

Verdict : NO BEATS. La distribution des classes predites montre que le modele
re-entraine perd la classe neutre (0 a 14 predits sur 268, contre 75 reels),
avec un signe de desequilibre qui depend de la graine - ce n'est donc pas un
effondrement sur une classe fixe.

Voir #18962 : la moitie Chronos du meme exemple est portee par la PR #19622.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s a jour

Critere 5 de #18962 : la table du chapitre 06 portait le re-entrainement FinBERT
en `GAP`.

- 19/02 : `GAP` -> `COVERED`, avec le harnais et le verdict mesure (NO BEATS,
  ecart moyen -0,1054, -2,92 sigma, aucune graine gagnante).
- 19/01 : la remarque « le portage ne produit pas de transaction » est perimee --
  le livrable v7 produit ses deux rebalancements (mesure du 2026-10-05). #18903
  reste ouverte ; c'est sa fermeture qui revient au coordinateur, pas le constat.
- Table des chiffres du livre (19/02) : `aucune reproduction (GAP)` -> les
  mesures hors echantillon.

La ligne 306 (« Exemples sans reproduction », 06/18/02 et 06/19/02) n'est pas
touchee : la PR #19622, ouverte sur la moitie Chronos, la reecrit deja.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 7, 2026

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

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-po-2023:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-10-07) :

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

prev: genre mot-clé fermant (#10093) — LEVÉ (2026-10-07T09:09:51Z).

aucun genre mots-clé fermant dans le body ni les commits ; prev: accepté(s) : #19559

Run vert du garde : ce commentaire bloquant est obsolète. Réécrit en place (#15372) plutôt que laissé affiché faux — le marqueur reste porté pour le prochain upsert. Historique : runs Always-on guards de la PR.

… lignes livrenees (#18903, #18957)

Addendum file profonde du coordinateur (msg-20261007T065859-z4zhz5) :
trois restes fermes dans un seul commit.

1. #18903, critere 4 : le README du modele de base refuse d'ecrire un
   verdict. Il l'ecrit desormais -- INCONCLUSIVE -- avec son motif :
   sur 40 seances et 2 ordres, l'echantillon est trop court pour
   conclure ; ce backtest verifie que le portage complete et trade,
   il ne mesure pas la strategie.
2. #18957 : la ligne 04/05, 04/18, 05/02, 05/15 de la section
   « Exemples sans reproduction » est retiree -- #19163 les a portes,
   ils sont COVERED plus haut dans la table.
3. #18962 : la ligne 06/18/02, 06/19/02 garde seulement Chronos
   (06/18/02, depend de #19622) ; FinBERT 19/02 passe COVERED par
   cette PR.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige
jsboige force-pushed the feature/qc-18962-finbert-finetune branch from c1c5191 to c9a878a Compare October 7, 2026 07:13
@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[INFO] Diagnostic du rouge prev_guard (jambe Always-on guards, run 37583230416) — defect de ce body, pas de la base

Verbatim du verdict : prev-abandoned -> [19626]. La référence prev: du tag Grain cite #19626, une PR fermée sans merge — l'invariant #13475 exclut explicitement les PRs abandonnées (closed-unmerged).

Correctif d'une ligne : remplacer #19626 dans le tag Grain par une PR mergée ou encore ouverte de la lane. Le picker de la lane imputait ce rouge à la base par corrélation inter-PR — vérification firsthand : il est bien porté par ce body.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #19670 (feat(qc,#18962): FinBERT re-entraine - portage 06/19/02 + mesure hors echantillon) 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.

@github-actions github-actions Bot added the pr-overlap Advisory: another open PR touches the same files (organ #13615) label Oct 7, 2026
@jsboige

jsboige commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2027:CoursIA
pr: 19670
head: c9a878a
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 8d4f490ea227a02bb6d5020f180bde9fbf4aec38f5936a8d0410df5709536552
diff-files: 9
diff-additions: 1912
diff-deletions: 8
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19670
organ-rc: 0
[/ADJOINT PREFLIGHT]

Dossier tiers emis par myia-po-2027:CoursIA, lane qui ne porte pas cette PR (porteuse : myia-po-2023:CoursIA). Bloc rendu par --emit (verdict et champs mecaniques derives par l'organe, rc=0) ; les quatre lectures sont de ce cycle.

Actes de lecture.

  • complete — les 4 surfaces lues integralement : body (integral, en trois passes, 9984 c), 5 commentaires, 0 review, 0 thread inline.
  • body — tag Grain: DEEP/qc -- lane myia-po-2023:CoursIA en ligne 1. Le body annonce 9 artefacts ; le diff porte exactement 9 fichiers, +1912/-8 (portage main_finetuned.py, harnais finetune/, mesures par graine, README, BOOK_MAPPING). Rien hors perimetre.
  • checks — derives par l'organe dans la fenetre REST (fold latest-wins, READY exige vert).
  • b0 — aucune review, aucun thread ; les 5 commentaires : 4 advisories bots (organ-duplication clean, variation-genre-signals — concerne le tally LIGHT de la lane, pas cette PR DEEP, prev-close-keyword LEVE par l'organe lui-meme a 09:09:51Z, path-collision advisory) + 1 [INFO] de diagnostic d'auteur sur le rouge prev_guard (defect du body, corrige — le meme advisory le constate LEVE). Aucune reserve de tiers a lever.
  • scope — pass : 9 fichiers coherents avec la table d'artefacts annoncee.
  • domain — pass (QC/ML, criteres C et G) : verdict NO BEATS, donc la charge C vise l'honnetete de la mesure, non la preuve d'edge — et elle est tenue : 4 graines (1, 2, 3, 42) avec mesures committes par graine + agregat, hors echantillon tenu a l'ecart avant l'entrainement (268 echantillons sur 6 mois), table par graine avec distribution de verite, ecart moyen −0,1054, σ inter-graines 0,0361 (−2,92 σ), 0/4 graines battant la base, McNemar exact par graine (analogue classe du DM). Backtests/executions : harnais GPU execute (RECOVERABLE-MACHINE, RTX 3080 Ti po-2023, declare dans le body), corpus hors depot (CC BY-NC 4.0 — seules les mesures committes). Le portage declare honnetement sa non-executabilite en CI (GPU requis) avec le harnais qui la remplace.

@myia-ai-01
myia-ai-01 merged commit b78c72b into main Oct 7, 2026
40 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-overlap Advisory: another open PR touches the same files (organ #13615)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants