AbstractIntegratedModule 1.2.5__tar.gz → 1.2.7__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 (23) hide show
  1. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
  2. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.py +124 -40
  3. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractOptimizedModules.c +200 -200
  4. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/PKG-INFO +1 -1
  5. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/README.md +110 -40
  6. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/pyproject.toml +1 -1
  7. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/setup.py +1 -1
  8. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
  9. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
  10. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
  11. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
  12. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/AbstractOptimizedModules.pyx +0 -0
  13. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/MANIFEST.in +0 -0
  14. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/Cargo.toml +0 -0
  15. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/pyproject.toml +0 -0
  16. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/src/lib.rs +0 -0
  17. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
  18. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
  19. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
  20. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
  21. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
  22. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
  23. {abstractintegratedmodule-1.2.5 → abstractintegratedmodule-1.2.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractIntegratedModule
3
- Version: 1.2.5
3
+ Version: 1.2.7
4
4
  Summary: Integrated Pipeline with Specialized Non-LLM AI Agent Framework for ARM64 architecture
5
5
  Author: Micro-Novelty
6
6
  Author-email: Micro-Novelty <hernikpuspita5@gmail.com>
@@ -1825,9 +1825,11 @@ class SNNNetwork:
1825
1825
  optimizer.step(self.layers)
1826
1826
  return loss, logits
1827
1827
 
1828
- def predict(self, input_spikes):
1828
+ def predict(self, input_spikes, task='classification'):
1829
1829
  self.eval()
1830
1830
  logits = self.forward(input_spikes)
1831
+ if task == 'regression':
1832
+ return logits[:, 0], logits
1831
1833
  return np.argmax(logits, axis=1), logits
1832
1834
 
1833
1835
  def firing_rates(self):
@@ -10979,12 +10981,17 @@ class AgentDistributedInference:
10979
10981
  rules = payload.get('rules')
10980
10982
  X = payload.get('X')
10981
10983
  y = payload.get('y')
10984
+
10982
10985
 
10983
10986
  # Sanitize if needed
10984
10987
  if test_titles:
10985
10988
  test_titles = self._sanitize_structured(test_titles)
10986
10989
  if label_map:
10987
10990
  label_map = self._sanitize_structured(label_map)
10991
+ if label_map is None or not isinstance(label_map, dict):
10992
+ raise ValueError('[>] Label map is None or invalid label map instance!')
10993
+
10994
+
10988
10995
  if rules:
10989
10996
  rules = self._sanitize_structured(rules)
10990
10997
  if X is not None:
@@ -10992,10 +10999,12 @@ class AgentDistributedInference:
10992
10999
  if y is not None:
10993
11000
  y = self._sanitize_structured(y)
10994
11001
 
10995
- if X is None or y is None:
10996
- print('[=] Got necessary titles, label_map and rules.')
11002
+ if X is None and y is None and test_titles is not None and rules is not None:
11003
+ print('[=] Got necessary titles, label_map, rules samples')
11004
+ elif X is not None and y is not None and test_titles is None and rules is None:
11005
+ print('[=] Got necessary titles, rules, label_map, X And Y samples.')
10997
11006
  else:
10998
- print('[=] Got necessary titles, label_map, rules and X And Y samples.')
11007
+ raise ValueError('[>] All samples are None!')
10999
11008
  else:
11000
11009
  text = payload.get('text')
11001
11010
  if text:
@@ -11006,9 +11015,8 @@ class AgentDistributedInference:
11006
11015
  text = str(payload) if payload else None
11007
11016
 
11008
11017
  if not text and not test_titles:
11009
- print('[===] ERROR: No text or test_titles in message payload!')
11010
- return {'type': self.MSG_TYPES['PREDICT_RESPONSE'], 'error': 'No text or test_titles provided'}
11011
-
11018
+ print('[INFO] No text or test_titles in message payload.')
11019
+
11012
11020
  # Run the actual prediction
11013
11021
  print(f'[=] Initiating prediction method')
11014
11022
  try:
@@ -13340,16 +13348,16 @@ class IntegratedPipeline:
13340
13348
  if value.shape[0] != num_classes and \
13341
13349
  (value.ndim < 2 or value.shape[1] != num_classes):
13342
13350
  return (True,
13343
- f"Array shape {value.shape} doesn't match "
13351
+ f"[>] Array shape {value.shape} doesn't match "
13344
13352
  f"{num_classes} classes in key '{key}'",
13345
13353
  "Hybrid feature stored incorrectly, clear entry")
13346
13354
  if value.size == 0:
13347
13355
  return (True,
13348
- f"Empty array in key '{key}'",
13356
+ f"[>] Empty array in key '{key}'",
13349
13357
  "Corrupted array, clear entry")
13350
13358
  if not np.isfinite(value).all():
13351
13359
  return (True,
13352
- f"NaN/Inf values in array at key '{key}'",
13360
+ f"[>] NaN/Inf values in array at key '{key}'",
13353
13361
  "Corrupted values, clear entry")
13354
13362
 
13355
13363
  # validate tuple values in dict
@@ -13359,10 +13367,10 @@ class IntegratedPipeline:
13359
13367
  )
13360
13368
  if corrupted:
13361
13369
  return (True,
13362
- f"Corrupted tuple value at key '{key}': {reason}",
13370
+ f"[>] Corrupted tuple value at key '{key}': {reason}",
13363
13371
  fix)
13364
13372
 
13365
- return (False, "Valid dict structure", None)
13373
+ return (False, "[>] Valid dict structure", None)
13366
13374
 
13367
13375
 
13368
13376
  def initialize_fitting(self, text):
@@ -13381,23 +13389,22 @@ class IntegratedPipeline:
13381
13389
  unique_in_batch = len(np.unique(y_raw))
13382
13390
 
13383
13391
  if num_classes is None:
13384
- # no model exists yet — this is the legitimate case where
13392
+ # no model exists — this is the legitimate case where
13385
13393
  # inferring from y_raw is correct (e.g. first-time initialization)
13386
13394
  num_classes = unique_in_batch
13387
13395
  print(f'[=] No existing model — initializing with {num_classes} classes '
13388
13396
  f'from this batch')
13389
13397
  elif unique_in_batch > num_classes:
13390
- # batch contains MORE classes than the model supports
13391
- # this is a real problem — can't onehot-encode into a smaller space
13398
+ # batch contains more classes than the model supports
13399
+ # a problem — can't onehot-encode into a smaller space
13392
13400
  print(f'[⚠️] Batch contains {unique_in_batch} unique classes but model '
13393
13401
  f'only supports {num_classes} — expanding to {unique_in_batch}')
13394
13402
  num_classes = unique_in_batch
13395
13403
  elif unique_in_batch < num_classes:
13396
13404
  # batch just doesn't happen to contain all classes.
13397
- # use the model's full num_classes so onehot stays the right width
13405
+ # use model's full num_classes so onehot stays the right width
13398
13406
  print(f'[=] Batch only contains {unique_in_batch}/{num_classes} classes '
13399
13407
  f'— using full model class count for onehot width')
13400
- # num_classes stays as the model's true value, no change needed
13401
13408
 
13402
13409
  y_onehot = np.zeros((len(y_raw), num_classes))
13403
13410
 
@@ -13408,9 +13415,7 @@ class IntegratedPipeline:
13408
13415
  else:
13409
13416
  print(f'[⚠️] Label {label_idx} out of range for {num_classes} classes '
13410
13417
  f'at sample {idx} — skipping onehot assignment')
13411
- # leaves that row as all-zeros rather than crashing or
13412
- # silently assigning to a wrong class
13413
-
13418
+
13414
13419
  return y_onehot
13415
13420
 
13416
13421
 
@@ -20651,9 +20656,9 @@ class SNNUtility:
20651
20656
  # SNN Network Build
20652
20657
  #-----------------
20653
20658
  def build_snn_network(n_in, n_hidden, n_classes, rng, decay=0.95,
20654
- threshold=0.1, input_noise_std=0.0, reduction='mean'):
20659
+ threshold=0.1, input_noise_std=0.0, reduction='mean', p=0.2):
20655
20660
  layer1 = LIFDenseLayer(n_in, n_hidden, decay=decay, threshold=threshold, rng=rng)
20656
- drop1 = SpikeDropout(p=0.2, rng=rng)
20661
+ drop1 = SpikeDropout(p=p, rng=rng)
20657
20662
  readout = ReadoutLayer(n_hidden, n_classes, decay=decay, rng=rng)
20658
20663
  net = SNNNetwork([layer1, drop1, readout], readout_reduction=reduction,
20659
20664
  input_noise_std=input_noise_std, rng=rng)
@@ -21117,23 +21122,69 @@ def print_confidence_report(results, top_k=3, max_print_threshold=50):
21117
21122
  f"|| Top-{top_k}: [{top_str}]")
21118
21123
  return pred_cache
21119
21124
 
21125
+ def initialize_snn_network(X=None, y=None, label_map=None, n_hidden=64, n_in=None, n_classes=None, seed=0, random_state=42):
21126
+ try:
21127
+ utility = SNNUtility()
21128
+ rng = utility.seed_everything(seed)
21129
+ if n_in is not None and n_classes is not None:
21130
+ net, hidden_layer = build_snn_network(n_in, n_hidden, n_classes, rng)
21131
+ else:
21132
+ X_train, X_test, y_train, y_test, X_val, y_val = _prepare_train_val_split(X=X, y=y, random_state=random_state)
21133
+ n_in = X_train.shape[1]
21134
+ n_classes = max(len(label_map), int(y_train.max() + 1))
21135
+ net, hidden_layer = build_snn_network(n_in, n_hidden, n_classes, rng)
21120
21136
 
21137
+ print(f'[>] Initialized SNN Network with hidden dim: {n_hidden}')
21138
+ return net, hidden_layer, utility
21139
+ except Exception as e:
21140
+ print(f'[>] Error initializing SNN Network and hidden layer: {e}')
21141
+ return None, None, None
21121
21142
 
21122
- def train_snn_network(X=None, y=None, net=None, hidden_layer=None, label_map=None,
21143
+ def train_snn_network(X=None, y=None, net=None, hidden_layer=None, utility=None, task='classification', label_map=None,
21123
21144
  epochs=50, batch_size=32, n_steps=20,
21124
21145
  n_hidden=64, lr=2e-3, seed=0, pretrain_steps=200, unsupervised_stdp=False,
21125
- random_state=42):
21146
+ random_state=42, ):
21126
21147
  tracker = DiagnosticsTracker()
21127
- utility = SNNUtility()
21128
21148
  cache = {}
21149
+ reg = (task == 'regression')
21150
+ if utility is None:
21151
+ utility = SNNUtility()
21129
21152
 
21130
21153
  rng = utility.seed_everything(seed)
21131
- X_train, X_test, y_train, y_test, X_val, y_val = _prepare_train_val_split(X=X, y=y, random_state=random_state)
21154
+ if reg:
21155
+ X = np.asarray(X, dtype=np.float64)
21156
+ y = np.asarray(y, dtype=np.float64)
21157
+ if X.ndim > 2:
21158
+ X = X.reshape(len(X), -1) # (N, W, F) -> (N, W*F)
21159
+ if y.ndim == 1:
21160
+ y = y.reshape(-1, 1)
21161
+ if len(X) != len(y):
21162
+ raise ValueError(f'X has {len(X)} samples but y has {len(y)}')
21163
+ n = len(X)
21164
+ a, b = int(0.70 * n), int(0.85 * n) # chronological: never shuffle a time series
21165
+ X_train, X_val, X_test = X[:a], X[a:b], X[b:]
21166
+ y_train, y_val, y_test = y[:a], y[a:b], y[b:]
21167
+ lo, hi = X_train.min(0), X_train.max(0) # [0,1] scaling for spike encoding (train stats)
21168
+ span = np.where(hi - lo < 1e-9, 1.0, hi - lo)
21169
+ scale_x = lambda A: np.clip((A - lo) / span, 0.0, 1.0)
21170
+ X_train, X_val, X_test = scale_x(X_train), scale_x(X_val), scale_x(X_test)
21171
+ y_mu, y_sd = y_train.mean(0), y_train.std(0) + 1e-9 # per-output standardisation
21172
+ y_train_net = (y_train - y_mu) / y_sd
21173
+ n_classes = y.shape[1] # readout width = number of regression outputs
21174
+ loss_fn = mse_loss
21175
+ else:
21176
+
21177
+ X_train, X_test, y_train, y_test, X_val, y_val = _prepare_train_val_split(X=X, y=y, random_state=random_state)
21178
+ y_train_net = y_train
21179
+ n_classes = max(len(label_map), int(y_train.max() + 1))
21180
+
21132
21181
  n_in = X_train.shape[1]
21133
- n_classes = max(len(label_map), int(y_train.max() + 1))
21134
- if net is None and hidden_layer is None:
21182
+ if net is None or hidden_layer is None:
21135
21183
  net, hidden_layer = build_snn_network(n_in, n_hidden, n_classes, rng)
21136
21184
 
21185
+ if reg:
21186
+ net.regression_scalers = {'lo': lo, 'span': span, 'y_mu': y_mu, 'y_sd': y_sd}
21187
+
21137
21188
  encoder = PoissonEncoder(n_steps=n_steps, max_rate=1.0, rng=rng)
21138
21189
  optimizer = Adam(lr=lr, weight_decay=1e-5)
21139
21190
  homeostasis = ThresholdHomeostasis(target_rate=0.15, adjust_rate=0.05)
@@ -21169,16 +21220,28 @@ def train_snn_network(X=None, y=None, net=None, hidden_layer=None, label_map=Non
21169
21220
 
21170
21221
  # Evaluation
21171
21222
  net.eval()
21172
- test_spikes = encoder.encode(X_test)
21173
- train_spikes = encoder.encode(X_train)
21174
- preds, _ = net.predict(test_spikes)
21175
- train_preds, _ = net.predict(train_spikes)
21176
- test_acc = utility.accuracy(preds, y_test)
21177
- train_acc = utility.accuracy(train_preds, y_train)
21178
- print(f"[=] Epoch {epoch:2d} || train_loss={np.mean(epoch_losses):.4f} "
21179
- f"train_acc={train_acc*100:5.1f} || test_acc={test_acc*100:5.1f}% || hidden_threshold={hidden_layer.threshold:.3f}")
21180
-
21181
- tracker.record(net, epoch, loss=loss, test_acc=test_acc)
21223
+ preds, _ = net.predict(encoder.encode(X_test), task=task)
21224
+ train_preds, _ = net.predict(encoder.encode(X_train), task=task)
21225
+ if reg:
21226
+ p_te = np.asarray(preds).reshape(len(X_test), -1) * y_sd + y_mu # back to original units
21227
+ p_tr = np.asarray(train_preds).reshape(len(X_train), -1) * y_sd + y_mu
21228
+ test_rmse = float(np.sqrt(np.mean((p_te - y_test) ** 2)))
21229
+ test_mae = float(np.mean(np.abs(p_te - y_test)))
21230
+ train_rmse = float(np.sqrt(np.mean((p_tr - y_train) ** 2)))
21231
+ r2 = float(1.0 - np.sum((p_te - y_test) ** 2) / (np.sum((y_test - y_train.mean(0)) ** 2) + 1e-12))
21232
+ print(f"[=] Epoch {epoch:2d} || train_loss={np.mean(epoch_losses):.4f} train_rmse={train_rmse:,.1f} || "
21233
+ f"test_rmse={test_rmse:,.1f} test_mae={test_mae:,.1f} R2={r2:.3f} || "
21234
+ f"hidden_threshold={hidden_layer.threshold:.3f}")
21235
+ test_score = r2
21236
+ else:
21237
+ test_acc = utility.accuracy(preds, y_test)
21238
+ train_acc = utility.accuracy(train_preds, y_train)
21239
+ print(f"[=] Epoch {epoch:2d} || train_loss={np.mean(epoch_losses):.4f} "
21240
+ f"train_acc={train_acc*100:5.1f} || test_acc={test_acc*100:5.1f}% || "
21241
+ f"hidden_threshold={hidden_layer.threshold:.3f}")
21242
+ test_score = test_acc
21243
+
21244
+ tracker.record(net, epoch, loss=loss, test_acc=test_score)
21182
21245
 
21183
21246
  report = network_report(net)
21184
21247
  print_report(report)
@@ -21188,8 +21251,25 @@ def train_snn_network(X=None, y=None, net=None, hidden_layer=None, label_map=Non
21188
21251
 
21189
21252
  return encoder, net, report, warnings
21190
21253
 
21254
+ def _snn_predict_regression(X, net, encoder, n_mc=20):
21255
+ sc = getattr(net, 'regression_scalers', None)
21256
+ if sc is None:
21257
+ raise ValueError('[>] net has no regression_scalers: train it with train_snn_network(task="regression") first')
21258
+ X = np.asarray(X, dtype=np.float64)
21259
+ X = X.reshape(len(X), -1) # (N, W*F)
21260
+ Xs = np.clip((X - sc['lo']) / sc['span'], 0.0, 1.0)
21261
+
21262
+ # the Poisson encoder is stochastic, its repeated to get a prediction and a spread
21263
+ outs = np.stack([net.predict(encoder.encode(Xs), task='regression')[1] for _ in range(n_mc)]) # (n_mc, N, n_out)
21264
+ mean = outs.mean(0) * sc['y_sd'] + sc['y_mu']
21265
+ std = outs.std(0) * sc['y_sd']
21266
+
21267
+ if mean.shape[1] == 1:
21268
+ mean, std = mean[:, 0], std[:, 0]
21269
+ return {'prediction': mean, 'std': std}
21191
21270
 
21192
- def snn_predict(X=None, y=None, label_map=None, encoder=None, net=None, random_state=42, max_print_threshold=50):
21271
+
21272
+ def snn_predict(X=None, y=None, task='classification', label_map=None, encoder=None, net=None, random_state=42, max_print_threshold=50):
21193
21273
  utility = SNNUtility()
21194
21274
  reverse_map = None
21195
21275
 
@@ -21223,9 +21303,13 @@ def snn_predict(X=None, y=None, label_map=None, encoder=None, net=None, random_s
21223
21303
  if label_map and isinstance(label_map, dict):
21224
21304
  reverse_map = {v: k for k, v in label_map.items()}
21225
21305
 
21306
+ if task == 'regression':
21307
+ result = _snn_predict_regression(X, net, encoder)
21308
+ return result
21309
+
21226
21310
  try:
21227
21311
  test_spikes = encoder.encode(X)
21228
- preds, logits = net.predict(test_spikes)
21312
+ preds, logits = net.predict(test_spikes, task=task)
21229
21313
  if reverse_map is not None:
21230
21314
  # SNN-specific: uncertainty from the encoder's own stochasticity
21231
21315
  mc_results = mc_confidence(net, encoder, X, n_samples=20, class_names=reverse_map)