oikan 0.0.2.3__tar.gz → 0.0.2.4__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.
- {oikan-0.0.2.3 → oikan-0.0.2.4}/PKG-INFO +73 -80
- {oikan-0.0.2.3 → oikan-0.0.2.4}/README.md +72 -79
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan/model.py +49 -27
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan/utils.py +3 -9
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan.egg-info/PKG-INFO +73 -80
- {oikan-0.0.2.3 → oikan-0.0.2.4}/pyproject.toml +1 -1
- {oikan-0.0.2.3 → oikan-0.0.2.4}/LICENSE +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan/__init__.py +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan/exceptions.py +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan/symbolic.py +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan.egg-info/SOURCES.txt +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan.egg-info/dependency_links.txt +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan.egg-info/requires.txt +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/oikan.egg-info/top_level.txt +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/setup.cfg +0 -0
- {oikan-0.0.2.3 → oikan-0.0.2.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oikan
|
3
|
-
Version: 0.0.2.
|
3
|
+
Version: 0.0.2.4
|
4
4
|
Summary: OIKAN: Optimized Interpretable Kolmogorov-Arnold Networks
|
5
5
|
Author: Arman Zhalgasbayev
|
6
6
|
License: MIT
|
@@ -32,20 +32,39 @@ OIKAN (Optimized Interpretable Kolmogorov-Arnold Networks) is a neuro-symbolic M
|
|
32
32
|
[](https://github.com/silvermete0r/oikan/issues)
|
33
33
|
[](https://silvermete0r.github.io/oikan/)
|
34
34
|
|
35
|
+
> **Important Disclaimer**: OIKAN is an experimental research project. It is not intended for production use or real-world applications. This framework is designed for research purposes, experimentation, and academic exploration of neuro-symbolic machine learning concepts.
|
36
|
+
|
35
37
|
## Key Features
|
36
38
|
- 🧠 **Neuro-Symbolic ML**: Combines neural network learning with symbolic mathematics
|
37
39
|
- 📊 **Automatic Formula Extraction**: Generates human-readable mathematical expressions
|
38
40
|
- 🎯 **Scikit-learn Compatible**: Familiar `.fit()` and `.predict()` interface
|
39
|
-
-
|
41
|
+
- 🔬 **Research-Focused**: Designed for academic exploration and experimentation
|
40
42
|
- 📈 **Multi-Task**: Supports both regression and classification problems
|
41
43
|
|
42
44
|
## Scientific Foundation
|
43
45
|
|
44
|
-
OIKAN
|
46
|
+
OIKAN implements the Kolmogorov-Arnold Representation Theorem through a novel neural architecture:
|
47
|
+
|
48
|
+
1. **Theorem Background**: Any continuous multivariate function f(x1,...,xn) can be represented as:
|
49
|
+
```
|
50
|
+
f(x1,...,xn) = ∑(j=0 to 2n){ φj( ∑(i=1 to n) ψij(xi) ) }
|
51
|
+
```
|
52
|
+
where φj and ψij are continuous single-variable functions.
|
45
53
|
|
46
|
-
|
47
|
-
|
48
|
-
|
54
|
+
2. **Neural Implementation**:
|
55
|
+
```python
|
56
|
+
# Pseudo-implementation of KAN architecture
|
57
|
+
class KANLayer:
|
58
|
+
def __init__(self, input_dim, output_dim):
|
59
|
+
self.edges = [SymbolicEdge() for _ in range(input_dim * output_dim)]
|
60
|
+
self.weights = initialize_weights(input_dim, output_dim)
|
61
|
+
|
62
|
+
def forward(self, x):
|
63
|
+
# Transform each input through basis functions
|
64
|
+
edge_outputs = [edge(x_i) for x_i, edge in zip(x, self.edges)]
|
65
|
+
# Combine using learned weights
|
66
|
+
return combine_weighted_outputs(edge_outputs, self.weights)
|
67
|
+
```
|
49
68
|
|
50
69
|
## Quick Start
|
51
70
|
|
@@ -68,11 +87,8 @@ pip install -e . # Install in development mode
|
|
68
87
|
from oikan.model import OIKANRegressor
|
69
88
|
from sklearn.model_selection import train_test_split
|
70
89
|
|
71
|
-
# Initialize model
|
72
|
-
model = OIKANRegressor(
|
73
|
-
hidden_dims=[16, 8], # Network architecture
|
74
|
-
dropout=0.1 # Regularization
|
75
|
-
)
|
90
|
+
# Initialize model
|
91
|
+
model = OIKANRegressor()
|
76
92
|
|
77
93
|
# Fit model (sklearn-style)
|
78
94
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
@@ -84,7 +100,7 @@ y_pred = model.predict(X_test)
|
|
84
100
|
# The output file will contain:
|
85
101
|
# - Detailed symbolic formulas for each feature
|
86
102
|
# - Instructions for practical implementation
|
87
|
-
# - Recommendations for
|
103
|
+
# - Recommendations for testing and validation
|
88
104
|
model.save_symbolic_formula("regression_formula.txt")
|
89
105
|
```
|
90
106
|
|
@@ -96,7 +112,7 @@ model.save_symbolic_formula("regression_formula.txt")
|
|
96
112
|
from oikan.model import OIKANClassifier
|
97
113
|
|
98
114
|
# Similar sklearn-style interface for classification
|
99
|
-
model = OIKANClassifier(
|
115
|
+
model = OIKANClassifier()
|
100
116
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
101
117
|
probas = model.predict_proba(X_test)
|
102
118
|
|
@@ -104,45 +120,41 @@ probas = model.predict_proba(X_test)
|
|
104
120
|
# The output file will contain:
|
105
121
|
# - Decision boundary formulas for each class
|
106
122
|
# - Softmax application instructions
|
107
|
-
# -
|
123
|
+
# - Recommendations for testing and validation
|
108
124
|
model.save_symbolic_formula("classification_formula.txt")
|
109
125
|
```
|
110
126
|
|
111
127
|
*Example of the saved symbolic formula instructions: [outputs/classification_symbolic_formula.txt](outputs/classification_symbolic_formula.txt)*
|
112
128
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
- Weight-based term pruning (threshold=1e-4)
|
143
|
-
- Automatic coefficient optimization
|
144
|
-
- Human-readable mathematical expressions
|
145
|
-
- Exportable to lightweight production code
|
129
|
+
|
130
|
+
### Key Design Principles
|
131
|
+
|
132
|
+
1. **Interpretability by Design**
|
133
|
+
```python
|
134
|
+
# Edge activation contains interpretable basis functions
|
135
|
+
ADVANCED_LIB = {
|
136
|
+
'x': (lambda x: x), # Linear
|
137
|
+
'x^2': (lambda x: x**2), # Quadratic
|
138
|
+
'sin(x)': np.sin, # Periodic
|
139
|
+
'tanh(x)': np.tanh # Bounded
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
2. **Automatic Simplification**
|
144
|
+
```python
|
145
|
+
def simplify_formula(terms, threshold=1e-4):
|
146
|
+
return [term for term in terms if abs(term.coefficient) > threshold]
|
147
|
+
```
|
148
|
+
|
149
|
+
3. **Research-Oriented Architecture**
|
150
|
+
```python
|
151
|
+
class SymbolicEdge:
|
152
|
+
def forward(self, x):
|
153
|
+
return sum(w * f(x) for w, f in zip(self.weights, self.basis_functions))
|
154
|
+
|
155
|
+
def get_formula(self):
|
156
|
+
return format_symbolic_terms(self.weights, self.basis_functions)
|
157
|
+
```
|
146
158
|
|
147
159
|
### Architecture Diagram
|
148
160
|
|
@@ -152,45 +164,26 @@ OIKAN implements a novel neuro-symbolic architecture based on Kolmogorov-Arnold
|
|
152
164
|
|
153
165
|
1. **Interpretability First**: All transformations maintain clear mathematical meaning
|
154
166
|
2. **Scikit-learn Compatibility**: Familiar `.fit()` and `.predict()` interface
|
155
|
-
3. **
|
167
|
+
3. **Symbolic Formula Exporting**: Export formulas as lightweight mathematical expressions
|
156
168
|
4. **Automatic Simplification**: Remove insignificant terms (|w| < 1e-4)
|
157
169
|
|
158
|
-
## Model Components
|
159
|
-
|
160
|
-
1. **Symbolic Edge Functions**
|
161
|
-
```python
|
162
|
-
class EdgeActivation(nn.Module):
|
163
|
-
"""Learnable edge activation with basis functions"""
|
164
|
-
def forward(self, x):
|
165
|
-
return sum(self.weights[i] * basis[i](x) for i in range(self.num_basis))
|
166
|
-
```
|
167
170
|
|
168
|
-
|
169
|
-
```python
|
170
|
-
class KANLayer(nn.Module):
|
171
|
-
"""Kolmogorov-Arnold Network layer"""
|
172
|
-
def forward(self, x):
|
173
|
-
edge_outputs = [self.edges[i](x[:,i]) for i in range(self.input_dim)]
|
174
|
-
return self.combine(edge_outputs)
|
175
|
-
```
|
171
|
+
### Key Model Components
|
176
172
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
terms = []
|
182
|
-
for i, edge in enumerate(self.edges):
|
183
|
-
if abs(self.weights[i]) > threshold:
|
184
|
-
terms.append(f"{self.weights[i]:.4f} * {edge.formula}")
|
185
|
-
return " + ".join(terms)
|
186
|
-
```
|
173
|
+
1. **EdgeActivation Layer**:
|
174
|
+
- Implements interpretable basis function transformations
|
175
|
+
- Automatically prunes insignificant terms
|
176
|
+
- Maintains mathematical transparency
|
187
177
|
|
188
|
-
|
178
|
+
2. **Formula Extraction**:
|
179
|
+
- Combines edge transformations with learned weights
|
180
|
+
- Applies symbolic simplification
|
181
|
+
- Generates human-readable expressions
|
189
182
|
|
190
|
-
|
191
|
-
-
|
192
|
-
-
|
193
|
-
-
|
183
|
+
3. **Training Process**:
|
184
|
+
- Gradient-based optimization of edge weights
|
185
|
+
- Automatic feature importance detection
|
186
|
+
- Complexity control through regularization
|
194
187
|
|
195
188
|
## Contributing
|
196
189
|
|
@@ -15,20 +15,39 @@ OIKAN (Optimized Interpretable Kolmogorov-Arnold Networks) is a neuro-symbolic M
|
|
15
15
|
[](https://github.com/silvermete0r/oikan/issues)
|
16
16
|
[](https://silvermete0r.github.io/oikan/)
|
17
17
|
|
18
|
+
> **Important Disclaimer**: OIKAN is an experimental research project. It is not intended for production use or real-world applications. This framework is designed for research purposes, experimentation, and academic exploration of neuro-symbolic machine learning concepts.
|
19
|
+
|
18
20
|
## Key Features
|
19
21
|
- 🧠 **Neuro-Symbolic ML**: Combines neural network learning with symbolic mathematics
|
20
22
|
- 📊 **Automatic Formula Extraction**: Generates human-readable mathematical expressions
|
21
23
|
- 🎯 **Scikit-learn Compatible**: Familiar `.fit()` and `.predict()` interface
|
22
|
-
-
|
24
|
+
- 🔬 **Research-Focused**: Designed for academic exploration and experimentation
|
23
25
|
- 📈 **Multi-Task**: Supports both regression and classification problems
|
24
26
|
|
25
27
|
## Scientific Foundation
|
26
28
|
|
27
|
-
OIKAN
|
29
|
+
OIKAN implements the Kolmogorov-Arnold Representation Theorem through a novel neural architecture:
|
30
|
+
|
31
|
+
1. **Theorem Background**: Any continuous multivariate function f(x1,...,xn) can be represented as:
|
32
|
+
```
|
33
|
+
f(x1,...,xn) = ∑(j=0 to 2n){ φj( ∑(i=1 to n) ψij(xi) ) }
|
34
|
+
```
|
35
|
+
where φj and ψij are continuous single-variable functions.
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
2. **Neural Implementation**:
|
38
|
+
```python
|
39
|
+
# Pseudo-implementation of KAN architecture
|
40
|
+
class KANLayer:
|
41
|
+
def __init__(self, input_dim, output_dim):
|
42
|
+
self.edges = [SymbolicEdge() for _ in range(input_dim * output_dim)]
|
43
|
+
self.weights = initialize_weights(input_dim, output_dim)
|
44
|
+
|
45
|
+
def forward(self, x):
|
46
|
+
# Transform each input through basis functions
|
47
|
+
edge_outputs = [edge(x_i) for x_i, edge in zip(x, self.edges)]
|
48
|
+
# Combine using learned weights
|
49
|
+
return combine_weighted_outputs(edge_outputs, self.weights)
|
50
|
+
```
|
32
51
|
|
33
52
|
## Quick Start
|
34
53
|
|
@@ -51,11 +70,8 @@ pip install -e . # Install in development mode
|
|
51
70
|
from oikan.model import OIKANRegressor
|
52
71
|
from sklearn.model_selection import train_test_split
|
53
72
|
|
54
|
-
# Initialize model
|
55
|
-
model = OIKANRegressor(
|
56
|
-
hidden_dims=[16, 8], # Network architecture
|
57
|
-
dropout=0.1 # Regularization
|
58
|
-
)
|
73
|
+
# Initialize model
|
74
|
+
model = OIKANRegressor()
|
59
75
|
|
60
76
|
# Fit model (sklearn-style)
|
61
77
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
@@ -67,7 +83,7 @@ y_pred = model.predict(X_test)
|
|
67
83
|
# The output file will contain:
|
68
84
|
# - Detailed symbolic formulas for each feature
|
69
85
|
# - Instructions for practical implementation
|
70
|
-
# - Recommendations for
|
86
|
+
# - Recommendations for testing and validation
|
71
87
|
model.save_symbolic_formula("regression_formula.txt")
|
72
88
|
```
|
73
89
|
|
@@ -79,7 +95,7 @@ model.save_symbolic_formula("regression_formula.txt")
|
|
79
95
|
from oikan.model import OIKANClassifier
|
80
96
|
|
81
97
|
# Similar sklearn-style interface for classification
|
82
|
-
model = OIKANClassifier(
|
98
|
+
model = OIKANClassifier()
|
83
99
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
84
100
|
probas = model.predict_proba(X_test)
|
85
101
|
|
@@ -87,45 +103,41 @@ probas = model.predict_proba(X_test)
|
|
87
103
|
# The output file will contain:
|
88
104
|
# - Decision boundary formulas for each class
|
89
105
|
# - Softmax application instructions
|
90
|
-
# -
|
106
|
+
# - Recommendations for testing and validation
|
91
107
|
model.save_symbolic_formula("classification_formula.txt")
|
92
108
|
```
|
93
109
|
|
94
110
|
*Example of the saved symbolic formula instructions: [outputs/classification_symbolic_formula.txt](outputs/classification_symbolic_formula.txt)*
|
95
111
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
- Weight-based term pruning (threshold=1e-4)
|
126
|
-
- Automatic coefficient optimization
|
127
|
-
- Human-readable mathematical expressions
|
128
|
-
- Exportable to lightweight production code
|
112
|
+
|
113
|
+
### Key Design Principles
|
114
|
+
|
115
|
+
1. **Interpretability by Design**
|
116
|
+
```python
|
117
|
+
# Edge activation contains interpretable basis functions
|
118
|
+
ADVANCED_LIB = {
|
119
|
+
'x': (lambda x: x), # Linear
|
120
|
+
'x^2': (lambda x: x**2), # Quadratic
|
121
|
+
'sin(x)': np.sin, # Periodic
|
122
|
+
'tanh(x)': np.tanh # Bounded
|
123
|
+
}
|
124
|
+
```
|
125
|
+
|
126
|
+
2. **Automatic Simplification**
|
127
|
+
```python
|
128
|
+
def simplify_formula(terms, threshold=1e-4):
|
129
|
+
return [term for term in terms if abs(term.coefficient) > threshold]
|
130
|
+
```
|
131
|
+
|
132
|
+
3. **Research-Oriented Architecture**
|
133
|
+
```python
|
134
|
+
class SymbolicEdge:
|
135
|
+
def forward(self, x):
|
136
|
+
return sum(w * f(x) for w, f in zip(self.weights, self.basis_functions))
|
137
|
+
|
138
|
+
def get_formula(self):
|
139
|
+
return format_symbolic_terms(self.weights, self.basis_functions)
|
140
|
+
```
|
129
141
|
|
130
142
|
### Architecture Diagram
|
131
143
|
|
@@ -135,45 +147,26 @@ OIKAN implements a novel neuro-symbolic architecture based on Kolmogorov-Arnold
|
|
135
147
|
|
136
148
|
1. **Interpretability First**: All transformations maintain clear mathematical meaning
|
137
149
|
2. **Scikit-learn Compatibility**: Familiar `.fit()` and `.predict()` interface
|
138
|
-
3. **
|
150
|
+
3. **Symbolic Formula Exporting**: Export formulas as lightweight mathematical expressions
|
139
151
|
4. **Automatic Simplification**: Remove insignificant terms (|w| < 1e-4)
|
140
152
|
|
141
|
-
## Model Components
|
142
|
-
|
143
|
-
1. **Symbolic Edge Functions**
|
144
|
-
```python
|
145
|
-
class EdgeActivation(nn.Module):
|
146
|
-
"""Learnable edge activation with basis functions"""
|
147
|
-
def forward(self, x):
|
148
|
-
return sum(self.weights[i] * basis[i](x) for i in range(self.num_basis))
|
149
|
-
```
|
150
153
|
|
151
|
-
|
152
|
-
```python
|
153
|
-
class KANLayer(nn.Module):
|
154
|
-
"""Kolmogorov-Arnold Network layer"""
|
155
|
-
def forward(self, x):
|
156
|
-
edge_outputs = [self.edges[i](x[:,i]) for i in range(self.input_dim)]
|
157
|
-
return self.combine(edge_outputs)
|
158
|
-
```
|
154
|
+
### Key Model Components
|
159
155
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
terms = []
|
165
|
-
for i, edge in enumerate(self.edges):
|
166
|
-
if abs(self.weights[i]) > threshold:
|
167
|
-
terms.append(f"{self.weights[i]:.4f} * {edge.formula}")
|
168
|
-
return " + ".join(terms)
|
169
|
-
```
|
156
|
+
1. **EdgeActivation Layer**:
|
157
|
+
- Implements interpretable basis function transformations
|
158
|
+
- Automatically prunes insignificant terms
|
159
|
+
- Maintains mathematical transparency
|
170
160
|
|
171
|
-
|
161
|
+
2. **Formula Extraction**:
|
162
|
+
- Combines edge transformations with learned weights
|
163
|
+
- Applies symbolic simplification
|
164
|
+
- Generates human-readable expressions
|
172
165
|
|
173
|
-
|
174
|
-
-
|
175
|
-
-
|
176
|
-
-
|
166
|
+
3. **Training Process**:
|
167
|
+
- Gradient-based optimization of edge weights
|
168
|
+
- Automatic feature importance detection
|
169
|
+
- Complexity control through regularization
|
177
170
|
|
178
171
|
## Contributing
|
179
172
|
|
@@ -30,7 +30,10 @@ class KANLayer(nn.Module):
|
|
30
30
|
for _ in range(input_dim)
|
31
31
|
])
|
32
32
|
|
33
|
-
|
33
|
+
# Updated initialization using Xavier uniform initialization
|
34
|
+
self.combination_weights = nn.Parameter(
|
35
|
+
nn.init.xavier_uniform_(torch.empty(input_dim, output_dim))
|
36
|
+
)
|
34
37
|
|
35
38
|
def forward(self, x):
|
36
39
|
x_split = x.split(1, dim=1) # list of (batch, 1) tensors for each input feature
|
@@ -49,7 +52,8 @@ class KANLayer(nn.Module):
|
|
49
52
|
for i in range(self.input_dim):
|
50
53
|
weight = self.combination_weights[i, j].item()
|
51
54
|
if abs(weight) > 1e-4:
|
52
|
-
|
55
|
+
# Pass lower threshold for improved precision
|
56
|
+
edge_formula = self.edges[i][j].get_symbolic_repr(threshold=1e-6)
|
53
57
|
if edge_formula != "0":
|
54
58
|
terms.append(f"({weight:.4f} * ({edge_formula}))")
|
55
59
|
formulas.append(" + ".join(terms) if terms else "0")
|
@@ -57,15 +61,13 @@ class KANLayer(nn.Module):
|
|
57
61
|
|
58
62
|
class BaseOIKAN(BaseEstimator):
|
59
63
|
"""Base OIKAN model implementing common functionality"""
|
60
|
-
def __init__(self, hidden_dims=[
|
64
|
+
def __init__(self, hidden_dims=[32, 16], dropout=0.1):
|
61
65
|
self.hidden_dims = hidden_dims
|
62
|
-
self.num_basis = num_basis
|
63
|
-
self.degree = degree
|
64
66
|
self.dropout = dropout # Dropout probability for uncertainty quantification
|
65
67
|
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # Auto device chooser
|
66
68
|
self.model = None
|
67
69
|
self._is_fitted = False
|
68
|
-
self.__name = "OIKAN v0.0.2"
|
70
|
+
self.__name = "OIKAN v0.0.2" # Manual configured version
|
69
71
|
self.loss_history = [] # <-- new attribute to store loss values
|
70
72
|
|
71
73
|
def _build_network(self, input_dim, output_dim):
|
@@ -73,7 +75,9 @@ class BaseOIKAN(BaseEstimator):
|
|
73
75
|
prev_dim = input_dim
|
74
76
|
for hidden_dim in self.hidden_dims:
|
75
77
|
layers.append(KANLayer(prev_dim, hidden_dim))
|
76
|
-
layers.append(nn.
|
78
|
+
layers.append(nn.BatchNorm1d(hidden_dim)) # Added batch normalization
|
79
|
+
layers.append(nn.ReLU()) # Added activation function
|
80
|
+
layers.append(nn.Dropout(self.dropout)) # Apply dropout for uncertainty quantification
|
77
81
|
prev_dim = hidden_dim
|
78
82
|
layers.append(KANLayer(prev_dim, output_dim))
|
79
83
|
return nn.Sequential(*layers).to(self.device)
|
@@ -85,6 +89,25 @@ class BaseOIKAN(BaseEstimator):
|
|
85
89
|
y = torch.FloatTensor(y)
|
86
90
|
return X.to(self.device), (y.to(self.device) if y is not None else None)
|
87
91
|
|
92
|
+
def _process_edge_formula(self, edge_formula, weight):
|
93
|
+
"""Helper to scale symbolic formula terms by a given weight"""
|
94
|
+
terms = []
|
95
|
+
for term in edge_formula.split(" + "):
|
96
|
+
if term and term != "0":
|
97
|
+
if "*" in term:
|
98
|
+
coef_str, rest = term.split("*", 1)
|
99
|
+
try:
|
100
|
+
coef = float(coef_str)
|
101
|
+
terms.append(f"{(coef * weight):.4f}*{rest}")
|
102
|
+
except Exception:
|
103
|
+
terms.append(term) # fallback
|
104
|
+
else:
|
105
|
+
try:
|
106
|
+
terms.append(f"{(float(term) * weight):.4f}")
|
107
|
+
except Exception:
|
108
|
+
terms.append(term)
|
109
|
+
return " + ".join(terms) if terms else "0"
|
110
|
+
|
88
111
|
def get_symbolic_formula(self):
|
89
112
|
"""Generate and cache symbolic formulas for production‐ready inference."""
|
90
113
|
if not self._is_fitted:
|
@@ -100,17 +123,9 @@ class BaseOIKAN(BaseEstimator):
|
|
100
123
|
for j in range(n_classes):
|
101
124
|
weight = first_layer.combination_weights[i, j].item()
|
102
125
|
if abs(weight) > 1e-4:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if term and term != "0":
|
107
|
-
if "*" in term:
|
108
|
-
coef, rest = term.split("*", 1)
|
109
|
-
coef = float(coef) * weight
|
110
|
-
terms.append(f"{coef:.4f}*{rest}")
|
111
|
-
else:
|
112
|
-
terms.append(f"{float(term)*weight:.4f}")
|
113
|
-
formulas[i][j] = " + ".join(terms) if terms else "0"
|
126
|
+
# Use improved threshold for formula extraction
|
127
|
+
edge_formula = first_layer.edges[i][j].get_symbolic_repr(threshold=1e-6)
|
128
|
+
formulas[i][j] = self._process_edge_formula(edge_formula, weight)
|
114
129
|
else:
|
115
130
|
formulas[i][j] = "0"
|
116
131
|
self.symbolic_formula = formulas
|
@@ -119,8 +134,9 @@ class BaseOIKAN(BaseEstimator):
|
|
119
134
|
formulas = []
|
120
135
|
first_layer = self.model[0]
|
121
136
|
for i in range(first_layer.input_dim):
|
122
|
-
formula
|
123
|
-
|
137
|
+
# Use improved threshold for formula extraction in regressor branch
|
138
|
+
edge_formula = first_layer.edges[i][0].get_symbolic_repr(threshold=1e-6)
|
139
|
+
formulas.append(self._process_edge_formula(edge_formula, 1.0))
|
124
140
|
self.symbolic_formula = formulas
|
125
141
|
return formulas
|
126
142
|
|
@@ -131,7 +147,7 @@ class BaseOIKAN(BaseEstimator):
|
|
131
147
|
- A header with the version and timestamp
|
132
148
|
- The symbolic formulas for each feature (and class for classification)
|
133
149
|
- A general formula, including softmax for classification
|
134
|
-
- Recommendations
|
150
|
+
- Recommendations and performance results.
|
135
151
|
"""
|
136
152
|
header = f"Generated by {self.__name} | Timestamp: {dt.now()}\n\n"
|
137
153
|
header += "Symbolic Formulas:\n"
|
@@ -157,8 +173,14 @@ class BaseOIKAN(BaseEstimator):
|
|
157
173
|
recs = ("\nRecommendations:\n"
|
158
174
|
"• Consider the symbolic formula for lightweight and interpretable inference.\n"
|
159
175
|
"• Validate approximation accuracy against the neural model.\n")
|
176
|
+
|
177
|
+
# Disclaimer regarding experimental usage
|
178
|
+
disclaimer = ("\nDisclaimer:\n"
|
179
|
+
"This experimental model is intended for research purposes only and is not production-ready. "
|
180
|
+
"Feel free to fork and build your own project based on this research: "
|
181
|
+
"https://github.com/silvermete0r/oikan\n")
|
160
182
|
|
161
|
-
output = header + formulas_text + general + recs
|
183
|
+
output = header + formulas_text + general + recs + disclaimer
|
162
184
|
with open(filename, "w") as f:
|
163
185
|
f.write(output)
|
164
186
|
print(f"Symbolic formulas saved to {filename}")
|
@@ -263,7 +285,7 @@ class BaseOIKAN(BaseEstimator):
|
|
263
285
|
|
264
286
|
class OIKANRegressor(BaseOIKAN, RegressorMixin):
|
265
287
|
"""OIKAN implementation for regression tasks"""
|
266
|
-
def fit(self, X, y, epochs=100, lr=0.01,
|
288
|
+
def fit(self, X, y, epochs=100, lr=0.01, verbose=True):
|
267
289
|
X, y = self._validate_data(X, y)
|
268
290
|
if len(y.shape) == 1:
|
269
291
|
y = y.reshape(-1, 1)
|
@@ -284,7 +306,7 @@ class OIKANRegressor(BaseOIKAN, RegressorMixin):
|
|
284
306
|
if torch.isnan(loss):
|
285
307
|
print("Warning: NaN loss detected, reinitializing model...")
|
286
308
|
self.model = None
|
287
|
-
return self.fit(X, y, epochs, lr/10,
|
309
|
+
return self.fit(X, y, epochs, lr/10, verbose)
|
288
310
|
|
289
311
|
loss.backward()
|
290
312
|
|
@@ -312,7 +334,7 @@ class OIKANRegressor(BaseOIKAN, RegressorMixin):
|
|
312
334
|
|
313
335
|
class OIKANClassifier(BaseOIKAN, ClassifierMixin):
|
314
336
|
"""OIKAN implementation for classification tasks"""
|
315
|
-
def fit(self, X, y, epochs=100, lr=0.01,
|
337
|
+
def fit(self, X, y, epochs=100, lr=0.01, verbose=True):
|
316
338
|
X, y = self._validate_data(X, y)
|
317
339
|
self.classes_ = torch.unique(y)
|
318
340
|
n_classes = len(self.classes_)
|
@@ -414,8 +436,8 @@ class OIKANClassifier(BaseOIKAN, ClassifierMixin):
|
|
414
436
|
weight = first_layer.combination_weights[i, j].item()
|
415
437
|
|
416
438
|
if abs(weight) > 1e-4:
|
417
|
-
#
|
418
|
-
edge_formula = edge.get_symbolic_repr()
|
439
|
+
# Improved precision by using a lower threshold
|
440
|
+
edge_formula = edge.get_symbolic_repr(threshold=1e-6)
|
419
441
|
terms = []
|
420
442
|
for term in edge_formula.split(" + "):
|
421
443
|
if term and term != "0":
|
@@ -3,17 +3,11 @@ import torch
|
|
3
3
|
import torch.nn as nn
|
4
4
|
import numpy as np
|
5
5
|
|
6
|
-
# Core basis functions with explicit variable notation
|
7
6
|
ADVANCED_LIB = {
|
8
7
|
'x': ('x', lambda x: x),
|
9
|
-
'x^2': ('x^2', lambda x:
|
10
|
-
'
|
11
|
-
'
|
12
|
-
'log': ('log(x)', lambda x: np.log(np.abs(x) + 1)),
|
13
|
-
'sqrt': ('sqrt(x)', lambda x: np.sqrt(np.abs(x))),
|
14
|
-
'tanh': ('tanh(x)', lambda x: np.tanh(x)),
|
15
|
-
'sin': ('sin(x)', lambda x: np.sin(np.clip(x, -10*np.pi, 10*np.pi))),
|
16
|
-
'abs': ('abs(x)', lambda x: np.abs(x))
|
8
|
+
'x^2': ('x^2', lambda x: x**2),
|
9
|
+
'sin': ('sin(x)', lambda x: np.sin(x)),
|
10
|
+
'tanh': ('tanh(x)', lambda x: np.tanh(x))
|
17
11
|
}
|
18
12
|
|
19
13
|
class EdgeActivation(nn.Module):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oikan
|
3
|
-
Version: 0.0.2.
|
3
|
+
Version: 0.0.2.4
|
4
4
|
Summary: OIKAN: Optimized Interpretable Kolmogorov-Arnold Networks
|
5
5
|
Author: Arman Zhalgasbayev
|
6
6
|
License: MIT
|
@@ -32,20 +32,39 @@ OIKAN (Optimized Interpretable Kolmogorov-Arnold Networks) is a neuro-symbolic M
|
|
32
32
|
[](https://github.com/silvermete0r/oikan/issues)
|
33
33
|
[](https://silvermete0r.github.io/oikan/)
|
34
34
|
|
35
|
+
> **Important Disclaimer**: OIKAN is an experimental research project. It is not intended for production use or real-world applications. This framework is designed for research purposes, experimentation, and academic exploration of neuro-symbolic machine learning concepts.
|
36
|
+
|
35
37
|
## Key Features
|
36
38
|
- 🧠 **Neuro-Symbolic ML**: Combines neural network learning with symbolic mathematics
|
37
39
|
- 📊 **Automatic Formula Extraction**: Generates human-readable mathematical expressions
|
38
40
|
- 🎯 **Scikit-learn Compatible**: Familiar `.fit()` and `.predict()` interface
|
39
|
-
-
|
41
|
+
- 🔬 **Research-Focused**: Designed for academic exploration and experimentation
|
40
42
|
- 📈 **Multi-Task**: Supports both regression and classification problems
|
41
43
|
|
42
44
|
## Scientific Foundation
|
43
45
|
|
44
|
-
OIKAN
|
46
|
+
OIKAN implements the Kolmogorov-Arnold Representation Theorem through a novel neural architecture:
|
47
|
+
|
48
|
+
1. **Theorem Background**: Any continuous multivariate function f(x1,...,xn) can be represented as:
|
49
|
+
```
|
50
|
+
f(x1,...,xn) = ∑(j=0 to 2n){ φj( ∑(i=1 to n) ψij(xi) ) }
|
51
|
+
```
|
52
|
+
where φj and ψij are continuous single-variable functions.
|
45
53
|
|
46
|
-
|
47
|
-
|
48
|
-
|
54
|
+
2. **Neural Implementation**:
|
55
|
+
```python
|
56
|
+
# Pseudo-implementation of KAN architecture
|
57
|
+
class KANLayer:
|
58
|
+
def __init__(self, input_dim, output_dim):
|
59
|
+
self.edges = [SymbolicEdge() for _ in range(input_dim * output_dim)]
|
60
|
+
self.weights = initialize_weights(input_dim, output_dim)
|
61
|
+
|
62
|
+
def forward(self, x):
|
63
|
+
# Transform each input through basis functions
|
64
|
+
edge_outputs = [edge(x_i) for x_i, edge in zip(x, self.edges)]
|
65
|
+
# Combine using learned weights
|
66
|
+
return combine_weighted_outputs(edge_outputs, self.weights)
|
67
|
+
```
|
49
68
|
|
50
69
|
## Quick Start
|
51
70
|
|
@@ -68,11 +87,8 @@ pip install -e . # Install in development mode
|
|
68
87
|
from oikan.model import OIKANRegressor
|
69
88
|
from sklearn.model_selection import train_test_split
|
70
89
|
|
71
|
-
# Initialize model
|
72
|
-
model = OIKANRegressor(
|
73
|
-
hidden_dims=[16, 8], # Network architecture
|
74
|
-
dropout=0.1 # Regularization
|
75
|
-
)
|
90
|
+
# Initialize model
|
91
|
+
model = OIKANRegressor()
|
76
92
|
|
77
93
|
# Fit model (sklearn-style)
|
78
94
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
@@ -84,7 +100,7 @@ y_pred = model.predict(X_test)
|
|
84
100
|
# The output file will contain:
|
85
101
|
# - Detailed symbolic formulas for each feature
|
86
102
|
# - Instructions for practical implementation
|
87
|
-
# - Recommendations for
|
103
|
+
# - Recommendations for testing and validation
|
88
104
|
model.save_symbolic_formula("regression_formula.txt")
|
89
105
|
```
|
90
106
|
|
@@ -96,7 +112,7 @@ model.save_symbolic_formula("regression_formula.txt")
|
|
96
112
|
from oikan.model import OIKANClassifier
|
97
113
|
|
98
114
|
# Similar sklearn-style interface for classification
|
99
|
-
model = OIKANClassifier(
|
115
|
+
model = OIKANClassifier()
|
100
116
|
model.fit(X_train, y_train, epochs=100, lr=0.01)
|
101
117
|
probas = model.predict_proba(X_test)
|
102
118
|
|
@@ -104,45 +120,41 @@ probas = model.predict_proba(X_test)
|
|
104
120
|
# The output file will contain:
|
105
121
|
# - Decision boundary formulas for each class
|
106
122
|
# - Softmax application instructions
|
107
|
-
# -
|
123
|
+
# - Recommendations for testing and validation
|
108
124
|
model.save_symbolic_formula("classification_formula.txt")
|
109
125
|
```
|
110
126
|
|
111
127
|
*Example of the saved symbolic formula instructions: [outputs/classification_symbolic_formula.txt](outputs/classification_symbolic_formula.txt)*
|
112
128
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
- Weight-based term pruning (threshold=1e-4)
|
143
|
-
- Automatic coefficient optimization
|
144
|
-
- Human-readable mathematical expressions
|
145
|
-
- Exportable to lightweight production code
|
129
|
+
|
130
|
+
### Key Design Principles
|
131
|
+
|
132
|
+
1. **Interpretability by Design**
|
133
|
+
```python
|
134
|
+
# Edge activation contains interpretable basis functions
|
135
|
+
ADVANCED_LIB = {
|
136
|
+
'x': (lambda x: x), # Linear
|
137
|
+
'x^2': (lambda x: x**2), # Quadratic
|
138
|
+
'sin(x)': np.sin, # Periodic
|
139
|
+
'tanh(x)': np.tanh # Bounded
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
2. **Automatic Simplification**
|
144
|
+
```python
|
145
|
+
def simplify_formula(terms, threshold=1e-4):
|
146
|
+
return [term for term in terms if abs(term.coefficient) > threshold]
|
147
|
+
```
|
148
|
+
|
149
|
+
3. **Research-Oriented Architecture**
|
150
|
+
```python
|
151
|
+
class SymbolicEdge:
|
152
|
+
def forward(self, x):
|
153
|
+
return sum(w * f(x) for w, f in zip(self.weights, self.basis_functions))
|
154
|
+
|
155
|
+
def get_formula(self):
|
156
|
+
return format_symbolic_terms(self.weights, self.basis_functions)
|
157
|
+
```
|
146
158
|
|
147
159
|
### Architecture Diagram
|
148
160
|
|
@@ -152,45 +164,26 @@ OIKAN implements a novel neuro-symbolic architecture based on Kolmogorov-Arnold
|
|
152
164
|
|
153
165
|
1. **Interpretability First**: All transformations maintain clear mathematical meaning
|
154
166
|
2. **Scikit-learn Compatibility**: Familiar `.fit()` and `.predict()` interface
|
155
|
-
3. **
|
167
|
+
3. **Symbolic Formula Exporting**: Export formulas as lightweight mathematical expressions
|
156
168
|
4. **Automatic Simplification**: Remove insignificant terms (|w| < 1e-4)
|
157
169
|
|
158
|
-
## Model Components
|
159
|
-
|
160
|
-
1. **Symbolic Edge Functions**
|
161
|
-
```python
|
162
|
-
class EdgeActivation(nn.Module):
|
163
|
-
"""Learnable edge activation with basis functions"""
|
164
|
-
def forward(self, x):
|
165
|
-
return sum(self.weights[i] * basis[i](x) for i in range(self.num_basis))
|
166
|
-
```
|
167
170
|
|
168
|
-
|
169
|
-
```python
|
170
|
-
class KANLayer(nn.Module):
|
171
|
-
"""Kolmogorov-Arnold Network layer"""
|
172
|
-
def forward(self, x):
|
173
|
-
edge_outputs = [self.edges[i](x[:,i]) for i in range(self.input_dim)]
|
174
|
-
return self.combine(edge_outputs)
|
175
|
-
```
|
171
|
+
### Key Model Components
|
176
172
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
terms = []
|
182
|
-
for i, edge in enumerate(self.edges):
|
183
|
-
if abs(self.weights[i]) > threshold:
|
184
|
-
terms.append(f"{self.weights[i]:.4f} * {edge.formula}")
|
185
|
-
return " + ".join(terms)
|
186
|
-
```
|
173
|
+
1. **EdgeActivation Layer**:
|
174
|
+
- Implements interpretable basis function transformations
|
175
|
+
- Automatically prunes insignificant terms
|
176
|
+
- Maintains mathematical transparency
|
187
177
|
|
188
|
-
|
178
|
+
2. **Formula Extraction**:
|
179
|
+
- Combines edge transformations with learned weights
|
180
|
+
- Applies symbolic simplification
|
181
|
+
- Generates human-readable expressions
|
189
182
|
|
190
|
-
|
191
|
-
-
|
192
|
-
-
|
193
|
-
-
|
183
|
+
3. **Training Process**:
|
184
|
+
- Gradient-based optimization of edge weights
|
185
|
+
- Automatic feature importance detection
|
186
|
+
- Complexity control through regularization
|
194
187
|
|
195
188
|
## Contributing
|
196
189
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|