edgefirst_decoder/model_config/mod.rs
1// SPDX-FileCopyrightText: Copyright 2026 Au-Zone Technologies
2// SPDX-License-Identifier: Apache-2.0
3
4//! Model configuration discovery.
5//!
6//! Finds what a model needs to be run and decoded — its output schema, class
7//! labels and input preprocessing — from whatever the model carries, and
8//! records where each value came from.
9//!
10//! # Sources
11//!
12//! Sources are read in this order; each fills only what the ones before it
13//! left unset, so `edgefirst.json` wins over a Hugging Face config field by
14//! field:
15//!
16//! 1. `edgefirst.json` embedded in the model (its `input.preprocessing`, then
17//! the legacy `validation.normalization` / `validation.preprocessing`);
18//! 2. `edgefirst.json` and `labels.txt` beside the model;
19//! 3. Hugging Face `config.json` + `preprocessor_config.json` embedded in the
20//! model;
21//! 4. the same files beside the model (the `optimum` export layout);
22//! 5. Ultralytics export metadata ([`infer_ultralytics_schema`]);
23//! 6. Hugging Face input/output names (`pixel_values` → `logits`), as guesses;
24//! 7. the documented defaults.
25//!
26//! [`ModelOverrides`] apply last.
27//!
28//! # Embedding conventions
29//!
30//! | Container | Where | Names |
31//! |---|---|---|
32//! | ONNX | `ModelProto.metadata_props` | `edgefirst` (legacy `edgefirst.json`), `labels`, `hf_config`, `hf_preprocessor_config` |
33//! | TFLite, HEF, DVM, TensorRT, any file | appended ZIP (TFLite associated files) | `edgefirst.json`, `labels.txt`, `config.json`, `preprocessor_config.json` |
34//! | any | the model's directory | as for ZIP |
35//!
36//! ONNX models are read by walking the top-level protobuf fields and seeking
37//! past the graph; ZIP trailers need the `model-files` feature (off by
38//! default). A `config.json` is used only when it looks like a Hugging Face
39//! config (a string `model_type` and `architectures` or
40//! `transformers_version`); any other `config.json` is skipped and noted.
41//!
42//! # Class labels
43//!
44//! Every label source — `edgefirst.json` `dataset.classes`, `labels.txt` and
45//! the ONNX `labels` key, Hugging Face `id2label` / `label2id`, Ultralytics
46//! `names` and the `labels` override — has leading and trailing whitespace
47//! removed from each name ([`str::trim`]), so ADE20K's `"bed "` resolves to
48//! `"bed"`. Whitespace inside a name (`"chest of drawers"`) is kept.
49//! Discovered class names never fail resolution: a source whose names are
50//! unusable (a name empty after trimming, a malformed `id2label`, or a count
51//! that disagrees with `num_labels` or the output) is ignored with a warning
52//! and a note naming the source and the index (`id2label[7]`), and the next
53//! source supplies the labels. The count is checked against the class count
54//! the decoder builder derives from the outputs, or the segmentation
55//! channels of a semantic model, so an earlier source that miscounts yields
56//! to a later one that fits; end-to-end detections and class maps carry no
57//! count, so there the first source wins. A ModelPack segmentation output
58//! has one channel more than its classes: the last is background and has no
59//! label, so a multitask model's masks and boxes share class indices. Ultralytics `names` that disagree with the output are
60//! ignored and the schema is laid out from the count a `labels` override
61//! gives, or else from the one output whose class count fits; when several
62//! could, the layout is ambiguous and resolution fails, naming the override
63//! and a sidecar `edgefirst.json` as the ways to settle it.
64//! When no source fits, the labels are empty with a warning.
65//! `labels.txt` skips blank lines, so it cannot name an empty class.
66//! Names that repeat ignoring case add a note, since they make matching
67//! classes by name ambiguous. The `labels` override is checked strictly.
68//!
69//! [`infer_ultralytics_schema`]: crate::infer_ultralytics_schema
70
71mod container;
72mod error;
73mod heuristics;
74mod hf;
75mod onnx;
76mod overrides;
77mod provenance;
78mod resolve;
79#[cfg(feature = "model-files")]
80mod ziptrailer;
81
82pub use container::{
83 read_embedded, read_embedded_bytes, read_sidecars, ConfigFile, ModelFiles, EDGEFIRST_JSON,
84 HF_CONFIG, HF_PREPROCESSOR, LABELS_TXT, ONNX_EDGEFIRST, ONNX_HF_CONFIG, ONNX_HF_PREPROCESSOR,
85 ONNX_LABELS,
86};
87pub use error::ModelConfigError;
88pub use overrides::{ModelOverrides, NormalizeOverride, ResizeOverride};
89pub use provenance::{
90 config_field_code, config_source_code, model_family_code, model_task_code, ConfigField,
91 ConfigSource, ModelFamily, ModelTask, Provenance,
92};
93pub use resolve::{resolve_model_config, resolve_sources, ModelSources, ResolvedModelConfig};