AbstractIntegratedModule 1.0.9__tar.gz → 1.1.1__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.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
  2. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.py +147 -41
  3. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractOptimizedModules.c +391 -348
  4. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/PKG-INFO +1 -1
  5. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/README.md +5 -4
  6. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/pyproject.toml +1 -1
  7. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/setup.py +1 -1
  8. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
  9. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
  10. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
  11. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
  12. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractOptimizedModules.pyx +0 -0
  13. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/MANIFEST.in +0 -0
  14. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/Cargo.toml +0 -0
  15. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/pyproject.toml +0 -0
  16. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/src/lib.rs +0 -0
  17. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
  18. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
  19. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
  20. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
  21. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
  22. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
  23. {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractIntegratedModule
3
- Version: 1.0.9
3
+ Version: 1.1.1
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>
@@ -869,10 +869,10 @@ class Transformer:
869
869
  if _OPT_AVAILABLE:
870
870
  B, S, D = batch_size, seq_len, d_model
871
871
  M = D // self.n_heads
872
-
873
872
  Q = optimized_project_heads(x, W_q_mix, B, S, self.n_heads, D, M)
874
873
  K = optimized_project_heads(x, W_k_mix, B, S, self.n_heads, D, M)
875
874
  V = optimized_project_heads(x, W_v_mix, B, S, self.n_heads, D, M)
875
+
876
876
  else:
877
877
  Q = np.einsum('bsd,hdm->bhsm', x, W_q_mix)
878
878
  K = np.einsum('bsd,hdm->bhsm', x, W_k_mix)
@@ -1854,9 +1854,15 @@ class Dense:
1854
1854
  db = np.sum(dz, axis=0, keepdims=True) / batch_size
1855
1855
  dx = np.dot(dz, self.W.T)
1856
1856
 
1857
- # gradient clipping — clipped by value
1858
- np.clip(dW, -clip_value, clip_value, out=dW)
1859
- np.clip(db, -clip_value, clip_value, out=db)
1857
+ # global norm clipping.
1858
+ # Preserves gradient DIRECTION, only scales magnitude down when
1859
+ # the total norm exceeds clip_value — avoided the frozen-equilibrium
1860
+ # pattern that per-element clipping can produce.
1861
+ total_norm = np.sqrt(np.sum(dW ** 2) + np.sum(db ** 2))
1862
+ if total_norm > clip_value:
1863
+ scale = clip_value / (total_norm + eps)
1864
+ dW *= scale
1865
+ db *= scale
1860
1866
 
1861
1867
  self.W -= lr * dW
1862
1868
  self.b -= lr * db
@@ -2144,10 +2150,12 @@ class MLP:
2144
2150
  print(f'[!] Cant adapt shape of Y sample arrays due to: {e}')
2145
2151
  return y_pred, y_true
2146
2152
 
2153
+
2147
2154
  def train(self, X, y, epochs=1000, lr=0.01, verbose=True, max_samples_for_focused_fit=500):
2148
2155
  X = self._sanitize_string_chars(X)
2149
2156
  y = self._sanitize_string_chars(y)
2150
2157
  focused_fit_condition = False
2158
+ parameters = sum(w.size for w in self.layers[0].W) + sum(b.size for b in self.layers[0].b)
2151
2159
 
2152
2160
  AME = self.AME_Encoder(X)
2153
2161
  AMR = 1.0 / (1.0 + np.exp(-float(AME)))
@@ -2160,7 +2168,7 @@ class MLP:
2160
2168
  if training_not_allowed:
2161
2169
  print(f'[!] MLP Training not allowed due to unsuitable data characteristics. Anisotropy: {anisotropy:.4f}, AME: {AME:.4f}')
2162
2170
  else:
2163
- print('[+] MLP Training started...')
2171
+ print(f'[+] MLP Training started with: {parameters} Parameters.')
2164
2172
  for epoch in range(epochs):
2165
2173
  if not focused_fit_condition:
2166
2174
  y_pred = self.forward(X, AME=AME, anisotropy=anisotropy)
@@ -2168,6 +2176,7 @@ class MLP:
2168
2176
  y_pred = self.focused_forward(X, AME=AME, anisotropy=anisotropy)
2169
2177
 
2170
2178
  y_pred, y_true = self.adapt_predict_shape(y_pred, y)
2179
+
2171
2180
  loss = Loss.categorical_crossentropy(y_true, y_pred)
2172
2181
  grad = Loss.softmax_crossentropy_derivative(y_true, y_pred)
2173
2182
  if focused_fit_condition:
@@ -13102,41 +13111,65 @@ class IntegratedPipeline:
13102
13111
  return unsuitable_training
13103
13112
 
13104
13113
  def sequence_encoding(self, datasets=None, label_map=None, max_len=32):
13114
+ if not datasets:
13115
+ raise Warning('[!] Dataset is None or empty! Make sure you provide a dataset or create it automatically.')
13116
+
13117
+ if not self.model2:
13118
+ intents = [d[1] for d in datasets]
13119
+ intent_to_id = {intent: i for i, intent in enumerate(sorted(set(intents)))}
13120
+ num_classes = self._get_num_classes(label_map=label_map)
13121
+ self.model2 = Transformer(
13122
+ vocab_size=len(self.vocab),
13123
+ d_model=self.transformer_d_model,
13124
+ n_heads=self.transformer_heads,
13125
+ num_classes=num_classes
13126
+ )
13127
+
13128
+ self._sync_vocab_to_embedding() # once, not per-item
13129
+
13130
+ vocab_size = self.model2.token_embedding.shape[0] # for bounds guard
13131
+
13105
13132
  input_sequences = []
13133
+ for item in datasets:
13134
+ text = item[0] if isinstance(item, tuple) else item
13106
13135
 
13107
- if datasets:
13108
- for item in datasets:
13109
- if not self.model2:
13110
- intents = [d[1] for d in datasets]
13111
- intent_to_id = {intent:i for i, intent in enumerate(sorted(set(intents)))}
13112
- num_classes = self._get_num_classes(label_map=label_map)
13113
- self.model2 = Transformer(
13114
- vocab_size=len(self.vocab),
13115
- d_model=self.transformer_d_model,
13116
- n_heads=self.transformer_heads,
13117
- num_classes=num_classes
13118
- )
13119
-
13120
- self._sync_vocab_to_embedding()
13121
- text = item[0] if isinstance(item, tuple) else item
13136
+ token_ids = self.encode(text, self.vocab, max_len=max_len)
13137
+ token_ids = np.asarray(token_ids)
13122
13138
 
13123
- token_ids = self.encode(text, self.vocab, max_len=max_len)
13124
- token_embs = self.model2.token_embedding[token_ids] # (max_len, d_model)
13125
- pos_embs = self.model2.pos_embedding[:max_len] # (max_len, d_model)
13139
+ # bounds guard before indexing, with informative context
13140
+ out_of_bounds = (token_ids < 0) | (token_ids >= vocab_size)
13141
+ if out_of_bounds.any():
13142
+ n_bad = out_of_bounds.sum()
13143
+ print(f'[⚠️] sequence_encoding: {n_bad} token id(s) out of '
13144
+ f'range [0, {vocab_size}) for text="{str(text)[:50]}" '
13145
+ f'— clamping to valid range. This usually means vocab '
13146
+ f'grew after model2 was constructed; consider rebuilding '
13147
+ f'model2 or resizing token_embedding.')
13148
+ token_ids = np.clip(token_ids, 0, vocab_size - 1)
13149
+
13150
+ token_embs = self.model2.token_embedding[token_ids]
13151
+ pos_embs = self.model2.pos_embedding[:max_len]
13152
+
13153
+ sequence_input = token_embs + pos_embs
13154
+ input_sequences.append(sequence_input)
13155
+
13156
+ return np.stack(input_sequences)
13126
13157
 
13127
- sequence_input = token_embs + pos_embs
13128
- input_sequences.append(sequence_input)
13129
- return np.stack(input_sequences) # shape: (batch, max_len, d_model)
13130
- else:
13131
- raise Warning('[!] Dataset is None! make sure you provide a dataset or create it Automatically!')
13132
-
13133
- return None
13134
13158
 
13135
13159
  def transformer_pooled_features(self, sequence_inputs):
13136
- # mean/max/std pooling over sequence dimension
13160
+ """Mean/max/std pooling over the sequence dimension."""
13161
+ sequence_inputs = np.asarray(sequence_inputs)
13162
+
13163
+ # guard degenerate single-timestep input, where std=0
13164
+ # everywhere is mathematically correct.
13165
+ if sequence_inputs.shape[1] == 1:
13166
+ print('[=] transformer_pooled_features: single-timestep input, '
13167
+ 'std_pool will be all zeros (no variance across T=1)')
13168
+
13137
13169
  mean_pool = np.mean(sequence_inputs, axis=1)
13138
- max_pool = np.max(sequence_inputs, axis=1)
13139
- std_pool = np.std(sequence_inputs, axis=1)
13170
+ max_pool = np.max(sequence_inputs, axis=1)
13171
+ std_pool = np.std(sequence_inputs, axis=1)
13172
+
13140
13173
  return np.concatenate([mean_pool, max_pool, std_pool], axis=-1)
13141
13174
 
13142
13175
  def _features_to_sequence(self, X_provided, d_model=None, min_seq_len=2):
@@ -13242,6 +13275,59 @@ class IntegratedPipeline:
13242
13275
  x = np.fromiter((v for v in clean_str.split() if v not in skip_values), dtype=float)
13243
13276
 
13244
13277
  return x
13278
+
13279
+ def _validate_onehot(self, y_true, context="train()"):
13280
+ """
13281
+ Robust one-hot validation for y_true, going beyond a simple .any() check.
13282
+ Catches: out-of-range values, negative values, non-binary floats,
13283
+ rows that don't sum to 1, and all-zero rows — each with a distinct,
13284
+ actionable error message instead of a generic failure.
13285
+ """
13286
+ y_true = np.asarray(y_true, dtype=np.float64)
13287
+
13288
+ if y_true.ndim == 1:
13289
+ y_true = y_true[np.newaxis, :]
13290
+
13291
+ issues = []
13292
+
13293
+ # 1. Values outside [0, 1] — catches your [5,3,1,4,3,2] case directly
13294
+ out_of_range = (y_true < 0) | (y_true > 1)
13295
+ if out_of_range.any():
13296
+ bad_rows = np.where(out_of_range.any(axis=1))[0]
13297
+ issues.append(
13298
+ f"values outside [0,1] at rows {bad_rows.tolist()[:5]} "
13299
+ f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
13300
+ f"— looks like raw label indices, not one-hot"
13301
+ )
13302
+
13303
+ # 2. Non-binary values (e.g. soft labels or corrupted floats like 0.5, 0.999999)
13304
+ # Only check this if values ARE in [0,1] — no point double-reporting.
13305
+ in_range = ~out_of_range
13306
+ non_binary = in_range & (~np.isclose(y_true, 0, atol=1e-6)) & (~np.isclose(y_true, 1, atol=1e-6))
13307
+ if non_binary.any():
13308
+ bad_rows = np.where(non_binary.any(axis=1))[0]
13309
+ issues.append(
13310
+ f"non-binary values at rows {bad_rows.tolist()[:5]} "
13311
+ f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
13312
+ f"— expected exactly 0 or 1 per class slot"
13313
+ )
13314
+
13315
+ # 3. Row sums must be exactly 1 (each sample has exactly one true class)
13316
+ row_sums = y_true.sum(axis=1)
13317
+ bad_sum_rows = np.where(~np.isclose(row_sums, 1.0, atol=1e-3))[0]
13318
+ if len(bad_sum_rows) > 0:
13319
+ issues.append(
13320
+ f"rows not summing to 1 at indices {bad_sum_rows.tolist()[:5]} "
13321
+ f"(sums: {row_sums[bad_sum_rows[:5]].tolist()}) "
13322
+ f"— either multi-label rows, all-zero rows, or raw indices"
13323
+ )
13324
+
13325
+ if issues:
13326
+ print(f"[WARNING] [{context}] y_true failed one-hot validation, one-hot encoding y sample...")
13327
+ return True
13328
+
13329
+ return False
13330
+
13245
13331
 
13246
13332
  def transformer_utilities(self, X_provided= None, X_raw=None, y_true=None, rules=None,
13247
13333
  datasets=None, label_map=None, batch_size=2, min_signal=1e-3,
@@ -13275,7 +13361,7 @@ class IntegratedPipeline:
13275
13361
  if X_provided is None:
13276
13362
  sequence_inputs = self.sequence_encoding(datasets, label_map=label_map)
13277
13363
  else:
13278
- sequence_inputs = self._features_to_sequence(X_provided)
13364
+ sequence_inputs = self._features_to_sequence(X_provided, d_model=self.transformer_d_model)
13279
13365
 
13280
13366
  unsuitable_training = self.training_necessary_condition(sequence_inputs, X_raw)
13281
13367
  lr = self.model2.transformer_lr if self.model2 else self.transformer_lr
@@ -13348,7 +13434,7 @@ class IntegratedPipeline:
13348
13434
  weak_rows = np.where(row_sums < min_signal)[0]
13349
13435
  weak_ratio = len(weak_rows) / len(X_raw_features)
13350
13436
 
13351
- print(f'[!] Zero ratio in samples: {weak_ratio * 100}')
13437
+ print(f'[!] Zero ratio in samples: {weak_ratio * 100}%')
13352
13438
  if weak_ratio > 0.3: # more than 30% zero rows means vocab mismatch
13353
13439
  if isinstance(X_raw_generation[0], str):
13354
13440
  print(f'[= ! =] High zero-row ratio ({weak_ratio:.0%}), refitting on current batch')
@@ -13401,6 +13487,16 @@ class IntegratedPipeline:
13401
13487
  else:
13402
13488
  self.vocab_size = 1
13403
13489
 
13490
+ onehot_validation = self._validate_onehot(y)
13491
+ if onehot_validation:
13492
+ if n_classes != len(label_map):
13493
+ n_classes = len(label_map)
13494
+ if n_classes > np.max(y):
13495
+ y = np.eye(n_classes)[np.asarray(y)]
13496
+ else:
13497
+ print('[⚠️] Warning: Y onehot encoding fails, Returning Y samples as is, This may cause Exploding Gradient in MLP Training!')
13498
+ y = y.copy()
13499
+
13404
13500
  if self.model2 is None:
13405
13501
  self.model2 = Transformer(
13406
13502
  vocab_size=self.vocab_size,
@@ -13408,11 +13504,11 @@ class IntegratedPipeline:
13408
13504
  n_heads=self.transformer_heads,
13409
13505
  num_classes=n_classes
13410
13506
  )
13507
+
13411
13508
  if self.use_transformer:
13412
13509
  self.model2.train(sequence_inputs, y_true, epochs=self.transformer_training_epochs, mode=mode, lr=lr, embedded=True, batch_size=batch_size)
13413
-
13414
- X = self.shape_adaptation(hybrid_X, input_dim)
13415
-
13510
+
13511
+ X = self.shape_adaptation(hybrid_X, input_dim)
13416
13512
  self.initialize_model_(X, input_dim, n_classes)
13417
13513
  self.model3.train(X, y, epochs=self.mlp_training_epochs, lr=self.mlp_lr, max_samples_for_focused_fit=max_samples_for_focused_fit)
13418
13514
  self.lstm_setup_inference(X, y, input_ids=sequence_inputs)
@@ -17144,6 +17240,18 @@ class PipelinePredictionManager:
17144
17240
  X_train, X_val, y_train, y_val = self._prepare_train_val_split(
17145
17241
  X, y, min_val_per_class=5, min_frac=0.1, max_frac=0.3
17146
17242
  )
17243
+
17244
+ onehot_validation = self.pipeline._validate_onehot(y_train)
17245
+ if onehot_validation:
17246
+ if num_classes != len(label_map):
17247
+ num_classes = len(label_map)
17248
+ if num_classes > np.max(y_train):
17249
+ y_train = np.eye(num_classes)[np.asarray(y_train)]
17250
+ y_val = np.eye(num_classes)[np.asarray(y_val)]
17251
+ else:
17252
+ print('[⚠️] Warning: Y onehot encoding fails, Returning y samples as is, This may cause Exploding Gradient in MLP Training!')
17253
+ y_train = y_train
17254
+ y_val = y_val
17147
17255
 
17148
17256
  X_mean = X_train.mean(axis=0)
17149
17257
  X_std = X_train.std(axis=0) + 1e-8
@@ -17258,9 +17366,7 @@ class PipelinePredictionManager:
17258
17366
  X = X_gen
17259
17367
  if X is not None and len(X) > 0:
17260
17368
  X = np.asarray(X)
17261
- if X_val is not None and len(X_val) > 0:
17262
- X = np.asarray(X_val)
17263
-
17369
+
17264
17370
  # MLP forward pass
17265
17371
  if hasattr(self.pipeline.mlp, 'predict_proba'):
17266
17372
  mlp_probs = self.pipeline.model3.predict_proba(X)