@ruvector/cnn 0.1.1 → 0.1.2

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.
package/index.d.ts CHANGED
@@ -151,7 +151,7 @@ export namespace LayerOps {
151
151
 
152
152
  /**
153
153
  * Apply global average pooling
154
- * @param input - Input tensor [C, H, W]
154
+ * @param input - Input tensor, channels-last [H*W, C]
155
155
  * @param channels - Number of channels
156
156
  * @param spatialSize - H * W
157
157
  * @returns Output [C]
package/index.js CHANGED
@@ -72,12 +72,14 @@ class CnnEmbedder {
72
72
  }
73
73
 
74
74
  const wasmConfig = new wasm.EmbedderConfig();
75
- wasmConfig.input_size = config.inputSize || 224;
76
- wasmConfig.embedding_dim = config.embeddingDim || 512;
75
+ wasmConfig.input_size = config.inputSize ?? 224;
76
+ wasmConfig.embedding_dim = config.embeddingDim ?? 512;
77
77
  wasmConfig.normalize = config.normalize !== false;
78
78
 
79
+ // The WASM constructor takes ownership of wasmConfig (its pointer is
80
+ // nulled), so read the dimension back from the embedder, not the config.
79
81
  this._inner = new wasm.WasmCnnEmbedder(wasmConfig);
80
- this._embeddingDim = wasmConfig.embedding_dim;
82
+ this._embeddingDim = this._inner.embedding_dim;
81
83
  }
82
84
 
83
85
  /**
@@ -203,7 +205,7 @@ const SimdOps = {
203
205
  */
204
206
  relu(data) {
205
207
  if (!initialized) throw new Error('Module not initialized');
206
- wasm.SimdOps.relu(data);
208
+ data.set(wasm.SimdOps.relu(data));
207
209
  },
208
210
 
209
211
  /**
@@ -212,7 +214,7 @@ const SimdOps = {
212
214
  */
213
215
  relu6(data) {
214
216
  if (!initialized) throw new Error('Module not initialized');
215
- wasm.SimdOps.relu6(data);
217
+ data.set(wasm.SimdOps.relu6(data));
216
218
  },
217
219
 
218
220
  /**
@@ -221,7 +223,7 @@ const SimdOps = {
221
223
  */
222
224
  l2Normalize(data) {
223
225
  if (!initialized) throw new Error('Module not initialized');
224
- wasm.SimdOps.l2_normalize(data);
226
+ data.set(wasm.SimdOps.l2_normalize(data));
225
227
  }
226
228
  };
227
229
 
@@ -230,7 +232,7 @@ const SimdOps = {
230
232
  */
231
233
  const LayerOps = {
232
234
  /**
233
- * Apply batch normalization
235
+ * Apply batch normalization over channels-last (NHWC) data
234
236
  * @param {Float32Array} input - Input data (modified in-place)
235
237
  * @param {Float32Array} gamma - Scale parameter
236
238
  * @param {Float32Array} beta - Shift parameter
@@ -240,19 +242,20 @@ const LayerOps = {
240
242
  */
241
243
  batchNorm(input, gamma, beta, mean, variance, epsilon = 1e-5) {
242
244
  if (!initialized) throw new Error('Module not initialized');
243
- wasm.LayerOps.batch_norm(input, gamma, beta, mean, variance, epsilon);
245
+ input.set(wasm.LayerOps.batch_norm(input, gamma, beta, mean, variance, epsilon));
244
246
  },
245
247
 
246
248
  /**
247
249
  * Apply global average pooling
248
- * @param {Float32Array} input - Input tensor [C, H, W]
250
+ * @param {Float32Array} input - Input tensor, channels-last [H*W, C]
249
251
  * @param {number} channels - Number of channels
250
252
  * @param {number} spatialSize - H * W
251
253
  * @returns {Float32Array} - Output [C]
252
254
  */
253
255
  globalAvgPool(input, channels, spatialSize) {
254
256
  if (!initialized) throw new Error('Module not initialized');
255
- return new Float32Array(wasm.LayerOps.global_avg_pool(input, channels, spatialSize));
257
+ // WASM signature is (input, height, width, channels); pass H*W as 1 x spatialSize.
258
+ return new Float32Array(wasm.LayerOps.global_avg_pool(input, 1, spatialSize, channels));
256
259
  }
257
260
  };
258
261
 
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@ruvector/cnn",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "CNN feature extraction for image embeddings - SIMD-optimized, pure Rust/WASM",
5
5
  "main": "index.js",
6
- "module": "index.mjs",
7
6
  "types": "index.d.ts",
8
7
  "files": [
9
8
  "index.js",
@@ -15,8 +14,8 @@
15
14
  "README.md"
16
15
  ],
17
16
  "scripts": {
18
- "build": "wasm-pack build ../../crates/ruvector-cnn-wasm --target web --out-dir ../../npm/packages/ruvector-cnn/pkg",
19
- "postbuild": "cp pkg/* . && rm -rf pkg",
17
+ "build": "wasm-pack build ../../../crates/ruvector-cnn-wasm --release --target web --out-dir ../../npm/packages/ruvector-cnn/pkg",
18
+ "postbuild": "cp pkg/ruvector_cnn_wasm* . && rm -rf pkg",
20
19
  "test": "node test.js"
21
20
  },
22
21
  "keywords": [
@@ -34,7 +34,7 @@ export class LayerOps {
34
34
  */
35
35
  static batch_norm(input: Float32Array, gamma: Float32Array, beta: Float32Array, mean: Float32Array, _var: Float32Array, epsilon: number): Float32Array;
36
36
  /**
37
- * Apply global average pooling
37
+ * Apply global average pooling over an NHWC tensor [H, W, C]
38
38
  * Returns one value per channel
39
39
  */
40
40
  static global_avg_pool(input: Float32Array, height: number, width: number, channels: number): Float32Array;
@@ -157,7 +157,7 @@ export interface InitOutput {
157
157
  readonly embedderconfig_new: () => number;
158
158
  readonly layerops_batch_norm: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => void;
159
159
  readonly layerops_global_avg_pool: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
160
- readonly simdops_dot_product: (a: number, b: number, c: number, d: number) => number;
160
+ readonly simdops_dot_product: (a: number, b: number, c: number, d: number, e: number) => void;
161
161
  readonly simdops_l2_normalize: (a: number, b: number, c: number) => void;
162
162
  readonly simdops_relu: (a: number, b: number, c: number) => void;
163
163
  readonly simdops_relu6: (a: number, b: number, c: number) => void;
@@ -166,12 +166,12 @@ export interface InitOutput {
166
166
  readonly wasmcnnembedder_extract: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
167
167
  readonly wasmcnnembedder_new: (a: number, b: number) => void;
168
168
  readonly wasminfonceloss_forward: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
169
- readonly wasminfonceloss_new: (a: number) => number;
169
+ readonly wasminfonceloss_new: (a: number, b: number) => void;
170
170
  readonly wasminfonceloss_temperature: (a: number) => number;
171
171
  readonly wasmtripletloss_forward: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
172
172
  readonly wasmtripletloss_forward_single: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
173
173
  readonly wasmtripletloss_margin: (a: number) => number;
174
- readonly wasmtripletloss_new: (a: number) => number;
174
+ readonly wasmtripletloss_new: (a: number, b: number) => void;
175
175
  readonly init: () => void;
176
176
  readonly __wbg_simdops_free: (a: number, b: number) => void;
177
177
  readonly __wbindgen_export: (a: number, b: number, c: number) => void;
@@ -16,7 +16,7 @@ export class EmbedderConfig {
16
16
  }
17
17
  constructor() {
18
18
  const ret = wasm.embedderconfig_new();
19
- this.__wbg_ptr = ret >>> 0;
19
+ this.__wbg_ptr = ret;
20
20
  EmbedderConfigFinalization.register(this, this.__wbg_ptr, this);
21
21
  return this;
22
22
  }
@@ -108,6 +108,11 @@ export class LayerOps {
108
108
  wasm.layerops_batch_norm(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, epsilon);
109
109
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
110
110
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
111
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
112
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
113
+ if (r3) {
114
+ throw takeObject(r2);
115
+ }
111
116
  var v6 = getArrayF32FromWasm0(r0, r1).slice();
112
117
  wasm.__wbindgen_export(r0, r1 * 4, 4);
113
118
  return v6;
@@ -116,7 +121,7 @@ export class LayerOps {
116
121
  }
117
122
  }
118
123
  /**
119
- * Apply global average pooling
124
+ * Apply global average pooling over an NHWC tensor [H, W, C]
120
125
  * Returns one value per channel
121
126
  * @param {Float32Array} input
122
127
  * @param {number} height
@@ -132,6 +137,11 @@ export class LayerOps {
132
137
  wasm.layerops_global_avg_pool(retptr, ptr0, len0, height, width, channels);
133
138
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
134
139
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
140
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
141
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
142
+ if (r3) {
143
+ throw takeObject(r2);
144
+ }
135
145
  var v2 = getArrayF32FromWasm0(r0, r1).slice();
136
146
  wasm.__wbindgen_export(r0, r1 * 4, 4);
137
147
  return v2;
@@ -163,12 +173,23 @@ export class SimdOps {
163
173
  * @returns {number}
164
174
  */
165
175
  static dot_product(a, b) {
166
- const ptr0 = passArrayF32ToWasm0(a, wasm.__wbindgen_export2);
167
- const len0 = WASM_VECTOR_LEN;
168
- const ptr1 = passArrayF32ToWasm0(b, wasm.__wbindgen_export2);
169
- const len1 = WASM_VECTOR_LEN;
170
- const ret = wasm.simdops_dot_product(ptr0, len0, ptr1, len1);
171
- return ret;
176
+ try {
177
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
178
+ const ptr0 = passArrayF32ToWasm0(a, wasm.__wbindgen_export2);
179
+ const len0 = WASM_VECTOR_LEN;
180
+ const ptr1 = passArrayF32ToWasm0(b, wasm.__wbindgen_export2);
181
+ const len1 = WASM_VECTOR_LEN;
182
+ wasm.simdops_dot_product(retptr, ptr0, len0, ptr1, len1);
183
+ var r0 = getDataViewMemory0().getFloat32(retptr + 4 * 0, true);
184
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
185
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
186
+ if (r2) {
187
+ throw takeObject(r1);
188
+ }
189
+ return r0;
190
+ } finally {
191
+ wasm.__wbindgen_add_to_stack_pointer(16);
192
+ }
172
193
  }
173
194
  /**
174
195
  * L2 normalize a vector (returns new array)
@@ -326,7 +347,7 @@ export class WasmCnnEmbedder {
326
347
  if (r2) {
327
348
  throw takeObject(r1);
328
349
  }
329
- this.__wbg_ptr = r0 >>> 0;
350
+ this.__wbg_ptr = r0;
330
351
  WasmCnnEmbedderFinalization.register(this, this.__wbg_ptr, this);
331
352
  return this;
332
353
  } finally {
@@ -380,10 +401,21 @@ export class WasmInfoNCELoss {
380
401
  * @param {number} temperature
381
402
  */
382
403
  constructor(temperature) {
383
- const ret = wasm.wasminfonceloss_new(temperature);
384
- this.__wbg_ptr = ret >>> 0;
385
- WasmInfoNCELossFinalization.register(this, this.__wbg_ptr, this);
386
- return this;
404
+ try {
405
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
406
+ wasm.wasminfonceloss_new(retptr, temperature);
407
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
408
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
409
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
410
+ if (r2) {
411
+ throw takeObject(r1);
412
+ }
413
+ this.__wbg_ptr = r0;
414
+ WasmInfoNCELossFinalization.register(this, this.__wbg_ptr, this);
415
+ return this;
416
+ } finally {
417
+ wasm.__wbindgen_add_to_stack_pointer(16);
418
+ }
387
419
  }
388
420
  /**
389
421
  * Get the temperature parameter
@@ -480,10 +512,21 @@ export class WasmTripletLoss {
480
512
  * @param {number} margin
481
513
  */
482
514
  constructor(margin) {
483
- const ret = wasm.wasmtripletloss_new(margin);
484
- this.__wbg_ptr = ret >>> 0;
485
- WasmTripletLossFinalization.register(this, this.__wbg_ptr, this);
486
- return this;
515
+ try {
516
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
517
+ wasm.wasmtripletloss_new(retptr, margin);
518
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
519
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
520
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
521
+ if (r2) {
522
+ throw takeObject(r1);
523
+ }
524
+ this.__wbg_ptr = r0;
525
+ WasmTripletLossFinalization.register(this, this.__wbg_ptr, this);
526
+ return this;
527
+ } finally {
528
+ wasm.__wbindgen_add_to_stack_pointer(16);
529
+ }
487
530
  }
488
531
  }
489
532
  if (Symbol.dispose) WasmTripletLoss.prototype[Symbol.dispose] = WasmTripletLoss.prototype.free;
@@ -494,11 +537,10 @@ if (Symbol.dispose) WasmTripletLoss.prototype[Symbol.dispose] = WasmTripletLoss.
494
537
  export function init() {
495
538
  wasm.init();
496
539
  }
497
-
498
540
  function __wbg_get_imports() {
499
541
  const import0 = {
500
542
  __proto__: null,
501
- __wbg___wbindgen_throw_39bc967c0e5a9b58: function(arg0, arg1) {
543
+ __wbg___wbindgen_throw_ea4887a5f8f9a9db: function(arg0, arg1) {
502
544
  throw new Error(getStringFromWasm0(arg0, arg1));
503
545
  },
504
546
  __wbg_error_a6fa202b58aa1cd3: function(arg0, arg1) {
@@ -540,22 +582,22 @@ function __wbg_get_imports() {
540
582
 
541
583
  const EmbedderConfigFinalization = (typeof FinalizationRegistry === 'undefined')
542
584
  ? { register: () => {}, unregister: () => {} }
543
- : new FinalizationRegistry(ptr => wasm.__wbg_embedderconfig_free(ptr >>> 0, 1));
585
+ : new FinalizationRegistry(ptr => wasm.__wbg_embedderconfig_free(ptr, 1));
544
586
  const LayerOpsFinalization = (typeof FinalizationRegistry === 'undefined')
545
587
  ? { register: () => {}, unregister: () => {} }
546
- : new FinalizationRegistry(ptr => wasm.__wbg_layerops_free(ptr >>> 0, 1));
588
+ : new FinalizationRegistry(ptr => wasm.__wbg_layerops_free(ptr, 1));
547
589
  const SimdOpsFinalization = (typeof FinalizationRegistry === 'undefined')
548
590
  ? { register: () => {}, unregister: () => {} }
549
- : new FinalizationRegistry(ptr => wasm.__wbg_simdops_free(ptr >>> 0, 1));
591
+ : new FinalizationRegistry(ptr => wasm.__wbg_simdops_free(ptr, 1));
550
592
  const WasmCnnEmbedderFinalization = (typeof FinalizationRegistry === 'undefined')
551
593
  ? { register: () => {}, unregister: () => {} }
552
- : new FinalizationRegistry(ptr => wasm.__wbg_wasmcnnembedder_free(ptr >>> 0, 1));
594
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmcnnembedder_free(ptr, 1));
553
595
  const WasmInfoNCELossFinalization = (typeof FinalizationRegistry === 'undefined')
554
596
  ? { register: () => {}, unregister: () => {} }
555
- : new FinalizationRegistry(ptr => wasm.__wbg_wasminfonceloss_free(ptr >>> 0, 1));
597
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasminfonceloss_free(ptr, 1));
556
598
  const WasmTripletLossFinalization = (typeof FinalizationRegistry === 'undefined')
557
599
  ? { register: () => {}, unregister: () => {} }
558
- : new FinalizationRegistry(ptr => wasm.__wbg_wasmtripletloss_free(ptr >>> 0, 1));
600
+ : new FinalizationRegistry(ptr => wasm.__wbg_wasmtripletloss_free(ptr, 1));
559
601
 
560
602
  function addHeapObject(obj) {
561
603
  if (heap_next === heap.length) heap.push(heap.length + 1);
@@ -600,8 +642,7 @@ function getFloat32ArrayMemory0() {
600
642
  }
601
643
 
602
644
  function getStringFromWasm0(ptr, len) {
603
- ptr = ptr >>> 0;
604
- return decodeText(ptr, len);
645
+ return decodeText(ptr >>> 0, len);
605
646
  }
606
647
 
607
648
  let cachedUint8ArrayMemory0 = null;
@@ -709,8 +750,9 @@ if (!('encodeInto' in cachedTextEncoder)) {
709
750
 
710
751
  let WASM_VECTOR_LEN = 0;
711
752
 
712
- let wasmModule, wasm;
753
+ let wasmModule, wasmInstance, wasm;
713
754
  function __wbg_finalize_init(instance, module) {
755
+ wasmInstance = instance;
714
756
  wasm = instance.exports;
715
757
  wasmModule = module;
716
758
  cachedDataViewMemory0 = null;
Binary file
@@ -15,7 +15,7 @@ export const __wbg_wasmtripletloss_free: (a: number, b: number) => void;
15
15
  export const embedderconfig_new: () => number;
16
16
  export const layerops_batch_norm: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => void;
17
17
  export const layerops_global_avg_pool: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
18
- export const simdops_dot_product: (a: number, b: number, c: number, d: number) => number;
18
+ export const simdops_dot_product: (a: number, b: number, c: number, d: number, e: number) => void;
19
19
  export const simdops_l2_normalize: (a: number, b: number, c: number) => void;
20
20
  export const simdops_relu: (a: number, b: number, c: number) => void;
21
21
  export const simdops_relu6: (a: number, b: number, c: number) => void;
@@ -24,12 +24,12 @@ export const wasmcnnembedder_embedding_dim: (a: number) => number;
24
24
  export const wasmcnnembedder_extract: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
25
25
  export const wasmcnnembedder_new: (a: number, b: number) => void;
26
26
  export const wasminfonceloss_forward: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
27
- export const wasminfonceloss_new: (a: number) => number;
27
+ export const wasminfonceloss_new: (a: number, b: number) => void;
28
28
  export const wasminfonceloss_temperature: (a: number) => number;
29
29
  export const wasmtripletloss_forward: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
30
30
  export const wasmtripletloss_forward_single: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
31
31
  export const wasmtripletloss_margin: (a: number) => number;
32
- export const wasmtripletloss_new: (a: number) => number;
32
+ export const wasmtripletloss_new: (a: number, b: number) => void;
33
33
  export const init: () => void;
34
34
  export const __wbg_simdops_free: (a: number, b: number) => void;
35
35
  export const __wbindgen_export: (a: number, b: number, c: number) => void;