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.
| Variante | Dépôt | Poids | Routage | Extraction | Mémoire maximale |
|---|---|---|---|---|---|
int8 (par défaut) | aufklarer/GLiNER2.5-Decide-340M-MLX-8bit | 567 MB | 7.6 ms | 8.9 ms | 0.85 GB |
fp16 | aufklarer/GLiNER2.5-Decide-340M-MLX-fp16 | 973 MB | 8.8 ms | 10.0 ms | 1.58 GB |
fp32 | aufklarer/GLiNER2.5-Decide-340M-MLX | 1.95 GB | 11.1 ms | 12.6 ms | 2.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
- Classification à étiquette unique et segments d’entités ; jusqu’à 512 tokens encodés par requête.
- Checkpoints span/count_lstm avec attention relative partagée, en FP32, FP16 ou INT8. Les modèles boundary, les graphes de relations et les contraintes conjointes ne font pas partie de cette première API.
- Les offsets d’entités sont en UTF-16, comme NSRange. Les dates et heures doivent être normalisées séparément.
- Un score ne garantit pas qu’une décision est correcte. Le module n’exécute aucun outil.
- La taille de téléchargement, la mémoire du processus et l’empreinte physique en mémoire unifiée sont des mesures différentes.
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.