AbstractIntegratedModule 0.4.0__tar.gz → 0.4.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.
Files changed (16) hide show
  1. abstractintegratedmodule-0.4.1/AbstractIntegratedModule.cp313-win_amd64.pyd +0 -0
  2. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.cpython-310-aarch64-linux-gnu.so +0 -0
  3. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.cpython-312-x86_64-linux-gnu.so +0 -0
  4. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1/AbstractIntegratedModule.egg-info}/PKG-INFO +3 -3
  5. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.py +372 -220
  6. {abstractintegratedmodule-0.4.0/AbstractIntegratedModule.egg-info → abstractintegratedmodule-0.4.1}/PKG-INFO +3 -3
  7. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/README.md +2 -2
  8. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/setup.py +1 -1
  9. abstractintegratedmodule-0.4.0/AbstractIntegratedModule.cp313-win_amd64.pyd +0 -0
  10. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.egg-info/SOURCES.txt +0 -0
  11. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.egg-info/dependency_links.txt +0 -0
  12. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.egg-info/requires.txt +0 -0
  13. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/AbstractIntegratedModule.egg-info/top_level.txt +0 -0
  14. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/MANIFEST.in +0 -0
  15. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/pyproject.toml +0 -0
  16. {abstractintegratedmodule-0.4.0 → abstractintegratedmodule-0.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractIntegratedModule
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Framework for Advanced Integrated Non-LLM AI Module library - Backend Framework for Non-LLM AI Agent Framework
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: Beta, 0.4.0.
45
+ - Development Stage: Beta, 0.4.1.
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.
@@ -62,7 +62,7 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
62
62
  - Proven Works on ARM64 Environment, Training and Prediction works efficient on Docker ARM64 environment with QEMU, good parallelizing behavior is guaranteed.
63
63
  - P2P Works efficiently in ARM64 Docker + QEMU, No conflicting socket and all prediction works efficiently.
64
64
  - AWE setup Proven Efficient on Hard-uncontrolled dataset such as Activity Recognition from the given Database.
65
-
65
+ - LSTM is Optimized efficiently for scarce data with AWE method.
66
66
  -----
67
67
 
68
68
  <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" />
@@ -1442,96 +1442,101 @@ class LSTMCell:
1442
1442
  def _g(self, v): return v[2*self.hidden_size:3*self.hidden_size]
1443
1443
  def _o(self, v): return v[3*self.hidden_size:]
1444
1444
 
1445
-
1446
- # ── forward ──────────────────────────────
1445
+ # _________ forward method for cell class _____________
1447
1446
  def forward(self, x_seq: np.ndarray, h0=None, c0=None):
1448
- """
1449
- x_seq : (T, input_size)
1450
- returns: hs (T, hidden), cs (T, hidden), cache (for BPTT)
1451
- """
1452
- T = x_seq.shape[0]
1453
- H = self.hidden_size
1447
+ T = x_seq.shape[0]
1448
+ H = self.hidden_size
1454
1449
  expected_input = self.input_size
1455
1450
 
1456
1451
  h = np.zeros(H) if h0 is None else h0.copy()
1457
1452
  c = np.zeros(H) if c0 is None else c0.copy()
1458
1453
 
1459
- hs, cs = np.zeros((T, H)), np.zeros((T, H))
1460
- cache = [] # store everything needed for backward
1454
+ hs = np.zeros((T, H))
1455
+ cs = np.zeros((T, H))
1456
+ cache = []
1457
+
1458
+ # preallocate xh buffer once
1459
+ xh = np.empty(expected_input + H)
1461
1460
 
1462
1461
  for t in range(T):
1463
- x = x_seq[t]
1462
+ x = x_seq[t]
1464
1463
  if x.ndim == 0:
1465
- x = x.reshape(1) # fix zero-dimensional
1464
+ x = x.reshape(1)
1466
1465
  if x.shape[0] < expected_input:
1467
- x = np.pad(x, (0, expected_input - x.shape[0])) # pad if too small
1466
+ x = np.pad(x, (0, expected_input - x.shape[0]))
1468
1467
  elif x.shape[0] > expected_input:
1469
- x = x[:expected_input] # truncate if too large
1470
-
1471
- xh = np.concatenate([x, h]) # (input+hidden,)
1468
+ x = x[:expected_input]
1469
+
1470
+ # write into buffer, no allocation
1471
+ xh[:expected_input] = x
1472
+ xh[expected_input:] = h
1472
1473
 
1473
- z = self.W @ xh + self.b # (4H,)
1474
- f = sigmoid(self._f(z)) # forget
1475
- i = sigmoid(self._i(z)) # input
1476
- g = np.tanh(self._g(z)) # candidate
1477
- o = sigmoid(self._o(z)) # output
1474
+ z = self.W @ xh + self.b
1475
+ H1, H2, H3 = H, H * 2, H * 3
1478
1476
 
1479
- c_new = f * c + i * g
1477
+ # direct slices, no method calls
1478
+ f = sigmoid(z[:H1])
1479
+ i = sigmoid(z[H1:H2])
1480
+ g = np.tanh(z[H2:H3])
1481
+ o = sigmoid(z[H3:])
1482
+
1483
+ c_new = f * c + i * g
1480
1484
  tanh_c = np.tanh(c_new)
1481
- h_new = o * tanh_c
1485
+ h_new = o * tanh_c
1482
1486
 
1483
- cache.append((x, h, c, f, i, g, o, c_new, tanh_c, xh))
1487
+ # store copies — h/c will be overwritten next iteration
1488
+ cache.append((x.copy(), h.copy(), c.copy(),
1489
+ f, i, g, o, c_new, tanh_c, xh.copy()))
1484
1490
  h, c = h_new, c_new
1485
- hs[t], cs[t] = h, c
1491
+ hs[t] = h
1492
+ cs[t] = c
1486
1493
 
1487
1494
  return hs, cs, cache
1488
1495
 
1489
- # ── backward (BPTT) ──────────────────────
1490
- def backward(self, dhs: np.ndarray, cache, dh_next=None, dc_next=None):
1491
- """
1492
- dhs : (T, hidden) — gradient of loss w.r.t. each hidden state
1493
- Returns: gradients dict + dx_seq
1494
- """
1495
- T = len(cache)
1496
+ # ________ backward method for Cell class __________
1497
+ def backward(self, dhs: np.ndarray, cache,
1498
+ dh_next=None, dc_next=None, T_limit=None):
1499
+ # T_limit avoids slicing cache list externally
1500
+ T = T_limit if T_limit is not None else len(cache)
1496
1501
  H = self.hidden_size
1497
1502
 
1498
- dW = np.zeros_like(self.W)
1499
- db = np.zeros_like(self.b)
1500
- dh = np.zeros(H) if dh_next is None else dh_next.copy()
1501
- dc = np.zeros(H) if dc_next is None else dc_next.copy()
1503
+ dW = np.zeros_like(self.W)
1504
+ db = np.zeros_like(self.b)
1505
+ dh = np.zeros(H) if dh_next is None else dh_next.copy()
1506
+ dc = np.zeros(H) if dc_next is None else dc_next.copy()
1502
1507
  dx_seq = np.zeros((T, self.input_size))
1503
1508
 
1509
+ # preallocate dz buffer once
1510
+ dz = np.empty(4 * H)
1511
+ H1, H2, H3 = H, H * 2, H * 3
1512
+
1504
1513
  for t in reversed(range(T)):
1505
1514
  x, h_prev, c_prev, f, i, g, o, c_new, tanh_c, xh = cache[t]
1506
1515
 
1507
- dh_total = dhs[t] + dh # gradient from loss + recurrence
1516
+ dh_total = dhs[t] + dh
1508
1517
 
1509
- # output gate
1510
1518
  do = dh_total * tanh_c
1511
1519
  dtanhc = dh_total * o
1512
-
1513
- # cell state
1514
1520
  dc_new = dtanhc * tanh_deriv(tanh_c) + dc
1515
1521
 
1516
- # gates
1517
1522
  df = dc_new * c_prev
1518
1523
  di = dc_new * g
1519
1524
  dg = dc_new * i
1520
- dc = dc_new * f # flows back to previous cell state
1521
-
1522
- # pre-activation gradients
1523
- df_pre = df * sigmoid_deriv(f)
1524
- di_pre = di * sigmoid_deriv(i)
1525
- dg_pre = dg * tanh_deriv(g)
1526
- do_pre = do * sigmoid_deriv(o)
1525
+ dc = dc_new * f
1527
1526
 
1528
- dz = np.concatenate([df_pre, di_pre, dg_pre, do_pre])
1527
+ # write into preallocated dz buffer
1528
+ dz[:H1] = df * sigmoid_deriv(f)
1529
+ dz[H1:H2] = di * sigmoid_deriv(i)
1530
+ dz[H2:H3] = dg * tanh_deriv(g)
1531
+ dz[H3:] = do * sigmoid_deriv(o)
1529
1532
 
1530
- dW += np.outer(dz, xh)
1533
+ # nplace accumulation, no intermediate allocation
1534
+ dW += np.outer(dz, xh) # unavoidable alloc but outer is C-level
1531
1535
  db += dz
1532
- dxh = self.W.T @ dz
1533
- dx_seq[t] = dxh[:self.input_size]
1534
- dh = dxh[self.input_size:]
1536
+
1537
+ dxh = self.W.T @ dz
1538
+ dx_seq[t] = dxh[:self.input_size]
1539
+ dh = dxh[self.input_size:]
1535
1540
 
1536
1541
  return {"dW": dW, "db": db}, dx_seq, dh, dc
1537
1542
 
@@ -1539,83 +1544,77 @@ class LSTMCell:
1539
1544
  # ─────────────────────────────────────────────
1540
1545
  # LSTM Network (cell + linear output head)
1541
1546
  # ─────────────────────────────────────────────
1542
-
1543
1547
  class LSTMNetwork:
1544
- """
1545
- One LSTM layer + a linear output projection.
1546
- input_size → hidden_size → output_size
1547
- """
1548
-
1549
1548
  def __init__(self, pipeline, input_size, hidden_size, output_size, seed=0):
1550
- self.cell = LSTMCell(input_size, hidden_size, seed)
1551
- H = hidden_size
1552
-
1553
- self.weight_shaper = GeometricWeightShaping(output_size, H)
1554
- self.Wy = None
1555
- self.by = np.zeros(output_size)
1556
- self.pipeline = pipeline
1557
-
1549
+ self.cell = LSTMCell(input_size, hidden_size, seed)
1550
+ self.weight_shaper = GeometricWeightShaping(output_size, hidden_size)
1551
+ self.Wy = None
1552
+ self.by = np.zeros(output_size)
1553
+ self.pipeline = pipeline
1554
+ self._trained = False
1555
+
1556
+ # forward method to calculate proper weight for prediction and training.
1558
1557
  def forward(self, x_seq):
1558
+ # also Wy init only here, removed from train_step
1559
1559
  if self.Wy is None:
1560
1560
  self.Wy = self.weight_shaper.weight_shaping(x_seq)
1561
-
1562
1561
  hs, cs, cache = self.cell.forward(x_seq)
1563
- # linear projection at every timestep
1564
- preds = hs @ self.Wy.T + self.by # (T, output_size)
1562
+ preds = hs @ self.Wy.T + self.by # (T, output_size)
1565
1563
  return preds, hs, cs, cache
1566
1564
 
1565
+ # calculate loss of MSE (Mean squared error.)
1567
1566
  def loss_mse(self, preds, targets, AMR):
1568
- if preds.shape != targets.shape:
1569
- if preds.shape[0] > targets.shape[0]:
1570
- targets = targets[:preds.shape[0], :]
1571
- if targets.shape[0] > preds.shape[0]:
1572
- preds = preds[:targets.shape[0], :]
1573
- else:
1574
- preds = preds[:targets.shape[0], :targets.shape[1]]
1575
-
1567
+ # proper and correct shape alignment
1568
+ min_T = min(preds.shape[0], targets.shape[0])
1569
+ min_F = min(preds.shape[1], targets.shape[1])
1570
+ preds = preds[:min_T, :min_F]
1571
+ targets = targets[:min_T, :min_F]
1572
+
1576
1573
  diff = preds - targets
1577
- return AMR * np.mean(diff ** 2), diff / len(diff)
1574
+ loss = (1.0 - AMR) * np.mean(diff ** 2)
1575
+ dloss = diff / (min_T * min_F) # FIX 3 — normalize by full element count
1576
+ return loss, dloss
1578
1577
 
1578
+ # backward method for the network to calculate proper weights with cell backward
1579
1579
  def backward(self, dpreds, hs, cache):
1580
- # gradient through linear head
1581
- min_T = min(dpreds.shape[0], hs.shape[0])
1582
- dpreds = dpreds[:min_T, :] # (min_T, out)
1583
- hs = hs[:min_T, :] # (min_T, hidden)
1580
+ min_T = min(dpreds.shape[0], hs.shape[0])
1581
+ dpreds = dpreds[:min_T]
1582
+ hs = hs[:min_T]
1584
1583
 
1585
- dWy = dpreds.T @ hs # (out, hidden)
1584
+ dWy = dpreds.T @ hs
1586
1585
  dby = dpreds.sum(axis=0)
1587
- dhs = dpreds @ self.Wy # (T, hidden)
1586
+ dhs = dpreds @ self.Wy
1588
1587
 
1589
- cell_grads, dx, _, _ = self.cell.backward(dhs, cache[:min_T])
1588
+ # pass min_T directly, need to avoid creating a sliced list
1589
+ cell_grads, dx, _, _ = self.cell.backward(dhs, cache, T_limit=min_T)
1590
1590
  return cell_grads, {"dWy": dWy, "dby": dby}, dx
1591
1591
 
1592
+ # update ensured proper gradient clipping
1592
1593
  def update(self, cell_grads, out_grads, lr=1e-3, clip=5.0):
1593
- """SGD with gradient clipping."""
1594
1594
  def clip_and_step(param, grad):
1595
- grad = np.clip(grad, -clip, clip)
1595
+ np.clip(grad, -clip, clip, out=grad)
1596
1596
  param -= lr * grad
1597
1597
 
1598
- clip_and_step(self.cell.W, cell_grads["dW"])
1599
- clip_and_step(self.cell.b, cell_grads["db"])
1600
- clip_and_step(self.Wy, out_grads["dWy"])
1601
- clip_and_step(self.by, out_grads["dby"])
1598
+ clip_and_step(self.cell.W, cell_grads["dW"])
1599
+ clip_and_step(self.cell.b, cell_grads["db"])
1600
+ clip_and_step(self.Wy, out_grads["dWy"])
1601
+ clip_and_step(self.by, out_grads["dby"])
1602
1602
 
1603
- def train_step(self, x_seq, targets, lr=1e-3):
1604
- if self.Wy is None:
1605
- self.Wy = self.weight_shaper.weight_shaping(x_seq)
1603
+ # train step for each LSTM fitting method
1604
+ def train_step(self, x_seq, targets, lr=1e-3, AMR=None):
1605
+ # accept precomputed AMR
1606
+ if AMR is None:
1607
+ AME = self.pipeline.AME_Encoder(x_seq)
1608
+ AMR = 1.0 / (1.0 + np.exp(-AME))
1606
1609
 
1607
1610
  preds, hs, cs, cache = self.forward(x_seq)
1608
-
1609
- AME = self.pipeline.AME_Encoder(x_seq)
1610
- AMR = 1.0 / (1.0 + np.exp(-AME))
1611
-
1612
- loss, dloss = self.loss_mse(preds, targets, AMR)
1611
+ loss, dloss = self.loss_mse(preds, targets, AMR)
1613
1612
  cell_grads, out_grads, _ = self.backward(dloss, hs, cache)
1614
1613
  self.update(cell_grads, out_grads, lr)
1615
-
1616
1614
  return loss, preds
1617
1615
 
1618
1616
 
1617
+
1619
1618
  # ─────────────────────────────────────────────
1620
1619
  # LSTM Engine
1621
1620
  # ─────────────────────────────────────────────
@@ -1654,147 +1653,265 @@ class LSTMEngine:
1654
1653
  self.residual_mean = None
1655
1654
 
1656
1655
  # ── calibrate on validation set ──────────
1657
- def calibrate(self, X_val, Y_val):
1658
- """
1659
- Collect residuals on clean (no-dropout) val predictions.
1660
- Must be called before predict().
1661
- """
1662
- residuals = []
1656
+ def calibrate_residual(self, X_val, Y_val):
1657
+ if len(X_val) == 0:
1658
+ self.residual_mean = 0.0
1659
+ self.residual_std = 1.0
1660
+ return
1661
+
1662
+ confidence_errors = []
1663
+
1663
1664
  for j in range(len(X_val)):
1664
1665
  preds, _, _, _ = self.model.forward(X_val[j])
1665
- err = (preds[:, 0] - Y_val[j, :, 0])
1666
- residuals.extend(err.tolist())
1667
1666
 
1668
- residuals = np.array(residuals)
1669
- self.residual_mean = residuals.mean()
1670
- self.residual_std = residuals.std()
1667
+ pred_vals = preds[:, 0] if preds.ndim > 1 else preds
1668
+
1669
+ # get true class
1670
+ true_vals = Y_val[j, :, 0] if Y_val[j].ndim > 1 else Y_val[j]
1671
+ min_len = min(len(pred_vals), len(true_vals))
1672
+
1673
+ # sigmoid to get predicted probability
1674
+ pred_prob = 1.0 / (1.0 + np.exp(-pred_vals[:min_len]))
1675
+ true_bin = true_vals[:min_len].astype(float)
1676
+
1677
+ # confidence error — how wrong was the predicted probability
1678
+ # correct prediction → low error
1679
+ # wrong prediction → high error
1680
+ err = np.abs(pred_prob - true_bin)
1681
+ confidence_errors.extend(err.tolist())
1682
+
1683
+ errors = np.array(confidence_errors)
1684
+
1685
+ # IQR outlier removal
1686
+ q25, q75 = np.percentile(errors, [25, 75])
1687
+ iqr = q75 - q25
1688
+ mask = (errors >= q25 - 1.5 * iqr) & (errors <= q75 + 1.5 * iqr)
1689
+ clean = errors[mask] if mask.sum() > 0 else errors
1690
+
1691
+ self.residual_mean = float(clean.mean())
1692
+ self.residual_std = float(max(clean.std(), 1e-6))
1693
+
1694
+ # floor std on small n — can't trust calibration with few samples
1695
+ if len(X_val) < 20:
1696
+ self.residual_std = max(self.residual_std, 0.1)
1697
+ print(f'[!] Small val set ({len(X_val)} samples) — flooring σ to 0.1')
1698
+
1699
+ self.calibration_coverage = float(mask.mean())
1700
+ self.n_calibration_samples = len(X_val)
1701
+
1671
1702
  print(f"[=] Calibrated: residual μ={self.residual_mean:.4f} "
1672
- f"[=] σ={self.residual_std:.4f}")
1703
+ f"σ={self.residual_std:.4f} "
1704
+ f"coverage={self.calibration_coverage:.1%} "
1705
+ f"n={self.n_calibration_samples}")
1706
+
1673
1707
 
1674
1708
  # ── MC dropout forward ────────────────────
1675
- def _mc_forward(self, x_seq: np.ndarray) -> Any:
1676
- """
1677
- One stochastic forward pass — dropout applied to h
1678
- between every timestep, scaled to preserve expected value.
1679
- """
1680
- T = x_seq.shape[0]
1681
- H = self.model.cell.hidden_size
1709
+ def _mc_forward(self, x_seq: np.ndarray) -> np.ndarray:
1710
+ T = x_seq.shape[0]
1711
+ H = self.model.cell.hidden_size
1682
1712
  expected_input = self.model.cell.input_size
1683
- p = self.dropout
1684
-
1685
- h = np.zeros(H)
1686
- c = np.zeros(H)
1687
- preds = []
1688
-
1689
- cell = self.model.cell
1713
+ p = self.dropout
1714
+ cell = self.model.cell
1715
+ W = cell.W
1716
+ b = cell.b
1717
+ H1, H2, H3 = H, H * 2, H * 3 # slice boundaries precomputed
1718
+
1719
+ # FIX 1 — Wy check once before loop, not T times inside
1720
+ if self.model.Wy is None:
1721
+ self.model.Wy = self.model.weight_shaper.weight_shaping(x_seq)
1722
+ Wy = self.model.Wy
1723
+ by = self.model.by
1724
+
1725
+ h = np.zeros(H)
1726
+ c = np.zeros(H)
1727
+ xh = np.empty(expected_input + H) # preallocate concat buffer
1728
+ preds = np.empty(T) # preallocate output
1729
+
1730
+ # precompute dropout scale factor
1731
+ inv_keep = 1.0 / (1.0 - p)
1690
1732
 
1691
1733
  for t in range(T):
1692
- x = x_seq[t]
1734
+ x = x_seq[t]
1735
+
1736
+ # shape alignment
1693
1737
  if x.ndim == 0:
1694
- x = x.reshape(1) # fix zero-dimensional
1738
+ x = x.reshape(1)
1695
1739
  if x.shape[0] < expected_input:
1696
- x = np.pad(x, (0, expected_input - x.shape[0])) # pad if too small
1740
+ x = np.pad(x, (0, expected_input - x.shape[0]))
1697
1741
  elif x.shape[0] > expected_input:
1698
- x = x[:expected_input] # truncate if too large
1699
- xh = np.concatenate([x, h])
1700
- z = cell.W @ xh + cell.b
1742
+ x = x[:expected_input]
1743
+
1744
+ # need to write into preallocated buffer instead of np.concatenate
1745
+ xh[:expected_input] = x
1746
+ xh[expected_input:] = h
1747
+
1748
+ z = W @ xh + b # (4H,)
1701
1749
 
1702
- # gate activations
1703
- f = sigmoid(cell._f(z))
1704
- i = sigmoid(cell._i(z))
1705
- g = np.tanh(cell._g(z))
1706
- o = sigmoid(cell._o(z))
1750
+ # direct slices instead of method calls
1751
+ f = sigmoid(z[:H1])
1752
+ i = sigmoid(z[H1:H2])
1753
+ g = np.tanh(z[H2:H3])
1754
+ o = sigmoid(z[H3:])
1707
1755
 
1708
1756
  c = f * c + i * g
1709
1757
  tanh_c = np.tanh(c)
1710
1758
  h = o * tanh_c
1711
1759
 
1712
- # ── dropout on h, inverted scaling ──
1713
- mask = (np.random.rand(H) > p).astype(float) / (1.0 - p)
1714
- h = h * mask # perturb hidden state only
1715
- # cell state c is untouched —
1716
- # preserves long-term memory
1717
- if self.model.Wy is None:
1718
- self.model.Wy = self.model.weight_shaper.weight_shaping(x_seq)
1760
+ # FIX 4 precomputed inv_keep, inplace mask application
1761
+ mask = (np.random.rand(H) > p) * inv_keep
1762
+ h *= mask
1719
1763
 
1720
- pred = h @ self.model.Wy.T + self.model.by
1721
- preds.append(pred[0])
1764
+ preds[t] = (h @ Wy.T + by)[0]
1722
1765
 
1723
- return np.array(preds) # (T,)
1766
+ return preds # (T,)
1724
1767
 
1725
- # ── gate uncertainty ──────────────────────
1726
- def _gate_uncertainty(self, x_seq: np.ndarray, AMR: float) -> Any:
1768
+ # ── gate uncertainty for LSTM prediction──────────────────────
1769
+ def _gate_uncertainty(self, x_seq: np.ndarray, AMR: float) -> np.ndarray:
1727
1770
  """
1728
1771
  Structural uncertainty from gate activations.
1729
-
1730
- High uncertainty when:
1731
- forget gate (f) is LOW → model is erasing memory
1732
- input gate (i) is HIGH → model is overwriting with new info
1733
- → transition moment, inherently harder to predict
1734
-
1735
- Returns per-timestep uncertainty in [0, 1].
1772
+ Vectorized — no Python loop over timesteps.
1736
1773
  """
1737
1774
  _, _, cache = self.model.cell.forward(x_seq)
1738
- gate_uncertainty = []
1739
- for entry in cache:
1740
- _, _, _, f, i, g, o, _, _, _ = entry
1741
- # mean forget across hidden dims — low = erasing
1742
- forget_instability = 1.0 - f.mean()
1743
- # mean input — high = overwriting
1744
- input_activity = i.mean()
1745
- # combined: both high = maximally uncertain transition
1746
- u = AMR * forget_instability + AMR * input_activity
1747
- gate_uncertainty.append(u)
1748
1775
 
1749
- return np.array(gate_uncertainty) # (T,)
1776
+ # cache[t] = (x, h_prev, c_prev, f, i, g, o, c_new, tanh_c, xh)
1777
+ # need to extract f and i directly as stacked arrays — shape (T, H)
1778
+ T = len(cache)
1779
+
1780
+ if T == 0:
1781
+ return np.array([0.0])
1782
+
1783
+ # vectorized extraction — one pass instead of T unpacks
1784
+ f_all = np.empty((T, cache[0][3].shape[0])) # (T, H)
1785
+ i_all = np.empty((T, cache[0][4].shape[0])) # (T, H)
1786
+
1787
+ for t, entry in enumerate(cache):
1788
+ f_all[t] = entry[3] # forget gate
1789
+ i_all[t] = entry[4] # input gate
1750
1790
 
1791
+ # vectorized computation — no per-timestep Python arithmetic
1792
+ forget_instability = 1.0 - f_all.mean(axis=1) # (T,)
1793
+ input_activity = i_all.mean(axis=1) # (T,)
1751
1794
 
1752
- # empirical quantiles from actual residuals:
1795
+ # precompute scalar factor once
1796
+ scale = 1.0 - AMR
1797
+ gate_uncertainty = scale * (forget_instability + input_activity)
1798
+
1799
+ return np.clip(gate_uncertainty, 0.0, 1.0)
1800
+
1801
+ # empirical quantiles from actual residuals
1753
1802
  def calibrate(self, X_val, Y_val):
1754
- residuals = []
1803
+ if len(X_val) == 0:
1804
+ self.residual_mean = 0.0
1805
+ self.residual_std = 1.0
1806
+ self.quantiles = {}
1807
+ return
1808
+
1809
+ all_errors = []
1755
1810
  for j in range(len(X_val)):
1756
- preds, _, _, _ = self.model.forward(X_val[j])
1757
- min_T = min(preds.shape[0], Y_val[j].shape[0])
1758
- err = preds[:min_T, 0] - Y_val[j, :min_T, 0]
1759
- residuals.extend(err.tolist())
1760
-
1761
- residuals = np.array(residuals)
1762
- self.residual_std = residuals.std()
1763
- self.residual_mean = residuals.mean()
1764
-
1765
- # store empirical quantiles instead of assuming normality
1766
- self.quantiles = {
1767
- 0.90: (np.percentile(residuals, 5),
1768
- np.percentile(residuals, 95)),
1769
- 0.95: (np.percentile(residuals, 2.5),
1770
- np.percentile(residuals, 97.5)),
1771
- 0.99: (np.percentile(residuals, 0.5),
1772
- np.percentile(residuals, 99.5)),
1773
- }
1811
+ preds, _, _, _ = self.model.forward(X_val[j])
1812
+ y = Y_val[j]
1813
+ pred_vals = preds[:, 0] if preds.ndim > 1 else preds
1814
+ true_vals = y[:, 0] if y.ndim > 1 else y
1815
+ min_T = min(len(pred_vals), len(true_vals))
1816
+ all_errors.append(pred_vals[:min_T] - true_vals[:min_T])
1817
+
1818
+ residuals = np.concatenate(all_errors)
1819
+ n = len(residuals)
1820
+
1821
+ self.residual_mean = float(residuals.mean())
1822
+ self.residual_std = float(max(residuals.std(), 1e-6))
1823
+
1824
+ # adapt confidence levels to sample size
1825
+ # small n → only compute what's statistically supportable
1826
+ if n < 20:
1827
+ # only 90% interval is reliable — use 10th/90th percentile
1828
+ # wide enough to be honest about uncertainty
1829
+ levels = [10.0, 90.0]
1830
+ p = np.percentile(residuals, levels)
1831
+ self.quantiles = {
1832
+ 0.90: (float(p[0]), float(p[1])),
1833
+ 0.95: (float(p[0]), float(p[1])), # same as 90% — honest, not fake precision
1834
+ 0.99: (float(p[0]), float(p[1])),
1835
+ }
1836
+ print(f'[!] n={n} too small for tail quantiles — '
1837
+ f'using 10th/90th for all intervals')
1838
+
1839
+ elif n < 50:
1840
+ # 90% and 95% supportable, 99% not reliable
1841
+ levels = [2.5, 5.0, 95.0, 97.5]
1842
+ p = np.percentile(residuals, levels)
1843
+ self.quantiles = {
1844
+ 0.90: (float(p[1]), float(p[2])),
1845
+ 0.95: (float(p[0]), float(p[3])),
1846
+ 0.99: (float(p[0]), float(p[3])), # same as 95% — honest
1847
+ }
1848
+ print(f'[!] n={n} insufficient for 99% interval — '
1849
+ f'using 95% as proxy')
1850
+
1851
+ else:
1852
+ # full precision justified
1853
+ levels = [0.5, 2.5, 5.0, 95.0, 97.5, 99.5]
1854
+ p = np.percentile(residuals, levels)
1855
+ self.quantiles = {
1856
+ 0.90: (float(p[2]), float(p[3])),
1857
+ 0.95: (float(p[1]), float(p[4])),
1858
+ 0.99: (float(p[0]), float(p[5])),
1859
+ }
1860
+
1861
+ # floor std on small n
1862
+ if n < 20:
1863
+ self.residual_std = max(self.residual_std, 0.1)
1864
+
1865
+ print(f"[=] Calibrated: μ={self.residual_mean:.4f} "
1866
+ f"σ={self.residual_std:.4f} "
1867
+ f"n={n} "
1868
+ f"90%=[{self.quantiles[0.90][0]:.4f}, {self.quantiles[0.90][1]:.4f}]")
1774
1869
 
1775
1870
  # interval to calculate prediction interval from MC mean + empirical quantiles
1776
1871
  def _interval(self, mc_mean, confidence_level):
1872
+ # flatten mc_mean safely — handles scalar, 0-d array, or 1-d array
1873
+ mc_scalar = float(np.asarray(mc_mean).flat[0])
1874
+
1875
+ if confidence_level not in self.quantiles:
1876
+ available = sorted(self.quantiles.keys())
1877
+ if not available:
1878
+ return mc_scalar - self.residual_std, mc_scalar + self.residual_std
1879
+ confidence_level = min(available, key=lambda k: abs(k - confidence_level))
1880
+ print(f'[!] Confidence level not found, using closest: {confidence_level}')
1881
+
1777
1882
  lo_bias, hi_bias = self.quantiles[confidence_level]
1778
- return mc_mean + lo_bias, mc_mean + hi_bias
1779
1883
 
1884
+ lo = mc_scalar + float(np.asarray(lo_bias).flat[0])
1885
+ hi = mc_scalar + float(np.asarray(hi_bias).flat[0])
1886
+
1887
+ if lo > hi:
1888
+ lo, hi = hi, lo
1889
+
1890
+ return lo, hi
1780
1891
 
1781
1892
  # MC sample counting for label confidence (last timestep)
1782
1893
  def _label_confidence_empirical(self, mc_samples_last, label_bins):
1783
1894
  """
1784
1895
  mc_samples_last : (n_samples,) — raw MC draws at last timestep
1785
1896
  label_bins : {"Good": (0, 35), "Moderate": (35, 75), ...}
1786
-
1787
- No distribution assumption — just count what fraction
1788
- of actual MC samples land in each bin.
1789
1897
  """
1790
- label_conf = {}
1791
1898
  n = len(mc_samples_last)
1899
+ if n == 0:
1900
+ return {name: 0.0 for name in label_bins}
1901
+
1902
+ names = list(label_bins.keys())
1903
+ bounds = np.array(list(label_bins.values())) # (n_bins, 2)
1904
+
1905
+ # vectorized — broadcast (n_samples,) against (n_bins, 2)
1906
+ # samples shape: (1, n_samples), bounds shape: (n_bins, 1)
1907
+ samples = mc_samples_last[np.newaxis, :] # (1, n_samples)
1908
+ lo = bounds[:, 0, np.newaxis] # (n_bins, 1)
1909
+ hi = bounds[:, 1, np.newaxis] # (n_bins, 1)
1792
1910
 
1793
- for name, (lo, hi) in label_bins.items():
1794
- hits = ((mc_samples_last >= lo) & (mc_samples_last < hi)).sum()
1795
- label_conf[name] = hits / n
1911
+ hits = ((samples >= lo) & (samples < hi)).sum(axis=1) # (n_bins,)
1912
+ probs = hits / n # (n_bins,)
1796
1913
 
1797
- return label_conf
1914
+ return dict(zip(names, probs.tolist()))
1798
1915
 
1799
1916
  # LSTM training loop with confidence layers integrated into the loss and validation monitoring.
1800
1917
  def fit_stm(self, X, Y, epochs=50, hidden=32, lr=5e-3, seq_len=20, print_every=5):
@@ -1804,7 +1921,7 @@ class LSTMEngine:
1804
1921
  AME = self.pipeline.AME_Encoder(X)
1805
1922
  AMR = 1.0 / (1.0 + np.exp(-AME))
1806
1923
 
1807
- n_train = int(AMR * len(X))
1924
+ n_train = int((1.0 - AMR) * len(X))
1808
1925
  X_tr, Y_tr = X[:n_train], Y[:n_train]
1809
1926
  X_te, Y_te = X[n_train:], Y[n_train:]
1810
1927
 
@@ -1814,7 +1931,7 @@ class LSTMEngine:
1814
1931
  np.random.shuffle(idx)
1815
1932
  epoch_loss = 0.0
1816
1933
  for j in idx:
1817
- loss, _ = model.train_step(X_tr[j], Y_tr[j], lr=lr)
1934
+ loss, _ = model.train_step(X_tr[j], Y_tr[j], lr=lr, AMR=AMR)
1818
1935
  epoch_loss += loss
1819
1936
  epoch_loss /= n_train
1820
1937
 
@@ -1841,7 +1958,10 @@ class LSTMEngine:
1841
1958
 
1842
1959
  print("[=] Training complete!")
1843
1960
  print(f"[=] Final val loss: {val_loss:.6f}")
1961
+ print('===== CALIBRATION METHOD =====')
1962
+ self.calibrate_residual(X_te, Y_te)
1844
1963
 
1964
+ # get optimal lstm samples amount for the model to process
1845
1965
  def lstm_optimal_samples(self, engine, x_seq, tolerance=0.005, max_n=500):
1846
1966
  """
1847
1967
  Run increasing n_samples until std estimate stabilizes.
@@ -1862,7 +1982,7 @@ class LSTMEngine:
1862
1982
  prev_std = current_std
1863
1983
  return max_n
1864
1984
 
1865
-
1985
+ # derive local bins for flexibility in scarce dataset
1866
1986
  def derive_bins_from_data(self, y_values, n_bins=4, labels=None):
1867
1987
  """
1868
1988
  Use percentiles of actual data to set boundaries.
@@ -1915,7 +2035,7 @@ class LSTMEngine:
1915
2035
  return bins
1916
2036
 
1917
2037
 
1918
- # ── main predict ─────────────────────────
2038
+ # ── main predict function for the whole network ─────────────────────────
1919
2039
  def predict(self, x_seq: np.ndarray,
1920
2040
  label_bins: dict = None,
1921
2041
  confidence_level: float = 0.90) -> Any:
@@ -1941,9 +2061,6 @@ class LSTMEngine:
1941
2061
  label_confidence: {label: probability} if label_bins given
1942
2062
  overall : single scalar confidence for last timestep
1943
2063
  """
1944
- assert self.residual_std is not None, \
1945
- "Call calibrate(X_val, Y_val) before predict()"
1946
-
1947
2064
  # ── point prediction ──────────────────
1948
2065
  preds_clean, _, _, _ = self.model.forward(x_seq)
1949
2066
  AME = self.pipeline.AME_Encoder(x_seq) # geometric complexity scalar
@@ -1969,7 +2086,11 @@ class LSTMEngine:
1969
2086
 
1970
2087
  # ── prediction interval ───────────────
1971
2088
  total_std = np.sqrt(mc_std**2 + self.residual_std**2)
1972
- low, high = self._interval(mc_mean, confidence_level)
2089
+ # compute interval for every timestep — always returns (T,) arrays
2090
+ interval_low = np.empty(len(mc_mean))
2091
+ interval_high = np.empty(len(mc_mean))
2092
+ for t in range(len(mc_mean)):
2093
+ interval_low[t], interval_high[t] = self._interval(mc_mean[t], confidence_level)
1973
2094
 
1974
2095
  # ── label confidence (last timestep) ──
1975
2096
  label_conf = None
@@ -1984,7 +2105,7 @@ class LSTMEngine:
1984
2105
  # ── overall scalar confidence ─────────
1985
2106
  # weighted combination of MC confidence and gate stability
1986
2107
  gate_stability = 1.0 - gate_unc[-1] # high = stable
1987
- overall = AMR * mc_confidence[-1] + \
2108
+ overall = (1.0 - AMR) * mc_confidence[-1] + \
1988
2109
  self.pipeline.confidence_threshold * gate_stability
1989
2110
 
1990
2111
  return {
@@ -1993,16 +2114,15 @@ class LSTMEngine:
1993
2114
  "mc_std" : mc_std,
1994
2115
  "mc_confidence" : mc_confidence,
1995
2116
  "gate_uncertainty": gate_unc,
1996
- "interval_low" : low,
1997
- "interval_high" : high,
2117
+ "interval_low" : interval_low,
2118
+ "interval_high" : interval_high,
1998
2119
  "label_confidence": label_conf,
1999
2120
  "overall" : overall,
2000
2121
  }
2001
2122
 
2002
2123
  # ─────────────────────────────────────────────
2003
- # Architecture summary helper
2124
+ # Architecture summary helper to visualize results
2004
2125
  # ─────────────────────────────────────────────
2005
-
2006
2126
  def architectural_summary(self, model: LSTMNetwork):
2007
2127
  H = model.cell.hidden_size
2008
2128
  I = model.cell.input_size
@@ -7515,7 +7635,11 @@ class IntegratedPipeline:
7515
7635
  elif isinstance(a, np.ndarray) and np.issubdtype(a.dtype, np.character):
7516
7636
  # catches arrays filled with string text
7517
7637
  clean_str = ' '.join(a.astype(str).flatten()).replace('[', '').replace(']', '')
7518
- a = np.fromstring(clean_str, sep=' ')
7638
+ try:
7639
+ a = np.fromstring(clean_str, sep=' ')
7640
+ except:
7641
+ clean_string = clean_str.strip(",")
7642
+ a = np.fromstring(clean_string, sep=' ')
7519
7643
  else:
7520
7644
  # Ensure standard float array if it was integers or objects
7521
7645
  a = np.asarray(a, dtype=float)
@@ -8358,18 +8482,18 @@ class IntegratedPipeline:
8358
8482
 
8359
8483
  if choose_method == 'Y':
8360
8484
  self.autonomous = True
8361
- probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic')
8485
+ probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic', embedded=True)
8362
8486
 
8363
8487
  else:
8364
8488
  method = input('|| Choose one method (ex: dynamic): ')
8365
8489
  if method:
8366
- probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method=method)
8490
+ probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method=method, embedded=True)
8367
8491
  else:
8368
8492
  print('|| Invalid Method.. returning to dynamic prediction..')
8369
- probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic')
8493
+ probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic', embedded=True)
8370
8494
  else:
8371
8495
  print('[+] Autonomous dynamic prediction: ')
8372
- probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic')
8496
+ probs, details = self.ensemble.predict_ensemble(input_ids, X, y, method='dynamic', embedded=True)
8373
8497
 
8374
8498
  self.modular_prediction_saving(input_ids, X, probs)
8375
8499
  print('🚀 Memory Added!')
@@ -11772,9 +11896,15 @@ class PipelinePredictionManager:
11772
11896
  if sequence_ids is not None:
11773
11897
  print("\n[🔍] Using sequence encoding for transformer input due to low anisotropy.")
11774
11898
  input_ids = sequence_ids.copy()
11899
+
11775
11900
  target_probs = self.pipeline.predict_proba(input_ids, X, type='Hybrid', embedded=True)
11776
11901
  target_probs = target_probs[:mlp_probs.shape[0], :mlp_probs.shape[1]]
11777
- target_pred_indices = np.argmax(target_probs, axis=1)
11902
+ target_pred_indices = np.argmax(target_probs, axis=1)
11903
+
11904
+ if self.pipeline.cache and 'label_bins' in self.pipeline.cache:
11905
+ print('[=] label_bins cache found!')
11906
+ label_bins = self.pipeline.cache['label_bins']
11907
+ lstm_probs, _ = self.pipeline.ensemble._get_lstm_probs(input_ids, X, label_bins=label_bins)
11778
11908
 
11779
11909
  results = []
11780
11910
  attention_data = [] if return_attention else None
@@ -11815,20 +11945,32 @@ class PipelinePredictionManager:
11815
11945
  else:
11816
11946
  trans_confidence = trans_probs_i[trans_class_idx]
11817
11947
 
11948
+ if lstm_probs is not None:
11949
+ lstm_probs_i = lstm_probs[i]
11950
+ lstm_class_idx = np.argmax(lstm_probs_i)
11951
+ if isinstance(lstm_probs_i, float):
11952
+ lstm_confidence = target_confidence
11953
+ else:
11954
+ lstm_confidence = lstm_probs_i[lstm_class_idx]
11955
+
11818
11956
  trans_label = reverse_map.get(trans_class_idx, f"unknown_{trans_class_idx}")
11819
11957
 
11820
11958
  calibration = self.pipeline._calibrate_probs(target_probs, target_pred_indices, attn_weights, input_ids)
11821
11959
  # Blend predictions (MLP decides class, transformer calibrates confidence)
11822
11960
  mlp_weight = mlp_confidence / (target_confidence + trans_confidence + eps)
11823
11961
  trans_weight = trans_confidence / (target_confidence + trans_confidence + eps)
11962
+ if lstm_confidence is not None:
11963
+ lstm_weight = lstm_confidence / (target_confidence + lstm_confidence + eps)
11824
11964
 
11825
11965
  calibration_weighting = calibration[target_class_idx] if target_class_idx < len(calibration) else 0.0
11826
11966
 
11827
11967
  # Weighted blend: calibration_weighting * calibrated + (1-weight) * mlp
11828
- final_probs = mlp_weight * target_probs[i][:len(calibration)] + trans_weight * calibration[i][:len(calibration)]
11829
-
11830
- final_class_idx = target_class_idx
11968
+ if lstm_weight is not None:
11969
+ final_probs = mlp_weight * target_probs[i][:len(calibration)] + trans_weight * calibration[i][:len(calibration)] + lstm_weight * calibration[i][:len(calibration)]
11970
+ else:
11971
+ final_probs = mlp_weight * target_probs[i][:len(calibration)] + trans_weight * calibration[i][:len(calibration)]
11831
11972
 
11973
+ final_class_idx = target_class_idx
11832
11974
  try:
11833
11975
  final_confidence = final_probs[final_class_idx]
11834
11976
  except IndexError:
@@ -11944,7 +12086,7 @@ class PipelinePredictionManager:
11944
12086
 
11945
12087
  elif not results[0].get('models_agree', True) and confidence > self.pipeline.confidence_threshold:
11946
12088
  if final_confidence is not None and confidence < self.pipeline.confidence_threshold:
11947
- print("\n[⚠️] High confidence detected, but both models don't agree. Using calibrated probabilities for final decision to ensure robustness.")
12089
+ print("\n[⚠️] Low confidence detected, but both models don't agree. Using calibrated probabilities for final decision to ensure robustness.")
11948
12090
  final_probs = self.pipeline.hybrid_prediction(rules, input_ids, dataset)
11949
12091
  final_idx = final_probs[0].argmax()
11950
12092
  original_idx = final_idx
@@ -11953,6 +12095,16 @@ class PipelinePredictionManager:
11953
12095
  final_idx = int(np.argmax(final_probs[:len(reverse_map)-1]))
11954
12096
  print(f"[⚠️] Clamping {final_idx} → {final_idx}")
11955
12097
  final_idx = int(final_idx)
12098
+ else:
12099
+ print('[🎯] Stable confidence established, But both Models doesnt Agree, Re-evaluating...')
12100
+ final_probs = self.pipeline.hybrid_prediction(rules, input_ids, dataset)
12101
+ final_idx = final_probs[0].argmax()
12102
+ original_idx = final_idx
12103
+
12104
+ if final_idx > len(reverse_map):
12105
+ final_idx = int(np.argmax(final_probs[:len(reverse_map)-1]))
12106
+ print(f"[⚠️] Clamping {final_idx} → {final_idx}")
12107
+ final_idx = int(final_idx)
11956
12108
 
11957
12109
  chosen_label = reverse_map.get(final_idx, f"unknown_{final_idx}")
11958
12110
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractIntegratedModule
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Framework for Advanced Integrated Non-LLM AI Module library - Backend Framework for Non-LLM AI Agent Framework
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: Beta, 0.4.0.
45
+ - Development Stage: Beta, 0.4.1.
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.
@@ -62,7 +62,7 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
62
62
  - Proven Works on ARM64 Environment, Training and Prediction works efficient on Docker ARM64 environment with QEMU, good parallelizing behavior is guaranteed.
63
63
  - P2P Works efficiently in ARM64 Docker + QEMU, No conflicting socket and all prediction works efficiently.
64
64
  - AWE setup Proven Efficient on Hard-uncontrolled dataset such as Activity Recognition from the given Database.
65
-
65
+ - LSTM is Optimized efficiently for scarce data with AWE method.
66
66
  -----
67
67
 
68
68
  <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" />
@@ -10,7 +10,7 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
10
10
  #### 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.
11
11
 
12
12
  ### Library Short Description:
13
- - Development Stage: Beta, 0.4.0.
13
+ - Development Stage: Beta, 0.4.1.
14
14
  - Maintainer: Micro-Novelty.
15
15
  - library Source-Code is Open-sourced on github.
16
16
  - Purpose: Specifically Designed for providing Non-LLM AI Agent Framework for edge Devices, Optimized for ARM64 architecture.
@@ -30,7 +30,7 @@ https://github.com/Micro-Novelty/IntegratedPipeline-Specialized-Non-LLM-AI-Agent
30
30
  - Proven Works on ARM64 Environment, Training and Prediction works efficient on Docker ARM64 environment with QEMU, good parallelizing behavior is guaranteed.
31
31
  - P2P Works efficiently in ARM64 Docker + QEMU, No conflicting socket and all prediction works efficiently.
32
32
  - AWE setup Proven Efficient on Hard-uncontrolled dataset such as Activity Recognition from the given Database.
33
-
33
+ - LSTM is Optimized efficiently for scarce data with AWE method.
34
34
  -----
35
35
 
36
36
  <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" />
@@ -8,7 +8,7 @@ class BinaryDistribution(Distribution):
8
8
 
9
9
  setup(
10
10
  name="AbstractIntegratedModule",
11
- version="0.4.0",
11
+ version="0.4.1",
12
12
  description="Framework for Advanced Integrated Non-LLM AI Module library - Backend Framework for Non-LLM AI Agent Framework",
13
13
  long_description=open("README.md", encoding="utf-8").read(),
14
14
  long_description_content_type="text/markdown",