oikan 0.0.3.10__py3-none-any.whl → 0.0.3.11__py3-none-any.whl
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.
- oikan/model.py +52 -10
- {oikan-0.0.3.10.dist-info → oikan-0.0.3.11.dist-info}/METADATA +4 -4
- {oikan-0.0.3.10.dist-info → oikan-0.0.3.11.dist-info}/RECORD +6 -6
- {oikan-0.0.3.10.dist-info → oikan-0.0.3.11.dist-info}/WHEEL +0 -0
- {oikan-0.0.3.10.dist-info → oikan-0.0.3.11.dist-info}/licenses/LICENSE +0 -0
- {oikan-0.0.3.10.dist-info → oikan-0.0.3.11.dist-info}/top_level.txt +0 -0
oikan/model.py
CHANGED
@@ -2,7 +2,6 @@ import numpy as np
|
|
2
2
|
import torch
|
3
3
|
import torch.nn as nn
|
4
4
|
import torch.optim as optim
|
5
|
-
from sklearn.preprocessing import PolynomialFeatures
|
6
5
|
from abc import ABC, abstractmethod
|
7
6
|
import json
|
8
7
|
from .elasticnet import ElasticNet
|
@@ -88,6 +87,7 @@ class OIKAN(ABC):
|
|
88
87
|
self.symbolic_model = None
|
89
88
|
self.evaluation_done = False
|
90
89
|
self.random_state = random_state
|
90
|
+
self.__version__ = '0.0.3'
|
91
91
|
|
92
92
|
if self.random_state is not None:
|
93
93
|
torch.manual_seed(self.random_state)
|
@@ -300,8 +300,10 @@ class OIKAN(ABC):
|
|
300
300
|
if self.neural_net is None:
|
301
301
|
self.neural_net = TabularNet(input_size, self.hidden_sizes, output_size, self.activation)
|
302
302
|
optimizer = optim.Adam(self.neural_net.parameters(), lr=self.lr)
|
303
|
-
dataset = torch.utils.data.TensorDataset(
|
304
|
-
|
303
|
+
dataset = torch.utils.data.TensorDataset(
|
304
|
+
torch.tensor(X, dtype=torch.float32),
|
305
|
+
torch.tensor(y, dtype=torch.float32)
|
306
|
+
)
|
305
307
|
loader = torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, shuffle=True)
|
306
308
|
self.neural_net.train()
|
307
309
|
|
@@ -362,14 +364,32 @@ class OIKAN(ABC):
|
|
362
364
|
|
363
365
|
if self.verbose:
|
364
366
|
print("\nStage 1: Coarse Model Fitting")
|
365
|
-
|
366
|
-
coarse_degree = 2 # Fixed low degree for coarse model
|
367
|
-
poly_coarse = PolynomialFeatures(degree=coarse_degree, include_bias=True)
|
368
367
|
|
368
|
+
# Generate polynomial features
|
369
369
|
if self.verbose:
|
370
370
|
print("Generating polynomial features...")
|
371
|
-
|
372
|
-
|
371
|
+
n_samples, n_features = X.shape
|
372
|
+
|
373
|
+
bias = np.ones((n_samples, 1))
|
374
|
+
features = X
|
375
|
+
powers_of_2 = X ** 2
|
376
|
+
|
377
|
+
X_poly_coarse = np.hstack([bias, features, powers_of_2])
|
378
|
+
basis_functions_coarse = ['1'] + [f'x{i}' for i in range(n_features)] + [f'x{i}^2' for i in range(n_features)]
|
379
|
+
|
380
|
+
# Generate random interaction features (O(N^2) -> O(N))
|
381
|
+
if self.verbose:
|
382
|
+
print("Generating random interaction features...")
|
383
|
+
rng = np.random.default_rng(self.random_state)
|
384
|
+
random_pairs = rng.choice(n_features, size=(n_features // 2, 2), replace=False)
|
385
|
+
interaction_features = np.array([X[:, i] * X[:, j] for i, j in random_pairs]).T
|
386
|
+
interaction_feature_names = [f"x{i} x{j}" for i, j in random_pairs]
|
387
|
+
|
388
|
+
# Combine all features
|
389
|
+
X_poly_coarse = np.hstack([X_poly_coarse, interaction_features])
|
390
|
+
basis_functions_coarse.extend(interaction_feature_names)
|
391
|
+
|
392
|
+
# Fit coarse elastic net model
|
373
393
|
if self.verbose:
|
374
394
|
print("Fitting coarse elastic net model...")
|
375
395
|
model_coarse = ElasticNet(alpha=self.alpha, l1_ratio=self.l1_ratio, fit_intercept=False, random_state=self.random_state)
|
@@ -377,7 +397,7 @@ class OIKAN(ABC):
|
|
377
397
|
|
378
398
|
if self.verbose:
|
379
399
|
print("Computing feature importances...")
|
380
|
-
|
400
|
+
|
381
401
|
if len(y.shape) == 1 or y.shape[1] == 1:
|
382
402
|
coef_coarse = model_coarse.coef_.flatten()
|
383
403
|
else:
|
@@ -443,7 +463,7 @@ class OIKAN(ABC):
|
|
443
463
|
coef = model_refined.coef_[c]
|
444
464
|
indices = np.where(np.abs(coef) > 1e-6)[0]
|
445
465
|
selected_indices.update(indices)
|
446
|
-
selected_indices =
|
466
|
+
selected_indices = [i for i in selected_indices if i < len(basis_functions_refined)]
|
447
467
|
basis_functions = [basis_functions_refined[i] for i in selected_indices]
|
448
468
|
for c in range(y.shape[1]):
|
449
469
|
coef = model_refined.coef_[c]
|
@@ -454,6 +474,22 @@ class OIKAN(ABC):
|
|
454
474
|
'basis_functions': basis_functions,
|
455
475
|
'coefficients_list': coefficients_list
|
456
476
|
}
|
477
|
+
|
478
|
+
def _print_system_info(self):
|
479
|
+
"""Prints system information (for debugging purposes)."""
|
480
|
+
import platform
|
481
|
+
import os
|
482
|
+
print("\n" + "="*30)
|
483
|
+
print("System Information:")
|
484
|
+
print(f"OIKAN version: {self.__version__}")
|
485
|
+
print(f"Python version: {platform.python_version()}")
|
486
|
+
print(f"NumPy version: {np.__version__}")
|
487
|
+
print(f"Torch version: {torch.__version__}")
|
488
|
+
print(f"Device: {'CUDA' if torch.cuda.is_available() else 'CPU'}")
|
489
|
+
print(f"Number of CPU cores: {os.cpu_count()}")
|
490
|
+
print(f"Memory Usage: {torch.cuda.memory_allocated() / (1024 ** 2) if torch.cuda.is_available() else 'N/A'} MB")
|
491
|
+
print(f"Architecture: {platform.machine()}")
|
492
|
+
print("="*30 + "\n")
|
457
493
|
|
458
494
|
class OIKANRegressor(OIKAN):
|
459
495
|
"""OIKAN model for regression tasks."""
|
@@ -468,6 +504,9 @@ class OIKANRegressor(OIKAN):
|
|
468
504
|
y : array-like of shape (n_samples,)
|
469
505
|
Target values.
|
470
506
|
"""
|
507
|
+
if self.verbose:
|
508
|
+
self._print_system_info()
|
509
|
+
|
471
510
|
X = np.asarray(X)
|
472
511
|
y = np.asarray(y).reshape(-1, 1)
|
473
512
|
|
@@ -533,6 +572,9 @@ class OIKANClassifier(OIKAN):
|
|
533
572
|
y : array-like of shape (n_samples,)
|
534
573
|
Target labels.
|
535
574
|
"""
|
575
|
+
if self.verbose:
|
576
|
+
self._print_system_info()
|
577
|
+
|
536
578
|
X = np.asarray(X)
|
537
579
|
from sklearn.preprocessing import LabelEncoder
|
538
580
|
le = LabelEncoder()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oikan
|
3
|
-
Version: 0.0.3.
|
3
|
+
Version: 0.0.3.11
|
4
4
|
Summary: OIKAN: Neuro-Symbolic ML for Scientific Discovery
|
5
5
|
Author: Arman Zhalgasbayev
|
6
6
|
License: MIT
|
@@ -67,7 +67,7 @@ OIKAN is a neuro-symbolic machine learning framework inspired by Kolmogorov-Arno
|
|
67
67
|
# Data augmentation for better coverage
|
68
68
|
self.augmented_data = self.augment_data(X, y, augmentation_factor=5)
|
69
69
|
# Symbolic regression for interpretable formulas
|
70
|
-
self.symbolic_regression = SymbolicRegression(alpha=alpha)
|
70
|
+
self.symbolic_regression = SymbolicRegression(alpha=alpha, l1_ratio=0.5)
|
71
71
|
```
|
72
72
|
|
73
73
|
2. **Basis Functions**: Core set of interpretable transformations:
|
@@ -120,7 +120,7 @@ pip install -e . # Install in development mode
|
|
120
120
|
|
121
121
|
### Regression Example
|
122
122
|
|
123
|
-
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as
|
123
|
+
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as ElasticNet assumes that the model intercept has already been accounted for.
|
124
124
|
|
125
125
|
```python
|
126
126
|
from oikan import OIKANRegressor
|
@@ -174,7 +174,7 @@ loaded_model.load("outputs/model.json")
|
|
174
174
|
|
175
175
|
### Classification Example
|
176
176
|
|
177
|
-
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as
|
177
|
+
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as ElasticNet assumes that the model intercept has already been accounted for.
|
178
178
|
|
179
179
|
```python
|
180
180
|
from oikan import OIKANClassifier
|
@@ -1,11 +1,11 @@
|
|
1
1
|
oikan/__init__.py,sha256=Dh1Rf9ONRdm75B6tFiv9Y9P6NNiHAiKPCGDMuag6TTE,724
|
2
2
|
oikan/elasticnet.py,sha256=eeuK4lJ-7lsGZIyiXNH6NKYxhbbKbPp1kp8vLe4t7_4,2614
|
3
3
|
oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
|
4
|
-
oikan/model.py,sha256=
|
4
|
+
oikan/model.py,sha256=ushOC7UGJWCy5VSkRUmtIBYN8SrXi9nlPW0lwP0ys-s,27937
|
5
5
|
oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
|
6
6
|
oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
|
7
|
-
oikan-0.0.3.
|
8
|
-
oikan-0.0.3.
|
9
|
-
oikan-0.0.3.
|
10
|
-
oikan-0.0.3.
|
11
|
-
oikan-0.0.3.
|
7
|
+
oikan-0.0.3.11.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
|
8
|
+
oikan-0.0.3.11.dist-info/METADATA,sha256=zMlMldKLUmYTv4UZclU9q4eLoLZi4yIwidlk2GK64xs,13139
|
9
|
+
oikan-0.0.3.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
10
|
+
oikan-0.0.3.11.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
|
11
|
+
oikan-0.0.3.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|