AbstractIntegratedModule 1.1.0__tar.gz → 1.1.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.
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.py +149 -65
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractOptimizedModules.c +391 -348
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/PKG-INFO +1 -1
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/README.md +5 -4
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/pyproject.toml +1 -1
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/setup.py +1 -1
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractOptimizedModules.pyx +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/MANIFEST.in +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/Cargo.toml +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/pyproject.toml +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/src/lib.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
- {abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/setup.cfg +0 -0
{abstractintegratedmodule-1.1.0 → abstractintegratedmodule-1.1.2}/AbstractIntegratedModule.py
RENAMED
|
@@ -21,6 +21,7 @@ from collections import defaultdict
|
|
|
21
21
|
import hashlib
|
|
22
22
|
import ssl
|
|
23
23
|
import os
|
|
24
|
+
import glob
|
|
24
25
|
import asyncio
|
|
25
26
|
import queue
|
|
26
27
|
import threading
|
|
@@ -1567,6 +1568,7 @@ class Transformer:
|
|
|
1567
1568
|
acc = float(np.mean(preds == true))
|
|
1568
1569
|
|
|
1569
1570
|
return loss, acc
|
|
1571
|
+
|
|
1570
1572
|
|
|
1571
1573
|
def _sanitize_string_chars(self, x):
|
|
1572
1574
|
if isinstance(x, (str, np.str_)):
|
|
@@ -2035,8 +2037,10 @@ class MLP:
|
|
|
2035
2037
|
# re adapt shape of pred_counts and error_counts if they don't match prob shape
|
|
2036
2038
|
if self.pred_counts.shape != prob.shape:
|
|
2037
2039
|
self.pred_counts = np.zeros_like(prob)
|
|
2040
|
+
self.pred_counts *= decay
|
|
2038
2041
|
if self.error_counts.shape != prob.shape:
|
|
2039
2042
|
self.error_counts = np.zeros_like(prob)
|
|
2043
|
+
self.error_counts *= decay
|
|
2040
2044
|
|
|
2041
2045
|
except Exception as e:
|
|
2042
2046
|
print(f'[!] Cant check and calibrate probs based on penalty due to: {e}')
|
|
@@ -2155,6 +2159,7 @@ class MLP:
|
|
|
2155
2159
|
X = self._sanitize_string_chars(X)
|
|
2156
2160
|
y = self._sanitize_string_chars(y)
|
|
2157
2161
|
focused_fit_condition = False
|
|
2162
|
+
parameters = sum(w.size for w in self.layers[0].W) + sum(b.size for b in self.layers[0].b)
|
|
2158
2163
|
|
|
2159
2164
|
AME = self.AME_Encoder(X)
|
|
2160
2165
|
AMR = 1.0 / (1.0 + np.exp(-float(AME)))
|
|
@@ -2167,7 +2172,7 @@ class MLP:
|
|
|
2167
2172
|
if training_not_allowed:
|
|
2168
2173
|
print(f'[!] MLP Training not allowed due to unsuitable data characteristics. Anisotropy: {anisotropy:.4f}, AME: {AME:.4f}')
|
|
2169
2174
|
else:
|
|
2170
|
-
print('[+] MLP Training started
|
|
2175
|
+
print(f'[+] MLP Training started with: {parameters} Parameters.')
|
|
2171
2176
|
for epoch in range(epochs):
|
|
2172
2177
|
if not focused_fit_condition:
|
|
2173
2178
|
y_pred = self.forward(X, AME=AME, anisotropy=anisotropy)
|
|
@@ -3899,9 +3904,6 @@ class CrossSessionAutomation:
|
|
|
3899
3904
|
print(f"✅ Session imported! Total memories: {len(self.pipeline.memory)}")
|
|
3900
3905
|
|
|
3901
3906
|
def sync_with_another_device(self, device_ip, port=5000):
|
|
3902
|
-
import socket
|
|
3903
|
-
import pickle
|
|
3904
|
-
|
|
3905
3907
|
# Export current session
|
|
3906
3908
|
temp_file = self.export_session(f"sync_{self.session_id}")
|
|
3907
3909
|
|
|
@@ -3919,8 +3921,6 @@ class CrossSessionAutomation:
|
|
|
3919
3921
|
|
|
3920
3922
|
|
|
3921
3923
|
def list_sessions(self, name):
|
|
3922
|
-
import glob
|
|
3923
|
-
|
|
3924
3924
|
sessions = glob.glob(f"{name}*.json")
|
|
3925
3925
|
|
|
3926
3926
|
print(f"\n📚 Available Sessions: {sessions}")
|
|
@@ -4267,7 +4267,7 @@ class ExplainabilityModule:
|
|
|
4267
4267
|
if not self.learned_from_feedback:
|
|
4268
4268
|
return
|
|
4269
4269
|
|
|
4270
|
-
print(f"\n🔄 Consolidating {len(self.learned_from_feedback)} supervised memories...")
|
|
4270
|
+
print(f"\n[🔄] Consolidating {len(self.learned_from_feedback)} supervised memories...")
|
|
4271
4271
|
|
|
4272
4272
|
# Extract all supervised examples
|
|
4273
4273
|
texts = [m['input'] for m in self.learned_from_feedback]
|
|
@@ -4523,7 +4523,7 @@ class ExplainabilityModule:
|
|
|
4523
4523
|
|
|
4524
4524
|
def _compute_anisotropy(self, attn_weights):
|
|
4525
4525
|
if attn_weights is None or len(attn_weights) == 0:
|
|
4526
|
-
return
|
|
4526
|
+
return self.pipeline.confidence_threshold
|
|
4527
4527
|
|
|
4528
4528
|
try:
|
|
4529
4529
|
|
|
@@ -4537,7 +4537,7 @@ class ExplainabilityModule:
|
|
|
4537
4537
|
return np.std(val) / (np.mean(val) + 1e-8)
|
|
4538
4538
|
|
|
4539
4539
|
except:
|
|
4540
|
-
return
|
|
4540
|
+
return self.pipeline.confidence_threshold
|
|
4541
4541
|
|
|
4542
4542
|
def _compute_attention_quality(self, attn_weights):
|
|
4543
4543
|
eps = 1e-5
|
|
@@ -4568,9 +4568,9 @@ class ExplainabilityModule:
|
|
|
4568
4568
|
|
|
4569
4569
|
quality = norm_entropy * (1.0 - AMR) + avg_max * AMR + norm_var * AMR
|
|
4570
4570
|
return np.clip(quality, 0, 1)
|
|
4571
|
-
except:
|
|
4572
|
-
print("[-] Error occurred while computing attention quality
|
|
4573
|
-
AMR =
|
|
4571
|
+
except Exception as e:
|
|
4572
|
+
print(f"[-] Error occurred while computing attention quality: {e}")
|
|
4573
|
+
AMR = self.pipeline.confidence_threshold
|
|
4574
4574
|
if attn_weights is not None:
|
|
4575
4575
|
print(f"[-] Attention weights shape: {attn_weights.shape}")
|
|
4576
4576
|
AME = self.AME_Encoder(attn_weights)
|
|
@@ -4680,19 +4680,19 @@ class ExplainabilityModule:
|
|
|
4680
4680
|
d1 = self.decision_history[idx1]
|
|
4681
4681
|
d2 = self.decision_history[idx2]
|
|
4682
4682
|
|
|
4683
|
-
comparison.append(f"🔄 Decision Comparison")
|
|
4683
|
+
comparison.append(f"🔄 Ensemble Decision Comparison")
|
|
4684
4684
|
comparison.append("====================================")
|
|
4685
4685
|
|
|
4686
|
-
comparison.append("[<] Earlier Decision:")
|
|
4686
|
+
comparison.append("[<] Ensemble Earlier Decision:")
|
|
4687
4687
|
comparison.append(f"[+] Input: {d1['input']}")
|
|
4688
4688
|
comparison.append(f"[+] Detail Focus: {d1['prediction']} ({d1['confidence']:.1%})")
|
|
4689
4689
|
|
|
4690
|
-
comparison.append("🧠 Later Decision:")
|
|
4690
|
+
comparison.append("🧠 Ensemble Later Decision:")
|
|
4691
4691
|
comparison.append(f"[=] Input: {d2['input']}")
|
|
4692
4692
|
comparison.append(f"[=] Detail Focus: {d2['prediction']} ({d2['confidence']:.1%})")
|
|
4693
4693
|
|
|
4694
|
-
comparison.append("🔬 Learning Progress: ")
|
|
4695
|
-
comparison.append(f"• Confidence {'increased' if d2['confidence'] > d1['confidence'] else 'decreased'} from {d1['confidence']} to {d2['confidence']}")
|
|
4694
|
+
comparison.append("🔬 Ensemble Learning Progress: ")
|
|
4695
|
+
comparison.append(f"• Confidence {'increased' if d2['confidence'] > d1['confidence'] else 'decreased'} from {d1['confidence']:.1%} to {d2['confidence']:.1%}")
|
|
4696
4696
|
comparison.append(f"• The model is becoming {'more' if d2['confidence'] > d1['confidence'] else 'less'} certain")
|
|
4697
4697
|
|
|
4698
4698
|
return '\n'.join(comparison)
|
|
@@ -4709,9 +4709,9 @@ class ExplainabilityModule:
|
|
|
4709
4709
|
|
|
4710
4710
|
# Check transformer confidence
|
|
4711
4711
|
if details['transformer']['confidence'] > 0.8:
|
|
4712
|
-
factors.append(f"✅ Transformer is confident ({details['transformer']['confidence']}) with focused attention")
|
|
4712
|
+
factors.append(f"✅ Transformer is confident ({details['transformer']['confidence']:.1%}) with focused attention")
|
|
4713
4713
|
elif details['transformer']['confidence'] < 0.5:
|
|
4714
|
-
factors.append(f"🤔 Transformer is uncertain ({details['transformer']['confidence']}) due to scattered attention")
|
|
4714
|
+
factors.append(f"🤔 Transformer is uncertain with uncertainty up to: ({details['transformer']['confidence']:.1%}), due to scattered attention")
|
|
4715
4715
|
|
|
4716
4716
|
# Check agreement
|
|
4717
4717
|
if details['agreement']:
|
|
@@ -4721,9 +4721,9 @@ class ExplainabilityModule:
|
|
|
4721
4721
|
|
|
4722
4722
|
# Attention quality
|
|
4723
4723
|
if details.get('attention_quality', 0) > 0.7:
|
|
4724
|
-
factors.append(f"[✅] High attention quality ({details['attention_quality']}) indicates clear consistent patterns!")
|
|
4724
|
+
factors.append(f"[✅] High attention quality: ({details['attention_quality']:.1%}) indicates clear consistent patterns!")
|
|
4725
4725
|
elif details.get('attention_quality', 0) < 0.3:
|
|
4726
|
-
factors.append(f"[-] Low Attention Quality
|
|
4726
|
+
factors.append(f"[-] Low Attention Quality: ({details['attention_quality']:.1%}) Indicates inconsistent and ambiguous patterns on seen data!")
|
|
4727
4727
|
|
|
4728
4728
|
return '\n'.join(factors)
|
|
4729
4729
|
|
|
@@ -9177,6 +9177,7 @@ class QueryNode:
|
|
|
9177
9177
|
|
|
9178
9178
|
return self.permission
|
|
9179
9179
|
|
|
9180
|
+
|
|
9180
9181
|
def _connect_with_peer(self, node):
|
|
9181
9182
|
node_id = id(node)
|
|
9182
9183
|
|
|
@@ -9206,6 +9207,7 @@ class QueryNode:
|
|
|
9206
9207
|
|
|
9207
9208
|
return self.permission
|
|
9208
9209
|
|
|
9210
|
+
|
|
9209
9211
|
def _adjust_trust(self, node_id, delta):
|
|
9210
9212
|
"""
|
|
9211
9213
|
trust that actually evolves. EMA-style bounded adjustment.
|
|
@@ -9214,6 +9216,7 @@ class QueryNode:
|
|
|
9214
9216
|
updated = float(np.clip(current + delta, 0.0, 1.0))
|
|
9215
9217
|
self._trust_scores[node_id] = updated
|
|
9216
9218
|
|
|
9219
|
+
|
|
9217
9220
|
def _identify_node(self, node):
|
|
9218
9221
|
eps = 1e-5
|
|
9219
9222
|
node_id = id(node)
|
|
@@ -9237,6 +9240,7 @@ class QueryNode:
|
|
|
9237
9240
|
) + eps
|
|
9238
9241
|
return False
|
|
9239
9242
|
|
|
9243
|
+
|
|
9240
9244
|
def _node_safety_check(self, node):
|
|
9241
9245
|
node_id = id(node)
|
|
9242
9246
|
trust = self._trust_scores.get(node_id, self._default_trust)
|
|
@@ -12092,9 +12096,15 @@ class IntegratedPipeline:
|
|
|
12092
12096
|
if 0 <= mlp_target < n_classes and i < calibrated.shape[0]:
|
|
12093
12097
|
if mlp_target_int is None:
|
|
12094
12098
|
mlp_target_int = int(mlp_target.flat[0])
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12099
|
+
|
|
12100
|
+
if len(calibrated.shape) >= 2:
|
|
12101
|
+
calibrated[i, mlp_target_int] = min(
|
|
12102
|
+
calibrated[i, mlp_target_int] * (1.5 * (1.0 - abstract_score)), 0.95
|
|
12103
|
+
)
|
|
12104
|
+
else:
|
|
12105
|
+
calibrated[mlp_target_int] = min(
|
|
12106
|
+
calibrated[mlp_target_int] * (1.5 * (1.0 - abstract_score)), 0.95
|
|
12107
|
+
)
|
|
12098
12108
|
|
|
12099
12109
|
if i <= len(calibrated):
|
|
12100
12110
|
try:
|
|
@@ -13110,41 +13120,65 @@ class IntegratedPipeline:
|
|
|
13110
13120
|
return unsuitable_training
|
|
13111
13121
|
|
|
13112
13122
|
def sequence_encoding(self, datasets=None, label_map=None, max_len=32):
|
|
13123
|
+
if not datasets:
|
|
13124
|
+
raise Warning('[!] Dataset is None or empty! Make sure you provide a dataset or create it automatically.')
|
|
13125
|
+
|
|
13126
|
+
if not self.model2:
|
|
13127
|
+
intents = [d[1] for d in datasets]
|
|
13128
|
+
intent_to_id = {intent: i for i, intent in enumerate(sorted(set(intents)))}
|
|
13129
|
+
num_classes = self._get_num_classes(label_map=label_map)
|
|
13130
|
+
self.model2 = Transformer(
|
|
13131
|
+
vocab_size=len(self.vocab),
|
|
13132
|
+
d_model=self.transformer_d_model,
|
|
13133
|
+
n_heads=self.transformer_heads,
|
|
13134
|
+
num_classes=num_classes
|
|
13135
|
+
)
|
|
13136
|
+
|
|
13137
|
+
self._sync_vocab_to_embedding() # once, not per-item
|
|
13138
|
+
|
|
13139
|
+
vocab_size = self.model2.token_embedding.shape[0] # for bounds guard
|
|
13140
|
+
|
|
13113
13141
|
input_sequences = []
|
|
13142
|
+
for item in datasets:
|
|
13143
|
+
text = item[0] if isinstance(item, tuple) else item
|
|
13114
13144
|
|
|
13115
|
-
|
|
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()
|
|
13129
|
-
text = item[0] if isinstance(item, tuple) else item
|
|
13145
|
+
token_ids = self.encode(text, self.vocab, max_len=max_len)
|
|
13146
|
+
token_ids = np.asarray(token_ids)
|
|
13130
13147
|
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13148
|
+
# bounds guard before indexing, with informative context
|
|
13149
|
+
out_of_bounds = (token_ids < 0) | (token_ids >= vocab_size)
|
|
13150
|
+
if out_of_bounds.any():
|
|
13151
|
+
n_bad = out_of_bounds.sum()
|
|
13152
|
+
print(f'[⚠️] sequence_encoding: {n_bad} token id(s) out of '
|
|
13153
|
+
f'range [0, {vocab_size}) for text="{str(text)[:50]}" '
|
|
13154
|
+
f'— clamping to valid range. This usually means vocab '
|
|
13155
|
+
f'grew after model2 was constructed; consider rebuilding '
|
|
13156
|
+
f'model2 or resizing token_embedding.')
|
|
13157
|
+
token_ids = np.clip(token_ids, 0, vocab_size - 1)
|
|
13158
|
+
|
|
13159
|
+
token_embs = self.model2.token_embedding[token_ids]
|
|
13160
|
+
pos_embs = self.model2.pos_embedding[:max_len]
|
|
13161
|
+
|
|
13162
|
+
sequence_input = token_embs + pos_embs
|
|
13163
|
+
input_sequences.append(sequence_input)
|
|
13164
|
+
|
|
13165
|
+
return np.stack(input_sequences)
|
|
13134
13166
|
|
|
13135
|
-
sequence_input = token_embs + pos_embs
|
|
13136
|
-
input_sequences.append(sequence_input)
|
|
13137
|
-
return np.stack(input_sequences) # shape: (batch, max_len, d_model)
|
|
13138
|
-
else:
|
|
13139
|
-
raise Warning('[!] Dataset is None! make sure you provide a dataset or create it Automatically!')
|
|
13140
|
-
|
|
13141
|
-
return None
|
|
13142
13167
|
|
|
13143
13168
|
def transformer_pooled_features(self, sequence_inputs):
|
|
13144
|
-
|
|
13169
|
+
"""Mean/max/std pooling over the sequence dimension."""
|
|
13170
|
+
sequence_inputs = np.asarray(sequence_inputs)
|
|
13171
|
+
|
|
13172
|
+
# guard degenerate single-timestep input, where std=0
|
|
13173
|
+
# everywhere is mathematically correct.
|
|
13174
|
+
if sequence_inputs.shape[1] == 1:
|
|
13175
|
+
print('[=] transformer_pooled_features: single-timestep input, '
|
|
13176
|
+
'std_pool will be all zeros (no variance across T=1)')
|
|
13177
|
+
|
|
13145
13178
|
mean_pool = np.mean(sequence_inputs, axis=1)
|
|
13146
|
-
max_pool
|
|
13147
|
-
std_pool
|
|
13179
|
+
max_pool = np.max(sequence_inputs, axis=1)
|
|
13180
|
+
std_pool = np.std(sequence_inputs, axis=1)
|
|
13181
|
+
|
|
13148
13182
|
return np.concatenate([mean_pool, max_pool, std_pool], axis=-1)
|
|
13149
13183
|
|
|
13150
13184
|
def _features_to_sequence(self, X_provided, d_model=None, min_seq_len=2):
|
|
@@ -13462,6 +13496,16 @@ class IntegratedPipeline:
|
|
|
13462
13496
|
else:
|
|
13463
13497
|
self.vocab_size = 1
|
|
13464
13498
|
|
|
13499
|
+
onehot_validation = self._validate_onehot(y)
|
|
13500
|
+
if onehot_validation:
|
|
13501
|
+
if n_classes != len(label_map):
|
|
13502
|
+
n_classes = len(label_map)
|
|
13503
|
+
if n_classes > np.max(y):
|
|
13504
|
+
y = np.eye(n_classes)[np.asarray(y)]
|
|
13505
|
+
else:
|
|
13506
|
+
print('[⚠️] Warning: Y onehot encoding fails, Returning Y samples as is, This may cause Exploding Gradient in MLP Training!')
|
|
13507
|
+
y = y.copy()
|
|
13508
|
+
|
|
13465
13509
|
if self.model2 is None:
|
|
13466
13510
|
self.model2 = Transformer(
|
|
13467
13511
|
vocab_size=self.vocab_size,
|
|
@@ -17127,6 +17171,42 @@ class PipelinePredictionManager:
|
|
|
17127
17171
|
|
|
17128
17172
|
return X_train, X_val, y_train, y_val
|
|
17129
17173
|
|
|
17174
|
+
def _compute_need_ensemble_method(self, anisotropy, AME, error_counts,
|
|
17175
|
+
anisotropy_threshold=0.3,
|
|
17176
|
+
ame_threshold=0.3,
|
|
17177
|
+
error_threshold=0.3,
|
|
17178
|
+
min_signals_required=1):
|
|
17179
|
+
"""
|
|
17180
|
+
Ensemble fallback is a safety net — it should trigger if ANY
|
|
17181
|
+
single strong risk signal fires, not only when all signals
|
|
17182
|
+
happen to align simultaneously. Uses max() over error_counts
|
|
17183
|
+
so a single persistently-wrong class triggers assistance even
|
|
17184
|
+
when most other classes are healthy.
|
|
17185
|
+
"""
|
|
17186
|
+
signals = []
|
|
17187
|
+
|
|
17188
|
+
if anisotropy is not None and anisotropy > anisotropy_threshold:
|
|
17189
|
+
signals.append(f'anisotropy={anisotropy:.3f}')
|
|
17190
|
+
|
|
17191
|
+
if AME is not None and AME > ame_threshold:
|
|
17192
|
+
signals.append(f'AME={AME:.3f}')
|
|
17193
|
+
|
|
17194
|
+
if error_counts is not None and len(error_counts) > 0:
|
|
17195
|
+
# FIX — max, not mean: catches localized single-class failure
|
|
17196
|
+
# that a flat average would dilute away
|
|
17197
|
+
worst_class_idx = int(np.argmax(error_counts))
|
|
17198
|
+
max_error = float(error_counts[worst_class_idx])
|
|
17199
|
+
if max_error > error_threshold:
|
|
17200
|
+
signals.append(f'error_rate(class={worst_class_idx}, '
|
|
17201
|
+
f'value={max_error:.2f})')
|
|
17202
|
+
|
|
17203
|
+
need_ensemble = len(signals) >= min_signals_required
|
|
17204
|
+
|
|
17205
|
+
if need_ensemble:
|
|
17206
|
+
print(f'[=] Ensemble method triggered by: {", ".join(signals)}')
|
|
17207
|
+
|
|
17208
|
+
return need_ensemble
|
|
17209
|
+
|
|
17130
17210
|
def advanced_prediction_method(self, titles=None, label_map=None, rules=None,
|
|
17131
17211
|
X=None, y=None,
|
|
17132
17212
|
show_proba=False, top_k=3,
|
|
@@ -17155,6 +17235,7 @@ class PipelinePredictionManager:
|
|
|
17155
17235
|
X_gen = None
|
|
17156
17236
|
sec_chosen_label = None
|
|
17157
17237
|
sec_confidence = 0.0
|
|
17238
|
+
final_confidence = 0.0
|
|
17158
17239
|
|
|
17159
17240
|
correct = 0
|
|
17160
17241
|
sec_correct= 0
|
|
@@ -17199,7 +17280,7 @@ class PipelinePredictionManager:
|
|
|
17199
17280
|
|
|
17200
17281
|
if 0 in X.shape:
|
|
17201
17282
|
print(f"[⚠️] Warning: X has zero samples in the total shapes, X shapes: {X.shape}. Creating an empty array with shape (1, n_features) for processing..")
|
|
17202
|
-
X = np.empty((1, X.shape[1])) #
|
|
17283
|
+
X = np.empty((1, X.shape[1])) # Created an empty array with shape (1, n_features)
|
|
17203
17284
|
X = X.reshape(1, -1) # Reshape to (1, n_features) if empty but has features
|
|
17204
17285
|
|
|
17205
17286
|
X_train, X_val, y_train, y_val = self._prepare_train_val_split(
|
|
@@ -17336,7 +17417,7 @@ class PipelinePredictionManager:
|
|
|
17336
17417
|
if hasattr(self.pipeline.mlp, 'predict_proba'):
|
|
17337
17418
|
mlp_probs = self.pipeline.model3.predict_proba(X)
|
|
17338
17419
|
else:
|
|
17339
|
-
logits = self.pipeline.
|
|
17420
|
+
logits = self.pipeline.model3.forward(X)
|
|
17340
17421
|
mlp_probs = self.pipeline._softmax(logits)
|
|
17341
17422
|
|
|
17342
17423
|
# Validate all MLP predictions at once
|
|
@@ -17358,7 +17439,6 @@ class PipelinePredictionManager:
|
|
|
17358
17439
|
if sequence_ids is not None:
|
|
17359
17440
|
print("\n[🔍] Using sequence encoding for transformer input due to low anisotropy.")
|
|
17360
17441
|
input_ids = sequence_ids.copy()
|
|
17361
|
-
|
|
17362
17442
|
# verify samples for accurate answer from cache
|
|
17363
17443
|
print('[🔍] Verifying Samples for possible predicted output in cache for accurate answer...')
|
|
17364
17444
|
cached = self.pipeline.accurate_cache_lookup.lookup(
|
|
@@ -17404,12 +17484,13 @@ class PipelinePredictionManager:
|
|
|
17404
17484
|
else:
|
|
17405
17485
|
lstm_probs = None
|
|
17406
17486
|
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17487
|
+
|
|
17488
|
+
threshold = 0.5 + (self.pipeline.confidence_threshold + np.mean(self.error_counts)) / 2
|
|
17489
|
+
need_ensemble_method = self._compute_need_ensemble_method(anisotropy, AME, self.error_counts,
|
|
17490
|
+
anisotropy_threshold=threshold,
|
|
17491
|
+
ame_threshold=threshold,
|
|
17492
|
+
error_threshold=threshold,
|
|
17493
|
+
min_signals_required=1)
|
|
17413
17494
|
|
|
17414
17495
|
results = []
|
|
17415
17496
|
attention_data = [] if return_attention else None
|
|
@@ -17722,7 +17803,7 @@ class PipelinePredictionManager:
|
|
|
17722
17803
|
if not results[0].get('models_agree', True) and self.pipeline.use_transformer:
|
|
17723
17804
|
trans_confidence = results[0].get('trans_confidence', 1e-8)
|
|
17724
17805
|
confidence = (confidence + trans_confidence / 2) + 1e-5
|
|
17725
|
-
print(f'[=] Calibrating confidence around: {confidence:.1%}
|
|
17806
|
+
print(f'[=] Calibrating confidence around: {confidence:.1%}')
|
|
17726
17807
|
|
|
17727
17808
|
if isinstance(chosen_label, str) and chosen_label.startswith("unknown") or float(confidence) < self.pipeline.confidence_threshold:
|
|
17728
17809
|
if chosen_label is None or chosen_label.startswith('unknown'):
|
|
@@ -17999,7 +18080,7 @@ class PipelinePredictionManager:
|
|
|
17999
18080
|
print(f"[!] Error in advanced prediction method: {e}, Initiating regular prediction method...")
|
|
18000
18081
|
traceback.print_exc()
|
|
18001
18082
|
try:
|
|
18002
|
-
results = self.regular_prediction_method(titles=titles, label_map=label_map, rules=rules, X=X, y=y, show_proba=False, top_k=3, batch_size=2, use_transformer=
|
|
18083
|
+
results = self.regular_prediction_method(titles=titles, label_map=label_map, rules=rules, X=X, y=y, show_proba=False, top_k=3, batch_size=2, use_transformer=self.pipeline.use_transformer)
|
|
18003
18084
|
chosen_label = results[0]['predicted']
|
|
18004
18085
|
confidence = results[0]['confidence']
|
|
18005
18086
|
except Exception as error:
|
|
@@ -18040,7 +18121,7 @@ class PipelinePredictionManager:
|
|
|
18040
18121
|
self.pred_counts *= decay
|
|
18041
18122
|
|
|
18042
18123
|
if final_probs is None:
|
|
18043
|
-
print('[!] Warning final probabilities is None! returning the probabilities...')
|
|
18124
|
+
print('[!] Warning final probabilities is None! returning the None probabilities...')
|
|
18044
18125
|
return final_probs
|
|
18045
18126
|
|
|
18046
18127
|
try:
|
|
@@ -18074,12 +18155,15 @@ class PipelinePredictionManager:
|
|
|
18074
18155
|
prob_sum = final_probs.sum()
|
|
18075
18156
|
if prob_sum > 1e-8:
|
|
18076
18157
|
final_probs /= prob_sum
|
|
18077
|
-
|
|
18158
|
+
|
|
18078
18159
|
# re adapt shape of pred_counts and error_counts if they don't match prob shape
|
|
18079
18160
|
if self.pred_counts.shape != final_probs.shape:
|
|
18080
18161
|
self.pred_counts = np.zeros_like(final_probs)
|
|
18162
|
+
self.pred_counts *= decay
|
|
18081
18163
|
if self.error_counts.shape != final_probs.shape:
|
|
18082
18164
|
self.error_counts = np.zeros_like(final_probs)
|
|
18165
|
+
self.error_counts *= decay
|
|
18166
|
+
|
|
18083
18167
|
|
|
18084
18168
|
except Exception as e:
|
|
18085
18169
|
print(f'[!] Cant check and calibrate probs based on penalty due to: {e}')
|