GLiNER: decisões e extração de entidades localmente
Prévia de desenvolvimento. Os pesos estão publicados no Hugging Face; o módulo Swift está em revisão e ainda não faz parte de uma versão do speech-swift.
O módulo GLiNER executa o GLiNER2.5-Decide em MLX Swift. Passe um texto e uma lista de rótulos permitidos para obter pontuações de classificação, ou peça trechos de entidades como uma pessoa e um horário.
Como funciona
Um codificador DeBERTa lê o texto e o esquema juntos. As cabeças de classificação pontuam seus rótulos. As cabeças de entidades identificam trechos da frase original. O runtime não gera uma resposta JSON token por 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
Três conversões MLX da revisão fixada 7ee5da4c estão publicadas no Hugging Face. O runtime baixa a variante escolhida no primeiro uso e depois reutiliza o cache local; o Python não é usado.
| Variante | Repositório | Pesos | Roteamento | Extração | Memória máxima |
|---|---|---|---|---|---|
int8 (padrão) | 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, máquina ociosa: mediana de uma requisição completa com tokenização, e memória máxima do processo. As três variantes retornam os mesmos rótulos, trechos e offsets que o modelo PyTorch original em 24 casos de referência, com diferenças de confiança abaixo de 0,006.
Linha de comando
A CLI speech oferece as duas tarefas como speech gliner classify e speech gliner extract. Os rótulos são passados separados por vírgula e --description label=text pode ser repetido. Sem texto, a entrada é lida do stdin. --variant escolhe int8 (padrão), fp16 ou fp32, e --model-dir carrega um pacote local em vez de baixar. Argumentos inválidos são rejeitados antes de o modelo carregar. Com --json, a saída inclui a probabilidade de cada rótulo, ou trechos com offsets UTF-16, além dos tempos de carga e inferência.
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
O cartão do modelo para agentes é um arquivo Markdown com a API exata, os campos de saída e os resultados verificados.
Precisão em um pequeno conjunto de comandos
Dos dezesseis exemplos de roteamento escritos à mão, 12 corresponderam ao esperado; dos oito exemplos de extração, 7. O port em Swift reproduz o modelo PyTorch original em 24 casos de referência: mesmos IDs de token, rótulos e trechos, com pontuações dentro de 0,001. Esses conjuntos pequenos verificam comportamento e fidelidade; não são um benchmark amplo de precisão.
Escopo e limitações
- Classificação de rótulo único e trechos de entidades; até 512 tokens codificados por requisição.
- Checkpoints span/count_lstm com atenção relativa compartilhada, em FP32, FP16 ou INT8. Modelos boundary, grafos de relações e restrições conjuntas não fazem parte desta primeira API.
- Os offsets de entidades usam UTF-16, como o NSRange. Datas e horários exigem normalização separada.
- As pontuações não garantem que uma decisão esteja correta. O módulo não executa nenhuma ferramenta.
- Tamanho de download, memória do processo e footprint físico na memória unificada são medidas diferentes.
Precisão e memória
O FP16 reduz pela metade o armazenamento dos pesos, para 973 MB. O INT8 quantiza as matrizes do codificador e os embeddings de tokens em 8 bits, em grupos de 64, com cabeças, normalização e ativações em FP16, resultando num arquivo de 567 MB. O runtime mantém as matrizes INT8 compactadas e decodifica apenas as linhas de embedding usadas por cada requisição.
As projeções de posição relativa do codificador dependem só dos pesos, então são calculadas uma vez no carregamento, e não a cada requisição. O modo opcional GLiNER.load(from:evaluateLayers:) materializa as camadas do codificador uma a uma para reduzir o pico de alocações.