Run each model on the Hexagon in the form measured to hold it
The engine knew f32 and int8, and gave the Hexagon int8 for every role it served. Measured on the tablet itself (inference.md §1.5), int8 lost 5% of the detector's faces at 40-80 px, moved the landmarks 1.5 px, emptied the segmenter's scores and cost the denoiser 5-9 dB; fp16 the HTP refuses outright. `Form` gains A16W8 and A16W16, and `Rung::form` now names one per role: detectors and landmarks A16W8, the segmenter, scene model, border filler and denoiser A16W16, XFeat int8. The embedder and the eye classifiers stay on the CPU. Each loader resolves its `<stem>.<form>.onnx` sibling; the segmenter and XFeat, compiled into the binary, embed their quantised forms on Android only and pick through `choose_embedded`. The probe, the compile step and the cache fingerprint follow the form instead of assuming int8. Detectors on the new form write `scrfd_*_a16+w600k_mbf`, and `model_ids` answers for all three spellings. On the tablet (ORT 1.29 + QNN 2.42), each shipped file against f32 on the same inputs, and against the CPU's f32 time: SCRFD 500m/2.5g/10g A16W8 100% of faces in every band 4.2/5.1/9.0 ms vs 17/56/198 landmarks A16W8 0.25 px in the 192 crop 0.5 ms vs 2.8 YOLO26n-seg A16W16 98.2% found, mask IoU 0.994 12.9 ms vs 90 scene model A16W16 98.9% of cells agree 15 ms vs 151 MI-GAN A16W16 41 dB from f32 in the fill 87 ms vs 488 XFeat int8 pano alignment 0.45 px (f32's own spread 0.41) 6.5 ms vs 58 denoiser A16W16 0.00 dB at every ISO 95 ms vs 1510 a tile Face numbers are over public COCO val2017 photographs, not a library. The APK carries the siblings (BUNDLED 15 -> 19; the old int8 detectors removed), about 43 MB more. The Windows installer and its CI count skip them; the Arch and Flatpak packages list their files and never had them. The ladder example takes a role per model, which is how the per-role forms above were seen landing on the NPU from the real probe.
This commit is contained in:
@@ -30,7 +30,8 @@ pub struct MiGan {
|
||||
|
||||
impl MiGan {
|
||||
/// From the model file, in whichever form the engine's rung wants
|
||||
/// (`resolve_model` picks an int8 sibling for the Hexagon).
|
||||
/// (`resolve_model` picks the `.a16w16.onnx` sibling on the Hexagon:
|
||||
/// int8 moved the fill 16 dB from f32's, 16-bit about 41).
|
||||
pub fn from_path(path: &std::path::Path) -> Result<Self, PanoError> {
|
||||
use dr_inference_engine::{resolve_model, Role};
|
||||
let (path, form) = resolve_model(Role::Inpainter, path);
|
||||
|
||||
@@ -36,18 +36,49 @@ pub struct XFeat {
|
||||
pub options: DecodeOptions,
|
||||
}
|
||||
|
||||
/// The bytes of both exports compiled into the binary, for whoever compiles
|
||||
/// engines ahead of the first request (docs/dev/inference.md §6).
|
||||
/// The Hexagon's forms (docs/dev/inference.md §1.5): int8, from the same
|
||||
/// network spelled for the HTP (the unfold as SpaceToDepth, the bilinear
|
||||
/// resizes as matrix products). Only Android has a Hexagon.
|
||||
#[cfg(all(feature = "embedded-model", target_os = "android"))]
|
||||
const EMBEDDED_LANDSCAPE_INT8: &[u8] =
|
||||
include_bytes!("../../../models/keypoints/xfeat-1024.int8.onnx");
|
||||
#[cfg(all(feature = "embedded-model", target_os = "android"))]
|
||||
const EMBEDDED_PORTRAIT_INT8: &[u8] =
|
||||
include_bytes!("../../../models/keypoints/xfeat-768.int8.onnx");
|
||||
|
||||
/// Every form of both exports compiled into the binary, landscape then
|
||||
/// portrait, for whoever compiles engines ahead of the first request
|
||||
/// (docs/dev/inference.md §6).
|
||||
#[cfg(feature = "embedded-model")]
|
||||
pub fn embedded_model_bytes() -> [&'static [u8]; 2] {
|
||||
[EMBEDDED_LANDSCAPE, EMBEDDED_PORTRAIT]
|
||||
pub fn embedded_models() -> [Vec<(dr_inference_engine::Form, &'static [u8])>; 2] {
|
||||
use dr_inference_engine::Form;
|
||||
#[allow(unused_mut)]
|
||||
let mut forms = [
|
||||
vec![(Form::F32, EMBEDDED_LANDSCAPE)],
|
||||
vec![(Form::F32, EMBEDDED_PORTRAIT)],
|
||||
];
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
forms[0].push((Form::Int8, EMBEDDED_LANDSCAPE_INT8));
|
||||
forms[1].push((Form::Int8, EMBEDDED_PORTRAIT_INT8));
|
||||
}
|
||||
forms
|
||||
}
|
||||
|
||||
impl XFeat {
|
||||
/// The weights compiled into the binary.
|
||||
/// The weights compiled into the binary, in the form the device's
|
||||
/// backend runs.
|
||||
#[cfg(feature = "embedded-model")]
|
||||
pub fn embedded() -> Result<Self, PanoError> {
|
||||
Self::from_bytes(EMBEDDED_LANDSCAPE, EMBEDDED_PORTRAIT)
|
||||
use dr_inference_engine::{choose_embedded, open, Role};
|
||||
let [l, p] = embedded_models();
|
||||
let (l, lf) = choose_embedded(Role::Keypoints, &l);
|
||||
let (p, pf) = choose_embedded(Role::Keypoints, &p);
|
||||
Ok(XFeat {
|
||||
landscape: open(Role::Keypoints, lf, l)?,
|
||||
portrait: open(Role::Keypoints, pf, p)?,
|
||||
options: DecodeOptions::default(),
|
||||
})
|
||||
}
|
||||
|
||||
/// From the two exports on disk.
|
||||
|
||||
Reference in New Issue
Block a user