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
@@ -0,0 +1,153 @@
1
+ # Microkernel Optimization Guide
2
+
3
+ This document outlines the architectural roadmap and concrete code-level strategies for
4
+ raising VolvoxAI's native CPU inference performance across INT4, INT8, FP16, and FP32 data
5
+ types.
6
+
7
+ ## 1. Architectural Shift
8
+
9
+ VolvoxAI should continue moving from generic `Conv2D` and `QConv2D` loops toward a
10
+ microkernel architecture:
11
+
12
+ 1. **NHWC layout**: keep activations in NHWC format so channels are contiguous in memory.
13
+ 2. **Indirection buffers**: remove padding and bounds checks from inner loops.
14
+ 3. **Weight packing**: arrange weights to match the target SIMD register width and kernel
15
+ tile shape.
16
+ 4. **Register tiling**: hardcode loop unrolling around the target register file, such as
17
+ computing multiple pixels and output channels per kernel call.
18
+
19
+ ## 2. Indirection Buffers
20
+
21
+ Branching inside the MAC loop for padding stalls the CPU pipeline. Precompute an array of
22
+ input pointers instead. Padded areas point to a zero buffer, so the microkernel can do
23
+ pointer dereferences and math without bounds checks.
24
+
25
+ ```c
26
+ static const int8_t zero_buffer[MAX_CHANNELS] = {0};
27
+
28
+ const int8_t** indirection_buffer =
29
+ malloc(output_height * output_width * kernel_size * sizeof(int8_t*));
30
+ int idx = 0;
31
+ for (int oy = 0; oy < output_height; oy++) {
32
+ for (int ox = 0; ox < output_width; ox++) {
33
+ for (int ky = 0; ky < kh; ky++) {
34
+ for (int kx = 0; kx < kw; kx++) {
35
+ int iy = oy * stride - pad_top + ky;
36
+ int ix = ox * stride - pad_left + kx;
37
+ if (iy >= 0 && iy < input_height && ix >= 0 && ix < input_width) {
38
+ indirection_buffer[idx++] =
39
+ input_image + (iy * input_width + ix) * channels;
40
+ } else {
41
+ indirection_buffer[idx++] = zero_buffer;
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## 3. Data Type Strategies
50
+
51
+ ### INT8
52
+
53
+ Use dot-product instructions where available. ARM provides `sdot`, while newer Intel and
54
+ AMD CPUs provide VNNI-family instructions. Pack weights into blocks that align with the
55
+ dot-product width, such as `[OC/8, IC/4, 8, 4]`.
56
+
57
+ ```c
58
+ #include <arm_neon.h>
59
+
60
+ void microkernel_qconv2d_int8_neon_sdot(
61
+ const int8_t** input_pointers,
62
+ const int8_t* packed_weights,
63
+ int32_t* output_accumulators,
64
+ int kernel_elements,
65
+ int channels)
66
+ {
67
+ int32x4_t acc0 = vld1q_s32(output_accumulators + 0);
68
+ int32x4_t acc1 = vld1q_s32(output_accumulators + 4);
69
+
70
+ for (int k = 0; k < kernel_elements; k++) {
71
+ const int8_t* in_ptr = input_pointers[k];
72
+ for (int c = 0; c < channels; c += 4) {
73
+ int8x8_t in_val = vld1_s8(in_ptr + c);
74
+ int8x16_t in_dup = vcombine_s8(in_val, in_val);
75
+ int8x16_t w_val = vld1q_s8(packed_weights);
76
+ packed_weights += 16;
77
+ acc0 = vdotq_s32(acc0, in_dup, w_val);
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### INT4
84
+
85
+ INT4 cuts memory bandwidth in half compared to INT8, which is useful for bandwidth-bound
86
+ LLM weights or heavily quantized vision models. Most CPUs lack native INT4 MAC
87
+ instructions, so the practical path is to unpack INT4 to INT8 in registers and feed the
88
+ INT8 kernel.
89
+
90
+ ```c
91
+ uint8x16_t w_int4 = vld1q_u8(packed_int4_weights);
92
+ uint8x16_t mask = vdupq_n_u8(0x0F);
93
+ uint8x16_t w_lo = vandq_u8(w_int4, mask);
94
+ uint8x16_t w_hi = vshrq_n_u8(w_int4, 4);
95
+ ```
96
+
97
+ ### FP16
98
+
99
+ Native FP16 execution reduces memory bandwidth and cache footprint on hardware with fast
100
+ half-precision arithmetic, such as ARMv8.2-A FP16 or AVX512-FP16.
101
+
102
+ ```c
103
+ #include <arm_neon.h>
104
+
105
+ void microkernel_conv2d_fp16_neon(
106
+ const float16_t* input,
107
+ const float16_t* packed_weights,
108
+ float16_t* output)
109
+ {
110
+ float16x8_t acc = vdupq_n_f16(0.0f);
111
+ float16x8_t in_val = vdupq_n_f16(input[0]);
112
+ float16x8_t w_val = vld1q_f16(packed_weights);
113
+ acc = vfmaq_f16(acc, in_val, w_val);
114
+ vst1q_f16(output, acc);
115
+ }
116
+ ```
117
+
118
+ ### FP32
119
+
120
+ FP32 should use register tiling to hide latency. On AVX2, one useful pointwise Conv shape is
121
+ six spatial pixels by 16 output channels, using broadcast input values and packed weights.
122
+
123
+ ```c
124
+ #include <immintrin.h>
125
+
126
+ void microkernel_conv2d_fp32_avx2(
127
+ const float* in_p0,
128
+ const float* in_p1,
129
+ const float* packed_weights,
130
+ float* out_p0,
131
+ float* out_p1)
132
+ {
133
+ __m256 acc0 = _mm256_setzero_ps();
134
+ __m256 acc1 = _mm256_setzero_ps();
135
+
136
+ for (int ic = 0; ic < input_channels; ic++) {
137
+ __m256 w0 = _mm256_loadu_ps(packed_weights + ic * 8);
138
+ acc0 = _mm256_fmadd_ps(_mm256_set1_ps(in_p0[ic]), w0, acc0);
139
+ acc1 = _mm256_fmadd_ps(_mm256_set1_ps(in_p1[ic]), w0, acc1);
140
+ }
141
+
142
+ _mm256_storeu_ps(out_p0, acc0);
143
+ _mm256_storeu_ps(out_p1, acc1);
144
+ }
145
+ ```
146
+
147
+ ## Action Plan
148
+
149
+ 1. Add reusable indirection-buffer builders during graph initialization.
150
+ 2. Extend weight-packing caches so each hot op has a layout matched to its microkernel.
151
+ 3. Replace generic inner loops in `quant_cpu_opt.c` with CPU-feature-routed microkernels.
152
+ 4. Keep the activation arena planner enabled for transient tensors with non-overlapping
153
+ lifetimes.
@@ -0,0 +1,108 @@
1
+ # Model Format
2
+
3
+ VolvoxAI loads inference packages made of:
4
+
5
+ ```text
6
+ config.json
7
+ model.safetensors
8
+ optional tokenizer/assets, such as vocab.bin, merges.txt, labels.txt
9
+ ```
10
+
11
+ Large `.safetensors` files and generated model directories should stay out of git.
12
+
13
+ ## Graph Model
14
+
15
+ A model graph contains:
16
+
17
+ - `Tensor`: name, shape, dtype, and `isWeight`.
18
+ - `Node`: `opType`, named `inputs`, named `outputs`, and `params`.
19
+ - `graph.outputNames`: output tensor names returned by WASM/CPU.
20
+
21
+ `GraphLoader.js` builds this graph from `config.json` and `model.safetensors`.
22
+ Applications can also construct graphs programmatically with `addInput`,
23
+ `addWeight`, and `addOp`.
24
+
25
+ ## Volvox Blueprint
26
+
27
+ The primary format is a precomputed Volvox blueprint:
28
+
29
+ ```json
30
+ {
31
+ "inputs": {
32
+ "image": { "shape": [1, 320, 320, 3], "dtype": "float32" }
33
+ },
34
+ "nodes": [
35
+ {
36
+ "opType": "Conv2D",
37
+ "inputs": { "input": "image", "weight": "stem.weight", "bias": "stem.bias" },
38
+ "outputs": { "out": "stem.out" },
39
+ "outputs_shape": { "out": [1, 160, 160, 32] },
40
+ "params": { "stride": [2, 2], "padding": [1, 1], "weight_layout": "OHWI" }
41
+ }
42
+ ]
43
+ }
44
+ ```
45
+
46
+ Exporters map source-model ops to Volvox `opType`s, precompute tensor shapes, and
47
+ write the weights into safetensors. The browser then only maps memory and executes.
48
+
49
+ ## Hugging Face Config Path
50
+
51
+ If `config.json` has `model_type` but no topological `nodes`, `GraphLoader` checks
52
+ `GraphLoader.ModelBuilders`. A model family can register a builder:
53
+
54
+ ```javascript
55
+ GraphLoader.ModelBuilders.llama = (graph, config, tensors) => {
56
+ // call graph.addOp(...) to assemble the model
57
+ };
58
+ ```
59
+
60
+ ## Safetensors Loading
61
+
62
+ VolvoxAI reads standard safetensors weights. Tensor metadata provides dtype, shape,
63
+ and byte offsets. Graph topology can also be embedded in safetensors metadata, but
64
+ the normal package layout keeps topology in `config.json`.
65
+
66
+ ## Layout Policy
67
+
68
+ Runtime image tensors use NHWC:
69
+
70
+ ```text
71
+ [batch, height, width, channels]
72
+ ```
73
+
74
+ Browser Conv2D kernels use HWIO/HWCM internally. Native TFLite exports may keep
75
+ TFLite-native layouts such as `OHWI` for regular conv and `1HWO` for depthwise conv;
76
+ the native engine prepares HWIO/HWCM compute caches at load time.
77
+
78
+ ## Precision Policy
79
+
80
+ VolvoxAI focuses on FP32 activations/intermediates and INT8-packed or quantized
81
+ weights.
82
+
83
+ - FP32 is the portable activation format across WebGPU, WASM, CPU, and native paths.
84
+ - INT8 reduces weight bandwidth and storage while avoiding the bit-unpacking cost of
85
+ INT4 on low-end GPUs.
86
+ - FP16 weights can be kept on disk for exported vision models; runtime paths widen or
87
+ handle them according to backend support.
88
+
89
+ INT8 handling:
90
+
91
+ - MatMul keeps an INT8 plus per-channel-scale fast path in browser shaders and native
92
+ kernels.
93
+ - Browser Conv2D/Conv1D dequantizes quantized weights to FP32 at load time.
94
+ - Native CPU can keep quantized Conv/Add islands in int8 via `native/quant_cpu_opt.c`.
95
+ - Native Vulkan/OpenGL graph paths are FP32-only, so `QConv2D` stays on CPU.
96
+
97
+ ## LLM Scope
98
+
99
+ VolvoxAI includes the core ops used by small GPT-style models: `Embedding`,
100
+ `LayerNorm`, `MatMul`, `SDPA`, and `GELU`. The native CLI includes TinyStories
101
+ generation with prefill/decode KV-cache orchestration.
102
+
103
+ It is not a frontier LLM runtime today:
104
+
105
+ - No INT4 weight format.
106
+ - Browser text generation currently needs application-side autoregressive loops.
107
+ - Native generation is ahead of browser generation helpers.
108
+
package/docs/models.md ADDED
@@ -0,0 +1,103 @@
1
+ # Models
2
+
3
+ The `models/` directory is ignored because generated model packages and source
4
+ weights are large. Regenerate examples from public sources when needed.
5
+
6
+ ## Dependencies
7
+
8
+ Model export is development-only and runs on the host, not in the Docker build image.
9
+ Install exporter dependencies once:
10
+
11
+ ```bash
12
+ make models_deps
13
+ ```
14
+
15
+ This installs `tools/requirements-export.txt`, including numpy, flatbuffers,
16
+ safetensors, torch, and transformers.
17
+
18
+ ## Commands
19
+
20
+ | Command | What it does |
21
+ | --- | --- |
22
+ | `make models` | Download and export EfficientDet Lite0 fp32/fp16/int8 plus TinyStories-1M. |
23
+ | `make models_efficientdet` | Export EfficientDet Lite0 packages from MediaPipe TFLite models. |
24
+ | `make models_tinystories` | Export `roneneldan/TinyStories-1M` plus tokenizer assets. |
25
+ | `make models_clean` | Remove regenerated example model directories. |
26
+
27
+ `tools/fetch_models.sh` accepts `efficientdet`, `tinystories`, or `all`. For
28
+ EfficientDet, set `ONLY=int8`, `ONLY=float16`, or `ONLY=float32` to fetch one
29
+ precision.
30
+
31
+ ## EfficientDet Lite0
32
+
33
+ EfficientDet packages contain:
34
+
35
+ ```text
36
+ config.json
37
+ model.safetensors
38
+ labels.txt
39
+ ```
40
+
41
+ The source TFLite models come from Google's MediaPipe model store, for example:
42
+
43
+ ```text
44
+ https://storage.googleapis.com/mediapipe-models/object_detector/efficientdet_lite0/int8/latest/efficientdet_lite0.tflite
45
+ ```
46
+
47
+ The exported package has an NHWC image input and named raw outputs:
48
+
49
+ ```text
50
+ input0: [1, 320, 320, 3] raw RGB 0..255
51
+ scores: [1, 19206, 90]
52
+ boxes: [1, 19206, 4]
53
+ ```
54
+
55
+ The COCO label file keeps the 90-slot class-id alignment. `???` entries are unused
56
+ placeholders and should not be deleted.
57
+
58
+ ## TinyStories
59
+
60
+ TinyStories exports:
61
+
62
+ ```text
63
+ config.json
64
+ model.safetensors
65
+ vocab.bin
66
+ merges.txt
67
+ tokens.i32
68
+ positions.i32
69
+ ```
70
+
71
+ The native runtime can use the package directly:
72
+
73
+ ```bash
74
+ ./native/volvoxai generate models/tinystories_1m \
75
+ --prompt "Once upon a time, Lily" \
76
+ --max-new 50
77
+ ```
78
+
79
+ ## TinyReceiptKIE
80
+
81
+ Custom TinyReceiptKIE checkpoints can be exported into the same package layout:
82
+
83
+ ```bash
84
+ python3 tools/export_kie_safetensors.py \
85
+ --checkpoint checkpoint.pt \
86
+ --out models/tiny_receipt_kie
87
+ ```
88
+
89
+ Then run it through the native chat alias:
90
+
91
+ ```bash
92
+ ./native/volvoxai chat models/tiny_receipt_kie \
93
+ --image image=receipt.jpg \
94
+ --prompt "What is the first number of the store's phone number?" \
95
+ --family auto \
96
+ --max-new 128
97
+ ```
98
+
99
+ The package declares the `tiny_receipt_kie` chat interface in `config.json` and keeps
100
+ weights in `model.safetensors`. LoRA is folded into dense linear weights during
101
+ export. If the checkpoint is a base model plus components, add `--lora lora.pt` and
102
+ repeat `--adapter family=adapter_family.pt` for each adapter family.
103
+
@@ -0,0 +1,189 @@
1
+ # Native Runtime
2
+
3
+ `native/` is a freestanding C runtime that runs the same Volvox blueprint package as
4
+ the browser runtime: `config.json` plus `.safetensors`. It has no static GPU SDK
5
+ dependency. Vulkan, OpenGL, Metal, and NNAPI are loaded dynamically when requested.
6
+
7
+ ## Build
8
+
9
+ ```bash
10
+ make build_native
11
+ ./native/volvoxai --version
12
+ ./native/volvoxai --help
13
+ ```
14
+
15
+ The Docker build compiles the native binary with clang, AVX2/FMA on x86, pthreads,
16
+ and the CPU/GPU backend sources. The binary embeds package version, git commit,
17
+ and UTC build date from the Makefile build.
18
+
19
+ ## Architecture
20
+
21
+ Key files:
22
+
23
+ - `engine.c`: parses the blueprint, builds tensors/nodes, owns the global engine context.
24
+ - `engine_runtime.c`: dispatches each node to CPU, Vulkan, OpenGL, Metal, or NNAPI.
25
+ - `graph_opt_fusion.c`: compile-time fusion pass for patterns such as Conv+ReLU6,
26
+ chained Add, depthwise-to-pointwise, concat+sigmoid, and alias elision.
27
+ - `conv_f32_opt.c`: optimized FP32 Conv2D with weight prepacking and IGEMM.
28
+ - `quant_cpu_opt.c`: INT8 quantized CPU path for `QConv2D`, quantized Add, and
29
+ quantization helpers.
30
+ - `kernels.c`: shared portable kernels used by both native and wasm32.
31
+ - `image_io.c`: PNG/JPEG decode through `stb_image.h` into NHWC tensors.
32
+ - `tokenizer.c` and `kie_runtime.c`: native BPE tokenizer and receipt KIE task runtime.
33
+
34
+ ## Raw Tensor Runner
35
+
36
+ ```bash
37
+ ./native/volvoxai run models/tinystories_1m \
38
+ --input tokens=models/tinystories_1m/tokens.i32 \
39
+ --input positions=models/tinystories_1m/positions.i32 \
40
+ --output logits=out.f32 \
41
+ --last-token 4 \
42
+ --debug
43
+ ```
44
+
45
+ Image-shaped inputs can be decoded directly:
46
+
47
+ ```bash
48
+ ./native/volvoxai run models/vision_model \
49
+ --image image=receipt.png \
50
+ --image-normalize zero-one \
51
+ --output logits=out.f32
52
+ ```
53
+
54
+ `--image-normalize` supports `zero-one`, `minus-one-one`, and `raw-255`.
55
+ Video, audio, camera, and streaming input should be handled by a frontend that feeds
56
+ decoded tensors to `run`.
57
+
58
+ ## Task Wrappers
59
+
60
+ Task wrappers sit on top of the tensor runner:
61
+
62
+ ```bash
63
+ ./native/volvoxai classify models/classifier \
64
+ --image image=photo.jpg \
65
+ --logits logits \
66
+ --labels labels.txt \
67
+ --top-k 5
68
+
69
+ ./native/volvoxai detect models/detector \
70
+ --image image=receipt.jpg \
71
+ --boxes boxes \
72
+ --scores scores \
73
+ --classes classes \
74
+ --max-det 20
75
+
76
+ ./native/volvoxai ctc models/ocr_line \
77
+ --image image=line.png \
78
+ --logits logits \
79
+ --labels labels.txt \
80
+ --blank 0
81
+
82
+ ./native/volvoxai seq2seq models/encoder_decoder \
83
+ --image image=receipt.jpg \
84
+ --prompt "What is the first number of the store phone?" \
85
+ --prompt-input q_tokens \
86
+ --decoder-input y_tokens \
87
+ --logits logits \
88
+ --max-new 192
89
+
90
+ ./native/volvoxai chat models/multimodal_chat \
91
+ --prompt "Summarize this receipt" \
92
+ --image image=receipt.jpg
93
+ ```
94
+
95
+ `classify` ranks logits, `ctc` performs greedy CTC collapse, and `detect` prints or
96
+ writes named raw tensors because detector output layouts vary by exporter. `seq2seq`
97
+ runs a greedy encoder-decoder loop. `chat` is a user-facing alias for multimodal
98
+ seq2seq packages.
99
+
100
+ ## Generation
101
+
102
+ TinyStories generation uses the same loaded graph repeatedly:
103
+
104
+ ```bash
105
+ ./native/volvoxai generate models/tinystories_1m \
106
+ --prompt "Once upon a time, Lily" \
107
+ --max-new 50 \
108
+ --debug
109
+ ```
110
+
111
+ Weights and graph load once. Generation updates token inputs and reruns the node loop.
112
+ For language models, `--vulkan` uses the MatMul-focused path: large MatMul/Gemm/Linear
113
+ nodes run through the `linearF32` shader, while small decode-time MatMuls stay on CPU
114
+ to avoid dispatch overhead.
115
+
116
+ ## Native GPU and NPU Backends
117
+
118
+ Driver loading is resolved at runtime:
119
+
120
+ - Vulkan (`--vulkan`): `libvulkan.so.1`, `libvulkan.so`, or `vulkan-1.dll`.
121
+ - OpenGL (`--opengl`): `libGL.so.1`, `opengl32.dll`, or macOS `OpenGL.framework`.
122
+ - Metal (`--metal`, macOS): default `MTLDevice` through the Objective-C runtime.
123
+ - NNAPI (`--nnapi`, Android build with `-DUSE_NNAPI`): Android Neural Networks API
124
+ for large MatMul/FullyConnected offload.
125
+
126
+ If multiple accelerator flags are passed, priority is `--nnapi`, then `--vulkan`,
127
+ then `--metal`, then `--opengl`.
128
+
129
+ EfficientDet-style vision graphs have graph-resident Vulkan and OpenGL paths for
130
+ fused Conv2D/ReLU6, MaxPool2D, same-size Add, Clip, Sigmoid, 2x nearest upsample,
131
+ Concat, and reshape/identity aliasing. The native GPU graph path is FP32-only;
132
+ quantized `QConv2D` runs on CPU.
133
+
134
+ On software Vulkan/OpenGL stacks, dispatch synchronization can be slower than the
135
+ AVX2 CPU path. The GPU win is on real mobile or desktop GPUs.
136
+
137
+ ## Benchmark Flags
138
+
139
+ For TFLite-style timing:
140
+
141
+ ```bash
142
+ ./native/volvoxai detect models/efficientdet_lite0_int8 \
143
+ --image input0=photo.jpg \
144
+ --image-normalize raw-255 \
145
+ --boxes boxes \
146
+ --scores scores \
147
+ --max-det 5 \
148
+ --num_threads 4 \
149
+ --warmup_runs 5 \
150
+ --num_runs 20
151
+ ```
152
+
153
+ `--num_threads` maps to `VOLVOX_NUM_THREADS`. `--debug` prints graph load, build,
154
+ node backend, and per-op timing logs.
155
+
156
+ See [efficientdet_tflite_vs_volvoxai.md](efficientdet_tflite_vs_volvoxai.md) for
157
+ the current EfficientDet benchmark methodology and results.
158
+
159
+ ## Android Cross-Compile
160
+
161
+ ```bash
162
+ NDK=$ANDROID_SDK/ndk/<version>
163
+ CC=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang
164
+ cd native && "$CC" -O3 -DUSE_NNAPI -pthread -Wno-unknown-attributes -I. \
165
+ cJSON.c safetensors.c kernels.c quant_cpu_opt.c conv_f32_opt.c tensor_f32_opt.c \
166
+ engine_runtime.c engine.c image_io.c kie_runtime.c \
167
+ vulkan_engine.c opengl_engine.c tokenizer.c nnapi_engine.c main.c \
168
+ -o volvoxai_android -lm -ldl -lneuralnetworks
169
+ ```
170
+
171
+ Then push the binary, model directory, and native shader outputs to the device:
172
+
173
+ ```bash
174
+ adb push volvoxai_android /data/local/tmp/volvoxai
175
+ adb shell "cd /data/local/tmp && VOLVOX_NUM_THREADS=2 ./volvoxai run models/tinystories_1m \
176
+ --input tokens=models/tinystories_1m/tokens.i32 \
177
+ --input positions=models/tinystories_1m/positions.i32 \
178
+ --output logits=out.f32 --vulkan --debug"
179
+ ```
180
+
181
+ ARM/NEON builds default to two CPU threads. Use one thread for stable profiling and
182
+ test two threads for throughput; using all cores is often slower because of big/little
183
+ scheduling and thermal limits.
184
+
185
+ ## Service Runtime
186
+
187
+ The Rust crate under `runtime/` builds a `libvolvoxai.so` Synurang service wrapper
188
+ around the C engine. See [../runtime/README.md](../runtime/README.md) for the FFI
189
+ service ABI, build commands, and current RPC coverage.