trekr 0.1.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.
- trekr-0.1.0/LICENSE +21 -0
- trekr-0.1.0/PKG-INFO +102 -0
- trekr-0.1.0/README.md +77 -0
- trekr-0.1.0/pyproject.toml +36 -0
- trekr-0.1.0/setup.cfg +4 -0
- trekr-0.1.0/src/trekr/__init__.py +3 -0
- trekr-0.1.0/src/trekr/__main__.py +5 -0
- trekr-0.1.0/src/trekr/cli.py +44 -0
- trekr-0.1.0/src/trekr/data/clip.expected.npz +0 -0
- trekr-0.1.0/src/trekr/data/clip.mp4 +0 -0
- trekr-0.1.0/src/trekr/envcheck.py +174 -0
- trekr-0.1.0/src/trekr/labels/__init__.py +1 -0
- trekr-0.1.0/src/trekr/labels/app.py +385 -0
- trekr-0.1.0/src/trekr/labels/check.py +95 -0
- trekr-0.1.0/src/trekr/labels/dlc.py +163 -0
- trekr-0.1.0/src/trekr/videocheck.py +80 -0
- trekr-0.1.0/src/trekr.egg-info/PKG-INFO +102 -0
- trekr-0.1.0/src/trekr.egg-info/SOURCES.txt +22 -0
- trekr-0.1.0/src/trekr.egg-info/dependency_links.txt +1 -0
- trekr-0.1.0/src/trekr.egg-info/entry_points.txt +2 -0
- trekr-0.1.0/src/trekr.egg-info/requires.txt +7 -0
- trekr-0.1.0/src/trekr.egg-info/top_level.txt +1 -0
- trekr-0.1.0/tests/test_basic.py +43 -0
- trekr-0.1.0/tests/test_labels.py +171 -0
trekr-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Koen Freerks
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trekr-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trekr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Checks for pose tracking: a window to find and fix label errors in DeepLabCut projects, the GPU against the PyTorch build, whether OpenCV decodes camera video with the right colours, and whether a video file changed.
|
|
5
|
+
Author: Koen Freerks
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Multimedia :: Video
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: numpy>=1.26
|
|
19
|
+
Requires-Dist: opencv-python-headless>=4.8
|
|
20
|
+
Requires-Dist: PySide6>=6.5
|
|
21
|
+
Requires-Dist: pyyaml>=6
|
|
22
|
+
Provides-Extra: test
|
|
23
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# trekr
|
|
27
|
+
|
|
28
|
+
An early, small release of **TREKR**, a pose-tracking tool in development. This
|
|
29
|
+
release holds three checks that are useful on their own.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install trekr
|
|
33
|
+
trekr labels PROJECT # check and fix DeepLabCut labels (a window)
|
|
34
|
+
trekr check
|
|
35
|
+
trekr videocheck VIDEO [--save REF.json | --against REF.json]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## `trekr labels`: find and fix label errors in a DeepLabCut project
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
trekr labels path/to/my-dlc-project # the folder with config.yaml and labeled-data/
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A wrong label -- a leg point on the neighbour, two points swapped, a point dropped in
|
|
45
|
+
the background -- trains a network to be wrong, and among hundreds of labelled animals
|
|
46
|
+
it is hard to find by eye. Such an error is almost always one point while the rest of
|
|
47
|
+
the animal is right. `trekr labels` compares each point with the rest of its animal
|
|
48
|
+
through the distances between them (which do not change when the animal turns, or is
|
|
49
|
+
seen upside down), against the usual distances in your own labels, and lists the
|
|
50
|
+
animals with the point that fits worst first.
|
|
51
|
+
|
|
52
|
+
- **To check:** click an animal: the image opens on it with its worst point selected.
|
|
53
|
+
A score is in units of the labels' own spread: right points score about 1; errors
|
|
54
|
+
stand far above (on a tested project, most animals above about 10 had a wrong point).
|
|
55
|
+
- **Hover** a point to see which keypoint of which animal it is, and its score.
|
|
56
|
+
- **Editing:** drag a point to move it, right-click to remove it; pick a keypoint in
|
|
57
|
+
the list and click to place it; Ctrl+Z / Ctrl+Y. F5 checks again after edits.
|
|
58
|
+
- **Saving** (Ctrl+S) writes the edited points into `CollectedData_<scorer>.csv`;
|
|
59
|
+
every other byte of the file stays as it was, and the original is kept beside it
|
|
60
|
+
(`.orig`). DeepLabCut trains from the `.h5` file, which you make again from the CSV:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import deeplabcut
|
|
64
|
+
deeplabcut.convertcsv2h5("path/to/my-dlc-project/config.yaml", userfeedback=False)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
One kind of animal per project (DeepLabCut's unique bodyparts are kept as they are and
|
|
68
|
+
not checked); single- and multi-animal projects; the labelled frames are the PNG images
|
|
69
|
+
in `labeled-data/`, so no videos are needed. The skeleton is drawn from `config.yaml`.
|
|
70
|
+
|
|
71
|
+
## `trekr check`: is this computer ready?
|
|
72
|
+
|
|
73
|
+
Every line says **OK**, **NOTE** (works, with a caveat) or **FAIL** (why, and what to
|
|
74
|
+
install); the exit status is 1 when anything fails.
|
|
75
|
+
|
|
76
|
+
- **The GPU against the PyTorch build** (if PyTorch is installed). A PyTorch build
|
|
77
|
+
carries compiled code for some GPU generations only, so a new card -- for example
|
|
78
|
+
the RTX 50 series -- can need a build for a newer CUDA. The check names the GPU's
|
|
79
|
+
architecture and the build's, and says which to install.
|
|
80
|
+
- **The NVIDIA driver against that CUDA version.**
|
|
81
|
+
- **Video decoding.** A tiny stored H.264 clip, encoded the way cameras write video
|
|
82
|
+
(BT.709 colour matrix, TV range), is decoded with the installed OpenCV and compared
|
|
83
|
+
with the frames a correct decoder gives. OpenCV 4.11 and 4.12 apply the wrong colour
|
|
84
|
+
matrix to such video: on the clip, red is off by 5.4 and blue by 2.5 grey levels on
|
|
85
|
+
average, up to 22. Every colour or brightness measured from video decoded that way
|
|
86
|
+
is shifted. OpenCV 4.13 and newer decode it exactly.
|
|
87
|
+
|
|
88
|
+
## `trekr videocheck`: is a video file still the one you recorded?
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
trekr videocheck run1.mp4 --save run1.fingerprint.json # once, next to your data
|
|
92
|
+
trekr videocheck run1.mp4 --against run1.fingerprint.json # later: the same file? (exit 2 if not)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The fingerprint is the file's size and a SHA-256 of its first and last megabyte (fast
|
|
96
|
+
for any size; nothing is decoded), with the frame count, frame rate and size as OpenCV
|
|
97
|
+
reads them. A re-encode, a cut or a different file under the same name shows up, with
|
|
98
|
+
what changed.
|
|
99
|
+
|
|
100
|
+
## Licence
|
|
101
|
+
|
|
102
|
+
MIT (see LICENSE).
|
trekr-0.1.0/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# trekr
|
|
2
|
+
|
|
3
|
+
An early, small release of **TREKR**, a pose-tracking tool in development. This
|
|
4
|
+
release holds three checks that are useful on their own.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install trekr
|
|
8
|
+
trekr labels PROJECT # check and fix DeepLabCut labels (a window)
|
|
9
|
+
trekr check
|
|
10
|
+
trekr videocheck VIDEO [--save REF.json | --against REF.json]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## `trekr labels`: find and fix label errors in a DeepLabCut project
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
trekr labels path/to/my-dlc-project # the folder with config.yaml and labeled-data/
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
A wrong label -- a leg point on the neighbour, two points swapped, a point dropped in
|
|
20
|
+
the background -- trains a network to be wrong, and among hundreds of labelled animals
|
|
21
|
+
it is hard to find by eye. Such an error is almost always one point while the rest of
|
|
22
|
+
the animal is right. `trekr labels` compares each point with the rest of its animal
|
|
23
|
+
through the distances between them (which do not change when the animal turns, or is
|
|
24
|
+
seen upside down), against the usual distances in your own labels, and lists the
|
|
25
|
+
animals with the point that fits worst first.
|
|
26
|
+
|
|
27
|
+
- **To check:** click an animal: the image opens on it with its worst point selected.
|
|
28
|
+
A score is in units of the labels' own spread: right points score about 1; errors
|
|
29
|
+
stand far above (on a tested project, most animals above about 10 had a wrong point).
|
|
30
|
+
- **Hover** a point to see which keypoint of which animal it is, and its score.
|
|
31
|
+
- **Editing:** drag a point to move it, right-click to remove it; pick a keypoint in
|
|
32
|
+
the list and click to place it; Ctrl+Z / Ctrl+Y. F5 checks again after edits.
|
|
33
|
+
- **Saving** (Ctrl+S) writes the edited points into `CollectedData_<scorer>.csv`;
|
|
34
|
+
every other byte of the file stays as it was, and the original is kept beside it
|
|
35
|
+
(`.orig`). DeepLabCut trains from the `.h5` file, which you make again from the CSV:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import deeplabcut
|
|
39
|
+
deeplabcut.convertcsv2h5("path/to/my-dlc-project/config.yaml", userfeedback=False)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
One kind of animal per project (DeepLabCut's unique bodyparts are kept as they are and
|
|
43
|
+
not checked); single- and multi-animal projects; the labelled frames are the PNG images
|
|
44
|
+
in `labeled-data/`, so no videos are needed. The skeleton is drawn from `config.yaml`.
|
|
45
|
+
|
|
46
|
+
## `trekr check`: is this computer ready?
|
|
47
|
+
|
|
48
|
+
Every line says **OK**, **NOTE** (works, with a caveat) or **FAIL** (why, and what to
|
|
49
|
+
install); the exit status is 1 when anything fails.
|
|
50
|
+
|
|
51
|
+
- **The GPU against the PyTorch build** (if PyTorch is installed). A PyTorch build
|
|
52
|
+
carries compiled code for some GPU generations only, so a new card -- for example
|
|
53
|
+
the RTX 50 series -- can need a build for a newer CUDA. The check names the GPU's
|
|
54
|
+
architecture and the build's, and says which to install.
|
|
55
|
+
- **The NVIDIA driver against that CUDA version.**
|
|
56
|
+
- **Video decoding.** A tiny stored H.264 clip, encoded the way cameras write video
|
|
57
|
+
(BT.709 colour matrix, TV range), is decoded with the installed OpenCV and compared
|
|
58
|
+
with the frames a correct decoder gives. OpenCV 4.11 and 4.12 apply the wrong colour
|
|
59
|
+
matrix to such video: on the clip, red is off by 5.4 and blue by 2.5 grey levels on
|
|
60
|
+
average, up to 22. Every colour or brightness measured from video decoded that way
|
|
61
|
+
is shifted. OpenCV 4.13 and newer decode it exactly.
|
|
62
|
+
|
|
63
|
+
## `trekr videocheck`: is a video file still the one you recorded?
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
trekr videocheck run1.mp4 --save run1.fingerprint.json # once, next to your data
|
|
67
|
+
trekr videocheck run1.mp4 --against run1.fingerprint.json # later: the same file? (exit 2 if not)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The fingerprint is the file's size and a SHA-256 of its first and last megabyte (fast
|
|
71
|
+
for any size; nothing is decoded), with the frame count, frame rate and size as OpenCV
|
|
72
|
+
reads them. A re-encode, a cut or a different file under the same name shows up, with
|
|
73
|
+
what changed.
|
|
74
|
+
|
|
75
|
+
## Licence
|
|
76
|
+
|
|
77
|
+
MIT (see LICENSE).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "trekr"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Checks for pose tracking: a window to find and fix label errors in DeepLabCut projects, the GPU against the PyTorch build, whether OpenCV decodes camera video with the right colours, and whether a video file changed."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "Koen Freerks" }]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = ["numpy>=1.26", "opencv-python-headless>=4.8", "PySide6>=6.5", "pyyaml>=6"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Environment :: X11 Applications :: Qt",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Topic :: Multimedia :: Video",
|
|
23
|
+
"Topic :: Scientific/Engineering",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
test = ["pytest>=8"]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
trekr = "trekr.cli:main"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.package-data]
|
|
36
|
+
trekr = ["data/*"]
|
trekr-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
trekr check is this computer ready for GPU video analysis?
|
|
3
|
+
trekr videocheck VIDEO [--save REF.json | --against REF.json]
|
|
4
|
+
a video file's fingerprint; is it still the same?
|
|
5
|
+
trekr labels DLC_PROJECT check and edit DeepLabCut labels (a window)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
|
|
12
|
+
from . import __version__
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv=None):
|
|
16
|
+
ap = argparse.ArgumentParser(prog="trekr", description="TREKR (early release): checks for a computer, its "
|
|
17
|
+
"video files, and pose labels.")
|
|
18
|
+
ap.add_argument("--version", action="version", version=f"trekr {__version__}")
|
|
19
|
+
sub = ap.add_subparsers(dest="command", required=True, metavar="command")
|
|
20
|
+
sub.add_parser("check", help="the GPU against the PyTorch build, the driver, and whether OpenCV decodes camera "
|
|
21
|
+
"video with the right colours")
|
|
22
|
+
v = sub.add_parser("videocheck", help="a video file's fingerprint (size, SHA-256 of both ends, stream facts); "
|
|
23
|
+
"save it, or compare the file with a saved one")
|
|
24
|
+
v.add_argument("video")
|
|
25
|
+
g = v.add_mutually_exclusive_group()
|
|
26
|
+
g.add_argument("--save", metavar="REF.json", help="write the fingerprint to this file")
|
|
27
|
+
g.add_argument("--against", metavar="REF.json", help="compare with a saved fingerprint (exit 2 if changed)")
|
|
28
|
+
lab = sub.add_parser("labels", help="find and fix label errors in a DeepLabCut project: every labelled "
|
|
29
|
+
"animal by how well its points fit together, worst first (a window)")
|
|
30
|
+
lab.add_argument("project", help="a DeepLabCut project folder (with config.yaml and labeled-data/), or one "
|
|
31
|
+
"labeled-data folder")
|
|
32
|
+
args = ap.parse_args(argv)
|
|
33
|
+
if args.command == "labels":
|
|
34
|
+
from .labels.app import run
|
|
35
|
+
return run(args.project)
|
|
36
|
+
if args.command == "check":
|
|
37
|
+
from . import envcheck
|
|
38
|
+
return envcheck.run()
|
|
39
|
+
from . import videocheck
|
|
40
|
+
return videocheck.run(args.video, save=args.save, against=args.against)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
raise SystemExit(main())
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`trekr check`: is this computer ready for GPU video analysis? Every line says
|
|
3
|
+
|
|
4
|
+
OK fine
|
|
5
|
+
NOTE works, with a caveat (what, and by how much)
|
|
6
|
+
FAIL will not work, or not correctly (why, and what to install)
|
|
7
|
+
|
|
8
|
+
1. Python, NumPy, OpenCV and (if installed) PyTorch: their versions.
|
|
9
|
+
2. Each GPU against the PyTorch build: a build carries code for some GPU generations
|
|
10
|
+
only, so a new card (e.g. the RTX 50 series) can need a newer build. And the NVIDIA
|
|
11
|
+
driver against the CUDA version the build was made for.
|
|
12
|
+
3. Video decoding: a stored H.264 clip encoded as cameras write it (BT.709 colours,
|
|
13
|
+
TV range) against the frames a correct decoder gives. OpenCV 4.11 and 4.12 decode
|
|
14
|
+
such video with the wrong colour matrix: on the stored clip red is off by 5.4 and blue
|
|
15
|
+
by 2.5 grey levels on average, up to 22 (measured 2026-10-07; 4.13 and 5.0 decode it
|
|
16
|
+
exactly). That shifts every colour measured from the video.
|
|
17
|
+
|
|
18
|
+
The exit status is 1 when anything fails.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import ctypes
|
|
24
|
+
import platform
|
|
25
|
+
import re
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
|
|
32
|
+
DATA = Path(__file__).parent / "data"
|
|
33
|
+
CLIP = DATA / "clip.mp4"
|
|
34
|
+
CLIP_EXPECTED = DATA / "clip.expected.npz"
|
|
35
|
+
SAME_PIXELS = 0.5 # mean grey levels up to which a decoded frame counts as the same
|
|
36
|
+
|
|
37
|
+
OK, NOTE, FAIL = "OK", "NOTE", "FAIL"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def driver():
|
|
41
|
+
"""(the NVIDIA driver's version, the newest CUDA it runs), each None if unknown."""
|
|
42
|
+
ver = cuda = None
|
|
43
|
+
try: # Linux: no program to start
|
|
44
|
+
m = re.search(r"Kernel Module(?: for \S+)?\s+(\d+(?:\.\d+)+)", Path("/proc/driver/nvidia/version").read_text())
|
|
45
|
+
ver = m.group(1) if m else None
|
|
46
|
+
except OSError:
|
|
47
|
+
pass
|
|
48
|
+
if ver is None:
|
|
49
|
+
try:
|
|
50
|
+
out = subprocess.run(["nvidia-smi", "--query-gpu=driver_version", "--format=csv,noheader"],
|
|
51
|
+
capture_output=True, text=True, timeout=10)
|
|
52
|
+
ver = (out.stdout.strip().splitlines() or [None])[0]
|
|
53
|
+
except (OSError, subprocess.SubprocessError):
|
|
54
|
+
pass
|
|
55
|
+
try:
|
|
56
|
+
lib = ctypes.CDLL("nvcuda.dll" if sys.platform == "win32" else "libcuda.so.1")
|
|
57
|
+
v = ctypes.c_int()
|
|
58
|
+
if lib.cuDriverGetVersion(ctypes.byref(v)) == 0 and v.value:
|
|
59
|
+
cuda = f"{v.value // 1000}.{v.value % 1000 // 10}"
|
|
60
|
+
except (OSError, AttributeError):
|
|
61
|
+
pass
|
|
62
|
+
return ver, cuda
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def arch_support(capability, archs):
|
|
66
|
+
"""How a PyTorch build (its arch list, e.g. ["sm_80", "sm_86", "compute_90"]) runs on a
|
|
67
|
+
GPU of this compute capability ((8, 9)): "native" (code for it, or for an earlier
|
|
68
|
+
minor of the same major), "jit" (only PTX of an earlier architecture: compiled when
|
|
69
|
+
first used), or None (it cannot run there)."""
|
|
70
|
+
major, minor = capability
|
|
71
|
+
native = jit = False
|
|
72
|
+
for a in archs:
|
|
73
|
+
m = re.fullmatch(r"(sm|compute)_(\d+)(\d)([a-z]?)", a)
|
|
74
|
+
if not m:
|
|
75
|
+
continue
|
|
76
|
+
kind, big, small, suffix = m.group(1), int(m.group(2)), int(m.group(3)), m.group(4)
|
|
77
|
+
if kind == "sm" and big == major and (small == minor or (small < minor and not suffix)):
|
|
78
|
+
native = True
|
|
79
|
+
elif kind == "compute" and not suffix and (big, small) <= (major, minor):
|
|
80
|
+
jit = True
|
|
81
|
+
return "native" if native else "jit" if jit else None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _span(archs):
|
|
85
|
+
sm = sorted((a for a in archs if a.startswith("sm_")), key=lambda a: int(re.sub(r"\D", "", a)))
|
|
86
|
+
return f"{sm[0]}-{sm[-1]}" if sm else "no GPU"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def decoding():
|
|
90
|
+
"""The stored clip as OpenCV decodes it here, against a correct decoder's frames:
|
|
91
|
+
{"frames" (None: cannot be read), "mean" (per channel, R G B), "max", "opencv", "reference"}."""
|
|
92
|
+
import cv2
|
|
93
|
+
e = np.load(CLIP_EXPECTED)
|
|
94
|
+
out = {"opencv": cv2.__version__, "reference": str(e["opencv"]), "frames": None, "mean": None, "max": None}
|
|
95
|
+
cap = cv2.VideoCapture(str(CLIP))
|
|
96
|
+
frames = []
|
|
97
|
+
try:
|
|
98
|
+
while len(frames) < len(e["frames"]):
|
|
99
|
+
ok, f = cap.read()
|
|
100
|
+
if not ok:
|
|
101
|
+
break
|
|
102
|
+
frames.append(cv2.cvtColor(f, cv2.COLOR_BGR2RGB))
|
|
103
|
+
finally:
|
|
104
|
+
cap.release()
|
|
105
|
+
if len(frames) != len(e["frames"]) or any(f.shape != e["frames"][0].shape for f in frames):
|
|
106
|
+
return out
|
|
107
|
+
d = np.abs(np.stack(frames).astype(int) - e["frames"].astype(int))
|
|
108
|
+
out.update(frames=len(frames), mean=d.mean((0, 1, 2)), max=int(d.max()))
|
|
109
|
+
return out
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def run(out=None):
|
|
113
|
+
"""Print the check; 0 when nothing fails, else 1."""
|
|
114
|
+
out = out or sys.stdout
|
|
115
|
+
fails = []
|
|
116
|
+
|
|
117
|
+
def say(level, text):
|
|
118
|
+
print(f"{level:5s} {text}", file=out)
|
|
119
|
+
if level == FAIL:
|
|
120
|
+
fails.append(text)
|
|
121
|
+
|
|
122
|
+
import cv2
|
|
123
|
+
say(OK, f"Python {platform.python_version()}, NumPy {np.__version__}, OpenCV {cv2.__version__}")
|
|
124
|
+
try:
|
|
125
|
+
import torch
|
|
126
|
+
except ImportError:
|
|
127
|
+
torch = None
|
|
128
|
+
say(NOTE, "PyTorch is not installed: the GPU check is skipped (pytorch.org, a build for your GPU's CUDA)")
|
|
129
|
+
if torch is not None:
|
|
130
|
+
if not torch.cuda.is_available():
|
|
131
|
+
say(FAIL, f"PyTorch {torch.__version__} sees no GPU it can use (built for "
|
|
132
|
+
f"{'CUDA ' + torch.version.cuda if torch.version.cuda else 'the CPU only'})")
|
|
133
|
+
else:
|
|
134
|
+
archs = torch.cuda.get_arch_list()
|
|
135
|
+
for i in range(torch.cuda.device_count()):
|
|
136
|
+
cap = torch.cuda.get_device_capability(i)
|
|
137
|
+
name = (f"GPU {i}: {torch.cuda.get_device_name(i)} (sm_{cap[0]}{cap[1]}, "
|
|
138
|
+
f"{torch.cuda.get_device_properties(i).total_memory / 2 ** 30:.0f} GB)")
|
|
139
|
+
how = arch_support(cap, archs)
|
|
140
|
+
if how == "native":
|
|
141
|
+
say(OK, f"{name}; PyTorch {torch.__version__} has code for {_span(archs)}")
|
|
142
|
+
elif how == "jit":
|
|
143
|
+
say(NOTE, f"{name}: this PyTorch has code for {_span(archs)} only; it is compiled for this "
|
|
144
|
+
f"GPU when first used (a slow start)")
|
|
145
|
+
else:
|
|
146
|
+
say(FAIL, f"{name}: this PyTorch has code for {_span(archs)} only. Install a PyTorch build "
|
|
147
|
+
f"whose architecture list includes sm_{cap[0]}{cap[1]} (pytorch.org; newer GPUs "
|
|
148
|
+
f"need builds for newer CUDA)")
|
|
149
|
+
ver, dcuda = driver()
|
|
150
|
+
rt = torch.version.cuda
|
|
151
|
+
if ver is None or dcuda is None or rt is None:
|
|
152
|
+
say(NOTE, f"NVIDIA driver {ver or 'unknown'}: the CUDA it runs is unknown")
|
|
153
|
+
else:
|
|
154
|
+
d, r = tuple(map(int, dcuda.split("."))), tuple(map(int, rt.split(".")))
|
|
155
|
+
if d[0] < r[0]:
|
|
156
|
+
say(FAIL, f"NVIDIA driver {ver} runs CUDA up to {dcuda}; this PyTorch is built for CUDA {rt}: "
|
|
157
|
+
f"update the driver, or install a PyTorch build for CUDA {d[0]}")
|
|
158
|
+
else:
|
|
159
|
+
say(OK, f"NVIDIA driver {ver} (CUDA {dcuda}); PyTorch built for CUDA {rt}"
|
|
160
|
+
+ (" runs on it by CUDA minor-version compatibility" if d < r else ""))
|
|
161
|
+
dec = decoding()
|
|
162
|
+
if dec["frames"] is None:
|
|
163
|
+
say(FAIL, f"OpenCV {dec['opencv']} cannot decode H.264 video (the stored test clip): install "
|
|
164
|
+
f"opencv-python-headless from PyPI, which brings its own decoder")
|
|
165
|
+
elif dec["mean"].max() <= SAME_PIXELS:
|
|
166
|
+
say(OK, f"OpenCV {dec['opencv']} decodes camera video (H.264, BT.709) with the right colours")
|
|
167
|
+
else:
|
|
168
|
+
m = dec["mean"]
|
|
169
|
+
say(FAIL, f"OpenCV {dec['opencv']} decodes camera video (H.264 tagged BT.709) with other colours than a "
|
|
170
|
+
f"correct decoder (OpenCV {dec['reference']}): R {m[0]:.1f}, G {m[1]:.1f}, B {m[2]:.1f} grey "
|
|
171
|
+
f"levels off on average, up to {dec['max']}. OpenCV 4.11 and 4.12 apply the wrong colour "
|
|
172
|
+
f"matrix; use 4.13 or newer")
|
|
173
|
+
print(f"\nNot ready: {len(fails)} problem(s) above (FAIL)." if fails else "\nReady.", file=out)
|
|
174
|
+
return 1 if fails else 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""`trekr labels`: find and fix label errors in a DeepLabCut project."""
|