AbstractIntegratedModule 1.0.8__tar.gz → 1.1.0__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.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
  2. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.py +192 -99
  3. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractOptimizedModules.c +200 -200
  4. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/PKG-INFO +1 -1
  5. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/README.md +4 -6
  6. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/pyproject.toml +1 -1
  7. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/setup.py +1 -1
  8. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
  9. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
  10. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
  11. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
  12. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/AbstractOptimizedModules.pyx +0 -0
  13. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/MANIFEST.in +0 -0
  14. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/Cargo.toml +0 -0
  15. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/pyproject.toml +0 -0
  16. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/src/lib.rs +0 -0
  17. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
  18. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
  19. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
  20. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
  21. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
  22. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
  23. {abstractintegratedmodule-1.0.8 → abstractintegratedmodule-1.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractIntegratedModule
3
- Version: 1.0.8
3
+ Version: 1.1.0
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,6 +2150,7 @@ 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)
@@ -2168,6 +2175,7 @@ class MLP:
2168
2175
  y_pred = self.focused_forward(X, AME=AME, anisotropy=anisotropy)
2169
2176
 
2170
2177
  y_pred, y_true = self.adapt_predict_shape(y_pred, y)
2178
+
2171
2179
  loss = Loss.categorical_crossentropy(y_true, y_pred)
2172
2180
  grad = Loss.softmax_crossentropy_derivative(y_true, y_pred)
2173
2181
  if focused_fit_condition:
@@ -11589,7 +11597,6 @@ class IntegratedPipeline:
11589
11597
  batch_probs = [None] * batch_size
11590
11598
  fresh_probs = None # explicit init, no UnboundLocalError
11591
11599
 
11592
-
11593
11600
  for i in range(batch_size):
11594
11601
  probs = self.model_probability_gate(
11595
11602
  batch_input_ids[i:i+1],
@@ -11601,92 +11608,96 @@ class IntegratedPipeline:
11601
11608
 
11602
11609
  needs_prediction = [i for i, p in enumerate(batch_probs) if p is None]
11603
11610
 
11604
- if needs_prediction:
11605
- fresh_input_ids = batch_input_ids[needs_prediction]
11606
- fresh_X = batch_X[needs_prediction]
11611
+ try:
11612
+ if needs_prediction:
11613
+ fresh_input_ids = batch_input_ids[needs_prediction]
11614
+ fresh_X = batch_X[needs_prediction]
11607
11615
 
11608
- transformer_pred, fresh_probs, attn_weights = self.model2.predict(fresh_input_ids)
11609
- mlp_pred = self.mlp.forward(fresh_X)
11616
+ transformer_pred, fresh_probs, attn_weights = self.model2.predict(fresh_input_ids)
11617
+ mlp_pred = self.mlp.forward(fresh_X)
11610
11618
 
11611
- # coerce indices to int
11612
- mlp_pred_indices = np.argmax(mlp_pred, axis=1).astype(int)
11613
- trans_pred_indices = np.argmax(fresh_probs, axis=1).astype(int)
11619
+ # coerce indices to int
11620
+ mlp_pred_indices = np.argmax(mlp_pred, axis=1).astype(int)
11621
+ trans_pred_indices = np.argmax(fresh_probs, axis=1).astype(int)
11614
11622
 
11615
- for i, idx in enumerate(needs_prediction):
11623
+ for i, idx in enumerate(needs_prediction):
11616
11624
 
11617
- # validate indices in range before use
11618
- mlp_cls = int(mlp_pred_indices[i])
11619
- trans_cls = int(trans_pred_indices[i])
11625
+ # validate indices in range before use
11626
+ mlp_cls = int(mlp_pred_indices[i])
11627
+ trans_cls = int(trans_pred_indices[i])
11620
11628
 
11621
- mlp_cls = mlp_cls if 0 <= mlp_cls < num_classes else 0
11622
- trans_cls = trans_cls if 0 <= trans_cls < num_classes else 0
11623
-
11624
- if mlp_cls != trans_cls:
11625
- calibrated = self._calibrate_probs(
11626
- fresh_probs[i:i+1],
11627
- [mlp_cls],
11628
- attn_weights[i:i+1] if attn_weights is not None else None,
11629
- fresh_input_ids[i:i+1]
11630
- )
11631
- # validate calibrated output shape
11632
- row = np.asarray(calibrated[0])
11633
- if row.shape[0] != num_classes:
11634
- aligned = np.zeros(num_classes)
11635
- aligned[:min(row.shape[0], num_classes)] = row[:num_classes]
11636
- row = aligned
11637
- batch_probs[idx] = row
11629
+ mlp_cls = mlp_cls if 0 <= mlp_cls < num_classes else 0
11630
+ trans_cls = trans_cls if 0 <= trans_cls < num_classes else 0
11638
11631
 
11639
- else:
11640
- # models agree — boost confidence on agreed class
11641
- probs_i = fresh_probs[i].copy()
11642
- probs_i[trans_cls] = min(probs_i[trans_cls] * 1.2, 0.95)
11643
- row_sum = probs_i.sum()
11644
- probs_i /= row_sum if row_sum > 1e-8 else 1.0
11645
- batch_probs[idx] = probs_i
11646
-
11647
- # instance-level save counter, not local idx_total
11648
- if getattr(self, '_prob_save_count', 0) < 2:
11649
- self.modular_probability_saving(
11650
- fresh_input_ids[i:i+1],
11651
- fresh_X[i:i+1],
11652
- np.array([batch_probs[idx]])
11653
- )
11654
- self._prob_save_count = getattr(self, '_prob_save_count', 0) + 1
11632
+ if mlp_cls != trans_cls:
11633
+ calibrated = self._calibrate_probs(
11634
+ fresh_probs[i:i+1],
11635
+ [mlp_cls],
11636
+ attn_weights[i:i+1] if attn_weights is not None else None,
11637
+ fresh_input_ids[i:i+1]
11638
+ )
11639
+ # validate calibrated output shape
11640
+ row = np.asarray(calibrated[0])
11641
+ if row.shape[0] != num_classes:
11642
+ aligned = np.zeros(num_classes)
11643
+ aligned[:min(row.shape[0], num_classes)] = row[:num_classes]
11644
+ row = aligned
11645
+ batch_probs[idx] = row
11655
11646
 
11656
- else:
11657
- raise Warning('[!] Data is None before batching!')
11647
+ else:
11648
+ # models agree boost confidence on agreed class
11649
+ probs_i = fresh_probs[i].copy() if i < len(fresh_probs) else fresh_probs[0]
11650
+ probs_i[trans_cls] = min(probs_i[trans_cls] * 1.2, 0.95)
11651
+ row_sum = probs_i.sum()
11652
+ probs_i /= row_sum if row_sum > 1e-8 else 1.0
11653
+ batch_probs[idx] = probs_i
11654
+
11655
+ # instance-level save counter, not local idx_total
11656
+ if getattr(self, '_prob_save_count', 0) < 2:
11657
+ self.modular_probability_saving(
11658
+ fresh_input_ids[i:i+1],
11659
+ fresh_X[i:i+1],
11660
+ np.array([batch_probs[idx]])
11661
+ )
11662
+ self._prob_save_count = getattr(self, '_prob_save_count', 0) + 1
11658
11663
 
11659
- # safe final assembly with consistent shape
11660
- valid_probs = []
11661
- for i, p in enumerate(batch_probs):
11662
- if p is None:
11663
- valid_probs.append(zero_row.copy())
11664
- elif isinstance(p, list):
11665
- arr = np.array(p, dtype=np.float64)
11666
- if arr.shape[0] != num_classes:
11667
- aligned = np.zeros(num_classes)
11668
- aligned[:min(arr.shape[0], num_classes)] = arr[:num_classes]
11669
- arr = aligned
11670
- valid_probs.append(arr)
11671
- elif isinstance(p, np.ndarray):
11672
- if p.shape[0] != num_classes:
11673
- aligned = np.zeros(num_classes)
11674
- aligned[:min(p.shape[0], num_classes)] = p[:num_classes]
11675
- p = aligned
11676
- valid_probs.append(p)
11677
11664
  else:
11678
- if output_memory is not None:
11679
- print('[=] Unexpected Sample type in batch probability, Using previous memory to fill gaps in Samples Ambiguity')
11680
- valid_probs.append(output_memory)
11681
- else:
11682
- print(f'[⚠️] Unexpected Sample type in batch_probs[{i}]: {type(p)} — using zeros to fill in valid probability')
11665
+ raise Warning('[!] Data is None before batching!')
11666
+
11667
+ # safe final assembly with consistent shape
11668
+ valid_probs = []
11669
+ for i, p in enumerate(batch_probs):
11670
+ if p is None:
11683
11671
  valid_probs.append(zero_row.copy())
11684
-
11685
- try:
11686
- return np.stack(valid_probs)
11687
- except ValueError as e:
11688
- print(f'[⚠️] Stack failed: {e} — shapes: {[p.shape for p in valid_probs]}')
11689
- return valid_probs
11672
+ elif isinstance(p, list):
11673
+ arr = np.array(p, dtype=np.float64)
11674
+ if arr.shape[0] != num_classes:
11675
+ aligned = np.zeros(num_classes)
11676
+ aligned[:min(arr.shape[0], num_classes)] = arr[:num_classes]
11677
+ arr = aligned
11678
+ valid_probs.append(arr)
11679
+ elif isinstance(p, np.ndarray):
11680
+ if p.shape[0] != num_classes:
11681
+ aligned = np.zeros(num_classes)
11682
+ aligned[:min(p.shape[0], num_classes)] = p[:num_classes]
11683
+ p = aligned
11684
+ valid_probs.append(p)
11685
+ else:
11686
+ if output_memory is not None:
11687
+ print('[=] Unexpected Sample type in batch probability, Using previous memory to fill gaps in Samples Ambiguity')
11688
+ valid_probs.append(output_memory)
11689
+ else:
11690
+ print(f'[⚠️] Unexpected Sample type in batch_probs[{i}]: {type(p)} — using zeros to fill in valid probability')
11691
+ valid_probs.append(zero_row.copy())
11692
+
11693
+ try:
11694
+ return np.stack(valid_probs)
11695
+ except ValueError as e:
11696
+ print(f'[⚠️] Stack failed: {e} — shapes: {[p.shape for p in valid_probs]}')
11697
+ return valid_probs
11698
+ except Exception as e:
11699
+ print(f'[⚠️] Error occured in probabilities batching: {e}')
11700
+ return None
11690
11701
 
11691
11702
 
11692
11703
  def hybrid_prediction(self, rules, input_ids, dataset, X=None, y=None, use_embedded=True):
@@ -11851,6 +11862,13 @@ class IntegratedPipeline:
11851
11862
  self.temporary_id.append(self.agent_id)
11852
11863
  id_history = self.temporary_id
11853
11864
 
11865
+ if input_ids is None and X is not None:
11866
+ logits = self.model3.forward(X)
11867
+ return self.model3._softmax(logits)
11868
+
11869
+ if input_ids is None and X is None:
11870
+ raise Warning('[!] X and input indices are None! cannot proceed with Batching probabilities!')
11871
+
11854
11872
  if self.use_transformer:
11855
11873
  is_batch = len(input_ids.shape) == 2 and input_ids.shape[0] > 1
11856
11874
  else:
@@ -11910,8 +11928,11 @@ class IntegratedPipeline:
11910
11928
  self.peer_assistance_threshold -= 0.2
11911
11929
  print('[+] Both Models agree, Normalizing prediction with confidence boost...')
11912
11930
  for i, target in enumerate(mlp_pred_indices):
11913
- probs[i, target] = min(probs[i, target] * 1.2, 0.95)
11914
- probs[i] /= probs[i].sum()
11931
+ if i < len(probs):
11932
+ probs[i, target] = min(probs[i, target] * 1.2, 0.95)
11933
+ probs[i] /= probs[i].sum()
11934
+ else:
11935
+ probs /= probs.sum()
11915
11936
 
11916
11937
 
11917
11938
  if not agreement and probs_memory is not None:
@@ -13229,6 +13250,59 @@ class IntegratedPipeline:
13229
13250
  x = np.fromiter((v for v in clean_str.split() if v not in skip_values), dtype=float)
13230
13251
 
13231
13252
  return x
13253
+
13254
+ def _validate_onehot(self, y_true, context="train()"):
13255
+ """
13256
+ Robust one-hot validation for y_true, going beyond a simple .any() check.
13257
+ Catches: out-of-range values, negative values, non-binary floats,
13258
+ rows that don't sum to 1, and all-zero rows — each with a distinct,
13259
+ actionable error message instead of a generic failure.
13260
+ """
13261
+ y_true = np.asarray(y_true, dtype=np.float64)
13262
+
13263
+ if y_true.ndim == 1:
13264
+ y_true = y_true[np.newaxis, :]
13265
+
13266
+ issues = []
13267
+
13268
+ # 1. Values outside [0, 1] — catches your [5,3,1,4,3,2] case directly
13269
+ out_of_range = (y_true < 0) | (y_true > 1)
13270
+ if out_of_range.any():
13271
+ bad_rows = np.where(out_of_range.any(axis=1))[0]
13272
+ issues.append(
13273
+ f"values outside [0,1] at rows {bad_rows.tolist()[:5]} "
13274
+ f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
13275
+ f"— looks like raw label indices, not one-hot"
13276
+ )
13277
+
13278
+ # 2. Non-binary values (e.g. soft labels or corrupted floats like 0.5, 0.999999)
13279
+ # Only check this if values ARE in [0,1] — no point double-reporting.
13280
+ in_range = ~out_of_range
13281
+ non_binary = in_range & (~np.isclose(y_true, 0, atol=1e-6)) & (~np.isclose(y_true, 1, atol=1e-6))
13282
+ if non_binary.any():
13283
+ bad_rows = np.where(non_binary.any(axis=1))[0]
13284
+ issues.append(
13285
+ f"non-binary values at rows {bad_rows.tolist()[:5]} "
13286
+ f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
13287
+ f"— expected exactly 0 or 1 per class slot"
13288
+ )
13289
+
13290
+ # 3. Row sums must be exactly 1 (each sample has exactly one true class)
13291
+ row_sums = y_true.sum(axis=1)
13292
+ bad_sum_rows = np.where(~np.isclose(row_sums, 1.0, atol=1e-3))[0]
13293
+ if len(bad_sum_rows) > 0:
13294
+ issues.append(
13295
+ f"rows not summing to 1 at indices {bad_sum_rows.tolist()[:5]} "
13296
+ f"(sums: {row_sums[bad_sum_rows[:5]].tolist()}) "
13297
+ f"— either multi-label rows, all-zero rows, or raw indices"
13298
+ )
13299
+
13300
+ if issues:
13301
+ print(f"[WARNING] [{context}] y_true failed one-hot validation, one-hot encoding y sample...")
13302
+ return True
13303
+
13304
+ return False
13305
+
13232
13306
 
13233
13307
  def transformer_utilities(self, X_provided= None, X_raw=None, y_true=None, rules=None,
13234
13308
  datasets=None, label_map=None, batch_size=2, min_signal=1e-3,
@@ -13262,7 +13336,7 @@ class IntegratedPipeline:
13262
13336
  if X_provided is None:
13263
13337
  sequence_inputs = self.sequence_encoding(datasets, label_map=label_map)
13264
13338
  else:
13265
- sequence_inputs = self._features_to_sequence(X_provided)
13339
+ sequence_inputs = self._features_to_sequence(X_provided, d_model=self.transformer_d_model)
13266
13340
 
13267
13341
  unsuitable_training = self.training_necessary_condition(sequence_inputs, X_raw)
13268
13342
  lr = self.model2.transformer_lr if self.model2 else self.transformer_lr
@@ -13335,7 +13409,7 @@ class IntegratedPipeline:
13335
13409
  weak_rows = np.where(row_sums < min_signal)[0]
13336
13410
  weak_ratio = len(weak_rows) / len(X_raw_features)
13337
13411
 
13338
- print(f'[!] Zero ratio in samples: {weak_ratio * 100}')
13412
+ print(f'[!] Zero ratio in samples: {weak_ratio * 100}%')
13339
13413
  if weak_ratio > 0.3: # more than 30% zero rows means vocab mismatch
13340
13414
  if isinstance(X_raw_generation[0], str):
13341
13415
  print(f'[= ! =] High zero-row ratio ({weak_ratio:.0%}), refitting on current batch')
@@ -13395,11 +13469,11 @@ class IntegratedPipeline:
13395
13469
  n_heads=self.transformer_heads,
13396
13470
  num_classes=n_classes
13397
13471
  )
13472
+
13398
13473
  if self.use_transformer:
13399
13474
  self.model2.train(sequence_inputs, y_true, epochs=self.transformer_training_epochs, mode=mode, lr=lr, embedded=True, batch_size=batch_size)
13400
-
13401
- X = self.shape_adaptation(hybrid_X, input_dim)
13402
-
13475
+
13476
+ X = self.shape_adaptation(hybrid_X, input_dim)
13403
13477
  self.initialize_model_(X, input_dim, n_classes)
13404
13478
  self.model3.train(X, y, epochs=self.mlp_training_epochs, lr=self.mlp_lr, max_samples_for_focused_fit=max_samples_for_focused_fit)
13405
13479
  self.lstm_setup_inference(X, y, input_ids=sequence_inputs)
@@ -16252,10 +16326,12 @@ class PipelinePredictionManager:
16252
16326
 
16253
16327
  # Forward pass through MLP
16254
16328
  if hasattr(self.pipeline.mlp, 'predict_proba'):
16255
- mlp_probs = self.pipeline.mlp.predict_proba(X_tfidf)
16329
+ if X_tfidf is None:
16330
+ X_tfidf = X
16331
+ mlp_probs = self.pipeline.model3.predict_proba(X)
16256
16332
  else:
16257
16333
  # Fallback if predict_proba not available
16258
- logits = self.pipeline.mlp.forward(X_tfidf)
16334
+ logits = self.pipeline.model3.forward(X)
16259
16335
  mlp_probs = self.pipeline._softmax(logits)
16260
16336
 
16261
16337
  # Validate all MLP predictions at once
@@ -16560,7 +16636,7 @@ class PipelinePredictionManager:
16560
16636
  else:
16561
16637
  input_datasets = self.pipeline._features_to_sequence(X)
16562
16638
 
16563
- pred_probs = self.pipeline.predict_proba(input_datasets, X_raw, type='Hybrid')[0]
16639
+ pred_probs = self.pipeline.predict_proba(input_datasets, X_raw, type='Hybrid', embedded=True)[0]
16564
16640
  try:
16565
16641
  pred_result = self.pipeline.hybrid_prediction(rules, input_datasets, datasets, X=X, y=y, use_embedded=True)
16566
16642
  except:
@@ -16658,9 +16734,16 @@ class PipelinePredictionManager:
16658
16734
  confidence = final_probs[i, class_idx]
16659
16735
  else:
16660
16736
  if isinstance(final_probs[i], (list, np.ndarray)):
16661
- confidence = final_probs[i][class_idx]
16737
+ if i < len(final_probs):
16738
+ confidence = final_probs[i][class_idx]
16739
+ else:
16740
+ confidence = np.mean(final_probs[class_idx])
16662
16741
  else:
16663
- confidence = float(final_probs[i]) # Single value
16742
+ if i < len(final_probs):
16743
+ confidence = float(final_probs[i]) # Single value
16744
+ else:
16745
+ confidence = float(np.mean(final_probs))
16746
+
16664
16747
 
16665
16748
  if confidence > best_confidence:
16666
16749
  best_idx = i
@@ -17122,6 +17205,18 @@ class PipelinePredictionManager:
17122
17205
  X_train, X_val, y_train, y_val = self._prepare_train_val_split(
17123
17206
  X, y, min_val_per_class=5, min_frac=0.1, max_frac=0.3
17124
17207
  )
17208
+
17209
+ onehot_validation = self.pipeline._validate_onehot(y_train)
17210
+ if onehot_validation:
17211
+ if num_classes != len(label_map):
17212
+ num_classes = len(label_map)
17213
+ if num_classes > np.max(y_train):
17214
+ y_train = np.eye(num_classes)[np.asarray(y_train)]
17215
+ y_val = np.eye(num_classes)[np.asarray(y_val)]
17216
+ else:
17217
+ print('[⚠️] Warning: Y onehot encoding fails, Returning y samples as is, This may cause Exploding Gradient in MLP Training!')
17218
+ y_train = y_train
17219
+ y_val = y_val
17125
17220
 
17126
17221
  X_mean = X_train.mean(axis=0)
17127
17222
  X_std = X_train.std(axis=0) + 1e-8
@@ -17197,7 +17292,7 @@ class PipelinePredictionManager:
17197
17292
  AME = self.pipeline.model2.AME_Encoder(input_ids)
17198
17293
 
17199
17294
  trans_probs, attn_weights = self.pipeline.model2.forward(input_ids, AME=AME, embedded=use_embedded)
17200
-
17295
+
17201
17296
  else:
17202
17297
  print("\n[⚡] Running MLP-only predictions")
17203
17298
  print("[⚡] Note: Transformer not available, so Transformer results will be replaced with MLP results.")
@@ -17236,12 +17331,10 @@ class PipelinePredictionManager:
17236
17331
  X = X_gen
17237
17332
  if X is not None and len(X) > 0:
17238
17333
  X = np.asarray(X)
17239
- if X_val is not None and len(X_val) > 0:
17240
- X = np.asarray(X_val)
17241
-
17334
+
17242
17335
  # MLP forward pass
17243
17336
  if hasattr(self.pipeline.mlp, 'predict_proba'):
17244
- mlp_probs = self.pipeline.mlp.predict_proba(X)
17337
+ mlp_probs = self.pipeline.model3.predict_proba(X)
17245
17338
  else:
17246
17339
  logits = self.pipeline.mlp.forward(X)
17247
17340
  mlp_probs = self.pipeline._softmax(logits)
@@ -17257,7 +17350,7 @@ class PipelinePredictionManager:
17257
17350
  # Replace invalid indices with argmax within valid range
17258
17351
  for i in range(len(mlp_pred_indices)):
17259
17352
  valid_probs = mlp_probs[i][:num_classes] if num_classes > 0 else mlp_probs[i]
17260
- if len(valid_probs) > 0:
17353
+ if len(valid_probs) > 0 and i < len(mlp_pred_indices):
17261
17354
  mlp_pred_indices[i] = int(np.argmax(valid_probs))
17262
17355
  else:
17263
17356
  mlp_pred_indices[i] = 0 # Default to first class