AbstractIntegratedModule 1.1.3__tar.gz → 1.1.5__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.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.py +306 -46
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractOptimizedModules.c +200 -200
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/PKG-INFO +1 -1
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/README.md +61 -17
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/pyproject.toml +1 -1
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/setup.py +1 -1
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractOptimizedModules.pyx +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/MANIFEST.in +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/Cargo.toml +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/pyproject.toml +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/src/lib.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
- {abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/setup.cfg +0 -0
{abstractintegratedmodule-1.1.3 → abstractintegratedmodule-1.1.5}/AbstractIntegratedModule.py
RENAMED
|
@@ -485,12 +485,12 @@ class GeometricWeightShaping:
|
|
|
485
485
|
subnet = x[:min(10, x.shape[0]), :min(10, x.shape[1])]
|
|
486
486
|
gradient = np.gradient(subnet.flatten())
|
|
487
487
|
|
|
488
|
-
|
|
488
|
+
mean_vector_mag = np.mean(np.linalg.norm(gradient, axis=-1))
|
|
489
489
|
X_mag = np.mean(np.linalg.norm(X, axis=-1))
|
|
490
490
|
# Regular AME Equations, higher AME provides capabilities for the model to experience errors during abstraction
|
|
491
491
|
# Lower AME means lower chance for un optimal abstraction.
|
|
492
492
|
|
|
493
|
-
AME = np.log1p(X_mag) * np.log1p(
|
|
493
|
+
AME = np.log1p(X_mag) * np.log1p(mean_vector_mag)
|
|
494
494
|
return AME
|
|
495
495
|
|
|
496
496
|
# anisotropy provides the model the standard complexity of the data geometry, allowing it to know how complex the data needs to be processed.
|
|
@@ -1920,6 +1920,48 @@ class MLP:
|
|
|
1920
1920
|
|
|
1921
1921
|
return self.softmax.forward(x)
|
|
1922
1922
|
|
|
1923
|
+
def k_fold_split(self, X, y, k=5, seed=42, min_fold_size=2):
|
|
1924
|
+
X = np.asarray(X)
|
|
1925
|
+
y = np.asarray(y)
|
|
1926
|
+
n = len(X)
|
|
1927
|
+
|
|
1928
|
+
# adapt k downward for small datasets, never produce
|
|
1929
|
+
# folds smaller than min_fold_size
|
|
1930
|
+
effective_k = min(k, max(2, n // min_fold_size))
|
|
1931
|
+
if effective_k < k:
|
|
1932
|
+
print(f'[⚠️] k_fold_split: reduced k from {k} to {effective_k} '
|
|
1933
|
+
f'for n={n} samples, to avoid folds smaller than '
|
|
1934
|
+
f'{min_fold_size} samples')
|
|
1935
|
+
|
|
1936
|
+
rng = np.random.default_rng(seed)
|
|
1937
|
+
idx = rng.permutation(n)
|
|
1938
|
+
folds = np.array_split(idx, effective_k)
|
|
1939
|
+
|
|
1940
|
+
for i in range(effective_k):
|
|
1941
|
+
val_idx = folds[i]
|
|
1942
|
+
train_idx = np.concatenate([folds[j] for j in range(effective_k) if j != i])
|
|
1943
|
+
yield X[train_idx], y[train_idx], X[val_idx], y[val_idx]
|
|
1944
|
+
|
|
1945
|
+
|
|
1946
|
+
def confusion_matrix(self, y_true, y_pred, num_classes):
|
|
1947
|
+
y_true = np.asarray(y_true)
|
|
1948
|
+
y_pred = np.asarray(y_pred)
|
|
1949
|
+
|
|
1950
|
+
cm = np.zeros((num_classes, num_classes), dtype=int)
|
|
1951
|
+
|
|
1952
|
+
# Convert to label arrays: use argmax only if input is one-hot/prob (2D+),
|
|
1953
|
+
# otherwise need to treat as already being class labels.
|
|
1954
|
+
true_labels = np.argmax(y_true, axis=1) if y_true.ndim > 1 else y_true
|
|
1955
|
+
pred_labels = np.argmax(y_pred, axis=1) if y_pred.ndim > 1 else y_pred
|
|
1956
|
+
|
|
1957
|
+
for t, p in zip(true_labels, pred_labels):
|
|
1958
|
+
if 0 <= t < num_classes and 0 <= p < num_classes:
|
|
1959
|
+
cm[t, p] += 1
|
|
1960
|
+
else:
|
|
1961
|
+
print(f'[⚠️] confusion_matrix: label out of range '
|
|
1962
|
+
f'(true={t}, pred={p}, num_classes={num_classes}) — skipped')
|
|
1963
|
+
return cm
|
|
1964
|
+
|
|
1923
1965
|
def performance_calculation(self, x, AME=None, anisotropy=None):
|
|
1924
1966
|
eps = 1e-5
|
|
1925
1967
|
standard_low_error_mean = eps
|
|
@@ -1943,7 +1985,7 @@ class MLP:
|
|
|
1943
1985
|
|
|
1944
1986
|
return performance_score
|
|
1945
1987
|
|
|
1946
|
-
def forward(self, x, AME=None, anisotropy=None):
|
|
1988
|
+
def forward(self, x, y=None, AME=None, anisotropy=None, condition=None):
|
|
1947
1989
|
eps = 1e-5
|
|
1948
1990
|
performance_score = self.performance_calculation(x, AME=AME, anisotropy=anisotropy)
|
|
1949
1991
|
|
|
@@ -1951,6 +1993,11 @@ class MLP:
|
|
|
1951
1993
|
x = layer.forward(x, performance_score)
|
|
1952
1994
|
|
|
1953
1995
|
output = self.softmax.forward(x)
|
|
1996
|
+
if not condition == 'training' and y is not None:
|
|
1997
|
+
if y.shape == output.shape:
|
|
1998
|
+
acc = np.mean(np.argmax(output, axis=1) == np.argmax(y, axis=1))
|
|
1999
|
+
loss = Loss.categorical_crossentropy(y, output)
|
|
2000
|
+
print(f"[=] MLP Forward validation score: | loss: {loss:.4f} | Acc: {acc:.2%}")
|
|
1954
2001
|
|
|
1955
2002
|
return output
|
|
1956
2003
|
|
|
@@ -2175,7 +2222,7 @@ class MLP:
|
|
|
2175
2222
|
print(f'[+] MLP Training started with: {parameters} Parameters.')
|
|
2176
2223
|
for epoch in range(epochs):
|
|
2177
2224
|
if not focused_fit_condition:
|
|
2178
|
-
y_pred = self.forward(X, AME=AME, anisotropy=anisotropy)
|
|
2225
|
+
y_pred = self.forward(X, y=y, AME=AME, anisotropy=anisotropy, condition='training')
|
|
2179
2226
|
else:
|
|
2180
2227
|
y_pred = self.focused_forward(X, AME=AME, anisotropy=anisotropy)
|
|
2181
2228
|
|
|
@@ -3402,7 +3449,7 @@ class WeightedEnsemblePredictor:
|
|
|
3402
3449
|
AME = self.pipeline.model2.AME_Encoder(input_ids)
|
|
3403
3450
|
|
|
3404
3451
|
trans_probs, attn_weights = self.pipeline.model2.forward(input_ids, AME=AME, embedded=embedded)
|
|
3405
|
-
mlp_probs = self.pipeline.model3.forward(X_mlp)
|
|
3452
|
+
mlp_probs = self.pipeline.model3.forward(X_mlp, y=y_true)
|
|
3406
3453
|
lstm_probs, lstm_weight_hint = self._get_lstm_probs(input_ids, X_mlp, label_bins=label_bins)
|
|
3407
3454
|
|
|
3408
3455
|
established_agreement = self.query_node._establish_node_connection("PredictEnsemble")
|
|
@@ -3956,6 +4003,7 @@ class ExplainabilityModule:
|
|
|
3956
4003
|
def data_preparation(self, titles, labels):
|
|
3957
4004
|
datasets = []
|
|
3958
4005
|
raw = []
|
|
4006
|
+
|
|
3959
4007
|
for title in titles:
|
|
3960
4008
|
tupled_title = (str(title))
|
|
3961
4009
|
datasets.append(tupled_title)
|
|
@@ -3978,6 +4026,7 @@ class ExplainabilityModule:
|
|
|
3978
4026
|
filled = int(value * max_width)
|
|
3979
4027
|
return '█' * filled + '░' * (max_width - filled)
|
|
3980
4028
|
|
|
4029
|
+
|
|
3981
4030
|
def _learn_from_feedback(self, text, correct_label, wrong_result, batch_size=2):
|
|
3982
4031
|
eps = 1e-5
|
|
3983
4032
|
print(f"\n[📚] Learning: '{text}' → {correct_label}...")
|
|
@@ -4447,9 +4496,8 @@ class ExplainabilityModule:
|
|
|
4447
4496
|
print('[=] Note: Very little Consistency meaning Transformer attention quality is Healthy and focused')
|
|
4448
4497
|
|
|
4449
4498
|
if isinstance(final_conf, np.ndarray):
|
|
4450
|
-
final_conf = 1.0 / (1.0 + np.
|
|
4451
|
-
#
|
|
4452
|
-
# with real covariance of distribution from the data.
|
|
4499
|
+
final_conf = 1.0 / (1.0 + np.exp(-final_conf))
|
|
4500
|
+
# Apply a sigmoid transformation to ensure the confidence is between 0 and 1
|
|
4453
4501
|
|
|
4454
4502
|
if np.isnan(final_conf).any() or np.isinf(final_conf).any():
|
|
4455
4503
|
final_conf = self.pipeline.confidence_threshold
|
|
@@ -5944,10 +5992,13 @@ class ModelStorage:
|
|
|
5944
5992
|
|
|
5945
5993
|
try:
|
|
5946
5994
|
weights = result
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
self.pipeline.network_model.
|
|
5995
|
+
if isinstance(weights, str):
|
|
5996
|
+
weights = json.loads(weights)
|
|
5997
|
+
|
|
5998
|
+
self.pipeline.network_model.cell.W = np.array(weights.get('lstm_W'))
|
|
5999
|
+
self.pipeline.network_model.cell.b = np.array(weights.get('lstm_b'))
|
|
6000
|
+
self.pipeline.network_model.Wy = np.array(weights.get('Wy')) if weights.get('Wy') else None
|
|
6001
|
+
self.pipeline.network_model.by = np.array(weights.get('by'))
|
|
5951
6002
|
self.pipeline.lstm_engine.residual_mean = weights.get('residual_mean', 0.0)
|
|
5952
6003
|
self.pipeline.lstm_engine.residual_std = weights.get('residual_std', 1.0)
|
|
5953
6004
|
self.pipeline.lstm_engine.n_samples = weights.get('n_samples', self.pipeline.lstm_engine.n_samples)
|
|
@@ -5963,6 +6014,7 @@ class ModelStorage:
|
|
|
5963
6014
|
|
|
5964
6015
|
except Exception as e:
|
|
5965
6016
|
print(f'[!] Cant load any Weights due to: {e}')
|
|
6017
|
+
traceback.print_exc()
|
|
5966
6018
|
|
|
5967
6019
|
|
|
5968
6020
|
def load_transformer_dict(self, memory_name):
|
|
@@ -9823,6 +9875,134 @@ class IntegratedPipeline:
|
|
|
9823
9875
|
"Clear and reinitialize memory")
|
|
9824
9876
|
|
|
9825
9877
|
|
|
9878
|
+
def k_fold_cross_validate(self, X, y, input_dim, n_classes, k=5, seed=42,
|
|
9879
|
+
epochs=None, lr=None, log_to_diagnostics=True):
|
|
9880
|
+
"""
|
|
9881
|
+
Orchestrates init → train → predict across k folds. Each fold gets
|
|
9882
|
+
a FRESH model (no weight carryover between folds), and the model
|
|
9883
|
+
that existed before k-fold started is restored afterward — k-fold
|
|
9884
|
+
here is purely an evaluation procedure, not a permanent side effect.
|
|
9885
|
+
"""
|
|
9886
|
+
X = np.asarray(X)
|
|
9887
|
+
y = np.asarray(y)
|
|
9888
|
+
|
|
9889
|
+
# preserve pre-existing model, restore it once CV is done
|
|
9890
|
+
original_model = getattr(self, 'model3', None)
|
|
9891
|
+
|
|
9892
|
+
recorder = None
|
|
9893
|
+
if log_to_diagnostics:
|
|
9894
|
+
try:
|
|
9895
|
+
from abstract_diagnostics import get_recorder
|
|
9896
|
+
recorder = get_recorder(self.memory_name)
|
|
9897
|
+
except ImportError:
|
|
9898
|
+
pass # diagnostics package not installed — silently skip, no crash
|
|
9899
|
+
|
|
9900
|
+
aggregate_cm = np.zeros((n_classes, n_classes), dtype=int)
|
|
9901
|
+
fold_accuracies = []
|
|
9902
|
+
|
|
9903
|
+
for fold_idx, (X_tr, y_tr, X_val, y_val) in enumerate(
|
|
9904
|
+
self.model3.k_fold_split(X, y, k=k, seed=seed)
|
|
9905
|
+
):
|
|
9906
|
+
# FRESH model every fold — this is the load-bearing line
|
|
9907
|
+
self.initialize_model_(X_tr, input_dim, n_classes)
|
|
9908
|
+
self.model3.train(X_tr, y_tr,
|
|
9909
|
+
epochs=epochs or self.mlp_training_epochs,
|
|
9910
|
+
lr=lr or self.mlp_lr)
|
|
9911
|
+
|
|
9912
|
+
y_pred = self.model3.forward(X_val)
|
|
9913
|
+
cm = self.model3.confusion_matrix(y_val, y_pred, n_classes)
|
|
9914
|
+
aggregate_cm += cm
|
|
9915
|
+
|
|
9916
|
+
fold_acc = np.trace(cm) / max(cm.sum(), 1)
|
|
9917
|
+
fold_accuracies.append(fold_acc)
|
|
9918
|
+
print(f'[=] Fold {fold_idx + 1}/{k}: accuracy={fold_acc:.2%}')
|
|
9919
|
+
|
|
9920
|
+
if recorder:
|
|
9921
|
+
recorder.log_scalar('mlp/kfold_accuracy', fold_acc, step=fold_idx)
|
|
9922
|
+
|
|
9923
|
+
self.model3 = original_model # restore — CV was evaluation only
|
|
9924
|
+
|
|
9925
|
+
mean_acc, std_acc = float(np.mean(fold_accuracies)), float(np.std(fold_accuracies))
|
|
9926
|
+
print(f'[=] K-Fold CV complete: {mean_acc:.2%} ± {std_acc:.2%}')
|
|
9927
|
+
|
|
9928
|
+
if recorder:
|
|
9929
|
+
recorder.log_scalar('mlp/kfold_mean_accuracy', mean_acc)
|
|
9930
|
+
recorder.log_scalar('mlp/kfold_std_accuracy', std_acc)
|
|
9931
|
+
|
|
9932
|
+
return {
|
|
9933
|
+
'fold_accuracies': fold_accuracies,
|
|
9934
|
+
'mean_accuracy': mean_acc,
|
|
9935
|
+
'std_accuracy': std_acc,
|
|
9936
|
+
'confusion_matrix': aggregate_cm,
|
|
9937
|
+
}
|
|
9938
|
+
|
|
9939
|
+
def evaluate_mlp_performance(self, X, y, label_map, k=5, seed=42):
|
|
9940
|
+
"""
|
|
9941
|
+
input_dim and n_classes are ALWAYS derived from the actual X/y
|
|
9942
|
+
given to this call — never accepted as separate parameters that
|
|
9943
|
+
could silently drift out of sync with the real data (the exact
|
|
9944
|
+
bug class this whole session was about).
|
|
9945
|
+
"""
|
|
9946
|
+
X = np.asarray(X)
|
|
9947
|
+
y = np.asarray(y)
|
|
9948
|
+
|
|
9949
|
+
if X.ndim == 1:
|
|
9950
|
+
X = X.reshape(-1, 1)
|
|
9951
|
+
|
|
9952
|
+
# derived input_dim directly from X, matching this call's
|
|
9953
|
+
# ACTUAL data.
|
|
9954
|
+
input_dim = X.shape[1]
|
|
9955
|
+
model_classes = self._get_num_classes()
|
|
9956
|
+
|
|
9957
|
+
#derived n_classes the same authoritative way used
|
|
9958
|
+
# throughout the rest of the pipeline (_get_num_classes as
|
|
9959
|
+
# primary source, cross-checked against y itself)
|
|
9960
|
+
|
|
9961
|
+
y_arr = np.asarray(y)
|
|
9962
|
+
|
|
9963
|
+
onehot_validation = self._validate_onehot(y)
|
|
9964
|
+
if onehot_validation:
|
|
9965
|
+
if model_classes != len(label_map):
|
|
9966
|
+
model_classes = len(label_map)
|
|
9967
|
+
if model_classes > np.max(y):
|
|
9968
|
+
y = np.eye(model_classes)[np.asarray(y)]
|
|
9969
|
+
else:
|
|
9970
|
+
print('[⚠️] Warning: Proper Y onehot encoding fails, modifying number of classes to exactly match Y values to do one final one hot encoding...')
|
|
9971
|
+
try:
|
|
9972
|
+
model_classes = np.max(y) + 1
|
|
9973
|
+
y = np.eye(model_classes)[np.asarray(y)]
|
|
9974
|
+
except:
|
|
9975
|
+
print('[!] Error: One hot encoding failed, please check your Y values and label map for consistency, passing raw Y and skipping MLP Training...')
|
|
9976
|
+
unsuitable = True
|
|
9977
|
+
y = y.copy() # fallback to raw y if one-hot fails
|
|
9978
|
+
|
|
9979
|
+
if y_arr.ndim > 1:
|
|
9980
|
+
n_classes_from_y = y_arr.shape[1]
|
|
9981
|
+
else:
|
|
9982
|
+
n_classes_from_y = int(y_arr.max()) + 1
|
|
9983
|
+
|
|
9984
|
+
if model_classes is not None and model_classes != n_classes_from_y:
|
|
9985
|
+
print(f'[⚠️] evaluate_mlp_performance: n_classes mismatch — '
|
|
9986
|
+
f'model reports {model_classes}, y data implies '
|
|
9987
|
+
f'{n_classes_from_y}. Using y-derived value ({n_classes_from_y}) '
|
|
9988
|
+
f'since k-fold must match the ACTUAL labels being evaluated.')
|
|
9989
|
+
n_classes = n_classes_from_y
|
|
9990
|
+
|
|
9991
|
+
print(f'[=] evaluate_mlp_performance: derived input_dim={input_dim}, '
|
|
9992
|
+
f'n_classes={n_classes} from provided X/y (shapes: '
|
|
9993
|
+
f'X={X.shape}, y={y_arr.shape})')
|
|
9994
|
+
|
|
9995
|
+
result = self.k_fold_cross_validate(X, y, input_dim, n_classes, k=k, seed=seed)
|
|
9996
|
+
|
|
9997
|
+
print('========= MLP Performance Evaluation Summary ============')
|
|
9998
|
+
print(f'[=>] MLP performance evaluation complete: mean accuracy={result["mean_accuracy"]:.2%}, '
|
|
9999
|
+
f'std accuracy={result["std_accuracy"]:.2%}')
|
|
10000
|
+
print(f'[=>] Confusion matrix:\n{result["confusion_matrix"]}')
|
|
10001
|
+
print(f'[=>] Fold accuracies: {result["fold_accuracies"]}')
|
|
10002
|
+
print(f'[=>] K-Fold CV complete: {result["mean_accuracy"]:.2%} ± {result["std_accuracy"]:.2%}')
|
|
10003
|
+
return result
|
|
10004
|
+
|
|
10005
|
+
|
|
9826
10006
|
def _validate_tuple_memory(self, memory: tuple, num_classes: int) -> tuple:
|
|
9827
10007
|
"""
|
|
9828
10008
|
Validate tuple memory entry.
|
|
@@ -11505,7 +11685,7 @@ class IntegratedPipeline:
|
|
|
11505
11685
|
method='dynamic', embedded=embedded
|
|
11506
11686
|
)
|
|
11507
11687
|
else:
|
|
11508
|
-
fresh_probs = self.model3.forward(fresh_X_raw)
|
|
11688
|
+
fresh_probs = self.model3.forward(fresh_X_raw, y=y_true)
|
|
11509
11689
|
try:
|
|
11510
11690
|
fresh_trans_probs, _ = self.model2.forward(fresh_input_ids, embedded=False)
|
|
11511
11691
|
except:
|
|
@@ -12878,6 +13058,7 @@ class IntegratedPipeline:
|
|
|
12878
13058
|
|
|
12879
13059
|
return float(np.asarray(arr).flat[-1]) # ultimate fallback, never crashes
|
|
12880
13060
|
|
|
13061
|
+
|
|
12881
13062
|
def _get_ensemble_confidence_for_true_class(self, X, Y, input_ids=None, eps=1e-3):
|
|
12882
13063
|
"""
|
|
12883
13064
|
Computes, per sample, how confident the MLP + Transformer ensemble
|
|
@@ -12921,7 +13102,7 @@ class IntegratedPipeline:
|
|
|
12921
13102
|
if X.shape != self.model3.layers[0].W.shape:
|
|
12922
13103
|
X = np.reshape(X, (n_samples, self.model3.layers[0].W.shape[0]))
|
|
12923
13104
|
|
|
12924
|
-
mlp_probs = np.asarray(self.model3.forward(X), dtype=np.float64)
|
|
13105
|
+
mlp_probs = np.asarray(self.model3.forward(X, y=Y), dtype=np.float64)
|
|
12925
13106
|
if mlp_probs.ndim == 1:
|
|
12926
13107
|
mlp_probs = mlp_probs.reshape(1, -1)
|
|
12927
13108
|
except Exception as e:
|
|
@@ -12987,6 +13168,7 @@ class IntegratedPipeline:
|
|
|
12987
13168
|
|
|
12988
13169
|
return confidences
|
|
12989
13170
|
|
|
13171
|
+
|
|
12990
13172
|
def lstm_setup_inference(self, raw_X, raw_Y, input_ids=None):
|
|
12991
13173
|
print("\n" + "=" * 55)
|
|
12992
13174
|
print("===== LSTM SETUP INFERENCE =====")
|
|
@@ -13139,6 +13321,7 @@ class IntegratedPipeline:
|
|
|
13139
13321
|
raise Warning('[!] Dataset is None or empty! Make sure you provide a dataset or create it automatically.')
|
|
13140
13322
|
|
|
13141
13323
|
if not self.model2:
|
|
13324
|
+
print(datasets)
|
|
13142
13325
|
intents = [d[1] for d in datasets]
|
|
13143
13326
|
intent_to_id = {intent: i for i, intent in enumerate(sorted(set(intents)))}
|
|
13144
13327
|
num_classes = self._get_num_classes(label_map=label_map)
|
|
@@ -13224,6 +13407,7 @@ class IntegratedPipeline:
|
|
|
13224
13407
|
|
|
13225
13408
|
if isinstance(X_provided, (str, np.str_)):
|
|
13226
13409
|
X_provided = _safe_parse_string(X_provided)
|
|
13410
|
+
|
|
13227
13411
|
|
|
13228
13412
|
if isinstance(X_provided, np.ndarray) and np.issubdtype(X_provided.dtype, np.character):
|
|
13229
13413
|
joined = ' '.join(X_provided.astype(str).flatten())
|
|
@@ -13316,7 +13500,7 @@ class IntegratedPipeline:
|
|
|
13316
13500
|
|
|
13317
13501
|
issues = []
|
|
13318
13502
|
|
|
13319
|
-
# 1. Values outside [0, 1]
|
|
13503
|
+
# 1. Values outside [0, 1].
|
|
13320
13504
|
out_of_range = (y_true < 0) | (y_true > 1)
|
|
13321
13505
|
if out_of_range.any():
|
|
13322
13506
|
bad_rows = np.where(out_of_range.any(axis=1))[0]
|
|
@@ -13349,7 +13533,7 @@ class IntegratedPipeline:
|
|
|
13349
13533
|
)
|
|
13350
13534
|
|
|
13351
13535
|
if issues:
|
|
13352
|
-
print(f"[>] [{context}]
|
|
13536
|
+
print(f"[>] [{context}] y sample is not properly one-hot encoded, one-hot encoding y sample...")
|
|
13353
13537
|
return True
|
|
13354
13538
|
|
|
13355
13539
|
return False
|
|
@@ -13358,6 +13542,7 @@ class IntegratedPipeline:
|
|
|
13358
13542
|
def transformer_utilities(self, X_provided= None, X_raw=None, y_true=None, rules=None,
|
|
13359
13543
|
datasets=None, label_map=None, batch_size=2, min_signal=1e-3,
|
|
13360
13544
|
max_samples_for_focused_fit=500):
|
|
13545
|
+
unsuitable = False
|
|
13361
13546
|
if X_provided is not None:
|
|
13362
13547
|
X_raw = X_provided
|
|
13363
13548
|
|
|
@@ -13520,8 +13705,14 @@ class IntegratedPipeline:
|
|
|
13520
13705
|
if n_classes > np.max(y):
|
|
13521
13706
|
y = np.eye(n_classes)[np.asarray(y)]
|
|
13522
13707
|
else:
|
|
13523
|
-
print('[⚠️] Warning: Y onehot encoding fails,
|
|
13524
|
-
|
|
13708
|
+
print('[⚠️] Warning: Proper Y onehot encoding fails, modifying number of classes to exactly match Y values to do one final one hot encoding...')
|
|
13709
|
+
try:
|
|
13710
|
+
n_classes = np.max(y) + 1
|
|
13711
|
+
y = np.eye(n_classes)[np.asarray(y)]
|
|
13712
|
+
except:
|
|
13713
|
+
print('[!] Error: One hot encoding failed, please check your Y values and label map for consistency, passing raw Y and skipping MLP Training...')
|
|
13714
|
+
unsuitable = True
|
|
13715
|
+
y = y.copy() # fallback to raw y if one-hot fails
|
|
13525
13716
|
|
|
13526
13717
|
if self.model2 is None:
|
|
13527
13718
|
self.model2 = Transformer(
|
|
@@ -13534,9 +13725,15 @@ class IntegratedPipeline:
|
|
|
13534
13725
|
if self.use_transformer:
|
|
13535
13726
|
self.model2.train(sequence_inputs, y_true, epochs=self.transformer_training_epochs, mode=mode, lr=lr, embedded=True, batch_size=batch_size)
|
|
13536
13727
|
|
|
13537
|
-
X = self.shape_adaptation(hybrid_X, input_dim)
|
|
13728
|
+
X = self.shape_adaptation(hybrid_X, input_dim)
|
|
13729
|
+
|
|
13730
|
+
|
|
13538
13731
|
self.initialize_model_(X, input_dim, n_classes)
|
|
13539
|
-
|
|
13732
|
+
if not unsuitable:
|
|
13733
|
+
self.model3.train(X, y, epochs=self.mlp_training_epochs, lr=self.mlp_lr, max_samples_for_focused_fit=max_samples_for_focused_fit)
|
|
13734
|
+
else:
|
|
13735
|
+
print('[->] MLP Training skipped due to unproper Y samples.')
|
|
13736
|
+
|
|
13540
13737
|
self.lstm_setup_inference(X, y, input_ids=sequence_inputs)
|
|
13541
13738
|
if self.lstm_engine:
|
|
13542
13739
|
self.storage.save_weights(self.memory_name, model_type='Pipeline')
|
|
@@ -14312,6 +14509,7 @@ class AsyncResultQueue:
|
|
|
14312
14509
|
logger.debug(f"[=] Submitted request {request_id}: {texts}")
|
|
14313
14510
|
return request_id
|
|
14314
14511
|
|
|
14512
|
+
|
|
14315
14513
|
async def wait_for_result(self, request_id: str, timeout: int = 30) -> Dict:
|
|
14316
14514
|
"""
|
|
14317
14515
|
Wait for a specific request to complete.
|
|
@@ -16176,7 +16374,6 @@ class PipelineAsyncManager:
|
|
|
16176
16374
|
class PipelinePredictionManager:
|
|
16177
16375
|
def __init__(self, pipeline, label_csv='labels.csv', target_title='title', label='label'):
|
|
16178
16376
|
self.pipeline = pipeline
|
|
16179
|
-
|
|
16180
16377
|
try:
|
|
16181
16378
|
print("📖 Loading labels from text file...")
|
|
16182
16379
|
self.titles, self.y_raw, self.label_map = self.load_labels_from_csv(label_csv, target_title, label)
|
|
@@ -16297,8 +16494,10 @@ class PipelinePredictionManager:
|
|
|
16297
16494
|
X_gen = None
|
|
16298
16495
|
use_embedded = False
|
|
16299
16496
|
attn_weights = None
|
|
16497
|
+
|
|
16300
16498
|
trans_probs = None
|
|
16301
16499
|
mlp_probs = None
|
|
16500
|
+
target_probs = None
|
|
16302
16501
|
|
|
16303
16502
|
print(f"\n[🚀] Regular Prediction Initiated...")
|
|
16304
16503
|
self.pipeline.titles = titles
|
|
@@ -16315,6 +16514,30 @@ class PipelinePredictionManager:
|
|
|
16315
16514
|
_, y, _, _ = self.pipeline.mlp_training_features(rules, dataset)
|
|
16316
16515
|
else:
|
|
16317
16516
|
dataset, _ = self.pipeline.data_preparation(titles, label_map)
|
|
16517
|
+
|
|
16518
|
+
if X is not None or y is not None and isinstance(X, (np.ndarray, list)) and isinstance(y, (np.ndarray, list)) and len(X) > 0 and len(y) > 0:
|
|
16519
|
+
X_train, X_val, y_train, y_val = self._prepare_train_val_split(
|
|
16520
|
+
X, y, min_val_per_class=5, min_frac=0.1, max_frac=0.3
|
|
16521
|
+
)
|
|
16522
|
+
|
|
16523
|
+
onehot_validation = self.pipeline._validate_onehot(y_train)
|
|
16524
|
+
if onehot_validation:
|
|
16525
|
+
if num_classes != len(label_map):
|
|
16526
|
+
num_classes = len(label_map)
|
|
16527
|
+
if num_classes > np.max(y_train):
|
|
16528
|
+
y_train = np.eye(num_classes)[np.asarray(y_train)]
|
|
16529
|
+
y_val = np.eye(num_classes)[np.asarray(y_val)]
|
|
16530
|
+
else:
|
|
16531
|
+
print('[⚠️] Warning: Y onehot encoding fails, Returning y samples as is, This may cause Exploding Gradient in MLP Training!')
|
|
16532
|
+
y_train = y_train
|
|
16533
|
+
y_val = y_val
|
|
16534
|
+
|
|
16535
|
+
X_mean = X_train.mean(axis=0)
|
|
16536
|
+
X_std = X_train.std(axis=0) + 1e-8
|
|
16537
|
+
|
|
16538
|
+
X_train = (X_train - X_mean) / X_std
|
|
16539
|
+
X = (X_val - X_mean) / X_std
|
|
16540
|
+
y = y_val.copy()
|
|
16318
16541
|
|
|
16319
16542
|
if X_gen is not None:
|
|
16320
16543
|
self.pipeline.transformer_utilities(X_provided=X, X_raw=X_gen, y_true=y, rules=rules, datasets=dataset, label_map=label_map, batch_size=batch_size)
|
|
@@ -16386,15 +16609,8 @@ class PipelinePredictionManager:
|
|
|
16386
16609
|
X_tfidf = X
|
|
16387
16610
|
|
|
16388
16611
|
# Forward pass through MLP
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
X_tfidf = X
|
|
16392
|
-
mlp_probs = self.pipeline.model3.predict_proba(X)
|
|
16393
|
-
else:
|
|
16394
|
-
# Fallback if predict_proba not available
|
|
16395
|
-
logits = self.pipeline.model3.forward(X)
|
|
16396
|
-
mlp_probs = self.pipeline._softmax(logits)
|
|
16397
|
-
|
|
16612
|
+
mlp_probs = self.pipeline.model3.forward(X, y=y)
|
|
16613
|
+
|
|
16398
16614
|
# Validate all MLP predictions at once
|
|
16399
16615
|
mlp_pred_indices = np.argmax(mlp_probs, axis=1)
|
|
16400
16616
|
if num_classes <= 0:
|
|
@@ -16674,6 +16890,7 @@ class PipelinePredictionManager:
|
|
|
16674
16890
|
self.pipeline.titles = titles
|
|
16675
16891
|
self.pipeline.labels = label_map
|
|
16676
16892
|
|
|
16893
|
+
num_classes = self.pipeline._get_num_classes(label_map=label_map)
|
|
16677
16894
|
try:
|
|
16678
16895
|
|
|
16679
16896
|
if titles is not None and rules is not None:
|
|
@@ -16685,10 +16902,34 @@ class PipelinePredictionManager:
|
|
|
16685
16902
|
else:
|
|
16686
16903
|
datasets, _ = self.pipeline.data_preparation(titles, label_map)
|
|
16687
16904
|
|
|
16905
|
+
if X is not None or y is not None and len(X) > 0 and len(y) > 0:
|
|
16906
|
+
X_train, X_val, y_train, y_val = self._prepare_train_val_split(
|
|
16907
|
+
X, y, min_val_per_class=5, min_frac=0.1, max_frac=0.3
|
|
16908
|
+
)
|
|
16909
|
+
|
|
16910
|
+
onehot_validation = self.pipeline._validate_onehot(y_train)
|
|
16911
|
+
if onehot_validation:
|
|
16912
|
+
if num_classes != len(label_map):
|
|
16913
|
+
num_classes = len(label_map)
|
|
16914
|
+
if num_classes > np.max(y_train):
|
|
16915
|
+
y_train = np.eye(num_classes)[np.asarray(y_train)]
|
|
16916
|
+
y_val = np.eye(num_classes)[np.asarray(y_val)]
|
|
16917
|
+
else:
|
|
16918
|
+
print('[⚠️] Warning: Y onehot encoding fails, Returning y samples as is, This may cause Exploding Gradient in MLP Training!')
|
|
16919
|
+
y_train = y_train
|
|
16920
|
+
y_val = y_val
|
|
16921
|
+
|
|
16922
|
+
X_mean = X_train.mean(axis=0)
|
|
16923
|
+
X_std = X_train.std(axis=0) + 1e-8
|
|
16924
|
+
|
|
16925
|
+
X_train = (X_train - X_mean) / X_std
|
|
16926
|
+
X = (X_val - X_mean) / X_std
|
|
16927
|
+
y = y_val.copy()
|
|
16928
|
+
|
|
16688
16929
|
if X_gen is not None:
|
|
16689
|
-
self.pipeline.transformer_utilities(X_provided=
|
|
16930
|
+
self.pipeline.transformer_utilities(X_provided=X_train, X_raw=X_gen, y_true=y_train, rules=rules, datasets=dataset, label_map=label_map, batch_size=batch_size)
|
|
16690
16931
|
else:
|
|
16691
|
-
self.pipeline.transformer_utilities(X_provided=
|
|
16932
|
+
self.pipeline.transformer_utilities(X_provided=X_train, X_raw=X, y_true=y_train, rules=rules, datasets=dataset, label_map=label_map, batch_size=batch_size)
|
|
16692
16933
|
|
|
16693
16934
|
reverse_map = {v: k for k, v in label_map.items()}
|
|
16694
16935
|
|
|
@@ -17209,7 +17450,7 @@ class PipelinePredictionManager:
|
|
|
17209
17450
|
signals.append(f'AME={AME:.3f}')
|
|
17210
17451
|
|
|
17211
17452
|
if error_counts is not None and len(error_counts) > 0:
|
|
17212
|
-
#
|
|
17453
|
+
# max: catches localized single-class failure
|
|
17213
17454
|
# that a flat average would dilute away
|
|
17214
17455
|
worst_class_idx = int(np.argmax(error_counts))
|
|
17215
17456
|
max_error = float(error_counts[worst_class_idx])
|
|
@@ -17248,6 +17489,7 @@ class PipelinePredictionManager:
|
|
|
17248
17489
|
AME = None
|
|
17249
17490
|
use_embedded = False
|
|
17250
17491
|
dataset = None
|
|
17492
|
+
target_probs = None
|
|
17251
17493
|
|
|
17252
17494
|
X_gen = None
|
|
17253
17495
|
sec_chosen_label = None
|
|
@@ -17431,12 +17673,8 @@ class PipelinePredictionManager:
|
|
|
17431
17673
|
X = np.asarray(X)
|
|
17432
17674
|
|
|
17433
17675
|
# MLP forward pass
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
else:
|
|
17437
|
-
logits = self.pipeline.model3.forward(X)
|
|
17438
|
-
mlp_probs = self.pipeline._softmax(logits)
|
|
17439
|
-
|
|
17676
|
+
mlp_probs = self.pipeline.model3.forward(X, y=y_val)
|
|
17677
|
+
|
|
17440
17678
|
# Validate all MLP predictions at once
|
|
17441
17679
|
mlp_pred_indices = np.argmax(mlp_probs, axis=1)
|
|
17442
17680
|
if num_classes <= 0:
|
|
@@ -17479,6 +17717,7 @@ class PipelinePredictionManager:
|
|
|
17479
17717
|
return result, cached['prediction'], cached['confidence']
|
|
17480
17718
|
else:
|
|
17481
17719
|
print(f'[!] Similarity: {cached['similarity']} is low, Cannot pick label due to low certainty, Initiating advanced prediction...')
|
|
17720
|
+
target_probs = mlp_probs.copy()
|
|
17482
17721
|
else:
|
|
17483
17722
|
print('[=] No verified output from cache available that matched samples, starting advanced prediction...')
|
|
17484
17723
|
if self.pipeline.use_transformer:
|
|
@@ -17487,7 +17726,7 @@ class PipelinePredictionManager:
|
|
|
17487
17726
|
|
|
17488
17727
|
target_probs = self.pipeline.predict_proba(input_ids, X, type='Hybrid', embedded=use_embedded)
|
|
17489
17728
|
else:
|
|
17490
|
-
target_probs = mlp_probs
|
|
17729
|
+
target_probs = mlp_probs.copy()
|
|
17491
17730
|
|
|
17492
17731
|
target_probs = target_probs[:mlp_probs.shape[0], :mlp_probs.shape[1]]
|
|
17493
17732
|
target_probs = self.pipeline.model3.continuous_predictive_correction(self, target_probs, mlp_pred_indices)
|
|
@@ -17571,7 +17810,9 @@ class PipelinePredictionManager:
|
|
|
17571
17810
|
|
|
17572
17811
|
# Transformer prediction and blending
|
|
17573
17812
|
if trans_probs is not None and attn_weights is not None:
|
|
17574
|
-
|
|
17813
|
+
if i < len(trans_probs):
|
|
17814
|
+
trans_probs_i = trans_probs[i]
|
|
17815
|
+
|
|
17575
17816
|
trans_class_idx = np.argmax(trans_probs_i)
|
|
17576
17817
|
if isinstance(trans_probs_i, float):
|
|
17577
17818
|
trans_confidence = target_confidence
|
|
@@ -17649,7 +17890,10 @@ class PipelinePredictionManager:
|
|
|
17649
17890
|
agreement = mlp_class_idx == trans_class_idx
|
|
17650
17891
|
|
|
17651
17892
|
else:
|
|
17652
|
-
|
|
17893
|
+
if i < len(mlp_probs):
|
|
17894
|
+
final_probs = mlp_probs[i]
|
|
17895
|
+
else:
|
|
17896
|
+
final_probs = mlp_probs[0]
|
|
17653
17897
|
|
|
17654
17898
|
final_class_idx = target_class_idx
|
|
17655
17899
|
final_confidence = target_confidence[0] if isinstance(target_confidence, np.ndarray) else target_confidence
|
|
@@ -17834,9 +18078,10 @@ class PipelinePredictionManager:
|
|
|
17834
18078
|
'X_samples': X,
|
|
17835
18079
|
'input_ids': input_ids
|
|
17836
18080
|
}
|
|
18081
|
+
print('[=] Displaying Test Performance Results....')
|
|
17837
18082
|
if titles is not None and len(titles) > 0:
|
|
17838
18083
|
correct, sec_correct = self.display_hybrid_results(payload, final_class_idx, results, top_k, verbose=True)
|
|
17839
|
-
|
|
18084
|
+
|
|
17840
18085
|
return results, chosen_label, confidence
|
|
17841
18086
|
|
|
17842
18087
|
else:
|
|
@@ -18122,7 +18367,8 @@ class PipelinePredictionManager:
|
|
|
18122
18367
|
else:
|
|
18123
18368
|
print(f'[⚡] Final Prediction: {chosen_label} with confidence: {confidence:.1%}')
|
|
18124
18369
|
chosen_label = chosen_label
|
|
18125
|
-
|
|
18370
|
+
|
|
18371
|
+
self.pipeline.evaluate_mlp_performance(X, y, self.label_map)
|
|
18126
18372
|
# delete pipelines cache
|
|
18127
18373
|
print('[🔍] Pipelines Cache Cleaned!')
|
|
18128
18374
|
self.pipeline.cache.clear()
|
|
@@ -18184,8 +18430,7 @@ class PipelinePredictionManager:
|
|
|
18184
18430
|
|
|
18185
18431
|
except Exception as e:
|
|
18186
18432
|
print(f'[!] Cant check and calibrate probs based on penalty due to: {e}')
|
|
18187
|
-
|
|
18188
|
-
|
|
18433
|
+
|
|
18189
18434
|
return final_probs
|
|
18190
18435
|
|
|
18191
18436
|
|
|
@@ -20301,6 +20546,21 @@ def PermissiveTest():
|
|
|
20301
20546
|
("Watching Slack", "communication"),
|
|
20302
20547
|
("Programming in Visual Studio Code", "focused_work"),
|
|
20303
20548
|
("Watching netflix.com - Chrome", "break"),
|
|
20549
|
+
("Listening to Spotify", "entertainment"),
|
|
20550
|
+
("Playing Steam Game", "gaming"),
|
|
20551
|
+
("Checking Discord messages", "communication"),
|
|
20552
|
+
("Reading documentation on StackOverflow", "research"),
|
|
20553
|
+
("Downloading files from Google Drive", "file_work"),
|
|
20554
|
+
("Using Terminal to run scripts", "system_work"),
|
|
20555
|
+
("Analyzing data in Excel", "data_work"),
|
|
20556
|
+
("Attending Zoom meeting", "communication"),
|
|
20557
|
+
("Designing in Photoshop", "creative"),
|
|
20558
|
+
("Learning from Coursera course", "learning"),
|
|
20559
|
+
("Using Calculator utility", "utility"),
|
|
20560
|
+
("Browsing Facebook on Chrome", "social_media"),
|
|
20561
|
+
("Reading an eBook in PDF format", "reading"),
|
|
20562
|
+
("Listening to a podcast", "audio_learning"),
|
|
20563
|
+
("Using Google Translate", "utility"),
|
|
20304
20564
|
]
|
|
20305
20565
|
rules = [
|
|
20306
20566
|
# === WORK / PRODUCTIVITY ===
|