Remove backend experiment notes from the published model repository
Browse files- README.md +2 -6
- vulkan/NOTES.md +0 -90
- xnnpack/NOTES.md +0 -119
README.md
CHANGED
|
@@ -48,15 +48,13 @@ These measure export agreement, not accuracy against ground-truth masks.
|
|
| 48 |
Choose FP32 when boundary precision matters.
|
| 49 |
|
| 50 |
Full-network INT8 remains unpublished because it loses substantial foreground
|
| 51 |
-
detail.
|
| 52 |
-
calibration, validation and rejected alternatives.
|
| 53 |
|
| 54 |
Vulkan FP16 preserves input normalization and one sensitive convolution in FP32.
|
| 55 |
On a Galaxy S20+ (Android 13, Mali), native forward medians were 337 ms for this
|
| 56 |
variant, versus 316 ms for XNNPACK FP32 and 189 ms for selective INT8. Android uses the standard Vulkan-first default when the Vulkan backend is
|
| 57 |
linked. Performance varies by device. Across 13 device-tested images, Vulkan FP16 averaged 0.9945 mask IoU
|
| 58 |
-
against FP32 (minimum 0.9854).
|
| 59 |
-
for the export recipe, phone validation and timing limitations.
|
| 60 |
|
| 61 |
## Repository structure
|
| 62 |
|
|
@@ -66,10 +64,8 @@ coreml/config.json 1.5 kB
|
|
| 66 |
coreml/u2netp_coreml_fp16.pte 3.3 MB
|
| 67 |
coreml/u2netp_coreml_fp32.pte 5.5 MB
|
| 68 |
vulkan/config.json 886 B
|
| 69 |
-
vulkan/NOTES.md 4.1 kB
|
| 70 |
vulkan/u2netp_vulkan_fp16.pte 2.4 MB
|
| 71 |
xnnpack/config.json 1.5 kB
|
| 72 |
-
xnnpack/NOTES.md 6.6 kB
|
| 73 |
xnnpack/u2netp_xnnpack_fp32.pte 4.6 MB
|
| 74 |
xnnpack/u2netp_xnnpack_int8.pte 4.0 MB
|
| 75 |
LICENSE 11.4 kB
|
|
|
|
| 48 |
Choose FP32 when boundary precision matters.
|
| 49 |
|
| 50 |
Full-network INT8 remains unpublished because it loses substantial foreground
|
| 51 |
+
detail.
|
|
|
|
| 52 |
|
| 53 |
Vulkan FP16 preserves input normalization and one sensitive convolution in FP32.
|
| 54 |
On a Galaxy S20+ (Android 13, Mali), native forward medians were 337 ms for this
|
| 55 |
variant, versus 316 ms for XNNPACK FP32 and 189 ms for selective INT8. Android uses the standard Vulkan-first default when the Vulkan backend is
|
| 56 |
linked. Performance varies by device. Across 13 device-tested images, Vulkan FP16 averaged 0.9945 mask IoU
|
| 57 |
+
against FP32 (minimum 0.9854).
|
|
|
|
| 58 |
|
| 59 |
## Repository structure
|
| 60 |
|
|
|
|
| 64 |
coreml/u2netp_coreml_fp16.pte 3.3 MB
|
| 65 |
coreml/u2netp_coreml_fp32.pte 5.5 MB
|
| 66 |
vulkan/config.json 886 B
|
|
|
|
| 67 |
vulkan/u2netp_vulkan_fp16.pte 2.4 MB
|
| 68 |
xnnpack/config.json 1.5 kB
|
|
|
|
| 69 |
xnnpack/u2netp_xnnpack_fp32.pte 4.6 MB
|
| 70 |
xnnpack/u2netp_xnnpack_int8.pte 4.0 MB
|
| 71 |
LICENSE 11.4 kB
|
vulkan/NOTES.md
DELETED
|
@@ -1,90 +0,0 @@
|
|
| 1 |
-
# Vulkan precision and Android validation
|
| 2 |
-
|
| 3 |
-
The published FP16 variant accepts RGB float32 `[1,3,320,320]` in `[0,1]` and returns float32
|
| 4 |
-
`[1,1,320,320]` foreground logits. Input normalization stays in FP32. The
|
| 5 |
-
export contains one Vulkan delegate for the network and one portable input
|
| 6 |
-
`amax` reduction. Texture limits are capped at 2048 in each dimension.
|
| 7 |
-
|
| 8 |
-
## FP16 with a sensitive FP32 convolution
|
| 9 |
-
|
| 10 |
-
The FP16 export fuses Conv/BatchNorm pairs before casting the network to half.
|
| 11 |
-
`stage2d.rebnconv1d.conv_s1` retains FP32 weights, bias and computation, with
|
| 12 |
-
casts around it inside the Vulkan delegate. Global `force_fp16` is deliberately
|
| 13 |
-
not used: it would also downcast this convolution and input normalization.
|
| 14 |
-
|
| 15 |
-
On the connected Galaxy S20+, an entirely FP16 export changed the bicycle mask
|
| 16 |
-
to 0.9418 IoU against XNNPACK FP32. Keeping this convolution in FP32 recovered
|
| 17 |
-
0.9932 IoU. The entirely FP16 candidate is not published.
|
| 18 |
-
|
| 19 |
-
## Device checks
|
| 20 |
-
|
| 21 |
-
Validation used Samsung Galaxy S20+ SM-G986B, Android 13, Mali GPU, arm64-v8a,
|
| 22 |
-
and the ExecuTorch 1.4.1 runtime/backend libraries shipped with RNE. A native
|
| 23 |
-
runner linked these exact libraries, loaded each actual `.pte`, checked float32
|
| 24 |
-
output type and element count, rejected non-finite output, and saved logits.
|
| 25 |
-
Exported method metadata was also checked against the config.
|
| 26 |
-
|
| 27 |
-
The comparison set is the same 13 images used for selective XNNPACK INT8
|
| 28 |
-
validation: `bike.jpg`, `boat.jpg`, `whisk.png`, plus COCO val2017 image IDs 139,
|
| 29 |
-
285, 632, 724, 776, 785, 802, 872, 885 and 1000. All-black and all-white inputs
|
| 30 |
-
were also checked. These are agreement measurements against the shipped
|
| 31 |
-
XNNPACK FP32 `.pte`, not ground-truth segmentation accuracy.
|
| 32 |
-
|
| 33 |
-
| Variant | Mean mask IoU (13 images) | Minimum mask IoU | File size |
|
| 34 |
-
| --- | --- | --- | --- |
|
| 35 |
-
| Vulkan FP16 with one FP32 convolution | 0.9945 | 0.9854 | 2,437,516 B |
|
| 36 |
-
|
| 37 |
-
The FP16 probability MAE was at most 0.00444 across those 13 images. The published
|
| 38 |
-
variant produced finite outputs on all 15 inputs.
|
| 39 |
-
|
| 40 |
-
Warm native forward measurements on the same bicycle input used three warm-up
|
| 41 |
-
runs followed by ten measured runs per variant:
|
| 42 |
-
|
| 43 |
-
| Variant | Median |
|
| 44 |
-
| --- | --- |
|
| 45 |
-
| XNNPACK FP32 | 315.6 ms |
|
| 46 |
-
| XNNPACK selective INT8 | 189.1 ms |
|
| 47 |
-
| Vulkan FP16 with one FP32 convolution | 337.2 ms |
|
| 48 |
-
| Vulkan FP32 (unpublished trial) | 403.1 ms |
|
| 49 |
-
|
| 50 |
-
These were sequential host-driven device checks, not interleaved benchmarks;
|
| 51 |
-
they exclude model loading, image preprocessing and rendering. Vulkan does not
|
| 52 |
-
win on this older Mali GPU. Android uses the standard Vulkan-first default
|
| 53 |
-
when the Vulkan backend is linked. Select XNNPACK INT8 for the faster option
|
| 54 |
-
on this tested phone; performance varies by device. A trial with only four half-precision convolutions was
|
| 55 |
-
also slower (421.9 ms) and is not published.
|
| 56 |
-
|
| 57 |
-
## Reproducing the export environment
|
| 58 |
-
|
| 59 |
-
The Vulkan AOT implementation is pinned to software-mansion-labs/executorch
|
| 60 |
-
`@ms/separate-backends-1.4.1`, commit
|
| 61 |
-
`0de5ce9470e4a18d6d45585f69519267bbe218b9`. Torch is 2.14.0. The nested
|
| 62 |
-
`pyproject.toml` records the fork dependency; see the repository Vulkan skill
|
| 63 |
-
for the source-built environment used by other Vulkan models.
|
| 64 |
-
|
| 65 |
-
For AOT-only export, a compatible ExecuTorch 1.4.1 wheel can provide the common
|
| 66 |
-
serialization binaries while the fork supplies its Vulkan Python package.
|
| 67 |
-
No host GPU runtime is needed; Android validation still uses the shipped native
|
| 68 |
-
Vulkan library. Clone the fork into a directory named `executorch`, check out
|
| 69 |
-
the commit above, then from export-scripts run:
|
| 70 |
-
|
| 71 |
-
```bash
|
| 72 |
-
uv run --project exporter_models/u2netp python - /path/to/executorch <<'PY'
|
| 73 |
-
import runpy
|
| 74 |
-
import sys
|
| 75 |
-
from pathlib import Path
|
| 76 |
-
import executorch.backends
|
| 77 |
-
|
| 78 |
-
fork = Path(sys.argv[1]).resolve()
|
| 79 |
-
executorch.backends.__path__.insert(0, str(fork / "backends"))
|
| 80 |
-
sys.argv = [
|
| 81 |
-
"exporter", "export", "u2netp", "--backend", "vulkan", "--all-variants",
|
| 82 |
-
"--output-dir", "exports/u2netp/vulkan",
|
| 83 |
-
]
|
| 84 |
-
runpy.run_module("exporter.cli", run_name="__main__")
|
| 85 |
-
PY
|
| 86 |
-
```
|
| 87 |
-
|
| 88 |
-
The release FP16 export was byte-identical to the device-validated candidate.
|
| 89 |
-
The Python wheel's native runtime cannot execute Vulkan on this Mac; it was
|
| 90 |
-
not used as a substitute for phone validation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xnnpack/NOTES.md
DELETED
|
@@ -1,119 +0,0 @@
|
|
| 1 |
-
# XNNPACK precision experiments
|
| 2 |
-
|
| 3 |
-
FP32 and selective INT8 are published. Full-network static INT8, an earlier
|
| 4 |
-
mixed INT8/FP32 recipe and FP16 were rejected because they changed the masks.
|
| 5 |
-
|
| 6 |
-
## Selective INT8 (published)
|
| 7 |
-
|
| 8 |
-
The final recipe quantizes only `stage1d.rebnconvin`, `stage1d.rebnconv1d`,
|
| 9 |
-
`stage2d.rebnconvin` and `stage2.rebnconvin`. These convolutions dominate host
|
| 10 |
-
latency. Remaining convolutions, concatenations and residual additions stay
|
| 11 |
-
FP32. Public I/O and normalization are unchanged.
|
| 12 |
-
|
| 13 |
-
PT2E uses per-channel symmetric INT8 weights and per-tensor affine INT8
|
| 14 |
-
activations with HistogramObserver. The weight observer minimum scale is
|
| 15 |
-
float32 epsilon. Calibration uses the same 13 pinned upstream images listed
|
| 16 |
-
below. Export scripts download these images automatically.
|
| 17 |
-
|
| 18 |
-
ExecuTorch 1.4.1's concatenation annotator ignores its filter argument, so
|
| 19 |
-
module exclusions alone do not keep skip connections in FP32. The export
|
| 20 |
-
selects only convolution operators, with an explicit module filter. Weight
|
| 21 |
-
attributes are allowed through this filter because they lack module-stack
|
| 22 |
-
metadata. This avoids quantizing unrelated concatenations.
|
| 23 |
-
|
| 24 |
-
Actual `.pte` execution was checked against the published FP32 `.pte` on the
|
| 25 |
-
three upstream images below plus ten COCO val2017 images, IDs 139, 285, 632,
|
| 26 |
-
724, 776, 785, 802, 872, 885 and 1000. None was used for calibration. Average
|
| 27 |
-
mask IoU was 0.9953, minimum 0.9868; probability MAE ranged from 0.00015 to
|
| 28 |
-
0.00543. All-black and all-white inputs also produced finite outputs.
|
| 29 |
-
|
| 30 |
-
| Image | Selective INT8 mask IoU | Probability MAE |
|
| 31 |
-
| ----------- | ---------------------- | --------------- |
|
| 32 |
-
| `bike.jpg` | 0.9947 | 0.00158 |
|
| 33 |
-
| `boat.jpg` | 0.9956 | 0.00152 |
|
| 34 |
-
| `whisk.png` | 0.9992 | 0.00055 |
|
| 35 |
-
|
| 36 |
-
On an Apple M1 Pro, 30 interleaved ExecuTorch runs after five warm-ups measured
|
| 37 |
-
156.0 ms median for FP32 and 87.4 ms for selective INT8 (1.78× faster). File
|
| 38 |
-
sizes were 4,610,948 and 4,007,684 bytes. These are host measurements, exclude
|
| 39 |
-
RNE preprocessing/rendering, and need on-device confirmation. This small
|
| 40 |
-
sample measures conversion agreement, not ground-truth segmentation accuracy.
|
| 41 |
-
|
| 42 |
-
The event-traced ExecuTorch 1.4.1 runtime and cloned profiler confirmed all
|
| 43 |
-
four selected convolutions execute as quantized XNNPACK kernels. Over five
|
| 44 |
-
real-input executions, the delegate accounted for 99.36% of method time and
|
| 45 |
-
the portable input `amax` for 0.63%.
|
| 46 |
-
|
| 47 |
-
## Static INT8
|
| 48 |
-
|
| 49 |
-
The experiment used PT2E `prepare_pt2e` / `convert_pt2e`,
|
| 50 |
-
`XNNPACKQuantizer`, and `get_symmetric_quantization_config(is_per_channel=True)`:
|
| 51 |
-
static INT8 activations with per-channel INT8 weights. Public inputs and
|
| 52 |
-
outputs remained float32. The export included the same image-maximum and
|
| 53 |
-
ImageNet normalization as FP32, and returned foreground logits before sigmoid.
|
| 54 |
-
|
| 55 |
-
Calibration used 13 RGB images from the upstream repository at commit
|
| 56 |
-
`ac7e1c817ecab7c7dff5ce6b1abba61cd213ff29`, resized to 320×320:
|
| 57 |
-
`0002-01.jpg`, `0003.jpg`, `girl.png`, `hockey.png`, `horse.jpg`, `im_01.png`,
|
| 58 |
-
`im_14.png`, `im_21.png`, `im_27.png`, `lamp2_meitu_1.jpg`, `long.jpg`,
|
| 59 |
-
`rifle1.jpg`, and `sailboat3.jpg`.
|
| 60 |
-
|
| 61 |
-
The three images below were held out from calibration. Results compare actual
|
| 62 |
-
ExecuTorch `.pte` execution against the shipped FP32 `.pte`. Mask IoU uses a
|
| 63 |
-
foreground-probability threshold of 0.5; MAE is measured after sigmoid in [0,1].
|
| 64 |
-
These measure conversion agreement, not accuracy against ground-truth masks.
|
| 65 |
-
|
| 66 |
-
| Image | Static INT8 mask IoU | Static INT8 probability MAE | Mixed INT8 mask IoU | Mixed INT8 probability MAE |
|
| 67 |
-
| ----------- | -------------------- | --------------------------- | ------------------- | -------------------------- |
|
| 68 |
-
| `bike.jpg` | 0.6692 | 0.09813 | 0.9629 | 0.01421 |
|
| 69 |
-
| `boat.jpg` | 0.8703 | 0.04655 | 0.9410 | 0.02156 |
|
| 70 |
-
| `whisk.png` | 0.9387 | 0.06170 | 0.9945 | 0.00458 |
|
| 71 |
-
|
| 72 |
-
Static INT8 is smaller and faster, but loses substantial foreground detail.
|
| 73 |
-
Those mask changes outweigh the size and latency improvements.
|
| 74 |
-
|
| 75 |
-
## Mixed INT8/FP32
|
| 76 |
-
|
| 77 |
-
The earlier candidate excluded convolutions in `stage1`, `stage2`, `stage1d`,
|
| 78 |
-
`stage2d`, `side1`, `side2`, and `outconv`, using the same calibration data.
|
| 79 |
-
The concatenation-filter issue described above still quantized skip connections,
|
| 80 |
-
including those inside excluded modules. Agreement improved, but the boat mask
|
| 81 |
-
still fell to 0.9410 IoU and the latency gain was small. This candidate is not
|
| 82 |
-
published. The selective recipe above replaces this approach.
|
| 83 |
-
|
| 84 |
-
## Host size and latency
|
| 85 |
-
|
| 86 |
-
Interleaved measurements used the same bicycle input, three warm-up calls,
|
| 87 |
-
then 20 executions per candidate through ExecuTorch on an Apple M1 Pro running
|
| 88 |
-
macOS 26.5.2, with torch 2.14.0, ExecuTorch 1.4.1 and torchao 0.18.0.
|
| 89 |
-
|
| 90 |
-
| Candidate | File size | Median inference |
|
| 91 |
-
| -------------------------- | --------- | ---------------- |
|
| 92 |
-
| FP32 (published) | 4.61 MB | 217 ms |
|
| 93 |
-
| Static INT8 (rejected) | 1.36 MB | 64 ms |
|
| 94 |
-
| Mixed INT8/FP32 (rejected) | 2.61 MB | 215 ms |
|
| 95 |
-
|
| 96 |
-
Other export/build work was running on the host, so these are indicative
|
| 97 |
-
comparisons rather than isolated device benchmarks. They exclude RNE image
|
| 98 |
-
preprocessing and rendering. The small calibration/validation sample does not
|
| 99 |
-
prove that every quantization strategy is unsuitable; it establishes why these
|
| 100 |
-
particular candidates were not shipped. A future attempt needs more calibration
|
| 101 |
-
coverage and a larger independent quality evaluation before publication.
|
| 102 |
-
|
| 103 |
-
## FP16 trial
|
| 104 |
-
|
| 105 |
-
An XNNPACK FP16 candidate kept input normalization and public I/O in FP32 and
|
| 106 |
-
fused each Conv/BatchNorm pair before converting the network to FP16. Eager
|
| 107 |
-
agreement looked promising, but the actual exported runtime shifted the bicycle
|
| 108 |
-
mask to 0.9549 IoU (probability MAE 0.01111) against the shipped FP32 model.
|
| 109 |
-
It is not published either. This result is specific to the XNNPACK FP16
|
| 110 |
-
candidate; the published CoreML FP16 artifact was validated separately.
|
| 111 |
-
|
| 112 |
-
## Delegation
|
| 113 |
-
|
| 114 |
-
A local event-traced ExecuTorch 1.4.1 build and `executorch-profiler` measured
|
| 115 |
-
five FP32 executions: 99.68% of elapsed time was inside the XNNPACK delegate and
|
| 116 |
-
0.31% was the portable `amax` input reduction. Convolution dominated execution.
|
| 117 |
-
These are timing shares, not a count of delegated graph operators. Removing
|
| 118 |
-
the reduction would not address the main cost and would change the upstream
|
| 119 |
-
image-dependent input normalization.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|