AbstractIntegratedModule 1.0.9__tar.gz → 1.1.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-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/PKG-INFO +1 -1
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.py +147 -41
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractOptimizedModules.c +391 -348
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/PKG-INFO +1 -1
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/README.md +5 -4
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/pyproject.toml +1 -1
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/setup.py +1 -1
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractOptimizedModules.pyx +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/MANIFEST.in +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/Cargo.toml +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/pyproject.toml +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/src/lib.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/libsqlite3-sys-ed07b882cd2aa5e2/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/serde_core-ebc15f2e9cad7f5f/out/private.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/debug/build/target-lexicon-08527f45de28143d/out/host.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/libsqlite3-sys-bf0400df4523274c/out/bindgen.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/serde_core-5cdb76131825e4af/out/private.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/abstract_model_storage/target/release/build/target-lexicon-43eb95a0588bf457/out/host.rs +0 -0
- {abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/setup.cfg +0 -0
{abstractintegratedmodule-1.0.9 → abstractintegratedmodule-1.1.1}/AbstractIntegratedModule.py
RENAMED
|
@@ -869,10 +869,10 @@ class Transformer:
|
|
|
869
869
|
if _OPT_AVAILABLE:
|
|
870
870
|
B, S, D = batch_size, seq_len, d_model
|
|
871
871
|
M = D // self.n_heads
|
|
872
|
-
|
|
873
872
|
Q = optimized_project_heads(x, W_q_mix, B, S, self.n_heads, D, M)
|
|
874
873
|
K = optimized_project_heads(x, W_k_mix, B, S, self.n_heads, D, M)
|
|
875
874
|
V = optimized_project_heads(x, W_v_mix, B, S, self.n_heads, D, M)
|
|
875
|
+
|
|
876
876
|
else:
|
|
877
877
|
Q = np.einsum('bsd,hdm->bhsm', x, W_q_mix)
|
|
878
878
|
K = np.einsum('bsd,hdm->bhsm', x, W_k_mix)
|
|
@@ -1854,9 +1854,15 @@ class Dense:
|
|
|
1854
1854
|
db = np.sum(dz, axis=0, keepdims=True) / batch_size
|
|
1855
1855
|
dx = np.dot(dz, self.W.T)
|
|
1856
1856
|
|
|
1857
|
-
#
|
|
1858
|
-
|
|
1859
|
-
|
|
1857
|
+
# global norm clipping.
|
|
1858
|
+
# Preserves gradient DIRECTION, only scales magnitude down when
|
|
1859
|
+
# the total norm exceeds clip_value — avoided the frozen-equilibrium
|
|
1860
|
+
# pattern that per-element clipping can produce.
|
|
1861
|
+
total_norm = np.sqrt(np.sum(dW ** 2) + np.sum(db ** 2))
|
|
1862
|
+
if total_norm > clip_value:
|
|
1863
|
+
scale = clip_value / (total_norm + eps)
|
|
1864
|
+
dW *= scale
|
|
1865
|
+
db *= scale
|
|
1860
1866
|
|
|
1861
1867
|
self.W -= lr * dW
|
|
1862
1868
|
self.b -= lr * db
|
|
@@ -2144,10 +2150,12 @@ class MLP:
|
|
|
2144
2150
|
print(f'[!] Cant adapt shape of Y sample arrays due to: {e}')
|
|
2145
2151
|
return y_pred, y_true
|
|
2146
2152
|
|
|
2153
|
+
|
|
2147
2154
|
def train(self, X, y, epochs=1000, lr=0.01, verbose=True, max_samples_for_focused_fit=500):
|
|
2148
2155
|
X = self._sanitize_string_chars(X)
|
|
2149
2156
|
y = self._sanitize_string_chars(y)
|
|
2150
2157
|
focused_fit_condition = False
|
|
2158
|
+
parameters = sum(w.size for w in self.layers[0].W) + sum(b.size for b in self.layers[0].b)
|
|
2151
2159
|
|
|
2152
2160
|
AME = self.AME_Encoder(X)
|
|
2153
2161
|
AMR = 1.0 / (1.0 + np.exp(-float(AME)))
|
|
@@ -2160,7 +2168,7 @@ class MLP:
|
|
|
2160
2168
|
if training_not_allowed:
|
|
2161
2169
|
print(f'[!] MLP Training not allowed due to unsuitable data characteristics. Anisotropy: {anisotropy:.4f}, AME: {AME:.4f}')
|
|
2162
2170
|
else:
|
|
2163
|
-
print('[+] MLP Training started
|
|
2171
|
+
print(f'[+] MLP Training started with: {parameters} Parameters.')
|
|
2164
2172
|
for epoch in range(epochs):
|
|
2165
2173
|
if not focused_fit_condition:
|
|
2166
2174
|
y_pred = self.forward(X, AME=AME, anisotropy=anisotropy)
|
|
@@ -2168,6 +2176,7 @@ class MLP:
|
|
|
2168
2176
|
y_pred = self.focused_forward(X, AME=AME, anisotropy=anisotropy)
|
|
2169
2177
|
|
|
2170
2178
|
y_pred, y_true = self.adapt_predict_shape(y_pred, y)
|
|
2179
|
+
|
|
2171
2180
|
loss = Loss.categorical_crossentropy(y_true, y_pred)
|
|
2172
2181
|
grad = Loss.softmax_crossentropy_derivative(y_true, y_pred)
|
|
2173
2182
|
if focused_fit_condition:
|
|
@@ -13102,41 +13111,65 @@ class IntegratedPipeline:
|
|
|
13102
13111
|
return unsuitable_training
|
|
13103
13112
|
|
|
13104
13113
|
def sequence_encoding(self, datasets=None, label_map=None, max_len=32):
|
|
13114
|
+
if not datasets:
|
|
13115
|
+
raise Warning('[!] Dataset is None or empty! Make sure you provide a dataset or create it automatically.')
|
|
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() # once, not per-item
|
|
13129
|
+
|
|
13130
|
+
vocab_size = self.model2.token_embedding.shape[0] # for bounds guard
|
|
13131
|
+
|
|
13105
13132
|
input_sequences = []
|
|
13133
|
+
for item in datasets:
|
|
13134
|
+
text = item[0] if isinstance(item, tuple) else item
|
|
13106
13135
|
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
if not self.model2:
|
|
13110
|
-
intents = [d[1] for d in datasets]
|
|
13111
|
-
intent_to_id = {intent:i for i, intent in enumerate(sorted(set(intents)))}
|
|
13112
|
-
num_classes = self._get_num_classes(label_map=label_map)
|
|
13113
|
-
self.model2 = Transformer(
|
|
13114
|
-
vocab_size=len(self.vocab),
|
|
13115
|
-
d_model=self.transformer_d_model,
|
|
13116
|
-
n_heads=self.transformer_heads,
|
|
13117
|
-
num_classes=num_classes
|
|
13118
|
-
)
|
|
13119
|
-
|
|
13120
|
-
self._sync_vocab_to_embedding()
|
|
13121
|
-
text = item[0] if isinstance(item, tuple) else item
|
|
13136
|
+
token_ids = self.encode(text, self.vocab, max_len=max_len)
|
|
13137
|
+
token_ids = np.asarray(token_ids)
|
|
13122
13138
|
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
13139
|
+
# bounds guard before indexing, with informative context
|
|
13140
|
+
out_of_bounds = (token_ids < 0) | (token_ids >= vocab_size)
|
|
13141
|
+
if out_of_bounds.any():
|
|
13142
|
+
n_bad = out_of_bounds.sum()
|
|
13143
|
+
print(f'[⚠️] sequence_encoding: {n_bad} token id(s) out of '
|
|
13144
|
+
f'range [0, {vocab_size}) for text="{str(text)[:50]}" '
|
|
13145
|
+
f'— clamping to valid range. This usually means vocab '
|
|
13146
|
+
f'grew after model2 was constructed; consider rebuilding '
|
|
13147
|
+
f'model2 or resizing token_embedding.')
|
|
13148
|
+
token_ids = np.clip(token_ids, 0, vocab_size - 1)
|
|
13149
|
+
|
|
13150
|
+
token_embs = self.model2.token_embedding[token_ids]
|
|
13151
|
+
pos_embs = self.model2.pos_embedding[:max_len]
|
|
13152
|
+
|
|
13153
|
+
sequence_input = token_embs + pos_embs
|
|
13154
|
+
input_sequences.append(sequence_input)
|
|
13155
|
+
|
|
13156
|
+
return np.stack(input_sequences)
|
|
13126
13157
|
|
|
13127
|
-
sequence_input = token_embs + pos_embs
|
|
13128
|
-
input_sequences.append(sequence_input)
|
|
13129
|
-
return np.stack(input_sequences) # shape: (batch, max_len, d_model)
|
|
13130
|
-
else:
|
|
13131
|
-
raise Warning('[!] Dataset is None! make sure you provide a dataset or create it Automatically!')
|
|
13132
|
-
|
|
13133
|
-
return None
|
|
13134
13158
|
|
|
13135
13159
|
def transformer_pooled_features(self, sequence_inputs):
|
|
13136
|
-
|
|
13160
|
+
"""Mean/max/std pooling over the sequence dimension."""
|
|
13161
|
+
sequence_inputs = np.asarray(sequence_inputs)
|
|
13162
|
+
|
|
13163
|
+
# guard degenerate single-timestep input, where std=0
|
|
13164
|
+
# everywhere is mathematically correct.
|
|
13165
|
+
if sequence_inputs.shape[1] == 1:
|
|
13166
|
+
print('[=] transformer_pooled_features: single-timestep input, '
|
|
13167
|
+
'std_pool will be all zeros (no variance across T=1)')
|
|
13168
|
+
|
|
13137
13169
|
mean_pool = np.mean(sequence_inputs, axis=1)
|
|
13138
|
-
max_pool
|
|
13139
|
-
std_pool
|
|
13170
|
+
max_pool = np.max(sequence_inputs, axis=1)
|
|
13171
|
+
std_pool = np.std(sequence_inputs, axis=1)
|
|
13172
|
+
|
|
13140
13173
|
return np.concatenate([mean_pool, max_pool, std_pool], axis=-1)
|
|
13141
13174
|
|
|
13142
13175
|
def _features_to_sequence(self, X_provided, d_model=None, min_seq_len=2):
|
|
@@ -13242,6 +13275,59 @@ class IntegratedPipeline:
|
|
|
13242
13275
|
x = np.fromiter((v for v in clean_str.split() if v not in skip_values), dtype=float)
|
|
13243
13276
|
|
|
13244
13277
|
return x
|
|
13278
|
+
|
|
13279
|
+
def _validate_onehot(self, y_true, context="train()"):
|
|
13280
|
+
"""
|
|
13281
|
+
Robust one-hot validation for y_true, going beyond a simple .any() check.
|
|
13282
|
+
Catches: out-of-range values, negative values, non-binary floats,
|
|
13283
|
+
rows that don't sum to 1, and all-zero rows — each with a distinct,
|
|
13284
|
+
actionable error message instead of a generic failure.
|
|
13285
|
+
"""
|
|
13286
|
+
y_true = np.asarray(y_true, dtype=np.float64)
|
|
13287
|
+
|
|
13288
|
+
if y_true.ndim == 1:
|
|
13289
|
+
y_true = y_true[np.newaxis, :]
|
|
13290
|
+
|
|
13291
|
+
issues = []
|
|
13292
|
+
|
|
13293
|
+
# 1. Values outside [0, 1] — catches your [5,3,1,4,3,2] case directly
|
|
13294
|
+
out_of_range = (y_true < 0) | (y_true > 1)
|
|
13295
|
+
if out_of_range.any():
|
|
13296
|
+
bad_rows = np.where(out_of_range.any(axis=1))[0]
|
|
13297
|
+
issues.append(
|
|
13298
|
+
f"values outside [0,1] at rows {bad_rows.tolist()[:5]} "
|
|
13299
|
+
f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
|
|
13300
|
+
f"— looks like raw label indices, not one-hot"
|
|
13301
|
+
)
|
|
13302
|
+
|
|
13303
|
+
# 2. Non-binary values (e.g. soft labels or corrupted floats like 0.5, 0.999999)
|
|
13304
|
+
# Only check this if values ARE in [0,1] — no point double-reporting.
|
|
13305
|
+
in_range = ~out_of_range
|
|
13306
|
+
non_binary = in_range & (~np.isclose(y_true, 0, atol=1e-6)) & (~np.isclose(y_true, 1, atol=1e-6))
|
|
13307
|
+
if non_binary.any():
|
|
13308
|
+
bad_rows = np.where(non_binary.any(axis=1))[0]
|
|
13309
|
+
issues.append(
|
|
13310
|
+
f"non-binary values at rows {bad_rows.tolist()[:5]} "
|
|
13311
|
+
f"(sample values: {y_true[bad_rows[0]].tolist() if len(bad_rows) else []}) "
|
|
13312
|
+
f"— expected exactly 0 or 1 per class slot"
|
|
13313
|
+
)
|
|
13314
|
+
|
|
13315
|
+
# 3. Row sums must be exactly 1 (each sample has exactly one true class)
|
|
13316
|
+
row_sums = y_true.sum(axis=1)
|
|
13317
|
+
bad_sum_rows = np.where(~np.isclose(row_sums, 1.0, atol=1e-3))[0]
|
|
13318
|
+
if len(bad_sum_rows) > 0:
|
|
13319
|
+
issues.append(
|
|
13320
|
+
f"rows not summing to 1 at indices {bad_sum_rows.tolist()[:5]} "
|
|
13321
|
+
f"(sums: {row_sums[bad_sum_rows[:5]].tolist()}) "
|
|
13322
|
+
f"— either multi-label rows, all-zero rows, or raw indices"
|
|
13323
|
+
)
|
|
13324
|
+
|
|
13325
|
+
if issues:
|
|
13326
|
+
print(f"[WARNING] [{context}] y_true failed one-hot validation, one-hot encoding y sample...")
|
|
13327
|
+
return True
|
|
13328
|
+
|
|
13329
|
+
return False
|
|
13330
|
+
|
|
13245
13331
|
|
|
13246
13332
|
def transformer_utilities(self, X_provided= None, X_raw=None, y_true=None, rules=None,
|
|
13247
13333
|
datasets=None, label_map=None, batch_size=2, min_signal=1e-3,
|
|
@@ -13275,7 +13361,7 @@ class IntegratedPipeline:
|
|
|
13275
13361
|
if X_provided is None:
|
|
13276
13362
|
sequence_inputs = self.sequence_encoding(datasets, label_map=label_map)
|
|
13277
13363
|
else:
|
|
13278
|
-
sequence_inputs = self._features_to_sequence(X_provided)
|
|
13364
|
+
sequence_inputs = self._features_to_sequence(X_provided, d_model=self.transformer_d_model)
|
|
13279
13365
|
|
|
13280
13366
|
unsuitable_training = self.training_necessary_condition(sequence_inputs, X_raw)
|
|
13281
13367
|
lr = self.model2.transformer_lr if self.model2 else self.transformer_lr
|
|
@@ -13348,7 +13434,7 @@ class IntegratedPipeline:
|
|
|
13348
13434
|
weak_rows = np.where(row_sums < min_signal)[0]
|
|
13349
13435
|
weak_ratio = len(weak_rows) / len(X_raw_features)
|
|
13350
13436
|
|
|
13351
|
-
print(f'[!] Zero ratio in samples: {weak_ratio * 100}')
|
|
13437
|
+
print(f'[!] Zero ratio in samples: {weak_ratio * 100}%')
|
|
13352
13438
|
if weak_ratio > 0.3: # more than 30% zero rows means vocab mismatch
|
|
13353
13439
|
if isinstance(X_raw_generation[0], str):
|
|
13354
13440
|
print(f'[= ! =] High zero-row ratio ({weak_ratio:.0%}), refitting on current batch')
|
|
@@ -13401,6 +13487,16 @@ class IntegratedPipeline:
|
|
|
13401
13487
|
else:
|
|
13402
13488
|
self.vocab_size = 1
|
|
13403
13489
|
|
|
13490
|
+
onehot_validation = self._validate_onehot(y)
|
|
13491
|
+
if onehot_validation:
|
|
13492
|
+
if n_classes != len(label_map):
|
|
13493
|
+
n_classes = len(label_map)
|
|
13494
|
+
if n_classes > np.max(y):
|
|
13495
|
+
y = np.eye(n_classes)[np.asarray(y)]
|
|
13496
|
+
else:
|
|
13497
|
+
print('[⚠️] Warning: Y onehot encoding fails, Returning Y samples as is, This may cause Exploding Gradient in MLP Training!')
|
|
13498
|
+
y = y.copy()
|
|
13499
|
+
|
|
13404
13500
|
if self.model2 is None:
|
|
13405
13501
|
self.model2 = Transformer(
|
|
13406
13502
|
vocab_size=self.vocab_size,
|
|
@@ -13408,11 +13504,11 @@ class IntegratedPipeline:
|
|
|
13408
13504
|
n_heads=self.transformer_heads,
|
|
13409
13505
|
num_classes=n_classes
|
|
13410
13506
|
)
|
|
13507
|
+
|
|
13411
13508
|
if self.use_transformer:
|
|
13412
13509
|
self.model2.train(sequence_inputs, y_true, epochs=self.transformer_training_epochs, mode=mode, lr=lr, embedded=True, batch_size=batch_size)
|
|
13413
|
-
|
|
13414
|
-
X = self.shape_adaptation(hybrid_X, input_dim)
|
|
13415
|
-
|
|
13510
|
+
|
|
13511
|
+
X = self.shape_adaptation(hybrid_X, input_dim)
|
|
13416
13512
|
self.initialize_model_(X, input_dim, n_classes)
|
|
13417
13513
|
self.model3.train(X, y, epochs=self.mlp_training_epochs, lr=self.mlp_lr, max_samples_for_focused_fit=max_samples_for_focused_fit)
|
|
13418
13514
|
self.lstm_setup_inference(X, y, input_ids=sequence_inputs)
|
|
@@ -17144,6 +17240,18 @@ class PipelinePredictionManager:
|
|
|
17144
17240
|
X_train, X_val, y_train, y_val = self._prepare_train_val_split(
|
|
17145
17241
|
X, y, min_val_per_class=5, min_frac=0.1, max_frac=0.3
|
|
17146
17242
|
)
|
|
17243
|
+
|
|
17244
|
+
onehot_validation = self.pipeline._validate_onehot(y_train)
|
|
17245
|
+
if onehot_validation:
|
|
17246
|
+
if num_classes != len(label_map):
|
|
17247
|
+
num_classes = len(label_map)
|
|
17248
|
+
if num_classes > np.max(y_train):
|
|
17249
|
+
y_train = np.eye(num_classes)[np.asarray(y_train)]
|
|
17250
|
+
y_val = np.eye(num_classes)[np.asarray(y_val)]
|
|
17251
|
+
else:
|
|
17252
|
+
print('[⚠️] Warning: Y onehot encoding fails, Returning y samples as is, This may cause Exploding Gradient in MLP Training!')
|
|
17253
|
+
y_train = y_train
|
|
17254
|
+
y_val = y_val
|
|
17147
17255
|
|
|
17148
17256
|
X_mean = X_train.mean(axis=0)
|
|
17149
17257
|
X_std = X_train.std(axis=0) + 1e-8
|
|
@@ -17258,9 +17366,7 @@ class PipelinePredictionManager:
|
|
|
17258
17366
|
X = X_gen
|
|
17259
17367
|
if X is not None and len(X) > 0:
|
|
17260
17368
|
X = np.asarray(X)
|
|
17261
|
-
|
|
17262
|
-
X = np.asarray(X_val)
|
|
17263
|
-
|
|
17369
|
+
|
|
17264
17370
|
# MLP forward pass
|
|
17265
17371
|
if hasattr(self.pipeline.mlp, 'predict_proba'):
|
|
17266
17372
|
mlp_probs = self.pipeline.model3.predict_proba(X)
|