GLiNER: decisiones y extracción de entidades en local

Versión preliminar de desarrollo. Los pesos están publicados en Hugging Face; el módulo Swift está en revisión y aún no forma parte de una versión de speech-swift.

El módulo GLiNER ejecuta GLiNER2.5-Decide en MLX Swift. Pásale un texto y una lista de etiquetas permitidas para obtener puntuaciones de clasificación, o pide fragmentos de entidades como una persona y una hora.

Cómo funciona

Un codificador DeBERTa lee el texto y el esquema a la vez. Las cabezas de clasificación puntúan tus etiquetas. Las cabezas de entidades identifican fragmentos de la frase original. El runtime no genera una respuesta JSON token a 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"]
)

Pesos

Hay tres conversiones MLX de la revisión fijada 7ee5da4c publicadas en Hugging Face. El runtime descarga la variante elegida en el primer uso y después reutiliza la caché local; no interviene Python.

VarianteRepositorioPesosEnrutadoExtracciónMemoria máxima
int8 (predeterminada)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, máquina sin otra carga: mediana de una petición completa con tokenización, y memoria máxima del proceso. Las tres variantes devuelven las mismas etiquetas, fragmentos y offsets que el modelo PyTorch original en 24 casos de referencia, con diferencias de confianza inferiores a 0,006.

Línea de comandos

La CLI speech ofrece ambas tareas como speech gliner classify y speech gliner extract. Las etiquetas se pasan separadas por comas y --description label=text puede repetirse. Si se omite el texto, se lee de stdin. --variant elige int8 (predeterminada), fp16 o fp32, y --model-dir carga un paquete local en lugar de descargarlo. Los argumentos no válidos se rechazan antes de cargar el modelo. Con --json, la salida incluye la probabilidad de cada etiqueta, o fragmentos con offsets UTF-16, además de los tiempos de carga e inferencia.

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 ficha del modelo para agentes es un archivo Markdown con la API exacta, los campos de salida y los resultados verificados.

Precisión en un pequeño conjunto de órdenes

De dieciséis ejemplos de enrutado escritos a mano, 12 coincidieron con lo esperado; de ocho ejemplos de extracción, 7. El port en Swift reproduce el modelo PyTorch original en 24 casos de referencia: mismos IDs de token, etiquetas y fragmentos, con puntuaciones dentro de 0,001. Estos conjuntos pequeños comprueban comportamiento y fidelidad; no son un benchmark amplio de precisión.

Alcance y limitaciones

Precisión y memoria

FP16 reduce a la mitad el almacenamiento de pesos, hasta 973 MB. INT8 cuantiza las matrices del codificador y los embeddings de tokens a 8 bits en grupos de 64, con cabezas, normalización y activaciones en FP16, para un archivo de 567 MB. El runtime mantiene empaquetadas las matrices INT8 y solo decodifica las filas de embedding que usa cada petición.

Las proyecciones de posición relativa del codificador solo dependen de los pesos, así que se calculan una vez al cargar en lugar de en cada petición. El modo opcional GLiNER.load(from:evaluateLayers:) materializa las capas del codificador una a una para reducir el pico de asignaciones.

Fuentes y atribución