easymodd 0.1.0__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.
- easymodd-0.1.0/LICENSE +21 -0
- easymodd-0.1.0/PKG-INFO +231 -0
- easymodd-0.1.0/README.md +193 -0
- easymodd-0.1.0/pyproject.toml +48 -0
- easymodd-0.1.0/setup.cfg +4 -0
- easymodd-0.1.0/src/easymodd/__init__.py +85 -0
- easymodd-0.1.0/src/easymodd/callbacks.py +40 -0
- easymodd-0.1.0/src/easymodd/checkpoints.py +59 -0
- easymodd-0.1.0/src/easymodd/cli.py +36 -0
- easymodd-0.1.0/src/easymodd/config.py +56 -0
- easymodd-0.1.0/src/easymodd/data.py +127 -0
- easymodd-0.1.0/src/easymodd/experiments.py +37 -0
- easymodd-0.1.0/src/easymodd/losses.py +57 -0
- easymodd-0.1.0/src/easymodd/metrics.py +18 -0
- easymodd-0.1.0/src/easymodd/models/__init__.py +7 -0
- easymodd-0.1.0/src/easymodd/models/mlp.py +24 -0
- easymodd-0.1.0/src/easymodd/models/text_transformer.py +29 -0
- easymodd-0.1.0/src/easymodd/models/vision_transformer.py +30 -0
- easymodd-0.1.0/src/easymodd/nn.py +165 -0
- easymodd-0.1.0/src/easymodd/optim.py +76 -0
- easymodd-0.1.0/src/easymodd/py.typed +0 -0
- easymodd-0.1.0/src/easymodd/registry.py +38 -0
- easymodd-0.1.0/src/easymodd/schedulers.py +37 -0
- easymodd-0.1.0/src/easymodd/secret_store.py +30 -0
- easymodd-0.1.0/src/easymodd/serialization.py +43 -0
- easymodd-0.1.0/src/easymodd/tensor.py +69 -0
- easymodd-0.1.0/src/easymodd/training.py +93 -0
- easymodd-0.1.0/src/easymodd/transforms.py +47 -0
- easymodd-0.1.0/src/easymodd/visualization.py +20 -0
- easymodd-0.1.0/src/easymodd.egg-info/PKG-INFO +231 -0
- easymodd-0.1.0/src/easymodd.egg-info/SOURCES.txt +33 -0
- easymodd-0.1.0/src/easymodd.egg-info/dependency_links.txt +1 -0
- easymodd-0.1.0/src/easymodd.egg-info/entry_points.txt +2 -0
- easymodd-0.1.0/src/easymodd.egg-info/requires.txt +14 -0
- easymodd-0.1.0/src/easymodd.egg-info/top_level.txt +1 -0
easymodd-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vnex Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
easymodd-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: easymodd
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A configurable, training-first numerical machine learning library
|
|
5
|
+
Author: Vnex Lab
|
|
6
|
+
Maintainer: Vnex Lab
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/vnex-lab/EasyMoDD
|
|
9
|
+
Project-URL: Repository, https://github.com/vnex-lab/EasyMoDD
|
|
10
|
+
Project-URL: Issues, https://github.com/vnex-lab/EasyMoDD/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/vnex-lab/EasyMoDD#readme
|
|
12
|
+
Project-URL: Support, https://ko-fi.com/vnexlab
|
|
13
|
+
Keywords: machine-learning,deep-learning,numpy,cuda,training,transformers
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy>=2.0
|
|
27
|
+
Provides-Extra: cuda
|
|
28
|
+
Requires-Dist: cupy-cuda12x>=13.6; extra == "cuda"
|
|
29
|
+
Provides-Extra: data
|
|
30
|
+
Requires-Dist: pandas>=2.0; extra == "data"
|
|
31
|
+
Requires-Dist: pyarrow>=15.0; extra == "data"
|
|
32
|
+
Requires-Dist: scikit-learn>=1.4; extra == "data"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
36
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# EasyMoDD
|
|
40
|
+
|
|
41
|
+
EasyMoDD is a configurable, training-first machine-learning library. It is
|
|
42
|
+
programmable from Python like a numerical library, with reusable tensors,
|
|
43
|
+
modules, datasets, losses, optimizers, trainers, model families, and checkpoint
|
|
44
|
+
policies.
|
|
45
|
+
|
|
46
|
+
Models initialize randomly unless a consuming project explicitly resumes from
|
|
47
|
+
its own checkpoint. EasyMoDD does not include a chatbot, web application,
|
|
48
|
+
built-in corpus, project `config.txt`, generated checkpoints, or demo data.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```powershell
|
|
53
|
+
python -m pip install easymodd
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
For a local checkout:
|
|
57
|
+
|
|
58
|
+
```powershell
|
|
59
|
+
python -m pip install -e .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Publish to PyPI
|
|
63
|
+
|
|
64
|
+
The package is configured for GitHub Actions Trusted Publishing. Before the
|
|
65
|
+
first release, create a PyPI project named `easymodd`, then add this trusted
|
|
66
|
+
publisher on PyPI:
|
|
67
|
+
|
|
68
|
+
- Owner: `vnex-lab`
|
|
69
|
+
- Repository: `EasyMoDD`
|
|
70
|
+
- Workflow: `publish.yml`
|
|
71
|
+
- Environment: `pypi`
|
|
72
|
+
|
|
73
|
+
After that one-time setup, publish a release from GitHub. The workflow builds
|
|
74
|
+
the wheel and source archive, validates both with Twine, and publishes them
|
|
75
|
+
without a stored PyPI token.
|
|
76
|
+
|
|
77
|
+
For a local dry run:
|
|
78
|
+
|
|
79
|
+
```powershell
|
|
80
|
+
python -m pip install --upgrade build twine
|
|
81
|
+
python -m build
|
|
82
|
+
python -m twine check dist/*
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The package version is controlled by `project.version` in `pyproject.toml`.
|
|
86
|
+
Increase it for every PyPI release, and do not reuse an already-uploaded
|
|
87
|
+
version.
|
|
88
|
+
|
|
89
|
+
Optional integrations:
|
|
90
|
+
|
|
91
|
+
```powershell
|
|
92
|
+
python -m pip install easymodd[cuda]
|
|
93
|
+
python -m pip install easymodd[data]
|
|
94
|
+
python -m pip install easymodd[dev]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Python API
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import numpy as np
|
|
101
|
+
from easymodd import ArrayDataset, MSELoss, SGD, Trainer, build_mlp
|
|
102
|
+
|
|
103
|
+
model = build_mlp(input_size=1, hidden_sizes=[8], output_size=1)
|
|
104
|
+
dataset = ArrayDataset(
|
|
105
|
+
np.array([[1.0], [2.0], [3.0]], dtype=np.float32),
|
|
106
|
+
np.array([[2.0], [4.0], [6.0]], dtype=np.float32),
|
|
107
|
+
)
|
|
108
|
+
history = Trainer(
|
|
109
|
+
SGD(model.parameters(), learning_rate=0.01),
|
|
110
|
+
MSELoss(),
|
|
111
|
+
max_steps=100,
|
|
112
|
+
).fit(model, dataset)
|
|
113
|
+
print(history.values["loss"][-1])
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The programmable foundation includes:
|
|
117
|
+
|
|
118
|
+
- NumPy and explicit CUDA backend helpers
|
|
119
|
+
- `Module`, `Parameter`, `Linear`, `ReLU`, and `Sequential`
|
|
120
|
+
- GELU, sigmoid, tanh, and dropout layers
|
|
121
|
+
- MLP model factory
|
|
122
|
+
- Model registries for custom factories
|
|
123
|
+
- `ArrayDataset` and packed `TextDataset`
|
|
124
|
+
- `BatchLoader`, deterministic splits, and `Subset`
|
|
125
|
+
- Composable transforms and batch collation
|
|
126
|
+
- MSE and cross-entropy loss contracts
|
|
127
|
+
- L1 and Huber losses
|
|
128
|
+
- SGD, Adam, and AdamW optimizers
|
|
129
|
+
- Cosine and warmup learning-rate schedulers
|
|
130
|
+
- Reusable `Trainer` and `TrainingHistory`
|
|
131
|
+
- Accuracy, MAE, and perplexity metrics
|
|
132
|
+
- JSONL metrics logging and early stopping callbacks
|
|
133
|
+
- Local experiment tracking and dependency-free summaries
|
|
134
|
+
- Versioned model/optimizer/scheduler serialization
|
|
135
|
+
- Environment-only secrets for optional integrations
|
|
136
|
+
- Config loading and validation for consuming projects
|
|
137
|
+
- Checkpoint enable/disable, retention, and compression policy
|
|
138
|
+
- Separate text Transformer and Vision Transformer configuration modules
|
|
139
|
+
|
|
140
|
+
The restored prototype scripts remain available as compatibility programs for
|
|
141
|
+
existing custom checkpoints. New projects should import EasyMoDD directly.
|
|
142
|
+
|
|
143
|
+
## Consumer Project Configuration
|
|
144
|
+
|
|
145
|
+
EasyMoDD does not force users into one project layout. A consuming project can
|
|
146
|
+
create its own `config.txt` using TOML syntax and load it with:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from easymodd import load_config
|
|
150
|
+
config = load_config("config.txt")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The config loader supports project-defined paths for datasets, runs, models,
|
|
154
|
+
logs, and checkpoints. The library never assumes a filename such as
|
|
155
|
+
`best.bin`.
|
|
156
|
+
|
|
157
|
+
A consumer project can configure checkpoint behavior like this:
|
|
158
|
+
|
|
159
|
+
```toml
|
|
160
|
+
[checkpoints]
|
|
161
|
+
enabled = true
|
|
162
|
+
keep_recent = 2
|
|
163
|
+
compress_old = true
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
When disabled, `CheckpointManager` creates no directory or files. When enabled,
|
|
167
|
+
older numbered checkpoints can be compressed while recent checkpoints remain
|
|
168
|
+
available.
|
|
169
|
+
|
|
170
|
+
## Package Layout
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
src/easymodd/
|
|
174
|
+
models/
|
|
175
|
+
mlp.py
|
|
176
|
+
text_transformer.py
|
|
177
|
+
vision_transformer.py
|
|
178
|
+
data.py
|
|
179
|
+
losses.py
|
|
180
|
+
nn.py
|
|
181
|
+
tensor.py
|
|
182
|
+
optim.py
|
|
183
|
+
training.py
|
|
184
|
+
checkpoints.py
|
|
185
|
+
config.py
|
|
186
|
+
cli.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Each model family has its own module. The shared training contracts are designed
|
|
190
|
+
so new model types can be added without changing dataset or checkpoint code.
|
|
191
|
+
|
|
192
|
+
## Extending EasyMoDD
|
|
193
|
+
|
|
194
|
+
Register a custom model factory:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from easymodd import ModelRegistry
|
|
198
|
+
|
|
199
|
+
registry = ModelRegistry()
|
|
200
|
+
registry.register("my_model", lambda width=8: build_my_model(width))
|
|
201
|
+
model = registry.create("my_model", width=32)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Optional integrations can read environment variables without storing secrets:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from easymodd import SecretStore
|
|
208
|
+
|
|
209
|
+
secrets = SecretStore(prefix="MY_APP_")
|
|
210
|
+
token = secrets.get("TRACKING_TOKEN")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
EasyMoDD never writes API keys to configs, checkpoints, experiment files, or
|
|
214
|
+
logs. Provider-specific integrations can be built on top of this helper.
|
|
215
|
+
|
|
216
|
+
## Data and Training
|
|
217
|
+
|
|
218
|
+
The library does not ship a general-purpose training database. Users provide
|
|
219
|
+
legally obtained text, image, or tabular data in their own projects. EasyMoDD
|
|
220
|
+
provides dataset contracts and validation helpers; it does not pretend that a
|
|
221
|
+
small demo corpus can produce a general assistant.
|
|
222
|
+
|
|
223
|
+
## Development Status
|
|
224
|
+
|
|
225
|
+
The tensor/module API, programmable MLP training loop, dataset contracts,
|
|
226
|
+
checkpoint policy, model-family layout, and config loader are implemented.
|
|
227
|
+
Text Transformer training, Vision Transformer training, full resume manifests,
|
|
228
|
+
evaluation, schedulers, callbacks, and additional model families are active
|
|
229
|
+
parts of the public-library roadmap.
|
|
230
|
+
|
|
231
|
+
Support development on [Ko-fi](https://ko-fi.com/vnexlab).
|
easymodd-0.1.0/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# EasyMoDD
|
|
2
|
+
|
|
3
|
+
EasyMoDD is a configurable, training-first machine-learning library. It is
|
|
4
|
+
programmable from Python like a numerical library, with reusable tensors,
|
|
5
|
+
modules, datasets, losses, optimizers, trainers, model families, and checkpoint
|
|
6
|
+
policies.
|
|
7
|
+
|
|
8
|
+
Models initialize randomly unless a consuming project explicitly resumes from
|
|
9
|
+
its own checkpoint. EasyMoDD does not include a chatbot, web application,
|
|
10
|
+
built-in corpus, project `config.txt`, generated checkpoints, or demo data.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```powershell
|
|
15
|
+
python -m pip install easymodd
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For a local checkout:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
python -m pip install -e .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Publish to PyPI
|
|
25
|
+
|
|
26
|
+
The package is configured for GitHub Actions Trusted Publishing. Before the
|
|
27
|
+
first release, create a PyPI project named `easymodd`, then add this trusted
|
|
28
|
+
publisher on PyPI:
|
|
29
|
+
|
|
30
|
+
- Owner: `vnex-lab`
|
|
31
|
+
- Repository: `EasyMoDD`
|
|
32
|
+
- Workflow: `publish.yml`
|
|
33
|
+
- Environment: `pypi`
|
|
34
|
+
|
|
35
|
+
After that one-time setup, publish a release from GitHub. The workflow builds
|
|
36
|
+
the wheel and source archive, validates both with Twine, and publishes them
|
|
37
|
+
without a stored PyPI token.
|
|
38
|
+
|
|
39
|
+
For a local dry run:
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
python -m pip install --upgrade build twine
|
|
43
|
+
python -m build
|
|
44
|
+
python -m twine check dist/*
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The package version is controlled by `project.version` in `pyproject.toml`.
|
|
48
|
+
Increase it for every PyPI release, and do not reuse an already-uploaded
|
|
49
|
+
version.
|
|
50
|
+
|
|
51
|
+
Optional integrations:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
python -m pip install easymodd[cuda]
|
|
55
|
+
python -m pip install easymodd[data]
|
|
56
|
+
python -m pip install easymodd[dev]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Python API
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import numpy as np
|
|
63
|
+
from easymodd import ArrayDataset, MSELoss, SGD, Trainer, build_mlp
|
|
64
|
+
|
|
65
|
+
model = build_mlp(input_size=1, hidden_sizes=[8], output_size=1)
|
|
66
|
+
dataset = ArrayDataset(
|
|
67
|
+
np.array([[1.0], [2.0], [3.0]], dtype=np.float32),
|
|
68
|
+
np.array([[2.0], [4.0], [6.0]], dtype=np.float32),
|
|
69
|
+
)
|
|
70
|
+
history = Trainer(
|
|
71
|
+
SGD(model.parameters(), learning_rate=0.01),
|
|
72
|
+
MSELoss(),
|
|
73
|
+
max_steps=100,
|
|
74
|
+
).fit(model, dataset)
|
|
75
|
+
print(history.values["loss"][-1])
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The programmable foundation includes:
|
|
79
|
+
|
|
80
|
+
- NumPy and explicit CUDA backend helpers
|
|
81
|
+
- `Module`, `Parameter`, `Linear`, `ReLU`, and `Sequential`
|
|
82
|
+
- GELU, sigmoid, tanh, and dropout layers
|
|
83
|
+
- MLP model factory
|
|
84
|
+
- Model registries for custom factories
|
|
85
|
+
- `ArrayDataset` and packed `TextDataset`
|
|
86
|
+
- `BatchLoader`, deterministic splits, and `Subset`
|
|
87
|
+
- Composable transforms and batch collation
|
|
88
|
+
- MSE and cross-entropy loss contracts
|
|
89
|
+
- L1 and Huber losses
|
|
90
|
+
- SGD, Adam, and AdamW optimizers
|
|
91
|
+
- Cosine and warmup learning-rate schedulers
|
|
92
|
+
- Reusable `Trainer` and `TrainingHistory`
|
|
93
|
+
- Accuracy, MAE, and perplexity metrics
|
|
94
|
+
- JSONL metrics logging and early stopping callbacks
|
|
95
|
+
- Local experiment tracking and dependency-free summaries
|
|
96
|
+
- Versioned model/optimizer/scheduler serialization
|
|
97
|
+
- Environment-only secrets for optional integrations
|
|
98
|
+
- Config loading and validation for consuming projects
|
|
99
|
+
- Checkpoint enable/disable, retention, and compression policy
|
|
100
|
+
- Separate text Transformer and Vision Transformer configuration modules
|
|
101
|
+
|
|
102
|
+
The restored prototype scripts remain available as compatibility programs for
|
|
103
|
+
existing custom checkpoints. New projects should import EasyMoDD directly.
|
|
104
|
+
|
|
105
|
+
## Consumer Project Configuration
|
|
106
|
+
|
|
107
|
+
EasyMoDD does not force users into one project layout. A consuming project can
|
|
108
|
+
create its own `config.txt` using TOML syntax and load it with:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from easymodd import load_config
|
|
112
|
+
config = load_config("config.txt")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The config loader supports project-defined paths for datasets, runs, models,
|
|
116
|
+
logs, and checkpoints. The library never assumes a filename such as
|
|
117
|
+
`best.bin`.
|
|
118
|
+
|
|
119
|
+
A consumer project can configure checkpoint behavior like this:
|
|
120
|
+
|
|
121
|
+
```toml
|
|
122
|
+
[checkpoints]
|
|
123
|
+
enabled = true
|
|
124
|
+
keep_recent = 2
|
|
125
|
+
compress_old = true
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
When disabled, `CheckpointManager` creates no directory or files. When enabled,
|
|
129
|
+
older numbered checkpoints can be compressed while recent checkpoints remain
|
|
130
|
+
available.
|
|
131
|
+
|
|
132
|
+
## Package Layout
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
src/easymodd/
|
|
136
|
+
models/
|
|
137
|
+
mlp.py
|
|
138
|
+
text_transformer.py
|
|
139
|
+
vision_transformer.py
|
|
140
|
+
data.py
|
|
141
|
+
losses.py
|
|
142
|
+
nn.py
|
|
143
|
+
tensor.py
|
|
144
|
+
optim.py
|
|
145
|
+
training.py
|
|
146
|
+
checkpoints.py
|
|
147
|
+
config.py
|
|
148
|
+
cli.py
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each model family has its own module. The shared training contracts are designed
|
|
152
|
+
so new model types can be added without changing dataset or checkpoint code.
|
|
153
|
+
|
|
154
|
+
## Extending EasyMoDD
|
|
155
|
+
|
|
156
|
+
Register a custom model factory:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from easymodd import ModelRegistry
|
|
160
|
+
|
|
161
|
+
registry = ModelRegistry()
|
|
162
|
+
registry.register("my_model", lambda width=8: build_my_model(width))
|
|
163
|
+
model = registry.create("my_model", width=32)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Optional integrations can read environment variables without storing secrets:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from easymodd import SecretStore
|
|
170
|
+
|
|
171
|
+
secrets = SecretStore(prefix="MY_APP_")
|
|
172
|
+
token = secrets.get("TRACKING_TOKEN")
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
EasyMoDD never writes API keys to configs, checkpoints, experiment files, or
|
|
176
|
+
logs. Provider-specific integrations can be built on top of this helper.
|
|
177
|
+
|
|
178
|
+
## Data and Training
|
|
179
|
+
|
|
180
|
+
The library does not ship a general-purpose training database. Users provide
|
|
181
|
+
legally obtained text, image, or tabular data in their own projects. EasyMoDD
|
|
182
|
+
provides dataset contracts and validation helpers; it does not pretend that a
|
|
183
|
+
small demo corpus can produce a general assistant.
|
|
184
|
+
|
|
185
|
+
## Development Status
|
|
186
|
+
|
|
187
|
+
The tensor/module API, programmable MLP training loop, dataset contracts,
|
|
188
|
+
checkpoint policy, model-family layout, and config loader are implemented.
|
|
189
|
+
Text Transformer training, Vision Transformer training, full resume manifests,
|
|
190
|
+
evaluation, schedulers, callbacks, and additional model families are active
|
|
191
|
+
parts of the public-library roadmap.
|
|
192
|
+
|
|
193
|
+
Support development on [Ko-fi](https://ko-fi.com/vnexlab).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "easymodd"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A configurable, training-first numerical machine learning library"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Vnex Lab" }]
|
|
10
|
+
maintainers = [{ name = "Vnex Lab" }]
|
|
11
|
+
keywords = ["machine-learning", "deep-learning", "numpy", "cuda", "training", "transformers"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Programming Language :: Python :: 3.14",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
22
|
+
]
|
|
23
|
+
dependencies = ["numpy>=2.0"]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/vnex-lab/EasyMoDD"
|
|
27
|
+
Repository = "https://github.com/vnex-lab/EasyMoDD"
|
|
28
|
+
Issues = "https://github.com/vnex-lab/EasyMoDD/issues"
|
|
29
|
+
Documentation = "https://github.com/vnex-lab/EasyMoDD#readme"
|
|
30
|
+
Support = "https://ko-fi.com/vnexlab"
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
cuda = ["cupy-cuda12x>=13.6"]
|
|
34
|
+
data = ["pandas>=2.0", "pyarrow>=15.0", "scikit-learn>=1.4"]
|
|
35
|
+
dev = ["build>=1.2", "pytest>=8.0", "twine>=5.0"]
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
easymodd = "easymodd.cli:main"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["setuptools>=68"]
|
|
42
|
+
build-backend = "setuptools.build_meta"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.package-data]
|
|
48
|
+
easymodd = ["py.typed"]
|
easymodd-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""EasyMoDD: configurable, training-first numerical machine learning tools."""
|
|
2
|
+
|
|
3
|
+
from .config import EasyMoDDConfig, load_config
|
|
4
|
+
from .tensor import Device, array, backend_of, get_backend, matmul, ones, randn, seed, zeros
|
|
5
|
+
from .nn import Dropout, GELU, Linear, Module, Parameter, ReLU, Sequential, Sigmoid, Tanh
|
|
6
|
+
from .optim import Adam, AdamW, SGD
|
|
7
|
+
from .schedulers import CosineScheduler, WarmupScheduler
|
|
8
|
+
from .metrics import accuracy, mean_absolute_error, perplexity
|
|
9
|
+
from .callbacks import EarlyStopping, MetricsLogger
|
|
10
|
+
from .serialization import load_state, save_state
|
|
11
|
+
from .training import Trainer, TrainingHistory
|
|
12
|
+
from .data import ArrayDataset, BatchLoader, Dataset, Subset, TextDataset, collate_batch, split_dataset
|
|
13
|
+
from .losses import CrossEntropyLoss, HuberLoss, L1Loss, MSELoss
|
|
14
|
+
from .checkpoints import CheckpointManager
|
|
15
|
+
from .experiments import Experiment
|
|
16
|
+
from .registry import ModelRegistry, models
|
|
17
|
+
from .secret_store import SecretStore
|
|
18
|
+
from .transforms import Compose, Flatten, MapTransform, Normalize, Standardize, ToFloat32
|
|
19
|
+
from .visualization import summarize_history, summarize_model
|
|
20
|
+
from .models import MLP, TextTransformerConfig, VisionTransformerConfig, build_mlp
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Device",
|
|
24
|
+
"ArrayDataset",
|
|
25
|
+
"BatchLoader",
|
|
26
|
+
"Adam",
|
|
27
|
+
"AdamW",
|
|
28
|
+
"CheckpointManager",
|
|
29
|
+
"Compose",
|
|
30
|
+
"CrossEntropyLoss",
|
|
31
|
+
"CosineScheduler",
|
|
32
|
+
"Dataset",
|
|
33
|
+
"Dropout",
|
|
34
|
+
"EarlyStopping",
|
|
35
|
+
"EasyMoDDConfig",
|
|
36
|
+
"Experiment",
|
|
37
|
+
"Flatten",
|
|
38
|
+
"GELU",
|
|
39
|
+
"HuberLoss",
|
|
40
|
+
"L1Loss",
|
|
41
|
+
"Linear",
|
|
42
|
+
"MSELoss",
|
|
43
|
+
"MapTransform",
|
|
44
|
+
"ModelRegistry",
|
|
45
|
+
"Normalize",
|
|
46
|
+
"MetricsLogger",
|
|
47
|
+
"Module",
|
|
48
|
+
"Parameter",
|
|
49
|
+
"ReLU",
|
|
50
|
+
"Sequential",
|
|
51
|
+
"SGD",
|
|
52
|
+
"SecretStore",
|
|
53
|
+
"Sigmoid",
|
|
54
|
+
"Standardize",
|
|
55
|
+
"Tanh",
|
|
56
|
+
"ToFloat32",
|
|
57
|
+
"WarmupScheduler",
|
|
58
|
+
"Trainer",
|
|
59
|
+
"TrainingHistory",
|
|
60
|
+
"TextDataset",
|
|
61
|
+
"Subset",
|
|
62
|
+
"array",
|
|
63
|
+
"accuracy",
|
|
64
|
+
"backend_of",
|
|
65
|
+
"MLP",
|
|
66
|
+
"TextTransformerConfig",
|
|
67
|
+
"VisionTransformerConfig",
|
|
68
|
+
"build_mlp",
|
|
69
|
+
"get_backend",
|
|
70
|
+
"load_config",
|
|
71
|
+
"load_state",
|
|
72
|
+
"matmul",
|
|
73
|
+
"mean_absolute_error",
|
|
74
|
+
"perplexity",
|
|
75
|
+
"collate_batch",
|
|
76
|
+
"models",
|
|
77
|
+
"ones",
|
|
78
|
+
"randn",
|
|
79
|
+
"seed",
|
|
80
|
+
"save_state",
|
|
81
|
+
"zeros",
|
|
82
|
+
"split_dataset",
|
|
83
|
+
"summarize_history",
|
|
84
|
+
"summarize_model",
|
|
85
|
+
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Reusable training callbacks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MetricsLogger:
|
|
10
|
+
"""Append one JSON object per training event."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, path: str | Path):
|
|
13
|
+
self.path = Path(path)
|
|
14
|
+
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
15
|
+
|
|
16
|
+
def __call__(self, *, step: int, metrics: dict[str, float]) -> None:
|
|
17
|
+
with self.path.open("a", encoding="utf-8") as handle:
|
|
18
|
+
handle.write(json.dumps({"step": step, **metrics}) + "\n")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EarlyStopping:
|
|
22
|
+
def __init__(self, metric: str = "loss", patience: int = 10, minimum_delta: float = 0.0):
|
|
23
|
+
if patience < 1:
|
|
24
|
+
raise ValueError("patience must be at least 1")
|
|
25
|
+
self.metric = metric
|
|
26
|
+
self.patience = patience
|
|
27
|
+
self.minimum_delta = minimum_delta
|
|
28
|
+
self.best = float("inf")
|
|
29
|
+
self.bad_steps = 0
|
|
30
|
+
|
|
31
|
+
def __call__(self, *, step: int, metrics: dict[str, float]) -> bool:
|
|
32
|
+
value = metrics.get(self.metric)
|
|
33
|
+
if value is None:
|
|
34
|
+
return False
|
|
35
|
+
if value < self.best - self.minimum_delta:
|
|
36
|
+
self.best = value
|
|
37
|
+
self.bad_steps = 0
|
|
38
|
+
else:
|
|
39
|
+
self.bad_steps += 1
|
|
40
|
+
return self.bad_steps >= self.patience
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Config-controlled checkpoint management."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import zipfile
|
|
8
|
+
from .serialization import save_state
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CheckpointManager:
|
|
12
|
+
"""Checkpoint policy that creates no files when disabled."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, directory: str | Path, enabled: bool = True,
|
|
15
|
+
keep_recent: int = 2, compress_old: bool = True):
|
|
16
|
+
if keep_recent < 1:
|
|
17
|
+
raise ValueError("keep_recent must be at least 1")
|
|
18
|
+
self.directory = Path(directory)
|
|
19
|
+
self.enabled = bool(enabled)
|
|
20
|
+
self.keep_recent = keep_recent
|
|
21
|
+
self.compress_old = bool(compress_old)
|
|
22
|
+
|
|
23
|
+
def save(self, state: dict, step: int) -> Path | None:
|
|
24
|
+
if not self.enabled:
|
|
25
|
+
return None
|
|
26
|
+
self.directory.mkdir(parents=True, exist_ok=True)
|
|
27
|
+
path = self.directory / f"step_{step:07d}.json"
|
|
28
|
+
path.write_text(json.dumps(state, indent=2), encoding="utf-8")
|
|
29
|
+
self._compress_old()
|
|
30
|
+
return path
|
|
31
|
+
|
|
32
|
+
def save_training_state(self, step: int, *, model, optimizer=None,
|
|
33
|
+
scheduler=None, config=None, metrics=None) -> Path | None:
|
|
34
|
+
if not self.enabled:
|
|
35
|
+
return None
|
|
36
|
+
self.directory.mkdir(parents=True, exist_ok=True)
|
|
37
|
+
path = self.directory / f"step_{step:07d}.pkl"
|
|
38
|
+
save_state(path, model=model, optimizer=optimizer, scheduler=scheduler,
|
|
39
|
+
config=config, metrics=metrics)
|
|
40
|
+
self._compress_artifacts()
|
|
41
|
+
return path
|
|
42
|
+
|
|
43
|
+
def _compress_old(self) -> None:
|
|
44
|
+
files = sorted(self.directory.glob("step_*.json"), key=lambda item: item.stat().st_mtime)
|
|
45
|
+
for path in files[:-self.keep_recent]:
|
|
46
|
+
archive = path.with_suffix(".zip")
|
|
47
|
+
if self.compress_old and not archive.exists():
|
|
48
|
+
with zipfile.ZipFile(archive, "w", zipfile.ZIP_DEFLATED) as handle:
|
|
49
|
+
handle.write(path, arcname=path.name)
|
|
50
|
+
path.unlink()
|
|
51
|
+
|
|
52
|
+
def _compress_artifacts(self) -> None:
|
|
53
|
+
files = sorted(self.directory.glob("step_*.pkl"), key=lambda item: item.stat().st_mtime)
|
|
54
|
+
for path in files[:-self.keep_recent]:
|
|
55
|
+
archive = path.with_suffix(".zip")
|
|
56
|
+
if self.compress_old and not archive.exists():
|
|
57
|
+
with zipfile.ZipFile(archive, "w", zipfile.ZIP_DEFLATED) as handle:
|
|
58
|
+
handle.write(path, arcname=path.name)
|
|
59
|
+
path.unlink()
|