precisionai-agritune 1.0.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.
- precisionai_agritune-1.0.0/.env.example +10 -0
- precisionai_agritune-1.0.0/.gitattributes +13 -0
- precisionai_agritune-1.0.0/.gitignore +152 -0
- precisionai_agritune-1.0.0/.pre-commit-config.yaml +48 -0
- precisionai_agritune-1.0.0/CHANGELOG.md +336 -0
- precisionai_agritune-1.0.0/CLAUDE.md +353 -0
- precisionai_agritune-1.0.0/CODE_OF_CONDUCT.md +83 -0
- precisionai_agritune-1.0.0/CONTRIBUTING.md +83 -0
- precisionai_agritune-1.0.0/LICENSE.md +201 -0
- precisionai_agritune-1.0.0/MANIFEST.in +13 -0
- precisionai_agritune-1.0.0/PKG-INFO +518 -0
- precisionai_agritune-1.0.0/README.md +246 -0
- precisionai_agritune-1.0.0/RELEASE_NOTES.md +152 -0
- precisionai_agritune-1.0.0/SECURITY.md +63 -0
- precisionai_agritune-1.0.0/assets/logo.svg +13 -0
- precisionai_agritune-1.0.0/precisionai/__init__.py +2 -0
- precisionai_agritune-1.0.0/precisionai/agritune/__init__.py +22 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/__init__.py +7 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/app.py +86 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/config.py +24 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/paths.py +47 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/__init__.py +19 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/dataset.py +37 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/encoder.py +52 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/evaluate.py +48 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/features.py +101 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/predict.py +45 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/routes/train.py +32 -0
- precisionai_agritune-1.0.0/precisionai/agritune/api/schemas.py +261 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/__init__.py +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/feature/__init__.py +22 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/feature/pipeline.py +102 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/feature/transforms.py +224 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/image/__init__.py +29 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/image/pipeline.py +479 -0
- precisionai_agritune-1.0.0/precisionai/agritune/augmentations/image/seeding.py +113 -0
- precisionai_agritune-1.0.0/precisionai/agritune/cli/__init__.py +10 -0
- precisionai_agritune-1.0.0/precisionai/agritune/cli/config.py +264 -0
- precisionai_agritune-1.0.0/precisionai/agritune/cli/handlers.py +327 -0
- precisionai_agritune-1.0.0/precisionai/agritune/cli/main.py +365 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/augmentation/hybrid.yaml +12 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/augmentation/none.yaml +2 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/augmentation/offline.yaml +12 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/augmentation/online.yaml +10 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/config.yaml +54 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/dataset/agricultural_segmentation.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/aspp.yaml +6 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/mask_former.yaml +9 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/mlp_probe.yaml +5 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/ppm.yaml +6 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/segmenter.yaml +8 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/decoder/token_fpn.yaml +8 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/encoder/fake.yaml +6 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/encoder/remote.yaml +7 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/feature_augmentation/light.yaml +9 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/feature_augmentation/none.yaml +8 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/feature_provider/cached.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/feature_provider/hybrid.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/feature_provider/online.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/optimizer/adam.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/optimizer/adamw.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/optimizer/sgd.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/cosine.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/cosine_warmup.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/linear_warmup.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/none.yaml +2 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/plateau.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/scheduler/polynomial.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/task/segmentation.yaml +7 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/templates/full_config.yaml +193 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/templates/manifest.csv +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/comet.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/jsonl.yaml +1 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/local.yaml +2 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/mlflow.yaml +4 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/neptune.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/null.yaml +1 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/tensorboard.yaml +1 -0
- precisionai_agritune-1.0.0/precisionai/agritune/configs/tracking/wandb.yaml +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/data/__init__.py +28 -0
- precisionai_agritune-1.0.0/precisionai/agritune/data/dataset.py +77 -0
- precisionai_agritune-1.0.0/precisionai/agritune/data/manifest.py +111 -0
- precisionai_agritune-1.0.0/precisionai/agritune/data/split.py +236 -0
- precisionai_agritune-1.0.0/precisionai/agritune/data/validation.py +170 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/__init__.py +53 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/base.py +16 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/batching.py +41 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/errors.py +47 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/fake.py +167 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/gateway.py +207 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/rate_limiter.py +122 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/remote.py +277 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/retry.py +156 -0
- precisionai_agritune-1.0.0/precisionai/agritune/encoder/validation.py +93 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/__init__.py +50 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/errors.py +13 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/integrity.py +54 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/keys.py +120 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/manifest.py +67 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/memory.py +334 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/migrate.py +83 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/precompute.py +126 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/prefetch.py +181 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/provider.py +252 -0
- precisionai_agritune-1.0.0/precisionai/agritune/features/store.py +521 -0
- precisionai_agritune-1.0.0/precisionai/agritune/logging/__init__.py +27 -0
- precisionai_agritune-1.0.0/precisionai/agritune/logging/progress.py +53 -0
- precisionai_agritune-1.0.0/precisionai/agritune/logging/provenance.py +202 -0
- precisionai_agritune-1.0.0/precisionai/agritune/logging/redaction.py +102 -0
- precisionai_agritune-1.0.0/precisionai/agritune/logging/setup.py +58 -0
- precisionai_agritune-1.0.0/precisionai/agritune/metrics/__init__.py +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/optimization/__init__.py +18 -0
- precisionai_agritune-1.0.0/precisionai/agritune/optimization/optimizers.py +66 -0
- precisionai_agritune-1.0.0/precisionai/agritune/optimization/registry.py +12 -0
- precisionai_agritune-1.0.0/precisionai/agritune/optimization/schedulers.py +99 -0
- precisionai_agritune-1.0.0/precisionai/agritune/schemas/__init__.py +35 -0
- precisionai_agritune-1.0.0/precisionai/agritune/schemas/augmentation.py +45 -0
- precisionai_agritune-1.0.0/precisionai/agritune/schemas/features.py +417 -0
- precisionai_agritune-1.0.0/precisionai/agritune/schemas/protocols.py +201 -0
- precisionai_agritune-1.0.0/precisionai/agritune/schemas/samples.py +71 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/__init__.py +48 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/benchmark_service.py +201 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/config_template_service.py +53 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/dataset_service.py +104 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/encoder_selection.py +70 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/evaluation_service.py +226 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/feature_service.py +202 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/prediction_service.py +265 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/segmentation_common.py +896 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/tracking_selection.py +109 -0
- precisionai_agritune-1.0.0/precisionai/agritune/services/training_service.py +927 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/__init__.py +3 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/__init__.py +26 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/__init__.py +20 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/aspp.py +103 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/mask_former.py +117 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/mlp_probe.py +74 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/pyramid_pooling.py +101 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/segmenter.py +100 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/decoders/token_fpn.py +136 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/losses.py +216 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/metrics.py +131 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/postprocessing.py +42 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/task.py +37 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/upsample.py +107 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tasks/segmentation/visualization.py +140 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/__init__.py +27 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/comet_tracker.py +89 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/jsonl.py +45 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/mlflow_tracker.py +71 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/multi.py +57 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/neptune_tracker.py +62 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/null.py +25 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/tensorboard.py +58 -0
- precisionai_agritune-1.0.0/precisionai/agritune/tracking/wandb_tracker.py +58 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/__init__.py +36 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/batch.py +45 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/checkpointing.py +234 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/distributed.py +50 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/evaluator.py +82 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/precision.py +80 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/prefetch.py +135 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/state.py +87 -0
- precisionai_agritune-1.0.0/precisionai/agritune/training/trainer.py +460 -0
- precisionai_agritune-1.0.0/precisionai/agritune/utils/__init__.py +11 -0
- precisionai_agritune-1.0.0/precisionai/agritune/utils/env.py +98 -0
- precisionai_agritune-1.0.0/precisionai/agritune/utils/scaffold.py +58 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/PKG-INFO +518 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/SOURCES.txt +177 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/dependency_links.txt +1 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/entry_points.txt +2 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/requires.txt +48 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/scm_file_list.json +309 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/scm_version.json +8 -0
- precisionai_agritune-1.0.0/precisionai_agritune.egg-info/top_level.txt +1 -0
- precisionai_agritune-1.0.0/pyproject.toml +204 -0
- precisionai_agritune-1.0.0/requirements-dev.txt +20 -0
- precisionai_agritune-1.0.0/requirements.txt +20 -0
- precisionai_agritune-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Copy to .env and fill in — .env is gitignored and never committed.
|
|
2
|
+
#
|
|
3
|
+
# Loaded into the environment before Hydra/OmegaConf composes the config, so
|
|
4
|
+
# `${oc.env:AGRITUNE_ENCODER_API_KEY,null}` in configs/encoder/remote.yaml resolves from here.
|
|
5
|
+
# Requires python-dotenv: pip install -e ".[dotenv]"
|
|
6
|
+
#
|
|
7
|
+
# Anything already exported in your shell wins over the values below.
|
|
8
|
+
|
|
9
|
+
# API key for the hosted encoder embeddings API (encoder=remote).
|
|
10
|
+
AGRITUNE_ENCODER_API_KEY=
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Normalize line endings to LF on commit, regardless of editor/OS settings.
|
|
2
|
+
* text=auto eol=lf
|
|
3
|
+
|
|
4
|
+
# Treat binary files as binary (no line-ending conversion).
|
|
5
|
+
*.png binary
|
|
6
|
+
*.jpg binary
|
|
7
|
+
*.jpeg binary
|
|
8
|
+
*.JPG binary
|
|
9
|
+
*.JPEG binary
|
|
10
|
+
*.svg binary
|
|
11
|
+
*.pdf binary
|
|
12
|
+
*.safetensors binary
|
|
13
|
+
*.ipynb text eol=lf
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Local environment / secrets — .env holds the encoder API key, .env.example is committed
|
|
2
|
+
.env
|
|
3
|
+
.env.local
|
|
4
|
+
|
|
5
|
+
# Virtual environments
|
|
6
|
+
.venv/
|
|
7
|
+
env/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
env.bak/
|
|
11
|
+
venv.bak/
|
|
12
|
+
|
|
13
|
+
# Byte-compiled / optimized / DLL files
|
|
14
|
+
__pycache__/
|
|
15
|
+
*.py[cod]
|
|
16
|
+
*$py.class
|
|
17
|
+
|
|
18
|
+
# C extensions
|
|
19
|
+
*.so
|
|
20
|
+
|
|
21
|
+
# Distribution / packaging
|
|
22
|
+
.Python
|
|
23
|
+
build/
|
|
24
|
+
develop-eggs/
|
|
25
|
+
dist/
|
|
26
|
+
downloads/
|
|
27
|
+
eggs/
|
|
28
|
+
.eggs/
|
|
29
|
+
lib/
|
|
30
|
+
lib64/
|
|
31
|
+
parts/
|
|
32
|
+
sdist/
|
|
33
|
+
var/
|
|
34
|
+
wheels/
|
|
35
|
+
share/python-wheels/
|
|
36
|
+
*.egg-info/
|
|
37
|
+
.installed.cfg
|
|
38
|
+
*.egg
|
|
39
|
+
MANIFEST
|
|
40
|
+
|
|
41
|
+
# PyInstaller
|
|
42
|
+
*.manifest
|
|
43
|
+
*.spec
|
|
44
|
+
|
|
45
|
+
# Installer logs
|
|
46
|
+
pip-log.txt
|
|
47
|
+
pip-delete-this-directory.txt
|
|
48
|
+
|
|
49
|
+
# Unit test / coverage reports
|
|
50
|
+
htmlcov/
|
|
51
|
+
.tox/
|
|
52
|
+
.nox/
|
|
53
|
+
.coverage
|
|
54
|
+
.coverage.*
|
|
55
|
+
.cache
|
|
56
|
+
nosetests.xml
|
|
57
|
+
coverage.xml
|
|
58
|
+
*.cover
|
|
59
|
+
*.py,cover
|
|
60
|
+
.hypothesis/
|
|
61
|
+
.pytest_cache/
|
|
62
|
+
cover/
|
|
63
|
+
|
|
64
|
+
# Sphinx documentation
|
|
65
|
+
docs/_build/
|
|
66
|
+
docs/readme.md
|
|
67
|
+
|
|
68
|
+
# Jupyter Notebook
|
|
69
|
+
.ipynb_checkpoints
|
|
70
|
+
|
|
71
|
+
# IPython
|
|
72
|
+
profile_default/
|
|
73
|
+
ipython_config.py
|
|
74
|
+
|
|
75
|
+
# pyenv
|
|
76
|
+
.python-version
|
|
77
|
+
|
|
78
|
+
# pipenv
|
|
79
|
+
Pipfile.lock
|
|
80
|
+
|
|
81
|
+
# pdm
|
|
82
|
+
.pdm.toml
|
|
83
|
+
|
|
84
|
+
# PEP 582
|
|
85
|
+
__pypackages__/
|
|
86
|
+
|
|
87
|
+
# mypy
|
|
88
|
+
.mypy_cache/
|
|
89
|
+
.dmypy.json
|
|
90
|
+
dmypy.json
|
|
91
|
+
|
|
92
|
+
# Pyre type checker
|
|
93
|
+
.pyre/
|
|
94
|
+
|
|
95
|
+
# pytype static type analyzer
|
|
96
|
+
.pytype/
|
|
97
|
+
|
|
98
|
+
# Cython debug symbols
|
|
99
|
+
cython_debug/
|
|
100
|
+
|
|
101
|
+
# PyCharm
|
|
102
|
+
.idea/
|
|
103
|
+
|
|
104
|
+
# VS Code
|
|
105
|
+
.vscode/
|
|
106
|
+
|
|
107
|
+
# PyTorch / Machine Learning artefacts
|
|
108
|
+
*.pth
|
|
109
|
+
*.pt
|
|
110
|
+
*.ckpt
|
|
111
|
+
*.pkl
|
|
112
|
+
*.h5
|
|
113
|
+
*.hdf5
|
|
114
|
+
*.onnx
|
|
115
|
+
*.pb
|
|
116
|
+
*.tflite
|
|
117
|
+
*.tfl
|
|
118
|
+
checkpoints/
|
|
119
|
+
models/
|
|
120
|
+
weights/
|
|
121
|
+
wandb/
|
|
122
|
+
mlruns/
|
|
123
|
+
.neptune/
|
|
124
|
+
|
|
125
|
+
# AgriTune run artefacts
|
|
126
|
+
runs/
|
|
127
|
+
feature_store/
|
|
128
|
+
*.safetensors
|
|
129
|
+
|
|
130
|
+
# Downloaded / prepared example datasets (see examples/datasets/)
|
|
131
|
+
examples/datasets/cwfid/
|
|
132
|
+
examples/datasets/phenobench/
|
|
133
|
+
sample_data/
|
|
134
|
+
|
|
135
|
+
# Claude Code local runtime state — session-local, changes every run
|
|
136
|
+
.claude/scheduled_tasks.lock
|
|
137
|
+
|
|
138
|
+
# OS files
|
|
139
|
+
.DS_Store
|
|
140
|
+
.DS_Store?
|
|
141
|
+
._*
|
|
142
|
+
.Spotlight-V100
|
|
143
|
+
.Trashes
|
|
144
|
+
ehthumbs.db
|
|
145
|
+
Thumbs.db
|
|
146
|
+
*~
|
|
147
|
+
|
|
148
|
+
# Temporary files
|
|
149
|
+
*.tmp
|
|
150
|
+
*.temp
|
|
151
|
+
*.swp
|
|
152
|
+
*.swo
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
# ── File hygiene ────────────────────────────────────────────────────────────
|
|
3
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
4
|
+
rev: v6.0.0
|
|
5
|
+
hooks:
|
|
6
|
+
- id: check-added-large-files
|
|
7
|
+
args: ["--maxkb=1800"]
|
|
8
|
+
- id: check-yaml
|
|
9
|
+
- id: check-json
|
|
10
|
+
- id: check-toml
|
|
11
|
+
- id: end-of-file-fixer
|
|
12
|
+
exclude: ^\.github/badges/
|
|
13
|
+
- id: trailing-whitespace
|
|
14
|
+
args: ["--markdown-linebreak-ext=md"]
|
|
15
|
+
exclude: ^\.github/badges/
|
|
16
|
+
- id: check-merge-conflict
|
|
17
|
+
- id: detect-private-key
|
|
18
|
+
- id: debug-statements
|
|
19
|
+
- id: fix-byte-order-marker
|
|
20
|
+
|
|
21
|
+
# ── Ruff: lint + format + import sorting ───────────────────────────────────
|
|
22
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
23
|
+
rev: v0.15.17
|
|
24
|
+
hooks:
|
|
25
|
+
- id: ruff
|
|
26
|
+
args: ["--fix"]
|
|
27
|
+
- id: ruff-format
|
|
28
|
+
|
|
29
|
+
# ── Type checking (pyright / pylance engine) ────────────────────────────────
|
|
30
|
+
- repo: local
|
|
31
|
+
hooks:
|
|
32
|
+
- id: pyright
|
|
33
|
+
name: pyright
|
|
34
|
+
entry: python -m pyright
|
|
35
|
+
language: system
|
|
36
|
+
types: [python]
|
|
37
|
+
pass_filenames: false
|
|
38
|
+
|
|
39
|
+
# ── Tests + coverage (≥ 90%) ────────────────────────────────────────────────
|
|
40
|
+
- repo: local
|
|
41
|
+
hooks:
|
|
42
|
+
- id: pytest
|
|
43
|
+
name: pytest (coverage ≥ 90%)
|
|
44
|
+
entry: python -m pytest
|
|
45
|
+
language: system
|
|
46
|
+
args: ["tests/", "-q", "--tb=short", "--no-header", "-m", "not integration and not distributed"]
|
|
47
|
+
pass_filenames: false
|
|
48
|
+
always_run: true
|
|
@@ -0,0 +1,336 @@
|
|
|
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.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Performance
|
|
11
|
+
|
|
12
|
+
- `feature_preload: host | device` (new `TrainingRunConfig` field, default `none`): reads the
|
|
13
|
+
training and validation splits' cached features once, before training, into one contiguous
|
|
14
|
+
buffer in RAM or GPU memory (new `precisionai.agritune.features.memory.InMemoryFeatureProvider`),
|
|
15
|
+
and decodes every mask once into a compact `uint8` cache (new
|
|
16
|
+
`segmentation_common.PreloadedBatches`). Each batch then becomes one gather, instead of a
|
|
17
|
+
per-sample store read, validation, and concatenation plus a PNG decode per mask every epoch.
|
|
18
|
+
Measured on an A100 with 113,584 training and 37,707 validation samples and a linear probe,
|
|
19
|
+
with every change in this release, epoch times including validation went from 1,921 s (reading
|
|
20
|
+
a sharded store) to 51–62 s with 57x38 grids in host RAM and 7.5 s with 16x16 grids on the GPU.
|
|
21
|
+
A 100-epoch run at 798x532 masks that took about 80 hours now takes 3 h 45 min end to end, and
|
|
22
|
+
reaches the same test metrics (mean IoU within 0.05 pp). Requires `feature_provider: cached`.
|
|
23
|
+
- Preloading reads each shard once and copies entries into the buffer on a small thread pool
|
|
24
|
+
(5.4 minutes for 252 GB of `float16` features, 3.2x faster than a single thread), and
|
|
25
|
+
`InMemoryFeatureProvider` resolves a sample's row by object identity after its first lookup, so
|
|
26
|
+
cache keys are not rehashed every epoch.
|
|
27
|
+
- `feature_preload_dtype: float16 | bfloat16 | float32` stores preloaded tokens in a smaller
|
|
28
|
+
dtype (cast back to `float32` on the device before the decoder); a value that would overflow
|
|
29
|
+
is rejected while preloading.
|
|
30
|
+
- `shuffle: true` (requires `feature_preload`) reshuffles training samples every epoch in an order
|
|
31
|
+
derived from `seed` and the epoch index, so a resumed run replays the same order.
|
|
32
|
+
- Every decoder (and the loss/metric resize fallbacks) now resizes logits with
|
|
33
|
+
`tasks.segmentation.upsample.bilinear_resize`, which computes exactly what
|
|
34
|
+
`F.interpolate(mode="bilinear", align_corners=False)` does as two small matrix products.
|
|
35
|
+
PyTorch's CUDA backward for bilinear upsampling scatters gradients with atomic adds, which took
|
|
36
|
+
48 of 61 ms per linear-probe step when upsampling a 16x16 grid to 224x224; the matrix form takes
|
|
37
|
+
8 ms for the whole step. Values match `F.interpolate` to floating-point rounding.
|
|
38
|
+
- `PrefetchingFeatureLoader` now issues its copies on a dedicated CUDA stream, so the next batch's
|
|
39
|
+
host-to-device transfer actually overlaps the current step instead of queueing behind it on the
|
|
40
|
+
default stream.
|
|
41
|
+
- `CachedFeatureProvider` keys no longer re-read and re-hash every image file on every epoch:
|
|
42
|
+
`build_image_hash_fn` memoizes each sample's image hash for the life of the run.
|
|
43
|
+
- `ShardedFeatureStore.read()` looks entries up in a per-shard index instead of scanning every
|
|
44
|
+
tensor name in the shard for each read, and both stores gain `read_many()`, which loads each
|
|
45
|
+
shard file once no matter what order keys are requested in.
|
|
46
|
+
- `EncoderFeatures.to()` no longer re-runs full validation (a non-finite scan plus host reads,
|
|
47
|
+
which force a GPU sync on every batch); new `EncoderFeatures.trusted()` builds an instance from
|
|
48
|
+
already-validated tensors.
|
|
49
|
+
|
|
50
|
+
### Security
|
|
51
|
+
|
|
52
|
+
- Every API request field naming a filesystem path (`manifest_path`, `store`, `checkpoint_path`,
|
|
53
|
+
`output_dir`, `config_path`, `augmentation_config_path`) is now resolved through a new
|
|
54
|
+
`precisionai.agritune.api.paths.resolve_under_root` helper and rejected with HTTP 400 if it
|
|
55
|
+
would resolve outside the configured API root (`AGRITUNE_API_ROOT`, defaulting to the server's
|
|
56
|
+
current working directory) — closing a path-traversal gap where an absolute path or a `..`
|
|
57
|
+
segment let a request read or write anywhere the server process could access (e.g.
|
|
58
|
+
`checkpoint_path` into `torch.load`, `output_dir` for prediction PNGs, `config_path` into
|
|
59
|
+
training). This API still has no built-in authentication by design — see `SECURITY.md`.
|
|
60
|
+
- Pull-request CI now requests `contents: read` only, reusable unit-test/pre-commit jobs declare
|
|
61
|
+
the same, and their checkouts set `persist-credentials: false` so pull-request code cannot run
|
|
62
|
+
with a repository write token.
|
|
63
|
+
- Logging redacts API keys, Authorization values, sensitive Hydra/dotlist overrides, and URL
|
|
64
|
+
userinfo/query credentials before emit, including DEBUG override dumps and encoder base URLs.
|
|
65
|
+
|
|
66
|
+
### Documentation
|
|
67
|
+
|
|
68
|
+
- `docs/datasets.md` explains that `agritune train` splits its own manifest into training and
|
|
69
|
+
validation (`val_fraction`, per sample, ignoring any `split` column), so test samples belong in a
|
|
70
|
+
separate manifest for `agritune evaluate`, with a worked example that holds out whole fields via
|
|
71
|
+
`grouped_split`. `docs/configuration.md`, `docs/reproducibility.md`, `docs/segmentation.md`,
|
|
72
|
+
`docs/feature-caching.md`, and the README cover preloading, shuffling, seeding, and output
|
|
73
|
+
resolution.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- Two `tests/unit/test_features.py` tests failed on Python 3.13 (and only there) with `Boolean value
|
|
78
|
+
of Tensor with more than one value is ambiguous`: they compared `EncoderFeatures` instances with
|
|
79
|
+
`==`, which the generated dataclass `__eq__` can only answer when both sides hold the same tensor
|
|
80
|
+
objects, and 3.13 now compares field by field. They compare the fields explicitly. No library
|
|
81
|
+
behavior changed.
|
|
82
|
+
- Training under `augmentation.mode: none` with `geometric.resize` built the decoder at the
|
|
83
|
+
dataset's *native* mask size, because the output-size probe skipped the resize that every
|
|
84
|
+
training batch still receives. The decoder then upsampled to the native size (8.5x more pixels
|
|
85
|
+
for 798x532 masks resized to 224x224), and the loss and metric resized every batch's logits back
|
|
86
|
+
down: three full-size resizes per step. The probe now applies `resize` exactly like
|
|
87
|
+
`build_training_batches` (and like `prediction_service` already did). On an A100 this alone cut
|
|
88
|
+
a 20,000-sample, two-epoch linear-probe run from 36.1 s to 4.7 s.
|
|
89
|
+
- `EncoderFeatures.uniform_patch_grid` reads the batch's patch grids in one host transfer instead
|
|
90
|
+
of one per sample (each a GPU synchronization when the grid is on a CUDA device).
|
|
91
|
+
- The decoder's initial weights are now drawn right after seeding the global RNG from
|
|
92
|
+
`trainer.seed`. Previously they depended on whatever had advanced the RNG earlier in the process
|
|
93
|
+
(every `DataLoader` pass draws a seed from it), so the same config could start from different
|
|
94
|
+
weights depending on unrelated code paths. New runs therefore start from different (but now
|
|
95
|
+
seed-determined) weights than earlier versions did for the same config; resuming an existing
|
|
96
|
+
checkpoint is unaffected.
|
|
97
|
+
- `SegmentationLoss` and `SegmentationMetric` accept class-index targets in any integer dtype
|
|
98
|
+
(widened to `int64` internally); a `uint8` target used to overflow the metric's
|
|
99
|
+
`targets * num_classes + predictions` index.
|
|
100
|
+
- Pyright generic-typing error in `segmentation_common._IndexDataset`.
|
|
101
|
+
- Pyright optional-palette subscript in `colorize_predictions` and live-test API-key narrowing
|
|
102
|
+
after `pytest.skip`.
|
|
103
|
+
- `SegmentationMetric.update` now follows `outputs`/`targets` onto whatever device they're
|
|
104
|
+
actually on (its confusion-matrix accumulator used to stay fixed on CPU, raising a
|
|
105
|
+
device-mismatch error the first time `Trainer`/`evaluate()` moved a batch to CUDA).
|
|
106
|
+
- Feature-space augmentation (`augmentations.feature.transforms`) now moves every random
|
|
107
|
+
mask/noise tensor it draws onto the same device as the features it perturbs, instead of
|
|
108
|
+
leaving it on the CPU-based checkpointed RNG's device — the same class of device-mismatch bug,
|
|
109
|
+
triggered whenever `feature_augmentation` is enabled on a CUDA training run.
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
|
|
113
|
+
- `TrainingRunConfig.device` (`"cpu"`, `"cuda"`, or `"cuda:N"`): the decoder and every batch's
|
|
114
|
+
features/targets now actually move to the configured device before `forward`/`compute_loss`
|
|
115
|
+
(previously nothing in the training pipeline ever called `.to()`, so `trainer.precision: fp16`
|
|
116
|
+
silently never engaged CUDA's gradient scaler). Rejected up front via a new
|
|
117
|
+
`_validate_device_config` if it names a CUDA device that is unavailable or out of range for the
|
|
118
|
+
machine's GPU count — never a silent fallback to CPU. Added `EncoderFeatures.to(device)` and a
|
|
119
|
+
`device` parameter on `evaluate()` to support this.
|
|
120
|
+
- `TrainingRunConfig.feature_read_workers`: exposes `CachedFeatureProvider`'s internal read
|
|
121
|
+
thread-pool size (previously a fixed constant) so it can be tuned independently of the
|
|
122
|
+
`DataLoader`'s `num_workers` — the dominant per-batch cost once `feature_provider: cached` skips
|
|
123
|
+
image loading entirely.
|
|
124
|
+
- `precisionai.agritune.training.prefetch.PrefetchingFeatureLoader`: overlaps one batch's feature
|
|
125
|
+
fetch (a `FeatureProvider.get_features` call — a disk/store read for `cached`/`hybrid`) with the
|
|
126
|
+
previous batch's model compute in a single background thread, wired into both `Trainer`'s
|
|
127
|
+
training loop and `evaluate()`, so the GPU is no longer idle waiting on a synchronous feature
|
|
128
|
+
read every batch.
|
|
129
|
+
- Info/debug/warning logging across previously-silent modules (services, encoder, evaluator),
|
|
130
|
+
plus `tqdm` progress bars over every long-running loop (training/validation batches,
|
|
131
|
+
evaluation, prediction, feature precompute, encoder benchmarking, and the CWFID/PhenoBench prep
|
|
132
|
+
scripts) via a new `precisionai.agritune.logging.progress_iter` helper. Progress bars are
|
|
133
|
+
opt-in per call (`show_progress`, default `False`) so the API stays headless; `Trainer`/
|
|
134
|
+
`evaluate()` gate them on `DistributedContext.is_main_process`, ready for the eventual DDP
|
|
135
|
+
rollout. The FastAPI app now calls `configure_logging()` on startup
|
|
136
|
+
(`AGRITUNE_LOG_LEVEL`, default `INFO`), and its Rich console handler now writes to stderr
|
|
137
|
+
instead of stdout so log lines never interleave with a CLI command's own JSON output.
|
|
138
|
+
- CWFID example: `examples/datasets/prepare_cwfid.py` downloads the public Crop/Weed Field Image
|
|
139
|
+
Dataset, writes an AgriTune manifest, and `examples/SANITY_CHECK.md` runs the full hosted-encoder
|
|
140
|
+
pipeline against it. A `--full` flag downloads all 60 frames without needing to know the exact
|
|
141
|
+
count.
|
|
142
|
+
- PhenoBench example: `examples/datasets/prepare_phenobench.py` downloads the public PhenoBench
|
|
143
|
+
sugar-beet dataset (1,407 train / 772 val real UAV field images, vs. CWFID's 60) and writes an
|
|
144
|
+
AgriTune manifest, collapsing its 5-way partial-visibility labels into AgriTune's 3-class
|
|
145
|
+
background/crop/weed convention.
|
|
146
|
+
- Optional `.env` support (`pip install precisionai-agritune[dotenv]`): a `.env` file is loaded into the
|
|
147
|
+
environment before Hydra composition, so `${oc.env:AGRITUNE_ENCODER_API_KEY,null}` in
|
|
148
|
+
`encoder/remote.yaml` resolves from it. Exported shell variables still take precedence, and
|
|
149
|
+
`AGRITUNE_ENV_FILE` selects a file outside the working directory.
|
|
150
|
+
- Repository foundations: packaging, CI, pre-commit, structured logging, CLI entrypoint (`agritune --help`).
|
|
151
|
+
- Core schemas/protocols, agricultural dataset/manifest/split system, deterministic augmentation
|
|
152
|
+
pipeline, encoder abstraction (fake + remote) with a rate-limited/retrying gateway, feature
|
|
153
|
+
cache and resumable precomputation, `CachedFeatureProvider`, segmentation task (linear + TokenFPN
|
|
154
|
+
decoders, losses, metrics), training engine (AMP, gradient accumulation, checkpointing/exact
|
|
155
|
+
resume, provenance), optimizer/scheduler registries, and JSONL/TensorBoard/MLflow/W&B tracking.
|
|
156
|
+
- `agritune features verify/inspect/clean`, `agritune evaluate`, `agritune predict`, and
|
|
157
|
+
`agritune encoder benchmark` commands, backed by their own services.
|
|
158
|
+
- `OnlineFeatureProvider` and `HybridFeatureProvider`, bridging an `EncoderGateway` into the
|
|
159
|
+
synchronous `FeatureProvider` interface (the v0.2 online/hybrid feature path).
|
|
160
|
+
- Feature-space augmentation (`augmentations.feature`): patch dropout, token masking, Gaussian
|
|
161
|
+
feature noise, CLS dropout, and channel dropout, wired into `Trainer` as an optional train-only
|
|
162
|
+
step.
|
|
163
|
+
- Per-class precision/recall in `SegmentationMetric`; a configurable `checkpoint_top_k` for
|
|
164
|
+
validation-ranked periodic checkpoints; a `temporal_split` dataset split strategy; a prediction
|
|
165
|
+
visualization module (`--overlays` on `agritune predict`); `NeptuneTracker` and `CometTracker`.
|
|
166
|
+
- Agricultural domain-specific image augmentations: sensor channel dropout, ground-sample-distance
|
|
167
|
+
(GSD) jitter, a red/green vegetation-index-balance jitter, and a seasonal/growth-stage hue shift.
|
|
168
|
+
- `augmentation.mode: hybrid` — deterministically reuses an offline variant most of the time, and
|
|
169
|
+
derives a fresh online seed for a configurable fraction of `(sample, epoch, occurrence)` combinations.
|
|
170
|
+
- `PrefetchingFeatureProvider` (`precisionai.agritune.features.prefetch`): overlaps encoding with
|
|
171
|
+
training via a bounded background queue, so an online/hybrid feature provider's network latency
|
|
172
|
+
is hidden behind the GPU training step instead of blocking it. Cancellable mid-consumption (e.g.
|
|
173
|
+
early stopping) without deadlocking `close()`.
|
|
174
|
+
- The API layer (`precisionai.agritune.api`): a thin FastAPI app (`create_app()`) with one route
|
|
175
|
+
per CLI command (`dataset validate/inspect`, `features build/verify/inspect/clean`, `train`,
|
|
176
|
+
`evaluate`, `predict`, `encoder benchmark`), calling the exact same `services/` functions as the
|
|
177
|
+
CLI. `ValueError`/`FileNotFoundError`/`FeatureNotCachedError`/`CheckpointMismatchError` map to
|
|
178
|
+
400/404/404/409 respectively; everything else surfaces as a 500, same as an uncaught CLI
|
|
179
|
+
traceback. Encoder-backend selection was extracted into `services.encoder_selection`, shared by
|
|
180
|
+
both entry points.
|
|
181
|
+
- Real Hydra config-group composition (`precisionai/agritune/configs/`): named YAML variants under
|
|
182
|
+
`dataset/`, `encoder/`, `augmentation/`, `feature_provider/`, `task/`, `decoder/`, `optimizer/`,
|
|
183
|
+
`scheduler/`, and `tracking/`, composed via a `defaults:` list in the packaged `config.yaml`.
|
|
184
|
+
`cli.config.load_training_run_config` resolves either shape: a plain flat YAML file (unchanged,
|
|
185
|
+
original behavior) or a `defaults:`-bearing file resolved through `hydra.compose()`, with the
|
|
186
|
+
same `key=value` override list also able to swap group variants (`decoder=token_fpn`,
|
|
187
|
+
`augmentation=online`). `feature_provider` (`cached`/`online`/`hybrid`), `augmentation`
|
|
188
|
+
(`none`/`offline`/`online`/`hybrid`), and `tracking` selection are now wired end-to-end into
|
|
189
|
+
`run_training`, which rejects the `augmentation=online|hybrid` + `feature_provider=cached`
|
|
190
|
+
combination before training starts.
|
|
191
|
+
- Four new segmentation decoders, alongside a generalized MLP probe replacing the old
|
|
192
|
+
linear-only baseline: `ASPPDecoder` (Atrous Spatial Pyramid Pooling, DeepLabv3-style),
|
|
193
|
+
`PyramidPoolingDecoder` (PSPNet-style pyramid pooling), `SegmenterMaskTransformerDecoder`
|
|
194
|
+
(Segmenter-style joint patch/class-token transformer with a scaled dot-product mask head), and
|
|
195
|
+
`MaskFormerDecoder` (MaskFormer/Mask2Former-style query-based mask classification, combined into
|
|
196
|
+
dense per-pixel scores rather than trained with the original papers' bipartite-matching loss).
|
|
197
|
+
`LinearProbeDecoder` is replaced by `MLPProbeDecoder` (`decoder=mlp_probe`): with
|
|
198
|
+
`hidden_dims=()` (the default) it is architecturally identical to the old linear probe;
|
|
199
|
+
`hidden_dims=(256,)` etc. adds non-linear depth. `build_decoder` now accepts a generic
|
|
200
|
+
`decoder_kwargs` passthrough forwarded to any decoder's constructor (also newly closing a gap
|
|
201
|
+
for `TokenFPNDecoder`'s `cls_fusion`/`hidden_dim`, previously unconfigurable outside direct
|
|
202
|
+
Python construction) — set via each decoder's own Hydra config-group variant
|
|
203
|
+
(`configs/decoder/{mlp_probe,token_fpn,aspp,ppm,segmenter,mask_former}.yaml`).
|
|
204
|
+
- `Trainer.fit`'s optional `train_metric` parameter: a `Metric` accumulated over every training
|
|
205
|
+
batch each epoch (reset at the epoch's start) and logged as `train_{name}` (e.g. `train_mean_iou`)
|
|
206
|
+
alongside the existing `train_loss`/`lr`, exposed via `Trainer.last_train_metrics`. `run_training`
|
|
207
|
+
now always passes one, so `TrainingRunResult.train_metrics` / `agritune train`'s printed summary
|
|
208
|
+
/ `POST /train`'s response report full segmentation metrics for the training set too, not just
|
|
209
|
+
loss — useful for spotting a train/val gap, though noisier than validation since it reflects a
|
|
210
|
+
moving model on (possibly augmented) training batches.
|
|
211
|
+
- `Evaluator.evaluate` (shared by `Trainer`'s validation pass and `agritune evaluate`) now also
|
|
212
|
+
computes a batch-size-weighted mean loss and adds it to its returned dict as `"loss"`, so
|
|
213
|
+
`val_metric_name: loss` (with `higher_is_better: false`) works as a checkpoint/early-stopping
|
|
214
|
+
signal. `EvaluationRunConfig`/`agritune evaluate --loss-*`/`POST /evaluate`'s `loss` field let the
|
|
215
|
+
loss config used for this be set to match what a checkpoint was actually trained under.
|
|
216
|
+
- `agritune features build --augmentation-config <path> --seed <int>` (and `POST /features/build`'s
|
|
217
|
+
matching `augmentation_config_path`/`seed` fields): precomputes a deterministic offline-augmented
|
|
218
|
+
variant alongside the unaugmented features, closing a gap where `feature_service.build_features`
|
|
219
|
+
already supported `augmentation_mode=OFFLINE` but neither entry point exposed it. The
|
|
220
|
+
`--augmentation-config` file is the same `mode`/`variant`/`geometric`/`photometric` shape as
|
|
221
|
+
`configs/augmentation/*.yaml` — point both the build and the training config's `augmentation:`
|
|
222
|
+
block at the same file so their cache keys match. New `cli.config.load_augmentation_selection`
|
|
223
|
+
shares the parsing between the CLI and the API route.
|
|
224
|
+
- `TrainingRunConfig.feature_augmentation` (`feature_augmentation:` in a flat YAML config, or the
|
|
225
|
+
new `feature_augmentation` Hydra group — `none`/`light` — in the composed one), closing a gap
|
|
226
|
+
where `FeatureAugmentationPipeline`/`FeatureAugmentationConfig` (patch dropout, token masking,
|
|
227
|
+
Gaussian feature noise, CLS dropout, channel dropout) were fully implemented and accepted by
|
|
228
|
+
`Trainer`'s constructor but never reachable from `agritune train`/`POST /train` — only from
|
|
229
|
+
direct Python construction. Included in the run's critical-config reproducibility fingerprint,
|
|
230
|
+
alongside image-space `augmentation`.
|
|
231
|
+
- `agritune config init --output <path> [--force]`: writes a fully-commented, flat training config
|
|
232
|
+
template spelling out every field `TrainingRunConfig` accepts at its default value, with the
|
|
233
|
+
dataset-specific fields marked `REQUIRED` as placeholders — the same shape as
|
|
234
|
+
`examples/segmentation/cwfid.yaml` without the CWFID-specific values. Backed by the new
|
|
235
|
+
`services.config_template_service`.
|
|
236
|
+
- `agritune dataset init --output <path> [--force]`: writes an example manifest CSV (a header row
|
|
237
|
+
plus a few placeholder samples) to start a new dataset's manifest from. Backed by
|
|
238
|
+
`services.dataset_service.write_manifest_template`, sharing its file-writing/overwrite-guard
|
|
239
|
+
logic with `config init` via the new `utils.scaffold` helper.
|
|
240
|
+
|
|
241
|
+
### Changed
|
|
242
|
+
|
|
243
|
+
- The PyPI distribution is now named `precisionai-agritune` (it was `pai-agritune`, which was never
|
|
244
|
+
published), matching `precisionai-agrieval`. Install with `pip install precisionai-agritune`; the
|
|
245
|
+
import package (`precisionai.agritune`) and the `agritune` command are unchanged. `release.yml`,
|
|
246
|
+
the README (including its PyPI and Python-version badges), `SECURITY.md`, the bug-report
|
|
247
|
+
template, install hints in error messages and tracking configs, and the tests that assert them
|
|
248
|
+
now use the new name.
|
|
249
|
+
- README: primary header is now "Precision AI AgriTune"; badges moved below the description; the
|
|
250
|
+
stale "Status" section (internal build-phase notes) was removed; `Installation` no longer opens
|
|
251
|
+
the document — a runnable `Quick Start` does, followed by `Project layout`, with a new
|
|
252
|
+
"FastAPI server" subsection under `Installation` covering the `[api]` extra and `uvicorn`.
|
|
253
|
+
`Quick Start` walks the packaged CWFID example end-to-end (dataset prep, validate, feature
|
|
254
|
+
build, train, evaluate) instead of a synthetic placeholder manifest, with a `fake-encoder`
|
|
255
|
+
fallback for anyone without hosted-encoder access yet.
|
|
256
|
+
- `pyproject.toml`'s `api` extra now also installs `uvicorn`, so `pip install "precisionai-agritune[api]"`
|
|
257
|
+
is sufficient to run the FastAPI server (previously required a separate manual `pip install
|
|
258
|
+
uvicorn`).
|
|
259
|
+
- The image augmentation pipeline (`augmentations.image`) now composes
|
|
260
|
+
[albumentations](https://albumentations.ai/) transforms instead of hand-rolled PIL/numpy code,
|
|
261
|
+
using `Compose.set_random_seed` for the same exact-reproducibility guarantee as before.
|
|
262
|
+
|
|
263
|
+
### Fixed
|
|
264
|
+
|
|
265
|
+
- `requirements.txt` no longer hard-pins a CUDA build of `torch` (`torch==2.14.0+cu130` via
|
|
266
|
+
`--extra-index-url .../cu130`) — that install fails outright on CPU-only/non-Linux machines,
|
|
267
|
+
contradicting this repo's own CPU-only CI. Now a plain `torch>=2.2`, matching `pyproject.toml`;
|
|
268
|
+
a comment (and a matching README note) shows the two-step CPU-only install
|
|
269
|
+
(`pip install torch --index-url https://download.pytorch.org/whl/cpu`, same as
|
|
270
|
+
`unit-test.yml`) needed on Linux, where PyPI's default wheel still bundles the full CUDA
|
|
271
|
+
runtime even on a machine with no GPU, plus how to opt into a specific CUDA build instead.
|
|
272
|
+
- `CODE_OF_CONDUCT.md` was missing the "Enforcement Guidelines" section (Correction/Warning/
|
|
273
|
+
Temporary Ban/Permanent Ban) from the official Contributor Covenant v2.1 text — restored
|
|
274
|
+
verbatim.
|
|
275
|
+
- `LICENSE.md` had several small wording drifts from the canonical Apache 2.0 text — replaced with
|
|
276
|
+
the exact upstream text.
|
|
277
|
+
- `.github/dependabot.yml` was missing the `groups: python-dependencies: patterns: ["*"]` block on
|
|
278
|
+
its `pip` update, so routine dependency bumps opened one PR per package instead of one grouped
|
|
279
|
+
weekly PR.
|
|
280
|
+
- `examples/SANITY_CHECK.md` and `examples/FEATURE_TEST_COMMANDS.md` pointed evaluate/predict at
|
|
281
|
+
`runs/cwfid-sanity/checkpoints/...`, a run_id `examples/segmentation/cwfid.yaml` never actually
|
|
282
|
+
produces (it sets `run_id: cwfid-sanity-mlp_probe-feature_aug`) — the checkpoint path in both
|
|
283
|
+
docs never existed. Corrected to the run_id the config actually writes.
|
|
284
|
+
- Flush partial gradient-accumulation windows instead of silently dropping their gradients.
|
|
285
|
+
- Execute gateway-split encoder batches concurrently while preserving response order.
|
|
286
|
+
- Preserve augmentation fingerprints through training batches so hybrid cache keys cannot reuse
|
|
287
|
+
stale features across different augmented images.
|
|
288
|
+
- Harden variable-grid feature masking, remote-response validation, checkpoint fingerprints,
|
|
289
|
+
secret-safe run provenance, and tracker-failure isolation.
|
|
290
|
+
- Persist early-stopping progress across resume so training cannot run extra epochs after a stop.
|
|
291
|
+
- Derive feature-cache keys from a canonical JSON payload so delimiter characters in sample IDs
|
|
292
|
+
cannot collide with adjacent fingerprint fields.
|
|
293
|
+
- Decode CLS embeddings from little-endian float32 base64, matching `encoding_format="base64"` on
|
|
294
|
+
the hosted encoder API — a float-list-only parser crashed on the real `pai-embedding` response.
|
|
295
|
+
- Defer `comet_ml`'s import to `CometTracker` construction instead of importing it at module load.
|
|
296
|
+
`comet_ml` auto-instruments other frameworks in the process (notably `mlflow`) merely by being
|
|
297
|
+
imported; since `tracking_selection.py` imports every tracker module up front, selecting any
|
|
298
|
+
*other* backend (e.g. `mlflow`) silently created an uninvited offline Comet experiment whenever
|
|
299
|
+
`comet_ml` happened to be installed alongside it — which it always is, since both ship in the
|
|
300
|
+
`precisionai-agritune[tracking]` extra.
|
|
301
|
+
- Derive a training run's decoder `output_size` from the actually-augmented probe sample instead
|
|
302
|
+
of the raw pre-augmentation one, so `augmentation.geometric.resize`/`random_crop` (which change
|
|
303
|
+
spatial size) no longer builds a decoder upsampling to the wrong resolution.
|
|
304
|
+
`SegmentationLoss.forward`/`SegmentationMetric.update` now also bilinearly resize logits to the
|
|
305
|
+
target's spatial size when they differ, since validation targets are never augmented and can
|
|
306
|
+
therefore legitimately disagree with training's working resolution under one fixed decoder.
|
|
307
|
+
- Log every encoder retry attempt (`EncoderGateway`) at `WARNING` instead of only counting it in
|
|
308
|
+
metrics — a bounded retry-then-fail run and an actual hang were previously indistinguishable from
|
|
309
|
+
the terminal, since nothing was printed during the backoff sleeps between attempts.
|
|
310
|
+
- CI (`unit-test.yml`/`pre-commit.yml`): install the CPU-only `torch` wheel
|
|
311
|
+
(`--index-url https://download.pytorch.org/whl/cpu`) before `pip install -e ".[dev]"` — the
|
|
312
|
+
default Linux PyPI wheel bundles the full CUDA runtime (several GB of `nvidia-*`/`triton`
|
|
313
|
+
packages) that a CPU-only CI runner never uses, and was exhausting the runner's disk.
|
|
314
|
+
- `evaluation_service.py`/`prediction_service.py`/`training_service.py`: build a decoder's
|
|
315
|
+
`output_size` via a new `segmentation_common.mask_output_size` helper that returns a concrete
|
|
316
|
+
`tuple[int, int]`, instead of `tuple(np.array(mask).shape)` (typed as a variable-length
|
|
317
|
+
`tuple[int, ...]`) — fixes a `pyright` `reportArgumentType` error that a newer `numpy` type-stub
|
|
318
|
+
resolution surfaces on some Python versions.
|
|
319
|
+
- `trailing-whitespace` pre-commit hook: pass `--markdown-linebreak-ext=md` so it stops stripping
|
|
320
|
+
intentional Markdown hard-break trailing spaces (it was rewriting `examples/SANITY_CHECK.md` on
|
|
321
|
+
every run).
|
|
322
|
+
- Fix the remaining pre-existing `pyright` errors, none introduced by recent work but all blocking
|
|
323
|
+
a clean `pre-commit`/CI run: `LossConfigRequest.name` (API schema) now uses the same `LossName`
|
|
324
|
+
literal as `SegmentationLossConfig` instead of a bare `str`; `ImageAugmentationPipeline` builds
|
|
325
|
+
its transform list typed as albumentations' own `TransformsSeqType` instead of the invariant-
|
|
326
|
+
incompatible `list[BasicTransform]`; `PrecisionContext.autocast()` is typed to yield `Any`
|
|
327
|
+
(`nullcontext`/`torch.autocast` disagree on what `__enter__` returns, but no caller binds it);
|
|
328
|
+
`cli/config.py`'s `_config_from_dict(resolved)` call gets the same `# type: ignore[arg-type]`
|
|
329
|
+
treatment the file already uses for `OmegaConf.to_container`'s deliberately-broad return type;
|
|
330
|
+
and several tests narrow an `Optional`/generic-`nn.Module` value with an `assert ... is not None`
|
|
331
|
+
/ `isinstance` check before using it, instead of relying on runtime knowledge pyright can't see.
|
|
332
|
+
- Untrack `.claude/scheduled_tasks.lock` (a Claude Code runtime lock file — session ID/PID/
|
|
333
|
+
timestamp, changes every session) and gitignore it; it was flapping `end-of-file-fixer` on
|
|
334
|
+
unrelated commits.
|
|
335
|
+
|
|
336
|
+
[Unreleased]: https://github.com/Precision-AI-Inc/agritune/compare/v0.1.0...HEAD
|