Files
rpa_vision_v3/docs/benchmarks/2026-06-08_benchmark_vllm_grounders.md
Dom 6d34b3cb68
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m44s
tests / Tests unitaires (sans GPU) (push) Failing after 1m49s
tests / Tests sécurité (critique) (push) Has been skipped
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>
2026-06-08 16:33:58 +02:00

11 KiB
Raw Blame History

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).