easydetect 0.7.2__tar.gz → 0.7.3__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.7.2 → easydetect-0.7.3}/PKG-INFO +1 -1
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/__init__.py +1 -1
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/model.py +17 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/trainer.py +4 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/pyproject.toml +1 -1
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_train_export.py +17 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/bench_finetune.py +9 -3
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/profile_train.py +9 -1
- {easydetect-0.7.2 → easydetect-0.7.3}/.gitignore +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/LICENSE +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/NOTICE +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/README.md +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/benchmark.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/cli.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/data/__init__.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/data/augment.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/data/dataset.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/data/keypoints.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/data/labels.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/downloads.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/errors.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/exporter.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/metrics.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/__init__.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/decoder.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/denoising.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/dfine_net.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/encoder.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/hgnetv2.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/ops.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/posenet.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/nn/sam_decoder.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/plotting.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/pose.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/pose_trainer.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/predictor.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/results.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/seg_trainer.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/segment.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/serve.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/sources.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/tracker.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/utils/__init__.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/utils/checkpoint.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/utils/loss.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/utils/ops.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/easydetect/validator.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/__init__.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/conftest.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/pose_toy.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_augment.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_benchmark.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_cli.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_coco2yolo.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_custom_pose.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_custom_seg.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_dataset.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_downloads.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_lab_api.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_model.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_nn.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_onnxruntime.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_plotting.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_pose.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_predictor.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_results.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_results_summary.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_robustness.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_segment.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_segment_lowres.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_serve.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_sources.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_sources_threads.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tests/test_tracker.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/bench.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/build_mirror.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/coco2yolo.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/compare_yolo.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/convert_dfine.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/convert_sam.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/eval_exports.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/hub_README.md +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/make_demo.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/make_toyset.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/pi_kit.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/train_pose.py +0 -0
- {easydetect-0.7.2 → easydetect-0.7.3}/tools/voc2yolo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: easydetect
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
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
|
|
@@ -24,7 +24,7 @@ needs numpy/opencv/openvino/pyyaml; training adds
|
|
|
24
24
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
-
__version__ = "0.7.
|
|
27
|
+
__version__ = "0.7.3"
|
|
28
28
|
|
|
29
29
|
from .errors import DownloadError, EasyDetectError, ModelNotFoundError
|
|
30
30
|
from .metrics import BoxMetrics, DetMetrics
|
|
@@ -457,6 +457,11 @@ class Detector:
|
|
|
457
457
|
self.names = {int(k): str(v) for k, v in ckpt.get("names", {}).items()}
|
|
458
458
|
self.net = DFINENet(ckpt["variant"], ckpt["num_classes"], pretrained_backbone=False)
|
|
459
459
|
self.net.load_state_dict(ckpt["model"])
|
|
460
|
+
# trained with fewer queries: runs (and fine-tunes again) with as many
|
|
461
|
+
if ckpt.get("queries") and ckpt["queries"] != self.net.decoder.num_queries:
|
|
462
|
+
self.net.trim(queries=int(ckpt["queries"]))
|
|
463
|
+
if ckpt.get("denoising") is not None:
|
|
464
|
+
self.net.decoder.num_denoising = int(ckpt["denoising"])
|
|
460
465
|
self.net.eval()
|
|
461
466
|
self.ir_path = None
|
|
462
467
|
self.predictor = None
|
|
@@ -505,6 +510,8 @@ class Detector:
|
|
|
505
510
|
seg_epochs: int = 20,
|
|
506
511
|
seg_batch: int = 16,
|
|
507
512
|
seg_lr: float = 1e-4,
|
|
513
|
+
queries: int | None = None,
|
|
514
|
+
denoising: int | None = None,
|
|
508
515
|
**kwargs: Any,
|
|
509
516
|
) -> Path:
|
|
510
517
|
"""Train on a data.yaml dataset. Returns the path of ``best.pt``.
|
|
@@ -518,6 +525,12 @@ class Detector:
|
|
|
518
525
|
``on_epoch_end`` is called with a dict of the epoch's numbers — the
|
|
519
526
|
same row that lands in ``results.csv``.
|
|
520
527
|
|
|
528
|
+
``queries`` (of 300) and ``denoising`` (training-only queries, 100)
|
|
529
|
+
make every step cheaper; on a CPU most of a step is spent on them, not
|
|
530
|
+
on the picture. ``queries=100, denoising=30`` trains dfine-n about
|
|
531
|
+
twice as fast on a laptop and suits scenes with a handful of objects;
|
|
532
|
+
the model keeps ``queries`` (it runs faster too).
|
|
533
|
+
|
|
521
534
|
A keypoint dataset (``kpt_shape`` in its data.yaml, Ultralytics' pose
|
|
522
535
|
format) also trains a keypoint network after the detector: on crops of
|
|
523
536
|
the labelled boxes, from the detector's backbone, for ``pose_epochs``
|
|
@@ -561,6 +574,10 @@ class Detector:
|
|
|
561
574
|
elif self.net.num_classes != cfg["nc"]:
|
|
562
575
|
self.net = self._reheaded_net(cfg["nc"])
|
|
563
576
|
|
|
577
|
+
if queries is not None:
|
|
578
|
+
self.net.trim(queries=int(queries))
|
|
579
|
+
if denoising is not None:
|
|
580
|
+
self.net.decoder.num_denoising = int(denoising)
|
|
564
581
|
device = _torch_device(device)
|
|
565
582
|
trainer = Trainer(
|
|
566
583
|
self.net,
|
|
@@ -436,6 +436,8 @@ class Trainer:
|
|
|
436
436
|
# a resumed run started where its first attempt did
|
|
437
437
|
"start": old.get("start") or self.origin,
|
|
438
438
|
"imgsz": self.imgsz,
|
|
439
|
+
"queries": self.net.decoder.num_queries,
|
|
440
|
+
"denoising": self.net.decoder.num_denoising,
|
|
439
441
|
"batch": self.batch,
|
|
440
442
|
"epochs": self.epochs,
|
|
441
443
|
"patience": self.patience,
|
|
@@ -736,6 +738,8 @@ class Trainer:
|
|
|
736
738
|
"scaler": self.scaler.state_dict() if self.amp else None,
|
|
737
739
|
"variant": net.variant,
|
|
738
740
|
"num_classes": net.num_classes,
|
|
741
|
+
"queries": net.decoder.num_queries,
|
|
742
|
+
"denoising": net.decoder.num_denoising,
|
|
739
743
|
"names": self.cfg["names"],
|
|
740
744
|
"epoch": epoch,
|
|
741
745
|
"best": self.best,
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "easydetect"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.3"
|
|
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"
|
|
@@ -477,3 +477,20 @@ def test_multiscale_mosaic_and_mixup_train_and_are_recorded(dataset, tmp_path, m
|
|
|
477
477
|
assert any("mixup" in line for line in setup["augment"])
|
|
478
478
|
assert any("random size, 32–64" in line for line in setup["augment"])
|
|
479
479
|
assert (32, 32) in sizes # the batches went through at the drawn size
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def test_fewer_queries_train_and_stay_with_the_model(dataset, tmp_path, monkeypatch):
|
|
483
|
+
monkeypatch.setattr("easydetect.nn.hgnetv2.HGNetv2.load_imagenet", lambda self, name, url: None)
|
|
484
|
+
model = Detector("dfine-n", verbose=False, pretrained=False)
|
|
485
|
+
best = model.train(data=str(dataset), project=str(tmp_path), epochs=1, imgsz=64, batch=2,
|
|
486
|
+
workers=0, device="cpu", val=False, amp=False, queries=40, denoising=10)
|
|
487
|
+
again = Detector(str(best), verbose=False)
|
|
488
|
+
again._ensure_net()
|
|
489
|
+
assert again.net.decoder.num_queries == 40 and again.net.decoder.num_denoising == 10
|
|
490
|
+
# at 160 px the encoder has more than 300 candidates: only the trim limits it
|
|
491
|
+
onnx = again.export(format="onnx", imgsz=160, out_dir=tmp_path / "x", verbose=False)
|
|
492
|
+
import onnxruntime as ort
|
|
493
|
+
|
|
494
|
+
out = ort.InferenceSession(str(onnx)).run(None, {"images": np.zeros((1, 3, 160, 160),
|
|
495
|
+
np.float32)})
|
|
496
|
+
assert any(o.shape[1] == 40 for o in out if o.ndim == 3)
|
|
@@ -141,14 +141,17 @@ def train_dfine(data: Path, out: Path, args) -> tuple[Path, float]:
|
|
|
141
141
|
# in a process of its own, as the yolo command is: a crash in what training
|
|
142
142
|
# leaves behind (loader workers, CUDA) then takes only that process down
|
|
143
143
|
started = time.time()
|
|
144
|
-
|
|
144
|
+
extra = {k: v for k, v in (("queries", args.queries), ("denoising", args.denoising),
|
|
145
|
+
("freeze", args.freeze)) if v is not None}
|
|
146
|
+
code = ("import json, sys; from easydetect import Detector; "
|
|
145
147
|
"print('BEST', Detector(sys.argv[1], verbose=False).train(data=sys.argv[2], "
|
|
146
148
|
"epochs=int(sys.argv[3]), imgsz=int(sys.argv[4]), batch=int(sys.argv[5]), "
|
|
147
149
|
"patience=int(sys.argv[3]), project=sys.argv[6], name=sys.argv[1], "
|
|
148
|
-
"workers=int(sys.argv[7])))")
|
|
150
|
+
"workers=int(sys.argv[7]), **json.loads(sys.argv[8])))")
|
|
149
151
|
best = None
|
|
150
152
|
with subprocess.Popen([sys.executable, "-c", code, args.dfine, str(data), str(args.epochs),
|
|
151
|
-
str(args.imgsz), str(args.batch), str(out), str(args.workers)
|
|
153
|
+
str(args.imgsz), str(args.batch), str(out), str(args.workers),
|
|
154
|
+
json.dumps(extra)],
|
|
152
155
|
env=UNBUFFERED, stdout=subprocess.PIPE, text=True) as proc:
|
|
153
156
|
for line in proc.stdout: # passed on as it comes
|
|
154
157
|
print(line, end="", flush=True)
|
|
@@ -276,6 +279,9 @@ def main():
|
|
|
276
279
|
parser.add_argument("--yolo", default="yolo26s.pt")
|
|
277
280
|
parser.add_argument("--dfine", default="dfine-s")
|
|
278
281
|
parser.add_argument("--device", default="CPU", help="OpenVINO device for scoring")
|
|
282
|
+
parser.add_argument("--queries", type=int, help="D-FINE decoder queries (of 300)")
|
|
283
|
+
parser.add_argument("--denoising", type=int, help="D-FINE denoising queries (100)")
|
|
284
|
+
parser.add_argument("--freeze", help="D-FINE parts not trained (backbone)")
|
|
279
285
|
parser.add_argument("--rescore", action="store_true",
|
|
280
286
|
help="score finished datasets again (their trained models are reused)")
|
|
281
287
|
args = parser.parse_args()
|
|
@@ -35,6 +35,9 @@ def main():
|
|
|
35
35
|
parser.add_argument("--steps", type=int, default=40)
|
|
36
36
|
parser.add_argument("--warmup", type=int, default=10)
|
|
37
37
|
parser.add_argument("--no-amp", action="store_true")
|
|
38
|
+
parser.add_argument("--freeze", default=None, help="backbone, encoder, …: parts not trained")
|
|
39
|
+
parser.add_argument("--queries", type=int, help="decoder queries while training (of 300)")
|
|
40
|
+
parser.add_argument("--denoising", type=int, help="denoising queries while training (100)")
|
|
38
41
|
parser.add_argument("--trace", action="store_true", help="also PyTorch's operator table")
|
|
39
42
|
parser.add_argument("--syncs", action="store_true",
|
|
40
43
|
help="list the lines of easydetect where a step waits for the GPU")
|
|
@@ -44,9 +47,14 @@ def main():
|
|
|
44
47
|
|
|
45
48
|
nc = load_data_yaml(args.data)["nc"]
|
|
46
49
|
net = DFINENet(args.model, nc)
|
|
50
|
+
if args.queries:
|
|
51
|
+
net.trim(queries=args.queries)
|
|
52
|
+
if args.denoising is not None:
|
|
53
|
+
net.decoder.num_denoising = args.denoising
|
|
47
54
|
with tempfile.TemporaryDirectory() as tmp:
|
|
48
55
|
tr = Trainer(net, args.data, epochs=1, imgsz=args.imgsz, batch=args.batch,
|
|
49
|
-
workers=args.workers, project=tmp, amp=not args.no_amp
|
|
56
|
+
workers=args.workers, project=tmp, amp=not args.no_amp,
|
|
57
|
+
freeze=args.freeze)
|
|
50
58
|
ds = DetDataset(args.data, "train", args.imgsz, augment=True)
|
|
51
59
|
dl = tr._loader(ds)
|
|
52
60
|
net = tr.net.to(tr.device).train()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|