volvoxai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/bin/volvox.js +72 -0
  4. package/dist/v0.1.0/volvoxai.js +4664 -0
  5. package/dist/v0.1.0/volvoxai.min.js +1848 -0
  6. package/dist/v0.1.0/volvoxai.wasm +0 -0
  7. package/dist/volvoxai.js +4664 -0
  8. package/dist/volvoxai.min.js +1848 -0
  9. package/dist/volvoxai.wasm +0 -0
  10. package/docs/README.md +22 -0
  11. package/docs/browser-runtime.md +87 -0
  12. package/docs/efficientdet_tflite_vs_volvoxai.md +445 -0
  13. package/docs/microkernel_optimization_guide.md +153 -0
  14. package/docs/model-format.md +108 -0
  15. package/docs/models.md +103 -0
  16. package/docs/native-runtime.md +189 -0
  17. package/docs/operation_list.md +232 -0
  18. package/docs/operator_fusion_patterns.md +58 -0
  19. package/docs/quickstart.md +115 -0
  20. package/docs/roadmap.md +19 -0
  21. package/docs/testing.md +97 -0
  22. package/docs/textbook/01-foundations.md +233 -0
  23. package/docs/textbook/02-tinystories-language-model.md +300 -0
  24. package/docs/textbook/03-efficientdet-vision-model.md +281 -0
  25. package/docs/textbook/04-precision-and-quantization.md +208 -0
  26. package/docs/textbook/05-inside-the-engine.md +155 -0
  27. package/docs/textbook/06-native-engine-architecture.md +338 -0
  28. package/docs/textbook/07-glossary-and-next-steps.md +258 -0
  29. package/docs/textbook/README.md +85 -0
  30. package/docs/textbook/ko/01-foundations.md +231 -0
  31. package/docs/textbook/ko/02-tinystories-language-model.md +300 -0
  32. package/docs/textbook/ko/03-efficientdet-vision-model.md +277 -0
  33. package/docs/textbook/ko/04-precision-and-quantization.md +206 -0
  34. package/docs/textbook/ko/05-inside-the-engine.md +154 -0
  35. package/docs/textbook/ko/06-native-engine-architecture.md +333 -0
  36. package/docs/textbook/ko/07-glossary-and-next-steps.md +253 -0
  37. package/docs/textbook/ko/README.md +83 -0
  38. package/docs/xnnpack_optimization_guide.md +197 -0
  39. package/js/CPUEngine.js +241 -0
  40. package/js/Graph.js +49 -0
  41. package/js/GraphExecutor.js +1020 -0
  42. package/js/GraphLoader.js +282 -0
  43. package/js/ShaderLibrary.js +236 -0
  44. package/js/Tensor.js +25 -0
  45. package/js/Tokenizer.js +266 -0
  46. package/js/VolvoxAI.js +130 -0
  47. package/js/WasmEngine.js +378 -0
  48. package/js/WebNNEngine.js +169 -0
  49. package/js/index.js +11 -0
  50. package/js/ops/add.js +31 -0
  51. package/js/ops/argMax.js +33 -0
  52. package/js/ops/averagePool2D.js +38 -0
  53. package/js/ops/batchNorm2D.js +28 -0
  54. package/js/ops/cast.js +19 -0
  55. package/js/ops/clip.js +15 -0
  56. package/js/ops/concat2.js +18 -0
  57. package/js/ops/conv1D.js +35 -0
  58. package/js/ops/conv2D.js +70 -0
  59. package/js/ops/convTranspose2D.js +45 -0
  60. package/js/ops/crossAttention.js +69 -0
  61. package/js/ops/crossSDPA.js +41 -0
  62. package/js/ops/dequantizeLinear.js +9 -0
  63. package/js/ops/div.js +15 -0
  64. package/js/ops/embedding.js +14 -0
  65. package/js/ops/expand.js +24 -0
  66. package/js/ops/gELU.js +9 -0
  67. package/js/ops/gather.js +51 -0
  68. package/js/ops/gatherElements.js +33 -0
  69. package/js/ops/globalAveragePool.js +21 -0
  70. package/js/ops/hardSigmoid.js +12 -0
  71. package/js/ops/hardSwish.js +12 -0
  72. package/js/ops/interp1D.js +25 -0
  73. package/js/ops/layerNorm.js +25 -0
  74. package/js/ops/leakyReLU.js +10 -0
  75. package/js/ops/logSoftmax.js +15 -0
  76. package/js/ops/matMul.js +35 -0
  77. package/js/ops/maxPool2D.js +36 -0
  78. package/js/ops/meanHeight.js +17 -0
  79. package/js/ops/mul.js +31 -0
  80. package/js/ops/nonMaxSuppression.js +72 -0
  81. package/js/ops/pReLU.js +11 -0
  82. package/js/ops/pad.js +35 -0
  83. package/js/ops/profileX.js +22 -0
  84. package/js/ops/profileY.js +22 -0
  85. package/js/ops/rMSNorm.js +14 -0
  86. package/js/ops/reLU.js +8 -0
  87. package/js/ops/reduceMean.js +17 -0
  88. package/js/ops/reduceSum.js +19 -0
  89. package/js/ops/reshape.js +6 -0
  90. package/js/ops/resize.js +44 -0
  91. package/js/ops/sDPA.js +44 -0
  92. package/js/ops/siLU.js +8 -0
  93. package/js/ops/sigmoid.js +6 -0
  94. package/js/ops/slice.js +36 -0
  95. package/js/ops/softmax.js +18 -0
  96. package/js/ops/spatialSoftargmaxY.js +28 -0
  97. package/js/ops/split.js +24 -0
  98. package/js/ops/sub.js +11 -0
  99. package/js/ops/tanh.js +7 -0
  100. package/js/ops/transpose.js +34 -0
  101. package/js/ops/upsample2x.js +23 -0
  102. package/js/ops/where.js +15 -0
  103. package/package.json +33 -0
  104. package/shaders/add.wgsl +13 -0
  105. package/shaders/add3Relu.wgsl +23 -0
  106. package/shaders/addRelu.wgsl +22 -0
  107. package/shaders/averagePool2D.wgsl +24 -0
  108. package/shaders/batchNorm2D.wgsl +21 -0
  109. package/shaders/binaryBroadcast.wgsl +34 -0
  110. package/shaders/broadcastBinary.wgsl +26 -0
  111. package/shaders/clip.wgsl +10 -0
  112. package/shaders/concat2.wgsl +16 -0
  113. package/shaders/concatCopy.wgsl +10 -0
  114. package/shaders/concatSigmoidCopy.wgsl +16 -0
  115. package/shaders/conv1D.wgsl +37 -0
  116. package/shaders/conv2D.wgsl +80 -0
  117. package/shaders/conv2DDepthwise4.wgsl +74 -0
  118. package/shaders/conv2DDepthwise8.wgsl +66 -0
  119. package/shaders/conv2DPointwise16.wgsl +67 -0
  120. package/shaders/conv2DPointwise16Tile.wgsl +86 -0
  121. package/shaders/conv2DPointwise8.wgsl +85 -0
  122. package/shaders/conv2DPointwise8Vec2.wgsl +70 -0
  123. package/shaders/conv2DPointwise8Vec4.wgsl +65 -0
  124. package/shaders/conv2DRegularC3Out16.wgsl +75 -0
  125. package/shaders/convTranspose2D.wgsl +33 -0
  126. package/shaders/copy.wgsl +13 -0
  127. package/shaders/crossAttention.wgsl +140 -0
  128. package/shaders/crossAttentionF32.wgsl +98 -0
  129. package/shaders/crossSDPA.wgsl +74 -0
  130. package/shaders/dequantizeLinear.wgsl +14 -0
  131. package/shaders/div.wgsl +34 -0
  132. package/shaders/elementwise.wgsl +13 -0
  133. package/shaders/embedding.wgsl +22 -0
  134. package/shaders/expand.wgsl +18 -0
  135. package/shaders/gELU.wgsl +13 -0
  136. package/shaders/gather.wgsl +17 -0
  137. package/shaders/generalTranspose.wgsl +19 -0
  138. package/shaders/globalAveragePool.wgsl +19 -0
  139. package/shaders/hardSigmoid.wgsl +13 -0
  140. package/shaders/hardSwish.wgsl +13 -0
  141. package/shaders/interp1D.wgsl +28 -0
  142. package/shaders/layerNorm.wgsl +33 -0
  143. package/shaders/leakyReLU.wgsl +11 -0
  144. package/shaders/linearF32.wgsl +33 -0
  145. package/shaders/linearF32RowMajor.wgsl +24 -0
  146. package/shaders/linearInt8.wgsl +42 -0
  147. package/shaders/logSoftmax.wgsl +22 -0
  148. package/shaders/maxPool2D.wgsl +37 -0
  149. package/shaders/meanHeight.wgsl +18 -0
  150. package/shaders/mul.wgsl +32 -0
  151. package/shaders/nonMaxSuppression.wgsl +92 -0
  152. package/shaders/pReLU.wgsl +14 -0
  153. package/shaders/pad.wgsl +19 -0
  154. package/shaders/profileX.wgsl +28 -0
  155. package/shaders/profileY.wgsl +28 -0
  156. package/shaders/quantizeLinear.wgsl +69 -0
  157. package/shaders/rMSNorm.wgsl +21 -0
  158. package/shaders/reLU.wgsl +13 -0
  159. package/shaders/reduce.wgsl +17 -0
  160. package/shaders/resize.wgsl +52 -0
  161. package/shaders/sDPA.wgsl +71 -0
  162. package/shaders/siLU.wgsl +13 -0
  163. package/shaders/sigmoid.wgsl +13 -0
  164. package/shaders/slice.wgsl +26 -0
  165. package/shaders/softmax.wgsl +23 -0
  166. package/shaders/spatialSoftargmaxY.wgsl +32 -0
  167. package/shaders/split.wgsl +15 -0
  168. package/shaders/sub.wgsl +34 -0
  169. package/shaders/tanh.wgsl +13 -0
  170. package/shaders/upsample2x.wgsl +24 -0
  171. package/shaders/where.wgsl +12 -0
  172. package/volvoxai.wasm +0 -0
Binary file
package/docs/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # VolvoxAI Documentation
2
+
3
+ This directory holds the detailed reference material for VolvoxAI. Start with
4
+ the root [README](../README.md) for the short overview, then use these pages for
5
+ the implementation details.
6
+
7
+ | Doc | What it covers |
8
+ | --- | --- |
9
+ | [quickstart.md](quickstart.md) | Build commands, browser bundle, CLI smoke tests, and model download commands. |
10
+ | [browser-runtime.md](browser-runtime.md) | Browser and Node runtime tiers: WebNN, WebGPU, WASM SIMD, and CPU. |
11
+ | [native-runtime.md](native-runtime.md) | Native C engine, native CLI tasks, GPU/NPU backends, Android cross-build notes. |
12
+ | [model-format.md](model-format.md) | Volvox blueprint format, safetensors loading, tensor layout, precision policy. |
13
+ | [models.md](models.md) | Regenerating EfficientDet, TinyStories, and TinyReceiptKIE model packages. |
14
+ | [operation_list.md](operation_list.md) | Per-op backend support matrix for browser and native runtimes. |
15
+ | [testing.md](testing.md) | WebGPU op tests, native smoke tests, parity checks, and known validation limits. |
16
+ | [roadmap.md](roadmap.md) | Current gaps and planned work. |
17
+ | [textbook/](textbook/README.md) | A from-scratch walkthrough of inference, tensors, models, and engine internals. |
18
+ | [efficientdet_tflite_vs_volvoxai.md](efficientdet_tflite_vs_volvoxai.md) | EfficientDet Lite0 CPU/GPU benchmark methodology and results. |
19
+ | [microkernel_optimization_guide.md](microkernel_optimization_guide.md) | CPU Conv/GEMM microkernel notes. |
20
+ | [operator_fusion_patterns.md](operator_fusion_patterns.md) | Graph fusion patterns applied by the native optimizer. |
21
+ | [xnnpack_optimization_guide.md](xnnpack_optimization_guide.md) | XNNPACK-style packing and indirection reference notes. |
22
+
@@ -0,0 +1,87 @@
1
+ # Browser and Node Runtime
2
+
3
+ VolvoxAI exposes one browser API and chooses the best available execution tier at
4
+ initialization and compilation time.
5
+
6
+ ## Backend Selection
7
+
8
+ `VolvoxAI.init(preferredBackend = "auto", wasmUrl = "./volvoxai.wasm")` accepts a
9
+ backend string or a strict ordered backend array.
10
+
11
+ | Call | Behavior |
12
+ | --- | --- |
13
+ | `VolvoxAI.init()` or `VolvoxAI.init("auto")` | Try WebNN, then WebGPU, then WASM, then CPU. |
14
+ | `VolvoxAI.init("webnn")` | Prefer WebNN; fall back to WASM then CPU. |
15
+ | `VolvoxAI.init("webgpu")` | Prefer WebGPU; fall back to WASM then CPU. |
16
+ | `VolvoxAI.init("wasm")` | Skip WebNN/WebGPU and use WASM with CPU fallback. |
17
+ | `VolvoxAI.init("cpu")` | CPU only. |
18
+ | `VolvoxAI.init(["wasm", "webgpu"])` | Strict allow-list. No CPU fallback unless `"cpu"` is included. |
19
+
20
+ Array mode is strict. `init()` throws if none of the listed backends initializes,
21
+ and `compile()` throws if the initialized backends cannot compile the graph.
22
+
23
+ ## Tier 1: WebNN
24
+
25
+ `WebNNEngine` builds an `MLGraphBuilder` graph and dispatches through
26
+ `navigator.ml`. The browser may route work to NPU, GPU, or CPU depending on the
27
+ platform, browser flags, drivers, and supported ops.
28
+
29
+ Current WebNN coverage:
30
+
31
+ `MatMul`/`Linear`/`Gemm`, `Add`, `Mul`, `ReLU`, `GELU`, `SiLU`/`Swish`,
32
+ `Sigmoid`, `Softmax`, `Reshape`/`Flatten`, `LayerNorm`, `Conv2D`,
33
+ `Embedding`, and `SDPA` decomposed into lower-level WebNN ops.
34
+
35
+ Missing low-cost mappings include `Sub`, `Div`, `Tanh`, `Clip`, `LeakyReLU`,
36
+ `PReLU`, `HardSwish`, `HardSigmoid`, `Transpose`, `Concat`, `Split`, `Slice`,
37
+ `Pad`, `Where`, `Gather`, `Cast`, `Expand`, reductions, pooling, batch norm,
38
+ resampling, and `ConvTranspose2D`.
39
+
40
+ Missing composite formulas include `RMSNorm`, `CrossSDPA`, `CrossAttention`,
41
+ `LogSoftmax`, `DequantizeLinear`, and `Conv1D` as a reshape plus `conv2d`.
42
+
43
+ WebNN requires a secure context such as HTTPS or localhost. Chromium WebNN support
44
+ is evolving and often needs `--enable-features=WebMachineLearningNeuralNetwork`.
45
+ `deviceType: "npu"` is not proof that an NPU executed the work; unsupported
46
+ accelerators can fall back to CPU.
47
+
48
+ Useful references:
49
+
50
+ - W3C WebNN: <https://www.w3.org/TR/webnn/>
51
+ - WebNN compatibility: <https://webnn.io/en/api-reference/browser-compatibility/api>
52
+ - Chromium flags: <https://webnn.io/en/api-reference/browser-compatibility/chrome-flags>
53
+
54
+ ## Tier 2: WebGPU
55
+
56
+ `GraphExecutor` allocates one GPU buffer per tensor, uploads weights once, and
57
+ builds one compute pipeline per node. `execute()` replays the prebuilt pipelines in
58
+ one command encoder, flushing every 20 dispatches.
59
+
60
+ The WebGPU path keeps the model resident on the GPU and returns a `GPUBuffer`.
61
+ Current limitation: it returns the final node's first output rather than a map of
62
+ all `graph.outputNames`. Multi-output models should use WASM/CPU until WebGPU
63
+ multi-output readback is implemented.
64
+
65
+ Unsupported WebGPU shader nodes currently warn and skip, leaving the output buffer
66
+ unwritten. Use [operation_list.md](operation_list.md) to check whether a model's
67
+ ops are safe on WebGPU.
68
+
69
+ ## Tier 3: WASM SIMD
70
+
71
+ `WasmEngine` loads the freestanding `volvoxai.wasm` module built from
72
+ `native/kernels.c`. It uses a bump allocator over `__heap_base` and places graph
73
+ tensors in WASM linear memory. Some pointwise, broadcast, and gather operations are
74
+ handled in JS over typed-array views into the same heap.
75
+
76
+ ## Tier 4: CPU
77
+
78
+ `CPUEngine` is the pure-JS reference backend. It is slower, but dependency-free and
79
+ useful for debugging, fallback behavior, and cross-tier correctness checks.
80
+
81
+ ## Node Import Behavior
82
+
83
+ `ShaderLibrary.js` statically imports every `shaders/*.wgsl` file as text, which
84
+ only works in the bundled browser build. It is not re-exported from `js/index.js`.
85
+ `GraphExecutor` lazy-loads it only when the WebGPU path compiles, so plain Node
86
+ imports can use WASM/CPU without a bundler.
87
+
@@ -0,0 +1,445 @@
1
+ # EfficientDet Lite0: TFLite vs VolvoxAI Native
2
+
3
+ This document compares MediaPipe EfficientDet Lite0 int8, float16-source, and
4
+ float32-source packages on the Linux CPU path, and records the Android
5
+ OpenGL GPU result for the float32 package.
6
+
7
+ Machine/runtime:
8
+
9
+ - CPU: AMD Ryzen 5 5600U with Radeon Graphics, single-thread runs
10
+ - TFLite: `/tmp/benchmark_model`, XNNPACK enabled, `--num_threads=1`,
11
+ `--warmup_runs=2`, `--num_runs=20`
12
+ - VolvoxAI: `./native/volvoxai detect ... --num_threads 1 --warmup_runs 2
13
+ --num_runs 20`
14
+ - Test image for VolvoxAI: `/tmp/volvox_dog.jpg`
15
+
16
+ Android GPU runtime:
17
+
18
+ - Device: Samsung SM-A528N, Qualcomm `lahaina`, Adreno 642L, Android SDK 34
19
+ - TFLite: `/data/local/tmp/benchmark_model`, GPU delegate, `--gpu_backend=gl`,
20
+ `--warmup_runs=2`, `--num_runs=20`
21
+ - VolvoxAI: Android arm64 build, `--opengl`, OpenGL ES 3.2,
22
+ `--warmup_runs 2`, `--num_runs 20`
23
+ - Test image for VolvoxAI: `/data/local/tmp/volvoxai_gltest/volvoxai_object_test.jpg`
24
+
25
+ Important caveats:
26
+
27
+ - TFLite `benchmark_model` measures generated tensor input. VolvoxAI `detect forward`
28
+ is the graph forward after the image input is loaded.
29
+ - VolvoxAI prints raw detection tensors. This is a speed comparison, not a validation of
30
+ MediaPipe postprocessing/NMS correctness.
31
+ - TFLite GPU defaults to allowing lower precision. The Android section includes both
32
+ the default GPU delegate result and a `--gpu_precision_loss_allowed=false` rerun.
33
+ - The TFLite float16 model uses float32 input/output and XNNPACK reports F32 kernels on
34
+ CPU. It is not an FP16 CPU-kernel speed test.
35
+ - Direct TFLite export keeps VolvoxAI tensors in NHWC and stores Conv weights in
36
+ TFLite-native layouts: regular Conv2D as `OHWI`, depthwise Conv2D as `1HWO`. The
37
+ native CPU path prepares a per-node HWIO/HWCM compute cache at engine init, so the
38
+ artifact stays TFLite-shaped without making the hot Conv loops stride through OHWI.
39
+ - The float16-source package stores floating weights as safetensors `F16`. Native CPU
40
+ keeps the artifact half-sized and prepares a widened Conv weight cache at engine init
41
+ for the default `cpu-f16w-pack` path. On this AVX2 CPU this is not native FP16
42
+ arithmetic; it is half-size storage plus one-time FP32 widening.
43
+
44
+ ## Artifacts
45
+
46
+ | Package | Source TFLite | Optional ONNX | Volvox weights | Volvox config | Volvox graph contract |
47
+ | --- | ---: | ---: | ---: | ---: | --- |
48
+ | `models/efficientdet_lite0_int8` | `4.4M` | `4.0M` | `3.4M` | `148K` | direct TFLite NHWC, quantized `QConv2D`, `I8` OHWI/1HWO weights |
49
+ | `models/efficientdet_lite0_fp16` | `7.0M` | `13M` | `6.4M` | `108K` | direct TFLite NHWC, `F16` OHWI/1HWO weights |
50
+ | `models/efficientdet_lite0_fp32` | `14M` | `13M` | `13M` | `108K` | direct TFLite NHWC, FP32 OHWI/1HWO weights |
51
+
52
+ The fp16-source package preserves half-precision storage in safetensors:
53
+
54
+ ```text
55
+ models/efficientdet_lite0_fp16/model.safetensors F16 tensors 253
56
+ Conv2D backend=cpu-f16w-pack
57
+ ```
58
+
59
+ The int8 package preserves quantized Conv nodes and quantization metadata:
60
+
61
+ ```text
62
+ models/efficientdet_lite0_int8/config.json QConv2D 182
63
+ models/efficientdet_lite0_fp16/config.json Conv2D 182
64
+ models/efficientdet_lite0_fp32/config.json Conv2D 182
65
+ models/efficientdet_lite0_fp16/config.json Transpose 0
66
+ models/efficientdet_lite0_fp32/config.json Transpose 0
67
+ ```
68
+
69
+ The direct TFLite configs report:
70
+
71
+ ```text
72
+ internal_layout=NHWC
73
+ conv_weight_layout=OHWI
74
+ depthwise_weight_layout=1HWO
75
+ ```
76
+
77
+ The first Conv/QConv weights match TFLite shapes:
78
+
79
+ ```text
80
+ w0 regular Conv2D (32, 3, 3, 3) # OHWI
81
+ w2 depthwise Conv2D (1, 3, 3, 32) # 1HWO
82
+ ```
83
+
84
+ The int8 VolvoxAI debug log confirms the quantized path is active:
85
+
86
+ ```text
87
+ QConv2D backend=cpu-qconv
88
+ QConv2D backend=cpu-qconv-f32
89
+ QConv2D backend=cpu-qconv-f32
90
+ ```
91
+
92
+ Most Conv nodes keep quantized NHWC activations and int8 weights with int32
93
+ accumulation/requantization. Some output-head nodes produce FP32 output
94
+ where the graph leaves the quantized island.
95
+
96
+ ## Export Commands
97
+
98
+ Download the float models:
99
+
100
+ ```bash
101
+ mkdir -p models/efficientdet_lite0_fp16 models/efficientdet_lite0_fp32
102
+
103
+ curl -L -o models/efficientdet_lite0_fp16/efficientdet_lite0_float16.tflite \
104
+ https://storage.googleapis.com/mediapipe-models/object_detector/efficientdet_lite0/float16/latest/efficientdet_lite0.tflite
105
+
106
+ curl -L -o models/efficientdet_lite0_fp32/efficientdet_lite0_float32.tflite \
107
+ https://storage.googleapis.com/mediapipe-models/object_detector/efficientdet_lite0/float32/latest/efficientdet_lite0.tflite
108
+
109
+ cp models/efficientdet_lite0_int8/labels.txt models/efficientdet_lite0_fp16/labels.txt
110
+ cp models/efficientdet_lite0_int8/labels.txt models/efficientdet_lite0_fp32/labels.txt
111
+ ```
112
+
113
+ Export TFLite directly to VolvoxAI:
114
+
115
+ ```bash
116
+ python3 tools/export_safetensors.py \
117
+ --model models/efficientdet_lite0_fp16/efficientdet_lite0_float16.tflite \
118
+ --out models/efficientdet_lite0_fp16/model.safetensors
119
+
120
+ python3 tools/export_safetensors.py \
121
+ --model models/efficientdet_lite0_fp32/efficientdet_lite0_float32.tflite \
122
+ --out models/efficientdet_lite0_fp32/model.safetensors
123
+ ```
124
+
125
+ The exporter auto-selects `F16` storage for the float16 TFLite model because its constant
126
+ weights are stored as half precision. Use `--weight-dtype float32` to force FP32 artifact
127
+ storage, or `--weight-dtype float16` to force half-precision storage.
128
+
129
+ The direct float exports reported:
130
+
131
+ ```text
132
+ float16: TFLite ops=516 folded_dequantize=253 lowered_nodes=263 optimized_nodes=262 weights=253
133
+ float32: TFLite ops=263 folded_dequantize=0 lowered_nodes=263 optimized_nodes=262 weights=253
134
+ ```
135
+
136
+ ## Benchmark Commands
137
+
138
+ TFLite:
139
+
140
+ ```bash
141
+ /tmp/benchmark_model \
142
+ --graph=models/efficientdet_lite0_int8/efficientdet_lite0.tflite \
143
+ --num_threads=1 \
144
+ --use_xnnpack=true \
145
+ --warmup_runs=2 \
146
+ --num_runs=20 \
147
+ --min_secs=0 \
148
+ --max_secs=30
149
+ ```
150
+
151
+ Add `--enable_op_profiling=true --op_profiling_output_mode=stdout` to reproduce
152
+ the TFLite op-sum tables below.
153
+
154
+ VolvoxAI:
155
+
156
+ ```bash
157
+ clang -O3 -mavx2 -mfma -pthread -Inative \
158
+ native/cJSON.c native/safetensors.c native/kernels.c native/quant_cpu_opt.c \
159
+ native/conv_f32_opt.c native/tensor_f32_opt.c native/engine_runtime.c \
160
+ native/engine.c native/image_io.c native/kie_runtime.c native/vulkan_engine.c \
161
+ native/opengl_engine.c native/tokenizer.c native/nnapi_engine.c native/main.c \
162
+ -o native/volvoxai -lm -ldl
163
+
164
+ ./native/volvoxai detect models/efficientdet_lite0_int8 \
165
+ --image input0=/tmp/volvox_dog.jpg \
166
+ --image-normalize raw-255 \
167
+ --boxes boxes \
168
+ --scores scores \
169
+ --max-det 5 \
170
+ --num_threads 1 \
171
+ --warmup_runs 2 \
172
+ --num_runs 20
173
+ ```
174
+
175
+ Add `--debug` to reproduce the VolvoxAI op-sum and load/init tables below.
176
+
177
+ For the float-source packages, replace the model directory with
178
+ `models/efficientdet_lite0_fp16` or `models/efficientdet_lite0_fp32`.
179
+
180
+ Android TFLite OpenGL GPU:
181
+
182
+ ```bash
183
+ adb shell 'cd /data/local/tmp && ./benchmark_model \
184
+ --graph=/data/local/tmp/tflite_gltest/efficientdet_lite0_float32.tflite \
185
+ --use_gpu=true \
186
+ --gpu_backend=gl \
187
+ --warmup_runs=2 \
188
+ --warmup_min_secs=0 \
189
+ --num_runs=20 \
190
+ --min_secs=0 \
191
+ --max_secs=60 \
192
+ --num_threads=1'
193
+ ```
194
+
195
+ Add `--gpu_precision_loss_allowed=false` for the strict fp32 GPU rerun.
196
+
197
+ Android VolvoxAI OpenGL ES:
198
+
199
+ ```bash
200
+ adb shell 'cd /data/local/tmp/volvoxai_gltest && ./volvoxai detect \
201
+ models/efficientdet_lite0_fp32 \
202
+ --image input0=volvoxai_object_test.jpg \
203
+ --image-normalize raw-255 \
204
+ --boxes boxes \
205
+ --scores scores \
206
+ --max-det 3 \
207
+ --opengl \
208
+ --warmup_runs 2 \
209
+ --num_runs 20'
210
+ ```
211
+
212
+ ## High-Level Result
213
+
214
+ Headline timings are timed first/avg/min/max after two warmup runs. They omit
215
+ TFLite op profiling and VolvoxAI `--debug` logging.
216
+
217
+ | Source model | TFLite first | TFLite avg | TFLite min | TFLite max | VolvoxAI first | VolvoxAI avg | VolvoxAI min | VolvoxAI max | Gap by avg |
218
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
219
+ | int8 | `26.758 ms` | `25.943 ms` | `25.234 ms` | `28.078 ms` | `37.589 ms` | `38.299 ms` | `37.589 ms` | `39.431 ms` | `1.48x` |
220
+ | float16 | `25.816 ms` | `25.857 ms` | `25.115 ms` | `27.432 ms` | `29.486 ms` | `30.895 ms` | `29.486 ms` | `32.473 ms` | `1.19x` |
221
+ | float32 | `25.355 ms` | `26.024 ms` | `25.004 ms` | `26.950 ms` | `29.361 ms` | `30.805 ms` | `29.361 ms` | `33.251 ms` | `1.18x` |
222
+
223
+ TFLite op profiling and VolvoxAI `--debug` summaries from matching 20-run jobs.
224
+ For VolvoxAI, the op row averages the last 20 debug summary blocks and excludes
225
+ the two warmup forwards.
226
+
227
+ | Source model | TFLite profiled op avg | TFLite nodes | VolvoxAI debug op avg | VolvoxAI nodes |
228
+ | --- | ---: | ---: | ---: | ---: |
229
+ | int8 | `25.579 ms` | `196` | `37.078 ms` | `265` |
230
+ | float16 | `26.326 ms` | `193` | `30.770 ms` | `262` |
231
+ | float32 | `26.255 ms` | `193` | `30.987 ms` | `262` |
232
+
233
+ Read:
234
+
235
+ - TFLite/XNNPACK is faster on one CPU thread. The int8 gap is `1.48x`.
236
+ - VolvoxAI int8 uses quantized `QConv2D` execution, but it is slower than the
237
+ float-source native path in this run.
238
+ - TFLite float16 and float32 are almost the same on CPU because XNNPACK reports F32 kernels
239
+ for both.
240
+ - VolvoxAI float16-source stores `F16` weights and defaults to a prepared
241
+ `cpu-f16w-pack` path. Direct half-weight consumption is not used for this
242
+ comparison because this AVX2 CPU lacks native FP16 arithmetic.
243
+ - The direct TFLite paths have no ONNX-derived Transpose nodes. The float
244
+ graph has 262 nodes, and the int8 graph is direct NHWC TFLite with 265 nodes.
245
+ - No-debug single-thread runs are `38.299 ms` for int8 and about `31 ms` for the
246
+ float-source packages.
247
+
248
+ ## TFLite Op Sums
249
+
250
+ These come from TFLite operator-profiling runs with the same thread/warmup/run counts.
251
+ The total row is the profiler's 20-run average, not the sum of rounded table rows.
252
+
253
+ | Op group | int8 | float16-source | float32-source |
254
+ | --- | ---: | ---: | ---: |
255
+ | Pointwise 1x1 / GEMM, 101 calls | `17.912 ms` | `18.009 ms` | `18.052 ms` |
256
+ | Depthwise Conv, 80 calls | `4.418 ms` | `5.197 ms` | `5.124 ms` |
257
+ | Stem Conv, 1 call | `1.758 ms` | `1.019 ms` | `0.951 ms` |
258
+ | Unary / activation | `0.871 ms` | `1.019 ms` | `1.043 ms` |
259
+ | Copy / tensor movement | `0.153 ms` | `0.711 ms` | `0.708 ms` |
260
+ | Binary Add | `0.103 ms` | `0.150 ms` | `0.159 ms` |
261
+ | ResizeNearest | `0.072 ms` | `0.085 ms` | `0.086 ms` |
262
+ | MaxPool | `0.017 ms` | `0.059 ms` | `0.056 ms` |
263
+ | Quantize | `0.208 ms` | n/a | n/a |
264
+ | Total profiled op avg | `25.579 ms` | `26.326 ms` | `26.255 ms` |
265
+
266
+ TFLite int8 uses XNNPACK quantized kernels:
267
+
268
+ ```text
269
+ Fully Connected (NC, QS8, QC8W) GEMM
270
+ Convolution (NHWC, QC8) DWConv
271
+ Convolution (NHWC, QC8) IGEMM
272
+ ```
273
+
274
+ The float16-source and float32-source TFLite runs both report:
275
+
276
+ ```text
277
+ Fully Connected (NC, F32) GEMM
278
+ Convolution (NHWC, F32) DWConv
279
+ Convolution (NHWC, F32) IGEMM
280
+ ```
281
+
282
+ ## VolvoxAI Op Sums
283
+
284
+ These average the 20 timed `--debug` forwards; the two warmup forwards are excluded.
285
+
286
+ | Op group | int8 package | float16-source package | float32-source package |
287
+ | --- | ---: | ---: | ---: |
288
+ | Conv aggregate | `QConv2D 34.80 ms` | `Conv2D cpu-f16w-pack 28.85 ms` | `Conv2D cpu-pack 28.93 ms` |
289
+ | Concat | `1.25 ms` | `1.37 ms` | `1.49 ms` |
290
+ | Add | `0.42 ms` | `0.33 ms` | `0.34 ms` |
291
+ | MaxPool2D | `0.40 ms` | `0.14 ms` | `0.14 ms` |
292
+ | ResizeNearest2D | `0.04 ms` | `0.08 ms` | `0.08 ms` |
293
+ | QuantizeLinear | `0.18 ms` | n/a | n/a |
294
+ | DequantizeLinear | aliased after Concat | n/a | n/a |
295
+ | Total profiled op avg | `37.08 ms` | `30.77 ms` | `30.99 ms` |
296
+
297
+ VolvoxAI load/init timings from representative debug runs:
298
+
299
+ | Package | load weights | build graph | engine init |
300
+ | --- | ---: | ---: | ---: |
301
+ | int8 | `3.523 ms` | `8.906 ms` | `14.800 ms` |
302
+ | float16-source | `7.216 ms` | `7.503 ms` | `36.135 ms` |
303
+ | float32-source | `12.595 ms` | `6.758 ms` | `40.580 ms` |
304
+
305
+ The float-source engine init includes layout/precision preparation:
306
+
307
+ ```text
308
+ fp16: prepack_conv weights=182 biases=182 pointwise_packs=101 igemm_indirs=1 19.720 ms
309
+ fp32: prepack_conv weights=182 biases=0 pointwise_packs=101 igemm_indirs=1 19.535 ms
310
+ ```
311
+
312
+ ## CPU Gap
313
+
314
+ The int8 VolvoxAI path is a real quantized graph island for most Conv nodes. It uses a
315
+ wide AVX2 pointwise tile plus an exact AVX2 byte-dot path for `input_zero_point = -128`
316
+ pointwise layers, vectorized same-quant MaxPool2D, vectorized contiguous QuantizeLinear,
317
+ and aliasing for final no-op DequantizeLinear nodes after Concat. It is not an
318
+ XNNPACK-class CPU implementation.
319
+
320
+ One-thread blockers:
321
+
322
+ 1. Pointwise and depthwise microkernels are much simpler than XNNPACK. They need
323
+ architecture-specific dot-product paths, better unrolling, and better cache blocking.
324
+ 2. Depthwise Conv needs XNNPACK-style indirection/bounds handling to remove per-MAC
325
+ padding math.
326
+ 3. Weight packing exists, but it is not microkernel-specific enough for VNNI/AVX512 or
327
+ ARM `sdot`/`udot`.
328
+ 4. Some graph tails leave the quantized island and produce FP32 output tensors.
329
+ 5. The fp16-source export preserves `F16` weight storage and prepares those weights once
330
+ for CPU Conv2D. This follows the guide's weight-preparation principle on AVX2, but
331
+ true hardware FP16 arithmetic requires ARM FP16, AVX512-FP16, or a GPU path.
332
+
333
+ ## Native GPU Status
334
+
335
+ OpenGL waits at the end of `engine_forward`, so reported forward time includes real
336
+ queued GPU work rather than only CPU-side dispatch/enqueue time.
337
+
338
+ Linux fp32 EfficientDet Lite0 timings on the Ryzen 5 5600U machine:
339
+
340
+ | Engine | Backend | Avg, warmup 2 / runs 20 | Notes |
341
+ | --- | --- | ---: | --- |
342
+ | VolvoxAI | CPU fp32 | `29.990 ms` | `--num_threads 1` |
343
+ | VolvoxAI | Vulkan graph | `45.523 ms` | AMD RADV Renoir, vector/tiled Conv2D shaders |
344
+ | VolvoxAI | OpenGL graph | `40.256 ms` | AMD Renoir Mesa, vector/tiled Conv2D shaders |
345
+
346
+ Representative corrected debug summaries show that most elapsed time is in the final GPU
347
+ wait, not in CPU enqueue:
348
+
349
+ ```text
350
+ OpenGL: engine_forward 46.823 ms, GPUWait 40.46 ms, Conv2D enqueue 3.42 ms
351
+ Vulkan: engine_forward 43.100 ms, GPUWait 39.41 ms, Conv2D enqueue 1.67 ms
352
+ ```
353
+
354
+ ## Android OpenGL GPU Result
355
+
356
+ Run on the attached SM-A528N / Adreno 642L device with the float32 EfficientDet Lite0
357
+ package.
358
+
359
+ | Engine | Backend | First | Avg | Min | Max | Gap vs TFLite default |
360
+ | --- | --- | ---: | ---: | ---: | ---: | ---: |
361
+ | TFLite | GPU delegate, OpenGL, default precision | `138.365 ms` | `127.211 ms` | `90.464 ms` | `139.163 ms` | `1.00x` |
362
+ | TFLite | GPU delegate, OpenGL, fp32 strict | `120.499 ms` | `130.962 ms` | `120.499 ms` | `139.626 ms` | `1.03x` |
363
+ | VolvoxAI | OpenGL ES 3.2, vector/tiled Conv2D | `118.918 ms` | `144.332 ms` | `118.918 ms` | `153.026 ms` | `1.13x` |
364
+
365
+ The OpenGL run uses Naga-generated GLES shaders for depthwise, pointwise, and the
366
+ EfficientDet stem Conv2D, and is `1.13x` slower than the TFLite OpenGL default-precision
367
+ baseline.
368
+
369
+ TFLite log confirmation:
370
+
371
+ ```text
372
+ Replacing 263 out of 263 node(s) with delegate (TfLiteGpuDelegateV2)
373
+ yielding 1 partitions for subgraph 0
374
+ Initialized OpenGL-based API
375
+ Created 1 GPU delegate kernels
376
+ Inference (avg): 127211 us
377
+ ```
378
+
379
+ VolvoxAI log confirmation:
380
+
381
+ ```text
382
+ [VolvoxAI GPU] OpenGL Compute initialized:
383
+ Qualcomm / Adreno (TM) 642L / OpenGL ES 3.2
384
+ [bench] detect: first=118.918 avg=144.332 min=118.918 max=153.026 ms
385
+ ```
386
+
387
+ The `--debug` run is not the benchmark average, but it identifies where the time goes:
388
+
389
+ ```text
390
+ [debug] engine_forward nodes=262 159.649 ms
391
+ [debug] --- op time summary (by total) ---
392
+ [debug] GPUWait 114.84 ms (n=1)
393
+ [debug] Conv2D 11.90 ms (n=182)
394
+ [debug] Add 2.51 ms (n=42)
395
+ [debug] MaxPool2D 0.76 ms (n=14)
396
+ [debug] ResizeNearest2D 0.62 ms (n=12)
397
+ [debug] Concat 0.18 ms (n=2)
398
+ [debug] Reshape 0.13 ms (n=10)
399
+ [debug] TOTAL 130.94 ms
400
+ ```
401
+
402
+ ## Android OpenGL Gap Analysis
403
+
404
+ The OpenGL path selects vectorized and tiled Naga-generated GLES shaders for
405
+ EfficientDet's dominant Conv shapes:
406
+
407
+ ```text
408
+ stem Conv2D: conv2DRegularC3Out16
409
+ depthwise Conv2D: conv2DDepthwise8
410
+ pointwise Conv2D: conv2DPointwise16Tile
411
+ head pointwise: conv2DPointwise8Vec4 / conv2DPointwise8Vec2
412
+ fallback Conv2D: conv2D / conv2DPointwise8
413
+ ```
414
+
415
+ The `1.13x` gap is small but not a measurement artifact. The VolvoxAI OpenGL path is a
416
+ per-node compute backend, while TFLite's GPU delegate compiles the whole graph into one
417
+ delegated partition.
418
+
419
+ Reasons for the gap:
420
+
421
+ 1. TFLite delegates the whole EfficientDet graph into one GPU partition and creates one
422
+ GPU delegate kernel. VolvoxAI executes the exported graph as 262 native nodes.
423
+ 2. VolvoxAI dispatches each graph op separately. Each dispatch binds buffers, launches
424
+ compute, and inserts a shader-storage memory barrier. That is correct but expensive for
425
+ hundreds of small mobile-GPU kernels.
426
+ 3. Each op creates a small uniform parameter buffer for that dispatch. This is minor
427
+ compared with `GPUWait`, but it is unnecessary per-node overhead.
428
+ 4. The OpenGL backend has only kernel-level specialization. It does not fuse larger
429
+ EfficientDet blocks across Add/Resize/Conv boundaries the way a graph delegate can.
430
+ 5. The Android OpenGL path runs fp32 GLES compute shaders. TFLite default precision can use
431
+ lower precision, but the strict fp32 TFLite rerun is `130.962 ms`, so precision
432
+ alone is not the reason.
433
+
434
+ The debug profile's `Conv2D 11.90 ms` row is CPU-side enqueue/profile time, not real GPU
435
+ compute time. The real queued GPU execution appears in `GPUWait 114.84 ms`; enqueue-only
436
+ OpenGL timing omits it.
437
+
438
+ Work to consistently match or beat the TFLite GPU delegate:
439
+
440
+ 1. Fuse EfficientDet blocks at graph compile time instead of dispatching every op as a
441
+ separate shader.
442
+ 2. Remove per-dispatch memory barriers when a graph-level dependency schedule can prove
443
+ ordering.
444
+ 3. Reuse persistent parameter buffers or push constants/equivalent small-uniform storage.
445
+ 4. Add a fp16/mobile GPU path and benchmark it separately from fp32.