GLiNER2

repository·main·Indexed 21 days ago

https://github.com/fastino-ai/gliner2

A unified model for Named Entity Recognition (NER), Text Classification, Structured Data Extraction, and Relation Extraction. GLiNER2 supports local inference and training, offering features such as long-document extraction, multi-task schema composition via create_schema(), and GPU acceleration through quantization, torch.compile, and FlashDeberta. It provides both a lightweight installation for schema validation and a full local install for model execution.

Tokens
49.5K
Snippets
113
Records
173
Agent score
77%

What's inside gliner2

  1. Use multi-label classification with thresholds

    main

    By default, .classification() performs single-label classification (returning a single string). To allow multiple labels to be assigned to a single text, set multi_label=True.

    You can also control which labels are returned by setting a cls_threshold. Only labels with a confidence score above this threshold will be included in the output list.

    schema = (extractor.create_schema()
        # Single-label classification
        .classification("primary_topic", ["tech", "business", "health", "sports", "politics"])
        
        # Multi-label classification with a threshold
        .classification("emotions", 
            ["happy", "sad", "angry", "surprised", "fearful", "disgusted"],
            multi_label=True,
            cls_threshold=0.4
        )
    )
    
    text = "URGENT: I'm thrilled to announce our new product!"
    results = extractor.extract(text, schema)
    # 'emotions' will return a list of labels meeting the threshold
  2. Implement adapter routing and batch processing

    main

    To handle multi-domain workloads efficiently, you can implement routing logic or batch processing by domain.

    Routing: Map document types to specific adapter paths and call load_adapter only when the domain changes.

    Batch Processing: Group documents by their domain and process them in batches. This minimizes the overhead of switching adapters by loading a single adapter once for all documents in that domain.

    # Example of routing logic
    def extract_with_routing(model, text, doc_type, adapters):
        adapter_path = adapters.get(doc_type)
        if adapter_path:
            model.load_adapter(adapter_path)
        else:
            model.unload_adapter()
        
        entity_types = {
            "legal": ["company", "person", "law"],
            "medical": ["disease", "drug", "symptom"],
            "support": ["order_id", "customer", "issue"]
        }
        return model.extract_entities(text, entity_types.get(doc_type, ["entity"]))
    
    # Example of batch processing by domain
    def process_by_domain(model, documents, adapters):
        results = {}
        for domain, docs in documents.items():
            model.load_adapter(adapters[domain])
            results[domain] = [
                model.extract_entities(doc, get_entity_types(domain))
                for doc in docs
            ]
        return results
  3. Configure custom thresholds for relations

    main

    You can control the confidence required for relation extraction in two ways:

    1. Global Threshold: Pass a threshold argument directly to extract_relations() to apply it to all requested relations.
    2. Per-Relation Threshold: Define a specific threshold within the schema for each relation type to tune precision/recall per relationship.

    Available threshold values are floats (e.g., 0.8 for high precision).

    # Global threshold
    results = extractor.extract_relations(
        text,
        ["acquired", "merged_with"],
        threshold=0.8
    )
    
    # Per-relation threshold via schema
    schema = extractor.create_schema().relations({
        "acquired": {
            "description": "Company acquisition relationship",
            "threshold": 0.9
        },
        "competes_with": {
            "description": "Competitive relationship",
            "threshold": 0.5
        }
    })
  4. When to use extract_json() vs create_schema().extract()

    main

    Choosing the right method depends on your extraction complexity:

    MethodBest Use Case
    extract_json()Structure-only extraction, quick data parsing, or single extraction tasks.
    create_schema().extract()Multi-task scenarios (entities + structures + classification) or complex pipelines where you need entities/classification alongside structured data.
  5. Compare field consistency in Relations vs JSON Structures

    main

    When preparing training data, note the fundamental difference in how field consistency is enforced between Relation Extraction and JSON Structure Extraction:

    FeatureRelation ExtractionJSON Structure Extraction
    Consistency RuleStrict: The first occurrence of a relation type defines the schema for all subsequent instances of that type.
    Schema BehaviorAll instances of type_x must have the same keys.
    JSON Structure RuleFlexible: Uses a union of all fields across instances.
    Schema BehaviorInstances of type_y can have different subsets of fields (e.g., one instance has "weight", another does not).

    Example of JSON Structure Flexibility (Allowed): [{"product": {"name": "A", "price": "$10"}}, {"product": {"name": "B", "price": "$20", "weight": "5kg"}}]

  6. What are LoRA Adapters and why use them?

    main

    LoRA (Low-Rank Adaptation) is a parameter-efficient fine-tuning technique in GLiNER2. Instead of fine-tuning the entire model, you train small, specialized layers called 'adapters' that sit on top of a frozen base model.

    Key Benefits:

    • Fast domain switching: You can swap between different domain specializations (e.g., legal to medical) in milliseconds using model.load_adapter().
    • Minimal storage: Adapters are significantly smaller (~2-10 MB) compared to full models (~100-500 MB).
    • Memory Efficiency: Training only ~1-5% of parameters reduces GPU memory requirements and speeds up training by 2-3x.
    • Easy Deployment: You only need to store one base model and multiple lightweight adapter files.
  7. Combine entities, classification, and structures in GLiNER2

    main

    GLiNER2 allows you to build complex, multi-task schemas using a fluent API. By combining different extraction methods, you can perform multiple information extraction tasks (like entity extraction, text classification, and structured data extraction) in a single model pass. This improves efficiency and maintains context across tasks.

    Supported schema components include:

    • .entities(labels): Extracts specific entity types. Labels can be a list of strings or a dictionary mapping labels to descriptions.
    • .classification(label, choices): Classifies the text into one of the provided categories.
    • .structure(name): Defines a structured object with specific fields using .field(name, ...).
    • .relations(label): Extracts relationships between entities.
    from gliner2 import GLiNER2
    
    extractor = GLiNER2.from_pretrained("your-model-name")
    
    schema = (extractor.create_schema()
        .entities(["person", "product", "company"])
        .classification("sentiment", ["positive", "negative", "neutral"])
        .classification("category", ["review", "news", "opinion"])
    )
    
    text = "Tim Cook announced that Apple's new iPhone is exceeding sales expectations."
    results = extractor.extract(text, schema)
  8. Configure field types and specifications in JSON extraction

    main

    Fields in the extract_json schema use a :: separator to define types, choices, and descriptions.

    Specification Formats:

    • "field_name::type::description"
    • "field_name::[choice1|choice2|choice3]::type::description" (for classification within a structure)
    • "field_name::description" (defaults to list type)
    • "field_name" (simple field, defaults to list)

    Supported Types & Behaviors:

    • str: Extracts the value as a string.
    • list: Extracts multiple values into a list (default behavior if type is omitted).
    • Choices: Using [choice1|choice2] allows you to perform classification within the structured extraction, forcing the model to pick from the provided options.
    # Example of choice fields and descriptions
    results = extractor.extract_json(
        text,
        {
            "reservation": [
                "restaurant::str::Restaurant name",
                "date::str",
                "time::str",
                "party_size::[1|2|3|4|5|6+]::str::Number of guests",
                "seating::[indoor|outdoor|bar]::str::Seating preference",
                "dietary::[vegetarian|vegan|gluten-free|none]::list::Dietary restrictions"
            ]
        }
    )
  9. Configure LoRA (Low-Rank Adaptation) for memory and performance

    main

    LoRA allows for parameter-efficient fine-tuning. You can tune its behavior via TrainingConfig:

    To reduce memory usage further:

    • Use a smaller rank with lora_r (e.g., 8).
    • Target specific modules using lora_target_modules. Targeting only the ["encoder"] or specific attention layers like ["encoder.query", "encoder.key", "encoder.value"] uses less memory.

    To improve LoRA performance (if it lags behind full fine-tuning):

    • Increase the rank with lora_r (e.g., 32).
    • Target more modules, including task heads: ["encoder", "span_rep", "classifier"] or even more extensively: ["encoder", "span_rep", "classifier", "count_embed", "count_pred"].
    • Increase the task_lr (e.g., 1e-3).
    • Train for more num_epochs.
  10. Extract multiple instances of a structure

    main

    GLiNER2 automatically identifies and extracts all occurrences of a defined structure within the text. If the text contains multiple distinct entities matching the schema (e.g., multiple transactions or multiple hotel bookings), the resulting JSON will contain a list of objects, one for each instance found.

    # Example: Multiple transactions extracted into a list
    text = """
    Recent transactions:
    - Jan 5: Starbucks $5.50 (food)
    - Jan 5: Uber $23.00 (transport)  
    - Jan 6: Amazon $156.99 (shopping)
    """
    
    results = extractor.extract_json(
        text,
        {
            "transaction": [
                "date::str",
                "merchant::str",
                "amount::str",
                "category::[food|transport|shopping|utilities]::str"
            ]
        }
    )
    # results['transaction'] will contain 3 objects
  11. Compose multi-task schemas with `create_schema()`

    main

    Use create_schema() to build a comprehensive analysis pipeline that performs entity extraction, classification, relation extraction, and structured data extraction in a single pass.

    Supported schema methods:

    • .entities(dict): Defines entity types and descriptions.
    • .classification(key, labels, multi_label=False, cls_threshold=None): Defines classification tasks.
    • .relations(dict): Defines relationship types and descriptions.
    • .structure(key): Starts a structured data block, followed by .field(name, dtype, choices=None) calls.

    Once the schema is built, pass it to extractor.extract(text, schema).

    # Use create_schema() for multi-task scenarios
    schema = (extractor.create_schema()
        # Extract key entities
        .entities({
            "person": "Names of people, executives, or individuals",
            "company": "Organization, corporation, or business names", 
            "product": "Products, services, or offerings mentioned"
        })
        
        # Classify the content
        .classification("sentiment", ["positive", "negative", "neutral"])
        .classification("category", ["technology", "business", "finance", "healthcare"])
        
        # Extract relationships
        .relations(["works_for", "founded", "located_in"])
        
        # Extract structured product details
        .structure("product_info")
            .field("name", dtype="str")
            .field("price", dtype="str")
            .field("features", dtype="list")
            .field("availability", dtype="str", choices=["in_stock", "pre_order", "sold_out"])
    )
    
    # Comprehensive extraction in one pass
    text = "Apple CEO Tim Cook unveiled the revolutionary iPhone 15 Pro for $999. The device features an A17 Pro chip and titanium design. Tim Cook works for Apple, which is located in Cupertino."
    
    results = extractor.extract(text, schema)
  12. Control entity output type (Single vs Multiple)

    main

    You can control whether the extractor returns all matches for an entity type or just the single best match using the dtype parameter within the schema configuration.

    • dtype="list" (Default): Extracts all matching entities found in the text.
    • dtype="str": Extracts only the single best match per entity type.
    # Multiple Entities (Default)
    schema = extractor.create_schema().entities(
        ["person", "organization"],
        dtype="list"  # Default
    )
    
    # Single Entity per Type
    schema = extractor.create_schema().entities(
        ["company", "ceo"],
        dtype="str"  # Single entity mode
    )