chore(dgx): snapshot consolidation WIP pour transfert poc DGX
Regroupe le WIP non committé requis pour le clone/runtime DGX (Option A) : - api_stream.py : préflight replay + smoke santé modèles + handler 403 WP-B - de-hardcode VLM : vlm_config, gpu/*, vram_orchestrator, ollama_manager - stream_processor, semantic_matcher, agent_chat (app/planner/intent) - workflows.db (acquis ; le transfert artifacts le mettra à jour + rewrite chemins) - docs : plans DGX, benchmarks VLM/grounders, recherche SOTA, coordination 8 juin Snapshot destiné à la branche poc-dgx poussée sur Gitea pour cloner le DGX. Scan anti-secret : clean. graphify (repo embarqué) exclu. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
125
docs/benchmarks/2026-06-08_benchmark_vllm_grounders.md
Normal file
125
docs/benchmarks/2026-06-08_benchmark_vllm_grounders.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Benchmark grounders GUI SOTA via vLLM sur DGX Spark
|
||||
|
||||
**Date :** 2026-06-08
|
||||
**Infra :** NVIDIA DGX Spark (GB10, aarch64, sm_121, 121 Go mémoire unifiée), `aivanov@192.168.1.45`
|
||||
**Moteur :** vLLM `vllm/vllm-openai:cu130-nightly` (image arm64 déjà pullée, ID `ffa30d66ff5c`), API OpenAI-compatible
|
||||
**Modèles évalués :** InfiGUI-G1-7B, Holo1.5-7B, Qwen3-VL-4B-Instruct (un seul servi à la fois, container recréé)
|
||||
**Harness :** identique aux benchs gemma4/qwen2.5vl du 2026-06-08 — mêmes 16 cas LeaBench (`benchmarks/computer_use/cases/leabench_extended_2026-05-24.jsonl`), mêmes images, même scoreur (`core.evaluation.computer_use_bench`). Scripts jetables dans `/tmp/vlm_bench/`. **Aucun code de production modifié, Ollama (`:11434`) non touché.**
|
||||
|
||||
---
|
||||
|
||||
## Résumé exécutif (verdict tranché)
|
||||
|
||||
1. **vLLM démarre proprement sur le DGX Spark (ARM64/Blackwell) pour les 3 modèles.** Pas de blocage flash-attn : vLLM sélectionne `FLASH_ATTN v2` et il fonctionne. Aucun flag exotique nécessaire — **le seul piège réel a été la mémoire** (voir §Montage). `--enforce-eager` non nécessaire.
|
||||
2. **Gagnant net : Qwen3-VL-4B-Instruct.** Avec garde-fou de présence : **accuracy 0,875 (14/16), 1 seul clic dangereux, ~1,1 s/cas, cible démo « Enregistrer » 2/2.** Meilleur que tous les gemma4 et que les deux grounders spécialisés, **pour seulement 4B**. Confirme le pari du leaderboard llm-stats sur écrans FR réels.
|
||||
3. **Les grounders « spécialisés » (Holo1.5, InfiGUI-G1) sont d'excellents localisateurs mais de mauvais décideurs seuls.** En sortie brute (raw, toujours-clic) ils visent juste sur les vraies cibles mais cliquent partout sur les écrans pièges → 9 à 12 clics dangereux. Leur sécurité dépend entièrement d'un gate externe.
|
||||
4. **Reste-t-il sûr ? Non en standalone.** Aucun modèle n'atteint 0 clic dangereux + haute accuracy seul. **La cascade de validation existante (OCR/template + vérif état UI avant/après clic) reste obligatoire AU-DESSUS du grounder.** Le grounder propose, la cascade vérifie.
|
||||
5. **Moteur recommandé : vLLM `cu130-nightly`, `--gpu-memory-utilization 0.40`** (Ollama occupe ~42 Go de la mémoire unifiée). Vision native préservée (safetensors HF, pas de GGUF/mmproj) — exactement ce qu'il fallait après l'échec UI-TARS/Ollama.
|
||||
|
||||
---
|
||||
|
||||
## Tableau comparatif (LeaBench 16 cas — même harness, comparaison directe)
|
||||
|
||||
Protocole « gated » = grounding natif + une passe de présence (yes/no) donnant au grounder pur une chance d'abstenir équitablement (identique au protocole du bench UI-TARS). « raw » = localisateur pur, toujours-clic si parsable (expose le comportement brut et les clics dangereux sans garde-fou).
|
||||
|
||||
| Modèle | Variante | Accuracy | Correct/16 | Clics dangereux | Cible démo « Enregistrer » | Latence/cas | Parsable | Licence |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| **Qwen3-VL-4B-Instruct** | **gated** | **0,875** | **14/16** | **1** | **2/2 ✅** | **~1,1 s** | 14/16 | Apache-2.0 |
|
||||
| Qwen3-VL-4B-Instruct | raw | 0,4375 | 7/16 | 9 | 2/2 ✅ | ~1,0 s | 14/16 | Apache-2.0 |
|
||||
| Holo1.5-7B | gated | 0,5625 | 9/16 | 4 | 0/2 (gate trop strict) | ~3,2 s | 16/16 | Apache-2.0 |
|
||||
| Holo1.5-7B | raw | 0,25 | 4/16 | 12 | 2/2 ✅ (localisation) | ~3,0 s | 16/16 | Apache-2.0 |
|
||||
| InfiGUI-G1-7B | gated | 0,50 | 8/16 | 7 | 2/2 ✅ | ~14,6 s | 16/16 | Apache-2.0 |
|
||||
| InfiGUI-G1-7B | raw | 0,3125 | 5/16 | 11 | 2/2 ✅ (localisation) | ~14,3 s | 16/16 | Apache-2.0 |
|
||||
| — *référence Ollama* — | | | | | | | | |
|
||||
| gemma4:31b | — | 0,75 | 12/16 | 1 | (cf. rapport 31b) | (plus lent) | — | — |
|
||||
| gemma4:26b | — | 0,6875 | 11/16 | **0** | 1/2 | (mesuré 06-08) | — | — |
|
||||
| qwen2.5vl:7b-rpa | — | 0,5625 | 9/16 | 6 | (cf. rapport qwen) | (rapide) | — | — |
|
||||
| qwen3vl:8b (Ollama) | — | 0,3125 | 5/16 | 0 | — | — | — | — |
|
||||
| UI-TARS-1.5-7B (Ollama) | — | N/A (aveugle, import sans mmproj) | 0/16 | N/A | échec HTTP 500 | — | — | — |
|
||||
|
||||
> Chiffres gemma4/qwen re-vérifiés via le scoreur sur les prédictions existantes (`gemma4:26b` 0,6875/0 dangereux ; `gemma4:31b` 0,75/1 ; `qwen2.5vl:7b-rpa` 0,5625/6 ; `qwen3vl:8b` 0,3125/0). Latences vLLM = moyenne mesurée sur les 2 appels (grounding + présence) des 16 cas.
|
||||
|
||||
---
|
||||
|
||||
## Montage vLLM (statut OK + flags utilisés)
|
||||
|
||||
**Commande de référence (identique pour les 3 modèles, seul `--model` change) :**
|
||||
```
|
||||
docker run -d --name vllm-grounder --device nvidia.com/gpu=all \
|
||||
-p 8000:8000 -v ~/.cache/huggingface:/root/.cache/huggingface --ipc=host \
|
||||
vllm/vllm-openai:cu130-nightly \
|
||||
--model <repo> --port 8000 \
|
||||
--gpu-memory-utilization 0.40 --max-num-seqs 4 --max-model-len 8192 \
|
||||
--trust-remote-code
|
||||
```
|
||||
|
||||
| Modèle | Repo HF | Démarrage | Détails |
|
||||
|---|---|---|---|
|
||||
| InfiGUI-G1-7B | `InfiX-ai/InfiGUI-G1-7B` | **OK** | archi `Qwen2_5_VLForConditionalGeneration`, KV cache 496k tokens, init ~60 s |
|
||||
| Holo1.5-7B | `Hcompany/Holo1.5-7B` | **OK** | base Qwen2.5-VL, non-gated, download ~16 Go |
|
||||
| Qwen3-VL-4B-Instruct | `Qwen/Qwen3-VL-4B-Instruct` | **OK** | archi `Qwen3VLForConditionalGeneration`, KV cache 253k tokens, init ~63 s |
|
||||
|
||||
**Pièges rencontrés et résolution :**
|
||||
1. **Mémoire (le vrai blocage, pas l'ARM).** Avec `--gpu-memory-utilization 0.85` (recommandation blog vLLM Spark) : `ValueError: Free memory on device cuda:0 (79.65/121.63 GiB) ... less than desired (103.38 GiB)`. **Ollama + autres process occupent ~42 Go de mémoire unifiée.** Résolu en passant à **0.40** (un 7B + KV cache tient largement dans ~48 Go ; concurrence max 60×).
|
||||
2. **flash-attn : aucun problème.** Contrairement à la crainte du doc recherche, vLLM cu130-nightly utilise `FLASH_ATTN v2` sans crash sur sm_121. `--enforce-eager` **non nécessaire**.
|
||||
3. **CUDA 13 / sm_121 :** l'image `cu130-nightly` gère nativement, aucune erreur `libcudart.so.12`.
|
||||
4. Aucun modèle gated, aucun token HF requis (warning rate-limit bénin).
|
||||
|
||||
Sanity vision confirmé pour chaque modèle (`/v1/chat/completions`, image base64 data-URI, HTTP 200, sortie non vide et au bon format coordonnées).
|
||||
|
||||
---
|
||||
|
||||
## Format natif par modèle (le piège « prompt unifié » évité)
|
||||
|
||||
Chaque modèle a un format distinct — adapté individuellement, **résolu empiriquement quand la doc était ambiguë.**
|
||||
|
||||
- **InfiGUI-G1-7B** (model card HF) : système `<think></think>` ; user `The screen's resolution is {W}x{H}. Locate the UI element(s) for "{instr}", output ... [{"point_2d":[x,y]}]`. Sortie = **pixels de l'image envoyée** + un bloc `<think>` de raisonnement (d'où sa latence ~10 s). `x_frac = x/W`.
|
||||
- **Holo1.5-7B** (hai-cookbook H Company) : `Localize an element on the GUI image according to the provided target and output a click position.` + cible. Sortie demandée en JSON `{"action":"click_absolute","x","y}` = **pixels de l'image envoyée**. `x_frac = x/W`. Pas de raisonnement → très rapide.
|
||||
- **Qwen3-VL-4B** : **format de coordonnées ambigu dans la doc** (issues QwenLM #1486/#1927 : pixels vs 0-1000). **Résolu par sanity call** : sur image 800×500, sortie `{"point_2d":[458,605]}` → en pixels y=605 impossible (>500) ; en **0-1000 normalisé** → (0,458 ; 0,605) ≈ cible connue (0,448 ; 0,612). Donc **coordonnées 0-1000**, `x_frac = x/1000`. **C'est exactement le piège à ne pas rater** : un parsing pixel aurait donné des clics hors écran silencieux.
|
||||
|
||||
Particularité Qwen3-VL : il **refuse nativement** sur cible absente (« There are none. », 2/16 non parsables = vraies abstentions du grounder lui-même), ce que ni Holo ni InfiGUI ne font.
|
||||
|
||||
---
|
||||
|
||||
## Licences (vérifiées)
|
||||
|
||||
| Modèle | Licence | Source |
|
||||
|---|---|---|
|
||||
| InfiGUI-G1-7B | **Apache-2.0** | model card HF `InfiX-ai/InfiGUI-G1-7B` |
|
||||
| Holo1.5-7B | **Apache-2.0** | model card HF `Hcompany/Holo1.5-7B` (« License: apache-2.0 ») — *note : le doc recherche le disait « open-weight », il est en réalité Apache-2.0, donc plus permissif qu'attendu* |
|
||||
| Qwen3-VL-4B-Instruct | **Apache-2.0** | repo `Qwen/Qwen3-VL-4B-Instruct` |
|
||||
|
||||
**Les 3 candidats sont Apache-2.0** → déployables en clinique sans friction licence. Bonne nouvelle : le fallback comme le gagnant sont tous deux permissifs.
|
||||
|
||||
---
|
||||
|
||||
## Verdict tranché
|
||||
|
||||
**Grounder recommandé : Qwen3-VL-4B-Instruct, servi par vLLM (`cu130-nightly`, `--gpu-memory-utilization 0.40`).**
|
||||
|
||||
Justification chiffrée :
|
||||
- **Accuracy la plus haute du panel (0,875), 1 seul clic dangereux**, devant gemma4:31b (0,75/1) et gemma4:26b (0,6875/0).
|
||||
- **Cible démo « Enregistrer » : 2/2** (les deux cas save-as), là où gemma4:26b n'en réussit qu'1/2. Coordonnées (0,458;0,605) et (0,428;0,573) bien dans le rayon.
|
||||
- **Le plus léger (4B) ET le plus rapide (~1 s/cas)** → meilleur ratio précision/VRAM/latence, idéal multi-postes Léa via l'API vLLM.
|
||||
- **Apache-2.0**, vision native (pas de GGUF), abstention partiellement native.
|
||||
|
||||
**Holo1.5-7B = fallback / challenger.** Localisateur brut excellent (vise juste sur les vraies cibles, 2/2 sur la démo en raw) et très rapide (3 s, pas de CoT), mais son jugement de présence séparé est trop strict (gate refuse 2 vraies cibles) → 0,5625 gated. À reconsidérer si on remplace la passe présence par la cascade interne du projet.
|
||||
|
||||
**InfiGUI-G1-7B = écarté pour ce besoin.** Bonne localisation mais le mode `<think>` impose ~14 s/cas (rédhibitoire temps-réel) et son gate de présence est faible (7 clics dangereux). Pas d'avantage face à Qwen3-VL-4B.
|
||||
|
||||
**UI-TARS-1.5 : non rebenché** (import Ollama cassé sans mmproj, cf. rapport dédié du 06-08). Le doc recherche le classait déjà dernier des spécialisés — confirmé non prioritaire.
|
||||
|
||||
### Sécurité de clic (santé) — reste-t-il sûr ?
|
||||
**Non en standalone.** Même le gagnant produit 1 clic dangereux/16 et dépend d'une passe de présence externe pour ne pas en produire 9 (cf. variante raw). **Conserver impérativement la cascade de validation existante au-dessus du grounder** (OCR/template + vérification état UI avant/après clic, garde-fou « ne clique pas si pas sûr à 100 % »). Le grounder VLM propose une coordonnée ; la cascade tranche. Choisir vLLM (vision fiable) plutôt qu'Ollama renforce ce contrat.
|
||||
|
||||
### Reco moteur
|
||||
**vLLM `vllm/vllm-openai:cu130-nightly` sur le DGX Spark**, épinglé au digest (pas le tag nightly mouvant), `--gpu-memory-utilization 0.40` tant qu'Ollama cohabite. API OpenAI-compatible → un serveur central sert N postes Léa. Plan B x86 RTX 5070 inutile ici : la stack ARM a tenu sans contournement lourd.
|
||||
|
||||
---
|
||||
|
||||
## Limites & honnêteté méthodo
|
||||
|
||||
- **16 cas seulement** (notepad/save-as/menu Démarrer Windows FR), pas Easily Assure dense haute résolution. Les scores sont indicatifs, pas un verdict ScreenSpot-Pro. Re-bencher sur écrans Easily réels avant décision finale POC.
|
||||
- Le protocole « gated » mélange grounding natif + une passe présence maison ; il avantage les modèles dont le jugement de présence est calibré (Qwen3-VL) et pénalise les localisateurs purs (Holo). En production, la passe présence sera remplacée par la cascade interne du projet → les chiffres « raw localisation » sont alors plus représentatifs de ce que le grounder apporte vraiment (et là Holo/Qwen3-VL/InfiGUI visent tous juste sur les vraies cibles).
|
||||
- Latences = mémoire unifiée LPDDR5X du Spark, mono-requête. Le débit multi-postes réel reste à mesurer.
|
||||
- Aucun secret/token/identité patient dans ce rapport. Container vLLM supprimé en fin de run (`docker rm -f vllm-grounder`), Ollama vérifié intact (HTTP 200).
|
||||
Reference in New Issue
Block a user