#[path = "arcface/mod.rs"]
mod common;
use coremlit::{
ComputeUnits, DataType, Model, MultiArray, ShapeConstraint,
embeddings::face::{
FaceEmbedder, FaceEmbedderOptions, FaceModel, TEMPLATE_SIZE, arcface, error::Error,
},
};
const INPUT_SHAPE: [usize; 4] = [1, 3, 112, 112];
const EMBEDDING_DIM: usize = 512;
fn face_tensor() -> MultiArray {
let len: usize = INPUT_SHAPE.iter().product();
MultiArray::from_slice(&INPUT_SHAPE, &vec![0.0f32; len]).expect("build face tensor")
}
#[test]
fn provenance_is_pinned() {
assert_eq!(common::HF_REPO, "FinDIT-Studio/facekit-coreml");
assert_eq!(common::HF_REVISION.len(), 40);
assert_eq!(common::SOURCE_PACK, "buffalo_l.zip");
assert_eq!(common::SOURCE_PACK_SHA256.len(), 64);
assert_eq!(common::SOURCE_MEMBER, "w600k_r50.onnx");
assert_eq!(common::SOURCE_MEMBER_SHA256.len(), 64);
assert_eq!(common::INSIGHTFACE_REVISION.len(), 40);
assert_ne!(
common::HF_REVISION,
common::INSIGHTFACE_REVISION,
"the artifact repo's revision and the upstream source's are different chains"
);
assert_ne!(
common::SOURCE_PACK_SHA256,
common::SOURCE_MEMBER_SHA256,
"the pack's hash is not the converted member's"
);
assert_eq!(common::ARTIFACT_SHA256.len(), 5);
for (path, sha) in common::ARTIFACT_SHA256 {
assert_eq!(sha.len(), 64, "{path} needs a full SHA-256");
assert!(
sha
.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_uppercase()),
"{path}: SHA-256 must be lowercase hex"
);
}
}
#[test]
fn the_library_and_this_suite_name_one_bundle() {
assert_eq!(arcface::BUNDLE_NAME, common::BUNDLE_NAME);
assert!(
arcface::STAGED_PATH.ends_with(arcface::BUNDLE_NAME),
"the library's staged path must name the bundle: {}",
arcface::STAGED_PATH
);
assert_eq!(arcface::MODEL.dim(), EMBEDDING_DIM);
assert_eq!(arcface::MODEL.input(), "data");
assert_eq!(arcface::MODEL.output(), "embedding");
assert_eq!(TEMPLATE_SIZE, INPUT_SHAPE[2]);
assert_eq!(TEMPLATE_SIZE, INPUT_SHAPE[3]);
}
#[test]
fn the_arcface_manifest_refuses_the_vendored_silero_bundle() {
let bundle = common::models_root()
.join("vadkit")
.join("silero-vad-unified-256ms-v6.2.1.mlmodelc");
assert!(
bundle.is_dir(),
"the vendored silero bundle is committed, so this gate is NOT model-gated; looked for {}",
bundle.display()
);
let options = FaceEmbedderOptions::new().with_compute(ComputeUnits::CpuOnly);
let error = FaceEmbedder::load(&bundle, arcface::MODEL, options)
.expect_err("silero declares no `data` feature");
assert!(
matches!(&error, Error::ContractMismatch(m)
if m.feature() == arcface::MODEL.input() && m.actual().contains("audio_input")),
"{error}"
);
let error = FaceEmbedder::load(
&bundle,
FaceModel::new("audio_input", "vad_output", EMBEDDING_DIM)
.with_preprocessing(arcface::MODEL.preprocessing()),
options,
)
.expect_err("silero's audio window is not a template face");
assert!(
matches!(&error, Error::ContractMismatch(m)
if m.feature() == "audio_input" && m.actual() == "[1, 4160]"),
"{error}"
);
}
#[test]
#[ignore = "requires the staged arcface model (FACEKIT_TEST_MODELS)"]
fn model_declares_the_pinned_io_contract() {
let model = Model::load(common::model_path(), ComputeUnits::CpuOnly).expect("load model");
let description = model.description();
let input = description.input("data").expect("`data` input");
assert_eq!(input.shape(), INPUT_SHAPE);
assert_eq!(input.data_type(), Some(DataType::F32));
assert_eq!(
input.shape_constraint(),
Some(ShapeConstraint::Fixed),
"the `data` input must accept exactly one shape; a flexible one reports the same NUMBERS \
through `shape()` and takes the graph off the accelerator"
);
let output = description.output("embedding").expect("`embedding` output");
assert_eq!(output.shape(), [1, EMBEDDING_DIM]);
assert_eq!(output.data_type(), Some(DataType::F32));
assert_eq!(output.shape_constraint(), Some(ShapeConstraint::Fixed));
assert_eq!(description.inputs().len(), 1, "exactly one input");
assert_eq!(description.outputs().len(), 1, "exactly one output");
assert!(
description.states().is_empty(),
"the ArcFace graph must declare NO `MLState` buffers: `FaceEmbedder::embed` predicts through \
the stateless API, which CoreML does not allow for a stateful model. Declared: {:?}",
description
.states()
.iter()
.map(coremlit::FeatureInfo::name)
.collect::<Vec<_>>()
);
assert!(
!input.is_optional(),
"the one input this door supplies is the one the graph requires"
);
let unsatisfiable: Vec<&str> = description
.inputs()
.iter()
.filter(|f| f.name() != "data" && !f.is_optional())
.map(coremlit::FeatureInfo::name)
.collect();
assert!(
unsatisfiable.is_empty(),
"the graph requires {unsatisfiable:?}, which this door never sends"
);
let embedder = FaceEmbedder::from_file(common::model_path(), arcface::MODEL).expect("load door");
assert_eq!(embedder.batch_capacity(), 1, "the artifact pins batch 1");
assert_eq!(embedder.dim(), EMBEDDING_DIM);
}
#[test]
#[ignore = "requires the staged arcface model (FACEKIT_TEST_MODELS)"]
fn artifact_matches_the_pinned_sha_manifest() {
common::assert_exact_sha_manifest(&common::model_path(), common::ARTIFACT_SHA256);
let checksums = common::models_dir().join("CHECKSUMS.sha256");
let text = std::fs::read_to_string(&checksums)
.unwrap_or_else(|e| panic!("read {checksums:?}: {e} — the kit stages its own manifest"));
let published: std::collections::BTreeMap<String, String> = text
.lines()
.filter(|line| !line.trim().is_empty())
.map(|line| {
let (sha, path) = line
.split_once(" ")
.unwrap_or_else(|| panic!("{checksums:?}: not `<sha256> <path>`: {line:?}"));
let relative = path
.trim()
.strip_prefix(&format!("./{}/", common::BUNDLE_NAME))
.unwrap_or_else(|| {
panic!(
"{checksums:?}: {path:?} is not under ./{}/",
common::BUNDLE_NAME
)
})
.to_owned();
(relative, sha.to_owned())
})
.collect();
let pinned: std::collections::BTreeMap<String, String> = common::ARTIFACT_SHA256
.iter()
.map(|(path, sha)| ((*path).to_owned(), (*sha).to_owned()))
.collect();
assert_eq!(
published, pinned,
"the staged CHECKSUMS.sha256 and this suite's pinned manifest describe different bundles"
);
}
#[test]
#[ignore = "requires the staged arcface model (FACEKIT_TEST_MODELS)"]
fn embedder_loads_under_every_compute_placement() {
for compute in [
ComputeUnits::All,
ComputeUnits::CpuOnly,
ComputeUnits::CpuAndGpu,
ComputeUnits::CpuAndNeuralEngine,
] {
let embedder = FaceEmbedder::load(
common::model_path(),
arcface::MODEL,
FaceEmbedderOptions::new().with_compute(compute),
)
.unwrap_or_else(|e| panic!("load under {compute:?}: {e}"));
assert_eq!(embedder.dim(), EMBEDDING_DIM);
}
assert!(
[
ComputeUnits::All,
ComputeUnits::CpuOnly,
ComputeUnits::CpuAndGpu,
ComputeUnits::CpuAndNeuralEngine,
]
.contains(&arcface::RECOMMENDED_COMPUTE),
"the recommended arm must be one of the four this gate loads under"
);
}
#[test]
#[ignore = "requires the staged arcface model (FACEKIT_TEST_MODELS)"]
fn the_graphs_embeddings_are_raw_and_not_unit_norm() {
let reference = common::load_reference();
let model = Model::load(common::model_path(), ComputeUnits::CpuOnly).expect("load model");
let preprocessing = arcface::MODEL.preprocessing();
for face in reference.faces.iter().take(3) {
let mut planar = vec![0.0f32; INPUT_SHAPE.iter().product()];
let side = TEMPLATE_SIZE;
for y in 0..side {
for x in 0..side {
for c in 0..3 {
planar[c * side * side + y * side + x] = f32::from(face.crop[(y * side + x) * 3 + c])
.mul_add(preprocessing.scale(), preprocessing.bias()[c]);
}
}
}
let input = MultiArray::from_slice(&INPUT_SHAPE, &planar).expect("build tensor");
let outputs = model
.predict_with(&[("data", &input)])
.unwrap_or_else(|e| panic!("{}: predict: {e}", face.id));
let raw = outputs.get("embedding").expect("output present");
assert_eq!(raw.shape(), [1, EMBEDDING_DIM]);
let values: &[f32] = raw.as_slice().expect("read embedding");
assert!(
values.iter().all(|v| v.is_finite()),
"{}: non-finite component",
face.id
);
let norm = values
.iter()
.map(|v| f64::from(*v) * f64::from(*v))
.sum::<f64>()
.sqrt();
eprintln!("[arcface] {}: raw ‖e‖ = {norm:.4}", face.id);
assert!(
norm > 2.0,
"{} embedded to norm {norm:.4} — an L2 in the graph would read 1.0, and coremlit's \
contract is that the DOOR normalises",
face.id
);
}
}
#[test]
#[ignore = "requires the staged arcface model (FACEKIT_TEST_MODELS)"]
fn runtime_accepts_exactly_the_pinned_shape() {
let model = Model::load(common::model_path(), ComputeUnits::CpuOnly).expect("load model");
let outputs = model
.predict_with(&[("data", &face_tensor())])
.expect("the pinned shape must be accepted");
assert_eq!(
outputs.get("embedding").expect("output present").shape(),
[1, EMBEDDING_DIM]
);
for shape in [
vec![1, TEMPLATE_SIZE, TEMPLATE_SIZE, 3],
vec![1, 3, TEMPLATE_SIZE, TEMPLATE_SIZE + 1],
vec![2, 3, TEMPLATE_SIZE, TEMPLATE_SIZE],
] {
let len: usize = shape.iter().product();
let input = MultiArray::from_slice(&shape, &vec![0.0f32; len]).expect("build tensor");
assert!(
model.predict_with(&[("data", &input)]).is_err(),
"{shape:?} must be refused by the runtime"
);
}
}