easydetect 0.2.0__tar.gz → 0.2.1__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.
- {easydetect-0.2.0 → easydetect-0.2.1}/PKG-INFO +14 -11
- {easydetect-0.2.0 → easydetect-0.2.1}/README.md +13 -10
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/__init__.py +1 -1
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/dataset.py +3 -3
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/labels.py +2 -2
- {easydetect-0.2.0 → easydetect-0.2.1}/pyproject.toml +2 -2
- easydetect-0.2.1/tests/test_lab_api.py +31 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/hub_README.md +1 -1
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/make_toyset.py +1 -1
- easydetect-0.2.0/platform/README.md +0 -199
- easydetect-0.2.0/platform/tests/conftest.py +0 -9
- easydetect-0.2.0/platform/tests/test_app.py +0 -1222
- easydetect-0.2.0/platform/tests/test_labeling.py +0 -94
- {easydetect-0.2.0 → easydetect-0.2.1}/.gitignore +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/LICENSE +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/NOTICE +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/cli.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/__init__.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/augment.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/downloads.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/errors.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/exporter.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/metrics.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/model.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/__init__.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/decoder.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/denoising.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/dfine_net.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/encoder.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/hgnetv2.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/ops.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/plotting.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/predictor.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/results.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/sources.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/tracker.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/trainer.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/__init__.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/loss.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/ops.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/validator.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/__init__.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/conftest.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_augment.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_cli.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_coco2yolo.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_dataset.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_downloads.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_model.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_nn.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_onnxruntime.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_predictor.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_results.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_sources.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_tracker.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_train_export.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/bench.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/build_mirror.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/coco2yolo.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/compare_yolo.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/convert_dfine.py +0 -0
- {easydetect-0.2.0 → easydetect-0.2.1}/tools/make_demo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: easydetect
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Easy real-time object detection you can ship: D-FINE with PyTorch training, OpenVINO inference on CPU/GPU/NPU, and a browser app to label and train. Apache-2.0 throughout.
|
|
5
5
|
Project-URL: Homepage, https://github.com/themakerrobot/easydetect
|
|
6
6
|
Project-URL: Source, https://github.com/themakerrobot/easydetect
|
|
@@ -145,18 +145,21 @@ faster on a small set, and `resume=True` picks a killed run back up.
|
|
|
145
145
|
|
|
146
146
|
## Label, train and watch it in a browser
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
folder whose model card is written
|
|
148
|
+
[easydetect lab](https://github.com/themakerrobot/easydetect-lab) is a web app on top of this package, in its own
|
|
149
|
+
repository: drop images in, label them (the model drafts the boxes, you correct
|
|
150
|
+
them), queue a training run, watch the curve, then run the result over a folder,
|
|
151
|
+
a video or your webcam — on one machine, with nothing leaving it. A finished run
|
|
152
|
+
hands you copy-ready code and a Hugging Face folder whose model card is written
|
|
153
|
+
from the run.
|
|
153
154
|
|
|
154
155
|
```bash
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
git clone https://github.com/themakerrobot/easydetect-lab
|
|
157
|
+
cd easydetect-lab
|
|
158
|
+
pip install -r requirements.txt # easydetect[train] from PyPI, and the web server
|
|
159
|
+
python run.py # http://<this machine>:8080
|
|
157
160
|
```
|
|
158
161
|
|
|
159
|
-

|
|
160
163
|
|
|
161
164
|
## Models
|
|
162
165
|
|
|
@@ -226,7 +229,7 @@ easydetect export model=best.pt format=openvino half=true
|
|
|
226
229
|
|
|
227
230
|
* [Using the model](https://github.com/themakerrobot/easydetect/blob/main/docs/usage.md) — sources, results, tracking, saving
|
|
228
231
|
* [Training](https://github.com/themakerrobot/easydetect/blob/main/docs/training.md) — datasets, validation, export, CLI
|
|
229
|
-
* [
|
|
232
|
+
* [easydetect lab](https://github.com/themakerrobot/easydetect-lab) — the browser app: labelling, jobs, sharing
|
|
230
233
|
* [Weights](https://github.com/themakerrobot/easydetect/blob/main/docs/weights.md) — the mirror, building it, offline use
|
|
231
234
|
* [Performance](https://github.com/themakerrobot/easydetect/blob/main/docs/performance.md) — measuring speed and improving it
|
|
232
235
|
* [Design](https://github.com/themakerrobot/easydetect/blob/main/docs/design.md) — architecture and provenance
|
|
@@ -259,7 +262,7 @@ Runtime이 함께 들어가고 PyTorch는 없습니다. `pip install "easydetect
|
|
|
259
262
|
`Detector("dfine-s", backend="onnxruntime")`로 ONNX Runtime(모든 CPU, 라즈베리파이
|
|
260
263
|
포함)을 쓸 수 있습니다. 두 엔진의 결과는 같습니다.
|
|
261
264
|
|
|
262
|
-
라벨링부터 학습·추론까지 브라우저로 하려면
|
|
265
|
+
라벨링부터 학습·추론까지 브라우저로 하려면 [easydetect lab](https://github.com/themakerrobot/easydetect-lab). 가중치 캐시는
|
|
263
266
|
`~/.easydetect/`, 사내 미러는 `EASYDETECT_ASSETS_URL` 환경변수로 지정합니다.
|
|
264
267
|
|
|
265
268
|
## Credits
|
|
@@ -103,18 +103,21 @@ faster on a small set, and `resume=True` picks a killed run back up.
|
|
|
103
103
|
|
|
104
104
|
## Label, train and watch it in a browser
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
folder whose model card is written
|
|
106
|
+
[easydetect lab](https://github.com/themakerrobot/easydetect-lab) is a web app on top of this package, in its own
|
|
107
|
+
repository: drop images in, label them (the model drafts the boxes, you correct
|
|
108
|
+
them), queue a training run, watch the curve, then run the result over a folder,
|
|
109
|
+
a video or your webcam — on one machine, with nothing leaving it. A finished run
|
|
110
|
+
hands you copy-ready code and a Hugging Face folder whose model card is written
|
|
111
|
+
from the run.
|
|
111
112
|
|
|
112
113
|
```bash
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
git clone https://github.com/themakerrobot/easydetect-lab
|
|
115
|
+
cd easydetect-lab
|
|
116
|
+
pip install -r requirements.txt # easydetect[train] from PyPI, and the web server
|
|
117
|
+
python run.py # http://<this machine>:8080
|
|
115
118
|
```
|
|
116
119
|
|
|
117
|
-

|
|
118
121
|
|
|
119
122
|
## Models
|
|
120
123
|
|
|
@@ -184,7 +187,7 @@ easydetect export model=best.pt format=openvino half=true
|
|
|
184
187
|
|
|
185
188
|
* [Using the model](https://github.com/themakerrobot/easydetect/blob/main/docs/usage.md) — sources, results, tracking, saving
|
|
186
189
|
* [Training](https://github.com/themakerrobot/easydetect/blob/main/docs/training.md) — datasets, validation, export, CLI
|
|
187
|
-
* [
|
|
190
|
+
* [easydetect lab](https://github.com/themakerrobot/easydetect-lab) — the browser app: labelling, jobs, sharing
|
|
188
191
|
* [Weights](https://github.com/themakerrobot/easydetect/blob/main/docs/weights.md) — the mirror, building it, offline use
|
|
189
192
|
* [Performance](https://github.com/themakerrobot/easydetect/blob/main/docs/performance.md) — measuring speed and improving it
|
|
190
193
|
* [Design](https://github.com/themakerrobot/easydetect/blob/main/docs/design.md) — architecture and provenance
|
|
@@ -217,7 +220,7 @@ Runtime이 함께 들어가고 PyTorch는 없습니다. `pip install "easydetect
|
|
|
217
220
|
`Detector("dfine-s", backend="onnxruntime")`로 ONNX Runtime(모든 CPU, 라즈베리파이
|
|
218
221
|
포함)을 쓸 수 있습니다. 두 엔진의 결과는 같습니다.
|
|
219
222
|
|
|
220
|
-
라벨링부터 학습·추론까지 브라우저로 하려면
|
|
223
|
+
라벨링부터 학습·추론까지 브라우저로 하려면 [easydetect lab](https://github.com/themakerrobot/easydetect-lab). 가중치 캐시는
|
|
221
224
|
`~/.easydetect/`, 사내 미러는 `EASYDETECT_ASSETS_URL` 환경변수로 지정합니다.
|
|
222
225
|
|
|
223
226
|
## Credits
|
|
@@ -24,7 +24,7 @@ needs numpy/opencv/openvino/pyyaml; training adds
|
|
|
24
24
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
-
__version__ = "0.2.
|
|
27
|
+
__version__ = "0.2.1"
|
|
28
28
|
|
|
29
29
|
from .errors import DownloadError, EasyDetectError, ModelNotFoundError
|
|
30
30
|
from .metrics import BoxMetrics, DetMetrics
|
|
@@ -72,10 +72,10 @@ def _locate(root: Path, yaml_dir: Path, spec: str) -> Path:
|
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def
|
|
75
|
+
def list_images(root: Path, spec, yaml_dir: Path | None = None):
|
|
76
76
|
"""Images for one split: a folder, a .txt list, or a list of either."""
|
|
77
77
|
if isinstance(spec, (list, tuple)):
|
|
78
|
-
files = [f for s in spec for f in
|
|
78
|
+
files = [f for s in spec for f in list_images(root, s, yaml_dir)]
|
|
79
79
|
return list(dict.fromkeys(files))
|
|
80
80
|
p = _locate(root, yaml_dir or root, str(spec))
|
|
81
81
|
if p.is_dir():
|
|
@@ -109,7 +109,7 @@ class DetDataset(Dataset):
|
|
|
109
109
|
f"{data_yaml} has no '{split}:' entry. Add one — it may point at the "
|
|
110
110
|
f"training images, but then mAP only measures memorisation."
|
|
111
111
|
)
|
|
112
|
-
self.files =
|
|
112
|
+
self.files = list_images(cfg["root"], cfg[split], cfg["yaml_dir"])
|
|
113
113
|
if not self.files:
|
|
114
114
|
raise FileNotFoundError(f"no images for split '{split}'")
|
|
115
115
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Apache-2.0
|
|
2
2
|
"""Where a label lives, and how one line of it reads — shared by everything.
|
|
3
3
|
|
|
4
|
-
The trainer reads labels,
|
|
4
|
+
The trainer reads labels, easydetect lab writes them, the exporter packs them.
|
|
5
5
|
If any two of those disagree on where ``a.jpg``'s boxes are, training runs on
|
|
6
6
|
nothing and nobody is told. So there is one rule, here, and no torch import:
|
|
7
|
-
the
|
|
7
|
+
the lab uses it at startup.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "easydetect"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Easy real-time object detection you can ship: D-FINE with PyTorch training, OpenVINO inference on CPU/GPU/NPU, and a browser app to label and train. Apache-2.0 throughout."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -84,5 +84,5 @@ ignore = ["B008", "E741"]
|
|
|
84
84
|
"easydetect/utils/loss.py" = ["E501", "B905", "UP", "B006", "B007"]
|
|
85
85
|
|
|
86
86
|
[tool.pytest.ini_options]
|
|
87
|
-
testpaths = ["tests"
|
|
87
|
+
testpaths = ["tests"]
|
|
88
88
|
filterwarnings = ["ignore::DeprecationWarning"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Apache-2.0
|
|
2
|
+
"""The names easydetect lab imports from this package.
|
|
3
|
+
|
|
4
|
+
The lab lives in its own repository (themakerrobot/easydetect-lab) and runs on
|
|
5
|
+
the PyPI release, so renaming or moving one of these breaks it only after a
|
|
6
|
+
release. This test makes such a change visible here, before it ships.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import importlib
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
LAB_IMPORTS = {
|
|
16
|
+
"easydetect": ["Detector", "__version__"],
|
|
17
|
+
"easydetect.data.dataset": ["DetDataset", "list_images", "load_data_yaml"],
|
|
18
|
+
"easydetect.data.labels": ["label_path", "label_row_to_box"],
|
|
19
|
+
"easydetect.downloads": ["MODEL_NAMES", "assets_url"],
|
|
20
|
+
"easydetect.plotting": ["draw_boxes"],
|
|
21
|
+
"easydetect.results": ["Boxes"],
|
|
22
|
+
"easydetect.sources": ["SourceLoader"],
|
|
23
|
+
"easydetect.validator": ["validate_torch"],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.mark.parametrize("module", sorted(LAB_IMPORTS))
|
|
28
|
+
def test_the_lab_finds_what_it_imports(module):
|
|
29
|
+
mod = importlib.import_module(module)
|
|
30
|
+
missing = [name for name in LAB_IMPORTS[module] if not hasattr(mod, name)]
|
|
31
|
+
assert not missing, f"easydetect lab imports {missing} from {module}"
|
|
@@ -105,7 +105,7 @@ model.export(format="openvino") # best.xml + best.bin + label
|
|
|
105
105
|
|
|
106
106
|
`data.yaml` is the common images/ + labels/ layout — a Roboflow export works as
|
|
107
107
|
it is. Or do it all in a browser: the
|
|
108
|
-
[
|
|
108
|
+
[easydetect lab](https://github.com/themakerrobot/easydetect-lab) collects
|
|
109
109
|
and labels images, trains, shows the numbers, and writes the upload folder for
|
|
110
110
|
`models/` with its README filled in from the run.
|
|
111
111
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Every box is exact, shapes barely overlap, backgrounds vary, so a run that
|
|
9
9
|
learns nothing here is broken rather than short of data. For trying the loop
|
|
10
|
-
(train, val, export, predict, the
|
|
10
|
+
(train, val, export, predict, the lab), not for judging accuracy.
|
|
11
11
|
"""
|
|
12
12
|
import pathlib
|
|
13
13
|
import random
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
# easydetect platform
|
|
2
|
-
|
|
3
|
-
Label images, train on them, watch the run, take the model away — in a browser,
|
|
4
|
-
on one machine. It is a separate application that uses the `easydetect` package; the
|
|
5
|
-
package itself stays a library with a CLI and no web dependencies.
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install -r platform/requirements.txt # in a clone, also: pip install -e ".[train]"
|
|
9
|
-
python platform/run.py # http://<this machine>:8080, from any machine
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-

|
|
13
|
-
|
|
14
|
-
[PLAN.md](PLAN.md) is what this is meant to become, and what is missing today.
|
|
15
|
-
|
|
16
|
-
The screens follow [themaker-ui](https://github.com/themakerrobot/themaker-ui),
|
|
17
|
-
the design kit shared by themakerrobot's education tools: its stylesheet and the
|
|
18
|
-
Pretendard font are copied unchanged into `static/css/` and `static/assets/`
|
|
19
|
-
(CI checks the copy against the kit's v1.0.0 tag), and what is particular to
|
|
20
|
-
this app sits in `static/css/app.css`. The **EN / 한** button at the top right
|
|
21
|
-
switches between Korean and English; the choice is remembered in the browser,
|
|
22
|
-
and a first visit follows the browser's language. Strings live in
|
|
23
|
-
`static/js/i18n.js` — Korean is the source, with an English entry for each.
|
|
24
|
-
Button names below are the English ones.
|
|
25
|
-
|
|
26
|
-
## The loop
|
|
27
|
-
|
|
28
|
-
1. **Collect** — four ways into a dataset, and all of them can add to one that
|
|
29
|
-
already exists: pick image files, upload a video and sample frames from it
|
|
30
|
-
(interval and cap are yours), upload a zip, or register a folder already on
|
|
31
|
-
this machine (`python platform/run.py label --source photos/ --names can,bottle`).
|
|
32
|
-
A YOLO-format export from a labelling service goes in as the zip it
|
|
33
|
-
downloaded as — Roboflow's *YOLOv8* / *YOLOv11* TXT, say — with its classes,
|
|
34
|
-
labels and train/valid split kept; *Statistics* and *Draw boxes* show it straight away.
|
|
35
|
-
Labels are stored where training reads them: in `labels/` beside an
|
|
36
|
-
`images/` folder, otherwise next to each picture, inside the folder.
|
|
37
|
-
2. **Label** — *Draw boxes* on the dataset card. Drag to draw, drag inside a box to
|
|
38
|
-
move it, drag a corner to resize, <kbd>1</kbd>–<kbd>9</kbd> to set the class,
|
|
39
|
-
<kbd>Del</kbd> to remove, <kbd>Ctrl</kbd>+<kbd>Z</kbd> to undo. Saving is
|
|
40
|
-
automatic. The wheel zooms and the middle button (or <kbd>Space</kbd>) pans,
|
|
41
|
-
for boxes too small to place at fit-to-window. <kbd>C</kbd> copies the
|
|
42
|
-
previous image's boxes — a fixed camera repeats itself. Classes can be added
|
|
43
|
-
from the sidebar and show how many boxes each has, and the file list can hide
|
|
44
|
-
what is already labelled. A dataset spread over folders (`train/images`,
|
|
45
|
-
`valid/images`, …) can be browsed one folder at a time, and ←/→ stay in it;
|
|
46
|
-
background frames — a label with no boxes — are marked apart from pictures
|
|
47
|
-
that have boxes.
|
|
48
|
-
3. **Keep the set honest** — *Statistics* counts boxes per class and flags what usually
|
|
49
|
-
bites: images with no label, labels with no boxes, specks under 0.1% of the
|
|
50
|
-
frame. *Duplicate* takes a snapshot before a risky relabel, *Merge selected* combines sets and
|
|
51
|
-
remaps class indices by name (index 0 rarely means the same thing in two
|
|
52
|
-
datasets), and an image can be dropped with its label from the labelling page.
|
|
53
|
-
4. **Let the model do the first pass** — *Auto-label* fills the current image;
|
|
54
|
-
*Auto-label all* queues a job over every unlabelled image in the dataset.
|
|
55
|
-
Correcting boxes is far quicker than drawing them, and once you have a
|
|
56
|
-
`best.pt` you can point the auto-labeller at it.
|
|
57
|
-
5. **Train** — a goal (빠르게 / 균형 / 정확하게) or your own model, epochs,
|
|
58
|
-
batch, backbone freezing, "stop when it stops improving" (patience) and
|
|
59
|
-
zoom/crop augmentation; image size and device under 고급 설정. A goal fills
|
|
60
|
-
only the fields you have not changed yourself. The header shows each NVIDIA GPU live —
|
|
61
|
-
utilisation, memory, temperature, power, read from `nvidia-smi` every two
|
|
62
|
-
seconds — and warns when the driver sees a GPU that PyTorch cannot use (a CPU
|
|
63
|
-
build of torch), since training would then run on the CPU. On a GPU the
|
|
64
|
-
presets batch four times larger. Jobs queue and run one
|
|
65
|
-
at a time; inside an epoch the job shows its batch, what is left and when it
|
|
66
|
-
is validating, and the loss and mAP curve updates per epoch; images are
|
|
67
|
-
decoded by loader processes (half the cores, at most eight —
|
|
68
|
-
`EASYDETECT_WORKERS` overrides); *Stop* stops within a batch;
|
|
69
|
-
*Train more* continues a finished run with more epochs in the same directory;
|
|
70
|
-
every run keeps a `train.log`, and a failure carries the end of it.
|
|
71
|
-
*Delete* removes a finished job with its weights, IR and log, and the runs
|
|
72
|
-
continued from it and the evaluations of it; it is refused while any of them
|
|
73
|
-
runs, or while a registered model uses those files. A run cut short — stopped,
|
|
74
|
-
crashed or interrupted by a restart — keeps its best epoch for evaluating,
|
|
75
|
-
downloading and registering.
|
|
76
|
-
*Run details* on the job shows what the run was set up with from its first
|
|
77
|
-
batch — starting weights, train/validation images and boxes per class,
|
|
78
|
-
trainable parameters, optimizer and schedule, augmentation, device, versions
|
|
79
|
-
— and, once it ends, the best epoch, time per epoch and final losses. The
|
|
80
|
-
trainer writes this to `run.json` in the run folder (`summary.json` repeats
|
|
81
|
-
it with the outcome), so it is there for scripts too.
|
|
82
|
-
6. **See what it learned** — *Evaluate* scores the run on its validation split and
|
|
83
|
-
draws every one of those frames with the truth in green and the prediction in
|
|
84
|
-
its class colour, next to per-class AP. A single mAP says whether to keep
|
|
85
|
-
going; this says what to fix.
|
|
86
|
-
7. **Run it on everything else** — *Predict* takes a dataset, a folder path on this
|
|
87
|
-
machine, or an uploaded video, and queues it like a training job. While it
|
|
88
|
-
works the job says how far it is ("이미지 54/300 · 상자 5개 · 남은 시간 약
|
|
89
|
-
43초") and shows frames as they are drawn; when done, the boxes per class and
|
|
90
|
-
the first 60 drawn frames are right there, with a zip of all of them (and
|
|
91
|
-
`results.json`) and, for a video, `annotated.mp4` to download. The model
|
|
92
|
-
picker lists your finished runs first — no need to register one to use it —
|
|
93
|
-
and auto-labelling drafts with the dataset's own latest run when it has one. *Webcam* opens the browser's camera and
|
|
94
|
-
posts a frame every 400 ms, so you see the model on live video even when the
|
|
95
|
-
server is somewhere else.
|
|
96
|
-
8. **Take it away** — `best.pt`, the OpenVINO IR as a zip (exported when a run
|
|
97
|
-
finishes), `results.csv`. *Register model* gives the run a name (the IR if it has
|
|
98
|
-
one, otherwise the weights) and it then appears wherever a model is chosen —
|
|
99
|
-
auto-labelling, batch inference, the webcam. A `.pt`, `.onnx` or IR (its
|
|
100
|
-
`.xml` and `.bin` picked together) from elsewhere goes into the same list.
|
|
101
|
-
*Use it in code* on a finished run gives Python, command-line and "another
|
|
102
|
-
PC" snippets with this run's paths filled in, ready to copy.
|
|
103
|
-
9. **Share it** — the *Hugging Face* tab builds the folder to upload: the IR,
|
|
104
|
-
`labels.txt`, optionally `best.pt`, and a `README.md` model card written
|
|
105
|
-
from the run itself — classes with their train/val box counts (and AP if
|
|
106
|
-
you evaluated), mAP, backbone, starting weights, the training settings and
|
|
107
|
-
hardware, and download-and-run code pointing at the repo and folder you
|
|
108
|
-
chose (by default the repo your weights come from, `models/<dataset>`).
|
|
109
|
-
It shows the `hf upload` command to run next. The plain IR zip carries the
|
|
110
|
-
same card.
|
|
111
|
-
|
|
112
|
-

|
|
113
|
-
|
|
114
|
-
## Where things live
|
|
115
|
-
|
|
116
|
-
Everything sits under `easydetect-platform/` in the directory you start from —
|
|
117
|
-
`--data /some/path` or `$EASYDETECT_PLATFORM_HOME` moves it:
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
easydetect-platform/
|
|
121
|
-
platform.db datasets, jobs, per-epoch numbers
|
|
122
|
-
datasets/<name>/ uploaded datasets (registered folders stay where they are)
|
|
123
|
-
runs/job<id>/ weights/, openvino/, results.csv, summary.json
|
|
124
|
-
(inference jobs: images/, results.json, annotated.mp4)
|
|
125
|
-
models/<name>/ models uploaded from outside
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## API
|
|
129
|
-
|
|
130
|
-
The pages are only clients of these, so a script can do anything the UI does:
|
|
131
|
-
|
|
132
|
-
| endpoint | |
|
|
133
|
-
| --- | --- |
|
|
134
|
-
| `POST /api/datasets` | multipart: `name`, `archive` (zip) |
|
|
135
|
-
| `POST /api/datasets/images` | multipart: `name`, `files` (images), optional `dataset_id` |
|
|
136
|
-
| `POST /api/datasets/video` | multipart: `name`, `video`, `every`, `max_frames` |
|
|
137
|
-
| `GET /api/datasets/{id}/export` | the dataset as a zip |
|
|
138
|
-
| `GET /api/datasets/{id}/stats` | boxes per class, and what looks wrong |
|
|
139
|
-
| `DELETE /api/datasets/{id}/images/{index}` | drop one image and its label |
|
|
140
|
-
| `POST /api/datasets/{id}/duplicate` | a copy to experiment on |
|
|
141
|
-
| `POST /api/datasets/merge` | `{ids, name}` — one set, class indices remapped |
|
|
142
|
-
| `DELETE /api/datasets/{id}` | |
|
|
143
|
-
| `POST /api/datasets/local` | `{path, name, names}` — register a folder in place |
|
|
144
|
-
| `GET /api/datasets` · `GET /api/datasets/{id}` | the second lists the images |
|
|
145
|
-
| `GET`/`POST /api/datasets/{id}/labels/{index}` | read and write one image's boxes |
|
|
146
|
-
| `POST /api/datasets/{id}/autolabel/{index}` | boxes for one image, from a model |
|
|
147
|
-
| `POST /api/datasets/{id}/autolabel` | queue a pass over the whole dataset |
|
|
148
|
-
| `POST /api/datasets/{id}/classes` | rename or add classes; data.yaml follows |
|
|
149
|
-
| `GET /api/models` | the registry, plus the names that download themselves |
|
|
150
|
-
| `POST /api/models` | `{job_id, name, note}` — register a finished run |
|
|
151
|
-
| `POST /api/models/upload` | multipart: `name`, `files` (a .pt or .onnx, or an IR's .xml + .bin together), `classes` |
|
|
152
|
-
| `DELETE /api/models/{id}` | forget it (files stay) |
|
|
153
|
-
| `POST /api/predict` | multipart: `model`, `conf`, and one of `dataset_id`, `path`, `video` |
|
|
154
|
-
| `POST /api/preview` | multipart: `model`, `conf`, `image` → annotated JPEG, one frame |
|
|
155
|
-
| `POST /api/jobs` | `{dataset_id, model, epochs, imgsz, batch, freeze, device}` |
|
|
156
|
-
| `GET /api/jobs` · `GET /api/jobs/{id}` | the second includes per-epoch rows |
|
|
157
|
-
| `GET /api/gpu` | utilisation, memory, temperature and power per GPU, from nvidia-smi |
|
|
158
|
-
| `GET /api/jobs/{id}/stream` | server-sent events: progress, then a status |
|
|
159
|
-
| `POST /api/jobs/{id}/cancel` | |
|
|
160
|
-
| `DELETE /api/jobs/{id}` | the job and its files, unless something still uses them |
|
|
161
|
-
| `POST /api/jobs/{id}/resume` | `{add_epochs}` — continue a finished run |
|
|
162
|
-
| `POST /api/jobs/{id}/evaluate` | `{conf}` — queue a scoring pass with pictures |
|
|
163
|
-
| `GET /api/jobs/{id}/report` · `/eval/{name}` | the numbers, and the pictures |
|
|
164
|
-
| `GET /api/jobs/{id}/download/{weights,openvino,results,log,predictions,video}` | |
|
|
165
|
-
| `GET /api/jobs/{id}/download/huggingface` | `?repo=&folder=&pt=` — the upload folder, zipped, with its README |
|
|
166
|
-
| `GET /api/jobs/{id}/modelcard` | the README.md that bundle would carry, and where it would go |
|
|
167
|
-
| `POST /api/jobs/{id}/predict` | multipart: `image`, `conf` → annotated JPEG |
|
|
168
|
-
|
|
169
|
-
## What it is not
|
|
170
|
-
|
|
171
|
-
One process, one SQLite file, one folder. No accounts, no permissions, no
|
|
172
|
-
quotas, no scheduler, and one job at a time. That is the point: a workstation or
|
|
173
|
-
a mini PC beside a line needs no infrastructure, and the data never leaves it.
|
|
174
|
-
|
|
175
|
-
When that stops being true — several people, several GPUs, work that must
|
|
176
|
-
survive a restart — the things to change are the worker (onto a real queue) and
|
|
177
|
-
the storage (onto a service), not the package underneath.
|
|
178
|
-
|
|
179
|
-
Other limits worth knowing:
|
|
180
|
-
|
|
181
|
-
* Boxes only. Polygons, keypoints, review workflows and team assignment are out
|
|
182
|
-
of scope; [CVAT](https://github.com/cvat-ai/cvat) (MIT) and
|
|
183
|
-
[Label Studio](https://github.com/HumanSignal/label-studio) (Apache-2.0) export
|
|
184
|
-
the same layout, so you can label there and train here.
|
|
185
|
-
* Training runs in this process, so restarting the server ends a run. Jobs left
|
|
186
|
-
behind are marked failed on the next start rather than spinning forever.
|
|
187
|
-
* It listens on every address (`0.0.0.0`) by default, so other machines can
|
|
188
|
-
open it — and it has no login: anyone who can reach the port can use it.
|
|
189
|
-
`--host 127.0.0.1` keeps it to this machine. Browsers only allow the webcam
|
|
190
|
-
on `https://` or `localhost`, so the same app is also served over HTTPS on
|
|
191
|
-
8443 (`--https-port`, 0 turns it off) with a certificate made on first start
|
|
192
|
-
and kept in `easydetect-platform/tls/`. The browser warns about it once; the
|
|
193
|
-
webcam tab opened over `http://` links to the HTTPS address.
|
|
194
|
-
|
|
195
|
-
## Tests
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
pytest platform/tests
|
|
199
|
-
```
|