hydraflow 0.14.3__tar.gz → 0.15.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.
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.github/workflows/ci.yaml +2 -2
- {hydraflow-0.14.3 → hydraflow-0.15.0}/PKG-INFO +12 -10
- {hydraflow-0.14.3 → hydraflow-0.15.0}/README.md +6 -4
- hydraflow-0.15.0/docs/index.md +117 -0
- hydraflow-0.15.0/docs/usage/quickstart.md +330 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/mkdocs.yaml +8 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/pyproject.toml +8 -13
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/__init__.py +3 -13
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/core/context.py +12 -32
- hydraflow-0.15.0/src/hydraflow/core/io.py +150 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/core/main.py +3 -3
- hydraflow-0.15.0/src/hydraflow/core/run.py +341 -0
- hydraflow-0.15.0/src/hydraflow/core/run_collection.py +525 -0
- hydraflow-0.15.0/src/hydraflow/core/run_info.py +84 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/app.py +3 -3
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/test_run.py +13 -20
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/conftest.py +20 -4
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/context/chdir.py +1 -1
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/context/log_run.py +1 -1
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/context/start_run.py +2 -2
- hydraflow-0.15.0/tests/core/context/test_chdir.py +24 -0
- hydraflow-0.15.0/tests/core/context/test_log_run.py +45 -0
- hydraflow-0.15.0/tests/core/context/test_start_run.py +29 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/main/default.py +3 -3
- hydraflow-0.15.0/tests/core/main/test_default.py +60 -0
- hydraflow-0.15.0/tests/core/main/test_force_new_run.py +29 -0
- hydraflow-0.15.0/tests/core/main/test_main.py +13 -0
- hydraflow-0.15.0/tests/core/main/test_match_overrides.py +15 -0
- hydraflow-0.15.0/tests/core/main/test_rerun_finished.py +20 -0
- hydraflow-0.15.0/tests/core/main/test_skip_finished.py +71 -0
- hydraflow-0.15.0/tests/core/run/run.py +31 -0
- hydraflow-0.15.0/tests/core/run/test_run.py +251 -0
- hydraflow-0.15.0/tests/core/run/test_run_collection.py +290 -0
- hydraflow-0.15.0/tests/core/run/test_run_info.py +48 -0
- hydraflow-0.14.3/tests/core/io/test_iter_dirs.py → hydraflow-0.15.0/tests/core/test_io.py +37 -21
- hydraflow-0.14.3/docs/index.md +0 -10
- hydraflow-0.14.3/docs/usage/quickstart.md +0 -143
- hydraflow-0.14.3/src/hydraflow/core/config.py +0 -122
- hydraflow-0.14.3/src/hydraflow/core/io.py +0 -229
- hydraflow-0.14.3/src/hydraflow/core/mlflow.py +0 -174
- hydraflow-0.14.3/src/hydraflow/core/param.py +0 -165
- hydraflow-0.14.3/src/hydraflow/entities/run_collection.py +0 -583
- hydraflow-0.14.3/src/hydraflow/entities/run_data.py +0 -61
- hydraflow-0.14.3/src/hydraflow/entities/run_info.py +0 -36
- hydraflow-0.14.3/tests/core/config/test_config.py +0 -54
- hydraflow-0.14.3/tests/core/config/test_params.py +0 -176
- hydraflow-0.14.3/tests/core/context/test_chdir.py +0 -30
- hydraflow-0.14.3/tests/core/context/test_log_run.py +0 -58
- hydraflow-0.14.3/tests/core/context/test_start_run.py +0 -34
- hydraflow-0.14.3/tests/core/io/hydra_dir.py +0 -34
- hydraflow-0.14.3/tests/core/io/test_hydra_dir.py +0 -64
- hydraflow-0.14.3/tests/core/io/test_run.py +0 -51
- hydraflow-0.14.3/tests/core/main/__init__.py +0 -0
- hydraflow-0.14.3/tests/core/main/test_default.py +0 -63
- hydraflow-0.14.3/tests/core/main/test_force_new_run.py +0 -36
- hydraflow-0.14.3/tests/core/main/test_match_overrides.py +0 -31
- hydraflow-0.14.3/tests/core/main/test_rerun_finished.py +0 -27
- hydraflow-0.14.3/tests/core/main/test_skip_finished.py +0 -60
- hydraflow-0.14.3/tests/core/param/__init__.py +0 -0
- hydraflow-0.14.3/tests/core/param/params.py +0 -39
- hydraflow-0.14.3/tests/core/param/test_param.py +0 -158
- hydraflow-0.14.3/tests/core/param/test_params.py +0 -49
- hydraflow-0.14.3/tests/core/test_mlflow.py +0 -83
- hydraflow-0.14.3/tests/entities/__init__.py +0 -0
- hydraflow-0.14.3/tests/entities/filter.py +0 -35
- hydraflow-0.14.3/tests/entities/test_collection.py +0 -417
- hydraflow-0.14.3/tests/entities/test_data.py +0 -44
- hydraflow-0.14.3/tests/entities/test_filter.py +0 -44
- hydraflow-0.14.3/tests/entities/test_info.py +0 -47
- hydraflow-0.14.3/tests/entities/test_values.py +0 -37
- hydraflow-0.14.3/tests/entities/values.py +0 -34
- hydraflow-0.14.3/tests/executor/__init__.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.devcontainer/devcontainer.json +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.devcontainer/postCreate.sh +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.devcontainer/starship.toml +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.gitattributes +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.github/workflows/docs.yaml +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.github/workflows/publish.yaml +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/.gitignore +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/LICENSE +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/apps/quickstart.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/cli.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/core/__init__.py +0 -0
- {hydraflow-0.14.3/src/hydraflow/entities → hydraflow-0.15.0/src/hydraflow/executor}/__init__.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/executor/aio.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/executor/conf.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/executor/io.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/executor/job.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/executor/parser.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/src/hydraflow/py.typed +0 -0
- {hydraflow-0.14.3/src/hydraflow/executor → hydraflow-0.15.0/tests}/__init__.py +0 -0
- {hydraflow-0.14.3/tests → hydraflow-0.15.0/tests/cli}/__init__.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/conftest.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/hydraflow.yaml +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/submit.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/test_setup.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/test_show.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/cli/test_version.py +0 -0
- {hydraflow-0.14.3/tests/cli → hydraflow-0.15.0/tests/core}/__init__.py +0 -0
- {hydraflow-0.14.3/tests/core → hydraflow-0.15.0/tests/core/context}/__init__.py +0 -0
- {hydraflow-0.14.3/tests/core/config → hydraflow-0.15.0/tests/core/main}/__init__.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/main/force_new_run.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/main/match_overrides.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/main/rerun_finished.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/core/main/skip_finished.py +0 -0
- {hydraflow-0.14.3/tests/core/context → hydraflow-0.15.0/tests/core/run}/__init__.py +0 -0
- {hydraflow-0.14.3/tests/core/io → hydraflow-0.15.0/tests/executor}/__init__.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/conftest.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/echo.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/read.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_aio.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_args.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_conf.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_io.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_job.py +0 -0
- {hydraflow-0.14.3 → hydraflow-0.15.0}/tests/executor/test_parser.py +0 -0
@@ -21,7 +21,7 @@ jobs:
|
|
21
21
|
fail-fast: false
|
22
22
|
matrix:
|
23
23
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
24
|
-
python-version: ["3.
|
24
|
+
python-version: ["3.13"]
|
25
25
|
|
26
26
|
steps:
|
27
27
|
- uses: actions/checkout@v4
|
@@ -36,7 +36,7 @@ jobs:
|
|
36
36
|
- name: Ruff check
|
37
37
|
run: ruff check
|
38
38
|
- name: Run test
|
39
|
-
run: uv run pytest -v --junitxml=junit.xml
|
39
|
+
run: uv run pytest -v -n8 --junitxml=junit.xml
|
40
40
|
- name: Upload Codecov Results
|
41
41
|
if: success()
|
42
42
|
uses: codecov/codecov-action@v4
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.
|
4
|
-
Summary: HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management
|
3
|
+
Version: 0.15.0
|
4
|
+
Summary: HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management, combining Hydra's configuration management with MLflow's tracking capabilities.
|
5
5
|
Project-URL: Documentation, https://daizutabi.github.io/hydraflow/
|
6
6
|
Project-URL: Source, https://github.com/daizutabi/hydraflow
|
7
7
|
Project-URL: Issues, https://github.com/daizutabi/hydraflow/issues
|
@@ -36,40 +36,40 @@ Classifier: Intended Audience :: Science/Research
|
|
36
36
|
Classifier: License :: OSI Approved :: MIT License
|
37
37
|
Classifier: Operating System :: OS Independent
|
38
38
|
Classifier: Programming Language :: Python
|
39
|
-
Classifier: Programming Language :: Python :: 3.10
|
40
|
-
Classifier: Programming Language :: Python :: 3.11
|
41
|
-
Classifier: Programming Language :: Python :: 3.12
|
42
39
|
Classifier: Programming Language :: Python :: 3.13
|
43
40
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
44
41
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
45
|
-
Requires-Python: >=3.
|
42
|
+
Requires-Python: >=3.13
|
46
43
|
Requires-Dist: hydra-core>=1.3
|
44
|
+
Requires-Dist: joblib>=1.4.0
|
47
45
|
Requires-Dist: mlflow>=2.15
|
48
46
|
Requires-Dist: omegaconf>=2.3
|
47
|
+
Requires-Dist: polars>=1.26
|
49
48
|
Requires-Dist: python-ulid>=3.0.0
|
50
49
|
Requires-Dist: rich>=13.9
|
50
|
+
Requires-Dist: ruff>=0.11
|
51
51
|
Requires-Dist: typer>=0.15
|
52
52
|
Description-Content-Type: text/markdown
|
53
53
|
|
54
54
|
# Hydraflow
|
55
55
|
|
56
56
|
[![PyPI Version][pypi-v-image]][pypi-v-link]
|
57
|
-
[![Python Version][python-v-image]][python-v-link]
|
58
57
|
[![Build Status][GHAction-image]][GHAction-link]
|
59
58
|
[![Coverage Status][codecov-image]][codecov-link]
|
60
59
|
[![Documentation Status][docs-image]][docs-link]
|
60
|
+
[![Python Version][python-v-image]][python-v-link]
|
61
61
|
|
62
62
|
<!-- Badges -->
|
63
63
|
[pypi-v-image]: https://img.shields.io/pypi/v/hydraflow.svg
|
64
64
|
[pypi-v-link]: https://pypi.org/project/hydraflow/
|
65
|
-
[python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
|
66
|
-
[python-v-link]: https://pypi.org/project/hydraflow
|
67
65
|
[GHAction-image]: https://github.com/daizutabi/hydraflow/actions/workflows/ci.yaml/badge.svg?branch=main&event=push
|
68
66
|
[GHAction-link]: https://github.com/daizutabi/hydraflow/actions?query=event%3Apush+branch%3Amain
|
69
67
|
[codecov-image]: https://codecov.io/github/daizutabi/hydraflow/coverage.svg?branch=main
|
70
68
|
[codecov-link]: https://codecov.io/github/daizutabi/hydraflow?branch=main
|
71
|
-
[docs-image]: https://
|
69
|
+
[docs-image]: https://img.shields.io/badge/docs-latest-blue.svg
|
72
70
|
[docs-link]: https://daizutabi.github.io/hydraflow/
|
71
|
+
[python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
|
72
|
+
[python-v-link]: https://pypi.org/project/hydraflow
|
73
73
|
|
74
74
|
## Overview
|
75
75
|
|
@@ -101,6 +101,8 @@ You can install Hydraflow via pip:
|
|
101
101
|
pip install hydraflow
|
102
102
|
```
|
103
103
|
|
104
|
+
**Requirements:** Python 3.13+
|
105
|
+
|
104
106
|
## Quick Start
|
105
107
|
|
106
108
|
Here is a simple example to get you started with Hydraflow:
|
@@ -1,22 +1,22 @@
|
|
1
1
|
# Hydraflow
|
2
2
|
|
3
3
|
[![PyPI Version][pypi-v-image]][pypi-v-link]
|
4
|
-
[![Python Version][python-v-image]][python-v-link]
|
5
4
|
[![Build Status][GHAction-image]][GHAction-link]
|
6
5
|
[![Coverage Status][codecov-image]][codecov-link]
|
7
6
|
[![Documentation Status][docs-image]][docs-link]
|
7
|
+
[![Python Version][python-v-image]][python-v-link]
|
8
8
|
|
9
9
|
<!-- Badges -->
|
10
10
|
[pypi-v-image]: https://img.shields.io/pypi/v/hydraflow.svg
|
11
11
|
[pypi-v-link]: https://pypi.org/project/hydraflow/
|
12
|
-
[python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
|
13
|
-
[python-v-link]: https://pypi.org/project/hydraflow
|
14
12
|
[GHAction-image]: https://github.com/daizutabi/hydraflow/actions/workflows/ci.yaml/badge.svg?branch=main&event=push
|
15
13
|
[GHAction-link]: https://github.com/daizutabi/hydraflow/actions?query=event%3Apush+branch%3Amain
|
16
14
|
[codecov-image]: https://codecov.io/github/daizutabi/hydraflow/coverage.svg?branch=main
|
17
15
|
[codecov-link]: https://codecov.io/github/daizutabi/hydraflow?branch=main
|
18
|
-
[docs-image]: https://
|
16
|
+
[docs-image]: https://img.shields.io/badge/docs-latest-blue.svg
|
19
17
|
[docs-link]: https://daizutabi.github.io/hydraflow/
|
18
|
+
[python-v-image]: https://img.shields.io/pypi/pyversions/hydraflow.svg
|
19
|
+
[python-v-link]: https://pypi.org/project/hydraflow
|
20
20
|
|
21
21
|
## Overview
|
22
22
|
|
@@ -48,6 +48,8 @@ You can install Hydraflow via pip:
|
|
48
48
|
pip install hydraflow
|
49
49
|
```
|
50
50
|
|
51
|
+
**Requirements:** Python 3.13+
|
52
|
+
|
51
53
|
## Quick Start
|
52
54
|
|
53
55
|
Here is a simple example to get you started with Hydraflow:
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# HydraFlow: Seamless ML Experiment Management
|
2
|
+
|
3
|
+
<div class="grid cards" markdown>
|
4
|
+
|
5
|
+
- 🚀 **Streamlined Experimentation**
|
6
|
+
Create, run, and track ML experiments with minimal boilerplate
|
7
|
+
- ⚙️ **Hydra + MLflow Integration**
|
8
|
+
Combine powerful configuration management with robust experiment tracking
|
9
|
+
- 📈 **Rich Analysis Tools**
|
10
|
+
Filter, group, and visualize experiment results with intuitive APIs
|
11
|
+
- ⚡ **Performance Optimized**
|
12
|
+
Parallel processing support for handling thousands of experiments efficiently
|
13
|
+
|
14
|
+
</div>
|
15
|
+
|
16
|
+
## What is HydraFlow?
|
17
|
+
|
18
|
+
HydraFlow seamlessly integrates [Hydra](https://hydra.cc/) and
|
19
|
+
[MLflow](https://mlflow.org/) to create a powerful framework for machine
|
20
|
+
learning experimentation. It solves common challenges in ML research and
|
21
|
+
production workflows:
|
22
|
+
|
23
|
+
- **Configuration Management**: Type-safe, hierarchical, and dynamic
|
24
|
+
configuration
|
25
|
+
- **Experiment Tracking**: Automatically log parameters, metrics, and artifacts
|
26
|
+
- **Results Analysis**: Flexible tools to filter, compare, and visualize
|
27
|
+
experiment results
|
28
|
+
- **Reproducibility**: Ensure experiments can be reliably reproduced with
|
29
|
+
exact parameters
|
30
|
+
|
31
|
+
## Key Features
|
32
|
+
|
33
|
+
**At Development Time:**
|
34
|
+
- Type-safe configuration with IDE autocompletion
|
35
|
+
- Declarative experiment definition with dataclasses
|
36
|
+
- Seamless integration with existing ML pipelines
|
37
|
+
|
38
|
+
**During Execution:**
|
39
|
+
- Parameter sweeps with one command
|
40
|
+
- Automatic configuration logging
|
41
|
+
- De-duplication of identical experiments
|
42
|
+
|
43
|
+
**After Completion:**
|
44
|
+
- Powerful filtering and grouping of results
|
45
|
+
- Conversion to DataFrames for analysis
|
46
|
+
- Configuration-aware implementation loading
|
47
|
+
|
48
|
+
## Quick Installation
|
49
|
+
|
50
|
+
```bash
|
51
|
+
pip install hydraflow
|
52
|
+
```
|
53
|
+
|
54
|
+
**Requirements:** Python 3.13+
|
55
|
+
|
56
|
+
## Minimal Example
|
57
|
+
|
58
|
+
```python
|
59
|
+
from dataclasses import dataclass
|
60
|
+
import hydraflow
|
61
|
+
import mlflow
|
62
|
+
|
63
|
+
@dataclass
|
64
|
+
class Config:
|
65
|
+
learning_rate: float = 0.001
|
66
|
+
batch_size: int = 32
|
67
|
+
|
68
|
+
@hydraflow.main(Config)
|
69
|
+
def experiment(run, cfg):
|
70
|
+
# Your experiment code here
|
71
|
+
mlflow.log_metric("accuracy", 0.95)
|
72
|
+
|
73
|
+
if __name__ == "__main__":
|
74
|
+
experiment()
|
75
|
+
```
|
76
|
+
|
77
|
+
Run this with parameter variations in one command:
|
78
|
+
|
79
|
+
```bash
|
80
|
+
python experiment.py -m learning_rate=0.01,0.001,0.0001 batch_size=16,32,64
|
81
|
+
```
|
82
|
+
|
83
|
+
## Post-experiment Analysis
|
84
|
+
|
85
|
+
After running your experiments, analyze the results with HydraFlow's
|
86
|
+
powerful API:
|
87
|
+
|
88
|
+
```python
|
89
|
+
from hydraflow import Run, RunCollection
|
90
|
+
|
91
|
+
# Load all runs from the "experiment" experiment
|
92
|
+
runs = Run.load(hydraflow.iter_run_dirs("mlruns", "experiment"))
|
93
|
+
|
94
|
+
# Filter runs by configuration parameters
|
95
|
+
best_runs = runs.filter(learning_rate=0.001, batch_size=32)
|
96
|
+
|
97
|
+
# Convert to DataFrame for further analysis
|
98
|
+
df = runs.to_frame("learning_rate", "batch_size",
|
99
|
+
accuracy=lambda run: run.get("metrics.accuracy"))
|
100
|
+
```
|
101
|
+
|
102
|
+
<!--
|
103
|
+
## Explore HydraFlow
|
104
|
+
|
105
|
+
<div class="grid cards" markdown>
|
106
|
+
|
107
|
+
- 📖 [**Getting Started**](usage/quickstart.md)
|
108
|
+
Learn the basics of HydraFlow with a step-by-step guide
|
109
|
+
- 🧩 [**API Reference**](api/index.md)
|
110
|
+
Detailed documentation of HydraFlow's classes and functions
|
111
|
+
- 💻 [**CLI Tools**](cli/index.md)
|
112
|
+
Discover HydraFlow's command-line utilities
|
113
|
+
- 💡 [**Advanced Usage**](advanced/index.md)
|
114
|
+
Tips, tricks, and best practices for complex workflows
|
115
|
+
|
116
|
+
</div>
|
117
|
+
-->
|
@@ -0,0 +1,330 @@
|
|
1
|
+
# HydraFlow Quickstart Guide
|
2
|
+
|
3
|
+
HydraFlow seamlessly integrates MLflow (for experiment tracking)
|
4
|
+
with Hydra (for configuration management), creating a powerful
|
5
|
+
framework for machine learning experimentation.
|
6
|
+
This quickstart shows you how to get up and running with HydraFlow in minutes.
|
7
|
+
|
8
|
+
## Hydra application
|
9
|
+
|
10
|
+
The following example demonstrates how to use a Hydraflow application.
|
11
|
+
|
12
|
+
```python title="apps/quickstart.py" linenums="1"
|
13
|
+
--8<-- "apps/quickstart.py"
|
14
|
+
```
|
15
|
+
|
16
|
+
### Hydraflow's `main` decorator
|
17
|
+
|
18
|
+
[`hydraflow.main`][] starts a new MLflow run that logs the Hydra
|
19
|
+
configuration. The decorated function must have two arguments: `run` and
|
20
|
+
`cfg`. The `run` argument is the current MLflow run with type
|
21
|
+
`mlflow.entities.Run`. The `cfg` argument is the Hydra configuration
|
22
|
+
with type `omegaconf.DictConfig`. You can annotate the arguments with
|
23
|
+
`Run` and `Config` to get type checking and autocompletion in your IDE,
|
24
|
+
although the `cfg` argument is not actually an instance of `Config`
|
25
|
+
(duck typing is used).
|
26
|
+
|
27
|
+
```python
|
28
|
+
@hydraflow.main(Config)
|
29
|
+
def app(run: Run, cfg: Config) -> None:
|
30
|
+
pass
|
31
|
+
```
|
32
|
+
|
33
|
+
## Run the application
|
34
|
+
|
35
|
+
```bash exec="on"
|
36
|
+
rm -rf mlruns outputs multirun
|
37
|
+
```
|
38
|
+
|
39
|
+
### Single-run
|
40
|
+
|
41
|
+
Run the Hydraflow application as a normal Python script.
|
42
|
+
|
43
|
+
```console exec="1" source="console"
|
44
|
+
$ python apps/quickstart.py
|
45
|
+
```
|
46
|
+
|
47
|
+
Check the MLflow CLI to view the experiment.
|
48
|
+
|
49
|
+
```console exec="1" source="console"
|
50
|
+
$ mlflow experiments search
|
51
|
+
```
|
52
|
+
|
53
|
+
The experiment name comes from the name of the Hydra job.
|
54
|
+
|
55
|
+
### Multi-run
|
56
|
+
|
57
|
+
Run the Hydraflow application with multiple configurations.
|
58
|
+
|
59
|
+
```console exec="1" source="console"
|
60
|
+
$ python apps/quickstart.py -m width=400,600 height=100,200,300
|
61
|
+
```
|
62
|
+
|
63
|
+
## Use Hydraflow API
|
64
|
+
|
65
|
+
### Iterate over run's directory
|
66
|
+
|
67
|
+
The [`hydraflow.iter_run_dirs`][] function iterates over the run
|
68
|
+
directories. The first argument is the path to the MLflow tracking root
|
69
|
+
directory (in most cases, this is `"mlruns"`).
|
70
|
+
|
71
|
+
```pycon exec="1" source="console" session="quickstart"
|
72
|
+
>>> import hydraflow
|
73
|
+
>>> for run_dir in hydraflow.iter_run_dirs("mlruns"):
|
74
|
+
... print(run_dir)
|
75
|
+
```
|
76
|
+
|
77
|
+
Optionally, you can specify the experiment name(s) to filter the runs.
|
78
|
+
|
79
|
+
```python
|
80
|
+
>>> hydraflow.iter_run_dirs("mlruns", "quickstart")
|
81
|
+
>>> hydraflow.iter_run_dirs("mlruns", ["quickstart1", "quickstart2"])
|
82
|
+
```
|
83
|
+
|
84
|
+
### Load a run
|
85
|
+
|
86
|
+
[`Run`][hydraflow.core.run.Run] is a class that represents a *Hydraflow*
|
87
|
+
run, not an MLflow run. A `Run` instance is created by passing a
|
88
|
+
`pathlib.Path` instance that points to the run directory to the `Run`
|
89
|
+
constructor.
|
90
|
+
|
91
|
+
```pycon exec="1" source="console" session="quickstart"
|
92
|
+
>>> from hydraflow import Run
|
93
|
+
>>> run_dirs = hydraflow.iter_run_dirs("mlruns", "quickstart")
|
94
|
+
>>> run_dir = next(run_dirs) # run_dirs is an iterator
|
95
|
+
>>> run = Run(run_dir)
|
96
|
+
>>> print(run)
|
97
|
+
>>> print(type(run))
|
98
|
+
```
|
99
|
+
|
100
|
+
You can use the [`load`][hydraflow.core.run.Run.load] class method to
|
101
|
+
load a `Run` instance, which accepts a `str` as well as `pathlib.Path`.
|
102
|
+
|
103
|
+
```pycon exec="1" source="console" session="quickstart"
|
104
|
+
>>> Run.load(str(run_dir))
|
105
|
+
>>> print(run)
|
106
|
+
```
|
107
|
+
|
108
|
+
!!! note
|
109
|
+
The use case of `Run.load` is to load multiple `Run` instances
|
110
|
+
from run directories as described below.
|
111
|
+
|
112
|
+
|
113
|
+
The `Run` instance has an `info` attribute that contains information
|
114
|
+
about the run.
|
115
|
+
|
116
|
+
```pycon exec="1" source="console" session="quickstart"
|
117
|
+
>>> print(run.info.run_dir)
|
118
|
+
>>> print(run.info.run_id)
|
119
|
+
>>> print(run.info.job_name) # Hydra job name = MLflow experiment name
|
120
|
+
```
|
121
|
+
|
122
|
+
The `Run` instance has a `cfg` attribute that contains the Hydra
|
123
|
+
configuration.
|
124
|
+
|
125
|
+
```pycon exec="1" source="console" session="quickstart"
|
126
|
+
>>> print(run.cfg)
|
127
|
+
```
|
128
|
+
|
129
|
+
### Configuration type of the run
|
130
|
+
|
131
|
+
Optionally, you can specify the config type of the run using the
|
132
|
+
`Run[C]` class.
|
133
|
+
|
134
|
+
```pycon exec="1" source="console" session="quickstart"
|
135
|
+
>>> from dataclasses import dataclass
|
136
|
+
>>> @dataclass
|
137
|
+
... class Config:
|
138
|
+
... width: int = 1024
|
139
|
+
... height: int = 768
|
140
|
+
>>> run = Run[Config](run_dir)
|
141
|
+
>>> print(run)
|
142
|
+
>>> # autocompletion occurs below, for example, run.cfg.height
|
143
|
+
>>> # run.cfg.[TAB]
|
144
|
+
```
|
145
|
+
|
146
|
+
The `Run[C]` class is a generic class that takes a config type `C` as a
|
147
|
+
type parameter. The `run.cfg` attribute is recognized as `C` type in
|
148
|
+
IDEs, which provides autocompletion and type checking.
|
149
|
+
|
150
|
+
### Get a run's configuration
|
151
|
+
|
152
|
+
The `get` method can be used to get a run's configuration.
|
153
|
+
|
154
|
+
```pycon exec="1" source="console" session="quickstart"
|
155
|
+
>>> print(run.get("width"))
|
156
|
+
>>> print(run.get("height"))
|
157
|
+
```
|
158
|
+
|
159
|
+
### Implementation of the run
|
160
|
+
|
161
|
+
Optionally, you can specify the implementation of the run. Use the
|
162
|
+
`Run[C, I]` class to specify the implementation type. The second
|
163
|
+
argument `impl_factory` is the implementation factory, which can be a
|
164
|
+
class or a function to generate the implementation. The `impl_factory`
|
165
|
+
is called with the run's artifacts directory as the first and only
|
166
|
+
argument.
|
167
|
+
|
168
|
+
```pycon exec="1" source="console" session="quickstart"
|
169
|
+
>>> from pathlib import Path
|
170
|
+
>>> class Impl:
|
171
|
+
... root_dir: Path
|
172
|
+
... def __init__(self, root_dir: Path):
|
173
|
+
... self.root_dir = root_dir
|
174
|
+
... def __repr__(self) -> str:
|
175
|
+
... return f"Impl({self.root_dir.stem!r})"
|
176
|
+
>>> run = Run[Config, Impl](run_dir, Impl)
|
177
|
+
>>> print(run)
|
178
|
+
```
|
179
|
+
|
180
|
+
The representation of the `Run` instance includes the implementation
|
181
|
+
type as shown above.
|
182
|
+
|
183
|
+
If you specify the implementation type, the `run.impl` attribute is
|
184
|
+
lazily initialized at the first time of the `run.impl` attribute access.
|
185
|
+
The `run.impl` attribute is recognized as `I` type in IDEs, which
|
186
|
+
provides autocompletion and type checking.
|
187
|
+
|
188
|
+
```pycon exec="1" source="console" session="quickstart"
|
189
|
+
>>> print(run.impl)
|
190
|
+
>>> print(run.impl.root_dir)
|
191
|
+
>>> # autocompletion occurs below, for example, run.impl.root_dir
|
192
|
+
>>> # run.impl.[TAB]
|
193
|
+
```
|
194
|
+
|
195
|
+
The `impl_factory` can accept two arguments: the run's artifacts
|
196
|
+
directory and the run's configuration.
|
197
|
+
|
198
|
+
```pycon exec="1" source="console" session="quickstart"
|
199
|
+
>>> from dataclasses import dataclass, field
|
200
|
+
>>> @dataclass
|
201
|
+
>>> class Size:
|
202
|
+
... root_dir: Path = field(repr=False)
|
203
|
+
... cfg: Config
|
204
|
+
... size: int = field(init=False)
|
205
|
+
... def __post_init__(self):
|
206
|
+
... self.size = self.cfg.width * self.cfg.height
|
207
|
+
>>> run = Run[Config, Size].load(run_dir, Size)
|
208
|
+
>>> print(run)
|
209
|
+
>>> print(run.impl)
|
210
|
+
```
|
211
|
+
|
212
|
+
### Collect runs
|
213
|
+
|
214
|
+
You can collect multiple `Run` instances from run directories as a
|
215
|
+
collection of runs [`RunCollection`][hydraflow.RunCollection].
|
216
|
+
|
217
|
+
```pycon exec="1" source="console" session="quickstart"
|
218
|
+
>>> from hydraflow import RunCollection
|
219
|
+
>>> run_dirs = hydraflow.iter_run_dirs("mlruns", "quickstart")
|
220
|
+
>>> rc = Run[Config, Size].load(run_dirs, Size)
|
221
|
+
>>> print(rc)
|
222
|
+
```
|
223
|
+
|
224
|
+
In the above example, the `load` class method is called with an iterable
|
225
|
+
of run directories and the implementation type. The `load` class method
|
226
|
+
returns a `RunCollection` instance instead of a single `Run` instance.
|
227
|
+
The representation of the `RunCollection` instance includes the run
|
228
|
+
collection type and the number of runs in the collection.
|
229
|
+
|
230
|
+
### Handle a run collection
|
231
|
+
|
232
|
+
The `RunCollection` instance has a [`first`][hydraflow.RunCollection.first]
|
233
|
+
and [`last`][hydraflow.RunCollection.last] method that returns the first
|
234
|
+
and last run in the collection.
|
235
|
+
|
236
|
+
```pycon exec="1" source="console" session="quickstart"
|
237
|
+
>>> print(rc.first())
|
238
|
+
>>> print(rc.last())
|
239
|
+
```
|
240
|
+
|
241
|
+
The [`filter`][hydraflow.RunCollection.filter] method filters the runs
|
242
|
+
by the given key-value pairs.
|
243
|
+
|
244
|
+
```pycon exec="1" source="console" session="quickstart"
|
245
|
+
>>> print(rc.filter(width=400))
|
246
|
+
```
|
247
|
+
|
248
|
+
If the value is a list, the run will be included if the value is in the
|
249
|
+
list.
|
250
|
+
|
251
|
+
```pycon exec="1" source="console" session="quickstart"
|
252
|
+
>>> print(rc.filter(height=[100, 300]))
|
253
|
+
```
|
254
|
+
|
255
|
+
If the value is a tuple, the run will be included if the value is
|
256
|
+
between the tuple. The start and end of the tuple are inclusive.
|
257
|
+
|
258
|
+
```pycon exec="1" source="console" session="quickstart"
|
259
|
+
>>> print(rc.filter(height=(100, 300)))
|
260
|
+
```
|
261
|
+
|
262
|
+
The [`get`][hydraflow.RunCollection.get] method returns a single `Run`
|
263
|
+
instance with the given key-value pairs.
|
264
|
+
|
265
|
+
```pycon exec="1" source="console" session="quickstart"
|
266
|
+
>>> run = rc.get(width=(350, 450), height=(150, 250))
|
267
|
+
>>> print(run)
|
268
|
+
>>> print(run.impl)
|
269
|
+
```
|
270
|
+
|
271
|
+
The [`to_frame`][hydraflow.RunCollection.to_frame] method returns a
|
272
|
+
polars DataFrame of the run collection.
|
273
|
+
|
274
|
+
```pycon exec="1" source="console" session="quickstart"
|
275
|
+
>>> print(rc.to_frame("width", "height"))
|
276
|
+
```
|
277
|
+
|
278
|
+
The `to_frame` method can take keyword arguments to customize the
|
279
|
+
DataFrame. Each keyword argument is a callable that takes a `Run`
|
280
|
+
instance and returns a value.
|
281
|
+
|
282
|
+
```pycon exec="1" source="console" session="quickstart"
|
283
|
+
>>> print(rc.to_frame("width", size=lambda run: run.impl.size))
|
284
|
+
```
|
285
|
+
|
286
|
+
The callable can return a list.
|
287
|
+
|
288
|
+
```pycon exec="1" source="console" session="quickstart"
|
289
|
+
>>> def to_list(run: Run) -> list[int]:
|
290
|
+
... return [2 * run.get("width"), 3 * run.get("height")]
|
291
|
+
>>> print(rc.to_frame("width", from_list=to_list))
|
292
|
+
```
|
293
|
+
|
294
|
+
The callable can also return a dictionary.
|
295
|
+
|
296
|
+
```pycon exec="1" source="console" session="quickstart"
|
297
|
+
>>> def to_dict(run: Run) -> dict[int, str]:
|
298
|
+
... width2 = 2 * run.get("width")
|
299
|
+
... name = f"h{run.get('height')}"
|
300
|
+
... return {"width2": width2, "name": name}
|
301
|
+
>>> print(rc.to_frame("width", from_dict=to_dict))
|
302
|
+
```
|
303
|
+
|
304
|
+
### Group runs
|
305
|
+
|
306
|
+
The [`group_by`][hydraflow.RunCollection.group_by] method groups the
|
307
|
+
runs by the given key.
|
308
|
+
|
309
|
+
```pycon exec="1" source="console" session="quickstart"
|
310
|
+
>>> grouped = rc.group_by("width")
|
311
|
+
>>> for key, group in grouped.items():
|
312
|
+
... print(key, group)
|
313
|
+
```
|
314
|
+
|
315
|
+
The `group_by` method can also take multiple keys.
|
316
|
+
|
317
|
+
```pycon exec="1" source="console" session="quickstart"
|
318
|
+
>>> grouped = rc.group_by("width", "height")
|
319
|
+
>>> for key, group in grouped.items():
|
320
|
+
... print(key, group)
|
321
|
+
```
|
322
|
+
|
323
|
+
The `group_by` method can also take a callable which accepts a sequence
|
324
|
+
of runs and returns a value. In this case, the `group_by` method returns
|
325
|
+
a polars DataFrame.
|
326
|
+
|
327
|
+
```pycon exec="1" source="console" session="quickstart"
|
328
|
+
>>> df = rc.group_by("width", n=lambda runs: len(runs))
|
329
|
+
>>> print(df)
|
330
|
+
```
|
@@ -49,6 +49,14 @@ markdown_extensions:
|
|
49
49
|
- pymdownx.superfences
|
50
50
|
- pymdownx.tabbed:
|
51
51
|
alternate_style: true
|
52
|
+
- attr_list
|
53
|
+
- md_in_html
|
54
|
+
- pymdownx.emoji:
|
55
|
+
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
56
|
+
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
57
|
+
options:
|
58
|
+
custom_icons:
|
59
|
+
- overrides/.icons
|
52
60
|
nav:
|
53
61
|
- Home: index.md
|
54
62
|
- Usage:
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "hydraflow"
|
7
|
-
version = "0.
|
8
|
-
description = "HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management
|
7
|
+
version = "0.15.0"
|
8
|
+
description = "HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management, combining Hydra's configuration management with MLflow's tracking capabilities."
|
9
9
|
readme = "README.md"
|
10
10
|
license = { file = "LICENSE" }
|
11
11
|
authors = [{ name = "daizutabi", email = "daizutabi@gmail.com" }]
|
@@ -17,14 +17,11 @@ classifiers = [
|
|
17
17
|
"License :: OSI Approved :: MIT License",
|
18
18
|
"Operating System :: OS Independent",
|
19
19
|
"Programming Language :: Python",
|
20
|
-
"Programming Language :: Python :: 3.10",
|
21
|
-
"Programming Language :: Python :: 3.11",
|
22
|
-
"Programming Language :: Python :: 3.12",
|
23
20
|
"Programming Language :: Python :: 3.13",
|
24
21
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
25
22
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
26
23
|
]
|
27
|
-
requires-python = ">=3.
|
24
|
+
requires-python = ">=3.13"
|
28
25
|
keywords = [
|
29
26
|
"machine-learning",
|
30
27
|
"mlflow",
|
@@ -37,12 +34,14 @@ keywords = [
|
|
37
34
|
"data-science",
|
38
35
|
]
|
39
36
|
dependencies = [
|
40
|
-
|
41
37
|
"hydra-core>=1.3",
|
38
|
+
"joblib>=1.4.0",
|
42
39
|
"mlflow>=2.15",
|
43
40
|
"omegaconf>=2.3",
|
41
|
+
"polars>=1.26",
|
44
42
|
"python-ulid>=3.0.0",
|
45
43
|
"rich>=13.9",
|
44
|
+
"ruff>=0.11",
|
46
45
|
"typer>=0.15",
|
47
46
|
]
|
48
47
|
|
@@ -69,9 +68,7 @@ docs = ["markdown-exec[ansi]", "mkapi", "mkdocs-material"]
|
|
69
68
|
addopts = [
|
70
69
|
"--cov=hydraflow",
|
71
70
|
"--cov-report=lcov:lcov.info",
|
72
|
-
"--dist=loadgroup",
|
73
71
|
"--doctest-modules",
|
74
|
-
"-n8",
|
75
72
|
]
|
76
73
|
filterwarnings = [
|
77
74
|
"ignore:Support for class-based `config` is deprecated",
|
@@ -84,7 +81,7 @@ skip_covered = true
|
|
84
81
|
|
85
82
|
[tool.ruff]
|
86
83
|
line-length = 88
|
87
|
-
target-version = "
|
84
|
+
target-version = "py313"
|
88
85
|
|
89
86
|
[tool.ruff.lint]
|
90
87
|
select = ["ALL"]
|
@@ -102,6 +99,7 @@ ignore = [
|
|
102
99
|
"EM101",
|
103
100
|
"FBT001",
|
104
101
|
"FBT002",
|
102
|
+
"PD",
|
105
103
|
"PGH003",
|
106
104
|
"PLR0911",
|
107
105
|
"PLR0913",
|
@@ -123,6 +121,3 @@ ignore = [
|
|
123
121
|
|
124
122
|
[tool.pyright]
|
125
123
|
include = ["src", "tests"]
|
126
|
-
strictDictionaryInference = true
|
127
|
-
strictListInference = true
|
128
|
-
strictSetInference = true
|