@george_onx: Seeing a lot of comparisons of Jev w/ GLiNER models lately. If you're benchmarking, GLiNER2.5 is the latest version we'…
Summary
GLiNER2.5 is a multilingual boundary checkpoint for unified schema-based information extraction, supporting entities, classification, structured records, relations, and span attributes in one model.
View Cached Full Text
Cached at: 09/22/26, 07:53 AM
Seeing a lot of comparisons of Jev w/ GLiNER models lately.
If you’re benchmarking, GLiNER2.5 is the latest version we’ve released. Tag @fastinoai with results so we can see how it holds up.
🤗 Model weights: https://t.co/WFyZXasPqw https://t.co/r18K0bTVUo
fastino/gliner2.5-multi-v1 · Hugging Face
Source: https://huggingface.co/fastino/gliner2.5-multi-v1

https://huggingface.co/fastino/gliner2.5-multi-v1#gliner25-multi-unified-schema-based-information-extractionGLiNER2.5 Multi: Unified Schema-Based Information Extraction
Extract entities, classify text, parse structured records, score span attributes, and extract relations — all in one boundary architecture.
GLiNER2.5 Multi is the multilingual boundary checkpoint. It is built on mDeBERTa-v3-base and is the default choice when you need entities, classification, records, and relations in one model across languages. Load it withAutoExtractor: the checkpoint’sarchitecturefield selectsBoundaryExtractorautomatically.
Fine-tune viaFastino. Join discussions onReddit.
- 🎯 One model, many tasks: entities, classification, structured records, relations, and span attributes in a single schema
- 📐 Boundary architecture: sparse start/end pairing instead of a fixed span-width grid — any span length that fits in the encoded window
- 🔗 Constrained decoding:
Classifierfor cross-task label constraints,JointIEfor typed entity–relation graphs - 💻 Local inference: CPU, CUDA, or MPS through
gliner2\[local\]— no external API required
https://huggingface.co/fastino/gliner2.5-multi-v1#gliner25-familyGLiNER2.5 family
This card is for**fastino/gliner2\.5\-multi\-v1**. All three checkpoints share the same public API.
https://huggingface.co/fastino/gliner2.5-multi-v1#installationInstallation
pip install "gliner2[local]"
Python 3.10 or newer is required. The\[local\]extra pulls in PyTorch so you can load Hub checkpoints.
https://huggingface.co/fastino/gliner2.5-multi-v1#load-the-modelLoad the model
Always useAutoExtractorfor GLiNER2.5.GLiNER2\.from\_pretrained\(\.\.\.\)is the legacyspanloader and will not dispatch this checkpoint.
from gliner2 import AutoExtractor
model = AutoExtractor.from_pretrained("fastino/gliner2.5-multi-v1")
print(type(model).__name__)
print(model.config.architecture)
# BoundaryExtractor
# boundary
Optional device, fp16, and compile flags:
model = AutoExtractor.from_pretrained(
"fastino/gliner2.5-multi-v1",
map_location="cuda", # or "cpu" / "mps"
quantize=True, # fp16 weights on GPU
compile=True, # torch.compile after the first tracing call
)
print(type(model).__name__, next(model.parameters()).device)
# BoundaryExtractor cuda:0
https://huggingface.co/fastino/gliner2.5-multi-v1#usageUsage
https://huggingface.co/fastino/gliner2.5-multi-v1#entity-extractionEntity extraction
text = "Apple CEO Tim Cook announced iPhone 15 in Cupertino yesterday."
result = model.extract_entities(
text,
["company", "person", "product", "location"],
include_confidence=True,
include_spans=True,
)
print(result)
# {
# "entities": {
# "company": [{"text": "Apple", "start": 0, "end": 5, "confidence": 0.98}],
# "person": [{"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.97}],
# "product": [{"text": "iPhone 15", "start": 29, "end": 38, "confidence": 0.96}],
# "location": [{"text": "Cupertino", "start": 42, "end": 51, "confidence": 0.95}],
# }
# }
Returned offsets are half-open character spans into the original string:text\[start:end\] == entity\["text"\].
Add descriptions when labels are domain-specific:
result = model.extract_entities(
"Patient received 400mg ibuprofen for severe headache at 2 PM.",
{
"medication": "Names of drugs or pharmaceutical substances",
"dosage": "Amounts such as 400mg, 2 tablets, or 5ml",
"symptom": "Reported symptoms or conditions",
"time": "Clock times or relative times",
},
include_spans=True,
)
print(result)
# {
# "entities": {
# "medication": [{"text": "ibuprofen", "start": 23, "end": 32}],
# "dosage": [{"text": "400mg", "start": 17, "end": 22}],
# "symptom": [{"text": "severe headache", "start": 37, "end": 52}],
# "time": [{"text": "2 PM", "start": 56, "end": 60}],
# }
# }
https://huggingface.co/fastino/gliner2.5-multi-v1#text-classificationText classification
Independent per-task decoding withclassify\_text:
result = model.classify_text(
"This laptop has amazing performance but terrible battery life!",
{"sentiment": ["positive", "negative", "neutral"]},
)
print(result)
# {"sentiment": "negative"}
result = model.classify_text(
"Great camera quality, decent performance, but poor battery life.",
{
"aspects": {
"labels": ["camera", "performance", "battery", "display", "price"],
"multi_label": True,
"cls_threshold": 0.4,
}
},
)
print(result)
# {"aspects": ["camera", "performance", "battery"]}
https://huggingface.co/fastino/gliner2.5-multi-v1#constrained-classificationConstrained classification
Usegliner2\.classification\.Classifierwhen labels on one task legally constrain another.classify\_textwill not enforce those rules.
from gliner2.classification import (
Classifier,
ClassificationSchema,
ClassificationConfig,
)
from gliner2.classification import constraints as C
clf = Classifier.from_pretrained("fastino/gliner2.5-multi-v1")
schema = (
ClassificationSchema()
.single("intent", ["read", "write", "delete"])
.multi("effects", ["read_only", "create", "modify", "delete"], min_labels=1)
.constrain(
C.implies(("intent", "delete"), ("effects", "delete")),
C.excludes(("intent", "read"), ("effects", "delete")),
)
)
result = clf.classify("Delete the temporary file from /tmp", schema)
print(result.value("intent"))
print(result.value("effects"))
print(result.feasible)
print(result.to_dict())
# delete
# ['delete']
# True
# {
# "intent": {
# "value": "delete",
# "confidence": 0.93,
# "probabilities": {"read": 0.02, "write": 0.05, "delete": 0.93},
# },
# "effects": {
# "value": ["delete"],
# "confidence": 0.88,
# "probabilities": {
# "read_only": 0.04, "create": 0.03, "modify": 0.05, "delete": 0.88
# },
# },
# "_meta": {"feasible": True, "decoder": "exact"},
# }
Prediction knobs belong inClassificationConfigon the call, not infrom\_pretrained:
result = clf.classify(
"Preview the report",
schema,
config=ClassificationConfig(decoder="beam", beam_size=16),
)
print(result.value("intent"), result.value("effects"), result.feasible)
# read ['read_only'] True
https://huggingface.co/fastino/gliner2.5-multi-v1#relation-extractionRelation extraction
This checkpoint was trained withenable\_relations=True. Independent decoding:
text = "Alice works for Acme in Paris."
result = model.extract_relations(
text,
["works_for", "located_in"],
include_spans=True,
include_confidence=True,
)
print(result)
# {
# "relation_extraction": {
# "works_for": [{
# "head": {"text": "Alice", "start": 0, "end": 5, "confidence": 0.91},
# "tail": {"text": "Acme", "start": 16, "end": 20, "confidence": 0.91},
# }],
# "located_in": [{
# "head": {"text": "Acme", "start": 16, "end": 20, "confidence": 0.87},
# "tail": {"text": "Paris", "start": 24, "end": 29, "confidence": 0.87},
# }],
# }
# }
Or through a schema:
schema = model.create_schema().relations(
{"works_for": {"threshold": 0.6}, "located_in": {"threshold": 0.6}}
)
result = model.extract(text, schema, include_spans=True)
print(result)
# {
# "relation_extraction": {
# "works_for": [{
# "head": {"text": "Alice", "start": 0, "end": 5},
# "tail": {"text": "Acme", "start": 16, "end": 20},
# }],
# "located_in": [{
# "head": {"text": "Acme", "start": 16, "end": 20},
# "tail": {"text": "Paris", "start": 24, "end": 29},
# }],
# }
# }
Independent extraction doesnotguarantee thatworks\_forheads are people and tails are organizations.
https://huggingface.co/fastino/gliner2.5-multi-v1#joint-information-extractionJoint information extraction
JointIEscores mention and relation candidates, then searches a globally consistent graph with typed endpoints and uniqueness constraints.
from gliner2.joint_ie import JointIE, JointIEConfig
joint = JointIE.from_pretrained("fastino/gliner2.5-multi-v1")
schema = (
joint.create_schema()
.entities(["person", "organization", "location"])
.relation("works_for", "person", "organization", unique_head=True)
.relation("located_in", "organization", "location")
.no_self_loops()
)
result = joint.extract(
"Alice works for Acme in Paris. Bob joined Acme last year.",
schema,
config=JointIEConfig(optimizer="beam", beam_size=32),
)
print(result.feasible)
print(result.to_dict())
# True
# {
# "entities": [
# {"id": "e1", "type": "person", "text": "Alice", "start": 0, "end": 5, "confidence": 0.94},
# {"id": "e2", "type": "organization", "text": "Acme", "start": 16, "end": 20, "confidence": 0.92},
# {"id": "e3", "type": "location", "text": "Paris", "start": 24, "end": 29, "confidence": 0.90},
# {"id": "e4", "type": "person", "text": "Bob", "start": 31, "end": 34, "confidence": 0.91},
# ],
# "relations": [
# {"type": "works_for", "head": "e1", "tail": "e2", "confidence": 0.88},
# {"type": "works_for", "head": "e4", "tail": "e2", "confidence": 0.81},
# {"type": "located_in", "head": "e2", "tail": "e3", "confidence": 0.86},
# ],
# }
Always checkresult\.feasible.Falsemeans the hard constraints could not be satisfied (distinct from “the text contains no facts”).
for rel in result.relations:
head = result.entity(rel.head)
tail = result.entity(rel.tail)
print(f"{head.text} -{rel.type}-> {tail.text}")
# Alice -works_for-> Acme
# Bob -works_for-> Acme
# Acme -located_in-> Paris
https://huggingface.co/fastino/gliner2.5-multi-v1#span-attributes-people-with-sentimentSpan attributes: people with sentiment
Attributes arespan-conditioned. The model finds entities first, then scores attribute labels at those exact spans. They are not extra entity types and they are not document-level classification.
from gliner2 import AutoExtractor, AttributeGroup
model = AutoExtractor.from_pretrained("fastino/gliner2.5-multi-v1")
text = (
"Alice was delighted with the promotion, "
"but Bob sounded frustrated about the delay."
)
schema = (
model.create_schema()
.entities(["person"])
.entity_attributes({
"sentiment": AttributeGroup(
["positive", "negative", "neutral"],
applies_to=["person"],
qualify_labels=True,
)
})
)
result = model.extract(
text,
schema,
include_spans=True,
include_confidence=True,
)
print(result)
# {
# "entities": {
# "person": [
# {
# "text": "Alice",
# "start": 0,
# "end": 5,
# "confidence": 0.96,
# "sentiment": {"label": "positive", "confidence": 0.89},
# },
# {
# "text": "Bob",
# "start": 44,
# "end": 47,
# "confidence": 0.95,
# "sentiment": {"label": "negative", "confidence": 0.84},
# },
# ]
# }
# }
applies\_to=\["person"\]keeps sentiment off other entity types.qualify\_labels=Trueencodes model-facing queries assentiment: positivewhile returning the short labelpositive.
Restrict sentiment to people while still extracting companies:
schema = (
model.create_schema()
.entities(["person", "organization"])
.entity_attributes({
"sentiment": AttributeGroup(
["positive", "negative", "neutral"],
applies_to=["person"],
qualify_labels=True,
)
})
)
result = model.extract(
"Alice praised Microsoft, but Bob criticized OpenAI.",
schema,
include_spans=True,
include_confidence=True,
)
print(result)
# {
# "entities": {
# "person": [
# {
# "text": "Alice",
# "start": 0,
# "end": 5,
# "confidence": 0.96,
# "sentiment": {"label": "positive", "confidence": 0.88},
# },
# {
# "text": "Bob",
# "start": 29,
# "end": 32,
# "confidence": 0.95,
# "sentiment": {"label": "negative", "confidence": 0.86},
# },
# ],
# "organization": [
# {"text": "Microsoft", "start": 14, "end": 23, "confidence": 0.97},
# {"text": "OpenAI", "start": 44, "end": 50, "confidence": 0.96},
# ],
# }
# }
Organization spans have nosentimentfield. Person spans do.
https://huggingface.co/fastino/gliner2.5-multi-v1#structured-recordsStructured records
Record mode keeps instance identity (who bought what) instead of flattening fields into unrelated lists. Enablenaturalmode with an anchor field:
schema = (
model.create_schema()
.structure("purchase", mode="natural", anchor="buyer")
.field("buyer", dtype="str", cardinality="required_one")
.field("item", dtype="str", cardinality="required_one")
)
result = model.extract(
"Alice bought apples and Bob bought oranges.",
schema,
)
print(result)
# {
# "purchase": [
# {"buyer": "Alice", "item": "apples"},
# {"buyer": "Bob", "item": "oranges"},
# ]
# }
This checkpoint was trained withenable\_records=True.
https://huggingface.co/fastino/gliner2.5-multi-v1#task-combinationTask combination
Compose entities, span attributes, classification, relations, and structures inoneextractcall:
from gliner2 import AttributeGroup
schema = (
model.create_schema()
.entities({
"person": "Named people",
"organization": "Companies or teams",
"product": "Named products or services",
})
.entity_attributes({
"sentiment": AttributeGroup(
["positive", "negative", "neutral"],
applies_to=["person"],
qualify_labels=True,
)
})
.classification("topic", ["technology", "business", "sports", "politics"])
.relations(["works_for", "announced"])
.structure("announcement", mode="natural", anchor="product")
.field("company", dtype="str")
.field("product", dtype="str", cardinality="required_one")
)
text = "Apple CEO Tim Cook unveiled the iPhone 15 Pro for $999."
result = model.extract(text, schema, include_spans=True, include_confidence=True)
print(result)
# {
# "entities": {
# "person": [{
# "text": "Tim Cook",
# "start": 10,
# "end": 18,
# "confidence": 0.97,
# "sentiment": {"label": "positive", "confidence": 0.82},
# }],
# "organization": [{"text": "Apple", "start": 0, "end": 5, "confidence": 0.98}],
# "product": [{"text": "iPhone 15 Pro", "start": 32, "end": 45, "confidence": 0.96}],
# },
# "topic": {"label": "technology", "confidence": 0.94},
# "relation_extraction": {
# "works_for": [{
# "head": {"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.86},
# "tail": {"text": "Apple", "start": 0, "end": 5, "confidence": 0.86},
# }],
# "announced": [{
# "head": {"text": "Tim Cook", "start": 10, "end": 18, "confidence": 0.84},
# "tail": {"text": "iPhone 15 Pro", "start": 32, "end": 45, "confidence": 0.84},
# }],
# },
# "announcement": [{
# "company": "Apple",
# "product": "iPhone 15 Pro",
# }],
# }
Document-leveltopicis independent of per-personsentiment.
https://huggingface.co/fastino/gliner2.5-multi-v1#batch-inferenceBatch inference
texts = [
"Google hired Jane Doe in London.",
"Tesla launched the Model 3 in California.",
]
results = model.batch_extract_entities(
texts,
["company", "person", "product", "location"],
batch_size=8,
include_spans=True,
)
print(results)
# [
# {
# "entities": {
# "company": [{"text": "Google", "start": 0, "end": 6}],
# "person": [{"text": "Jane Doe", "start": 13, "end": 21}],
# "product": [],
# "location": [{"text": "London", "start": 25, "end": 31}],
# }
# },
# {
# "entities": {
# "company": [{"text": "Tesla", "start": 0, "end": 5}],
# "person": [],
# "product": [{"text": "Model 3", "start": 19, "end": 26}],
# "location": [{"text": "California", "start": 30, "end": 40}],
# }
# },
# ]
batch\_extractaccepts one schema or a list of schemas (one per document).
https://huggingface.co/fastino/gliner2.5-multi-v1#long-documentsLong documents
extract\(\.\.\.\)withmax\_lentruncates. Long-context helpers scan overlapping word chunks and remap spans to document offsets.
long_text = ("Quarterly overview. " * 40) + "Satya Nadella spoke in Redmond about Microsoft."
result = model.extract_entities_long(
long_text,
["person", "organization", "location"],
chunk_size=384,
chunk_overlap=64,
include_spans=True,
)
print(result)
# {
# "entities": {
# "person": [{"text": "Satya Nadella", "start": 800, "end": 813}],
# "organization": [{"text": "Microsoft", "start": 837, "end": 846}],
# "location": [{"text": "Redmond", "start": 823, "end": 830}],
# }
# }
result = model.extract_long(long_text, schema, chunk_size=384, chunk_overlap=64)
print(result["topic"])
# technology
The same idea applies toClassifier\.classify\_longandJointIE\.extract\_long.
Limits:
- A span is kept only if its start and end fall in thesame chunk.
- A relation is kept only if both endpoints were extracted in the same chunk.
- Boundary models can represent arbitrarily long spansinside one encoded window; they do not stitch a mention whose endpoints never co-occur.
https://huggingface.co/fastino/gliner2.5-multi-v1#model-detailsModel details
- Architecture:GLiNER2boundaryextractor (
BoundaryExtractor) - **Candidate search:**sparse start/end pairing (not a dense
\[L, W\]width grid) - **Span length:**any length that fits in the encoded window (
max\_len=4096) - Encoder:
microsoft/mdeberta\-v3\-base - **Parameters:**287M
- Weights:~594 MB (mostly FP16)
- **Language:**Multilingual
- **Heads enabled:**classification, records (
enable\_records=True), relations (enable\_relations=True) - Overlap default:
flat(weighted interval scheduling); override per call withoverlap\_policy - **Input / output:**text → entities, labels, span attributes, records, and relation edges
Do not load this checkpoint withGLiNER2/SpanExtractor. Those classes expect the legacy span architecture.
https://huggingface.co/fastino/gliner2.5-multi-v1#citationCitation
If you use this model, please cite:
@misc{zaratiana2025gliner2efficientmultitaskinformation,
title={GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface},
author={Urchade Zaratiana and Gil Pasternak and Oliver Boyd and George Hurn-Maloney and Ash Lewis},
year={2025},
eprint={2507.18546},
archivePrefix={arXiv},
primaryClass={cs.CL},
url={https://arxiv.org/abs/2507.18546},
}
https://huggingface.co/fastino/gliner2.5-multi-v1#licenseLicense
Apache License 2.0.
https://huggingface.co/fastino/gliner2.5-multi-v1#linksLinks
- Repository:https://github.com/fastino-ai/GLiNER2
- Paper:https://arxiv.org/abs/2507.18546
- Docs:boundary architecture·span attributes·constrained classification·joint IE
- Organization:Fastino AI
Similar Articles
GLiNER2: An Efficient Multi-Task Information Extraction System with Schema-Driven Interface
GLiNER2 is a unified transformer-based framework for multiple NLP tasks, offering improved efficiency and accessibility over large language models by supporting named entity recognition, text classification, and hierarchical data extraction in a single model.
@mervenoyann: GLM-5.2 is comparable to Opus 4.8 with 1M context > new IS attention reuses one indexer every 4 sparse layers (2.9× per…
GLM-5.2 is a new model comparable to Opus 4.8, featuring 1M context, new IS attention, improved speculative decoding, and flexible thinking-effort levels. It is released under MIT license with day-0 support in transformers, vLLM, and SGLang.
GLiNER-Relex: A Unified Framework for Joint Named Entity Recognition and Relation Extraction
GLiNER-Relex is a unified framework for joint named entity recognition and relation extraction that leverages a shared transformer encoder for zero-shot capabilities. The paper demonstrates competitive performance on standard benchmarks and releases the model as an open-source Python package.
Benchmarking Google Embeddings 2 against Open-Source Models for Multilingual Dense Retrieval and RAG Systems
This paper benchmarks Google Embeddings 2 against five open-source models for multilingual dense retrieval and RAG, finding GE2 top in accuracy but slower, with mE5-L as a competitive low-latency alternative.
@MiaAI_lab: GLM-5.2 is the best Chinese open model yet. The output screams quality — I can really feel the difference. The problem …
GLM-5.2 is praised as the best Chinese open model yet for output quality, but note its high token consumption. The user hopes to run it on 3 DGX Sparks.