feat(poster): first draft

This commit is contained in:
HEL
2026-08-09 22:43:21 +02:00
parent 74398852d6
commit 82dc2545b9
6 changed files with 163 additions and 95 deletions
+5 -1
View File
@@ -6,6 +6,7 @@ set shell := ["bash", "-uc"]
outdir := "out"
report_out_path := outdir / "report.pdf"
summary_out_path := outdir / "summary.pdf"
poster_out_path := outdir / "poster.pdf"
default: all
@@ -35,4 +36,7 @@ report: _setup
summary: _setup
typst c --root . summary/exec_summary.typ {{summary_out_path}}
all: report summary
poster: _setup
typst c --root . poster/poster.typ {{poster_out_path}}
all: report summary poster
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.9 KiB

+22
View File
@@ -0,0 +1,22 @@
import qrcode
import qrcode.constants
from qrcode.image.svg import SvgPathImage
def main():
urls: dict[str, str] = {
"gitea": "https://git.kb28.ch/HEL/midas",
"github": "https://github.com/LordBaryhobal/midas",
}
factory = SvgPathImage
for name, url in urls.items():
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_Q, version=4)
qr.add_data(url)
qr.make()
img = qr.make_image(image_factory=factory)
img.save(f"qr_{name}.svg")
if __name__ == "__main__":
main()
+132 -93
View File
@@ -10,9 +10,56 @@
#import "@preview/isc-hei-poster:0.8.1": isc-poster, isc-card, isc-colbreak
#import "@preview/cetz:0.5.2": canvas, draw
#import "../meta.typ"
#import "../report/figs/architecture.typ"
#import "@local/codly:1.3.1": codly, codly-init, local
#import "@preview/codly-languages:0.1.10": codly-languages
#let poster-orientation = "portrait"
#show: codly-init
#codly(
languages: codly-languages
+ (
midas: (
name: "Midas",
color: rgb("#eedd47"),
icon: box(
image(
"../assets/icon.svg",
height: 130%,
fit: "contain",
),
),
),
),
)
#set raw(
syntaxes: path("../midas.sublime-syntax")
)
#show raw.where(block: true): set text(size: 0.9em)
/*
#show columns: it => {
it
place(
top + center,
//dx: 0cm,
//dy: 21cm,
dx: -6cm,
dy: 21.3cm,
rect(
stroke: gray + 2pt,
fill: white,
radius: 0.5cm,
//image("../assets/icon.svg", width: 3cm)
image("../assets/icon.svg", width: 4cm)
)
)
}
*/
#show: isc-poster.with(
title: meta.title,
subtitle: meta.subtitle,
@@ -33,127 +80,119 @@
)
#isc-card(title: "Summary")[
Les dossiers de santé électroniques ne peuvent être centralisés sans risque juridique et éthique. Ce travail présente *MediFL*, un cadre d'apprentissage fédéré intégrant la
confidentialité différentielle (ε-DP) et une agrégation robuste aux nœuds défaillants. Évalué sur trois cohortes hospitalières totalisant 180 000 patients, MediFL atteint une AUC de *0.91* avec un budget de confidentialité ε = 0.5, à seulement trois points de l'oracle centralisé (AUC 0.94). La convergence est assurée en *60 rounds* de communication, sans qu'aucune donnée brute ne quitte les établissements participants.
Python is one of the most popular programming languages, especially in data science. Although highly flexible and somewhat easy to learn, its leniency can often lead to type errors. Indeed, with duck-typing, the developer is responsible for making sure operations are valid and do what they are meant to do.
This project introduces *Midas*, a new type system built on top of Python's type hints, capable of checking types at *compile-time* and generating *runtime assertions* for cases that are not statically known.
Midas allows users to define *custom types* in a simple DSL, use them in Python type hints and compile their code to a fully type-checked script with added assertions.
Its typing rules are stricter than Python's and allow typing complex operations on Pandas dataframes too.
]
#isc-card(title: "Introduction")[
L'accès partagé aux dossiers médicaux électroniques permettrait d'entraîner des modèles prédictifs plus robustes et de détecter des pathologies rares. Cependant, la réglementation (RGPD, LPD suisse) et les impératifs éthiques empêchent la transmission de données brutes entre établissements. L'apprentissage fédéré déplace le calcul vers les données plutôt que l'inverse : seuls des gradients de modèle sont échangés, jamais les dossiers patients.
Data science and data engineering, by definition, involve handling some kind of data. In the real world, data comes in a variety of forms. Sometimes, different kinds of values can be mixed, such as when computing a speed from a distance and a duration, but sometimes they cannot. This is exactly what happened to NASA's Mars Climate Orbiter, which failed its orbital insertion because of a unit mixup@MCOReport.
*Verrou scientifique :* comment garantir une confidentialité formelle (ε-DP) tout en préservant la convergence du modèle global face à l'hétérogénéité statistique des cohortes chaque hôpital ayant ses propres pratiques de codage et démographies ?
To avoid such mistakes, many programming languages and frameworks use some form of static typing, which allows compiler to detect, report and prevent mixing incompatible values before even running the program. Python does not use such a system but rather implements _duck-typing_. This allows developers to completely omit typing annotations and the interpreter will only check the necessary attributes and methods when they are accessed *at runtime*.
Static type checkers such as Pyright and MyPy already provide some informational diagnostics, but do not _enforce_ safety.
I developed *Midas* to help developers and data engineers even further by (1)~allowing custom type definitions in a more powerful language than Python's type annotations and (2)~generating assertions to verify at runtime values which cannot be checked statically. This new type system also allows users to define some *dependent types*, binding value constraints which are checked at runtime.
#figure(
rect(width: 100%, height: 7cm, fill: luma(235), stroke: none,
align(center + horizon)[_Architecture MediFL — des hôpitaux au modèle global_]),
caption: [Vue d'ensemble de MediFL : chaque établissement entraîne localement et transmet des gradients bruités au serveur agrégateur.],
)
{
set par(justify: false)
architecture.overview
},
caption: [Implementation architecture overview]
) <fig:architecture>
]
#isc-card(title: "Implementation")[
Le protocole MediFL se déroule en trois phases par round :
The type checker is composed of four main elements, as shown in @fig:architecture:
- *Types Registry*: holds all builtin and user-defined types
- *Midas Typer*: parses custom definitions and registers types
- *Python Typer*: checks Python source code
- *Generator*: inserts runtime assertions to produce a runnable script
+ *Distribution* le serveur envoie les poids globaux $theta_t$ aux $K$ participants sélectionnés aléatoirement.
+ *Entraînement local + clipping* chaque hôpital minimise la cross-entropie sur ses données puis clippe les gradients à norme $ C$.
+ *Agrégation DP-FedAvg* le serveur somme les gradients bruités et met à jour $theta_{t+1}$.
Typing rules were first formally defined, drawing heavily on _Types and Progamming Languages_@tapl.
The definition language parser's implementation follows R. Nystrom's _Crafting Interpreters_@Nystrom2021. The whole system is itself implemented in Python, leveraging the language's own `ast` module to parse and manipulate source code.
#table(
columns: (1fr, auto, auto, auto),
inset: 7pt,
align: (left, center, center, center),
table.header([*Méthode*], [*AUC*], [*Rounds*], [*ε*]),
[FedAvg (baseline)], [0.84], [50], [],
[FedAvg + DP], [0.82], [80], [1.0],
[*MediFL (hybride)*], [*0.91*], [*60*], [*0.5*],
[Oracle centralisé], [0.94], [], [],
)
Concrètement, le code correspond à une agrégation DP-FedAvg classique:
#figure(
```python
def dp_fedavg(grads, sizes, eps=0.5, C=1.0):
clipped = [clip(g, norm=C) for g in grads]
sigma = C * calibrate_sigma(eps, delta=1e-5)
noisy = [g + randn(sigma) for g in clipped]
w = [n / sum(sizes) for n in sizes]
return sum(wi * gi for wi, gi in zip(w, noisy))
```,
caption: [Agrégation DP-FedAvg clipping + bruit gaussien calibré sur ε.],
)
The type checker also includes some machinery to infer the result types of several *dataframe operations* and *aggregation methods*.
]
// ─── Column 2 ────────────────────────────────────────────────────────────────
#isc-colbreak()
// ─── Dodecahedron figure (reused from exec-summary) ──────────────────────────
#let ex_fig = canvas(length: 2cm, {
import draw: *
let phi = (1 + calc.sqrt(5)) / 2
ortho(flatten: true, {
hide({
line((-phi, -1, 0), (-phi, 1, 0), (phi, 1, 0), (phi, -1, 0), close: true, name: "xy")
line((-1, 0, -phi), (1, 0, -phi), (1, 0, phi), (-1, 0, phi), close: true, name: "xz")
line((0, -phi, -1), (0, -phi, 1), (0, phi, 1), (0, phi, -1), close: true, name: "yz")
})
intersections("a", "yz", "xy")
intersections("b", "xz", "yz")
intersections("c", "xy", "xz")
set-style(stroke: (thickness: 0.5pt, cap: "round", join: "round"))
line((0, 0, 0), "c.1", (phi, 1, 0), (phi, -1, 0), "c.3")
line("c.0", (-phi, 1, 0), "a.2")
line((0, 0, 0), "b.1", (1, 0, phi), (-1, 0, phi), "b.3")
line("b.0", (1, 0, -phi), "c.2")
line((0, 0, 0), "a.1", (0, phi, 1), (0, phi, -1), "a.3")
line("a.0", (0, -phi, 1), "b.2")
anchor("A", (0, phi, 1))
content("A", [$A$], anchor: "north", padding: .1)
anchor("B", (-1, 0, phi))
content("B", [$B$], anchor: "south", padding: .1)
anchor("C", (1, 0, phi))
content("C", [$C$], anchor: "south", padding: .1)
line("A", "B", stroke: (dash: "dashed"))
line("A", "C", stroke: (dash: "dashed"))
})
})
#isc-card(title: "Results")[
Évaluation sur les cohortes des HUG (Genève), du CHUV (Lausanne) et de l'Inselspital (Berne), ainsi que sur le jeu de données public MIMIC-IV (53 000 séjours UCI). La
convergence est atteinte en 60 rounds, contre 80 pour FedAvg+DP classique.
Developers can define *custom types* and *predicates* using the Midas language. *Dependent types* and *dataframe schemas* are supported, as shown in @fig:example-midas.
#figure(
grid(
columns: (1fr, 1fr),
gutter: 8pt,
align(center + horizon, ex_fig),
image("figs/made.svg", height: 7cm, fit: "contain"),
),
caption: [Graphe de connectivité inter-sites (gauche) et courbes de convergence AUC par méthode (droite). MediFL converge plus vite malgré le bruit différentiel.],
#codly(
header: [types.midas]
)
#figure(
```midas
predicate not_empty(text: str) = len(text) != 0
type Height = float where _ >= 0
alias People = Frame[
name: str where not_empty(_),
height: Height
]
```,
caption: [Example custom type definitions]
) <fig:example-midas>
Le budget de confidentialité ε = 0.5 est maintenu grâce à la composition RDP (*Rényi Differential Privacy*). L'écart résiduel avec l'oracle centralisé (3 points AUC) s'explique principalement par l'hétérogénéité des distributions inter-sites (Non-IID). Sur les cohortes de plus de 10 000 patients, l'AUC monte à *0.93*.
These types can then be used in a regular Python script. Running the type checker and compiler will then produce _diagnostics_. Some may be simple warnings about unknown variables, but definite type errors will prevent compilation. As demonstrated in @fig:example-python, type checking of dataframe operations is rather extensive, providing great coverage of common data science applications.
#codly(
header: [script.py],
highlights: (
(
line: 3,
start: 11,
tag: [#h(2pt)Column[Height]],
fill: blue.lighten(60%)
),
(
line: 4,
start: 17,
tag: [#h(2pt)Height],
fill: blue.lighten(60%)
),
)
)
#figure(
```python
import pandas as pd
people: People = cast(People, pd.read_csv(...))
heights = people["height"]
median_height = heights.median()
```,
caption: [Example type checking of dataframe operations]
) <fig:example-python>
Cast expressions such as in @fig:example-python:2 insert runtime assertion to check that values do conform to the expect type.
]
#isc-card(title: "Discussion")[
*Forces :* MediFL ne nécessite aucun transfert de données brutes entre établissements. La confidentialité est prouvable formellement = 0.5, δ = 10⁻⁵). L'architecture
tolère jusqu'à 30 % de participants défaillants par round grâce à l'agrégation pondérée par taille de cohorte.
*Strengths~:* strict static checking of a great subset of Python, thorough runtime checking of cast expressions and dependent types, extensive type inference of dataframe operations, modular and easily extensible
*Limites :* l'ajout de bruit gaussien dégrade la convergence sur les cohortes de petite taille (\< 2 000 patients). L'optimisation conjointe du budget ε et du taux de
participation par round reste un problème ouvert. La communication reste un goulot d'étranglement pour des réseaux hospitaliers à faible bande passante.
*Current Limitations~:* bypass of logical short-circuiting, unsupported reverse operators, oblivious to references and remote modifications
*Perspective :* extension à la confidentialité locale (LDP) pour des scénarios sans serveur central de confiance, et intégration de techniques de compression de gradients
(Top-k sparsification) pour réduire la charge réseau.
*Possible Extensions~:* multi-file projects with ```py import``` statements, Numpy arrays, constraint solving
]
#let repos = (
([Main repository], path("figs/qr_gitea.svg"), meta.project-repos),
([Mirror], path("figs/qr_github.svg"), meta.mirror-repo),
)
#isc-card(title: "Conclusion")[
MediFL démontre qu'il est possible d'approcher la précision d'un modèle centralisé (AUC 0.91 vs 0.94) tout en offrant des garanties formelles de confidentialité
différentielle = 0.5). Le cadre est générique : il s'applique à toute tâche de classification médicale distribuée sans modification architecturale majeure. Le code
source est publié en open source sous licence Apache 2.0.
Midas provides a solid foundation for a hybrid typing system which can make Python better and safer. Its modular architecture makes it easily extensible.
The source code is published openly under the Apache 2.0 license.
#grid(
columns: (1fr,) * repos.len(),
align: center,
..repos.map(r => strong(text(size: 0.8em, r.at(0)))),
..repos.map(r => image(r.at(1), width: 3cm)),
..repos.map(r => text(size: 0.8em, r.at(2)))
)
]
#isc-card(title: "References")[
+ B. McMahan et al., _Communication-Efficient Learning of Deep Networks_, AISTATS 2017.
+ M. Abadi et al., _Deep Learning with Differential Privacy_, CCS 2016.
+ T. Li et al., _Federated Learning: Challenges, Methods, and Future Directions_, IEEE Signal Processing Magazine, 2020.
+ I. Mironov, _Rényi Differential Privacy of the Gaussian Mechanism_, CSF 2017.
#bibliography("../report/bibliography.bib", title: none)
]