addernet 1.2.0__tar.gz → 1.2.2__tar.gz

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 (48) hide show
  1. {addernet-1.2.0/addernet.egg-info → addernet-1.2.2}/PKG-INFO +1 -1
  2. {addernet-1.2.0 → addernet-1.2.2}/addernet/addernet_hdc.py +16 -2
  3. {addernet-1.2.0 → addernet-1.2.2/addernet.egg-info}/PKG-INFO +1 -1
  4. {addernet-1.2.0 → addernet-1.2.2}/pyproject.toml +1 -1
  5. {addernet-1.2.0 → addernet-1.2.2}/python/addernet_hdc.py +158 -12
  6. {addernet-1.2.0 → addernet-1.2.2}/setup.py +1 -1
  7. {addernet-1.2.0 → addernet-1.2.2}/LICENSE +0 -0
  8. {addernet-1.2.0 → addernet-1.2.2}/MANIFEST.in +0 -0
  9. {addernet-1.2.0 → addernet-1.2.2}/Makefile +0 -0
  10. {addernet-1.2.0 → addernet-1.2.2}/README.md +0 -0
  11. {addernet-1.2.0 → addernet-1.2.2}/README_DEV.md +0 -0
  12. {addernet-1.2.0 → addernet-1.2.2}/addernet/__init__.py +0 -0
  13. {addernet-1.2.0 → addernet-1.2.2}/addernet/addernet.py +0 -0
  14. {addernet-1.2.0 → addernet-1.2.2}/addernet/attention.py +0 -0
  15. {addernet-1.2.0 → addernet-1.2.2}/addernet/boost.py +0 -0
  16. {addernet-1.2.0 → addernet-1.2.2}/addernet/build_ext.py +0 -0
  17. {addernet-1.2.0 → addernet-1.2.2}/addernet/cluster.py +0 -0
  18. {addernet-1.2.0 → addernet-1.2.2}/addernet/libaddernet.so +0 -0
  19. {addernet-1.2.0 → addernet-1.2.2}/addernet/libaddernet_hdc.so +0 -0
  20. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet.c +0 -0
  21. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet.h +0 -0
  22. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet_hdc.c +0 -0
  23. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/addernet_hdc.h +0 -0
  24. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core.c +0 -0
  25. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core.h +0 -0
  26. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_core_cuda.c +0 -0
  27. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_cuda_batch.c +0 -0
  28. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_lsh.c +0 -0
  29. {addernet-1.2.0 → addernet-1.2.2}/addernet/src/hdc_lsh.h +0 -0
  30. {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/SOURCES.txt +0 -0
  31. {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/dependency_links.txt +0 -0
  32. {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/entry_points.txt +0 -0
  33. {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/requires.txt +0 -0
  34. {addernet-1.2.0 → addernet-1.2.2}/addernet.egg-info/top_level.txt +0 -0
  35. {addernet-1.2.0 → addernet-1.2.2}/python/__init__.py +0 -0
  36. {addernet-1.2.0 → addernet-1.2.2}/python/addernet.py +0 -0
  37. {addernet-1.2.0 → addernet-1.2.2}/setup.cfg +0 -0
  38. {addernet-1.2.0 → addernet-1.2.2}/src/addernet.c +0 -0
  39. {addernet-1.2.0 → addernet-1.2.2}/src/addernet.h +0 -0
  40. {addernet-1.2.0 → addernet-1.2.2}/src/addernet_cuda.cu +0 -0
  41. {addernet-1.2.0 → addernet-1.2.2}/src/addernet_hdc.c +0 -0
  42. {addernet-1.2.0 → addernet-1.2.2}/src/addernet_hdc.h +0 -0
  43. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core.c +0 -0
  44. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core.h +0 -0
  45. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_core_cuda.c +0 -0
  46. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_cuda_batch.c +0 -0
  47. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_lsh.c +0 -0
  48. {addernet-1.2.0 → addernet-1.2.2}/src/hdc_lsh.h +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: addernet
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Neural networks with zero multiplications at inference. AdderNet + HDC for embedded systems.
5
5
  Author: AdderNet Team
6
6
  License: Apache-2.0
@@ -40,6 +40,18 @@ if _lib is None:
40
40
  "Build it first: cd addernet_lib && make hdc"
41
41
  )
42
42
 
43
+ # ---- Optional CUDA Native library ----
44
+
45
+ _lib_cuda = None
46
+ try:
47
+ for _name in _LIB_NAMES:
48
+ _cuda_path = _name.replace("libaddernet_hdc.so", "libaddernet_cuda.so")
49
+ if os.path.exists(_cuda_path):
50
+ _lib_cuda = ctypes.CDLL(_cuda_path)
51
+ break
52
+ except OSError:
53
+ pass
54
+
43
55
  # ---- Opaque pointer type ----
44
56
 
45
57
  _AnHdcPtr = ctypes.c_void_p
@@ -213,7 +225,7 @@ class AdderNetHDC:
213
225
  """
214
226
 
215
227
  def __init__(self, n_vars=1, n_classes=2, table_size=256, bias=None,
216
- seed=42, _ptr=None):
228
+ seed=42, use_gpu=False, _ptr=None):
217
229
  """
218
230
  Create a new model.
219
231
 
@@ -223,7 +235,10 @@ class AdderNetHDC:
223
235
  table_size: encoding table size per variable (power of 2)
224
236
  bias: list of bias values per variable (default: table_size//2)
225
237
  seed: random seed for reproducibility
238
+ use_gpu: toggle between CPU and CUDA backend
226
239
  """
240
+ self.use_gpu = use_gpu
241
+
227
242
  if _ptr is not None:
228
243
  self._ptr = _ptr
229
244
  self._n_vars = n_vars
@@ -706,4 +721,3 @@ def hdc_detect_backend():
706
721
  """
707
722
  backends = ["SCALAR", "AVX2", "NEON"]
708
723
  return backends[_lib.hdc_detect_backend()]
709
- ackends[_lib.hdc_detect_backend()]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: addernet
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: Neural networks with zero multiplications at inference. AdderNet + HDC for embedded systems.
5
5
  Author: AdderNet Team
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "addernet"
7
- version = "1.2.0"
7
+ version = "1.2.2"
8
8
  description = "Neural networks with zero multiplications at inference. AdderNet + HDC for embedded systems."
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
@@ -40,6 +40,18 @@ if _lib is None:
40
40
  "Build it first: cd addernet_lib && make hdc"
41
41
  )
42
42
 
43
+ # ---- Optional CUDA Native library ----
44
+
45
+ _lib_cuda = None
46
+ try:
47
+ for _name in _LIB_NAMES:
48
+ _cuda_path = _name.replace("libaddernet_hdc.so", "libaddernet_cuda.so")
49
+ if os.path.exists(_cuda_path):
50
+ _lib_cuda = ctypes.CDLL(_cuda_path)
51
+ break
52
+ except OSError:
53
+ pass
54
+
43
55
  # ---- Opaque pointer type ----
44
56
 
45
57
  _AnHdcPtr = ctypes.c_void_p
@@ -63,7 +75,7 @@ _lib.an_hdc_train.argtypes = [
63
75
  ctypes.c_int,
64
76
  ]
65
77
 
66
- _lib.an_hdc_retrain.restype = None
78
+ _lib.an_hdc_retrain.restype = ctypes.c_int
67
79
  _lib.an_hdc_retrain.argtypes = [
68
80
  _AnHdcPtr,
69
81
  ctypes.POINTER(ctypes.c_double),
@@ -71,9 +83,11 @@ _lib.an_hdc_retrain.argtypes = [
71
83
  ctypes.c_int,
72
84
  ctypes.c_int,
73
85
  ctypes.c_float,
74
- ctypes.c_float,
86
+ ctypes.c_int,
75
87
  ctypes.c_float,
76
88
  ctypes.c_int,
89
+ ctypes.c_int,
90
+ ctypes.POINTER(ctypes.c_int),
77
91
  ]
78
92
 
79
93
  _lib.an_hdc_predict.restype = ctypes.c_int
@@ -96,6 +110,15 @@ _lib.an_hdc_predict_batch_avx.argtypes = [
96
110
  ctypes.c_int,
97
111
  ]
98
112
 
113
+ if _lib_cuda is not None:
114
+ _lib_cuda.an_hdc_predict_batch_cuda.restype = ctypes.c_int
115
+ _lib_cuda.an_hdc_predict_batch_cuda.argtypes = [
116
+ _AnHdcPtr,
117
+ ctypes.POINTER(ctypes.c_double),
118
+ ctypes.POINTER(ctypes.c_int),
119
+ ctypes.c_int,
120
+ ]
121
+
99
122
  _lib.an_hdc_save.restype = ctypes.c_int
100
123
  _lib.an_hdc_save.argtypes = [_AnHdcPtr, ctypes.c_char_p]
101
124
 
@@ -145,6 +168,15 @@ _lib.an_hdc_predict_top_k.argtypes = [
145
168
  ctypes.c_int,
146
169
  ]
147
170
 
171
+ # Problem 6: Interaction encoding
172
+ _lib.an_hdc_set_interactions.restype = None
173
+ _lib.an_hdc_set_interactions.argtypes = [
174
+ _AnHdcPtr,
175
+ ctypes.POINTER(ctypes.c_int),
176
+ ctypes.POINTER(ctypes.c_int),
177
+ ctypes.c_int,
178
+ ]
179
+
148
180
  # OPT-8: Backend detection
149
181
  _lib.hdc_detect_backend.restype = ctypes.c_int
150
182
  _lib.hdc_detect_backend.argtypes = []
@@ -155,6 +187,7 @@ _lib.hv_seed.argtypes = [ctypes.c_uint]
155
187
  # HDC primitive bindings (for direct hypervector manipulation)
156
188
 
157
189
  _HV_WORDS = 40 # HDC_WORDS = ceil(2500/64)
190
+ _HV_DIM = 2500 # HDC_DIM — actual hypervector dimensionality
158
191
  HDC_BYTES = _HV_WORDS * 8 # 320 bytes per hypervector
159
192
  _HV_t = ctypes.c_uint64 * _HV_WORDS
160
193
 
@@ -192,7 +225,7 @@ class AdderNetHDC:
192
225
  """
193
226
 
194
227
  def __init__(self, n_vars=1, n_classes=2, table_size=256, bias=None,
195
- seed=42, _ptr=None):
228
+ seed=42, use_gpu=False, _ptr=None):
196
229
  """
197
230
  Create a new model.
198
231
 
@@ -202,7 +235,10 @@ class AdderNetHDC:
202
235
  table_size: encoding table size per variable (power of 2)
203
236
  bias: list of bias values per variable (default: table_size//2)
204
237
  seed: random seed for reproducibility
238
+ use_gpu: toggle between CPU and CUDA backend
205
239
  """
240
+ self.use_gpu = use_gpu
241
+
206
242
  if _ptr is not None:
207
243
  self._ptr = _ptr
208
244
  self._n_vars = n_vars
@@ -228,7 +264,8 @@ class AdderNetHDC:
228
264
  _lib.an_hdc_free(self._ptr)
229
265
  self._ptr = None
230
266
 
231
- def train(self, X, y, n_iter=0, lr=1.0, margin=0, regenerate=0.0, patience=0):
267
+ def train(self, X, y, n_iter=0, lr=1.0, margin=0, regenerate=0.0,
268
+ patience=10, verbose=False, interactions=0):
232
269
  """
233
270
  Train the codebook from labeled data, with optional iterative retraining.
234
271
 
@@ -241,9 +278,22 @@ class AdderNetHDC:
241
278
  y: n_samples class labels (int, 0-indexed)
242
279
  n_iter: number of iterative correction passes (0 = single-pass, default)
243
280
  lr: learning rate for iterative retraining (default 1.0)
244
- margin: additive RefineHD margin in Hamming distance units (0 = AdaptHD pure, 50 recommended)
281
+ margin: RefineHD margin aceita 4 formas:
282
+ 0 / None → desligado (AdaptHD puro)
283
+ float 0-1 → fração de D (ex: 0.05 = 5% de D)
284
+ '5%' → percentual string (ex: '5%', '10%')
285
+ int > 0 → distância Hamming absoluta em bits
245
286
  regenerate: NeuralHD dimension regeneration rate (0.0 = off, 0.02-0.05 recommended)
246
287
  patience: early stopping patience in epochs (0 = disabled, 5 recommended)
288
+ verbose: if True, print epoch progress to stderr every 10 epochs. If int, print every N epochs.
289
+ interactions: number of top correlated feature pairs to encode (0 = disabled, 10 recommended)
290
+ Returns:
291
+ dict with training history:
292
+ 'epochs_run': epochs actually executed,
293
+ 'best_val_accuracy': best validation accuracy (last 25% of data),
294
+ 'best_train_accuracy': best training accuracy (first 75% of data),
295
+ 'best_epoch': epoch of best val accuracy,
296
+ 'stopped_early': True if early stopping triggered
247
297
  """
248
298
  X = np.ascontiguousarray(X, dtype=np.float64)
249
299
  y = np.ascontiguousarray(y, dtype=np.int32)
@@ -255,6 +305,35 @@ class AdderNetHDC:
255
305
  if len(y) != n:
256
306
  raise ValueError(f"X has {n} samples but y has {len(y)}")
257
307
 
308
+ # Default history for single-pass training
309
+ history = {
310
+ 'epochs_run': 0,
311
+ 'best_val_accuracy': 0.0,
312
+ 'best_train_accuracy': 0.0,
313
+ 'best_epoch': 0,
314
+ 'stopped_early': False,
315
+ }
316
+
317
+ # Problema 6: Detect and set interaction pairs
318
+ if interactions > 0 and X.shape[1] > 1:
319
+ corr = np.corrcoef(X.T)
320
+ pairs = []
321
+ for ii in range(corr.shape[0]):
322
+ for jj in range(ii + 1, corr.shape[1]):
323
+ pairs.append((abs(corr[ii, jj]), ii, jj))
324
+ pairs.sort(reverse=True)
325
+ top_pairs = pairs[:interactions]
326
+ if top_pairs:
327
+ pairs_i = np.array([p[1] for p in top_pairs], dtype=np.int32)
328
+ pairs_j = np.array([p[2] for p in top_pairs], dtype=np.int32)
329
+ _lib.an_hdc_set_interactions(
330
+ self._ptr,
331
+ pairs_i.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
332
+ pairs_j.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
333
+ len(top_pairs),
334
+ )
335
+
336
+ # Initial train (encodes samples including interactions)
258
337
  _lib.an_hdc_train(
259
338
  self._ptr,
260
339
  X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
@@ -263,6 +342,46 @@ class AdderNetHDC:
263
342
  )
264
343
 
265
344
  if n_iter > 0:
345
+ D = _HV_WORDS * 64 # total bits no hipervector (2500)
346
+
347
+ # ── Conversão de margin ──────────────────────────────
348
+ if margin == 0 or margin is None:
349
+ margin_int = 0 # desligado — AdaptHD puro
350
+
351
+ elif isinstance(margin, str) and margin.endswith('%'):
352
+ pct = float(margin[:-1]) / 100.0
353
+ margin_int = max(1, int(pct * D))
354
+
355
+ elif isinstance(margin, float) and 0.0 < margin < 1.0:
356
+ margin_int = max(1, int(margin * D))
357
+
358
+ elif isinstance(margin, int) and margin > 0:
359
+ margin_int = margin
360
+
361
+ else:
362
+ raise ValueError(
363
+ f"margin deve ser: 0 (off), float 0-1 (fração de D), "
364
+ f"'5%' (percentual), ou int (bits). Recebeu: {margin!r}"
365
+ )
366
+
367
+ # Clamp: nunca maior que 20% de D
368
+ margin_int = min(margin_int, int(D * 0.20))
369
+
370
+ if verbose:
371
+ if margin_int == 0:
372
+ print(f" margin=off (AdaptHD puro)")
373
+ else:
374
+ print(f" margin={margin!r} → {margin_int} bits ({margin_int/D*100:.1f}% de D={D})")
375
+
376
+ # Verbose level: True → 10, int → as-is, False → 0
377
+ if verbose is True:
378
+ verbose_level = 10
379
+ elif isinstance(verbose, int) and verbose > 0:
380
+ verbose_level = verbose
381
+ else:
382
+ verbose_level = 0
383
+
384
+ epochs_run = ctypes.c_int(0)
266
385
  _lib.an_hdc_retrain(
267
386
  self._ptr,
268
387
  X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
@@ -270,11 +389,27 @@ class AdderNetHDC:
270
389
  n,
271
390
  n_iter,
272
391
  ctypes.c_float(lr),
273
- ctypes.c_float(margin),
392
+ ctypes.c_int(margin_int),
274
393
  ctypes.c_float(regenerate),
275
394
  ctypes.c_int(patience),
395
+ ctypes.c_int(verbose_level),
396
+ ctypes.byref(epochs_run),
276
397
  )
277
398
 
399
+ # Compute final accuracies on train/val split
400
+ n_val = max(1, n // 4)
401
+ n_train_split = n - n_val
402
+ train_acc = float(self.accuracy(X[:n_train_split], y[:n_train_split]))
403
+ val_acc = float(self.accuracy(X[n_train_split:], y[n_train_split:]))
404
+
405
+ history['epochs_run'] = epochs_run.value
406
+ history['best_val_accuracy'] = val_acc
407
+ history['best_train_accuracy'] = train_acc
408
+ history['best_epoch'] = epochs_run.value
409
+ history['stopped_early'] = (epochs_run.value < n_iter)
410
+
411
+ return history
412
+
278
413
  def predict(self, x):
279
414
  """
280
415
  Classify one sample.
@@ -304,12 +439,23 @@ class AdderNetHDC:
304
439
  X = X.reshape(-1, self._n_vars)
305
440
  n = X.shape[0]
306
441
  outputs = np.empty(n, dtype=np.int32)
307
- _lib.an_hdc_predict_batch(
308
- self._ptr,
309
- X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
310
- outputs.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
311
- n,
312
- )
442
+
443
+ if getattr(self, 'use_gpu', False):
444
+ if _lib_cuda is None:
445
+ raise RuntimeError("CUDA backend requested but libaddernet_cuda.so not found")
446
+ _lib_cuda.an_hdc_predict_batch_cuda(
447
+ self._ptr,
448
+ X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
449
+ outputs.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
450
+ n,
451
+ )
452
+ else:
453
+ _lib.an_hdc_predict_batch(
454
+ self._ptr,
455
+ X.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
456
+ outputs.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
457
+ n,
458
+ )
313
459
  return outputs
314
460
 
315
461
  def predict_batch_avx(self, X):
@@ -71,7 +71,7 @@ if bdist_wheel is not None:
71
71
  cmdclass_dict['bdist_wheel'] = bdist_wheel
72
72
 
73
73
  setup(
74
- version="1.2.0",
74
+ version="1.2.2",
75
75
  ext_modules=ext_modules,
76
76
  cmdclass=cmdclass_dict,
77
77
  package_data={'addernet': ['src/*.c', 'src/*.h']}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes