GLiNER : décisions et extraction d’entités en local

Préversion de développement. Les poids sont publiés sur Hugging Face ; le module Swift est en cours de revue et ne fait pas encore partie d’une version de speech-swift.

Le module GLiNER exécute GLiNER2.5-Decide en MLX Swift. Donnez-lui un texte et une liste d’étiquettes autorisées pour obtenir des scores de classification, ou demandez des segments d’entités comme une personne et une heure.

Fonctionnement

Un encodeur DeBERTa lit le texte et le schéma ensemble. Les têtes de classification notent vos étiquettes. Les têtes d’entités repèrent des segments de la phrase d’origine. Le runtime ne génère pas de réponse JSON token par token.

import GLiNER
let model = try await GLiNER.fromPretrained()
let choices = try model.classify(
    "Remind me to call Dad at six PM.",
    labels: ["create_reminder", "send_message", "other"]
)
let spans = try model.extractEntities(
    "Remind me to call Dad at six PM.",
    labels: ["person", "time"]
)

Poids

Trois conversions MLX de la révision amont figée 7ee5da4c sont publiées sur Hugging Face. Le runtime télécharge la variante choisie à la première utilisation puis réutilise le cache local ; Python n’intervient pas.

VarianteDépôtPoidsRoutageExtractionMémoire maximale
int8 (par défaut)aufklarer/GLiNER2.5-Decide-340M-MLX-8bit567 MB7.6 ms8.9 ms0.85 GB
fp16aufklarer/GLiNER2.5-Decide-340M-MLX-fp16973 MB8.8 ms10.0 ms1.58 GB
fp32aufklarer/GLiNER2.5-Decide-340M-MLX1.95 GB11.1 ms12.6 ms2.55 GB

Apple M5 Pro, machine au repos : médiane d’une requête complète avec tokenisation, et mémoire maximale du processus. Les trois variantes renvoient les mêmes étiquettes, segments et offsets que le modèle PyTorch d’origine sur 24 cas de référence, avec des écarts de confiance inférieurs à 0,006.

Ligne de commande

La CLI speech propose les deux tâches avec speech gliner classify et speech gliner extract. Les étiquettes se passent séparées par des virgules et --description label=text peut être répété. Sans texte, l’entrée est lue sur stdin. --variant choisit int8 (par défaut), fp16 ou fp32, et --model-dir charge un paquet local au lieu de le télécharger. Les arguments invalides sont refusés avant le chargement du modèle. Avec --json, la sortie contient la probabilité de chaque étiquette, ou les segments avec leurs offsets UTF-16, ainsi que les temps de chargement et d’inférence.

swift build -c release --product speech --disable-sandbox
scripts/build_mlx_metallib.sh release
.build/release/speech gliner classify "Remind me to call Dad at six PM." \
  --labels create_reminder,send_message,set_timer,other
.build/release/speech gliner extract "Remind me to call Dad at six PM." \
  --labels person,time --json

La fiche du modèle pour les agents est un fichier Markdown qui décrit l’API exacte, les champs de sortie et les résultats vérifiés.

Précision sur un petit ensemble de commandes

Sur seize exemples de routage écrits à la main, 12 correspondaient à l’attendu ; sur huit exemples d’extraction, 7. Le portage Swift reproduit le modèle PyTorch d’origine sur 24 cas de référence : mêmes IDs de token, étiquettes et segments, avec des scores à 0,001 près. Ces petits ensembles vérifient le comportement et la fidélité ; ce n’est pas un benchmark de précision général.

Périmètre et limites

Précision numérique et mémoire

FP16 réduit de moitié le stockage des poids, à 973 Mo. INT8 quantifie les matrices de l’encodeur et les embeddings de tokens sur 8 bits par groupes de 64, avec têtes, normalisation et activations en FP16, pour un fichier de 567 Mo. Le runtime garde les matrices INT8 compressées et ne décode que les lignes d’embedding utilisées par une requête.

Les projections de position relative de l’encodeur ne dépendent que des poids : elles sont calculées une seule fois au chargement plutôt qu’à chaque requête. Le mode optionnel GLiNER.load(from:evaluateLayers:) matérialise les couches de l’encodeur une par une pour réduire le pic d’allocations.

Sources et attribution