1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Native CoreML **face embedding**: the identity half of a video face
//! pipeline, as `audio::speaker` is for voices.
//!
//! Apple Vision supplies the face *spine* — rectangles, capture quality,
//! roll/yaw/pitch, landmarks — but not a face *embedding*:
//! `VNGenerateFaceprintRequest` is private, and the public
//! `VNGenerateImageFeaturePrintRequest` is a whole-image feature print, not an
//! identity-tuned space. So the identity half has to be a model of our own.
//!
//! ```no_run
//! use coremlit::embeddings::face::{FaceAlign, FaceCrop, FaceEmbedder, FaceModel, Point};
//!
//! # let (rgb, width, height) = (vec![0u8; 64 * 48 * 3], 64usize, 48usize);
//! let crop = FaceCrop::new(&rgb, width, height)?;
//! let landmarks = [
//! Point::new(18.5, 16.0), // left eye (the VIEWER's left)
//! Point::new(41.0, 13.5), // right eye
//! Point::new(30.5, 25.0), // nose tip
//! Point::new(21.0, 35.5), // left mouth corner
//! Point::new(40.0, 33.0), // right mouth corner
//! ];
//! let aligned = FaceAlign::to_template(crop, &landmarks)?;
//!
//! // Preprocessing is the MANIFEST's, never a constant here.
//! let manifest = FaceModel::new("data", "embedding", 512);
//! let embedder = FaceEmbedder::from_file("Models/facekit/w600k_r50.mlmodelc", manifest)?;
//! let embeddings = embedder.embed(&[aligned])?; // batch is the unit
//! assert_eq!(embeddings.len(), 1);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! macOS only (built on [`crate`]).
//!
//! # The shapes that are deliberate
//!
//! - **Alignment is OUTSIDE the embedder.** [`FaceAlign::to_template`] is a
//! pure function producing an explicit [`AlignedFace`], so the 5-point
//! similarity transform every downstream cosine passes through has a golden
//! of its own instead of hiding inside a preprocessing step. See the
//! [`align`] module.
//! - **Batch is the unit.** A keyframe with N faces is one
//! [`FaceEmbedder::embed`] call, whatever the graph's own batch dimension is.
//! - **Preprocessing belongs to the manifest.** Channel order, scale, bias and
//! layout are [`FaceModel`] fields, so a second artifact with different
//! preprocessing is a different value, not a second code path. See the
//! [`embed`] module for the census table that makes this non-negotiable.
//! - **The space is produced by `load`, and it knows which bytes it came
//! from.** [`FaceEmbedder::load`] hashes the artifact directory it loads
//! into an [`ArtifactDigest`], and every [`FaceEmbedding`] carries that
//! alongside the feature names, width and preprocessing. Two vectors compare
//! only if byte-identical weights produced them **as read at `load`**, from
//! the same output feature — [`FaceEmbedding::dot`] cannot return a score
//! across different weights. The artifact must not be modified in place while
//! an embedder holds it: replace a model by atomic `rename` and load a new
//! embedder. See the [`artifact`] module.
//! - **The load contract is a value, and a type proves it was checked.**
//! [`FaceEmbedder`] holds a crate-internal `Checked` model whose only
//! constructor runs this door's contract, so an extra required input, a
//! declared state buffer, a wrong element type and a flexible input shape are
//! all refused when the model is loaded rather than discovered at predict
//! time — and deleting the check does not compile. The [`embed`] module
//! carries the contract, and the legacy `neuralNetwork` export it refuses
//! deliberately.
//!
//! # ONE artifact is staged, and it is gated
//!
//! Issue #115's census established that **no face-embedding model clears both
//! the licence bar and the off-angle accuracy bar**: `buffalo_l`'s `w600k_r50`
//! is the accuracy reference (CFP-FP 99.33; 2.22 % frontal-to-profile identity
//! splits at FAR 1e-3) but InsightFace's zoo states "ALL models are available
//! for non-commercial research purposes only", and the best commercially
//! granted artifact, AuraFace, splits identity on those same pairs **38.55 %**
//! of the time. The owner's response (issue #115, "Owner decisions — recorded")
//! was that CI and development MAY use research-only weights, on the standing
//! basis that **coremlit never redistributes them**, with every such artifact
//! behind a `commercial-`prefixed feature outside `default`.
//!
//! That is what the `arcface` module is: a conversion of `w600k_r50`, published
//! to a PRIVATE Hugging Face repository CI fetches with a read token, behind
//! `commercial-face-arcface`. It is the register's first research-only row at
//! BOTH layers (the weights and WebFace600K), and the first artifact for which
//! `tests/model_licences.rs`'s directions 2 and 3 bind something rather than
//! standing as tripwires.
//!
//! **Only the ARTIFACT is gated, and the rest of this module is not.** Two
//! thirds of what is here is encumbered by nothing: [`align`] is `f64`
//! arithmetic and an integer resampler over a synthetic golden, with no
//! weights and no photograph in it, and [`FaceEmbedder`] loads a
//! **caller-supplied** path — including an artifact whose licence permits a
//! product. Pushing either behind a gate documented "requires a commercial
//! licence" would make the register say something false about code that
//! requires nothing, so `face` stays a plain feature and the manifest module
//! carries the gate alone.
//!
//! What the artifact buys, all of it measured in `conversion/face/README.md`
//! and asserted by the `commercial-face-arcface` gates in `tests/face/`:
//! cross-implementation parity against the committed fp32 ONNX reference on
//! every compute arm, the 18 same-person / 135 different-person pairs at
//! InsightFace's own 0.28 / 0.20 operating point, a four-arm placement table,
//! and 287 faces/s on the recommended arm.
//!
//! Three roads that do NOT exist are recorded here because each looks like the
//! obvious next step and none of them is:
//!
//! 1. **A public artifact repository.** Granite, SigLIP, CED, CLAP and the
//! speakerkit overlay are FinDIT-Studio re-conversions `NOTICE` describes as
//! weights this project redistributes. A research-only model cannot travel
//! that road, which is why this one's repository is private.
//! 2. **A third-party CoreML build.** InsightFace ships ONNX only, and both
//! CoreML ArcFace builds a Hugging Face search surfaces declare `ImageType`
//! inputs that [`crate::Model`] cannot bind (`crate::Features` is a
//! `Vec<(String, MultiArray)>` end to end). Each has a second disqualifier
//! of its own — `RuiSumida/ArcFace-R100-CoreML` emulates PReLU with 100
//! `NonZero` + 50 `scatterNd` + 50 `gatherNd`, forcing the ANE off the
//! graph, and publishes CFP-FP 94.21 against issue #115's proven-bad line of
//! 97.3; `RuiSumida/InsightFace-glintr100-CoreML` is the better graph and
//! ships no README, no licence and no statement of provenance.
//! 3. **Converting inside the CI job.** The licence register's two key
//! exemptions are `Unpinned` (the lock pins a moving revision) and
//! `Unmanifested` (a glob table with no per-file manifest); neither covers
//! bytes produced by the job and never published, so such an artifact could
//! not be keyed at all.
// **The absent half of the gate, provable only as a compile error.** Under
// plain `face` the manifest module does not exist, and no runtime assertion can
// see an absence — so the proof is a `compile_fail` doctest, and it is attached
// only in the configuration whose claim it is. Its two-sided partner, plus the
// deliberate assertion that a caller CAN write this artifact's manifest by hand
// under plain `face`, is `tests/face/gate.rs`.
// The staged `w600k_r50` artifact's manifest: what to load, how it wants its
// pixels, and which placement it was measured fastest on. Behind
// `commercial-face-arcface` because the weights and their corpus are
// research-only; everything else in this module works on any artifact the
// caller supplies and is not gated.
//
// A PLAIN comment rather than a `///` one, and that is load-bearing: an outer
// doc comment on a `mod` declaration merges with the module file's own `//!`
// block and rustdoc then resolves the WHOLE merged block from the outer
// fragment's scope — so `super` inside `arcface/mod.rs` would mean
// `embeddings`, and every relative link in it would break or go redundant. The
// module documents itself.
pub use ArtifactDigest;
pub use ;
pub use ;