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.
Files changed (62) hide show
  1. {easydetect-0.2.0 → easydetect-0.2.1}/PKG-INFO +14 -11
  2. {easydetect-0.2.0 → easydetect-0.2.1}/README.md +13 -10
  3. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/__init__.py +1 -1
  4. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/dataset.py +3 -3
  5. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/labels.py +2 -2
  6. {easydetect-0.2.0 → easydetect-0.2.1}/pyproject.toml +2 -2
  7. easydetect-0.2.1/tests/test_lab_api.py +31 -0
  8. {easydetect-0.2.0 → easydetect-0.2.1}/tools/hub_README.md +1 -1
  9. {easydetect-0.2.0 → easydetect-0.2.1}/tools/make_toyset.py +1 -1
  10. easydetect-0.2.0/platform/README.md +0 -199
  11. easydetect-0.2.0/platform/tests/conftest.py +0 -9
  12. easydetect-0.2.0/platform/tests/test_app.py +0 -1222
  13. easydetect-0.2.0/platform/tests/test_labeling.py +0 -94
  14. {easydetect-0.2.0 → easydetect-0.2.1}/.gitignore +0 -0
  15. {easydetect-0.2.0 → easydetect-0.2.1}/LICENSE +0 -0
  16. {easydetect-0.2.0 → easydetect-0.2.1}/NOTICE +0 -0
  17. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/cli.py +0 -0
  18. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/__init__.py +0 -0
  19. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/data/augment.py +0 -0
  20. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/downloads.py +0 -0
  21. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/errors.py +0 -0
  22. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/exporter.py +0 -0
  23. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/metrics.py +0 -0
  24. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/model.py +0 -0
  25. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/__init__.py +0 -0
  26. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/decoder.py +0 -0
  27. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/denoising.py +0 -0
  28. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/dfine_net.py +0 -0
  29. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/encoder.py +0 -0
  30. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/hgnetv2.py +0 -0
  31. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/nn/ops.py +0 -0
  32. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/plotting.py +0 -0
  33. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/predictor.py +0 -0
  34. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/results.py +0 -0
  35. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/sources.py +0 -0
  36. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/tracker.py +0 -0
  37. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/trainer.py +0 -0
  38. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/__init__.py +0 -0
  39. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/loss.py +0 -0
  40. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/utils/ops.py +0 -0
  41. {easydetect-0.2.0 → easydetect-0.2.1}/easydetect/validator.py +0 -0
  42. {easydetect-0.2.0 → easydetect-0.2.1}/tests/__init__.py +0 -0
  43. {easydetect-0.2.0 → easydetect-0.2.1}/tests/conftest.py +0 -0
  44. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_augment.py +0 -0
  45. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_cli.py +0 -0
  46. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_coco2yolo.py +0 -0
  47. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_dataset.py +0 -0
  48. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_downloads.py +0 -0
  49. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_model.py +0 -0
  50. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_nn.py +0 -0
  51. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_onnxruntime.py +0 -0
  52. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_predictor.py +0 -0
  53. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_results.py +0 -0
  54. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_sources.py +0 -0
  55. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_tracker.py +0 -0
  56. {easydetect-0.2.0 → easydetect-0.2.1}/tests/test_train_export.py +0 -0
  57. {easydetect-0.2.0 → easydetect-0.2.1}/tools/bench.py +0 -0
  58. {easydetect-0.2.0 → easydetect-0.2.1}/tools/build_mirror.py +0 -0
  59. {easydetect-0.2.0 → easydetect-0.2.1}/tools/coco2yolo.py +0 -0
  60. {easydetect-0.2.0 → easydetect-0.2.1}/tools/compare_yolo.py +0 -0
  61. {easydetect-0.2.0 → easydetect-0.2.1}/tools/convert_dfine.py +0 -0
  62. {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.0
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
- `platform/` is a web app on top of this package: drop images in, label them (the
149
- model drafts the boxes, you correct them), queue a training run, watch the curve,
150
- then run the result over a folder, a video or your webcam — on one machine, with
151
- nothing leaving it. A finished run hands you copy-ready code and a Hugging Face
152
- folder whose model card is written from the run.
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
- pip install -r platform/requirements.txt
156
- python platform/run.py # http://<this machine>:8080
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
- ![the platform](https://raw.githubusercontent.com/themakerrobot/easydetect/main/docs/assets/platform.jpg)
162
+ ![easydetect lab](https://raw.githubusercontent.com/themakerrobot/easydetect-lab/main/docs/lab.jpg)
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
- * [Platform](https://github.com/themakerrobot/easydetect/blob/main/platform/README.md) — the browser app: labelling, jobs, sharing
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
- 라벨링부터 학습·추론까지 브라우저로 하려면 `python platform/run.py`. 가중치 캐시는
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
- `platform/` is a web app on top of this package: drop images in, label them (the
107
- model drafts the boxes, you correct them), queue a training run, watch the curve,
108
- then run the result over a folder, a video or your webcam — on one machine, with
109
- nothing leaving it. A finished run hands you copy-ready code and a Hugging Face
110
- folder whose model card is written from the run.
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
- pip install -r platform/requirements.txt
114
- python platform/run.py # http://<this machine>:8080
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
- ![the platform](https://raw.githubusercontent.com/themakerrobot/easydetect/main/docs/assets/platform.jpg)
120
+ ![easydetect lab](https://raw.githubusercontent.com/themakerrobot/easydetect-lab/main/docs/lab.jpg)
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
- * [Platform](https://github.com/themakerrobot/easydetect/blob/main/platform/README.md) — the browser app: labelling, jobs, sharing
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
- 라벨링부터 학습·추론까지 브라우저로 하려면 `python platform/run.py`. 가중치 캐시는
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.0"
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 _list_images(root: Path, spec, yaml_dir: Path | None = None):
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 _list_images(root, s, yaml_dir)]
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 = _list_images(cfg["root"], cfg[split], cfg["yaml_dir"])
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, the platform writes them, the exporter packs them.
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 platform uses it at startup.
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.0"
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", "platform/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
- [platform](https://github.com/themakerrobot/easydetect/tree/main/platform) collects
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 platform), not for judging accuracy.
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
- ![the platform](../docs/assets/platform.jpg)
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
- ![labelling](../docs/assets/labeling.jpg)
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
- ```
@@ -1,9 +0,0 @@
1
- # Apache-2.0
2
- """The platform's modules live beside it, not on the install path."""
3
-
4
- from __future__ import annotations
5
-
6
- import sys
7
- from pathlib import Path
8
-
9
- sys.path.insert(0, str(Path(__file__).resolve().parents[1]))