AbstractIntegratedModule 0.6.8__tar.gz → 0.7.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.
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.egg-info/PKG-INFO +11 -3
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.py +282 -111
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractOptimizedModules.c +152 -152
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/PKG-INFO +11 -3
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/README.md +10 -2
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/setup.py +2 -9
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractOptimizedModules.pyx +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/MANIFEST.in +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/Cargo.toml +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/pyproject.toml +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/src/lib.rs +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/pyproject.toml +0 -0
- {abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AbstractIntegratedModule
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
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.
|
|
45
|
+
- Development Stage: 0.7.1 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.
|
|
@@ -65,9 +65,17 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
|
|
|
65
65
|
- Robust Advanced prediction capabilities proven effective on ARM64 Using MLP + LSTM Architectures.
|
|
66
66
|
- Transformer Modules Optimized using Cython, to reduce Memory overhead and Reduce CPU Usage, With Reduced Training Time.
|
|
67
67
|
- Changelog:
|
|
68
|
-
- v0.
|
|
68
|
+
- v0.7.1:
|
|
69
69
|
- [=] New features:
|
|
70
70
|
- Added Rust specific compiled binary for handling complex weight matrices.
|
|
71
|
+
- added specific optimized weight saving handling with rust optimization.
|
|
72
|
+
- Adding Optimization and refinements, especially bug fixes in:
|
|
73
|
+
- IntegratedPipeline lstm samples creating
|
|
74
|
+
- IntegratedPipeline shape adaptation
|
|
75
|
+
- IntegratedPipeline probability calibration
|
|
76
|
+
- IntegratedPipeline auto generate labels text
|
|
77
|
+
- IntegratedPipeline MLP samples generation.
|
|
78
|
+
|
|
71
79
|
-----
|
|
72
80
|
|
|
73
81
|
<img width="1280" height="600" alt="WhatsApp Image 2026-05-27 at 07 16 32" src="https://github.com/user-attachments/assets/4b58a556-45a3-419b-96fd-9c1b76cac574" />
|
{abstractintegratedmodule-0.6.8 → abstractintegratedmodule-0.7.1}/AbstractIntegratedModule.py
RENAMED
|
@@ -31,6 +31,7 @@ from typing import Any, Callable, Tuple, Optional, Dict, List
|
|
|
31
31
|
from datetime import datetime, timedelta
|
|
32
32
|
from enum import IntEnum, Enum
|
|
33
33
|
from collections import deque
|
|
34
|
+
from collections import Counter
|
|
34
35
|
import traceback
|
|
35
36
|
from concurrent.futures import TimeoutError as FutureTimeoutError
|
|
36
37
|
import secrets
|
|
@@ -62,6 +63,15 @@ except ImportError as e:
|
|
|
62
63
|
_OPT_AVAILABLE = False
|
|
63
64
|
print(f'[=] Cython not available: {e}, using numpy fallback')
|
|
64
65
|
|
|
66
|
+
try:
|
|
67
|
+
import abstract_weights_core as wc
|
|
68
|
+
_RUST_MODULE_AVAILABLE = True
|
|
69
|
+
print('[=] Rust weight storage loaded ✅')
|
|
70
|
+
except ImportError as e:
|
|
71
|
+
_RUST_MODULE_AVAILABLE = False
|
|
72
|
+
print(f'[=] Rust weight storage unavailable due to: {e}, using Python sqlite3 fallback')
|
|
73
|
+
|
|
74
|
+
|
|
65
75
|
# initial Setup logging for AgentDistributedInference and ModelStorage class logger and security logger
|
|
66
76
|
logger = logging.getLogger(__name__)
|
|
67
77
|
_integrated_pipeline_lock = threading.Lock()
|
|
@@ -2772,7 +2782,6 @@ class WeightedEnsemblePredictor:
|
|
|
2772
2782
|
predictions = [r['prediction'] for r in results]
|
|
2773
2783
|
confidences = [r['confidence'] for r in results]
|
|
2774
2784
|
|
|
2775
|
-
from collections import Counter
|
|
2776
2785
|
distribution = Counter(predictions)
|
|
2777
2786
|
|
|
2778
2787
|
print("\n📊 Batch Summary:")
|
|
@@ -4885,6 +4894,16 @@ class ModelStorage:
|
|
|
4885
4894
|
}
|
|
4886
4895
|
|
|
4887
4896
|
weight_json = json.dumps(weights, default=str)
|
|
4897
|
+
if _RUST_MODULE_AVAILABLE:
|
|
4898
|
+
try:
|
|
4899
|
+
wc.save_lstm_weights(self.db_path, memory_name, weight_json)
|
|
4900
|
+
print('[||] LSTM weights saved using Rust module !')
|
|
4901
|
+
return
|
|
4902
|
+
except Exception as e:
|
|
4903
|
+
print(f'[!] Rust save failed, falling back to Python: {e}')
|
|
4904
|
+
else:
|
|
4905
|
+
print('[=] Rust module unavailable, using python sqlite3.')
|
|
4906
|
+
|
|
4888
4907
|
try:
|
|
4889
4908
|
c.execute("""
|
|
4890
4909
|
INSERT INTO weight_storage
|
|
@@ -4949,6 +4968,15 @@ class ModelStorage:
|
|
|
4949
4968
|
output_bias = tf.output_bias
|
|
4950
4969
|
)
|
|
4951
4970
|
binary_data = buf.getvalue()
|
|
4971
|
+
if _RUST_MODULE_AVAILABLE:
|
|
4972
|
+
try:
|
|
4973
|
+
wc.save_transformer_weights(self.db_path, memory_name, binary_data)
|
|
4974
|
+
print('[||] LSTM weights saved using Rust module for flexibility!')
|
|
4975
|
+
return
|
|
4976
|
+
except Exception as e:
|
|
4977
|
+
print(f'[!] Rust save failed, falling back to Python: {e}')
|
|
4978
|
+
else:
|
|
4979
|
+
print('[=] Rust module unavailable, using python sqlite3.')
|
|
4952
4980
|
|
|
4953
4981
|
try:
|
|
4954
4982
|
c.execute("""
|
|
@@ -4988,21 +5016,48 @@ class ModelStorage:
|
|
|
4988
5016
|
except:
|
|
4989
5017
|
conn = sqlite3.connect(self.db_path)
|
|
4990
5018
|
|
|
4991
|
-
c = conn.cursor()
|
|
5019
|
+
c = conn.cursor()
|
|
5020
|
+
|
|
4992
5021
|
|
|
4993
5022
|
try:
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5023
|
+
if _RUST_MODULE_AVAILABLE:
|
|
5024
|
+
try:
|
|
5025
|
+
binary = wc.load_transformer_weights(self.db_path, memory_name)
|
|
5026
|
+
|
|
5027
|
+
buf = io.BytesIO(bytes(binary))
|
|
5028
|
+
data = np.load(buf, allow_pickle=False)
|
|
5029
|
+
|
|
5030
|
+
print('[+] Transformer weights data loaded using Rust module!')
|
|
5031
|
+
|
|
5032
|
+
except Exception as e:
|
|
5033
|
+
print(f'[=] Cant load Transformer weights: {e}, using python sqlite3 to handle weights.')
|
|
5034
|
+
time.sleep(3)
|
|
5035
|
+
c.execute("""
|
|
5036
|
+
SELECT weights FROM weight_storage
|
|
5037
|
+
WHERE memory_name = ? AND model_type = 'transformer' AND is_active = 1
|
|
5038
|
+
ORDER BY id DESC LIMIT 1
|
|
5039
|
+
""", (memory_name,))
|
|
5040
|
+
row = c.fetchone()
|
|
5041
|
+
if not row:
|
|
5042
|
+
print(f'[=] No saved transformer weights for {memory_name}')
|
|
5043
|
+
return False
|
|
5044
|
+
|
|
5045
|
+
buf = io.BytesIO(bytes(row[0]))
|
|
5046
|
+
data = np.load(buf, allow_pickle=False)
|
|
5047
|
+
|
|
5048
|
+
else:
|
|
5049
|
+
c.execute("""
|
|
5050
|
+
SELECT weights FROM weight_storage
|
|
5051
|
+
WHERE memory_name = ? AND model_type = 'transformer' AND is_active = 1
|
|
5052
|
+
ORDER BY id DESC LIMIT 1
|
|
5053
|
+
""", (memory_name,))
|
|
5054
|
+
row = c.fetchone()
|
|
5055
|
+
if not row:
|
|
5056
|
+
print(f'[=] No saved transformer weights for {memory_name}')
|
|
5057
|
+
return False
|
|
5003
5058
|
|
|
5004
|
-
|
|
5005
|
-
|
|
5059
|
+
buf = io.BytesIO(bytes(row[0]))
|
|
5060
|
+
data = np.load(buf, allow_pickle=False)
|
|
5006
5061
|
|
|
5007
5062
|
t = self.pipeline.model2
|
|
5008
5063
|
t.token_embedding = data['token_embedding']
|
|
@@ -5035,7 +5090,15 @@ class ModelStorage:
|
|
|
5035
5090
|
|
|
5036
5091
|
def load_weights(self, memory_name):
|
|
5037
5092
|
"""Load weights from database. Returns True if found."""
|
|
5038
|
-
|
|
5093
|
+
if _RUST_MODULE_AVAILABLE:
|
|
5094
|
+
try:
|
|
5095
|
+
result = wc.load_lstm_weights(self.db_path, memory_name)
|
|
5096
|
+
print('[+] LSTM weights loaded via Rust module')
|
|
5097
|
+
except Exception as e:
|
|
5098
|
+
result = self.weight_retrieval(memory_name)
|
|
5099
|
+
print(f'[=] Cant load LSTM Weights due to: {e}, using python sqlite3 as fallback.')
|
|
5100
|
+
else:
|
|
5101
|
+
result = self.weight_retrieval(memory_name)
|
|
5039
5102
|
|
|
5040
5103
|
if not result:
|
|
5041
5104
|
print(f'[=] No saved weights for {memory_name}')
|
|
@@ -5072,22 +5135,30 @@ class ModelStorage:
|
|
|
5072
5135
|
except:
|
|
5073
5136
|
db_path = self.get_database_path()
|
|
5074
5137
|
conn = sqlite3.connect(db_path)
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5138
|
+
|
|
5139
|
+
if _RUST_MODULE_AVAILABLE:
|
|
5140
|
+
try:
|
|
5141
|
+
data = wc.load_attention_dict(self.db_path, memory_name)
|
|
5142
|
+
print('[+] Transformer attention loaded using Rust module!')
|
|
5143
|
+
return data
|
|
5144
|
+
except Exception as e:
|
|
5145
|
+
print(f'[=]: {e}, Loading transformer attention from python sqlite3...')
|
|
5146
|
+
else:
|
|
5147
|
+
conn = sqlite3.connect(self.db_path)
|
|
5148
|
+
c = conn.cursor()
|
|
5149
|
+
|
|
5150
|
+
c.execute("""
|
|
5151
|
+
SELECT model_data FROM model_attn_storage
|
|
5152
|
+
WHERE memory_name = ? AND is_active = 1
|
|
5153
|
+
""", (memory_name,))
|
|
5154
|
+
|
|
5155
|
+
result = c.fetchone()
|
|
5156
|
+
conn.close()
|
|
5157
|
+
|
|
5158
|
+
if result:
|
|
5159
|
+
return json.loads(result[0])
|
|
5089
5160
|
except Exception as e:
|
|
5090
|
-
print(f'Error handling attention dict: {e}')
|
|
5161
|
+
print(f'[!] Error handling attention dict: {e}')
|
|
5091
5162
|
|
|
5092
5163
|
return None
|
|
5093
5164
|
|
|
@@ -9836,59 +9907,62 @@ class IntegratedPipeline:
|
|
|
9836
9907
|
|
|
9837
9908
|
def _calibrate_probs(self, probs, target_preds, attn_weights, input_ids):
|
|
9838
9909
|
calibrated = probs.copy()
|
|
9910
|
+
|
|
9839
9911
|
if isinstance(input_ids, list):
|
|
9840
9912
|
input_ids = np.array(input_ids)
|
|
9841
9913
|
|
|
9842
|
-
|
|
9843
|
-
n_classes = probs.shape[1]
|
|
9844
|
-
else:
|
|
9845
|
-
n_classes = probs.shape[0]
|
|
9846
|
-
|
|
9914
|
+
n_classes = probs.shape[1] if probs.ndim > 1 else probs.shape[0]
|
|
9847
9915
|
batch_size = len(target_preds)
|
|
9848
9916
|
eps = 1e-5
|
|
9849
9917
|
|
|
9850
|
-
|
|
9851
|
-
for i in range(batch_size):
|
|
9852
|
-
mlp_target = target_preds[i]
|
|
9918
|
+
temperature_accum = []
|
|
9853
9919
|
|
|
9854
|
-
|
|
9855
|
-
anisotropy = self.anisotropy_measurement(mlp_target)
|
|
9856
|
-
else:
|
|
9857
|
-
try:
|
|
9858
|
-
anisotropy = self.anisotropy_measurement(attn_weights[i])
|
|
9859
|
-
except:
|
|
9860
|
-
anisotropy = self.anisotropy_measurement(attn_weights)
|
|
9920
|
+
attn_len = len(attn_weights) if attn_weights is not None else 0
|
|
9861
9921
|
|
|
9862
|
-
|
|
9863
|
-
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
|
|
9922
|
+
for i in range(batch_size):
|
|
9923
|
+
# consistent bound check, no off-by-one
|
|
9924
|
+
mlp_target = target_preds[i] if i < attn_len else target_preds[0]
|
|
9925
|
+
|
|
9926
|
+
# anisotropy needs an array-like input
|
|
9927
|
+
if attn_weights is None:
|
|
9928
|
+
# no attention available
|
|
9929
|
+
anisotropy = eps
|
|
9930
|
+
elif i < attn_len:
|
|
9931
|
+
anisotropy = self.anisotropy_measurement(attn_weights[i])
|
|
9932
|
+
else:
|
|
9933
|
+
anisotropy = self.anisotropy_measurement(attn_weights[0])
|
|
9867
9934
|
|
|
9935
|
+
if attn_weights is not None and i < attn_len:
|
|
9936
|
+
attn = attn_weights[i]
|
|
9937
|
+
score_quality = np.std(attn) if attn.size > 0 else self.confidence_threshold
|
|
9938
|
+
abstract_score = self.confidence_threshold + score_quality * anisotropy
|
|
9939
|
+
else:
|
|
9940
|
+
if attn_weights is not None and attn_len > 0:
|
|
9941
|
+
# use last valid index
|
|
9942
|
+
fallback_attn = attn_weights[min(i, attn_len - 1)]
|
|
9943
|
+
score_quality = 1.0 / (1.0 + np.exp(-fallback_attn))
|
|
9868
9944
|
else:
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9945
|
+
score_quality = self.confidence_threshold # neutral default
|
|
9946
|
+
abstract_score = (1.0 - np.mean(score_quality)) + eps
|
|
9947
|
+
|
|
9948
|
+
temp = (1.0 - abstract_score) + score_quality * anisotropy
|
|
9949
|
+
if isinstance(temp, np.ndarray):
|
|
9950
|
+
temp = float(np.clip(np.mean(temp), 1e-5, 5.0))
|
|
9951
|
+
temperature_accum.append(temp)
|
|
9952
|
+
|
|
9953
|
+
# bounds guard before indexing
|
|
9954
|
+
if 0 <= mlp_target < n_classes and i < calibrated.shape[0]:
|
|
9955
|
+
calibrated[i, mlp_target] = min(
|
|
9956
|
+
calibrated[i, mlp_target] * (1.5 * (1.0 - abstract_score)), 0.95
|
|
9957
|
+
)
|
|
9882
9958
|
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9959
|
+
row_sum = calibrated[i].sum()
|
|
9960
|
+
if row_sum > eps:
|
|
9961
|
+
calibrated[i] /= row_sum
|
|
9962
|
+
else:
|
|
9963
|
+
calibrated[i] = np.full(n_classes, 1.0 / n_classes)
|
|
9887
9964
|
|
|
9888
|
-
|
|
9889
|
-
except Exception as e:
|
|
9890
|
-
print(f'[!] cant calibrate probability due to: {e}, returning regular probability.')
|
|
9891
|
-
calibrated = calibrated.copy()
|
|
9965
|
+
self.temperature = float(np.mean(temperature_accum)) if temperature_accum else 1.0
|
|
9892
9966
|
|
|
9893
9967
|
return calibrated
|
|
9894
9968
|
|
|
@@ -10020,10 +10094,9 @@ class IntegratedPipeline:
|
|
|
10020
10094
|
|
|
10021
10095
|
|
|
10022
10096
|
def auto_generate_labels_from_texts(self, rules, texts):
|
|
10023
|
-
import re
|
|
10024
10097
|
y_raw = []
|
|
10025
10098
|
self.rules = rules
|
|
10026
|
-
|
|
10099
|
+
|
|
10027
10100
|
for text in texts:
|
|
10028
10101
|
text_lower = text.lower()
|
|
10029
10102
|
matched = False
|
|
@@ -10032,74 +10105,107 @@ class IntegratedPipeline:
|
|
|
10032
10105
|
y_raw.append(label)
|
|
10033
10106
|
matched = True
|
|
10034
10107
|
break
|
|
10035
|
-
|
|
10036
10108
|
if not matched:
|
|
10037
10109
|
y_raw.append('other')
|
|
10038
|
-
|
|
10039
|
-
from collections import Counter
|
|
10110
|
+
|
|
10040
10111
|
print("\n[📊] Auto-generated label distribution:")
|
|
10041
|
-
for label, count in Counter(y_raw).items():
|
|
10112
|
+
for label, count in sorted(Counter(y_raw).items()):
|
|
10042
10113
|
print(f" {label}: {count} ({count/len(texts)*100:.1f}%)")
|
|
10043
|
-
|
|
10044
|
-
return y_raw
|
|
10045
10114
|
|
|
10115
|
+
return y_raw
|
|
10046
10116
|
|
|
10047
10117
|
|
|
10048
10118
|
def mlp_training_features(self, rules, dataset):
|
|
10049
10119
|
print("\n[🔄] Preparing MLP data from dataset format")
|
|
10050
10120
|
|
|
10051
|
-
texts = [item[:-1] for item in dataset]
|
|
10052
|
-
labels = [item[-1] for item in dataset]
|
|
10053
|
-
|
|
10054
10121
|
if isinstance(dataset[0], tuple) and len(dataset[0]) == 2:
|
|
10055
|
-
|
|
10122
|
+
print('[=] Dataset Type 1: [(features, label), ...]')
|
|
10056
10123
|
features_list = []
|
|
10057
|
-
labels_list
|
|
10058
|
-
print('[=] Dataset Type 1: [(value), (value)]')
|
|
10124
|
+
labels_list = []
|
|
10059
10125
|
for item in dataset:
|
|
10060
10126
|
features, label = item
|
|
10061
10127
|
features_list.append(features)
|
|
10062
10128
|
labels_list.append(label)
|
|
10063
|
-
|
|
10064
10129
|
X_mlp = np.array(features_list)
|
|
10065
10130
|
y_raw = np.array(labels_list)
|
|
10066
|
-
|
|
10131
|
+
|
|
10067
10132
|
elif isinstance(dataset[0], (list, np.ndarray)) and len(dataset[0]) > 1:
|
|
10068
|
-
print('[=] Dataset Type 2')
|
|
10133
|
+
print('[=] Dataset Type 2: [feature1, feature2, ..., label]')
|
|
10134
|
+
texts = [item[:-1] for item in dataset]
|
|
10135
|
+
labels = [item[-1] for item in dataset]
|
|
10069
10136
|
X_mlp = np.array(texts)
|
|
10070
10137
|
y_raw = np.array(labels)
|
|
10071
10138
|
|
|
10072
|
-
else:
|
|
10073
|
-
print('[=] Dataset type 3')
|
|
10074
|
-
X_mlp = dataset.copy()
|
|
10075
|
-
y_raw = self.auto_generate_labels_from_texts(rules, dataset)
|
|
10139
|
+
else:
|
|
10140
|
+
print('[=] Dataset type 3: raw texts, auto-labeling via rules')
|
|
10141
|
+
X_mlp = dataset.copy()
|
|
10142
|
+
y_raw = self.auto_generate_labels_from_texts(rules, dataset)
|
|
10076
10143
|
|
|
10077
10144
|
unique_labels = sorted(set(y_raw))
|
|
10078
|
-
label_to_idx
|
|
10079
|
-
y_indices
|
|
10145
|
+
label_to_idx = {l: i for i, l in enumerate(unique_labels)}
|
|
10146
|
+
y_indices = np.array([label_to_idx[l] for l in y_raw])
|
|
10080
10147
|
|
|
10081
10148
|
n_classes = len(unique_labels)
|
|
10082
|
-
y_onehot
|
|
10149
|
+
y_onehot = np.zeros((len(y_indices), n_classes))
|
|
10083
10150
|
y_onehot[np.arange(len(y_indices)), y_indices] = 1
|
|
10084
10151
|
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10152
|
+
if isinstance(X_mlp, np.ndarray) and X_mlp.ndim > 1:
|
|
10153
|
+
input_dim = X_mlp.shape[1]
|
|
10154
|
+
elif isinstance(X_mlp, np.ndarray):
|
|
10155
|
+
input_dim = 1 # 1D array — single feature per sample
|
|
10088
10156
|
else:
|
|
10089
|
-
input_dim = len(X_mlp)
|
|
10157
|
+
input_dim = len(X_mlp[0]) if len(X_mlp) > 0 else 0
|
|
10090
10158
|
|
|
10091
10159
|
print(f"\n✅ MLP data ready:")
|
|
10092
|
-
print(f"[=] X shape: {
|
|
10160
|
+
print(f"[=] X shape: {X_mlp.shape if isinstance(X_mlp, np.ndarray) else len(X_mlp)}")
|
|
10161
|
+
print(f"[=] input_dim: {input_dim}")
|
|
10093
10162
|
print(f"[=] y shape: {y_onehot.shape}")
|
|
10094
|
-
print(f"[=] Classes: {label_to_idx}")
|
|
10095
|
-
return X_mlp, y_onehot, n_classes, input_dim
|
|
10163
|
+
print(f"[=] Classes: {label_to_idx}")
|
|
10096
10164
|
|
|
10097
|
-
|
|
10098
|
-
tuple_ver = (inp, inp)
|
|
10099
|
-
if X.shape != tuple_ver:
|
|
10100
|
-
X = X[:inp, :inp]
|
|
10165
|
+
return X_mlp, y_onehot, n_classes, input_dim
|
|
10101
10166
|
|
|
10102
|
-
|
|
10167
|
+
|
|
10168
|
+
def shape_adaptation(self, X, target_features):
|
|
10169
|
+
"""
|
|
10170
|
+
Adapts X's FEATURE dimension (columns) to match target_features.
|
|
10171
|
+
Sample count (rows) is never touched — only column width changes.
|
|
10172
|
+
|
|
10173
|
+
Args:
|
|
10174
|
+
X: (n_samples, n_features) array
|
|
10175
|
+
target_features: desired number of feature columns
|
|
10176
|
+
"""
|
|
10177
|
+
try:
|
|
10178
|
+
if X.ndim == 1:
|
|
10179
|
+
X = X.reshape(1, -1)
|
|
10180
|
+
|
|
10181
|
+
n_samples, n_features = X.shape
|
|
10182
|
+
|
|
10183
|
+
if n_features == target_features:
|
|
10184
|
+
return X
|
|
10185
|
+
|
|
10186
|
+
print(f'[⚠️] shape_adaptation: X has {n_features} features, '
|
|
10187
|
+
f'target is {target_features} — adapting columns only '
|
|
10188
|
+
f'(rows={n_samples} unchanged)')
|
|
10189
|
+
|
|
10190
|
+
X_adapted = np.zeros((n_samples, target_features))
|
|
10191
|
+
min_features = min(n_features, target_features)
|
|
10192
|
+
X_adapted[:, :min_features] = X[:, :min_features]
|
|
10193
|
+
|
|
10194
|
+
if n_features > target_features:
|
|
10195
|
+
print(f'[⚠️] shape_adaptation: TRUNCATED {n_features - target_features} '
|
|
10196
|
+
f'feature columns ({n_features} → {target_features})')
|
|
10197
|
+
else:
|
|
10198
|
+
print(f'[=] shape_adaptation: PADDED {target_features - n_features} '
|
|
10199
|
+
f'feature columns with zeros')
|
|
10200
|
+
except Exception as e:
|
|
10201
|
+
print(f'[-] Fallback to primitive shape adaptation due to {e}')
|
|
10202
|
+
print(f'[!] WARNING: This may pad shapes aggressively! ')
|
|
10203
|
+
inp = X.shape[1]
|
|
10204
|
+
tuple_ver = (inp, inp)
|
|
10205
|
+
if X.shape != tuple_ver:
|
|
10206
|
+
X = X[:inp, :inp]
|
|
10207
|
+
|
|
10208
|
+
return X_adapted
|
|
10103
10209
|
|
|
10104
10210
|
def AME_Encoder(self, x):
|
|
10105
10211
|
X = np.asarray(x)
|
|
@@ -10154,9 +10260,40 @@ class IntegratedPipeline:
|
|
|
10154
10260
|
|
|
10155
10261
|
return X, y, input_dim, n_classes
|
|
10156
10262
|
|
|
10157
|
-
def _set_lstm_samples(self, X, Y):
|
|
10158
|
-
|
|
10159
|
-
Y
|
|
10263
|
+
def _set_lstm_samples(self, X, Y, min_samples_for_split=10, use_cache_augmentation=True):
|
|
10264
|
+
"""
|
|
10265
|
+
Reshape X, Y for LSTM input. If sample count is too small for a
|
|
10266
|
+
meaningful train/val split, augment with verified entries from
|
|
10267
|
+
AccurateAnswerCache before reshaping.
|
|
10268
|
+
"""
|
|
10269
|
+
try:
|
|
10270
|
+
X = np.array(X)
|
|
10271
|
+
Y = np.array(Y)
|
|
10272
|
+
|
|
10273
|
+
# augment from accurate_cache before reshaping.
|
|
10274
|
+
if use_cache_augmentation and len(X) < min_samples_for_split:
|
|
10275
|
+
if hasattr(self, 'accurate_cache') and self.accurate_cache_lookup.cache:
|
|
10276
|
+
print(f'[=] Only {len(X)} samples — augmenting from accurate_cache '
|
|
10277
|
+
f'(has {len(self.accurate_cache_lookup.cache)} verified entries)')
|
|
10278
|
+
|
|
10279
|
+
cached_X, cached_Y = self._extract_cache_samples_for_lstm(
|
|
10280
|
+
target_count=min_samples_for_split - len(X)
|
|
10281
|
+
)
|
|
10282
|
+
|
|
10283
|
+
if len(cached_X) > 0:
|
|
10284
|
+
X = np.concatenate([X, cached_X], axis=0)
|
|
10285
|
+
Y = np.concatenate([Y, cached_Y], axis=0)
|
|
10286
|
+
print(f'[=] Augmented to {len(X)} samples using '
|
|
10287
|
+
f'{len(cached_X)} verified cache entries')
|
|
10288
|
+
else:
|
|
10289
|
+
print('[=] No suitable cache entries found for augmentation')
|
|
10290
|
+
|
|
10291
|
+
X = X[..., np.newaxis]
|
|
10292
|
+
Y = Y[..., np.newaxis]
|
|
10293
|
+
except Exception as e:
|
|
10294
|
+
print(f'[!] Error in seeting LSTM Samples: {e}, filling gaps with regular newaxis to populate data.')
|
|
10295
|
+
X = X = np.array(X)[..., np.newaxis]
|
|
10296
|
+
Y = np.array(Y)[..., np.newaxis]
|
|
10160
10297
|
|
|
10161
10298
|
print('[=] Successfully set up LSTM Samples:')
|
|
10162
10299
|
print(f'[=] X.shape: {X.shape}')
|
|
@@ -10164,6 +10301,37 @@ class IntegratedPipeline:
|
|
|
10164
10301
|
|
|
10165
10302
|
return X, Y
|
|
10166
10303
|
|
|
10304
|
+
|
|
10305
|
+
def _extract_cache_samples_for_lstm(self, target_count):
|
|
10306
|
+
"""
|
|
10307
|
+
Pull verified-correct entries from AccurateAnswerCache to use as
|
|
10308
|
+
additional LSTM training samples — only entries with multiple
|
|
10309
|
+
confirmed hits (hit_count >= 1) to avoid using unverified noise.
|
|
10310
|
+
"""
|
|
10311
|
+
if not hasattr(self, 'accurate_cache') or not self.accurate_cache_lookup.cache:
|
|
10312
|
+
return np.array([]), np.array([])
|
|
10313
|
+
|
|
10314
|
+
candidates = [
|
|
10315
|
+
entry for entry in self.accurate_cache_lookup.cache.values()
|
|
10316
|
+
if entry.get('hit_count', 0) >= 1 # only entries confirmed at least once
|
|
10317
|
+
]
|
|
10318
|
+
|
|
10319
|
+
# prioritize highest-confidence, most-confirmed entries first
|
|
10320
|
+
candidates.sort(key=lambda e: (e['hit_count'], e['confidence']), reverse=True)
|
|
10321
|
+
selected = candidates[:target_count]
|
|
10322
|
+
|
|
10323
|
+
if not selected:
|
|
10324
|
+
return np.array([]), np.array([])
|
|
10325
|
+
|
|
10326
|
+
cached_X = np.array([e['x_mlp'] for e in selected])
|
|
10327
|
+
cached_Y = np.array([
|
|
10328
|
+
e['prediction'] if isinstance(e['prediction'], (int, float))
|
|
10329
|
+
else e['confidence'] # fallback if prediction is a label string
|
|
10330
|
+
for e in selected
|
|
10331
|
+
])
|
|
10332
|
+
|
|
10333
|
+
return cached_X, cached_Y
|
|
10334
|
+
|
|
10167
10335
|
def lstm_setup_inference(self, raw_X, raw_Y):
|
|
10168
10336
|
print("\n" + "=" * 55)
|
|
10169
10337
|
print("===== LSTM SETUP INFERENCE =====")
|
|
@@ -10176,7 +10344,9 @@ class IntegratedPipeline:
|
|
|
10176
10344
|
AME = self.AME_Encoder(raw_X) # geometric complexity scalar
|
|
10177
10345
|
AMR = 1.0 / (1.0 + np.exp(-AME)) # abstract modelling rate
|
|
10178
10346
|
|
|
10179
|
-
|
|
10347
|
+
augmentation = AMR > self.confidence_threshold and self.peer_assistance_threshold < 0.15
|
|
10348
|
+
X, Y = self._set_lstm_samples(raw_X, raw_Y, use_cache_augmentation=augmentation)
|
|
10349
|
+
|
|
10180
10350
|
n_train = int(0.8 * len(X)) # 80% of the data training is used for training
|
|
10181
10351
|
X_val = X[n_train:]
|
|
10182
10352
|
Y_val = Y[n_train:]
|
|
@@ -12245,7 +12415,8 @@ class PipelineAsyncManager:
|
|
|
12245
12415
|
predicted_output.append(advanced_result)
|
|
12246
12416
|
|
|
12247
12417
|
# Get stats
|
|
12248
|
-
print(f"[=] Stats: {self.get_stats()}")
|
|
12418
|
+
print(f"[=] Stats: {self.get_stats()}")
|
|
12419
|
+
print('[=] Returning predicted output as list')
|
|
12249
12420
|
return predicted_output
|
|
12250
12421
|
|
|
12251
12422
|
except Exception as e:
|