phasesweep 0.3.6__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.
- phasesweep-0.3.6/.github/workflows/ci.yml +41 -0
- phasesweep-0.3.6/.github/workflows/publish.yml +155 -0
- phasesweep-0.3.6/.gitignore +180 -0
- phasesweep-0.3.6/.gitmodules +3 -0
- phasesweep-0.3.6/.pre-commit-config.yaml +67 -0
- phasesweep-0.3.6/LICENSE +21 -0
- phasesweep-0.3.6/PKG-INFO +206 -0
- phasesweep-0.3.6/README.md +161 -0
- phasesweep-0.3.6/docs/config.md +381 -0
- phasesweep-0.3.6/docs/config_reference.yaml +231 -0
- phasesweep-0.3.6/docs/development.md +288 -0
- phasesweep-0.3.6/docs/images/diagramA_dag.png +0 -0
- phasesweep-0.3.6/docs/images/diagramB_statemachine.png +0 -0
- phasesweep-0.3.6/docs/images/diagramE_guardlayer.png +0 -0
- phasesweep-0.3.6/docs/invariants.md +528 -0
- phasesweep-0.3.6/docs/mcp.md +232 -0
- phasesweep-0.3.6/docs/mcp_setup.md +101 -0
- phasesweep-0.3.6/docs/runtime.md +298 -0
- phasesweep-0.3.6/examples/catalog.yaml +17 -0
- phasesweep-0.3.6/examples/experiment.yaml +86 -0
- phasesweep-0.3.6/examples/mcp_experiment.yaml +70 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/README.md +112 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/catalog.yaml +15 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/experiment.yaml +79 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/gpu_smoke.yaml +64 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/mcp_experiment.yaml +79 -0
- phasesweep-0.3.6/examples/tiny_decoder_enwik8/run_trial.py +235 -0
- phasesweep-0.3.6/pyproject.toml +136 -0
- phasesweep-0.3.6/scripts/check_module_size.sh +34 -0
- phasesweep-0.3.6/setup.cfg +4 -0
- phasesweep-0.3.6/src/phasesweep/__init__.py +31 -0
- phasesweep-0.3.6/src/phasesweep/__main__.py +5 -0
- phasesweep-0.3.6/src/phasesweep/_metadata.py +11 -0
- phasesweep-0.3.6/src/phasesweep/cli.py +832 -0
- phasesweep-0.3.6/src/phasesweep/config/__init__.py +64 -0
- phasesweep-0.3.6/src/phasesweep/config/common.py +207 -0
- phasesweep-0.3.6/src/phasesweep/config/io.py +173 -0
- phasesweep-0.3.6/src/phasesweep/config/models.py +1219 -0
- phasesweep-0.3.6/src/phasesweep/config/search.py +521 -0
- phasesweep-0.3.6/src/phasesweep/engine/__init__.py +72 -0
- phasesweep-0.3.6/src/phasesweep/engine/artifact_roots.py +416 -0
- phasesweep-0.3.6/src/phasesweep/engine/artifacts.py +395 -0
- phasesweep-0.3.6/src/phasesweep/engine/attempts.py +1235 -0
- phasesweep-0.3.6/src/phasesweep/engine/cleanup.py +245 -0
- phasesweep-0.3.6/src/phasesweep/engine/confound.py +512 -0
- phasesweep-0.3.6/src/phasesweep/engine/errors.py +179 -0
- phasesweep-0.3.6/src/phasesweep/engine/evidence.py +716 -0
- phasesweep-0.3.6/src/phasesweep/engine/fingerprints.py +268 -0
- phasesweep-0.3.6/src/phasesweep/engine/generation.py +512 -0
- phasesweep-0.3.6/src/phasesweep/engine/guards.py +223 -0
- phasesweep-0.3.6/src/phasesweep/engine/ledger.py +1389 -0
- phasesweep-0.3.6/src/phasesweep/engine/locking.py +175 -0
- phasesweep-0.3.6/src/phasesweep/engine/optuna.py +309 -0
- phasesweep-0.3.6/src/phasesweep/engine/paths.py +208 -0
- phasesweep-0.3.6/src/phasesweep/engine/phase.py +1685 -0
- phasesweep-0.3.6/src/phasesweep/engine/provenance.py +127 -0
- phasesweep-0.3.6/src/phasesweep/engine/publication.py +200 -0
- phasesweep-0.3.6/src/phasesweep/engine/publication_validation.py +880 -0
- phasesweep-0.3.6/src/phasesweep/engine/read.py +818 -0
- phasesweep-0.3.6/src/phasesweep/engine/resume.py +229 -0
- phasesweep-0.3.6/src/phasesweep/engine/run.py +870 -0
- phasesweep-0.3.6/src/phasesweep/engine/selection.py +241 -0
- phasesweep-0.3.6/src/phasesweep/engine/state.py +238 -0
- phasesweep-0.3.6/src/phasesweep/engine/study_policy.py +650 -0
- phasesweep-0.3.6/src/phasesweep/engine/trial.py +947 -0
- phasesweep-0.3.6/src/phasesweep/errors.py +134 -0
- phasesweep-0.3.6/src/phasesweep/evidence/__init__.py +19 -0
- phasesweep-0.3.6/src/phasesweep/evidence/evaluation.py +936 -0
- phasesweep-0.3.6/src/phasesweep/evidence/models.py +626 -0
- phasesweep-0.3.6/src/phasesweep/evidence/wandb.py +736 -0
- phasesweep-0.3.6/src/phasesweep/examples/__init__.py +1 -0
- phasesweep-0.3.6/src/phasesweep/examples/fake_train.py +168 -0
- phasesweep-0.3.6/src/phasesweep/mcp/__init__.py +30 -0
- phasesweep-0.3.6/src/phasesweep/mcp/agent_prompt.md +16 -0
- phasesweep-0.3.6/src/phasesweep/mcp/audit.py +114 -0
- phasesweep-0.3.6/src/phasesweep/mcp/errors.py +277 -0
- phasesweep-0.3.6/src/phasesweep/mcp/recovery.py +973 -0
- phasesweep-0.3.6/src/phasesweep/mcp/redaction.py +269 -0
- phasesweep-0.3.6/src/phasesweep/mcp/registry.py +620 -0
- phasesweep-0.3.6/src/phasesweep/mcp/run_control.py +942 -0
- phasesweep-0.3.6/src/phasesweep/mcp/runner.py +1044 -0
- phasesweep-0.3.6/src/phasesweep/mcp/runs.py +1647 -0
- phasesweep-0.3.6/src/phasesweep/mcp/scaffold.py +129 -0
- phasesweep-0.3.6/src/phasesweep/mcp/server.py +943 -0
- phasesweep-0.3.6/src/phasesweep/mcp/snapshots.py +660 -0
- phasesweep-0.3.6/src/phasesweep/mcp/tool_names.py +16 -0
- phasesweep-0.3.6/src/phasesweep/mcp/tools.py +848 -0
- phasesweep-0.3.6/src/phasesweep/py.typed +1 -0
- phasesweep-0.3.6/src/phasesweep/reporting.py +195 -0
- phasesweep-0.3.6/src/phasesweep/runtime/__init__.py +1 -0
- phasesweep-0.3.6/src/phasesweep/runtime/commands.py +422 -0
- phasesweep-0.3.6/src/phasesweep/runtime/files.py +1343 -0
- phasesweep-0.3.6/src/phasesweep/runtime/gpu.py +976 -0
- phasesweep-0.3.6/src/phasesweep/runtime/json.py +66 -0
- phasesweep-0.3.6/src/phasesweep/runtime/process.py +1189 -0
- phasesweep-0.3.6/src/phasesweep/runtime/reaper.py +782 -0
- phasesweep-0.3.6/src/phasesweep/runtime/shutdown.py +662 -0
- phasesweep-0.3.6/src/phasesweep/runtime/supervisor.py +349 -0
- phasesweep-0.3.6/src/phasesweep/runtime/time.py +36 -0
- phasesweep-0.3.6/src/phasesweep/templates/starter_experiment.yaml +57 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/PKG-INFO +206 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/SOURCES.txt +194 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/dependency_links.txt +1 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/entry_points.txt +3 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/requires.txt +22 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/scm_file_list.json +190 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/scm_version.json +8 -0
- phasesweep-0.3.6/src/phasesweep.egg-info/top_level.txt +1 -0
- phasesweep-0.3.6/tests/__init__.py +0 -0
- phasesweep-0.3.6/tests/conftest.py +785 -0
- phasesweep-0.3.6/tests/fixtures/__init__.py +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/README.md +88 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/.gitignore +3 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/artifact_root_binding.json +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generation.yaml +6 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generations/cd4512ad12d842a1ab02d436d9e82348/config.snapshot.yaml +55 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generations/cd4512ad12d842a1ab02d436d9e82348/generation.yaml +6 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generations/cd4512ad12d842a1ab02d436d9e82348/phases/p/winner.yaml +69 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generations/cd4512ad12d842a1ab02d436d9e82348/reproducibility.json +28 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/generations/cd4512ad12d842a1ab02d436d9e82348/summary.yaml +64 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/last_successful_generation.yaml +5 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/attempt_lifecycle.json +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/command.txt +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/overrides_resolved.json +3 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/process_identity.json +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/stderr.log +0 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00000__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_cc31794be3a342f484b06f055ff72700/stdout.log +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/attempt_lifecycle.json +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/command.txt +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/overrides_resolved.json +3 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/process_identity.json +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/stderr.log +0 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trial_00001__generation_cd4512ad12d842a1ab02d436d9e82348__attempt_2853324d9a4c4d4388b55d279351b9ab/stdout.log +1 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/trials.csv +3 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/p/winner.yaml +69 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/run.log +9 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/artifact_root/t/summary.yaml +64 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/ledger/study.journal +38 -0
- phasesweep-0.3.6/tests/fixtures/ledgers/current-journal/manifest.json +29 -0
- phasesweep-0.3.6/tests/fixtures/make_ledger_fixtures.py +577 -0
- phasesweep-0.3.6/tests/ledger_fixtures.py +463 -0
- phasesweep-0.3.6/tests/mcp_helpers.py +496 -0
- phasesweep-0.3.6/tests/recovery_helpers.py +240 -0
- phasesweep-0.3.6/tests/test_abort_recovery.py +318 -0
- phasesweep-0.3.6/tests/test_attempt_resolution.py +86 -0
- phasesweep-0.3.6/tests/test_cli.py +1039 -0
- phasesweep-0.3.6/tests/test_config.py +865 -0
- phasesweep-0.3.6/tests/test_configuration_revalidation.py +199 -0
- phasesweep-0.3.6/tests/test_confound.py +721 -0
- phasesweep-0.3.6/tests/test_e2e.py +173 -0
- phasesweep-0.3.6/tests/test_engine_read.py +946 -0
- phasesweep-0.3.6/tests/test_engine_state.py +20 -0
- phasesweep-0.3.6/tests/test_engine_status_shape.py +177 -0
- phasesweep-0.3.6/tests/test_error_routing.py +1771 -0
- phasesweep-0.3.6/tests/test_extractors.py +1291 -0
- phasesweep-0.3.6/tests/test_filesystem_layout.py +290 -0
- phasesweep-0.3.6/tests/test_fingerprint.py +2073 -0
- phasesweep-0.3.6/tests/test_format_cutover.py +1077 -0
- phasesweep-0.3.6/tests/test_gpu_pool.py +1136 -0
- phasesweep-0.3.6/tests/test_init.py +241 -0
- phasesweep-0.3.6/tests/test_ledger_contract.py +703 -0
- phasesweep-0.3.6/tests/test_ledger_read_paths.py +360 -0
- phasesweep-0.3.6/tests/test_locking.py +864 -0
- phasesweep-0.3.6/tests/test_mcp_cancel.py +459 -0
- phasesweep-0.3.6/tests/test_mcp_check.py +339 -0
- phasesweep-0.3.6/tests/test_mcp_e2e.py +667 -0
- phasesweep-0.3.6/tests/test_mcp_launch.py +1732 -0
- phasesweep-0.3.6/tests/test_mcp_read_tools.py +1065 -0
- phasesweep-0.3.6/tests/test_mcp_recovery.py +1824 -0
- phasesweep-0.3.6/tests/test_mcp_redaction.py +328 -0
- phasesweep-0.3.6/tests/test_mcp_registry.py +575 -0
- phasesweep-0.3.6/tests/test_mcp_runner.py +2404 -0
- phasesweep-0.3.6/tests/test_mcp_runs.py +1746 -0
- phasesweep-0.3.6/tests/test_mcp_scaffold.py +292 -0
- phasesweep-0.3.6/tests/test_mcp_status_timing.py +560 -0
- phasesweep-0.3.6/tests/test_overrides.py +781 -0
- phasesweep-0.3.6/tests/test_param_validation.py +929 -0
- phasesweep-0.3.6/tests/test_process_supervision.py +2206 -0
- phasesweep-0.3.6/tests/test_protocol.py +213 -0
- phasesweep-0.3.6/tests/test_public_metadata.py +217 -0
- phasesweep-0.3.6/tests/test_publication_transaction.py +1644 -0
- phasesweep-0.3.6/tests/test_reporting.py +288 -0
- phasesweep-0.3.6/tests/test_runner_signal_guard.py +86 -0
- phasesweep-0.3.6/tests/test_runtime_behavior.py +1791 -0
- phasesweep-0.3.6/tests/test_selector.py +277 -0
- phasesweep-0.3.6/tests/test_shutdown.py +599 -0
- phasesweep-0.3.6/tests/test_stale_reaper.py +1985 -0
- phasesweep-0.3.6/tests/test_storage_urls.py +255 -0
- phasesweep-0.3.6/tests/test_tier_guard.py +317 -0
- phasesweep-0.3.6/tests/test_timeouts.py +917 -0
- phasesweep-0.3.6/tests/test_tiny_decoder_example.py +196 -0
- phasesweep-0.3.6/tests/test_trial_evidence.py +1120 -0
- phasesweep-0.3.6/tests/test_trial_launch.py +675 -0
- phasesweep-0.3.6/tests/test_wandb_live.py +177 -0
- phasesweep-0.3.6/tests/tiers.py +527 -0
- phasesweep-0.3.6/tests/wandb_live_trainer.py +64 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
linux:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.13"
|
|
17
|
+
- name: Install static-check dependencies
|
|
18
|
+
run: >-
|
|
19
|
+
python -m pip install
|
|
20
|
+
'ruff>=0.5' 'mypy>=1.10' 'types-PyYAML>=6.0'
|
|
21
|
+
'optuna==4.9.0' 'cmaes>=0.10'
|
|
22
|
+
'pydantic>=2.0' 'pyyaml>=6.0' 'click>=8.1' 'mcp>=1.27,<1.28'
|
|
23
|
+
- run: ruff check .
|
|
24
|
+
- run: ruff format --check .
|
|
25
|
+
- run: mypy src
|
|
26
|
+
# Fast in-process contracts, run from src/ without building the package.
|
|
27
|
+
# The maintainer approved this step for one Python version within about
|
|
28
|
+
# 20 seconds of CI time; anything slower stays local with the full suite.
|
|
29
|
+
# Collecting the whole suite runs the integration-tier guard over every
|
|
30
|
+
# test module without executing one; it imports each module, so a test
|
|
31
|
+
# that needs Hydra or W&B must import it inside the test. The size check
|
|
32
|
+
# covers every tracked src and test module, not only the ones a commit
|
|
33
|
+
# touched.
|
|
34
|
+
- name: Contract tests
|
|
35
|
+
run: |
|
|
36
|
+
bash scripts/check_module_size.sh
|
|
37
|
+
python -m pip install 'pytest>=7'
|
|
38
|
+
PYTHONPATH=src python -m pytest --collect-only -q -p no:cacheprovider
|
|
39
|
+
PYTHONPATH=src python -m pytest -p no:cacheprovider \
|
|
40
|
+
tests/test_ledger_contract.py tests/test_error_routing.py \
|
|
41
|
+
tests/test_tier_guard.py tests/test_ledger_read_paths.py
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
# Scope concurrency by release tag so distinct releases cannot replace an older pending run.
|
|
11
|
+
concurrency:
|
|
12
|
+
group: pypi-publish-${{ github.event.release.tag_name }}
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build-distributions:
|
|
17
|
+
if: github.event.release.prerelease == false
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 15
|
|
20
|
+
steps:
|
|
21
|
+
- name: Check out the release commit
|
|
22
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
23
|
+
with:
|
|
24
|
+
ref: ${{ github.sha }}
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.13"
|
|
31
|
+
- name: Install packaging tools
|
|
32
|
+
run: python -m pip install build packaging twine
|
|
33
|
+
- name: Validate the release tag and commit
|
|
34
|
+
id: release
|
|
35
|
+
env:
|
|
36
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
37
|
+
run: |
|
|
38
|
+
if ! git merge-base --is-ancestor HEAD origin/main; then
|
|
39
|
+
echo "Release tag ${RELEASE_TAG} is not contained in main." >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
python - <<'PY'
|
|
43
|
+
import os
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
|
|
46
|
+
from packaging.version import InvalidVersion, Version
|
|
47
|
+
|
|
48
|
+
tag = os.environ["RELEASE_TAG"]
|
|
49
|
+
if not tag.startswith("v"):
|
|
50
|
+
raise SystemExit(f"release tag must start with 'v': {tag!r}")
|
|
51
|
+
try:
|
|
52
|
+
version = Version(tag[1:])
|
|
53
|
+
except InvalidVersion as error:
|
|
54
|
+
raise SystemExit(f"release tag is not a PEP 440 version: {tag!r}") from error
|
|
55
|
+
# Post releases and epochs remain valid stable public PEP 440 versions.
|
|
56
|
+
if version.is_prerelease or version.is_devrelease or version.local is not None:
|
|
57
|
+
raise SystemExit(f"release tag must be a stable public version: {tag!r}")
|
|
58
|
+
with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output:
|
|
59
|
+
print(f"version={version}", file=output)
|
|
60
|
+
PY
|
|
61
|
+
- name: Build distributions
|
|
62
|
+
env:
|
|
63
|
+
# An annotated RC tag on the same commit must not override the release tag.
|
|
64
|
+
SETUPTOOLS_SCM_OVERRIDES_FOR_PHASESWEEP: >-
|
|
65
|
+
{scm.git.describe_command = ["git", "describe", "--dirty", "--tags",
|
|
66
|
+
"--long", "--abbrev=40", "--exact-match", "--match",
|
|
67
|
+
"${{ github.event.release.tag_name }}"]}
|
|
68
|
+
run: python -m build
|
|
69
|
+
- name: Check distribution metadata
|
|
70
|
+
run: python -m twine check --strict dist/*
|
|
71
|
+
- name: Verify distribution versions
|
|
72
|
+
env:
|
|
73
|
+
EXPECTED_VERSION: ${{ steps.release.outputs.version }}
|
|
74
|
+
run: |
|
|
75
|
+
python - <<'PY'
|
|
76
|
+
import os
|
|
77
|
+
import tarfile
|
|
78
|
+
from email.parser import BytesParser
|
|
79
|
+
from pathlib import Path
|
|
80
|
+
from zipfile import ZipFile
|
|
81
|
+
|
|
82
|
+
from packaging.utils import canonicalize_name
|
|
83
|
+
from packaging.version import Version
|
|
84
|
+
|
|
85
|
+
expected_version = Version(os.environ["EXPECTED_VERSION"])
|
|
86
|
+
wheels = list(Path("dist").glob("*.whl"))
|
|
87
|
+
sdists = list(Path("dist").glob("*.tar.gz"))
|
|
88
|
+
if len(wheels) != 1 or len(sdists) != 1:
|
|
89
|
+
raise SystemExit(f"expected one wheel and one sdist, found {wheels!r} and {sdists!r}")
|
|
90
|
+
with ZipFile(wheels[0]) as archive:
|
|
91
|
+
metadata_paths = [
|
|
92
|
+
name for name in archive.namelist() if name.endswith(".dist-info/METADATA")
|
|
93
|
+
]
|
|
94
|
+
if len(metadata_paths) != 1:
|
|
95
|
+
raise SystemExit(
|
|
96
|
+
f"expected one .dist-info/METADATA in {wheels[0]}, found {metadata_paths!r}"
|
|
97
|
+
)
|
|
98
|
+
metadata_path = metadata_paths[0]
|
|
99
|
+
wheel_metadata = BytesParser().parsebytes(archive.read(metadata_path))
|
|
100
|
+
with tarfile.open(sdists[0]) as archive:
|
|
101
|
+
metadata_members = [
|
|
102
|
+
member
|
|
103
|
+
for member in archive.getmembers()
|
|
104
|
+
if member.name.endswith("/PKG-INFO") and len(Path(member.name).parts) == 2
|
|
105
|
+
]
|
|
106
|
+
if len(metadata_members) != 1:
|
|
107
|
+
names = [member.name for member in metadata_members]
|
|
108
|
+
raise SystemExit(
|
|
109
|
+
f"expected one top-level PKG-INFO in {sdists[0]}, found {names!r}"
|
|
110
|
+
)
|
|
111
|
+
metadata_member = metadata_members[0]
|
|
112
|
+
metadata_file = archive.extractfile(metadata_member)
|
|
113
|
+
if metadata_file is None:
|
|
114
|
+
raise SystemExit(f"could not read {metadata_member.name} from {sdists[0]}")
|
|
115
|
+
sdist_metadata = BytesParser().parse(metadata_file)
|
|
116
|
+
for artifact, metadata in (
|
|
117
|
+
(wheels[0], wheel_metadata),
|
|
118
|
+
(sdists[0], sdist_metadata),
|
|
119
|
+
):
|
|
120
|
+
if canonicalize_name(metadata["Name"]) != "phasesweep":
|
|
121
|
+
raise SystemExit(f"unexpected project name in {artifact}: {metadata['Name']!r}")
|
|
122
|
+
actual_version = Version(metadata["Version"])
|
|
123
|
+
if actual_version != expected_version:
|
|
124
|
+
raise SystemExit(
|
|
125
|
+
f"release tag expects {expected_version}, but {artifact} contains {actual_version}"
|
|
126
|
+
)
|
|
127
|
+
PY
|
|
128
|
+
- name: Store distributions
|
|
129
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
130
|
+
with:
|
|
131
|
+
name: release-distributions
|
|
132
|
+
path: dist/
|
|
133
|
+
if-no-files-found: error
|
|
134
|
+
retention-days: 7
|
|
135
|
+
|
|
136
|
+
publish-to-pypi:
|
|
137
|
+
if: github.event.release.prerelease == false
|
|
138
|
+
needs: build-distributions
|
|
139
|
+
runs-on: ubuntu-latest
|
|
140
|
+
timeout-minutes: 10
|
|
141
|
+
environment:
|
|
142
|
+
name: pypi
|
|
143
|
+
url: https://pypi.org/p/phasesweep
|
|
144
|
+
permissions:
|
|
145
|
+
id-token: write
|
|
146
|
+
steps:
|
|
147
|
+
- name: Retrieve distributions
|
|
148
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
149
|
+
with:
|
|
150
|
+
name: release-distributions
|
|
151
|
+
path: dist/
|
|
152
|
+
- name: Publish distributions to PyPI
|
|
153
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
154
|
+
with:
|
|
155
|
+
attestations: true
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
_version.py
|
|
29
|
+
|
|
30
|
+
# phasesweep local outputs
|
|
31
|
+
runs/
|
|
32
|
+
|
|
33
|
+
# PyInstaller
|
|
34
|
+
# Usually these files are written by a python script from a template
|
|
35
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
36
|
+
*.manifest
|
|
37
|
+
*.spec
|
|
38
|
+
|
|
39
|
+
# Installer logs
|
|
40
|
+
pip-log.txt
|
|
41
|
+
pip-delete-this-directory.txt
|
|
42
|
+
|
|
43
|
+
# Unit test / coverage reports
|
|
44
|
+
htmlcov/
|
|
45
|
+
.tox/
|
|
46
|
+
.nox/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
.cache
|
|
50
|
+
nosetests.xml
|
|
51
|
+
coverage.xml
|
|
52
|
+
*.cover
|
|
53
|
+
*.py.cover
|
|
54
|
+
*.lcov
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
db.sqlite3-journal
|
|
68
|
+
|
|
69
|
+
# Flask stuff:
|
|
70
|
+
instance/
|
|
71
|
+
.webassets-cache
|
|
72
|
+
|
|
73
|
+
# Scrapy stuff:
|
|
74
|
+
.scrapy
|
|
75
|
+
|
|
76
|
+
# Sphinx documentation
|
|
77
|
+
docs/_build/
|
|
78
|
+
|
|
79
|
+
# PyBuilder
|
|
80
|
+
.pybuilder/
|
|
81
|
+
target/
|
|
82
|
+
|
|
83
|
+
# Jupyter Notebook
|
|
84
|
+
.ipynb_checkpoints
|
|
85
|
+
|
|
86
|
+
# IPython
|
|
87
|
+
profile_default/
|
|
88
|
+
ipython_config.py
|
|
89
|
+
|
|
90
|
+
# UV
|
|
91
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
92
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
93
|
+
# commonly ignored for libraries.
|
|
94
|
+
# uv.lock
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
98
|
+
__pypackages__/
|
|
99
|
+
|
|
100
|
+
# Celery stuff
|
|
101
|
+
celerybeat-schedule*
|
|
102
|
+
celerybeat.pid
|
|
103
|
+
|
|
104
|
+
# Redis
|
|
105
|
+
*.rdb
|
|
106
|
+
*.aof
|
|
107
|
+
*.pid
|
|
108
|
+
|
|
109
|
+
# RabbitMQ
|
|
110
|
+
mnesia/
|
|
111
|
+
rabbitmq/
|
|
112
|
+
rabbitmq-data/
|
|
113
|
+
|
|
114
|
+
# ActiveMQ
|
|
115
|
+
activemq-data/
|
|
116
|
+
|
|
117
|
+
# SageMath parsed files
|
|
118
|
+
*.sage.py
|
|
119
|
+
|
|
120
|
+
# Environments
|
|
121
|
+
.env
|
|
122
|
+
.envrc
|
|
123
|
+
.venv
|
|
124
|
+
env/
|
|
125
|
+
venv/
|
|
126
|
+
ENV/
|
|
127
|
+
env.bak/
|
|
128
|
+
venv.bak/
|
|
129
|
+
|
|
130
|
+
# Spyder project settings
|
|
131
|
+
.spyderproject
|
|
132
|
+
.spyproject
|
|
133
|
+
|
|
134
|
+
# Rope project settings
|
|
135
|
+
.ropeproject
|
|
136
|
+
|
|
137
|
+
# mkdocs documentation
|
|
138
|
+
/site
|
|
139
|
+
|
|
140
|
+
# mypy
|
|
141
|
+
.mypy_cache/
|
|
142
|
+
.dmypy.json
|
|
143
|
+
dmypy.json
|
|
144
|
+
|
|
145
|
+
# Pyre type checker
|
|
146
|
+
.pyre/
|
|
147
|
+
|
|
148
|
+
# pytype static type analyzer
|
|
149
|
+
.pytype/
|
|
150
|
+
|
|
151
|
+
# Cython debug symbols
|
|
152
|
+
cython_debug/
|
|
153
|
+
|
|
154
|
+
# Visual Studio Code
|
|
155
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
156
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
157
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
158
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
159
|
+
# .vscode/
|
|
160
|
+
# Temporary file for partial code execution
|
|
161
|
+
tempCodeRunnerFile.py
|
|
162
|
+
|
|
163
|
+
# Ruff stuff:
|
|
164
|
+
.ruff_cache/
|
|
165
|
+
|
|
166
|
+
# PyPI configuration file
|
|
167
|
+
.pypirc
|
|
168
|
+
|
|
169
|
+
# Marimo
|
|
170
|
+
marimo/_static/
|
|
171
|
+
marimo/_lsp/
|
|
172
|
+
__marimo__/
|
|
173
|
+
|
|
174
|
+
# Streamlit
|
|
175
|
+
.streamlit/secrets.toml
|
|
176
|
+
|
|
177
|
+
# Golden ledger fixtures are committed on purpose: real PhaseSweep output whose
|
|
178
|
+
# trial logs (*.log) and artifact trees would otherwise be ignored above.
|
|
179
|
+
# See tests/fixtures/ledgers/README.md.
|
|
180
|
+
!tests/fixtures/ledgers/**
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Every hook is `repo: local` with `language: system`: it runs the tool already
|
|
2
|
+
# installed in the active development environment (`pip install -e ".[dev]"`),
|
|
3
|
+
# so pre-commit builds no per-hook environments, needs no network, and uses the
|
|
4
|
+
# same tool versions as manual runs. Activate that environment before
|
|
5
|
+
# committing or pushing.
|
|
6
|
+
minimum_pre_commit_version: "3.2.0"
|
|
7
|
+
default_install_hook_types: [pre-commit, pre-push]
|
|
8
|
+
default_stages: [pre-commit]
|
|
9
|
+
|
|
10
|
+
repos:
|
|
11
|
+
- repo: local
|
|
12
|
+
hooks:
|
|
13
|
+
- id: ruff
|
|
14
|
+
name: ruff check
|
|
15
|
+
entry: ruff check --force-exclude --fix
|
|
16
|
+
language: system
|
|
17
|
+
types_or: [python, pyi]
|
|
18
|
+
require_serial: true
|
|
19
|
+
- id: ruff-format
|
|
20
|
+
name: ruff format
|
|
21
|
+
entry: ruff format --force-exclude
|
|
22
|
+
language: system
|
|
23
|
+
types_or: [python, pyi]
|
|
24
|
+
require_serial: true
|
|
25
|
+
- id: pathlint
|
|
26
|
+
name: pathlint
|
|
27
|
+
entry: pathlint
|
|
28
|
+
language: system
|
|
29
|
+
files: ^(src|tests)/.*\.py$
|
|
30
|
+
# doc_check.py is a maintainer script outside the repository; without it
|
|
31
|
+
# the hook reports the skip and passes. Its report prints only on failure.
|
|
32
|
+
- id: doc-check
|
|
33
|
+
name: doc-check (strict)
|
|
34
|
+
entry: >-
|
|
35
|
+
bash -c 'script="$HOME/scripts/py/doc_check.py";
|
|
36
|
+
[ -f "$script" ] || { echo "doc_check.py not found; skipped"; exit 0; };
|
|
37
|
+
out=$(python "$script" --strict "$@") || { printf "%s\n" "$out"; exit 1; }' --
|
|
38
|
+
language: system
|
|
39
|
+
files: ^src/.*\.py$
|
|
40
|
+
verbose: true
|
|
41
|
+
- id: module-size
|
|
42
|
+
name: module size
|
|
43
|
+
entry: bash scripts/check_module_size.sh
|
|
44
|
+
language: system
|
|
45
|
+
files: ^(src|tests)/.*\.py$
|
|
46
|
+
# Runs on every commit: the contracts span all of src/ and the pytest
|
|
47
|
+
# configuration.
|
|
48
|
+
- id: contract-tests
|
|
49
|
+
name: contract tests
|
|
50
|
+
entry: pytest tests/test_ledger_contract.py tests/test_error_routing.py tests/test_tier_guard.py -q -p no:cacheprovider
|
|
51
|
+
language: system
|
|
52
|
+
pass_filenames: false
|
|
53
|
+
always_run: true
|
|
54
|
+
# Collecting the whole suite runs the integration-tier guard over every
|
|
55
|
+
# test module without executing any test.
|
|
56
|
+
- id: tier-guard
|
|
57
|
+
name: tier guard (whole-suite collection)
|
|
58
|
+
entry: pytest --collect-only -q -p no:cacheprovider
|
|
59
|
+
language: system
|
|
60
|
+
pass_filenames: false
|
|
61
|
+
always_run: true
|
|
62
|
+
- id: mypy
|
|
63
|
+
name: mypy
|
|
64
|
+
entry: mypy src
|
|
65
|
+
language: system
|
|
66
|
+
pass_filenames: false
|
|
67
|
+
stages: [pre-push]
|
phasesweep-0.3.6/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peter Szemraj
|
|
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.
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: phasesweep
|
|
3
|
+
Version: 0.3.6
|
|
4
|
+
Summary: YAML-driven phase-chained hyperparameter sweeps with Optuna: each phase's winner is set for all following sweeps.
|
|
5
|
+
Author: Peter Szemraj
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/pszemraj/phasesweep
|
|
8
|
+
Project-URL: Documentation, https://github.com/pszemraj/phasesweep/tree/main/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/pszemraj/phasesweep.git
|
|
10
|
+
Project-URL: Issues, https://github.com/pszemraj/phasesweep/issues
|
|
11
|
+
Keywords: experiments,hyperparameter-optimization,machine-learning,optuna,sweeps
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: POSIX
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: optuna<4.10,>=4.0
|
|
26
|
+
Requires-Dist: cmaes>=0.10
|
|
27
|
+
Requires-Dist: pydantic>=2.0
|
|
28
|
+
Requires-Dist: pyyaml>=6.0
|
|
29
|
+
Requires-Dist: click>=8.1
|
|
30
|
+
Provides-Extra: wandb
|
|
31
|
+
Requires-Dist: wandb<0.29,>=0.28; extra == "wandb"
|
|
32
|
+
Provides-Extra: mcp
|
|
33
|
+
Requires-Dist: mcp<1.28,>=1.27; extra == "mcp"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: hydra-core<1.4,>=1.3; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
37
|
+
Requires-Dist: setuptools-scm[simple]>=9.2; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
40
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
41
|
+
Requires-Dist: mcp<1.28,>=1.27; extra == "dev"
|
|
42
|
+
Requires-Dist: pre-commit>=3.2; extra == "dev"
|
|
43
|
+
Requires-Dist: pathlint>=0.2; extra == "dev"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# PhaseSweep
|
|
47
|
+
|
|
48
|
+
PhaseSweep runs phase-chained hyperparameter sweeps from one ordinary YAML file. That file contains your trainer configuration, the metric, and the search plan. PhaseSweep materializes the configured trainer input for every trial, decides what to try next, persists each phase winner, and carries selected values forward as fixed inputs to later phases.
|
|
49
|
+
|
|
50
|
+
This is useful when a full joint sweep is too expensive or hard to interpret. For example, choose architecture depth, then tune learning rate, then regularization. The [configuration guide](https://github.com/pszemraj/phasesweep/blob/main/docs/config.md#phase-composition) explains the inheritance model and its tradeoffs.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
The starter generated by `phasesweep init` searches depth before learning rate (abridged; the full file also sets storage, the working directory, and the metric extractor):
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
experiment: phasesweep_starter
|
|
60
|
+
|
|
61
|
+
# The trainer receives one complete generated YAML per trial.
|
|
62
|
+
trial_command: "python -m phasesweep.examples.fake_train --config {config_path}"
|
|
63
|
+
|
|
64
|
+
trainer_config:
|
|
65
|
+
model:
|
|
66
|
+
n_layers: 8
|
|
67
|
+
dropout: 0.1
|
|
68
|
+
optimizer:
|
|
69
|
+
lr: 0.0003
|
|
70
|
+
weight_decay: 0.05
|
|
71
|
+
|
|
72
|
+
metric:
|
|
73
|
+
name: eval_loss
|
|
74
|
+
goal: minimize
|
|
75
|
+
|
|
76
|
+
phases:
|
|
77
|
+
- name: depth
|
|
78
|
+
n_trials: 2
|
|
79
|
+
sampler: { type: grid }
|
|
80
|
+
search_space:
|
|
81
|
+
model.n_layers: { type: categorical, choices: [6, 8] }
|
|
82
|
+
|
|
83
|
+
- name: learning_rate
|
|
84
|
+
inherits: [depth] # the winning model.n_layers is fixed here
|
|
85
|
+
n_trials: 2
|
|
86
|
+
sampler: { type: grid }
|
|
87
|
+
search_space:
|
|
88
|
+
optimizer.lr: { type: categorical, choices: [0.0001, 0.0003] }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The packaged fake trainer uses the optional `report_objective(...)` envelope
|
|
92
|
+
helper. Your own trainer can report through W&B, ordinary JSON, or logs without
|
|
93
|
+
importing PhaseSweep.
|
|
94
|
+
|
|
95
|
+
## Install and try it
|
|
96
|
+
|
|
97
|
+
Requirements: Python 3.11+ and a POSIX host for real runs. GPUs are optional.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
python -m pip install phasesweep
|
|
101
|
+
phasesweep --version
|
|
102
|
+
|
|
103
|
+
mkdir phasesweep-demo && cd phasesweep-demo
|
|
104
|
+
phasesweep init # writes the starter experiment.yaml
|
|
105
|
+
phasesweep validate experiment.yaml # checks it without launching anything
|
|
106
|
+
phasesweep run experiment.yaml # four tiny trials, a few seconds
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`phasesweep init` never overwrites an existing file; use `-o PATH` for another
|
|
110
|
+
destination.
|
|
111
|
+
|
|
112
|
+
The run log shows the phase chaining directly (abridged):
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
[depth/trial_0] python -m phasesweep.examples.fake_train --config .../trainer_config.yaml
|
|
116
|
+
[depth/trial_1] python -m phasesweep.examples.fake_train --config .../trainer_config.yaml
|
|
117
|
+
phase=depth WINNER trial=0 metric=0.3 params={'model.n_layers': 8}
|
|
118
|
+
[learning_rate/trial_0] python -m phasesweep.examples.fake_train --config .../trainer_config.yaml
|
|
119
|
+
[learning_rate/trial_1] python -m phasesweep.examples.fake_train --config .../trainer_config.yaml
|
|
120
|
+
phase=learning_rate WINNER trial=0 metric=0.3 params={'optimizer.lr': 0.0003}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The `depth` winner's `model.n_layers: 8` is injected into every `learning_rate` trial's complete YAML. Winners persist in the working directory, so you can inspect them any time (abridged):
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
phasesweep show-winners experiment.yaml
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
phase: learning_rate
|
|
131
|
+
metric:
|
|
132
|
+
eval_loss: 0.3
|
|
133
|
+
goal: minimize
|
|
134
|
+
trial_number: 0
|
|
135
|
+
params:
|
|
136
|
+
optimizer.lr: 0.0003
|
|
137
|
+
effective_overrides:
|
|
138
|
+
model.n_layers: 8
|
|
139
|
+
optimizer.lr: 0.0003
|
|
140
|
+
# ... completion state, fingerprints, objective provenance, and confound
|
|
141
|
+
# verdicts on the ranked population follow
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The starter uses `storage: auto`, so its ledger and outputs live together under
|
|
145
|
+
`<workdir>/<experiment>/`. The ledger is an Optuna journal: `phasesweep status`
|
|
146
|
+
prints its path, and Optuna's own CLI and dashboard can
|
|
147
|
+
[read it](https://github.com/pszemraj/phasesweep/blob/main/docs/runtime.md#inspect-the-ledger-with-optuna). See
|
|
148
|
+
[runtime behavior](https://github.com/pszemraj/phasesweep/blob/main/docs/runtime.md) for state layout, current-format
|
|
149
|
+
requirements, locks, cleanup, GPU isolation, and resume.
|
|
150
|
+
|
|
151
|
+
## Use your own trainer
|
|
152
|
+
|
|
153
|
+
Choose the input interface your trainer already accepts:
|
|
154
|
+
|
|
155
|
+
| Input | Command placeholder |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| Complete base-plus-overrides YAML (`yaml_file`, default) | `--config {config_path}` |
|
|
158
|
+
| Command-line flags (`argparse`) | `{overrides}` produces `--key=value` |
|
|
159
|
+
| Native Hydra overrides (`hydra`) | `{overrides}` produces `key=value` |
|
|
160
|
+
| Nested overrides-only JSON (`json_file`) | `--overrides {overrides_path}` |
|
|
161
|
+
|
|
162
|
+
> [!TIP]
|
|
163
|
+
> `phasesweep run experiment.yaml --dry-run` prints one rendered command per
|
|
164
|
+
> phase without launching work. Use it to check that your placeholders render
|
|
165
|
+
> what the trainer expects.
|
|
166
|
+
|
|
167
|
+
For ordinary JSON output, pass an output path under `{trial_dir}` to your
|
|
168
|
+
trainer and select it with `extractor: {type: json, path: result.json, key: eval.loss}`.
|
|
169
|
+
For W&B, use `extractor: {type: wandb, entity: YOUR_ENTITY, project: YOUR_PROJECT, metric_key: eval/loss}`,
|
|
170
|
+
have the trainer honor the supplied W&B identity, and install the extra:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
python -m pip install "phasesweep[wandb]"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`metric.goal` ranks each trial's selected scalar. Log matching selects the
|
|
177
|
+
last observation by default; W&B selects an exact finished-summary key.
|
|
178
|
+
The trainer owns evaluation, early stopping, checkpoint selection, and
|
|
179
|
+
aggregation. Inheritance transfers parameters, not model weights.
|
|
180
|
+
|
|
181
|
+
See the [configuration guide](https://github.com/pszemraj/phasesweep/blob/main/docs/config.md) for input types, reporting,
|
|
182
|
+
credentials, and selection details. The [Tiny Decoder Enwik8
|
|
183
|
+
example](https://github.com/pszemraj/phasesweep/blob/main/examples/tiny_decoder_enwik8/README.md) is a complete real-trainer
|
|
184
|
+
integration.
|
|
185
|
+
|
|
186
|
+
## Connect an agent
|
|
187
|
+
|
|
188
|
+
The optional MCP server connects an AI agent to experiments you have approved without exposing config or storage paths, trainer commands, environment values, or raw logs. Sampled winner values follow the catalog's `visible_params` policy. Follow the [MCP setup](https://github.com/pszemraj/phasesweep/blob/main/docs/mcp_setup.md) to install the extra, review the catalog authority boundary, configure a client-owned connection, and verify the result.
|
|
189
|
+
|
|
190
|
+
## Reference
|
|
191
|
+
|
|
192
|
+
- [Configuration guide](https://github.com/pszemraj/phasesweep/blob/main/docs/config.md): Experiment YAML, search spaces, inheritance, gates, and objective extractors.
|
|
193
|
+
- [Configuration reference](https://github.com/pszemraj/phasesweep/blob/main/docs/config_reference.yaml): per-key types, defaults, valid values, interactions, and lifecycle warnings.
|
|
194
|
+
- [Runtime behavior](https://github.com/pszemraj/phasesweep/blob/main/docs/runtime.md): filesystem layout, locks, GPU leases, process supervision, fingerprints, and resume.
|
|
195
|
+
- [MCP setup](https://github.com/pszemraj/phasesweep/blob/main/docs/mcp_setup.md): installed-package agent onboarding and client-owned setup.
|
|
196
|
+
- [MCP operator reference](https://github.com/pszemraj/phasesweep/blob/main/docs/mcp.md): catalog fields, tools, authorization, run state, and recovery.
|
|
197
|
+
- [Toy experiment and MCP catalog](https://github.com/pszemraj/phasesweep/blob/main/examples/experiment.yaml): a checkout-local CLI example backed by the packaged fake trainer, plus an [MCP catalog](https://github.com/pszemraj/phasesweep/blob/main/examples/catalog.yaml) whose detached-run state and experiment outputs use absolute scratch paths under `/tmp`.
|
|
198
|
+
- [Tiny Decoder Enwik8 example](https://github.com/pszemraj/phasesweep/blob/main/examples/tiny_decoder_enwik8/README.md): real-trainer integration.
|
|
199
|
+
- [Durability invariants](https://github.com/pszemraj/phasesweep/blob/main/docs/invariants.md): the ordering rules the ledger, publication, and recovery paths must hold, and the test that owns each one.
|
|
200
|
+
- [Development](https://github.com/pszemraj/phasesweep/blob/main/docs/development.md): source checkout, contributor setup, and quality gates.
|
|
201
|
+
|
|
202
|
+
[](https://deepwiki.com/pszemraj/phasesweep)
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT. See [LICENSE](https://github.com/pszemraj/phasesweep/blob/main/LICENSE).
|