AbstractIntegratedModule 0.8.5__tar.gz → 0.8.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.
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.egg-info/PKG-INFO +5 -4
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.py +219 -83
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractOptimizedModules.c +200 -200
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/PKG-INFO +5 -4
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/README.md +4 -3
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/setup.py +1 -1
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractOptimizedModules.pyx +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/MANIFEST.in +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/Cargo.toml +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/pyproject.toml +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/src/lib.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/pyproject.toml +0 -0
- {abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AbstractIntegratedModule
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.7
|
|
4
4
|
Summary: Library for Advanced Integrated Non-LLM AI Models - Optimized Backend Framework For Non-LLM AI Agent
|
|
5
5
|
Author: Micro-Novelty
|
|
6
6
|
Author-email: hernikpuspita5@gmail.com
|
|
@@ -42,7 +42,7 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
|
|
|
42
42
|
#### Note: The README here you are reading is a direct copy from my README Repository, to download the necessary files, you can visit my Repository with the provided link above.
|
|
43
43
|
|
|
44
44
|
### Library Short Description:
|
|
45
|
-
- Development Stage: 0.8.
|
|
45
|
+
- Development Stage: 0.8.7 Official Release.
|
|
46
46
|
- Maintainer: Micro-Novelty.
|
|
47
47
|
- library Source-Code is Open-sourced on github.
|
|
48
48
|
- Purpose: Specifically Designed for providing Non-LLM AI Agent Framework for edge Devices, Optimized for ARM64 architecture.
|
|
@@ -80,9 +80,10 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
|
|
|
80
80
|
- Transformer Optimized using Cython, to reduce Memory overhead and Reduce CPU Usage, With Reduced Training Time.
|
|
81
81
|
______________
|
|
82
82
|
- Changelog:
|
|
83
|
-
- v0.8.
|
|
83
|
+
- v0.8.7:
|
|
84
84
|
- [=] New features:
|
|
85
|
-
- Added new
|
|
85
|
+
- Added new continuos predictive correction for MLP class to reduce inflated confidence despite outputting wrong answer.
|
|
86
|
+
- Reduced the frequency of penalty based calibration in advanced prediction method to prevent the models from being too conservative.
|
|
86
87
|
- Fixed P2P Vulnerabilities:
|
|
87
88
|
- Empty allowed_ips in PRODUCTION/HARDENED mode now DENIES external IPs instead of allowing all
|
|
88
89
|
- Startup validation warns about dangerous config combinations
|
{abstractintegratedmodule-0.8.5 → abstractintegratedmodule-0.8.7}/AbstractIntegratedModule.py
RENAMED
|
@@ -1716,7 +1716,11 @@ class MLP:
|
|
|
1716
1716
|
self.layers2 = []
|
|
1717
1717
|
self.lr = 0.1
|
|
1718
1718
|
self.feed_layers = []
|
|
1719
|
-
|
|
1719
|
+
|
|
1720
|
+
self.error_counts = None
|
|
1721
|
+
self.pred_counts = None
|
|
1722
|
+
self.error_decay = None
|
|
1723
|
+
|
|
1720
1724
|
self.softmax = SoftmaxOutput()
|
|
1721
1725
|
|
|
1722
1726
|
|
|
@@ -1735,7 +1739,7 @@ class MLP:
|
|
|
1735
1739
|
def forward(self, x):
|
|
1736
1740
|
for layer in self.layers:
|
|
1737
1741
|
x = layer.forward(x)
|
|
1738
|
-
|
|
1742
|
+
|
|
1739
1743
|
return self.softmax.forward(x)
|
|
1740
1744
|
|
|
1741
1745
|
|
|
@@ -1757,7 +1761,40 @@ class MLP:
|
|
|
1757
1761
|
|
|
1758
1762
|
return calibration
|
|
1759
1763
|
|
|
1764
|
+
def continuos_predictive_correction(self, manager, prob, predicted_index):
|
|
1765
|
+
eps = 1e-5
|
|
1760
1766
|
|
|
1767
|
+
error_counts = manager.error_counts
|
|
1768
|
+
pred_counts = manager.pred_counts
|
|
1769
|
+
decay = manager.decay
|
|
1770
|
+
label_map = manager.label_map
|
|
1771
|
+
|
|
1772
|
+
self.error_counts = error_counts
|
|
1773
|
+
self.pred_counts = pred_counts
|
|
1774
|
+
self.error_decay = decay
|
|
1775
|
+
|
|
1776
|
+
try:
|
|
1777
|
+
self.pred_counts[predicted_index] += 1.0
|
|
1778
|
+
n_classes = len(label_map)
|
|
1779
|
+
|
|
1780
|
+
for c in range(n_classes):
|
|
1781
|
+
if self.pred_counts[c] > 0:
|
|
1782
|
+
error_rate = self.error_counts[c] / (self.pred_counts[c] + 1e-8)
|
|
1783
|
+
# sigmoid-shaped dampening — never goes negative
|
|
1784
|
+
# error_rate=0.0 → multiplier=1.0 (no change)
|
|
1785
|
+
# error_rate=0.5 → multiplier≈0.67
|
|
1786
|
+
# error_rate=1.0 → multiplier≈0.5
|
|
1787
|
+
reputation = 1.0 / (1.0 + error_rate)
|
|
1788
|
+
prob[c] *= reputation
|
|
1789
|
+
|
|
1790
|
+
prob_sum = prob.sum()
|
|
1791
|
+
if prob_sum > 1e-8:
|
|
1792
|
+
prob /= prob_sum
|
|
1793
|
+
|
|
1794
|
+
except Exception as e:
|
|
1795
|
+
print(f'[!] Cant check and calibrate probs based on penalty due to: {e}')
|
|
1796
|
+
|
|
1797
|
+
return prob
|
|
1761
1798
|
|
|
1762
1799
|
|
|
1763
1800
|
def focused_backward(self, grad, lr, AME, anisotropy):
|
|
@@ -2893,7 +2930,7 @@ class WeightedEnsemblePredictor:
|
|
|
2893
2930
|
AME = self.pipeline.model2.AME_Encoder(input_ids)
|
|
2894
2931
|
|
|
2895
2932
|
trans_probs, attn_weights = self.pipeline.model2.forward(input_ids, AME=AME, embedded=embedded)
|
|
2896
|
-
mlp_probs = self.pipeline.
|
|
2933
|
+
mlp_probs = self.pipeline.model3.forward(X_mlp)
|
|
2897
2934
|
lstm_probs, lstm_weight_hint = self._get_lstm_probs(input_ids, X_mlp, label_bins=label_bins)
|
|
2898
2935
|
|
|
2899
2936
|
established_agreement = self.query_node._establish_node_connection("PredictEnsemble")
|
|
@@ -8544,6 +8581,7 @@ class IntegratedPipeline:
|
|
|
8544
8581
|
self.temperature = 1.0
|
|
8545
8582
|
self.transformer_lr = 0.1
|
|
8546
8583
|
self.max_seq_len = 16
|
|
8584
|
+
self.error_decay = 0.85
|
|
8547
8585
|
|
|
8548
8586
|
self.memory_name = memory_name
|
|
8549
8587
|
|
|
@@ -13517,41 +13555,51 @@ class PipelineAsyncManager:
|
|
|
13517
13555
|
self._save_state()
|
|
13518
13556
|
|
|
13519
13557
|
|
|
13520
|
-
def advanced_batch_prediction(self, test_titles, label_map, rules,
|
|
13558
|
+
def advanced_batch_prediction(self, test_titles, label_map, rules,
|
|
13559
|
+
X=None, y=None, api_key=None, client_ip=None):
|
|
13521
13560
|
try:
|
|
13522
|
-
attn_weights
|
|
13523
|
-
final_idx
|
|
13561
|
+
attn_weights = None
|
|
13562
|
+
final_idx = None
|
|
13524
13563
|
attn_weight_rate = None
|
|
13525
|
-
|
|
13564
|
+
confidence = None
|
|
13565
|
+
chosen_label = None
|
|
13526
13566
|
|
|
13527
13567
|
reverse_label_map = {v: k for k, v in label_map.items()}
|
|
13568
|
+
n_classes = len(label_map)
|
|
13528
13569
|
|
|
13529
13570
|
if 'attn_weights' in self.pipeline.model2.cache:
|
|
13530
13571
|
attn_weights = self.pipeline.model2.cache['attn_weights']
|
|
13531
13572
|
if attn_weights is not None:
|
|
13532
13573
|
attn_weight_growth = 1.0 / (1.0 + np.exp(-attn_weights[0]))
|
|
13533
|
-
attn_weight_rate
|
|
13574
|
+
attn_weight_rate = float(np.std(attn_weight_growth))
|
|
13534
13575
|
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
expected_labels = [text[1] for text in test_titles] # Your ground truth
|
|
13576
|
+
texts = [text[0] for text in test_titles]
|
|
13577
|
+
expected_labels = [text[1] for text in test_titles]
|
|
13538
13578
|
predicted_output = []
|
|
13539
13579
|
|
|
13540
|
-
|
|
13580
|
+
text_payload = {
|
|
13581
|
+
"test_titles" : test_titles,
|
|
13582
|
+
"label_map" : label_map,
|
|
13583
|
+
"rules" : rules,
|
|
13584
|
+
"X" : X,
|
|
13585
|
+
"y" : y,
|
|
13586
|
+
"use_transformer": True
|
|
13587
|
+
}
|
|
13541
13588
|
|
|
13542
13589
|
if not self.pipeline.intents:
|
|
13543
|
-
result
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
)
|
|
13590
|
+
result = self.predict(
|
|
13591
|
+
text_payload,
|
|
13592
|
+
timeout=self.pipeline.timeout,
|
|
13593
|
+
retries=None,
|
|
13594
|
+
api_key=api_key,
|
|
13595
|
+
client_ip=client_ip,
|
|
13596
|
+
)
|
|
13597
|
+
confidence = None # no confidence from this path
|
|
13550
13598
|
else:
|
|
13551
13599
|
result, chosen_label, confidence = self.advanced_prediction_method(
|
|
13552
|
-
self.prediction_manager, test_titles, label_map, rules,
|
|
13553
|
-
X=X, y=y, method='Transformer_included'
|
|
13554
|
-
|
|
13600
|
+
self.prediction_manager, test_titles, label_map, rules,
|
|
13601
|
+
X=X, y=y, method='Transformer_included'
|
|
13602
|
+
)
|
|
13555
13603
|
try:
|
|
13556
13604
|
if isinstance(result, list) and len(result) > 0:
|
|
13557
13605
|
final_idx = result[0].get('index')
|
|
@@ -13560,62 +13608,107 @@ class PipelineAsyncManager:
|
|
|
13560
13608
|
except (KeyError, IndexError):
|
|
13561
13609
|
final_idx = None
|
|
13562
13610
|
|
|
13563
|
-
print(f'[=+=] Local single advanced
|
|
13611
|
+
print(f'[=+=] Local single advanced prediction: {result}')
|
|
13612
|
+
print('[=] Initiating batch prediction...')
|
|
13564
13613
|
|
|
13565
|
-
print('[=] Initiating Batch prediction for multiple texts...')
|
|
13566
13614
|
results = self.predict_batch(
|
|
13567
13615
|
texts=texts,
|
|
13568
13616
|
timeout=self.pipeline.timeout,
|
|
13569
|
-
api_key=api_key
|
|
13617
|
+
api_key=api_key
|
|
13618
|
+
)
|
|
13619
|
+
|
|
13620
|
+
# class reputation track: how many times each class
|
|
13621
|
+
# was predicted wrong vs total predictions so far
|
|
13622
|
+
# error_rate[c] ∈ [0,1] — higher = this class is unreliable recently
|
|
13623
|
+
error_counts = np.zeros(n_classes, dtype=np.float64)
|
|
13624
|
+
pred_counts = np.zeros(n_classes, dtype=np.float64)
|
|
13625
|
+
decay = self.pipeline.error_decay # how fast old errors fade — tunable
|
|
13570
13626
|
|
|
13571
13627
|
print("========📊 PREDICTION RESULTS============")
|
|
13572
|
-
|
|
13573
|
-
for text, expected, probs in
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13628
|
+
|
|
13629
|
+
for idx, (text, expected, probs) in enumerate(
|
|
13630
|
+
zip(texts, expected_labels, results)
|
|
13631
|
+
):
|
|
13632
|
+
probs = np.asarray(probs, dtype=np.float64).copy()
|
|
13633
|
+
|
|
13634
|
+
# ── calibrate with single-prediction context ──────────────
|
|
13635
|
+
if (confidence is not None and
|
|
13636
|
+
attn_weight_rate is not None and
|
|
13637
|
+
final_idx is not None):
|
|
13638
|
+
|
|
13639
|
+
if 0 <= final_idx < len(probs):
|
|
13640
|
+
boost = (1.0 - attn_weight_rate) * confidence
|
|
13641
|
+
probs[final_idx] = min(probs[final_idx] + boost, 0.95)
|
|
13582
13642
|
else:
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13643
|
+
boost = (1.0 - attn_weight_rate) * confidence
|
|
13644
|
+
probs = np.clip(probs + boost, 0.0, 0.95)
|
|
13645
|
+
|
|
13646
|
+
# ── apply class reputation penalty ────────────────────────
|
|
13647
|
+
# ounded reputation-based penalty
|
|
13648
|
+
# classes with high recent error rate get their probs dampened
|
|
13649
|
+
for c in range(n_classes):
|
|
13650
|
+
if pred_counts[c] > 0:
|
|
13651
|
+
error_rate = error_counts[c] / (pred_counts[c] + 1e-8)
|
|
13652
|
+
# sigmoid-shaped dampening — never goes negative
|
|
13653
|
+
# error_rate=0.0 → multiplier=1.0 (no change)
|
|
13654
|
+
# error_rate=0.5 → multiplier≈0.67
|
|
13655
|
+
# error_rate=1.0 → multiplier≈0.5
|
|
13656
|
+
reputation = 1.0 / (1.0 + error_rate)
|
|
13657
|
+
probs[c] *= reputation
|
|
13658
|
+
|
|
13659
|
+
# renormalize after reputation dampening
|
|
13660
|
+
prob_sum = probs.sum()
|
|
13661
|
+
if prob_sum > 1e-8:
|
|
13662
|
+
probs /= prob_sum
|
|
13663
|
+
|
|
13664
|
+
predicted_index = int(np.argmax(probs))
|
|
13665
|
+
predicted_label = reverse_label_map.get(
|
|
13666
|
+
predicted_index, f"class_{predicted_index}"
|
|
13667
|
+
)
|
|
13668
|
+
pred_conf = float(probs[predicted_index])
|
|
13669
|
+
|
|
13670
|
+
top_3_indices = np.argsort(probs)[-3:][::-1]
|
|
13671
|
+
top_3 = [
|
|
13672
|
+
(reverse_label_map.get(int(i), f"class_{i}"), float(probs[i]))
|
|
13673
|
+
for i in top_3_indices
|
|
13674
|
+
]
|
|
13587
13675
|
|
|
13588
|
-
predicted_index = np.argmax(calibrated_probs) # Get index with highest probability
|
|
13589
|
-
predicted_label = reverse_label_map.get(predicted_index, f"class_{predicted_index}")
|
|
13590
|
-
confidence = calibrated_probs[predicted_index]
|
|
13591
|
-
|
|
13592
|
-
# Get top 3 predictions for more insight
|
|
13593
|
-
top_3_indices = np.argsort(calibrated_probs)[-3:][::-1]
|
|
13594
|
-
top_3 = [(reverse_label_map.get(idx, f"class_{idx}"), calibrated_probs[idx]) for idx in top_3_indices]
|
|
13595
|
-
|
|
13596
13676
|
print(f"\n📌 Input: '{text}'")
|
|
13597
13677
|
print(f" [=] Expected: {expected}")
|
|
13598
|
-
print(f" 🎯 Predicted: {predicted_label} ({
|
|
13599
|
-
|
|
13600
|
-
# Show top 3 possibilities
|
|
13678
|
+
print(f" 🎯 Predicted: {predicted_label} ({pred_conf:.1%})")
|
|
13601
13679
|
print(f" 🔍 Top possibilities:")
|
|
13602
13680
|
for label, conf in top_3:
|
|
13603
13681
|
bar = '█' * int(conf * 20)
|
|
13604
13682
|
print(f"[•] {label:<25} {bar} {conf:.1%}")
|
|
13605
|
-
|
|
13606
|
-
# Match expected vs predicted
|
|
13683
|
+
|
|
13607
13684
|
print('===== COMPARISON MATCHING =====')
|
|
13608
|
-
|
|
13609
|
-
|
|
13685
|
+
is_correct = predicted_label == expected
|
|
13686
|
+
|
|
13687
|
+
# update class reputation — decay old counts first..
|
|
13688
|
+
error_counts *= decay
|
|
13689
|
+
pred_counts *= decay
|
|
13690
|
+
|
|
13691
|
+
pred_counts[predicted_index] += 1.0
|
|
13692
|
+
if not is_correct:
|
|
13693
|
+
print(f"[❌] INCORRECT (expected: {expected})")
|
|
13694
|
+
error_counts[predicted_index] += 1.0
|
|
13610
13695
|
else:
|
|
13611
|
-
print(f"[
|
|
13696
|
+
print(f"[✅] CORRECT!")
|
|
13612
13697
|
|
|
13613
|
-
predicted_output.append(
|
|
13698
|
+
predicted_output.append(
|
|
13699
|
+
f'{text} -> {predicted_label} With {pred_conf:.1%} Confidence'
|
|
13700
|
+
)
|
|
13614
13701
|
|
|
13615
|
-
#
|
|
13702
|
+
# batch accuracy summary
|
|
13703
|
+
correct = sum(
|
|
13704
|
+
1 for text, exp in zip(texts, expected_labels)
|
|
13705
|
+
for po in [predicted_output]
|
|
13706
|
+
if f'-> {exp}' in po
|
|
13707
|
+
)
|
|
13708
|
+
print(f"\n[=] Batch complete")
|
|
13616
13709
|
print(f"[=] Stats: {self.get_stats()}")
|
|
13617
|
-
print('[=] Returning predicted output
|
|
13618
|
-
return predicted_output
|
|
13710
|
+
print('[=] Returning predicted output.')
|
|
13711
|
+
return predicted_output
|
|
13619
13712
|
|
|
13620
13713
|
except Exception as e:
|
|
13621
13714
|
print(f'[=] Error in advanced batch prediction: {e}')
|
|
@@ -13891,7 +13984,14 @@ class PipelinePredictionManager:
|
|
|
13891
13984
|
self.titles, self.y_raw, self.label_map = self.load_labels_from_csv(label_csv, target_title, label)
|
|
13892
13985
|
except Exception as e:
|
|
13893
13986
|
print(f"Error loading labels: {e}")
|
|
13894
|
-
self.titles, self.y_raw, self.label_map =
|
|
13987
|
+
self.titles, self.y_raw, self.label_map = None, None, None
|
|
13988
|
+
|
|
13989
|
+
if self.label_map is not None:
|
|
13990
|
+
self.error_counts = np.zeros(len(self.label_map), dtype=np.float64)
|
|
13991
|
+
self.pred_counts = np.zeros(len(self.label_map), dtype=np.float64)
|
|
13992
|
+
self.decay = self.pipeline.error_decay # how fast old errors fade — tunable
|
|
13993
|
+
else:
|
|
13994
|
+
raise Warning('[!] Label map is None, consider adding label map!')
|
|
13895
13995
|
|
|
13896
13996
|
print(f"✅ Loaded {len(self.titles)} labeled examples")
|
|
13897
13997
|
|
|
@@ -13907,8 +14007,6 @@ class PipelinePredictionManager:
|
|
|
13907
14007
|
4. User home directory
|
|
13908
14008
|
5. Common data folders (Downloads, Documents, Desktop)
|
|
13909
14009
|
"""
|
|
13910
|
-
import os
|
|
13911
|
-
import sys
|
|
13912
14010
|
|
|
13913
14011
|
# build candidate paths
|
|
13914
14012
|
candidates = []
|
|
@@ -14638,9 +14736,10 @@ class PipelinePredictionManager:
|
|
|
14638
14736
|
print(f'[!] Similarity: {cached['similarity']} is low, Cannot pick label due to low certainty, Initiating advanced prediction...')
|
|
14639
14737
|
else:
|
|
14640
14738
|
print('[=] No verified output from cache available that matched samples, starting advanced prediction...')
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14739
|
+
target_probs = self.pipeline.predict_proba(input_ids, X, type='Hybrid', embedded=True)
|
|
14740
|
+
target_probs = target_probs[:mlp_probs.shape[0], :mlp_probs.shape[1]]
|
|
14741
|
+
target_probs = self.pipeline.model3.continuos_predictive_correction(self, target_probs, mlp_pred_indices)
|
|
14742
|
+
|
|
14644
14743
|
target_pred_indices = np.argmax(target_probs, axis=1)
|
|
14645
14744
|
|
|
14646
14745
|
if self.pipeline.cache and 'label_bins' in self.pipeline.cache:
|
|
@@ -14653,13 +14752,6 @@ class PipelinePredictionManager:
|
|
|
14653
14752
|
results = []
|
|
14654
14753
|
attention_data = [] if return_attention else None
|
|
14655
14754
|
|
|
14656
|
-
target_probs = self.pipeline.predict_proba(input_ids, X, type='Hybrid', embedded=True)
|
|
14657
|
-
target_probs = target_probs[:mlp_probs.shape[0], :mlp_probs.shape[1]]
|
|
14658
|
-
target_pred_indices = np.argmax(target_probs, axis=1)
|
|
14659
|
-
|
|
14660
|
-
results = []
|
|
14661
|
-
attention_data = [] if return_attention else None
|
|
14662
|
-
|
|
14663
14755
|
for i, title in enumerate(titles):
|
|
14664
14756
|
# Parse input
|
|
14665
14757
|
if isinstance(title, tuple):
|
|
@@ -14726,7 +14818,8 @@ class PipelinePredictionManager:
|
|
|
14726
14818
|
final_probs = mlp_weight * target_probs[i][:len(calibration)] + trans_weight * calibration[i][:len(calibration)] + lstm_weight * calibration[i][:len(calibration)]
|
|
14727
14819
|
else:
|
|
14728
14820
|
final_probs = mlp_weight * target_probs[i][:len(calibration)] + trans_weight * calibration[i][:len(calibration)]
|
|
14729
|
-
|
|
14821
|
+
|
|
14822
|
+
final_probs = self.calibration_penalized_check(final_probs, target_class_idx)
|
|
14730
14823
|
final_class_idx = target_class_idx
|
|
14731
14824
|
try:
|
|
14732
14825
|
final_confidence = final_probs[final_class_idx]
|
|
@@ -14740,6 +14833,8 @@ class PipelinePredictionManager:
|
|
|
14740
14833
|
agreement = mlp_class_idx == trans_class_idx
|
|
14741
14834
|
else:
|
|
14742
14835
|
final_probs = mlp_probs[i]
|
|
14836
|
+
final_probs = self.calibration_penalized_check(final_probs, mlp_class_idx)
|
|
14837
|
+
|
|
14743
14838
|
final_class_idx = mlp_class_idx
|
|
14744
14839
|
final_confidence = mlp_confidence[0] if isinstance(mlp_confidence, np.ndarray) else mlp_confidence
|
|
14745
14840
|
if isinstance(final_confidence, np.ndarray) or isinstance(final_confidence, list):
|
|
@@ -14843,7 +14938,8 @@ class PipelinePredictionManager:
|
|
|
14843
14938
|
print("\n[⚠️] Disagreement detected between MLP and Transformer predictions. Using calibrated probabilities for final decision.")
|
|
14844
14939
|
if not self.pipeline.autonomous and need_peer_condition:
|
|
14845
14940
|
print('|| Uncertain advanced prediction, requesting peer assistance if allowed...')
|
|
14846
|
-
final_probs = self.pipeline._handle_distributed_connections(final_probs, attn_weights, input_ids, agreement)
|
|
14941
|
+
final_probs = self.pipeline._handle_distributed_connections(final_probs, attn_weights, input_ids, agreement)
|
|
14942
|
+
|
|
14847
14943
|
final_idx = final_probs[0].argmax()
|
|
14848
14944
|
original_idx = final_idx
|
|
14849
14945
|
|
|
@@ -14865,8 +14961,9 @@ class PipelinePredictionManager:
|
|
|
14865
14961
|
|
|
14866
14962
|
print('[||] Iniating local peer output search in database for best output...')
|
|
14867
14963
|
final_probs = self.pipeline.distribution._handle_peer_agent_request(final_probs, attn_weights, input_ids, type='DevicePeer', agreement=agreement)
|
|
14964
|
+
|
|
14868
14965
|
final_idx = final_probs[0].argmax()
|
|
14869
|
-
original_idx = final_idx
|
|
14966
|
+
original_idx = final_idx
|
|
14870
14967
|
|
|
14871
14968
|
if final_idx > len(reverse_map):
|
|
14872
14969
|
final_idx = int(np.argmax(final_probs[:len(reverse_map)-1]))
|
|
@@ -14884,9 +14981,10 @@ class PipelinePredictionManager:
|
|
|
14884
14981
|
if final_confidence is not None and confidence < self.pipeline.confidence_threshold:
|
|
14885
14982
|
print("\n[⚠️] Low confidence detected, but both models don't agree. Using calibrated probabilities for final decision to ensure robustness.")
|
|
14886
14983
|
final_probs = self.pipeline.hybrid_prediction(rules, input_ids, dataset)
|
|
14984
|
+
|
|
14887
14985
|
final_idx = final_probs[0].argmax()
|
|
14888
14986
|
original_idx = final_idx
|
|
14889
|
-
|
|
14987
|
+
|
|
14890
14988
|
if final_idx > len(reverse_map):
|
|
14891
14989
|
final_idx = int(np.argmax(final_probs[:len(reverse_map)-1]))
|
|
14892
14990
|
print(f"[⚠️] Clamping {final_idx} → {final_idx}")
|
|
@@ -14894,9 +14992,9 @@ class PipelinePredictionManager:
|
|
|
14894
14992
|
else:
|
|
14895
14993
|
print('[🎯] Stable confidence established, But both Models doesnt Agree, Re-evaluating...')
|
|
14896
14994
|
final_probs = self.pipeline.hybrid_prediction(rules, input_ids, dataset)
|
|
14995
|
+
|
|
14897
14996
|
final_idx = final_probs[0].argmax()
|
|
14898
14997
|
original_idx = final_idx
|
|
14899
|
-
|
|
14900
14998
|
if final_idx > len(reverse_map):
|
|
14901
14999
|
final_idx = int(np.argmax(final_probs[:len(reverse_map)-1]))
|
|
14902
15000
|
print(f"[⚠️] Clamping {final_idx} → {final_idx}")
|
|
@@ -14912,6 +15010,7 @@ class PipelinePredictionManager:
|
|
|
14912
15010
|
print("\n[⚠️] Uncertain confidence and disagreement detected. Using ensemble method for final decision.")
|
|
14913
15011
|
input_forward = sequence_ids if sequence_ids is not None else input_ids
|
|
14914
15012
|
final_probs, details = self.pipeline.ensemble.predict_ensemble(input_forward, X, y, method='dynamic', embedded=True)
|
|
15013
|
+
|
|
14915
15014
|
final_idx = final_probs[0].argmax()
|
|
14916
15015
|
original_idx = final_idx
|
|
14917
15016
|
|
|
@@ -14928,7 +15027,7 @@ class PipelinePredictionManager:
|
|
|
14928
15027
|
else:
|
|
14929
15028
|
input_forward = sequence_ids if sequence_ids is not None else input_ids
|
|
14930
15029
|
final_idx = final_probs[0].argmax() if final_probs is not None else target_probs[0].argmax()
|
|
14931
|
-
|
|
15030
|
+
|
|
14932
15031
|
original_idx = final_idx
|
|
14933
15032
|
|
|
14934
15033
|
if final_idx > len(reverse_map):
|
|
@@ -15010,7 +15109,8 @@ class PipelinePredictionManager:
|
|
|
15010
15109
|
confidence = float(final_probs[0][final_idx])
|
|
15011
15110
|
except:
|
|
15012
15111
|
confidence = float(final_probs[0][len(reverse_map)-1]) if isinstance(final_probs[0], (float, int)) else 0.0
|
|
15013
|
-
|
|
15112
|
+
|
|
15113
|
+
|
|
15014
15114
|
if isinstance(chosen_label, str) and chosen_label.startswith("unknown") or float(confidence) < self.pipeline.confidence_threshold:
|
|
15015
15115
|
if chosen_label.startswith("unknown"):
|
|
15016
15116
|
chosen_label = 'Unknown'
|
|
@@ -15084,7 +15184,7 @@ class PipelinePredictionManager:
|
|
|
15084
15184
|
'X_samples': X,
|
|
15085
15185
|
'input_ids': input_ids
|
|
15086
15186
|
}
|
|
15087
|
-
correct, sec_correct = self.display_hybrid_results(payload, results, top_k, verbose=True)
|
|
15187
|
+
correct, sec_correct = self.display_hybrid_results(payload, final_class_idx, results, top_k, verbose=True)
|
|
15088
15188
|
if sec_chosen_label and sec_correct > correct:
|
|
15089
15189
|
print(f'[⚡] Second Prediction: {sec_chosen_label} has higher accuracies, relying on: {sec_chosen_label} as final label.')
|
|
15090
15190
|
chosen_label = sec_chosen_label # overrides previous chosen label if accuracy is higher
|
|
@@ -15097,18 +15197,48 @@ class PipelinePredictionManager:
|
|
|
15097
15197
|
self.pipeline.cache.clear()
|
|
15098
15198
|
|
|
15099
15199
|
return results, chosen_label, confidence
|
|
15200
|
+
|
|
15201
|
+
|
|
15202
|
+
def calibration_penalized_check(self, final_probs, predicted_index):
|
|
15203
|
+
# update class reputation.
|
|
15204
|
+
try:
|
|
15205
|
+
decay = self.pipeline.error_decay
|
|
15206
|
+
self.error_counts *= decay
|
|
15207
|
+
self.pred_counts *= decay
|
|
15208
|
+
|
|
15209
|
+
self.pred_counts[predicted_index] += 1.0
|
|
15210
|
+
n_classes = len(self.label_map)
|
|
15211
|
+
|
|
15212
|
+
for c in range(n_classes):
|
|
15213
|
+
if self.pred_counts[c] > 0:
|
|
15214
|
+
error_rate = self.error_counts[c] / (self.pred_counts[c] + 1e-8)
|
|
15215
|
+
# sigmoid-shaped dampening — never goes negative
|
|
15216
|
+
# error_rate=0.0 → multiplier=1.0 (no change)
|
|
15217
|
+
# error_rate=0.5 → multiplier≈0.67
|
|
15218
|
+
# error_rate=1.0 → multiplier≈0.5
|
|
15219
|
+
reputation = 1.0 / (1.0 + error_rate)
|
|
15220
|
+
final_probs[c] *= reputation
|
|
15221
|
+
|
|
15222
|
+
prob_sum = final_probs.sum()
|
|
15223
|
+
if prob_sum > 1e-8:
|
|
15224
|
+
final_probs /= prob_sum
|
|
15225
|
+
|
|
15226
|
+
except Exception as e:
|
|
15227
|
+
print(f'[!] Cant check and calibrate probs based on penalty due to: {e}')
|
|
15100
15228
|
|
|
15229
|
+
return final_probs
|
|
15230
|
+
|
|
15101
15231
|
|
|
15102
|
-
def display_hybrid_results(self, payload, results, top_k=3, verbose=False):
|
|
15232
|
+
def display_hybrid_results(self, payload, predicted_index, results, top_k=3, verbose=False):
|
|
15103
15233
|
print("\n" + "="*80)
|
|
15104
15234
|
print("[🎯] == PREDICTION RESULTS == ")
|
|
15105
15235
|
print("="*80)
|
|
15106
|
-
|
|
15236
|
+
|
|
15107
15237
|
correct = 0
|
|
15108
15238
|
sec_correct = 0
|
|
15109
15239
|
total_with_expected = 0
|
|
15110
15240
|
X_samples, input_ids = payload['X_samples'], payload['input_ids']
|
|
15111
|
-
|
|
15241
|
+
|
|
15112
15242
|
for idx, result in enumerate(results):
|
|
15113
15243
|
print(f"\n{idx+1}. 📌 '{result['title']}'")
|
|
15114
15244
|
|
|
@@ -15116,6 +15246,7 @@ class PipelinePredictionManager:
|
|
|
15116
15246
|
total_with_expected += 1
|
|
15117
15247
|
status = ": ✅" if result['predicted'] == result['expected'] else ": ❌"
|
|
15118
15248
|
print(f"[=] First Expectation: {result['expected']} || Model Answer: {status}")
|
|
15249
|
+
|
|
15119
15250
|
if 'sec_predicted' in result:
|
|
15120
15251
|
sec_status = ": ✅" if result['sec_predicted'] == result['expected'] else ": ❌"
|
|
15121
15252
|
print(f"[=] Second Expectation: {result['expected']} || Model Answer: {sec_status}")
|
|
@@ -15126,6 +15257,8 @@ class PipelinePredictionManager:
|
|
|
15126
15257
|
source='automatic_verified')
|
|
15127
15258
|
|
|
15128
15259
|
sec_correct += 1
|
|
15260
|
+
else:
|
|
15261
|
+
self.error_counts[predicted_index] += 1.0
|
|
15129
15262
|
|
|
15130
15263
|
if result['predicted'] == result['expected']:
|
|
15131
15264
|
if result['sec_index'] is None:
|
|
@@ -15137,6 +15270,9 @@ class PipelinePredictionManager:
|
|
|
15137
15270
|
source='automatic_verified')
|
|
15138
15271
|
|
|
15139
15272
|
correct += 1
|
|
15273
|
+
else:
|
|
15274
|
+
self.error_counts[predicted_index] += 1.0
|
|
15275
|
+
|
|
15140
15276
|
|
|
15141
15277
|
# Agreement indicator
|
|
15142
15278
|
agree_symbol = "✓" if result.get('models_agree', True) else "⚠️"
|