Repository navigation
feat(token-classification): expose GLiNER2.5 CLI options, fix leftovers - #2521
Merged
Merged
Conversation
Expose the GLiNER2.5 load-time options on `mlxcel extract` and fix three token-classification leftovers from #2383/#2387/#2390/#2391. `--max-len <N>` and `--word-splitter <whitespace|char>` reach the loaded Gliner2_5Model through SpanExtractorLoadOptions and load_span_extractor_with; a max_len outside 1..=32768 produces the existing config error text before any model loads, and default behavior is unchanged when the flags are absent. Both are visible in `mlxcel extract --help`. The Viterbi lattice accumulates in f64 as upstream's f64 bias adds do, keeping the `decode(&[Vec<f32>]) -> Vec<usize>` signature and the existing tie resolution. The Privacy Filter band mask is built once per query chunk per forward and shared across layers instead of per chunk per layer. A checkpoint whose tensor shapes do not match the config now fails at load naming the tensor with its expected and actual shape instead of aborting inside MLX; quantized planes (a `.scales` sibling) and optional biases and sinks are skipped, missing tensor, wrong rank and wrong dimension covered. Validation: the filtered cargo test --profile test-fast runs for token_classification, extract and openai_privacy_filter with --test-threads=1, extract --help, fmt --check and clippy -D warnings pass with --features cuda on GB10 (test binary under gpu-lock, MLX_ENABLE_TF32=0). The item 1 CLI tests were written first and failed to compile before the flags existed. Closes #2468
--max-len and --word-splitter are now CLI flags on mlxcel extract (PR #2521); document them in the extract options paragraph and replace the stale "no CLI flag yet" statement in the GLiNER2.5 Input paragraph.
Bilingual technical report for the token-classification leftovers PR (#2468): GLiNER2.5 CLI options, Viterbi f64, band mask sharing, shape validation.
manual_find -> Iterator::find in gliner2_5_small_dir, .err().expect -> expect_err (3 sites), and drop a redundant i32 cast in the band-mask chunk test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #2468: the four token-classification leftovers in one PR.
Item 1: GLiNER2.5 CLI options
mlxcel extractgains--max-len <N>and--word-splitter <whitespace|char>, wired throughSpanExtractorLoadOptionsandload_span_extractor_withto the loadedGliner2_5Model. Amax_lenoutside1..=MAX_SUPPORTED_MAX_LENproduces the existing config error text (GLiNER2.5 max_len must be an integer in 1..=32768, got ...) before any model loads, and an unknown splitter is refused with--word-splitter must be whitespace or char, got '<value>'. Absent flags keep the checkpoint's own values. The char splitter scores every non-space character separately for scripts without word spacing such as CJK.Tests:
extract_gliner_flags_parseandextract_gliner_flags_reject_bad_valuesgo through the realCliparser (both were written first and failed to compile before the flags existed), and two checkpoint-backed gates run againstfastino/gliner2.5-small-v1:--word-splitter charon the fixture's CJK case matching the mlx-vlmcharcase, and--max-lenreaching the loaded model including the out-of-range text. Flags are visible inmlxcel extract --help.Item 2: Viterbi f64 accumulation
The constrained BIOES lattice sums in f64 as upstream's f64 bias adds do, keeping the public
decode(&[Vec<f32>]) -> Vec<usize>signature and tie resolution.f64_accumulation_keeps_an_increment_f32_losesdecodes a lattice where at V = 2^24 the f32 ULP is 2 and V + 1 rounds back to V, tying the closingE-x; f64 keeps the increment and closes the entity. All existing Viterbi tests pass unchanged.Item 3: band mask once per chunk
The Privacy Filter band masks are built once per query chunk per forward (
band_windows) and shared by every layer, instead of per chunk per layer. Spans are unchanged on the existing fixtures, andband_masks_are_built_once_per_chunk_per_forwardcountsBAND_MASKS_BUILT: 40 tokens in 7-query chunks builds 6 masks, not 12.Item 4: checkpoint shape validation
PrivacyFilterModel::from_weightsvalidates every dense tensor against the config-derived shapes before the model graph is built and returns an error naming the tensor with its expected and actual shape, instead of aborting inside MLX.malformed_shapes_error_with_the_tensor_namedcovers a missing tensor, a wrong rank and a wrong dimension, and proves a quantized plane (a.scalessibling) is skipped.Validation
The filtered
cargo test --profile test-fastruns fortoken_classification,extractandopenai_privacy_filterwith--test-threads=1,extract --help,cargo fmt --all -- --checkandcargo clippy --profile test-fast -- -D warningspass locally with--features cudaon GB10 (test binary undergpu-lock,MLX_CUDA_ARCHITECTURES=121,MLX_ENABLE_TF32=0).Closes #2468