kasn 0.1.0__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.
- kasn/__init__.py +49 -0
- kasn/_utils.py +55 -0
- kasn/base.py +595 -0
- kasn/classifier.py +130 -0
- kasn/datasets.py +141 -0
- kasn/losses.py +109 -0
- kasn/network.py +272 -0
- kasn/preprocessing.py +61 -0
- kasn/regressor.py +145 -0
- kasn/splines.py +99 -0
- kasn/theory.py +88 -0
- kasn/tuning.py +163 -0
- kasn-0.1.0.dist-info/METADATA +77 -0
- kasn-0.1.0.dist-info/RECORD +16 -0
- kasn-0.1.0.dist-info/WHEEL +4 -0
- kasn-0.1.0.dist-info/licenses/LICENSE +21 -0
kasn/__init__.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Kolmogorov-Arnold Sieve Networks (KASN).
|
|
2
|
+
|
|
3
|
+
Sieve extremum estimation with deep Kolmogorov-Arnold networks, learned
|
|
4
|
+
B-spline edges and Group Lasso regularisation.
|
|
5
|
+
|
|
6
|
+
KASNRegressor
|
|
7
|
+
Squared, Huber, quantile and Poisson criteria.
|
|
8
|
+
KASNClassifier
|
|
9
|
+
Binary logistic criterion.
|
|
10
|
+
tune_kasn
|
|
11
|
+
Prune-aware greedy hyperparameter search on a validation fold.
|
|
12
|
+
make_kasn_regression
|
|
13
|
+
Monte Carlo designs of Section 4.
|
|
14
|
+
load
|
|
15
|
+
Restore any estimator written by ``.save()``.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
from .base import _read_payload
|
|
21
|
+
from .classifier import KASNClassifier
|
|
22
|
+
from .datasets import make_kasn_regression, target_function
|
|
23
|
+
from .losses import make_loss
|
|
24
|
+
from .network import KASNLayer, KASNNetwork
|
|
25
|
+
from .preprocessing import EmpiricalCDFTransformer
|
|
26
|
+
from .regressor import KASNRegressor
|
|
27
|
+
from .splines import BSplineBasis
|
|
28
|
+
from .theory import architecture, check_conditions
|
|
29
|
+
from .tuning import TuningResult, tune_kasn
|
|
30
|
+
|
|
31
|
+
__version__ = "0.1.0"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load(path, device: Optional[str] = None):
|
|
35
|
+
"""Load a ``KASNRegressor`` or ``KASNClassifier`` written by ``.save()``."""
|
|
36
|
+
payload = _read_payload(path)
|
|
37
|
+
classes = {"KASNRegressor": KASNRegressor,
|
|
38
|
+
"KASNClassifier": KASNClassifier}
|
|
39
|
+
if payload["class"] not in classes:
|
|
40
|
+
raise ValueError(f"unknown estimator class {payload['class']!r}")
|
|
41
|
+
return classes[payload["class"]]._from_payload(payload, device)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"KASNRegressor", "KASNClassifier", "load", "tune_kasn", "TuningResult",
|
|
46
|
+
"make_kasn_regression", "target_function", "make_loss",
|
|
47
|
+
"EmpiricalCDFTransformer", "BSplineBasis", "KASNLayer", "KASNNetwork",
|
|
48
|
+
"architecture", "check_conditions", "__version__",
|
|
49
|
+
]
|
kasn/_utils.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Small internal helpers: devices, seeding and serialisation hygiene."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
from typing import Any, Iterator, Optional, Union
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def resolve_device(device: Union[str, torch.device, None]) -> torch.device:
|
|
13
|
+
"""``'auto'`` (or ``None``) picks CUDA when available, otherwise CPU."""
|
|
14
|
+
if device is None or device == "auto":
|
|
15
|
+
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
16
|
+
return torch.device(device)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@contextlib.contextmanager
|
|
20
|
+
def seeded(random_state: Optional[int],
|
|
21
|
+
device: torch.device) -> Iterator[None]:
|
|
22
|
+
"""Seed torch inside a forked RNG so the caller's global state is untouched.
|
|
23
|
+
|
|
24
|
+
Every candidate in a hyperparameter search therefore starts from the same
|
|
25
|
+
initialisation, and repeated fits do not consume each other's draws.
|
|
26
|
+
"""
|
|
27
|
+
if random_state is None:
|
|
28
|
+
yield
|
|
29
|
+
return
|
|
30
|
+
devices = []
|
|
31
|
+
if device.type == "cuda":
|
|
32
|
+
devices = [device.index if device.index is not None
|
|
33
|
+
else torch.cuda.current_device()]
|
|
34
|
+
with torch.random.fork_rng(devices=devices):
|
|
35
|
+
torch.manual_seed(int(random_state))
|
|
36
|
+
yield
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def plain(obj: Any) -> Any:
|
|
40
|
+
"""Recursively convert numpy scalars and arrays to built-in Python types.
|
|
41
|
+
|
|
42
|
+
``torch.load(weights_only=True)`` accepts only built-in containers and
|
|
43
|
+
tensors, so everything saved alongside the state dict passes through here.
|
|
44
|
+
"""
|
|
45
|
+
if isinstance(obj, dict):
|
|
46
|
+
return {str(k): plain(v) for k, v in obj.items()}
|
|
47
|
+
if isinstance(obj, (list, tuple)):
|
|
48
|
+
return type(obj)(plain(v) for v in obj)
|
|
49
|
+
if isinstance(obj, np.generic):
|
|
50
|
+
return obj.item()
|
|
51
|
+
if isinstance(obj, np.ndarray):
|
|
52
|
+
return obj.tolist()
|
|
53
|
+
if isinstance(obj, torch.device):
|
|
54
|
+
return str(obj)
|
|
55
|
+
return obj
|