diff --git a/docs/architectures.md b/docs/architectures.md index 7be1d74a..fee9b962 100644 --- a/docs/architectures.md +++ b/docs/architectures.md @@ -32,7 +32,7 @@ All stateless architectures apply the checkpoint's text-only `config.max_len` before encoding labels. Whether labels share a later backbone context with the text depends on the architecture: uni-encoders share it, while bi-encoders keep the two sequences separate. Cached StreamingSpan sessions use their causal -decoder context instead. See [Input limits and truncation](input_limits.md) for +decoder context instead. See [Input limits and truncation](usage.md#input-limits-and-truncation) for the complete behavior and production preflight guidance. ## Vanilla GLiNER (UniEncoderSpan) @@ -660,7 +660,7 @@ complete current entity snapshot with document-relative character offsets. It is not a delta: callers that render live changes should compare consecutive snapshots to identify additions, updates, and removals. -The [StreamingSpan guide](streaming.md) covers the session API, persistent +The [StreamingSpan guide](usage.md#streamingspan-models) covers the session API, persistent batches, asynchronous microbatching, cache cleanup, configuration, and deployment trade-offs. A PII-oriented checkpoint is available at [knowledgator/gliner-stream-pii-v1.0](https://huggingface.co/knowledgator/gliner-stream-pii-v1.0). diff --git a/docs/configs.md b/docs/configs.md index d128624d..c141fe0b 100644 --- a/docs/configs.md +++ b/docs/configs.md @@ -163,7 +163,7 @@ configurations may override the base default. This is not necessarily the backbone's total context length. Uni-encoder prompts and text share the later transformer subword/context limit, while bi-encoders encode labels separately. See [Input limits and -truncation](input_limits.md) for all limits and the StreamingSpan exception. +truncation](usage.md#input-limits-and-truncation) for all limits and the StreamingSpan exception. --- diff --git a/docs/convert_to_onnx.md b/docs/convert_to_onnx.md index b816e7e2..dda88503 100644 --- a/docs/convert_to_onnx.md +++ b/docs/convert_to_onnx.md @@ -16,16 +16,16 @@ automatically; keep an OpenVINO `.xml` file beside its matching `.bin` file. ## Installation -ONNX Runtime CPU support is included in the default installation: +For ONNX Runtime CPU support, install the optional `onnx` extra: ```bash -pip install gliner +pip install "gliner[onnx]" ``` Install the Python `onnx` package when exporting a PyTorch checkpoint to ONNX: ```bash -pip install gliner onnx +pip install "gliner[onnx]" onnx ``` For ONNX Runtime with CUDA execution providers, install the GPU extra: @@ -35,6 +35,9 @@ pip install "gliner[gpu]" ``` Add `onnx` to the same command if this environment will also export models. +Choose only one of `gliner[onnx]` and `gliner[gpu]`: both runtime packages +provide the same Python module and must not be installed together. The default +`gliner` installation does not install either ONNX Runtime package. For direct OpenVINO export and inference, install the OpenVINO extra. Direct OpenVINO conversion does not create an intermediate ONNX model: diff --git a/docs/index.md b/docs/index.md index ffe6192c..b4ee1d93 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,9 +10,7 @@ This documentation includes installation guides, tutorials, advanced topics, and intro instalation quickstart -input_limits usage -streaming configs training architectures diff --git a/docs/input_limits.md b/docs/input_limits.md deleted file mode 100644 index 2ff23fa7..00000000 --- a/docs/input_limits.md +++ /dev/null @@ -1,217 +0,0 @@ -# Input limits and truncation - -GLiNER does not automatically split a long document into windows. For ordinary -stateless inference, each input that exceeds the checkpoint's `config.max_len` -is reduced to a prefix. In GLiNER 0.2.27 this produces a `UserWarning`, but the -prediction call still succeeds and its return value does not say that part of -the input was skipped. - -This behavior applies to span, token, bi-encoder, decoder, and relation -extraction models. Cached StreamingSpan sessions are the exception described -under **Architecture-specific limits** below. - -## What `config.max_len` counts - -`config.max_len` is the maximum number of **text tokens produced by GLiNER's -word splitter**. It is not a character count, a whitespace-word count, a -transformer subword count, or the total prompt-plus-text sequence length. - -For raw-text inference, the processing order is: - -```text -raw text - -> WordsSplitter(config.words_splitter_type) - -> N text tokens - -> if N > config.max_len: warn and keep tokens[:config.max_len] - -> add the entity/relation-type prompt - -> transformer subword tokenization - -> model -``` - -The default `whitespace` splitter also separates punctuation. For example, -`"Acme, Inc."` becomes four splitter tokens (`Acme`, `,`, `Inc`, `.`), even -though a simple `text.split()` returns two strings. Other -`words_splitter_type` values segment text differently. Always inspect the -loaded checkpoint rather than assuming the configuration default: - -```python -print(model.config.max_len) -print(model.config.words_splitter_type) -``` - -The base configuration defaults to `max_len=384`, but checkpoints can save a -different value. For example, -`EmergentMethods/gliner_medium_news-v2.1` saves `max_len=296`. - -## Do labels reduce the text budget? - -At the `config.max_len` stage, **no**. GLiNER splits and truncates the text -first, then prepends or separately encodes the entity-type prompt. Ten labels -and one hundred labels therefore receive the same `config.max_len` allowance -for text. - -There is a second, independent limit to consider. A transformer sees -subtokens, and uni-encoder architectures put the label prompt and retained text -in one transformer sequence. Prompt subtokens therefore consume part of any -finite tokenizer or backbone context capacity. A finite tokenizer limit can -truncate the text tail; a backbone limit can instead reject an oversized -combined sequence. Either way, adding labels reduces the remaining combined -headroom even though it does not change `config.max_len`. - -GLiNER calls the transformer tokenizer with `truncation=True` but without an -explicit tokenizer `max_length`, so the tokenizer's registered limit and -truncation side determine tokenizer-level behavior. Some tokenizers do not -register a finite limit; Transformers may then warn that no maximum was -provided and perform no tokenizer-level truncation. That does not prove that -the backbone supports an unlimited sequence. - -## Behavior when text exceeds `max_len` - -For each input independently, when `num_tokens > model.config.max_len`, GLiNER -0.2.27: - -1. emits a `UserWarning` such as - `Sentence of length 987 has been truncated to 296`; -2. retains only the first `max_len` splitter tokens; -3. runs inference normally on that prefix; and -4. returns ordinary-looking predictions with no truncation metadata. - -Text after the retained prefix is never presented to the model. Entities there -cannot be returned, and entities crossing the boundary are incomplete. The -same prefix truncation occurs during training when a pre-tokenized example is -too long. - -Python warning filters control whether the warning is visible. With the default -filter, repeated warnings from the same location may be shown only once per -process. Warnings may also bypass an application's structured logs. Do not use -the presence or absence of the warning as a per-request completeness signal. - -As of 0.2.27, `predict_entities` and `inference` do not provide a -`return_truncation_info` result and do not have a `truncation="error"` mode. -[Issue #231](https://github.com/urchade/GLiNER/issues/231) tracks the request for -fail-on-truncation behavior. - -## Production preflight without processor internals - -Use the public `prepare_batch` stage to count exactly the splitter tokens that -stateless inference will receive. This avoids depending on -`model.data_processor.words_splitter`: - -```python -def truncation_info(model, text, labels): - prepared = model.prepare_batch(text, labels) - num_tokens = len(prepared["tokens"][0]) if prepared["tokens"] else 0 - max_len = model.config.max_len - return { - "truncated": num_tokens > max_len, - "num_tokens": num_tokens, - "max_len": max_len, - } - - -info = truncation_info(model, text, labels) -if info["truncated"]: - raise ValueError( - f"GLiNER input has {info['num_tokens']} tokens; " - f"the model limit is {info['max_len']}" - ) - -entities = model.predict_entities(text, labels) -``` - -For a batch, `prepared["tokens"]` contains one token list per non-empty input; -`prepared["valid_to_orig_idx"]` maps those lists back to the original batch -indices. Emit the resulting information in the service response or reject the -request before inference, according to the service contract. - -This preflight covers `config.max_len`; it does not measure a combined -uni-encoder subword sequence, an inference-packing limit, or a cached streaming -session's remaining context. - -## Processing long documents - -For full-document coverage, split the text into overlapping windows no longer -than `config.max_len`, predict each window, shift its character offsets back to -document coordinates, and reconcile duplicate predictions from overlaps. The -public preparation result includes the exact token-to-character maps needed to -make splitter-aligned windows: - -```python -def iter_gliner_windows(model, text, labels, overlap): - prepared = model.prepare_batch(text, labels) - if not prepared["tokens"]: - return - - tokens = prepared["tokens"][0] - starts = prepared["start_token_map"][0] - ends = prepared["end_token_map"][0] - window_size = model.config.max_len - - if not 0 <= overlap < window_size: - raise ValueError("overlap must be in [0, model.config.max_len)") - - step = window_size - overlap - for first in range(0, len(tokens), step): - last = min(first + window_size, len(tokens)) - char_start = starts[first] - char_end = ends[last - 1] - yield char_start, text[char_start:char_end] - if last == len(tokens): - break -``` - -For span models, an overlap of at least `max_width - 1` tokens ensures that an -entity no wider than `max_width` is fully contained in some window. A larger -overlap may be useful for contextual accuracy, and token-level models may need -a task-specific overlap because their entity length is not bounded by -`max_width`. Relation extraction also needs application-specific merging; -relations whose endpoints never occur together in a window cannot be inferred. - -GLiNER does not merge window outputs for you. When shifting an entity from a -window beginning at `char_start`, add `char_start` to both `entity["start"]` and -`entity["end"]`. A common overlap policy is to group predictions by -`(start, end, label)` and retain the highest score. - -## Changing `max_len` - -The loader's `max_length` argument overrides the saved `config.max_len`: - -```python -model = GLiNER.from_pretrained( - "urchade/gliner_small-v2.1", - max_length=512, -) -``` - -The name difference is intentional: `max_length=` at load time writes -`model.config.max_len`. Passing `max_length` or `truncation` to -`predict_entities` is not a supported way to change the word-level limit. - -Increasing this value does not resize the backbone context, change the -transformer tokenizer's `model_max_length`, or guarantee quality beyond the -lengths used to train the checkpoint. Subword expansion and the label prompt -can make the combined sequence longer than the word-token count suggests, and -longer inputs require more memory. Prefer windowing unless the checkpoint and -backbone are known to support the larger value. - -## Architecture-specific limits - -| Architecture or path | How the label prompt is encoded | Effective-limit notes | -|---|---|---| -| UniEncoderSpan and UniEncoderToken | Prompt and text share one backbone sequence | `config.max_len` is text-only, but a finite backbone/tokenizer subword limit includes the prompt | -| UniEncoder span/token decoders | Main encoder prompt and text share a sequence; generated labels use an auxiliary decoder | The main encoder has the same two-stage limits as other uni-encoders; the decoder has its own generation limits | -| UniEncoder relation extraction | Entity labels, relation labels, and text share one sequence | Both prompt types can consume the combined backbone context, but neither changes the first-stage text-only `config.max_len` check | -| BiEncoderSpan and BiEncoderToken | Text and labels are encoded separately | Label count does not consume the text encoder sequence; each encoder still has its own tokenizer/backbone limit | -| StreamingSpan without `session_id` | Prompt and text share one causal sequence | Uses the normal stateless `config.max_len` prefix truncation, followed by the causal backbone limit | -| Cached StreamingSpan session | The initial prompt and all appended text share the decoder context | Stateless `config.max_len` truncation is bypassed; exceeding the smaller of `max_cache_length` and the decoder's native limit raises `ValueError` instead of dropping old text | - -Inference packing adds another independent setting: -`InferencePackingConfig.max_length` is measured in already-tokenized backbone -token IDs, not splitter tokens. If one encoded request is longer than that -value, the current packer keeps its first `max_length` token IDs without the -`config.max_len` warning. Set the packing limit for the complete encoded -request (including a uni-encoder prompt), or disable packing for requests that -may exceed it. - -Finally, `max_width` is not an input-length limit. It controls the widest -candidate entity span, in splitter tokens, for span-based architectures. diff --git a/docs/instalation.md b/docs/instalation.md index 98ba6e89..a36bd7c5 100644 --- a/docs/instalation.md +++ b/docs/instalation.md @@ -9,12 +9,15 @@ To begin using the GLiNER model, you can install the GLiNER Python library throu pip install gliner ``` :::tip[ONNX Runtime] -CPU inference with ONNX Runtime is included in the default installation. Install the separate `onnx` package to export models, or use the GPU feature for CUDA execution providers. +ONNX Runtime is optional. Choose the `onnx` extra for CPU inference or the `gpu` extra for CUDA execution providers. Install only one: the CPU and GPU packages share the same Python module. Install the separate `onnx` package to export models. ::: ```bash -pip install onnx # required for ONNX export +pip install "gliner[onnx]" # CPU-backed ONNX Runtime +# or pip install "gliner[gpu]" # GPU-backed ONNX Runtime + +pip install onnx # additionally required for ONNX export ``` :::tip[OpenVINO] diff --git a/docs/intro.md b/docs/intro.md index 925d5b4c..f3028c20 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -85,13 +85,16 @@ To begin using the GLiNER model, you can install the GLiNER Python library throu !pip install gliner ``` -CPU ONNX Runtime support is included in the default installation. Install -`onnx` when exporting models, or install GLiNER with the GPU feature for CUDA -execution providers: +ONNX Runtime is optional. Choose the `onnx` extra for CPU inference or the +`gpu` extra for CUDA execution providers. Install only one: the CPU and GPU +packages share the same Python module. Also install `onnx` when exporting models: ```bash -!pip install onnx -!pip install "gliner[gpu]" +!pip install "gliner[onnx]" # CPU +# or +!pip install "gliner[gpu]" # NVIDIA GPU + +!pip install onnx # additionally required for ONNX export ``` Install OpenVINO support to export models directly to OpenVINO IR or run them diff --git a/docs/serving.md b/docs/serving.md index 16ef029c..ecc60a04 100644 --- a/docs/serving.md +++ b/docs/serving.md @@ -80,7 +80,11 @@ outputs = client.predict( ``` Each dictionary key is returned as the entity label; its value is the prompt encoded -for that text. A single dictionary is shared across every input text. +for that text. A single dictionary is shared across every input text. When supplying +a list of dictionaries, its length and order must match the input texts, and each +dictionary contains all labels for its corresponding text. For a single text, put +all labels in one dictionary. See [Label descriptions](usage.md#label-descriptions) +for examples of shared and per-text label sets. Network or server errors surface as `gliner.serve.client.GLiNERClientError`. @@ -90,7 +94,7 @@ overrides the loaded model's text-only `config.max_len`; requests above it can still return HTTP success after GLiNER keeps only the prefix and emits a Python warning inside the replica. If the service contract requires full-input coverage, validate or window requests explicitly. See [Input limits and -truncation](input_limits.md) for a preflight that uses the public model API. +truncation](usage.md#input-limits-and-truncation) for a preflight that uses the public model API. ::: **HTTP request (no client library):** diff --git a/docs/streaming.md b/docs/streaming.md deleted file mode 100644 index 5af8da12..00000000 --- a/docs/streaming.md +++ /dev/null @@ -1,367 +0,0 @@ -# StreamingSpan - -StreamingSpan is GLiNER's architecture for named entity recognition over text -that arrives incrementally. It uses a causal decoder as the text backbone, -retains reusable state between chunks, and revises recent span predictions when -new right context becomes available. - -Use the -[knowledgator/gliner-stream-pii-v1.0](https://huggingface.co/knowledgator/gliner-stream-pii-v1.0) -checkpoint to get started with streaming PII detection. `GLiNER.from_pretrained` -reads `model_type="gliner_streaming_span"` from the checkpoint and selects -`StreamingSpanGLiNER` automatically. - -```python -from gliner import GLiNER - -model = GLiNER.from_pretrained("knowledgator/gliner-stream-pii-v1.0") -model.eval() -``` - -## Quick start - -Pass one chunk at a time with a stable session ID. The chunks are concatenated -exactly as supplied, so retain spaces and punctuation at chunk boundaries. - -```python -labels = ["person", "email address", "phone number"] -session_id = "support-call-42" -chunks = [ - "Customer Alice Johnson ", - "can be reached at alice@example.com ", - "or +1 202-555-0147.", -] - -try: - for chunk in chunks: - snapshot = model.inference( - [chunk], - labels, - session_id=[session_id], - threshold=0.5, - )[0] - print(snapshot) -finally: - model.clear_session(session_id) -``` - -Each `snapshot` is the complete set of entities currently active for the -accumulated session text. It is not a list of only the entities detected in the -latest chunk. An entity has the same shape as an ordinary GLiNER prediction: - -```python -{ - "start": 9, # document-relative, inclusive character offset - "end": 22, # document-relative, exclusive character offset - "text": "Alice Johnson", - "label": "person", - "score": 0.93, -} -``` - -Scores and even the active boundaries may change between snapshots as more -context arrives. Consumers that need an event stream should diff consecutive -snapshots by `(start, end, label)`. - -## Architecture - -![GLiNER StreamingSpan architecture](images/gliner-streaming-architecture.svg) - -StreamingSpan uses the following cold and warm paths: - -1. On the first append, labels and text are serialized as - `label<