silver-run 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.
@@ -0,0 +1,33 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2024-08-04
9
+
10
+ ### Added
11
+ - Initial release of silver-run
12
+ - Backend-neutral training lifecycle management
13
+ - Event logging and inspection for training runs
14
+ - Checkpoint management with pluggable storage backends
15
+ - Async/await support for modern Python training workflows
16
+ - In-memory checkpoint store for local development
17
+ - Full training state machine (created, running, paused, stopped, cancelled, completed, failed)
18
+ - Comprehensive test suite with async test coverage
19
+ - Support for Python 3.8-3.12
20
+
21
+ ### Features
22
+ - `TrainingRun` - Main class for managing training lifecycle
23
+ - `TrainingBackend` - Abstract interface for training implementations
24
+ - `CheckpointStore` - Pluggable checkpoint storage interface
25
+ - `MemoryCheckpointStore` - In-memory checkpoint implementation
26
+ - `TrainingContext` - Context object passed to training backends
27
+ - State management (start, pause, resume, stop, cancel, complete, fail)
28
+ - Event emission and logging with timestamps
29
+ - Checkpoint creation and retrieval
30
+ - Backend execution with automatic state management
31
+ - Pause/resume functionality for long-running training
32
+
33
+ ## [Unreleased]
@@ -0,0 +1,115 @@
1
+ # Contributing to silver-run
2
+
3
+ Thank you for your interest in contributing to silver-run! This document provides guidelines and instructions for contributing to the project.
4
+
5
+ ## Development Setup
6
+
7
+ ### Prerequisites
8
+ - Python 3.8 or higher
9
+ - Git
10
+ - Virtual environment (recommended)
11
+
12
+ ### Setting Up Development Environment
13
+
14
+ 1. **Clone the repository**
15
+ ```bash
16
+ git clone https://github.com/adfgdartec/silver-run.git
17
+ cd silver-run
18
+ ```
19
+
20
+ 2. **Create a virtual environment**
21
+ ```bash
22
+ python -m venv venv
23
+ source venv/bin/activate # On Windows: venv\Scripts\activate
24
+ ```
25
+
26
+ 3. **Install development dependencies**
27
+ ```bash
28
+ pip install -e ".[dev]"
29
+ ```
30
+
31
+ 4. **Run tests**
32
+ ```bash
33
+ pytest
34
+ ```
35
+
36
+ 5. **Run tests with coverage**
37
+ ```bash
38
+ pytest --cov=silver_run --cov-report=html
39
+ ```
40
+
41
+ ## Code Style
42
+
43
+ We use the following tools to maintain code quality:
44
+
45
+ - **flake8** for linting
46
+ - **mypy** for type checking
47
+ - **pytest** for testing
48
+
49
+ Run all quality checks:
50
+ ```bash
51
+ flake8 src/ tests/
52
+ mypy src/
53
+ pytest
54
+ ```
55
+
56
+ ## Making Changes
57
+
58
+ 1. **Create a branch**
59
+ ```bash
60
+ git checkout -b feature/your-feature-name
61
+ ```
62
+
63
+ 2. **Make your changes**
64
+ - Write clear, descriptive commit messages
65
+ - Add tests for new functionality
66
+ - Update documentation as needed
67
+
68
+ 3. **Run tests**
69
+ ```bash
70
+ pytest
71
+ ```
72
+
73
+ 4. **Submit a pull request**
74
+ - Describe your changes clearly
75
+ - Reference any related issues
76
+ - Ensure all tests pass
77
+
78
+ ## Testing
79
+
80
+ We aim for high test coverage. When adding new features:
81
+
82
+ - Write unit tests for new functions
83
+ - Test async functions properly
84
+ - Test edge cases and error conditions
85
+ - Ensure existing tests still pass
86
+
87
+ ### Test Structure
88
+ ```
89
+ tests/
90
+ ├── __init__.py
91
+ └── test_run.py
92
+ ```
93
+
94
+ ## Documentation
95
+
96
+ - Update docstrings for any modified functions
97
+ - Add examples for new features
98
+ - Update README.md if user-facing changes are made
99
+
100
+ ## Release Process
101
+
102
+ Releases are managed by maintainers:
103
+
104
+ 1. Update version in `pyproject.toml`
105
+ 2. Update `CHANGELOG.md`
106
+ 3. Create a GitHub release
107
+ 4. Package will be automatically published to PyPI
108
+
109
+ ## Questions?
110
+
111
+ Feel free to open an issue for questions or discussions about contributions.
112
+
113
+ ## License
114
+
115
+ By contributing, you agree that your contributions will be licensed under the Apache-2.0 License.
@@ -0,0 +1,12 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+
4
+ Copyright 2026 Silver Contributors
5
+
6
+ Licensed under the Apache License, Version 2.0. You may obtain a copy of the
7
+ License at https://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software distributed
10
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
12
+ specific language governing permissions and limitations under the License.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include CONTRIBUTING.md
5
+ recursive-include src *.py
6
+ recursive-include tests *.py
@@ -0,0 +1,319 @@
1
+ Metadata-Version: 2.4
2
+ Name: silver-run
3
+ Version: 0.1.0
4
+ Summary: Backend-neutral ML run lifecycle, events, and checkpoints for Silver.
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/adfgdartec/silver-run
7
+ Project-URL: Repository, https://github.com/adfgdartec/silver-run
8
+ Project-URL: Issues, https://github.com/adfgdartec/silver-run/issues
9
+ Keywords: machine-learning,training,checkpoint,experiments,python
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
25
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
27
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
28
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
29
+ Requires-Dist: build>=0.10.0; extra == "dev"
30
+ Requires-Dist: twine>=4.0.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # silver-run
34
+
35
+ [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
36
+ [![License](https://img.shields.io/badge/license-Apache%202.0-green.svg)](LICENSE)
37
+ [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](tests/)
38
+ [![Code Style](https://img.shields.io/badge/code%20style-flake8-blue.svg)](https://flake8.pycqa.org/)
39
+
40
+ Backend-neutral ML run lifecycle, events, and checkpoints for Silver. A Python package designed for ML researchers who need flexible training orchestration across different frameworks.
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install silver-run
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ```python
51
+ from silver_run import TrainingRun, TrainingBackend, TrainingContext
52
+ import asyncio
53
+
54
+ class MyBackend(TrainingBackend):
55
+ async def run(self, context: TrainingContext):
56
+ for epoch in range(10):
57
+ if context.should_stop():
58
+ break
59
+ # Your training logic here
60
+ context.emit({
61
+ "kind": "epoch",
62
+ "epoch": epoch,
63
+ "metrics": {"loss": 0.5 - epoch * 0.05}
64
+ })
65
+ await asyncio.sleep(0.1)
66
+
67
+ async def main():
68
+ run = TrainingRun()
69
+ backend = MyBackend()
70
+ final_state = await run.execute(backend)
71
+ print(f"Run finished with state: {final_state.value}")
72
+
73
+ asyncio.run(main())
74
+ ```
75
+
76
+ ## Features
77
+
78
+ - **Training Lifecycle Management**: Full state machine (created, running, paused, stopped, cancelled, completed, failed)
79
+ - **Event Logging**: Comprehensive event tracking with timestamps for training observability
80
+ - **Checkpoint Management**: Pluggable storage backends for model checkpointing
81
+ - **Backend-Agnostic**: Works with PyTorch, TensorFlow, JAX, or any custom training framework
82
+ - **Async/Await Support**: Modern Python async patterns for concurrent training
83
+ - **Pause/Resume**: Control long-running training jobs with pause and resume functionality
84
+ - **Type Safety**: Full type hints for better IDE support and fewer bugs
85
+
86
+ ## Use Cases
87
+
88
+ ### PyTorch Training Integration
89
+
90
+ ```python
91
+ from silver_run import TrainingRun, TrainingBackend, TrainingContext
92
+ import torch
93
+ import asyncio
94
+
95
+ class PyTorchBackend(TrainingBackend):
96
+ def __init__(self, model, optimizer, train_loader):
97
+ self.model = model
98
+ self.optimizer = optimizer
99
+ self.train_loader = train_loader
100
+
101
+ async def run(self, context: TrainingContext):
102
+ for epoch in range(10):
103
+ if context.should_stop():
104
+ break
105
+
106
+ self.model.train()
107
+ total_loss = 0
108
+
109
+ for batch_idx, (data, target) in enumerate(self.train_loader):
110
+ self.optimizer.zero_grad()
111
+ output = self.model(data)
112
+ loss = torch.nn.functional.cross_entropy(output, target)
113
+ loss.backward()
114
+ self.optimizer.step()
115
+ total_loss += loss.item()
116
+
117
+ # Emit epoch completion event
118
+ context.emit({
119
+ "kind": "epoch",
120
+ "epoch": epoch,
121
+ "metrics": {"loss": total_loss / len(self.train_loader)}
122
+ })
123
+
124
+ # Checkpoint every 5 epochs
125
+ if epoch % 5 == 0:
126
+ await context.checkpoint({
127
+ "epoch": epoch,
128
+ "model_state_dict": self.model.state_dict(),
129
+ "optimizer_state_dict": self.optimizer.state_dict()
130
+ })
131
+
132
+ async def main():
133
+ model = torch.nn.Linear(10, 2)
134
+ optimizer = torch.optim.Adam(model.parameters())
135
+ train_loader = [...] # Your data loader
136
+
137
+ run = TrainingRun()
138
+ backend = PyTorchBackend(model, optimizer, train_loader)
139
+ final_state = await run.execute(backend)
140
+
141
+ # Review events
142
+ for event in run.events():
143
+ print(f"{event.kind}: {event.data}")
144
+
145
+ asyncio.run(main())
146
+ ```
147
+
148
+ ### Training with Pause/Resume
149
+
150
+ ```python
151
+ from silver_run import TrainingRun, TrainingBackend
152
+ import asyncio
153
+
154
+ class LongRunningBackend(TrainingBackend):
155
+ async def run(self, context: TrainingContext):
156
+ for step in range(1000):
157
+ if context.should_stop():
158
+ break
159
+
160
+ # Simulate training step
161
+ await asyncio.sleep(0.01)
162
+
163
+ # Emit progress
164
+ if step % 100 == 0:
165
+ context.emit({
166
+ "kind": "progress",
167
+ "step": step,
168
+ "total": 1000
169
+ })
170
+
171
+ async def main():
172
+ run = TrainingRun()
173
+ backend = LongRunningBackend()
174
+
175
+ # Start training in background
176
+ training_task = asyncio.create_task(run.execute(backend))
177
+
178
+ # Pause after some time
179
+ await asyncio.sleep(0.5)
180
+ run.pause()
181
+ print("Training paused")
182
+
183
+ # Resume after some time
184
+ await asyncio.sleep(0.5)
185
+ run.resume()
186
+ print("Training resumed")
187
+
188
+ # Wait for completion
189
+ final_state = await training_task
190
+ print(f"Training finished: {final_state.value}")
191
+
192
+ asyncio.run(main())
193
+ ```
194
+
195
+ ### Custom Checkpoint Storage
196
+
197
+ ```python
198
+ from silver_run import TrainingRun, CheckpointStore, Checkpoint
199
+ import asyncio
200
+
201
+ class S3CheckpointStore(CheckpointStore):
202
+ def __init__(self, bucket, prefix):
203
+ self.bucket = bucket
204
+ self.prefix = prefix
205
+ self.checkpoints = {}
206
+
207
+ async def save(self, checkpoint: Checkpoint):
208
+ # Save to S3
209
+ key = f"{self.prefix}/{checkpoint.id}"
210
+ print(f"Saving checkpoint to S3: {key}")
211
+ self.checkpoints[checkpoint.id] = checkpoint
212
+
213
+ async def latest(self):
214
+ if not self.checkpoints:
215
+ return None
216
+ return list(self.checkpoints.values())[-1]
217
+
218
+ async def get(self, id: str):
219
+ return self.checkpoints.get(id)
220
+
221
+ async def main():
222
+ store = S3CheckpointStore("my-bucket", "checkpoints")
223
+ run = TrainingRun(options=TrainingRunOptions(checkpoint_store=store))
224
+
225
+ # Use custom checkpoint store
226
+ await run.checkpoint({"model": "state"}, "checkpoint-1")
227
+ latest = await run.latest_checkpoint()
228
+ print(f"Latest checkpoint: {latest.id}")
229
+
230
+ asyncio.run(main())
231
+ ```
232
+
233
+ ## Advanced Usage
234
+
235
+ ### Event Filtering and Analysis
236
+
237
+ ```python
238
+ from silver_run import TrainingRun
239
+
240
+ # Filter events by type
241
+ def get_epoch_events(run):
242
+ return [e for e in run.events() if e.kind == "epoch"]
243
+
244
+ def get_error_events(run):
245
+ return [e for e in run.events() if e.kind == "error"]
246
+
247
+ # Analyze training progression
248
+ def analyze_training(run):
249
+ epoch_events = get_epoch_events(run)
250
+ losses = [e.data.get("metrics", {}).get("loss") for e in epoch_events]
251
+
252
+ if losses:
253
+ print(f"Initial loss: {losses[0]}")
254
+ print(f"Final loss: {losses[-1]}")
255
+ print(f"Loss reduction: {losses[0] - losses[-1]}")
256
+ ```
257
+
258
+ ### Multi-Run Experiments
259
+
260
+ ```python
261
+ from silver_run import TrainingRun
262
+ import asyncio
263
+
264
+ async def run_experiment(config):
265
+ run = TrainingRun()
266
+ backend = MyBackend(config)
267
+ return await run.execute(backend)
268
+
269
+ async def main():
270
+ configs = [
271
+ {"learning_rate": 0.001},
272
+ {"learning_rate": 0.01},
273
+ {"learning_rate": 0.1}
274
+ ]
275
+
276
+ results = await asyncio.gather(*[
277
+ run_experiment(config) for config in configs
278
+ ])
279
+
280
+ for config, result in zip(configs, results):
281
+ print(f"LR {config['learning_rate']}: {result.value}")
282
+
283
+ asyncio.run(main())
284
+ ```
285
+
286
+ ## Requirements
287
+
288
+ - Python 3.8+
289
+
290
+ ## Development
291
+
292
+ ```bash
293
+ # Install development dependencies
294
+ pip install -e ".[dev]"
295
+
296
+ # Run tests
297
+ pytest
298
+
299
+ # Run tests with coverage
300
+ pytest --cov=silver_run --cov-report=html
301
+
302
+ # Run linting
303
+ flake8 src/ tests/
304
+ mypy src/
305
+ ```
306
+
307
+ ## Contributing
308
+
309
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
310
+
311
+ ## License
312
+
313
+ Apache-2.0 - see [LICENSE](LICENSE) file for details.
314
+
315
+ ## Related Packages
316
+
317
+ - [silver-data](https://github.com/adfgdartec/silver-data) - Dataset handling
318
+ - [silver-diagnostics](https://github.com/adfgdartec/silver-diagnostics) - ML diagnostics
319
+ - [silver-adapters](https://github.com/adfgdartec/silver-adapters) - Framework adapters